blob: 6f7c324fffda3235711fc1d01a5b0e285525d68f [file] [log] [blame]
Bart De Schuymerff587202005-02-08 20:02:28 +00001/* ebt_among
2 *
3 * Authors:
4 * Grzegorz Borowiak <grzes@gnu.univ.gda.pl>
5 *
6 * August, 2003
7 */
8
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +00009#include <stdio.h>
10#include <string.h>
11#include <stdlib.h>
12#include <getopt.h>
13#include <ctype.h>
14#include <netinet/ether.h>
15#include "../include/ebtables_u.h"
16#include "../include/ethernetdb.h"
17#include <linux/if_ether.h>
18#include <linux/netfilter_bridge/ebt_among.h>
Bart De Schuymer8069b5a2006-08-17 10:18:02 +000019#include <sys/mman.h>
20#include <sys/stat.h>
21#include <fcntl.h>
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +000022
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +000023#define AMONG_DST '1'
24#define AMONG_SRC '2'
Bart De Schuymer8069b5a2006-08-17 10:18:02 +000025#define AMONG_DST_F '3'
26#define AMONG_SRC_F '4'
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +000027
gborowiak6c6d7312003-09-16 19:26:38 +000028static struct option opts[] = {
29 {"among-dst", required_argument, 0, AMONG_DST},
30 {"among-src", required_argument, 0, AMONG_SRC},
Bart De Schuymer8069b5a2006-08-17 10:18:02 +000031 {"among-dst-file", required_argument, 0, AMONG_DST_F},
32 {"among-src-file", required_argument, 0, AMONG_SRC_F},
gborowiak6c6d7312003-09-16 19:26:38 +000033 {0}
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +000034};
35
36#ifdef DEBUG
37static void hexdump(const void *mem, int howmany)
38{
39 printf("\n");
40 const unsigned char *p = mem;
41 int i;
Bart De Schuymerf8c97432003-09-27 17:39:09 +000042
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +000043 for (i = 0; i < howmany; i++) {
44 if (i % 32 == 0) {
45 printf("\n%04x: ", i);
46 }
gborowiak6c6d7312003-09-16 19:26:38 +000047 printf("%2.2x%c", p[i], ". "[i % 4 == 3]);
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +000048 }
49 printf("\n");
50}
gborowiak6c6d7312003-09-16 19:26:38 +000051#endif /* DEBUG */
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +000052
53static void print_help()
54{
55 printf(
56"`among' options:\n"
Bart De Schuymer8069b5a2006-08-17 10:18:02 +000057"--among-dst [!] list : matches if ether dst is in list\n"
58"--among-src [!] list : matches if ether src is in list\n"
59"--among-dst-file [!] file : obtain dst list from file\n"
60"--among-src-file [!] file : obtain src list from file\n"
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +000061"list has form:\n"
gborowiak6c6d7312003-09-16 19:26:38 +000062" xx:xx:xx:xx:xx:xx[=ip.ip.ip.ip],yy:yy:yy:yy:yy:yy[=ip.ip.ip.ip]"
63",...,zz:zz:zz:zz:zz:zz[=ip.ip.ip.ip][,]\n"
gborowiakc50ce6a2003-09-07 13:16:26 +000064"Things in brackets are optional.\n"
Bart De Schuymerf8c97432003-09-27 17:39:09 +000065"If you want to allow two (or more) IP addresses to one MAC address, you\n"
Bart De Schuymer7cc696b2003-10-12 12:34:10 +000066"can specify two (or more) pairs with the same MAC, e.g.\n"
gborowiakc50ce6a2003-09-07 13:16:26 +000067" 00:00:00:fa:eb:fe=153.19.120.250,00:00:00:fa:eb:fe=192.168.0.1\n"
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +000068 );
69}
70
71static void init(struct ebt_entry_match *match)
72{
gborowiak6c6d7312003-09-16 19:26:38 +000073 struct ebt_among_info *amonginfo =
74 (struct ebt_among_info *) match->data;
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +000075
76 memset(amonginfo, 0, sizeof(struct ebt_among_info));
77}
78
gborowiakc50ce6a2003-09-07 13:16:26 +000079static struct ebt_mac_wormhash *new_wormhash(int n)
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +000080{
gborowiak6c6d7312003-09-16 19:26:38 +000081 int size =
82 sizeof(struct ebt_mac_wormhash) +
83 n * sizeof(struct ebt_mac_wormhash_tuple);
84 struct ebt_mac_wormhash *result =
85 (struct ebt_mac_wormhash *) malloc(size);
Bart De Schuymerf8c97432003-09-27 17:39:09 +000086
Bart De Schuymerff587202005-02-08 20:02:28 +000087 if (!result)
88 ebt_print_memory();
gborowiakc50ce6a2003-09-07 13:16:26 +000089 memset(result, 0, size);
90 result->poolsize = n;
91 return result;
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +000092}
93
gborowiak6c6d7312003-09-16 19:26:38 +000094static void copy_wormhash(struct ebt_mac_wormhash *d,
95 const struct ebt_mac_wormhash *s)
gborowiakc50ce6a2003-09-07 13:16:26 +000096{
97 int dpoolsize = d->poolsize;
98 int dsize, ssize, amount;
Bart De Schuymerf8c97432003-09-27 17:39:09 +000099
gborowiakc50ce6a2003-09-07 13:16:26 +0000100 dsize = ebt_mac_wormhash_size(d);
101 ssize = ebt_mac_wormhash_size(s);
102 amount = dsize < ssize ? dsize : ssize;
103 memcpy(d, s, amount);
104 d->poolsize = dpoolsize;
105}
106
107/* Returns:
108 * -1 when '\0' reached
109 * -2 when `n' bytes read and no delimiter found
110 * 0 when no less than `n' bytes read and delimiter found
111 * if `destbuf' is not NULL, it is filled by read bytes and ended with '\0'
112 * *pp is set on the first byte not copied to `destbuf'
113 */
gborowiak6c6d7312003-09-16 19:26:38 +0000114static int read_until(const char **pp, const char *delimiters,
115 char *destbuf, int n)
gborowiakc50ce6a2003-09-07 13:16:26 +0000116{
117 int count = 0;
118 int ret = 0;
119 char c;
Bart De Schuymerf8c97432003-09-27 17:39:09 +0000120
gborowiakc50ce6a2003-09-07 13:16:26 +0000121 while (1) {
122 c = **pp;
123 if (!c) {
124 ret = -1;
125 break;
126 }
127 if (strchr(delimiters, c)) {
128 ret = 0;
129 break;
130 }
131 if (count == n) {
132 ret = -2;
133 break;
134 }
gborowiak6c6d7312003-09-16 19:26:38 +0000135 if (destbuf)
136 destbuf[count++] = c;
gborowiakc50ce6a2003-09-07 13:16:26 +0000137 (*pp)++;
138 }
gborowiak6c6d7312003-09-16 19:26:38 +0000139 if (destbuf)
140 destbuf[count] = 0;
gborowiakc50ce6a2003-09-07 13:16:26 +0000141 return ret;
142}
143
gborowiak6c6d7312003-09-16 19:26:38 +0000144static int fcmp(const void *va, const void *vb) {
145 const struct ebt_mac_wormhash_tuple *a = va;
146 const struct ebt_mac_wormhash_tuple *b = vb;
147 int ca = ((const unsigned char*)a->cmp)[7];
148 int cb = ((const unsigned char*)b->cmp)[7];
Bart De Schuymerf8c97432003-09-27 17:39:09 +0000149
gborowiak6c6d7312003-09-16 19:26:38 +0000150 return ca - cb;
151}
152
153static void index_table(struct ebt_mac_wormhash *wh)
154{
155 int ipool, itable;
156 int c;
Bart De Schuymerf8c97432003-09-27 17:39:09 +0000157
gborowiak6c6d7312003-09-16 19:26:38 +0000158 for (itable = 0; itable <= 256; itable++) {
159 wh->table[itable] = wh->poolsize;
160 }
161 ipool = 0;
162 itable = 0;
163 while (1) {
164 wh->table[itable] = ipool;
165 c = ((const unsigned char*)wh->pool[ipool].cmp)[7];
166 if (itable <= c) {
167 itable++;
168 } else {
169 ipool++;
170 }
171 if (ipool > wh->poolsize)
172 break;
173 }
174}
175
gborowiakc50ce6a2003-09-07 13:16:26 +0000176static struct ebt_mac_wormhash *create_wormhash(const char *arg)
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +0000177{
178 const char *pc = arg;
179 const char *anchor;
gborowiakc50ce6a2003-09-07 13:16:26 +0000180 char *endptr;
181 struct ebt_mac_wormhash *workcopy, *result, *h;
182 unsigned char mac[6];
183 unsigned char ip[4];
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +0000184 int nmacs = 0;
gborowiakc50ce6a2003-09-07 13:16:26 +0000185 int i;
186 char token[4];
Bart De Schuymerf8c97432003-09-27 17:39:09 +0000187
gborowiakc50ce6a2003-09-07 13:16:26 +0000188 if (!(workcopy = new_wormhash(1024))) {
Bart De Schuymer64182a32004-01-21 20:39:54 +0000189 ebt_print_memory();
gborowiakc50ce6a2003-09-07 13:16:26 +0000190 }
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +0000191 while (1) {
gborowiakc50ce6a2003-09-07 13:16:26 +0000192 /* remember current position, we'll need it on error */
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +0000193 anchor = pc;
gborowiakc50ce6a2003-09-07 13:16:26 +0000194
gborowiak6c6d7312003-09-16 19:26:38 +0000195 /* collect MAC; all its bytes are followed by ':' (colon),
196 * except for the last one which can be followed by
197 * ',' (comma), '=' or '\0' */
gborowiakc50ce6a2003-09-07 13:16:26 +0000198 for (i = 0; i < 5; i++) {
gborowiak6c6d7312003-09-16 19:26:38 +0000199 if (read_until(&pc, ":", token, 2) < 0
200 || token[0] == 0) {
Bart De Schuymerff587202005-02-08 20:02:28 +0000201 ebt_print_error("MAC parse error: %.20s", anchor);
202 return NULL;
gborowiakc50ce6a2003-09-07 13:16:26 +0000203 }
204 mac[i] = strtol(token, &endptr, 16);
205 if (*endptr) {
Bart De Schuymerff587202005-02-08 20:02:28 +0000206 ebt_print_error("MAC parse error: %.20s", anchor);
207 return NULL;
gborowiakc50ce6a2003-09-07 13:16:26 +0000208 }
209 pc++;
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +0000210 }
gborowiakc50ce6a2003-09-07 13:16:26 +0000211 if (read_until(&pc, "=,", token, 2) == -2 || token[0] == 0) {
Bart De Schuymer64182a32004-01-21 20:39:54 +0000212 ebt_print_error("MAC parse error: %.20s", anchor);
Bart De Schuymerff587202005-02-08 20:02:28 +0000213 return NULL;
gborowiakc50ce6a2003-09-07 13:16:26 +0000214 }
215 mac[i] = strtol(token, &endptr, 16);
216 if (*endptr) {
Bart De Schuymer64182a32004-01-21 20:39:54 +0000217 ebt_print_error("MAC parse error: %.20s", anchor);
Bart De Schuymerff587202005-02-08 20:02:28 +0000218 return NULL;
gborowiakc50ce6a2003-09-07 13:16:26 +0000219 }
220 if (*pc == '=') {
221 /* an IP follows the MAC; collect similarly to MAC */
222 pc++;
223 anchor = pc;
224 for (i = 0; i < 3; i++) {
Bart De Schuymerff587202005-02-08 20:02:28 +0000225 if (read_until(&pc, ".", token, 3) < 0 || token[0] == 0) {
226 ebt_print_error("IP parse error: %.20s", anchor);
227 return NULL;
gborowiakc50ce6a2003-09-07 13:16:26 +0000228 }
229 ip[i] = strtol(token, &endptr, 10);
230 if (*endptr) {
Bart De Schuymerff587202005-02-08 20:02:28 +0000231 ebt_print_error("IP parse error: %.20s", anchor);
232 return NULL;
gborowiakc50ce6a2003-09-07 13:16:26 +0000233 }
234 pc++;
235 }
Bart De Schuymerff587202005-02-08 20:02:28 +0000236 if (read_until(&pc, ",", token, 3) == -2 || token[0] == 0) {
237 ebt_print_error("IP parse error: %.20s", anchor);
238 return NULL;
gborowiakc50ce6a2003-09-07 13:16:26 +0000239 }
240 ip[3] = strtol(token, &endptr, 10);
241 if (*endptr) {
Bart De Schuymerff587202005-02-08 20:02:28 +0000242 ebt_print_error("IP parse error: %.20s", anchor);
243 return NULL;
gborowiakc50ce6a2003-09-07 13:16:26 +0000244 }
gborowiak6c6d7312003-09-16 19:26:38 +0000245 if (*(uint32_t*)ip == 0) {
Bart De Schuymer64182a32004-01-21 20:39:54 +0000246 ebt_print_error("Illegal IP 0.0.0.0");
Bart De Schuymerff587202005-02-08 20:02:28 +0000247 return NULL;
gborowiak6c6d7312003-09-16 19:26:38 +0000248 }
249 } else {
gborowiakc50ce6a2003-09-07 13:16:26 +0000250 /* no IP, we set it to 0.0.0.0 */
251 memset(ip, 0, 4);
252 }
gborowiak6c6d7312003-09-16 19:26:38 +0000253
gborowiakc50ce6a2003-09-07 13:16:26 +0000254 /* we have collected MAC and IP, so we add an entry */
gborowiak6c6d7312003-09-16 19:26:38 +0000255 memcpy(((char *) workcopy->pool[nmacs].cmp) + 2, mac, 6);
256 workcopy->pool[nmacs].ip = *(const uint32_t *) ip;
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +0000257 nmacs++;
gborowiak6c6d7312003-09-16 19:26:38 +0000258
gborowiakc50ce6a2003-09-07 13:16:26 +0000259 /* re-allocate memory if needed */
260 if (*pc && nmacs >= workcopy->poolsize) {
261 if (!(h = new_wormhash(nmacs * 2))) {
Bart De Schuymer64182a32004-01-21 20:39:54 +0000262 ebt_print_memory();
gborowiakc50ce6a2003-09-07 13:16:26 +0000263 }
264 copy_wormhash(h, workcopy);
265 free(workcopy);
266 workcopy = h;
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +0000267 }
gborowiak6c6d7312003-09-16 19:26:38 +0000268
gborowiakc50ce6a2003-09-07 13:16:26 +0000269 /* check if end of string was reached */
270 if (!*pc) {
271 break;
272 }
gborowiak6c6d7312003-09-16 19:26:38 +0000273
274 /* now `pc' points to comma if we are here; */
275 /* increment this to the next char */
gborowiakc50ce6a2003-09-07 13:16:26 +0000276 /* but first assert :-> */
277 if (*pc != ',') {
Bart De Schuymer64182a32004-01-21 20:39:54 +0000278 ebt_print_error("Something went wrong; no comma...\n");
Bart De Schuymerff587202005-02-08 20:02:28 +0000279 return NULL;
gborowiakc50ce6a2003-09-07 13:16:26 +0000280 }
281 pc++;
gborowiak6c6d7312003-09-16 19:26:38 +0000282
283 /* again check if end of string was reached; */
284 /* we allow an ending comma */
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +0000285 if (!*pc) {
286 break;
287 }
288 }
gborowiakc50ce6a2003-09-07 13:16:26 +0000289 if (!(result = new_wormhash(nmacs))) {
Bart De Schuymer64182a32004-01-21 20:39:54 +0000290 ebt_print_memory();
gborowiakc50ce6a2003-09-07 13:16:26 +0000291 }
292 copy_wormhash(result, workcopy);
293 free(workcopy);
gborowiak6c6d7312003-09-16 19:26:38 +0000294 qsort(&result->pool, result->poolsize,
295 sizeof(struct ebt_mac_wormhash_tuple), fcmp);
296 index_table(result);
gborowiakc50ce6a2003-09-07 13:16:26 +0000297 return result;
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +0000298}
299
300#define OPT_DST 0x01
301#define OPT_SRC 0x02
gborowiak6c6d7312003-09-16 19:26:38 +0000302static int parse(int c, char **argv, int argc,
303 const struct ebt_u_entry *entry, unsigned int *flags,
304 struct ebt_entry_match **match)
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +0000305{
gborowiak6c6d7312003-09-16 19:26:38 +0000306 struct ebt_among_info *info =
307 (struct ebt_among_info *) (*match)->data;
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +0000308 struct ebt_mac_wormhash *wh;
gborowiakc50ce6a2003-09-07 13:16:26 +0000309 struct ebt_entry_match *h;
310 int new_size, old_size;
Bart De Schuymer8069b5a2006-08-17 10:18:02 +0000311 long flen;
312 int fd;
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +0000313
314 switch (c) {
Bart De Schuymer8069b5a2006-08-17 10:18:02 +0000315 case AMONG_DST_F:
316 case AMONG_SRC_F:
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +0000317 case AMONG_DST:
318 case AMONG_SRC:
Bart De Schuymer8069b5a2006-08-17 10:18:02 +0000319 if (c == AMONG_DST || c == AMONG_DST_F) {
Bart De Schuymerff587202005-02-08 20:02:28 +0000320 ebt_check_option2(flags, OPT_DST);
321 } else {
322 ebt_check_option2(flags, OPT_SRC);
323 }
324 if (ebt_check_inverse2(optarg)) {
Bart De Schuymer8069b5a2006-08-17 10:18:02 +0000325 if (c == AMONG_DST || c == AMONG_DST_F)
gborowiakc50ce6a2003-09-07 13:16:26 +0000326 info->bitmask |= EBT_AMONG_DST_NEG;
327 else
328 info->bitmask |= EBT_AMONG_SRC_NEG;
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +0000329 }
Bart De Schuymer8069b5a2006-08-17 10:18:02 +0000330 if (c == AMONG_DST_F || c == AMONG_SRC_F) {
331 struct stat stats;
332
333 if ((fd = open(optarg, O_RDONLY)) == -1)
334 ebt_print_error("Couldn't open file '%s'", optarg);
335 fstat(fd, &stats);
336 flen = stats.st_size;
337 /* use mmap because the file will probably be big */
338 optarg = mmap(0, flen, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0);
339 if (optarg == MAP_FAILED)
340 ebt_print_error("Couldn't map file to memory");
341 if (optarg[flen-1] != '\n')
342 ebt_print_error("File should end with a newline");
343 if (strchr(optarg, '\n') != optarg+flen-1)
344 ebt_print_error("File should only contain one line");
345 optarg[flen-1] = '\0';
346 if (ebt_errormsg[0] != '\0') {
347 munmap(argv, flen);
348 close(fd);
349 exit(-1);
350 }
351 }
Bart De Schuymerff587202005-02-08 20:02:28 +0000352 wh = create_wormhash(optarg);
353 if (ebt_errormsg[0] != '\0')
354 break;
355
356 old_size = sizeof(struct ebt_entry_match) + (**match).match_size;
357 h = malloc((new_size = old_size + ebt_mac_wormhash_size(wh)));
358 if (!h)
359 ebt_print_memory();
gborowiakc50ce6a2003-09-07 13:16:26 +0000360 memcpy(h, *match, old_size);
Bart De Schuymerff587202005-02-08 20:02:28 +0000361 memcpy((char *) h + old_size, wh, ebt_mac_wormhash_size(wh));
gborowiakc50ce6a2003-09-07 13:16:26 +0000362 h->match_size = new_size - sizeof(struct ebt_entry_match);
gborowiak6c6d7312003-09-16 19:26:38 +0000363 info = (struct ebt_among_info *) h->data;
gborowiakc50ce6a2003-09-07 13:16:26 +0000364 if (c == AMONG_DST) {
gborowiak6c6d7312003-09-16 19:26:38 +0000365 info->wh_dst_ofs =
366 old_size - sizeof(struct ebt_entry_match);
gborowiakc50ce6a2003-09-07 13:16:26 +0000367 } else {
gborowiak6c6d7312003-09-16 19:26:38 +0000368 info->wh_src_ofs =
369 old_size - sizeof(struct ebt_entry_match);
gborowiakc50ce6a2003-09-07 13:16:26 +0000370 }
371 free(*match);
372 *match = h;
373 free(wh);
Bart De Schuymer8069b5a2006-08-17 10:18:02 +0000374 if (c == AMONG_DST_F || c == AMONG_SRC_F) {
375 munmap(argv, flen);
376 close(fd);
377 }
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +0000378 break;
379 default:
380 return 0;
381 }
382 return 1;
383}
384
385static void final_check(const struct ebt_u_entry *entry,
gborowiak6c6d7312003-09-16 19:26:38 +0000386 const struct ebt_entry_match *match,
387 const char *name, unsigned int hookmask,
388 unsigned int time)
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +0000389{
390}
391
gborowiak6c6d7312003-09-16 19:26:38 +0000392#ifdef DEBUG
393static void wormhash_debug(const struct ebt_mac_wormhash *wh)
394{
395 int i;
Bart De Schuymerf8c97432003-09-27 17:39:09 +0000396
gborowiak6c6d7312003-09-16 19:26:38 +0000397 printf("poolsize: %d\n", wh->poolsize);
398 for (i = 0; i <= 256; i++) {
399 printf("%02x ", wh->table[i]);
400 if (i % 16 == 15) {
401 printf("\n");
402 }
403 }
404 printf("\n");
405}
406#endif /* DEBUG */
407
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +0000408static void wormhash_printout(const struct ebt_mac_wormhash *wh)
409{
410 int i;
gborowiakc50ce6a2003-09-07 13:16:26 +0000411 unsigned char *ip;
Bart De Schuymerf8c97432003-09-27 17:39:09 +0000412
gborowiak6c6d7312003-09-16 19:26:38 +0000413 for (i = 0; i < wh->poolsize; i++) {
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +0000414 const struct ebt_mac_wormhash_tuple *p;
Bart De Schuymerf8c97432003-09-27 17:39:09 +0000415
gborowiak6c6d7312003-09-16 19:26:38 +0000416 p = (const struct ebt_mac_wormhash_tuple *)(&wh->pool[i]);
Bart De Schuymer510c9ce2006-01-23 18:50:54 +0000417 ebt_print_mac(((const unsigned char *) &p->cmp[0]) + 2);
gborowiak6c6d7312003-09-16 19:26:38 +0000418 if (p->ip) {
419 ip = (unsigned char *) &p->ip;
420 printf("=%u.%u.%u.%u", ip[0], ip[1], ip[2], ip[3]);
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +0000421 }
gborowiak6c6d7312003-09-16 19:26:38 +0000422 printf(",");
423 }
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +0000424 printf(" ");
425}
426
427static void print(const struct ebt_u_entry *entry,
gborowiak6c6d7312003-09-16 19:26:38 +0000428 const struct ebt_entry_match *match)
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +0000429{
gborowiakc50ce6a2003-09-07 13:16:26 +0000430 struct ebt_among_info *info = (struct ebt_among_info *)match->data;
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +0000431
gborowiakc50ce6a2003-09-07 13:16:26 +0000432 if (info->wh_dst_ofs) {
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +0000433 printf("--among-dst ");
gborowiakc50ce6a2003-09-07 13:16:26 +0000434 if (info->bitmask && EBT_AMONG_DST_NEG) {
435 printf("! ");
436 }
437 wormhash_printout(ebt_among_wh_dst(info));
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +0000438 }
gborowiakc50ce6a2003-09-07 13:16:26 +0000439 if (info->wh_src_ofs) {
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +0000440 printf("--among-src ");
gborowiakc50ce6a2003-09-07 13:16:26 +0000441 if (info->bitmask && EBT_AMONG_SRC_NEG) {
442 printf("! ");
443 }
444 wormhash_printout(ebt_among_wh_src(info));
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +0000445 }
446}
447
gborowiak6c6d7312003-09-16 19:26:38 +0000448static int compare_wh(const struct ebt_mac_wormhash *aw,
449 const struct ebt_mac_wormhash *bw)
gborowiakc50ce6a2003-09-07 13:16:26 +0000450{
451 int as, bs;
Bart De Schuymerf8c97432003-09-27 17:39:09 +0000452
gborowiakc50ce6a2003-09-07 13:16:26 +0000453 as = ebt_mac_wormhash_size(aw);
454 bs = ebt_mac_wormhash_size(bw);
455 if (as != bs)
456 return 0;
457 if (as && memcmp(aw, bw, as))
458 return 0;
459 return 1;
460}
461
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +0000462static int compare(const struct ebt_entry_match *m1,
gborowiak6c6d7312003-09-16 19:26:38 +0000463 const struct ebt_entry_match *m2)
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +0000464{
gborowiak6c6d7312003-09-16 19:26:38 +0000465 struct ebt_among_info *a = (struct ebt_among_info *) m1->data;
466 struct ebt_among_info *b = (struct ebt_among_info *) m2->data;
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +0000467
gborowiak6c6d7312003-09-16 19:26:38 +0000468 if (!compare_wh(ebt_among_wh_dst(a), ebt_among_wh_dst(b)))
469 return 0;
470 if (!compare_wh(ebt_among_wh_src(a), ebt_among_wh_src(b)))
471 return 0;
472 if (a->bitmask != b->bitmask)
473 return 0;
gborowiakc50ce6a2003-09-07 13:16:26 +0000474 return 1;
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +0000475}
476
gborowiak6c6d7312003-09-16 19:26:38 +0000477static struct ebt_u_match among_match = {
478 .name = EBT_AMONG_MATCH,
479 .size = sizeof(struct ebt_among_info),
480 .help = print_help,
481 .init = init,
482 .parse = parse,
483 .final_check = final_check,
484 .print = print,
485 .compare = compare,
486 .extra_ops = opts,
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +0000487};
488
Bart De Schuymer64182a32004-01-21 20:39:54 +0000489void _init(void)
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +0000490{
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000491 ebt_register_match(&among_match);
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +0000492}