blob: edd678e798d034586c20d70a9295b55a76f0ba07 [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>
Bart De Schuymere1c315a2006-12-22 18:08:41 +000014#include <unistd.h>
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +000015#include <netinet/ether.h>
16#include "../include/ebtables_u.h"
17#include "../include/ethernetdb.h"
18#include <linux/if_ether.h>
19#include <linux/netfilter_bridge/ebt_among.h>
Bart De Schuymer8069b5a2006-08-17 10:18:02 +000020#include <sys/mman.h>
21#include <sys/stat.h>
22#include <fcntl.h>
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +000023
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +000024#define AMONG_DST '1'
25#define AMONG_SRC '2'
Bart De Schuymer8069b5a2006-08-17 10:18:02 +000026#define AMONG_DST_F '3'
27#define AMONG_SRC_F '4'
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +000028
gborowiak6c6d7312003-09-16 19:26:38 +000029static struct option opts[] = {
30 {"among-dst", required_argument, 0, AMONG_DST},
31 {"among-src", required_argument, 0, AMONG_SRC},
Bart De Schuymer8069b5a2006-08-17 10:18:02 +000032 {"among-dst-file", required_argument, 0, AMONG_DST_F},
33 {"among-src-file", required_argument, 0, AMONG_SRC_F},
gborowiak6c6d7312003-09-16 19:26:38 +000034 {0}
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +000035};
36
37#ifdef DEBUG
38static void hexdump(const void *mem, int howmany)
39{
40 printf("\n");
41 const unsigned char *p = mem;
42 int i;
Bart De Schuymerf8c97432003-09-27 17:39:09 +000043
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +000044 for (i = 0; i < howmany; i++) {
45 if (i % 32 == 0) {
46 printf("\n%04x: ", i);
47 }
gborowiak6c6d7312003-09-16 19:26:38 +000048 printf("%2.2x%c", p[i], ". "[i % 4 == 3]);
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +000049 }
50 printf("\n");
51}
gborowiak6c6d7312003-09-16 19:26:38 +000052#endif /* DEBUG */
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +000053
54static void print_help()
55{
56 printf(
57"`among' options:\n"
Bart De Schuymer8069b5a2006-08-17 10:18:02 +000058"--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"
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +000062"list has form:\n"
gborowiak6c6d7312003-09-16 19:26:38 +000063" 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"
gborowiakc50ce6a2003-09-07 13:16:26 +000065"Things in brackets are optional.\n"
Bart De Schuymerf8c97432003-09-27 17:39:09 +000066"If you want to allow two (or more) IP addresses to one MAC address, you\n"
Bart De Schuymer7cc696b2003-10-12 12:34:10 +000067"can specify two (or more) pairs with the same MAC, e.g.\n"
gborowiakc50ce6a2003-09-07 13:16:26 +000068" 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 +000069 );
70}
71
72static void init(struct ebt_entry_match *match)
73{
gborowiak6c6d7312003-09-16 19:26:38 +000074 struct ebt_among_info *amonginfo =
75 (struct ebt_among_info *) match->data;
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +000076
77 memset(amonginfo, 0, sizeof(struct ebt_among_info));
78}
79
gborowiakc50ce6a2003-09-07 13:16:26 +000080static struct ebt_mac_wormhash *new_wormhash(int n)
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +000081{
gborowiak6c6d7312003-09-16 19:26:38 +000082 int size =
83 sizeof(struct ebt_mac_wormhash) +
84 n * sizeof(struct ebt_mac_wormhash_tuple);
85 struct ebt_mac_wormhash *result =
86 (struct ebt_mac_wormhash *) malloc(size);
Bart De Schuymerf8c97432003-09-27 17:39:09 +000087
Bart De Schuymerff587202005-02-08 20:02:28 +000088 if (!result)
89 ebt_print_memory();
gborowiakc50ce6a2003-09-07 13:16:26 +000090 memset(result, 0, size);
91 result->poolsize = n;
92 return result;
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +000093}
94
gborowiak6c6d7312003-09-16 19:26:38 +000095static void copy_wormhash(struct ebt_mac_wormhash *d,
96 const struct ebt_mac_wormhash *s)
gborowiakc50ce6a2003-09-07 13:16:26 +000097{
98 int dpoolsize = d->poolsize;
99 int dsize, ssize, amount;
Bart De Schuymerf8c97432003-09-27 17:39:09 +0000100
gborowiakc50ce6a2003-09-07 13:16:26 +0000101 dsize = ebt_mac_wormhash_size(d);
102 ssize = ebt_mac_wormhash_size(s);
103 amount = dsize < ssize ? dsize : ssize;
104 memcpy(d, s, amount);
105 d->poolsize = dpoolsize;
106}
107
108/* Returns:
109 * -1 when '\0' reached
110 * -2 when `n' bytes read and no delimiter found
111 * 0 when no less than `n' bytes read and delimiter found
112 * if `destbuf' is not NULL, it is filled by read bytes and ended with '\0'
113 * *pp is set on the first byte not copied to `destbuf'
114 */
gborowiak6c6d7312003-09-16 19:26:38 +0000115static int read_until(const char **pp, const char *delimiters,
116 char *destbuf, int n)
gborowiakc50ce6a2003-09-07 13:16:26 +0000117{
118 int count = 0;
119 int ret = 0;
120 char c;
Bart De Schuymerf8c97432003-09-27 17:39:09 +0000121
gborowiakc50ce6a2003-09-07 13:16:26 +0000122 while (1) {
123 c = **pp;
124 if (!c) {
125 ret = -1;
126 break;
127 }
128 if (strchr(delimiters, c)) {
129 ret = 0;
130 break;
131 }
132 if (count == n) {
133 ret = -2;
134 break;
135 }
gborowiak6c6d7312003-09-16 19:26:38 +0000136 if (destbuf)
137 destbuf[count++] = c;
gborowiakc50ce6a2003-09-07 13:16:26 +0000138 (*pp)++;
139 }
gborowiak6c6d7312003-09-16 19:26:38 +0000140 if (destbuf)
141 destbuf[count] = 0;
gborowiakc50ce6a2003-09-07 13:16:26 +0000142 return ret;
143}
144
gborowiak6c6d7312003-09-16 19:26:38 +0000145static int fcmp(const void *va, const void *vb) {
146 const struct ebt_mac_wormhash_tuple *a = va;
147 const struct ebt_mac_wormhash_tuple *b = vb;
148 int ca = ((const unsigned char*)a->cmp)[7];
149 int cb = ((const unsigned char*)b->cmp)[7];
Bart De Schuymerf8c97432003-09-27 17:39:09 +0000150
gborowiak6c6d7312003-09-16 19:26:38 +0000151 return ca - cb;
152}
153
154static void index_table(struct ebt_mac_wormhash *wh)
155{
156 int ipool, itable;
157 int c;
Bart De Schuymerf8c97432003-09-27 17:39:09 +0000158
gborowiak6c6d7312003-09-16 19:26:38 +0000159 for (itable = 0; itable <= 256; itable++) {
160 wh->table[itable] = wh->poolsize;
161 }
162 ipool = 0;
163 itable = 0;
164 while (1) {
165 wh->table[itable] = ipool;
166 c = ((const unsigned char*)wh->pool[ipool].cmp)[7];
167 if (itable <= c) {
168 itable++;
169 } else {
170 ipool++;
171 }
172 if (ipool > wh->poolsize)
173 break;
174 }
175}
176
gborowiakc50ce6a2003-09-07 13:16:26 +0000177static struct ebt_mac_wormhash *create_wormhash(const char *arg)
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +0000178{
179 const char *pc = arg;
180 const char *anchor;
gborowiakc50ce6a2003-09-07 13:16:26 +0000181 char *endptr;
182 struct ebt_mac_wormhash *workcopy, *result, *h;
183 unsigned char mac[6];
184 unsigned char ip[4];
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +0000185 int nmacs = 0;
gborowiakc50ce6a2003-09-07 13:16:26 +0000186 int i;
187 char token[4];
Bart De Schuymerf8c97432003-09-27 17:39:09 +0000188
gborowiakc50ce6a2003-09-07 13:16:26 +0000189 if (!(workcopy = new_wormhash(1024))) {
Bart De Schuymer64182a32004-01-21 20:39:54 +0000190 ebt_print_memory();
gborowiakc50ce6a2003-09-07 13:16:26 +0000191 }
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +0000192 while (1) {
gborowiakc50ce6a2003-09-07 13:16:26 +0000193 /* remember current position, we'll need it on error */
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +0000194 anchor = pc;
gborowiakc50ce6a2003-09-07 13:16:26 +0000195
gborowiak6c6d7312003-09-16 19:26:38 +0000196 /* collect MAC; all its bytes are followed by ':' (colon),
197 * except for the last one which can be followed by
198 * ',' (comma), '=' or '\0' */
gborowiakc50ce6a2003-09-07 13:16:26 +0000199 for (i = 0; i < 5; i++) {
gborowiak6c6d7312003-09-16 19:26:38 +0000200 if (read_until(&pc, ":", token, 2) < 0
201 || token[0] == 0) {
Bart De Schuymerff587202005-02-08 20:02:28 +0000202 ebt_print_error("MAC parse error: %.20s", anchor);
203 return NULL;
gborowiakc50ce6a2003-09-07 13:16:26 +0000204 }
205 mac[i] = strtol(token, &endptr, 16);
206 if (*endptr) {
Bart De Schuymerff587202005-02-08 20:02:28 +0000207 ebt_print_error("MAC parse error: %.20s", anchor);
208 return NULL;
gborowiakc50ce6a2003-09-07 13:16:26 +0000209 }
210 pc++;
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +0000211 }
gborowiakc50ce6a2003-09-07 13:16:26 +0000212 if (read_until(&pc, "=,", token, 2) == -2 || token[0] == 0) {
Bart De Schuymer64182a32004-01-21 20:39:54 +0000213 ebt_print_error("MAC parse error: %.20s", anchor);
Bart De Schuymerff587202005-02-08 20:02:28 +0000214 return NULL;
gborowiakc50ce6a2003-09-07 13:16:26 +0000215 }
216 mac[i] = strtol(token, &endptr, 16);
217 if (*endptr) {
Bart De Schuymer64182a32004-01-21 20:39:54 +0000218 ebt_print_error("MAC parse error: %.20s", anchor);
Bart De Schuymerff587202005-02-08 20:02:28 +0000219 return NULL;
gborowiakc50ce6a2003-09-07 13:16:26 +0000220 }
221 if (*pc == '=') {
222 /* an IP follows the MAC; collect similarly to MAC */
223 pc++;
224 anchor = pc;
225 for (i = 0; i < 3; i++) {
Bart De Schuymerff587202005-02-08 20:02:28 +0000226 if (read_until(&pc, ".", token, 3) < 0 || token[0] == 0) {
227 ebt_print_error("IP parse error: %.20s", anchor);
228 return NULL;
gborowiakc50ce6a2003-09-07 13:16:26 +0000229 }
230 ip[i] = strtol(token, &endptr, 10);
231 if (*endptr) {
Bart De Schuymerff587202005-02-08 20:02:28 +0000232 ebt_print_error("IP parse error: %.20s", anchor);
233 return NULL;
gborowiakc50ce6a2003-09-07 13:16:26 +0000234 }
235 pc++;
236 }
Bart De Schuymerff587202005-02-08 20:02:28 +0000237 if (read_until(&pc, ",", token, 3) == -2 || token[0] == 0) {
238 ebt_print_error("IP parse error: %.20s", anchor);
239 return NULL;
gborowiakc50ce6a2003-09-07 13:16:26 +0000240 }
241 ip[3] = strtol(token, &endptr, 10);
242 if (*endptr) {
Bart De Schuymerff587202005-02-08 20:02:28 +0000243 ebt_print_error("IP parse error: %.20s", anchor);
244 return NULL;
gborowiakc50ce6a2003-09-07 13:16:26 +0000245 }
gborowiak6c6d7312003-09-16 19:26:38 +0000246 if (*(uint32_t*)ip == 0) {
Bart De Schuymer64182a32004-01-21 20:39:54 +0000247 ebt_print_error("Illegal IP 0.0.0.0");
Bart De Schuymerff587202005-02-08 20:02:28 +0000248 return NULL;
gborowiak6c6d7312003-09-16 19:26:38 +0000249 }
250 } else {
gborowiakc50ce6a2003-09-07 13:16:26 +0000251 /* no IP, we set it to 0.0.0.0 */
252 memset(ip, 0, 4);
253 }
gborowiak6c6d7312003-09-16 19:26:38 +0000254
gborowiakc50ce6a2003-09-07 13:16:26 +0000255 /* we have collected MAC and IP, so we add an entry */
gborowiak6c6d7312003-09-16 19:26:38 +0000256 memcpy(((char *) workcopy->pool[nmacs].cmp) + 2, mac, 6);
257 workcopy->pool[nmacs].ip = *(const uint32_t *) ip;
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +0000258 nmacs++;
gborowiak6c6d7312003-09-16 19:26:38 +0000259
gborowiakc50ce6a2003-09-07 13:16:26 +0000260 /* re-allocate memory if needed */
261 if (*pc && nmacs >= workcopy->poolsize) {
262 if (!(h = new_wormhash(nmacs * 2))) {
Bart De Schuymer64182a32004-01-21 20:39:54 +0000263 ebt_print_memory();
gborowiakc50ce6a2003-09-07 13:16:26 +0000264 }
265 copy_wormhash(h, workcopy);
266 free(workcopy);
267 workcopy = h;
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +0000268 }
gborowiak6c6d7312003-09-16 19:26:38 +0000269
gborowiakc50ce6a2003-09-07 13:16:26 +0000270 /* check if end of string was reached */
271 if (!*pc) {
272 break;
273 }
gborowiak6c6d7312003-09-16 19:26:38 +0000274
275 /* now `pc' points to comma if we are here; */
276 /* increment this to the next char */
gborowiakc50ce6a2003-09-07 13:16:26 +0000277 /* but first assert :-> */
278 if (*pc != ',') {
Bart De Schuymer64182a32004-01-21 20:39:54 +0000279 ebt_print_error("Something went wrong; no comma...\n");
Bart De Schuymerff587202005-02-08 20:02:28 +0000280 return NULL;
gborowiakc50ce6a2003-09-07 13:16:26 +0000281 }
282 pc++;
gborowiak6c6d7312003-09-16 19:26:38 +0000283
284 /* again check if end of string was reached; */
285 /* we allow an ending comma */
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +0000286 if (!*pc) {
287 break;
288 }
289 }
gborowiakc50ce6a2003-09-07 13:16:26 +0000290 if (!(result = new_wormhash(nmacs))) {
Bart De Schuymer64182a32004-01-21 20:39:54 +0000291 ebt_print_memory();
gborowiakc50ce6a2003-09-07 13:16:26 +0000292 }
293 copy_wormhash(result, workcopy);
294 free(workcopy);
gborowiak6c6d7312003-09-16 19:26:38 +0000295 qsort(&result->pool, result->poolsize,
296 sizeof(struct ebt_mac_wormhash_tuple), fcmp);
297 index_table(result);
gborowiakc50ce6a2003-09-07 13:16:26 +0000298 return result;
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +0000299}
300
301#define OPT_DST 0x01
302#define OPT_SRC 0x02
gborowiak6c6d7312003-09-16 19:26:38 +0000303static int parse(int c, char **argv, int argc,
304 const struct ebt_u_entry *entry, unsigned int *flags,
305 struct ebt_entry_match **match)
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +0000306{
gborowiak6c6d7312003-09-16 19:26:38 +0000307 struct ebt_among_info *info =
308 (struct ebt_among_info *) (*match)->data;
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +0000309 struct ebt_mac_wormhash *wh;
gborowiakc50ce6a2003-09-07 13:16:26 +0000310 struct ebt_entry_match *h;
311 int new_size, old_size;
Bart De Schuymer8069b5a2006-08-17 10:18:02 +0000312 long flen;
313 int fd;
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +0000314
315 switch (c) {
Bart De Schuymer8069b5a2006-08-17 10:18:02 +0000316 case AMONG_DST_F:
317 case AMONG_SRC_F:
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +0000318 case AMONG_DST:
319 case AMONG_SRC:
Bart De Schuymer8069b5a2006-08-17 10:18:02 +0000320 if (c == AMONG_DST || c == AMONG_DST_F) {
Bart De Schuymerff587202005-02-08 20:02:28 +0000321 ebt_check_option2(flags, OPT_DST);
322 } else {
323 ebt_check_option2(flags, OPT_SRC);
324 }
325 if (ebt_check_inverse2(optarg)) {
Bart De Schuymer8069b5a2006-08-17 10:18:02 +0000326 if (c == AMONG_DST || c == AMONG_DST_F)
gborowiakc50ce6a2003-09-07 13:16:26 +0000327 info->bitmask |= EBT_AMONG_DST_NEG;
328 else
329 info->bitmask |= EBT_AMONG_SRC_NEG;
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +0000330 }
Bart De Schuymer8069b5a2006-08-17 10:18:02 +0000331 if (c == AMONG_DST_F || c == AMONG_SRC_F) {
332 struct stat stats;
333
334 if ((fd = open(optarg, O_RDONLY)) == -1)
335 ebt_print_error("Couldn't open file '%s'", optarg);
336 fstat(fd, &stats);
337 flen = stats.st_size;
338 /* use mmap because the file will probably be big */
339 optarg = mmap(0, flen, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0);
340 if (optarg == MAP_FAILED)
341 ebt_print_error("Couldn't map file to memory");
342 if (optarg[flen-1] != '\n')
343 ebt_print_error("File should end with a newline");
344 if (strchr(optarg, '\n') != optarg+flen-1)
345 ebt_print_error("File should only contain one line");
346 optarg[flen-1] = '\0';
347 if (ebt_errormsg[0] != '\0') {
348 munmap(argv, flen);
349 close(fd);
350 exit(-1);
351 }
352 }
Bart De Schuymerff587202005-02-08 20:02:28 +0000353 wh = create_wormhash(optarg);
354 if (ebt_errormsg[0] != '\0')
355 break;
356
357 old_size = sizeof(struct ebt_entry_match) + (**match).match_size;
358 h = malloc((new_size = old_size + ebt_mac_wormhash_size(wh)));
359 if (!h)
360 ebt_print_memory();
gborowiakc50ce6a2003-09-07 13:16:26 +0000361 memcpy(h, *match, old_size);
Bart De Schuymerff587202005-02-08 20:02:28 +0000362 memcpy((char *) h + old_size, wh, ebt_mac_wormhash_size(wh));
gborowiakc50ce6a2003-09-07 13:16:26 +0000363 h->match_size = new_size - sizeof(struct ebt_entry_match);
gborowiak6c6d7312003-09-16 19:26:38 +0000364 info = (struct ebt_among_info *) h->data;
gborowiakc50ce6a2003-09-07 13:16:26 +0000365 if (c == AMONG_DST) {
gborowiak6c6d7312003-09-16 19:26:38 +0000366 info->wh_dst_ofs =
367 old_size - sizeof(struct ebt_entry_match);
gborowiakc50ce6a2003-09-07 13:16:26 +0000368 } else {
gborowiak6c6d7312003-09-16 19:26:38 +0000369 info->wh_src_ofs =
370 old_size - sizeof(struct ebt_entry_match);
gborowiakc50ce6a2003-09-07 13:16:26 +0000371 }
372 free(*match);
373 *match = h;
374 free(wh);
Bart De Schuymer8069b5a2006-08-17 10:18:02 +0000375 if (c == AMONG_DST_F || c == AMONG_SRC_F) {
376 munmap(argv, flen);
377 close(fd);
378 }
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +0000379 break;
380 default:
381 return 0;
382 }
383 return 1;
384}
385
386static void final_check(const struct ebt_u_entry *entry,
gborowiak6c6d7312003-09-16 19:26:38 +0000387 const struct ebt_entry_match *match,
388 const char *name, unsigned int hookmask,
389 unsigned int time)
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +0000390{
391}
392
gborowiak6c6d7312003-09-16 19:26:38 +0000393#ifdef DEBUG
394static void wormhash_debug(const struct ebt_mac_wormhash *wh)
395{
396 int i;
Bart De Schuymerf8c97432003-09-27 17:39:09 +0000397
gborowiak6c6d7312003-09-16 19:26:38 +0000398 printf("poolsize: %d\n", wh->poolsize);
399 for (i = 0; i <= 256; i++) {
400 printf("%02x ", wh->table[i]);
401 if (i % 16 == 15) {
402 printf("\n");
403 }
404 }
405 printf("\n");
406}
407#endif /* DEBUG */
408
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +0000409static void wormhash_printout(const struct ebt_mac_wormhash *wh)
410{
411 int i;
gborowiakc50ce6a2003-09-07 13:16:26 +0000412 unsigned char *ip;
Bart De Schuymerf8c97432003-09-27 17:39:09 +0000413
gborowiak6c6d7312003-09-16 19:26:38 +0000414 for (i = 0; i < wh->poolsize; i++) {
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +0000415 const struct ebt_mac_wormhash_tuple *p;
Bart De Schuymerf8c97432003-09-27 17:39:09 +0000416
gborowiak6c6d7312003-09-16 19:26:38 +0000417 p = (const struct ebt_mac_wormhash_tuple *)(&wh->pool[i]);
Bart De Schuymer510c9ce2006-01-23 18:50:54 +0000418 ebt_print_mac(((const unsigned char *) &p->cmp[0]) + 2);
gborowiak6c6d7312003-09-16 19:26:38 +0000419 if (p->ip) {
420 ip = (unsigned char *) &p->ip;
421 printf("=%u.%u.%u.%u", ip[0], ip[1], ip[2], ip[3]);
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +0000422 }
gborowiak6c6d7312003-09-16 19:26:38 +0000423 printf(",");
424 }
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +0000425 printf(" ");
426}
427
428static void print(const struct ebt_u_entry *entry,
gborowiak6c6d7312003-09-16 19:26:38 +0000429 const struct ebt_entry_match *match)
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +0000430{
gborowiakc50ce6a2003-09-07 13:16:26 +0000431 struct ebt_among_info *info = (struct ebt_among_info *)match->data;
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +0000432
gborowiakc50ce6a2003-09-07 13:16:26 +0000433 if (info->wh_dst_ofs) {
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +0000434 printf("--among-dst ");
gborowiakc50ce6a2003-09-07 13:16:26 +0000435 if (info->bitmask && EBT_AMONG_DST_NEG) {
436 printf("! ");
437 }
438 wormhash_printout(ebt_among_wh_dst(info));
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +0000439 }
gborowiakc50ce6a2003-09-07 13:16:26 +0000440 if (info->wh_src_ofs) {
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +0000441 printf("--among-src ");
gborowiakc50ce6a2003-09-07 13:16:26 +0000442 if (info->bitmask && EBT_AMONG_SRC_NEG) {
443 printf("! ");
444 }
445 wormhash_printout(ebt_among_wh_src(info));
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +0000446 }
447}
448
gborowiak6c6d7312003-09-16 19:26:38 +0000449static int compare_wh(const struct ebt_mac_wormhash *aw,
450 const struct ebt_mac_wormhash *bw)
gborowiakc50ce6a2003-09-07 13:16:26 +0000451{
452 int as, bs;
Bart De Schuymerf8c97432003-09-27 17:39:09 +0000453
gborowiakc50ce6a2003-09-07 13:16:26 +0000454 as = ebt_mac_wormhash_size(aw);
455 bs = ebt_mac_wormhash_size(bw);
456 if (as != bs)
457 return 0;
458 if (as && memcmp(aw, bw, as))
459 return 0;
460 return 1;
461}
462
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +0000463static int compare(const struct ebt_entry_match *m1,
gborowiak6c6d7312003-09-16 19:26:38 +0000464 const struct ebt_entry_match *m2)
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +0000465{
gborowiak6c6d7312003-09-16 19:26:38 +0000466 struct ebt_among_info *a = (struct ebt_among_info *) m1->data;
467 struct ebt_among_info *b = (struct ebt_among_info *) m2->data;
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +0000468
gborowiak6c6d7312003-09-16 19:26:38 +0000469 if (!compare_wh(ebt_among_wh_dst(a), ebt_among_wh_dst(b)))
470 return 0;
471 if (!compare_wh(ebt_among_wh_src(a), ebt_among_wh_src(b)))
472 return 0;
473 if (a->bitmask != b->bitmask)
474 return 0;
gborowiakc50ce6a2003-09-07 13:16:26 +0000475 return 1;
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +0000476}
477
gborowiak6c6d7312003-09-16 19:26:38 +0000478static struct ebt_u_match among_match = {
479 .name = EBT_AMONG_MATCH,
480 .size = sizeof(struct ebt_among_info),
481 .help = print_help,
482 .init = init,
483 .parse = parse,
484 .final_check = final_check,
485 .print = print,
486 .compare = compare,
487 .extra_ops = opts,
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +0000488};
489
Bart De Schuymer64182a32004-01-21 20:39:54 +0000490void _init(void)
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +0000491{
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000492 ebt_register_match(&among_match);
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +0000493}