blob: 1756e44bbdf500fd8d8345ee5efdc9c48dd387ca [file] [log] [blame]
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +00001#include <stdio.h>
2#include <string.h>
3#include <stdlib.h>
4#include <getopt.h>
5#include <ctype.h>
6#include <netinet/ether.h>
7#include "../include/ebtables_u.h"
8#include "../include/ethernetdb.h"
9#include <linux/if_ether.h>
10#include <linux/netfilter_bridge/ebt_among.h>
11
gborowiak6c6d7312003-09-16 19:26:38 +000012#define NODEBUG
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +000013
14#define AMONG_DST '1'
15#define AMONG_SRC '2'
16
gborowiak6c6d7312003-09-16 19:26:38 +000017static struct option opts[] = {
18 {"among-dst", required_argument, 0, AMONG_DST},
19 {"among-src", required_argument, 0, AMONG_SRC},
20 {0}
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +000021};
22
23#ifdef DEBUG
24static void hexdump(const void *mem, int howmany)
25{
26 printf("\n");
27 const unsigned char *p = mem;
28 int i;
Bart De Schuymerf8c97432003-09-27 17:39:09 +000029
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +000030 for (i = 0; i < howmany; i++) {
31 if (i % 32 == 0) {
32 printf("\n%04x: ", i);
33 }
gborowiak6c6d7312003-09-16 19:26:38 +000034 printf("%2.2x%c", p[i], ". "[i % 4 == 3]);
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +000035 }
36 printf("\n");
37}
gborowiak6c6d7312003-09-16 19:26:38 +000038#endif /* DEBUG */
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +000039
40static void print_help()
41{
42 printf(
43"`among' options:\n"
Bart De Schuymer8339ff12004-01-14 20:05:27 +000044"--among-dst [!] list : matches if ether dst is in list\n"
45"--among-src [!] list : matches if ether src is in list\n"
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +000046"list has form:\n"
gborowiak6c6d7312003-09-16 19:26:38 +000047" xx:xx:xx:xx:xx:xx[=ip.ip.ip.ip],yy:yy:yy:yy:yy:yy[=ip.ip.ip.ip]"
48",...,zz:zz:zz:zz:zz:zz[=ip.ip.ip.ip][,]\n"
gborowiakc50ce6a2003-09-07 13:16:26 +000049"Things in brackets are optional.\n"
Bart De Schuymerf8c97432003-09-27 17:39:09 +000050"If you want to allow two (or more) IP addresses to one MAC address, you\n"
Bart De Schuymer7cc696b2003-10-12 12:34:10 +000051"can specify two (or more) pairs with the same MAC, e.g.\n"
gborowiakc50ce6a2003-09-07 13:16:26 +000052" 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 +000053 );
54}
55
56static void init(struct ebt_entry_match *match)
57{
gborowiak6c6d7312003-09-16 19:26:38 +000058 struct ebt_among_info *amonginfo =
59 (struct ebt_among_info *) match->data;
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +000060
61 memset(amonginfo, 0, sizeof(struct ebt_among_info));
62}
63
gborowiakc50ce6a2003-09-07 13:16:26 +000064static struct ebt_mac_wormhash *new_wormhash(int n)
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +000065{
gborowiak6c6d7312003-09-16 19:26:38 +000066 int size =
67 sizeof(struct ebt_mac_wormhash) +
68 n * sizeof(struct ebt_mac_wormhash_tuple);
69 struct ebt_mac_wormhash *result =
70 (struct ebt_mac_wormhash *) malloc(size);
Bart De Schuymerf8c97432003-09-27 17:39:09 +000071
gborowiakc50ce6a2003-09-07 13:16:26 +000072 memset(result, 0, size);
73 result->poolsize = n;
74 return result;
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +000075}
76
gborowiak6c6d7312003-09-16 19:26:38 +000077static void copy_wormhash(struct ebt_mac_wormhash *d,
78 const struct ebt_mac_wormhash *s)
gborowiakc50ce6a2003-09-07 13:16:26 +000079{
80 int dpoolsize = d->poolsize;
81 int dsize, ssize, amount;
Bart De Schuymerf8c97432003-09-27 17:39:09 +000082
gborowiakc50ce6a2003-09-07 13:16:26 +000083 dsize = ebt_mac_wormhash_size(d);
84 ssize = ebt_mac_wormhash_size(s);
85 amount = dsize < ssize ? dsize : ssize;
86 memcpy(d, s, amount);
87 d->poolsize = dpoolsize;
88}
89
90/* Returns:
91 * -1 when '\0' reached
92 * -2 when `n' bytes read and no delimiter found
93 * 0 when no less than `n' bytes read and delimiter found
94 * if `destbuf' is not NULL, it is filled by read bytes and ended with '\0'
95 * *pp is set on the first byte not copied to `destbuf'
96 */
gborowiak6c6d7312003-09-16 19:26:38 +000097static int read_until(const char **pp, const char *delimiters,
98 char *destbuf, int n)
gborowiakc50ce6a2003-09-07 13:16:26 +000099{
100 int count = 0;
101 int ret = 0;
102 char c;
Bart De Schuymerf8c97432003-09-27 17:39:09 +0000103
gborowiakc50ce6a2003-09-07 13:16:26 +0000104 while (1) {
105 c = **pp;
106 if (!c) {
107 ret = -1;
108 break;
109 }
110 if (strchr(delimiters, c)) {
111 ret = 0;
112 break;
113 }
114 if (count == n) {
115 ret = -2;
116 break;
117 }
gborowiak6c6d7312003-09-16 19:26:38 +0000118 if (destbuf)
119 destbuf[count++] = c;
gborowiakc50ce6a2003-09-07 13:16:26 +0000120 (*pp)++;
121 }
gborowiak6c6d7312003-09-16 19:26:38 +0000122 if (destbuf)
123 destbuf[count] = 0;
gborowiakc50ce6a2003-09-07 13:16:26 +0000124 return ret;
125}
126
gborowiak6c6d7312003-09-16 19:26:38 +0000127static int fcmp(const void *va, const void *vb) {
128 const struct ebt_mac_wormhash_tuple *a = va;
129 const struct ebt_mac_wormhash_tuple *b = vb;
130 int ca = ((const unsigned char*)a->cmp)[7];
131 int cb = ((const unsigned char*)b->cmp)[7];
Bart De Schuymerf8c97432003-09-27 17:39:09 +0000132
gborowiak6c6d7312003-09-16 19:26:38 +0000133 return ca - cb;
134}
135
136static void index_table(struct ebt_mac_wormhash *wh)
137{
138 int ipool, itable;
139 int c;
Bart De Schuymerf8c97432003-09-27 17:39:09 +0000140
gborowiak6c6d7312003-09-16 19:26:38 +0000141 for (itable = 0; itable <= 256; itable++) {
142 wh->table[itable] = wh->poolsize;
143 }
144 ipool = 0;
145 itable = 0;
146 while (1) {
147 wh->table[itable] = ipool;
148 c = ((const unsigned char*)wh->pool[ipool].cmp)[7];
149 if (itable <= c) {
150 itable++;
151 } else {
152 ipool++;
153 }
154 if (ipool > wh->poolsize)
155 break;
156 }
157}
158
gborowiakc50ce6a2003-09-07 13:16:26 +0000159static struct ebt_mac_wormhash *create_wormhash(const char *arg)
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +0000160{
161 const char *pc = arg;
162 const char *anchor;
gborowiakc50ce6a2003-09-07 13:16:26 +0000163 char *endptr;
164 struct ebt_mac_wormhash *workcopy, *result, *h;
165 unsigned char mac[6];
166 unsigned char ip[4];
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +0000167 int nmacs = 0;
gborowiakc50ce6a2003-09-07 13:16:26 +0000168 int i;
169 char token[4];
Bart De Schuymerf8c97432003-09-27 17:39:09 +0000170
gborowiakc50ce6a2003-09-07 13:16:26 +0000171 if (!(workcopy = new_wormhash(1024))) {
Bart De Schuymer64182a32004-01-21 20:39:54 +0000172 ebt_print_memory();
gborowiakc50ce6a2003-09-07 13:16:26 +0000173 }
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +0000174 while (1) {
gborowiakc50ce6a2003-09-07 13:16:26 +0000175 /* remember current position, we'll need it on error */
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +0000176 anchor = pc;
gborowiakc50ce6a2003-09-07 13:16:26 +0000177
gborowiak6c6d7312003-09-16 19:26:38 +0000178 /* collect MAC; all its bytes are followed by ':' (colon),
179 * except for the last one which can be followed by
180 * ',' (comma), '=' or '\0' */
gborowiakc50ce6a2003-09-07 13:16:26 +0000181 for (i = 0; i < 5; i++) {
gborowiak6c6d7312003-09-16 19:26:38 +0000182 if (read_until(&pc, ":", token, 2) < 0
183 || token[0] == 0) {
Bart De Schuymer64182a32004-01-21 20:39:54 +0000184 ebt_print_error("MAC parse error: %.20s",
185 anchor);
gborowiakc50ce6a2003-09-07 13:16:26 +0000186 }
187 mac[i] = strtol(token, &endptr, 16);
188 if (*endptr) {
Bart De Schuymer64182a32004-01-21 20:39:54 +0000189 ebt_print_error("MAC parse error: %.20s",
190 anchor);
gborowiakc50ce6a2003-09-07 13:16:26 +0000191 }
192 pc++;
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +0000193 }
gborowiakc50ce6a2003-09-07 13:16:26 +0000194 if (read_until(&pc, "=,", token, 2) == -2 || token[0] == 0) {
Bart De Schuymer64182a32004-01-21 20:39:54 +0000195 ebt_print_error("MAC parse error: %.20s", anchor);
gborowiakc50ce6a2003-09-07 13:16:26 +0000196 }
197 mac[i] = strtol(token, &endptr, 16);
198 if (*endptr) {
Bart De Schuymer64182a32004-01-21 20:39:54 +0000199 ebt_print_error("MAC parse error: %.20s", anchor);
gborowiakc50ce6a2003-09-07 13:16:26 +0000200 }
201 if (*pc == '=') {
202 /* an IP follows the MAC; collect similarly to MAC */
203 pc++;
204 anchor = pc;
205 for (i = 0; i < 3; i++) {
gborowiak6c6d7312003-09-16 19:26:38 +0000206 if (read_until(&pc, ".", token, 3) < 0
207 || token[0] == 0) {
Bart De Schuymer64182a32004-01-21 20:39:54 +0000208 ebt_print_error
gborowiak6c6d7312003-09-16 19:26:38 +0000209 ("IP parse error: %.20s",
210 anchor);
gborowiakc50ce6a2003-09-07 13:16:26 +0000211 }
212 ip[i] = strtol(token, &endptr, 10);
213 if (*endptr) {
Bart De Schuymer64182a32004-01-21 20:39:54 +0000214 ebt_print_error
gborowiak6c6d7312003-09-16 19:26:38 +0000215 ("IP parse error: %.20s",
216 anchor);
gborowiakc50ce6a2003-09-07 13:16:26 +0000217 }
218 pc++;
219 }
gborowiak6c6d7312003-09-16 19:26:38 +0000220 if (read_until(&pc, ",", token, 3) == -2
221 || token[0] == 0) {
Bart De Schuymer64182a32004-01-21 20:39:54 +0000222 ebt_print_error("IP parse error: %.20s",
gborowiak6c6d7312003-09-16 19:26:38 +0000223 anchor);
gborowiakc50ce6a2003-09-07 13:16:26 +0000224 }
225 ip[3] = strtol(token, &endptr, 10);
226 if (*endptr) {
Bart De Schuymer64182a32004-01-21 20:39:54 +0000227 ebt_print_error("IP parse error: %.20s",
gborowiak6c6d7312003-09-16 19:26:38 +0000228 anchor);
gborowiakc50ce6a2003-09-07 13:16:26 +0000229 }
gborowiak6c6d7312003-09-16 19:26:38 +0000230 if (*(uint32_t*)ip == 0) {
Bart De Schuymer64182a32004-01-21 20:39:54 +0000231 ebt_print_error("Illegal IP 0.0.0.0");
gborowiak6c6d7312003-09-16 19:26:38 +0000232 }
233 } else {
gborowiakc50ce6a2003-09-07 13:16:26 +0000234 /* no IP, we set it to 0.0.0.0 */
235 memset(ip, 0, 4);
236 }
gborowiak6c6d7312003-09-16 19:26:38 +0000237
gborowiakc50ce6a2003-09-07 13:16:26 +0000238 /* we have collected MAC and IP, so we add an entry */
gborowiak6c6d7312003-09-16 19:26:38 +0000239 memcpy(((char *) workcopy->pool[nmacs].cmp) + 2, mac, 6);
240 workcopy->pool[nmacs].ip = *(const uint32_t *) ip;
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +0000241 nmacs++;
gborowiak6c6d7312003-09-16 19:26:38 +0000242
gborowiakc50ce6a2003-09-07 13:16:26 +0000243 /* re-allocate memory if needed */
244 if (*pc && nmacs >= workcopy->poolsize) {
245 if (!(h = new_wormhash(nmacs * 2))) {
Bart De Schuymer64182a32004-01-21 20:39:54 +0000246 ebt_print_memory();
gborowiakc50ce6a2003-09-07 13:16:26 +0000247 }
248 copy_wormhash(h, workcopy);
249 free(workcopy);
250 workcopy = h;
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +0000251 }
gborowiak6c6d7312003-09-16 19:26:38 +0000252
gborowiakc50ce6a2003-09-07 13:16:26 +0000253 /* check if end of string was reached */
254 if (!*pc) {
255 break;
256 }
gborowiak6c6d7312003-09-16 19:26:38 +0000257
258 /* now `pc' points to comma if we are here; */
259 /* increment this to the next char */
gborowiakc50ce6a2003-09-07 13:16:26 +0000260 /* but first assert :-> */
261 if (*pc != ',') {
Bart De Schuymer64182a32004-01-21 20:39:54 +0000262 ebt_print_error("Something went wrong; no comma...\n");
gborowiakc50ce6a2003-09-07 13:16:26 +0000263 }
264 pc++;
gborowiak6c6d7312003-09-16 19:26:38 +0000265
266 /* again check if end of string was reached; */
267 /* we allow an ending comma */
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +0000268 if (!*pc) {
269 break;
270 }
271 }
gborowiakc50ce6a2003-09-07 13:16:26 +0000272 if (!(result = new_wormhash(nmacs))) {
Bart De Schuymer64182a32004-01-21 20:39:54 +0000273 ebt_print_memory();
gborowiakc50ce6a2003-09-07 13:16:26 +0000274 }
275 copy_wormhash(result, workcopy);
276 free(workcopy);
gborowiak6c6d7312003-09-16 19:26:38 +0000277 qsort(&result->pool, result->poolsize,
278 sizeof(struct ebt_mac_wormhash_tuple), fcmp);
279 index_table(result);
gborowiakc50ce6a2003-09-07 13:16:26 +0000280 return result;
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +0000281}
282
283#define OPT_DST 0x01
284#define OPT_SRC 0x02
gborowiak6c6d7312003-09-16 19:26:38 +0000285static int parse(int c, char **argv, int argc,
286 const struct ebt_u_entry *entry, unsigned int *flags,
287 struct ebt_entry_match **match)
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +0000288{
gborowiak6c6d7312003-09-16 19:26:38 +0000289 struct ebt_among_info *info =
290 (struct ebt_among_info *) (*match)->data;
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +0000291 struct ebt_mac_wormhash *wh;
gborowiakc50ce6a2003-09-07 13:16:26 +0000292 struct ebt_entry_match *h;
293 int new_size, old_size;
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +0000294
295 switch (c) {
296 case AMONG_DST:
297 case AMONG_SRC:
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000298 if (ebt_check_inverse(optarg)) {
gborowiakc50ce6a2003-09-07 13:16:26 +0000299 if (c == AMONG_DST)
300 info->bitmask |= EBT_AMONG_DST_NEG;
301 else
302 info->bitmask |= EBT_AMONG_SRC_NEG;
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +0000303 }
304 if (optind > argc)
Bart De Schuymer64182a32004-01-21 20:39:54 +0000305 ebt_print_error("No MAC list specified\n");
gborowiakc50ce6a2003-09-07 13:16:26 +0000306 wh = create_wormhash(argv[optind - 1]);
gborowiak6c6d7312003-09-16 19:26:38 +0000307 old_size = sizeof(struct ebt_entry_match) +
308 (**match).match_size;
309 h = malloc((new_size =
310 old_size + ebt_mac_wormhash_size(wh)));
gborowiakc50ce6a2003-09-07 13:16:26 +0000311 memcpy(h, *match, old_size);
gborowiak6c6d7312003-09-16 19:26:38 +0000312 memcpy((char *) h + old_size, wh,
313 ebt_mac_wormhash_size(wh));
gborowiakc50ce6a2003-09-07 13:16:26 +0000314 h->match_size = new_size - sizeof(struct ebt_entry_match);
gborowiak6c6d7312003-09-16 19:26:38 +0000315 info = (struct ebt_among_info *) h->data;
gborowiakc50ce6a2003-09-07 13:16:26 +0000316 if (c == AMONG_DST) {
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000317 ebt_check_option(flags, OPT_DST);
gborowiak6c6d7312003-09-16 19:26:38 +0000318 info->wh_dst_ofs =
319 old_size - sizeof(struct ebt_entry_match);
gborowiakc50ce6a2003-09-07 13:16:26 +0000320 } else {
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000321 ebt_check_option(flags, OPT_SRC);
gborowiak6c6d7312003-09-16 19:26:38 +0000322 info->wh_src_ofs =
323 old_size - sizeof(struct ebt_entry_match);
gborowiakc50ce6a2003-09-07 13:16:26 +0000324 }
325 free(*match);
326 *match = h;
327 free(wh);
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +0000328 break;
329 default:
330 return 0;
331 }
332 return 1;
333}
334
335static void final_check(const struct ebt_u_entry *entry,
gborowiak6c6d7312003-09-16 19:26:38 +0000336 const struct ebt_entry_match *match,
337 const char *name, unsigned int hookmask,
338 unsigned int time)
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +0000339{
340}
341
gborowiak6c6d7312003-09-16 19:26:38 +0000342#ifdef DEBUG
343static void wormhash_debug(const struct ebt_mac_wormhash *wh)
344{
345 int i;
Bart De Schuymerf8c97432003-09-27 17:39:09 +0000346
gborowiak6c6d7312003-09-16 19:26:38 +0000347 printf("poolsize: %d\n", wh->poolsize);
348 for (i = 0; i <= 256; i++) {
349 printf("%02x ", wh->table[i]);
350 if (i % 16 == 15) {
351 printf("\n");
352 }
353 }
354 printf("\n");
355}
356#endif /* DEBUG */
357
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +0000358static void wormhash_printout(const struct ebt_mac_wormhash *wh)
359{
360 int i;
gborowiakc50ce6a2003-09-07 13:16:26 +0000361 unsigned char *ip;
Bart De Schuymerf8c97432003-09-27 17:39:09 +0000362
gborowiak6c6d7312003-09-16 19:26:38 +0000363 for (i = 0; i < wh->poolsize; i++) {
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +0000364 const struct ebt_mac_wormhash_tuple *p;
Bart De Schuymerf8c97432003-09-27 17:39:09 +0000365
gborowiak6c6d7312003-09-16 19:26:38 +0000366 p = (const struct ebt_mac_wormhash_tuple *)(&wh->pool[i]);
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000367 ebt_print_mac(((const char *) &p->cmp[0]) + 2);
gborowiak6c6d7312003-09-16 19:26:38 +0000368 if (p->ip) {
369 ip = (unsigned char *) &p->ip;
370 printf("=%u.%u.%u.%u", ip[0], ip[1], ip[2], ip[3]);
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +0000371 }
gborowiak6c6d7312003-09-16 19:26:38 +0000372 printf(",");
373 }
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +0000374 printf(" ");
375}
376
377static void print(const struct ebt_u_entry *entry,
gborowiak6c6d7312003-09-16 19:26:38 +0000378 const struct ebt_entry_match *match)
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +0000379{
gborowiakc50ce6a2003-09-07 13:16:26 +0000380 struct ebt_among_info *info = (struct ebt_among_info *)match->data;
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +0000381
gborowiakc50ce6a2003-09-07 13:16:26 +0000382 if (info->wh_dst_ofs) {
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +0000383 printf("--among-dst ");
gborowiakc50ce6a2003-09-07 13:16:26 +0000384 if (info->bitmask && EBT_AMONG_DST_NEG) {
385 printf("! ");
386 }
387 wormhash_printout(ebt_among_wh_dst(info));
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +0000388 }
gborowiakc50ce6a2003-09-07 13:16:26 +0000389 if (info->wh_src_ofs) {
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +0000390 printf("--among-src ");
gborowiakc50ce6a2003-09-07 13:16:26 +0000391 if (info->bitmask && EBT_AMONG_SRC_NEG) {
392 printf("! ");
393 }
394 wormhash_printout(ebt_among_wh_src(info));
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +0000395 }
396}
397
gborowiak6c6d7312003-09-16 19:26:38 +0000398static int compare_wh(const struct ebt_mac_wormhash *aw,
399 const struct ebt_mac_wormhash *bw)
gborowiakc50ce6a2003-09-07 13:16:26 +0000400{
401 int as, bs;
Bart De Schuymerf8c97432003-09-27 17:39:09 +0000402
gborowiakc50ce6a2003-09-07 13:16:26 +0000403 as = ebt_mac_wormhash_size(aw);
404 bs = ebt_mac_wormhash_size(bw);
405 if (as != bs)
406 return 0;
407 if (as && memcmp(aw, bw, as))
408 return 0;
409 return 1;
410}
411
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +0000412static int compare(const struct ebt_entry_match *m1,
gborowiak6c6d7312003-09-16 19:26:38 +0000413 const struct ebt_entry_match *m2)
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +0000414{
gborowiak6c6d7312003-09-16 19:26:38 +0000415 struct ebt_among_info *a = (struct ebt_among_info *) m1->data;
416 struct ebt_among_info *b = (struct ebt_among_info *) m2->data;
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +0000417
gborowiak6c6d7312003-09-16 19:26:38 +0000418 if (!compare_wh(ebt_among_wh_dst(a), ebt_among_wh_dst(b)))
419 return 0;
420 if (!compare_wh(ebt_among_wh_src(a), ebt_among_wh_src(b)))
421 return 0;
422 if (a->bitmask != b->bitmask)
423 return 0;
gborowiakc50ce6a2003-09-07 13:16:26 +0000424 return 1;
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +0000425}
426
gborowiak6c6d7312003-09-16 19:26:38 +0000427static struct ebt_u_match among_match = {
428 .name = EBT_AMONG_MATCH,
429 .size = sizeof(struct ebt_among_info),
430 .help = print_help,
431 .init = init,
432 .parse = parse,
433 .final_check = final_check,
434 .print = print,
435 .compare = compare,
436 .extra_ops = opts,
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +0000437};
438
Bart De Schuymer64182a32004-01-21 20:39:54 +0000439void _init(void)
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +0000440{
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000441 ebt_register_match(&among_match);
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +0000442}