blob: b9d20a4475bfd8a36cb6969db09c6995d2b8b5b6 [file] [log] [blame]
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001/*
2 * ebtables.c, v2.0 April 2002
3 *
4 * Author: Bart De Schuymer
5 *
6 * This code is stongly inspired on the iptables code which is
7 * Copyright (C) 1999 Paul `Rusty' Russell & Michael J. Neuling
8 *
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License as
11 * published by the Free Software Foundation; either version 2 of the
12 * License, or (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 */
23
24#include <getopt.h>
25#include <string.h>
26#include <errno.h>
27#include <stdio.h>
28#include <stdlib.h>
29#include <sys/socket.h>
30#include <sys/types.h>
31#include <linux/netfilter_bridge/ebtables.h>
32#include <linux/br_db.h> // the database
33#include <netinet/in.h>
Bart De Schuymer41830412002-06-05 19:41:28 +000034#include <netinet/ether.h>
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000035#include <asm/types.h>
36#include "include/ebtables_u.h"
Bart De Schuymerc8531032002-06-14 21:55:29 +000037#include <unistd.h>
38#include <fcntl.h>
39#include <sys/wait.h>
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000040
41// here are the number-name correspondences kept for the ethernet
42// frame type field
43#define PROTOCOLFILE "/etc/ethertypes"
44
Bart De Schuymerc8531032002-06-14 21:55:29 +000045#ifndef PROC_SYS_MODPROBE
46#define PROC_SYS_MODPROBE "/proc/sys/kernel/modprobe"
47#endif
48
Bart De Schuymer60332e02002-06-23 08:01:47 +000049#define DATABASEHOOKNR -2
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000050#define DATABASEHOOKNAME "DB"
51
52static char *prog_name = PROGNAME;
53static char *prog_version = PROGVERSION;
Bart De Schuymer60332e02002-06-23 08:01:47 +000054char *hooknames[NF_BR_NUMHOOKS] =
55{
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000056 [NF_BR_PRE_ROUTING]"PREROUTING",
57 [NF_BR_LOCAL_IN]"INPUT",
58 [NF_BR_FORWARD]"FORWARD",
59 [NF_BR_LOCAL_OUT]"OUTPUT",
60 [NF_BR_POST_ROUTING]"POSTROUTING",
61 [NF_BR_BROUTING]"BROUTING"
62};
63
64// default command line options
65static struct option ebt_original_options[] = {
66 { "append" , required_argument, 0, 'A' },
67 { "insert" , required_argument, 0, 'I' },
68 { "delete" , required_argument, 0, 'D' },
69 { "list" , optional_argument, 0, 'L' },
Bart De Schuymer9af14f92002-07-10 20:49:10 +000070 { "Lc" , no_argument , 0, 4 },
71 { "Ln" , no_argument , 0, 5 },
72 { "Lx" , no_argument , 0, 6 },
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000073 { "zero" , optional_argument, 0, 'Z' },
74 { "flush" , optional_argument, 0, 'F' },
75 { "policy" , required_argument, 0, 'P' },
76 { "in-interface" , required_argument, 0, 'i' },
77 { "in-if" , required_argument, 0, 'i' },
78 { "logical-in" , required_argument, 0, 2 },
79 { "logical-out" , required_argument, 0, 3 },
80 { "out-interface" , required_argument, 0, 'o' },
81 { "out-if" , required_argument, 0, 'o' },
82 { "version" , no_argument , 0, 'V' },
83 { "help" , no_argument , 0, 'h' },
84 { "jump" , required_argument, 0, 'j' },
85 { "proto" , required_argument, 0, 'p' },
86 { "protocol" , required_argument, 0, 'p' },
87 { "db" , required_argument, 0, 'b' },
88 { "source" , required_argument, 0, 's' },
89 { "src" , required_argument, 0, 's' },
90 { "destination" , required_argument, 0, 'd' },
91 { "dst" , required_argument, 0, 'd' },
92 { "table" , required_argument, 0, 't' },
Bart De Schuymerc8531032002-06-14 21:55:29 +000093 { "modprobe" , required_argument, 0, 'M' },
Bart De Schuymer1ab41562002-06-23 17:09:54 +000094 { "new-chain" , required_argument, 0, 'N' },
95 { "rename-chain" , required_argument, 0, 'E' },
96 { "delete-chain" , required_argument, 0, 'X' },
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000097 { 0 }
98};
99
100static struct option *ebt_options = ebt_original_options;
101
102// yup, all the possible target names
103char* standard_targets[NUM_STANDARD_TARGETS] = {
104 "ACCEPT",
105 "DROP",
106 "CONTINUE",
Bart De Schuymer60332e02002-06-23 08:01:47 +0000107 "RETURN",
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000108};
109
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000110unsigned char mac_type_unicast[ETH_ALEN] = {0,0,0,0,0,0};
111unsigned char msk_type_unicast[ETH_ALEN] = {1,0,0,0,0,0};
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000112unsigned char mac_type_multicast[ETH_ALEN] = {1,0,0,0,0,0};
113unsigned char msk_type_multicast[ETH_ALEN] = {1,0,0,0,0,0};
114unsigned char mac_type_broadcast[ETH_ALEN] = {255,255,255,255,255,255};
115unsigned char msk_type_broadcast[ETH_ALEN] = {255,255,255,255,255,255};
116
117// tells what happened to the old rules
118static unsigned short *counterchanges;
119// holds all the data
120static struct ebt_u_replace replace;
121
122// the chosen table
123static struct ebt_u_table *table = NULL;
124// the lists of supported tables, matches, watchers and targets
125static struct ebt_u_table *tables = NULL;
126static struct ebt_u_match *matches = NULL;
127static struct ebt_u_watcher *watchers = NULL;
128static struct ebt_u_target *targets = NULL;
129
130struct ebt_u_target *find_target(const char *name)
131{
132 struct ebt_u_target *t = targets;
133
134 while(t && strcmp(t->name, name))
135 t = t->next;
136 return t;
137}
138
139struct ebt_u_match *find_match(const char *name)
140{
141 struct ebt_u_match *m = matches;
142
143 while(m && strcmp(m->name, name))
144 m = m->next;
145 return m;
146}
147
148struct ebt_u_watcher *find_watcher(const char *name)
149{
150 struct ebt_u_watcher *w = watchers;
151
152 while(w && strcmp(w->name, name))
153 w = w->next;
154 return w;
155}
156
157struct ebt_u_table *find_table(char *name)
158{
159 struct ebt_u_table *t = tables;
160
161 while (t && strcmp(t->name, name))
162 t = t->next;
163 return t;
164}
165
166// The pointers in here are special:
167// The struct ebt_target * pointer is actually a struct ebt_u_target * pointer.
168// instead of making yet a few other structs, we just do a cast.
169// We need a struct ebt_u_target pointer because we know the address of the data
170// they point to won't change. We want to allow that the struct ebt_u_target.t
171// member can change.
172// Same holds for the struct ebt_match and struct ebt_watcher pointers
173struct ebt_u_entry *new_entry;
174
175void initialize_entry(struct ebt_u_entry *e)
176{
177 e->bitmask = EBT_NOPROTO;
178 e->invflags = 0;
179 e->ethproto = 0;
180 strcpy(e->in, "");
181 strcpy(e->out, "");
182 strcpy(e->logical_in, "");
183 strcpy(e->logical_out, "");
184 e->m_list = NULL;
185 e->w_list = NULL;
186 // the init function of the standard target should have put the verdict
187 // on CONTINUE
188 e->t = (struct ebt_entry_target *)find_target(EBT_STANDARD_TARGET);
189 if (!e->t)
190 print_bug("Couldn't load standard target\n");
191}
192
193// this doesn't free e, becoz the calling function might need e->next
194void free_u_entry(struct ebt_u_entry *e)
195{
196 struct ebt_u_match_list *m_l, *m_l2;
197 struct ebt_u_watcher_list *w_l, *w_l2;
198
199 m_l = e->m_list;
200 while (m_l) {
201 m_l2 = m_l->next;
202 free(m_l->m);
203 free(m_l);
204 m_l = m_l2;
205 }
206 w_l = e->w_list;
207 while (w_l) {
208 w_l2 = w_l->next;
209 free(w_l->w);
210 free(w_l);
211 w_l = w_l2;
212 }
213 free(e->t);
214}
215
216// the user will use the match, so put it in new_entry
217static void add_match(struct ebt_u_match *m)
218{
219 struct ebt_u_match_list **m_list, *new;
220
221 m->used = 1;
222 for (m_list = &new_entry->m_list;
223 *m_list; m_list = &(*m_list)->next);
224 new = (struct ebt_u_match_list *)
225 malloc(sizeof(struct ebt_u_match_list));
226 if (!new)
227 print_memory();
228 *m_list = new;
229 new->next = NULL;
230 new->m = (struct ebt_entry_match *)m;
231}
232
233static void add_watcher(struct ebt_u_watcher *w)
234{
235 struct ebt_u_watcher_list **w_list;
236 struct ebt_u_watcher_list *new;
237
238 w->used = 1;
239 for (w_list = &new_entry->w_list;
240 *w_list; w_list = &(*w_list)->next);
241 new = (struct ebt_u_watcher_list *)
242 malloc(sizeof(struct ebt_u_watcher_list));
243 if (!new)
244 print_memory();
245 *w_list = new;
246 new->next = NULL;
247 new->w = (struct ebt_entry_watcher *)w;
248}
249
250static int global_option_offset = 0;
251#define OPTION_OFFSET 256
252static struct option *
253merge_options(struct option *oldopts, const struct option *newopts,
254 unsigned int *options_offset)
255{
256 unsigned int num_old, num_new, i;
257 struct option *merge;
258
259 if (!newopts || !oldopts || !options_offset)
260 print_bug("merge wrong");
261 for (num_old = 0; oldopts[num_old].name; num_old++);
262 for (num_new = 0; newopts[num_new].name; num_new++);
263
264 global_option_offset += OPTION_OFFSET;
265 *options_offset = global_option_offset;
266
267 merge = malloc(sizeof(struct option) * (num_new + num_old + 1));
268 if (!merge)
269 print_memory();
270 memcpy(merge, oldopts, num_old * sizeof(struct option));
271 for (i = 0; i < num_new; i++) {
272 merge[num_old + i] = newopts[i];
273 merge[num_old + i].val += *options_offset;
274 }
275 memset(merge + num_old + num_new, 0, sizeof(struct option));
276 // only free dynamically allocated stuff
277 if (oldopts != ebt_original_options)
278 free(oldopts);
279
280 return merge;
281}
282
283void register_match(struct ebt_u_match *m)
284{
285 int size = m->size + sizeof(struct ebt_entry_match);
286 struct ebt_u_match **i;
287
288 m->m = (struct ebt_entry_match *)malloc(size);
289 if (!m->m)
290 print_memory();
291 strcpy(m->m->u.name, m->name);
292 m->m->match_size = m->size;
293 ebt_options = merge_options
294 (ebt_options, m->extra_ops, &(m->option_offset));
295 m->init(m->m);
296
297 for (i = &matches; *i; i = &((*i)->next));
298 m->next = NULL;
299 *i = m;
300}
301
302void register_watcher(struct ebt_u_watcher *w)
303{
304 int size = w->size + sizeof(struct ebt_entry_watcher);
305 struct ebt_u_watcher **i;
306
307 w->w = (struct ebt_entry_watcher *)malloc(size);
308 if (!w->w)
309 print_memory();
310 strcpy(w->w->u.name, w->name);
311 w->w->watcher_size = w->size;
312 ebt_options = merge_options
313 (ebt_options, w->extra_ops, &(w->option_offset));
314 w->init(w->w);
315
316 for (i = &watchers; *i; i = &((*i)->next));
317 w->next = NULL;
318 *i = w;
319}
320
321void register_target(struct ebt_u_target *t)
322{
323 int size = t->size + sizeof(struct ebt_entry_target);
324 struct ebt_u_target **i;
325
326 t->t = (struct ebt_entry_target *)malloc(size);
327 if (!t->t)
328 print_memory();
329 strcpy(t->t->u.name, t->name);
330 t->t->target_size = t->size;
331 ebt_options = merge_options
332 (ebt_options, t->extra_ops, &(t->option_offset));
333 t->init(t->t);
334 for (i = &targets; *i; i = &((*i)->next));
335 t->next = NULL;
336 *i = t;
337}
338
339void register_table(struct ebt_u_table *t)
340{
341 t->next = tables;
342 tables = t;
343}
344
Bart De Schuymerc8531032002-06-14 21:55:29 +0000345// blatently stolen (again) from iptables.c userspace program
346// find out where the modprobe utility is located
347static char *get_modprobe(void)
348{
349 int procfile;
350 char *ret;
351
352 procfile = open(PROC_SYS_MODPROBE, O_RDONLY);
353 if (procfile < 0)
354 return NULL;
355
356 ret = malloc(1024);
357 if (ret) {
358 switch (read(procfile, ret, 1024)) {
359 case -1: goto fail;
360 case 1024: goto fail; /* Partial read. Wierd */
361 }
362 if (ret[strlen(ret)-1]=='\n')
363 ret[strlen(ret)-1]=0;
364 close(procfile);
365 return ret;
366 }
367 fail:
368 free(ret);
369 close(procfile);
370 return NULL;
371}
372
373// I hate stealing, really... Lets call it a tribute.
374int ebtables_insmod(const char *modname, const char *modprobe)
375{
376 char *buf = NULL;
377 char *argv[3];
378
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000379 // If they don't explicitly set it, read out of kernel
Bart De Schuymerc8531032002-06-14 21:55:29 +0000380 if (!modprobe) {
381 buf = get_modprobe();
382 if (!buf)
383 return -1;
384 modprobe = buf;
385 }
386
387 switch (fork()) {
388 case 0:
389 argv[0] = (char *)modprobe;
390 argv[1] = (char *)modname;
391 argv[2] = NULL;
392 execv(argv[0], argv);
393
394 /* not usually reached */
395 exit(0);
396 case -1:
397 return -1;
398
399 default: /* parent */
400 wait(NULL);
401 }
402
403 free(buf);
404 return 0;
405}
406
407
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000408// used to parse /etc/ethertypes
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000409int disregard_whitespace(char *buffer, FILE *ifp)
410{
411 int hlp;
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000412
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000413 buffer[0] = '\t';
414 while (buffer[0] == '\t' || buffer[0] == '\n' || buffer[0] == ' ') {
415 hlp = fscanf(ifp, "%c", buffer);
416 if (hlp == EOF || hlp == 0) return -1;
417 }
418 return 0;
419}
420
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000421// used to parse /etc/ethertypes
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000422int disregard_tabspace(char *buffer, FILE *ifp)
423{
424 int hlp;
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000425
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000426 buffer[0] = '\t';
427 while (buffer[0] == '\t' || buffer[0] == ' ') {
428 hlp = fscanf(ifp, "%c", buffer);
429 if (hlp == EOF || hlp == 0) return -1;
430 }
431 return 0;
432}
433
Bart De Schuymerbbca3202002-06-05 18:55:44 +0000434// helper function: processes a line of data from the file /etc/ethertypes
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000435int get_a_line(char *buffer, char *value, FILE *ifp)
436{
437 int i, hlp;
438 char anotherhlp;
439
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000440 // discard comment lines and whitespace
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000441 while (1) {
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000442 if (disregard_whitespace(buffer, ifp))
443 return -1;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000444 if (buffer[0] == '#')
445 while (1) {
446 hlp = fscanf(ifp, "%c", &anotherhlp);
447 if (!hlp || hlp == EOF)
448 return -1;
449 if (anotherhlp == '\n')
450 break;
451 }
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000452 else
453 break;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000454 }
455
456 // buffer[0] already contains the first letter
457 for (i = 1; i < 21; i++) {
458 hlp = fscanf(ifp, "%c", buffer + i);
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000459 if (hlp == EOF || hlp == 0)
460 return -1;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000461 if (buffer[i] == '\t' || buffer[i] == ' ')
462 break;
463 }
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000464 if (i == 21)
465 return -1;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000466 buffer[i] = '\0';
467 if (disregard_tabspace(value, ifp))
468 return -1;
469 // maybe I should allow 0x0800 instead of 0800, but I'm feeling lazy
470 // buffer[0] already contains the first letter
471 for (i = 1; i < 5; i++) {
472 hlp = fscanf(ifp, "%c", value+i);
473 if (value[i] == '\n' || value[i] == '\t' ||
474 value[i] == ' ' || hlp == EOF)
475 break;
476 }
477 if (i == 5) return -1;
Bart De Schuymerbbca3202002-06-05 18:55:44 +0000478 // discard comments at the end of a line
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000479 if (value[i] == '\t' || value[i] == ' ')
480 while (1) {
481 hlp = fscanf(ifp, "%c", &anotherhlp);
482 if (!hlp || hlp == EOF || anotherhlp == '\n')
483 break;
484 }
485 value[i] = '\0';
486 return 0;
487}
488
Bart De Schuymerb909f9b2002-06-26 18:35:31 +0000489// translate a hexadecimal number to a protocol name, parsing /etc/ethertypes
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000490// returns 0 on success
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000491int number_to_name(unsigned short proto, char *name)
492{
493 FILE *ifp;
494 char buffer[21], value[5], *bfr;
495 unsigned short i;
496
497 if ( !(ifp = fopen(PROTOCOLFILE, "r")) )
498 return -1;
499 while (1) {
500 if (get_a_line(buffer, value, ifp)) {
501 fclose(ifp);
502 return -1;
503 }
504 i = (unsigned short) strtol(value, &bfr, 16);
505 if (*bfr != '\0' || i != proto)
506 continue;
507 strcpy(name, buffer);
508 fclose(ifp);
509 return 0;
510 }
511}
512
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000513// we use replace.flags, so we can't use the following values:
514// 0x01 == OPT_COMMAND, 0x02 == OPT_TABLE, 0x100 == OPT_ZERO
515#define LIST_N 0x04
516#define LIST_C 0x08
517#define LIST_X 0x10
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000518// helper function for list_rules()
Bart De Schuymer60332e02002-06-23 08:01:47 +0000519static void list_em(struct ebt_u_entries *entries)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000520{
521 int i, j, space = 0, digits;
522 struct ebt_u_entry *hlp;
523 struct ebt_u_match_list *m_l;
524 struct ebt_u_watcher_list *w_l;
525 struct ebt_u_match *m;
526 struct ebt_u_watcher *w;
527 struct ebt_u_target *t;
528 char name[21];
529
Bart De Schuymer60332e02002-06-23 08:01:47 +0000530 hlp = entries->entries;
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000531 if (replace.flags & LIST_X && entries->policy != EBT_ACCEPT) {
532 printf("ebtables -t %s -P %s %s\n", replace.name,
533 entries->name, standard_targets[-entries->policy - 1]);
534 } else if (!(replace.flags & LIST_X)) {
535 printf("\nBridge chain: %s\nPolicy: %s\n", entries->name,
536 standard_targets[-entries->policy - 1]);
537 printf("nr. of entries: %d \n", entries->nentries);
538 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000539
Bart De Schuymer60332e02002-06-23 08:01:47 +0000540 i = entries->nentries;
Bart De Schuymerf8f8f292002-06-25 15:43:57 +0000541 while (i > 9) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000542 space++;
543 i /= 10;
544 }
545
Bart De Schuymer60332e02002-06-23 08:01:47 +0000546 for (i = 0; i < entries->nentries; i++) {
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000547 if (replace.flags & LIST_N) {
548 digits = 0;
549 // A little work to get nice rule numbers.
550 j = i + 1;
551 while (j > 9) {
552 digits++;
553 j /= 10;
554 }
555 for (j = 0; j < space - digits; j++)
556 printf(" ");
557 printf("%d. ", i + 1);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000558 }
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000559 if (replace.flags & LIST_X)
560 printf("ebtables -t %s -A %s ",
561 replace.name, entries->name);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000562
563 // Don't print anything about the protocol if no protocol was
564 // specified, obviously this means any protocol will do.
565 if (!(hlp->bitmask & EBT_NOPROTO)) {
Bart De Schuymer60332e02002-06-23 08:01:47 +0000566 printf("-p ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000567 if (hlp->invflags & EBT_IPROTO)
568 printf("! ");
569 if (hlp->bitmask & EBT_802_3)
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000570 printf("Length ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000571 else {
572 if (number_to_name(ntohs(hlp->ethproto), name))
Bart De Schuymer60332e02002-06-23 08:01:47 +0000573 printf("0x%x ", ntohs(hlp->ethproto));
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000574 else
Bart De Schuymer60332e02002-06-23 08:01:47 +0000575 printf("%s ", name);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000576 }
577 }
578 if (hlp->bitmask & EBT_SOURCEMAC) {
579 char hlpmsk[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
580
Bart De Schuymer60332e02002-06-23 08:01:47 +0000581 printf("-s ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000582 if (hlp->invflags & EBT_ISOURCE)
583 printf("! ");
584 if (!memcmp(hlp->sourcemac, mac_type_unicast, 6) &&
585 !memcmp(hlp->sourcemsk, msk_type_unicast, 6)) {
586 printf("Unicast");
587 goto endsrc;
588 }
589 if (!memcmp(hlp->sourcemac, mac_type_multicast, 6) &&
590 !memcmp(hlp->sourcemsk, msk_type_multicast, 6)) {
591 printf("Multicast");
592 goto endsrc;
593 }
594 if (!memcmp(hlp->sourcemac, mac_type_broadcast, 6) &&
595 !memcmp(hlp->sourcemsk, msk_type_broadcast, 6)) {
596 printf("Broadcast");
597 goto endsrc;
598 }
Bart De Schuymer41830412002-06-05 19:41:28 +0000599 printf("%s", ether_ntoa((struct ether_addr *)
600 hlp->sourcemac));
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000601 if (memcmp(hlp->sourcemsk, hlpmsk, 6)) {
602 printf("/");
Bart De Schuymer41830412002-06-05 19:41:28 +0000603 printf("%s", ether_ntoa((struct ether_addr *)
604 hlp->sourcemsk));
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000605 }
606endsrc:
Bart De Schuymer60332e02002-06-23 08:01:47 +0000607 printf(" ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000608 }
609 if (hlp->bitmask & EBT_DESTMAC) {
610 char hlpmsk[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
611
Bart De Schuymer60332e02002-06-23 08:01:47 +0000612 printf("-d ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000613 if (hlp->invflags & EBT_IDEST)
614 printf("! ");
615 if (!memcmp(hlp->destmac, mac_type_unicast, 6) &&
616 !memcmp(hlp->destmsk, msk_type_unicast, 6)) {
617 printf("Unicast");
618 goto enddst;
619 }
620 if (!memcmp(hlp->destmac, mac_type_multicast, 6) &&
621 !memcmp(hlp->destmsk, msk_type_multicast, 6)) {
622 printf("Multicast");
623 goto enddst;
624 }
625 if (!memcmp(hlp->destmac, mac_type_broadcast, 6) &&
626 !memcmp(hlp->destmsk, msk_type_broadcast, 6)) {
627 printf("Broadcast");
628 goto enddst;
629 }
Bart De Schuymer41830412002-06-05 19:41:28 +0000630 printf("%s", ether_ntoa((struct ether_addr *)
631 hlp->destmac));
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000632 if (memcmp(hlp->destmsk, hlpmsk, 6)) {
633 printf("/");
Bart De Schuymer41830412002-06-05 19:41:28 +0000634 printf("%s", ether_ntoa((struct ether_addr *)
635 hlp->destmsk));
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000636 }
637enddst:
Bart De Schuymer60332e02002-06-23 08:01:47 +0000638 printf(" ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000639 }
640 if (hlp->in[0] != '\0') {
Bart De Schuymer60332e02002-06-23 08:01:47 +0000641 printf("-i ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000642 if (hlp->invflags & EBT_IIN)
643 printf("! ");
Bart De Schuymer60332e02002-06-23 08:01:47 +0000644 printf("%s ", hlp->in);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000645 }
646 if (hlp->logical_in[0] != '\0') {
Bart De Schuymer60332e02002-06-23 08:01:47 +0000647 printf("--logical-in ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000648 if (hlp->invflags & EBT_ILOGICALIN)
649 printf("! ");
Bart De Schuymer60332e02002-06-23 08:01:47 +0000650 printf("%s ", hlp->logical_in);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000651 }
652 if (hlp->logical_out[0] != '\0') {
Bart De Schuymer60332e02002-06-23 08:01:47 +0000653 printf("--logical-out ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000654 if (hlp->invflags & EBT_ILOGICALOUT)
655 printf("! ");
Bart De Schuymerb3d8f262002-07-07 14:26:15 +0000656 printf("%s ", hlp->logical_out);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000657 }
658 if (hlp->out[0] != '\0') {
Bart De Schuymer60332e02002-06-23 08:01:47 +0000659 printf("-o ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000660 if (hlp->invflags & EBT_IOUT)
661 printf("! ");
Bart De Schuymerb3d8f262002-07-07 14:26:15 +0000662 printf("%s ", hlp->out);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000663 }
664
665 m_l = hlp->m_list;
666 while (m_l) {
667 m = find_match(m_l->m->u.name);
668 if (!m)
669 print_bug("Match not found");
670 m->print(hlp, m_l->m);
671 m_l = m_l->next;
672 }
673 w_l = hlp->w_list;
674 while (w_l) {
675 w = find_watcher(w_l->w->u.name);
676 if (!w)
677 print_bug("Watcher not found");
678 w->print(hlp, w_l->w);
679 w_l = w_l->next;
680 }
681
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000682 printf("-j ");
683 if (strcmp(hlp->t->u.name, EBT_STANDARD_TARGET))
684 printf("%s ", hlp->t->u.name);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000685 t = find_target(hlp->t->u.name);
686 if (!t)
687 print_bug("Target not found");
688 t->print(hlp, hlp->t);
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000689 if (replace.flags & LIST_C)
690 printf(", count = %llu",
691 replace.counters[entries->counter_offset + i].pcnt);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000692 printf("\n");
693 hlp = hlp->next;
694 }
695}
696
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000697struct ebt_u_entries *nr_to_chain(int nr)
Bart De Schuymer60332e02002-06-23 08:01:47 +0000698{
699 if (nr == -1)
700 return NULL;
701 if (nr < NF_BR_NUMHOOKS)
702 return replace.hook_entry[nr];
703 else {
704 int i;
705 struct ebt_u_chain_list *cl = replace.udc;
706
707 i = nr - NF_BR_NUMHOOKS;
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000708 while (i > 0 && cl) {
Bart De Schuymer60332e02002-06-23 08:01:47 +0000709 cl = cl->next;
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000710 i--;
711 }
Bart De Schuymer60332e02002-06-23 08:01:47 +0000712 if (cl)
713 return cl->udc;
714 else
715 return NULL;
716 }
717}
718
719static struct ebt_u_entries *to_chain()
720{
721 return nr_to_chain(replace.selected_hook);
722}
723
724struct ebt_u_stack
725{
726 int chain_nr;
727 int n;
728 struct ebt_u_entry *e;
729 struct ebt_u_entries *entries;
730};
731
732void check_for_loops()
733{
734 int chain_nr , i, j , k, sp = 0, verdict;
735 struct ebt_u_entries *entries, *entries2;
736 struct ebt_u_stack *stack = NULL;
737 struct ebt_u_entry *e;
738
739 i = -1;
740 // initialize hook_mask to 0
741 while (1) {
742 i++;
743 if (i < NF_BR_NUMHOOKS && !(replace.valid_hooks & (1 << i)))
744 continue;
745 entries = nr_to_chain(i);
746 if (!entries)
747 break;
748 entries->hook_mask = 0;
749 }
750 if (i > NF_BR_NUMHOOKS) {
751 stack = (struct ebt_u_stack *)malloc((i - NF_BR_NUMHOOKS) *
752 sizeof(struct ebt_u_stack));
753 if (!stack)
754 print_memory();
755 }
756
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000757 // check for loops, starting from every base chain
Bart De Schuymer60332e02002-06-23 08:01:47 +0000758 for (i = 0; i < NF_BR_NUMHOOKS; i++) {
759 if (!(replace.valid_hooks & (1 << i)))
760 continue;
761 entries = nr_to_chain(i);
762 entries->hook_mask = (1 << i);
763 chain_nr = i;
764
765 e = entries->entries;
766 for (j = 0; j < entries->nentries; j++) {
767 if (strcmp(e->t->u.name, EBT_STANDARD_TARGET))
768 goto letscontinue;
769 verdict = ((struct ebt_standard_target *)(e->t))->verdict;
770 if (verdict < 0)
771 goto letscontinue;
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000772 entries2 = nr_to_chain(verdict + NF_BR_NUMHOOKS);
Bart De Schuymer60332e02002-06-23 08:01:47 +0000773 entries2->hook_mask |= entries->hook_mask;
774 // now see if we've been here before
775 for (k = 0; k < sp; k++)
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000776 if (stack[k].chain_nr == verdict + NF_BR_NUMHOOKS)
Bart De Schuymer1a0a9c32002-06-24 21:10:16 +0000777 print_error("Loop from chain %s to chain %s",
778 nr_to_chain(chain_nr)->name, nr_to_chain(stack[k].chain_nr)->name);
Bart De Schuymer60332e02002-06-23 08:01:47 +0000779 // jump to the chain, make sure we know how to get back
780 stack[sp].chain_nr = chain_nr;
781 stack[sp].n = j;
782 stack[sp].entries = entries;
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000783 stack[sp].e = e;
784 sp++;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000785 j = -1;
786 e = entries2->entries;
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000787 chain_nr = verdict + NF_BR_NUMHOOKS;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000788 entries = entries2;
789 continue;
790letscontinue:
791 e = e->next;
792 }
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000793 // we are at the end of a standard chain
Bart De Schuymer60332e02002-06-23 08:01:47 +0000794 if (sp == 0)
795 continue;
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000796 // go back to the chain one level higher
Bart De Schuymer60332e02002-06-23 08:01:47 +0000797 sp--;
798 j = stack[sp].n;
799 chain_nr = stack[sp].chain_nr;
800 e = stack[sp].e;
801 entries = stack[sp].entries;
802 goto letscontinue;
803 }
804 free(stack);
805 return;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000806}
807
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000808// parse the chain name and return the corresponding nr
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000809// returns -1 on failure
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000810int get_hooknr(char* arg)
811{
812 int i;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000813 struct ebt_u_chain_list *cl = replace.udc;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000814
815 // database is special case (not really a chain)
816 if (!strcmp(arg, DATABASEHOOKNAME))
817 return DATABASEHOOKNR;
818
Bart De Schuymer60332e02002-06-23 08:01:47 +0000819 for (i = 0; i < NF_BR_NUMHOOKS; i++) {
820 if (!(replace.valid_hooks & (1 << i)))
821 continue;
822 if (!strcmp(arg, replace.hook_entry[i]->name))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000823 return i;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000824 }
825 while(cl) {
826 if (!strcmp(arg, cl->udc->name))
827 return i;
828 i++;
829 cl = cl->next;
830 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000831 return -1;
832}
833
834// yup, print out help
835void print_help()
836{
837 struct ebt_u_match_list *m_l;
838 struct ebt_u_watcher_list *w_l;
839
840 printf(
841"%s v%s\n"
842"Usage:\n"
843"ebtables -[ADI] chain rule-specification [options]\n"
844"ebtables -P chain target\n"
845"ebtables -[LFZ] [chain]\n"
846"ebtables -[b] [y,n]\n"
847"Commands:\n"
848"--append -A chain : Append to chain\n"
849"--delete -D chain : Delete matching rule from chain\n"
850"--delete -D chain rulenum : Delete rule at position rulenum from chain\n"
851"--insert -I chain rulenum : insert rule at position rulenum in chain\n"
852"--list -L [chain] : List the rules in a chain or in all chains\n"
853"--list -L "DATABASEHOOKNAME" : List the database (if present)\n"
854"--flush -F [chain] : Delete all rules in chain or in all chains\n"
855"--zero -Z [chain] : Put counters on zero in chain or in all chains\n"
856"--policy -P chain target : Change policy on chain to target\n"
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000857"--new-chain -N chain : Create a user defined chain\n"
858"--rename-chain -E old new : Rename a chain\n"
859"--delete-chain -X chain : Delete a user defined chain\n"
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000860"Options:\n"
861"--proto -p [!] proto : protocol hexadecimal, by name or LENGTH\n"
862"--src -s [!] address[/mask]: source mac address\n"
863"--dst -d [!] address[/mask]: destination mac address\n"
864"--in-if -i [!] name : network input interface name\n"
865"--out-if -o [!] name : network output interface name\n"
866"--logical-in [!] name : logical bridge input interface name\n"
867"--logical-out [!] name : logical bridge output interface name\n"
Bart De Schuymerc8531032002-06-14 21:55:29 +0000868"--modprobe -M : try to insert modules using this command\n"
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000869"--version -V : print package version\n"
870"\n" ,
871 prog_name,
872 prog_version);
873
874 m_l = new_entry->m_list;
875 while (m_l) {
876 ((struct ebt_u_match *)m_l->m)->help();
877 printf("\n");
878 m_l = m_l->next;
879 }
880 w_l = new_entry->w_list;
881 while (w_l) {
882 ((struct ebt_u_watcher *)w_l->w)->help();
883 printf("\n");
884 w_l = w_l->next;
885 }
886 ((struct ebt_u_target *)new_entry->t)->help();
887 printf("\n");
888 if (table->help)
889 table->help(hooknames);
890 exit(0);
891}
892
893// execute command L
894static void list_rules()
895{
896 int i;
897
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000898 if (!(replace.flags & LIST_X))
899 printf("Bridge table: %s\n", table->name);
Bart De Schuymer60332e02002-06-23 08:01:47 +0000900 if (replace.selected_hook != -1) {
901 list_em(to_chain());
902 } else {
903 struct ebt_u_chain_list *cl = replace.udc;
904
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000905 // create new chains and rename standard chains when necessary
906 if (replace.flags & LIST_X) {
907 while (cl) {
908 printf("ebtables -t %s -N %s\n", replace.name,
909 cl->udc->name);
910 cl = cl->next;
911 }
912 cl = replace.udc;
913 for (i = 0; i < NF_BR_NUMHOOKS; i++)
914 if (replace.valid_hooks & (1 << i) &&
915 strcmp(replace.hook_entry[i]->name, hooknames[i]))
916 printf("ebtables -t %s -E %s %s\n",
917 replace.name, hooknames[i],
918 replace.hook_entry[i]->name);
919 }
Bart De Schuymer60332e02002-06-23 08:01:47 +0000920 i = 0;
921 while (1) {
922 if (i < NF_BR_NUMHOOKS) {
923 if (replace.valid_hooks & (1 << i))
924 list_em(replace.hook_entry[i]);
925 i++;
926 continue;
927 } else {
928 if (!cl)
929 break;
930 list_em(cl->udc);
931 cl = cl->next;
932 }
933 }
934 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000935}
936
937// execute command P
938static void change_policy(int policy)
939{
940 int i;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000941 struct ebt_u_entries *entries = to_chain();
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000942
943 // don't do anything if the policy is the same
Bart De Schuymer60332e02002-06-23 08:01:47 +0000944 if (entries->policy != policy) {
945 entries->policy = policy;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000946 replace.num_counters = replace.nentries;
947 if (replace.nentries) {
948 // '+ 1' for the CNT_END
949 if (!(counterchanges = (unsigned short *) malloc(
950 (replace.nentries + 1) * sizeof(unsigned short))))
951 print_memory();
952 // done nothing special to the rules
953 for (i = 0; i < replace.nentries; i++)
954 counterchanges[i] = CNT_NORM;
955 counterchanges[replace.nentries] = CNT_END;
956 }
957 else
958 counterchanges = NULL;
959 }
960 else
961 exit(0);
962}
963
964// flush one chain or the complete table
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000965// -1 == nothing to do
966// 0 == give back to kernel
967static int flush_chains()
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000968{
Bart De Schuymer60332e02002-06-23 08:01:47 +0000969 int i, j, oldnentries, numdel;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000970 unsigned short *cnt;
971 struct ebt_u_entry *u_e, *tmp;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000972 struct ebt_u_entries *entries = to_chain();
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000973
974 // flush whole table
Bart De Schuymer60332e02002-06-23 08:01:47 +0000975 if (!entries) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000976 if (replace.nentries == 0)
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000977 return -1;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000978 replace.nentries = 0;
979 // no need for the kernel to give us counters back
980 replace.num_counters = 0;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000981
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000982 // free everything and zero (n)entries
Bart De Schuymer60332e02002-06-23 08:01:47 +0000983 i = -1;
984 while (1) {
985 i++;
986 entries = nr_to_chain(i);
987 if (!entries) {
988 if (i < NF_BR_NUMHOOKS)
989 continue;
990 else
991 break;
992 }
993 entries->nentries = 0;
994 entries->counter_offset = 0;
995 u_e = entries->entries;
996 entries->entries = NULL;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000997 while (u_e) {
998 free_u_entry(u_e);
999 tmp = u_e->next;
1000 free(u_e);
1001 u_e = tmp;
1002 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001003 }
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001004 return 0;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001005 }
1006
Bart De Schuymer60332e02002-06-23 08:01:47 +00001007 if (entries->nentries == 0)
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001008 return -1;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001009 oldnentries = replace.nentries;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001010 replace.nentries -= entries->nentries;
1011 numdel = entries->nentries;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001012
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001013 if (replace.nentries) {
1014 // +1 for CNT_END
1015 if ( !(counterchanges = (unsigned short *)
1016 malloc((oldnentries + 1) * sizeof(unsigned short))) )
1017 print_memory();
Bart De Schuymer60332e02002-06-23 08:01:47 +00001018 }
1019 // delete the counters belonging to the specified chain,
1020 // update counter_offset
1021 i = -1;
Bart De Schuymerf8f8f292002-06-25 15:43:57 +00001022 cnt = counterchanges;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001023 while (1) {
1024 i++;
1025 entries = nr_to_chain(i);
1026 if (!entries) {
1027 if (i < NF_BR_NUMHOOKS)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001028 continue;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001029 else
1030 break;
1031 }
1032 if (i > replace.selected_hook)
1033 entries->counter_offset -= numdel;
1034 if (replace.nentries) {
1035 for (j = 0; j < entries->nentries; j++) {
1036 if (i == replace.selected_hook)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001037 *cnt = CNT_DEL;
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001038 else
1039 *cnt = CNT_NORM;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001040 cnt++;
1041 }
1042 }
Bart De Schuymer60332e02002-06-23 08:01:47 +00001043 }
1044
1045 if (replace.nentries) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001046 *cnt = CNT_END;
1047 replace.num_counters = oldnentries;
1048 }
1049 else
1050 replace.num_counters = 0;
1051
Bart De Schuymer60332e02002-06-23 08:01:47 +00001052 entries = to_chain();
1053 entries->nentries = 0;
1054 u_e = entries->entries;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001055 while (u_e) {
1056 free_u_entry(u_e);
1057 tmp = u_e->next;
1058 free(u_e);
1059 u_e = tmp;
1060 }
Bart De Schuymer60332e02002-06-23 08:01:47 +00001061 entries->entries = NULL;
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001062 return 0;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001063}
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001064
1065// -1 == no match
1066static int check_rule_exists(int rule_nr)
1067{
1068 struct ebt_u_entry *u_e;
1069 struct ebt_u_match_list *m_l, *m_l2;
1070 struct ebt_u_match *m;
1071 struct ebt_u_watcher_list *w_l, *w_l2;
1072 struct ebt_u_watcher *w;
1073 struct ebt_u_target *t = (struct ebt_u_target *)new_entry->t;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001074 struct ebt_u_entries *entries = to_chain();
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001075 int i, j, k;
1076
1077 // handle '-D chain rulenr' command
1078 if (rule_nr != -1) {
Bart De Schuymer60332e02002-06-23 08:01:47 +00001079 if (rule_nr > entries->nentries)
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001080 return -1;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001081 // user starts counting from 1
1082 return rule_nr - 1;
1083 }
Bart De Schuymer60332e02002-06-23 08:01:47 +00001084 u_e = entries->entries;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001085 // check for an existing rule (if there are duplicate rules,
1086 // take the first occurance)
Bart De Schuymer60332e02002-06-23 08:01:47 +00001087 for (i = 0; i < entries->nentries; i++, u_e = u_e->next) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001088 if (!u_e)
1089 print_bug("Hmm, trouble");
1090 if ( u_e->ethproto == new_entry->ethproto
1091 && !strcmp(u_e->in, new_entry->in)
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001092 && !strcmp(u_e->out, new_entry->out)) {
Bart De Schuymer60332e02002-06-23 08:01:47 +00001093 if (strcmp(u_e->logical_in, new_entry->logical_in) ||
1094 strcmp(u_e->logical_out, new_entry->logical_out))
1095 continue;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001096 if (new_entry->bitmask & EBT_SOURCEMAC &&
Bart De Schuymer60332e02002-06-23 08:01:47 +00001097 memcmp(u_e->sourcemac, new_entry->sourcemac, ETH_ALEN))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001098 continue;
1099 if (new_entry->bitmask & EBT_DESTMAC &&
Bart De Schuymer60332e02002-06-23 08:01:47 +00001100 memcmp(u_e->destmac, new_entry->destmac, ETH_ALEN))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001101 continue;
1102 if (new_entry->bitmask != u_e->bitmask ||
1103 new_entry->invflags != u_e->invflags)
1104 continue;
1105 // compare all matches
1106 m_l = new_entry->m_list;
1107 j = 0;
1108 while (m_l) {
1109 m = (struct ebt_u_match *)(m_l->m);
1110 m_l2 = u_e->m_list;
1111 while (m_l2 &&
1112 strcmp(m_l2->m->u.name, m->m->u.name))
1113 m_l2 = m_l2->next;
1114 if (!m_l2 || !m->compare(m->m, m_l2->m))
1115 goto letscontinue;
1116 j++;
1117 m_l = m_l->next;
1118 }
1119 // now be sure they have the same nr of matches
1120 k = 0;
1121 m_l = u_e->m_list;
1122 while (m_l) {
1123 k++;
1124 m_l = m_l->next;
1125 }
1126 if (j != k)
1127 continue;
1128
1129 // compare all watchers
1130 w_l = new_entry->w_list;
1131 j = 0;
1132 while (w_l) {
1133 w = (struct ebt_u_watcher *)(w_l->w);
1134 w_l2 = u_e->w_list;
1135 while (w_l2 &&
1136 strcmp(w_l2->w->u.name, w->w->u.name))
1137 w_l2 = w_l2->next;
1138 if (!w_l2 || !w->compare(w->w, w_l2->w))
1139 goto letscontinue;
1140 j++;
1141 w_l = w_l->next;
1142 }
1143 k = 0;
1144 w_l = u_e->w_list;
1145 while (w_l) {
1146 k++;
1147 w_l = w_l->next;
1148 }
1149 if (j != k)
1150 continue;
1151 if (strcmp(t->t->u.name, u_e->t->u.name))
1152 continue;
1153 if (!t->compare(t->t, u_e->t))
1154 continue;
1155 return i;
1156 }
1157letscontinue:
1158 }
1159 return -1;
1160}
1161
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001162// execute command A or I
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001163static void add_rule(int rule_nr)
1164{
1165 int i, j;
1166 struct ebt_u_entry *u_e, *u_e2;
1167 unsigned short *cnt;
1168 struct ebt_u_match_list *m_l;
1169 struct ebt_u_watcher_list *w_l;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001170 struct ebt_u_entries *entries = to_chain(), *entries2;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001171
1172 if (rule_nr != -1) { // command -I
Bart De Schuymer60332e02002-06-23 08:01:47 +00001173 if (--rule_nr > entries->nentries)
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001174 print_error("rule nr too high: %d > %d", rule_nr + 1,
1175 entries->nentries + 1);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001176 } else
Bart De Schuymer60332e02002-06-23 08:01:47 +00001177 rule_nr = entries->nentries;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001178 // we're adding one rule
1179 replace.num_counters = replace.nentries;
1180 replace.nentries++;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001181 entries->nentries++;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001182
1183 // handle counter stuff
1184 // +1 for CNT_END
1185 if ( !(counterchanges = (unsigned short *)
1186 malloc((replace.nentries + 1) * sizeof(unsigned short))) )
1187 print_memory();
1188 cnt = counterchanges;
1189 for (i = 0; i < replace.selected_hook; i++) {
Bart De Schuymer60332e02002-06-23 08:01:47 +00001190 if (i < NF_BR_NUMHOOKS && !(replace.valid_hooks & (1 << i)))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001191 continue;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001192 entries2 = nr_to_chain(i);
1193 for (j = 0; j < entries2->nentries; j++) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001194 *cnt = CNT_NORM;
1195 cnt++;
1196 }
1197 }
1198 for (i = 0; i < rule_nr; i++) {
1199 *cnt = CNT_NORM;
1200 cnt++;
1201 }
1202 *cnt = CNT_ADD;
1203 cnt++;
1204 while (cnt != counterchanges + replace.nentries) {
1205 *cnt = CNT_NORM;
1206 cnt++;
1207 }
1208 *cnt = CNT_END;
1209
1210 // go to the right position in the chain
1211 u_e2 = NULL;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001212 u_e = entries->entries;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001213 for (i = 0; i < rule_nr; i++) {
1214 u_e2 = u_e;
1215 u_e = u_e->next;
1216 }
1217 // insert the rule
1218 if (u_e2)
1219 u_e2->next = new_entry;
1220 else
Bart De Schuymer60332e02002-06-23 08:01:47 +00001221 entries->entries = new_entry;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001222 new_entry->next = u_e;
1223
1224 // put the ebt_[match, watcher, target] pointers in place
1225 m_l = new_entry->m_list;
1226 while (m_l) {
1227 m_l->m = ((struct ebt_u_match *)m_l->m)->m;
1228 m_l = m_l->next;
1229 }
1230 w_l = new_entry->w_list;
1231 while (w_l) {
1232 w_l->w = ((struct ebt_u_watcher *)w_l->w)->w;
1233 w_l = w_l->next;
1234 }
1235 new_entry->t = ((struct ebt_u_target *)new_entry->t)->t;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001236
1237 // update the counter_offset of chains behind this one
1238 i = replace.selected_hook;
1239 while (1) {
1240 i++;
1241 entries = nr_to_chain(i);
1242 if (!entries) {
1243 if (i < NF_BR_NUMHOOKS)
1244 continue;
1245 else
1246 break;
1247 } else
1248 entries->counter_offset++;
1249 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001250}
1251
1252// execute command D
1253static void delete_rule(int rule_nr)
1254{
1255 int i, j, lentmp = 0;
1256 unsigned short *cnt;
1257 struct ebt_u_entry *u_e, *u_e2;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001258 struct ebt_u_entries *entries = to_chain(), *entries2;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001259
1260 if ( (i = check_rule_exists(rule_nr)) == -1 )
Bart De Schuymer60332e02002-06-23 08:01:47 +00001261 print_error("Sorry, rule does not exist");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001262
1263 // we're deleting a rule
1264 replace.num_counters = replace.nentries;
1265 replace.nentries--;
1266
1267 if (replace.nentries) {
1268 for (j = 0; j < replace.selected_hook; j++) {
Bart De Schuymer60332e02002-06-23 08:01:47 +00001269 if (j < NF_BR_NUMHOOKS &&
1270 !(replace.valid_hooks & (1 << j)))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001271 continue;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001272 entries2 = nr_to_chain(j);
1273 lentmp += entries2->nentries;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001274 }
1275 lentmp += i;
1276 // +1 for CNT_END
1277 if ( !(counterchanges = (unsigned short *)malloc(
1278 (replace.num_counters + 1) * sizeof(unsigned short))) )
1279 print_memory();
1280 cnt = counterchanges;
1281 for (j = 0; j < lentmp; j++) {
1282 *cnt = CNT_NORM;
1283 cnt++;
1284 }
1285 *cnt = CNT_DEL;
1286 cnt++;
1287 for (j = 0; j < replace.num_counters - lentmp; j++) {
1288 *cnt = CNT_NORM;
1289 cnt++;
1290 }
1291 *cnt = CNT_END;
1292 }
1293 else
1294 replace.num_counters = 0;
1295
1296 // go to the right position in the chain
1297 u_e2 = NULL;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001298 u_e = entries->entries;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001299 for (j = 0; j < i; j++) {
1300 u_e2 = u_e;
1301 u_e = u_e->next;
1302 }
1303
1304 // remove from the chain
1305 if (u_e2)
1306 u_e2->next = u_e->next;
1307 else
Bart De Schuymer60332e02002-06-23 08:01:47 +00001308 entries->entries = u_e->next;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001309
Bart De Schuymer60332e02002-06-23 08:01:47 +00001310 entries->nentries--;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001311 // free everything
1312 free_u_entry(u_e);
1313 free(u_e);
Bart De Schuymer60332e02002-06-23 08:01:47 +00001314 // update the counter_offset of chains behind this one
1315 i = replace.selected_hook;
1316 while (1) {
1317 i++;
1318 entries = nr_to_chain(i);
1319 if (!entries) {
1320 if (i < NF_BR_NUMHOOKS)
1321 continue;
1322 else
1323 break;
1324 } else
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001325 entries->counter_offset--;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001326 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001327}
1328
1329// execute command Z
1330void zero_counters(int zerochain)
1331{
1332
1333 if (zerochain == -1) {
1334 // tell main() we don't update the counters
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001335 // this results in tricking the kernel to zero its counters,
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001336 // naively expecting userspace to update its counters. Muahahaha
1337 counterchanges = NULL;
1338 replace.num_counters = 0;
1339 } else {
1340 int i, j;
1341 unsigned short *cnt;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001342 struct ebt_u_entries *entries = nr_to_chain(zerochain), *e2;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001343
Bart De Schuymer60332e02002-06-23 08:01:47 +00001344 if (entries->nentries == 0)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001345 exit(0);
1346 counterchanges = (unsigned short *)
1347 malloc((replace.nentries + 1) * sizeof(unsigned short));
1348 if (!counterchanges)
1349 print_memory();
1350 cnt = counterchanges;
1351 for (i = 0; i < zerochain; i++) {
Bart De Schuymer60332e02002-06-23 08:01:47 +00001352 if (i < NF_BR_NUMHOOKS &&
1353 !(replace.valid_hooks & (1 << i)))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001354 continue;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001355 e2 = nr_to_chain(i);
1356 for (j = 0; j < e2->nentries; j++) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001357 *cnt = CNT_NORM;
1358 cnt++;
1359 }
1360 }
Bart De Schuymer60332e02002-06-23 08:01:47 +00001361 for (i = 0; i < entries->nentries; i++) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001362 *cnt = CNT_ZERO;
1363 cnt++;
1364 }
1365 while (cnt != counterchanges + replace.nentries) {
1366 *cnt = CNT_NORM;
1367 cnt++;
1368 }
1369 *cnt = CNT_END;
1370 }
1371}
1372
1373// list the database (optionally compiled into the kernel)
1374static void list_db()
1375{
1376 struct brdb_dbinfo nr;
1377 struct brdb_dbentry *db;
1378 char name[21];
1379 int i;
1380
1381 get_dbinfo(&nr);
1382
1383 // 0 : database disabled (-db n)
1384 if (!(nr.nentries))
1385 print_error("Database not present"
1386 " (disabled), try ebtables --db y");
1387 nr.nentries--;
1388 if (!nr.nentries) print_error("Database empty");
1389 if ( !(db = (struct brdb_dbentry *)
1390 malloc(nr.nentries * sizeof(struct brdb_dbentry))) )
1391 print_memory();
1392
1393 get_db(nr.nentries, db);
1394 printf("number of entries: %d\n", nr.nentries);
1395 for (i = 0; i < nr.nentries; i++) {
1396 printf(
1397 "%d:\n"
1398 "hook : %s\n"
1399 "in-if : %s\n"
1400 "out-if : %s\n"
1401 "protocol: ", i + 1, hooknames[db->hook], db->in, db->out);
1402 if (db->ethproto == IDENTIFY802_3)
1403 printf("802.2/802.3 STYLE LENGTH FIELD\n");
1404 else {
1405 if (number_to_name(ntohs(db->ethproto), name))
1406 printf("%x\n",ntohs(db->ethproto));
1407 else
1408 printf("%s\n", name);
1409 }
1410 db++;
1411 }
1412 exit(0);
1413}
1414
1415// handle db [dis,en]abling
1416static void allowdb(char yorn)
1417{
1418 __u16 decision;
1419
1420 if (yorn != 'y' && yorn != 'n')
1421 print_error("Option [y] or [n] needed");
1422
1423 if (yorn == 'y')
1424 decision = BRDB_DB;
1425 else
1426 decision = BRDB_NODB;
1427
1428 deliver_allowdb(&decision);
1429
1430 exit(0);
1431}
1432
Bart De Schuymer28bf6f62002-06-26 18:57:24 +00001433// 0 == success
1434// 1 == success, but for the special 'protocol' LENGTH
1435// -1 == failure
1436int name_to_number(char *name, __u16 *proto)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001437{
1438 FILE *ifp;
1439 char buffer[21], value[5], *bfr;
1440 unsigned short i;
1441
1442 if (!strcasecmp("LENGTH", name)) {
Bart De Schuymer28bf6f62002-06-26 18:57:24 +00001443 *proto = 0;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001444 new_entry->bitmask |= EBT_802_3;
1445 return 1;
1446 }
1447 if ( !(ifp = fopen(PROTOCOLFILE, "r")) )
1448 return -1;
1449 while (1) {
1450 if (get_a_line(buffer, value, ifp)) return -1;
1451 if (strcasecmp(buffer, name))
1452 continue;
1453 i = (unsigned short) strtol(value, &bfr, 16);
1454 if (*bfr != '\0')
1455 return -1;
Bart De Schuymer28bf6f62002-06-26 18:57:24 +00001456 *proto = i;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001457 fclose(ifp);
1458 return 0;
1459 }
1460 return -1;
1461}
1462
1463// put the mac address into 6 (ETH_ALEN) bytes
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001464int getmac_and_mask(char *from, char *to, char *mask)
1465{
1466 char *p;
1467 int i;
Bart De Schuymer41830412002-06-05 19:41:28 +00001468 struct ether_addr *addr;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001469
1470 if (strcasecmp(from, "Unicast") == 0) {
1471 memcpy(to, mac_type_unicast, ETH_ALEN);
1472 memcpy(mask, msk_type_unicast, ETH_ALEN);
1473 return 0;
1474 }
1475 if (strcasecmp(from, "Multicast") == 0) {
1476 memcpy(to, mac_type_multicast, ETH_ALEN);
1477 memcpy(mask, msk_type_multicast, ETH_ALEN);
1478 return 0;
1479 }
1480 if (strcasecmp(from, "Broadcast") == 0) {
1481 memcpy(to, mac_type_broadcast, ETH_ALEN);
1482 memcpy(mask, msk_type_broadcast, ETH_ALEN);
1483 return 0;
1484 }
1485 if ( (p = strrchr(from, '/')) != NULL) {
1486 *p = '\0';
Bart De Schuymer41830412002-06-05 19:41:28 +00001487 if (!(addr = ether_aton(p + 1)))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001488 return -1;
Bart De Schuymer41830412002-06-05 19:41:28 +00001489 memcpy(mask, addr, ETH_ALEN);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001490 } else
1491 memset(mask, 0xff, ETH_ALEN);
Bart De Schuymer41830412002-06-05 19:41:28 +00001492 if (!(addr = ether_aton(from)))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001493 return -1;
Bart De Schuymer41830412002-06-05 19:41:28 +00001494 memcpy(to, addr, ETH_ALEN);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001495 for (i = 0; i < ETH_ALEN; i++)
1496 to[i] &= mask[i];
1497 return 0;
1498}
1499
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001500// executes the final_check() function for all extensions used by the rule
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +00001501void do_final_checks(struct ebt_u_entry *e, struct ebt_u_entries *entries)
1502{
1503 struct ebt_u_match_list *m_l;
1504 struct ebt_u_watcher_list *w_l;
1505 struct ebt_u_target *t;
1506 struct ebt_u_match *m;
1507 struct ebt_u_watcher *w;
1508
1509 m_l = e->m_list;
1510 w_l = e->w_list;
1511 while (m_l) {
1512 m = find_match(m_l->m->u.name);
1513 m->final_check(e, m_l->m, replace.name,
1514 entries->hook_mask, 1);
1515 m_l = m_l->next;
1516 }
1517 while (w_l) {
1518 w = find_watcher(w_l->w->u.name);
1519 w->final_check(e, w_l->w, replace.name,
1520 entries->hook_mask, 1);
1521 w_l = w_l->next;
1522 }
1523 t = find_target(e->t->u.name);
1524 t->final_check(e, e->t, replace.name,
1525 entries->hook_mask, 1);
1526}
1527
Bart De Schuymerb909f9b2002-06-26 18:35:31 +00001528// used for the -X command
1529void check_for_references(int chain_nr)
1530{
1531 int i = -1, j;
1532 struct ebt_u_entries *entries;
1533 struct ebt_u_entry *e;
1534
1535 while (1) {
1536 i++;
1537 entries = nr_to_chain(i);
1538 if (!entries) {
1539 if (i < NF_BR_NUMHOOKS)
1540 continue;
1541 else
1542 break;
1543 }
1544 e = entries->entries;
1545 j = 0;
1546 while (e) {
1547 j++;
1548 if (strcmp(e->t->u.name, EBT_STANDARD_TARGET)) {
1549 e = e->next;
1550 continue;
1551 }
1552 if (((struct ebt_standard_target *)e->t)->verdict == chain_nr)
1553 print_error("Can't delete the chain, it's referenced "
1554 "in chain %s, rule %d", entries->name, j);
1555 e = e->next;
1556 }
1557 }
1558}
1559
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001560int check_inverse(const char option[])
1561{
1562 if (strcmp(option, "!") == 0) {
1563 optind++;
1564 return 1;
1565 }
1566 return 0;
1567}
1568
1569void check_option(unsigned int *flags, unsigned int mask)
1570{
1571 if (*flags & mask)
1572 print_error("Multiple use of same option not allowed");
1573 *flags |= mask;
1574}
1575
1576#define OPT_COMMAND 0x01
1577#define OPT_TABLE 0x02
1578#define OPT_IN 0x04
1579#define OPT_OUT 0x08
1580#define OPT_JUMP 0x10
1581#define OPT_PROTOCOL 0x20
1582#define OPT_SOURCE 0x40
1583#define OPT_DEST 0x80
1584#define OPT_ZERO 0x100
1585#define OPT_LOGICALIN 0x200
1586#define OPT_LOGICALOUT 0x400
1587// the main thing
1588int main(int argc, char *argv[])
1589{
1590 char *buffer, allowbc = 'n';
1591 int c, i;
1592 // this special one for the -Z option (we can have -Z <this> -L <that>)
1593 int zerochain = -1;
Bart De Schuymerf8f8f292002-06-25 15:43:57 +00001594 int policy = 0;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001595 int rule_nr = -1;// used for -D chain number
1596 struct ebt_u_target *t;
1597 struct ebt_u_match *m;
1598 struct ebt_u_watcher *w;
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001599 struct ebt_u_match_list *m_l;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001600 struct ebt_u_watcher_list *w_l;
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001601 struct ebt_u_entries *entries;
Bart De Schuymerc8531032002-06-14 21:55:29 +00001602 const char *modprobe = NULL;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001603
1604 // initialize the table name, OPT_ flags, selected hook and command
1605 strcpy(replace.name, "filter");
1606 replace.flags = 0;
1607 replace.selected_hook = -1;
1608 replace.command = 'h';
1609
1610 new_entry = (struct ebt_u_entry *)malloc(sizeof(struct ebt_u_entry));
1611 if (!new_entry)
1612 print_memory();
1613 // put some sane values in our new entry
1614 initialize_entry(new_entry);
1615
Bart De Schuymer60332e02002-06-23 08:01:47 +00001616 // The scenario induced by this loop makes that:
1617 // '-t' and '-M' (if specified) have to come before '-A' and the like
1618
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001619 // getopt saves the day
1620 while ((c = getopt_long(argc, argv,
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001621 "-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 +00001622 switch (c) {
1623
1624 case 'A': // add a rule
1625 case 'D': // delete a rule
1626 case 'P': // define policy
1627 case 'I': // insert a rule
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001628 case 'N': // make a user defined chain
1629 case 'E': // rename chain
1630 case 'X': // delete chain
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001631 replace.command = c;
1632 if (replace.flags & OPT_COMMAND)
1633 print_error("Multiple commands not allowed");
1634 replace.flags |= OPT_COMMAND;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001635 if ( !(table = find_table(replace.name)) )
1636 print_error("Bad table name");
1637 // get the kernel's information
1638 if (get_table(&replace)) {
1639 ebtables_insmod("ebtables", modprobe);
1640 if (get_table(&replace))
1641 print_error("can't initialize ebtables "
1642 "table %s", replace.name);
1643 }
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001644 if (optarg[0] == '-')
1645 print_error("No chain name specified");
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001646 if (c == 'N') {
1647 struct ebt_u_chain_list *cl, **cl2;
1648
1649 if (get_hooknr(optarg) != -1)
1650 print_error("Chain %s already exists",
1651 optarg);
1652 if (find_target(optarg))
1653 print_error("Target with name %s exists"
1654 , optarg);
1655 if (strlen(optarg) >= EBT_CHAIN_MAXNAMELEN)
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001656 print_error("Chain name length can't exceed %d",
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001657 EBT_CHAIN_MAXNAMELEN - 1);
1658 cl = (struct ebt_u_chain_list *)
1659 malloc(sizeof(struct ebt_u_chain_list));
1660 if (!cl)
1661 print_memory();
1662 cl->next = NULL;
1663 cl->udc = (struct ebt_u_entries *)
1664 malloc(sizeof(struct ebt_u_entries));
1665 if (!cl->udc)
1666 print_memory();
1667 cl->udc->nentries = 0;
1668 cl->udc->policy = EBT_ACCEPT;
1669 cl->udc->counter_offset = replace.nentries;
1670 cl->udc->hook_mask = 0;
1671 strcpy(cl->udc->name, optarg);
1672 cl->udc->entries = NULL;
1673 cl->kernel_start = NULL;
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001674 // put the new chain at the end
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001675 cl2 = &replace.udc;
1676 while (*cl2)
1677 cl2 = &((*cl2)->next);
1678 *cl2 = cl;
1679 break;
1680 }
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001681 if ((replace.selected_hook = get_hooknr(optarg)) == -1)
1682 print_error("Chain %s doesn't exist", optarg);
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001683 if (c == 'E') {
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001684 if (optind >= argc || argv[optind][0] == '-')
1685 print_error("No new chain name specified");
1686 if (strlen(argv[optind]) >= EBT_CHAIN_MAXNAMELEN)
1687 print_error("Chain name len can't exceed %d",
1688 EBT_CHAIN_MAXNAMELEN - 1);
1689 if (get_hooknr(argv[optind]) != -1)
1690 print_error("Chain %s already exists",
1691 argv[optind]);
1692 entries = to_chain();
1693 strcpy(entries->name, argv[optind]);
1694 optind++;
1695 break;
1696 }
1697 if (c == 'X') {
1698 struct ebt_u_chain_list *cl, **cl2;
1699
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001700 if (replace.selected_hook < NF_BR_NUMHOOKS)
1701 print_error("You can't remove a standard chain");
Bart De Schuymerb909f9b2002-06-26 18:35:31 +00001702 // if the chain is referenced, don't delete it
1703 check_for_references(replace.selected_hook - NF_BR_NUMHOOKS);
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001704 flush_chains();
1705 entries = to_chain();
1706 if (replace.udc->udc == entries) {
1707 cl = replace.udc;
1708 replace.udc = replace.udc->next;
1709 free(cl->udc);
1710 free(cl);
1711 break;
1712 }
1713 cl2 = &(replace.udc);
1714 while ((*cl2)->next->udc != entries)
1715 cl2 = &((*cl2)->next);
1716 cl = (*cl2)->next;
1717 (*cl2)->next = (*cl2)->next->next;
1718 free(cl->udc);
1719 free(cl);
1720 break;
1721 }
1722
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001723 if (c == 'D' && optind < argc &&
1724 argv[optind][0] != '-') {
1725 rule_nr = strtol(argv[optind], &buffer, 10);
1726 if (*buffer != '\0' || rule_nr < 0)
1727 print_error("Problem with the "
1728 "specified rule number");
1729 optind++;
1730 }
1731 if (c == 'P') {
1732 if (optind >= argc)
1733 print_error("No policy specified");
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001734 policy = 0;
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001735 for (i = 0; i < NUM_STANDARD_TARGETS; i++)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001736 if (!strcmp(argv[optind],
1737 standard_targets[i])) {
Bart De Schuymer60332e02002-06-23 08:01:47 +00001738 policy = -i -1;
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001739 if (policy == EBT_CONTINUE)
1740 policy = 0;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001741 break;
1742 }
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001743 if (policy == 0)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001744 print_error("Wrong policy");
1745 optind++;
1746 }
1747 if (c == 'I') {
1748 if (optind >= argc)
1749 print_error("No rulenr for -I"
1750 " specified");
1751 rule_nr = strtol(argv[optind], &buffer, 10);
1752 if (*buffer != '\0' || rule_nr < 0)
1753 print_error("Problem with the specified"
1754 " rule number");
1755 optind++;
1756 }
1757 break;
1758
1759 case 'L': // list
1760 case 'F': // flush
1761 case 'Z': // zero counters
1762 if (c == 'Z') {
1763 if (replace.flags & OPT_ZERO)
1764 print_error("Multiple commands"
1765 " not allowed");
1766 if ( (replace.flags & OPT_COMMAND &&
1767 replace.command != 'L'))
1768 print_error("command -Z only allowed "
1769 "together with command -L");
1770 replace.flags |= OPT_ZERO;
1771 } else {
1772 replace.command = c;
1773 if (replace.flags & OPT_COMMAND)
1774 print_error("Multiple commands"
1775 " not allowed");
1776 replace.flags |= OPT_COMMAND;
1777 }
Bart De Schuymer60332e02002-06-23 08:01:47 +00001778 if ( !(table = find_table(replace.name)) )
1779 print_error("Bad table name");
1780 // get the kernel's information
1781 if (get_table(&replace)) {
1782 ebtables_insmod("ebtables", modprobe);
1783 if (get_table(&replace))
1784 print_error("can't initialize ebtables "
1785 "table %s", replace.name);
1786 }
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001787 i = -1;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001788 if (optarg) {
1789 if ( (i = get_hooknr(optarg)) == -1 )
1790 print_error("Bad chain");
1791 } else
1792 if (optind < argc && argv[optind][0] != '-') {
1793 if ((i = get_hooknr(argv[optind]))
1794 == -1)
1795 print_error("Bad chain");
1796 optind++;
1797 }
1798 if (i != -1) {
1799 if (c == 'Z')
1800 zerochain = i;
1801 else
1802 replace.selected_hook = i;
1803 }
1804 break;
1805
1806 case 'V': // version
1807 replace.command = 'V';
1808 if (replace.flags & OPT_COMMAND)
1809 print_error("Multiple commands not allowed");
1810 printf("%s, %s\n", prog_name, prog_version);
1811 exit(0);
1812
Bart De Schuymerc8531032002-06-14 21:55:29 +00001813 case 'M': // modprobe
Bart De Schuymer60332e02002-06-23 08:01:47 +00001814 if (replace.command != 'h')
1815 print_error("Please put the -M option earlier");
Bart De Schuymerc8531032002-06-14 21:55:29 +00001816 modprobe = optarg;
1817 break;
1818
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001819 case 'h': // help
1820 if (replace.flags & OPT_COMMAND)
1821 print_error("Multiple commands not allowed");
1822 replace.command = 'h';
1823 // All other arguments should be extension names
1824 while (optind < argc) {
1825 struct ebt_u_match *m;
1826 struct ebt_u_watcher *w;
1827
1828 if ((m = find_match(argv[optind])))
1829 add_match(m);
1830 else if ((w = find_watcher(argv[optind])))
1831 add_watcher(w);
1832 else {
1833 if (!(t = find_target(argv[optind])))
1834 print_error("Extension %s "
1835 "not found", argv[optind]);
1836 if (replace.flags & OPT_JUMP)
1837 print_error("Sorry, you can "
1838 "only see help for one "
1839 "target extension each time");
1840 replace.flags |= OPT_JUMP;
1841 new_entry->t =
1842 (struct ebt_entry_target *)t;
1843 }
1844 optind++;
1845 }
1846 break;
1847
1848 case 't': // table
Bart De Schuymer60332e02002-06-23 08:01:47 +00001849 if (replace.command != 'h')
1850 print_error("Please put the -t option first");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001851 check_option(&replace.flags, OPT_TABLE);
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001852 if (strlen(optarg) > EBT_TABLE_MAXNAMELEN - 1)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001853 print_error("Table name too long");
1854 strcpy(replace.name, optarg);
1855 break;
1856
1857 case 'i': // input interface
1858 case 2 : // logical input interface
1859 case 'o': // output interface
1860 case 3 : // logical output interface
1861 case 'j': // target
1862 case 'p': // net family protocol
1863 case 's': // source mac
1864 case 'd': // destination mac
1865 if ((replace.flags & OPT_COMMAND) == 0)
1866 print_error("No command specified");
1867 if ( replace.command != 'A' &&
1868 replace.command != 'D' && replace.command != 'I')
1869 print_error("Command and option do not match");
1870 if (c == 'i') {
1871 check_option(&replace.flags, OPT_IN);
1872 if (replace.selected_hook > 2 &&
1873 replace.selected_hook < NF_BR_BROUTING)
1874 print_error("Use in-interface only in "
1875 "INPUT, FORWARD, PREROUTING and"
1876 "BROUTING chains");
1877 if (check_inverse(optarg))
1878 new_entry->invflags |= EBT_IIN;
1879
1880 if (optind > argc)
1881 print_error("No in-interface "
1882 "specified");
1883 if (strlen(argv[optind - 1]) >= IFNAMSIZ)
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001884 print_error("Illegal interface length");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001885 strcpy(new_entry->in, argv[optind - 1]);
1886 break;
1887 }
1888 if (c == 2) {
1889 check_option(&replace.flags, OPT_LOGICALIN);
1890 if (replace.selected_hook > 2 &&
1891 replace.selected_hook < NF_BR_BROUTING)
1892 print_error("Use logical in-interface "
1893 "only in INPUT, FORWARD, "
1894 "PREROUTING and BROUTING chains");
1895 if (check_inverse(optarg))
1896 new_entry->invflags |= EBT_ILOGICALIN;
1897
1898 if (optind > argc)
1899 print_error("No logical in-interface "
1900 "specified");
1901 if (strlen(argv[optind - 1]) >= IFNAMSIZ)
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001902 print_error("Illegal interface length");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001903 strcpy(new_entry->logical_in, argv[optind - 1]);
1904 break;
1905 }
1906 if (c == 'o') {
1907 check_option(&replace.flags, OPT_OUT);
1908 if (replace.selected_hook < 2)
1909 print_error("Use out-interface only"
1910 " in OUTPUT, FORWARD and "
1911 "POSTROUTING chains");
1912 if (check_inverse(optarg))
1913 new_entry->invflags |= EBT_IOUT;
1914
1915 if (optind > argc)
1916 print_error("No out-interface "
1917 "specified");
1918
1919 if (strlen(argv[optind - 1]) >= IFNAMSIZ)
1920 print_error("Illegal interface "
1921 "length");
1922 strcpy(new_entry->out, argv[optind - 1]);
1923 break;
1924 }
1925 if (c == 3) {
1926 check_option(&replace.flags, OPT_LOGICALOUT);
1927 if (replace.selected_hook < 2)
1928 print_error("Use logical out-interface "
1929 "only in OUTPUT, FORWARD and "
1930 "POSTROUTING chains");
1931 if (check_inverse(optarg))
1932 new_entry->invflags |= EBT_ILOGICALOUT;
1933
1934 if (optind > argc)
1935 print_error("No logical out-interface "
1936 "specified");
1937
1938 if (strlen(argv[optind - 1]) >= IFNAMSIZ)
1939 print_error("Illegal interface "
1940 "length");
1941 strcpy(new_entry->logical_out,
1942 argv[optind - 1]);
1943 break;
1944 }
1945 if (c == 'j') {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001946 check_option(&replace.flags, OPT_JUMP);
1947 for (i = 0; i < NUM_STANDARD_TARGETS; i++)
1948 if (!strcmp(optarg,
1949 standard_targets[i])) {
1950 t = find_target(
1951 EBT_STANDARD_TARGET);
1952 ((struct ebt_standard_target *)
Bart De Schuymer60332e02002-06-23 08:01:47 +00001953 t->t)->verdict = -i - 1;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001954 break;
1955 }
Bart De Schuymer60332e02002-06-23 08:01:47 +00001956 if (-i - 1 == EBT_RETURN) {
1957 if (replace.selected_hook < NF_BR_NUMHOOKS)
1958 print_error("Return target"
1959 " only for user defined chains");
1960 }
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +00001961 if (i != NUM_STANDARD_TARGETS)
1962 break;
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001963 if ((i = get_hooknr(optarg)) != -1) {
1964 if (i < NF_BR_NUMHOOKS)
1965 print_error("don't jump"
1966 " to a standard chain");
1967 t = find_target(
1968 EBT_STANDARD_TARGET);
1969 ((struct ebt_standard_target *)
1970 t->t)->verdict = i - NF_BR_NUMHOOKS;
1971 break;
1972 }
1973 else {
1974 // must be an extension then
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001975 struct ebt_u_target *t;
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001976
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001977 t = find_target(optarg);
1978 // -j standard not allowed either
1979 if (!t || t ==
1980 (struct ebt_u_target *)new_entry->t)
1981 print_error("Illegal target "
1982 "name");
1983 new_entry->t =
1984 (struct ebt_entry_target *)t;
1985 }
1986 break;
1987 }
1988 if (c == 's') {
1989 check_option(&replace.flags, OPT_SOURCE);
1990 if (check_inverse(optarg))
1991 new_entry->invflags |= EBT_ISOURCE;
1992
1993 if (optind > argc)
1994 print_error("No source mac "
1995 "specified");
1996 if (getmac_and_mask(argv[optind - 1],
1997 new_entry->sourcemac, new_entry->sourcemsk))
1998 print_error("Problem with specified "
1999 "source mac");
2000 new_entry->bitmask |= EBT_SOURCEMAC;
2001 break;
2002 }
2003 if (c == 'd') {
2004 check_option(&replace.flags, OPT_DEST);
2005 if (check_inverse(optarg))
2006 new_entry->invflags |= EBT_IDEST;
2007
2008 if (optind > argc)
2009 print_error("No destination mac "
2010 "specified");
2011 if (getmac_and_mask(argv[optind - 1],
2012 new_entry->destmac, new_entry->destmsk))
2013 print_error("Problem with specified "
2014 "destination mac");
2015 new_entry->bitmask |= EBT_DESTMAC;
2016 break;
2017 }
2018 check_option(&replace.flags, OPT_PROTOCOL);
2019 if (check_inverse(optarg))
2020 new_entry->invflags |= EBT_IPROTO;
2021
2022 if (optind > argc)
2023 print_error("No protocol specified");
2024 new_entry->bitmask &= ~((unsigned int)EBT_NOPROTO);
2025 i = strtol(argv[optind - 1], &buffer, 16);
2026 if (*buffer == '\0' && (i < 0 || i > 0xFFFF))
2027 print_error("Problem with the specified "
2028 "protocol");
2029 new_entry->ethproto = i;
Bart De Schuymer28bf6f62002-06-26 18:57:24 +00002030 if (*buffer != '\0') {
2031 if ((i = name_to_number(argv[optind - 1],
2032 &new_entry->ethproto)) == -1)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002033 print_error("Problem with the specified"
2034 " protocol");
Bart De Schuymer28bf6f62002-06-26 18:57:24 +00002035 if (i == 1)
2036 new_entry->bitmask |= EBT_802_3;
2037 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002038 if (new_entry->ethproto < 1536 &&
2039 !(new_entry->bitmask & EBT_802_3))
2040 print_error("Sorry, protocols have values above"
2041 " or equal to 1536 (0x0600)");
2042 break;
2043
2044 case 'b': // allow database?
2045 if (replace.flags & OPT_COMMAND)
2046 print_error("Multiple commands not allowed");
2047 replace.command = c;
2048 allowbc = *optarg;
2049 break;
2050
Bart De Schuymer9af14f92002-07-10 20:49:10 +00002051 case 4 : // Lc
2052 check_option(&replace.flags, LIST_C);
2053 if (replace.selected_hook == DATABASEHOOKNR)
2054 print_error("--Lc not valid for listing"
2055 " the database");
2056 if (replace.command != 'L')
2057 print_error("Use --Lc with -L");
2058 if (replace.flags & LIST_X)
2059 print_error("--Lx not compatible with --Lc");
2060 replace.flags |= LIST_C;
2061 break;
2062 case 5 : // Ln
2063 check_option(&replace.flags, LIST_N);
2064 if (replace.selected_hook == DATABASEHOOKNR)
2065 print_error("--Ln not valid for listing"
2066 " the database");
2067 if (replace.command != 'L')
2068 print_error("Use --Ln with -L");
2069 if (replace.flags & LIST_X)
2070 print_error("--Lx not compatible with --Ln");
2071 replace.flags |= LIST_N;
2072 break;
2073 case 6 : // Lx
2074 check_option(&replace.flags, LIST_X);
2075 if (replace.selected_hook == DATABASEHOOKNR)
2076 print_error("--Lx not valid for listing"
2077 " the database");
2078 if (replace.command != 'L')
2079 print_error("Use --Lx with -L");
2080 if (replace.flags & LIST_C)
2081 print_error("--Lx not compatible with --Lc");
2082 if (replace.flags & LIST_N)
2083 print_error("--Lx not compatible with --Ln");
2084 replace.flags |= LIST_X;
2085 break;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002086
Bart De Schuymer9af14f92002-07-10 20:49:10 +00002087 default:
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002088 // is it a target option?
2089 t = (struct ebt_u_target *)new_entry->t;
2090 if ((t->parse(c - t->option_offset, argv, argc,
2091 new_entry, &t->flags, &t->t)))
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00002092 goto check_extension;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002093
2094 // is it a match_option?
2095 for (m = matches; m; m = m->next)
2096 if (m->parse(c - m->option_offset, argv,
2097 argc, new_entry, &m->flags, &m->m))
2098 break;
2099
2100 if (m != NULL) {
2101 if (m->used == 0)
2102 add_match(m);
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00002103 goto check_extension;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002104 }
2105
2106 // is it a watcher option?
2107 for (w = watchers; w; w = w->next)
2108 if (w->parse(c-w->option_offset, argv,
2109 argc, new_entry, &w->flags, &w->w))
2110 break;
2111
2112 if (w == NULL)
2113 print_error("Unknown argument");
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00002114 if (w->used == 0)
2115 add_watcher(w);
2116check_extension:
Bart De Schuymer60332e02002-06-23 08:01:47 +00002117 if (replace.command != 'A' && replace.command != 'I' &&
2118 replace.command != 'D')
2119 print_error("extensions only for -A, -I and -D");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002120 }
2121 }
2122
Bart De Schuymer25c741d2002-06-23 18:54:34 +00002123 if ( !table && !(table = find_table(replace.name)) )
2124 print_error("Bad table name");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002125 // database stuff before ebtables stuff
2126 if (replace.command == 'b')
2127 allowdb(allowbc);
2128 if (replace.command == 'L' && replace.selected_hook == DATABASEHOOKNR)
2129 list_db();
2130
2131 if ( (replace.flags & OPT_COMMAND) && replace.command != 'L' &&
2132 replace.flags & OPT_ZERO )
2133 print_error("Command -Z only allowed together with command -L");
2134
2135 if (replace.command == 'A' || replace.command == 'I' ||
2136 replace.command == 'D') {
2137 if (replace.selected_hook == -1)
2138 print_error("Not enough information");
2139 }
2140
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002141 // do this after parsing everything, so we can print specific info
2142 if (replace.command == 'h' && !(replace.flags & OPT_ZERO))
2143 print_help();
2144
2145 // do the final checks
Bart De Schuymer60332e02002-06-23 08:01:47 +00002146 if (replace.command == 'A' || replace.command == 'I' ||
2147 replace.command == 'D') {
2148 // this will put the hook_mask right for the chains
2149 check_for_loops();
2150 entries = to_chain();
2151 m_l = new_entry->m_list;
2152 w_l = new_entry->w_list;
2153 t = (struct ebt_u_target *)new_entry->t;
2154 while (m_l) {
2155 m = (struct ebt_u_match *)(m_l->m);
2156 m->final_check(new_entry, m->m, replace.name,
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +00002157 entries->hook_mask, 0);
Bart De Schuymer60332e02002-06-23 08:01:47 +00002158 m_l = m_l->next;
2159 }
2160 while (w_l) {
2161 w = (struct ebt_u_watcher *)(w_l->w);
2162 w->final_check(new_entry, w->w, replace.name,
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +00002163 entries->hook_mask, 0);
Bart De Schuymer60332e02002-06-23 08:01:47 +00002164 w_l = w_l->next;
2165 }
2166 t->final_check(new_entry, t->t, replace.name,
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +00002167 entries->hook_mask, 0);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002168 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002169 // so, the extensions can work with the host endian
2170 // the kernel does not have to do this ofcourse
2171 new_entry->ethproto = htons(new_entry->ethproto);
2172
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002173 if (replace.command == 'P')
2174 change_policy(policy);
2175 else if (replace.command == 'L') {
2176 list_rules();
2177 if (replace.flags & OPT_ZERO)
2178 zero_counters(zerochain);
2179 else
2180 exit(0);
2181 }
2182 if (replace.flags & OPT_ZERO)
2183 zero_counters(zerochain);
Bart De Schuymer1ab41562002-06-23 17:09:54 +00002184 else if (replace.command == 'F') {
2185 if (flush_chains() == -1)
2186 exit(0);
2187 } else if (replace.command == 'A' || replace.command == 'I') {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002188 add_rule(rule_nr);
Bart De Schuymer1ab41562002-06-23 17:09:54 +00002189 check_for_loops();
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +00002190 // do the final_check(), for all entries
2191 // needed when adding a rule that has a chain target
2192 i = -1;
2193 while (1) {
2194 struct ebt_u_entry *e;
2195
2196 i++;
2197 entries = nr_to_chain(i);
2198 if (!entries) {
2199 if (i < NF_BR_NUMHOOKS)
2200 continue;
2201 else
2202 break;
2203 }
2204 e = entries->entries;
2205 while (e) {
2206 // userspace extensions use host endian
2207 e->ethproto = ntohs(e->ethproto);
2208 do_final_checks(e, entries);
2209 e->ethproto = htons(e->ethproto);
2210 e = e->next;
2211 }
2212 }
Bart De Schuymer1ab41562002-06-23 17:09:54 +00002213 } else if (replace.command == 'D')
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002214 delete_rule(rule_nr);
Bart De Schuymer1ab41562002-06-23 17:09:54 +00002215 // commands -N, -E, -X fall through
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002216
2217 if (table->check)
2218 table->check(&replace);
2219
2220 deliver_table(&replace);
2221
2222 if (counterchanges)
2223 deliver_counters(&replace, counterchanges);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002224 return 0;
2225}