1 /*
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>
21 #include <errno.h>
22
23 #include "m_ematch.h"
24 #include <linux/tc_ematch/tc_em_nbyte.h>
25
26 extern struct ematch_util nbyte_ematch_util;
27
nbyte_print_usage(FILE * fd)28 static 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" \
34 " LAYER := { link | network | transport | 0..%d }\n" \
35 "\n" \
36 "Example: nbyte(\"ababa\" at 12 layer 1)\n",
37 TCF_LAYER_MAX);
38 }
39
nbyte_parse_eopt(struct nlmsghdr * n,struct tcf_ematch_hdr * hdr,struct bstr * args)40 static 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;
47 struct tcf_em_nbyte nb = {};
48
49 #define PARSE_ERR(CARG, FMT, ARGS...) \
50 em_parse_error(EINVAL, args, CARG, &nbyte_ematch_util, FMT, ##ARGS)
51
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");
92
93 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
nbyte_print_eopt(FILE * fd,struct tcf_ematch_hdr * hdr,void * data,int data_len)105 static 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);
131
132 return 0;
133 }
134
135 struct 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 };
142