blob: 52b4d10a13e2235141d40983398de47f602fbe31 [file] [log] [blame]
shemminger311b4142005-06-23 20:25:16 +00001/*
2 * em_nbyte.c N-Byte Ematch
3 *
4 * This program is free software; you can distribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version
7 * 2 of the License, or (at your option) any later version.
8 *
9 * Authors: Thomas Graf <tgraf@suug.ch>
10 */
11
12#include <stdio.h>
13#include <stdlib.h>
14#include <unistd.h>
15#include <syslog.h>
16#include <fcntl.h>
17#include <sys/socket.h>
18#include <netinet/in.h>
19#include <arpa/inet.h>
20#include <string.h>
shemminger311b4142005-06-23 20:25:16 +000021#include <errno.h>
22
23#include "m_ematch.h"
24#include <linux/tc_ematch/tc_em_nbyte.h>
25
26extern struct ematch_util nbyte_ematch_util;
27
28static void nbyte_print_usage(FILE *fd)
29{
30 fprintf(fd,
31 "Usage: nbyte(NEEDLE at OFFSET [layer LAYER])\n" \
32 "where: NEEDLE := { string | \"c-escape-sequence\" }\n" \
33 " OFFSET := int\n" \
Lionel Elie Mamanebc45ded2007-10-12 10:56:43 +020034 " LAYER := { link | network | transport | 0..%d }\n" \
shemminger311b4142005-06-23 20:25:16 +000035 "\n" \
36 "Example: nbyte(\"ababa\" at 12 layer 1)\n",
37 TCF_LAYER_MAX);
38}
39
40static int nbyte_parse_eopt(struct nlmsghdr *n, struct tcf_ematch_hdr *hdr,
41 struct bstr *args)
42{
43 struct bstr *a;
44 struct bstr *needle = args;
45 unsigned long offset = 0, layer = TCF_LAYER_NETWORK;
46 int offset_present = 0;
Phil Sutterd17b1362016-07-18 16:48:42 +020047 struct tcf_em_nbyte nb = {};
shemminger311b4142005-06-23 20:25:16 +000048
49#define PARSE_ERR(CARG, FMT, ARGS...) \
Stephen Hemminger32a121c2016-03-21 11:48:36 -070050 em_parse_error(EINVAL, args, CARG, &nbyte_ematch_util, FMT, ##ARGS)
shemminger311b4142005-06-23 20:25:16 +000051
52 if (args == NULL)
53 return PARSE_ERR(args, "nbyte: missing arguments");
54
55 if (needle->len <= 0)
56 return PARSE_ERR(args, "nbyte: needle length is 0");
57
58 for (a = bstr_next(args); a; a = bstr_next(a)) {
59 if (!bstrcmp(a, "at")) {
60 if (a->next == NULL)
61 return PARSE_ERR(a, "nbyte: missing argument");
62 a = bstr_next(a);
63
64 offset = bstrtoul(a);
65 if (offset == ULONG_MAX)
66 return PARSE_ERR(a, "nbyte: invalid offset, " \
67 "must be numeric");
68
69 offset_present = 1;
70 } else if (!bstrcmp(a, "layer")) {
71 if (a->next == NULL)
72 return PARSE_ERR(a, "nbyte: missing argument");
73 a = bstr_next(a);
74
75 layer = parse_layer(a);
76 if (layer == INT_MAX) {
77 layer = bstrtoul(a);
78 if (layer == ULONG_MAX)
79 return PARSE_ERR(a, "nbyte: invalid " \
80 "layer");
81 }
82
83 if (layer > TCF_LAYER_MAX)
84 return PARSE_ERR(a, "nbyte: illegal layer, " \
85 "must be in 0..%d", TCF_LAYER_MAX);
86 } else
87 return PARSE_ERR(a, "nbyte: unknown parameter");
88 }
89
90 if (offset_present == 0)
91 return PARSE_ERR(a, "nbyte: offset required");
Stephen Hemmingerae665a52006-12-05 10:10:22 -080092
shemminger311b4142005-06-23 20:25:16 +000093 nb.len = needle->len;
94 nb.layer = (__u8) layer;
95 nb.off = (__u16) offset;
96
97 addraw_l(n, MAX_MSG, hdr, sizeof(*hdr));
98 addraw_l(n, MAX_MSG, &nb, sizeof(nb));
99 addraw_l(n, MAX_MSG, needle->data, needle->len);
100
101#undef PARSE_ERR
102 return 0;
103}
104
105static int nbyte_print_eopt(FILE *fd, struct tcf_ematch_hdr *hdr, void *data,
106 int data_len)
107{
108 int i;
109 struct tcf_em_nbyte *nb = data;
110 __u8 *needle;
111
112 if (data_len < sizeof(*nb)) {
113 fprintf(stderr, "NByte header size mismatch\n");
114 return -1;
115 }
116
117 if (data_len < sizeof(*nb) + nb->len) {
118 fprintf(stderr, "NByte payload size mismatch\n");
119 return -1;
120 }
121
122 needle = data + sizeof(*nb);
123
124 for (i = 0; i < nb->len; i++)
125 fprintf(fd, "%02x ", needle[i]);
126
127 fprintf(fd, "\"");
128 for (i = 0; i < nb->len; i++)
129 fprintf(fd, "%c", isprint(needle[i]) ? needle[i] : '.');
130 fprintf(fd, "\" at %d layer %d", nb->off, nb->layer);
Stephen Hemmingerae665a52006-12-05 10:10:22 -0800131
shemminger311b4142005-06-23 20:25:16 +0000132 return 0;
133}
134
135struct ematch_util nbyte_ematch_util = {
136 .kind = "nbyte",
137 .kind_num = TCF_EM_NBYTE,
138 .parse_eopt = nbyte_parse_eopt,
139 .print_eopt = nbyte_print_eopt,
140 .print_usage = nbyte_print_usage
141};