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