blob: 9198edca37028f54587888ba81b099b831f34e29 [file] [log] [blame]
Jan Engelhardt9640e522007-09-10 11:50:46 +00001/* Shared library add-on to iptables to add u32 matching,
2 * generalized matching on values found at packet offsets
3 *
4 * Detailed doc is in the kernel module source
5 * net/netfilter/xt_u32.c
6 *
7 * (C) 2002 by Don Cohen <don-netf@isis.cs3-inc.com>
Jan Engelhardt9640e522007-09-10 11:50:46 +00008 * Released under the terms of GNU GPL v2
Jan Engelhardt032722b2007-10-20 15:17:30 +00009 *
10 * Copyright © CC Computer Consultants GmbH, 2007
11 * Contact: <jengelh@computergmbh.de>
Jan Engelhardt9640e522007-09-10 11:50:46 +000012 */
Jan Engelhardt9640e522007-09-10 11:50:46 +000013#include <ctype.h>
14#include <errno.h>
Jan Engelhardt4f7f1872011-03-02 23:06:59 +010015#include <stdint.h>
Jan Engelhardt9640e522007-09-10 11:50:46 +000016#include <stdlib.h>
17#include <stdio.h>
Jan Engelhardt9640e522007-09-10 11:50:46 +000018#include <xtables.h>
Jan Engelhardta2a7f2b2008-09-01 14:20:13 +020019#include <linux/netfilter/xt_u32.h>
Jan Engelhardt9640e522007-09-10 11:50:46 +000020
Jan Engelhardt4f7f1872011-03-02 23:06:59 +010021enum {
22 O_U32 = 0,
23};
24
25static const struct xt_option_entry u32_opts[] = {
26 {.name = "u32", .id = O_U32, .type = XTTYPE_STRING},
27 XTOPT_TABLEEND,
Jan Engelhardt9640e522007-09-10 11:50:46 +000028};
29
30static void u32_help(void)
31{
32 printf(
Jan Engelhardt8b7c64d2008-04-15 11:48:25 +020033 "u32 match options:\n"
Jan Engelhardt9640e522007-09-10 11:50:46 +000034 "[!] --u32 tests\n"
35 "\t\t""tests := location \"=\" value | tests \"&&\" location \"=\" value\n"
36 "\t\t""value := range | value \",\" range\n"
37 "\t\t""range := number | number \":\" number\n"
38 "\t\t""location := number | location operator number\n"
Jan Engelhardt8b7c64d2008-04-15 11:48:25 +020039 "\t\t""operator := \"&\" | \"<<\" | \">>\" | \"@\"\n");
Jan Engelhardt9640e522007-09-10 11:50:46 +000040}
41
42static void u32_dump(const struct xt_u32 *data)
43{
44 const struct xt_u32_test *ct;
45 unsigned int testind, i;
46
Jan Engelhardt73866352010-12-18 02:04:59 +010047 printf(" \"");
Jan Engelhardt9640e522007-09-10 11:50:46 +000048 for (testind = 0; testind < data->ntests; ++testind) {
49 ct = &data->tests[testind];
50
51 if (testind > 0)
52 printf("&&");
53
54 printf("0x%x", ct->location[0].number);
55 for (i = 1; i < ct->nnums; ++i) {
56 switch (ct->location[i].nextop) {
57 case XT_U32_AND:
58 printf("&");
59 break;
60 case XT_U32_LEFTSH:
61 printf("<<");
62 break;
63 case XT_U32_RIGHTSH:
64 printf(">>");
65 break;
66 case XT_U32_AT:
67 printf("@");
68 break;
69 }
70 printf("0x%x", ct->location[i].number);
71 }
72
73 printf("=");
74 for (i = 0; i < ct->nvalues; ++i) {
75 if (i > 0)
76 printf(",");
77 if (ct->value[i].min == ct->value[i].max)
78 printf("0x%x", ct->value[i].min);
79 else
80 printf("0x%x:0x%x", ct->value[i].min,
81 ct->value[i].max);
82 }
83 }
Jan Engelhardt73866352010-12-18 02:04:59 +010084 putchar('\"');
Jan Engelhardt9640e522007-09-10 11:50:46 +000085}
86
87/* string_to_number() is not quite what we need here ... */
Jan Engelhardt4f7f1872011-03-02 23:06:59 +010088static uint32_t parse_number(const char **s, int pos)
Jan Engelhardt9640e522007-09-10 11:50:46 +000089{
Jan Engelhardt7ac40522011-01-07 12:34:04 +010090 uint32_t number;
Jan Engelhardt9640e522007-09-10 11:50:46 +000091 char *end;
92
93 errno = 0;
94 number = strtoul(*s, &end, 0);
95 if (end == *s)
Jan Engelhardt1829ed42009-02-21 03:29:44 +010096 xtables_error(PARAMETER_PROBLEM,
Jan Engelhardt9640e522007-09-10 11:50:46 +000097 "u32: at char %d: expected number", pos);
98 if (errno != 0)
Jan Engelhardt1829ed42009-02-21 03:29:44 +010099 xtables_error(PARAMETER_PROBLEM,
Jan Engelhardt9640e522007-09-10 11:50:46 +0000100 "u32: at char %d: error reading number", pos);
101 *s = end;
102 return number;
103}
104
Jan Engelhardt4f7f1872011-03-02 23:06:59 +0100105static void u32_parse(struct xt_option_call *cb)
Jan Engelhardt9640e522007-09-10 11:50:46 +0000106{
Jan Engelhardt4f7f1872011-03-02 23:06:59 +0100107 struct xt_u32 *data = cb->data;
Jan Engelhardt9640e522007-09-10 11:50:46 +0000108 unsigned int testind = 0, locind = 0, valind = 0;
109 struct xt_u32_test *ct = &data->tests[testind]; /* current test */
Jan Engelhardt4f7f1872011-03-02 23:06:59 +0100110 const char *arg = cb->arg; /* the argument string */
111 const char *start = cb->arg;
Jan Engelhardt9640e522007-09-10 11:50:46 +0000112 int state = 0;
113
Jan Engelhardt373e8512011-05-06 22:40:35 +0200114 xtables_option_parse(cb);
Jan Engelhardt4f7f1872011-03-02 23:06:59 +0100115 data->invert = cb->invert;
Jan Engelhardt9640e522007-09-10 11:50:46 +0000116
117 /*
118 * states:
119 * 0 = looking for numbers and operations,
120 * 1 = looking for ranges
121 */
122 while (1) {
123 /* read next operand/number or range */
124 while (isspace(*arg))
125 ++arg;
126
127 if (*arg == '\0') {
128 /* end of argument found */
129 if (state == 0)
Jan Engelhardt1829ed42009-02-21 03:29:44 +0100130 xtables_error(PARAMETER_PROBLEM,
Jan Engelhardt9640e522007-09-10 11:50:46 +0000131 "u32: abrupt end of input after location specifier");
132 if (valind == 0)
Jan Engelhardt1829ed42009-02-21 03:29:44 +0100133 xtables_error(PARAMETER_PROBLEM,
Jan Engelhardt9640e522007-09-10 11:50:46 +0000134 "u32: test ended with no value specified");
135
136 ct->nnums = locind;
137 ct->nvalues = valind;
138 data->ntests = ++testind;
139
140 if (testind > XT_U32_MAXSIZE)
Jan Engelhardt1829ed42009-02-21 03:29:44 +0100141 xtables_error(PARAMETER_PROBLEM,
Jan Engelhardt55951a02007-09-19 12:59:33 +0000142 "u32: at char %u: too many \"&&\"s",
143 (unsigned int)(arg - start));
Jan Engelhardt4f7f1872011-03-02 23:06:59 +0100144 return;
Jan Engelhardt9640e522007-09-10 11:50:46 +0000145 }
146
147 if (state == 0) {
148 /*
149 * reading location: read a number if nothing read yet,
150 * otherwise either op number or = to end location spec
151 */
152 if (*arg == '=') {
153 if (locind == 0) {
Jan Engelhardt1829ed42009-02-21 03:29:44 +0100154 xtables_error(PARAMETER_PROBLEM,
Jan Engelhardt55951a02007-09-19 12:59:33 +0000155 "u32: at char %u: "
Jan Engelhardt9640e522007-09-10 11:50:46 +0000156 "location spec missing",
Jan Engelhardt55951a02007-09-19 12:59:33 +0000157 (unsigned int)(arg - start));
Jan Engelhardt9640e522007-09-10 11:50:46 +0000158 } else {
159 ++arg;
160 state = 1;
161 }
162 } else {
163 if (locind != 0) {
164 /* need op before number */
165 if (*arg == '&') {
166 ct->location[locind].nextop = XT_U32_AND;
167 } else if (*arg == '<') {
168 if (*++arg != '<')
Jan Engelhardt1829ed42009-02-21 03:29:44 +0100169 xtables_error(PARAMETER_PROBLEM,
Jan Engelhardt55951a02007-09-19 12:59:33 +0000170 "u32: at char %u: a second '<' was expected", (unsigned int)(arg - start));
Jan Engelhardt9640e522007-09-10 11:50:46 +0000171 ct->location[locind].nextop = XT_U32_LEFTSH;
172 } else if (*arg == '>') {
173 if (*++arg != '>')
Jan Engelhardt1829ed42009-02-21 03:29:44 +0100174 xtables_error(PARAMETER_PROBLEM,
Jan Engelhardt55951a02007-09-19 12:59:33 +0000175 "u32: at char %u: a second '>' was expected", (unsigned int)(arg - start));
Jan Engelhardt9640e522007-09-10 11:50:46 +0000176 ct->location[locind].nextop = XT_U32_RIGHTSH;
177 } else if (*arg == '@') {
178 ct->location[locind].nextop = XT_U32_AT;
179 } else {
Jan Engelhardt1829ed42009-02-21 03:29:44 +0100180 xtables_error(PARAMETER_PROBLEM,
Jan Engelhardt55951a02007-09-19 12:59:33 +0000181 "u32: at char %u: operator expected", (unsigned int)(arg - start));
Jan Engelhardt9640e522007-09-10 11:50:46 +0000182 }
183 ++arg;
184 }
185 /* now a number; string_to_number skips white space? */
186 ct->location[locind].number =
187 parse_number(&arg, arg - start);
188 if (++locind > XT_U32_MAXSIZE)
Jan Engelhardt1829ed42009-02-21 03:29:44 +0100189 xtables_error(PARAMETER_PROBLEM,
Jan Engelhardt55951a02007-09-19 12:59:33 +0000190 "u32: at char %u: too many operators", (unsigned int)(arg - start));
Jan Engelhardt9640e522007-09-10 11:50:46 +0000191 }
192 } else {
193 /*
194 * state 1 - reading values: read a range if nothing
195 * read yet, otherwise either ,range or && to end
196 * test spec
197 */
198 if (*arg == '&') {
199 if (*++arg != '&')
Jan Engelhardt1829ed42009-02-21 03:29:44 +0100200 xtables_error(PARAMETER_PROBLEM,
Jan Engelhardt55951a02007-09-19 12:59:33 +0000201 "u32: at char %u: a second '&' was expected", (unsigned int)(arg - start));
Jan Engelhardt9640e522007-09-10 11:50:46 +0000202 if (valind == 0) {
Jan Engelhardt1829ed42009-02-21 03:29:44 +0100203 xtables_error(PARAMETER_PROBLEM,
Jan Engelhardt55951a02007-09-19 12:59:33 +0000204 "u32: at char %u: value spec missing", (unsigned int)(arg - start));
Jan Engelhardt9640e522007-09-10 11:50:46 +0000205 } else {
206 ct->nnums = locind;
207 ct->nvalues = valind;
208 ct = &data->tests[++testind];
209 if (testind > XT_U32_MAXSIZE)
Jan Engelhardt1829ed42009-02-21 03:29:44 +0100210 xtables_error(PARAMETER_PROBLEM,
Jan Engelhardt55951a02007-09-19 12:59:33 +0000211 "u32: at char %u: too many \"&&\"s", (unsigned int)(arg - start));
Jan Engelhardt9640e522007-09-10 11:50:46 +0000212 ++arg;
213 state = 0;
214 locind = 0;
215 valind = 0;
216 }
217 } else { /* read value range */
218 if (valind > 0) { /* need , before number */
219 if (*arg != ',')
Jan Engelhardt1829ed42009-02-21 03:29:44 +0100220 xtables_error(PARAMETER_PROBLEM,
Jan Engelhardt55951a02007-09-19 12:59:33 +0000221 "u32: at char %u: expected \",\" or \"&&\"", (unsigned int)(arg - start));
Jan Engelhardt9640e522007-09-10 11:50:46 +0000222 ++arg;
223 }
224 ct->value[valind].min =
225 parse_number(&arg, arg - start);
226
227 while (isspace(*arg))
228 ++arg;
229
230 if (*arg == ':') {
231 ++arg;
232 ct->value[valind].max =
233 parse_number(&arg, arg-start);
234 } else {
235 ct->value[valind].max =
236 ct->value[valind].min;
237 }
238
239 if (++valind > XT_U32_MAXSIZE)
Jan Engelhardt1829ed42009-02-21 03:29:44 +0100240 xtables_error(PARAMETER_PROBLEM,
Jan Engelhardt55951a02007-09-19 12:59:33 +0000241 "u32: at char %u: too many \",\"s", (unsigned int)(arg - start));
Jan Engelhardt9640e522007-09-10 11:50:46 +0000242 }
243 }
244 }
245}
246
Jan Engelhardt9640e522007-09-10 11:50:46 +0000247static void u32_print(const void *ip, const struct xt_entry_match *match,
248 int numeric)
249{
250 const struct xt_u32 *data = (const void *)match->data;
Jan Engelhardt73866352010-12-18 02:04:59 +0100251 printf(" u32");
Jan Engelhardt9640e522007-09-10 11:50:46 +0000252 if (data->invert)
Jan Engelhardt73866352010-12-18 02:04:59 +0100253 printf(" !");
Jan Engelhardt9640e522007-09-10 11:50:46 +0000254 u32_dump(data);
Jan Engelhardt9640e522007-09-10 11:50:46 +0000255}
256
257static void u32_save(const void *ip, const struct xt_entry_match *match)
258{
259 const struct xt_u32 *data = (const void *)match->data;
260 if (data->invert)
Jan Engelhardt73866352010-12-18 02:04:59 +0100261 printf(" !");
262 printf(" --u32");
Jan Engelhardt9640e522007-09-10 11:50:46 +0000263 u32_dump(data);
Jan Engelhardt9640e522007-09-10 11:50:46 +0000264}
265
Jan Engelhardt181dead2007-10-04 16:27:07 +0000266static struct xtables_match u32_match = {
Jan Engelhardt9640e522007-09-10 11:50:46 +0000267 .name = "u32",
Jan Engelhardt42979362009-06-01 11:56:23 +0200268 .family = NFPROTO_UNSPEC,
Jan Engelhardt8b7c64d2008-04-15 11:48:25 +0200269 .version = XTABLES_VERSION,
Jan Engelhardt9640e522007-09-10 11:50:46 +0000270 .size = XT_ALIGN(sizeof(struct xt_u32)),
271 .userspacesize = XT_ALIGN(sizeof(struct xt_u32)),
272 .help = u32_help,
Jan Engelhardt9640e522007-09-10 11:50:46 +0000273 .print = u32_print,
274 .save = u32_save,
Jan Engelhardt4f7f1872011-03-02 23:06:59 +0100275 .x6_parse = u32_parse,
276 .x6_options = u32_opts,
Jan Engelhardt9640e522007-09-10 11:50:46 +0000277};
278
279void _init(void)
280{
Jan Engelhardt181dead2007-10-04 16:27:07 +0000281 xtables_register_match(&u32_match);
Jan Engelhardt9640e522007-09-10 11:50:46 +0000282}