blob: 56fd63015a989de94a8abd63f88a8fd175b57be1 [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
Bart De Schuymer8d1d8942002-07-15 20:09:09 +000065// do not mess around with the already assigned numbers unless
66// you know what you are doing
Bart De Schuymer62423742002-07-14 19:06:20 +000067static struct option ebt_original_options[] =
68{
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000069 { "append" , required_argument, 0, 'A' },
70 { "insert" , required_argument, 0, 'I' },
71 { "delete" , required_argument, 0, 'D' },
72 { "list" , optional_argument, 0, 'L' },
Bart De Schuymer9af14f92002-07-10 20:49:10 +000073 { "Lc" , no_argument , 0, 4 },
74 { "Ln" , no_argument , 0, 5 },
75 { "Lx" , no_argument , 0, 6 },
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000076 { "zero" , optional_argument, 0, 'Z' },
77 { "flush" , optional_argument, 0, 'F' },
78 { "policy" , required_argument, 0, 'P' },
79 { "in-interface" , required_argument, 0, 'i' },
80 { "in-if" , required_argument, 0, 'i' },
81 { "logical-in" , required_argument, 0, 2 },
82 { "logical-out" , required_argument, 0, 3 },
83 { "out-interface" , required_argument, 0, 'o' },
84 { "out-if" , required_argument, 0, 'o' },
85 { "version" , no_argument , 0, 'V' },
86 { "help" , no_argument , 0, 'h' },
87 { "jump" , required_argument, 0, 'j' },
88 { "proto" , required_argument, 0, 'p' },
89 { "protocol" , required_argument, 0, 'p' },
90 { "db" , required_argument, 0, 'b' },
91 { "source" , required_argument, 0, 's' },
92 { "src" , required_argument, 0, 's' },
93 { "destination" , required_argument, 0, 'd' },
94 { "dst" , required_argument, 0, 'd' },
95 { "table" , required_argument, 0, 't' },
Bart De Schuymerc8531032002-06-14 21:55:29 +000096 { "modprobe" , required_argument, 0, 'M' },
Bart De Schuymer1ab41562002-06-23 17:09:54 +000097 { "new-chain" , required_argument, 0, 'N' },
98 { "rename-chain" , required_argument, 0, 'E' },
99 { "delete-chain" , required_argument, 0, 'X' },
Bart De Schuymer62423742002-07-14 19:06:20 +0000100 { "atomic-init" , required_argument, 0, 7 },
Bart De Schuymer62423742002-07-14 19:06:20 +0000101 { "atomic-commit" , required_argument, 0, 8 },
102 { "atomic" , required_argument, 0, 9 },
103 { "atomic-save" , required_argument, 0, 10 },
Bart De Schuymer8d1d8942002-07-15 20:09:09 +0000104 { "init-table" , no_argument , 0, 11 },
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000105 { 0 }
106};
107
108static struct option *ebt_options = ebt_original_options;
109
110// yup, all the possible target names
Bart De Schuymer62423742002-07-14 19:06:20 +0000111char* standard_targets[NUM_STANDARD_TARGETS] =
112{
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000113 "ACCEPT",
114 "DROP",
115 "CONTINUE",
Bart De Schuymer60332e02002-06-23 08:01:47 +0000116 "RETURN",
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000117};
118
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000119unsigned char mac_type_unicast[ETH_ALEN] = {0,0,0,0,0,0};
120unsigned char msk_type_unicast[ETH_ALEN] = {1,0,0,0,0,0};
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000121unsigned char mac_type_multicast[ETH_ALEN] = {1,0,0,0,0,0};
122unsigned char msk_type_multicast[ETH_ALEN] = {1,0,0,0,0,0};
123unsigned char mac_type_broadcast[ETH_ALEN] = {255,255,255,255,255,255};
124unsigned char msk_type_broadcast[ETH_ALEN] = {255,255,255,255,255,255};
125
126// tells what happened to the old rules
127static unsigned short *counterchanges;
128// holds all the data
129static struct ebt_u_replace replace;
130
131// the chosen table
132static struct ebt_u_table *table = NULL;
133// the lists of supported tables, matches, watchers and targets
134static struct ebt_u_table *tables = NULL;
135static struct ebt_u_match *matches = NULL;
136static struct ebt_u_watcher *watchers = NULL;
137static struct ebt_u_target *targets = NULL;
138
139struct ebt_u_target *find_target(const char *name)
140{
141 struct ebt_u_target *t = targets;
142
143 while(t && strcmp(t->name, name))
144 t = t->next;
145 return t;
146}
147
148struct ebt_u_match *find_match(const char *name)
149{
150 struct ebt_u_match *m = matches;
151
152 while(m && strcmp(m->name, name))
153 m = m->next;
154 return m;
155}
156
157struct ebt_u_watcher *find_watcher(const char *name)
158{
159 struct ebt_u_watcher *w = watchers;
160
161 while(w && strcmp(w->name, name))
162 w = w->next;
163 return w;
164}
165
166struct ebt_u_table *find_table(char *name)
167{
168 struct ebt_u_table *t = tables;
169
170 while (t && strcmp(t->name, name))
171 t = t->next;
172 return t;
173}
174
175// The pointers in here are special:
176// The struct ebt_target * pointer is actually a struct ebt_u_target * pointer.
177// instead of making yet a few other structs, we just do a cast.
178// We need a struct ebt_u_target pointer because we know the address of the data
179// they point to won't change. We want to allow that the struct ebt_u_target.t
180// member can change.
181// Same holds for the struct ebt_match and struct ebt_watcher pointers
182struct ebt_u_entry *new_entry;
183
Bart De Schuymer62423742002-07-14 19:06:20 +0000184static void initialize_entry(struct ebt_u_entry *e)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000185{
186 e->bitmask = EBT_NOPROTO;
187 e->invflags = 0;
188 e->ethproto = 0;
189 strcpy(e->in, "");
190 strcpy(e->out, "");
191 strcpy(e->logical_in, "");
192 strcpy(e->logical_out, "");
193 e->m_list = NULL;
194 e->w_list = NULL;
195 // the init function of the standard target should have put the verdict
196 // on CONTINUE
197 e->t = (struct ebt_entry_target *)find_target(EBT_STANDARD_TARGET);
198 if (!e->t)
199 print_bug("Couldn't load standard target\n");
200}
201
202// this doesn't free e, becoz the calling function might need e->next
Bart De Schuymer62423742002-07-14 19:06:20 +0000203static void free_u_entry(struct ebt_u_entry *e)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000204{
205 struct ebt_u_match_list *m_l, *m_l2;
206 struct ebt_u_watcher_list *w_l, *w_l2;
207
208 m_l = e->m_list;
209 while (m_l) {
210 m_l2 = m_l->next;
211 free(m_l->m);
212 free(m_l);
213 m_l = m_l2;
214 }
215 w_l = e->w_list;
216 while (w_l) {
217 w_l2 = w_l->next;
218 free(w_l->w);
219 free(w_l);
220 w_l = w_l2;
221 }
222 free(e->t);
223}
224
225// the user will use the match, so put it in new_entry
226static void add_match(struct ebt_u_match *m)
227{
228 struct ebt_u_match_list **m_list, *new;
229
230 m->used = 1;
231 for (m_list = &new_entry->m_list;
232 *m_list; m_list = &(*m_list)->next);
233 new = (struct ebt_u_match_list *)
234 malloc(sizeof(struct ebt_u_match_list));
235 if (!new)
236 print_memory();
237 *m_list = new;
238 new->next = NULL;
239 new->m = (struct ebt_entry_match *)m;
240}
241
242static void add_watcher(struct ebt_u_watcher *w)
243{
244 struct ebt_u_watcher_list **w_list;
245 struct ebt_u_watcher_list *new;
246
247 w->used = 1;
248 for (w_list = &new_entry->w_list;
249 *w_list; w_list = &(*w_list)->next);
250 new = (struct ebt_u_watcher_list *)
251 malloc(sizeof(struct ebt_u_watcher_list));
252 if (!new)
253 print_memory();
254 *w_list = new;
255 new->next = NULL;
256 new->w = (struct ebt_entry_watcher *)w;
257}
258
259static int global_option_offset = 0;
260#define OPTION_OFFSET 256
261static struct option *
262merge_options(struct option *oldopts, const struct option *newopts,
263 unsigned int *options_offset)
264{
265 unsigned int num_old, num_new, i;
266 struct option *merge;
267
268 if (!newopts || !oldopts || !options_offset)
269 print_bug("merge wrong");
270 for (num_old = 0; oldopts[num_old].name; num_old++);
271 for (num_new = 0; newopts[num_new].name; num_new++);
272
273 global_option_offset += OPTION_OFFSET;
274 *options_offset = global_option_offset;
275
276 merge = malloc(sizeof(struct option) * (num_new + num_old + 1));
277 if (!merge)
278 print_memory();
279 memcpy(merge, oldopts, num_old * sizeof(struct option));
280 for (i = 0; i < num_new; i++) {
281 merge[num_old + i] = newopts[i];
282 merge[num_old + i].val += *options_offset;
283 }
284 memset(merge + num_old + num_new, 0, sizeof(struct option));
285 // only free dynamically allocated stuff
286 if (oldopts != ebt_original_options)
287 free(oldopts);
288
289 return merge;
290}
291
292void register_match(struct ebt_u_match *m)
293{
294 int size = m->size + sizeof(struct ebt_entry_match);
295 struct ebt_u_match **i;
296
297 m->m = (struct ebt_entry_match *)malloc(size);
298 if (!m->m)
299 print_memory();
300 strcpy(m->m->u.name, m->name);
301 m->m->match_size = m->size;
302 ebt_options = merge_options
303 (ebt_options, m->extra_ops, &(m->option_offset));
304 m->init(m->m);
305
306 for (i = &matches; *i; i = &((*i)->next));
307 m->next = NULL;
308 *i = m;
309}
310
311void register_watcher(struct ebt_u_watcher *w)
312{
313 int size = w->size + sizeof(struct ebt_entry_watcher);
314 struct ebt_u_watcher **i;
315
316 w->w = (struct ebt_entry_watcher *)malloc(size);
317 if (!w->w)
318 print_memory();
319 strcpy(w->w->u.name, w->name);
320 w->w->watcher_size = w->size;
321 ebt_options = merge_options
322 (ebt_options, w->extra_ops, &(w->option_offset));
323 w->init(w->w);
324
325 for (i = &watchers; *i; i = &((*i)->next));
326 w->next = NULL;
327 *i = w;
328}
329
330void register_target(struct ebt_u_target *t)
331{
332 int size = t->size + sizeof(struct ebt_entry_target);
333 struct ebt_u_target **i;
334
335 t->t = (struct ebt_entry_target *)malloc(size);
336 if (!t->t)
337 print_memory();
338 strcpy(t->t->u.name, t->name);
339 t->t->target_size = t->size;
340 ebt_options = merge_options
341 (ebt_options, t->extra_ops, &(t->option_offset));
342 t->init(t->t);
343 for (i = &targets; *i; i = &((*i)->next));
344 t->next = NULL;
345 *i = t;
346}
347
348void register_table(struct ebt_u_table *t)
349{
350 t->next = tables;
351 tables = t;
352}
353
Bart De Schuymerc8531032002-06-14 21:55:29 +0000354// blatently stolen (again) from iptables.c userspace program
355// find out where the modprobe utility is located
356static char *get_modprobe(void)
357{
358 int procfile;
359 char *ret;
360
361 procfile = open(PROC_SYS_MODPROBE, O_RDONLY);
362 if (procfile < 0)
363 return NULL;
364
365 ret = malloc(1024);
366 if (ret) {
367 switch (read(procfile, ret, 1024)) {
368 case -1: goto fail;
369 case 1024: goto fail; /* Partial read. Wierd */
370 }
371 if (ret[strlen(ret)-1]=='\n')
372 ret[strlen(ret)-1]=0;
373 close(procfile);
374 return ret;
375 }
376 fail:
377 free(ret);
378 close(procfile);
379 return NULL;
380}
381
382// I hate stealing, really... Lets call it a tribute.
383int ebtables_insmod(const char *modname, const char *modprobe)
384{
385 char *buf = NULL;
386 char *argv[3];
387
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000388 // If they don't explicitly set it, read out of kernel
Bart De Schuymerc8531032002-06-14 21:55:29 +0000389 if (!modprobe) {
390 buf = get_modprobe();
391 if (!buf)
392 return -1;
393 modprobe = buf;
394 }
395
396 switch (fork()) {
397 case 0:
398 argv[0] = (char *)modprobe;
399 argv[1] = (char *)modname;
400 argv[2] = NULL;
401 execv(argv[0], argv);
402
403 /* not usually reached */
404 exit(0);
405 case -1:
406 return -1;
407
408 default: /* parent */
409 wait(NULL);
410 }
411
412 free(buf);
413 return 0;
414}
415
Bart De Schuymerbbca3202002-06-05 18:55:44 +0000416// helper function: processes a line of data from the file /etc/ethertypes
Bart De Schuymer62423742002-07-14 19:06:20 +0000417static int get_a_line(char *buffer, char *value, FILE *ifp)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000418{
Bart De Schuymerf662ce52002-07-19 18:40:55 +0000419 char line[80], *p;
420 const char delim[] = " \t\n";
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000421
Bart De Schuymerf662ce52002-07-19 18:40:55 +0000422 while (fgets(line, sizeof(line), ifp)) {
423 p = strtok(line, delim);
424 if (!p || p[0] == '#')
425 continue;
426 if (strlen(p) > 20)
427 continue;
428 strcpy(buffer, p);
429 p = strtok(NULL, delim);
430 if (!p || strlen(p) > 10)
431 continue;
432 strcpy(value, p);
433 return 0;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000434 }
Bart De Schuymerf662ce52002-07-19 18:40:55 +0000435 return -1;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000436}
437
Bart De Schuymerb909f9b2002-06-26 18:35:31 +0000438// translate a hexadecimal number to a protocol name, parsing /etc/ethertypes
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000439// returns 0 on success
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000440int number_to_name(unsigned short proto, char *name)
441{
442 FILE *ifp;
Bart De Schuymerf662ce52002-07-19 18:40:55 +0000443 char buffer[21], value[11], *bfr;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000444 unsigned short i;
445
446 if ( !(ifp = fopen(PROTOCOLFILE, "r")) )
447 return -1;
448 while (1) {
449 if (get_a_line(buffer, value, ifp)) {
450 fclose(ifp);
451 return -1;
452 }
453 i = (unsigned short) strtol(value, &bfr, 16);
454 if (*bfr != '\0' || i != proto)
455 continue;
456 strcpy(name, buffer);
457 fclose(ifp);
458 return 0;
459 }
460}
461
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000462// we use replace.flags, so we can't use the following values:
463// 0x01 == OPT_COMMAND, 0x02 == OPT_TABLE, 0x100 == OPT_ZERO
464#define LIST_N 0x04
465#define LIST_C 0x08
466#define LIST_X 0x10
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000467// helper function for list_rules()
Bart De Schuymer60332e02002-06-23 08:01:47 +0000468static void list_em(struct ebt_u_entries *entries)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000469{
470 int i, j, space = 0, digits;
471 struct ebt_u_entry *hlp;
472 struct ebt_u_match_list *m_l;
473 struct ebt_u_watcher_list *w_l;
474 struct ebt_u_match *m;
475 struct ebt_u_watcher *w;
476 struct ebt_u_target *t;
477 char name[21];
478
Bart De Schuymer60332e02002-06-23 08:01:47 +0000479 hlp = entries->entries;
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000480 if (replace.flags & LIST_X && entries->policy != EBT_ACCEPT) {
481 printf("ebtables -t %s -P %s %s\n", replace.name,
482 entries->name, standard_targets[-entries->policy - 1]);
483 } else if (!(replace.flags & LIST_X)) {
484 printf("\nBridge chain: %s\nPolicy: %s\n", entries->name,
485 standard_targets[-entries->policy - 1]);
486 printf("nr. of entries: %d \n", entries->nentries);
487 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000488
Bart De Schuymer60332e02002-06-23 08:01:47 +0000489 i = entries->nentries;
Bart De Schuymerf8f8f292002-06-25 15:43:57 +0000490 while (i > 9) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000491 space++;
492 i /= 10;
493 }
494
Bart De Schuymer60332e02002-06-23 08:01:47 +0000495 for (i = 0; i < entries->nentries; i++) {
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000496 if (replace.flags & LIST_N) {
497 digits = 0;
498 // A little work to get nice rule numbers.
499 j = i + 1;
500 while (j > 9) {
501 digits++;
502 j /= 10;
503 }
504 for (j = 0; j < space - digits; j++)
505 printf(" ");
506 printf("%d. ", i + 1);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000507 }
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000508 if (replace.flags & LIST_X)
509 printf("ebtables -t %s -A %s ",
510 replace.name, entries->name);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000511
512 // Don't print anything about the protocol if no protocol was
513 // specified, obviously this means any protocol will do.
514 if (!(hlp->bitmask & EBT_NOPROTO)) {
Bart De Schuymer60332e02002-06-23 08:01:47 +0000515 printf("-p ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000516 if (hlp->invflags & EBT_IPROTO)
517 printf("! ");
518 if (hlp->bitmask & EBT_802_3)
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000519 printf("Length ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000520 else {
521 if (number_to_name(ntohs(hlp->ethproto), name))
Bart De Schuymer60332e02002-06-23 08:01:47 +0000522 printf("0x%x ", ntohs(hlp->ethproto));
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000523 else
Bart De Schuymer60332e02002-06-23 08:01:47 +0000524 printf("%s ", name);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000525 }
526 }
527 if (hlp->bitmask & EBT_SOURCEMAC) {
528 char hlpmsk[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
529
Bart De Schuymer60332e02002-06-23 08:01:47 +0000530 printf("-s ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000531 if (hlp->invflags & EBT_ISOURCE)
532 printf("! ");
533 if (!memcmp(hlp->sourcemac, mac_type_unicast, 6) &&
534 !memcmp(hlp->sourcemsk, msk_type_unicast, 6)) {
535 printf("Unicast");
536 goto endsrc;
537 }
538 if (!memcmp(hlp->sourcemac, mac_type_multicast, 6) &&
539 !memcmp(hlp->sourcemsk, msk_type_multicast, 6)) {
540 printf("Multicast");
541 goto endsrc;
542 }
543 if (!memcmp(hlp->sourcemac, mac_type_broadcast, 6) &&
544 !memcmp(hlp->sourcemsk, msk_type_broadcast, 6)) {
545 printf("Broadcast");
546 goto endsrc;
547 }
Bart De Schuymer41830412002-06-05 19:41:28 +0000548 printf("%s", ether_ntoa((struct ether_addr *)
549 hlp->sourcemac));
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000550 if (memcmp(hlp->sourcemsk, hlpmsk, 6)) {
551 printf("/");
Bart De Schuymer41830412002-06-05 19:41:28 +0000552 printf("%s", ether_ntoa((struct ether_addr *)
553 hlp->sourcemsk));
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000554 }
555endsrc:
Bart De Schuymer60332e02002-06-23 08:01:47 +0000556 printf(" ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000557 }
558 if (hlp->bitmask & EBT_DESTMAC) {
559 char hlpmsk[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
560
Bart De Schuymer60332e02002-06-23 08:01:47 +0000561 printf("-d ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000562 if (hlp->invflags & EBT_IDEST)
563 printf("! ");
564 if (!memcmp(hlp->destmac, mac_type_unicast, 6) &&
565 !memcmp(hlp->destmsk, msk_type_unicast, 6)) {
566 printf("Unicast");
567 goto enddst;
568 }
569 if (!memcmp(hlp->destmac, mac_type_multicast, 6) &&
570 !memcmp(hlp->destmsk, msk_type_multicast, 6)) {
571 printf("Multicast");
572 goto enddst;
573 }
574 if (!memcmp(hlp->destmac, mac_type_broadcast, 6) &&
575 !memcmp(hlp->destmsk, msk_type_broadcast, 6)) {
576 printf("Broadcast");
577 goto enddst;
578 }
Bart De Schuymer41830412002-06-05 19:41:28 +0000579 printf("%s", ether_ntoa((struct ether_addr *)
580 hlp->destmac));
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000581 if (memcmp(hlp->destmsk, hlpmsk, 6)) {
582 printf("/");
Bart De Schuymer41830412002-06-05 19:41:28 +0000583 printf("%s", ether_ntoa((struct ether_addr *)
584 hlp->destmsk));
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000585 }
586enddst:
Bart De Schuymer60332e02002-06-23 08:01:47 +0000587 printf(" ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000588 }
589 if (hlp->in[0] != '\0') {
Bart De Schuymer60332e02002-06-23 08:01:47 +0000590 printf("-i ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000591 if (hlp->invflags & EBT_IIN)
592 printf("! ");
Bart De Schuymer60332e02002-06-23 08:01:47 +0000593 printf("%s ", hlp->in);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000594 }
595 if (hlp->logical_in[0] != '\0') {
Bart De Schuymer60332e02002-06-23 08:01:47 +0000596 printf("--logical-in ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000597 if (hlp->invflags & EBT_ILOGICALIN)
598 printf("! ");
Bart De Schuymer60332e02002-06-23 08:01:47 +0000599 printf("%s ", hlp->logical_in);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000600 }
601 if (hlp->logical_out[0] != '\0') {
Bart De Schuymer60332e02002-06-23 08:01:47 +0000602 printf("--logical-out ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000603 if (hlp->invflags & EBT_ILOGICALOUT)
604 printf("! ");
Bart De Schuymerb3d8f262002-07-07 14:26:15 +0000605 printf("%s ", hlp->logical_out);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000606 }
607 if (hlp->out[0] != '\0') {
Bart De Schuymer60332e02002-06-23 08:01:47 +0000608 printf("-o ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000609 if (hlp->invflags & EBT_IOUT)
610 printf("! ");
Bart De Schuymerb3d8f262002-07-07 14:26:15 +0000611 printf("%s ", hlp->out);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000612 }
613
614 m_l = hlp->m_list;
615 while (m_l) {
616 m = find_match(m_l->m->u.name);
617 if (!m)
618 print_bug("Match not found");
619 m->print(hlp, m_l->m);
620 m_l = m_l->next;
621 }
622 w_l = hlp->w_list;
623 while (w_l) {
624 w = find_watcher(w_l->w->u.name);
625 if (!w)
626 print_bug("Watcher not found");
627 w->print(hlp, w_l->w);
628 w_l = w_l->next;
629 }
630
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000631 printf("-j ");
632 if (strcmp(hlp->t->u.name, EBT_STANDARD_TARGET))
633 printf("%s ", hlp->t->u.name);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000634 t = find_target(hlp->t->u.name);
635 if (!t)
636 print_bug("Target not found");
637 t->print(hlp, hlp->t);
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000638 if (replace.flags & LIST_C)
639 printf(", count = %llu",
640 replace.counters[entries->counter_offset + i].pcnt);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000641 printf("\n");
642 hlp = hlp->next;
643 }
644}
645
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000646struct ebt_u_entries *nr_to_chain(int nr)
Bart De Schuymer60332e02002-06-23 08:01:47 +0000647{
648 if (nr == -1)
649 return NULL;
650 if (nr < NF_BR_NUMHOOKS)
651 return replace.hook_entry[nr];
652 else {
653 int i;
654 struct ebt_u_chain_list *cl = replace.udc;
655
656 i = nr - NF_BR_NUMHOOKS;
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000657 while (i > 0 && cl) {
Bart De Schuymer60332e02002-06-23 08:01:47 +0000658 cl = cl->next;
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000659 i--;
660 }
Bart De Schuymer60332e02002-06-23 08:01:47 +0000661 if (cl)
662 return cl->udc;
663 else
664 return NULL;
665 }
666}
667
668static struct ebt_u_entries *to_chain()
669{
670 return nr_to_chain(replace.selected_hook);
671}
672
673struct ebt_u_stack
674{
675 int chain_nr;
676 int n;
677 struct ebt_u_entry *e;
678 struct ebt_u_entries *entries;
679};
680
Bart De Schuymer62423742002-07-14 19:06:20 +0000681static void check_for_loops()
Bart De Schuymer60332e02002-06-23 08:01:47 +0000682{
683 int chain_nr , i, j , k, sp = 0, verdict;
684 struct ebt_u_entries *entries, *entries2;
685 struct ebt_u_stack *stack = NULL;
686 struct ebt_u_entry *e;
687
688 i = -1;
689 // initialize hook_mask to 0
690 while (1) {
691 i++;
692 if (i < NF_BR_NUMHOOKS && !(replace.valid_hooks & (1 << i)))
693 continue;
694 entries = nr_to_chain(i);
695 if (!entries)
696 break;
697 entries->hook_mask = 0;
698 }
699 if (i > NF_BR_NUMHOOKS) {
700 stack = (struct ebt_u_stack *)malloc((i - NF_BR_NUMHOOKS) *
701 sizeof(struct ebt_u_stack));
702 if (!stack)
703 print_memory();
704 }
705
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000706 // check for loops, starting from every base chain
Bart De Schuymer60332e02002-06-23 08:01:47 +0000707 for (i = 0; i < NF_BR_NUMHOOKS; i++) {
708 if (!(replace.valid_hooks & (1 << i)))
709 continue;
710 entries = nr_to_chain(i);
711 entries->hook_mask = (1 << i);
712 chain_nr = i;
713
714 e = entries->entries;
715 for (j = 0; j < entries->nentries; j++) {
716 if (strcmp(e->t->u.name, EBT_STANDARD_TARGET))
717 goto letscontinue;
718 verdict = ((struct ebt_standard_target *)(e->t))->verdict;
719 if (verdict < 0)
720 goto letscontinue;
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000721 entries2 = nr_to_chain(verdict + NF_BR_NUMHOOKS);
Bart De Schuymer60332e02002-06-23 08:01:47 +0000722 entries2->hook_mask |= entries->hook_mask;
723 // now see if we've been here before
724 for (k = 0; k < sp; k++)
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000725 if (stack[k].chain_nr == verdict + NF_BR_NUMHOOKS)
Bart De Schuymer1a0a9c32002-06-24 21:10:16 +0000726 print_error("Loop from chain %s to chain %s",
727 nr_to_chain(chain_nr)->name, nr_to_chain(stack[k].chain_nr)->name);
Bart De Schuymer60332e02002-06-23 08:01:47 +0000728 // jump to the chain, make sure we know how to get back
729 stack[sp].chain_nr = chain_nr;
730 stack[sp].n = j;
731 stack[sp].entries = entries;
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000732 stack[sp].e = e;
733 sp++;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000734 j = -1;
735 e = entries2->entries;
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000736 chain_nr = verdict + NF_BR_NUMHOOKS;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000737 entries = entries2;
738 continue;
739letscontinue:
740 e = e->next;
741 }
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000742 // we are at the end of a standard chain
Bart De Schuymer60332e02002-06-23 08:01:47 +0000743 if (sp == 0)
744 continue;
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000745 // go back to the chain one level higher
Bart De Schuymer60332e02002-06-23 08:01:47 +0000746 sp--;
747 j = stack[sp].n;
748 chain_nr = stack[sp].chain_nr;
749 e = stack[sp].e;
750 entries = stack[sp].entries;
751 goto letscontinue;
752 }
753 free(stack);
754 return;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000755}
756
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000757// parse the chain name and return the corresponding nr
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000758// returns -1 on failure
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000759int get_hooknr(char* arg)
760{
761 int i;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000762 struct ebt_u_chain_list *cl = replace.udc;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000763
764 // database is special case (not really a chain)
765 if (!strcmp(arg, DATABASEHOOKNAME))
766 return DATABASEHOOKNR;
767
Bart De Schuymer60332e02002-06-23 08:01:47 +0000768 for (i = 0; i < NF_BR_NUMHOOKS; i++) {
769 if (!(replace.valid_hooks & (1 << i)))
770 continue;
771 if (!strcmp(arg, replace.hook_entry[i]->name))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000772 return i;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000773 }
774 while(cl) {
775 if (!strcmp(arg, cl->udc->name))
776 return i;
777 i++;
778 cl = cl->next;
779 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000780 return -1;
781}
782
783// yup, print out help
Bart De Schuymer62423742002-07-14 19:06:20 +0000784static void print_help()
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000785{
786 struct ebt_u_match_list *m_l;
787 struct ebt_u_watcher_list *w_l;
788
789 printf(
790"%s v%s\n"
791"Usage:\n"
792"ebtables -[ADI] chain rule-specification [options]\n"
793"ebtables -P chain target\n"
794"ebtables -[LFZ] [chain]\n"
795"ebtables -[b] [y,n]\n"
796"Commands:\n"
797"--append -A chain : Append to chain\n"
798"--delete -D chain : Delete matching rule from chain\n"
799"--delete -D chain rulenum : Delete rule at position rulenum from chain\n"
800"--insert -I chain rulenum : insert rule at position rulenum in chain\n"
801"--list -L [chain] : List the rules in a chain or in all chains\n"
802"--list -L "DATABASEHOOKNAME" : List the database (if present)\n"
803"--flush -F [chain] : Delete all rules in chain or in all chains\n"
Bart De Schuymer8d1d8942002-07-15 20:09:09 +0000804"--init-table : Replace the kernel table with the initial table\n"
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000805"--zero -Z [chain] : Put counters on zero in chain or in all chains\n"
806"--policy -P chain target : Change policy on chain to target\n"
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000807"--new-chain -N chain : Create a user defined chain\n"
808"--rename-chain -E old new : Rename a chain\n"
809"--delete-chain -X chain : Delete a user defined chain\n"
Bart De Schuymer62423742002-07-14 19:06:20 +0000810"--atomic-commit file : update the kernel w/ the table contained in file\n"
811"--atomic-init file : put the initial kernel table into file\n"
812"--atomic-save file : put the current kernel table into file\n"
813"--atomic file : write changes to file instead of kernel\n"
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000814"Options:\n"
815"--proto -p [!] proto : protocol hexadecimal, by name or LENGTH\n"
816"--src -s [!] address[/mask]: source mac address\n"
817"--dst -d [!] address[/mask]: destination mac address\n"
818"--in-if -i [!] name : network input interface name\n"
819"--out-if -o [!] name : network output interface name\n"
820"--logical-in [!] name : logical bridge input interface name\n"
821"--logical-out [!] name : logical bridge output interface name\n"
Bart De Schuymer5cbc8e02002-07-14 21:15:28 +0000822"--modprobe -M program : try to insert modules using this program\n"
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000823"--version -V : print package version\n"
824"\n" ,
825 prog_name,
826 prog_version);
827
828 m_l = new_entry->m_list;
829 while (m_l) {
830 ((struct ebt_u_match *)m_l->m)->help();
831 printf("\n");
832 m_l = m_l->next;
833 }
834 w_l = new_entry->w_list;
835 while (w_l) {
836 ((struct ebt_u_watcher *)w_l->w)->help();
837 printf("\n");
838 w_l = w_l->next;
839 }
840 ((struct ebt_u_target *)new_entry->t)->help();
841 printf("\n");
842 if (table->help)
843 table->help(hooknames);
844 exit(0);
845}
846
847// execute command L
848static void list_rules()
849{
850 int i;
851
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000852 if (!(replace.flags & LIST_X))
853 printf("Bridge table: %s\n", table->name);
Bart De Schuymer60332e02002-06-23 08:01:47 +0000854 if (replace.selected_hook != -1) {
855 list_em(to_chain());
856 } else {
857 struct ebt_u_chain_list *cl = replace.udc;
858
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000859 // create new chains and rename standard chains when necessary
860 if (replace.flags & LIST_X) {
861 while (cl) {
862 printf("ebtables -t %s -N %s\n", replace.name,
863 cl->udc->name);
864 cl = cl->next;
865 }
866 cl = replace.udc;
867 for (i = 0; i < NF_BR_NUMHOOKS; i++)
868 if (replace.valid_hooks & (1 << i) &&
869 strcmp(replace.hook_entry[i]->name, hooknames[i]))
870 printf("ebtables -t %s -E %s %s\n",
871 replace.name, hooknames[i],
872 replace.hook_entry[i]->name);
873 }
Bart De Schuymer60332e02002-06-23 08:01:47 +0000874 i = 0;
875 while (1) {
876 if (i < NF_BR_NUMHOOKS) {
877 if (replace.valid_hooks & (1 << i))
878 list_em(replace.hook_entry[i]);
879 i++;
880 continue;
881 } else {
882 if (!cl)
883 break;
884 list_em(cl->udc);
885 cl = cl->next;
886 }
887 }
888 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000889}
890
891// execute command P
892static void change_policy(int policy)
893{
894 int i;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000895 struct ebt_u_entries *entries = to_chain();
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000896
897 // don't do anything if the policy is the same
Bart De Schuymer60332e02002-06-23 08:01:47 +0000898 if (entries->policy != policy) {
899 entries->policy = policy;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000900 replace.num_counters = replace.nentries;
901 if (replace.nentries) {
902 // '+ 1' for the CNT_END
903 if (!(counterchanges = (unsigned short *) malloc(
904 (replace.nentries + 1) * sizeof(unsigned short))))
905 print_memory();
906 // done nothing special to the rules
907 for (i = 0; i < replace.nentries; i++)
908 counterchanges[i] = CNT_NORM;
909 counterchanges[replace.nentries] = CNT_END;
910 }
911 else
912 counterchanges = NULL;
913 }
914 else
915 exit(0);
916}
917
918// flush one chain or the complete table
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000919// -1 == nothing to do
920// 0 == give back to kernel
921static int flush_chains()
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000922{
Bart De Schuymer60332e02002-06-23 08:01:47 +0000923 int i, j, oldnentries, numdel;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000924 unsigned short *cnt;
925 struct ebt_u_entry *u_e, *tmp;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000926 struct ebt_u_entries *entries = to_chain();
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000927
928 // flush whole table
Bart De Schuymer60332e02002-06-23 08:01:47 +0000929 if (!entries) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000930 if (replace.nentries == 0)
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000931 return -1;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000932 replace.nentries = 0;
933 // no need for the kernel to give us counters back
934 replace.num_counters = 0;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000935
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000936 // free everything and zero (n)entries
Bart De Schuymer60332e02002-06-23 08:01:47 +0000937 i = -1;
938 while (1) {
939 i++;
940 entries = nr_to_chain(i);
941 if (!entries) {
942 if (i < NF_BR_NUMHOOKS)
943 continue;
944 else
945 break;
946 }
947 entries->nentries = 0;
948 entries->counter_offset = 0;
949 u_e = entries->entries;
950 entries->entries = NULL;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000951 while (u_e) {
952 free_u_entry(u_e);
953 tmp = u_e->next;
954 free(u_e);
955 u_e = tmp;
956 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000957 }
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000958 return 0;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000959 }
960
Bart De Schuymer60332e02002-06-23 08:01:47 +0000961 if (entries->nentries == 0)
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000962 return -1;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000963 oldnentries = replace.nentries;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000964 replace.nentries -= entries->nentries;
965 numdel = entries->nentries;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000966
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000967 if (replace.nentries) {
968 // +1 for CNT_END
969 if ( !(counterchanges = (unsigned short *)
970 malloc((oldnentries + 1) * sizeof(unsigned short))) )
971 print_memory();
Bart De Schuymer60332e02002-06-23 08:01:47 +0000972 }
973 // delete the counters belonging to the specified chain,
974 // update counter_offset
975 i = -1;
Bart De Schuymerf8f8f292002-06-25 15:43:57 +0000976 cnt = counterchanges;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000977 while (1) {
978 i++;
979 entries = nr_to_chain(i);
980 if (!entries) {
981 if (i < NF_BR_NUMHOOKS)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000982 continue;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000983 else
984 break;
985 }
986 if (i > replace.selected_hook)
987 entries->counter_offset -= numdel;
988 if (replace.nentries) {
989 for (j = 0; j < entries->nentries; j++) {
990 if (i == replace.selected_hook)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000991 *cnt = CNT_DEL;
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000992 else
993 *cnt = CNT_NORM;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000994 cnt++;
995 }
996 }
Bart De Schuymer60332e02002-06-23 08:01:47 +0000997 }
998
999 if (replace.nentries) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001000 *cnt = CNT_END;
1001 replace.num_counters = oldnentries;
1002 }
1003 else
1004 replace.num_counters = 0;
1005
Bart De Schuymer60332e02002-06-23 08:01:47 +00001006 entries = to_chain();
1007 entries->nentries = 0;
1008 u_e = entries->entries;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001009 while (u_e) {
1010 free_u_entry(u_e);
1011 tmp = u_e->next;
1012 free(u_e);
1013 u_e = tmp;
1014 }
Bart De Schuymer60332e02002-06-23 08:01:47 +00001015 entries->entries = NULL;
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001016 return 0;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001017}
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001018
1019// -1 == no match
1020static int check_rule_exists(int rule_nr)
1021{
1022 struct ebt_u_entry *u_e;
1023 struct ebt_u_match_list *m_l, *m_l2;
1024 struct ebt_u_match *m;
1025 struct ebt_u_watcher_list *w_l, *w_l2;
1026 struct ebt_u_watcher *w;
1027 struct ebt_u_target *t = (struct ebt_u_target *)new_entry->t;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001028 struct ebt_u_entries *entries = to_chain();
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001029 int i, j, k;
1030
1031 // handle '-D chain rulenr' command
1032 if (rule_nr != -1) {
Bart De Schuymer60332e02002-06-23 08:01:47 +00001033 if (rule_nr > entries->nentries)
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001034 return -1;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001035 // user starts counting from 1
1036 return rule_nr - 1;
1037 }
Bart De Schuymer60332e02002-06-23 08:01:47 +00001038 u_e = entries->entries;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001039 // check for an existing rule (if there are duplicate rules,
1040 // take the first occurance)
Bart De Schuymer60332e02002-06-23 08:01:47 +00001041 for (i = 0; i < entries->nentries; i++, u_e = u_e->next) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001042 if (!u_e)
1043 print_bug("Hmm, trouble");
1044 if ( u_e->ethproto == new_entry->ethproto
1045 && !strcmp(u_e->in, new_entry->in)
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001046 && !strcmp(u_e->out, new_entry->out)) {
Bart De Schuymer60332e02002-06-23 08:01:47 +00001047 if (strcmp(u_e->logical_in, new_entry->logical_in) ||
1048 strcmp(u_e->logical_out, new_entry->logical_out))
1049 continue;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001050 if (new_entry->bitmask & EBT_SOURCEMAC &&
Bart De Schuymer60332e02002-06-23 08:01:47 +00001051 memcmp(u_e->sourcemac, new_entry->sourcemac, ETH_ALEN))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001052 continue;
1053 if (new_entry->bitmask & EBT_DESTMAC &&
Bart De Schuymer60332e02002-06-23 08:01:47 +00001054 memcmp(u_e->destmac, new_entry->destmac, ETH_ALEN))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001055 continue;
1056 if (new_entry->bitmask != u_e->bitmask ||
1057 new_entry->invflags != u_e->invflags)
1058 continue;
1059 // compare all matches
1060 m_l = new_entry->m_list;
1061 j = 0;
1062 while (m_l) {
1063 m = (struct ebt_u_match *)(m_l->m);
1064 m_l2 = u_e->m_list;
1065 while (m_l2 &&
1066 strcmp(m_l2->m->u.name, m->m->u.name))
1067 m_l2 = m_l2->next;
1068 if (!m_l2 || !m->compare(m->m, m_l2->m))
1069 goto letscontinue;
1070 j++;
1071 m_l = m_l->next;
1072 }
1073 // now be sure they have the same nr of matches
1074 k = 0;
1075 m_l = u_e->m_list;
1076 while (m_l) {
1077 k++;
1078 m_l = m_l->next;
1079 }
1080 if (j != k)
1081 continue;
1082
1083 // compare all watchers
1084 w_l = new_entry->w_list;
1085 j = 0;
1086 while (w_l) {
1087 w = (struct ebt_u_watcher *)(w_l->w);
1088 w_l2 = u_e->w_list;
1089 while (w_l2 &&
1090 strcmp(w_l2->w->u.name, w->w->u.name))
1091 w_l2 = w_l2->next;
1092 if (!w_l2 || !w->compare(w->w, w_l2->w))
1093 goto letscontinue;
1094 j++;
1095 w_l = w_l->next;
1096 }
1097 k = 0;
1098 w_l = u_e->w_list;
1099 while (w_l) {
1100 k++;
1101 w_l = w_l->next;
1102 }
1103 if (j != k)
1104 continue;
1105 if (strcmp(t->t->u.name, u_e->t->u.name))
1106 continue;
1107 if (!t->compare(t->t, u_e->t))
1108 continue;
1109 return i;
1110 }
1111letscontinue:
1112 }
1113 return -1;
1114}
1115
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001116// execute command A or I
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001117static void add_rule(int rule_nr)
1118{
1119 int i, j;
1120 struct ebt_u_entry *u_e, *u_e2;
1121 unsigned short *cnt;
1122 struct ebt_u_match_list *m_l;
1123 struct ebt_u_watcher_list *w_l;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001124 struct ebt_u_entries *entries = to_chain(), *entries2;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001125
1126 if (rule_nr != -1) { // command -I
Bart De Schuymer60332e02002-06-23 08:01:47 +00001127 if (--rule_nr > entries->nentries)
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001128 print_error("rule nr too high: %d > %d", rule_nr + 1,
1129 entries->nentries + 1);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001130 } else
Bart De Schuymer60332e02002-06-23 08:01:47 +00001131 rule_nr = entries->nentries;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001132 // we're adding one rule
1133 replace.num_counters = replace.nentries;
1134 replace.nentries++;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001135 entries->nentries++;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001136
1137 // handle counter stuff
1138 // +1 for CNT_END
1139 if ( !(counterchanges = (unsigned short *)
1140 malloc((replace.nentries + 1) * sizeof(unsigned short))) )
1141 print_memory();
1142 cnt = counterchanges;
1143 for (i = 0; i < replace.selected_hook; i++) {
Bart De Schuymer60332e02002-06-23 08:01:47 +00001144 if (i < NF_BR_NUMHOOKS && !(replace.valid_hooks & (1 << i)))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001145 continue;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001146 entries2 = nr_to_chain(i);
1147 for (j = 0; j < entries2->nentries; j++) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001148 *cnt = CNT_NORM;
1149 cnt++;
1150 }
1151 }
1152 for (i = 0; i < rule_nr; i++) {
1153 *cnt = CNT_NORM;
1154 cnt++;
1155 }
1156 *cnt = CNT_ADD;
1157 cnt++;
1158 while (cnt != counterchanges + replace.nentries) {
1159 *cnt = CNT_NORM;
1160 cnt++;
1161 }
1162 *cnt = CNT_END;
1163
1164 // go to the right position in the chain
1165 u_e2 = NULL;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001166 u_e = entries->entries;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001167 for (i = 0; i < rule_nr; i++) {
1168 u_e2 = u_e;
1169 u_e = u_e->next;
1170 }
1171 // insert the rule
1172 if (u_e2)
1173 u_e2->next = new_entry;
1174 else
Bart De Schuymer60332e02002-06-23 08:01:47 +00001175 entries->entries = new_entry;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001176 new_entry->next = u_e;
1177
1178 // put the ebt_[match, watcher, target] pointers in place
1179 m_l = new_entry->m_list;
1180 while (m_l) {
1181 m_l->m = ((struct ebt_u_match *)m_l->m)->m;
1182 m_l = m_l->next;
1183 }
1184 w_l = new_entry->w_list;
1185 while (w_l) {
1186 w_l->w = ((struct ebt_u_watcher *)w_l->w)->w;
1187 w_l = w_l->next;
1188 }
1189 new_entry->t = ((struct ebt_u_target *)new_entry->t)->t;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001190
1191 // update the counter_offset of chains behind this one
1192 i = replace.selected_hook;
1193 while (1) {
1194 i++;
1195 entries = nr_to_chain(i);
1196 if (!entries) {
1197 if (i < NF_BR_NUMHOOKS)
1198 continue;
1199 else
1200 break;
1201 } else
1202 entries->counter_offset++;
1203 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001204}
1205
1206// execute command D
1207static void delete_rule(int rule_nr)
1208{
1209 int i, j, lentmp = 0;
1210 unsigned short *cnt;
1211 struct ebt_u_entry *u_e, *u_e2;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001212 struct ebt_u_entries *entries = to_chain(), *entries2;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001213
1214 if ( (i = check_rule_exists(rule_nr)) == -1 )
Bart De Schuymer60332e02002-06-23 08:01:47 +00001215 print_error("Sorry, rule does not exist");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001216
1217 // we're deleting a rule
1218 replace.num_counters = replace.nentries;
1219 replace.nentries--;
1220
1221 if (replace.nentries) {
1222 for (j = 0; j < replace.selected_hook; j++) {
Bart De Schuymer60332e02002-06-23 08:01:47 +00001223 if (j < NF_BR_NUMHOOKS &&
1224 !(replace.valid_hooks & (1 << j)))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001225 continue;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001226 entries2 = nr_to_chain(j);
1227 lentmp += entries2->nentries;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001228 }
1229 lentmp += i;
1230 // +1 for CNT_END
1231 if ( !(counterchanges = (unsigned short *)malloc(
1232 (replace.num_counters + 1) * sizeof(unsigned short))) )
1233 print_memory();
1234 cnt = counterchanges;
1235 for (j = 0; j < lentmp; j++) {
1236 *cnt = CNT_NORM;
1237 cnt++;
1238 }
1239 *cnt = CNT_DEL;
1240 cnt++;
1241 for (j = 0; j < replace.num_counters - lentmp; j++) {
1242 *cnt = CNT_NORM;
1243 cnt++;
1244 }
1245 *cnt = CNT_END;
1246 }
1247 else
1248 replace.num_counters = 0;
1249
1250 // go to the right position in the chain
1251 u_e2 = NULL;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001252 u_e = entries->entries;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001253 for (j = 0; j < i; j++) {
1254 u_e2 = u_e;
1255 u_e = u_e->next;
1256 }
1257
1258 // remove from the chain
1259 if (u_e2)
1260 u_e2->next = u_e->next;
1261 else
Bart De Schuymer60332e02002-06-23 08:01:47 +00001262 entries->entries = u_e->next;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001263
Bart De Schuymer60332e02002-06-23 08:01:47 +00001264 entries->nentries--;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001265 // free everything
1266 free_u_entry(u_e);
1267 free(u_e);
Bart De Schuymer60332e02002-06-23 08:01:47 +00001268 // update the counter_offset of chains behind this one
1269 i = replace.selected_hook;
1270 while (1) {
1271 i++;
1272 entries = nr_to_chain(i);
1273 if (!entries) {
1274 if (i < NF_BR_NUMHOOKS)
1275 continue;
1276 else
1277 break;
1278 } else
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001279 entries->counter_offset--;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001280 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001281}
1282
1283// execute command Z
Bart De Schuymer62423742002-07-14 19:06:20 +00001284static void zero_counters(int zerochain)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001285{
1286
1287 if (zerochain == -1) {
1288 // tell main() we don't update the counters
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001289 // this results in tricking the kernel to zero its counters,
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001290 // naively expecting userspace to update its counters. Muahahaha
1291 counterchanges = NULL;
1292 replace.num_counters = 0;
1293 } else {
1294 int i, j;
1295 unsigned short *cnt;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001296 struct ebt_u_entries *entries = nr_to_chain(zerochain), *e2;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001297
Bart De Schuymer60332e02002-06-23 08:01:47 +00001298 if (entries->nentries == 0)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001299 exit(0);
1300 counterchanges = (unsigned short *)
1301 malloc((replace.nentries + 1) * sizeof(unsigned short));
1302 if (!counterchanges)
1303 print_memory();
1304 cnt = counterchanges;
1305 for (i = 0; i < zerochain; i++) {
Bart De Schuymer60332e02002-06-23 08:01:47 +00001306 if (i < NF_BR_NUMHOOKS &&
1307 !(replace.valid_hooks & (1 << i)))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001308 continue;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001309 e2 = nr_to_chain(i);
1310 for (j = 0; j < e2->nentries; j++) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001311 *cnt = CNT_NORM;
1312 cnt++;
1313 }
1314 }
Bart De Schuymer60332e02002-06-23 08:01:47 +00001315 for (i = 0; i < entries->nentries; i++) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001316 *cnt = CNT_ZERO;
1317 cnt++;
1318 }
1319 while (cnt != counterchanges + replace.nentries) {
1320 *cnt = CNT_NORM;
1321 cnt++;
1322 }
1323 *cnt = CNT_END;
1324 }
1325}
1326
1327// list the database (optionally compiled into the kernel)
1328static void list_db()
1329{
1330 struct brdb_dbinfo nr;
1331 struct brdb_dbentry *db;
1332 char name[21];
1333 int i;
1334
1335 get_dbinfo(&nr);
1336
1337 // 0 : database disabled (-db n)
1338 if (!(nr.nentries))
1339 print_error("Database not present"
1340 " (disabled), try ebtables --db y");
1341 nr.nentries--;
1342 if (!nr.nentries) print_error("Database empty");
1343 if ( !(db = (struct brdb_dbentry *)
1344 malloc(nr.nentries * sizeof(struct brdb_dbentry))) )
1345 print_memory();
1346
1347 get_db(nr.nentries, db);
1348 printf("number of entries: %d\n", nr.nentries);
1349 for (i = 0; i < nr.nentries; i++) {
1350 printf(
1351 "%d:\n"
1352 "hook : %s\n"
1353 "in-if : %s\n"
1354 "out-if : %s\n"
1355 "protocol: ", i + 1, hooknames[db->hook], db->in, db->out);
1356 if (db->ethproto == IDENTIFY802_3)
1357 printf("802.2/802.3 STYLE LENGTH FIELD\n");
1358 else {
1359 if (number_to_name(ntohs(db->ethproto), name))
1360 printf("%x\n",ntohs(db->ethproto));
1361 else
1362 printf("%s\n", name);
1363 }
1364 db++;
1365 }
1366 exit(0);
1367}
1368
1369// handle db [dis,en]abling
1370static void allowdb(char yorn)
1371{
1372 __u16 decision;
1373
1374 if (yorn != 'y' && yorn != 'n')
1375 print_error("Option [y] or [n] needed");
1376
1377 if (yorn == 'y')
1378 decision = BRDB_DB;
1379 else
1380 decision = BRDB_NODB;
1381
1382 deliver_allowdb(&decision);
1383
1384 exit(0);
1385}
1386
Bart De Schuymer28bf6f62002-06-26 18:57:24 +00001387// 0 == success
1388// 1 == success, but for the special 'protocol' LENGTH
1389// -1 == failure
1390int name_to_number(char *name, __u16 *proto)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001391{
1392 FILE *ifp;
Bart De Schuymerf662ce52002-07-19 18:40:55 +00001393 char buffer[21], value[11], *bfr;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001394 unsigned short i;
1395
1396 if (!strcasecmp("LENGTH", name)) {
Bart De Schuymer28bf6f62002-06-26 18:57:24 +00001397 *proto = 0;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001398 new_entry->bitmask |= EBT_802_3;
1399 return 1;
1400 }
1401 if ( !(ifp = fopen(PROTOCOLFILE, "r")) )
1402 return -1;
1403 while (1) {
1404 if (get_a_line(buffer, value, ifp)) return -1;
1405 if (strcasecmp(buffer, name))
1406 continue;
1407 i = (unsigned short) strtol(value, &bfr, 16);
Bart De Schuymerf662ce52002-07-19 18:40:55 +00001408 if (*bfr != '\0') {
1409 fclose(ifp);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001410 return -1;
Bart De Schuymerf662ce52002-07-19 18:40:55 +00001411 }
Bart De Schuymer28bf6f62002-06-26 18:57:24 +00001412 *proto = i;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001413 fclose(ifp);
1414 return 0;
1415 }
1416 return -1;
1417}
1418
1419// put the mac address into 6 (ETH_ALEN) bytes
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001420int getmac_and_mask(char *from, char *to, char *mask)
1421{
1422 char *p;
1423 int i;
Bart De Schuymer41830412002-06-05 19:41:28 +00001424 struct ether_addr *addr;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001425
1426 if (strcasecmp(from, "Unicast") == 0) {
1427 memcpy(to, mac_type_unicast, ETH_ALEN);
1428 memcpy(mask, msk_type_unicast, ETH_ALEN);
1429 return 0;
1430 }
1431 if (strcasecmp(from, "Multicast") == 0) {
1432 memcpy(to, mac_type_multicast, ETH_ALEN);
1433 memcpy(mask, msk_type_multicast, ETH_ALEN);
1434 return 0;
1435 }
1436 if (strcasecmp(from, "Broadcast") == 0) {
1437 memcpy(to, mac_type_broadcast, ETH_ALEN);
1438 memcpy(mask, msk_type_broadcast, ETH_ALEN);
1439 return 0;
1440 }
1441 if ( (p = strrchr(from, '/')) != NULL) {
1442 *p = '\0';
Bart De Schuymer41830412002-06-05 19:41:28 +00001443 if (!(addr = ether_aton(p + 1)))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001444 return -1;
Bart De Schuymer41830412002-06-05 19:41:28 +00001445 memcpy(mask, addr, ETH_ALEN);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001446 } else
1447 memset(mask, 0xff, ETH_ALEN);
Bart De Schuymer41830412002-06-05 19:41:28 +00001448 if (!(addr = ether_aton(from)))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001449 return -1;
Bart De Schuymer41830412002-06-05 19:41:28 +00001450 memcpy(to, addr, ETH_ALEN);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001451 for (i = 0; i < ETH_ALEN; i++)
1452 to[i] &= mask[i];
1453 return 0;
1454}
1455
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001456// executes the final_check() function for all extensions used by the rule
Bart De Schuymer62423742002-07-14 19:06:20 +00001457static void do_final_checks(struct ebt_u_entry *e, struct ebt_u_entries *entries)
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +00001458{
1459 struct ebt_u_match_list *m_l;
1460 struct ebt_u_watcher_list *w_l;
1461 struct ebt_u_target *t;
1462 struct ebt_u_match *m;
1463 struct ebt_u_watcher *w;
1464
1465 m_l = e->m_list;
1466 w_l = e->w_list;
1467 while (m_l) {
1468 m = find_match(m_l->m->u.name);
1469 m->final_check(e, m_l->m, replace.name,
1470 entries->hook_mask, 1);
1471 m_l = m_l->next;
1472 }
1473 while (w_l) {
1474 w = find_watcher(w_l->w->u.name);
1475 w->final_check(e, w_l->w, replace.name,
1476 entries->hook_mask, 1);
1477 w_l = w_l->next;
1478 }
1479 t = find_target(e->t->u.name);
1480 t->final_check(e, e->t, replace.name,
1481 entries->hook_mask, 1);
1482}
1483
Bart De Schuymerb909f9b2002-06-26 18:35:31 +00001484// used for the -X command
Bart De Schuymer62423742002-07-14 19:06:20 +00001485static void check_for_references(int chain_nr)
Bart De Schuymerb909f9b2002-06-26 18:35:31 +00001486{
1487 int i = -1, j;
1488 struct ebt_u_entries *entries;
1489 struct ebt_u_entry *e;
1490
1491 while (1) {
1492 i++;
1493 entries = nr_to_chain(i);
1494 if (!entries) {
1495 if (i < NF_BR_NUMHOOKS)
1496 continue;
1497 else
1498 break;
1499 }
1500 e = entries->entries;
1501 j = 0;
1502 while (e) {
1503 j++;
1504 if (strcmp(e->t->u.name, EBT_STANDARD_TARGET)) {
1505 e = e->next;
1506 continue;
1507 }
1508 if (((struct ebt_standard_target *)e->t)->verdict == chain_nr)
1509 print_error("Can't delete the chain, it's referenced "
1510 "in chain %s, rule %d", entries->name, j);
1511 e = e->next;
1512 }
1513 }
1514}
1515
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001516int check_inverse(const char option[])
1517{
1518 if (strcmp(option, "!") == 0) {
1519 optind++;
1520 return 1;
1521 }
1522 return 0;
1523}
1524
1525void check_option(unsigned int *flags, unsigned int mask)
1526{
1527 if (*flags & mask)
1528 print_error("Multiple use of same option not allowed");
1529 *flags |= mask;
1530}
1531
1532#define OPT_COMMAND 0x01
1533#define OPT_TABLE 0x02
1534#define OPT_IN 0x04
1535#define OPT_OUT 0x08
1536#define OPT_JUMP 0x10
1537#define OPT_PROTOCOL 0x20
1538#define OPT_SOURCE 0x40
1539#define OPT_DEST 0x80
1540#define OPT_ZERO 0x100
1541#define OPT_LOGICALIN 0x200
1542#define OPT_LOGICALOUT 0x400
1543// the main thing
1544int main(int argc, char *argv[])
1545{
1546 char *buffer, allowbc = 'n';
1547 int c, i;
1548 // this special one for the -Z option (we can have -Z <this> -L <that>)
1549 int zerochain = -1;
Bart De Schuymerf8f8f292002-06-25 15:43:57 +00001550 int policy = 0;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001551 int rule_nr = -1;// used for -D chain number
1552 struct ebt_u_target *t;
1553 struct ebt_u_match *m;
1554 struct ebt_u_watcher *w;
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001555 struct ebt_u_match_list *m_l;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001556 struct ebt_u_watcher_list *w_l;
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001557 struct ebt_u_entries *entries;
Bart De Schuymerc8531032002-06-14 21:55:29 +00001558 const char *modprobe = NULL;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001559
1560 // initialize the table name, OPT_ flags, selected hook and command
1561 strcpy(replace.name, "filter");
1562 replace.flags = 0;
1563 replace.selected_hook = -1;
1564 replace.command = 'h';
Bart De Schuymer62423742002-07-14 19:06:20 +00001565 replace.filename = NULL;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001566
1567 new_entry = (struct ebt_u_entry *)malloc(sizeof(struct ebt_u_entry));
1568 if (!new_entry)
1569 print_memory();
1570 // put some sane values in our new entry
1571 initialize_entry(new_entry);
1572
Bart De Schuymer60332e02002-06-23 08:01:47 +00001573 // The scenario induced by this loop makes that:
Bart De Schuymer62423742002-07-14 19:06:20 +00001574 // '-t' ,'-M' and --atomic (if specified) have to come
1575 // before '-A' and the like
Bart De Schuymer60332e02002-06-23 08:01:47 +00001576
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001577 // getopt saves the day
1578 while ((c = getopt_long(argc, argv,
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001579 "-A:D:I:N:E:X: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 +00001580 switch (c) {
1581
1582 case 'A': // add a rule
1583 case 'D': // delete a rule
1584 case 'P': // define policy
1585 case 'I': // insert a rule
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001586 case 'N': // make a user defined chain
1587 case 'E': // rename chain
1588 case 'X': // delete chain
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001589 replace.command = c;
1590 if (replace.flags & OPT_COMMAND)
1591 print_error("Multiple commands not allowed");
1592 replace.flags |= OPT_COMMAND;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001593 if ( !(table = find_table(replace.name)) )
1594 print_error("Bad table name");
1595 // get the kernel's information
1596 if (get_table(&replace)) {
1597 ebtables_insmod("ebtables", modprobe);
1598 if (get_table(&replace))
1599 print_error("can't initialize ebtables "
1600 "table %s", replace.name);
1601 }
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001602 if (optarg[0] == '-')
1603 print_error("No chain name specified");
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001604 if (c == 'N') {
1605 struct ebt_u_chain_list *cl, **cl2;
1606
1607 if (get_hooknr(optarg) != -1)
1608 print_error("Chain %s already exists",
1609 optarg);
1610 if (find_target(optarg))
1611 print_error("Target with name %s exists"
1612 , optarg);
1613 if (strlen(optarg) >= EBT_CHAIN_MAXNAMELEN)
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001614 print_error("Chain name length can't exceed %d",
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001615 EBT_CHAIN_MAXNAMELEN - 1);
1616 cl = (struct ebt_u_chain_list *)
1617 malloc(sizeof(struct ebt_u_chain_list));
1618 if (!cl)
1619 print_memory();
1620 cl->next = NULL;
1621 cl->udc = (struct ebt_u_entries *)
1622 malloc(sizeof(struct ebt_u_entries));
1623 if (!cl->udc)
1624 print_memory();
1625 cl->udc->nentries = 0;
1626 cl->udc->policy = EBT_ACCEPT;
1627 cl->udc->counter_offset = replace.nentries;
1628 cl->udc->hook_mask = 0;
1629 strcpy(cl->udc->name, optarg);
1630 cl->udc->entries = NULL;
1631 cl->kernel_start = NULL;
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001632 // put the new chain at the end
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001633 cl2 = &replace.udc;
1634 while (*cl2)
1635 cl2 = &((*cl2)->next);
1636 *cl2 = cl;
1637 break;
1638 }
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001639 if ((replace.selected_hook = get_hooknr(optarg)) == -1)
1640 print_error("Chain %s doesn't exist", optarg);
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001641 if (c == 'E') {
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001642 if (optind >= argc || argv[optind][0] == '-')
1643 print_error("No new chain name specified");
1644 if (strlen(argv[optind]) >= EBT_CHAIN_MAXNAMELEN)
1645 print_error("Chain name len can't exceed %d",
1646 EBT_CHAIN_MAXNAMELEN - 1);
1647 if (get_hooknr(argv[optind]) != -1)
1648 print_error("Chain %s already exists",
1649 argv[optind]);
1650 entries = to_chain();
1651 strcpy(entries->name, argv[optind]);
1652 optind++;
1653 break;
1654 }
1655 if (c == 'X') {
1656 struct ebt_u_chain_list *cl, **cl2;
1657
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001658 if (replace.selected_hook < NF_BR_NUMHOOKS)
1659 print_error("You can't remove a standard chain");
Bart De Schuymerb909f9b2002-06-26 18:35:31 +00001660 // if the chain is referenced, don't delete it
1661 check_for_references(replace.selected_hook - NF_BR_NUMHOOKS);
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001662 flush_chains();
1663 entries = to_chain();
1664 if (replace.udc->udc == entries) {
1665 cl = replace.udc;
1666 replace.udc = replace.udc->next;
1667 free(cl->udc);
1668 free(cl);
1669 break;
1670 }
1671 cl2 = &(replace.udc);
1672 while ((*cl2)->next->udc != entries)
1673 cl2 = &((*cl2)->next);
1674 cl = (*cl2)->next;
1675 (*cl2)->next = (*cl2)->next->next;
1676 free(cl->udc);
1677 free(cl);
1678 break;
1679 }
1680
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001681 if (c == 'D' && optind < argc &&
1682 argv[optind][0] != '-') {
1683 rule_nr = strtol(argv[optind], &buffer, 10);
1684 if (*buffer != '\0' || rule_nr < 0)
1685 print_error("Problem with the "
1686 "specified rule number");
1687 optind++;
1688 }
1689 if (c == 'P') {
1690 if (optind >= argc)
1691 print_error("No policy specified");
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001692 policy = 0;
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001693 for (i = 0; i < NUM_STANDARD_TARGETS; i++)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001694 if (!strcmp(argv[optind],
1695 standard_targets[i])) {
Bart De Schuymer60332e02002-06-23 08:01:47 +00001696 policy = -i -1;
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001697 if (policy == EBT_CONTINUE)
1698 policy = 0;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001699 break;
1700 }
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001701 if (policy == 0)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001702 print_error("Wrong policy");
1703 optind++;
1704 }
1705 if (c == 'I') {
1706 if (optind >= argc)
1707 print_error("No rulenr for -I"
1708 " specified");
1709 rule_nr = strtol(argv[optind], &buffer, 10);
1710 if (*buffer != '\0' || rule_nr < 0)
1711 print_error("Problem with the specified"
1712 " rule number");
1713 optind++;
1714 }
1715 break;
1716
1717 case 'L': // list
1718 case 'F': // flush
1719 case 'Z': // zero counters
1720 if (c == 'Z') {
1721 if (replace.flags & OPT_ZERO)
1722 print_error("Multiple commands"
1723 " not allowed");
1724 if ( (replace.flags & OPT_COMMAND &&
1725 replace.command != 'L'))
1726 print_error("command -Z only allowed "
1727 "together with command -L");
1728 replace.flags |= OPT_ZERO;
1729 } else {
1730 replace.command = c;
1731 if (replace.flags & OPT_COMMAND)
1732 print_error("Multiple commands"
1733 " not allowed");
1734 replace.flags |= OPT_COMMAND;
1735 }
Bart De Schuymer60332e02002-06-23 08:01:47 +00001736 if ( !(table = find_table(replace.name)) )
1737 print_error("Bad table name");
1738 // get the kernel's information
1739 if (get_table(&replace)) {
1740 ebtables_insmod("ebtables", modprobe);
1741 if (get_table(&replace))
1742 print_error("can't initialize ebtables "
1743 "table %s", replace.name);
1744 }
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001745 i = -1;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001746 if (optarg) {
1747 if ( (i = get_hooknr(optarg)) == -1 )
1748 print_error("Bad chain");
1749 } else
1750 if (optind < argc && argv[optind][0] != '-') {
1751 if ((i = get_hooknr(argv[optind]))
1752 == -1)
1753 print_error("Bad chain");
1754 optind++;
1755 }
1756 if (i != -1) {
1757 if (c == 'Z')
1758 zerochain = i;
1759 else
1760 replace.selected_hook = i;
1761 }
1762 break;
1763
1764 case 'V': // version
1765 replace.command = 'V';
1766 if (replace.flags & OPT_COMMAND)
1767 print_error("Multiple commands not allowed");
1768 printf("%s, %s\n", prog_name, prog_version);
1769 exit(0);
1770
Bart De Schuymerc8531032002-06-14 21:55:29 +00001771 case 'M': // modprobe
Bart De Schuymer60332e02002-06-23 08:01:47 +00001772 if (replace.command != 'h')
1773 print_error("Please put the -M option earlier");
Bart De Schuymerc8531032002-06-14 21:55:29 +00001774 modprobe = optarg;
1775 break;
1776
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001777 case 'h': // help
1778 if (replace.flags & OPT_COMMAND)
1779 print_error("Multiple commands not allowed");
1780 replace.command = 'h';
1781 // All other arguments should be extension names
1782 while (optind < argc) {
1783 struct ebt_u_match *m;
1784 struct ebt_u_watcher *w;
1785
1786 if ((m = find_match(argv[optind])))
1787 add_match(m);
1788 else if ((w = find_watcher(argv[optind])))
1789 add_watcher(w);
1790 else {
1791 if (!(t = find_target(argv[optind])))
1792 print_error("Extension %s "
1793 "not found", argv[optind]);
1794 if (replace.flags & OPT_JUMP)
1795 print_error("Sorry, you can "
1796 "only see help for one "
1797 "target extension each time");
1798 replace.flags |= OPT_JUMP;
1799 new_entry->t =
1800 (struct ebt_entry_target *)t;
1801 }
1802 optind++;
1803 }
1804 break;
1805
1806 case 't': // table
Bart De Schuymer60332e02002-06-23 08:01:47 +00001807 if (replace.command != 'h')
1808 print_error("Please put the -t option first");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001809 check_option(&replace.flags, OPT_TABLE);
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001810 if (strlen(optarg) > EBT_TABLE_MAXNAMELEN - 1)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001811 print_error("Table name too long");
1812 strcpy(replace.name, optarg);
1813 break;
1814
1815 case 'i': // input interface
1816 case 2 : // logical input interface
1817 case 'o': // output interface
1818 case 3 : // logical output interface
1819 case 'j': // target
1820 case 'p': // net family protocol
1821 case 's': // source mac
1822 case 'd': // destination mac
1823 if ((replace.flags & OPT_COMMAND) == 0)
1824 print_error("No command specified");
1825 if ( replace.command != 'A' &&
1826 replace.command != 'D' && replace.command != 'I')
1827 print_error("Command and option do not match");
1828 if (c == 'i') {
1829 check_option(&replace.flags, OPT_IN);
1830 if (replace.selected_hook > 2 &&
1831 replace.selected_hook < NF_BR_BROUTING)
1832 print_error("Use in-interface only in "
1833 "INPUT, FORWARD, PREROUTING and"
1834 "BROUTING chains");
1835 if (check_inverse(optarg))
1836 new_entry->invflags |= EBT_IIN;
1837
1838 if (optind > argc)
1839 print_error("No in-interface "
1840 "specified");
1841 if (strlen(argv[optind - 1]) >= IFNAMSIZ)
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001842 print_error("Illegal interface length");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001843 strcpy(new_entry->in, argv[optind - 1]);
1844 break;
1845 }
1846 if (c == 2) {
1847 check_option(&replace.flags, OPT_LOGICALIN);
1848 if (replace.selected_hook > 2 &&
1849 replace.selected_hook < NF_BR_BROUTING)
1850 print_error("Use logical in-interface "
1851 "only in INPUT, FORWARD, "
1852 "PREROUTING and BROUTING chains");
1853 if (check_inverse(optarg))
1854 new_entry->invflags |= EBT_ILOGICALIN;
1855
1856 if (optind > argc)
1857 print_error("No logical in-interface "
1858 "specified");
1859 if (strlen(argv[optind - 1]) >= IFNAMSIZ)
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001860 print_error("Illegal interface length");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001861 strcpy(new_entry->logical_in, argv[optind - 1]);
1862 break;
1863 }
1864 if (c == 'o') {
1865 check_option(&replace.flags, OPT_OUT);
1866 if (replace.selected_hook < 2)
1867 print_error("Use out-interface only"
1868 " in OUTPUT, FORWARD and "
1869 "POSTROUTING chains");
1870 if (check_inverse(optarg))
1871 new_entry->invflags |= EBT_IOUT;
1872
1873 if (optind > argc)
1874 print_error("No out-interface "
1875 "specified");
1876
1877 if (strlen(argv[optind - 1]) >= IFNAMSIZ)
1878 print_error("Illegal interface "
1879 "length");
1880 strcpy(new_entry->out, argv[optind - 1]);
1881 break;
1882 }
1883 if (c == 3) {
1884 check_option(&replace.flags, OPT_LOGICALOUT);
1885 if (replace.selected_hook < 2)
1886 print_error("Use logical out-interface "
1887 "only in OUTPUT, FORWARD and "
1888 "POSTROUTING chains");
1889 if (check_inverse(optarg))
1890 new_entry->invflags |= EBT_ILOGICALOUT;
1891
1892 if (optind > argc)
1893 print_error("No logical out-interface "
1894 "specified");
1895
1896 if (strlen(argv[optind - 1]) >= IFNAMSIZ)
1897 print_error("Illegal interface "
1898 "length");
1899 strcpy(new_entry->logical_out,
1900 argv[optind - 1]);
1901 break;
1902 }
1903 if (c == 'j') {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001904 check_option(&replace.flags, OPT_JUMP);
1905 for (i = 0; i < NUM_STANDARD_TARGETS; i++)
1906 if (!strcmp(optarg,
1907 standard_targets[i])) {
1908 t = find_target(
1909 EBT_STANDARD_TARGET);
1910 ((struct ebt_standard_target *)
Bart De Schuymer60332e02002-06-23 08:01:47 +00001911 t->t)->verdict = -i - 1;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001912 break;
1913 }
Bart De Schuymer60332e02002-06-23 08:01:47 +00001914 if (-i - 1 == EBT_RETURN) {
1915 if (replace.selected_hook < NF_BR_NUMHOOKS)
1916 print_error("Return target"
1917 " only for user defined chains");
1918 }
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +00001919 if (i != NUM_STANDARD_TARGETS)
1920 break;
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001921 if ((i = get_hooknr(optarg)) != -1) {
1922 if (i < NF_BR_NUMHOOKS)
1923 print_error("don't jump"
1924 " to a standard chain");
1925 t = find_target(
1926 EBT_STANDARD_TARGET);
1927 ((struct ebt_standard_target *)
1928 t->t)->verdict = i - NF_BR_NUMHOOKS;
1929 break;
1930 }
1931 else {
1932 // must be an extension then
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001933 struct ebt_u_target *t;
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001934
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001935 t = find_target(optarg);
1936 // -j standard not allowed either
1937 if (!t || t ==
1938 (struct ebt_u_target *)new_entry->t)
1939 print_error("Illegal target "
1940 "name");
1941 new_entry->t =
1942 (struct ebt_entry_target *)t;
1943 }
1944 break;
1945 }
1946 if (c == 's') {
1947 check_option(&replace.flags, OPT_SOURCE);
1948 if (check_inverse(optarg))
1949 new_entry->invflags |= EBT_ISOURCE;
1950
1951 if (optind > argc)
1952 print_error("No source mac "
1953 "specified");
1954 if (getmac_and_mask(argv[optind - 1],
1955 new_entry->sourcemac, new_entry->sourcemsk))
1956 print_error("Problem with specified "
1957 "source mac");
1958 new_entry->bitmask |= EBT_SOURCEMAC;
1959 break;
1960 }
1961 if (c == 'd') {
1962 check_option(&replace.flags, OPT_DEST);
1963 if (check_inverse(optarg))
1964 new_entry->invflags |= EBT_IDEST;
1965
1966 if (optind > argc)
1967 print_error("No destination mac "
1968 "specified");
1969 if (getmac_and_mask(argv[optind - 1],
1970 new_entry->destmac, new_entry->destmsk))
1971 print_error("Problem with specified "
1972 "destination mac");
1973 new_entry->bitmask |= EBT_DESTMAC;
1974 break;
1975 }
1976 check_option(&replace.flags, OPT_PROTOCOL);
1977 if (check_inverse(optarg))
1978 new_entry->invflags |= EBT_IPROTO;
1979
1980 if (optind > argc)
1981 print_error("No protocol specified");
1982 new_entry->bitmask &= ~((unsigned int)EBT_NOPROTO);
1983 i = strtol(argv[optind - 1], &buffer, 16);
1984 if (*buffer == '\0' && (i < 0 || i > 0xFFFF))
1985 print_error("Problem with the specified "
1986 "protocol");
1987 new_entry->ethproto = i;
Bart De Schuymer28bf6f62002-06-26 18:57:24 +00001988 if (*buffer != '\0') {
1989 if ((i = name_to_number(argv[optind - 1],
1990 &new_entry->ethproto)) == -1)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001991 print_error("Problem with the specified"
1992 " protocol");
Bart De Schuymer28bf6f62002-06-26 18:57:24 +00001993 if (i == 1)
1994 new_entry->bitmask |= EBT_802_3;
1995 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001996 if (new_entry->ethproto < 1536 &&
1997 !(new_entry->bitmask & EBT_802_3))
1998 print_error("Sorry, protocols have values above"
1999 " or equal to 1536 (0x0600)");
2000 break;
2001
2002 case 'b': // allow database?
2003 if (replace.flags & OPT_COMMAND)
2004 print_error("Multiple commands not allowed");
2005 replace.command = c;
2006 allowbc = *optarg;
2007 break;
2008
Bart De Schuymer9af14f92002-07-10 20:49:10 +00002009 case 4 : // Lc
2010 check_option(&replace.flags, LIST_C);
2011 if (replace.selected_hook == DATABASEHOOKNR)
2012 print_error("--Lc not valid for listing"
2013 " the database");
2014 if (replace.command != 'L')
2015 print_error("Use --Lc with -L");
2016 if (replace.flags & LIST_X)
2017 print_error("--Lx not compatible with --Lc");
2018 replace.flags |= LIST_C;
2019 break;
2020 case 5 : // Ln
2021 check_option(&replace.flags, LIST_N);
2022 if (replace.selected_hook == DATABASEHOOKNR)
2023 print_error("--Ln not valid for listing"
2024 " the database");
2025 if (replace.command != 'L')
2026 print_error("Use --Ln with -L");
2027 if (replace.flags & LIST_X)
2028 print_error("--Lx not compatible with --Ln");
2029 replace.flags |= LIST_N;
2030 break;
2031 case 6 : // Lx
2032 check_option(&replace.flags, LIST_X);
2033 if (replace.selected_hook == DATABASEHOOKNR)
2034 print_error("--Lx not valid for listing"
2035 " the database");
2036 if (replace.command != 'L')
2037 print_error("Use --Lx with -L");
2038 if (replace.flags & LIST_C)
2039 print_error("--Lx not compatible with --Lc");
2040 if (replace.flags & LIST_N)
2041 print_error("--Lx not compatible with --Ln");
2042 replace.flags |= LIST_X;
2043 break;
Bart De Schuymer62423742002-07-14 19:06:20 +00002044 case 8 : // atomic-commit
2045 replace.command = c;
2046 if (replace.flags & OPT_COMMAND)
2047 print_error("Multiple commands not allowed");
2048 replace.flags |= OPT_COMMAND;
2049 replace.filename = (char *)malloc(strlen(optarg) + 1);
2050 strcpy(replace.filename, optarg);
2051 // get the information from the file
2052 get_table(&replace);
Bart De Schuymer868bf642002-07-16 18:14:20 +00002053 if (replace.nentries) {
2054 counterchanges = (unsigned short *)
2055 malloc(sizeof(unsigned short) * (replace.nentries + 1));
2056 for (i = 0; i < replace.nentries; i++)
2057 counterchanges[i] = CNT_NORM;
2058 counterchanges[i] = CNT_END;
2059 }
Bart De Schuymer62423742002-07-14 19:06:20 +00002060 free(replace.filename);
2061 replace.filename = NULL;
2062 break;
2063 case 7 : // atomic-init
2064 case 10: // atomic-save
Bart De Schuymer8d1d8942002-07-15 20:09:09 +00002065 case 11: // init-table
Bart De Schuymer62423742002-07-14 19:06:20 +00002066 replace.command = c;
2067 if (replace.flags & OPT_COMMAND)
2068 print_error("Multiple commands not allowed");
2069 replace.flags |= OPT_COMMAND;
2070 if ( !(table = find_table(replace.name)) )
2071 print_error("Bad table name");
2072 if (get_table(&replace)) {
2073 ebtables_insmod("ebtables", modprobe);
2074 if (get_table(&replace))
2075 print_error("can't initialize ebtables "
2076 "table %s", replace.name);
2077 }
Bart De Schuymera8d920b2002-07-16 18:30:44 +00002078 if (replace.nentries) {
Bart De Schuymer5f16dc72002-07-16 18:08:36 +00002079 counterchanges = (unsigned short *)
2080 malloc(sizeof(unsigned short) * (replace.nentries + 1));
2081 for (i = 0; i < replace.nentries; i++)
2082 counterchanges[i] = CNT_NORM;
2083 counterchanges[i] = CNT_END;
2084 }
Bart De Schuymer8d1d8942002-07-15 20:09:09 +00002085 if (c == 11)
2086 break;
Bart De Schuymer62423742002-07-14 19:06:20 +00002087 case 9 : // atomic
2088 replace.filename = (char *)malloc(strlen(optarg) + 1);
2089 strcpy(replace.filename, optarg);
2090 break;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002091
Bart De Schuymer9af14f92002-07-10 20:49:10 +00002092 default:
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002093 // is it a target option?
2094 t = (struct ebt_u_target *)new_entry->t;
2095 if ((t->parse(c - t->option_offset, argv, argc,
2096 new_entry, &t->flags, &t->t)))
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00002097 goto check_extension;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002098
2099 // is it a match_option?
2100 for (m = matches; m; m = m->next)
2101 if (m->parse(c - m->option_offset, argv,
2102 argc, new_entry, &m->flags, &m->m))
2103 break;
2104
2105 if (m != NULL) {
2106 if (m->used == 0)
2107 add_match(m);
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00002108 goto check_extension;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002109 }
2110
2111 // is it a watcher option?
2112 for (w = watchers; w; w = w->next)
2113 if (w->parse(c-w->option_offset, argv,
2114 argc, new_entry, &w->flags, &w->w))
2115 break;
2116
2117 if (w == NULL)
2118 print_error("Unknown argument");
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00002119 if (w->used == 0)
2120 add_watcher(w);
2121check_extension:
Bart De Schuymer60332e02002-06-23 08:01:47 +00002122 if (replace.command != 'A' && replace.command != 'I' &&
2123 replace.command != 'D')
2124 print_error("extensions only for -A, -I and -D");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002125 }
2126 }
2127
Bart De Schuymer25c741d2002-06-23 18:54:34 +00002128 if ( !table && !(table = find_table(replace.name)) )
2129 print_error("Bad table name");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002130 // database stuff before ebtables stuff
2131 if (replace.command == 'b')
2132 allowdb(allowbc);
2133 if (replace.command == 'L' && replace.selected_hook == DATABASEHOOKNR)
2134 list_db();
2135
2136 if ( (replace.flags & OPT_COMMAND) && replace.command != 'L' &&
2137 replace.flags & OPT_ZERO )
2138 print_error("Command -Z only allowed together with command -L");
2139
2140 if (replace.command == 'A' || replace.command == 'I' ||
2141 replace.command == 'D') {
2142 if (replace.selected_hook == -1)
2143 print_error("Not enough information");
2144 }
2145
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002146 // do this after parsing everything, so we can print specific info
2147 if (replace.command == 'h' && !(replace.flags & OPT_ZERO))
2148 print_help();
2149
2150 // do the final checks
Bart De Schuymer60332e02002-06-23 08:01:47 +00002151 if (replace.command == 'A' || replace.command == 'I' ||
2152 replace.command == 'D') {
2153 // this will put the hook_mask right for the chains
2154 check_for_loops();
2155 entries = to_chain();
2156 m_l = new_entry->m_list;
2157 w_l = new_entry->w_list;
2158 t = (struct ebt_u_target *)new_entry->t;
2159 while (m_l) {
2160 m = (struct ebt_u_match *)(m_l->m);
2161 m->final_check(new_entry, m->m, replace.name,
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +00002162 entries->hook_mask, 0);
Bart De Schuymer60332e02002-06-23 08:01:47 +00002163 m_l = m_l->next;
2164 }
2165 while (w_l) {
2166 w = (struct ebt_u_watcher *)(w_l->w);
2167 w->final_check(new_entry, w->w, replace.name,
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +00002168 entries->hook_mask, 0);
Bart De Schuymer60332e02002-06-23 08:01:47 +00002169 w_l = w_l->next;
2170 }
2171 t->final_check(new_entry, t->t, replace.name,
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +00002172 entries->hook_mask, 0);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002173 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002174 // so, the extensions can work with the host endian
2175 // the kernel does not have to do this ofcourse
2176 new_entry->ethproto = htons(new_entry->ethproto);
2177
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002178 if (replace.command == 'P')
2179 change_policy(policy);
2180 else if (replace.command == 'L') {
2181 list_rules();
2182 if (replace.flags & OPT_ZERO)
2183 zero_counters(zerochain);
2184 else
2185 exit(0);
2186 }
2187 if (replace.flags & OPT_ZERO)
2188 zero_counters(zerochain);
Bart De Schuymer1ab41562002-06-23 17:09:54 +00002189 else if (replace.command == 'F') {
2190 if (flush_chains() == -1)
2191 exit(0);
2192 } else if (replace.command == 'A' || replace.command == 'I') {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002193 add_rule(rule_nr);
Bart De Schuymer1ab41562002-06-23 17:09:54 +00002194 check_for_loops();
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +00002195 // do the final_check(), for all entries
2196 // needed when adding a rule that has a chain target
2197 i = -1;
2198 while (1) {
2199 struct ebt_u_entry *e;
2200
2201 i++;
2202 entries = nr_to_chain(i);
2203 if (!entries) {
2204 if (i < NF_BR_NUMHOOKS)
2205 continue;
2206 else
2207 break;
2208 }
2209 e = entries->entries;
2210 while (e) {
2211 // userspace extensions use host endian
2212 e->ethproto = ntohs(e->ethproto);
2213 do_final_checks(e, entries);
2214 e->ethproto = htons(e->ethproto);
2215 e = e->next;
2216 }
2217 }
Bart De Schuymer1ab41562002-06-23 17:09:54 +00002218 } else if (replace.command == 'D')
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002219 delete_rule(rule_nr);
Bart De Schuymer8d1d8942002-07-15 20:09:09 +00002220 // commands -N, -E, -X, --atomic-commit, --atomic-commit, --atomic-save,
2221 // --init-table fall through
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002222
2223 if (table->check)
2224 table->check(&replace);
2225
2226 deliver_table(&replace);
2227
2228 if (counterchanges)
2229 deliver_counters(&replace, counterchanges);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002230 return 0;
2231}