blob: dddb6233a0db4944654cf1f13e2c3db2ac923e94 [file] [log] [blame]
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001/*
2 * ebtables.c, v2.0 April 2002
3 *
4 * Author: Bart De Schuymer
5 *
6 * This code is stongly inspired on the iptables code which is
7 * Copyright (C) 1999 Paul `Rusty' Russell & Michael J. Neuling
8 *
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License as
11 * published by the Free Software Foundation; either version 2 of the
12 * License, or (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 */
23
24#include <getopt.h>
25#include <string.h>
26#include <errno.h>
27#include <stdio.h>
28#include <stdlib.h>
29#include <sys/socket.h>
30#include <sys/types.h>
31#include <linux/netfilter_bridge/ebtables.h>
32#include <linux/br_db.h> // the database
33#include <netinet/in.h>
Bart De Schuymer41830412002-06-05 19:41:28 +000034#include <netinet/ether.h>
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000035#include <asm/types.h>
36#include "include/ebtables_u.h"
37
38// here are the number-name correspondences kept for the ethernet
39// frame type field
40#define PROTOCOLFILE "/etc/ethertypes"
41
42#define DATABASEHOOKNR NF_BR_NUMHOOKS
43#define DATABASEHOOKNAME "DB"
44
45static char *prog_name = PROGNAME;
46static char *prog_version = PROGVERSION;
47char* hooknames[NF_BR_NUMHOOKS] = {
48 [NF_BR_PRE_ROUTING]"PREROUTING",
49 [NF_BR_LOCAL_IN]"INPUT",
50 [NF_BR_FORWARD]"FORWARD",
51 [NF_BR_LOCAL_OUT]"OUTPUT",
52 [NF_BR_POST_ROUTING]"POSTROUTING",
53 [NF_BR_BROUTING]"BROUTING"
54};
55
56// default command line options
57static struct option ebt_original_options[] = {
58 { "append" , required_argument, 0, 'A' },
59 { "insert" , required_argument, 0, 'I' },
60 { "delete" , required_argument, 0, 'D' },
61 { "list" , optional_argument, 0, 'L' },
62 { "zero" , optional_argument, 0, 'Z' },
63 { "flush" , optional_argument, 0, 'F' },
64 { "policy" , required_argument, 0, 'P' },
65 { "in-interface" , required_argument, 0, 'i' },
66 { "in-if" , required_argument, 0, 'i' },
67 { "logical-in" , required_argument, 0, 2 },
68 { "logical-out" , required_argument, 0, 3 },
69 { "out-interface" , required_argument, 0, 'o' },
70 { "out-if" , required_argument, 0, 'o' },
71 { "version" , no_argument , 0, 'V' },
72 { "help" , no_argument , 0, 'h' },
73 { "jump" , required_argument, 0, 'j' },
74 { "proto" , required_argument, 0, 'p' },
75 { "protocol" , required_argument, 0, 'p' },
76 { "db" , required_argument, 0, 'b' },
77 { "source" , required_argument, 0, 's' },
78 { "src" , required_argument, 0, 's' },
79 { "destination" , required_argument, 0, 'd' },
80 { "dst" , required_argument, 0, 'd' },
81 { "table" , required_argument, 0, 't' },
82 { 0 }
83};
84
85static struct option *ebt_options = ebt_original_options;
86
87// yup, all the possible target names
88char* standard_targets[NUM_STANDARD_TARGETS] = {
89 "ACCEPT",
90 "DROP",
91 "CONTINUE",
92};
93
94unsigned char mac_type_unicast[ETH_ALEN] = {0,0,0,0,0,0};
95unsigned char msk_type_unicast[ETH_ALEN] = {1,0,0,0,0,0};
96unsigned char mac_type_multicast[ETH_ALEN] = {1,0,0,0,0,0};
97unsigned char msk_type_multicast[ETH_ALEN] = {1,0,0,0,0,0};
98unsigned char mac_type_broadcast[ETH_ALEN] = {255,255,255,255,255,255};
99unsigned char msk_type_broadcast[ETH_ALEN] = {255,255,255,255,255,255};
100
101// tells what happened to the old rules
102static unsigned short *counterchanges;
103// holds all the data
104static struct ebt_u_replace replace;
105
106// the chosen table
107static struct ebt_u_table *table = NULL;
108// the lists of supported tables, matches, watchers and targets
109static struct ebt_u_table *tables = NULL;
110static struct ebt_u_match *matches = NULL;
111static struct ebt_u_watcher *watchers = NULL;
112static struct ebt_u_target *targets = NULL;
113
114struct ebt_u_target *find_target(const char *name)
115{
116 struct ebt_u_target *t = targets;
117
118 while(t && strcmp(t->name, name))
119 t = t->next;
120 return t;
121}
122
123struct ebt_u_match *find_match(const char *name)
124{
125 struct ebt_u_match *m = matches;
126
127 while(m && strcmp(m->name, name))
128 m = m->next;
129 return m;
130}
131
132struct ebt_u_watcher *find_watcher(const char *name)
133{
134 struct ebt_u_watcher *w = watchers;
135
136 while(w && strcmp(w->name, name))
137 w = w->next;
138 return w;
139}
140
141struct ebt_u_table *find_table(char *name)
142{
143 struct ebt_u_table *t = tables;
144
145 while (t && strcmp(t->name, name))
146 t = t->next;
147 return t;
148}
149
150// The pointers in here are special:
151// The struct ebt_target * pointer is actually a struct ebt_u_target * pointer.
152// instead of making yet a few other structs, we just do a cast.
153// We need a struct ebt_u_target pointer because we know the address of the data
154// they point to won't change. We want to allow that the struct ebt_u_target.t
155// member can change.
156// Same holds for the struct ebt_match and struct ebt_watcher pointers
157struct ebt_u_entry *new_entry;
158
159void initialize_entry(struct ebt_u_entry *e)
160{
161 e->bitmask = EBT_NOPROTO;
162 e->invflags = 0;
163 e->ethproto = 0;
164 strcpy(e->in, "");
165 strcpy(e->out, "");
166 strcpy(e->logical_in, "");
167 strcpy(e->logical_out, "");
168 e->m_list = NULL;
169 e->w_list = NULL;
170 // the init function of the standard target should have put the verdict
171 // on CONTINUE
172 e->t = (struct ebt_entry_target *)find_target(EBT_STANDARD_TARGET);
173 if (!e->t)
174 print_bug("Couldn't load standard target\n");
175}
176
177// this doesn't free e, becoz the calling function might need e->next
178void free_u_entry(struct ebt_u_entry *e)
179{
180 struct ebt_u_match_list *m_l, *m_l2;
181 struct ebt_u_watcher_list *w_l, *w_l2;
182
183 m_l = e->m_list;
184 while (m_l) {
185 m_l2 = m_l->next;
186 free(m_l->m);
187 free(m_l);
188 m_l = m_l2;
189 }
190 w_l = e->w_list;
191 while (w_l) {
192 w_l2 = w_l->next;
193 free(w_l->w);
194 free(w_l);
195 w_l = w_l2;
196 }
197 free(e->t);
198}
199
200// the user will use the match, so put it in new_entry
201static void add_match(struct ebt_u_match *m)
202{
203 struct ebt_u_match_list **m_list, *new;
204
205 m->used = 1;
206 for (m_list = &new_entry->m_list;
207 *m_list; m_list = &(*m_list)->next);
208 new = (struct ebt_u_match_list *)
209 malloc(sizeof(struct ebt_u_match_list));
210 if (!new)
211 print_memory();
212 *m_list = new;
213 new->next = NULL;
214 new->m = (struct ebt_entry_match *)m;
215}
216
217static void add_watcher(struct ebt_u_watcher *w)
218{
219 struct ebt_u_watcher_list **w_list;
220 struct ebt_u_watcher_list *new;
221
222 w->used = 1;
223 for (w_list = &new_entry->w_list;
224 *w_list; w_list = &(*w_list)->next);
225 new = (struct ebt_u_watcher_list *)
226 malloc(sizeof(struct ebt_u_watcher_list));
227 if (!new)
228 print_memory();
229 *w_list = new;
230 new->next = NULL;
231 new->w = (struct ebt_entry_watcher *)w;
232}
233
234static int global_option_offset = 0;
235#define OPTION_OFFSET 256
236static struct option *
237merge_options(struct option *oldopts, const struct option *newopts,
238 unsigned int *options_offset)
239{
240 unsigned int num_old, num_new, i;
241 struct option *merge;
242
243 if (!newopts || !oldopts || !options_offset)
244 print_bug("merge wrong");
245 for (num_old = 0; oldopts[num_old].name; num_old++);
246 for (num_new = 0; newopts[num_new].name; num_new++);
247
248 global_option_offset += OPTION_OFFSET;
249 *options_offset = global_option_offset;
250
251 merge = malloc(sizeof(struct option) * (num_new + num_old + 1));
252 if (!merge)
253 print_memory();
254 memcpy(merge, oldopts, num_old * sizeof(struct option));
255 for (i = 0; i < num_new; i++) {
256 merge[num_old + i] = newopts[i];
257 merge[num_old + i].val += *options_offset;
258 }
259 memset(merge + num_old + num_new, 0, sizeof(struct option));
260 // only free dynamically allocated stuff
261 if (oldopts != ebt_original_options)
262 free(oldopts);
263
264 return merge;
265}
266
267void register_match(struct ebt_u_match *m)
268{
269 int size = m->size + sizeof(struct ebt_entry_match);
270 struct ebt_u_match **i;
271
272 m->m = (struct ebt_entry_match *)malloc(size);
273 if (!m->m)
274 print_memory();
275 strcpy(m->m->u.name, m->name);
276 m->m->match_size = m->size;
277 ebt_options = merge_options
278 (ebt_options, m->extra_ops, &(m->option_offset));
279 m->init(m->m);
280
281 for (i = &matches; *i; i = &((*i)->next));
282 m->next = NULL;
283 *i = m;
284}
285
286void register_watcher(struct ebt_u_watcher *w)
287{
288 int size = w->size + sizeof(struct ebt_entry_watcher);
289 struct ebt_u_watcher **i;
290
291 w->w = (struct ebt_entry_watcher *)malloc(size);
292 if (!w->w)
293 print_memory();
294 strcpy(w->w->u.name, w->name);
295 w->w->watcher_size = w->size;
296 ebt_options = merge_options
297 (ebt_options, w->extra_ops, &(w->option_offset));
298 w->init(w->w);
299
300 for (i = &watchers; *i; i = &((*i)->next));
301 w->next = NULL;
302 *i = w;
303}
304
305void register_target(struct ebt_u_target *t)
306{
307 int size = t->size + sizeof(struct ebt_entry_target);
308 struct ebt_u_target **i;
309
310 t->t = (struct ebt_entry_target *)malloc(size);
311 if (!t->t)
312 print_memory();
313 strcpy(t->t->u.name, t->name);
314 t->t->target_size = t->size;
315 ebt_options = merge_options
316 (ebt_options, t->extra_ops, &(t->option_offset));
317 t->init(t->t);
318 for (i = &targets; *i; i = &((*i)->next));
319 t->next = NULL;
320 *i = t;
321}
322
323void register_table(struct ebt_u_table *t)
324{
325 t->next = tables;
326 tables = t;
327}
328
329// used to parse /etc/etherproto
330int disregard_whitespace(char *buffer, FILE *ifp)
331{
332 int hlp;
333 buffer[0] = '\t';
334 while (buffer[0] == '\t' || buffer[0] == '\n' || buffer[0] == ' ') {
335 hlp = fscanf(ifp, "%c", buffer);
336 if (hlp == EOF || hlp == 0) return -1;
337 }
338 return 0;
339}
340
341// used to parse /etc/etherproto
342int disregard_tabspace(char *buffer, FILE *ifp)
343{
344 int hlp;
345 buffer[0] = '\t';
346 while (buffer[0] == '\t' || buffer[0] == ' ') {
347 hlp = fscanf(ifp, "%c", buffer);
348 if (hlp == EOF || hlp == 0) return -1;
349 }
350 return 0;
351}
352
Bart De Schuymerbbca3202002-06-05 18:55:44 +0000353// helper function: processes a line of data from the file /etc/ethertypes
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000354int get_a_line(char *buffer, char *value, FILE *ifp)
355{
356 int i, hlp;
357 char anotherhlp;
358
359 /* discard comment lines && whitespace*/
360 while (1) {
361 if (disregard_whitespace(buffer, ifp)) return -1;
362 if (buffer[0] == '#')
363 while (1) {
364 hlp = fscanf(ifp, "%c", &anotherhlp);
365 if (!hlp || hlp == EOF)
366 return -1;
367 if (anotherhlp == '\n')
368 break;
369 }
370 else break;
371 }
372
373 // buffer[0] already contains the first letter
374 for (i = 1; i < 21; i++) {
375 hlp = fscanf(ifp, "%c", buffer + i);
376 if (hlp == EOF || hlp == 0) return -1;
377 if (buffer[i] == '\t' || buffer[i] == ' ')
378 break;
379 }
380 if (i == 21) return -1;
381 buffer[i] = '\0';
382 if (disregard_tabspace(value, ifp))
383 return -1;
384 // maybe I should allow 0x0800 instead of 0800, but I'm feeling lazy
385 // buffer[0] already contains the first letter
386 for (i = 1; i < 5; i++) {
387 hlp = fscanf(ifp, "%c", value+i);
388 if (value[i] == '\n' || value[i] == '\t' ||
389 value[i] == ' ' || hlp == EOF)
390 break;
391 }
392 if (i == 5) return -1;
Bart De Schuymerbbca3202002-06-05 18:55:44 +0000393 // discard comments at the end of a line
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000394 if (value[i] == '\t' || value[i] == ' ')
395 while (1) {
396 hlp = fscanf(ifp, "%c", &anotherhlp);
397 if (!hlp || hlp == EOF || anotherhlp == '\n')
398 break;
399 }
400 value[i] = '\0';
401 return 0;
402}
403
404// helper function for list_em()
405int number_to_name(unsigned short proto, char *name)
406{
407 FILE *ifp;
408 char buffer[21], value[5], *bfr;
409 unsigned short i;
410
411 if ( !(ifp = fopen(PROTOCOLFILE, "r")) )
412 return -1;
413 while (1) {
414 if (get_a_line(buffer, value, ifp)) {
415 fclose(ifp);
416 return -1;
417 }
418 i = (unsigned short) strtol(value, &bfr, 16);
419 if (*bfr != '\0' || i != proto)
420 continue;
421 strcpy(name, buffer);
422 fclose(ifp);
423 return 0;
424 }
425}
426
427// helper function for list_rules()
428static void list_em(int hooknr)
429{
430 int i, j, space = 0, digits;
431 struct ebt_u_entry *hlp;
432 struct ebt_u_match_list *m_l;
433 struct ebt_u_watcher_list *w_l;
434 struct ebt_u_match *m;
435 struct ebt_u_watcher *w;
436 struct ebt_u_target *t;
437 char name[21];
438
439 hlp = replace.hook_entry[hooknr]->entries;
440 printf("\nBridge chain: %s\nPolicy: %s\n", hooknames[hooknr],
441 standard_targets[replace.hook_entry[hooknr]->policy]);
442 printf("nr. of entries: %d \n", replace.hook_entry[hooknr]->nentries);
443
444 i = replace.hook_entry[hooknr]->nentries;
445 while (i >9) {
446 space++;
447 i /= 10;
448 }
449
450 for (i = 0; i < replace.hook_entry[hooknr]->nentries; i++) {
451 digits = 0;
452 // A little work to get nice rule numbers.
453 while (j > 9) {
454 digits++;
455 j /= 10;
456 }
457 for (j = 0; j < space - digits; j++)
458 printf(" ");
459 printf("%d. ", i + 1);
460
461 // Don't print anything about the protocol if no protocol was
462 // specified, obviously this means any protocol will do.
463 if (!(hlp->bitmask & EBT_NOPROTO)) {
464 printf("eth proto: ");
465 if (hlp->invflags & EBT_IPROTO)
466 printf("! ");
467 if (hlp->bitmask & EBT_802_3)
468 printf("Length, ");
469 else {
470 if (number_to_name(ntohs(hlp->ethproto), name))
471 printf("0x%x, ", ntohs(hlp->ethproto));
472 else
473 printf("%s, ", name);
474 }
475 }
476 if (hlp->bitmask & EBT_SOURCEMAC) {
477 char hlpmsk[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
478
479 printf("source mac: ");
480 if (hlp->invflags & EBT_ISOURCE)
481 printf("! ");
482 if (!memcmp(hlp->sourcemac, mac_type_unicast, 6) &&
483 !memcmp(hlp->sourcemsk, msk_type_unicast, 6)) {
484 printf("Unicast");
485 goto endsrc;
486 }
487 if (!memcmp(hlp->sourcemac, mac_type_multicast, 6) &&
488 !memcmp(hlp->sourcemsk, msk_type_multicast, 6)) {
489 printf("Multicast");
490 goto endsrc;
491 }
492 if (!memcmp(hlp->sourcemac, mac_type_broadcast, 6) &&
493 !memcmp(hlp->sourcemsk, msk_type_broadcast, 6)) {
494 printf("Broadcast");
495 goto endsrc;
496 }
Bart De Schuymer41830412002-06-05 19:41:28 +0000497 printf("%s", ether_ntoa((struct ether_addr *)
498 hlp->sourcemac));
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000499 if (memcmp(hlp->sourcemsk, hlpmsk, 6)) {
500 printf("/");
Bart De Schuymer41830412002-06-05 19:41:28 +0000501 printf("%s", ether_ntoa((struct ether_addr *)
502 hlp->sourcemsk));
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000503 }
504endsrc:
505 printf(", ");
506 }
507 if (hlp->bitmask & EBT_DESTMAC) {
508 char hlpmsk[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
509
510 printf("dest mac: ");
511 if (hlp->invflags & EBT_IDEST)
512 printf("! ");
513 if (!memcmp(hlp->destmac, mac_type_unicast, 6) &&
514 !memcmp(hlp->destmsk, msk_type_unicast, 6)) {
515 printf("Unicast");
516 goto enddst;
517 }
518 if (!memcmp(hlp->destmac, mac_type_multicast, 6) &&
519 !memcmp(hlp->destmsk, msk_type_multicast, 6)) {
520 printf("Multicast");
521 goto enddst;
522 }
523 if (!memcmp(hlp->destmac, mac_type_broadcast, 6) &&
524 !memcmp(hlp->destmsk, msk_type_broadcast, 6)) {
525 printf("Broadcast");
526 goto enddst;
527 }
Bart De Schuymer41830412002-06-05 19:41:28 +0000528 printf("%s", ether_ntoa((struct ether_addr *)
529 hlp->destmac));
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000530 if (memcmp(hlp->destmsk, hlpmsk, 6)) {
531 printf("/");
Bart De Schuymer41830412002-06-05 19:41:28 +0000532 printf("%s", ether_ntoa((struct ether_addr *)
533 hlp->destmsk));
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000534 }
535enddst:
536 printf(", ");
537 }
538 if (hlp->in[0] != '\0') {
539 if (hlp->invflags & EBT_IIN)
540 printf("! ");
541 printf("in-if: %s, ", hlp->in);
542 }
543 if (hlp->logical_in[0] != '\0') {
544 if (hlp->invflags & EBT_ILOGICALIN)
545 printf("! ");
546 printf("logical in-if: %s, ", hlp->logical_in);
547 }
548 if (hlp->logical_out[0] != '\0') {
549 if (hlp->invflags & EBT_ILOGICALOUT)
550 printf("! ");
551 printf("logical out-if: %s, ", hlp->logical_out);
552 }
553 if (hlp->out[0] != '\0') {
554 if (hlp->invflags & EBT_IOUT)
555 printf("! ");
556 printf("out-if: %s, ", hlp->out);
557 }
558
559 m_l = hlp->m_list;
560 while (m_l) {
561 m = find_match(m_l->m->u.name);
562 if (!m)
563 print_bug("Match not found");
564 m->print(hlp, m_l->m);
565 m_l = m_l->next;
566 }
567 w_l = hlp->w_list;
568 while (w_l) {
569 w = find_watcher(w_l->w->u.name);
570 if (!w)
571 print_bug("Watcher not found");
572 w->print(hlp, w_l->w);
573 w_l = w_l->next;
574 }
575
576 printf("target: ");
577 t = find_target(hlp->t->u.name);
578 if (!t)
579 print_bug("Target not found");
580 t->print(hlp, hlp->t);
581 printf(", count = %llu",
582 replace.counters[replace.counter_entry[hooknr] + i].pcnt);
583 printf("\n");
584 hlp = hlp->next;
585 }
586}
587
588// parse the chain name and return the corresponding nr
589int get_hooknr(char* arg)
590{
591 int i;
592
593 // database is special case (not really a chain)
594 if (!strcmp(arg, DATABASEHOOKNAME))
595 return DATABASEHOOKNR;
596
597 for (i = 0; i < NF_BR_NUMHOOKS; i++)
598 if (!strcmp(arg, hooknames[i]))
599 return i;
600 return -1;
601}
602
603// yup, print out help
604void print_help()
605{
606 struct ebt_u_match_list *m_l;
607 struct ebt_u_watcher_list *w_l;
608
609 printf(
610"%s v%s\n"
611"Usage:\n"
612"ebtables -[ADI] chain rule-specification [options]\n"
613"ebtables -P chain target\n"
614"ebtables -[LFZ] [chain]\n"
615"ebtables -[b] [y,n]\n"
616"Commands:\n"
617"--append -A chain : Append to chain\n"
618"--delete -D chain : Delete matching rule from chain\n"
619"--delete -D chain rulenum : Delete rule at position rulenum from chain\n"
620"--insert -I chain rulenum : insert rule at position rulenum in chain\n"
621"--list -L [chain] : List the rules in a chain or in all chains\n"
622"--list -L "DATABASEHOOKNAME" : List the database (if present)\n"
623"--flush -F [chain] : Delete all rules in chain or in all chains\n"
624"--zero -Z [chain] : Put counters on zero in chain or in all chains\n"
625"--policy -P chain target : Change policy on chain to target\n"
626"Options:\n"
627"--proto -p [!] proto : protocol hexadecimal, by name or LENGTH\n"
628"--src -s [!] address[/mask]: source mac address\n"
629"--dst -d [!] address[/mask]: destination mac address\n"
630"--in-if -i [!] name : network input interface name\n"
631"--out-if -o [!] name : network output interface name\n"
632"--logical-in [!] name : logical bridge input interface name\n"
633"--logical-out [!] name : logical bridge output interface name\n"
634"--version -V : print package version\n"
635"\n" ,
636 prog_name,
637 prog_version);
638
639 m_l = new_entry->m_list;
640 while (m_l) {
641 ((struct ebt_u_match *)m_l->m)->help();
642 printf("\n");
643 m_l = m_l->next;
644 }
645 w_l = new_entry->w_list;
646 while (w_l) {
647 ((struct ebt_u_watcher *)w_l->w)->help();
648 printf("\n");
649 w_l = w_l->next;
650 }
651 ((struct ebt_u_target *)new_entry->t)->help();
652 printf("\n");
653 if (table->help)
654 table->help(hooknames);
655 exit(0);
656}
657
658// execute command L
659static void list_rules()
660{
661 int i;
662
663 printf("Bridge table: %s\n", table->name);
664 if (replace.selected_hook != -1) list_em(replace.selected_hook);
665 else
666 for (i = 0; i < NF_BR_NUMHOOKS; i++)
667 if (replace.valid_hooks & (1 << i))
668 list_em(i);
669 return;
670}
671
672// execute command P
673static void change_policy(int policy)
674{
675 int i;
676
677 // don't do anything if the policy is the same
678 if (replace.hook_entry[replace.selected_hook]->policy != policy) {
679 replace.hook_entry[replace.selected_hook]->policy = policy;
680 replace.num_counters = replace.nentries;
681 if (replace.nentries) {
682 // '+ 1' for the CNT_END
683 if (!(counterchanges = (unsigned short *) malloc(
684 (replace.nentries + 1) * sizeof(unsigned short))))
685 print_memory();
686 // done nothing special to the rules
687 for (i = 0; i < replace.nentries; i++)
688 counterchanges[i] = CNT_NORM;
689 counterchanges[replace.nentries] = CNT_END;
690 }
691 else
692 counterchanges = NULL;
693 }
694 else
695 exit(0);
696}
697
698// flush one chain or the complete table
699static void flush_chains()
700{
701 int i, j, oldnentries;
702 unsigned short *cnt;
703 struct ebt_u_entry *u_e, *tmp;
704
705 // flush whole table
706 if (replace.selected_hook == -1) {
707 if (replace.nentries == 0)
708 exit(0);
709 replace.nentries = 0;
710 // no need for the kernel to give us counters back
711 replace.num_counters = 0;
712 // free everything and zero (n)entries
713 for (i = 0; i < NF_BR_NUMHOOKS; i++) {
714 if (!(replace.valid_hooks & (1 << i)))
715 continue;
716 replace.hook_entry[i]->nentries = 0;
717 u_e = replace.hook_entry[i]->entries;
718 while (u_e) {
719 free_u_entry(u_e);
720 tmp = u_e->next;
721 free(u_e);
722 u_e = tmp;
723 }
724 replace.hook_entry[i]->entries = NULL;
725 }
726 return;
727 }
728
729 if (replace.hook_entry[replace.selected_hook]->nentries == 0)
730 exit(0);
731 oldnentries = replace.nentries;
732 replace.nentries = replace.nentries -
733 replace.hook_entry[replace.selected_hook]->nentries;
734
735 // delete the counters belonging to the specified chain
736 if (replace.nentries) {
737 // +1 for CNT_END
738 if ( !(counterchanges = (unsigned short *)
739 malloc((oldnentries + 1) * sizeof(unsigned short))) )
740 print_memory();
741 cnt = counterchanges;
742 for (i = 0; i < NF_BR_NUMHOOKS; i++) {
743 if (!(replace.valid_hooks & (1 << i)))
744 continue;
745 for (j = 0; j < replace.hook_entry[i]->nentries; j++) {
746 if (i != replace.selected_hook)
747 *cnt = CNT_NORM;
748 else
749 *cnt = CNT_DEL;
750 cnt++;
751 }
752 }
753 *cnt = CNT_END;
754 replace.num_counters = oldnentries;
755 }
756 else
757 replace.num_counters = 0;
758
759 replace.hook_entry[replace.selected_hook]->nentries = 0;
760 u_e = replace.hook_entry[replace.selected_hook]->entries;
761 while (u_e) {
762 free_u_entry(u_e);
763 tmp = u_e->next;
764 free(u_e);
765 u_e = tmp;
766 }
767 replace.hook_entry[replace.selected_hook]->entries = NULL;
768}
769
770// -1 == no match
771static int check_rule_exists(int rule_nr)
772{
773 struct ebt_u_entry *u_e;
774 struct ebt_u_match_list *m_l, *m_l2;
775 struct ebt_u_match *m;
776 struct ebt_u_watcher_list *w_l, *w_l2;
777 struct ebt_u_watcher *w;
778 struct ebt_u_target *t = (struct ebt_u_target *)new_entry->t;
779 int i, j, k;
780
781 // handle '-D chain rulenr' command
782 if (rule_nr != -1) {
783 if (rule_nr >
784 replace.hook_entry[replace.selected_hook]->nentries)
785 return 0;
786 // user starts counting from 1
787 return rule_nr - 1;
788 }
789 u_e = replace.hook_entry[replace.selected_hook]->entries;
790 // check for an existing rule (if there are duplicate rules,
791 // take the first occurance)
792 for (i = 0; i < replace.hook_entry[replace.selected_hook]->nentries;
793 i++, u_e = u_e->next) {
794 if (!u_e)
795 print_bug("Hmm, trouble");
796 if ( u_e->ethproto == new_entry->ethproto
797 && !strcmp(u_e->in, new_entry->in)
798 && !strcmp(u_e->out, new_entry->out)
799 && u_e->bitmask == new_entry->bitmask) {
800 if (new_entry->bitmask & EBT_SOURCEMAC &&
801 strcmp(u_e->sourcemac, new_entry->sourcemac))
802 continue;
803 if (new_entry->bitmask & EBT_DESTMAC &&
804 strcmp(u_e->destmac, new_entry->destmac))
805 continue;
806 if (new_entry->bitmask != u_e->bitmask ||
807 new_entry->invflags != u_e->invflags)
808 continue;
809 // compare all matches
810 m_l = new_entry->m_list;
811 j = 0;
812 while (m_l) {
813 m = (struct ebt_u_match *)(m_l->m);
814 m_l2 = u_e->m_list;
815 while (m_l2 &&
816 strcmp(m_l2->m->u.name, m->m->u.name))
817 m_l2 = m_l2->next;
818 if (!m_l2 || !m->compare(m->m, m_l2->m))
819 goto letscontinue;
820 j++;
821 m_l = m_l->next;
822 }
823 // now be sure they have the same nr of matches
824 k = 0;
825 m_l = u_e->m_list;
826 while (m_l) {
827 k++;
828 m_l = m_l->next;
829 }
830 if (j != k)
831 continue;
832
833 // compare all watchers
834 w_l = new_entry->w_list;
835 j = 0;
836 while (w_l) {
837 w = (struct ebt_u_watcher *)(w_l->w);
838 w_l2 = u_e->w_list;
839 while (w_l2 &&
840 strcmp(w_l2->w->u.name, w->w->u.name))
841 w_l2 = w_l2->next;
842 if (!w_l2 || !w->compare(w->w, w_l2->w))
843 goto letscontinue;
844 j++;
845 w_l = w_l->next;
846 }
847 k = 0;
848 w_l = u_e->w_list;
849 while (w_l) {
850 k++;
851 w_l = w_l->next;
852 }
853 if (j != k)
854 continue;
855 if (strcmp(t->t->u.name, u_e->t->u.name))
856 continue;
857 if (!t->compare(t->t, u_e->t))
858 continue;
859 return i;
860 }
861letscontinue:
862 }
863 return -1;
864}
865
866// execute command A
867static void add_rule(int rule_nr)
868{
869 int i, j;
870 struct ebt_u_entry *u_e, *u_e2;
871 unsigned short *cnt;
872 struct ebt_u_match_list *m_l;
873 struct ebt_u_watcher_list *w_l;
874
875 if (rule_nr != -1) { // command -I
876 if (--rule_nr >
877 replace.hook_entry[replace.selected_hook]->nentries)
878 print_error("rule nr too high: %d > %d", rule_nr,
879 replace.hook_entry[replace.selected_hook]->nentries);
880 } else
881 rule_nr = replace.hook_entry[replace.selected_hook]->nentries;
882 // we're adding one rule
883 replace.num_counters = replace.nentries;
884 replace.nentries++;
885 replace.hook_entry[replace.selected_hook]->nentries++;
886
887 // handle counter stuff
888 // +1 for CNT_END
889 if ( !(counterchanges = (unsigned short *)
890 malloc((replace.nentries + 1) * sizeof(unsigned short))) )
891 print_memory();
892 cnt = counterchanges;
893 for (i = 0; i < replace.selected_hook; i++) {
894 if (!(replace.valid_hooks & (1 << i)))
895 continue;
896 for (j = 0; j < replace.hook_entry[i]->nentries; j++) {
897 *cnt = CNT_NORM;
898 cnt++;
899 }
900 }
901 for (i = 0; i < rule_nr; i++) {
902 *cnt = CNT_NORM;
903 cnt++;
904 }
905 *cnt = CNT_ADD;
906 cnt++;
907 while (cnt != counterchanges + replace.nentries) {
908 *cnt = CNT_NORM;
909 cnt++;
910 }
911 *cnt = CNT_END;
912
913 // go to the right position in the chain
914 u_e2 = NULL;
915 u_e = replace.hook_entry[replace.selected_hook]->entries;
916 for (i = 0; i < rule_nr; i++) {
917 u_e2 = u_e;
918 u_e = u_e->next;
919 }
920 // insert the rule
921 if (u_e2)
922 u_e2->next = new_entry;
923 else
924 replace.hook_entry[replace.selected_hook]->entries = new_entry;
925 new_entry->next = u_e;
926
927 // put the ebt_[match, watcher, target] pointers in place
928 m_l = new_entry->m_list;
929 while (m_l) {
930 m_l->m = ((struct ebt_u_match *)m_l->m)->m;
931 m_l = m_l->next;
932 }
933 w_l = new_entry->w_list;
934 while (w_l) {
935 w_l->w = ((struct ebt_u_watcher *)w_l->w)->w;
936 w_l = w_l->next;
937 }
938 new_entry->t = ((struct ebt_u_target *)new_entry->t)->t;
939}
940
941// execute command D
942static void delete_rule(int rule_nr)
943{
944 int i, j, lentmp = 0;
945 unsigned short *cnt;
946 struct ebt_u_entry *u_e, *u_e2;
947
948 if ( (i = check_rule_exists(rule_nr)) == -1 )
949 print_error("Sorry, rule does not exists");
950
951 // we're deleting a rule
952 replace.num_counters = replace.nentries;
953 replace.nentries--;
954
955 if (replace.nentries) {
956 for (j = 0; j < replace.selected_hook; j++) {
957 if (!(replace.valid_hooks & (1 << j)))
958 continue;
959 lentmp += replace.hook_entry[j]->nentries;
960 }
961 lentmp += i;
962 // +1 for CNT_END
963 if ( !(counterchanges = (unsigned short *)malloc(
964 (replace.num_counters + 1) * sizeof(unsigned short))) )
965 print_memory();
966 cnt = counterchanges;
967 for (j = 0; j < lentmp; j++) {
968 *cnt = CNT_NORM;
969 cnt++;
970 }
971 *cnt = CNT_DEL;
972 cnt++;
973 for (j = 0; j < replace.num_counters - lentmp; j++) {
974 *cnt = CNT_NORM;
975 cnt++;
976 }
977 *cnt = CNT_END;
978 }
979 else
980 replace.num_counters = 0;
981
982 // go to the right position in the chain
983 u_e2 = NULL;
984 u_e = replace.hook_entry[replace.selected_hook]->entries;
985 for (j = 0; j < i; j++) {
986 u_e2 = u_e;
987 u_e = u_e->next;
988 }
989
990 // remove from the chain
991 if (u_e2)
992 u_e2->next = u_e->next;
993 else
994 replace.hook_entry[replace.selected_hook]->entries = u_e->next;
995
996 replace.hook_entry[replace.selected_hook]->nentries--;
997 // free everything
998 free_u_entry(u_e);
999 free(u_e);
1000}
1001
1002// execute command Z
1003void zero_counters(int zerochain)
1004{
1005
1006 if (zerochain == -1) {
1007 // tell main() we don't update the counters
1008 // this results in tricking the kernel to zero his counters,
1009 // naively expecting userspace to update its counters. Muahahaha
1010 counterchanges = NULL;
1011 replace.num_counters = 0;
1012 } else {
1013 int i, j;
1014 unsigned short *cnt;
1015
1016 if (replace.hook_entry[zerochain]->nentries == 0)
1017 exit(0);
1018 counterchanges = (unsigned short *)
1019 malloc((replace.nentries + 1) * sizeof(unsigned short));
1020 if (!counterchanges)
1021 print_memory();
1022 cnt = counterchanges;
1023 for (i = 0; i < zerochain; i++) {
1024 if (!(replace.valid_hooks & (1 << i)))
1025 continue;
1026 for (j = 0; j < replace.hook_entry[i]->nentries; j++) {
1027 *cnt = CNT_NORM;
1028 cnt++;
1029 }
1030 }
1031 for (i = 0; i < replace.hook_entry[zerochain]->nentries; i++) {
1032 *cnt = CNT_ZERO;
1033 cnt++;
1034 }
1035 while (cnt != counterchanges + replace.nentries) {
1036 *cnt = CNT_NORM;
1037 cnt++;
1038 }
1039 *cnt = CNT_END;
1040 }
1041}
1042
1043// list the database (optionally compiled into the kernel)
1044static void list_db()
1045{
1046 struct brdb_dbinfo nr;
1047 struct brdb_dbentry *db;
1048 char name[21];
1049 int i;
1050
1051 get_dbinfo(&nr);
1052
1053 // 0 : database disabled (-db n)
1054 if (!(nr.nentries))
1055 print_error("Database not present"
1056 " (disabled), try ebtables --db y");
1057 nr.nentries--;
1058 if (!nr.nentries) print_error("Database empty");
1059 if ( !(db = (struct brdb_dbentry *)
1060 malloc(nr.nentries * sizeof(struct brdb_dbentry))) )
1061 print_memory();
1062
1063 get_db(nr.nentries, db);
1064 printf("number of entries: %d\n", nr.nentries);
1065 for (i = 0; i < nr.nentries; i++) {
1066 printf(
1067 "%d:\n"
1068 "hook : %s\n"
1069 "in-if : %s\n"
1070 "out-if : %s\n"
1071 "protocol: ", i + 1, hooknames[db->hook], db->in, db->out);
1072 if (db->ethproto == IDENTIFY802_3)
1073 printf("802.2/802.3 STYLE LENGTH FIELD\n");
1074 else {
1075 if (number_to_name(ntohs(db->ethproto), name))
1076 printf("%x\n",ntohs(db->ethproto));
1077 else
1078 printf("%s\n", name);
1079 }
1080 db++;
1081 }
1082 exit(0);
1083}
1084
1085// handle db [dis,en]abling
1086static void allowdb(char yorn)
1087{
1088 __u16 decision;
1089
1090 if (yorn != 'y' && yorn != 'n')
1091 print_error("Option [y] or [n] needed");
1092
1093 if (yorn == 'y')
1094 decision = BRDB_DB;
1095 else
1096 decision = BRDB_NODB;
1097
1098 deliver_allowdb(&decision);
1099
1100 exit(0);
1101}
1102
1103// set ethproto
1104int name_to_protocol(char *name)
1105{
1106 FILE *ifp;
1107 char buffer[21], value[5], *bfr;
1108 unsigned short i;
1109
1110 if (!strcasecmp("LENGTH", name)) {
1111 new_entry->ethproto = 0;
1112 new_entry->bitmask |= EBT_802_3;
1113 return 1;
1114 }
1115 if ( !(ifp = fopen(PROTOCOLFILE, "r")) )
1116 return -1;
1117 while (1) {
1118 if (get_a_line(buffer, value, ifp)) return -1;
1119 if (strcasecmp(buffer, name))
1120 continue;
1121 i = (unsigned short) strtol(value, &bfr, 16);
1122 if (*bfr != '\0')
1123 return -1;
1124 new_entry->ethproto = i;
1125 fclose(ifp);
1126 return 0;
1127 }
1128 return -1;
1129}
1130
1131// put the mac address into 6 (ETH_ALEN) bytes
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001132int getmac_and_mask(char *from, char *to, char *mask)
1133{
1134 char *p;
1135 int i;
Bart De Schuymer41830412002-06-05 19:41:28 +00001136 struct ether_addr *addr;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001137
1138 if (strcasecmp(from, "Unicast") == 0) {
1139 memcpy(to, mac_type_unicast, ETH_ALEN);
1140 memcpy(mask, msk_type_unicast, ETH_ALEN);
1141 return 0;
1142 }
1143 if (strcasecmp(from, "Multicast") == 0) {
1144 memcpy(to, mac_type_multicast, ETH_ALEN);
1145 memcpy(mask, msk_type_multicast, ETH_ALEN);
1146 return 0;
1147 }
1148 if (strcasecmp(from, "Broadcast") == 0) {
1149 memcpy(to, mac_type_broadcast, ETH_ALEN);
1150 memcpy(mask, msk_type_broadcast, ETH_ALEN);
1151 return 0;
1152 }
1153 if ( (p = strrchr(from, '/')) != NULL) {
1154 *p = '\0';
Bart De Schuymer41830412002-06-05 19:41:28 +00001155 if (!(addr = ether_aton(p + 1)))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001156 return -1;
Bart De Schuymer41830412002-06-05 19:41:28 +00001157 memcpy(mask, addr, ETH_ALEN);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001158 } else
1159 memset(mask, 0xff, ETH_ALEN);
Bart De Schuymer41830412002-06-05 19:41:28 +00001160 if (!(addr = ether_aton(from)))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001161 return -1;
Bart De Schuymer41830412002-06-05 19:41:28 +00001162 memcpy(to, addr, ETH_ALEN);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001163 for (i = 0; i < ETH_ALEN; i++)
1164 to[i] &= mask[i];
1165 return 0;
1166}
1167
1168int check_inverse(const char option[])
1169{
1170 if (strcmp(option, "!") == 0) {
1171 optind++;
1172 return 1;
1173 }
1174 return 0;
1175}
1176
1177void check_option(unsigned int *flags, unsigned int mask)
1178{
1179 if (*flags & mask)
1180 print_error("Multiple use of same option not allowed");
1181 *flags |= mask;
1182}
1183
1184#define OPT_COMMAND 0x01
1185#define OPT_TABLE 0x02
1186#define OPT_IN 0x04
1187#define OPT_OUT 0x08
1188#define OPT_JUMP 0x10
1189#define OPT_PROTOCOL 0x20
1190#define OPT_SOURCE 0x40
1191#define OPT_DEST 0x80
1192#define OPT_ZERO 0x100
1193#define OPT_LOGICALIN 0x200
1194#define OPT_LOGICALOUT 0x400
1195// the main thing
1196int main(int argc, char *argv[])
1197{
1198 char *buffer, allowbc = 'n';
1199 int c, i;
1200 // this special one for the -Z option (we can have -Z <this> -L <that>)
1201 int zerochain = -1;
1202 int policy = -1;
1203 int rule_nr = -1;// used for -D chain number
1204 struct ebt_u_target *t;
1205 struct ebt_u_match *m;
1206 struct ebt_u_watcher *w;
1207 struct ebt_u_match_list *m_l;
1208 struct ebt_u_watcher_list *w_l;
1209
1210 // initialize the table name, OPT_ flags, selected hook and command
1211 strcpy(replace.name, "filter");
1212 replace.flags = 0;
1213 replace.selected_hook = -1;
1214 replace.command = 'h';
1215
1216 new_entry = (struct ebt_u_entry *)malloc(sizeof(struct ebt_u_entry));
1217 if (!new_entry)
1218 print_memory();
1219 // put some sane values in our new entry
1220 initialize_entry(new_entry);
1221
1222 // getopt saves the day
1223 while ((c = getopt_long(argc, argv,
1224 "-A:D:I:L::Z::F::P:Vhi:o:j:p:b:s:d:t:", ebt_options, NULL)) != -1) {
1225 switch (c) {
1226
1227 case 'A': // add a rule
1228 case 'D': // delete a rule
1229 case 'P': // define policy
1230 case 'I': // insert a rule
1231 replace.command = c;
1232 if (replace.flags & OPT_COMMAND)
1233 print_error("Multiple commands not allowed");
1234 replace.flags |= OPT_COMMAND;
1235 if ((replace.selected_hook = get_hooknr(optarg)) == -1)
1236 print_error("Bad chain");
1237 if (c == 'D' && optind < argc &&
1238 argv[optind][0] != '-') {
1239 rule_nr = strtol(argv[optind], &buffer, 10);
1240 if (*buffer != '\0' || rule_nr < 0)
1241 print_error("Problem with the "
1242 "specified rule number");
1243 optind++;
1244 }
1245 if (c == 'P') {
1246 if (optind >= argc)
1247 print_error("No policy specified");
1248 for (i = 0; i < 2; i++)
1249 if (!strcmp(argv[optind],
1250 standard_targets[i])) {
1251 policy = i;
1252 break;
1253 }
1254 if (policy == -1)
1255 print_error("Wrong policy");
1256 optind++;
1257 }
1258 if (c == 'I') {
1259 if (optind >= argc)
1260 print_error("No rulenr for -I"
1261 " specified");
1262 rule_nr = strtol(argv[optind], &buffer, 10);
1263 if (*buffer != '\0' || rule_nr < 0)
1264 print_error("Problem with the specified"
1265 " rule number");
1266 optind++;
1267 }
1268 break;
1269
1270 case 'L': // list
1271 case 'F': // flush
1272 case 'Z': // zero counters
1273 if (c == 'Z') {
1274 if (replace.flags & OPT_ZERO)
1275 print_error("Multiple commands"
1276 " not allowed");
1277 if ( (replace.flags & OPT_COMMAND &&
1278 replace.command != 'L'))
1279 print_error("command -Z only allowed "
1280 "together with command -L");
1281 replace.flags |= OPT_ZERO;
1282 } else {
1283 replace.command = c;
1284 if (replace.flags & OPT_COMMAND)
1285 print_error("Multiple commands"
1286 " not allowed");
1287 replace.flags |= OPT_COMMAND;
1288 }
1289 i = -1;
1290 if (optarg) {
1291 if ( (i = get_hooknr(optarg)) == -1 )
1292 print_error("Bad chain");
1293 } else
1294 if (optind < argc && argv[optind][0] != '-') {
1295 if ((i = get_hooknr(argv[optind]))
1296 == -1)
1297 print_error("Bad chain");
1298 optind++;
1299 }
1300 if (i != -1) {
1301 if (c == 'Z')
1302 zerochain = i;
1303 else
1304 replace.selected_hook = i;
1305 }
1306 break;
1307
1308 case 'V': // version
1309 replace.command = 'V';
1310 if (replace.flags & OPT_COMMAND)
1311 print_error("Multiple commands not allowed");
1312 printf("%s, %s\n", prog_name, prog_version);
1313 exit(0);
1314
1315 case 'h': // help
1316 if (replace.flags & OPT_COMMAND)
1317 print_error("Multiple commands not allowed");
1318 replace.command = 'h';
1319 // All other arguments should be extension names
1320 while (optind < argc) {
1321 struct ebt_u_match *m;
1322 struct ebt_u_watcher *w;
1323
1324 if ((m = find_match(argv[optind])))
1325 add_match(m);
1326 else if ((w = find_watcher(argv[optind])))
1327 add_watcher(w);
1328 else {
1329 if (!(t = find_target(argv[optind])))
1330 print_error("Extension %s "
1331 "not found", argv[optind]);
1332 if (replace.flags & OPT_JUMP)
1333 print_error("Sorry, you can "
1334 "only see help for one "
1335 "target extension each time");
1336 replace.flags |= OPT_JUMP;
1337 new_entry->t =
1338 (struct ebt_entry_target *)t;
1339 }
1340 optind++;
1341 }
1342 break;
1343
1344 case 't': // table
1345 check_option(&replace.flags, OPT_TABLE);
1346 if (strlen(optarg) > EBT_TABLE_MAXNAMELEN)
1347 print_error("Table name too long");
1348 strcpy(replace.name, optarg);
1349 break;
1350
1351 case 'i': // input interface
1352 case 2 : // logical input interface
1353 case 'o': // output interface
1354 case 3 : // logical output interface
1355 case 'j': // target
1356 case 'p': // net family protocol
1357 case 's': // source mac
1358 case 'd': // destination mac
1359 if ((replace.flags & OPT_COMMAND) == 0)
1360 print_error("No command specified");
1361 if ( replace.command != 'A' &&
1362 replace.command != 'D' && replace.command != 'I')
1363 print_error("Command and option do not match");
1364 if (c == 'i') {
1365 check_option(&replace.flags, OPT_IN);
1366 if (replace.selected_hook > 2 &&
1367 replace.selected_hook < NF_BR_BROUTING)
1368 print_error("Use in-interface only in "
1369 "INPUT, FORWARD, PREROUTING and"
1370 "BROUTING chains");
1371 if (check_inverse(optarg))
1372 new_entry->invflags |= EBT_IIN;
1373
1374 if (optind > argc)
1375 print_error("No in-interface "
1376 "specified");
1377 if (strlen(argv[optind - 1]) >= IFNAMSIZ)
1378 print_error("Illegal interfacelength");
1379 strcpy(new_entry->in, argv[optind - 1]);
1380 break;
1381 }
1382 if (c == 2) {
1383 check_option(&replace.flags, OPT_LOGICALIN);
1384 if (replace.selected_hook > 2 &&
1385 replace.selected_hook < NF_BR_BROUTING)
1386 print_error("Use logical in-interface "
1387 "only in INPUT, FORWARD, "
1388 "PREROUTING and BROUTING chains");
1389 if (check_inverse(optarg))
1390 new_entry->invflags |= EBT_ILOGICALIN;
1391
1392 if (optind > argc)
1393 print_error("No logical in-interface "
1394 "specified");
1395 if (strlen(argv[optind - 1]) >= IFNAMSIZ)
1396 print_error("Illegal interfacelength");
1397 strcpy(new_entry->logical_in, argv[optind - 1]);
1398 break;
1399 }
1400 if (c == 'o') {
1401 check_option(&replace.flags, OPT_OUT);
1402 if (replace.selected_hook < 2)
1403 print_error("Use out-interface only"
1404 " in OUTPUT, FORWARD and "
1405 "POSTROUTING chains");
1406 if (check_inverse(optarg))
1407 new_entry->invflags |= EBT_IOUT;
1408
1409 if (optind > argc)
1410 print_error("No out-interface "
1411 "specified");
1412
1413 if (strlen(argv[optind - 1]) >= IFNAMSIZ)
1414 print_error("Illegal interface "
1415 "length");
1416 strcpy(new_entry->out, argv[optind - 1]);
1417 break;
1418 }
1419 if (c == 3) {
1420 check_option(&replace.flags, OPT_LOGICALOUT);
1421 if (replace.selected_hook < 2)
1422 print_error("Use logical out-interface "
1423 "only in OUTPUT, FORWARD and "
1424 "POSTROUTING chains");
1425 if (check_inverse(optarg))
1426 new_entry->invflags |= EBT_ILOGICALOUT;
1427
1428 if (optind > argc)
1429 print_error("No logical out-interface "
1430 "specified");
1431
1432 if (strlen(argv[optind - 1]) >= IFNAMSIZ)
1433 print_error("Illegal interface "
1434 "length");
1435 strcpy(new_entry->logical_out,
1436 argv[optind - 1]);
1437 break;
1438 }
1439 if (c == 'j') {
1440
1441 check_option(&replace.flags, OPT_JUMP);
1442 for (i = 0; i < NUM_STANDARD_TARGETS; i++)
1443 if (!strcmp(optarg,
1444 standard_targets[i])) {
1445 t = find_target(
1446 EBT_STANDARD_TARGET);
1447 ((struct ebt_standard_target *)
1448 t->t)->verdict = i;
1449 break;
1450 }
1451 // must be an extension then
1452 if (i == NUM_STANDARD_TARGETS) {
1453 struct ebt_u_target *t;
1454 t = find_target(optarg);
1455 // -j standard not allowed either
1456 if (!t || t ==
1457 (struct ebt_u_target *)new_entry->t)
1458 print_error("Illegal target "
1459 "name");
1460 new_entry->t =
1461 (struct ebt_entry_target *)t;
1462 }
1463 break;
1464 }
1465 if (c == 's') {
1466 check_option(&replace.flags, OPT_SOURCE);
1467 if (check_inverse(optarg))
1468 new_entry->invflags |= EBT_ISOURCE;
1469
1470 if (optind > argc)
1471 print_error("No source mac "
1472 "specified");
1473 if (getmac_and_mask(argv[optind - 1],
1474 new_entry->sourcemac, new_entry->sourcemsk))
1475 print_error("Problem with specified "
1476 "source mac");
1477 new_entry->bitmask |= EBT_SOURCEMAC;
1478 break;
1479 }
1480 if (c == 'd') {
1481 check_option(&replace.flags, OPT_DEST);
1482 if (check_inverse(optarg))
1483 new_entry->invflags |= EBT_IDEST;
1484
1485 if (optind > argc)
1486 print_error("No destination mac "
1487 "specified");
1488 if (getmac_and_mask(argv[optind - 1],
1489 new_entry->destmac, new_entry->destmsk))
1490 print_error("Problem with specified "
1491 "destination mac");
1492 new_entry->bitmask |= EBT_DESTMAC;
1493 break;
1494 }
1495 check_option(&replace.flags, OPT_PROTOCOL);
1496 if (check_inverse(optarg))
1497 new_entry->invflags |= EBT_IPROTO;
1498
1499 if (optind > argc)
1500 print_error("No protocol specified");
1501 new_entry->bitmask &= ~((unsigned int)EBT_NOPROTO);
1502 i = strtol(argv[optind - 1], &buffer, 16);
1503 if (*buffer == '\0' && (i < 0 || i > 0xFFFF))
1504 print_error("Problem with the specified "
1505 "protocol");
1506 new_entry->ethproto = i;
1507 if (*buffer != '\0')
1508 if (name_to_protocol(argv[optind - 1]) == -1)
1509 print_error("Problem with the specified"
1510 " protocol");
1511 if (new_entry->ethproto < 1536 &&
1512 !(new_entry->bitmask & EBT_802_3))
1513 print_error("Sorry, protocols have values above"
1514 " or equal to 1536 (0x0600)");
1515 break;
1516
1517 case 'b': // allow database?
1518 if (replace.flags & OPT_COMMAND)
1519 print_error("Multiple commands not allowed");
1520 replace.command = c;
1521 allowbc = *optarg;
1522 break;
1523
1524 default:
1525
1526 // is it a target option?
1527 t = (struct ebt_u_target *)new_entry->t;
1528 if ((t->parse(c - t->option_offset, argv, argc,
1529 new_entry, &t->flags, &t->t)))
1530 continue;
1531
1532 // is it a match_option?
1533 for (m = matches; m; m = m->next)
1534 if (m->parse(c - m->option_offset, argv,
1535 argc, new_entry, &m->flags, &m->m))
1536 break;
1537
1538 if (m != NULL) {
1539 if (m->used == 0)
1540 add_match(m);
1541 continue;
1542 }
1543
1544 // is it a watcher option?
1545 for (w = watchers; w; w = w->next)
1546 if (w->parse(c-w->option_offset, argv,
1547 argc, new_entry, &w->flags, &w->w))
1548 break;
1549
1550 if (w == NULL)
1551 print_error("Unknown argument");
1552 if (w->used == 0)
1553 add_watcher(w);
1554 }
1555 }
1556
1557 // database stuff before ebtables stuff
1558 if (replace.command == 'b')
1559 allowdb(allowbc);
1560 if (replace.command == 'L' && replace.selected_hook == DATABASEHOOKNR)
1561 list_db();
1562
1563 if ( (replace.flags & OPT_COMMAND) && replace.command != 'L' &&
1564 replace.flags & OPT_ZERO )
1565 print_error("Command -Z only allowed together with command -L");
1566
1567 if (replace.command == 'A' || replace.command == 'I' ||
1568 replace.command == 'D') {
1569 if (replace.selected_hook == -1)
1570 print_error("Not enough information");
1571 }
1572
1573 if ( !(table = find_table(replace.name)) )
1574 print_error("Bad table name");
1575
1576 // do this after parsing everything, so we can print specific info
1577 if (replace.command == 'h' && !(replace.flags & OPT_ZERO))
1578 print_help();
1579
1580 // do the final checks
1581 m_l = new_entry->m_list;
1582 w_l = new_entry->w_list;
1583 t = (struct ebt_u_target *)new_entry->t;
1584 while (m_l) {
1585 m = (struct ebt_u_match *)(m_l->m);
1586 m->final_check(new_entry, m->m, replace.name,
1587 replace.selected_hook);
1588 m_l = m_l->next;
1589 }
1590 while (w_l) {
1591 w = (struct ebt_u_watcher *)(w_l->w);
1592 w->final_check(new_entry, w->w, replace.name,
1593 replace.selected_hook);
1594 w_l = w_l->next;
1595 }
1596 t->final_check(new_entry, t->t, replace.name, replace.selected_hook);
1597
1598 // so, the extensions can work with the host endian
1599 // the kernel does not have to do this ofcourse
1600 new_entry->ethproto = htons(new_entry->ethproto);
1601
1602 // get the kernel's information
1603 get_table(&replace);
1604 // check if selected_hook is a valid_hook
1605 if (replace.selected_hook >= 0 &&
1606 !(replace.valid_hooks & (1 << replace.selected_hook)))
1607 print_error("Bad chain name");
1608 if (replace.command == 'P')
1609 change_policy(policy);
1610 else if (replace.command == 'L') {
1611 list_rules();
1612 if (replace.flags & OPT_ZERO)
1613 zero_counters(zerochain);
1614 else
1615 exit(0);
1616 }
1617 if (replace.flags & OPT_ZERO)
1618 zero_counters(zerochain);
1619 else if (replace.command == 'F')
1620 flush_chains();
1621 else if (replace.command == 'A' || replace.command == 'I')
1622 add_rule(rule_nr);
1623 else if (replace.command == 'D')
1624 delete_rule(rule_nr);
1625
1626 if (table->check)
1627 table->check(&replace);
1628
1629 deliver_table(&replace);
1630
1631 if (counterchanges)
1632 deliver_counters(&replace, counterchanges);
1633 return 0;
1634}