blob: 2fc217cc799344ddf1d8a685840d7a3fdac8ff29 [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 Schuymer60332e02002-06-23 08:01:47 +000049#define DATABASEHOOKNR -2
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000050#define DATABASEHOOKNAME "DB"
51
52static char *prog_name = PROGNAME;
53static char *prog_version = PROGVERSION;
Bart De Schuymer60332e02002-06-23 08:01:47 +000054char *hooknames[NF_BR_NUMHOOKS] =
55{
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000056 [NF_BR_PRE_ROUTING]"PREROUTING",
57 [NF_BR_LOCAL_IN]"INPUT",
58 [NF_BR_FORWARD]"FORWARD",
59 [NF_BR_LOCAL_OUT]"OUTPUT",
60 [NF_BR_POST_ROUTING]"POSTROUTING",
61 [NF_BR_BROUTING]"BROUTING"
62};
63
64// default command line options
65static struct option ebt_original_options[] = {
66 { "append" , required_argument, 0, 'A' },
67 { "insert" , required_argument, 0, 'I' },
68 { "delete" , required_argument, 0, 'D' },
69 { "list" , optional_argument, 0, 'L' },
70 { "zero" , optional_argument, 0, 'Z' },
71 { "flush" , optional_argument, 0, 'F' },
72 { "policy" , required_argument, 0, 'P' },
73 { "in-interface" , required_argument, 0, 'i' },
74 { "in-if" , required_argument, 0, 'i' },
75 { "logical-in" , required_argument, 0, 2 },
76 { "logical-out" , required_argument, 0, 3 },
77 { "out-interface" , required_argument, 0, 'o' },
78 { "out-if" , required_argument, 0, 'o' },
79 { "version" , no_argument , 0, 'V' },
80 { "help" , no_argument , 0, 'h' },
81 { "jump" , required_argument, 0, 'j' },
82 { "proto" , required_argument, 0, 'p' },
83 { "protocol" , required_argument, 0, 'p' },
84 { "db" , required_argument, 0, 'b' },
85 { "source" , required_argument, 0, 's' },
86 { "src" , required_argument, 0, 's' },
87 { "destination" , required_argument, 0, 'd' },
88 { "dst" , required_argument, 0, 'd' },
89 { "table" , required_argument, 0, 't' },
Bart De Schuymerc8531032002-06-14 21:55:29 +000090 { "modprobe" , required_argument, 0, 'M' },
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000091 { 0 }
92};
93
94static struct option *ebt_options = ebt_original_options;
95
96// yup, all the possible target names
97char* standard_targets[NUM_STANDARD_TARGETS] = {
98 "ACCEPT",
99 "DROP",
100 "CONTINUE",
Bart De Schuymer60332e02002-06-23 08:01:47 +0000101 "RETURN",
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000102};
103
104unsigned char mac_type_unicast[ETH_ALEN] = {0,0,0,0,0,0};
105unsigned char msk_type_unicast[ETH_ALEN] = {1,0,0,0,0,0};
106unsigned char mac_type_multicast[ETH_ALEN] = {1,0,0,0,0,0};
107unsigned char msk_type_multicast[ETH_ALEN] = {1,0,0,0,0,0};
108unsigned char mac_type_broadcast[ETH_ALEN] = {255,255,255,255,255,255};
109unsigned char msk_type_broadcast[ETH_ALEN] = {255,255,255,255,255,255};
110
111// tells what happened to the old rules
112static unsigned short *counterchanges;
113// holds all the data
114static struct ebt_u_replace replace;
115
116// the chosen table
117static struct ebt_u_table *table = NULL;
118// the lists of supported tables, matches, watchers and targets
119static struct ebt_u_table *tables = NULL;
120static struct ebt_u_match *matches = NULL;
121static struct ebt_u_watcher *watchers = NULL;
122static struct ebt_u_target *targets = NULL;
123
124struct ebt_u_target *find_target(const char *name)
125{
126 struct ebt_u_target *t = targets;
127
128 while(t && strcmp(t->name, name))
129 t = t->next;
130 return t;
131}
132
133struct ebt_u_match *find_match(const char *name)
134{
135 struct ebt_u_match *m = matches;
136
137 while(m && strcmp(m->name, name))
138 m = m->next;
139 return m;
140}
141
142struct ebt_u_watcher *find_watcher(const char *name)
143{
144 struct ebt_u_watcher *w = watchers;
145
146 while(w && strcmp(w->name, name))
147 w = w->next;
148 return w;
149}
150
151struct ebt_u_table *find_table(char *name)
152{
153 struct ebt_u_table *t = tables;
154
155 while (t && strcmp(t->name, name))
156 t = t->next;
157 return t;
158}
159
160// The pointers in here are special:
161// The struct ebt_target * pointer is actually a struct ebt_u_target * pointer.
162// instead of making yet a few other structs, we just do a cast.
163// We need a struct ebt_u_target pointer because we know the address of the data
164// they point to won't change. We want to allow that the struct ebt_u_target.t
165// member can change.
166// Same holds for the struct ebt_match and struct ebt_watcher pointers
167struct ebt_u_entry *new_entry;
168
169void initialize_entry(struct ebt_u_entry *e)
170{
171 e->bitmask = EBT_NOPROTO;
172 e->invflags = 0;
173 e->ethproto = 0;
174 strcpy(e->in, "");
175 strcpy(e->out, "");
176 strcpy(e->logical_in, "");
177 strcpy(e->logical_out, "");
178 e->m_list = NULL;
179 e->w_list = NULL;
180 // the init function of the standard target should have put the verdict
181 // on CONTINUE
182 e->t = (struct ebt_entry_target *)find_target(EBT_STANDARD_TARGET);
183 if (!e->t)
184 print_bug("Couldn't load standard target\n");
185}
186
187// this doesn't free e, becoz the calling function might need e->next
188void free_u_entry(struct ebt_u_entry *e)
189{
190 struct ebt_u_match_list *m_l, *m_l2;
191 struct ebt_u_watcher_list *w_l, *w_l2;
192
193 m_l = e->m_list;
194 while (m_l) {
195 m_l2 = m_l->next;
196 free(m_l->m);
197 free(m_l);
198 m_l = m_l2;
199 }
200 w_l = e->w_list;
201 while (w_l) {
202 w_l2 = w_l->next;
203 free(w_l->w);
204 free(w_l);
205 w_l = w_l2;
206 }
207 free(e->t);
208}
209
210// the user will use the match, so put it in new_entry
211static void add_match(struct ebt_u_match *m)
212{
213 struct ebt_u_match_list **m_list, *new;
214
215 m->used = 1;
216 for (m_list = &new_entry->m_list;
217 *m_list; m_list = &(*m_list)->next);
218 new = (struct ebt_u_match_list *)
219 malloc(sizeof(struct ebt_u_match_list));
220 if (!new)
221 print_memory();
222 *m_list = new;
223 new->next = NULL;
224 new->m = (struct ebt_entry_match *)m;
225}
226
227static void add_watcher(struct ebt_u_watcher *w)
228{
229 struct ebt_u_watcher_list **w_list;
230 struct ebt_u_watcher_list *new;
231
232 w->used = 1;
233 for (w_list = &new_entry->w_list;
234 *w_list; w_list = &(*w_list)->next);
235 new = (struct ebt_u_watcher_list *)
236 malloc(sizeof(struct ebt_u_watcher_list));
237 if (!new)
238 print_memory();
239 *w_list = new;
240 new->next = NULL;
241 new->w = (struct ebt_entry_watcher *)w;
242}
243
244static int global_option_offset = 0;
245#define OPTION_OFFSET 256
246static struct option *
247merge_options(struct option *oldopts, const struct option *newopts,
248 unsigned int *options_offset)
249{
250 unsigned int num_old, num_new, i;
251 struct option *merge;
252
253 if (!newopts || !oldopts || !options_offset)
254 print_bug("merge wrong");
255 for (num_old = 0; oldopts[num_old].name; num_old++);
256 for (num_new = 0; newopts[num_new].name; num_new++);
257
258 global_option_offset += OPTION_OFFSET;
259 *options_offset = global_option_offset;
260
261 merge = malloc(sizeof(struct option) * (num_new + num_old + 1));
262 if (!merge)
263 print_memory();
264 memcpy(merge, oldopts, num_old * sizeof(struct option));
265 for (i = 0; i < num_new; i++) {
266 merge[num_old + i] = newopts[i];
267 merge[num_old + i].val += *options_offset;
268 }
269 memset(merge + num_old + num_new, 0, sizeof(struct option));
270 // only free dynamically allocated stuff
271 if (oldopts != ebt_original_options)
272 free(oldopts);
273
274 return merge;
275}
276
277void register_match(struct ebt_u_match *m)
278{
279 int size = m->size + sizeof(struct ebt_entry_match);
280 struct ebt_u_match **i;
281
282 m->m = (struct ebt_entry_match *)malloc(size);
283 if (!m->m)
284 print_memory();
285 strcpy(m->m->u.name, m->name);
286 m->m->match_size = m->size;
287 ebt_options = merge_options
288 (ebt_options, m->extra_ops, &(m->option_offset));
289 m->init(m->m);
290
291 for (i = &matches; *i; i = &((*i)->next));
292 m->next = NULL;
293 *i = m;
294}
295
296void register_watcher(struct ebt_u_watcher *w)
297{
298 int size = w->size + sizeof(struct ebt_entry_watcher);
299 struct ebt_u_watcher **i;
300
301 w->w = (struct ebt_entry_watcher *)malloc(size);
302 if (!w->w)
303 print_memory();
304 strcpy(w->w->u.name, w->name);
305 w->w->watcher_size = w->size;
306 ebt_options = merge_options
307 (ebt_options, w->extra_ops, &(w->option_offset));
308 w->init(w->w);
309
310 for (i = &watchers; *i; i = &((*i)->next));
311 w->next = NULL;
312 *i = w;
313}
314
315void register_target(struct ebt_u_target *t)
316{
317 int size = t->size + sizeof(struct ebt_entry_target);
318 struct ebt_u_target **i;
319
320 t->t = (struct ebt_entry_target *)malloc(size);
321 if (!t->t)
322 print_memory();
323 strcpy(t->t->u.name, t->name);
324 t->t->target_size = t->size;
325 ebt_options = merge_options
326 (ebt_options, t->extra_ops, &(t->option_offset));
327 t->init(t->t);
328 for (i = &targets; *i; i = &((*i)->next));
329 t->next = NULL;
330 *i = t;
331}
332
333void register_table(struct ebt_u_table *t)
334{
335 t->next = tables;
336 tables = t;
337}
338
Bart De Schuymerc8531032002-06-14 21:55:29 +0000339// blatently stolen (again) from iptables.c userspace program
340// find out where the modprobe utility is located
341static char *get_modprobe(void)
342{
343 int procfile;
344 char *ret;
345
346 procfile = open(PROC_SYS_MODPROBE, O_RDONLY);
347 if (procfile < 0)
348 return NULL;
349
350 ret = malloc(1024);
351 if (ret) {
352 switch (read(procfile, ret, 1024)) {
353 case -1: goto fail;
354 case 1024: goto fail; /* Partial read. Wierd */
355 }
356 if (ret[strlen(ret)-1]=='\n')
357 ret[strlen(ret)-1]=0;
358 close(procfile);
359 return ret;
360 }
361 fail:
362 free(ret);
363 close(procfile);
364 return NULL;
365}
366
367// I hate stealing, really... Lets call it a tribute.
368int ebtables_insmod(const char *modname, const char *modprobe)
369{
370 char *buf = NULL;
371 char *argv[3];
372
373 /* If they don't explicitly set it, read out of kernel */
374 if (!modprobe) {
375 buf = get_modprobe();
376 if (!buf)
377 return -1;
378 modprobe = buf;
379 }
380
381 switch (fork()) {
382 case 0:
383 argv[0] = (char *)modprobe;
384 argv[1] = (char *)modname;
385 argv[2] = NULL;
386 execv(argv[0], argv);
387
388 /* not usually reached */
389 exit(0);
390 case -1:
391 return -1;
392
393 default: /* parent */
394 wait(NULL);
395 }
396
397 free(buf);
398 return 0;
399}
400
401
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000402// used to parse /etc/etherproto
403int disregard_whitespace(char *buffer, FILE *ifp)
404{
405 int hlp;
406 buffer[0] = '\t';
407 while (buffer[0] == '\t' || buffer[0] == '\n' || buffer[0] == ' ') {
408 hlp = fscanf(ifp, "%c", buffer);
409 if (hlp == EOF || hlp == 0) return -1;
410 }
411 return 0;
412}
413
414// used to parse /etc/etherproto
415int disregard_tabspace(char *buffer, FILE *ifp)
416{
417 int hlp;
418 buffer[0] = '\t';
419 while (buffer[0] == '\t' || buffer[0] == ' ') {
420 hlp = fscanf(ifp, "%c", buffer);
421 if (hlp == EOF || hlp == 0) return -1;
422 }
423 return 0;
424}
425
Bart De Schuymerbbca3202002-06-05 18:55:44 +0000426// helper function: processes a line of data from the file /etc/ethertypes
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000427int get_a_line(char *buffer, char *value, FILE *ifp)
428{
429 int i, hlp;
430 char anotherhlp;
431
432 /* discard comment lines && whitespace*/
433 while (1) {
434 if (disregard_whitespace(buffer, ifp)) return -1;
435 if (buffer[0] == '#')
436 while (1) {
437 hlp = fscanf(ifp, "%c", &anotherhlp);
438 if (!hlp || hlp == EOF)
439 return -1;
440 if (anotherhlp == '\n')
441 break;
442 }
443 else break;
444 }
445
446 // buffer[0] already contains the first letter
447 for (i = 1; i < 21; i++) {
448 hlp = fscanf(ifp, "%c", buffer + i);
449 if (hlp == EOF || hlp == 0) return -1;
450 if (buffer[i] == '\t' || buffer[i] == ' ')
451 break;
452 }
453 if (i == 21) return -1;
454 buffer[i] = '\0';
455 if (disregard_tabspace(value, ifp))
456 return -1;
457 // maybe I should allow 0x0800 instead of 0800, but I'm feeling lazy
458 // buffer[0] already contains the first letter
459 for (i = 1; i < 5; i++) {
460 hlp = fscanf(ifp, "%c", value+i);
461 if (value[i] == '\n' || value[i] == '\t' ||
462 value[i] == ' ' || hlp == EOF)
463 break;
464 }
465 if (i == 5) return -1;
Bart De Schuymerbbca3202002-06-05 18:55:44 +0000466 // discard comments at the end of a line
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000467 if (value[i] == '\t' || value[i] == ' ')
468 while (1) {
469 hlp = fscanf(ifp, "%c", &anotherhlp);
470 if (!hlp || hlp == EOF || anotherhlp == '\n')
471 break;
472 }
473 value[i] = '\0';
474 return 0;
475}
476
477// helper function for list_em()
478int number_to_name(unsigned short proto, char *name)
479{
480 FILE *ifp;
481 char buffer[21], value[5], *bfr;
482 unsigned short i;
483
484 if ( !(ifp = fopen(PROTOCOLFILE, "r")) )
485 return -1;
486 while (1) {
487 if (get_a_line(buffer, value, ifp)) {
488 fclose(ifp);
489 return -1;
490 }
491 i = (unsigned short) strtol(value, &bfr, 16);
492 if (*bfr != '\0' || i != proto)
493 continue;
494 strcpy(name, buffer);
495 fclose(ifp);
496 return 0;
497 }
498}
499
500// helper function for list_rules()
Bart De Schuymer60332e02002-06-23 08:01:47 +0000501static void list_em(struct ebt_u_entries *entries)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000502{
503 int i, j, space = 0, digits;
504 struct ebt_u_entry *hlp;
505 struct ebt_u_match_list *m_l;
506 struct ebt_u_watcher_list *w_l;
507 struct ebt_u_match *m;
508 struct ebt_u_watcher *w;
509 struct ebt_u_target *t;
510 char name[21];
511
Bart De Schuymer60332e02002-06-23 08:01:47 +0000512 hlp = entries->entries;
513 printf("\nBridge chain: %s\nPolicy: %s\n", entries->name,
514 standard_targets[-entries->policy - 1]);
515 printf("nr. of entries: %d \n", entries->nentries);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000516
Bart De Schuymer60332e02002-06-23 08:01:47 +0000517 i = entries->nentries;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000518 while (i >9) {
519 space++;
520 i /= 10;
521 }
522
Bart De Schuymer60332e02002-06-23 08:01:47 +0000523 for (i = 0; i < entries->nentries; i++) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000524 digits = 0;
525 // A little work to get nice rule numbers.
526 while (j > 9) {
527 digits++;
528 j /= 10;
529 }
530 for (j = 0; j < space - digits; j++)
531 printf(" ");
532 printf("%d. ", i + 1);
533
534 // Don't print anything about the protocol if no protocol was
535 // specified, obviously this means any protocol will do.
536 if (!(hlp->bitmask & EBT_NOPROTO)) {
Bart De Schuymer60332e02002-06-23 08:01:47 +0000537 printf("-p ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000538 if (hlp->invflags & EBT_IPROTO)
539 printf("! ");
540 if (hlp->bitmask & EBT_802_3)
541 printf("Length, ");
542 else {
543 if (number_to_name(ntohs(hlp->ethproto), name))
Bart De Schuymer60332e02002-06-23 08:01:47 +0000544 printf("0x%x ", ntohs(hlp->ethproto));
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000545 else
Bart De Schuymer60332e02002-06-23 08:01:47 +0000546 printf("%s ", name);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000547 }
548 }
549 if (hlp->bitmask & EBT_SOURCEMAC) {
550 char hlpmsk[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
551
Bart De Schuymer60332e02002-06-23 08:01:47 +0000552 printf("-s ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000553 if (hlp->invflags & EBT_ISOURCE)
554 printf("! ");
555 if (!memcmp(hlp->sourcemac, mac_type_unicast, 6) &&
556 !memcmp(hlp->sourcemsk, msk_type_unicast, 6)) {
557 printf("Unicast");
558 goto endsrc;
559 }
560 if (!memcmp(hlp->sourcemac, mac_type_multicast, 6) &&
561 !memcmp(hlp->sourcemsk, msk_type_multicast, 6)) {
562 printf("Multicast");
563 goto endsrc;
564 }
565 if (!memcmp(hlp->sourcemac, mac_type_broadcast, 6) &&
566 !memcmp(hlp->sourcemsk, msk_type_broadcast, 6)) {
567 printf("Broadcast");
568 goto endsrc;
569 }
Bart De Schuymer41830412002-06-05 19:41:28 +0000570 printf("%s", ether_ntoa((struct ether_addr *)
571 hlp->sourcemac));
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000572 if (memcmp(hlp->sourcemsk, hlpmsk, 6)) {
573 printf("/");
Bart De Schuymer41830412002-06-05 19:41:28 +0000574 printf("%s", ether_ntoa((struct ether_addr *)
575 hlp->sourcemsk));
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000576 }
577endsrc:
Bart De Schuymer60332e02002-06-23 08:01:47 +0000578 printf(" ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000579 }
580 if (hlp->bitmask & EBT_DESTMAC) {
581 char hlpmsk[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
582
Bart De Schuymer60332e02002-06-23 08:01:47 +0000583 printf("-d ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000584 if (hlp->invflags & EBT_IDEST)
585 printf("! ");
586 if (!memcmp(hlp->destmac, mac_type_unicast, 6) &&
587 !memcmp(hlp->destmsk, msk_type_unicast, 6)) {
588 printf("Unicast");
589 goto enddst;
590 }
591 if (!memcmp(hlp->destmac, mac_type_multicast, 6) &&
592 !memcmp(hlp->destmsk, msk_type_multicast, 6)) {
593 printf("Multicast");
594 goto enddst;
595 }
596 if (!memcmp(hlp->destmac, mac_type_broadcast, 6) &&
597 !memcmp(hlp->destmsk, msk_type_broadcast, 6)) {
598 printf("Broadcast");
599 goto enddst;
600 }
Bart De Schuymer41830412002-06-05 19:41:28 +0000601 printf("%s", ether_ntoa((struct ether_addr *)
602 hlp->destmac));
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000603 if (memcmp(hlp->destmsk, hlpmsk, 6)) {
604 printf("/");
Bart De Schuymer41830412002-06-05 19:41:28 +0000605 printf("%s", ether_ntoa((struct ether_addr *)
606 hlp->destmsk));
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000607 }
608enddst:
Bart De Schuymer60332e02002-06-23 08:01:47 +0000609 printf(" ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000610 }
611 if (hlp->in[0] != '\0') {
Bart De Schuymer60332e02002-06-23 08:01:47 +0000612 printf("-i ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000613 if (hlp->invflags & EBT_IIN)
614 printf("! ");
Bart De Schuymer60332e02002-06-23 08:01:47 +0000615 printf("%s ", hlp->in);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000616 }
617 if (hlp->logical_in[0] != '\0') {
Bart De Schuymer60332e02002-06-23 08:01:47 +0000618 printf("--logical-in ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000619 if (hlp->invflags & EBT_ILOGICALIN)
620 printf("! ");
Bart De Schuymer60332e02002-06-23 08:01:47 +0000621 printf("%s ", hlp->logical_in);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000622 }
623 if (hlp->logical_out[0] != '\0') {
Bart De Schuymer60332e02002-06-23 08:01:47 +0000624 printf("--logical-out ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000625 if (hlp->invflags & EBT_ILOGICALOUT)
626 printf("! ");
Bart De Schuymer60332e02002-06-23 08:01:47 +0000627 printf("%s, ", hlp->logical_out);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000628 }
629 if (hlp->out[0] != '\0') {
Bart De Schuymer60332e02002-06-23 08:01:47 +0000630 printf("-o ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000631 if (hlp->invflags & EBT_IOUT)
632 printf("! ");
Bart De Schuymer60332e02002-06-23 08:01:47 +0000633 printf("%s, ", hlp->out);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000634 }
635
636 m_l = hlp->m_list;
637 while (m_l) {
638 m = find_match(m_l->m->u.name);
639 if (!m)
640 print_bug("Match not found");
641 m->print(hlp, m_l->m);
642 m_l = m_l->next;
643 }
644 w_l = hlp->w_list;
645 while (w_l) {
646 w = find_watcher(w_l->w->u.name);
647 if (!w)
648 print_bug("Watcher not found");
649 w->print(hlp, w_l->w);
650 w_l = w_l->next;
651 }
652
Bart De Schuymer60332e02002-06-23 08:01:47 +0000653 printf("-j ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000654 t = find_target(hlp->t->u.name);
655 if (!t)
656 print_bug("Target not found");
657 t->print(hlp, hlp->t);
658 printf(", count = %llu",
Bart De Schuymer60332e02002-06-23 08:01:47 +0000659 replace.counters[entries->counter_offset + i].pcnt);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000660 printf("\n");
661 hlp = hlp->next;
662 }
663}
664
Bart De Schuymer60332e02002-06-23 08:01:47 +0000665static struct ebt_u_entries *nr_to_chain(int nr)
666{
667 if (nr == -1)
668 return NULL;
669 if (nr < NF_BR_NUMHOOKS)
670 return replace.hook_entry[nr];
671 else {
672 int i;
673 struct ebt_u_chain_list *cl = replace.udc;
674
675 i = nr - NF_BR_NUMHOOKS;
676 while (i > 0 && cl)
677 cl = cl->next;
678 if (cl)
679 return cl->udc;
680 else
681 return NULL;
682 }
683}
684
685static struct ebt_u_entries *to_chain()
686{
687 return nr_to_chain(replace.selected_hook);
688}
689
690struct ebt_u_stack
691{
692 int chain_nr;
693 int n;
694 struct ebt_u_entry *e;
695 struct ebt_u_entries *entries;
696};
697
698void check_for_loops()
699{
700 int chain_nr , i, j , k, sp = 0, verdict;
701 struct ebt_u_entries *entries, *entries2;
702 struct ebt_u_stack *stack = NULL;
703 struct ebt_u_entry *e;
704
705 i = -1;
706 // initialize hook_mask to 0
707 while (1) {
708 i++;
709 if (i < NF_BR_NUMHOOKS && !(replace.valid_hooks & (1 << i)))
710 continue;
711 entries = nr_to_chain(i);
712 if (!entries)
713 break;
714 entries->hook_mask = 0;
715 }
716 if (i > NF_BR_NUMHOOKS) {
717 stack = (struct ebt_u_stack *)malloc((i - NF_BR_NUMHOOKS) *
718 sizeof(struct ebt_u_stack));
719 if (!stack)
720 print_memory();
721 }
722
723 for (i = 0; i < NF_BR_NUMHOOKS; i++) {
724 if (!(replace.valid_hooks & (1 << i)))
725 continue;
726 entries = nr_to_chain(i);
727 entries->hook_mask = (1 << i);
728 chain_nr = i;
729
730 e = entries->entries;
731 for (j = 0; j < entries->nentries; j++) {
732 if (strcmp(e->t->u.name, EBT_STANDARD_TARGET))
733 goto letscontinue;
734 verdict = ((struct ebt_standard_target *)(e->t))->verdict;
735 if (verdict < 0)
736 goto letscontinue;
737 // no jumping to a standard chain
738 if (verdict < NF_BR_NUMHOOKS)
739 goto error;
740 entries2 = nr_to_chain(verdict);
741 entries2->hook_mask |= entries->hook_mask;
742 // now see if we've been here before
743 for (k = 0; k < sp; k++)
744 if (stack[k].chain_nr == verdict)
745 goto error;
746 // jump to the chain, make sure we know how to get back
747 stack[sp].chain_nr = chain_nr;
748 stack[sp].n = j;
749 stack[sp].entries = entries;
750 stack[sp++].e = e;
751 j = -1;
752 e = entries2->entries;
753 chain_nr = verdict;
754 entries = entries2;
755 continue;
756letscontinue:
757 e = e->next;
758 }
759 // we are in a standard chain
760 if (sp == 0)
761 continue;
762 // go back to the chain one level lower
763 sp--;
764 j = stack[sp].n;
765 chain_nr = stack[sp].chain_nr;
766 e = stack[sp].e;
767 entries = stack[sp].entries;
768 goto letscontinue;
769 }
770 free(stack);
771 return;
772error:
773 print_error("Loop");
774}
775
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000776// parse the chain name and return the corresponding nr
777int get_hooknr(char* arg)
778{
779 int i;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000780 struct ebt_u_chain_list *cl = replace.udc;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000781
782 // database is special case (not really a chain)
783 if (!strcmp(arg, DATABASEHOOKNAME))
784 return DATABASEHOOKNR;
785
Bart De Schuymer60332e02002-06-23 08:01:47 +0000786 for (i = 0; i < NF_BR_NUMHOOKS; i++) {
787 if (!(replace.valid_hooks & (1 << i)))
788 continue;
789 if (!strcmp(arg, replace.hook_entry[i]->name))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000790 return i;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000791 }
792 while(cl) {
793 if (!strcmp(arg, cl->udc->name))
794 return i;
795 i++;
796 cl = cl->next;
797 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000798 return -1;
799}
800
801// yup, print out help
802void print_help()
803{
804 struct ebt_u_match_list *m_l;
805 struct ebt_u_watcher_list *w_l;
806
807 printf(
808"%s v%s\n"
809"Usage:\n"
810"ebtables -[ADI] chain rule-specification [options]\n"
811"ebtables -P chain target\n"
812"ebtables -[LFZ] [chain]\n"
813"ebtables -[b] [y,n]\n"
814"Commands:\n"
815"--append -A chain : Append to chain\n"
816"--delete -D chain : Delete matching rule from chain\n"
817"--delete -D chain rulenum : Delete rule at position rulenum from chain\n"
818"--insert -I chain rulenum : insert rule at position rulenum in chain\n"
819"--list -L [chain] : List the rules in a chain or in all chains\n"
820"--list -L "DATABASEHOOKNAME" : List the database (if present)\n"
821"--flush -F [chain] : Delete all rules in chain or in all chains\n"
822"--zero -Z [chain] : Put counters on zero in chain or in all chains\n"
823"--policy -P chain target : Change policy on chain to target\n"
824"Options:\n"
825"--proto -p [!] proto : protocol hexadecimal, by name or LENGTH\n"
826"--src -s [!] address[/mask]: source mac address\n"
827"--dst -d [!] address[/mask]: destination mac address\n"
828"--in-if -i [!] name : network input interface name\n"
829"--out-if -o [!] name : network output interface name\n"
830"--logical-in [!] name : logical bridge input interface name\n"
831"--logical-out [!] name : logical bridge output interface name\n"
Bart De Schuymerc8531032002-06-14 21:55:29 +0000832"--modprobe -M : try to insert modules using this command\n"
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000833"--version -V : print package version\n"
834"\n" ,
835 prog_name,
836 prog_version);
837
838 m_l = new_entry->m_list;
839 while (m_l) {
840 ((struct ebt_u_match *)m_l->m)->help();
841 printf("\n");
842 m_l = m_l->next;
843 }
844 w_l = new_entry->w_list;
845 while (w_l) {
846 ((struct ebt_u_watcher *)w_l->w)->help();
847 printf("\n");
848 w_l = w_l->next;
849 }
850 ((struct ebt_u_target *)new_entry->t)->help();
851 printf("\n");
852 if (table->help)
853 table->help(hooknames);
854 exit(0);
855}
856
857// execute command L
858static void list_rules()
859{
860 int i;
861
862 printf("Bridge table: %s\n", table->name);
Bart De Schuymer60332e02002-06-23 08:01:47 +0000863 if (replace.selected_hook != -1) {
864 list_em(to_chain());
865 } else {
866 struct ebt_u_chain_list *cl = replace.udc;
867
868 i = 0;
869 while (1) {
870 if (i < NF_BR_NUMHOOKS) {
871 if (replace.valid_hooks & (1 << i))
872 list_em(replace.hook_entry[i]);
873 i++;
874 continue;
875 } else {
876 if (!cl)
877 break;
878 list_em(cl->udc);
879 cl = cl->next;
880 }
881 }
882 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000883 return;
884}
885
886// execute command P
887static void change_policy(int policy)
888{
889 int i;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000890 struct ebt_u_entries *entries = to_chain();
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000891
892 // don't do anything if the policy is the same
Bart De Schuymer60332e02002-06-23 08:01:47 +0000893 if (entries->policy != policy) {
894 entries->policy = policy;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000895 replace.num_counters = replace.nentries;
896 if (replace.nentries) {
897 // '+ 1' for the CNT_END
898 if (!(counterchanges = (unsigned short *) malloc(
899 (replace.nentries + 1) * sizeof(unsigned short))))
900 print_memory();
901 // done nothing special to the rules
902 for (i = 0; i < replace.nentries; i++)
903 counterchanges[i] = CNT_NORM;
904 counterchanges[replace.nentries] = CNT_END;
905 }
906 else
907 counterchanges = NULL;
908 }
909 else
910 exit(0);
911}
912
913// flush one chain or the complete table
914static void flush_chains()
915{
Bart De Schuymer60332e02002-06-23 08:01:47 +0000916 int i, j, oldnentries, numdel;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000917 unsigned short *cnt;
918 struct ebt_u_entry *u_e, *tmp;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000919 struct ebt_u_entries *entries = to_chain();
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000920
921 // flush whole table
Bart De Schuymer60332e02002-06-23 08:01:47 +0000922 if (!entries) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000923 if (replace.nentries == 0)
924 exit(0);
925 replace.nentries = 0;
926 // no need for the kernel to give us counters back
927 replace.num_counters = 0;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000928
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000929 // free everything and zero (n)entries
Bart De Schuymer60332e02002-06-23 08:01:47 +0000930 i = -1;
931 while (1) {
932 i++;
933 entries = nr_to_chain(i);
934 if (!entries) {
935 if (i < NF_BR_NUMHOOKS)
936 continue;
937 else
938 break;
939 }
940 entries->nentries = 0;
941 entries->counter_offset = 0;
942 u_e = entries->entries;
943 entries->entries = NULL;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000944 while (u_e) {
945 free_u_entry(u_e);
946 tmp = u_e->next;
947 free(u_e);
948 u_e = tmp;
949 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000950 }
951 return;
952 }
953
Bart De Schuymer60332e02002-06-23 08:01:47 +0000954 if (entries->nentries == 0)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000955 exit(0);
956 oldnentries = replace.nentries;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000957 replace.nentries -= entries->nentries;
958 numdel = entries->nentries;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000959
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000960 if (replace.nentries) {
961 // +1 for CNT_END
962 if ( !(counterchanges = (unsigned short *)
963 malloc((oldnentries + 1) * sizeof(unsigned short))) )
964 print_memory();
965 cnt = counterchanges;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000966 }
967 // delete the counters belonging to the specified chain,
968 // update counter_offset
969 i = -1;
970 while (1) {
971 i++;
972 entries = nr_to_chain(i);
973 if (!entries) {
974 if (i < NF_BR_NUMHOOKS)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000975 continue;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000976 else
977 break;
978 }
979 if (i > replace.selected_hook)
980 entries->counter_offset -= numdel;
981 if (replace.nentries) {
982 for (j = 0; j < entries->nentries; j++) {
983 if (i == replace.selected_hook)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000984 *cnt = CNT_NORM;
985 else
986 *cnt = CNT_DEL;
987 cnt++;
988 }
989 }
Bart De Schuymer60332e02002-06-23 08:01:47 +0000990 }
991
992 if (replace.nentries) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000993 *cnt = CNT_END;
994 replace.num_counters = oldnentries;
995 }
996 else
997 replace.num_counters = 0;
998
Bart De Schuymer60332e02002-06-23 08:01:47 +0000999 entries = to_chain();
1000 entries->nentries = 0;
1001 u_e = entries->entries;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001002 while (u_e) {
1003 free_u_entry(u_e);
1004 tmp = u_e->next;
1005 free(u_e);
1006 u_e = tmp;
1007 }
Bart De Schuymer60332e02002-06-23 08:01:47 +00001008 entries->entries = NULL;
1009}
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001010
1011// -1 == no match
1012static int check_rule_exists(int rule_nr)
1013{
1014 struct ebt_u_entry *u_e;
1015 struct ebt_u_match_list *m_l, *m_l2;
1016 struct ebt_u_match *m;
1017 struct ebt_u_watcher_list *w_l, *w_l2;
1018 struct ebt_u_watcher *w;
1019 struct ebt_u_target *t = (struct ebt_u_target *)new_entry->t;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001020 struct ebt_u_entries *entries = to_chain();
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001021 int i, j, k;
1022
1023 // handle '-D chain rulenr' command
1024 if (rule_nr != -1) {
Bart De Schuymer60332e02002-06-23 08:01:47 +00001025 if (rule_nr > entries->nentries)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001026 return 0;
1027 // user starts counting from 1
1028 return rule_nr - 1;
1029 }
Bart De Schuymer60332e02002-06-23 08:01:47 +00001030 u_e = entries->entries;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001031 // check for an existing rule (if there are duplicate rules,
1032 // take the first occurance)
Bart De Schuymer60332e02002-06-23 08:01:47 +00001033 for (i = 0; i < entries->nentries; i++, u_e = u_e->next) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001034 if (!u_e)
1035 print_bug("Hmm, trouble");
1036 if ( u_e->ethproto == new_entry->ethproto
1037 && !strcmp(u_e->in, new_entry->in)
1038 && !strcmp(u_e->out, new_entry->out)
1039 && u_e->bitmask == new_entry->bitmask) {
Bart De Schuymer60332e02002-06-23 08:01:47 +00001040 if (strcmp(u_e->logical_in, new_entry->logical_in) ||
1041 strcmp(u_e->logical_out, new_entry->logical_out))
1042 continue;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001043 if (new_entry->bitmask & EBT_SOURCEMAC &&
Bart De Schuymer60332e02002-06-23 08:01:47 +00001044 memcmp(u_e->sourcemac, new_entry->sourcemac, ETH_ALEN))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001045 continue;
1046 if (new_entry->bitmask & EBT_DESTMAC &&
Bart De Schuymer60332e02002-06-23 08:01:47 +00001047 memcmp(u_e->destmac, new_entry->destmac, ETH_ALEN))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001048 continue;
1049 if (new_entry->bitmask != u_e->bitmask ||
1050 new_entry->invflags != u_e->invflags)
1051 continue;
1052 // compare all matches
1053 m_l = new_entry->m_list;
1054 j = 0;
1055 while (m_l) {
1056 m = (struct ebt_u_match *)(m_l->m);
1057 m_l2 = u_e->m_list;
1058 while (m_l2 &&
1059 strcmp(m_l2->m->u.name, m->m->u.name))
1060 m_l2 = m_l2->next;
1061 if (!m_l2 || !m->compare(m->m, m_l2->m))
1062 goto letscontinue;
1063 j++;
1064 m_l = m_l->next;
1065 }
1066 // now be sure they have the same nr of matches
1067 k = 0;
1068 m_l = u_e->m_list;
1069 while (m_l) {
1070 k++;
1071 m_l = m_l->next;
1072 }
1073 if (j != k)
1074 continue;
1075
1076 // compare all watchers
1077 w_l = new_entry->w_list;
1078 j = 0;
1079 while (w_l) {
1080 w = (struct ebt_u_watcher *)(w_l->w);
1081 w_l2 = u_e->w_list;
1082 while (w_l2 &&
1083 strcmp(w_l2->w->u.name, w->w->u.name))
1084 w_l2 = w_l2->next;
1085 if (!w_l2 || !w->compare(w->w, w_l2->w))
1086 goto letscontinue;
1087 j++;
1088 w_l = w_l->next;
1089 }
1090 k = 0;
1091 w_l = u_e->w_list;
1092 while (w_l) {
1093 k++;
1094 w_l = w_l->next;
1095 }
1096 if (j != k)
1097 continue;
1098 if (strcmp(t->t->u.name, u_e->t->u.name))
1099 continue;
1100 if (!t->compare(t->t, u_e->t))
1101 continue;
1102 return i;
1103 }
1104letscontinue:
1105 }
1106 return -1;
1107}
1108
1109// execute command A
1110static void add_rule(int rule_nr)
1111{
1112 int i, j;
1113 struct ebt_u_entry *u_e, *u_e2;
1114 unsigned short *cnt;
1115 struct ebt_u_match_list *m_l;
1116 struct ebt_u_watcher_list *w_l;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001117 struct ebt_u_entries *entries = to_chain(), *entries2;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001118
1119 if (rule_nr != -1) { // command -I
Bart De Schuymer60332e02002-06-23 08:01:47 +00001120 if (--rule_nr > entries->nentries)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001121 print_error("rule nr too high: %d > %d", rule_nr,
Bart De Schuymer60332e02002-06-23 08:01:47 +00001122 entries->nentries);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001123 } else
Bart De Schuymer60332e02002-06-23 08:01:47 +00001124 rule_nr = entries->nentries;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001125 // we're adding one rule
1126 replace.num_counters = replace.nentries;
1127 replace.nentries++;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001128 entries->nentries++;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001129
1130 // handle counter stuff
1131 // +1 for CNT_END
1132 if ( !(counterchanges = (unsigned short *)
1133 malloc((replace.nentries + 1) * sizeof(unsigned short))) )
1134 print_memory();
1135 cnt = counterchanges;
1136 for (i = 0; i < replace.selected_hook; i++) {
Bart De Schuymer60332e02002-06-23 08:01:47 +00001137 if (i < NF_BR_NUMHOOKS && !(replace.valid_hooks & (1 << i)))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001138 continue;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001139 entries2 = nr_to_chain(i);
1140 for (j = 0; j < entries2->nentries; j++) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001141 *cnt = CNT_NORM;
1142 cnt++;
1143 }
1144 }
1145 for (i = 0; i < rule_nr; i++) {
1146 *cnt = CNT_NORM;
1147 cnt++;
1148 }
1149 *cnt = CNT_ADD;
1150 cnt++;
1151 while (cnt != counterchanges + replace.nentries) {
1152 *cnt = CNT_NORM;
1153 cnt++;
1154 }
1155 *cnt = CNT_END;
1156
1157 // go to the right position in the chain
1158 u_e2 = NULL;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001159 u_e = entries->entries;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001160 for (i = 0; i < rule_nr; i++) {
1161 u_e2 = u_e;
1162 u_e = u_e->next;
1163 }
1164 // insert the rule
1165 if (u_e2)
1166 u_e2->next = new_entry;
1167 else
Bart De Schuymer60332e02002-06-23 08:01:47 +00001168 entries->entries = new_entry;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001169 new_entry->next = u_e;
1170
1171 // put the ebt_[match, watcher, target] pointers in place
1172 m_l = new_entry->m_list;
1173 while (m_l) {
1174 m_l->m = ((struct ebt_u_match *)m_l->m)->m;
1175 m_l = m_l->next;
1176 }
1177 w_l = new_entry->w_list;
1178 while (w_l) {
1179 w_l->w = ((struct ebt_u_watcher *)w_l->w)->w;
1180 w_l = w_l->next;
1181 }
1182 new_entry->t = ((struct ebt_u_target *)new_entry->t)->t;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001183
1184 // update the counter_offset of chains behind this one
1185 i = replace.selected_hook;
1186 while (1) {
1187 i++;
1188 entries = nr_to_chain(i);
1189 if (!entries) {
1190 if (i < NF_BR_NUMHOOKS)
1191 continue;
1192 else
1193 break;
1194 } else
1195 entries->counter_offset++;
1196 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001197}
1198
1199// execute command D
1200static void delete_rule(int rule_nr)
1201{
1202 int i, j, lentmp = 0;
1203 unsigned short *cnt;
1204 struct ebt_u_entry *u_e, *u_e2;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001205 struct ebt_u_entries *entries = to_chain(), *entries2;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001206
1207 if ( (i = check_rule_exists(rule_nr)) == -1 )
Bart De Schuymer60332e02002-06-23 08:01:47 +00001208 print_error("Sorry, rule does not exist");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001209
1210 // we're deleting a rule
1211 replace.num_counters = replace.nentries;
1212 replace.nentries--;
1213
1214 if (replace.nentries) {
1215 for (j = 0; j < replace.selected_hook; j++) {
Bart De Schuymer60332e02002-06-23 08:01:47 +00001216 if (j < NF_BR_NUMHOOKS &&
1217 !(replace.valid_hooks & (1 << j)))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001218 continue;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001219 entries2 = nr_to_chain(j);
1220 lentmp += entries2->nentries;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001221 }
1222 lentmp += i;
1223 // +1 for CNT_END
1224 if ( !(counterchanges = (unsigned short *)malloc(
1225 (replace.num_counters + 1) * sizeof(unsigned short))) )
1226 print_memory();
1227 cnt = counterchanges;
1228 for (j = 0; j < lentmp; j++) {
1229 *cnt = CNT_NORM;
1230 cnt++;
1231 }
1232 *cnt = CNT_DEL;
1233 cnt++;
1234 for (j = 0; j < replace.num_counters - lentmp; j++) {
1235 *cnt = CNT_NORM;
1236 cnt++;
1237 }
1238 *cnt = CNT_END;
1239 }
1240 else
1241 replace.num_counters = 0;
1242
1243 // go to the right position in the chain
1244 u_e2 = NULL;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001245 u_e = entries->entries;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001246 for (j = 0; j < i; j++) {
1247 u_e2 = u_e;
1248 u_e = u_e->next;
1249 }
1250
1251 // remove from the chain
1252 if (u_e2)
1253 u_e2->next = u_e->next;
1254 else
Bart De Schuymer60332e02002-06-23 08:01:47 +00001255 entries->entries = u_e->next;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001256
Bart De Schuymer60332e02002-06-23 08:01:47 +00001257 entries->nentries--;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001258 // free everything
1259 free_u_entry(u_e);
1260 free(u_e);
Bart De Schuymer60332e02002-06-23 08:01:47 +00001261 // update the counter_offset of chains behind this one
1262 i = replace.selected_hook;
1263 while (1) {
1264 i++;
1265 entries = nr_to_chain(i);
1266 if (!entries) {
1267 if (i < NF_BR_NUMHOOKS)
1268 continue;
1269 else
1270 break;
1271 } else
1272 entries->counter_offset--;
1273 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001274}
1275
1276// execute command Z
1277void zero_counters(int zerochain)
1278{
1279
1280 if (zerochain == -1) {
1281 // tell main() we don't update the counters
1282 // this results in tricking the kernel to zero his counters,
1283 // naively expecting userspace to update its counters. Muahahaha
1284 counterchanges = NULL;
1285 replace.num_counters = 0;
1286 } else {
1287 int i, j;
1288 unsigned short *cnt;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001289 struct ebt_u_entries *entries = nr_to_chain(zerochain), *e2;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001290
Bart De Schuymer60332e02002-06-23 08:01:47 +00001291 if (entries->nentries == 0)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001292 exit(0);
1293 counterchanges = (unsigned short *)
1294 malloc((replace.nentries + 1) * sizeof(unsigned short));
1295 if (!counterchanges)
1296 print_memory();
1297 cnt = counterchanges;
1298 for (i = 0; i < zerochain; i++) {
Bart De Schuymer60332e02002-06-23 08:01:47 +00001299 if (i < NF_BR_NUMHOOKS &&
1300 !(replace.valid_hooks & (1 << i)))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001301 continue;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001302 e2 = nr_to_chain(i);
1303 for (j = 0; j < e2->nentries; j++) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001304 *cnt = CNT_NORM;
1305 cnt++;
1306 }
1307 }
Bart De Schuymer60332e02002-06-23 08:01:47 +00001308 for (i = 0; i < entries->nentries; i++) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001309 *cnt = CNT_ZERO;
1310 cnt++;
1311 }
1312 while (cnt != counterchanges + replace.nentries) {
1313 *cnt = CNT_NORM;
1314 cnt++;
1315 }
1316 *cnt = CNT_END;
1317 }
1318}
1319
1320// list the database (optionally compiled into the kernel)
1321static void list_db()
1322{
1323 struct brdb_dbinfo nr;
1324 struct brdb_dbentry *db;
1325 char name[21];
1326 int i;
1327
1328 get_dbinfo(&nr);
1329
1330 // 0 : database disabled (-db n)
1331 if (!(nr.nentries))
1332 print_error("Database not present"
1333 " (disabled), try ebtables --db y");
1334 nr.nentries--;
1335 if (!nr.nentries) print_error("Database empty");
1336 if ( !(db = (struct brdb_dbentry *)
1337 malloc(nr.nentries * sizeof(struct brdb_dbentry))) )
1338 print_memory();
1339
1340 get_db(nr.nentries, db);
1341 printf("number of entries: %d\n", nr.nentries);
1342 for (i = 0; i < nr.nentries; i++) {
1343 printf(
1344 "%d:\n"
1345 "hook : %s\n"
1346 "in-if : %s\n"
1347 "out-if : %s\n"
1348 "protocol: ", i + 1, hooknames[db->hook], db->in, db->out);
1349 if (db->ethproto == IDENTIFY802_3)
1350 printf("802.2/802.3 STYLE LENGTH FIELD\n");
1351 else {
1352 if (number_to_name(ntohs(db->ethproto), name))
1353 printf("%x\n",ntohs(db->ethproto));
1354 else
1355 printf("%s\n", name);
1356 }
1357 db++;
1358 }
1359 exit(0);
1360}
1361
1362// handle db [dis,en]abling
1363static void allowdb(char yorn)
1364{
1365 __u16 decision;
1366
1367 if (yorn != 'y' && yorn != 'n')
1368 print_error("Option [y] or [n] needed");
1369
1370 if (yorn == 'y')
1371 decision = BRDB_DB;
1372 else
1373 decision = BRDB_NODB;
1374
1375 deliver_allowdb(&decision);
1376
1377 exit(0);
1378}
1379
1380// set ethproto
1381int name_to_protocol(char *name)
1382{
1383 FILE *ifp;
1384 char buffer[21], value[5], *bfr;
1385 unsigned short i;
1386
1387 if (!strcasecmp("LENGTH", name)) {
1388 new_entry->ethproto = 0;
1389 new_entry->bitmask |= EBT_802_3;
1390 return 1;
1391 }
1392 if ( !(ifp = fopen(PROTOCOLFILE, "r")) )
1393 return -1;
1394 while (1) {
1395 if (get_a_line(buffer, value, ifp)) return -1;
1396 if (strcasecmp(buffer, name))
1397 continue;
1398 i = (unsigned short) strtol(value, &bfr, 16);
1399 if (*bfr != '\0')
1400 return -1;
1401 new_entry->ethproto = i;
1402 fclose(ifp);
1403 return 0;
1404 }
1405 return -1;
1406}
1407
1408// put the mac address into 6 (ETH_ALEN) bytes
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001409int getmac_and_mask(char *from, char *to, char *mask)
1410{
1411 char *p;
1412 int i;
Bart De Schuymer41830412002-06-05 19:41:28 +00001413 struct ether_addr *addr;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001414
1415 if (strcasecmp(from, "Unicast") == 0) {
1416 memcpy(to, mac_type_unicast, ETH_ALEN);
1417 memcpy(mask, msk_type_unicast, ETH_ALEN);
1418 return 0;
1419 }
1420 if (strcasecmp(from, "Multicast") == 0) {
1421 memcpy(to, mac_type_multicast, ETH_ALEN);
1422 memcpy(mask, msk_type_multicast, ETH_ALEN);
1423 return 0;
1424 }
1425 if (strcasecmp(from, "Broadcast") == 0) {
1426 memcpy(to, mac_type_broadcast, ETH_ALEN);
1427 memcpy(mask, msk_type_broadcast, ETH_ALEN);
1428 return 0;
1429 }
1430 if ( (p = strrchr(from, '/')) != NULL) {
1431 *p = '\0';
Bart De Schuymer41830412002-06-05 19:41:28 +00001432 if (!(addr = ether_aton(p + 1)))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001433 return -1;
Bart De Schuymer41830412002-06-05 19:41:28 +00001434 memcpy(mask, addr, ETH_ALEN);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001435 } else
1436 memset(mask, 0xff, ETH_ALEN);
Bart De Schuymer41830412002-06-05 19:41:28 +00001437 if (!(addr = ether_aton(from)))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001438 return -1;
Bart De Schuymer41830412002-06-05 19:41:28 +00001439 memcpy(to, addr, ETH_ALEN);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001440 for (i = 0; i < ETH_ALEN; i++)
1441 to[i] &= mask[i];
1442 return 0;
1443}
1444
1445int check_inverse(const char option[])
1446{
1447 if (strcmp(option, "!") == 0) {
1448 optind++;
1449 return 1;
1450 }
1451 return 0;
1452}
1453
1454void check_option(unsigned int *flags, unsigned int mask)
1455{
1456 if (*flags & mask)
1457 print_error("Multiple use of same option not allowed");
1458 *flags |= mask;
1459}
1460
1461#define OPT_COMMAND 0x01
1462#define OPT_TABLE 0x02
1463#define OPT_IN 0x04
1464#define OPT_OUT 0x08
1465#define OPT_JUMP 0x10
1466#define OPT_PROTOCOL 0x20
1467#define OPT_SOURCE 0x40
1468#define OPT_DEST 0x80
1469#define OPT_ZERO 0x100
1470#define OPT_LOGICALIN 0x200
1471#define OPT_LOGICALOUT 0x400
1472// the main thing
1473int main(int argc, char *argv[])
1474{
1475 char *buffer, allowbc = 'n';
1476 int c, i;
1477 // this special one for the -Z option (we can have -Z <this> -L <that>)
1478 int zerochain = -1;
1479 int policy = -1;
1480 int rule_nr = -1;// used for -D chain number
1481 struct ebt_u_target *t;
1482 struct ebt_u_match *m;
1483 struct ebt_u_watcher *w;
1484 struct ebt_u_match_list *m_l;
1485 struct ebt_u_watcher_list *w_l;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001486 struct ebt_u_entries *entries;
Bart De Schuymerc8531032002-06-14 21:55:29 +00001487 const char *modprobe = NULL;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001488
1489 // initialize the table name, OPT_ flags, selected hook and command
1490 strcpy(replace.name, "filter");
1491 replace.flags = 0;
1492 replace.selected_hook = -1;
1493 replace.command = 'h';
1494
1495 new_entry = (struct ebt_u_entry *)malloc(sizeof(struct ebt_u_entry));
1496 if (!new_entry)
1497 print_memory();
1498 // put some sane values in our new entry
1499 initialize_entry(new_entry);
1500
Bart De Schuymer60332e02002-06-23 08:01:47 +00001501 // The scenario induced by this loop makes that:
1502 // '-t' and '-M' (if specified) have to come before '-A' and the like
1503
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001504 // getopt saves the day
1505 while ((c = getopt_long(argc, argv,
Bart De Schuymerc8531032002-06-14 21:55:29 +00001506 "-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 +00001507 switch (c) {
1508
1509 case 'A': // add a rule
1510 case 'D': // delete a rule
1511 case 'P': // define policy
1512 case 'I': // insert a rule
1513 replace.command = c;
1514 if (replace.flags & OPT_COMMAND)
1515 print_error("Multiple commands not allowed");
1516 replace.flags |= OPT_COMMAND;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001517 if ( !(table = find_table(replace.name)) )
1518 print_error("Bad table name");
1519 // get the kernel's information
1520 if (get_table(&replace)) {
1521 ebtables_insmod("ebtables", modprobe);
1522 if (get_table(&replace))
1523 print_error("can't initialize ebtables "
1524 "table %s", replace.name);
1525 }
1526 // here we already need the kernel table
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001527 if ((replace.selected_hook = get_hooknr(optarg)) == -1)
1528 print_error("Bad chain");
1529 if (c == 'D' && optind < argc &&
1530 argv[optind][0] != '-') {
1531 rule_nr = strtol(argv[optind], &buffer, 10);
1532 if (*buffer != '\0' || rule_nr < 0)
1533 print_error("Problem with the "
1534 "specified rule number");
1535 optind++;
1536 }
1537 if (c == 'P') {
1538 if (optind >= argc)
1539 print_error("No policy specified");
Bart De Schuymer60332e02002-06-23 08:01:47 +00001540 for (i = 0; i < 4; i++)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001541 if (!strcmp(argv[optind],
1542 standard_targets[i])) {
Bart De Schuymer60332e02002-06-23 08:01:47 +00001543 policy = -i -1;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001544 break;
1545 }
1546 if (policy == -1)
1547 print_error("Wrong policy");
1548 optind++;
1549 }
1550 if (c == 'I') {
1551 if (optind >= argc)
1552 print_error("No rulenr for -I"
1553 " specified");
1554 rule_nr = strtol(argv[optind], &buffer, 10);
1555 if (*buffer != '\0' || rule_nr < 0)
1556 print_error("Problem with the specified"
1557 " rule number");
1558 optind++;
1559 }
1560 break;
1561
1562 case 'L': // list
1563 case 'F': // flush
1564 case 'Z': // zero counters
1565 if (c == 'Z') {
1566 if (replace.flags & OPT_ZERO)
1567 print_error("Multiple commands"
1568 " not allowed");
1569 if ( (replace.flags & OPT_COMMAND &&
1570 replace.command != 'L'))
1571 print_error("command -Z only allowed "
1572 "together with command -L");
1573 replace.flags |= OPT_ZERO;
1574 } else {
1575 replace.command = c;
1576 if (replace.flags & OPT_COMMAND)
1577 print_error("Multiple commands"
1578 " not allowed");
1579 replace.flags |= OPT_COMMAND;
1580 }
1581 i = -1;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001582 if ( !(table = find_table(replace.name)) )
1583 print_error("Bad table name");
1584 // get the kernel's information
1585 if (get_table(&replace)) {
1586 ebtables_insmod("ebtables", modprobe);
1587 if (get_table(&replace))
1588 print_error("can't initialize ebtables "
1589 "table %s", replace.name);
1590 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001591 if (optarg) {
1592 if ( (i = get_hooknr(optarg)) == -1 )
1593 print_error("Bad chain");
1594 } else
1595 if (optind < argc && argv[optind][0] != '-') {
1596 if ((i = get_hooknr(argv[optind]))
1597 == -1)
1598 print_error("Bad chain");
1599 optind++;
1600 }
1601 if (i != -1) {
1602 if (c == 'Z')
1603 zerochain = i;
1604 else
1605 replace.selected_hook = i;
1606 }
1607 break;
1608
1609 case 'V': // version
1610 replace.command = 'V';
1611 if (replace.flags & OPT_COMMAND)
1612 print_error("Multiple commands not allowed");
1613 printf("%s, %s\n", prog_name, prog_version);
1614 exit(0);
1615
Bart De Schuymerc8531032002-06-14 21:55:29 +00001616 case 'M': // modprobe
Bart De Schuymer60332e02002-06-23 08:01:47 +00001617 if (replace.command != 'h')
1618 print_error("Please put the -M option earlier");
Bart De Schuymerc8531032002-06-14 21:55:29 +00001619 modprobe = optarg;
1620 break;
1621
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001622 case 'h': // help
1623 if (replace.flags & OPT_COMMAND)
1624 print_error("Multiple commands not allowed");
1625 replace.command = 'h';
1626 // All other arguments should be extension names
1627 while (optind < argc) {
1628 struct ebt_u_match *m;
1629 struct ebt_u_watcher *w;
1630
1631 if ((m = find_match(argv[optind])))
1632 add_match(m);
1633 else if ((w = find_watcher(argv[optind])))
1634 add_watcher(w);
1635 else {
1636 if (!(t = find_target(argv[optind])))
1637 print_error("Extension %s "
1638 "not found", argv[optind]);
1639 if (replace.flags & OPT_JUMP)
1640 print_error("Sorry, you can "
1641 "only see help for one "
1642 "target extension each time");
1643 replace.flags |= OPT_JUMP;
1644 new_entry->t =
1645 (struct ebt_entry_target *)t;
1646 }
1647 optind++;
1648 }
1649 break;
1650
1651 case 't': // table
Bart De Schuymer60332e02002-06-23 08:01:47 +00001652 if (replace.command != 'h')
1653 print_error("Please put the -t option first");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001654 check_option(&replace.flags, OPT_TABLE);
1655 if (strlen(optarg) > EBT_TABLE_MAXNAMELEN)
1656 print_error("Table name too long");
1657 strcpy(replace.name, optarg);
1658 break;
1659
1660 case 'i': // input interface
1661 case 2 : // logical input interface
1662 case 'o': // output interface
1663 case 3 : // logical output interface
1664 case 'j': // target
1665 case 'p': // net family protocol
1666 case 's': // source mac
1667 case 'd': // destination mac
1668 if ((replace.flags & OPT_COMMAND) == 0)
1669 print_error("No command specified");
1670 if ( replace.command != 'A' &&
1671 replace.command != 'D' && replace.command != 'I')
1672 print_error("Command and option do not match");
1673 if (c == 'i') {
1674 check_option(&replace.flags, OPT_IN);
1675 if (replace.selected_hook > 2 &&
1676 replace.selected_hook < NF_BR_BROUTING)
1677 print_error("Use in-interface only in "
1678 "INPUT, FORWARD, PREROUTING and"
1679 "BROUTING chains");
1680 if (check_inverse(optarg))
1681 new_entry->invflags |= EBT_IIN;
1682
1683 if (optind > argc)
1684 print_error("No in-interface "
1685 "specified");
1686 if (strlen(argv[optind - 1]) >= IFNAMSIZ)
1687 print_error("Illegal interfacelength");
1688 strcpy(new_entry->in, argv[optind - 1]);
1689 break;
1690 }
1691 if (c == 2) {
1692 check_option(&replace.flags, OPT_LOGICALIN);
1693 if (replace.selected_hook > 2 &&
1694 replace.selected_hook < NF_BR_BROUTING)
1695 print_error("Use logical in-interface "
1696 "only in INPUT, FORWARD, "
1697 "PREROUTING and BROUTING chains");
1698 if (check_inverse(optarg))
1699 new_entry->invflags |= EBT_ILOGICALIN;
1700
1701 if (optind > argc)
1702 print_error("No logical in-interface "
1703 "specified");
1704 if (strlen(argv[optind - 1]) >= IFNAMSIZ)
1705 print_error("Illegal interfacelength");
1706 strcpy(new_entry->logical_in, argv[optind - 1]);
1707 break;
1708 }
1709 if (c == 'o') {
1710 check_option(&replace.flags, OPT_OUT);
1711 if (replace.selected_hook < 2)
1712 print_error("Use out-interface only"
1713 " in OUTPUT, FORWARD and "
1714 "POSTROUTING chains");
1715 if (check_inverse(optarg))
1716 new_entry->invflags |= EBT_IOUT;
1717
1718 if (optind > argc)
1719 print_error("No out-interface "
1720 "specified");
1721
1722 if (strlen(argv[optind - 1]) >= IFNAMSIZ)
1723 print_error("Illegal interface "
1724 "length");
1725 strcpy(new_entry->out, argv[optind - 1]);
1726 break;
1727 }
1728 if (c == 3) {
1729 check_option(&replace.flags, OPT_LOGICALOUT);
1730 if (replace.selected_hook < 2)
1731 print_error("Use logical out-interface "
1732 "only in OUTPUT, FORWARD and "
1733 "POSTROUTING chains");
1734 if (check_inverse(optarg))
1735 new_entry->invflags |= EBT_ILOGICALOUT;
1736
1737 if (optind > argc)
1738 print_error("No logical out-interface "
1739 "specified");
1740
1741 if (strlen(argv[optind - 1]) >= IFNAMSIZ)
1742 print_error("Illegal interface "
1743 "length");
1744 strcpy(new_entry->logical_out,
1745 argv[optind - 1]);
1746 break;
1747 }
1748 if (c == 'j') {
1749
1750 check_option(&replace.flags, OPT_JUMP);
1751 for (i = 0; i < NUM_STANDARD_TARGETS; i++)
1752 if (!strcmp(optarg,
1753 standard_targets[i])) {
1754 t = find_target(
1755 EBT_STANDARD_TARGET);
1756 ((struct ebt_standard_target *)
Bart De Schuymer60332e02002-06-23 08:01:47 +00001757 t->t)->verdict = -i - 1;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001758 break;
1759 }
Bart De Schuymer60332e02002-06-23 08:01:47 +00001760 if (-i - 1 == EBT_RETURN) {
1761 if (replace.selected_hook < NF_BR_NUMHOOKS)
1762 print_error("Return target"
1763 " only for user defined chains");
1764 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001765 // must be an extension then
1766 if (i == NUM_STANDARD_TARGETS) {
1767 struct ebt_u_target *t;
1768 t = find_target(optarg);
1769 // -j standard not allowed either
1770 if (!t || t ==
1771 (struct ebt_u_target *)new_entry->t)
1772 print_error("Illegal target "
1773 "name");
1774 new_entry->t =
1775 (struct ebt_entry_target *)t;
1776 }
1777 break;
1778 }
1779 if (c == 's') {
1780 check_option(&replace.flags, OPT_SOURCE);
1781 if (check_inverse(optarg))
1782 new_entry->invflags |= EBT_ISOURCE;
1783
1784 if (optind > argc)
1785 print_error("No source mac "
1786 "specified");
1787 if (getmac_and_mask(argv[optind - 1],
1788 new_entry->sourcemac, new_entry->sourcemsk))
1789 print_error("Problem with specified "
1790 "source mac");
1791 new_entry->bitmask |= EBT_SOURCEMAC;
1792 break;
1793 }
1794 if (c == 'd') {
1795 check_option(&replace.flags, OPT_DEST);
1796 if (check_inverse(optarg))
1797 new_entry->invflags |= EBT_IDEST;
1798
1799 if (optind > argc)
1800 print_error("No destination mac "
1801 "specified");
1802 if (getmac_and_mask(argv[optind - 1],
1803 new_entry->destmac, new_entry->destmsk))
1804 print_error("Problem with specified "
1805 "destination mac");
1806 new_entry->bitmask |= EBT_DESTMAC;
1807 break;
1808 }
1809 check_option(&replace.flags, OPT_PROTOCOL);
1810 if (check_inverse(optarg))
1811 new_entry->invflags |= EBT_IPROTO;
1812
1813 if (optind > argc)
1814 print_error("No protocol specified");
1815 new_entry->bitmask &= ~((unsigned int)EBT_NOPROTO);
1816 i = strtol(argv[optind - 1], &buffer, 16);
1817 if (*buffer == '\0' && (i < 0 || i > 0xFFFF))
1818 print_error("Problem with the specified "
1819 "protocol");
1820 new_entry->ethproto = i;
1821 if (*buffer != '\0')
1822 if (name_to_protocol(argv[optind - 1]) == -1)
1823 print_error("Problem with the specified"
1824 " protocol");
1825 if (new_entry->ethproto < 1536 &&
1826 !(new_entry->bitmask & EBT_802_3))
1827 print_error("Sorry, protocols have values above"
1828 " or equal to 1536 (0x0600)");
1829 break;
1830
1831 case 'b': // allow database?
1832 if (replace.flags & OPT_COMMAND)
1833 print_error("Multiple commands not allowed");
1834 replace.command = c;
1835 allowbc = *optarg;
1836 break;
1837
1838 default:
1839
1840 // is it a target option?
1841 t = (struct ebt_u_target *)new_entry->t;
1842 if ((t->parse(c - t->option_offset, argv, argc,
1843 new_entry, &t->flags, &t->t)))
1844 continue;
1845
1846 // is it a match_option?
1847 for (m = matches; m; m = m->next)
1848 if (m->parse(c - m->option_offset, argv,
1849 argc, new_entry, &m->flags, &m->m))
1850 break;
1851
1852 if (m != NULL) {
1853 if (m->used == 0)
1854 add_match(m);
1855 continue;
1856 }
1857
1858 // is it a watcher option?
1859 for (w = watchers; w; w = w->next)
1860 if (w->parse(c-w->option_offset, argv,
1861 argc, new_entry, &w->flags, &w->w))
1862 break;
1863
1864 if (w == NULL)
1865 print_error("Unknown argument");
Bart De Schuymer60332e02002-06-23 08:01:47 +00001866 if (replace.command != 'A' && replace.command != 'I' &&
1867 replace.command != 'D')
1868 print_error("extensions only for -A, -I and -D");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001869 if (w->used == 0)
1870 add_watcher(w);
1871 }
1872 }
1873
1874 // database stuff before ebtables stuff
1875 if (replace.command == 'b')
1876 allowdb(allowbc);
1877 if (replace.command == 'L' && replace.selected_hook == DATABASEHOOKNR)
1878 list_db();
1879
1880 if ( (replace.flags & OPT_COMMAND) && replace.command != 'L' &&
1881 replace.flags & OPT_ZERO )
1882 print_error("Command -Z only allowed together with command -L");
1883
1884 if (replace.command == 'A' || replace.command == 'I' ||
1885 replace.command == 'D') {
1886 if (replace.selected_hook == -1)
1887 print_error("Not enough information");
1888 }
1889
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001890 // do this after parsing everything, so we can print specific info
1891 if (replace.command == 'h' && !(replace.flags & OPT_ZERO))
1892 print_help();
1893
1894 // do the final checks
Bart De Schuymer60332e02002-06-23 08:01:47 +00001895 if (replace.command == 'A' || replace.command == 'I' ||
1896 replace.command == 'D') {
1897 // this will put the hook_mask right for the chains
1898 check_for_loops();
1899 entries = to_chain();
1900 m_l = new_entry->m_list;
1901 w_l = new_entry->w_list;
1902 t = (struct ebt_u_target *)new_entry->t;
1903 while (m_l) {
1904 m = (struct ebt_u_match *)(m_l->m);
1905 m->final_check(new_entry, m->m, replace.name,
1906 entries->hook_mask);
1907 m_l = m_l->next;
1908 }
1909 while (w_l) {
1910 w = (struct ebt_u_watcher *)(w_l->w);
1911 w->final_check(new_entry, w->w, replace.name,
1912 entries->hook_mask);
1913 w_l = w_l->next;
1914 }
1915 t->final_check(new_entry, t->t, replace.name,
1916 entries->hook_mask);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001917 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001918
1919 // so, the extensions can work with the host endian
1920 // the kernel does not have to do this ofcourse
1921 new_entry->ethproto = htons(new_entry->ethproto);
1922
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001923 if (replace.command == 'P')
1924 change_policy(policy);
1925 else if (replace.command == 'L') {
1926 list_rules();
1927 if (replace.flags & OPT_ZERO)
1928 zero_counters(zerochain);
1929 else
1930 exit(0);
1931 }
1932 if (replace.flags & OPT_ZERO)
1933 zero_counters(zerochain);
1934 else if (replace.command == 'F')
1935 flush_chains();
1936 else if (replace.command == 'A' || replace.command == 'I')
1937 add_rule(rule_nr);
1938 else if (replace.command == 'D')
1939 delete_rule(rule_nr);
1940
1941 if (table->check)
1942 table->check(&replace);
1943
1944 deliver_table(&replace);
1945
1946 if (counterchanges)
1947 deliver_counters(&replace, counterchanges);
Bart De Schuymer60332e02002-06-23 08:01:47 +00001948// list_rules();
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001949 return 0;
1950}