blob: a8d2202301cdcd08f0edf52302a2bf3da247aab2 [file] [log] [blame]
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001/*
2 * ebtables.c, v2.0 April 2002
3 *
4 * Author: Bart De Schuymer
5 *
6 * This code is stongly inspired on the iptables code which is
7 * Copyright (C) 1999 Paul `Rusty' Russell & Michael J. Neuling
8 *
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License as
11 * published by the Free Software Foundation; either version 2 of the
12 * License, or (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 */
23
24#include <getopt.h>
25#include <string.h>
26#include <errno.h>
27#include <stdio.h>
28#include <stdlib.h>
29#include <sys/socket.h>
30#include <sys/types.h>
31#include <linux/netfilter_bridge/ebtables.h>
32#include <linux/br_db.h> // the database
33#include <netinet/in.h>
Bart De Schuymer41830412002-06-05 19:41:28 +000034#include <netinet/ether.h>
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000035#include <asm/types.h>
36#include "include/ebtables_u.h"
Bart De Schuymerc8531032002-06-14 21:55:29 +000037#include <unistd.h>
38#include <fcntl.h>
39#include <sys/wait.h>
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000040
41// here are the number-name correspondences kept for the ethernet
42// frame type field
43#define PROTOCOLFILE "/etc/ethertypes"
44
Bart De Schuymerc8531032002-06-14 21:55:29 +000045#ifndef PROC_SYS_MODPROBE
46#define PROC_SYS_MODPROBE "/proc/sys/kernel/modprobe"
47#endif
48
Bart De Schuymer60332e02002-06-23 08:01:47 +000049#define DATABASEHOOKNR -2
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000050#define DATABASEHOOKNAME "DB"
51
52static char *prog_name = PROGNAME;
53static char *prog_version = PROGVERSION;
Bart De Schuymer60332e02002-06-23 08:01:47 +000054char *hooknames[NF_BR_NUMHOOKS] =
55{
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000056 [NF_BR_PRE_ROUTING]"PREROUTING",
57 [NF_BR_LOCAL_IN]"INPUT",
58 [NF_BR_FORWARD]"FORWARD",
59 [NF_BR_LOCAL_OUT]"OUTPUT",
60 [NF_BR_POST_ROUTING]"POSTROUTING",
61 [NF_BR_BROUTING]"BROUTING"
62};
63
64// default command line options
Bart De Schuymer8d1d8942002-07-15 20:09:09 +000065// do not mess around with the already assigned numbers unless
66// you know what you are doing
Bart De Schuymer62423742002-07-14 19:06:20 +000067static struct option ebt_original_options[] =
68{
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000069 { "append" , required_argument, 0, 'A' },
70 { "insert" , required_argument, 0, 'I' },
71 { "delete" , required_argument, 0, 'D' },
72 { "list" , optional_argument, 0, 'L' },
Bart De Schuymer9af14f92002-07-10 20:49:10 +000073 { "Lc" , no_argument , 0, 4 },
74 { "Ln" , no_argument , 0, 5 },
75 { "Lx" , no_argument , 0, 6 },
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000076 { "zero" , optional_argument, 0, 'Z' },
77 { "flush" , optional_argument, 0, 'F' },
78 { "policy" , required_argument, 0, 'P' },
79 { "in-interface" , required_argument, 0, 'i' },
80 { "in-if" , required_argument, 0, 'i' },
81 { "logical-in" , required_argument, 0, 2 },
82 { "logical-out" , required_argument, 0, 3 },
83 { "out-interface" , required_argument, 0, 'o' },
84 { "out-if" , required_argument, 0, 'o' },
85 { "version" , no_argument , 0, 'V' },
86 { "help" , no_argument , 0, 'h' },
87 { "jump" , required_argument, 0, 'j' },
88 { "proto" , required_argument, 0, 'p' },
89 { "protocol" , required_argument, 0, 'p' },
90 { "db" , required_argument, 0, 'b' },
91 { "source" , required_argument, 0, 's' },
92 { "src" , required_argument, 0, 's' },
93 { "destination" , required_argument, 0, 'd' },
94 { "dst" , required_argument, 0, 'd' },
95 { "table" , required_argument, 0, 't' },
Bart De Schuymerc8531032002-06-14 21:55:29 +000096 { "modprobe" , required_argument, 0, 'M' },
Bart De Schuymer1ab41562002-06-23 17:09:54 +000097 { "new-chain" , required_argument, 0, 'N' },
98 { "rename-chain" , required_argument, 0, 'E' },
99 { "delete-chain" , required_argument, 0, 'X' },
Bart De Schuymer62423742002-07-14 19:06:20 +0000100 { "atomic-init" , required_argument, 0, 7 },
Bart De Schuymer62423742002-07-14 19:06:20 +0000101 { "atomic-commit" , required_argument, 0, 8 },
102 { "atomic" , required_argument, 0, 9 },
103 { "atomic-save" , required_argument, 0, 10 },
Bart De Schuymer8d1d8942002-07-15 20:09:09 +0000104 { "init-table" , no_argument , 0, 11 },
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000105 { 0 }
106};
107
108static struct option *ebt_options = ebt_original_options;
109
110// yup, all the possible target names
Bart De Schuymer62423742002-07-14 19:06:20 +0000111char* standard_targets[NUM_STANDARD_TARGETS] =
112{
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000113 "ACCEPT",
114 "DROP",
115 "CONTINUE",
Bart De Schuymer60332e02002-06-23 08:01:47 +0000116 "RETURN",
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000117};
118
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000119unsigned char mac_type_unicast[ETH_ALEN] = {0,0,0,0,0,0};
120unsigned char msk_type_unicast[ETH_ALEN] = {1,0,0,0,0,0};
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000121unsigned char mac_type_multicast[ETH_ALEN] = {1,0,0,0,0,0};
122unsigned char msk_type_multicast[ETH_ALEN] = {1,0,0,0,0,0};
123unsigned char mac_type_broadcast[ETH_ALEN] = {255,255,255,255,255,255};
124unsigned char msk_type_broadcast[ETH_ALEN] = {255,255,255,255,255,255};
125
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000126// 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
Bart De Schuymerbbca3202002-06-05 18:55:44 +0000414// helper function: processes a line of data from the file /etc/ethertypes
Bart De Schuymer62423742002-07-14 19:06:20 +0000415static int get_a_line(char *buffer, char *value, FILE *ifp)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000416{
Bart De Schuymerf662ce52002-07-19 18:40:55 +0000417 char line[80], *p;
418 const char delim[] = " \t\n";
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000419
Bart De Schuymerf662ce52002-07-19 18:40:55 +0000420 while (fgets(line, sizeof(line), ifp)) {
421 p = strtok(line, delim);
422 if (!p || p[0] == '#')
423 continue;
424 if (strlen(p) > 20)
425 continue;
426 strcpy(buffer, p);
427 p = strtok(NULL, delim);
428 if (!p || strlen(p) > 10)
429 continue;
430 strcpy(value, p);
431 return 0;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000432 }
Bart De Schuymerf662ce52002-07-19 18:40:55 +0000433 return -1;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000434}
435
Bart De Schuymerb909f9b2002-06-26 18:35:31 +0000436// translate a hexadecimal number to a protocol name, parsing /etc/ethertypes
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000437// returns 0 on success
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000438int number_to_name(unsigned short proto, char *name)
439{
440 FILE *ifp;
Bart De Schuymerf662ce52002-07-19 18:40:55 +0000441 char buffer[21], value[11], *bfr;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000442 unsigned short i;
443
444 if ( !(ifp = fopen(PROTOCOLFILE, "r")) )
445 return -1;
446 while (1) {
447 if (get_a_line(buffer, value, ifp)) {
448 fclose(ifp);
449 return -1;
450 }
451 i = (unsigned short) strtol(value, &bfr, 16);
452 if (*bfr != '\0' || i != proto)
453 continue;
454 strcpy(name, buffer);
455 fclose(ifp);
456 return 0;
457 }
458}
459
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000460// we use replace.flags, so we can't use the following values:
461// 0x01 == OPT_COMMAND, 0x02 == OPT_TABLE, 0x100 == OPT_ZERO
462#define LIST_N 0x04
463#define LIST_C 0x08
464#define LIST_X 0x10
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000465// helper function for list_rules()
Bart De Schuymer60332e02002-06-23 08:01:47 +0000466static void list_em(struct ebt_u_entries *entries)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000467{
468 int i, j, space = 0, digits;
469 struct ebt_u_entry *hlp;
470 struct ebt_u_match_list *m_l;
471 struct ebt_u_watcher_list *w_l;
472 struct ebt_u_match *m;
473 struct ebt_u_watcher *w;
474 struct ebt_u_target *t;
475 char name[21];
476
Bart De Schuymer60332e02002-06-23 08:01:47 +0000477 hlp = entries->entries;
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000478 if (replace.flags & LIST_X && entries->policy != EBT_ACCEPT) {
479 printf("ebtables -t %s -P %s %s\n", replace.name,
480 entries->name, standard_targets[-entries->policy - 1]);
481 } else if (!(replace.flags & LIST_X)) {
482 printf("\nBridge chain: %s\nPolicy: %s\n", entries->name,
483 standard_targets[-entries->policy - 1]);
484 printf("nr. of entries: %d \n", entries->nentries);
485 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000486
Bart De Schuymer60332e02002-06-23 08:01:47 +0000487 i = entries->nentries;
Bart De Schuymerf8f8f292002-06-25 15:43:57 +0000488 while (i > 9) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000489 space++;
490 i /= 10;
491 }
492
Bart De Schuymer60332e02002-06-23 08:01:47 +0000493 for (i = 0; i < entries->nentries; i++) {
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000494 if (replace.flags & LIST_N) {
495 digits = 0;
496 // A little work to get nice rule numbers.
497 j = i + 1;
498 while (j > 9) {
499 digits++;
500 j /= 10;
501 }
502 for (j = 0; j < space - digits; j++)
503 printf(" ");
504 printf("%d. ", i + 1);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000505 }
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000506 if (replace.flags & LIST_X)
507 printf("ebtables -t %s -A %s ",
508 replace.name, entries->name);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000509
510 // Don't print anything about the protocol if no protocol was
511 // specified, obviously this means any protocol will do.
512 if (!(hlp->bitmask & EBT_NOPROTO)) {
Bart De Schuymer60332e02002-06-23 08:01:47 +0000513 printf("-p ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000514 if (hlp->invflags & EBT_IPROTO)
515 printf("! ");
516 if (hlp->bitmask & EBT_802_3)
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000517 printf("Length ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000518 else {
519 if (number_to_name(ntohs(hlp->ethproto), name))
Bart De Schuymer60332e02002-06-23 08:01:47 +0000520 printf("0x%x ", ntohs(hlp->ethproto));
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000521 else
Bart De Schuymer60332e02002-06-23 08:01:47 +0000522 printf("%s ", name);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000523 }
524 }
525 if (hlp->bitmask & EBT_SOURCEMAC) {
526 char hlpmsk[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
527
Bart De Schuymer60332e02002-06-23 08:01:47 +0000528 printf("-s ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000529 if (hlp->invflags & EBT_ISOURCE)
530 printf("! ");
531 if (!memcmp(hlp->sourcemac, mac_type_unicast, 6) &&
532 !memcmp(hlp->sourcemsk, msk_type_unicast, 6)) {
533 printf("Unicast");
534 goto endsrc;
535 }
536 if (!memcmp(hlp->sourcemac, mac_type_multicast, 6) &&
537 !memcmp(hlp->sourcemsk, msk_type_multicast, 6)) {
538 printf("Multicast");
539 goto endsrc;
540 }
541 if (!memcmp(hlp->sourcemac, mac_type_broadcast, 6) &&
542 !memcmp(hlp->sourcemsk, msk_type_broadcast, 6)) {
543 printf("Broadcast");
544 goto endsrc;
545 }
Bart De Schuymer41830412002-06-05 19:41:28 +0000546 printf("%s", ether_ntoa((struct ether_addr *)
547 hlp->sourcemac));
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000548 if (memcmp(hlp->sourcemsk, hlpmsk, 6)) {
549 printf("/");
Bart De Schuymer41830412002-06-05 19:41:28 +0000550 printf("%s", ether_ntoa((struct ether_addr *)
551 hlp->sourcemsk));
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000552 }
553endsrc:
Bart De Schuymer60332e02002-06-23 08:01:47 +0000554 printf(" ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000555 }
556 if (hlp->bitmask & EBT_DESTMAC) {
557 char hlpmsk[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
558
Bart De Schuymer60332e02002-06-23 08:01:47 +0000559 printf("-d ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000560 if (hlp->invflags & EBT_IDEST)
561 printf("! ");
562 if (!memcmp(hlp->destmac, mac_type_unicast, 6) &&
563 !memcmp(hlp->destmsk, msk_type_unicast, 6)) {
564 printf("Unicast");
565 goto enddst;
566 }
567 if (!memcmp(hlp->destmac, mac_type_multicast, 6) &&
568 !memcmp(hlp->destmsk, msk_type_multicast, 6)) {
569 printf("Multicast");
570 goto enddst;
571 }
572 if (!memcmp(hlp->destmac, mac_type_broadcast, 6) &&
573 !memcmp(hlp->destmsk, msk_type_broadcast, 6)) {
574 printf("Broadcast");
575 goto enddst;
576 }
Bart De Schuymer41830412002-06-05 19:41:28 +0000577 printf("%s", ether_ntoa((struct ether_addr *)
578 hlp->destmac));
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000579 if (memcmp(hlp->destmsk, hlpmsk, 6)) {
580 printf("/");
Bart De Schuymer41830412002-06-05 19:41:28 +0000581 printf("%s", ether_ntoa((struct ether_addr *)
582 hlp->destmsk));
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000583 }
584enddst:
Bart De Schuymer60332e02002-06-23 08:01:47 +0000585 printf(" ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000586 }
587 if (hlp->in[0] != '\0') {
Bart De Schuymer60332e02002-06-23 08:01:47 +0000588 printf("-i ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000589 if (hlp->invflags & EBT_IIN)
590 printf("! ");
Bart De Schuymer60332e02002-06-23 08:01:47 +0000591 printf("%s ", hlp->in);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000592 }
593 if (hlp->logical_in[0] != '\0') {
Bart De Schuymer60332e02002-06-23 08:01:47 +0000594 printf("--logical-in ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000595 if (hlp->invflags & EBT_ILOGICALIN)
596 printf("! ");
Bart De Schuymer60332e02002-06-23 08:01:47 +0000597 printf("%s ", hlp->logical_in);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000598 }
599 if (hlp->logical_out[0] != '\0') {
Bart De Schuymer60332e02002-06-23 08:01:47 +0000600 printf("--logical-out ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000601 if (hlp->invflags & EBT_ILOGICALOUT)
602 printf("! ");
Bart De Schuymerb3d8f262002-07-07 14:26:15 +0000603 printf("%s ", hlp->logical_out);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000604 }
605 if (hlp->out[0] != '\0') {
Bart De Schuymer60332e02002-06-23 08:01:47 +0000606 printf("-o ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000607 if (hlp->invflags & EBT_IOUT)
608 printf("! ");
Bart De Schuymerb3d8f262002-07-07 14:26:15 +0000609 printf("%s ", hlp->out);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000610 }
611
612 m_l = hlp->m_list;
613 while (m_l) {
614 m = find_match(m_l->m->u.name);
615 if (!m)
616 print_bug("Match not found");
617 m->print(hlp, m_l->m);
618 m_l = m_l->next;
619 }
620 w_l = hlp->w_list;
621 while (w_l) {
622 w = find_watcher(w_l->w->u.name);
623 if (!w)
624 print_bug("Watcher not found");
625 w->print(hlp, w_l->w);
626 w_l = w_l->next;
627 }
628
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000629 printf("-j ");
630 if (strcmp(hlp->t->u.name, EBT_STANDARD_TARGET))
631 printf("%s ", hlp->t->u.name);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000632 t = find_target(hlp->t->u.name);
633 if (!t)
634 print_bug("Target not found");
635 t->print(hlp, hlp->t);
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000636 if (replace.flags & LIST_C)
637 printf(", count = %llu",
638 replace.counters[entries->counter_offset + i].pcnt);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000639 printf("\n");
640 hlp = hlp->next;
641 }
642}
643
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000644struct ebt_u_entries *nr_to_chain(int nr)
Bart De Schuymer60332e02002-06-23 08:01:47 +0000645{
646 if (nr == -1)
647 return NULL;
648 if (nr < NF_BR_NUMHOOKS)
649 return replace.hook_entry[nr];
650 else {
651 int i;
652 struct ebt_u_chain_list *cl = replace.udc;
653
654 i = nr - NF_BR_NUMHOOKS;
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000655 while (i > 0 && cl) {
Bart De Schuymer60332e02002-06-23 08:01:47 +0000656 cl = cl->next;
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000657 i--;
658 }
Bart De Schuymer60332e02002-06-23 08:01:47 +0000659 if (cl)
660 return cl->udc;
661 else
662 return NULL;
663 }
664}
665
666static struct ebt_u_entries *to_chain()
667{
668 return nr_to_chain(replace.selected_hook);
669}
670
671struct ebt_u_stack
672{
673 int chain_nr;
674 int n;
675 struct ebt_u_entry *e;
676 struct ebt_u_entries *entries;
677};
678
Bart De Schuymer62423742002-07-14 19:06:20 +0000679static void check_for_loops()
Bart De Schuymer60332e02002-06-23 08:01:47 +0000680{
681 int chain_nr , i, j , k, sp = 0, verdict;
682 struct ebt_u_entries *entries, *entries2;
683 struct ebt_u_stack *stack = NULL;
684 struct ebt_u_entry *e;
685
686 i = -1;
687 // initialize hook_mask to 0
688 while (1) {
689 i++;
690 if (i < NF_BR_NUMHOOKS && !(replace.valid_hooks & (1 << i)))
691 continue;
692 entries = nr_to_chain(i);
693 if (!entries)
694 break;
695 entries->hook_mask = 0;
696 }
697 if (i > NF_BR_NUMHOOKS) {
698 stack = (struct ebt_u_stack *)malloc((i - NF_BR_NUMHOOKS) *
699 sizeof(struct ebt_u_stack));
700 if (!stack)
701 print_memory();
702 }
703
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000704 // check for loops, starting from every base chain
Bart De Schuymer60332e02002-06-23 08:01:47 +0000705 for (i = 0; i < NF_BR_NUMHOOKS; i++) {
706 if (!(replace.valid_hooks & (1 << i)))
707 continue;
708 entries = nr_to_chain(i);
709 entries->hook_mask = (1 << i);
710 chain_nr = i;
711
712 e = entries->entries;
713 for (j = 0; j < entries->nentries; j++) {
714 if (strcmp(e->t->u.name, EBT_STANDARD_TARGET))
715 goto letscontinue;
716 verdict = ((struct ebt_standard_target *)(e->t))->verdict;
717 if (verdict < 0)
718 goto letscontinue;
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000719 entries2 = nr_to_chain(verdict + NF_BR_NUMHOOKS);
Bart De Schuymer60332e02002-06-23 08:01:47 +0000720 entries2->hook_mask |= entries->hook_mask;
721 // now see if we've been here before
722 for (k = 0; k < sp; k++)
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000723 if (stack[k].chain_nr == verdict + NF_BR_NUMHOOKS)
Bart De Schuymer1a0a9c32002-06-24 21:10:16 +0000724 print_error("Loop from chain %s to chain %s",
725 nr_to_chain(chain_nr)->name, nr_to_chain(stack[k].chain_nr)->name);
Bart De Schuymer60332e02002-06-23 08:01:47 +0000726 // jump to the chain, make sure we know how to get back
727 stack[sp].chain_nr = chain_nr;
728 stack[sp].n = j;
729 stack[sp].entries = entries;
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000730 stack[sp].e = e;
731 sp++;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000732 j = -1;
733 e = entries2->entries;
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000734 chain_nr = verdict + NF_BR_NUMHOOKS;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000735 entries = entries2;
736 continue;
737letscontinue:
738 e = e->next;
739 }
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000740 // we are at the end of a standard chain
Bart De Schuymer60332e02002-06-23 08:01:47 +0000741 if (sp == 0)
742 continue;
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000743 // go back to the chain one level higher
Bart De Schuymer60332e02002-06-23 08:01:47 +0000744 sp--;
745 j = stack[sp].n;
746 chain_nr = stack[sp].chain_nr;
747 e = stack[sp].e;
748 entries = stack[sp].entries;
749 goto letscontinue;
750 }
751 free(stack);
752 return;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000753}
754
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000755// parse the chain name and return the corresponding nr
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000756// returns -1 on failure
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000757int get_hooknr(char* arg)
758{
759 int i;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000760 struct ebt_u_chain_list *cl = replace.udc;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000761
762 // database is special case (not really a chain)
763 if (!strcmp(arg, DATABASEHOOKNAME))
764 return DATABASEHOOKNR;
765
Bart De Schuymer60332e02002-06-23 08:01:47 +0000766 for (i = 0; i < NF_BR_NUMHOOKS; i++) {
767 if (!(replace.valid_hooks & (1 << i)))
768 continue;
769 if (!strcmp(arg, replace.hook_entry[i]->name))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000770 return i;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000771 }
772 while(cl) {
773 if (!strcmp(arg, cl->udc->name))
774 return i;
775 i++;
776 cl = cl->next;
777 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000778 return -1;
779}
780
781// yup, print out help
Bart De Schuymer62423742002-07-14 19:06:20 +0000782static void print_help()
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000783{
784 struct ebt_u_match_list *m_l;
785 struct ebt_u_watcher_list *w_l;
786
787 printf(
788"%s v%s\n"
789"Usage:\n"
790"ebtables -[ADI] chain rule-specification [options]\n"
791"ebtables -P chain target\n"
792"ebtables -[LFZ] [chain]\n"
793"ebtables -[b] [y,n]\n"
794"Commands:\n"
795"--append -A chain : Append to chain\n"
796"--delete -D chain : Delete matching rule from chain\n"
797"--delete -D chain rulenum : Delete rule at position rulenum from chain\n"
798"--insert -I chain rulenum : insert rule at position rulenum in chain\n"
799"--list -L [chain] : List the rules in a chain or in all chains\n"
800"--list -L "DATABASEHOOKNAME" : List the database (if present)\n"
801"--flush -F [chain] : Delete all rules in chain or in all chains\n"
Bart De Schuymer8d1d8942002-07-15 20:09:09 +0000802"--init-table : Replace the kernel table with the initial table\n"
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000803"--zero -Z [chain] : Put counters on zero in chain or in all chains\n"
804"--policy -P chain target : Change policy on chain to target\n"
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000805"--new-chain -N chain : Create a user defined chain\n"
806"--rename-chain -E old new : Rename a chain\n"
807"--delete-chain -X chain : Delete a user defined chain\n"
Bart De Schuymer62423742002-07-14 19:06:20 +0000808"--atomic-commit file : update the kernel w/ the table contained in file\n"
809"--atomic-init file : put the initial kernel table into file\n"
810"--atomic-save file : put the current kernel table into file\n"
811"--atomic file : write changes to file instead of kernel\n"
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000812"Options:\n"
813"--proto -p [!] proto : protocol hexadecimal, by name or LENGTH\n"
814"--src -s [!] address[/mask]: source mac address\n"
815"--dst -d [!] address[/mask]: destination mac address\n"
816"--in-if -i [!] name : network input interface name\n"
817"--out-if -o [!] name : network output interface name\n"
818"--logical-in [!] name : logical bridge input interface name\n"
819"--logical-out [!] name : logical bridge output interface name\n"
Bart De Schuymer5cbc8e02002-07-14 21:15:28 +0000820"--modprobe -M program : try to insert modules using this program\n"
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000821"--version -V : print package version\n"
822"\n" ,
823 prog_name,
824 prog_version);
825
826 m_l = new_entry->m_list;
827 while (m_l) {
828 ((struct ebt_u_match *)m_l->m)->help();
829 printf("\n");
830 m_l = m_l->next;
831 }
832 w_l = new_entry->w_list;
833 while (w_l) {
834 ((struct ebt_u_watcher *)w_l->w)->help();
835 printf("\n");
836 w_l = w_l->next;
837 }
838 ((struct ebt_u_target *)new_entry->t)->help();
839 printf("\n");
840 if (table->help)
841 table->help(hooknames);
842 exit(0);
843}
844
845// execute command L
846static void list_rules()
847{
848 int i;
849
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000850 if (!(replace.flags & LIST_X))
851 printf("Bridge table: %s\n", table->name);
Bart De Schuymer60332e02002-06-23 08:01:47 +0000852 if (replace.selected_hook != -1) {
853 list_em(to_chain());
854 } else {
855 struct ebt_u_chain_list *cl = replace.udc;
856
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000857 // create new chains and rename standard chains when necessary
858 if (replace.flags & LIST_X) {
859 while (cl) {
860 printf("ebtables -t %s -N %s\n", replace.name,
861 cl->udc->name);
862 cl = cl->next;
863 }
864 cl = replace.udc;
865 for (i = 0; i < NF_BR_NUMHOOKS; i++)
866 if (replace.valid_hooks & (1 << i) &&
867 strcmp(replace.hook_entry[i]->name, hooknames[i]))
868 printf("ebtables -t %s -E %s %s\n",
869 replace.name, hooknames[i],
870 replace.hook_entry[i]->name);
871 }
Bart De Schuymer60332e02002-06-23 08:01:47 +0000872 i = 0;
873 while (1) {
874 if (i < NF_BR_NUMHOOKS) {
875 if (replace.valid_hooks & (1 << i))
876 list_em(replace.hook_entry[i]);
877 i++;
878 continue;
879 } else {
880 if (!cl)
881 break;
882 list_em(cl->udc);
883 cl = cl->next;
884 }
885 }
886 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000887}
888
889// execute command P
890static void change_policy(int policy)
891{
892 int i;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000893 struct ebt_u_entries *entries = to_chain();
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000894
895 // don't do anything if the policy is the same
Bart De Schuymer60332e02002-06-23 08:01:47 +0000896 if (entries->policy != policy) {
897 entries->policy = policy;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000898 replace.num_counters = replace.nentries;
899 if (replace.nentries) {
900 // '+ 1' for the CNT_END
Bart De Schuymered053432002-07-21 19:35:39 +0000901 if (!(replace.counterchanges = (unsigned short *) malloc(
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000902 (replace.nentries + 1) * sizeof(unsigned short))))
903 print_memory();
904 // done nothing special to the rules
905 for (i = 0; i < replace.nentries; i++)
Bart De Schuymered053432002-07-21 19:35:39 +0000906 replace.counterchanges[i] = CNT_NORM;
907 replace.counterchanges[replace.nentries] = CNT_END;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000908 }
909 else
Bart De Schuymered053432002-07-21 19:35:39 +0000910 replace.counterchanges = NULL;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000911 }
912 else
913 exit(0);
914}
915
916// flush one chain or the complete table
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000917// -1 == nothing to do
918// 0 == give back to kernel
919static int flush_chains()
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000920{
Bart De Schuymer60332e02002-06-23 08:01:47 +0000921 int i, j, oldnentries, numdel;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000922 unsigned short *cnt;
923 struct ebt_u_entry *u_e, *tmp;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000924 struct ebt_u_entries *entries = to_chain();
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000925
926 // flush whole table
Bart De Schuymer60332e02002-06-23 08:01:47 +0000927 if (!entries) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000928 if (replace.nentries == 0)
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000929 return -1;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000930 replace.nentries = 0;
931 // no need for the kernel to give us counters back
932 replace.num_counters = 0;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000933
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000934 // free everything and zero (n)entries
Bart De Schuymer60332e02002-06-23 08:01:47 +0000935 i = -1;
936 while (1) {
937 i++;
938 entries = nr_to_chain(i);
939 if (!entries) {
940 if (i < NF_BR_NUMHOOKS)
941 continue;
942 else
943 break;
944 }
945 entries->nentries = 0;
946 entries->counter_offset = 0;
947 u_e = entries->entries;
948 entries->entries = NULL;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000949 while (u_e) {
950 free_u_entry(u_e);
951 tmp = u_e->next;
952 free(u_e);
953 u_e = tmp;
954 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000955 }
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000956 return 0;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000957 }
958
Bart De Schuymer60332e02002-06-23 08:01:47 +0000959 if (entries->nentries == 0)
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000960 return -1;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000961 oldnentries = replace.nentries;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000962 replace.nentries -= entries->nentries;
963 numdel = entries->nentries;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000964
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000965 if (replace.nentries) {
966 // +1 for CNT_END
Bart De Schuymered053432002-07-21 19:35:39 +0000967 if ( !(replace.counterchanges = (unsigned short *)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000968 malloc((oldnentries + 1) * sizeof(unsigned short))) )
969 print_memory();
Bart De Schuymer60332e02002-06-23 08:01:47 +0000970 }
971 // delete the counters belonging to the specified chain,
972 // update counter_offset
973 i = -1;
Bart De Schuymered053432002-07-21 19:35:39 +0000974 cnt = replace.counterchanges;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000975 while (1) {
976 i++;
977 entries = nr_to_chain(i);
978 if (!entries) {
979 if (i < NF_BR_NUMHOOKS)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000980 continue;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000981 else
982 break;
983 }
984 if (i > replace.selected_hook)
985 entries->counter_offset -= numdel;
986 if (replace.nentries) {
987 for (j = 0; j < entries->nentries; j++) {
988 if (i == replace.selected_hook)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000989 *cnt = CNT_DEL;
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000990 else
991 *cnt = CNT_NORM;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000992 cnt++;
993 }
994 }
Bart De Schuymer60332e02002-06-23 08:01:47 +0000995 }
996
997 if (replace.nentries) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000998 *cnt = CNT_END;
999 replace.num_counters = oldnentries;
1000 }
1001 else
1002 replace.num_counters = 0;
1003
Bart De Schuymer60332e02002-06-23 08:01:47 +00001004 entries = to_chain();
1005 entries->nentries = 0;
1006 u_e = entries->entries;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001007 while (u_e) {
1008 free_u_entry(u_e);
1009 tmp = u_e->next;
1010 free(u_e);
1011 u_e = tmp;
1012 }
Bart De Schuymer60332e02002-06-23 08:01:47 +00001013 entries->entries = NULL;
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001014 return 0;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001015}
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001016
1017// -1 == no match
1018static int check_rule_exists(int rule_nr)
1019{
1020 struct ebt_u_entry *u_e;
1021 struct ebt_u_match_list *m_l, *m_l2;
1022 struct ebt_u_match *m;
1023 struct ebt_u_watcher_list *w_l, *w_l2;
1024 struct ebt_u_watcher *w;
1025 struct ebt_u_target *t = (struct ebt_u_target *)new_entry->t;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001026 struct ebt_u_entries *entries = to_chain();
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001027 int i, j, k;
1028
1029 // handle '-D chain rulenr' command
1030 if (rule_nr != -1) {
Bart De Schuymer60332e02002-06-23 08:01:47 +00001031 if (rule_nr > entries->nentries)
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001032 return -1;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001033 // user starts counting from 1
1034 return rule_nr - 1;
1035 }
Bart De Schuymer60332e02002-06-23 08:01:47 +00001036 u_e = entries->entries;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001037 // check for an existing rule (if there are duplicate rules,
1038 // take the first occurance)
Bart De Schuymer60332e02002-06-23 08:01:47 +00001039 for (i = 0; i < entries->nentries; i++, u_e = u_e->next) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001040 if (!u_e)
1041 print_bug("Hmm, trouble");
1042 if ( u_e->ethproto == new_entry->ethproto
1043 && !strcmp(u_e->in, new_entry->in)
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001044 && !strcmp(u_e->out, new_entry->out)) {
Bart De Schuymer60332e02002-06-23 08:01:47 +00001045 if (strcmp(u_e->logical_in, new_entry->logical_in) ||
1046 strcmp(u_e->logical_out, new_entry->logical_out))
1047 continue;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001048 if (new_entry->bitmask & EBT_SOURCEMAC &&
Bart De Schuymer60332e02002-06-23 08:01:47 +00001049 memcmp(u_e->sourcemac, new_entry->sourcemac, ETH_ALEN))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001050 continue;
1051 if (new_entry->bitmask & EBT_DESTMAC &&
Bart De Schuymer60332e02002-06-23 08:01:47 +00001052 memcmp(u_e->destmac, new_entry->destmac, ETH_ALEN))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001053 continue;
1054 if (new_entry->bitmask != u_e->bitmask ||
1055 new_entry->invflags != u_e->invflags)
1056 continue;
1057 // compare all matches
1058 m_l = new_entry->m_list;
1059 j = 0;
1060 while (m_l) {
1061 m = (struct ebt_u_match *)(m_l->m);
1062 m_l2 = u_e->m_list;
1063 while (m_l2 &&
1064 strcmp(m_l2->m->u.name, m->m->u.name))
1065 m_l2 = m_l2->next;
1066 if (!m_l2 || !m->compare(m->m, m_l2->m))
1067 goto letscontinue;
1068 j++;
1069 m_l = m_l->next;
1070 }
1071 // now be sure they have the same nr of matches
1072 k = 0;
1073 m_l = u_e->m_list;
1074 while (m_l) {
1075 k++;
1076 m_l = m_l->next;
1077 }
1078 if (j != k)
1079 continue;
1080
1081 // compare all watchers
1082 w_l = new_entry->w_list;
1083 j = 0;
1084 while (w_l) {
1085 w = (struct ebt_u_watcher *)(w_l->w);
1086 w_l2 = u_e->w_list;
1087 while (w_l2 &&
1088 strcmp(w_l2->w->u.name, w->w->u.name))
1089 w_l2 = w_l2->next;
1090 if (!w_l2 || !w->compare(w->w, w_l2->w))
1091 goto letscontinue;
1092 j++;
1093 w_l = w_l->next;
1094 }
1095 k = 0;
1096 w_l = u_e->w_list;
1097 while (w_l) {
1098 k++;
1099 w_l = w_l->next;
1100 }
1101 if (j != k)
1102 continue;
1103 if (strcmp(t->t->u.name, u_e->t->u.name))
1104 continue;
1105 if (!t->compare(t->t, u_e->t))
1106 continue;
1107 return i;
1108 }
1109letscontinue:
1110 }
1111 return -1;
1112}
1113
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001114// execute command A or I
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001115static void add_rule(int rule_nr)
1116{
1117 int i, j;
1118 struct ebt_u_entry *u_e, *u_e2;
1119 unsigned short *cnt;
1120 struct ebt_u_match_list *m_l;
1121 struct ebt_u_watcher_list *w_l;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001122 struct ebt_u_entries *entries = to_chain(), *entries2;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001123
1124 if (rule_nr != -1) { // command -I
Bart De Schuymer60332e02002-06-23 08:01:47 +00001125 if (--rule_nr > entries->nentries)
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001126 print_error("rule nr too high: %d > %d", rule_nr + 1,
1127 entries->nentries + 1);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001128 } else
Bart De Schuymer60332e02002-06-23 08:01:47 +00001129 rule_nr = entries->nentries;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001130 // we're adding one rule
1131 replace.num_counters = replace.nentries;
1132 replace.nentries++;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001133 entries->nentries++;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001134
1135 // handle counter stuff
1136 // +1 for CNT_END
Bart De Schuymered053432002-07-21 19:35:39 +00001137 if ( !(replace.counterchanges = (unsigned short *)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001138 malloc((replace.nentries + 1) * sizeof(unsigned short))) )
1139 print_memory();
Bart De Schuymered053432002-07-21 19:35:39 +00001140 cnt = replace.counterchanges;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001141 for (i = 0; i < replace.selected_hook; i++) {
Bart De Schuymer60332e02002-06-23 08:01:47 +00001142 if (i < NF_BR_NUMHOOKS && !(replace.valid_hooks & (1 << i)))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001143 continue;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001144 entries2 = nr_to_chain(i);
1145 for (j = 0; j < entries2->nentries; j++) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001146 *cnt = CNT_NORM;
1147 cnt++;
1148 }
1149 }
1150 for (i = 0; i < rule_nr; i++) {
1151 *cnt = CNT_NORM;
1152 cnt++;
1153 }
1154 *cnt = CNT_ADD;
1155 cnt++;
Bart De Schuymered053432002-07-21 19:35:39 +00001156 while (cnt != replace.counterchanges + replace.nentries) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001157 *cnt = CNT_NORM;
1158 cnt++;
1159 }
1160 *cnt = CNT_END;
1161
1162 // go to the right position in the chain
1163 u_e2 = NULL;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001164 u_e = entries->entries;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001165 for (i = 0; i < rule_nr; i++) {
1166 u_e2 = u_e;
1167 u_e = u_e->next;
1168 }
1169 // insert the rule
1170 if (u_e2)
1171 u_e2->next = new_entry;
1172 else
Bart De Schuymer60332e02002-06-23 08:01:47 +00001173 entries->entries = new_entry;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001174 new_entry->next = u_e;
1175
1176 // put the ebt_[match, watcher, target] pointers in place
1177 m_l = new_entry->m_list;
1178 while (m_l) {
1179 m_l->m = ((struct ebt_u_match *)m_l->m)->m;
1180 m_l = m_l->next;
1181 }
1182 w_l = new_entry->w_list;
1183 while (w_l) {
1184 w_l->w = ((struct ebt_u_watcher *)w_l->w)->w;
1185 w_l = w_l->next;
1186 }
1187 new_entry->t = ((struct ebt_u_target *)new_entry->t)->t;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001188
1189 // update the counter_offset of chains behind this one
1190 i = replace.selected_hook;
1191 while (1) {
1192 i++;
1193 entries = nr_to_chain(i);
1194 if (!entries) {
1195 if (i < NF_BR_NUMHOOKS)
1196 continue;
1197 else
1198 break;
1199 } else
1200 entries->counter_offset++;
1201 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001202}
1203
1204// execute command D
1205static void delete_rule(int rule_nr)
1206{
1207 int i, j, lentmp = 0;
1208 unsigned short *cnt;
1209 struct ebt_u_entry *u_e, *u_e2;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001210 struct ebt_u_entries *entries = to_chain(), *entries2;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001211
1212 if ( (i = check_rule_exists(rule_nr)) == -1 )
Bart De Schuymer60332e02002-06-23 08:01:47 +00001213 print_error("Sorry, rule does not exist");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001214
1215 // we're deleting a rule
1216 replace.num_counters = replace.nentries;
1217 replace.nentries--;
1218
1219 if (replace.nentries) {
1220 for (j = 0; j < replace.selected_hook; j++) {
Bart De Schuymer60332e02002-06-23 08:01:47 +00001221 if (j < NF_BR_NUMHOOKS &&
1222 !(replace.valid_hooks & (1 << j)))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001223 continue;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001224 entries2 = nr_to_chain(j);
1225 lentmp += entries2->nentries;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001226 }
1227 lentmp += i;
1228 // +1 for CNT_END
Bart De Schuymered053432002-07-21 19:35:39 +00001229 if ( !(replace.counterchanges = (unsigned short *)malloc(
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001230 (replace.num_counters + 1) * sizeof(unsigned short))) )
1231 print_memory();
Bart De Schuymered053432002-07-21 19:35:39 +00001232 cnt = replace.counterchanges;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001233 for (j = 0; j < lentmp; j++) {
1234 *cnt = CNT_NORM;
1235 cnt++;
1236 }
1237 *cnt = CNT_DEL;
1238 cnt++;
1239 for (j = 0; j < replace.num_counters - lentmp; j++) {
1240 *cnt = CNT_NORM;
1241 cnt++;
1242 }
1243 *cnt = CNT_END;
1244 }
1245 else
1246 replace.num_counters = 0;
1247
1248 // go to the right position in the chain
1249 u_e2 = NULL;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001250 u_e = entries->entries;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001251 for (j = 0; j < i; j++) {
1252 u_e2 = u_e;
1253 u_e = u_e->next;
1254 }
1255
1256 // remove from the chain
1257 if (u_e2)
1258 u_e2->next = u_e->next;
1259 else
Bart De Schuymer60332e02002-06-23 08:01:47 +00001260 entries->entries = u_e->next;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001261
Bart De Schuymer60332e02002-06-23 08:01:47 +00001262 entries->nentries--;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001263 // free everything
1264 free_u_entry(u_e);
1265 free(u_e);
Bart De Schuymer60332e02002-06-23 08:01:47 +00001266 // update the counter_offset of chains behind this one
1267 i = replace.selected_hook;
1268 while (1) {
1269 i++;
1270 entries = nr_to_chain(i);
1271 if (!entries) {
1272 if (i < NF_BR_NUMHOOKS)
1273 continue;
1274 else
1275 break;
1276 } else
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001277 entries->counter_offset--;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001278 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001279}
1280
1281// execute command Z
Bart De Schuymer62423742002-07-14 19:06:20 +00001282static void zero_counters(int zerochain)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001283{
1284
1285 if (zerochain == -1) {
1286 // tell main() we don't update the counters
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001287 // this results in tricking the kernel to zero its counters,
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001288 // naively expecting userspace to update its counters. Muahahaha
Bart De Schuymered053432002-07-21 19:35:39 +00001289 replace.counterchanges = NULL;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001290 replace.num_counters = 0;
1291 } else {
1292 int i, j;
1293 unsigned short *cnt;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001294 struct ebt_u_entries *entries = nr_to_chain(zerochain), *e2;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001295
Bart De Schuymer60332e02002-06-23 08:01:47 +00001296 if (entries->nentries == 0)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001297 exit(0);
Bart De Schuymered053432002-07-21 19:35:39 +00001298 replace.counterchanges = (unsigned short *)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001299 malloc((replace.nentries + 1) * sizeof(unsigned short));
Bart De Schuymered053432002-07-21 19:35:39 +00001300 if (!replace.counterchanges)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001301 print_memory();
Bart De Schuymered053432002-07-21 19:35:39 +00001302 cnt = replace.counterchanges;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001303 for (i = 0; i < zerochain; i++) {
Bart De Schuymer60332e02002-06-23 08:01:47 +00001304 if (i < NF_BR_NUMHOOKS &&
1305 !(replace.valid_hooks & (1 << i)))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001306 continue;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001307 e2 = nr_to_chain(i);
1308 for (j = 0; j < e2->nentries; j++) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001309 *cnt = CNT_NORM;
1310 cnt++;
1311 }
1312 }
Bart De Schuymer60332e02002-06-23 08:01:47 +00001313 for (i = 0; i < entries->nentries; i++) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001314 *cnt = CNT_ZERO;
1315 cnt++;
1316 }
Bart De Schuymered053432002-07-21 19:35:39 +00001317 while (cnt != replace.counterchanges + replace.nentries) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001318 *cnt = CNT_NORM;
1319 cnt++;
1320 }
1321 *cnt = CNT_END;
1322 }
1323}
1324
1325// list the database (optionally compiled into the kernel)
1326static void list_db()
1327{
1328 struct brdb_dbinfo nr;
1329 struct brdb_dbentry *db;
1330 char name[21];
1331 int i;
1332
1333 get_dbinfo(&nr);
1334
1335 // 0 : database disabled (-db n)
1336 if (!(nr.nentries))
1337 print_error("Database not present"
1338 " (disabled), try ebtables --db y");
1339 nr.nentries--;
1340 if (!nr.nentries) print_error("Database empty");
1341 if ( !(db = (struct brdb_dbentry *)
1342 malloc(nr.nentries * sizeof(struct brdb_dbentry))) )
1343 print_memory();
1344
1345 get_db(nr.nentries, db);
1346 printf("number of entries: %d\n", nr.nentries);
1347 for (i = 0; i < nr.nentries; i++) {
1348 printf(
1349 "%d:\n"
1350 "hook : %s\n"
1351 "in-if : %s\n"
1352 "out-if : %s\n"
1353 "protocol: ", i + 1, hooknames[db->hook], db->in, db->out);
1354 if (db->ethproto == IDENTIFY802_3)
1355 printf("802.2/802.3 STYLE LENGTH FIELD\n");
1356 else {
1357 if (number_to_name(ntohs(db->ethproto), name))
1358 printf("%x\n",ntohs(db->ethproto));
1359 else
1360 printf("%s\n", name);
1361 }
1362 db++;
1363 }
1364 exit(0);
1365}
1366
1367// handle db [dis,en]abling
1368static void allowdb(char yorn)
1369{
1370 __u16 decision;
1371
1372 if (yorn != 'y' && yorn != 'n')
1373 print_error("Option [y] or [n] needed");
1374
1375 if (yorn == 'y')
1376 decision = BRDB_DB;
1377 else
1378 decision = BRDB_NODB;
1379
1380 deliver_allowdb(&decision);
1381
1382 exit(0);
1383}
1384
Bart De Schuymer28bf6f62002-06-26 18:57:24 +00001385// 0 == success
1386// 1 == success, but for the special 'protocol' LENGTH
1387// -1 == failure
1388int name_to_number(char *name, __u16 *proto)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001389{
1390 FILE *ifp;
Bart De Schuymerf662ce52002-07-19 18:40:55 +00001391 char buffer[21], value[11], *bfr;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001392 unsigned short i;
1393
1394 if (!strcasecmp("LENGTH", name)) {
Bart De Schuymer28bf6f62002-06-26 18:57:24 +00001395 *proto = 0;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001396 new_entry->bitmask |= EBT_802_3;
1397 return 1;
1398 }
1399 if ( !(ifp = fopen(PROTOCOLFILE, "r")) )
1400 return -1;
1401 while (1) {
1402 if (get_a_line(buffer, value, ifp)) return -1;
1403 if (strcasecmp(buffer, name))
1404 continue;
1405 i = (unsigned short) strtol(value, &bfr, 16);
Bart De Schuymerf662ce52002-07-19 18:40:55 +00001406 if (*bfr != '\0') {
1407 fclose(ifp);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001408 return -1;
Bart De Schuymerf662ce52002-07-19 18:40:55 +00001409 }
Bart De Schuymer28bf6f62002-06-26 18:57:24 +00001410 *proto = i;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001411 fclose(ifp);
1412 return 0;
1413 }
1414 return -1;
1415}
1416
1417// put the mac address into 6 (ETH_ALEN) bytes
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001418int getmac_and_mask(char *from, char *to, char *mask)
1419{
1420 char *p;
1421 int i;
Bart De Schuymer41830412002-06-05 19:41:28 +00001422 struct ether_addr *addr;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001423
1424 if (strcasecmp(from, "Unicast") == 0) {
1425 memcpy(to, mac_type_unicast, ETH_ALEN);
1426 memcpy(mask, msk_type_unicast, ETH_ALEN);
1427 return 0;
1428 }
1429 if (strcasecmp(from, "Multicast") == 0) {
1430 memcpy(to, mac_type_multicast, ETH_ALEN);
1431 memcpy(mask, msk_type_multicast, ETH_ALEN);
1432 return 0;
1433 }
1434 if (strcasecmp(from, "Broadcast") == 0) {
1435 memcpy(to, mac_type_broadcast, ETH_ALEN);
1436 memcpy(mask, msk_type_broadcast, ETH_ALEN);
1437 return 0;
1438 }
1439 if ( (p = strrchr(from, '/')) != NULL) {
1440 *p = '\0';
Bart De Schuymer41830412002-06-05 19:41:28 +00001441 if (!(addr = ether_aton(p + 1)))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001442 return -1;
Bart De Schuymer41830412002-06-05 19:41:28 +00001443 memcpy(mask, addr, ETH_ALEN);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001444 } else
1445 memset(mask, 0xff, ETH_ALEN);
Bart De Schuymer41830412002-06-05 19:41:28 +00001446 if (!(addr = ether_aton(from)))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001447 return -1;
Bart De Schuymer41830412002-06-05 19:41:28 +00001448 memcpy(to, addr, ETH_ALEN);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001449 for (i = 0; i < ETH_ALEN; i++)
1450 to[i] &= mask[i];
1451 return 0;
1452}
1453
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001454// executes the final_check() function for all extensions used by the rule
Bart De Schuymer62423742002-07-14 19:06:20 +00001455static void do_final_checks(struct ebt_u_entry *e, struct ebt_u_entries *entries)
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +00001456{
1457 struct ebt_u_match_list *m_l;
1458 struct ebt_u_watcher_list *w_l;
1459 struct ebt_u_target *t;
1460 struct ebt_u_match *m;
1461 struct ebt_u_watcher *w;
1462
1463 m_l = e->m_list;
1464 w_l = e->w_list;
1465 while (m_l) {
1466 m = find_match(m_l->m->u.name);
1467 m->final_check(e, m_l->m, replace.name,
1468 entries->hook_mask, 1);
1469 m_l = m_l->next;
1470 }
1471 while (w_l) {
1472 w = find_watcher(w_l->w->u.name);
1473 w->final_check(e, w_l->w, replace.name,
1474 entries->hook_mask, 1);
1475 w_l = w_l->next;
1476 }
1477 t = find_target(e->t->u.name);
1478 t->final_check(e, e->t, replace.name,
1479 entries->hook_mask, 1);
1480}
1481
Bart De Schuymerb909f9b2002-06-26 18:35:31 +00001482// used for the -X command
Bart De Schuymer62423742002-07-14 19:06:20 +00001483static void check_for_references(int chain_nr)
Bart De Schuymerb909f9b2002-06-26 18:35:31 +00001484{
1485 int i = -1, j;
1486 struct ebt_u_entries *entries;
1487 struct ebt_u_entry *e;
1488
1489 while (1) {
1490 i++;
1491 entries = nr_to_chain(i);
1492 if (!entries) {
1493 if (i < NF_BR_NUMHOOKS)
1494 continue;
1495 else
1496 break;
1497 }
1498 e = entries->entries;
1499 j = 0;
1500 while (e) {
1501 j++;
1502 if (strcmp(e->t->u.name, EBT_STANDARD_TARGET)) {
1503 e = e->next;
1504 continue;
1505 }
1506 if (((struct ebt_standard_target *)e->t)->verdict == chain_nr)
1507 print_error("Can't delete the chain, it's referenced "
1508 "in chain %s, rule %d", entries->name, j);
1509 e = e->next;
1510 }
1511 }
1512}
1513
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001514int check_inverse(const char option[])
1515{
1516 if (strcmp(option, "!") == 0) {
1517 optind++;
1518 return 1;
1519 }
1520 return 0;
1521}
1522
1523void check_option(unsigned int *flags, unsigned int mask)
1524{
1525 if (*flags & mask)
1526 print_error("Multiple use of same option not allowed");
1527 *flags |= mask;
1528}
1529
1530#define OPT_COMMAND 0x01
1531#define OPT_TABLE 0x02
1532#define OPT_IN 0x04
1533#define OPT_OUT 0x08
1534#define OPT_JUMP 0x10
1535#define OPT_PROTOCOL 0x20
1536#define OPT_SOURCE 0x40
1537#define OPT_DEST 0x80
1538#define OPT_ZERO 0x100
1539#define OPT_LOGICALIN 0x200
1540#define OPT_LOGICALOUT 0x400
1541// the main thing
1542int main(int argc, char *argv[])
1543{
1544 char *buffer, allowbc = 'n';
1545 int c, i;
1546 // this special one for the -Z option (we can have -Z <this> -L <that>)
1547 int zerochain = -1;
Bart De Schuymerf8f8f292002-06-25 15:43:57 +00001548 int policy = 0;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001549 int rule_nr = -1;// used for -D chain number
1550 struct ebt_u_target *t;
1551 struct ebt_u_match *m;
1552 struct ebt_u_watcher *w;
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001553 struct ebt_u_match_list *m_l;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001554 struct ebt_u_watcher_list *w_l;
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001555 struct ebt_u_entries *entries;
Bart De Schuymerc8531032002-06-14 21:55:29 +00001556 const char *modprobe = NULL;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001557
1558 // initialize the table name, OPT_ flags, selected hook and command
1559 strcpy(replace.name, "filter");
1560 replace.flags = 0;
1561 replace.selected_hook = -1;
1562 replace.command = 'h';
Bart De Schuymer62423742002-07-14 19:06:20 +00001563 replace.filename = NULL;
Bart De Schuymered053432002-07-21 19:35:39 +00001564 replace.counterchanges = NULL;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001565
1566 new_entry = (struct ebt_u_entry *)malloc(sizeof(struct ebt_u_entry));
1567 if (!new_entry)
1568 print_memory();
1569 // put some sane values in our new entry
1570 initialize_entry(new_entry);
1571
Bart De Schuymer60332e02002-06-23 08:01:47 +00001572 // The scenario induced by this loop makes that:
Bart De Schuymer62423742002-07-14 19:06:20 +00001573 // '-t' ,'-M' and --atomic (if specified) have to come
1574 // before '-A' and the like
Bart De Schuymer60332e02002-06-23 08:01:47 +00001575
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001576 // getopt saves the day
1577 while ((c = getopt_long(argc, argv,
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001578 "-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 +00001579 switch (c) {
1580
1581 case 'A': // add a rule
1582 case 'D': // delete a rule
1583 case 'P': // define policy
1584 case 'I': // insert a rule
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001585 case 'N': // make a user defined chain
1586 case 'E': // rename chain
1587 case 'X': // delete chain
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001588 replace.command = c;
1589 if (replace.flags & OPT_COMMAND)
1590 print_error("Multiple commands not allowed");
1591 replace.flags |= OPT_COMMAND;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001592 if ( !(table = find_table(replace.name)) )
1593 print_error("Bad table name");
1594 // get the kernel's information
1595 if (get_table(&replace)) {
1596 ebtables_insmod("ebtables", modprobe);
1597 if (get_table(&replace))
1598 print_error("can't initialize ebtables "
1599 "table %s", replace.name);
1600 }
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001601 if (optarg[0] == '-')
1602 print_error("No chain name specified");
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001603 if (c == 'N') {
1604 struct ebt_u_chain_list *cl, **cl2;
1605
1606 if (get_hooknr(optarg) != -1)
1607 print_error("Chain %s already exists",
1608 optarg);
1609 if (find_target(optarg))
1610 print_error("Target with name %s exists"
1611 , optarg);
1612 if (strlen(optarg) >= EBT_CHAIN_MAXNAMELEN)
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001613 print_error("Chain name length can't exceed %d",
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001614 EBT_CHAIN_MAXNAMELEN - 1);
1615 cl = (struct ebt_u_chain_list *)
1616 malloc(sizeof(struct ebt_u_chain_list));
1617 if (!cl)
1618 print_memory();
1619 cl->next = NULL;
1620 cl->udc = (struct ebt_u_entries *)
1621 malloc(sizeof(struct ebt_u_entries));
1622 if (!cl->udc)
1623 print_memory();
1624 cl->udc->nentries = 0;
1625 cl->udc->policy = EBT_ACCEPT;
1626 cl->udc->counter_offset = replace.nentries;
1627 cl->udc->hook_mask = 0;
1628 strcpy(cl->udc->name, optarg);
1629 cl->udc->entries = NULL;
1630 cl->kernel_start = NULL;
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001631 // put the new chain at the end
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001632 cl2 = &replace.udc;
1633 while (*cl2)
1634 cl2 = &((*cl2)->next);
1635 *cl2 = cl;
1636 break;
1637 }
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001638 if ((replace.selected_hook = get_hooknr(optarg)) == -1)
1639 print_error("Chain %s doesn't exist", optarg);
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001640 if (c == 'E') {
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001641 if (optind >= argc || argv[optind][0] == '-')
1642 print_error("No new chain name specified");
1643 if (strlen(argv[optind]) >= EBT_CHAIN_MAXNAMELEN)
1644 print_error("Chain name len can't exceed %d",
1645 EBT_CHAIN_MAXNAMELEN - 1);
1646 if (get_hooknr(argv[optind]) != -1)
1647 print_error("Chain %s already exists",
1648 argv[optind]);
1649 entries = to_chain();
1650 strcpy(entries->name, argv[optind]);
1651 optind++;
1652 break;
1653 }
1654 if (c == 'X') {
1655 struct ebt_u_chain_list *cl, **cl2;
1656
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001657 if (replace.selected_hook < NF_BR_NUMHOOKS)
1658 print_error("You can't remove a standard chain");
Bart De Schuymerb909f9b2002-06-26 18:35:31 +00001659 // if the chain is referenced, don't delete it
1660 check_for_references(replace.selected_hook - NF_BR_NUMHOOKS);
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001661 flush_chains();
1662 entries = to_chain();
1663 if (replace.udc->udc == entries) {
1664 cl = replace.udc;
1665 replace.udc = replace.udc->next;
1666 free(cl->udc);
1667 free(cl);
1668 break;
1669 }
1670 cl2 = &(replace.udc);
1671 while ((*cl2)->next->udc != entries)
1672 cl2 = &((*cl2)->next);
1673 cl = (*cl2)->next;
1674 (*cl2)->next = (*cl2)->next->next;
1675 free(cl->udc);
1676 free(cl);
1677 break;
1678 }
1679
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001680 if (c == 'D' && optind < argc &&
1681 argv[optind][0] != '-') {
1682 rule_nr = strtol(argv[optind], &buffer, 10);
1683 if (*buffer != '\0' || rule_nr < 0)
1684 print_error("Problem with the "
1685 "specified rule number");
1686 optind++;
1687 }
1688 if (c == 'P') {
1689 if (optind >= argc)
1690 print_error("No policy specified");
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001691 policy = 0;
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001692 for (i = 0; i < NUM_STANDARD_TARGETS; i++)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001693 if (!strcmp(argv[optind],
1694 standard_targets[i])) {
Bart De Schuymer60332e02002-06-23 08:01:47 +00001695 policy = -i -1;
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001696 if (policy == EBT_CONTINUE)
1697 policy = 0;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001698 break;
1699 }
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001700 if (policy == 0)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001701 print_error("Wrong policy");
1702 optind++;
1703 }
1704 if (c == 'I') {
1705 if (optind >= argc)
1706 print_error("No rulenr for -I"
1707 " specified");
1708 rule_nr = strtol(argv[optind], &buffer, 10);
1709 if (*buffer != '\0' || rule_nr < 0)
1710 print_error("Problem with the specified"
1711 " rule number");
1712 optind++;
1713 }
1714 break;
1715
1716 case 'L': // list
1717 case 'F': // flush
1718 case 'Z': // zero counters
1719 if (c == 'Z') {
1720 if (replace.flags & OPT_ZERO)
1721 print_error("Multiple commands"
1722 " not allowed");
1723 if ( (replace.flags & OPT_COMMAND &&
1724 replace.command != 'L'))
1725 print_error("command -Z only allowed "
1726 "together with command -L");
1727 replace.flags |= OPT_ZERO;
1728 } else {
1729 replace.command = c;
1730 if (replace.flags & OPT_COMMAND)
1731 print_error("Multiple commands"
1732 " not allowed");
1733 replace.flags |= OPT_COMMAND;
1734 }
Bart De Schuymer60332e02002-06-23 08:01:47 +00001735 if ( !(table = find_table(replace.name)) )
1736 print_error("Bad table name");
1737 // get the kernel's information
1738 if (get_table(&replace)) {
1739 ebtables_insmod("ebtables", modprobe);
1740 if (get_table(&replace))
1741 print_error("can't initialize ebtables "
1742 "table %s", replace.name);
1743 }
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001744 i = -1;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001745 if (optarg) {
1746 if ( (i = get_hooknr(optarg)) == -1 )
1747 print_error("Bad chain");
1748 } else
1749 if (optind < argc && argv[optind][0] != '-') {
1750 if ((i = get_hooknr(argv[optind]))
1751 == -1)
1752 print_error("Bad chain");
1753 optind++;
1754 }
1755 if (i != -1) {
1756 if (c == 'Z')
1757 zerochain = i;
1758 else
1759 replace.selected_hook = i;
1760 }
1761 break;
1762
1763 case 'V': // version
1764 replace.command = 'V';
1765 if (replace.flags & OPT_COMMAND)
1766 print_error("Multiple commands not allowed");
1767 printf("%s, %s\n", prog_name, prog_version);
1768 exit(0);
1769
Bart De Schuymerc8531032002-06-14 21:55:29 +00001770 case 'M': // modprobe
Bart De Schuymer60332e02002-06-23 08:01:47 +00001771 if (replace.command != 'h')
1772 print_error("Please put the -M option earlier");
Bart De Schuymerc8531032002-06-14 21:55:29 +00001773 modprobe = optarg;
1774 break;
1775
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001776 case 'h': // help
1777 if (replace.flags & OPT_COMMAND)
1778 print_error("Multiple commands not allowed");
1779 replace.command = 'h';
1780 // All other arguments should be extension names
1781 while (optind < argc) {
1782 struct ebt_u_match *m;
1783 struct ebt_u_watcher *w;
1784
1785 if ((m = find_match(argv[optind])))
1786 add_match(m);
1787 else if ((w = find_watcher(argv[optind])))
1788 add_watcher(w);
1789 else {
1790 if (!(t = find_target(argv[optind])))
1791 print_error("Extension %s "
1792 "not found", argv[optind]);
1793 if (replace.flags & OPT_JUMP)
1794 print_error("Sorry, you can "
1795 "only see help for one "
1796 "target extension each time");
1797 replace.flags |= OPT_JUMP;
1798 new_entry->t =
1799 (struct ebt_entry_target *)t;
1800 }
1801 optind++;
1802 }
1803 break;
1804
1805 case 't': // table
Bart De Schuymer60332e02002-06-23 08:01:47 +00001806 if (replace.command != 'h')
1807 print_error("Please put the -t option first");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001808 check_option(&replace.flags, OPT_TABLE);
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001809 if (strlen(optarg) > EBT_TABLE_MAXNAMELEN - 1)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001810 print_error("Table name too long");
1811 strcpy(replace.name, optarg);
1812 break;
1813
1814 case 'i': // input interface
1815 case 2 : // logical input interface
1816 case 'o': // output interface
1817 case 3 : // logical output interface
1818 case 'j': // target
1819 case 'p': // net family protocol
1820 case 's': // source mac
1821 case 'd': // destination mac
1822 if ((replace.flags & OPT_COMMAND) == 0)
1823 print_error("No command specified");
1824 if ( replace.command != 'A' &&
1825 replace.command != 'D' && replace.command != 'I')
1826 print_error("Command and option do not match");
1827 if (c == 'i') {
1828 check_option(&replace.flags, OPT_IN);
1829 if (replace.selected_hook > 2 &&
1830 replace.selected_hook < NF_BR_BROUTING)
1831 print_error("Use in-interface only in "
1832 "INPUT, FORWARD, PREROUTING and"
1833 "BROUTING chains");
1834 if (check_inverse(optarg))
1835 new_entry->invflags |= EBT_IIN;
1836
1837 if (optind > argc)
1838 print_error("No in-interface "
1839 "specified");
1840 if (strlen(argv[optind - 1]) >= IFNAMSIZ)
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001841 print_error("Illegal interface length");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001842 strcpy(new_entry->in, argv[optind - 1]);
1843 break;
1844 }
1845 if (c == 2) {
1846 check_option(&replace.flags, OPT_LOGICALIN);
1847 if (replace.selected_hook > 2 &&
1848 replace.selected_hook < NF_BR_BROUTING)
1849 print_error("Use logical in-interface "
1850 "only in INPUT, FORWARD, "
1851 "PREROUTING and BROUTING chains");
1852 if (check_inverse(optarg))
1853 new_entry->invflags |= EBT_ILOGICALIN;
1854
1855 if (optind > argc)
1856 print_error("No logical in-interface "
1857 "specified");
1858 if (strlen(argv[optind - 1]) >= IFNAMSIZ)
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001859 print_error("Illegal interface length");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001860 strcpy(new_entry->logical_in, argv[optind - 1]);
1861 break;
1862 }
1863 if (c == 'o') {
1864 check_option(&replace.flags, OPT_OUT);
1865 if (replace.selected_hook < 2)
1866 print_error("Use out-interface only"
1867 " in OUTPUT, FORWARD and "
1868 "POSTROUTING chains");
1869 if (check_inverse(optarg))
1870 new_entry->invflags |= EBT_IOUT;
1871
1872 if (optind > argc)
1873 print_error("No out-interface "
1874 "specified");
1875
1876 if (strlen(argv[optind - 1]) >= IFNAMSIZ)
1877 print_error("Illegal interface "
1878 "length");
1879 strcpy(new_entry->out, argv[optind - 1]);
1880 break;
1881 }
1882 if (c == 3) {
1883 check_option(&replace.flags, OPT_LOGICALOUT);
1884 if (replace.selected_hook < 2)
1885 print_error("Use logical out-interface "
1886 "only in OUTPUT, FORWARD and "
1887 "POSTROUTING chains");
1888 if (check_inverse(optarg))
1889 new_entry->invflags |= EBT_ILOGICALOUT;
1890
1891 if (optind > argc)
1892 print_error("No logical out-interface "
1893 "specified");
1894
1895 if (strlen(argv[optind - 1]) >= IFNAMSIZ)
1896 print_error("Illegal interface "
1897 "length");
1898 strcpy(new_entry->logical_out,
1899 argv[optind - 1]);
1900 break;
1901 }
1902 if (c == 'j') {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001903 check_option(&replace.flags, OPT_JUMP);
1904 for (i = 0; i < NUM_STANDARD_TARGETS; i++)
1905 if (!strcmp(optarg,
1906 standard_targets[i])) {
1907 t = find_target(
1908 EBT_STANDARD_TARGET);
1909 ((struct ebt_standard_target *)
Bart De Schuymer60332e02002-06-23 08:01:47 +00001910 t->t)->verdict = -i - 1;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001911 break;
1912 }
Bart De Schuymer60332e02002-06-23 08:01:47 +00001913 if (-i - 1 == EBT_RETURN) {
1914 if (replace.selected_hook < NF_BR_NUMHOOKS)
1915 print_error("Return target"
1916 " only for user defined chains");
1917 }
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +00001918 if (i != NUM_STANDARD_TARGETS)
1919 break;
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001920 if ((i = get_hooknr(optarg)) != -1) {
1921 if (i < NF_BR_NUMHOOKS)
1922 print_error("don't jump"
1923 " to a standard chain");
1924 t = find_target(
1925 EBT_STANDARD_TARGET);
1926 ((struct ebt_standard_target *)
1927 t->t)->verdict = i - NF_BR_NUMHOOKS;
1928 break;
1929 }
1930 else {
1931 // must be an extension then
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001932 struct ebt_u_target *t;
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001933
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001934 t = find_target(optarg);
1935 // -j standard not allowed either
1936 if (!t || t ==
1937 (struct ebt_u_target *)new_entry->t)
1938 print_error("Illegal target "
1939 "name");
1940 new_entry->t =
1941 (struct ebt_entry_target *)t;
1942 }
1943 break;
1944 }
1945 if (c == 's') {
1946 check_option(&replace.flags, OPT_SOURCE);
1947 if (check_inverse(optarg))
1948 new_entry->invflags |= EBT_ISOURCE;
1949
1950 if (optind > argc)
1951 print_error("No source mac "
1952 "specified");
1953 if (getmac_and_mask(argv[optind - 1],
1954 new_entry->sourcemac, new_entry->sourcemsk))
1955 print_error("Problem with specified "
1956 "source mac");
1957 new_entry->bitmask |= EBT_SOURCEMAC;
1958 break;
1959 }
1960 if (c == 'd') {
1961 check_option(&replace.flags, OPT_DEST);
1962 if (check_inverse(optarg))
1963 new_entry->invflags |= EBT_IDEST;
1964
1965 if (optind > argc)
1966 print_error("No destination mac "
1967 "specified");
1968 if (getmac_and_mask(argv[optind - 1],
1969 new_entry->destmac, new_entry->destmsk))
1970 print_error("Problem with specified "
1971 "destination mac");
1972 new_entry->bitmask |= EBT_DESTMAC;
1973 break;
1974 }
1975 check_option(&replace.flags, OPT_PROTOCOL);
1976 if (check_inverse(optarg))
1977 new_entry->invflags |= EBT_IPROTO;
1978
1979 if (optind > argc)
1980 print_error("No protocol specified");
1981 new_entry->bitmask &= ~((unsigned int)EBT_NOPROTO);
1982 i = strtol(argv[optind - 1], &buffer, 16);
1983 if (*buffer == '\0' && (i < 0 || i > 0xFFFF))
1984 print_error("Problem with the specified "
1985 "protocol");
1986 new_entry->ethproto = i;
Bart De Schuymer28bf6f62002-06-26 18:57:24 +00001987 if (*buffer != '\0') {
1988 if ((i = name_to_number(argv[optind - 1],
1989 &new_entry->ethproto)) == -1)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001990 print_error("Problem with the specified"
1991 " protocol");
Bart De Schuymer28bf6f62002-06-26 18:57:24 +00001992 if (i == 1)
1993 new_entry->bitmask |= EBT_802_3;
1994 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001995 if (new_entry->ethproto < 1536 &&
1996 !(new_entry->bitmask & EBT_802_3))
1997 print_error("Sorry, protocols have values above"
1998 " or equal to 1536 (0x0600)");
1999 break;
2000
2001 case 'b': // allow database?
2002 if (replace.flags & OPT_COMMAND)
2003 print_error("Multiple commands not allowed");
2004 replace.command = c;
2005 allowbc = *optarg;
2006 break;
2007
Bart De Schuymer9af14f92002-07-10 20:49:10 +00002008 case 4 : // Lc
2009 check_option(&replace.flags, LIST_C);
2010 if (replace.selected_hook == DATABASEHOOKNR)
2011 print_error("--Lc not valid for listing"
2012 " the database");
2013 if (replace.command != 'L')
2014 print_error("Use --Lc with -L");
2015 if (replace.flags & LIST_X)
2016 print_error("--Lx not compatible with --Lc");
2017 replace.flags |= LIST_C;
2018 break;
2019 case 5 : // Ln
2020 check_option(&replace.flags, LIST_N);
2021 if (replace.selected_hook == DATABASEHOOKNR)
2022 print_error("--Ln not valid for listing"
2023 " the database");
2024 if (replace.command != 'L')
2025 print_error("Use --Ln with -L");
2026 if (replace.flags & LIST_X)
2027 print_error("--Lx not compatible with --Ln");
2028 replace.flags |= LIST_N;
2029 break;
2030 case 6 : // Lx
2031 check_option(&replace.flags, LIST_X);
2032 if (replace.selected_hook == DATABASEHOOKNR)
2033 print_error("--Lx not valid for listing"
2034 " the database");
2035 if (replace.command != 'L')
2036 print_error("Use --Lx with -L");
2037 if (replace.flags & LIST_C)
2038 print_error("--Lx not compatible with --Lc");
2039 if (replace.flags & LIST_N)
2040 print_error("--Lx not compatible with --Ln");
2041 replace.flags |= LIST_X;
2042 break;
Bart De Schuymer62423742002-07-14 19:06:20 +00002043 case 8 : // atomic-commit
2044 replace.command = c;
2045 if (replace.flags & OPT_COMMAND)
2046 print_error("Multiple commands not allowed");
2047 replace.flags |= OPT_COMMAND;
2048 replace.filename = (char *)malloc(strlen(optarg) + 1);
2049 strcpy(replace.filename, optarg);
2050 // get the information from the file
2051 get_table(&replace);
Bart De Schuymer868bf642002-07-16 18:14:20 +00002052 if (replace.nentries) {
Bart De Schuymered053432002-07-21 19:35:39 +00002053 replace.counterchanges = (unsigned short *)
Bart De Schuymer868bf642002-07-16 18:14:20 +00002054 malloc(sizeof(unsigned short) * (replace.nentries + 1));
2055 for (i = 0; i < replace.nentries; i++)
Bart De Schuymered053432002-07-21 19:35:39 +00002056 replace.counterchanges[i] = CNT_NORM;
2057 replace.counterchanges[i] = CNT_END;
Bart De Schuymer868bf642002-07-16 18:14:20 +00002058 }
Bart De Schuymer62423742002-07-14 19:06:20 +00002059 free(replace.filename);
2060 replace.filename = NULL;
2061 break;
2062 case 7 : // atomic-init
2063 case 10: // atomic-save
Bart De Schuymer8d1d8942002-07-15 20:09:09 +00002064 case 11: // init-table
Bart De Schuymer62423742002-07-14 19:06:20 +00002065 replace.command = c;
2066 if (replace.flags & OPT_COMMAND)
2067 print_error("Multiple commands not allowed");
2068 replace.flags |= OPT_COMMAND;
2069 if ( !(table = find_table(replace.name)) )
2070 print_error("Bad table name");
2071 if (get_table(&replace)) {
2072 ebtables_insmod("ebtables", modprobe);
2073 if (get_table(&replace))
2074 print_error("can't initialize ebtables "
2075 "table %s", replace.name);
2076 }
Bart De Schuymera8d920b2002-07-16 18:30:44 +00002077 if (replace.nentries) {
Bart De Schuymered053432002-07-21 19:35:39 +00002078 replace.counterchanges = (unsigned short *)
Bart De Schuymer5f16dc72002-07-16 18:08:36 +00002079 malloc(sizeof(unsigned short) * (replace.nentries + 1));
2080 for (i = 0; i < replace.nentries; i++)
Bart De Schuymered053432002-07-21 19:35:39 +00002081 replace.counterchanges[i] = CNT_NORM;
2082 replace.counterchanges[i] = CNT_END;
Bart De Schuymer5f16dc72002-07-16 18:08:36 +00002083 }
Bart De Schuymer8d1d8942002-07-15 20:09:09 +00002084 if (c == 11)
2085 break;
Bart De Schuymer62423742002-07-14 19:06:20 +00002086 case 9 : // atomic
2087 replace.filename = (char *)malloc(strlen(optarg) + 1);
2088 strcpy(replace.filename, optarg);
2089 break;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002090
Bart De Schuymer9af14f92002-07-10 20:49:10 +00002091 default:
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002092 // is it a target option?
2093 t = (struct ebt_u_target *)new_entry->t;
2094 if ((t->parse(c - t->option_offset, argv, argc,
2095 new_entry, &t->flags, &t->t)))
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00002096 goto check_extension;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002097
2098 // is it a match_option?
2099 for (m = matches; m; m = m->next)
2100 if (m->parse(c - m->option_offset, argv,
2101 argc, new_entry, &m->flags, &m->m))
2102 break;
2103
2104 if (m != NULL) {
2105 if (m->used == 0)
2106 add_match(m);
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00002107 goto check_extension;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002108 }
2109
2110 // is it a watcher option?
2111 for (w = watchers; w; w = w->next)
2112 if (w->parse(c-w->option_offset, argv,
2113 argc, new_entry, &w->flags, &w->w))
2114 break;
2115
2116 if (w == NULL)
2117 print_error("Unknown argument");
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00002118 if (w->used == 0)
2119 add_watcher(w);
2120check_extension:
Bart De Schuymer60332e02002-06-23 08:01:47 +00002121 if (replace.command != 'A' && replace.command != 'I' &&
2122 replace.command != 'D')
2123 print_error("extensions only for -A, -I and -D");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002124 }
2125 }
2126
Bart De Schuymer25c741d2002-06-23 18:54:34 +00002127 if ( !table && !(table = find_table(replace.name)) )
2128 print_error("Bad table name");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002129 // database stuff before ebtables stuff
2130 if (replace.command == 'b')
2131 allowdb(allowbc);
2132 if (replace.command == 'L' && replace.selected_hook == DATABASEHOOKNR)
2133 list_db();
2134
2135 if ( (replace.flags & OPT_COMMAND) && replace.command != 'L' &&
2136 replace.flags & OPT_ZERO )
2137 print_error("Command -Z only allowed together with command -L");
2138
2139 if (replace.command == 'A' || replace.command == 'I' ||
2140 replace.command == 'D') {
2141 if (replace.selected_hook == -1)
2142 print_error("Not enough information");
2143 }
2144
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002145 // do this after parsing everything, so we can print specific info
2146 if (replace.command == 'h' && !(replace.flags & OPT_ZERO))
2147 print_help();
2148
2149 // do the final checks
Bart De Schuymer60332e02002-06-23 08:01:47 +00002150 if (replace.command == 'A' || replace.command == 'I' ||
2151 replace.command == 'D') {
2152 // this will put the hook_mask right for the chains
2153 check_for_loops();
2154 entries = to_chain();
2155 m_l = new_entry->m_list;
2156 w_l = new_entry->w_list;
2157 t = (struct ebt_u_target *)new_entry->t;
2158 while (m_l) {
2159 m = (struct ebt_u_match *)(m_l->m);
2160 m->final_check(new_entry, m->m, replace.name,
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +00002161 entries->hook_mask, 0);
Bart De Schuymer60332e02002-06-23 08:01:47 +00002162 m_l = m_l->next;
2163 }
2164 while (w_l) {
2165 w = (struct ebt_u_watcher *)(w_l->w);
2166 w->final_check(new_entry, w->w, replace.name,
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +00002167 entries->hook_mask, 0);
Bart De Schuymer60332e02002-06-23 08:01:47 +00002168 w_l = w_l->next;
2169 }
2170 t->final_check(new_entry, t->t, replace.name,
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +00002171 entries->hook_mask, 0);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002172 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002173 // so, the extensions can work with the host endian
2174 // the kernel does not have to do this ofcourse
2175 new_entry->ethproto = htons(new_entry->ethproto);
2176
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002177 if (replace.command == 'P')
2178 change_policy(policy);
2179 else if (replace.command == 'L') {
2180 list_rules();
2181 if (replace.flags & OPT_ZERO)
2182 zero_counters(zerochain);
2183 else
2184 exit(0);
2185 }
2186 if (replace.flags & OPT_ZERO)
2187 zero_counters(zerochain);
Bart De Schuymer1ab41562002-06-23 17:09:54 +00002188 else if (replace.command == 'F') {
2189 if (flush_chains() == -1)
2190 exit(0);
2191 } else if (replace.command == 'A' || replace.command == 'I') {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002192 add_rule(rule_nr);
Bart De Schuymer1ab41562002-06-23 17:09:54 +00002193 check_for_loops();
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +00002194 // do the final_check(), for all entries
2195 // needed when adding a rule that has a chain target
2196 i = -1;
2197 while (1) {
2198 struct ebt_u_entry *e;
2199
2200 i++;
2201 entries = nr_to_chain(i);
2202 if (!entries) {
2203 if (i < NF_BR_NUMHOOKS)
2204 continue;
2205 else
2206 break;
2207 }
2208 e = entries->entries;
2209 while (e) {
2210 // userspace extensions use host endian
2211 e->ethproto = ntohs(e->ethproto);
2212 do_final_checks(e, entries);
2213 e->ethproto = htons(e->ethproto);
2214 e = e->next;
2215 }
2216 }
Bart De Schuymer1ab41562002-06-23 17:09:54 +00002217 } else if (replace.command == 'D')
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002218 delete_rule(rule_nr);
Bart De Schuymer8d1d8942002-07-15 20:09:09 +00002219 // commands -N, -E, -X, --atomic-commit, --atomic-commit, --atomic-save,
2220 // --init-table fall through
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002221
2222 if (table->check)
2223 table->check(&replace);
2224
2225 deliver_table(&replace);
2226
Bart De Schuymered053432002-07-21 19:35:39 +00002227 if (replace.counterchanges)
2228 deliver_counters(&replace);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002229 return 0;
2230}