blob: 0c87e6222ad3370b9df0acdbbe6bb40a6ef56a64 [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 Schuymer62423742002-07-14 19:06:20 +000065static struct option ebt_original_options[] =
66{
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000067 { "append" , required_argument, 0, 'A' },
68 { "insert" , required_argument, 0, 'I' },
69 { "delete" , required_argument, 0, 'D' },
70 { "list" , optional_argument, 0, 'L' },
Bart De Schuymer9af14f92002-07-10 20:49:10 +000071 { "Lc" , no_argument , 0, 4 },
72 { "Ln" , no_argument , 0, 5 },
73 { "Lx" , no_argument , 0, 6 },
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000074 { "zero" , optional_argument, 0, 'Z' },
75 { "flush" , optional_argument, 0, 'F' },
76 { "policy" , required_argument, 0, 'P' },
77 { "in-interface" , required_argument, 0, 'i' },
78 { "in-if" , required_argument, 0, 'i' },
79 { "logical-in" , required_argument, 0, 2 },
80 { "logical-out" , required_argument, 0, 3 },
81 { "out-interface" , required_argument, 0, 'o' },
82 { "out-if" , required_argument, 0, 'o' },
83 { "version" , no_argument , 0, 'V' },
84 { "help" , no_argument , 0, 'h' },
85 { "jump" , required_argument, 0, 'j' },
86 { "proto" , required_argument, 0, 'p' },
87 { "protocol" , required_argument, 0, 'p' },
88 { "db" , required_argument, 0, 'b' },
89 { "source" , required_argument, 0, 's' },
90 { "src" , required_argument, 0, 's' },
91 { "destination" , required_argument, 0, 'd' },
92 { "dst" , required_argument, 0, 'd' },
93 { "table" , required_argument, 0, 't' },
Bart De Schuymerc8531032002-06-14 21:55:29 +000094 { "modprobe" , required_argument, 0, 'M' },
Bart De Schuymer1ab41562002-06-23 17:09:54 +000095 { "new-chain" , required_argument, 0, 'N' },
96 { "rename-chain" , required_argument, 0, 'E' },
97 { "delete-chain" , required_argument, 0, 'X' },
Bart De Schuymer62423742002-07-14 19:06:20 +000098 { "atomic-init" , required_argument, 0, 7 },
99 // communication.c uses fact that atomic-commit equals 8
100 { "atomic-commit" , required_argument, 0, 8 },
101 { "atomic" , required_argument, 0, 9 },
102 { "atomic-save" , required_argument, 0, 10 },
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000103 { 0 }
104};
105
106static struct option *ebt_options = ebt_original_options;
107
108// yup, all the possible target names
Bart De Schuymer62423742002-07-14 19:06:20 +0000109char* standard_targets[NUM_STANDARD_TARGETS] =
110{
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000111 "ACCEPT",
112 "DROP",
113 "CONTINUE",
Bart De Schuymer60332e02002-06-23 08:01:47 +0000114 "RETURN",
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000115};
116
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000117unsigned char mac_type_unicast[ETH_ALEN] = {0,0,0,0,0,0};
118unsigned char msk_type_unicast[ETH_ALEN] = {1,0,0,0,0,0};
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000119unsigned char mac_type_multicast[ETH_ALEN] = {1,0,0,0,0,0};
120unsigned char msk_type_multicast[ETH_ALEN] = {1,0,0,0,0,0};
121unsigned char mac_type_broadcast[ETH_ALEN] = {255,255,255,255,255,255};
122unsigned char msk_type_broadcast[ETH_ALEN] = {255,255,255,255,255,255};
123
124// tells what happened to the old rules
125static unsigned short *counterchanges;
126// holds all the data
127static struct ebt_u_replace replace;
128
129// the chosen table
130static struct ebt_u_table *table = NULL;
131// the lists of supported tables, matches, watchers and targets
132static struct ebt_u_table *tables = NULL;
133static struct ebt_u_match *matches = NULL;
134static struct ebt_u_watcher *watchers = NULL;
135static struct ebt_u_target *targets = NULL;
136
137struct ebt_u_target *find_target(const char *name)
138{
139 struct ebt_u_target *t = targets;
140
141 while(t && strcmp(t->name, name))
142 t = t->next;
143 return t;
144}
145
146struct ebt_u_match *find_match(const char *name)
147{
148 struct ebt_u_match *m = matches;
149
150 while(m && strcmp(m->name, name))
151 m = m->next;
152 return m;
153}
154
155struct ebt_u_watcher *find_watcher(const char *name)
156{
157 struct ebt_u_watcher *w = watchers;
158
159 while(w && strcmp(w->name, name))
160 w = w->next;
161 return w;
162}
163
164struct ebt_u_table *find_table(char *name)
165{
166 struct ebt_u_table *t = tables;
167
168 while (t && strcmp(t->name, name))
169 t = t->next;
170 return t;
171}
172
173// The pointers in here are special:
174// The struct ebt_target * pointer is actually a struct ebt_u_target * pointer.
175// instead of making yet a few other structs, we just do a cast.
176// We need a struct ebt_u_target pointer because we know the address of the data
177// they point to won't change. We want to allow that the struct ebt_u_target.t
178// member can change.
179// Same holds for the struct ebt_match and struct ebt_watcher pointers
180struct ebt_u_entry *new_entry;
181
Bart De Schuymer62423742002-07-14 19:06:20 +0000182static void initialize_entry(struct ebt_u_entry *e)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000183{
184 e->bitmask = EBT_NOPROTO;
185 e->invflags = 0;
186 e->ethproto = 0;
187 strcpy(e->in, "");
188 strcpy(e->out, "");
189 strcpy(e->logical_in, "");
190 strcpy(e->logical_out, "");
191 e->m_list = NULL;
192 e->w_list = NULL;
193 // the init function of the standard target should have put the verdict
194 // on CONTINUE
195 e->t = (struct ebt_entry_target *)find_target(EBT_STANDARD_TARGET);
196 if (!e->t)
197 print_bug("Couldn't load standard target\n");
198}
199
200// this doesn't free e, becoz the calling function might need e->next
Bart De Schuymer62423742002-07-14 19:06:20 +0000201static void free_u_entry(struct ebt_u_entry *e)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000202{
203 struct ebt_u_match_list *m_l, *m_l2;
204 struct ebt_u_watcher_list *w_l, *w_l2;
205
206 m_l = e->m_list;
207 while (m_l) {
208 m_l2 = m_l->next;
209 free(m_l->m);
210 free(m_l);
211 m_l = m_l2;
212 }
213 w_l = e->w_list;
214 while (w_l) {
215 w_l2 = w_l->next;
216 free(w_l->w);
217 free(w_l);
218 w_l = w_l2;
219 }
220 free(e->t);
221}
222
223// the user will use the match, so put it in new_entry
224static void add_match(struct ebt_u_match *m)
225{
226 struct ebt_u_match_list **m_list, *new;
227
228 m->used = 1;
229 for (m_list = &new_entry->m_list;
230 *m_list; m_list = &(*m_list)->next);
231 new = (struct ebt_u_match_list *)
232 malloc(sizeof(struct ebt_u_match_list));
233 if (!new)
234 print_memory();
235 *m_list = new;
236 new->next = NULL;
237 new->m = (struct ebt_entry_match *)m;
238}
239
240static void add_watcher(struct ebt_u_watcher *w)
241{
242 struct ebt_u_watcher_list **w_list;
243 struct ebt_u_watcher_list *new;
244
245 w->used = 1;
246 for (w_list = &new_entry->w_list;
247 *w_list; w_list = &(*w_list)->next);
248 new = (struct ebt_u_watcher_list *)
249 malloc(sizeof(struct ebt_u_watcher_list));
250 if (!new)
251 print_memory();
252 *w_list = new;
253 new->next = NULL;
254 new->w = (struct ebt_entry_watcher *)w;
255}
256
257static int global_option_offset = 0;
258#define OPTION_OFFSET 256
259static struct option *
260merge_options(struct option *oldopts, const struct option *newopts,
261 unsigned int *options_offset)
262{
263 unsigned int num_old, num_new, i;
264 struct option *merge;
265
266 if (!newopts || !oldopts || !options_offset)
267 print_bug("merge wrong");
268 for (num_old = 0; oldopts[num_old].name; num_old++);
269 for (num_new = 0; newopts[num_new].name; num_new++);
270
271 global_option_offset += OPTION_OFFSET;
272 *options_offset = global_option_offset;
273
274 merge = malloc(sizeof(struct option) * (num_new + num_old + 1));
275 if (!merge)
276 print_memory();
277 memcpy(merge, oldopts, num_old * sizeof(struct option));
278 for (i = 0; i < num_new; i++) {
279 merge[num_old + i] = newopts[i];
280 merge[num_old + i].val += *options_offset;
281 }
282 memset(merge + num_old + num_new, 0, sizeof(struct option));
283 // only free dynamically allocated stuff
284 if (oldopts != ebt_original_options)
285 free(oldopts);
286
287 return merge;
288}
289
290void register_match(struct ebt_u_match *m)
291{
292 int size = m->size + sizeof(struct ebt_entry_match);
293 struct ebt_u_match **i;
294
295 m->m = (struct ebt_entry_match *)malloc(size);
296 if (!m->m)
297 print_memory();
298 strcpy(m->m->u.name, m->name);
299 m->m->match_size = m->size;
300 ebt_options = merge_options
301 (ebt_options, m->extra_ops, &(m->option_offset));
302 m->init(m->m);
303
304 for (i = &matches; *i; i = &((*i)->next));
305 m->next = NULL;
306 *i = m;
307}
308
309void register_watcher(struct ebt_u_watcher *w)
310{
311 int size = w->size + sizeof(struct ebt_entry_watcher);
312 struct ebt_u_watcher **i;
313
314 w->w = (struct ebt_entry_watcher *)malloc(size);
315 if (!w->w)
316 print_memory();
317 strcpy(w->w->u.name, w->name);
318 w->w->watcher_size = w->size;
319 ebt_options = merge_options
320 (ebt_options, w->extra_ops, &(w->option_offset));
321 w->init(w->w);
322
323 for (i = &watchers; *i; i = &((*i)->next));
324 w->next = NULL;
325 *i = w;
326}
327
328void register_target(struct ebt_u_target *t)
329{
330 int size = t->size + sizeof(struct ebt_entry_target);
331 struct ebt_u_target **i;
332
333 t->t = (struct ebt_entry_target *)malloc(size);
334 if (!t->t)
335 print_memory();
336 strcpy(t->t->u.name, t->name);
337 t->t->target_size = t->size;
338 ebt_options = merge_options
339 (ebt_options, t->extra_ops, &(t->option_offset));
340 t->init(t->t);
341 for (i = &targets; *i; i = &((*i)->next));
342 t->next = NULL;
343 *i = t;
344}
345
346void register_table(struct ebt_u_table *t)
347{
348 t->next = tables;
349 tables = t;
350}
351
Bart De Schuymerc8531032002-06-14 21:55:29 +0000352// blatently stolen (again) from iptables.c userspace program
353// find out where the modprobe utility is located
354static char *get_modprobe(void)
355{
356 int procfile;
357 char *ret;
358
359 procfile = open(PROC_SYS_MODPROBE, O_RDONLY);
360 if (procfile < 0)
361 return NULL;
362
363 ret = malloc(1024);
364 if (ret) {
365 switch (read(procfile, ret, 1024)) {
366 case -1: goto fail;
367 case 1024: goto fail; /* Partial read. Wierd */
368 }
369 if (ret[strlen(ret)-1]=='\n')
370 ret[strlen(ret)-1]=0;
371 close(procfile);
372 return ret;
373 }
374 fail:
375 free(ret);
376 close(procfile);
377 return NULL;
378}
379
380// I hate stealing, really... Lets call it a tribute.
381int ebtables_insmod(const char *modname, const char *modprobe)
382{
383 char *buf = NULL;
384 char *argv[3];
385
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000386 // If they don't explicitly set it, read out of kernel
Bart De Schuymerc8531032002-06-14 21:55:29 +0000387 if (!modprobe) {
388 buf = get_modprobe();
389 if (!buf)
390 return -1;
391 modprobe = buf;
392 }
393
394 switch (fork()) {
395 case 0:
396 argv[0] = (char *)modprobe;
397 argv[1] = (char *)modname;
398 argv[2] = NULL;
399 execv(argv[0], argv);
400
401 /* not usually reached */
402 exit(0);
403 case -1:
404 return -1;
405
406 default: /* parent */
407 wait(NULL);
408 }
409
410 free(buf);
411 return 0;
412}
413
414
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000415// used to parse /etc/ethertypes
Bart De Schuymer62423742002-07-14 19:06:20 +0000416static int disregard_whitespace(char *buffer, FILE *ifp)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000417{
418 int hlp;
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000419
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000420 buffer[0] = '\t';
421 while (buffer[0] == '\t' || buffer[0] == '\n' || buffer[0] == ' ') {
422 hlp = fscanf(ifp, "%c", buffer);
423 if (hlp == EOF || hlp == 0) return -1;
424 }
425 return 0;
426}
427
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000428// used to parse /etc/ethertypes
Bart De Schuymer62423742002-07-14 19:06:20 +0000429static int disregard_tabspace(char *buffer, FILE *ifp)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000430{
431 int hlp;
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000432
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000433 buffer[0] = '\t';
434 while (buffer[0] == '\t' || buffer[0] == ' ') {
435 hlp = fscanf(ifp, "%c", buffer);
436 if (hlp == EOF || hlp == 0) return -1;
437 }
438 return 0;
439}
440
Bart De Schuymerbbca3202002-06-05 18:55:44 +0000441// helper function: processes a line of data from the file /etc/ethertypes
Bart De Schuymer62423742002-07-14 19:06:20 +0000442static int get_a_line(char *buffer, char *value, FILE *ifp)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000443{
444 int i, hlp;
445 char anotherhlp;
446
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000447 // discard comment lines and whitespace
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000448 while (1) {
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000449 if (disregard_whitespace(buffer, ifp))
450 return -1;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000451 if (buffer[0] == '#')
452 while (1) {
453 hlp = fscanf(ifp, "%c", &anotherhlp);
454 if (!hlp || hlp == EOF)
455 return -1;
456 if (anotherhlp == '\n')
457 break;
458 }
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000459 else
460 break;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000461 }
462
463 // buffer[0] already contains the first letter
464 for (i = 1; i < 21; i++) {
465 hlp = fscanf(ifp, "%c", buffer + i);
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000466 if (hlp == EOF || hlp == 0)
467 return -1;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000468 if (buffer[i] == '\t' || buffer[i] == ' ')
469 break;
470 }
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000471 if (i == 21)
472 return -1;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000473 buffer[i] = '\0';
474 if (disregard_tabspace(value, ifp))
475 return -1;
476 // maybe I should allow 0x0800 instead of 0800, but I'm feeling lazy
477 // buffer[0] already contains the first letter
478 for (i = 1; i < 5; i++) {
479 hlp = fscanf(ifp, "%c", value+i);
480 if (value[i] == '\n' || value[i] == '\t' ||
481 value[i] == ' ' || hlp == EOF)
482 break;
483 }
484 if (i == 5) return -1;
Bart De Schuymerbbca3202002-06-05 18:55:44 +0000485 // discard comments at the end of a line
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000486 if (value[i] == '\t' || value[i] == ' ')
487 while (1) {
488 hlp = fscanf(ifp, "%c", &anotherhlp);
489 if (!hlp || hlp == EOF || anotherhlp == '\n')
490 break;
491 }
492 value[i] = '\0';
493 return 0;
494}
495
Bart De Schuymerb909f9b2002-06-26 18:35:31 +0000496// translate a hexadecimal number to a protocol name, parsing /etc/ethertypes
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000497// returns 0 on success
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000498int number_to_name(unsigned short proto, char *name)
499{
500 FILE *ifp;
501 char buffer[21], value[5], *bfr;
502 unsigned short i;
503
504 if ( !(ifp = fopen(PROTOCOLFILE, "r")) )
505 return -1;
506 while (1) {
507 if (get_a_line(buffer, value, ifp)) {
508 fclose(ifp);
509 return -1;
510 }
511 i = (unsigned short) strtol(value, &bfr, 16);
512 if (*bfr != '\0' || i != proto)
513 continue;
514 strcpy(name, buffer);
515 fclose(ifp);
516 return 0;
517 }
518}
519
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000520// we use replace.flags, so we can't use the following values:
521// 0x01 == OPT_COMMAND, 0x02 == OPT_TABLE, 0x100 == OPT_ZERO
522#define LIST_N 0x04
523#define LIST_C 0x08
524#define LIST_X 0x10
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000525// helper function for list_rules()
Bart De Schuymer60332e02002-06-23 08:01:47 +0000526static void list_em(struct ebt_u_entries *entries)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000527{
528 int i, j, space = 0, digits;
529 struct ebt_u_entry *hlp;
530 struct ebt_u_match_list *m_l;
531 struct ebt_u_watcher_list *w_l;
532 struct ebt_u_match *m;
533 struct ebt_u_watcher *w;
534 struct ebt_u_target *t;
535 char name[21];
536
Bart De Schuymer60332e02002-06-23 08:01:47 +0000537 hlp = entries->entries;
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000538 if (replace.flags & LIST_X && entries->policy != EBT_ACCEPT) {
539 printf("ebtables -t %s -P %s %s\n", replace.name,
540 entries->name, standard_targets[-entries->policy - 1]);
541 } else if (!(replace.flags & LIST_X)) {
542 printf("\nBridge chain: %s\nPolicy: %s\n", entries->name,
543 standard_targets[-entries->policy - 1]);
544 printf("nr. of entries: %d \n", entries->nentries);
545 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000546
Bart De Schuymer60332e02002-06-23 08:01:47 +0000547 i = entries->nentries;
Bart De Schuymerf8f8f292002-06-25 15:43:57 +0000548 while (i > 9) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000549 space++;
550 i /= 10;
551 }
552
Bart De Schuymer60332e02002-06-23 08:01:47 +0000553 for (i = 0; i < entries->nentries; i++) {
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000554 if (replace.flags & LIST_N) {
555 digits = 0;
556 // A little work to get nice rule numbers.
557 j = i + 1;
558 while (j > 9) {
559 digits++;
560 j /= 10;
561 }
562 for (j = 0; j < space - digits; j++)
563 printf(" ");
564 printf("%d. ", i + 1);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000565 }
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000566 if (replace.flags & LIST_X)
567 printf("ebtables -t %s -A %s ",
568 replace.name, entries->name);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000569
570 // Don't print anything about the protocol if no protocol was
571 // specified, obviously this means any protocol will do.
572 if (!(hlp->bitmask & EBT_NOPROTO)) {
Bart De Schuymer60332e02002-06-23 08:01:47 +0000573 printf("-p ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000574 if (hlp->invflags & EBT_IPROTO)
575 printf("! ");
576 if (hlp->bitmask & EBT_802_3)
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000577 printf("Length ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000578 else {
579 if (number_to_name(ntohs(hlp->ethproto), name))
Bart De Schuymer60332e02002-06-23 08:01:47 +0000580 printf("0x%x ", ntohs(hlp->ethproto));
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000581 else
Bart De Schuymer60332e02002-06-23 08:01:47 +0000582 printf("%s ", name);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000583 }
584 }
585 if (hlp->bitmask & EBT_SOURCEMAC) {
586 char hlpmsk[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
587
Bart De Schuymer60332e02002-06-23 08:01:47 +0000588 printf("-s ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000589 if (hlp->invflags & EBT_ISOURCE)
590 printf("! ");
591 if (!memcmp(hlp->sourcemac, mac_type_unicast, 6) &&
592 !memcmp(hlp->sourcemsk, msk_type_unicast, 6)) {
593 printf("Unicast");
594 goto endsrc;
595 }
596 if (!memcmp(hlp->sourcemac, mac_type_multicast, 6) &&
597 !memcmp(hlp->sourcemsk, msk_type_multicast, 6)) {
598 printf("Multicast");
599 goto endsrc;
600 }
601 if (!memcmp(hlp->sourcemac, mac_type_broadcast, 6) &&
602 !memcmp(hlp->sourcemsk, msk_type_broadcast, 6)) {
603 printf("Broadcast");
604 goto endsrc;
605 }
Bart De Schuymer41830412002-06-05 19:41:28 +0000606 printf("%s", ether_ntoa((struct ether_addr *)
607 hlp->sourcemac));
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000608 if (memcmp(hlp->sourcemsk, hlpmsk, 6)) {
609 printf("/");
Bart De Schuymer41830412002-06-05 19:41:28 +0000610 printf("%s", ether_ntoa((struct ether_addr *)
611 hlp->sourcemsk));
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000612 }
613endsrc:
Bart De Schuymer60332e02002-06-23 08:01:47 +0000614 printf(" ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000615 }
616 if (hlp->bitmask & EBT_DESTMAC) {
617 char hlpmsk[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
618
Bart De Schuymer60332e02002-06-23 08:01:47 +0000619 printf("-d ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000620 if (hlp->invflags & EBT_IDEST)
621 printf("! ");
622 if (!memcmp(hlp->destmac, mac_type_unicast, 6) &&
623 !memcmp(hlp->destmsk, msk_type_unicast, 6)) {
624 printf("Unicast");
625 goto enddst;
626 }
627 if (!memcmp(hlp->destmac, mac_type_multicast, 6) &&
628 !memcmp(hlp->destmsk, msk_type_multicast, 6)) {
629 printf("Multicast");
630 goto enddst;
631 }
632 if (!memcmp(hlp->destmac, mac_type_broadcast, 6) &&
633 !memcmp(hlp->destmsk, msk_type_broadcast, 6)) {
634 printf("Broadcast");
635 goto enddst;
636 }
Bart De Schuymer41830412002-06-05 19:41:28 +0000637 printf("%s", ether_ntoa((struct ether_addr *)
638 hlp->destmac));
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000639 if (memcmp(hlp->destmsk, hlpmsk, 6)) {
640 printf("/");
Bart De Schuymer41830412002-06-05 19:41:28 +0000641 printf("%s", ether_ntoa((struct ether_addr *)
642 hlp->destmsk));
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000643 }
644enddst:
Bart De Schuymer60332e02002-06-23 08:01:47 +0000645 printf(" ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000646 }
647 if (hlp->in[0] != '\0') {
Bart De Schuymer60332e02002-06-23 08:01:47 +0000648 printf("-i ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000649 if (hlp->invflags & EBT_IIN)
650 printf("! ");
Bart De Schuymer60332e02002-06-23 08:01:47 +0000651 printf("%s ", hlp->in);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000652 }
653 if (hlp->logical_in[0] != '\0') {
Bart De Schuymer60332e02002-06-23 08:01:47 +0000654 printf("--logical-in ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000655 if (hlp->invflags & EBT_ILOGICALIN)
656 printf("! ");
Bart De Schuymer60332e02002-06-23 08:01:47 +0000657 printf("%s ", hlp->logical_in);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000658 }
659 if (hlp->logical_out[0] != '\0') {
Bart De Schuymer60332e02002-06-23 08:01:47 +0000660 printf("--logical-out ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000661 if (hlp->invflags & EBT_ILOGICALOUT)
662 printf("! ");
Bart De Schuymerb3d8f262002-07-07 14:26:15 +0000663 printf("%s ", hlp->logical_out);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000664 }
665 if (hlp->out[0] != '\0') {
Bart De Schuymer60332e02002-06-23 08:01:47 +0000666 printf("-o ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000667 if (hlp->invflags & EBT_IOUT)
668 printf("! ");
Bart De Schuymerb3d8f262002-07-07 14:26:15 +0000669 printf("%s ", hlp->out);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000670 }
671
672 m_l = hlp->m_list;
673 while (m_l) {
674 m = find_match(m_l->m->u.name);
675 if (!m)
676 print_bug("Match not found");
677 m->print(hlp, m_l->m);
678 m_l = m_l->next;
679 }
680 w_l = hlp->w_list;
681 while (w_l) {
682 w = find_watcher(w_l->w->u.name);
683 if (!w)
684 print_bug("Watcher not found");
685 w->print(hlp, w_l->w);
686 w_l = w_l->next;
687 }
688
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000689 printf("-j ");
690 if (strcmp(hlp->t->u.name, EBT_STANDARD_TARGET))
691 printf("%s ", hlp->t->u.name);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000692 t = find_target(hlp->t->u.name);
693 if (!t)
694 print_bug("Target not found");
695 t->print(hlp, hlp->t);
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000696 if (replace.flags & LIST_C)
697 printf(", count = %llu",
698 replace.counters[entries->counter_offset + i].pcnt);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000699 printf("\n");
700 hlp = hlp->next;
701 }
702}
703
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000704struct ebt_u_entries *nr_to_chain(int nr)
Bart De Schuymer60332e02002-06-23 08:01:47 +0000705{
706 if (nr == -1)
707 return NULL;
708 if (nr < NF_BR_NUMHOOKS)
709 return replace.hook_entry[nr];
710 else {
711 int i;
712 struct ebt_u_chain_list *cl = replace.udc;
713
714 i = nr - NF_BR_NUMHOOKS;
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000715 while (i > 0 && cl) {
Bart De Schuymer60332e02002-06-23 08:01:47 +0000716 cl = cl->next;
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000717 i--;
718 }
Bart De Schuymer60332e02002-06-23 08:01:47 +0000719 if (cl)
720 return cl->udc;
721 else
722 return NULL;
723 }
724}
725
726static struct ebt_u_entries *to_chain()
727{
728 return nr_to_chain(replace.selected_hook);
729}
730
731struct ebt_u_stack
732{
733 int chain_nr;
734 int n;
735 struct ebt_u_entry *e;
736 struct ebt_u_entries *entries;
737};
738
Bart De Schuymer62423742002-07-14 19:06:20 +0000739static void check_for_loops()
Bart De Schuymer60332e02002-06-23 08:01:47 +0000740{
741 int chain_nr , i, j , k, sp = 0, verdict;
742 struct ebt_u_entries *entries, *entries2;
743 struct ebt_u_stack *stack = NULL;
744 struct ebt_u_entry *e;
745
746 i = -1;
747 // initialize hook_mask to 0
748 while (1) {
749 i++;
750 if (i < NF_BR_NUMHOOKS && !(replace.valid_hooks & (1 << i)))
751 continue;
752 entries = nr_to_chain(i);
753 if (!entries)
754 break;
755 entries->hook_mask = 0;
756 }
757 if (i > NF_BR_NUMHOOKS) {
758 stack = (struct ebt_u_stack *)malloc((i - NF_BR_NUMHOOKS) *
759 sizeof(struct ebt_u_stack));
760 if (!stack)
761 print_memory();
762 }
763
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000764 // check for loops, starting from every base chain
Bart De Schuymer60332e02002-06-23 08:01:47 +0000765 for (i = 0; i < NF_BR_NUMHOOKS; i++) {
766 if (!(replace.valid_hooks & (1 << i)))
767 continue;
768 entries = nr_to_chain(i);
769 entries->hook_mask = (1 << i);
770 chain_nr = i;
771
772 e = entries->entries;
773 for (j = 0; j < entries->nentries; j++) {
774 if (strcmp(e->t->u.name, EBT_STANDARD_TARGET))
775 goto letscontinue;
776 verdict = ((struct ebt_standard_target *)(e->t))->verdict;
777 if (verdict < 0)
778 goto letscontinue;
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000779 entries2 = nr_to_chain(verdict + NF_BR_NUMHOOKS);
Bart De Schuymer60332e02002-06-23 08:01:47 +0000780 entries2->hook_mask |= entries->hook_mask;
781 // now see if we've been here before
782 for (k = 0; k < sp; k++)
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000783 if (stack[k].chain_nr == verdict + NF_BR_NUMHOOKS)
Bart De Schuymer1a0a9c32002-06-24 21:10:16 +0000784 print_error("Loop from chain %s to chain %s",
785 nr_to_chain(chain_nr)->name, nr_to_chain(stack[k].chain_nr)->name);
Bart De Schuymer60332e02002-06-23 08:01:47 +0000786 // jump to the chain, make sure we know how to get back
787 stack[sp].chain_nr = chain_nr;
788 stack[sp].n = j;
789 stack[sp].entries = entries;
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000790 stack[sp].e = e;
791 sp++;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000792 j = -1;
793 e = entries2->entries;
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000794 chain_nr = verdict + NF_BR_NUMHOOKS;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000795 entries = entries2;
796 continue;
797letscontinue:
798 e = e->next;
799 }
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000800 // we are at the end of a standard chain
Bart De Schuymer60332e02002-06-23 08:01:47 +0000801 if (sp == 0)
802 continue;
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000803 // go back to the chain one level higher
Bart De Schuymer60332e02002-06-23 08:01:47 +0000804 sp--;
805 j = stack[sp].n;
806 chain_nr = stack[sp].chain_nr;
807 e = stack[sp].e;
808 entries = stack[sp].entries;
809 goto letscontinue;
810 }
811 free(stack);
812 return;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000813}
814
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000815// parse the chain name and return the corresponding nr
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000816// returns -1 on failure
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000817int get_hooknr(char* arg)
818{
819 int i;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000820 struct ebt_u_chain_list *cl = replace.udc;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000821
822 // database is special case (not really a chain)
823 if (!strcmp(arg, DATABASEHOOKNAME))
824 return DATABASEHOOKNR;
825
Bart De Schuymer60332e02002-06-23 08:01:47 +0000826 for (i = 0; i < NF_BR_NUMHOOKS; i++) {
827 if (!(replace.valid_hooks & (1 << i)))
828 continue;
829 if (!strcmp(arg, replace.hook_entry[i]->name))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000830 return i;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000831 }
832 while(cl) {
833 if (!strcmp(arg, cl->udc->name))
834 return i;
835 i++;
836 cl = cl->next;
837 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000838 return -1;
839}
840
841// yup, print out help
Bart De Schuymer62423742002-07-14 19:06:20 +0000842static void print_help()
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000843{
844 struct ebt_u_match_list *m_l;
845 struct ebt_u_watcher_list *w_l;
846
847 printf(
848"%s v%s\n"
849"Usage:\n"
850"ebtables -[ADI] chain rule-specification [options]\n"
851"ebtables -P chain target\n"
852"ebtables -[LFZ] [chain]\n"
853"ebtables -[b] [y,n]\n"
854"Commands:\n"
855"--append -A chain : Append to chain\n"
856"--delete -D chain : Delete matching rule from chain\n"
857"--delete -D chain rulenum : Delete rule at position rulenum from chain\n"
858"--insert -I chain rulenum : insert rule at position rulenum in chain\n"
859"--list -L [chain] : List the rules in a chain or in all chains\n"
860"--list -L "DATABASEHOOKNAME" : List the database (if present)\n"
861"--flush -F [chain] : Delete all rules in chain or in all chains\n"
862"--zero -Z [chain] : Put counters on zero in chain or in all chains\n"
863"--policy -P chain target : Change policy on chain to target\n"
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000864"--new-chain -N chain : Create a user defined chain\n"
865"--rename-chain -E old new : Rename a chain\n"
866"--delete-chain -X chain : Delete a user defined chain\n"
Bart De Schuymer62423742002-07-14 19:06:20 +0000867"--atomic-commit file : update the kernel w/ the table contained in file\n"
868"--atomic-init file : put the initial kernel table into file\n"
869"--atomic-save file : put the current kernel table into file\n"
870"--atomic file : write changes to file instead of kernel\n"
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000871"Options:\n"
872"--proto -p [!] proto : protocol hexadecimal, by name or LENGTH\n"
873"--src -s [!] address[/mask]: source mac address\n"
874"--dst -d [!] address[/mask]: destination mac address\n"
875"--in-if -i [!] name : network input interface name\n"
876"--out-if -o [!] name : network output interface name\n"
877"--logical-in [!] name : logical bridge input interface name\n"
878"--logical-out [!] name : logical bridge output interface name\n"
Bart De Schuymer5cbc8e02002-07-14 21:15:28 +0000879"--modprobe -M program : try to insert modules using this program\n"
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000880"--version -V : print package version\n"
881"\n" ,
882 prog_name,
883 prog_version);
884
885 m_l = new_entry->m_list;
886 while (m_l) {
887 ((struct ebt_u_match *)m_l->m)->help();
888 printf("\n");
889 m_l = m_l->next;
890 }
891 w_l = new_entry->w_list;
892 while (w_l) {
893 ((struct ebt_u_watcher *)w_l->w)->help();
894 printf("\n");
895 w_l = w_l->next;
896 }
897 ((struct ebt_u_target *)new_entry->t)->help();
898 printf("\n");
899 if (table->help)
900 table->help(hooknames);
901 exit(0);
902}
903
904// execute command L
905static void list_rules()
906{
907 int i;
908
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000909 if (!(replace.flags & LIST_X))
910 printf("Bridge table: %s\n", table->name);
Bart De Schuymer60332e02002-06-23 08:01:47 +0000911 if (replace.selected_hook != -1) {
912 list_em(to_chain());
913 } else {
914 struct ebt_u_chain_list *cl = replace.udc;
915
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000916 // create new chains and rename standard chains when necessary
917 if (replace.flags & LIST_X) {
918 while (cl) {
919 printf("ebtables -t %s -N %s\n", replace.name,
920 cl->udc->name);
921 cl = cl->next;
922 }
923 cl = replace.udc;
924 for (i = 0; i < NF_BR_NUMHOOKS; i++)
925 if (replace.valid_hooks & (1 << i) &&
926 strcmp(replace.hook_entry[i]->name, hooknames[i]))
927 printf("ebtables -t %s -E %s %s\n",
928 replace.name, hooknames[i],
929 replace.hook_entry[i]->name);
930 }
Bart De Schuymer60332e02002-06-23 08:01:47 +0000931 i = 0;
932 while (1) {
933 if (i < NF_BR_NUMHOOKS) {
934 if (replace.valid_hooks & (1 << i))
935 list_em(replace.hook_entry[i]);
936 i++;
937 continue;
938 } else {
939 if (!cl)
940 break;
941 list_em(cl->udc);
942 cl = cl->next;
943 }
944 }
945 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000946}
947
948// execute command P
949static void change_policy(int policy)
950{
951 int i;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000952 struct ebt_u_entries *entries = to_chain();
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000953
954 // don't do anything if the policy is the same
Bart De Schuymer60332e02002-06-23 08:01:47 +0000955 if (entries->policy != policy) {
956 entries->policy = policy;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000957 replace.num_counters = replace.nentries;
958 if (replace.nentries) {
959 // '+ 1' for the CNT_END
960 if (!(counterchanges = (unsigned short *) malloc(
961 (replace.nentries + 1) * sizeof(unsigned short))))
962 print_memory();
963 // done nothing special to the rules
964 for (i = 0; i < replace.nentries; i++)
965 counterchanges[i] = CNT_NORM;
966 counterchanges[replace.nentries] = CNT_END;
967 }
968 else
969 counterchanges = NULL;
970 }
971 else
972 exit(0);
973}
974
975// flush one chain or the complete table
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000976// -1 == nothing to do
977// 0 == give back to kernel
978static int flush_chains()
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000979{
Bart De Schuymer60332e02002-06-23 08:01:47 +0000980 int i, j, oldnentries, numdel;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000981 unsigned short *cnt;
982 struct ebt_u_entry *u_e, *tmp;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000983 struct ebt_u_entries *entries = to_chain();
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000984
985 // flush whole table
Bart De Schuymer60332e02002-06-23 08:01:47 +0000986 if (!entries) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000987 if (replace.nentries == 0)
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000988 return -1;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000989 replace.nentries = 0;
990 // no need for the kernel to give us counters back
991 replace.num_counters = 0;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000992
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000993 // free everything and zero (n)entries
Bart De Schuymer60332e02002-06-23 08:01:47 +0000994 i = -1;
995 while (1) {
996 i++;
997 entries = nr_to_chain(i);
998 if (!entries) {
999 if (i < NF_BR_NUMHOOKS)
1000 continue;
1001 else
1002 break;
1003 }
1004 entries->nentries = 0;
1005 entries->counter_offset = 0;
1006 u_e = entries->entries;
1007 entries->entries = NULL;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001008 while (u_e) {
1009 free_u_entry(u_e);
1010 tmp = u_e->next;
1011 free(u_e);
1012 u_e = tmp;
1013 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001014 }
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001015 return 0;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001016 }
1017
Bart De Schuymer60332e02002-06-23 08:01:47 +00001018 if (entries->nentries == 0)
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001019 return -1;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001020 oldnentries = replace.nentries;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001021 replace.nentries -= entries->nentries;
1022 numdel = entries->nentries;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001023
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001024 if (replace.nentries) {
1025 // +1 for CNT_END
1026 if ( !(counterchanges = (unsigned short *)
1027 malloc((oldnentries + 1) * sizeof(unsigned short))) )
1028 print_memory();
Bart De Schuymer60332e02002-06-23 08:01:47 +00001029 }
1030 // delete the counters belonging to the specified chain,
1031 // update counter_offset
1032 i = -1;
Bart De Schuymerf8f8f292002-06-25 15:43:57 +00001033 cnt = counterchanges;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001034 while (1) {
1035 i++;
1036 entries = nr_to_chain(i);
1037 if (!entries) {
1038 if (i < NF_BR_NUMHOOKS)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001039 continue;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001040 else
1041 break;
1042 }
1043 if (i > replace.selected_hook)
1044 entries->counter_offset -= numdel;
1045 if (replace.nentries) {
1046 for (j = 0; j < entries->nentries; j++) {
1047 if (i == replace.selected_hook)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001048 *cnt = CNT_DEL;
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001049 else
1050 *cnt = CNT_NORM;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001051 cnt++;
1052 }
1053 }
Bart De Schuymer60332e02002-06-23 08:01:47 +00001054 }
1055
1056 if (replace.nentries) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001057 *cnt = CNT_END;
1058 replace.num_counters = oldnentries;
1059 }
1060 else
1061 replace.num_counters = 0;
1062
Bart De Schuymer60332e02002-06-23 08:01:47 +00001063 entries = to_chain();
1064 entries->nentries = 0;
1065 u_e = entries->entries;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001066 while (u_e) {
1067 free_u_entry(u_e);
1068 tmp = u_e->next;
1069 free(u_e);
1070 u_e = tmp;
1071 }
Bart De Schuymer60332e02002-06-23 08:01:47 +00001072 entries->entries = NULL;
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001073 return 0;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001074}
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001075
1076// -1 == no match
1077static int check_rule_exists(int rule_nr)
1078{
1079 struct ebt_u_entry *u_e;
1080 struct ebt_u_match_list *m_l, *m_l2;
1081 struct ebt_u_match *m;
1082 struct ebt_u_watcher_list *w_l, *w_l2;
1083 struct ebt_u_watcher *w;
1084 struct ebt_u_target *t = (struct ebt_u_target *)new_entry->t;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001085 struct ebt_u_entries *entries = to_chain();
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001086 int i, j, k;
1087
1088 // handle '-D chain rulenr' command
1089 if (rule_nr != -1) {
Bart De Schuymer60332e02002-06-23 08:01:47 +00001090 if (rule_nr > entries->nentries)
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001091 return -1;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001092 // user starts counting from 1
1093 return rule_nr - 1;
1094 }
Bart De Schuymer60332e02002-06-23 08:01:47 +00001095 u_e = entries->entries;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001096 // check for an existing rule (if there are duplicate rules,
1097 // take the first occurance)
Bart De Schuymer60332e02002-06-23 08:01:47 +00001098 for (i = 0; i < entries->nentries; i++, u_e = u_e->next) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001099 if (!u_e)
1100 print_bug("Hmm, trouble");
1101 if ( u_e->ethproto == new_entry->ethproto
1102 && !strcmp(u_e->in, new_entry->in)
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001103 && !strcmp(u_e->out, new_entry->out)) {
Bart De Schuymer60332e02002-06-23 08:01:47 +00001104 if (strcmp(u_e->logical_in, new_entry->logical_in) ||
1105 strcmp(u_e->logical_out, new_entry->logical_out))
1106 continue;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001107 if (new_entry->bitmask & EBT_SOURCEMAC &&
Bart De Schuymer60332e02002-06-23 08:01:47 +00001108 memcmp(u_e->sourcemac, new_entry->sourcemac, ETH_ALEN))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001109 continue;
1110 if (new_entry->bitmask & EBT_DESTMAC &&
Bart De Schuymer60332e02002-06-23 08:01:47 +00001111 memcmp(u_e->destmac, new_entry->destmac, ETH_ALEN))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001112 continue;
1113 if (new_entry->bitmask != u_e->bitmask ||
1114 new_entry->invflags != u_e->invflags)
1115 continue;
1116 // compare all matches
1117 m_l = new_entry->m_list;
1118 j = 0;
1119 while (m_l) {
1120 m = (struct ebt_u_match *)(m_l->m);
1121 m_l2 = u_e->m_list;
1122 while (m_l2 &&
1123 strcmp(m_l2->m->u.name, m->m->u.name))
1124 m_l2 = m_l2->next;
1125 if (!m_l2 || !m->compare(m->m, m_l2->m))
1126 goto letscontinue;
1127 j++;
1128 m_l = m_l->next;
1129 }
1130 // now be sure they have the same nr of matches
1131 k = 0;
1132 m_l = u_e->m_list;
1133 while (m_l) {
1134 k++;
1135 m_l = m_l->next;
1136 }
1137 if (j != k)
1138 continue;
1139
1140 // compare all watchers
1141 w_l = new_entry->w_list;
1142 j = 0;
1143 while (w_l) {
1144 w = (struct ebt_u_watcher *)(w_l->w);
1145 w_l2 = u_e->w_list;
1146 while (w_l2 &&
1147 strcmp(w_l2->w->u.name, w->w->u.name))
1148 w_l2 = w_l2->next;
1149 if (!w_l2 || !w->compare(w->w, w_l2->w))
1150 goto letscontinue;
1151 j++;
1152 w_l = w_l->next;
1153 }
1154 k = 0;
1155 w_l = u_e->w_list;
1156 while (w_l) {
1157 k++;
1158 w_l = w_l->next;
1159 }
1160 if (j != k)
1161 continue;
1162 if (strcmp(t->t->u.name, u_e->t->u.name))
1163 continue;
1164 if (!t->compare(t->t, u_e->t))
1165 continue;
1166 return i;
1167 }
1168letscontinue:
1169 }
1170 return -1;
1171}
1172
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001173// execute command A or I
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001174static void add_rule(int rule_nr)
1175{
1176 int i, j;
1177 struct ebt_u_entry *u_e, *u_e2;
1178 unsigned short *cnt;
1179 struct ebt_u_match_list *m_l;
1180 struct ebt_u_watcher_list *w_l;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001181 struct ebt_u_entries *entries = to_chain(), *entries2;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001182
1183 if (rule_nr != -1) { // command -I
Bart De Schuymer60332e02002-06-23 08:01:47 +00001184 if (--rule_nr > entries->nentries)
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001185 print_error("rule nr too high: %d > %d", rule_nr + 1,
1186 entries->nentries + 1);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001187 } else
Bart De Schuymer60332e02002-06-23 08:01:47 +00001188 rule_nr = entries->nentries;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001189 // we're adding one rule
1190 replace.num_counters = replace.nentries;
1191 replace.nentries++;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001192 entries->nentries++;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001193
1194 // handle counter stuff
1195 // +1 for CNT_END
1196 if ( !(counterchanges = (unsigned short *)
1197 malloc((replace.nentries + 1) * sizeof(unsigned short))) )
1198 print_memory();
1199 cnt = counterchanges;
1200 for (i = 0; i < replace.selected_hook; i++) {
Bart De Schuymer60332e02002-06-23 08:01:47 +00001201 if (i < NF_BR_NUMHOOKS && !(replace.valid_hooks & (1 << i)))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001202 continue;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001203 entries2 = nr_to_chain(i);
1204 for (j = 0; j < entries2->nentries; j++) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001205 *cnt = CNT_NORM;
1206 cnt++;
1207 }
1208 }
1209 for (i = 0; i < rule_nr; i++) {
1210 *cnt = CNT_NORM;
1211 cnt++;
1212 }
1213 *cnt = CNT_ADD;
1214 cnt++;
1215 while (cnt != counterchanges + replace.nentries) {
1216 *cnt = CNT_NORM;
1217 cnt++;
1218 }
1219 *cnt = CNT_END;
1220
1221 // go to the right position in the chain
1222 u_e2 = NULL;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001223 u_e = entries->entries;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001224 for (i = 0; i < rule_nr; i++) {
1225 u_e2 = u_e;
1226 u_e = u_e->next;
1227 }
1228 // insert the rule
1229 if (u_e2)
1230 u_e2->next = new_entry;
1231 else
Bart De Schuymer60332e02002-06-23 08:01:47 +00001232 entries->entries = new_entry;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001233 new_entry->next = u_e;
1234
1235 // put the ebt_[match, watcher, target] pointers in place
1236 m_l = new_entry->m_list;
1237 while (m_l) {
1238 m_l->m = ((struct ebt_u_match *)m_l->m)->m;
1239 m_l = m_l->next;
1240 }
1241 w_l = new_entry->w_list;
1242 while (w_l) {
1243 w_l->w = ((struct ebt_u_watcher *)w_l->w)->w;
1244 w_l = w_l->next;
1245 }
1246 new_entry->t = ((struct ebt_u_target *)new_entry->t)->t;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001247
1248 // update the counter_offset of chains behind this one
1249 i = replace.selected_hook;
1250 while (1) {
1251 i++;
1252 entries = nr_to_chain(i);
1253 if (!entries) {
1254 if (i < NF_BR_NUMHOOKS)
1255 continue;
1256 else
1257 break;
1258 } else
1259 entries->counter_offset++;
1260 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001261}
1262
1263// execute command D
1264static void delete_rule(int rule_nr)
1265{
1266 int i, j, lentmp = 0;
1267 unsigned short *cnt;
1268 struct ebt_u_entry *u_e, *u_e2;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001269 struct ebt_u_entries *entries = to_chain(), *entries2;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001270
1271 if ( (i = check_rule_exists(rule_nr)) == -1 )
Bart De Schuymer60332e02002-06-23 08:01:47 +00001272 print_error("Sorry, rule does not exist");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001273
1274 // we're deleting a rule
1275 replace.num_counters = replace.nentries;
1276 replace.nentries--;
1277
1278 if (replace.nentries) {
1279 for (j = 0; j < replace.selected_hook; j++) {
Bart De Schuymer60332e02002-06-23 08:01:47 +00001280 if (j < NF_BR_NUMHOOKS &&
1281 !(replace.valid_hooks & (1 << j)))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001282 continue;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001283 entries2 = nr_to_chain(j);
1284 lentmp += entries2->nentries;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001285 }
1286 lentmp += i;
1287 // +1 for CNT_END
1288 if ( !(counterchanges = (unsigned short *)malloc(
1289 (replace.num_counters + 1) * sizeof(unsigned short))) )
1290 print_memory();
1291 cnt = counterchanges;
1292 for (j = 0; j < lentmp; j++) {
1293 *cnt = CNT_NORM;
1294 cnt++;
1295 }
1296 *cnt = CNT_DEL;
1297 cnt++;
1298 for (j = 0; j < replace.num_counters - lentmp; j++) {
1299 *cnt = CNT_NORM;
1300 cnt++;
1301 }
1302 *cnt = CNT_END;
1303 }
1304 else
1305 replace.num_counters = 0;
1306
1307 // go to the right position in the chain
1308 u_e2 = NULL;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001309 u_e = entries->entries;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001310 for (j = 0; j < i; j++) {
1311 u_e2 = u_e;
1312 u_e = u_e->next;
1313 }
1314
1315 // remove from the chain
1316 if (u_e2)
1317 u_e2->next = u_e->next;
1318 else
Bart De Schuymer60332e02002-06-23 08:01:47 +00001319 entries->entries = u_e->next;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001320
Bart De Schuymer60332e02002-06-23 08:01:47 +00001321 entries->nentries--;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001322 // free everything
1323 free_u_entry(u_e);
1324 free(u_e);
Bart De Schuymer60332e02002-06-23 08:01:47 +00001325 // update the counter_offset of chains behind this one
1326 i = replace.selected_hook;
1327 while (1) {
1328 i++;
1329 entries = nr_to_chain(i);
1330 if (!entries) {
1331 if (i < NF_BR_NUMHOOKS)
1332 continue;
1333 else
1334 break;
1335 } else
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001336 entries->counter_offset--;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001337 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001338}
1339
1340// execute command Z
Bart De Schuymer62423742002-07-14 19:06:20 +00001341static void zero_counters(int zerochain)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001342{
1343
1344 if (zerochain == -1) {
1345 // tell main() we don't update the counters
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001346 // this results in tricking the kernel to zero its counters,
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001347 // naively expecting userspace to update its counters. Muahahaha
1348 counterchanges = NULL;
1349 replace.num_counters = 0;
1350 } else {
1351 int i, j;
1352 unsigned short *cnt;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001353 struct ebt_u_entries *entries = nr_to_chain(zerochain), *e2;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001354
Bart De Schuymer60332e02002-06-23 08:01:47 +00001355 if (entries->nentries == 0)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001356 exit(0);
1357 counterchanges = (unsigned short *)
1358 malloc((replace.nentries + 1) * sizeof(unsigned short));
1359 if (!counterchanges)
1360 print_memory();
1361 cnt = counterchanges;
1362 for (i = 0; i < zerochain; i++) {
Bart De Schuymer60332e02002-06-23 08:01:47 +00001363 if (i < NF_BR_NUMHOOKS &&
1364 !(replace.valid_hooks & (1 << i)))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001365 continue;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001366 e2 = nr_to_chain(i);
1367 for (j = 0; j < e2->nentries; j++) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001368 *cnt = CNT_NORM;
1369 cnt++;
1370 }
1371 }
Bart De Schuymer60332e02002-06-23 08:01:47 +00001372 for (i = 0; i < entries->nentries; i++) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001373 *cnt = CNT_ZERO;
1374 cnt++;
1375 }
1376 while (cnt != counterchanges + replace.nentries) {
1377 *cnt = CNT_NORM;
1378 cnt++;
1379 }
1380 *cnt = CNT_END;
1381 }
1382}
1383
1384// list the database (optionally compiled into the kernel)
1385static void list_db()
1386{
1387 struct brdb_dbinfo nr;
1388 struct brdb_dbentry *db;
1389 char name[21];
1390 int i;
1391
1392 get_dbinfo(&nr);
1393
1394 // 0 : database disabled (-db n)
1395 if (!(nr.nentries))
1396 print_error("Database not present"
1397 " (disabled), try ebtables --db y");
1398 nr.nentries--;
1399 if (!nr.nentries) print_error("Database empty");
1400 if ( !(db = (struct brdb_dbentry *)
1401 malloc(nr.nentries * sizeof(struct brdb_dbentry))) )
1402 print_memory();
1403
1404 get_db(nr.nentries, db);
1405 printf("number of entries: %d\n", nr.nentries);
1406 for (i = 0; i < nr.nentries; i++) {
1407 printf(
1408 "%d:\n"
1409 "hook : %s\n"
1410 "in-if : %s\n"
1411 "out-if : %s\n"
1412 "protocol: ", i + 1, hooknames[db->hook], db->in, db->out);
1413 if (db->ethproto == IDENTIFY802_3)
1414 printf("802.2/802.3 STYLE LENGTH FIELD\n");
1415 else {
1416 if (number_to_name(ntohs(db->ethproto), name))
1417 printf("%x\n",ntohs(db->ethproto));
1418 else
1419 printf("%s\n", name);
1420 }
1421 db++;
1422 }
1423 exit(0);
1424}
1425
1426// handle db [dis,en]abling
1427static void allowdb(char yorn)
1428{
1429 __u16 decision;
1430
1431 if (yorn != 'y' && yorn != 'n')
1432 print_error("Option [y] or [n] needed");
1433
1434 if (yorn == 'y')
1435 decision = BRDB_DB;
1436 else
1437 decision = BRDB_NODB;
1438
1439 deliver_allowdb(&decision);
1440
1441 exit(0);
1442}
1443
Bart De Schuymer28bf6f62002-06-26 18:57:24 +00001444// 0 == success
1445// 1 == success, but for the special 'protocol' LENGTH
1446// -1 == failure
1447int name_to_number(char *name, __u16 *proto)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001448{
1449 FILE *ifp;
1450 char buffer[21], value[5], *bfr;
1451 unsigned short i;
1452
1453 if (!strcasecmp("LENGTH", name)) {
Bart De Schuymer28bf6f62002-06-26 18:57:24 +00001454 *proto = 0;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001455 new_entry->bitmask |= EBT_802_3;
1456 return 1;
1457 }
1458 if ( !(ifp = fopen(PROTOCOLFILE, "r")) )
1459 return -1;
1460 while (1) {
1461 if (get_a_line(buffer, value, ifp)) return -1;
1462 if (strcasecmp(buffer, name))
1463 continue;
1464 i = (unsigned short) strtol(value, &bfr, 16);
1465 if (*bfr != '\0')
1466 return -1;
Bart De Schuymer28bf6f62002-06-26 18:57:24 +00001467 *proto = i;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001468 fclose(ifp);
1469 return 0;
1470 }
1471 return -1;
1472}
1473
1474// put the mac address into 6 (ETH_ALEN) bytes
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001475int getmac_and_mask(char *from, char *to, char *mask)
1476{
1477 char *p;
1478 int i;
Bart De Schuymer41830412002-06-05 19:41:28 +00001479 struct ether_addr *addr;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001480
1481 if (strcasecmp(from, "Unicast") == 0) {
1482 memcpy(to, mac_type_unicast, ETH_ALEN);
1483 memcpy(mask, msk_type_unicast, ETH_ALEN);
1484 return 0;
1485 }
1486 if (strcasecmp(from, "Multicast") == 0) {
1487 memcpy(to, mac_type_multicast, ETH_ALEN);
1488 memcpy(mask, msk_type_multicast, ETH_ALEN);
1489 return 0;
1490 }
1491 if (strcasecmp(from, "Broadcast") == 0) {
1492 memcpy(to, mac_type_broadcast, ETH_ALEN);
1493 memcpy(mask, msk_type_broadcast, ETH_ALEN);
1494 return 0;
1495 }
1496 if ( (p = strrchr(from, '/')) != NULL) {
1497 *p = '\0';
Bart De Schuymer41830412002-06-05 19:41:28 +00001498 if (!(addr = ether_aton(p + 1)))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001499 return -1;
Bart De Schuymer41830412002-06-05 19:41:28 +00001500 memcpy(mask, addr, ETH_ALEN);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001501 } else
1502 memset(mask, 0xff, ETH_ALEN);
Bart De Schuymer41830412002-06-05 19:41:28 +00001503 if (!(addr = ether_aton(from)))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001504 return -1;
Bart De Schuymer41830412002-06-05 19:41:28 +00001505 memcpy(to, addr, ETH_ALEN);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001506 for (i = 0; i < ETH_ALEN; i++)
1507 to[i] &= mask[i];
1508 return 0;
1509}
1510
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001511// executes the final_check() function for all extensions used by the rule
Bart De Schuymer62423742002-07-14 19:06:20 +00001512static void do_final_checks(struct ebt_u_entry *e, struct ebt_u_entries *entries)
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +00001513{
1514 struct ebt_u_match_list *m_l;
1515 struct ebt_u_watcher_list *w_l;
1516 struct ebt_u_target *t;
1517 struct ebt_u_match *m;
1518 struct ebt_u_watcher *w;
1519
1520 m_l = e->m_list;
1521 w_l = e->w_list;
1522 while (m_l) {
1523 m = find_match(m_l->m->u.name);
1524 m->final_check(e, m_l->m, replace.name,
1525 entries->hook_mask, 1);
1526 m_l = m_l->next;
1527 }
1528 while (w_l) {
1529 w = find_watcher(w_l->w->u.name);
1530 w->final_check(e, w_l->w, replace.name,
1531 entries->hook_mask, 1);
1532 w_l = w_l->next;
1533 }
1534 t = find_target(e->t->u.name);
1535 t->final_check(e, e->t, replace.name,
1536 entries->hook_mask, 1);
1537}
1538
Bart De Schuymerb909f9b2002-06-26 18:35:31 +00001539// used for the -X command
Bart De Schuymer62423742002-07-14 19:06:20 +00001540static void check_for_references(int chain_nr)
Bart De Schuymerb909f9b2002-06-26 18:35:31 +00001541{
1542 int i = -1, j;
1543 struct ebt_u_entries *entries;
1544 struct ebt_u_entry *e;
1545
1546 while (1) {
1547 i++;
1548 entries = nr_to_chain(i);
1549 if (!entries) {
1550 if (i < NF_BR_NUMHOOKS)
1551 continue;
1552 else
1553 break;
1554 }
1555 e = entries->entries;
1556 j = 0;
1557 while (e) {
1558 j++;
1559 if (strcmp(e->t->u.name, EBT_STANDARD_TARGET)) {
1560 e = e->next;
1561 continue;
1562 }
1563 if (((struct ebt_standard_target *)e->t)->verdict == chain_nr)
1564 print_error("Can't delete the chain, it's referenced "
1565 "in chain %s, rule %d", entries->name, j);
1566 e = e->next;
1567 }
1568 }
1569}
1570
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001571int check_inverse(const char option[])
1572{
1573 if (strcmp(option, "!") == 0) {
1574 optind++;
1575 return 1;
1576 }
1577 return 0;
1578}
1579
1580void check_option(unsigned int *flags, unsigned int mask)
1581{
1582 if (*flags & mask)
1583 print_error("Multiple use of same option not allowed");
1584 *flags |= mask;
1585}
1586
1587#define OPT_COMMAND 0x01
1588#define OPT_TABLE 0x02
1589#define OPT_IN 0x04
1590#define OPT_OUT 0x08
1591#define OPT_JUMP 0x10
1592#define OPT_PROTOCOL 0x20
1593#define OPT_SOURCE 0x40
1594#define OPT_DEST 0x80
1595#define OPT_ZERO 0x100
1596#define OPT_LOGICALIN 0x200
1597#define OPT_LOGICALOUT 0x400
1598// the main thing
1599int main(int argc, char *argv[])
1600{
1601 char *buffer, allowbc = 'n';
1602 int c, i;
1603 // this special one for the -Z option (we can have -Z <this> -L <that>)
1604 int zerochain = -1;
Bart De Schuymerf8f8f292002-06-25 15:43:57 +00001605 int policy = 0;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001606 int rule_nr = -1;// used for -D chain number
1607 struct ebt_u_target *t;
1608 struct ebt_u_match *m;
1609 struct ebt_u_watcher *w;
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001610 struct ebt_u_match_list *m_l;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001611 struct ebt_u_watcher_list *w_l;
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001612 struct ebt_u_entries *entries;
Bart De Schuymerc8531032002-06-14 21:55:29 +00001613 const char *modprobe = NULL;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001614
1615 // initialize the table name, OPT_ flags, selected hook and command
1616 strcpy(replace.name, "filter");
1617 replace.flags = 0;
1618 replace.selected_hook = -1;
1619 replace.command = 'h';
Bart De Schuymer62423742002-07-14 19:06:20 +00001620 replace.filename = NULL;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001621
1622 new_entry = (struct ebt_u_entry *)malloc(sizeof(struct ebt_u_entry));
1623 if (!new_entry)
1624 print_memory();
1625 // put some sane values in our new entry
1626 initialize_entry(new_entry);
1627
Bart De Schuymer60332e02002-06-23 08:01:47 +00001628 // The scenario induced by this loop makes that:
Bart De Schuymer62423742002-07-14 19:06:20 +00001629 // '-t' ,'-M' and --atomic (if specified) have to come
1630 // before '-A' and the like
Bart De Schuymer60332e02002-06-23 08:01:47 +00001631
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001632 // getopt saves the day
1633 while ((c = getopt_long(argc, argv,
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001634 "-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 +00001635 switch (c) {
1636
1637 case 'A': // add a rule
1638 case 'D': // delete a rule
1639 case 'P': // define policy
1640 case 'I': // insert a rule
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001641 case 'N': // make a user defined chain
1642 case 'E': // rename chain
1643 case 'X': // delete chain
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001644 replace.command = c;
1645 if (replace.flags & OPT_COMMAND)
1646 print_error("Multiple commands not allowed");
1647 replace.flags |= OPT_COMMAND;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001648 if ( !(table = find_table(replace.name)) )
1649 print_error("Bad table name");
1650 // get the kernel's information
1651 if (get_table(&replace)) {
1652 ebtables_insmod("ebtables", modprobe);
1653 if (get_table(&replace))
1654 print_error("can't initialize ebtables "
1655 "table %s", replace.name);
1656 }
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001657 if (optarg[0] == '-')
1658 print_error("No chain name specified");
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001659 if (c == 'N') {
1660 struct ebt_u_chain_list *cl, **cl2;
1661
1662 if (get_hooknr(optarg) != -1)
1663 print_error("Chain %s already exists",
1664 optarg);
1665 if (find_target(optarg))
1666 print_error("Target with name %s exists"
1667 , optarg);
1668 if (strlen(optarg) >= EBT_CHAIN_MAXNAMELEN)
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001669 print_error("Chain name length can't exceed %d",
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001670 EBT_CHAIN_MAXNAMELEN - 1);
1671 cl = (struct ebt_u_chain_list *)
1672 malloc(sizeof(struct ebt_u_chain_list));
1673 if (!cl)
1674 print_memory();
1675 cl->next = NULL;
1676 cl->udc = (struct ebt_u_entries *)
1677 malloc(sizeof(struct ebt_u_entries));
1678 if (!cl->udc)
1679 print_memory();
1680 cl->udc->nentries = 0;
1681 cl->udc->policy = EBT_ACCEPT;
1682 cl->udc->counter_offset = replace.nentries;
1683 cl->udc->hook_mask = 0;
1684 strcpy(cl->udc->name, optarg);
1685 cl->udc->entries = NULL;
1686 cl->kernel_start = NULL;
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001687 // put the new chain at the end
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001688 cl2 = &replace.udc;
1689 while (*cl2)
1690 cl2 = &((*cl2)->next);
1691 *cl2 = cl;
1692 break;
1693 }
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001694 if ((replace.selected_hook = get_hooknr(optarg)) == -1)
1695 print_error("Chain %s doesn't exist", optarg);
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001696 if (c == 'E') {
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001697 if (optind >= argc || argv[optind][0] == '-')
1698 print_error("No new chain name specified");
1699 if (strlen(argv[optind]) >= EBT_CHAIN_MAXNAMELEN)
1700 print_error("Chain name len can't exceed %d",
1701 EBT_CHAIN_MAXNAMELEN - 1);
1702 if (get_hooknr(argv[optind]) != -1)
1703 print_error("Chain %s already exists",
1704 argv[optind]);
1705 entries = to_chain();
1706 strcpy(entries->name, argv[optind]);
1707 optind++;
1708 break;
1709 }
1710 if (c == 'X') {
1711 struct ebt_u_chain_list *cl, **cl2;
1712
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001713 if (replace.selected_hook < NF_BR_NUMHOOKS)
1714 print_error("You can't remove a standard chain");
Bart De Schuymerb909f9b2002-06-26 18:35:31 +00001715 // if the chain is referenced, don't delete it
1716 check_for_references(replace.selected_hook - NF_BR_NUMHOOKS);
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001717 flush_chains();
1718 entries = to_chain();
1719 if (replace.udc->udc == entries) {
1720 cl = replace.udc;
1721 replace.udc = replace.udc->next;
1722 free(cl->udc);
1723 free(cl);
1724 break;
1725 }
1726 cl2 = &(replace.udc);
1727 while ((*cl2)->next->udc != entries)
1728 cl2 = &((*cl2)->next);
1729 cl = (*cl2)->next;
1730 (*cl2)->next = (*cl2)->next->next;
1731 free(cl->udc);
1732 free(cl);
1733 break;
1734 }
1735
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001736 if (c == 'D' && optind < argc &&
1737 argv[optind][0] != '-') {
1738 rule_nr = strtol(argv[optind], &buffer, 10);
1739 if (*buffer != '\0' || rule_nr < 0)
1740 print_error("Problem with the "
1741 "specified rule number");
1742 optind++;
1743 }
1744 if (c == 'P') {
1745 if (optind >= argc)
1746 print_error("No policy specified");
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001747 policy = 0;
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001748 for (i = 0; i < NUM_STANDARD_TARGETS; i++)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001749 if (!strcmp(argv[optind],
1750 standard_targets[i])) {
Bart De Schuymer60332e02002-06-23 08:01:47 +00001751 policy = -i -1;
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001752 if (policy == EBT_CONTINUE)
1753 policy = 0;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001754 break;
1755 }
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001756 if (policy == 0)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001757 print_error("Wrong policy");
1758 optind++;
1759 }
1760 if (c == 'I') {
1761 if (optind >= argc)
1762 print_error("No rulenr for -I"
1763 " specified");
1764 rule_nr = strtol(argv[optind], &buffer, 10);
1765 if (*buffer != '\0' || rule_nr < 0)
1766 print_error("Problem with the specified"
1767 " rule number");
1768 optind++;
1769 }
1770 break;
1771
1772 case 'L': // list
1773 case 'F': // flush
1774 case 'Z': // zero counters
1775 if (c == 'Z') {
1776 if (replace.flags & OPT_ZERO)
1777 print_error("Multiple commands"
1778 " not allowed");
1779 if ( (replace.flags & OPT_COMMAND &&
1780 replace.command != 'L'))
1781 print_error("command -Z only allowed "
1782 "together with command -L");
1783 replace.flags |= OPT_ZERO;
1784 } else {
1785 replace.command = c;
1786 if (replace.flags & OPT_COMMAND)
1787 print_error("Multiple commands"
1788 " not allowed");
1789 replace.flags |= OPT_COMMAND;
1790 }
Bart De Schuymer60332e02002-06-23 08:01:47 +00001791 if ( !(table = find_table(replace.name)) )
1792 print_error("Bad table name");
1793 // get the kernel's information
1794 if (get_table(&replace)) {
1795 ebtables_insmod("ebtables", modprobe);
1796 if (get_table(&replace))
1797 print_error("can't initialize ebtables "
1798 "table %s", replace.name);
1799 }
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001800 i = -1;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001801 if (optarg) {
1802 if ( (i = get_hooknr(optarg)) == -1 )
1803 print_error("Bad chain");
1804 } else
1805 if (optind < argc && argv[optind][0] != '-') {
1806 if ((i = get_hooknr(argv[optind]))
1807 == -1)
1808 print_error("Bad chain");
1809 optind++;
1810 }
1811 if (i != -1) {
1812 if (c == 'Z')
1813 zerochain = i;
1814 else
1815 replace.selected_hook = i;
1816 }
1817 break;
1818
1819 case 'V': // version
1820 replace.command = 'V';
1821 if (replace.flags & OPT_COMMAND)
1822 print_error("Multiple commands not allowed");
1823 printf("%s, %s\n", prog_name, prog_version);
1824 exit(0);
1825
Bart De Schuymerc8531032002-06-14 21:55:29 +00001826 case 'M': // modprobe
Bart De Schuymer60332e02002-06-23 08:01:47 +00001827 if (replace.command != 'h')
1828 print_error("Please put the -M option earlier");
Bart De Schuymerc8531032002-06-14 21:55:29 +00001829 modprobe = optarg;
1830 break;
1831
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001832 case 'h': // help
1833 if (replace.flags & OPT_COMMAND)
1834 print_error("Multiple commands not allowed");
1835 replace.command = 'h';
1836 // All other arguments should be extension names
1837 while (optind < argc) {
1838 struct ebt_u_match *m;
1839 struct ebt_u_watcher *w;
1840
1841 if ((m = find_match(argv[optind])))
1842 add_match(m);
1843 else if ((w = find_watcher(argv[optind])))
1844 add_watcher(w);
1845 else {
1846 if (!(t = find_target(argv[optind])))
1847 print_error("Extension %s "
1848 "not found", argv[optind]);
1849 if (replace.flags & OPT_JUMP)
1850 print_error("Sorry, you can "
1851 "only see help for one "
1852 "target extension each time");
1853 replace.flags |= OPT_JUMP;
1854 new_entry->t =
1855 (struct ebt_entry_target *)t;
1856 }
1857 optind++;
1858 }
1859 break;
1860
1861 case 't': // table
Bart De Schuymer60332e02002-06-23 08:01:47 +00001862 if (replace.command != 'h')
1863 print_error("Please put the -t option first");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001864 check_option(&replace.flags, OPT_TABLE);
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001865 if (strlen(optarg) > EBT_TABLE_MAXNAMELEN - 1)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001866 print_error("Table name too long");
1867 strcpy(replace.name, optarg);
1868 break;
1869
1870 case 'i': // input interface
1871 case 2 : // logical input interface
1872 case 'o': // output interface
1873 case 3 : // logical output interface
1874 case 'j': // target
1875 case 'p': // net family protocol
1876 case 's': // source mac
1877 case 'd': // destination mac
1878 if ((replace.flags & OPT_COMMAND) == 0)
1879 print_error("No command specified");
1880 if ( replace.command != 'A' &&
1881 replace.command != 'D' && replace.command != 'I')
1882 print_error("Command and option do not match");
1883 if (c == 'i') {
1884 check_option(&replace.flags, OPT_IN);
1885 if (replace.selected_hook > 2 &&
1886 replace.selected_hook < NF_BR_BROUTING)
1887 print_error("Use in-interface only in "
1888 "INPUT, FORWARD, PREROUTING and"
1889 "BROUTING chains");
1890 if (check_inverse(optarg))
1891 new_entry->invflags |= EBT_IIN;
1892
1893 if (optind > argc)
1894 print_error("No in-interface "
1895 "specified");
1896 if (strlen(argv[optind - 1]) >= IFNAMSIZ)
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001897 print_error("Illegal interface length");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001898 strcpy(new_entry->in, argv[optind - 1]);
1899 break;
1900 }
1901 if (c == 2) {
1902 check_option(&replace.flags, OPT_LOGICALIN);
1903 if (replace.selected_hook > 2 &&
1904 replace.selected_hook < NF_BR_BROUTING)
1905 print_error("Use logical in-interface "
1906 "only in INPUT, FORWARD, "
1907 "PREROUTING and BROUTING chains");
1908 if (check_inverse(optarg))
1909 new_entry->invflags |= EBT_ILOGICALIN;
1910
1911 if (optind > argc)
1912 print_error("No logical in-interface "
1913 "specified");
1914 if (strlen(argv[optind - 1]) >= IFNAMSIZ)
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001915 print_error("Illegal interface length");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001916 strcpy(new_entry->logical_in, argv[optind - 1]);
1917 break;
1918 }
1919 if (c == 'o') {
1920 check_option(&replace.flags, OPT_OUT);
1921 if (replace.selected_hook < 2)
1922 print_error("Use out-interface only"
1923 " in OUTPUT, FORWARD and "
1924 "POSTROUTING chains");
1925 if (check_inverse(optarg))
1926 new_entry->invflags |= EBT_IOUT;
1927
1928 if (optind > argc)
1929 print_error("No out-interface "
1930 "specified");
1931
1932 if (strlen(argv[optind - 1]) >= IFNAMSIZ)
1933 print_error("Illegal interface "
1934 "length");
1935 strcpy(new_entry->out, argv[optind - 1]);
1936 break;
1937 }
1938 if (c == 3) {
1939 check_option(&replace.flags, OPT_LOGICALOUT);
1940 if (replace.selected_hook < 2)
1941 print_error("Use logical out-interface "
1942 "only in OUTPUT, FORWARD and "
1943 "POSTROUTING chains");
1944 if (check_inverse(optarg))
1945 new_entry->invflags |= EBT_ILOGICALOUT;
1946
1947 if (optind > argc)
1948 print_error("No logical out-interface "
1949 "specified");
1950
1951 if (strlen(argv[optind - 1]) >= IFNAMSIZ)
1952 print_error("Illegal interface "
1953 "length");
1954 strcpy(new_entry->logical_out,
1955 argv[optind - 1]);
1956 break;
1957 }
1958 if (c == 'j') {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001959 check_option(&replace.flags, OPT_JUMP);
1960 for (i = 0; i < NUM_STANDARD_TARGETS; i++)
1961 if (!strcmp(optarg,
1962 standard_targets[i])) {
1963 t = find_target(
1964 EBT_STANDARD_TARGET);
1965 ((struct ebt_standard_target *)
Bart De Schuymer60332e02002-06-23 08:01:47 +00001966 t->t)->verdict = -i - 1;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001967 break;
1968 }
Bart De Schuymer60332e02002-06-23 08:01:47 +00001969 if (-i - 1 == EBT_RETURN) {
1970 if (replace.selected_hook < NF_BR_NUMHOOKS)
1971 print_error("Return target"
1972 " only for user defined chains");
1973 }
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +00001974 if (i != NUM_STANDARD_TARGETS)
1975 break;
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001976 if ((i = get_hooknr(optarg)) != -1) {
1977 if (i < NF_BR_NUMHOOKS)
1978 print_error("don't jump"
1979 " to a standard chain");
1980 t = find_target(
1981 EBT_STANDARD_TARGET);
1982 ((struct ebt_standard_target *)
1983 t->t)->verdict = i - NF_BR_NUMHOOKS;
1984 break;
1985 }
1986 else {
1987 // must be an extension then
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001988 struct ebt_u_target *t;
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001989
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001990 t = find_target(optarg);
1991 // -j standard not allowed either
1992 if (!t || t ==
1993 (struct ebt_u_target *)new_entry->t)
1994 print_error("Illegal target "
1995 "name");
1996 new_entry->t =
1997 (struct ebt_entry_target *)t;
1998 }
1999 break;
2000 }
2001 if (c == 's') {
2002 check_option(&replace.flags, OPT_SOURCE);
2003 if (check_inverse(optarg))
2004 new_entry->invflags |= EBT_ISOURCE;
2005
2006 if (optind > argc)
2007 print_error("No source mac "
2008 "specified");
2009 if (getmac_and_mask(argv[optind - 1],
2010 new_entry->sourcemac, new_entry->sourcemsk))
2011 print_error("Problem with specified "
2012 "source mac");
2013 new_entry->bitmask |= EBT_SOURCEMAC;
2014 break;
2015 }
2016 if (c == 'd') {
2017 check_option(&replace.flags, OPT_DEST);
2018 if (check_inverse(optarg))
2019 new_entry->invflags |= EBT_IDEST;
2020
2021 if (optind > argc)
2022 print_error("No destination mac "
2023 "specified");
2024 if (getmac_and_mask(argv[optind - 1],
2025 new_entry->destmac, new_entry->destmsk))
2026 print_error("Problem with specified "
2027 "destination mac");
2028 new_entry->bitmask |= EBT_DESTMAC;
2029 break;
2030 }
2031 check_option(&replace.flags, OPT_PROTOCOL);
2032 if (check_inverse(optarg))
2033 new_entry->invflags |= EBT_IPROTO;
2034
2035 if (optind > argc)
2036 print_error("No protocol specified");
2037 new_entry->bitmask &= ~((unsigned int)EBT_NOPROTO);
2038 i = strtol(argv[optind - 1], &buffer, 16);
2039 if (*buffer == '\0' && (i < 0 || i > 0xFFFF))
2040 print_error("Problem with the specified "
2041 "protocol");
2042 new_entry->ethproto = i;
Bart De Schuymer28bf6f62002-06-26 18:57:24 +00002043 if (*buffer != '\0') {
2044 if ((i = name_to_number(argv[optind - 1],
2045 &new_entry->ethproto)) == -1)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002046 print_error("Problem with the specified"
2047 " protocol");
Bart De Schuymer28bf6f62002-06-26 18:57:24 +00002048 if (i == 1)
2049 new_entry->bitmask |= EBT_802_3;
2050 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002051 if (new_entry->ethproto < 1536 &&
2052 !(new_entry->bitmask & EBT_802_3))
2053 print_error("Sorry, protocols have values above"
2054 " or equal to 1536 (0x0600)");
2055 break;
2056
2057 case 'b': // allow database?
2058 if (replace.flags & OPT_COMMAND)
2059 print_error("Multiple commands not allowed");
2060 replace.command = c;
2061 allowbc = *optarg;
2062 break;
2063
Bart De Schuymer9af14f92002-07-10 20:49:10 +00002064 case 4 : // Lc
2065 check_option(&replace.flags, LIST_C);
2066 if (replace.selected_hook == DATABASEHOOKNR)
2067 print_error("--Lc not valid for listing"
2068 " the database");
2069 if (replace.command != 'L')
2070 print_error("Use --Lc with -L");
2071 if (replace.flags & LIST_X)
2072 print_error("--Lx not compatible with --Lc");
2073 replace.flags |= LIST_C;
2074 break;
2075 case 5 : // Ln
2076 check_option(&replace.flags, LIST_N);
2077 if (replace.selected_hook == DATABASEHOOKNR)
2078 print_error("--Ln not valid for listing"
2079 " the database");
2080 if (replace.command != 'L')
2081 print_error("Use --Ln with -L");
2082 if (replace.flags & LIST_X)
2083 print_error("--Lx not compatible with --Ln");
2084 replace.flags |= LIST_N;
2085 break;
2086 case 6 : // Lx
2087 check_option(&replace.flags, LIST_X);
2088 if (replace.selected_hook == DATABASEHOOKNR)
2089 print_error("--Lx not valid for listing"
2090 " the database");
2091 if (replace.command != 'L')
2092 print_error("Use --Lx with -L");
2093 if (replace.flags & LIST_C)
2094 print_error("--Lx not compatible with --Lc");
2095 if (replace.flags & LIST_N)
2096 print_error("--Lx not compatible with --Ln");
2097 replace.flags |= LIST_X;
2098 break;
Bart De Schuymer62423742002-07-14 19:06:20 +00002099 case 8 : // atomic-commit
2100 replace.command = c;
2101 if (replace.flags & OPT_COMMAND)
2102 print_error("Multiple commands not allowed");
2103 replace.flags |= OPT_COMMAND;
2104 replace.filename = (char *)malloc(strlen(optarg) + 1);
2105 strcpy(replace.filename, optarg);
2106 // get the information from the file
2107 get_table(&replace);
2108 replace.num_counters = 0;
2109 free(replace.filename);
2110 replace.filename = NULL;
2111 break;
2112 case 7 : // atomic-init
2113 case 10: // atomic-save
2114 replace.command = c;
2115 if (replace.flags & OPT_COMMAND)
2116 print_error("Multiple commands not allowed");
2117 replace.flags |= OPT_COMMAND;
2118 if ( !(table = find_table(replace.name)) )
2119 print_error("Bad table name");
2120 if (get_table(&replace)) {
2121 ebtables_insmod("ebtables", modprobe);
2122 if (get_table(&replace))
2123 print_error("can't initialize ebtables "
2124 "table %s", replace.name);
2125 }
2126 case 9 : // atomic
2127 replace.filename = (char *)malloc(strlen(optarg) + 1);
2128 strcpy(replace.filename, optarg);
2129 break;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002130
Bart De Schuymer9af14f92002-07-10 20:49:10 +00002131 default:
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002132 // is it a target option?
2133 t = (struct ebt_u_target *)new_entry->t;
2134 if ((t->parse(c - t->option_offset, argv, argc,
2135 new_entry, &t->flags, &t->t)))
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00002136 goto check_extension;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002137
2138 // is it a match_option?
2139 for (m = matches; m; m = m->next)
2140 if (m->parse(c - m->option_offset, argv,
2141 argc, new_entry, &m->flags, &m->m))
2142 break;
2143
2144 if (m != NULL) {
2145 if (m->used == 0)
2146 add_match(m);
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00002147 goto check_extension;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002148 }
2149
2150 // is it a watcher option?
2151 for (w = watchers; w; w = w->next)
2152 if (w->parse(c-w->option_offset, argv,
2153 argc, new_entry, &w->flags, &w->w))
2154 break;
2155
2156 if (w == NULL)
2157 print_error("Unknown argument");
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00002158 if (w->used == 0)
2159 add_watcher(w);
2160check_extension:
Bart De Schuymer60332e02002-06-23 08:01:47 +00002161 if (replace.command != 'A' && replace.command != 'I' &&
2162 replace.command != 'D')
2163 print_error("extensions only for -A, -I and -D");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002164 }
2165 }
2166
Bart De Schuymer25c741d2002-06-23 18:54:34 +00002167 if ( !table && !(table = find_table(replace.name)) )
2168 print_error("Bad table name");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002169 // database stuff before ebtables stuff
2170 if (replace.command == 'b')
2171 allowdb(allowbc);
2172 if (replace.command == 'L' && replace.selected_hook == DATABASEHOOKNR)
2173 list_db();
2174
2175 if ( (replace.flags & OPT_COMMAND) && replace.command != 'L' &&
2176 replace.flags & OPT_ZERO )
2177 print_error("Command -Z only allowed together with command -L");
2178
2179 if (replace.command == 'A' || replace.command == 'I' ||
2180 replace.command == 'D') {
2181 if (replace.selected_hook == -1)
2182 print_error("Not enough information");
2183 }
2184
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002185 // do this after parsing everything, so we can print specific info
2186 if (replace.command == 'h' && !(replace.flags & OPT_ZERO))
2187 print_help();
2188
2189 // do the final checks
Bart De Schuymer60332e02002-06-23 08:01:47 +00002190 if (replace.command == 'A' || replace.command == 'I' ||
2191 replace.command == 'D') {
2192 // this will put the hook_mask right for the chains
2193 check_for_loops();
2194 entries = to_chain();
2195 m_l = new_entry->m_list;
2196 w_l = new_entry->w_list;
2197 t = (struct ebt_u_target *)new_entry->t;
2198 while (m_l) {
2199 m = (struct ebt_u_match *)(m_l->m);
2200 m->final_check(new_entry, m->m, replace.name,
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +00002201 entries->hook_mask, 0);
Bart De Schuymer60332e02002-06-23 08:01:47 +00002202 m_l = m_l->next;
2203 }
2204 while (w_l) {
2205 w = (struct ebt_u_watcher *)(w_l->w);
2206 w->final_check(new_entry, w->w, replace.name,
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +00002207 entries->hook_mask, 0);
Bart De Schuymer60332e02002-06-23 08:01:47 +00002208 w_l = w_l->next;
2209 }
2210 t->final_check(new_entry, t->t, replace.name,
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +00002211 entries->hook_mask, 0);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002212 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002213 // so, the extensions can work with the host endian
2214 // the kernel does not have to do this ofcourse
2215 new_entry->ethproto = htons(new_entry->ethproto);
2216
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002217 if (replace.command == 'P')
2218 change_policy(policy);
2219 else if (replace.command == 'L') {
2220 list_rules();
2221 if (replace.flags & OPT_ZERO)
2222 zero_counters(zerochain);
2223 else
2224 exit(0);
2225 }
2226 if (replace.flags & OPT_ZERO)
2227 zero_counters(zerochain);
Bart De Schuymer1ab41562002-06-23 17:09:54 +00002228 else if (replace.command == 'F') {
2229 if (flush_chains() == -1)
2230 exit(0);
2231 } else if (replace.command == 'A' || replace.command == 'I') {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002232 add_rule(rule_nr);
Bart De Schuymer1ab41562002-06-23 17:09:54 +00002233 check_for_loops();
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +00002234 // do the final_check(), for all entries
2235 // needed when adding a rule that has a chain target
2236 i = -1;
2237 while (1) {
2238 struct ebt_u_entry *e;
2239
2240 i++;
2241 entries = nr_to_chain(i);
2242 if (!entries) {
2243 if (i < NF_BR_NUMHOOKS)
2244 continue;
2245 else
2246 break;
2247 }
2248 e = entries->entries;
2249 while (e) {
2250 // userspace extensions use host endian
2251 e->ethproto = ntohs(e->ethproto);
2252 do_final_checks(e, entries);
2253 e->ethproto = htons(e->ethproto);
2254 e = e->next;
2255 }
2256 }
Bart De Schuymer1ab41562002-06-23 17:09:54 +00002257 } else if (replace.command == 'D')
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002258 delete_rule(rule_nr);
Bart De Schuymer62423742002-07-14 19:06:20 +00002259 // commands -N, -E, -X, --atomic-commit fall through
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002260
2261 if (table->check)
2262 table->check(&replace);
2263
2264 deliver_table(&replace);
2265
2266 if (counterchanges)
2267 deliver_counters(&replace, counterchanges);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002268 return 0;
2269}