blob: df98b9a17335f2f6e533c3e3f82f887327c77461 [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
gborowiakc50ce6a2003-09-07 13:16:26 +000012//#define DEBUG
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +000013
14#define AMONG_DST '1'
15#define AMONG_SRC '2'
16
17static struct option opts[] =
18{
19 { "among-dst" , required_argument, 0, AMONG_DST },
20 { "among-src" , required_argument, 0, AMONG_SRC },
21 { 0 }
22};
23
24#ifdef DEBUG
25static void hexdump(const void *mem, int howmany)
26{
27 printf("\n");
28 const unsigned char *p = mem;
29 int i;
30 for (i = 0; i < howmany; i++) {
31 if (i % 32 == 0) {
32 printf("\n%04x: ", i);
33 }
gborowiakc50ce6a2003-09-07 13:16:26 +000034 printf("%2.2x%c", p[i], ". "[i%4==3]);
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +000035 }
36 printf("\n");
37}
38#endif /* DEBUG */
39
40static void print_help()
41{
42 printf(
43"`among' options:\n"
44"--among-dst list : matches if ether dst is in list\n"
45"--among-src list : matches if ether src is in list\n"
46"list has form:\n"
gborowiakc50ce6a2003-09-07 13:16:26 +000047" xx:xx:xx:xx:xx:xx[=ip.ip.ip.ip],yy:yy:yy:yy:yy:yy[=ip.ip.ip.ip],...,zz:zz:zz:zz:zz:zz[=ip.ip.ip.ip][,]\n"
48"Things in brackets are optional.\n"
49"If you want to allow two (or more) IP addresses to one MAC address, you can\n"
50"specify two (or more) pairs witch the same MAC, e.g.\n"
51" 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 +000052 );
53}
54
55static void init(struct ebt_entry_match *match)
56{
57 struct ebt_among_info *amonginfo = (struct ebt_among_info *)match->data;
58
59 memset(amonginfo, 0, sizeof(struct ebt_among_info));
60}
61
gborowiakc50ce6a2003-09-07 13:16:26 +000062static struct ebt_mac_wormhash *new_wormhash(int n)
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +000063{
gborowiakc50ce6a2003-09-07 13:16:26 +000064 int size = sizeof(struct ebt_mac_wormhash) + n * sizeof(struct ebt_mac_wormhash_tuple);
65 struct ebt_mac_wormhash *result = (struct ebt_mac_wormhash *)malloc(size);
66 memset(result, 0, size);
67 result->poolsize = n;
68 return result;
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +000069}
70
gborowiakc50ce6a2003-09-07 13:16:26 +000071static void copy_wormhash(struct ebt_mac_wormhash *d, const struct ebt_mac_wormhash *s)
72{
73 int dpoolsize = d->poolsize;
74 int dsize, ssize, amount;
75 dsize = ebt_mac_wormhash_size(d);
76 ssize = ebt_mac_wormhash_size(s);
77 amount = dsize < ssize ? dsize : ssize;
78 memcpy(d, s, amount);
79 d->poolsize = dpoolsize;
80}
81
82/* Returns:
83 * -1 when '\0' reached
84 * -2 when `n' bytes read and no delimiter found
85 * 0 when no less than `n' bytes read and delimiter found
86 * if `destbuf' is not NULL, it is filled by read bytes and ended with '\0'
87 * *pp is set on the first byte not copied to `destbuf'
88 */
89static int read_until(const char **pp, const char *delimiters, char *destbuf, int n)
90{
91 int count = 0;
92 int ret = 0;
93 char c;
94 while (1) {
95 c = **pp;
96 if (!c) {
97 ret = -1;
98 break;
99 }
100 if (strchr(delimiters, c)) {
101 ret = 0;
102 break;
103 }
104 if (count == n) {
105 ret = -2;
106 break;
107 }
108 if (destbuf) destbuf[count++] = c;
109 (*pp)++;
110 }
111 if (destbuf) destbuf[count] = 0;
112 return ret;
113}
114
115static struct ebt_mac_wormhash *create_wormhash(const char *arg)
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +0000116{
117 const char *pc = arg;
118 const char *anchor;
gborowiakc50ce6a2003-09-07 13:16:26 +0000119 char *endptr;
120 struct ebt_mac_wormhash *workcopy, *result, *h;
121 unsigned char mac[6];
122 unsigned char ip[4];
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +0000123 int index;
124 int nmacs = 0;
gborowiakc50ce6a2003-09-07 13:16:26 +0000125 int i;
126 char token[4];
127 if (!(workcopy = new_wormhash(1024))) {
128 print_error("memory problem");
129 }
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +0000130 while (1) {
gborowiakc50ce6a2003-09-07 13:16:26 +0000131 /* remember current position, we'll need it on error */
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +0000132 anchor = pc;
gborowiakc50ce6a2003-09-07 13:16:26 +0000133
134 /* collect MAC; all its bytes are followed by ':' (colon), except for
135 * the last one which can be followed by ',' (comma), '=' or '\0' */
136 for (i = 0; i < 5; i++) {
137 if (read_until(&pc, ":", token, 2) < 0 || token[0] == 0) {
138 print_error("MAC parse error: %.20s", anchor);
139 }
140 mac[i] = strtol(token, &endptr, 16);
141 if (*endptr) {
142 print_error("MAC parse error: %.20s", anchor);
143 }
144 pc++;
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +0000145 }
gborowiakc50ce6a2003-09-07 13:16:26 +0000146 if (read_until(&pc, "=,", token, 2) == -2 || token[0] == 0) {
147 print_error("MAC parse error: %.20s", anchor);
148 }
149 mac[i] = strtol(token, &endptr, 16);
150 if (*endptr) {
151 print_error("MAC parse error: %.20s", anchor);
152 }
153 if (*pc == '=') {
154 /* an IP follows the MAC; collect similarly to MAC */
155 pc++;
156 anchor = pc;
157 for (i = 0; i < 3; i++) {
158 if (read_until(&pc, ".", token, 3) < 0 || token[0] == 0) {
159 print_error("IP parse error: %.20s", anchor);
160 }
161 ip[i] = strtol(token, &endptr, 10);
162 if (*endptr) {
163 print_error("IP parse error: %.20s", anchor);
164 }
165 pc++;
166 }
167 if (read_until(&pc, ",", token, 3) == -2 || token[0] == 0) {
168 print_error("IP parse error: %.20s", anchor);
169 }
170 ip[3] = strtol(token, &endptr, 10);
171 if (*endptr) {
172 print_error("IP parse error: %.20s", anchor);
173 }
174 }
175 else {
176 /* no IP, we set it to 0.0.0.0 */
177 memset(ip, 0, 4);
178 }
179
180 /* we have collected MAC and IP, so we add an entry */
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +0000181 index = (unsigned char)mac[5];
gborowiakc50ce6a2003-09-07 13:16:26 +0000182 memcpy(((char*)workcopy->pool[nmacs].cmp)+2, mac, 6);
183 workcopy->pool[nmacs].ip = *(const uint32_t*)ip;
184 workcopy->pool[nmacs].next_ofs = workcopy->table[index];
185 workcopy->table[index] = ((const char*)&workcopy->pool[nmacs]) - (const char*)workcopy;
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +0000186 nmacs++;
gborowiakc50ce6a2003-09-07 13:16:26 +0000187
188 /* re-allocate memory if needed */
189 if (*pc && nmacs >= workcopy->poolsize) {
190 if (!(h = new_wormhash(nmacs * 2))) {
191 print_error("memory problem");
192 }
193 copy_wormhash(h, workcopy);
194 free(workcopy);
195 workcopy = h;
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +0000196 }
gborowiakc50ce6a2003-09-07 13:16:26 +0000197
198 /* check if end of string was reached */
199 if (!*pc) {
200 break;
201 }
202
203 /* now `pc' points to comma if we are here; increment this to the next char */
204 /* but first assert :-> */
205 if (*pc != ',') {
206 print_error("Something went wrong; no comma...\n");
207 }
208 pc++;
209
210 /* again check if end of string was reached; we allow an ending comma */
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +0000211 if (!*pc) {
212 break;
213 }
214 }
gborowiakc50ce6a2003-09-07 13:16:26 +0000215 if (!(result = new_wormhash(nmacs))) {
216 print_error("memory problem");
217 }
218 copy_wormhash(result, workcopy);
219 free(workcopy);
220 return result;
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +0000221}
222
223#define OPT_DST 0x01
224#define OPT_SRC 0x02
225static int parse(int c, char **argv, int argc, const struct ebt_u_entry *entry,
226 unsigned int *flags, struct ebt_entry_match **match)
227{
gborowiakc50ce6a2003-09-07 13:16:26 +0000228 struct ebt_among_info *info = (struct ebt_among_info *)(*match)->data;
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +0000229 struct ebt_mac_wormhash *wh;
gborowiakc50ce6a2003-09-07 13:16:26 +0000230 struct ebt_entry_match *h;
231 int new_size, old_size;
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +0000232
233 switch (c) {
234 case AMONG_DST:
235 case AMONG_SRC:
gborowiakc50ce6a2003-09-07 13:16:26 +0000236 if (check_inverse(optarg)) {
237 if (c == AMONG_DST)
238 info->bitmask |= EBT_AMONG_DST_NEG;
239 else
240 info->bitmask |= EBT_AMONG_SRC_NEG;
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +0000241 }
242 if (optind > argc)
243 print_error("No MAC list specified\n");
gborowiakc50ce6a2003-09-07 13:16:26 +0000244 wh = create_wormhash(argv[optind - 1]);
245 old_size = sizeof(struct ebt_entry_match) + (**match).match_size;
246 h = malloc((new_size = old_size + ebt_mac_wormhash_size(wh)));
247 memcpy(h, *match, old_size);
248 memcpy((char*)h + old_size, wh, ebt_mac_wormhash_size(wh));
249 h->match_size = new_size - sizeof(struct ebt_entry_match);
250 info = (struct ebt_among_info *)h->data;
251 if (c == AMONG_DST) {
252 check_option(flags, OPT_DST);
253 info->wh_dst_ofs = old_size - sizeof(struct ebt_entry_match);
254 } else {
255 check_option(flags, OPT_SRC);
256 info->wh_src_ofs = old_size - sizeof(struct ebt_entry_match);
257 }
258 free(*match);
259 *match = h;
260 free(wh);
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +0000261 break;
262 default:
263 return 0;
264 }
265 return 1;
266}
267
268static void final_check(const struct ebt_u_entry *entry,
269 const struct ebt_entry_match *match, const char *name,
270 unsigned int hookmask, unsigned int time)
271{
272}
273
274static void wormhash_printout(const struct ebt_mac_wormhash *wh)
275{
276 int i;
277 int offset;
gborowiakc50ce6a2003-09-07 13:16:26 +0000278 unsigned char *ip;
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +0000279 for (i = 0; i < 256; i++) {
280 const struct ebt_mac_wormhash_tuple *p;
281 offset = wh->table[i];
282 while (offset) {
283 p = (const struct ebt_mac_wormhash_tuple*)((const char*)wh + offset);
gborowiakc50ce6a2003-09-07 13:16:26 +0000284 printf("%s", ether_ntoa((const struct ether_addr *)(((const char*)&p->cmp[0]) + 2)));
285 if (p->ip) {
286 ip = (unsigned char*)&p->ip;
287 printf("=%u.%u.%u.%u", ip[0], ip[1], ip[2], ip[3]);
288 }
289 printf(",");
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +0000290 offset = p->next_ofs;
291 }
292 }
293 printf(" ");
294}
295
296static void print(const struct ebt_u_entry *entry,
297 const struct ebt_entry_match *match)
298{
gborowiakc50ce6a2003-09-07 13:16:26 +0000299 struct ebt_among_info *info = (struct ebt_among_info *)match->data;
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +0000300
gborowiakc50ce6a2003-09-07 13:16:26 +0000301 if (info->wh_dst_ofs) {
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +0000302 printf("--among-dst ");
gborowiakc50ce6a2003-09-07 13:16:26 +0000303 if (info->bitmask && EBT_AMONG_DST_NEG) {
304 printf("! ");
305 }
306 wormhash_printout(ebt_among_wh_dst(info));
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +0000307 }
gborowiakc50ce6a2003-09-07 13:16:26 +0000308 if (info->wh_src_ofs) {
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +0000309 printf("--among-src ");
gborowiakc50ce6a2003-09-07 13:16:26 +0000310 if (info->bitmask && EBT_AMONG_SRC_NEG) {
311 printf("! ");
312 }
313 wormhash_printout(ebt_among_wh_src(info));
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +0000314 }
315}
316
gborowiakc50ce6a2003-09-07 13:16:26 +0000317static int compare_wh(const struct ebt_mac_wormhash *aw, const struct ebt_mac_wormhash *bw)
318{
319 int as, bs;
320 as = ebt_mac_wormhash_size(aw);
321 bs = ebt_mac_wormhash_size(bw);
322 if (as != bs)
323 return 0;
324 if (as && memcmp(aw, bw, as))
325 return 0;
326 return 1;
327}
328
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +0000329static int compare(const struct ebt_entry_match *m1,
330 const struct ebt_entry_match *m2)
331{
gborowiakc50ce6a2003-09-07 13:16:26 +0000332 struct ebt_among_info *a = (struct ebt_among_info *)m1->data;
333 struct ebt_among_info *b = (struct ebt_among_info *)m2->data;
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +0000334
gborowiakc50ce6a2003-09-07 13:16:26 +0000335 if (!compare_wh(ebt_among_wh_dst(a), ebt_among_wh_dst(b))) return 0;
336 if (!compare_wh(ebt_among_wh_src(a), ebt_among_wh_src(b))) return 0;
337 if (a->bitmask != b->bitmask) return 0;
338 return 1;
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +0000339}
340
341static struct ebt_u_match among_match =
342{
343 EBT_AMONG_MATCH,
344 sizeof(struct ebt_among_info),
345 print_help,
346 init,
347 parse,
348 final_check,
349 print,
350 compare,
351 opts
352};
353
354static void _init(void) __attribute__ ((constructor));
355static void _init(void)
356{
357 register_match(&among_match);
358}