blob: 7e01b49daa59ead5174833f5b3ec415b00e98cbe [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>
19
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +000020#define AMONG_DST '1'
21#define AMONG_SRC '2'
22
gborowiak6c6d7312003-09-16 19:26:38 +000023static struct option opts[] = {
24 {"among-dst", required_argument, 0, AMONG_DST},
25 {"among-src", required_argument, 0, AMONG_SRC},
26 {0}
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +000027};
28
29#ifdef DEBUG
30static void hexdump(const void *mem, int howmany)
31{
32 printf("\n");
33 const unsigned char *p = mem;
34 int i;
Bart De Schuymerf8c97432003-09-27 17:39:09 +000035
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +000036 for (i = 0; i < howmany; i++) {
37 if (i % 32 == 0) {
38 printf("\n%04x: ", i);
39 }
gborowiak6c6d7312003-09-16 19:26:38 +000040 printf("%2.2x%c", p[i], ". "[i % 4 == 3]);
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +000041 }
42 printf("\n");
43}
gborowiak6c6d7312003-09-16 19:26:38 +000044#endif /* DEBUG */
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +000045
46static void print_help()
47{
48 printf(
49"`among' options:\n"
Bart De Schuymer8339ff12004-01-14 20:05:27 +000050"--among-dst [!] list : matches if ether dst is in list\n"
51"--among-src [!] list : matches if ether src is in list\n"
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +000052"list has form:\n"
gborowiak6c6d7312003-09-16 19:26:38 +000053" xx:xx:xx:xx:xx:xx[=ip.ip.ip.ip],yy:yy:yy:yy:yy:yy[=ip.ip.ip.ip]"
54",...,zz:zz:zz:zz:zz:zz[=ip.ip.ip.ip][,]\n"
gborowiakc50ce6a2003-09-07 13:16:26 +000055"Things in brackets are optional.\n"
Bart De Schuymerf8c97432003-09-27 17:39:09 +000056"If you want to allow two (or more) IP addresses to one MAC address, you\n"
Bart De Schuymer7cc696b2003-10-12 12:34:10 +000057"can specify two (or more) pairs with the same MAC, e.g.\n"
gborowiakc50ce6a2003-09-07 13:16:26 +000058" 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 +000059 );
60}
61
62static void init(struct ebt_entry_match *match)
63{
gborowiak6c6d7312003-09-16 19:26:38 +000064 struct ebt_among_info *amonginfo =
65 (struct ebt_among_info *) match->data;
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +000066
67 memset(amonginfo, 0, sizeof(struct ebt_among_info));
68}
69
gborowiakc50ce6a2003-09-07 13:16:26 +000070static struct ebt_mac_wormhash *new_wormhash(int n)
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +000071{
gborowiak6c6d7312003-09-16 19:26:38 +000072 int size =
73 sizeof(struct ebt_mac_wormhash) +
74 n * sizeof(struct ebt_mac_wormhash_tuple);
75 struct ebt_mac_wormhash *result =
76 (struct ebt_mac_wormhash *) malloc(size);
Bart De Schuymerf8c97432003-09-27 17:39:09 +000077
Bart De Schuymerff587202005-02-08 20:02:28 +000078 if (!result)
79 ebt_print_memory();
gborowiakc50ce6a2003-09-07 13:16:26 +000080 memset(result, 0, size);
81 result->poolsize = n;
82 return result;
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +000083}
84
gborowiak6c6d7312003-09-16 19:26:38 +000085static void copy_wormhash(struct ebt_mac_wormhash *d,
86 const struct ebt_mac_wormhash *s)
gborowiakc50ce6a2003-09-07 13:16:26 +000087{
88 int dpoolsize = d->poolsize;
89 int dsize, ssize, amount;
Bart De Schuymerf8c97432003-09-27 17:39:09 +000090
gborowiakc50ce6a2003-09-07 13:16:26 +000091 dsize = ebt_mac_wormhash_size(d);
92 ssize = ebt_mac_wormhash_size(s);
93 amount = dsize < ssize ? dsize : ssize;
94 memcpy(d, s, amount);
95 d->poolsize = dpoolsize;
96}
97
98/* Returns:
99 * -1 when '\0' reached
100 * -2 when `n' bytes read and no delimiter found
101 * 0 when no less than `n' bytes read and delimiter found
102 * if `destbuf' is not NULL, it is filled by read bytes and ended with '\0'
103 * *pp is set on the first byte not copied to `destbuf'
104 */
gborowiak6c6d7312003-09-16 19:26:38 +0000105static int read_until(const char **pp, const char *delimiters,
106 char *destbuf, int n)
gborowiakc50ce6a2003-09-07 13:16:26 +0000107{
108 int count = 0;
109 int ret = 0;
110 char c;
Bart De Schuymerf8c97432003-09-27 17:39:09 +0000111
gborowiakc50ce6a2003-09-07 13:16:26 +0000112 while (1) {
113 c = **pp;
114 if (!c) {
115 ret = -1;
116 break;
117 }
118 if (strchr(delimiters, c)) {
119 ret = 0;
120 break;
121 }
122 if (count == n) {
123 ret = -2;
124 break;
125 }
gborowiak6c6d7312003-09-16 19:26:38 +0000126 if (destbuf)
127 destbuf[count++] = c;
gborowiakc50ce6a2003-09-07 13:16:26 +0000128 (*pp)++;
129 }
gborowiak6c6d7312003-09-16 19:26:38 +0000130 if (destbuf)
131 destbuf[count] = 0;
gborowiakc50ce6a2003-09-07 13:16:26 +0000132 return ret;
133}
134
gborowiak6c6d7312003-09-16 19:26:38 +0000135static int fcmp(const void *va, const void *vb) {
136 const struct ebt_mac_wormhash_tuple *a = va;
137 const struct ebt_mac_wormhash_tuple *b = vb;
138 int ca = ((const unsigned char*)a->cmp)[7];
139 int cb = ((const unsigned char*)b->cmp)[7];
Bart De Schuymerf8c97432003-09-27 17:39:09 +0000140
gborowiak6c6d7312003-09-16 19:26:38 +0000141 return ca - cb;
142}
143
144static void index_table(struct ebt_mac_wormhash *wh)
145{
146 int ipool, itable;
147 int c;
Bart De Schuymerf8c97432003-09-27 17:39:09 +0000148
gborowiak6c6d7312003-09-16 19:26:38 +0000149 for (itable = 0; itable <= 256; itable++) {
150 wh->table[itable] = wh->poolsize;
151 }
152 ipool = 0;
153 itable = 0;
154 while (1) {
155 wh->table[itable] = ipool;
156 c = ((const unsigned char*)wh->pool[ipool].cmp)[7];
157 if (itable <= c) {
158 itable++;
159 } else {
160 ipool++;
161 }
162 if (ipool > wh->poolsize)
163 break;
164 }
165}
166
gborowiakc50ce6a2003-09-07 13:16:26 +0000167static struct ebt_mac_wormhash *create_wormhash(const char *arg)
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +0000168{
169 const char *pc = arg;
170 const char *anchor;
gborowiakc50ce6a2003-09-07 13:16:26 +0000171 char *endptr;
172 struct ebt_mac_wormhash *workcopy, *result, *h;
173 unsigned char mac[6];
174 unsigned char ip[4];
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +0000175 int nmacs = 0;
gborowiakc50ce6a2003-09-07 13:16:26 +0000176 int i;
177 char token[4];
Bart De Schuymerf8c97432003-09-27 17:39:09 +0000178
gborowiakc50ce6a2003-09-07 13:16:26 +0000179 if (!(workcopy = new_wormhash(1024))) {
Bart De Schuymer64182a32004-01-21 20:39:54 +0000180 ebt_print_memory();
gborowiakc50ce6a2003-09-07 13:16:26 +0000181 }
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +0000182 while (1) {
gborowiakc50ce6a2003-09-07 13:16:26 +0000183 /* remember current position, we'll need it on error */
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +0000184 anchor = pc;
gborowiakc50ce6a2003-09-07 13:16:26 +0000185
gborowiak6c6d7312003-09-16 19:26:38 +0000186 /* collect MAC; all its bytes are followed by ':' (colon),
187 * except for the last one which can be followed by
188 * ',' (comma), '=' or '\0' */
gborowiakc50ce6a2003-09-07 13:16:26 +0000189 for (i = 0; i < 5; i++) {
gborowiak6c6d7312003-09-16 19:26:38 +0000190 if (read_until(&pc, ":", token, 2) < 0
191 || token[0] == 0) {
Bart De Schuymerff587202005-02-08 20:02:28 +0000192 ebt_print_error("MAC parse error: %.20s", anchor);
193 return NULL;
gborowiakc50ce6a2003-09-07 13:16:26 +0000194 }
195 mac[i] = strtol(token, &endptr, 16);
196 if (*endptr) {
Bart De Schuymerff587202005-02-08 20:02:28 +0000197 ebt_print_error("MAC parse error: %.20s", anchor);
198 return NULL;
gborowiakc50ce6a2003-09-07 13:16:26 +0000199 }
200 pc++;
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +0000201 }
gborowiakc50ce6a2003-09-07 13:16:26 +0000202 if (read_until(&pc, "=,", token, 2) == -2 || token[0] == 0) {
Bart De Schuymer64182a32004-01-21 20:39:54 +0000203 ebt_print_error("MAC parse error: %.20s", anchor);
Bart De Schuymerff587202005-02-08 20:02:28 +0000204 return NULL;
gborowiakc50ce6a2003-09-07 13:16:26 +0000205 }
206 mac[i] = strtol(token, &endptr, 16);
207 if (*endptr) {
Bart De Schuymer64182a32004-01-21 20:39:54 +0000208 ebt_print_error("MAC parse error: %.20s", anchor);
Bart De Schuymerff587202005-02-08 20:02:28 +0000209 return NULL;
gborowiakc50ce6a2003-09-07 13:16:26 +0000210 }
211 if (*pc == '=') {
212 /* an IP follows the MAC; collect similarly to MAC */
213 pc++;
214 anchor = pc;
215 for (i = 0; i < 3; i++) {
Bart De Schuymerff587202005-02-08 20:02:28 +0000216 if (read_until(&pc, ".", token, 3) < 0 || token[0] == 0) {
217 ebt_print_error("IP parse error: %.20s", anchor);
218 return NULL;
gborowiakc50ce6a2003-09-07 13:16:26 +0000219 }
220 ip[i] = strtol(token, &endptr, 10);
221 if (*endptr) {
Bart De Schuymerff587202005-02-08 20:02:28 +0000222 ebt_print_error("IP parse error: %.20s", anchor);
223 return NULL;
gborowiakc50ce6a2003-09-07 13:16:26 +0000224 }
225 pc++;
226 }
Bart De Schuymerff587202005-02-08 20:02:28 +0000227 if (read_until(&pc, ",", token, 3) == -2 || token[0] == 0) {
228 ebt_print_error("IP parse error: %.20s", anchor);
229 return NULL;
gborowiakc50ce6a2003-09-07 13:16:26 +0000230 }
231 ip[3] = strtol(token, &endptr, 10);
232 if (*endptr) {
Bart De Schuymerff587202005-02-08 20:02:28 +0000233 ebt_print_error("IP parse error: %.20s", anchor);
234 return NULL;
gborowiakc50ce6a2003-09-07 13:16:26 +0000235 }
gborowiak6c6d7312003-09-16 19:26:38 +0000236 if (*(uint32_t*)ip == 0) {
Bart De Schuymer64182a32004-01-21 20:39:54 +0000237 ebt_print_error("Illegal IP 0.0.0.0");
Bart De Schuymerff587202005-02-08 20:02:28 +0000238 return NULL;
gborowiak6c6d7312003-09-16 19:26:38 +0000239 }
240 } else {
gborowiakc50ce6a2003-09-07 13:16:26 +0000241 /* no IP, we set it to 0.0.0.0 */
242 memset(ip, 0, 4);
243 }
gborowiak6c6d7312003-09-16 19:26:38 +0000244
gborowiakc50ce6a2003-09-07 13:16:26 +0000245 /* we have collected MAC and IP, so we add an entry */
gborowiak6c6d7312003-09-16 19:26:38 +0000246 memcpy(((char *) workcopy->pool[nmacs].cmp) + 2, mac, 6);
247 workcopy->pool[nmacs].ip = *(const uint32_t *) ip;
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +0000248 nmacs++;
gborowiak6c6d7312003-09-16 19:26:38 +0000249
gborowiakc50ce6a2003-09-07 13:16:26 +0000250 /* re-allocate memory if needed */
251 if (*pc && nmacs >= workcopy->poolsize) {
252 if (!(h = new_wormhash(nmacs * 2))) {
Bart De Schuymer64182a32004-01-21 20:39:54 +0000253 ebt_print_memory();
gborowiakc50ce6a2003-09-07 13:16:26 +0000254 }
255 copy_wormhash(h, workcopy);
256 free(workcopy);
257 workcopy = h;
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +0000258 }
gborowiak6c6d7312003-09-16 19:26:38 +0000259
gborowiakc50ce6a2003-09-07 13:16:26 +0000260 /* check if end of string was reached */
261 if (!*pc) {
262 break;
263 }
gborowiak6c6d7312003-09-16 19:26:38 +0000264
265 /* now `pc' points to comma if we are here; */
266 /* increment this to the next char */
gborowiakc50ce6a2003-09-07 13:16:26 +0000267 /* but first assert :-> */
268 if (*pc != ',') {
Bart De Schuymer64182a32004-01-21 20:39:54 +0000269 ebt_print_error("Something went wrong; no comma...\n");
Bart De Schuymerff587202005-02-08 20:02:28 +0000270 return NULL;
gborowiakc50ce6a2003-09-07 13:16:26 +0000271 }
272 pc++;
gborowiak6c6d7312003-09-16 19:26:38 +0000273
274 /* again check if end of string was reached; */
275 /* we allow an ending comma */
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +0000276 if (!*pc) {
277 break;
278 }
279 }
gborowiakc50ce6a2003-09-07 13:16:26 +0000280 if (!(result = new_wormhash(nmacs))) {
Bart De Schuymer64182a32004-01-21 20:39:54 +0000281 ebt_print_memory();
gborowiakc50ce6a2003-09-07 13:16:26 +0000282 }
283 copy_wormhash(result, workcopy);
284 free(workcopy);
gborowiak6c6d7312003-09-16 19:26:38 +0000285 qsort(&result->pool, result->poolsize,
286 sizeof(struct ebt_mac_wormhash_tuple), fcmp);
287 index_table(result);
gborowiakc50ce6a2003-09-07 13:16:26 +0000288 return result;
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +0000289}
290
291#define OPT_DST 0x01
292#define OPT_SRC 0x02
gborowiak6c6d7312003-09-16 19:26:38 +0000293static int parse(int c, char **argv, int argc,
294 const struct ebt_u_entry *entry, unsigned int *flags,
295 struct ebt_entry_match **match)
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +0000296{
gborowiak6c6d7312003-09-16 19:26:38 +0000297 struct ebt_among_info *info =
298 (struct ebt_among_info *) (*match)->data;
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +0000299 struct ebt_mac_wormhash *wh;
gborowiakc50ce6a2003-09-07 13:16:26 +0000300 struct ebt_entry_match *h;
301 int new_size, old_size;
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +0000302
303 switch (c) {
304 case AMONG_DST:
305 case AMONG_SRC:
Bart De Schuymerff587202005-02-08 20:02:28 +0000306 if (c == AMONG_DST) {
307 ebt_check_option2(flags, OPT_DST);
308 } else {
309 ebt_check_option2(flags, OPT_SRC);
310 }
311 if (ebt_check_inverse2(optarg)) {
gborowiakc50ce6a2003-09-07 13:16:26 +0000312 if (c == AMONG_DST)
313 info->bitmask |= EBT_AMONG_DST_NEG;
314 else
315 info->bitmask |= EBT_AMONG_SRC_NEG;
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +0000316 }
Bart De Schuymerff587202005-02-08 20:02:28 +0000317 wh = create_wormhash(optarg);
318 if (ebt_errormsg[0] != '\0')
319 break;
320
321 old_size = sizeof(struct ebt_entry_match) + (**match).match_size;
322 h = malloc((new_size = old_size + ebt_mac_wormhash_size(wh)));
323 if (!h)
324 ebt_print_memory();
gborowiakc50ce6a2003-09-07 13:16:26 +0000325 memcpy(h, *match, old_size);
Bart De Schuymerff587202005-02-08 20:02:28 +0000326 memcpy((char *) h + old_size, wh, ebt_mac_wormhash_size(wh));
gborowiakc50ce6a2003-09-07 13:16:26 +0000327 h->match_size = new_size - sizeof(struct ebt_entry_match);
gborowiak6c6d7312003-09-16 19:26:38 +0000328 info = (struct ebt_among_info *) h->data;
gborowiakc50ce6a2003-09-07 13:16:26 +0000329 if (c == AMONG_DST) {
gborowiak6c6d7312003-09-16 19:26:38 +0000330 info->wh_dst_ofs =
331 old_size - sizeof(struct ebt_entry_match);
gborowiakc50ce6a2003-09-07 13:16:26 +0000332 } else {
gborowiak6c6d7312003-09-16 19:26:38 +0000333 info->wh_src_ofs =
334 old_size - sizeof(struct ebt_entry_match);
gborowiakc50ce6a2003-09-07 13:16:26 +0000335 }
336 free(*match);
337 *match = h;
338 free(wh);
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +0000339 break;
340 default:
341 return 0;
342 }
343 return 1;
344}
345
346static void final_check(const struct ebt_u_entry *entry,
gborowiak6c6d7312003-09-16 19:26:38 +0000347 const struct ebt_entry_match *match,
348 const char *name, unsigned int hookmask,
349 unsigned int time)
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +0000350{
351}
352
gborowiak6c6d7312003-09-16 19:26:38 +0000353#ifdef DEBUG
354static void wormhash_debug(const struct ebt_mac_wormhash *wh)
355{
356 int i;
Bart De Schuymerf8c97432003-09-27 17:39:09 +0000357
gborowiak6c6d7312003-09-16 19:26:38 +0000358 printf("poolsize: %d\n", wh->poolsize);
359 for (i = 0; i <= 256; i++) {
360 printf("%02x ", wh->table[i]);
361 if (i % 16 == 15) {
362 printf("\n");
363 }
364 }
365 printf("\n");
366}
367#endif /* DEBUG */
368
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +0000369static void wormhash_printout(const struct ebt_mac_wormhash *wh)
370{
371 int i;
gborowiakc50ce6a2003-09-07 13:16:26 +0000372 unsigned char *ip;
Bart De Schuymerf8c97432003-09-27 17:39:09 +0000373
gborowiak6c6d7312003-09-16 19:26:38 +0000374 for (i = 0; i < wh->poolsize; i++) {
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +0000375 const struct ebt_mac_wormhash_tuple *p;
Bart De Schuymerf8c97432003-09-27 17:39:09 +0000376
gborowiak6c6d7312003-09-16 19:26:38 +0000377 p = (const struct ebt_mac_wormhash_tuple *)(&wh->pool[i]);
Bart De Schuymer510c9ce2006-01-23 18:50:54 +0000378 ebt_print_mac(((const unsigned char *) &p->cmp[0]) + 2);
gborowiak6c6d7312003-09-16 19:26:38 +0000379 if (p->ip) {
380 ip = (unsigned char *) &p->ip;
381 printf("=%u.%u.%u.%u", ip[0], ip[1], ip[2], ip[3]);
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +0000382 }
gborowiak6c6d7312003-09-16 19:26:38 +0000383 printf(",");
384 }
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +0000385 printf(" ");
386}
387
388static void print(const struct ebt_u_entry *entry,
gborowiak6c6d7312003-09-16 19:26:38 +0000389 const struct ebt_entry_match *match)
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +0000390{
gborowiakc50ce6a2003-09-07 13:16:26 +0000391 struct ebt_among_info *info = (struct ebt_among_info *)match->data;
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +0000392
gborowiakc50ce6a2003-09-07 13:16:26 +0000393 if (info->wh_dst_ofs) {
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +0000394 printf("--among-dst ");
gborowiakc50ce6a2003-09-07 13:16:26 +0000395 if (info->bitmask && EBT_AMONG_DST_NEG) {
396 printf("! ");
397 }
398 wormhash_printout(ebt_among_wh_dst(info));
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +0000399 }
gborowiakc50ce6a2003-09-07 13:16:26 +0000400 if (info->wh_src_ofs) {
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +0000401 printf("--among-src ");
gborowiakc50ce6a2003-09-07 13:16:26 +0000402 if (info->bitmask && EBT_AMONG_SRC_NEG) {
403 printf("! ");
404 }
405 wormhash_printout(ebt_among_wh_src(info));
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +0000406 }
407}
408
gborowiak6c6d7312003-09-16 19:26:38 +0000409static int compare_wh(const struct ebt_mac_wormhash *aw,
410 const struct ebt_mac_wormhash *bw)
gborowiakc50ce6a2003-09-07 13:16:26 +0000411{
412 int as, bs;
Bart De Schuymerf8c97432003-09-27 17:39:09 +0000413
gborowiakc50ce6a2003-09-07 13:16:26 +0000414 as = ebt_mac_wormhash_size(aw);
415 bs = ebt_mac_wormhash_size(bw);
416 if (as != bs)
417 return 0;
418 if (as && memcmp(aw, bw, as))
419 return 0;
420 return 1;
421}
422
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +0000423static int compare(const struct ebt_entry_match *m1,
gborowiak6c6d7312003-09-16 19:26:38 +0000424 const struct ebt_entry_match *m2)
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +0000425{
gborowiak6c6d7312003-09-16 19:26:38 +0000426 struct ebt_among_info *a = (struct ebt_among_info *) m1->data;
427 struct ebt_among_info *b = (struct ebt_among_info *) m2->data;
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +0000428
gborowiak6c6d7312003-09-16 19:26:38 +0000429 if (!compare_wh(ebt_among_wh_dst(a), ebt_among_wh_dst(b)))
430 return 0;
431 if (!compare_wh(ebt_among_wh_src(a), ebt_among_wh_src(b)))
432 return 0;
433 if (a->bitmask != b->bitmask)
434 return 0;
gborowiakc50ce6a2003-09-07 13:16:26 +0000435 return 1;
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +0000436}
437
gborowiak6c6d7312003-09-16 19:26:38 +0000438static struct ebt_u_match among_match = {
439 .name = EBT_AMONG_MATCH,
440 .size = sizeof(struct ebt_among_info),
441 .help = print_help,
442 .init = init,
443 .parse = parse,
444 .final_check = final_check,
445 .print = print,
446 .compare = compare,
447 .extra_ops = opts,
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +0000448};
449
Bart De Schuymer64182a32004-01-21 20:39:54 +0000450void _init(void)
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +0000451{
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000452 ebt_register_match(&among_match);
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +0000453}