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