4 * Grzegorz Borowiak <grzes@gnu.univ.gda.pl>
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>
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
},
38 static void hexdump(const void *mem
, int howmany
)
41 const unsigned char *p
= mem
;
44 for (i
= 0; i
< howmany
; i
++) {
46 printf("\n%04x: ", i
);
48 printf("%2.2x%c", p
[i
], ". "[i
% 4 == 3]);
54 static void print_help()
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"
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"
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
)
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
);
92 memset(result
, 0, size
);
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
;
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
)
130 if (strchr(delimiters
, c
)) {
139 destbuf
[count
++] = c
;
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];
156 static void index_table(struct ebt_mac_wormhash
*wh
)
161 for (itable
= 0; itable
<= 256; itable
++) {
162 wh
->table
[itable
] = wh
->poolsize
;
167 wh
->table
[itable
] = ipool
;
168 c
= ((const unsigned char*)wh
->pool
[ipool
].cmp
)[7];
174 if (ipool
> wh
->poolsize
)
179 static struct ebt_mac_wormhash
*create_wormhash(const char *arg
)
181 const char *pc
= arg
;
184 struct ebt_mac_wormhash
*workcopy
, *result
, *h
;
185 unsigned char mac
[6];
191 if (!(workcopy
= new_wormhash(1024))) {
195 /* remember current position, we'll need it on error */
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
204 ebt_print_error("MAC parse error: %.20s", anchor
);
208 mac
[i
] = strtol(token
, &endptr
, 16);
210 ebt_print_error("MAC parse error: %.20s", anchor
);
216 if (read_until(&pc
, "=,", token
, 2) == -2 || token
[0] == 0) {
217 ebt_print_error("MAC parse error: %.20s", anchor
);
220 mac
[i
] = strtol(token
, &endptr
, 16);
222 ebt_print_error("MAC parse error: %.20s", anchor
);
226 /* an IP follows the MAC; collect similarly to MAC */
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
);
234 ip
[i
] = strtol(token
, &endptr
, 10);
236 ebt_print_error("IP parse error: %.20s", anchor
);
241 if (read_until(&pc
, ",", token
, 3) == -2 || token
[0] == 0) {
242 ebt_print_error("IP parse error: %.20s", anchor
);
245 ip
[3] = strtol(token
, &endptr
, 10);
247 ebt_print_error("IP parse error: %.20s", anchor
);
250 if (ip
[0] == 0 && ip
[1] == 0 && ip
[2] == 0 && ip
[3] == 0) {
251 ebt_print_error("Illegal IP 0.0.0.0");
255 /* no IP, we set it to 0.0.0.0 */
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);
264 /* re-allocate memory if needed */
265 if (*pc
&& nmacs
>= workcopy
->poolsize
) {
266 if (!(h
= new_wormhash(nmacs
* 2))) {
269 copy_wormhash(h
, workcopy
);
274 /* check if end of string was reached */
279 /* now `pc' points to comma if we are here; */
280 /* increment this to the next char */
281 /* but first assert :-> */
283 ebt_print_error("Something went wrong; no comma...\n");
288 /* again check if end of string was reached; */
289 /* we allow an ending comma */
294 if (!(result
= new_wormhash(nmacs
))) {
297 copy_wormhash(result
, workcopy
);
299 qsort(&result
->pool
, result
->poolsize
,
300 sizeof(struct ebt_mac_wormhash_tuple
), fcmp
);
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
;
324 if (c
== AMONG_DST
|| c
== AMONG_DST_F
) {
325 ebt_check_option2(flags
, OPT_DST
);
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
;
333 info
->bitmask
|= EBT_AMONG_SRC_NEG
;
335 if (c
== AMONG_DST_F
|| c
== AMONG_SRC_F
) {
338 if ((fd
= open(optarg
, O_RDONLY
)) == -1)
339 ebt_print_error("Couldn't open file '%s'", optarg
);
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') {
357 wh
= create_wormhash(optarg
);
358 if (ebt_errormsg
[0] != '\0')
361 new_size
= old_size
+ebt_mac_wormhash_size(wh
);
362 h
= malloc(sizeof(struct ebt_entry_match
)+EBT_ALIGN(new_size
));
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
;
373 info
->wh_src_ofs
= old_size
;
379 if (c
== AMONG_DST_F
|| c
== AMONG_SRC_F
) {
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
,
398 static void wormhash_debug(const struct ebt_mac_wormhash
*wh
)
402 printf("poolsize: %d\n", wh
->poolsize
);
403 for (i
= 0; i
<= 256; i
++) {
404 printf("%02x ", wh
->table
[i
]);
413 static void wormhash_printout(const struct ebt_mac_wormhash
*wh
)
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);
424 ip
= (unsigned char *) &p
->ip
;
425 printf("=%u.%u.%u.%u", ip
[0], ip
[1], ip
[2], ip
[3]);
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
) {
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
) {
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
)
458 as
= ebt_mac_wormhash_size(aw
);
459 bs
= ebt_mac_wormhash_size(bw
);
462 if (as
&& memcmp(aw
, bw
, as
))
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
)))
475 if (!compare_wh(ebt_among_wh_src(a
), ebt_among_wh_src(b
)))
477 if (a
->bitmask
!= b
->bitmask
)
482 static struct ebt_u_match among_match
= {
484 .size
= sizeof(struct ebt_among_info
),
488 .final_check
= final_check
,
496 ebt_register_match(&among_match
);