blob: 56459785c6173ebc4efe1f39d6ab2fc395faeefd [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
416
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000417// used to parse /etc/ethertypes
Bart De Schuymer62423742002-07-14 19:06:20 +0000418static int disregard_whitespace(char *buffer, FILE *ifp)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000419{
420 int hlp;
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000421
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000422 buffer[0] = '\t';
423 while (buffer[0] == '\t' || buffer[0] == '\n' || buffer[0] == ' ') {
424 hlp = fscanf(ifp, "%c", buffer);
425 if (hlp == EOF || hlp == 0) return -1;
426 }
427 return 0;
428}
429
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000430// used to parse /etc/ethertypes
Bart De Schuymer62423742002-07-14 19:06:20 +0000431static int disregard_tabspace(char *buffer, FILE *ifp)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000432{
433 int hlp;
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000434
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000435 buffer[0] = '\t';
436 while (buffer[0] == '\t' || buffer[0] == ' ') {
437 hlp = fscanf(ifp, "%c", buffer);
438 if (hlp == EOF || hlp == 0) return -1;
439 }
440 return 0;
441}
442
Bart De Schuymerbbca3202002-06-05 18:55:44 +0000443// helper function: processes a line of data from the file /etc/ethertypes
Bart De Schuymer62423742002-07-14 19:06:20 +0000444static int get_a_line(char *buffer, char *value, FILE *ifp)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000445{
446 int i, hlp;
447 char anotherhlp;
448
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000449 // discard comment lines and whitespace
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000450 while (1) {
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000451 if (disregard_whitespace(buffer, ifp))
452 return -1;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000453 if (buffer[0] == '#')
454 while (1) {
455 hlp = fscanf(ifp, "%c", &anotherhlp);
456 if (!hlp || hlp == EOF)
457 return -1;
458 if (anotherhlp == '\n')
459 break;
460 }
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000461 else
462 break;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000463 }
464
465 // buffer[0] already contains the first letter
466 for (i = 1; i < 21; i++) {
467 hlp = fscanf(ifp, "%c", buffer + i);
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000468 if (hlp == EOF || hlp == 0)
469 return -1;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000470 if (buffer[i] == '\t' || buffer[i] == ' ')
471 break;
472 }
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000473 if (i == 21)
474 return -1;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000475 buffer[i] = '\0';
476 if (disregard_tabspace(value, ifp))
477 return -1;
478 // maybe I should allow 0x0800 instead of 0800, but I'm feeling lazy
479 // buffer[0] already contains the first letter
480 for (i = 1; i < 5; i++) {
481 hlp = fscanf(ifp, "%c", value+i);
482 if (value[i] == '\n' || value[i] == '\t' ||
483 value[i] == ' ' || hlp == EOF)
484 break;
485 }
486 if (i == 5) return -1;
Bart De Schuymerbbca3202002-06-05 18:55:44 +0000487 // discard comments at the end of a line
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000488 if (value[i] == '\t' || value[i] == ' ')
489 while (1) {
490 hlp = fscanf(ifp, "%c", &anotherhlp);
491 if (!hlp || hlp == EOF || anotherhlp == '\n')
492 break;
493 }
494 value[i] = '\0';
495 return 0;
496}
497
Bart De Schuymerb909f9b2002-06-26 18:35:31 +0000498// translate a hexadecimal number to a protocol name, parsing /etc/ethertypes
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000499// returns 0 on success
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000500int number_to_name(unsigned short proto, char *name)
501{
502 FILE *ifp;
503 char buffer[21], value[5], *bfr;
504 unsigned short i;
505
506 if ( !(ifp = fopen(PROTOCOLFILE, "r")) )
507 return -1;
508 while (1) {
509 if (get_a_line(buffer, value, ifp)) {
510 fclose(ifp);
511 return -1;
512 }
513 i = (unsigned short) strtol(value, &bfr, 16);
514 if (*bfr != '\0' || i != proto)
515 continue;
516 strcpy(name, buffer);
517 fclose(ifp);
518 return 0;
519 }
520}
521
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000522// we use replace.flags, so we can't use the following values:
523// 0x01 == OPT_COMMAND, 0x02 == OPT_TABLE, 0x100 == OPT_ZERO
524#define LIST_N 0x04
525#define LIST_C 0x08
526#define LIST_X 0x10
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000527// helper function for list_rules()
Bart De Schuymer60332e02002-06-23 08:01:47 +0000528static void list_em(struct ebt_u_entries *entries)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000529{
530 int i, j, space = 0, digits;
531 struct ebt_u_entry *hlp;
532 struct ebt_u_match_list *m_l;
533 struct ebt_u_watcher_list *w_l;
534 struct ebt_u_match *m;
535 struct ebt_u_watcher *w;
536 struct ebt_u_target *t;
537 char name[21];
538
Bart De Schuymer60332e02002-06-23 08:01:47 +0000539 hlp = entries->entries;
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000540 if (replace.flags & LIST_X && entries->policy != EBT_ACCEPT) {
541 printf("ebtables -t %s -P %s %s\n", replace.name,
542 entries->name, standard_targets[-entries->policy - 1]);
543 } else if (!(replace.flags & LIST_X)) {
544 printf("\nBridge chain: %s\nPolicy: %s\n", entries->name,
545 standard_targets[-entries->policy - 1]);
546 printf("nr. of entries: %d \n", entries->nentries);
547 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000548
Bart De Schuymer60332e02002-06-23 08:01:47 +0000549 i = entries->nentries;
Bart De Schuymerf8f8f292002-06-25 15:43:57 +0000550 while (i > 9) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000551 space++;
552 i /= 10;
553 }
554
Bart De Schuymer60332e02002-06-23 08:01:47 +0000555 for (i = 0; i < entries->nentries; i++) {
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000556 if (replace.flags & LIST_N) {
557 digits = 0;
558 // A little work to get nice rule numbers.
559 j = i + 1;
560 while (j > 9) {
561 digits++;
562 j /= 10;
563 }
564 for (j = 0; j < space - digits; j++)
565 printf(" ");
566 printf("%d. ", i + 1);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000567 }
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000568 if (replace.flags & LIST_X)
569 printf("ebtables -t %s -A %s ",
570 replace.name, entries->name);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000571
572 // Don't print anything about the protocol if no protocol was
573 // specified, obviously this means any protocol will do.
574 if (!(hlp->bitmask & EBT_NOPROTO)) {
Bart De Schuymer60332e02002-06-23 08:01:47 +0000575 printf("-p ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000576 if (hlp->invflags & EBT_IPROTO)
577 printf("! ");
578 if (hlp->bitmask & EBT_802_3)
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000579 printf("Length ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000580 else {
581 if (number_to_name(ntohs(hlp->ethproto), name))
Bart De Schuymer60332e02002-06-23 08:01:47 +0000582 printf("0x%x ", ntohs(hlp->ethproto));
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000583 else
Bart De Schuymer60332e02002-06-23 08:01:47 +0000584 printf("%s ", name);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000585 }
586 }
587 if (hlp->bitmask & EBT_SOURCEMAC) {
588 char hlpmsk[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
589
Bart De Schuymer60332e02002-06-23 08:01:47 +0000590 printf("-s ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000591 if (hlp->invflags & EBT_ISOURCE)
592 printf("! ");
593 if (!memcmp(hlp->sourcemac, mac_type_unicast, 6) &&
594 !memcmp(hlp->sourcemsk, msk_type_unicast, 6)) {
595 printf("Unicast");
596 goto endsrc;
597 }
598 if (!memcmp(hlp->sourcemac, mac_type_multicast, 6) &&
599 !memcmp(hlp->sourcemsk, msk_type_multicast, 6)) {
600 printf("Multicast");
601 goto endsrc;
602 }
603 if (!memcmp(hlp->sourcemac, mac_type_broadcast, 6) &&
604 !memcmp(hlp->sourcemsk, msk_type_broadcast, 6)) {
605 printf("Broadcast");
606 goto endsrc;
607 }
Bart De Schuymer41830412002-06-05 19:41:28 +0000608 printf("%s", ether_ntoa((struct ether_addr *)
609 hlp->sourcemac));
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000610 if (memcmp(hlp->sourcemsk, hlpmsk, 6)) {
611 printf("/");
Bart De Schuymer41830412002-06-05 19:41:28 +0000612 printf("%s", ether_ntoa((struct ether_addr *)
613 hlp->sourcemsk));
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000614 }
615endsrc:
Bart De Schuymer60332e02002-06-23 08:01:47 +0000616 printf(" ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000617 }
618 if (hlp->bitmask & EBT_DESTMAC) {
619 char hlpmsk[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
620
Bart De Schuymer60332e02002-06-23 08:01:47 +0000621 printf("-d ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000622 if (hlp->invflags & EBT_IDEST)
623 printf("! ");
624 if (!memcmp(hlp->destmac, mac_type_unicast, 6) &&
625 !memcmp(hlp->destmsk, msk_type_unicast, 6)) {
626 printf("Unicast");
627 goto enddst;
628 }
629 if (!memcmp(hlp->destmac, mac_type_multicast, 6) &&
630 !memcmp(hlp->destmsk, msk_type_multicast, 6)) {
631 printf("Multicast");
632 goto enddst;
633 }
634 if (!memcmp(hlp->destmac, mac_type_broadcast, 6) &&
635 !memcmp(hlp->destmsk, msk_type_broadcast, 6)) {
636 printf("Broadcast");
637 goto enddst;
638 }
Bart De Schuymer41830412002-06-05 19:41:28 +0000639 printf("%s", ether_ntoa((struct ether_addr *)
640 hlp->destmac));
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000641 if (memcmp(hlp->destmsk, hlpmsk, 6)) {
642 printf("/");
Bart De Schuymer41830412002-06-05 19:41:28 +0000643 printf("%s", ether_ntoa((struct ether_addr *)
644 hlp->destmsk));
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000645 }
646enddst:
Bart De Schuymer60332e02002-06-23 08:01:47 +0000647 printf(" ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000648 }
649 if (hlp->in[0] != '\0') {
Bart De Schuymer60332e02002-06-23 08:01:47 +0000650 printf("-i ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000651 if (hlp->invflags & EBT_IIN)
652 printf("! ");
Bart De Schuymer60332e02002-06-23 08:01:47 +0000653 printf("%s ", hlp->in);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000654 }
655 if (hlp->logical_in[0] != '\0') {
Bart De Schuymer60332e02002-06-23 08:01:47 +0000656 printf("--logical-in ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000657 if (hlp->invflags & EBT_ILOGICALIN)
658 printf("! ");
Bart De Schuymer60332e02002-06-23 08:01:47 +0000659 printf("%s ", hlp->logical_in);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000660 }
661 if (hlp->logical_out[0] != '\0') {
Bart De Schuymer60332e02002-06-23 08:01:47 +0000662 printf("--logical-out ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000663 if (hlp->invflags & EBT_ILOGICALOUT)
664 printf("! ");
Bart De Schuymerb3d8f262002-07-07 14:26:15 +0000665 printf("%s ", hlp->logical_out);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000666 }
667 if (hlp->out[0] != '\0') {
Bart De Schuymer60332e02002-06-23 08:01:47 +0000668 printf("-o ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000669 if (hlp->invflags & EBT_IOUT)
670 printf("! ");
Bart De Schuymerb3d8f262002-07-07 14:26:15 +0000671 printf("%s ", hlp->out);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000672 }
673
674 m_l = hlp->m_list;
675 while (m_l) {
676 m = find_match(m_l->m->u.name);
677 if (!m)
678 print_bug("Match not found");
679 m->print(hlp, m_l->m);
680 m_l = m_l->next;
681 }
682 w_l = hlp->w_list;
683 while (w_l) {
684 w = find_watcher(w_l->w->u.name);
685 if (!w)
686 print_bug("Watcher not found");
687 w->print(hlp, w_l->w);
688 w_l = w_l->next;
689 }
690
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000691 printf("-j ");
692 if (strcmp(hlp->t->u.name, EBT_STANDARD_TARGET))
693 printf("%s ", hlp->t->u.name);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000694 t = find_target(hlp->t->u.name);
695 if (!t)
696 print_bug("Target not found");
697 t->print(hlp, hlp->t);
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000698 if (replace.flags & LIST_C)
699 printf(", count = %llu",
700 replace.counters[entries->counter_offset + i].pcnt);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000701 printf("\n");
702 hlp = hlp->next;
703 }
704}
705
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000706struct ebt_u_entries *nr_to_chain(int nr)
Bart De Schuymer60332e02002-06-23 08:01:47 +0000707{
708 if (nr == -1)
709 return NULL;
710 if (nr < NF_BR_NUMHOOKS)
711 return replace.hook_entry[nr];
712 else {
713 int i;
714 struct ebt_u_chain_list *cl = replace.udc;
715
716 i = nr - NF_BR_NUMHOOKS;
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000717 while (i > 0 && cl) {
Bart De Schuymer60332e02002-06-23 08:01:47 +0000718 cl = cl->next;
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000719 i--;
720 }
Bart De Schuymer60332e02002-06-23 08:01:47 +0000721 if (cl)
722 return cl->udc;
723 else
724 return NULL;
725 }
726}
727
728static struct ebt_u_entries *to_chain()
729{
730 return nr_to_chain(replace.selected_hook);
731}
732
733struct ebt_u_stack
734{
735 int chain_nr;
736 int n;
737 struct ebt_u_entry *e;
738 struct ebt_u_entries *entries;
739};
740
Bart De Schuymer62423742002-07-14 19:06:20 +0000741static void check_for_loops()
Bart De Schuymer60332e02002-06-23 08:01:47 +0000742{
743 int chain_nr , i, j , k, sp = 0, verdict;
744 struct ebt_u_entries *entries, *entries2;
745 struct ebt_u_stack *stack = NULL;
746 struct ebt_u_entry *e;
747
748 i = -1;
749 // initialize hook_mask to 0
750 while (1) {
751 i++;
752 if (i < NF_BR_NUMHOOKS && !(replace.valid_hooks & (1 << i)))
753 continue;
754 entries = nr_to_chain(i);
755 if (!entries)
756 break;
757 entries->hook_mask = 0;
758 }
759 if (i > NF_BR_NUMHOOKS) {
760 stack = (struct ebt_u_stack *)malloc((i - NF_BR_NUMHOOKS) *
761 sizeof(struct ebt_u_stack));
762 if (!stack)
763 print_memory();
764 }
765
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000766 // check for loops, starting from every base chain
Bart De Schuymer60332e02002-06-23 08:01:47 +0000767 for (i = 0; i < NF_BR_NUMHOOKS; i++) {
768 if (!(replace.valid_hooks & (1 << i)))
769 continue;
770 entries = nr_to_chain(i);
771 entries->hook_mask = (1 << i);
772 chain_nr = i;
773
774 e = entries->entries;
775 for (j = 0; j < entries->nentries; j++) {
776 if (strcmp(e->t->u.name, EBT_STANDARD_TARGET))
777 goto letscontinue;
778 verdict = ((struct ebt_standard_target *)(e->t))->verdict;
779 if (verdict < 0)
780 goto letscontinue;
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000781 entries2 = nr_to_chain(verdict + NF_BR_NUMHOOKS);
Bart De Schuymer60332e02002-06-23 08:01:47 +0000782 entries2->hook_mask |= entries->hook_mask;
783 // now see if we've been here before
784 for (k = 0; k < sp; k++)
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000785 if (stack[k].chain_nr == verdict + NF_BR_NUMHOOKS)
Bart De Schuymer1a0a9c32002-06-24 21:10:16 +0000786 print_error("Loop from chain %s to chain %s",
787 nr_to_chain(chain_nr)->name, nr_to_chain(stack[k].chain_nr)->name);
Bart De Schuymer60332e02002-06-23 08:01:47 +0000788 // jump to the chain, make sure we know how to get back
789 stack[sp].chain_nr = chain_nr;
790 stack[sp].n = j;
791 stack[sp].entries = entries;
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000792 stack[sp].e = e;
793 sp++;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000794 j = -1;
795 e = entries2->entries;
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000796 chain_nr = verdict + NF_BR_NUMHOOKS;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000797 entries = entries2;
798 continue;
799letscontinue:
800 e = e->next;
801 }
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000802 // we are at the end of a standard chain
Bart De Schuymer60332e02002-06-23 08:01:47 +0000803 if (sp == 0)
804 continue;
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000805 // go back to the chain one level higher
Bart De Schuymer60332e02002-06-23 08:01:47 +0000806 sp--;
807 j = stack[sp].n;
808 chain_nr = stack[sp].chain_nr;
809 e = stack[sp].e;
810 entries = stack[sp].entries;
811 goto letscontinue;
812 }
813 free(stack);
814 return;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000815}
816
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000817// parse the chain name and return the corresponding nr
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000818// returns -1 on failure
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000819int get_hooknr(char* arg)
820{
821 int i;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000822 struct ebt_u_chain_list *cl = replace.udc;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000823
824 // database is special case (not really a chain)
825 if (!strcmp(arg, DATABASEHOOKNAME))
826 return DATABASEHOOKNR;
827
Bart De Schuymer60332e02002-06-23 08:01:47 +0000828 for (i = 0; i < NF_BR_NUMHOOKS; i++) {
829 if (!(replace.valid_hooks & (1 << i)))
830 continue;
831 if (!strcmp(arg, replace.hook_entry[i]->name))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000832 return i;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000833 }
834 while(cl) {
835 if (!strcmp(arg, cl->udc->name))
836 return i;
837 i++;
838 cl = cl->next;
839 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000840 return -1;
841}
842
843// yup, print out help
Bart De Schuymer62423742002-07-14 19:06:20 +0000844static void print_help()
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000845{
846 struct ebt_u_match_list *m_l;
847 struct ebt_u_watcher_list *w_l;
848
849 printf(
850"%s v%s\n"
851"Usage:\n"
852"ebtables -[ADI] chain rule-specification [options]\n"
853"ebtables -P chain target\n"
854"ebtables -[LFZ] [chain]\n"
855"ebtables -[b] [y,n]\n"
856"Commands:\n"
857"--append -A chain : Append to chain\n"
858"--delete -D chain : Delete matching rule from chain\n"
859"--delete -D chain rulenum : Delete rule at position rulenum from chain\n"
860"--insert -I chain rulenum : insert rule at position rulenum in chain\n"
861"--list -L [chain] : List the rules in a chain or in all chains\n"
862"--list -L "DATABASEHOOKNAME" : List the database (if present)\n"
863"--flush -F [chain] : Delete all rules in chain or in all chains\n"
Bart De Schuymer8d1d8942002-07-15 20:09:09 +0000864"--init-table : Replace the kernel table with the initial table\n"
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000865"--zero -Z [chain] : Put counters on zero in chain or in all chains\n"
866"--policy -P chain target : Change policy on chain to target\n"
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000867"--new-chain -N chain : Create a user defined chain\n"
868"--rename-chain -E old new : Rename a chain\n"
869"--delete-chain -X chain : Delete a user defined chain\n"
Bart De Schuymer62423742002-07-14 19:06:20 +0000870"--atomic-commit file : update the kernel w/ the table contained in file\n"
871"--atomic-init file : put the initial kernel table into file\n"
872"--atomic-save file : put the current kernel table into file\n"
873"--atomic file : write changes to file instead of kernel\n"
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000874"Options:\n"
875"--proto -p [!] proto : protocol hexadecimal, by name or LENGTH\n"
876"--src -s [!] address[/mask]: source mac address\n"
877"--dst -d [!] address[/mask]: destination mac address\n"
878"--in-if -i [!] name : network input interface name\n"
879"--out-if -o [!] name : network output interface name\n"
880"--logical-in [!] name : logical bridge input interface name\n"
881"--logical-out [!] name : logical bridge output interface name\n"
Bart De Schuymer5cbc8e02002-07-14 21:15:28 +0000882"--modprobe -M program : try to insert modules using this program\n"
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000883"--version -V : print package version\n"
884"\n" ,
885 prog_name,
886 prog_version);
887
888 m_l = new_entry->m_list;
889 while (m_l) {
890 ((struct ebt_u_match *)m_l->m)->help();
891 printf("\n");
892 m_l = m_l->next;
893 }
894 w_l = new_entry->w_list;
895 while (w_l) {
896 ((struct ebt_u_watcher *)w_l->w)->help();
897 printf("\n");
898 w_l = w_l->next;
899 }
900 ((struct ebt_u_target *)new_entry->t)->help();
901 printf("\n");
902 if (table->help)
903 table->help(hooknames);
904 exit(0);
905}
906
907// execute command L
908static void list_rules()
909{
910 int i;
911
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000912 if (!(replace.flags & LIST_X))
913 printf("Bridge table: %s\n", table->name);
Bart De Schuymer60332e02002-06-23 08:01:47 +0000914 if (replace.selected_hook != -1) {
915 list_em(to_chain());
916 } else {
917 struct ebt_u_chain_list *cl = replace.udc;
918
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000919 // create new chains and rename standard chains when necessary
920 if (replace.flags & LIST_X) {
921 while (cl) {
922 printf("ebtables -t %s -N %s\n", replace.name,
923 cl->udc->name);
924 cl = cl->next;
925 }
926 cl = replace.udc;
927 for (i = 0; i < NF_BR_NUMHOOKS; i++)
928 if (replace.valid_hooks & (1 << i) &&
929 strcmp(replace.hook_entry[i]->name, hooknames[i]))
930 printf("ebtables -t %s -E %s %s\n",
931 replace.name, hooknames[i],
932 replace.hook_entry[i]->name);
933 }
Bart De Schuymer60332e02002-06-23 08:01:47 +0000934 i = 0;
935 while (1) {
936 if (i < NF_BR_NUMHOOKS) {
937 if (replace.valid_hooks & (1 << i))
938 list_em(replace.hook_entry[i]);
939 i++;
940 continue;
941 } else {
942 if (!cl)
943 break;
944 list_em(cl->udc);
945 cl = cl->next;
946 }
947 }
948 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000949}
950
951// execute command P
952static void change_policy(int policy)
953{
954 int i;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000955 struct ebt_u_entries *entries = to_chain();
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000956
957 // don't do anything if the policy is the same
Bart De Schuymer60332e02002-06-23 08:01:47 +0000958 if (entries->policy != policy) {
959 entries->policy = policy;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000960 replace.num_counters = replace.nentries;
961 if (replace.nentries) {
962 // '+ 1' for the CNT_END
963 if (!(counterchanges = (unsigned short *) malloc(
964 (replace.nentries + 1) * sizeof(unsigned short))))
965 print_memory();
966 // done nothing special to the rules
967 for (i = 0; i < replace.nentries; i++)
968 counterchanges[i] = CNT_NORM;
969 counterchanges[replace.nentries] = CNT_END;
970 }
971 else
972 counterchanges = NULL;
973 }
974 else
975 exit(0);
976}
977
978// flush one chain or the complete table
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000979// -1 == nothing to do
980// 0 == give back to kernel
981static int flush_chains()
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000982{
Bart De Schuymer60332e02002-06-23 08:01:47 +0000983 int i, j, oldnentries, numdel;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000984 unsigned short *cnt;
985 struct ebt_u_entry *u_e, *tmp;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000986 struct ebt_u_entries *entries = to_chain();
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000987
988 // flush whole table
Bart De Schuymer60332e02002-06-23 08:01:47 +0000989 if (!entries) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000990 if (replace.nentries == 0)
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000991 return -1;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000992 replace.nentries = 0;
993 // no need for the kernel to give us counters back
994 replace.num_counters = 0;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000995
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000996 // free everything and zero (n)entries
Bart De Schuymer60332e02002-06-23 08:01:47 +0000997 i = -1;
998 while (1) {
999 i++;
1000 entries = nr_to_chain(i);
1001 if (!entries) {
1002 if (i < NF_BR_NUMHOOKS)
1003 continue;
1004 else
1005 break;
1006 }
1007 entries->nentries = 0;
1008 entries->counter_offset = 0;
1009 u_e = entries->entries;
1010 entries->entries = NULL;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001011 while (u_e) {
1012 free_u_entry(u_e);
1013 tmp = u_e->next;
1014 free(u_e);
1015 u_e = tmp;
1016 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001017 }
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001018 return 0;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001019 }
1020
Bart De Schuymer60332e02002-06-23 08:01:47 +00001021 if (entries->nentries == 0)
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001022 return -1;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001023 oldnentries = replace.nentries;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001024 replace.nentries -= entries->nentries;
1025 numdel = entries->nentries;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001026
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001027 if (replace.nentries) {
1028 // +1 for CNT_END
1029 if ( !(counterchanges = (unsigned short *)
1030 malloc((oldnentries + 1) * sizeof(unsigned short))) )
1031 print_memory();
Bart De Schuymer60332e02002-06-23 08:01:47 +00001032 }
1033 // delete the counters belonging to the specified chain,
1034 // update counter_offset
1035 i = -1;
Bart De Schuymerf8f8f292002-06-25 15:43:57 +00001036 cnt = counterchanges;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001037 while (1) {
1038 i++;
1039 entries = nr_to_chain(i);
1040 if (!entries) {
1041 if (i < NF_BR_NUMHOOKS)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001042 continue;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001043 else
1044 break;
1045 }
1046 if (i > replace.selected_hook)
1047 entries->counter_offset -= numdel;
1048 if (replace.nentries) {
1049 for (j = 0; j < entries->nentries; j++) {
1050 if (i == replace.selected_hook)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001051 *cnt = CNT_DEL;
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001052 else
1053 *cnt = CNT_NORM;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001054 cnt++;
1055 }
1056 }
Bart De Schuymer60332e02002-06-23 08:01:47 +00001057 }
1058
1059 if (replace.nentries) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001060 *cnt = CNT_END;
1061 replace.num_counters = oldnentries;
1062 }
1063 else
1064 replace.num_counters = 0;
1065
Bart De Schuymer60332e02002-06-23 08:01:47 +00001066 entries = to_chain();
1067 entries->nentries = 0;
1068 u_e = entries->entries;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001069 while (u_e) {
1070 free_u_entry(u_e);
1071 tmp = u_e->next;
1072 free(u_e);
1073 u_e = tmp;
1074 }
Bart De Schuymer60332e02002-06-23 08:01:47 +00001075 entries->entries = NULL;
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001076 return 0;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001077}
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001078
1079// -1 == no match
1080static int check_rule_exists(int rule_nr)
1081{
1082 struct ebt_u_entry *u_e;
1083 struct ebt_u_match_list *m_l, *m_l2;
1084 struct ebt_u_match *m;
1085 struct ebt_u_watcher_list *w_l, *w_l2;
1086 struct ebt_u_watcher *w;
1087 struct ebt_u_target *t = (struct ebt_u_target *)new_entry->t;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001088 struct ebt_u_entries *entries = to_chain();
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001089 int i, j, k;
1090
1091 // handle '-D chain rulenr' command
1092 if (rule_nr != -1) {
Bart De Schuymer60332e02002-06-23 08:01:47 +00001093 if (rule_nr > entries->nentries)
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001094 return -1;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001095 // user starts counting from 1
1096 return rule_nr - 1;
1097 }
Bart De Schuymer60332e02002-06-23 08:01:47 +00001098 u_e = entries->entries;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001099 // check for an existing rule (if there are duplicate rules,
1100 // take the first occurance)
Bart De Schuymer60332e02002-06-23 08:01:47 +00001101 for (i = 0; i < entries->nentries; i++, u_e = u_e->next) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001102 if (!u_e)
1103 print_bug("Hmm, trouble");
1104 if ( u_e->ethproto == new_entry->ethproto
1105 && !strcmp(u_e->in, new_entry->in)
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001106 && !strcmp(u_e->out, new_entry->out)) {
Bart De Schuymer60332e02002-06-23 08:01:47 +00001107 if (strcmp(u_e->logical_in, new_entry->logical_in) ||
1108 strcmp(u_e->logical_out, new_entry->logical_out))
1109 continue;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001110 if (new_entry->bitmask & EBT_SOURCEMAC &&
Bart De Schuymer60332e02002-06-23 08:01:47 +00001111 memcmp(u_e->sourcemac, new_entry->sourcemac, ETH_ALEN))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001112 continue;
1113 if (new_entry->bitmask & EBT_DESTMAC &&
Bart De Schuymer60332e02002-06-23 08:01:47 +00001114 memcmp(u_e->destmac, new_entry->destmac, ETH_ALEN))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001115 continue;
1116 if (new_entry->bitmask != u_e->bitmask ||
1117 new_entry->invflags != u_e->invflags)
1118 continue;
1119 // compare all matches
1120 m_l = new_entry->m_list;
1121 j = 0;
1122 while (m_l) {
1123 m = (struct ebt_u_match *)(m_l->m);
1124 m_l2 = u_e->m_list;
1125 while (m_l2 &&
1126 strcmp(m_l2->m->u.name, m->m->u.name))
1127 m_l2 = m_l2->next;
1128 if (!m_l2 || !m->compare(m->m, m_l2->m))
1129 goto letscontinue;
1130 j++;
1131 m_l = m_l->next;
1132 }
1133 // now be sure they have the same nr of matches
1134 k = 0;
1135 m_l = u_e->m_list;
1136 while (m_l) {
1137 k++;
1138 m_l = m_l->next;
1139 }
1140 if (j != k)
1141 continue;
1142
1143 // compare all watchers
1144 w_l = new_entry->w_list;
1145 j = 0;
1146 while (w_l) {
1147 w = (struct ebt_u_watcher *)(w_l->w);
1148 w_l2 = u_e->w_list;
1149 while (w_l2 &&
1150 strcmp(w_l2->w->u.name, w->w->u.name))
1151 w_l2 = w_l2->next;
1152 if (!w_l2 || !w->compare(w->w, w_l2->w))
1153 goto letscontinue;
1154 j++;
1155 w_l = w_l->next;
1156 }
1157 k = 0;
1158 w_l = u_e->w_list;
1159 while (w_l) {
1160 k++;
1161 w_l = w_l->next;
1162 }
1163 if (j != k)
1164 continue;
1165 if (strcmp(t->t->u.name, u_e->t->u.name))
1166 continue;
1167 if (!t->compare(t->t, u_e->t))
1168 continue;
1169 return i;
1170 }
1171letscontinue:
1172 }
1173 return -1;
1174}
1175
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001176// execute command A or I
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001177static void add_rule(int rule_nr)
1178{
1179 int i, j;
1180 struct ebt_u_entry *u_e, *u_e2;
1181 unsigned short *cnt;
1182 struct ebt_u_match_list *m_l;
1183 struct ebt_u_watcher_list *w_l;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001184 struct ebt_u_entries *entries = to_chain(), *entries2;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001185
1186 if (rule_nr != -1) { // command -I
Bart De Schuymer60332e02002-06-23 08:01:47 +00001187 if (--rule_nr > entries->nentries)
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001188 print_error("rule nr too high: %d > %d", rule_nr + 1,
1189 entries->nentries + 1);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001190 } else
Bart De Schuymer60332e02002-06-23 08:01:47 +00001191 rule_nr = entries->nentries;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001192 // we're adding one rule
1193 replace.num_counters = replace.nentries;
1194 replace.nentries++;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001195 entries->nentries++;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001196
1197 // handle counter stuff
1198 // +1 for CNT_END
1199 if ( !(counterchanges = (unsigned short *)
1200 malloc((replace.nentries + 1) * sizeof(unsigned short))) )
1201 print_memory();
1202 cnt = counterchanges;
1203 for (i = 0; i < replace.selected_hook; i++) {
Bart De Schuymer60332e02002-06-23 08:01:47 +00001204 if (i < NF_BR_NUMHOOKS && !(replace.valid_hooks & (1 << i)))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001205 continue;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001206 entries2 = nr_to_chain(i);
1207 for (j = 0; j < entries2->nentries; j++) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001208 *cnt = CNT_NORM;
1209 cnt++;
1210 }
1211 }
1212 for (i = 0; i < rule_nr; i++) {
1213 *cnt = CNT_NORM;
1214 cnt++;
1215 }
1216 *cnt = CNT_ADD;
1217 cnt++;
1218 while (cnt != counterchanges + replace.nentries) {
1219 *cnt = CNT_NORM;
1220 cnt++;
1221 }
1222 *cnt = CNT_END;
1223
1224 // go to the right position in the chain
1225 u_e2 = NULL;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001226 u_e = entries->entries;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001227 for (i = 0; i < rule_nr; i++) {
1228 u_e2 = u_e;
1229 u_e = u_e->next;
1230 }
1231 // insert the rule
1232 if (u_e2)
1233 u_e2->next = new_entry;
1234 else
Bart De Schuymer60332e02002-06-23 08:01:47 +00001235 entries->entries = new_entry;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001236 new_entry->next = u_e;
1237
1238 // put the ebt_[match, watcher, target] pointers in place
1239 m_l = new_entry->m_list;
1240 while (m_l) {
1241 m_l->m = ((struct ebt_u_match *)m_l->m)->m;
1242 m_l = m_l->next;
1243 }
1244 w_l = new_entry->w_list;
1245 while (w_l) {
1246 w_l->w = ((struct ebt_u_watcher *)w_l->w)->w;
1247 w_l = w_l->next;
1248 }
1249 new_entry->t = ((struct ebt_u_target *)new_entry->t)->t;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001250
1251 // update the counter_offset of chains behind this one
1252 i = replace.selected_hook;
1253 while (1) {
1254 i++;
1255 entries = nr_to_chain(i);
1256 if (!entries) {
1257 if (i < NF_BR_NUMHOOKS)
1258 continue;
1259 else
1260 break;
1261 } else
1262 entries->counter_offset++;
1263 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001264}
1265
1266// execute command D
1267static void delete_rule(int rule_nr)
1268{
1269 int i, j, lentmp = 0;
1270 unsigned short *cnt;
1271 struct ebt_u_entry *u_e, *u_e2;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001272 struct ebt_u_entries *entries = to_chain(), *entries2;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001273
1274 if ( (i = check_rule_exists(rule_nr)) == -1 )
Bart De Schuymer60332e02002-06-23 08:01:47 +00001275 print_error("Sorry, rule does not exist");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001276
1277 // we're deleting a rule
1278 replace.num_counters = replace.nentries;
1279 replace.nentries--;
1280
1281 if (replace.nentries) {
1282 for (j = 0; j < replace.selected_hook; j++) {
Bart De Schuymer60332e02002-06-23 08:01:47 +00001283 if (j < NF_BR_NUMHOOKS &&
1284 !(replace.valid_hooks & (1 << j)))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001285 continue;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001286 entries2 = nr_to_chain(j);
1287 lentmp += entries2->nentries;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001288 }
1289 lentmp += i;
1290 // +1 for CNT_END
1291 if ( !(counterchanges = (unsigned short *)malloc(
1292 (replace.num_counters + 1) * sizeof(unsigned short))) )
1293 print_memory();
1294 cnt = counterchanges;
1295 for (j = 0; j < lentmp; j++) {
1296 *cnt = CNT_NORM;
1297 cnt++;
1298 }
1299 *cnt = CNT_DEL;
1300 cnt++;
1301 for (j = 0; j < replace.num_counters - lentmp; j++) {
1302 *cnt = CNT_NORM;
1303 cnt++;
1304 }
1305 *cnt = CNT_END;
1306 }
1307 else
1308 replace.num_counters = 0;
1309
1310 // go to the right position in the chain
1311 u_e2 = NULL;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001312 u_e = entries->entries;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001313 for (j = 0; j < i; j++) {
1314 u_e2 = u_e;
1315 u_e = u_e->next;
1316 }
1317
1318 // remove from the chain
1319 if (u_e2)
1320 u_e2->next = u_e->next;
1321 else
Bart De Schuymer60332e02002-06-23 08:01:47 +00001322 entries->entries = u_e->next;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001323
Bart De Schuymer60332e02002-06-23 08:01:47 +00001324 entries->nentries--;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001325 // free everything
1326 free_u_entry(u_e);
1327 free(u_e);
Bart De Schuymer60332e02002-06-23 08:01:47 +00001328 // update the counter_offset of chains behind this one
1329 i = replace.selected_hook;
1330 while (1) {
1331 i++;
1332 entries = nr_to_chain(i);
1333 if (!entries) {
1334 if (i < NF_BR_NUMHOOKS)
1335 continue;
1336 else
1337 break;
1338 } else
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001339 entries->counter_offset--;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001340 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001341}
1342
1343// execute command Z
Bart De Schuymer62423742002-07-14 19:06:20 +00001344static void zero_counters(int zerochain)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001345{
1346
1347 if (zerochain == -1) {
1348 // tell main() we don't update the counters
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001349 // this results in tricking the kernel to zero its counters,
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001350 // naively expecting userspace to update its counters. Muahahaha
1351 counterchanges = NULL;
1352 replace.num_counters = 0;
1353 } else {
1354 int i, j;
1355 unsigned short *cnt;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001356 struct ebt_u_entries *entries = nr_to_chain(zerochain), *e2;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001357
Bart De Schuymer60332e02002-06-23 08:01:47 +00001358 if (entries->nentries == 0)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001359 exit(0);
1360 counterchanges = (unsigned short *)
1361 malloc((replace.nentries + 1) * sizeof(unsigned short));
1362 if (!counterchanges)
1363 print_memory();
1364 cnt = counterchanges;
1365 for (i = 0; i < zerochain; i++) {
Bart De Schuymer60332e02002-06-23 08:01:47 +00001366 if (i < NF_BR_NUMHOOKS &&
1367 !(replace.valid_hooks & (1 << i)))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001368 continue;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001369 e2 = nr_to_chain(i);
1370 for (j = 0; j < e2->nentries; j++) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001371 *cnt = CNT_NORM;
1372 cnt++;
1373 }
1374 }
Bart De Schuymer60332e02002-06-23 08:01:47 +00001375 for (i = 0; i < entries->nentries; i++) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001376 *cnt = CNT_ZERO;
1377 cnt++;
1378 }
1379 while (cnt != counterchanges + replace.nentries) {
1380 *cnt = CNT_NORM;
1381 cnt++;
1382 }
1383 *cnt = CNT_END;
1384 }
1385}
1386
1387// list the database (optionally compiled into the kernel)
1388static void list_db()
1389{
1390 struct brdb_dbinfo nr;
1391 struct brdb_dbentry *db;
1392 char name[21];
1393 int i;
1394
1395 get_dbinfo(&nr);
1396
1397 // 0 : database disabled (-db n)
1398 if (!(nr.nentries))
1399 print_error("Database not present"
1400 " (disabled), try ebtables --db y");
1401 nr.nentries--;
1402 if (!nr.nentries) print_error("Database empty");
1403 if ( !(db = (struct brdb_dbentry *)
1404 malloc(nr.nentries * sizeof(struct brdb_dbentry))) )
1405 print_memory();
1406
1407 get_db(nr.nentries, db);
1408 printf("number of entries: %d\n", nr.nentries);
1409 for (i = 0; i < nr.nentries; i++) {
1410 printf(
1411 "%d:\n"
1412 "hook : %s\n"
1413 "in-if : %s\n"
1414 "out-if : %s\n"
1415 "protocol: ", i + 1, hooknames[db->hook], db->in, db->out);
1416 if (db->ethproto == IDENTIFY802_3)
1417 printf("802.2/802.3 STYLE LENGTH FIELD\n");
1418 else {
1419 if (number_to_name(ntohs(db->ethproto), name))
1420 printf("%x\n",ntohs(db->ethproto));
1421 else
1422 printf("%s\n", name);
1423 }
1424 db++;
1425 }
1426 exit(0);
1427}
1428
1429// handle db [dis,en]abling
1430static void allowdb(char yorn)
1431{
1432 __u16 decision;
1433
1434 if (yorn != 'y' && yorn != 'n')
1435 print_error("Option [y] or [n] needed");
1436
1437 if (yorn == 'y')
1438 decision = BRDB_DB;
1439 else
1440 decision = BRDB_NODB;
1441
1442 deliver_allowdb(&decision);
1443
1444 exit(0);
1445}
1446
Bart De Schuymer28bf6f62002-06-26 18:57:24 +00001447// 0 == success
1448// 1 == success, but for the special 'protocol' LENGTH
1449// -1 == failure
1450int name_to_number(char *name, __u16 *proto)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001451{
1452 FILE *ifp;
1453 char buffer[21], value[5], *bfr;
1454 unsigned short i;
1455
1456 if (!strcasecmp("LENGTH", name)) {
Bart De Schuymer28bf6f62002-06-26 18:57:24 +00001457 *proto = 0;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001458 new_entry->bitmask |= EBT_802_3;
1459 return 1;
1460 }
1461 if ( !(ifp = fopen(PROTOCOLFILE, "r")) )
1462 return -1;
1463 while (1) {
1464 if (get_a_line(buffer, value, ifp)) return -1;
1465 if (strcasecmp(buffer, name))
1466 continue;
1467 i = (unsigned short) strtol(value, &bfr, 16);
1468 if (*bfr != '\0')
1469 return -1;
Bart De Schuymer28bf6f62002-06-26 18:57:24 +00001470 *proto = i;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001471 fclose(ifp);
1472 return 0;
1473 }
1474 return -1;
1475}
1476
1477// put the mac address into 6 (ETH_ALEN) bytes
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001478int getmac_and_mask(char *from, char *to, char *mask)
1479{
1480 char *p;
1481 int i;
Bart De Schuymer41830412002-06-05 19:41:28 +00001482 struct ether_addr *addr;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001483
1484 if (strcasecmp(from, "Unicast") == 0) {
1485 memcpy(to, mac_type_unicast, ETH_ALEN);
1486 memcpy(mask, msk_type_unicast, ETH_ALEN);
1487 return 0;
1488 }
1489 if (strcasecmp(from, "Multicast") == 0) {
1490 memcpy(to, mac_type_multicast, ETH_ALEN);
1491 memcpy(mask, msk_type_multicast, ETH_ALEN);
1492 return 0;
1493 }
1494 if (strcasecmp(from, "Broadcast") == 0) {
1495 memcpy(to, mac_type_broadcast, ETH_ALEN);
1496 memcpy(mask, msk_type_broadcast, ETH_ALEN);
1497 return 0;
1498 }
1499 if ( (p = strrchr(from, '/')) != NULL) {
1500 *p = '\0';
Bart De Schuymer41830412002-06-05 19:41:28 +00001501 if (!(addr = ether_aton(p + 1)))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001502 return -1;
Bart De Schuymer41830412002-06-05 19:41:28 +00001503 memcpy(mask, addr, ETH_ALEN);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001504 } else
1505 memset(mask, 0xff, ETH_ALEN);
Bart De Schuymer41830412002-06-05 19:41:28 +00001506 if (!(addr = ether_aton(from)))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001507 return -1;
Bart De Schuymer41830412002-06-05 19:41:28 +00001508 memcpy(to, addr, ETH_ALEN);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001509 for (i = 0; i < ETH_ALEN; i++)
1510 to[i] &= mask[i];
1511 return 0;
1512}
1513
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001514// executes the final_check() function for all extensions used by the rule
Bart De Schuymer62423742002-07-14 19:06:20 +00001515static void do_final_checks(struct ebt_u_entry *e, struct ebt_u_entries *entries)
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +00001516{
1517 struct ebt_u_match_list *m_l;
1518 struct ebt_u_watcher_list *w_l;
1519 struct ebt_u_target *t;
1520 struct ebt_u_match *m;
1521 struct ebt_u_watcher *w;
1522
1523 m_l = e->m_list;
1524 w_l = e->w_list;
1525 while (m_l) {
1526 m = find_match(m_l->m->u.name);
1527 m->final_check(e, m_l->m, replace.name,
1528 entries->hook_mask, 1);
1529 m_l = m_l->next;
1530 }
1531 while (w_l) {
1532 w = find_watcher(w_l->w->u.name);
1533 w->final_check(e, w_l->w, replace.name,
1534 entries->hook_mask, 1);
1535 w_l = w_l->next;
1536 }
1537 t = find_target(e->t->u.name);
1538 t->final_check(e, e->t, replace.name,
1539 entries->hook_mask, 1);
1540}
1541
Bart De Schuymerb909f9b2002-06-26 18:35:31 +00001542// used for the -X command
Bart De Schuymer62423742002-07-14 19:06:20 +00001543static void check_for_references(int chain_nr)
Bart De Schuymerb909f9b2002-06-26 18:35:31 +00001544{
1545 int i = -1, j;
1546 struct ebt_u_entries *entries;
1547 struct ebt_u_entry *e;
1548
1549 while (1) {
1550 i++;
1551 entries = nr_to_chain(i);
1552 if (!entries) {
1553 if (i < NF_BR_NUMHOOKS)
1554 continue;
1555 else
1556 break;
1557 }
1558 e = entries->entries;
1559 j = 0;
1560 while (e) {
1561 j++;
1562 if (strcmp(e->t->u.name, EBT_STANDARD_TARGET)) {
1563 e = e->next;
1564 continue;
1565 }
1566 if (((struct ebt_standard_target *)e->t)->verdict == chain_nr)
1567 print_error("Can't delete the chain, it's referenced "
1568 "in chain %s, rule %d", entries->name, j);
1569 e = e->next;
1570 }
1571 }
1572}
1573
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001574int check_inverse(const char option[])
1575{
1576 if (strcmp(option, "!") == 0) {
1577 optind++;
1578 return 1;
1579 }
1580 return 0;
1581}
1582
1583void check_option(unsigned int *flags, unsigned int mask)
1584{
1585 if (*flags & mask)
1586 print_error("Multiple use of same option not allowed");
1587 *flags |= mask;
1588}
1589
1590#define OPT_COMMAND 0x01
1591#define OPT_TABLE 0x02
1592#define OPT_IN 0x04
1593#define OPT_OUT 0x08
1594#define OPT_JUMP 0x10
1595#define OPT_PROTOCOL 0x20
1596#define OPT_SOURCE 0x40
1597#define OPT_DEST 0x80
1598#define OPT_ZERO 0x100
1599#define OPT_LOGICALIN 0x200
1600#define OPT_LOGICALOUT 0x400
1601// the main thing
1602int main(int argc, char *argv[])
1603{
1604 char *buffer, allowbc = 'n';
1605 int c, i;
1606 // this special one for the -Z option (we can have -Z <this> -L <that>)
1607 int zerochain = -1;
Bart De Schuymerf8f8f292002-06-25 15:43:57 +00001608 int policy = 0;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001609 int rule_nr = -1;// used for -D chain number
1610 struct ebt_u_target *t;
1611 struct ebt_u_match *m;
1612 struct ebt_u_watcher *w;
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001613 struct ebt_u_match_list *m_l;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001614 struct ebt_u_watcher_list *w_l;
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001615 struct ebt_u_entries *entries;
Bart De Schuymerc8531032002-06-14 21:55:29 +00001616 const char *modprobe = NULL;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001617
1618 // initialize the table name, OPT_ flags, selected hook and command
1619 strcpy(replace.name, "filter");
1620 replace.flags = 0;
1621 replace.selected_hook = -1;
1622 replace.command = 'h';
Bart De Schuymer62423742002-07-14 19:06:20 +00001623 replace.filename = NULL;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001624
1625 new_entry = (struct ebt_u_entry *)malloc(sizeof(struct ebt_u_entry));
1626 if (!new_entry)
1627 print_memory();
1628 // put some sane values in our new entry
1629 initialize_entry(new_entry);
1630
Bart De Schuymer60332e02002-06-23 08:01:47 +00001631 // The scenario induced by this loop makes that:
Bart De Schuymer62423742002-07-14 19:06:20 +00001632 // '-t' ,'-M' and --atomic (if specified) have to come
1633 // before '-A' and the like
Bart De Schuymer60332e02002-06-23 08:01:47 +00001634
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001635 // getopt saves the day
1636 while ((c = getopt_long(argc, argv,
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001637 "-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 +00001638 switch (c) {
1639
1640 case 'A': // add a rule
1641 case 'D': // delete a rule
1642 case 'P': // define policy
1643 case 'I': // insert a rule
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001644 case 'N': // make a user defined chain
1645 case 'E': // rename chain
1646 case 'X': // delete chain
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001647 replace.command = c;
1648 if (replace.flags & OPT_COMMAND)
1649 print_error("Multiple commands not allowed");
1650 replace.flags |= OPT_COMMAND;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001651 if ( !(table = find_table(replace.name)) )
1652 print_error("Bad table name");
1653 // get the kernel's information
1654 if (get_table(&replace)) {
1655 ebtables_insmod("ebtables", modprobe);
1656 if (get_table(&replace))
1657 print_error("can't initialize ebtables "
1658 "table %s", replace.name);
1659 }
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001660 if (optarg[0] == '-')
1661 print_error("No chain name specified");
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001662 if (c == 'N') {
1663 struct ebt_u_chain_list *cl, **cl2;
1664
1665 if (get_hooknr(optarg) != -1)
1666 print_error("Chain %s already exists",
1667 optarg);
1668 if (find_target(optarg))
1669 print_error("Target with name %s exists"
1670 , optarg);
1671 if (strlen(optarg) >= EBT_CHAIN_MAXNAMELEN)
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001672 print_error("Chain name length can't exceed %d",
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001673 EBT_CHAIN_MAXNAMELEN - 1);
1674 cl = (struct ebt_u_chain_list *)
1675 malloc(sizeof(struct ebt_u_chain_list));
1676 if (!cl)
1677 print_memory();
1678 cl->next = NULL;
1679 cl->udc = (struct ebt_u_entries *)
1680 malloc(sizeof(struct ebt_u_entries));
1681 if (!cl->udc)
1682 print_memory();
1683 cl->udc->nentries = 0;
1684 cl->udc->policy = EBT_ACCEPT;
1685 cl->udc->counter_offset = replace.nentries;
1686 cl->udc->hook_mask = 0;
1687 strcpy(cl->udc->name, optarg);
1688 cl->udc->entries = NULL;
1689 cl->kernel_start = NULL;
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001690 // put the new chain at the end
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001691 cl2 = &replace.udc;
1692 while (*cl2)
1693 cl2 = &((*cl2)->next);
1694 *cl2 = cl;
1695 break;
1696 }
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001697 if ((replace.selected_hook = get_hooknr(optarg)) == -1)
1698 print_error("Chain %s doesn't exist", optarg);
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001699 if (c == 'E') {
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001700 if (optind >= argc || argv[optind][0] == '-')
1701 print_error("No new chain name specified");
1702 if (strlen(argv[optind]) >= EBT_CHAIN_MAXNAMELEN)
1703 print_error("Chain name len can't exceed %d",
1704 EBT_CHAIN_MAXNAMELEN - 1);
1705 if (get_hooknr(argv[optind]) != -1)
1706 print_error("Chain %s already exists",
1707 argv[optind]);
1708 entries = to_chain();
1709 strcpy(entries->name, argv[optind]);
1710 optind++;
1711 break;
1712 }
1713 if (c == 'X') {
1714 struct ebt_u_chain_list *cl, **cl2;
1715
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001716 if (replace.selected_hook < NF_BR_NUMHOOKS)
1717 print_error("You can't remove a standard chain");
Bart De Schuymerb909f9b2002-06-26 18:35:31 +00001718 // if the chain is referenced, don't delete it
1719 check_for_references(replace.selected_hook - NF_BR_NUMHOOKS);
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001720 flush_chains();
1721 entries = to_chain();
1722 if (replace.udc->udc == entries) {
1723 cl = replace.udc;
1724 replace.udc = replace.udc->next;
1725 free(cl->udc);
1726 free(cl);
1727 break;
1728 }
1729 cl2 = &(replace.udc);
1730 while ((*cl2)->next->udc != entries)
1731 cl2 = &((*cl2)->next);
1732 cl = (*cl2)->next;
1733 (*cl2)->next = (*cl2)->next->next;
1734 free(cl->udc);
1735 free(cl);
1736 break;
1737 }
1738
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001739 if (c == 'D' && optind < argc &&
1740 argv[optind][0] != '-') {
1741 rule_nr = strtol(argv[optind], &buffer, 10);
1742 if (*buffer != '\0' || rule_nr < 0)
1743 print_error("Problem with the "
1744 "specified rule number");
1745 optind++;
1746 }
1747 if (c == 'P') {
1748 if (optind >= argc)
1749 print_error("No policy specified");
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001750 policy = 0;
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001751 for (i = 0; i < NUM_STANDARD_TARGETS; i++)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001752 if (!strcmp(argv[optind],
1753 standard_targets[i])) {
Bart De Schuymer60332e02002-06-23 08:01:47 +00001754 policy = -i -1;
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001755 if (policy == EBT_CONTINUE)
1756 policy = 0;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001757 break;
1758 }
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001759 if (policy == 0)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001760 print_error("Wrong policy");
1761 optind++;
1762 }
1763 if (c == 'I') {
1764 if (optind >= argc)
1765 print_error("No rulenr for -I"
1766 " specified");
1767 rule_nr = strtol(argv[optind], &buffer, 10);
1768 if (*buffer != '\0' || rule_nr < 0)
1769 print_error("Problem with the specified"
1770 " rule number");
1771 optind++;
1772 }
1773 break;
1774
1775 case 'L': // list
1776 case 'F': // flush
1777 case 'Z': // zero counters
1778 if (c == 'Z') {
1779 if (replace.flags & OPT_ZERO)
1780 print_error("Multiple commands"
1781 " not allowed");
1782 if ( (replace.flags & OPT_COMMAND &&
1783 replace.command != 'L'))
1784 print_error("command -Z only allowed "
1785 "together with command -L");
1786 replace.flags |= OPT_ZERO;
1787 } else {
1788 replace.command = c;
1789 if (replace.flags & OPT_COMMAND)
1790 print_error("Multiple commands"
1791 " not allowed");
1792 replace.flags |= OPT_COMMAND;
1793 }
Bart De Schuymer60332e02002-06-23 08:01:47 +00001794 if ( !(table = find_table(replace.name)) )
1795 print_error("Bad table name");
1796 // get the kernel's information
1797 if (get_table(&replace)) {
1798 ebtables_insmod("ebtables", modprobe);
1799 if (get_table(&replace))
1800 print_error("can't initialize ebtables "
1801 "table %s", replace.name);
1802 }
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001803 i = -1;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001804 if (optarg) {
1805 if ( (i = get_hooknr(optarg)) == -1 )
1806 print_error("Bad chain");
1807 } else
1808 if (optind < argc && argv[optind][0] != '-') {
1809 if ((i = get_hooknr(argv[optind]))
1810 == -1)
1811 print_error("Bad chain");
1812 optind++;
1813 }
1814 if (i != -1) {
1815 if (c == 'Z')
1816 zerochain = i;
1817 else
1818 replace.selected_hook = i;
1819 }
1820 break;
1821
1822 case 'V': // version
1823 replace.command = 'V';
1824 if (replace.flags & OPT_COMMAND)
1825 print_error("Multiple commands not allowed");
1826 printf("%s, %s\n", prog_name, prog_version);
1827 exit(0);
1828
Bart De Schuymerc8531032002-06-14 21:55:29 +00001829 case 'M': // modprobe
Bart De Schuymer60332e02002-06-23 08:01:47 +00001830 if (replace.command != 'h')
1831 print_error("Please put the -M option earlier");
Bart De Schuymerc8531032002-06-14 21:55:29 +00001832 modprobe = optarg;
1833 break;
1834
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001835 case 'h': // help
1836 if (replace.flags & OPT_COMMAND)
1837 print_error("Multiple commands not allowed");
1838 replace.command = 'h';
1839 // All other arguments should be extension names
1840 while (optind < argc) {
1841 struct ebt_u_match *m;
1842 struct ebt_u_watcher *w;
1843
1844 if ((m = find_match(argv[optind])))
1845 add_match(m);
1846 else if ((w = find_watcher(argv[optind])))
1847 add_watcher(w);
1848 else {
1849 if (!(t = find_target(argv[optind])))
1850 print_error("Extension %s "
1851 "not found", argv[optind]);
1852 if (replace.flags & OPT_JUMP)
1853 print_error("Sorry, you can "
1854 "only see help for one "
1855 "target extension each time");
1856 replace.flags |= OPT_JUMP;
1857 new_entry->t =
1858 (struct ebt_entry_target *)t;
1859 }
1860 optind++;
1861 }
1862 break;
1863
1864 case 't': // table
Bart De Schuymer60332e02002-06-23 08:01:47 +00001865 if (replace.command != 'h')
1866 print_error("Please put the -t option first");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001867 check_option(&replace.flags, OPT_TABLE);
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001868 if (strlen(optarg) > EBT_TABLE_MAXNAMELEN - 1)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001869 print_error("Table name too long");
1870 strcpy(replace.name, optarg);
1871 break;
1872
1873 case 'i': // input interface
1874 case 2 : // logical input interface
1875 case 'o': // output interface
1876 case 3 : // logical output interface
1877 case 'j': // target
1878 case 'p': // net family protocol
1879 case 's': // source mac
1880 case 'd': // destination mac
1881 if ((replace.flags & OPT_COMMAND) == 0)
1882 print_error("No command specified");
1883 if ( replace.command != 'A' &&
1884 replace.command != 'D' && replace.command != 'I')
1885 print_error("Command and option do not match");
1886 if (c == 'i') {
1887 check_option(&replace.flags, OPT_IN);
1888 if (replace.selected_hook > 2 &&
1889 replace.selected_hook < NF_BR_BROUTING)
1890 print_error("Use in-interface only in "
1891 "INPUT, FORWARD, PREROUTING and"
1892 "BROUTING chains");
1893 if (check_inverse(optarg))
1894 new_entry->invflags |= EBT_IIN;
1895
1896 if (optind > argc)
1897 print_error("No in-interface "
1898 "specified");
1899 if (strlen(argv[optind - 1]) >= IFNAMSIZ)
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001900 print_error("Illegal interface length");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001901 strcpy(new_entry->in, argv[optind - 1]);
1902 break;
1903 }
1904 if (c == 2) {
1905 check_option(&replace.flags, OPT_LOGICALIN);
1906 if (replace.selected_hook > 2 &&
1907 replace.selected_hook < NF_BR_BROUTING)
1908 print_error("Use logical in-interface "
1909 "only in INPUT, FORWARD, "
1910 "PREROUTING and BROUTING chains");
1911 if (check_inverse(optarg))
1912 new_entry->invflags |= EBT_ILOGICALIN;
1913
1914 if (optind > argc)
1915 print_error("No logical in-interface "
1916 "specified");
1917 if (strlen(argv[optind - 1]) >= IFNAMSIZ)
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001918 print_error("Illegal interface length");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001919 strcpy(new_entry->logical_in, argv[optind - 1]);
1920 break;
1921 }
1922 if (c == 'o') {
1923 check_option(&replace.flags, OPT_OUT);
1924 if (replace.selected_hook < 2)
1925 print_error("Use out-interface only"
1926 " in OUTPUT, FORWARD and "
1927 "POSTROUTING chains");
1928 if (check_inverse(optarg))
1929 new_entry->invflags |= EBT_IOUT;
1930
1931 if (optind > argc)
1932 print_error("No out-interface "
1933 "specified");
1934
1935 if (strlen(argv[optind - 1]) >= IFNAMSIZ)
1936 print_error("Illegal interface "
1937 "length");
1938 strcpy(new_entry->out, argv[optind - 1]);
1939 break;
1940 }
1941 if (c == 3) {
1942 check_option(&replace.flags, OPT_LOGICALOUT);
1943 if (replace.selected_hook < 2)
1944 print_error("Use logical out-interface "
1945 "only in OUTPUT, FORWARD and "
1946 "POSTROUTING chains");
1947 if (check_inverse(optarg))
1948 new_entry->invflags |= EBT_ILOGICALOUT;
1949
1950 if (optind > argc)
1951 print_error("No logical out-interface "
1952 "specified");
1953
1954 if (strlen(argv[optind - 1]) >= IFNAMSIZ)
1955 print_error("Illegal interface "
1956 "length");
1957 strcpy(new_entry->logical_out,
1958 argv[optind - 1]);
1959 break;
1960 }
1961 if (c == 'j') {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001962 check_option(&replace.flags, OPT_JUMP);
1963 for (i = 0; i < NUM_STANDARD_TARGETS; i++)
1964 if (!strcmp(optarg,
1965 standard_targets[i])) {
1966 t = find_target(
1967 EBT_STANDARD_TARGET);
1968 ((struct ebt_standard_target *)
Bart De Schuymer60332e02002-06-23 08:01:47 +00001969 t->t)->verdict = -i - 1;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001970 break;
1971 }
Bart De Schuymer60332e02002-06-23 08:01:47 +00001972 if (-i - 1 == EBT_RETURN) {
1973 if (replace.selected_hook < NF_BR_NUMHOOKS)
1974 print_error("Return target"
1975 " only for user defined chains");
1976 }
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +00001977 if (i != NUM_STANDARD_TARGETS)
1978 break;
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001979 if ((i = get_hooknr(optarg)) != -1) {
1980 if (i < NF_BR_NUMHOOKS)
1981 print_error("don't jump"
1982 " to a standard chain");
1983 t = find_target(
1984 EBT_STANDARD_TARGET);
1985 ((struct ebt_standard_target *)
1986 t->t)->verdict = i - NF_BR_NUMHOOKS;
1987 break;
1988 }
1989 else {
1990 // must be an extension then
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001991 struct ebt_u_target *t;
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001992
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001993 t = find_target(optarg);
1994 // -j standard not allowed either
1995 if (!t || t ==
1996 (struct ebt_u_target *)new_entry->t)
1997 print_error("Illegal target "
1998 "name");
1999 new_entry->t =
2000 (struct ebt_entry_target *)t;
2001 }
2002 break;
2003 }
2004 if (c == 's') {
2005 check_option(&replace.flags, OPT_SOURCE);
2006 if (check_inverse(optarg))
2007 new_entry->invflags |= EBT_ISOURCE;
2008
2009 if (optind > argc)
2010 print_error("No source mac "
2011 "specified");
2012 if (getmac_and_mask(argv[optind - 1],
2013 new_entry->sourcemac, new_entry->sourcemsk))
2014 print_error("Problem with specified "
2015 "source mac");
2016 new_entry->bitmask |= EBT_SOURCEMAC;
2017 break;
2018 }
2019 if (c == 'd') {
2020 check_option(&replace.flags, OPT_DEST);
2021 if (check_inverse(optarg))
2022 new_entry->invflags |= EBT_IDEST;
2023
2024 if (optind > argc)
2025 print_error("No destination mac "
2026 "specified");
2027 if (getmac_and_mask(argv[optind - 1],
2028 new_entry->destmac, new_entry->destmsk))
2029 print_error("Problem with specified "
2030 "destination mac");
2031 new_entry->bitmask |= EBT_DESTMAC;
2032 break;
2033 }
2034 check_option(&replace.flags, OPT_PROTOCOL);
2035 if (check_inverse(optarg))
2036 new_entry->invflags |= EBT_IPROTO;
2037
2038 if (optind > argc)
2039 print_error("No protocol specified");
2040 new_entry->bitmask &= ~((unsigned int)EBT_NOPROTO);
2041 i = strtol(argv[optind - 1], &buffer, 16);
2042 if (*buffer == '\0' && (i < 0 || i > 0xFFFF))
2043 print_error("Problem with the specified "
2044 "protocol");
2045 new_entry->ethproto = i;
Bart De Schuymer28bf6f62002-06-26 18:57:24 +00002046 if (*buffer != '\0') {
2047 if ((i = name_to_number(argv[optind - 1],
2048 &new_entry->ethproto)) == -1)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002049 print_error("Problem with the specified"
2050 " protocol");
Bart De Schuymer28bf6f62002-06-26 18:57:24 +00002051 if (i == 1)
2052 new_entry->bitmask |= EBT_802_3;
2053 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002054 if (new_entry->ethproto < 1536 &&
2055 !(new_entry->bitmask & EBT_802_3))
2056 print_error("Sorry, protocols have values above"
2057 " or equal to 1536 (0x0600)");
2058 break;
2059
2060 case 'b': // allow database?
2061 if (replace.flags & OPT_COMMAND)
2062 print_error("Multiple commands not allowed");
2063 replace.command = c;
2064 allowbc = *optarg;
2065 break;
2066
Bart De Schuymer9af14f92002-07-10 20:49:10 +00002067 case 4 : // Lc
2068 check_option(&replace.flags, LIST_C);
2069 if (replace.selected_hook == DATABASEHOOKNR)
2070 print_error("--Lc not valid for listing"
2071 " the database");
2072 if (replace.command != 'L')
2073 print_error("Use --Lc with -L");
2074 if (replace.flags & LIST_X)
2075 print_error("--Lx not compatible with --Lc");
2076 replace.flags |= LIST_C;
2077 break;
2078 case 5 : // Ln
2079 check_option(&replace.flags, LIST_N);
2080 if (replace.selected_hook == DATABASEHOOKNR)
2081 print_error("--Ln not valid for listing"
2082 " the database");
2083 if (replace.command != 'L')
2084 print_error("Use --Ln with -L");
2085 if (replace.flags & LIST_X)
2086 print_error("--Lx not compatible with --Ln");
2087 replace.flags |= LIST_N;
2088 break;
2089 case 6 : // Lx
2090 check_option(&replace.flags, LIST_X);
2091 if (replace.selected_hook == DATABASEHOOKNR)
2092 print_error("--Lx not valid for listing"
2093 " the database");
2094 if (replace.command != 'L')
2095 print_error("Use --Lx with -L");
2096 if (replace.flags & LIST_C)
2097 print_error("--Lx not compatible with --Lc");
2098 if (replace.flags & LIST_N)
2099 print_error("--Lx not compatible with --Ln");
2100 replace.flags |= LIST_X;
2101 break;
Bart De Schuymer62423742002-07-14 19:06:20 +00002102 case 8 : // atomic-commit
2103 replace.command = c;
2104 if (replace.flags & OPT_COMMAND)
2105 print_error("Multiple commands not allowed");
2106 replace.flags |= OPT_COMMAND;
2107 replace.filename = (char *)malloc(strlen(optarg) + 1);
2108 strcpy(replace.filename, optarg);
2109 // get the information from the file
2110 get_table(&replace);
2111 replace.num_counters = 0;
2112 free(replace.filename);
2113 replace.filename = NULL;
2114 break;
2115 case 7 : // atomic-init
2116 case 10: // atomic-save
Bart De Schuymer8d1d8942002-07-15 20:09:09 +00002117 case 11: // init-table
Bart De Schuymer62423742002-07-14 19:06:20 +00002118 replace.command = c;
2119 if (replace.flags & OPT_COMMAND)
2120 print_error("Multiple commands not allowed");
2121 replace.flags |= OPT_COMMAND;
2122 if ( !(table = find_table(replace.name)) )
2123 print_error("Bad table name");
2124 if (get_table(&replace)) {
2125 ebtables_insmod("ebtables", modprobe);
2126 if (get_table(&replace))
2127 print_error("can't initialize ebtables "
2128 "table %s", replace.name);
2129 }
Bart De Schuymer8d1d8942002-07-15 20:09:09 +00002130 replace.num_counters = 0;
2131 if (c == 11)
2132 break;
Bart De Schuymer62423742002-07-14 19:06:20 +00002133 case 9 : // atomic
2134 replace.filename = (char *)malloc(strlen(optarg) + 1);
2135 strcpy(replace.filename, optarg);
2136 break;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002137
Bart De Schuymer9af14f92002-07-10 20:49:10 +00002138 default:
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002139 // is it a target option?
2140 t = (struct ebt_u_target *)new_entry->t;
2141 if ((t->parse(c - t->option_offset, argv, argc,
2142 new_entry, &t->flags, &t->t)))
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00002143 goto check_extension;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002144
2145 // is it a match_option?
2146 for (m = matches; m; m = m->next)
2147 if (m->parse(c - m->option_offset, argv,
2148 argc, new_entry, &m->flags, &m->m))
2149 break;
2150
2151 if (m != NULL) {
2152 if (m->used == 0)
2153 add_match(m);
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00002154 goto check_extension;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002155 }
2156
2157 // is it a watcher option?
2158 for (w = watchers; w; w = w->next)
2159 if (w->parse(c-w->option_offset, argv,
2160 argc, new_entry, &w->flags, &w->w))
2161 break;
2162
2163 if (w == NULL)
2164 print_error("Unknown argument");
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00002165 if (w->used == 0)
2166 add_watcher(w);
2167check_extension:
Bart De Schuymer60332e02002-06-23 08:01:47 +00002168 if (replace.command != 'A' && replace.command != 'I' &&
2169 replace.command != 'D')
2170 print_error("extensions only for -A, -I and -D");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002171 }
2172 }
2173
Bart De Schuymer25c741d2002-06-23 18:54:34 +00002174 if ( !table && !(table = find_table(replace.name)) )
2175 print_error("Bad table name");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002176 // database stuff before ebtables stuff
2177 if (replace.command == 'b')
2178 allowdb(allowbc);
2179 if (replace.command == 'L' && replace.selected_hook == DATABASEHOOKNR)
2180 list_db();
2181
2182 if ( (replace.flags & OPT_COMMAND) && replace.command != 'L' &&
2183 replace.flags & OPT_ZERO )
2184 print_error("Command -Z only allowed together with command -L");
2185
2186 if (replace.command == 'A' || replace.command == 'I' ||
2187 replace.command == 'D') {
2188 if (replace.selected_hook == -1)
2189 print_error("Not enough information");
2190 }
2191
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002192 // do this after parsing everything, so we can print specific info
2193 if (replace.command == 'h' && !(replace.flags & OPT_ZERO))
2194 print_help();
2195
2196 // do the final checks
Bart De Schuymer60332e02002-06-23 08:01:47 +00002197 if (replace.command == 'A' || replace.command == 'I' ||
2198 replace.command == 'D') {
2199 // this will put the hook_mask right for the chains
2200 check_for_loops();
2201 entries = to_chain();
2202 m_l = new_entry->m_list;
2203 w_l = new_entry->w_list;
2204 t = (struct ebt_u_target *)new_entry->t;
2205 while (m_l) {
2206 m = (struct ebt_u_match *)(m_l->m);
2207 m->final_check(new_entry, m->m, replace.name,
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +00002208 entries->hook_mask, 0);
Bart De Schuymer60332e02002-06-23 08:01:47 +00002209 m_l = m_l->next;
2210 }
2211 while (w_l) {
2212 w = (struct ebt_u_watcher *)(w_l->w);
2213 w->final_check(new_entry, w->w, replace.name,
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +00002214 entries->hook_mask, 0);
Bart De Schuymer60332e02002-06-23 08:01:47 +00002215 w_l = w_l->next;
2216 }
2217 t->final_check(new_entry, t->t, replace.name,
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +00002218 entries->hook_mask, 0);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002219 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002220 // so, the extensions can work with the host endian
2221 // the kernel does not have to do this ofcourse
2222 new_entry->ethproto = htons(new_entry->ethproto);
2223
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002224 if (replace.command == 'P')
2225 change_policy(policy);
2226 else if (replace.command == 'L') {
2227 list_rules();
2228 if (replace.flags & OPT_ZERO)
2229 zero_counters(zerochain);
2230 else
2231 exit(0);
2232 }
2233 if (replace.flags & OPT_ZERO)
2234 zero_counters(zerochain);
Bart De Schuymer1ab41562002-06-23 17:09:54 +00002235 else if (replace.command == 'F') {
2236 if (flush_chains() == -1)
2237 exit(0);
2238 } else if (replace.command == 'A' || replace.command == 'I') {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002239 add_rule(rule_nr);
Bart De Schuymer1ab41562002-06-23 17:09:54 +00002240 check_for_loops();
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +00002241 // do the final_check(), for all entries
2242 // needed when adding a rule that has a chain target
2243 i = -1;
2244 while (1) {
2245 struct ebt_u_entry *e;
2246
2247 i++;
2248 entries = nr_to_chain(i);
2249 if (!entries) {
2250 if (i < NF_BR_NUMHOOKS)
2251 continue;
2252 else
2253 break;
2254 }
2255 e = entries->entries;
2256 while (e) {
2257 // userspace extensions use host endian
2258 e->ethproto = ntohs(e->ethproto);
2259 do_final_checks(e, entries);
2260 e->ethproto = htons(e->ethproto);
2261 e = e->next;
2262 }
2263 }
Bart De Schuymer1ab41562002-06-23 17:09:54 +00002264 } else if (replace.command == 'D')
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002265 delete_rule(rule_nr);
Bart De Schuymer8d1d8942002-07-15 20:09:09 +00002266 // commands -N, -E, -X, --atomic-commit, --atomic-commit, --atomic-save,
2267 // --init-table fall through
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002268
2269 if (table->check)
2270 table->check(&replace);
2271
2272 deliver_table(&replace);
2273
2274 if (counterchanges)
2275 deliver_counters(&replace, counterchanges);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002276 return 0;
2277}