Correct PPTP server firewall rules chain.
[tomato/davidwu.git] / release / src / router / ebtables / extensions / ebt_among.c
blobf97d07ec118ed8e91156c75e757d4888b493f123
1 /* ebt_among
3 * Authors:
4 * Grzegorz Borowiak <grzes@gnu.univ.gda.pl>
6 * August, 2003
7 */
9 #include <stdio.h>
10 #include <string.h>
11 #include <stdlib.h>
12 #include <getopt.h>
13 #include <ctype.h>
14 #include <unistd.h>
15 #include "../include/ebtables_u.h"
16 #include <netinet/ether.h>
17 #include "../include/ethernetdb.h"
18 #include <linux/if_ether.h>
19 #include <linux/netfilter_bridge/ebt_among.h>
20 #include <sys/mman.h>
21 #include <sys/stat.h>
22 #include <fcntl.h>
24 #define AMONG_DST '1'
25 #define AMONG_SRC '2'
26 #define AMONG_DST_F '3'
27 #define AMONG_SRC_F '4'
29 static struct option opts[] = {
30 {"among-dst", required_argument, 0, AMONG_DST},
31 {"among-src", required_argument, 0, AMONG_SRC},
32 {"among-dst-file", required_argument, 0, AMONG_DST_F},
33 {"among-src-file", required_argument, 0, AMONG_SRC_F},
34 {0}
37 #ifdef DEBUG
38 static void hexdump(const void *mem, int howmany)
40 printf("\n");
41 const unsigned char *p = mem;
42 int i;
44 for (i = 0; i < howmany; i++) {
45 if (i % 32 == 0) {
46 printf("\n%04x: ", i);
48 printf("%2.2x%c", p[i], ". "[i % 4 == 3]);
50 printf("\n");
52 #endif /* DEBUG */
54 static void print_help()
56 printf(
57 "`among' options:\n"
58 "--among-dst [!] list : matches if ether dst is in list\n"
59 "--among-src [!] list : matches if ether src is in list\n"
60 "--among-dst-file [!] file : obtain dst list from file\n"
61 "--among-src-file [!] file : obtain src list from file\n"
62 "list has form:\n"
63 " xx:xx:xx:xx:xx:xx[=ip.ip.ip.ip],yy:yy:yy:yy:yy:yy[=ip.ip.ip.ip]"
64 ",...,zz:zz:zz:zz:zz:zz[=ip.ip.ip.ip][,]\n"
65 "Things in brackets are optional.\n"
66 "If you want to allow two (or more) IP addresses to one MAC address, you\n"
67 "can specify two (or more) pairs with the same MAC, e.g.\n"
68 " 00:00:00:fa:eb:fe=153.19.120.250,00:00:00:fa:eb:fe=192.168.0.1\n"
71 static int old_size;
73 static void init(struct ebt_entry_match *match)
75 struct ebt_among_info *amonginfo =
76 (struct ebt_among_info *) match->data;
78 memset(amonginfo, 0, sizeof(struct ebt_among_info));
79 old_size = sizeof(struct ebt_among_info);
82 static struct ebt_mac_wormhash *new_wormhash(int n)
84 int size =
85 sizeof(struct ebt_mac_wormhash) +
86 n * sizeof(struct ebt_mac_wormhash_tuple);
87 struct ebt_mac_wormhash *result =
88 (struct ebt_mac_wormhash *) malloc(size);
90 if (!result)
91 ebt_print_memory();
92 memset(result, 0, size);
93 result->poolsize = n;
94 return result;
97 static void copy_wormhash(struct ebt_mac_wormhash *d,
98 const struct ebt_mac_wormhash *s)
100 int dpoolsize = d->poolsize;
101 int dsize, ssize, amount;
103 dsize = ebt_mac_wormhash_size(d);
104 ssize = ebt_mac_wormhash_size(s);
105 amount = dsize < ssize ? dsize : ssize;
106 memcpy(d, s, amount);
107 d->poolsize = dpoolsize;
110 /* Returns:
111 * -1 when '\0' reached
112 * -2 when `n' bytes read and no delimiter found
113 * 0 when no less than `n' bytes read and delimiter found
114 * if `destbuf' is not NULL, it is filled by read bytes and ended with '\0'
115 * *pp is set on the first byte not copied to `destbuf'
117 static int read_until(const char **pp, const char *delimiters,
118 char *destbuf, int n)
120 int count = 0;
121 int ret = 0;
122 char c;
124 while (1) {
125 c = **pp;
126 if (!c) {
127 ret = -1;
128 break;
130 if (strchr(delimiters, c)) {
131 ret = 0;
132 break;
134 if (count == n) {
135 ret = -2;
136 break;
138 if (destbuf)
139 destbuf[count++] = c;
140 (*pp)++;
142 if (destbuf)
143 destbuf[count] = 0;
144 return ret;
147 static int fcmp(const void *va, const void *vb) {
148 const struct ebt_mac_wormhash_tuple *a = va;
149 const struct ebt_mac_wormhash_tuple *b = vb;
150 int ca = ((const unsigned char*)a->cmp)[7];
151 int cb = ((const unsigned char*)b->cmp)[7];
153 return ca - cb;
156 static void index_table(struct ebt_mac_wormhash *wh)
158 int ipool, itable;
159 int c;
161 for (itable = 0; itable <= 256; itable++) {
162 wh->table[itable] = wh->poolsize;
164 ipool = 0;
165 itable = 0;
166 while (1) {
167 wh->table[itable] = ipool;
168 c = ((const unsigned char*)wh->pool[ipool].cmp)[7];
169 if (itable <= c) {
170 itable++;
171 } else {
172 ipool++;
174 if (ipool > wh->poolsize)
175 break;
179 static struct ebt_mac_wormhash *create_wormhash(const char *arg)
181 const char *pc = arg;
182 const char *anchor;
183 char *endptr;
184 struct ebt_mac_wormhash *workcopy, *result, *h;
185 unsigned char mac[6];
186 unsigned char ip[4];
187 int nmacs = 0;
188 int i;
189 char token[4];
191 if (!(workcopy = new_wormhash(1024))) {
192 ebt_print_memory();
194 while (1) {
195 /* remember current position, we'll need it on error */
196 anchor = pc;
198 /* collect MAC; all its bytes are followed by ':' (colon),
199 * except for the last one which can be followed by
200 * ',' (comma), '=' or '\0' */
201 for (i = 0; i < 5; i++) {
202 if (read_until(&pc, ":", token, 2) < 0
203 || token[0] == 0) {
204 ebt_print_error("MAC parse error: %.20s", anchor);
205 free(workcopy);
206 return NULL;
208 mac[i] = strtol(token, &endptr, 16);
209 if (*endptr) {
210 ebt_print_error("MAC parse error: %.20s", anchor);
211 free(workcopy);
212 return NULL;
214 pc++;
216 if (read_until(&pc, "=,", token, 2) == -2 || token[0] == 0) {
217 ebt_print_error("MAC parse error: %.20s", anchor);
218 return NULL;
220 mac[i] = strtol(token, &endptr, 16);
221 if (*endptr) {
222 ebt_print_error("MAC parse error: %.20s", anchor);
223 return NULL;
225 if (*pc == '=') {
226 /* an IP follows the MAC; collect similarly to MAC */
227 pc++;
228 anchor = pc;
229 for (i = 0; i < 3; i++) {
230 if (read_until(&pc, ".", token, 3) < 0 || token[0] == 0) {
231 ebt_print_error("IP parse error: %.20s", anchor);
232 return NULL;
234 ip[i] = strtol(token, &endptr, 10);
235 if (*endptr) {
236 ebt_print_error("IP parse error: %.20s", anchor);
237 return NULL;
239 pc++;
241 if (read_until(&pc, ",", token, 3) == -2 || token[0] == 0) {
242 ebt_print_error("IP parse error: %.20s", anchor);
243 return NULL;
245 ip[3] = strtol(token, &endptr, 10);
246 if (*endptr) {
247 ebt_print_error("IP parse error: %.20s", anchor);
248 return NULL;
250 if (ip[0] == 0 && ip[1] == 0 && ip[2] == 0 && ip[3] == 0) {
251 ebt_print_error("Illegal IP 0.0.0.0");
252 return NULL;
254 } else {
255 /* no IP, we set it to 0.0.0.0 */
256 memset(ip, 0, 4);
259 /* we have collected MAC and IP, so we add an entry */
260 memcpy(((char *) workcopy->pool[nmacs].cmp) + 2, mac, 6);
261 memcpy(&(workcopy->pool[nmacs].ip), ip, 4);
262 nmacs++;
264 /* re-allocate memory if needed */
265 if (*pc && nmacs >= workcopy->poolsize) {
266 if (!(h = new_wormhash(nmacs * 2))) {
267 ebt_print_memory();
269 copy_wormhash(h, workcopy);
270 free(workcopy);
271 workcopy = h;
274 /* check if end of string was reached */
275 if (!*pc) {
276 break;
279 /* now `pc' points to comma if we are here; */
280 /* increment this to the next char */
281 /* but first assert :-> */
282 if (*pc != ',') {
283 ebt_print_error("Something went wrong; no comma...\n");
284 return NULL;
286 pc++;
288 /* again check if end of string was reached; */
289 /* we allow an ending comma */
290 if (!*pc) {
291 break;
294 if (!(result = new_wormhash(nmacs))) {
295 ebt_print_memory();
297 copy_wormhash(result, workcopy);
298 free(workcopy);
299 qsort(&result->pool, result->poolsize,
300 sizeof(struct ebt_mac_wormhash_tuple), fcmp);
301 index_table(result);
302 return result;
305 #define OPT_DST 0x01
306 #define OPT_SRC 0x02
307 static int parse(int c, char **argv, int argc,
308 const struct ebt_u_entry *entry, unsigned int *flags,
309 struct ebt_entry_match **match)
311 struct ebt_among_info *info =
312 (struct ebt_among_info *) (*match)->data;
313 struct ebt_mac_wormhash *wh;
314 struct ebt_entry_match *h;
315 int new_size;
316 long flen = 0;
317 int fd = -1;
319 switch (c) {
320 case AMONG_DST_F:
321 case AMONG_SRC_F:
322 case AMONG_DST:
323 case AMONG_SRC:
324 if (c == AMONG_DST || c == AMONG_DST_F) {
325 ebt_check_option2(flags, OPT_DST);
326 } else {
327 ebt_check_option2(flags, OPT_SRC);
329 if (ebt_check_inverse2(optarg)) {
330 if (c == AMONG_DST || c == AMONG_DST_F)
331 info->bitmask |= EBT_AMONG_DST_NEG;
332 else
333 info->bitmask |= EBT_AMONG_SRC_NEG;
335 if (c == AMONG_DST_F || c == AMONG_SRC_F) {
336 struct stat stats;
338 if ((fd = open(optarg, O_RDONLY)) == -1)
339 ebt_print_error("Couldn't open file '%s'", optarg);
340 fstat(fd, &stats);
341 flen = stats.st_size;
342 /* use mmap because the file will probably be big */
343 optarg = mmap(0, flen, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0);
344 if (optarg == MAP_FAILED)
345 ebt_print_error("Couldn't map file to memory");
346 if (optarg[flen-1] != '\n')
347 ebt_print_error("File should end with a newline");
348 if (strchr(optarg, '\n') != optarg+flen-1)
349 ebt_print_error("File should only contain one line");
350 optarg[flen-1] = '\0';
351 if (ebt_errormsg[0] != '\0') {
352 munmap(argv, flen);
353 close(fd);
354 exit(-1);
357 wh = create_wormhash(optarg);
358 if (ebt_errormsg[0] != '\0')
359 break;
361 new_size = old_size+ebt_mac_wormhash_size(wh);
362 h = malloc(sizeof(struct ebt_entry_match)+EBT_ALIGN(new_size));
363 if (!h)
364 ebt_print_memory();
365 memcpy(h, *match, old_size+sizeof(struct ebt_entry_match));
366 memcpy((char *)h+old_size+sizeof(struct ebt_entry_match), wh,
367 ebt_mac_wormhash_size(wh));
368 h->match_size = EBT_ALIGN(new_size);
369 info = (struct ebt_among_info *) h->data;
370 if (c == AMONG_DST || c == AMONG_DST_F) {
371 info->wh_dst_ofs = old_size;
372 } else {
373 info->wh_src_ofs = old_size;
375 old_size = new_size;
376 free(*match);
377 *match = h;
378 free(wh);
379 if (c == AMONG_DST_F || c == AMONG_SRC_F) {
380 munmap(argv, flen);
381 close(fd);
383 break;
384 default:
385 return 0;
387 return 1;
390 static void final_check(const struct ebt_u_entry *entry,
391 const struct ebt_entry_match *match,
392 const char *name, unsigned int hookmask,
393 unsigned int time)
397 #ifdef DEBUG
398 static void wormhash_debug(const struct ebt_mac_wormhash *wh)
400 int i;
402 printf("poolsize: %d\n", wh->poolsize);
403 for (i = 0; i <= 256; i++) {
404 printf("%02x ", wh->table[i]);
405 if (i % 16 == 15) {
406 printf("\n");
409 printf("\n");
411 #endif /* DEBUG */
413 static void wormhash_printout(const struct ebt_mac_wormhash *wh)
415 int i;
416 unsigned char *ip;
418 for (i = 0; i < wh->poolsize; i++) {
419 const struct ebt_mac_wormhash_tuple *p;
421 p = (const struct ebt_mac_wormhash_tuple *)(&wh->pool[i]);
422 ebt_print_mac(((const unsigned char *) &p->cmp[0]) + 2);
423 if (p->ip) {
424 ip = (unsigned char *) &p->ip;
425 printf("=%u.%u.%u.%u", ip[0], ip[1], ip[2], ip[3]);
427 printf(",");
429 printf(" ");
432 static void print(const struct ebt_u_entry *entry,
433 const struct ebt_entry_match *match)
435 struct ebt_among_info *info = (struct ebt_among_info *)match->data;
437 if (info->wh_dst_ofs) {
438 printf("--among-dst ");
439 if (info->bitmask && EBT_AMONG_DST_NEG) {
440 printf("! ");
442 wormhash_printout(ebt_among_wh_dst(info));
444 if (info->wh_src_ofs) {
445 printf("--among-src ");
446 if (info->bitmask && EBT_AMONG_SRC_NEG) {
447 printf("! ");
449 wormhash_printout(ebt_among_wh_src(info));
453 static int compare_wh(const struct ebt_mac_wormhash *aw,
454 const struct ebt_mac_wormhash *bw)
456 int as, bs;
458 as = ebt_mac_wormhash_size(aw);
459 bs = ebt_mac_wormhash_size(bw);
460 if (as != bs)
461 return 0;
462 if (as && memcmp(aw, bw, as))
463 return 0;
464 return 1;
467 static int compare(const struct ebt_entry_match *m1,
468 const struct ebt_entry_match *m2)
470 struct ebt_among_info *a = (struct ebt_among_info *) m1->data;
471 struct ebt_among_info *b = (struct ebt_among_info *) m2->data;
473 if (!compare_wh(ebt_among_wh_dst(a), ebt_among_wh_dst(b)))
474 return 0;
475 if (!compare_wh(ebt_among_wh_src(a), ebt_among_wh_src(b)))
476 return 0;
477 if (a->bitmask != b->bitmask)
478 return 0;
479 return 1;
482 static struct ebt_u_match among_match = {
483 .name = "among",
484 .size = sizeof(struct ebt_among_info),
485 .help = print_help,
486 .init = init,
487 .parse = parse,
488 .final_check = final_check,
489 .print = print,
490 .compare = compare,
491 .extra_ops = opts,
494 void _init(void)
496 ebt_register_match(&among_match);