blob: a79cfd17e670efe8e63b31207128c4502b6d206a [file] [log] [blame]
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001/*
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00002 * ebtables.c, v2.0 July 2002
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00003 *
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>
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000026#include <stdio.h>
27#include <stdlib.h>
Bart De Schuymerd4586482002-08-11 16:15:55 +000028#include <stdarg.h>
Bart De Schuymer41830412002-06-05 19:41:28 +000029#include <netinet/ether.h>
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000030#include "include/ebtables_u.h"
Bart De Schuymerc7bfa272002-11-20 19:40:13 +000031#include "include/ethernetdb.h"
Bart De Schuymerc8531032002-06-14 21:55:29 +000032#include <unistd.h>
33#include <fcntl.h>
34#include <sys/wait.h>
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000035
Bart De Schuymerc7bfa272002-11-20 19:40:13 +000036/*
37 * Don't use this function, use print_bug()
38 */
Bart De Schuymerd4586482002-08-11 16:15:55 +000039void __print_bug(char *file, int line, char *format, ...)
40{
41 va_list l;
42
43 va_start(l, format);
44 printf(PROGNAME" v"PROGVERSION":%s:%d:--BUG--: \n", file, line);
45 vprintf(format, l);
46 printf("\n");
47 va_end(l);
48 exit (-1);
49}
50
Bart De Schuymerc8531032002-06-14 21:55:29 +000051#ifndef PROC_SYS_MODPROBE
52#define PROC_SYS_MODPROBE "/proc/sys/kernel/modprobe"
53#endif
Bart De Schuymer5885b362002-12-03 20:51:36 +000054#define ATOMIC_ENV_VARIABLE "EBTABLES_ATOMIC_FILE"
Bart De Schuymer57a3f6a2003-04-01 16:59:33 +000055#define PRINT_VERSION printf(PROGNAME" v"PROGVERSION" ("PROGDATE")\n")
56
Bart De Schuymerc8531032002-06-14 21:55:29 +000057
Bart De Schuymer60332e02002-06-23 08:01:47 +000058char *hooknames[NF_BR_NUMHOOKS] =
59{
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000060 [NF_BR_PRE_ROUTING]"PREROUTING",
61 [NF_BR_LOCAL_IN]"INPUT",
62 [NF_BR_FORWARD]"FORWARD",
63 [NF_BR_LOCAL_OUT]"OUTPUT",
64 [NF_BR_POST_ROUTING]"POSTROUTING",
65 [NF_BR_BROUTING]"BROUTING"
66};
67
Bart De Schuymerc7bfa272002-11-20 19:40:13 +000068/*
69 * default command line options
70 * do not mess around with the already assigned numbers unless
71 * you know what you are doing
72 */
Bart De Schuymer62423742002-07-14 19:06:20 +000073static struct option ebt_original_options[] =
74{
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000075 { "append" , required_argument, 0, 'A' },
76 { "insert" , required_argument, 0, 'I' },
77 { "delete" , required_argument, 0, 'D' },
78 { "list" , optional_argument, 0, 'L' },
Bart De Schuymer9af14f92002-07-10 20:49:10 +000079 { "Lc" , no_argument , 0, 4 },
80 { "Ln" , no_argument , 0, 5 },
81 { "Lx" , no_argument , 0, 6 },
Bart De Schuymer22d03a22003-05-03 20:28:22 +000082 { "Lmac2" , no_argument , 0, 12 },
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000083 { "zero" , optional_argument, 0, 'Z' },
84 { "flush" , optional_argument, 0, 'F' },
85 { "policy" , required_argument, 0, 'P' },
86 { "in-interface" , required_argument, 0, 'i' },
87 { "in-if" , required_argument, 0, 'i' },
88 { "logical-in" , required_argument, 0, 2 },
89 { "logical-out" , required_argument, 0, 3 },
90 { "out-interface" , required_argument, 0, 'o' },
91 { "out-if" , required_argument, 0, 'o' },
92 { "version" , no_argument , 0, 'V' },
93 { "help" , no_argument , 0, 'h' },
94 { "jump" , required_argument, 0, 'j' },
95 { "proto" , required_argument, 0, 'p' },
96 { "protocol" , required_argument, 0, 'p' },
97 { "db" , required_argument, 0, 'b' },
98 { "source" , required_argument, 0, 's' },
99 { "src" , required_argument, 0, 's' },
100 { "destination" , required_argument, 0, 'd' },
101 { "dst" , required_argument, 0, 'd' },
102 { "table" , required_argument, 0, 't' },
Bart De Schuymerc8531032002-06-14 21:55:29 +0000103 { "modprobe" , required_argument, 0, 'M' },
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000104 { "new-chain" , required_argument, 0, 'N' },
105 { "rename-chain" , required_argument, 0, 'E' },
106 { "delete-chain" , required_argument, 0, 'X' },
Bart De Schuymer5885b362002-12-03 20:51:36 +0000107 { "atomic-init" , no_argument , 0, 7 },
108 { "atomic-commit" , no_argument , 0, 8 },
109 { "atomic-file" , required_argument, 0, 9 },
110 { "atomic-save" , no_argument , 0, 10 },
Bart De Schuymer8d1d8942002-07-15 20:09:09 +0000111 { "init-table" , no_argument , 0, 11 },
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000112 { 0 }
113};
114
115static struct option *ebt_options = ebt_original_options;
116
Bart De Schuymer62423742002-07-14 19:06:20 +0000117char* standard_targets[NUM_STANDARD_TARGETS] =
118{
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000119 "ACCEPT",
120 "DROP",
121 "CONTINUE",
Bart De Schuymer60332e02002-06-23 08:01:47 +0000122 "RETURN",
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000123};
124
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000125unsigned char mac_type_unicast[ETH_ALEN] = {0,0,0,0,0,0};
126unsigned char msk_type_unicast[ETH_ALEN] = {1,0,0,0,0,0};
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000127unsigned char mac_type_multicast[ETH_ALEN] = {1,0,0,0,0,0};
128unsigned char msk_type_multicast[ETH_ALEN] = {1,0,0,0,0,0};
129unsigned char mac_type_broadcast[ETH_ALEN] = {255,255,255,255,255,255};
130unsigned char msk_type_broadcast[ETH_ALEN] = {255,255,255,255,255,255};
131
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000132/*
133 * holds all the data
134 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000135static struct ebt_u_replace replace;
136
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000137/*
138 * the chosen table
139 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000140static struct ebt_u_table *table = NULL;
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000141/*
142 * the lists of supported tables, matches, watchers and targets
143 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000144static struct ebt_u_table *tables = NULL;
145static struct ebt_u_match *matches = NULL;
146static struct ebt_u_watcher *watchers = NULL;
147static struct ebt_u_target *targets = NULL;
148
149struct ebt_u_target *find_target(const char *name)
150{
151 struct ebt_u_target *t = targets;
152
153 while(t && strcmp(t->name, name))
154 t = t->next;
155 return t;
156}
157
158struct ebt_u_match *find_match(const char *name)
159{
160 struct ebt_u_match *m = matches;
161
162 while(m && strcmp(m->name, name))
163 m = m->next;
164 return m;
165}
166
167struct ebt_u_watcher *find_watcher(const char *name)
168{
169 struct ebt_u_watcher *w = watchers;
170
171 while(w && strcmp(w->name, name))
172 w = w->next;
173 return w;
174}
175
176struct ebt_u_table *find_table(char *name)
177{
178 struct ebt_u_table *t = tables;
179
180 while (t && strcmp(t->name, name))
181 t = t->next;
182 return t;
183}
184
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000185/*
186 * The pointers in here are special:
187 * The struct ebt_target * pointer is actually a struct ebt_u_target * pointer.
188 * instead of making yet a few other structs, we just do a cast.
189 * We need a struct ebt_u_target pointer because we know the address of the data
190 * they point to won't change. We want to allow that the struct ebt_u_target.t
191 * member can change.
192 * Same holds for the struct ebt_match and struct ebt_watcher pointers
193 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000194struct ebt_u_entry *new_entry;
195
Bart De Schuymer62423742002-07-14 19:06:20 +0000196static void initialize_entry(struct ebt_u_entry *e)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000197{
198 e->bitmask = EBT_NOPROTO;
199 e->invflags = 0;
200 e->ethproto = 0;
201 strcpy(e->in, "");
202 strcpy(e->out, "");
203 strcpy(e->logical_in, "");
204 strcpy(e->logical_out, "");
205 e->m_list = NULL;
206 e->w_list = NULL;
Bart De Schuymerc27432e2003-01-09 22:01:07 +0000207 /*
208 * the init function of the standard target should have put the verdict
209 * on CONTINUE
210 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000211 e->t = (struct ebt_entry_target *)find_target(EBT_STANDARD_TARGET);
212 if (!e->t)
Bart De Schuymerd4586482002-08-11 16:15:55 +0000213 print_bug("Couldn't load standard target");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000214}
215
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000216/*
217 * this doesn't free e, becoz the calling function might need e->next
218 */
Bart De Schuymer62423742002-07-14 19:06:20 +0000219static void free_u_entry(struct ebt_u_entry *e)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000220{
221 struct ebt_u_match_list *m_l, *m_l2;
222 struct ebt_u_watcher_list *w_l, *w_l2;
223
224 m_l = e->m_list;
225 while (m_l) {
226 m_l2 = m_l->next;
227 free(m_l->m);
228 free(m_l);
229 m_l = m_l2;
230 }
231 w_l = e->w_list;
232 while (w_l) {
233 w_l2 = w_l->next;
234 free(w_l->w);
235 free(w_l);
236 w_l = w_l2;
237 }
238 free(e->t);
239}
240
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000241/*
242 * the user will use the match, so put it in new_entry
243 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000244static void add_match(struct ebt_u_match *m)
245{
246 struct ebt_u_match_list **m_list, *new;
247
248 m->used = 1;
Bart De Schuymerc56a31a2002-07-25 08:16:08 +0000249 for (m_list = &new_entry->m_list; *m_list; m_list = &(*m_list)->next);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000250 new = (struct ebt_u_match_list *)
251 malloc(sizeof(struct ebt_u_match_list));
252 if (!new)
253 print_memory();
254 *m_list = new;
255 new->next = NULL;
256 new->m = (struct ebt_entry_match *)m;
257}
258
259static void add_watcher(struct ebt_u_watcher *w)
260{
261 struct ebt_u_watcher_list **w_list;
262 struct ebt_u_watcher_list *new;
263
264 w->used = 1;
Bart De Schuymerc56a31a2002-07-25 08:16:08 +0000265 for (w_list = &new_entry->w_list; *w_list; w_list = &(*w_list)->next);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000266 new = (struct ebt_u_watcher_list *)
267 malloc(sizeof(struct ebt_u_watcher_list));
268 if (!new)
269 print_memory();
270 *w_list = new;
271 new->next = NULL;
272 new->w = (struct ebt_entry_watcher *)w;
273}
274
275static int global_option_offset = 0;
276#define OPTION_OFFSET 256
277static struct option *
278merge_options(struct option *oldopts, const struct option *newopts,
279 unsigned int *options_offset)
280{
281 unsigned int num_old, num_new, i;
282 struct option *merge;
283
284 if (!newopts || !oldopts || !options_offset)
285 print_bug("merge wrong");
286 for (num_old = 0; oldopts[num_old].name; num_old++);
287 for (num_new = 0; newopts[num_new].name; num_new++);
288
289 global_option_offset += OPTION_OFFSET;
290 *options_offset = global_option_offset;
291
292 merge = malloc(sizeof(struct option) * (num_new + num_old + 1));
293 if (!merge)
294 print_memory();
295 memcpy(merge, oldopts, num_old * sizeof(struct option));
296 for (i = 0; i < num_new; i++) {
297 merge[num_old + i] = newopts[i];
298 merge[num_old + i].val += *options_offset;
299 }
300 memset(merge + num_old + num_new, 0, sizeof(struct option));
Bart De Schuymer9895a8e2003-01-11 10:14:24 +0000301 /* only free dynamically allocated stuff */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000302 if (oldopts != ebt_original_options)
303 free(oldopts);
304
305 return merge;
306}
307
308void register_match(struct ebt_u_match *m)
309{
310 int size = m->size + sizeof(struct ebt_entry_match);
311 struct ebt_u_match **i;
312
313 m->m = (struct ebt_entry_match *)malloc(size);
314 if (!m->m)
315 print_memory();
316 strcpy(m->m->u.name, m->name);
317 m->m->match_size = m->size;
318 ebt_options = merge_options
319 (ebt_options, m->extra_ops, &(m->option_offset));
320 m->init(m->m);
321
322 for (i = &matches; *i; i = &((*i)->next));
323 m->next = NULL;
324 *i = m;
325}
326
327void register_watcher(struct ebt_u_watcher *w)
328{
329 int size = w->size + sizeof(struct ebt_entry_watcher);
330 struct ebt_u_watcher **i;
331
332 w->w = (struct ebt_entry_watcher *)malloc(size);
333 if (!w->w)
334 print_memory();
335 strcpy(w->w->u.name, w->name);
336 w->w->watcher_size = w->size;
337 ebt_options = merge_options
338 (ebt_options, w->extra_ops, &(w->option_offset));
339 w->init(w->w);
340
341 for (i = &watchers; *i; i = &((*i)->next));
342 w->next = NULL;
343 *i = w;
344}
345
346void register_target(struct ebt_u_target *t)
347{
348 int size = t->size + sizeof(struct ebt_entry_target);
349 struct ebt_u_target **i;
350
351 t->t = (struct ebt_entry_target *)malloc(size);
352 if (!t->t)
353 print_memory();
354 strcpy(t->t->u.name, t->name);
355 t->t->target_size = t->size;
356 ebt_options = merge_options
357 (ebt_options, t->extra_ops, &(t->option_offset));
358 t->init(t->t);
Bart De Schuymerc56a31a2002-07-25 08:16:08 +0000359
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000360 for (i = &targets; *i; i = &((*i)->next));
361 t->next = NULL;
362 *i = t;
363}
364
365void register_table(struct ebt_u_table *t)
366{
367 t->next = tables;
368 tables = t;
369}
370
Bart De Schuymer0cb01792003-05-04 16:52:04 +0000371const char *modprobe = NULL;
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000372/*
373 * blatently stolen (again) from iptables.c userspace program
374 * find out where the modprobe utility is located
375 */
Bart De Schuymerc8531032002-06-14 21:55:29 +0000376static char *get_modprobe(void)
377{
378 int procfile;
379 char *ret;
380
381 procfile = open(PROC_SYS_MODPROBE, O_RDONLY);
382 if (procfile < 0)
383 return NULL;
384
385 ret = malloc(1024);
386 if (ret) {
387 switch (read(procfile, ret, 1024)) {
388 case -1: goto fail;
389 case 1024: goto fail; /* Partial read. Wierd */
390 }
391 if (ret[strlen(ret)-1]=='\n')
392 ret[strlen(ret)-1]=0;
393 close(procfile);
394 return ret;
395 }
396 fail:
397 free(ret);
398 close(procfile);
399 return NULL;
400}
401
Bart De Schuymer0cb01792003-05-04 16:52:04 +0000402int ebtables_insmod(const char *modname)
Bart De Schuymerc8531032002-06-14 21:55:29 +0000403{
404 char *buf = NULL;
405 char *argv[3];
406
Bart De Schuymer9895a8e2003-01-11 10:14:24 +0000407 /* If they don't explicitly set it, read out of kernel */
Bart De Schuymerc8531032002-06-14 21:55:29 +0000408 if (!modprobe) {
409 buf = get_modprobe();
410 if (!buf)
411 return -1;
412 modprobe = buf;
413 }
414
415 switch (fork()) {
416 case 0:
417 argv[0] = (char *)modprobe;
418 argv[1] = (char *)modname;
419 argv[2] = NULL;
420 execv(argv[0], argv);
421
422 /* not usually reached */
423 exit(0);
424 case -1:
425 return -1;
426
427 default: /* parent */
428 wait(NULL);
429 }
430
431 free(buf);
432 return 0;
433}
434
Bart De Schuymer9a0fbf22003-01-11 16:16:54 +0000435static void list_extensions()
436{
437 struct ebt_u_table *tbl = tables;
438 struct ebt_u_target *t = targets;
439 struct ebt_u_match *m = matches;
440 struct ebt_u_watcher *w = watchers;
441
Bart De Schuymer57a3f6a2003-04-01 16:59:33 +0000442 PRINT_VERSION;
Bart De Schuymer9a0fbf22003-01-11 16:16:54 +0000443 printf("Supported userspace extensions:\n\nSupported tables:\n");
444 while(tbl) {
445 printf("%s\n", tbl->name);
446 tbl = tbl->next;
447 }
448 printf("\nSupported targets:\n");
449 while(t) {
450 printf("%s\n", t->name);
451 t = t->next;
452 }
453 printf("\nSupported matches:\n");
454 while(m) {
455 printf("%s\n", m->name);
456 m = m->next;
457 }
458 printf("\nSupported watchers:\n");
459 while(w) {
460 printf("%s\n", w->name);
461 w = w->next;
462 }
463 exit(0);
464}
465
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000466/*
467 * we use replace.flags, so we can't use the following values:
468 * 0x01 == OPT_COMMAND, 0x02 == OPT_TABLE, 0x100 == OPT_ZERO
469 */
Bart De Schuymer22d03a22003-05-03 20:28:22 +0000470#define LIST_N 0x04
471#define LIST_C 0x08
472#define LIST_X 0x10
473#define LIST_MAC2 0x20
474
475void print_mac(const char *mac)
476{
477 if (replace.flags & LIST_MAC2) {
478 int j;
479 for (j = 0; j < ETH_ALEN; j++)
480 printf("%02x%s", (unsigned char)mac[j],
481 (j==ETH_ALEN-1) ? "" : ":");
482 } else
483 printf("%s", ether_ntoa((struct ether_addr *) mac));
484}
485
486void print_mac_and_mask(const char *mac, const char *mask)
487{
488 char hlpmsk[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
489
490 print_mac(mac);
491 if (memcmp(mask, hlpmsk, 6)) {
492 printf("/");
493 print_mac(mask);
494 }
495}
496
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000497/*
498 * helper function for list_rules()
499 */
Bart De Schuymer60332e02002-06-23 08:01:47 +0000500static void list_em(struct ebt_u_entries *entries)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000501{
502 int i, j, space = 0, digits;
503 struct ebt_u_entry *hlp;
504 struct ebt_u_match_list *m_l;
505 struct ebt_u_watcher_list *w_l;
506 struct ebt_u_match *m;
507 struct ebt_u_watcher *w;
508 struct ebt_u_target *t;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000509
Bart De Schuymer60332e02002-06-23 08:01:47 +0000510 hlp = entries->entries;
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000511 if (replace.flags & LIST_X && entries->policy != EBT_ACCEPT) {
512 printf("ebtables -t %s -P %s %s\n", replace.name,
513 entries->name, standard_targets[-entries->policy - 1]);
514 } else if (!(replace.flags & LIST_X)) {
Bart De Schuymerc87c9642002-08-01 15:34:16 +0000515 printf("\nBridge chain: %s, entries: %d, policy: %s\n",
516 entries->name, entries->nentries,
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000517 standard_targets[-entries->policy - 1]);
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000518 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000519
Bart De Schuymer60332e02002-06-23 08:01:47 +0000520 i = entries->nentries;
Bart De Schuymerf8f8f292002-06-25 15:43:57 +0000521 while (i > 9) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000522 space++;
523 i /= 10;
524 }
525
Bart De Schuymer60332e02002-06-23 08:01:47 +0000526 for (i = 0; i < entries->nentries; i++) {
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000527 if (replace.flags & LIST_N) {
528 digits = 0;
Bart De Schuymer9895a8e2003-01-11 10:14:24 +0000529 /* A little work to get nice rule numbers. */
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000530 j = i + 1;
531 while (j > 9) {
532 digits++;
533 j /= 10;
534 }
535 for (j = 0; j < space - digits; j++)
536 printf(" ");
537 printf("%d. ", i + 1);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000538 }
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000539 if (replace.flags & LIST_X)
540 printf("ebtables -t %s -A %s ",
541 replace.name, entries->name);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000542
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000543 /*
544 * Don't print anything about the protocol if no protocol was
545 * specified, obviously this means any protocol will do.
546 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000547 if (!(hlp->bitmask & EBT_NOPROTO)) {
Bart De Schuymer60332e02002-06-23 08:01:47 +0000548 printf("-p ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000549 if (hlp->invflags & EBT_IPROTO)
550 printf("! ");
551 if (hlp->bitmask & EBT_802_3)
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000552 printf("Length ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000553 else {
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000554 struct ethertypeent *ent;
555
556 ent = getethertypebynumber(ntohs(hlp->ethproto));
557 if (!ent)
Bart De Schuymer60332e02002-06-23 08:01:47 +0000558 printf("0x%x ", ntohs(hlp->ethproto));
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000559 else
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000560 printf("%s ", ent->e_name);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000561 }
562 }
563 if (hlp->bitmask & EBT_SOURCEMAC) {
Bart De Schuymer60332e02002-06-23 08:01:47 +0000564 printf("-s ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000565 if (hlp->invflags & EBT_ISOURCE)
566 printf("! ");
567 if (!memcmp(hlp->sourcemac, mac_type_unicast, 6) &&
568 !memcmp(hlp->sourcemsk, msk_type_unicast, 6)) {
569 printf("Unicast");
570 goto endsrc;
571 }
572 if (!memcmp(hlp->sourcemac, mac_type_multicast, 6) &&
573 !memcmp(hlp->sourcemsk, msk_type_multicast, 6)) {
574 printf("Multicast");
575 goto endsrc;
576 }
577 if (!memcmp(hlp->sourcemac, mac_type_broadcast, 6) &&
578 !memcmp(hlp->sourcemsk, msk_type_broadcast, 6)) {
579 printf("Broadcast");
580 goto endsrc;
581 }
Bart De Schuymer22d03a22003-05-03 20:28:22 +0000582 print_mac_and_mask(hlp->sourcemac, hlp->sourcemsk);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000583endsrc:
Bart De Schuymer60332e02002-06-23 08:01:47 +0000584 printf(" ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000585 }
586 if (hlp->bitmask & EBT_DESTMAC) {
Bart De Schuymer60332e02002-06-23 08:01:47 +0000587 printf("-d ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000588 if (hlp->invflags & EBT_IDEST)
589 printf("! ");
590 if (!memcmp(hlp->destmac, mac_type_unicast, 6) &&
591 !memcmp(hlp->destmsk, msk_type_unicast, 6)) {
592 printf("Unicast");
593 goto enddst;
594 }
595 if (!memcmp(hlp->destmac, mac_type_multicast, 6) &&
596 !memcmp(hlp->destmsk, msk_type_multicast, 6)) {
597 printf("Multicast");
598 goto enddst;
599 }
600 if (!memcmp(hlp->destmac, mac_type_broadcast, 6) &&
601 !memcmp(hlp->destmsk, msk_type_broadcast, 6)) {
602 printf("Broadcast");
603 goto enddst;
604 }
Bart De Schuymer22d03a22003-05-03 20:28:22 +0000605 print_mac_and_mask(hlp->destmac, hlp->destmsk);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000606enddst:
Bart De Schuymer60332e02002-06-23 08:01:47 +0000607 printf(" ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000608 }
609 if (hlp->in[0] != '\0') {
Bart De Schuymer60332e02002-06-23 08:01:47 +0000610 printf("-i ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000611 if (hlp->invflags & EBT_IIN)
612 printf("! ");
Bart De Schuymer60332e02002-06-23 08:01:47 +0000613 printf("%s ", hlp->in);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000614 }
615 if (hlp->logical_in[0] != '\0') {
Bart De Schuymer60332e02002-06-23 08:01:47 +0000616 printf("--logical-in ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000617 if (hlp->invflags & EBT_ILOGICALIN)
618 printf("! ");
Bart De Schuymer60332e02002-06-23 08:01:47 +0000619 printf("%s ", hlp->logical_in);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000620 }
621 if (hlp->logical_out[0] != '\0') {
Bart De Schuymer60332e02002-06-23 08:01:47 +0000622 printf("--logical-out ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000623 if (hlp->invflags & EBT_ILOGICALOUT)
624 printf("! ");
Bart De Schuymerb3d8f262002-07-07 14:26:15 +0000625 printf("%s ", hlp->logical_out);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000626 }
627 if (hlp->out[0] != '\0') {
Bart De Schuymer60332e02002-06-23 08:01:47 +0000628 printf("-o ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000629 if (hlp->invflags & EBT_IOUT)
630 printf("! ");
Bart De Schuymerb3d8f262002-07-07 14:26:15 +0000631 printf("%s ", hlp->out);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000632 }
633
634 m_l = hlp->m_list;
635 while (m_l) {
636 m = find_match(m_l->m->u.name);
637 if (!m)
638 print_bug("Match not found");
639 m->print(hlp, m_l->m);
640 m_l = m_l->next;
641 }
642 w_l = hlp->w_list;
643 while (w_l) {
644 w = find_watcher(w_l->w->u.name);
645 if (!w)
646 print_bug("Watcher not found");
647 w->print(hlp, w_l->w);
648 w_l = w_l->next;
649 }
650
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000651 printf("-j ");
652 if (strcmp(hlp->t->u.name, EBT_STANDARD_TARGET))
653 printf("%s ", hlp->t->u.name);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000654 t = find_target(hlp->t->u.name);
655 if (!t)
656 print_bug("Target not found");
657 t->print(hlp, hlp->t);
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000658 if (replace.flags & LIST_C)
Bart De Schuymer73fccca2002-10-17 22:00:23 +0000659 printf(", pcnt = %llu -- bcnt = %llu",
660 replace.counters[entries->counter_offset + i].pcnt,
661 replace.counters[entries->counter_offset + i].bcnt);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000662 printf("\n");
663 hlp = hlp->next;
664 }
665}
666
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000667struct ebt_u_entries *nr_to_chain(int nr)
Bart De Schuymer60332e02002-06-23 08:01:47 +0000668{
669 if (nr == -1)
670 return NULL;
671 if (nr < NF_BR_NUMHOOKS)
672 return replace.hook_entry[nr];
673 else {
674 int i;
675 struct ebt_u_chain_list *cl = replace.udc;
676
677 i = nr - NF_BR_NUMHOOKS;
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000678 while (i > 0 && cl) {
Bart De Schuymer60332e02002-06-23 08:01:47 +0000679 cl = cl->next;
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000680 i--;
681 }
Bart De Schuymer60332e02002-06-23 08:01:47 +0000682 if (cl)
683 return cl->udc;
684 else
685 return NULL;
686 }
687}
688
Bart De Schuymercc440052002-11-06 21:10:33 +0000689static inline struct ebt_u_entries *to_chain()
Bart De Schuymer60332e02002-06-23 08:01:47 +0000690{
691 return nr_to_chain(replace.selected_hook);
692}
693
694struct ebt_u_stack
695{
696 int chain_nr;
697 int n;
698 struct ebt_u_entry *e;
699 struct ebt_u_entries *entries;
700};
701
Bart De Schuymer62423742002-07-14 19:06:20 +0000702static void check_for_loops()
Bart De Schuymer60332e02002-06-23 08:01:47 +0000703{
704 int chain_nr , i, j , k, sp = 0, verdict;
705 struct ebt_u_entries *entries, *entries2;
706 struct ebt_u_stack *stack = NULL;
707 struct ebt_u_entry *e;
708
709 i = -1;
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000710 /*
711 * initialize hook_mask to 0
712 */
Bart De Schuymer60332e02002-06-23 08:01:47 +0000713 while (1) {
714 i++;
715 if (i < NF_BR_NUMHOOKS && !(replace.valid_hooks & (1 << i)))
716 continue;
717 entries = nr_to_chain(i);
718 if (!entries)
719 break;
720 entries->hook_mask = 0;
721 }
722 if (i > NF_BR_NUMHOOKS) {
723 stack = (struct ebt_u_stack *)malloc((i - NF_BR_NUMHOOKS) *
724 sizeof(struct ebt_u_stack));
725 if (!stack)
726 print_memory();
727 }
728
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000729 /*
730 * check for loops, starting from every base chain
731 */
Bart De Schuymer60332e02002-06-23 08:01:47 +0000732 for (i = 0; i < NF_BR_NUMHOOKS; i++) {
733 if (!(replace.valid_hooks & (1 << i)))
734 continue;
735 entries = nr_to_chain(i);
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000736 /*
737 * (1 << NF_BR_NUMHOOKS) implies it's a standard chain
738 * (usefull in the final_check() funtions)
739 */
Bart De Schuymerb26649e2002-07-25 14:51:54 +0000740 entries->hook_mask = (1 << i) | (1 << NF_BR_NUMHOOKS);
Bart De Schuymer60332e02002-06-23 08:01:47 +0000741 chain_nr = i;
742
743 e = entries->entries;
744 for (j = 0; j < entries->nentries; j++) {
745 if (strcmp(e->t->u.name, EBT_STANDARD_TARGET))
746 goto letscontinue;
747 verdict = ((struct ebt_standard_target *)(e->t))->verdict;
748 if (verdict < 0)
749 goto letscontinue;
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000750 entries2 = nr_to_chain(verdict + NF_BR_NUMHOOKS);
Bart De Schuymer60332e02002-06-23 08:01:47 +0000751 entries2->hook_mask |= entries->hook_mask;
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000752 /*
753 * now see if we've been here before
754 */
Bart De Schuymer60332e02002-06-23 08:01:47 +0000755 for (k = 0; k < sp; k++)
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000756 if (stack[k].chain_nr == verdict + NF_BR_NUMHOOKS)
Bart De Schuymer1a0a9c32002-06-24 21:10:16 +0000757 print_error("Loop from chain %s to chain %s",
Bart De Schuymerc56a31a2002-07-25 08:16:08 +0000758 nr_to_chain(chain_nr)->name,
759 nr_to_chain(stack[k].chain_nr)->name);
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000760 /*
761 * jump to the chain, make sure we know how to get back
762 */
Bart De Schuymer60332e02002-06-23 08:01:47 +0000763 stack[sp].chain_nr = chain_nr;
764 stack[sp].n = j;
765 stack[sp].entries = entries;
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000766 stack[sp].e = e;
767 sp++;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000768 j = -1;
769 e = entries2->entries;
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000770 chain_nr = verdict + NF_BR_NUMHOOKS;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000771 entries = entries2;
772 continue;
773letscontinue:
774 e = e->next;
775 }
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000776 /*
777 * we are at the end of a standard chain
778 */
Bart De Schuymer60332e02002-06-23 08:01:47 +0000779 if (sp == 0)
780 continue;
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000781 /*
782 * go back to the chain one level higher
783 */
Bart De Schuymer60332e02002-06-23 08:01:47 +0000784 sp--;
785 j = stack[sp].n;
786 chain_nr = stack[sp].chain_nr;
787 e = stack[sp].e;
788 entries = stack[sp].entries;
789 goto letscontinue;
790 }
791 free(stack);
792 return;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000793}
794
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000795/*
796 * parse the chain name and return the corresponding nr
797 * returns -1 on failure
798 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000799int get_hooknr(char* arg)
800{
801 int i;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000802 struct ebt_u_chain_list *cl = replace.udc;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000803
Bart De Schuymer60332e02002-06-23 08:01:47 +0000804 for (i = 0; i < NF_BR_NUMHOOKS; i++) {
805 if (!(replace.valid_hooks & (1 << i)))
806 continue;
807 if (!strcmp(arg, replace.hook_entry[i]->name))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000808 return i;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000809 }
810 while(cl) {
811 if (!strcmp(arg, cl->udc->name))
812 return i;
813 i++;
814 cl = cl->next;
815 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000816 return -1;
817}
818
Bart De Schuymer62423742002-07-14 19:06:20 +0000819static void print_help()
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000820{
821 struct ebt_u_match_list *m_l;
822 struct ebt_u_watcher_list *w_l;
823
Bart De Schuymer57a3f6a2003-04-01 16:59:33 +0000824 PRINT_VERSION;
825 printf(
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000826"Usage:\n"
827"ebtables -[ADI] chain rule-specification [options]\n"
828"ebtables -P chain target\n"
829"ebtables -[LFZ] [chain]\n"
Bart De Schuymer5885b362002-12-03 20:51:36 +0000830"ebtables -[NX] [chain]\n"
831"ebtables -E old-chain-name new-chain-name\n\n"
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000832"Commands:\n"
Bart De Schuymer23f6dcf2002-08-17 09:14:07 +0000833"--append -A chain : append to chain\n"
834"--delete -D chain : delete matching rule from chain\n"
835"--delete -D chain rulenum : delete rule at position rulenum from chain\n"
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000836"--insert -I chain rulenum : insert rule at position rulenum in chain\n"
Bart De Schuymer23f6dcf2002-08-17 09:14:07 +0000837"--list -L [chain] : list the rules in a chain or in all chains\n"
838"--flush -F [chain] : delete all rules in chain or in all chains\n"
839"--init-table : replace the kernel table with the initial table\n"
840"--zero -Z [chain] : put counters on zero in chain or in all chains\n"
841"--policy -P chain target : change policy on chain to target\n"
842"--new-chain -N chain : create a user defined chain\n"
843"--rename-chain -E old new : rename a chain\n"
844"--delete-chain -X chain : delete a user defined chain\n"
Bart De Schuymer5885b362002-12-03 20:51:36 +0000845"--atomic-commit : update the kernel w/t table contained in <FILE>\n"
846"--atomic-init : put the initial kernel table into <FILE>\n"
847"--atomic-save : put the current kernel table into <FILE>\n"
Bart De Schuymer97819962002-12-11 21:23:07 +0000848"--atomic-file file : set <FILE> to file\n\n"
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000849"Options:\n"
850"--proto -p [!] proto : protocol hexadecimal, by name or LENGTH\n"
851"--src -s [!] address[/mask]: source mac address\n"
852"--dst -d [!] address[/mask]: destination mac address\n"
853"--in-if -i [!] name : network input interface name\n"
854"--out-if -o [!] name : network output interface name\n"
855"--logical-in [!] name : logical bridge input interface name\n"
856"--logical-out [!] name : logical bridge output interface name\n"
Bart De Schuymer5cbc8e02002-07-14 21:15:28 +0000857"--modprobe -M program : try to insert modules using this program\n"
Bart De Schuymer5885b362002-12-03 20:51:36 +0000858"--version -V : print package version\n\n"
859"Environment variable:\n"
860ATOMIC_ENV_VARIABLE " : if set <FILE> (see above) will equal its value"
861"\n\n");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000862
863 m_l = new_entry->m_list;
864 while (m_l) {
865 ((struct ebt_u_match *)m_l->m)->help();
866 printf("\n");
867 m_l = m_l->next;
868 }
869 w_l = new_entry->w_list;
870 while (w_l) {
871 ((struct ebt_u_watcher *)w_l->w)->help();
872 printf("\n");
873 w_l = w_l->next;
874 }
875 ((struct ebt_u_target *)new_entry->t)->help();
876 printf("\n");
877 if (table->help)
878 table->help(hooknames);
879 exit(0);
880}
881
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000882/*
883 * execute command L
884 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000885static void list_rules()
886{
887 int i;
888
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000889 if (!(replace.flags & LIST_X))
890 printf("Bridge table: %s\n", table->name);
Bart De Schuymer60332e02002-06-23 08:01:47 +0000891 if (replace.selected_hook != -1) {
892 list_em(to_chain());
893 } else {
894 struct ebt_u_chain_list *cl = replace.udc;
895
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000896 /*
897 * create new chains and rename standard chains when necessary
898 */
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000899 if (replace.flags & LIST_X) {
900 while (cl) {
901 printf("ebtables -t %s -N %s\n", replace.name,
902 cl->udc->name);
903 cl = cl->next;
904 }
905 cl = replace.udc;
906 for (i = 0; i < NF_BR_NUMHOOKS; i++)
907 if (replace.valid_hooks & (1 << i) &&
908 strcmp(replace.hook_entry[i]->name, hooknames[i]))
909 printf("ebtables -t %s -E %s %s\n",
910 replace.name, hooknames[i],
911 replace.hook_entry[i]->name);
912 }
Bart De Schuymer60332e02002-06-23 08:01:47 +0000913 i = 0;
914 while (1) {
915 if (i < NF_BR_NUMHOOKS) {
916 if (replace.valid_hooks & (1 << i))
917 list_em(replace.hook_entry[i]);
918 i++;
919 continue;
920 } else {
921 if (!cl)
922 break;
923 list_em(cl->udc);
924 cl = cl->next;
925 }
926 }
927 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000928}
929
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000930/*
931 * execute command P
932 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000933static void change_policy(int policy)
934{
935 int i;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000936 struct ebt_u_entries *entries = to_chain();
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000937
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000938 /*
939 * don't do anything if the policy is the same
940 */
Bart De Schuymer60332e02002-06-23 08:01:47 +0000941 if (entries->policy != policy) {
942 entries->policy = policy;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000943 replace.num_counters = replace.nentries;
944 if (replace.nentries) {
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000945 /*
946 * '+ 1' for the CNT_END
947 */
Bart De Schuymered053432002-07-21 19:35:39 +0000948 if (!(replace.counterchanges = (unsigned short *) malloc(
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000949 (replace.nentries + 1) * sizeof(unsigned short))))
950 print_memory();
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000951 /*
952 * done nothing special to the rules
953 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000954 for (i = 0; i < replace.nentries; i++)
Bart De Schuymered053432002-07-21 19:35:39 +0000955 replace.counterchanges[i] = CNT_NORM;
956 replace.counterchanges[replace.nentries] = CNT_END;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000957 }
958 else
Bart De Schuymered053432002-07-21 19:35:39 +0000959 replace.counterchanges = NULL;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000960 }
961 else
962 exit(0);
963}
964
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000965/*
966 * flush one chain or the complete table
967 * -1 == nothing to do
968 * 0 == give back to kernel
969 */
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000970static int flush_chains()
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000971{
Bart De Schuymer60332e02002-06-23 08:01:47 +0000972 int i, j, oldnentries, numdel;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000973 unsigned short *cnt;
974 struct ebt_u_entry *u_e, *tmp;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000975 struct ebt_u_entries *entries = to_chain();
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000976
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000977 /*
978 * flush whole table
979 */
Bart De Schuymer60332e02002-06-23 08:01:47 +0000980 if (!entries) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000981 if (replace.nentries == 0)
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000982 return -1;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000983 replace.nentries = 0;
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000984 /*
985 * no need for the kernel to give us counters back
986 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000987 replace.num_counters = 0;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000988
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000989 /*
990 * free everything and zero (n)entries
991 */
Bart De Schuymer60332e02002-06-23 08:01:47 +0000992 i = -1;
993 while (1) {
994 i++;
995 entries = nr_to_chain(i);
996 if (!entries) {
997 if (i < NF_BR_NUMHOOKS)
998 continue;
999 else
1000 break;
1001 }
1002 entries->nentries = 0;
1003 entries->counter_offset = 0;
1004 u_e = entries->entries;
1005 entries->entries = NULL;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001006 while (u_e) {
1007 free_u_entry(u_e);
1008 tmp = u_e->next;
1009 free(u_e);
1010 u_e = tmp;
1011 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001012 }
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001013 return 0;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001014 }
1015
Bart De Schuymer60332e02002-06-23 08:01:47 +00001016 if (entries->nentries == 0)
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001017 return -1;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001018 oldnentries = replace.nentries;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001019 replace.nentries -= entries->nentries;
1020 numdel = entries->nentries;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001021
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001022 if (replace.nentries) {
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001023 /*
1024 * +1 for CNT_END
1025 */
Bart De Schuymered053432002-07-21 19:35:39 +00001026 if ( !(replace.counterchanges = (unsigned short *)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001027 malloc((oldnentries + 1) * sizeof(unsigned short))) )
1028 print_memory();
Bart De Schuymer60332e02002-06-23 08:01:47 +00001029 }
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001030 /*
1031 * delete the counters belonging to the specified chain,
1032 * update counter_offset
1033 */
Bart De Schuymer60332e02002-06-23 08:01:47 +00001034 i = -1;
Bart De Schuymered053432002-07-21 19:35:39 +00001035 cnt = replace.counterchanges;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001036 while (1) {
1037 i++;
1038 entries = nr_to_chain(i);
1039 if (!entries) {
1040 if (i < NF_BR_NUMHOOKS)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001041 continue;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001042 else
1043 break;
1044 }
1045 if (i > replace.selected_hook)
1046 entries->counter_offset -= numdel;
1047 if (replace.nentries) {
1048 for (j = 0; j < entries->nentries; j++) {
1049 if (i == replace.selected_hook)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001050 *cnt = CNT_DEL;
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001051 else
1052 *cnt = CNT_NORM;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001053 cnt++;
1054 }
1055 }
Bart De Schuymer60332e02002-06-23 08:01:47 +00001056 }
1057
1058 if (replace.nentries) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001059 *cnt = CNT_END;
1060 replace.num_counters = oldnentries;
Bart De Schuymercc440052002-11-06 21:10:33 +00001061 } else
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001062 replace.num_counters = 0;
1063
Bart De Schuymer60332e02002-06-23 08:01:47 +00001064 entries = to_chain();
1065 entries->nentries = 0;
1066 u_e = entries->entries;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001067 while (u_e) {
1068 free_u_entry(u_e);
1069 tmp = u_e->next;
1070 free(u_e);
1071 u_e = tmp;
1072 }
Bart De Schuymer60332e02002-06-23 08:01:47 +00001073 entries->entries = NULL;
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001074 return 0;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001075}
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001076
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001077/*
1078 * -1 == no match
1079 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001080static int check_rule_exists(int rule_nr)
1081{
1082 struct ebt_u_entry *u_e;
1083 struct ebt_u_match_list *m_l, *m_l2;
1084 struct ebt_u_match *m;
1085 struct ebt_u_watcher_list *w_l, *w_l2;
1086 struct ebt_u_watcher *w;
1087 struct ebt_u_target *t = (struct ebt_u_target *)new_entry->t;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001088 struct ebt_u_entries *entries = to_chain();
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001089 int i, j, k;
1090
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001091 /*
1092 * handle '-D chain rulenr' command
1093 */
Bart De Schuymerc3b97f52003-04-17 17:03:49 +00001094 if (rule_nr != 0) {
Bart De Schuymer60332e02002-06-23 08:01:47 +00001095 if (rule_nr > entries->nentries)
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001096 return -1;
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001097 /*
1098 * user starts counting from 1
1099 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001100 return rule_nr - 1;
1101 }
Bart De Schuymer60332e02002-06-23 08:01:47 +00001102 u_e = entries->entries;
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001103 /*
1104 * check for an existing rule (if there are duplicate rules,
1105 * take the first occurance)
1106 */
Bart De Schuymer60332e02002-06-23 08:01:47 +00001107 for (i = 0; i < entries->nentries; i++, u_e = u_e->next) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001108 if (!u_e)
1109 print_bug("Hmm, trouble");
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001110 if (u_e->ethproto != new_entry->ethproto)
1111 continue;
1112 if (strcmp(u_e->in, new_entry->in))
1113 continue;
1114 if (strcmp(u_e->out, new_entry->out))
1115 continue;
1116 if (strcmp(u_e->logical_in, new_entry->logical_in))
1117 continue;
1118 if (strcmp(u_e->logical_out, new_entry->logical_out))
1119 continue;
1120 if (new_entry->bitmask & EBT_SOURCEMAC &&
1121 memcmp(u_e->sourcemac, new_entry->sourcemac, ETH_ALEN))
1122 continue;
1123 if (new_entry->bitmask & EBT_DESTMAC &&
1124 memcmp(u_e->destmac, new_entry->destmac, ETH_ALEN))
1125 continue;
1126 if (new_entry->bitmask != u_e->bitmask ||
1127 new_entry->invflags != u_e->invflags)
1128 continue;
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001129 /*
1130 * compare all matches
1131 */
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001132 m_l = new_entry->m_list;
1133 j = 0;
1134 while (m_l) {
1135 m = (struct ebt_u_match *)(m_l->m);
1136 m_l2 = u_e->m_list;
1137 while (m_l2 && strcmp(m_l2->m->u.name, m->m->u.name))
1138 m_l2 = m_l2->next;
1139 if (!m_l2 || !m->compare(m->m, m_l2->m))
1140 goto letscontinue;
1141 j++;
1142 m_l = m_l->next;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001143 }
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001144 /*
1145 * now be sure they have the same nr of matches
1146 */
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001147 k = 0;
1148 m_l = u_e->m_list;
1149 while (m_l) {
1150 k++;
1151 m_l = m_l->next;
1152 }
1153 if (j != k)
1154 continue;
1155
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001156 /*
1157 * compare all watchers
1158 */
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001159 w_l = new_entry->w_list;
1160 j = 0;
1161 while (w_l) {
1162 w = (struct ebt_u_watcher *)(w_l->w);
1163 w_l2 = u_e->w_list;
1164 while (w_l2 && strcmp(w_l2->w->u.name, w->w->u.name))
1165 w_l2 = w_l2->next;
1166 if (!w_l2 || !w->compare(w->w, w_l2->w))
1167 goto letscontinue;
1168 j++;
1169 w_l = w_l->next;
1170 }
1171 k = 0;
1172 w_l = u_e->w_list;
1173 while (w_l) {
1174 k++;
1175 w_l = w_l->next;
1176 }
1177 if (j != k)
1178 continue;
1179 if (strcmp(t->t->u.name, u_e->t->u.name))
1180 continue;
1181 if (!t->compare(t->t, u_e->t))
1182 continue;
1183 return i;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001184letscontinue:
1185 }
1186 return -1;
1187}
1188
Bart De Schuymer9895a8e2003-01-11 10:14:24 +00001189/* execute command A or I */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001190static void add_rule(int rule_nr)
1191{
1192 int i, j;
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001193 struct ebt_u_entry **u_e;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001194 unsigned short *cnt;
1195 struct ebt_u_match_list *m_l;
1196 struct ebt_u_watcher_list *w_l;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001197 struct ebt_u_entries *entries = to_chain(), *entries2;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001198
Bart De Schuymerc3b97f52003-04-17 17:03:49 +00001199 if (rule_nr <= 0)
1200 rule_nr += entries->nentries;
1201 else
1202 rule_nr--;
1203 if (rule_nr > entries->nentries || rule_nr < 0)
1204 print_error("The specified rule number is incorrect");
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001205 /*
1206 * we're adding one rule
1207 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001208 replace.num_counters = replace.nentries;
1209 replace.nentries++;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001210 entries->nentries++;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001211
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001212 /*
1213 * handle counter stuff
1214 * +1 for CNT_END
1215 */
Bart De Schuymered053432002-07-21 19:35:39 +00001216 if ( !(replace.counterchanges = (unsigned short *)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001217 malloc((replace.nentries + 1) * sizeof(unsigned short))) )
1218 print_memory();
Bart De Schuymered053432002-07-21 19:35:39 +00001219 cnt = replace.counterchanges;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001220 for (i = 0; i < replace.selected_hook; i++) {
Bart De Schuymer60332e02002-06-23 08:01:47 +00001221 if (i < NF_BR_NUMHOOKS && !(replace.valid_hooks & (1 << i)))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001222 continue;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001223 entries2 = nr_to_chain(i);
1224 for (j = 0; j < entries2->nentries; j++) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001225 *cnt = CNT_NORM;
1226 cnt++;
1227 }
1228 }
1229 for (i = 0; i < rule_nr; i++) {
1230 *cnt = CNT_NORM;
1231 cnt++;
1232 }
1233 *cnt = CNT_ADD;
1234 cnt++;
Bart De Schuymered053432002-07-21 19:35:39 +00001235 while (cnt != replace.counterchanges + replace.nentries) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001236 *cnt = CNT_NORM;
1237 cnt++;
1238 }
1239 *cnt = CNT_END;
1240
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001241 /*
1242 * go to the right position in the chain
1243 */
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001244 u_e = &entries->entries;
1245 for (i = 0; i < rule_nr; i++)
1246 u_e = &(*u_e)->next;
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001247 /*
1248 * insert the rule
1249 */
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001250 new_entry->next = *u_e;
1251 *u_e = new_entry;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001252
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001253 /*
1254 * put the ebt_[match, watcher, target] pointers in place
1255 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001256 m_l = new_entry->m_list;
1257 while (m_l) {
1258 m_l->m = ((struct ebt_u_match *)m_l->m)->m;
1259 m_l = m_l->next;
1260 }
1261 w_l = new_entry->w_list;
1262 while (w_l) {
1263 w_l->w = ((struct ebt_u_watcher *)w_l->w)->w;
1264 w_l = w_l->next;
1265 }
1266 new_entry->t = ((struct ebt_u_target *)new_entry->t)->t;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001267
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001268 /*
1269 * update the counter_offset of chains behind this one
1270 */
Bart De Schuymer60332e02002-06-23 08:01:47 +00001271 i = replace.selected_hook;
1272 while (1) {
1273 i++;
1274 entries = nr_to_chain(i);
1275 if (!entries) {
1276 if (i < NF_BR_NUMHOOKS)
1277 continue;
1278 else
1279 break;
1280 } else
1281 entries->counter_offset++;
1282 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001283}
1284
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001285/*
1286 * execute command D
1287 */
Bart De Schuymercc440052002-11-06 21:10:33 +00001288static void delete_rule(int begin, int end)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001289{
Bart De Schuymercc440052002-11-06 21:10:33 +00001290 int j, lentmp = 0, nr_deletes;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001291 unsigned short *cnt;
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001292 struct ebt_u_entry **u_e, *u_e2;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001293 struct ebt_u_entries *entries = to_chain(), *entries2;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001294
Bart De Schuymer336f35e2003-05-22 20:53:12 +00001295 if (begin < 0)
Bart De Schuymerc3b97f52003-04-17 17:03:49 +00001296 begin += entries->nentries + 1;
Bart De Schuymerc3b97f52003-04-17 17:03:49 +00001297 if (end < 0)
1298 end += entries->nentries + 1;
Bart De Schuymer1446c292003-05-25 09:47:01 +00001299
1300 if (begin < 0 || begin > end || end > entries->nentries)
Bart De Schuymerc3b97f52003-04-17 17:03:49 +00001301 print_error("Sorry, wrong rule numbers");
Bart De Schuymer336f35e2003-05-22 20:53:12 +00001302
Bart De Schuymercc440052002-11-06 21:10:33 +00001303 if ((begin = check_rule_exists(begin)) == -1 ||
1304 (end = check_rule_exists(end)) == -1)
Bart De Schuymer60332e02002-06-23 08:01:47 +00001305 print_error("Sorry, rule does not exist");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001306
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001307 /*
1308 * we're deleting rules
1309 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001310 replace.num_counters = replace.nentries;
Bart De Schuymercc440052002-11-06 21:10:33 +00001311 nr_deletes = end - begin + 1;
1312 replace.nentries -= nr_deletes;
1313 entries->nentries -= nr_deletes;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001314
1315 if (replace.nentries) {
1316 for (j = 0; j < replace.selected_hook; j++) {
Bart De Schuymer60332e02002-06-23 08:01:47 +00001317 if (j < NF_BR_NUMHOOKS &&
1318 !(replace.valid_hooks & (1 << j)))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001319 continue;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001320 entries2 = nr_to_chain(j);
1321 lentmp += entries2->nentries;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001322 }
Bart De Schuymercc440052002-11-06 21:10:33 +00001323 lentmp += begin;
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001324 /*
1325 * +1 for CNT_END
1326 */
Bart De Schuymered053432002-07-21 19:35:39 +00001327 if ( !(replace.counterchanges = (unsigned short *)malloc(
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001328 (replace.num_counters + 1) * sizeof(unsigned short))) )
1329 print_memory();
Bart De Schuymered053432002-07-21 19:35:39 +00001330 cnt = replace.counterchanges;
Bart De Schuymercc440052002-11-06 21:10:33 +00001331 for (j = 0; j < lentmp; j++, cnt++)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001332 *cnt = CNT_NORM;
Bart De Schuymercc440052002-11-06 21:10:33 +00001333 for (j = 0; j < nr_deletes; j++, cnt++)
1334 *cnt = CNT_DEL;
1335
1336 for (j = 0; j < replace.num_counters - lentmp - nr_deletes;
1337 j++, cnt++)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001338 *cnt = CNT_NORM;
Bart De Schuymercc440052002-11-06 21:10:33 +00001339
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001340 *cnt = CNT_END;
1341 }
1342 else
1343 replace.num_counters = 0;
1344
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001345 /*
1346 * go to the right position in the chain
1347 */
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001348 u_e = &entries->entries;
Bart De Schuymercc440052002-11-06 21:10:33 +00001349 for (j = 0; j < begin; j++)
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001350 u_e = &(*u_e)->next;
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001351 /*
1352 * remove the rules
1353 */
Bart De Schuymercc440052002-11-06 21:10:33 +00001354 j = nr_deletes;
1355 while(j--) {
1356 u_e2 = *u_e;
1357 *u_e = (*u_e)->next;
Bart De Schuymer9895a8e2003-01-11 10:14:24 +00001358 /* free everything */
Bart De Schuymercc440052002-11-06 21:10:33 +00001359 free_u_entry(u_e2);
1360 free(u_e2);
1361 }
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001362
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001363 /*
1364 * update the counter_offset of chains behind this one
1365 */
Bart De Schuymercc440052002-11-06 21:10:33 +00001366 j = replace.selected_hook;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001367 while (1) {
Bart De Schuymercc440052002-11-06 21:10:33 +00001368 j++;
1369 entries = nr_to_chain(j);
Bart De Schuymer60332e02002-06-23 08:01:47 +00001370 if (!entries) {
Bart De Schuymercc440052002-11-06 21:10:33 +00001371 if (j < NF_BR_NUMHOOKS)
Bart De Schuymer60332e02002-06-23 08:01:47 +00001372 continue;
1373 else
1374 break;
Bart De Schuymercc440052002-11-06 21:10:33 +00001375 } else
1376 entries->counter_offset -= nr_deletes;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001377 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001378}
1379
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001380/*
1381 * execute command Z
1382 */
Bart De Schuymer62423742002-07-14 19:06:20 +00001383static void zero_counters(int zerochain)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001384{
1385
1386 if (zerochain == -1) {
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001387 /*
1388 * tell main() we don't update the counters
1389 * this results in tricking the kernel to zero its counters,
1390 * naively expecting userspace to update its counters. Muahahaha
1391 */
Bart De Schuymered053432002-07-21 19:35:39 +00001392 replace.counterchanges = NULL;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001393 replace.num_counters = 0;
1394 } else {
1395 int i, j;
1396 unsigned short *cnt;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001397 struct ebt_u_entries *entries = nr_to_chain(zerochain), *e2;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001398
Bart De Schuymer60332e02002-06-23 08:01:47 +00001399 if (entries->nentries == 0)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001400 exit(0);
Bart De Schuymered053432002-07-21 19:35:39 +00001401 replace.counterchanges = (unsigned short *)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001402 malloc((replace.nentries + 1) * sizeof(unsigned short));
Bart De Schuymered053432002-07-21 19:35:39 +00001403 if (!replace.counterchanges)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001404 print_memory();
Bart De Schuymered053432002-07-21 19:35:39 +00001405 cnt = replace.counterchanges;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001406 for (i = 0; i < zerochain; i++) {
Bart De Schuymer60332e02002-06-23 08:01:47 +00001407 if (i < NF_BR_NUMHOOKS &&
1408 !(replace.valid_hooks & (1 << i)))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001409 continue;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001410 e2 = nr_to_chain(i);
1411 for (j = 0; j < e2->nentries; j++) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001412 *cnt = CNT_NORM;
1413 cnt++;
1414 }
1415 }
Bart De Schuymer60332e02002-06-23 08:01:47 +00001416 for (i = 0; i < entries->nentries; i++) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001417 *cnt = CNT_ZERO;
1418 cnt++;
1419 }
Bart De Schuymered053432002-07-21 19:35:39 +00001420 while (cnt != replace.counterchanges + replace.nentries) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001421 *cnt = CNT_NORM;
1422 cnt++;
1423 }
1424 *cnt = CNT_END;
1425 }
1426}
1427
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001428/*
1429 * Checks the type for validity and calls getethertypebynumber()
1430 */
1431struct ethertypeent *parseethertypebynumber(int type)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001432{
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001433 if (type < 1536)
1434 print_error("Ethernet protocols have values >= 0x0600");
1435 if (type > 0xffff)
1436 print_error("Ethernet protocols have values <= 0xffff");
1437 return getethertypebynumber(type);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001438}
1439
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001440/*
1441 * put the mac address into 6 (ETH_ALEN) bytes
1442 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001443int getmac_and_mask(char *from, char *to, char *mask)
1444{
1445 char *p;
1446 int i;
Bart De Schuymer41830412002-06-05 19:41:28 +00001447 struct ether_addr *addr;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001448
1449 if (strcasecmp(from, "Unicast") == 0) {
1450 memcpy(to, mac_type_unicast, ETH_ALEN);
1451 memcpy(mask, msk_type_unicast, ETH_ALEN);
1452 return 0;
1453 }
1454 if (strcasecmp(from, "Multicast") == 0) {
1455 memcpy(to, mac_type_multicast, ETH_ALEN);
1456 memcpy(mask, msk_type_multicast, ETH_ALEN);
1457 return 0;
1458 }
1459 if (strcasecmp(from, "Broadcast") == 0) {
1460 memcpy(to, mac_type_broadcast, ETH_ALEN);
1461 memcpy(mask, msk_type_broadcast, ETH_ALEN);
1462 return 0;
1463 }
1464 if ( (p = strrchr(from, '/')) != NULL) {
1465 *p = '\0';
Bart De Schuymer41830412002-06-05 19:41:28 +00001466 if (!(addr = ether_aton(p + 1)))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001467 return -1;
Bart De Schuymer41830412002-06-05 19:41:28 +00001468 memcpy(mask, addr, ETH_ALEN);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001469 } else
1470 memset(mask, 0xff, ETH_ALEN);
Bart De Schuymer41830412002-06-05 19:41:28 +00001471 if (!(addr = ether_aton(from)))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001472 return -1;
Bart De Schuymer41830412002-06-05 19:41:28 +00001473 memcpy(to, addr, ETH_ALEN);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001474 for (i = 0; i < ETH_ALEN; i++)
1475 to[i] &= mask[i];
1476 return 0;
1477}
1478
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001479/*
1480 * executes the final_check() function for all extensions used by the rule
1481 */
Bart De Schuymer62423742002-07-14 19:06:20 +00001482static void do_final_checks(struct ebt_u_entry *e, struct ebt_u_entries *entries)
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +00001483{
1484 struct ebt_u_match_list *m_l;
1485 struct ebt_u_watcher_list *w_l;
1486 struct ebt_u_target *t;
1487 struct ebt_u_match *m;
1488 struct ebt_u_watcher *w;
1489
1490 m_l = e->m_list;
1491 w_l = e->w_list;
1492 while (m_l) {
1493 m = find_match(m_l->m->u.name);
1494 m->final_check(e, m_l->m, replace.name,
1495 entries->hook_mask, 1);
1496 m_l = m_l->next;
1497 }
1498 while (w_l) {
1499 w = find_watcher(w_l->w->u.name);
1500 w->final_check(e, w_l->w, replace.name,
1501 entries->hook_mask, 1);
1502 w_l = w_l->next;
1503 }
1504 t = find_target(e->t->u.name);
1505 t->final_check(e, e->t, replace.name,
1506 entries->hook_mask, 1);
1507}
1508
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001509/*
1510 * used for the -X command
1511 */
Bart De Schuymer62423742002-07-14 19:06:20 +00001512static void check_for_references(int chain_nr)
Bart De Schuymerb909f9b2002-06-26 18:35:31 +00001513{
1514 int i = -1, j;
1515 struct ebt_u_entries *entries;
1516 struct ebt_u_entry *e;
1517
1518 while (1) {
1519 i++;
1520 entries = nr_to_chain(i);
1521 if (!entries) {
1522 if (i < NF_BR_NUMHOOKS)
1523 continue;
1524 else
1525 break;
1526 }
1527 e = entries->entries;
1528 j = 0;
1529 while (e) {
Bart De Schuymerc27432e2003-01-09 22:01:07 +00001530 int chain_jmp;
1531
Bart De Schuymerb909f9b2002-06-26 18:35:31 +00001532 j++;
1533 if (strcmp(e->t->u.name, EBT_STANDARD_TARGET)) {
1534 e = e->next;
1535 continue;
1536 }
Bart De Schuymerc27432e2003-01-09 22:01:07 +00001537 chain_jmp = ((struct ebt_standard_target *)e->t)->verdict;
1538 if (chain_jmp == chain_nr)
Bart De Schuymerb909f9b2002-06-26 18:35:31 +00001539 print_error("Can't delete the chain, it's referenced "
1540 "in chain %s, rule %d", entries->name, j);
Bart De Schuymerc27432e2003-01-09 22:01:07 +00001541 /* adjust the chain jumps when necessary */
1542 if (chain_jmp > chain_nr)
1543 ((struct ebt_standard_target *)e->t)->verdict--;
Bart De Schuymerb909f9b2002-06-26 18:35:31 +00001544 e = e->next;
1545 }
1546 }
1547}
1548
Bart De Schuymercc440052002-11-06 21:10:33 +00001549static int parse_delete_rule(const char *argv, int *rule_nr, int *rule_nr_end)
1550{
1551 char *colon = strchr(argv, ':'), *buffer;
1552
1553 if (colon) {
1554 *colon = '\0';
1555 if (*(colon + 1) == '\0')
Bart De Schuymerc3b97f52003-04-17 17:03:49 +00001556 *rule_nr_end = -1; /* until the last rule */
Bart De Schuymercc440052002-11-06 21:10:33 +00001557 else {
1558 *rule_nr_end = strtol(colon + 1, &buffer, 10);
Bart De Schuymerc3b97f52003-04-17 17:03:49 +00001559 if (*buffer != '\0' || *rule_nr_end == 0)
Bart De Schuymercc440052002-11-06 21:10:33 +00001560 return -1;
1561 }
1562 }
1563 if (colon == argv)
Bart De Schuymerc3b97f52003-04-17 17:03:49 +00001564 *rule_nr = 1; /* beginning with the first rule */
Bart De Schuymercc440052002-11-06 21:10:33 +00001565 else {
1566 *rule_nr = strtol(argv, &buffer, 10);
Bart De Schuymerc3b97f52003-04-17 17:03:49 +00001567 if (*buffer != '\0' || *rule_nr == 0)
Bart De Schuymercc440052002-11-06 21:10:33 +00001568 return -1;
1569 }
1570 if (!colon)
1571 *rule_nr_end = *rule_nr;
Bart De Schuymercc440052002-11-06 21:10:33 +00001572 return 0;
1573}
1574
Bart De Schuymera615b962002-11-03 14:54:09 +00001575static int invert = 0;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001576int check_inverse(const char option[])
1577{
1578 if (strcmp(option, "!") == 0) {
Bart De Schuymera615b962002-11-03 14:54:09 +00001579 if (invert == 1)
1580 print_error("double use of '!' not allowed");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001581 optind++;
Bart De Schuymera615b962002-11-03 14:54:09 +00001582 invert = 1;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001583 return 1;
1584 }
Bart De Schuymera615b962002-11-03 14:54:09 +00001585 return invert;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001586}
1587
1588void check_option(unsigned int *flags, unsigned int mask)
1589{
1590 if (*flags & mask)
1591 print_error("Multiple use of same option not allowed");
1592 *flags |= mask;
1593}
1594
Bart De Schuymer0cb01792003-05-04 16:52:04 +00001595static void get_kernel_table()
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001596{
1597 if ( !(table = find_table(replace.name)) )
1598 print_error("Bad table name");
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001599 /*
1600 * get the kernel's information
1601 */
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001602 if (get_table(&replace)) {
Bart De Schuymer0cb01792003-05-04 16:52:04 +00001603 ebtables_insmod("ebtables");
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001604 if (get_table(&replace))
1605 print_error("The kernel doesn't support the ebtables "
1606 "%s table", replace.name);
1607 }
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001608 /*
Bart De Schuymer5885b362002-12-03 20:51:36 +00001609 * when listing a table contained in a file, we don't demand that
1610 * the user knows the table's name
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001611 */
Bart De Schuymer62a7fdb2002-08-24 21:01:21 +00001612 if ( !(table = find_table(replace.name)) )
1613 print_error("Bad table name");
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001614}
1615
Bart De Schuymerc5075142002-08-18 14:21:19 +00001616#define print_if_l_error print_error("Interface name length must be less " \
1617 "than %d", IFNAMSIZ)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001618#define OPT_COMMAND 0x01
1619#define OPT_TABLE 0x02
1620#define OPT_IN 0x04
1621#define OPT_OUT 0x08
1622#define OPT_JUMP 0x10
1623#define OPT_PROTOCOL 0x20
1624#define OPT_SOURCE 0x40
1625#define OPT_DEST 0x80
1626#define OPT_ZERO 0x100
1627#define OPT_LOGICALIN 0x200
1628#define OPT_LOGICALOUT 0x400
Bart De Schuymer5885b362002-12-03 20:51:36 +00001629/* the main thing */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001630int main(int argc, char *argv[])
1631{
Bart De Schuymer923a5732002-08-11 12:01:33 +00001632 char *buffer;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001633 int c, i;
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001634 /*
1635 * this special one for the -Z option (we can have -Z <this> -L <that>)
1636 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001637 int zerochain = -1;
Bart De Schuymerf8f8f292002-06-25 15:43:57 +00001638 int policy = 0;
Bart De Schuymerc3b97f52003-04-17 17:03:49 +00001639 int rule_nr = 0; /* used for -[D,I] */
1640 int rule_nr_end = 0; /* used for -I */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001641 struct ebt_u_target *t;
1642 struct ebt_u_match *m;
1643 struct ebt_u_watcher *w;
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001644 struct ebt_u_match_list *m_l;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001645 struct ebt_u_watcher_list *w_l;
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001646 struct ebt_u_entries *entries;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001647
Bart De Schuymera615b962002-11-03 14:54:09 +00001648 opterr = 0;
1649
Bart De Schuymer5885b362002-12-03 20:51:36 +00001650 replace.filename = getenv(ATOMIC_ENV_VARIABLE);
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001651 /*
1652 * initialize the table name, OPT_ flags, selected hook and command
1653 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001654 strcpy(replace.name, "filter");
1655 replace.flags = 0;
1656 replace.selected_hook = -1;
1657 replace.command = 'h';
Bart De Schuymered053432002-07-21 19:35:39 +00001658 replace.counterchanges = NULL;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001659
1660 new_entry = (struct ebt_u_entry *)malloc(sizeof(struct ebt_u_entry));
1661 if (!new_entry)
1662 print_memory();
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001663 /*
1664 * put some sane values in our new entry
1665 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001666 initialize_entry(new_entry);
1667
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001668 /*
1669 * The scenario induced by this loop makes that:
1670 * '-t' ,'-M' and --atomic (if specified) have to come
1671 * before '-A' and the like
1672 */
Bart De Schuymer60332e02002-06-23 08:01:47 +00001673
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001674 /*
1675 * getopt saves the day
1676 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001677 while ((c = getopt_long(argc, argv,
Bart De Schuymeraac31142002-08-11 11:57:52 +00001678 "-A:D:I:N:E:X:L::Z::F::P:Vhi:o:j:p:s:d:t:M:", ebt_options, NULL)) != -1) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001679 switch (c) {
1680
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001681 case 'A': /* add a rule */
1682 case 'D': /* delete a rule */
1683 case 'P': /* define policy */
1684 case 'I': /* insert a rule */
1685 case 'N': /* make a user defined chain */
1686 case 'E': /* rename chain */
1687 case 'X': /* delete chain */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001688 replace.command = c;
1689 if (replace.flags & OPT_COMMAND)
1690 print_error("Multiple commands not allowed");
1691 replace.flags |= OPT_COMMAND;
Bart De Schuymer0cb01792003-05-04 16:52:04 +00001692 get_kernel_table();
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001693 if (optarg[0] == '-' || !strcmp(optarg, "!"))
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001694 print_error("No chain name specified");
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001695 if (c == 'N') {
1696 struct ebt_u_chain_list *cl, **cl2;
1697
1698 if (get_hooknr(optarg) != -1)
1699 print_error("Chain %s already exists",
1700 optarg);
1701 if (find_target(optarg))
1702 print_error("Target with name %s exists"
1703 , optarg);
1704 if (strlen(optarg) >= EBT_CHAIN_MAXNAMELEN)
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001705 print_error("Chain name length can't exceed %d",
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001706 EBT_CHAIN_MAXNAMELEN - 1);
1707 cl = (struct ebt_u_chain_list *)
1708 malloc(sizeof(struct ebt_u_chain_list));
1709 if (!cl)
1710 print_memory();
1711 cl->next = NULL;
1712 cl->udc = (struct ebt_u_entries *)
1713 malloc(sizeof(struct ebt_u_entries));
1714 if (!cl->udc)
1715 print_memory();
1716 cl->udc->nentries = 0;
1717 cl->udc->policy = EBT_ACCEPT;
1718 cl->udc->counter_offset = replace.nentries;
1719 cl->udc->hook_mask = 0;
1720 strcpy(cl->udc->name, optarg);
1721 cl->udc->entries = NULL;
1722 cl->kernel_start = NULL;
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001723 /*
1724 * put the new chain at the end
1725 */
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001726 cl2 = &replace.udc;
1727 while (*cl2)
1728 cl2 = &((*cl2)->next);
1729 *cl2 = cl;
1730 break;
1731 }
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001732 if ((replace.selected_hook = get_hooknr(optarg)) == -1)
1733 print_error("Chain %s doesn't exist", optarg);
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001734 if (c == 'E') {
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001735 if (optind >= argc || argv[optind][0] == '-' ||
1736 !strcmp(argv[optind], "!"))
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001737 print_error("No new chain name specified");
1738 if (strlen(argv[optind]) >= EBT_CHAIN_MAXNAMELEN)
1739 print_error("Chain name len can't exceed %d",
1740 EBT_CHAIN_MAXNAMELEN - 1);
1741 if (get_hooknr(argv[optind]) != -1)
1742 print_error("Chain %s already exists",
1743 argv[optind]);
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001744 if (find_target(argv[optind]))
1745 print_error("Target with name %s exists"
1746 , argv[optind]);
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001747 entries = to_chain();
1748 strcpy(entries->name, argv[optind]);
1749 optind++;
1750 break;
1751 }
1752 if (c == 'X') {
1753 struct ebt_u_chain_list *cl, **cl2;
1754
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001755 if (replace.selected_hook < NF_BR_NUMHOOKS)
1756 print_error("You can't remove a standard chain");
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001757 /*
Bart De Schuymerc27432e2003-01-09 22:01:07 +00001758 * if the chain is referenced, don't delete it,
1759 * also decrement jumps to a chain behind the
1760 * one we're deleting
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001761 */
Bart De Schuymerb909f9b2002-06-26 18:35:31 +00001762 check_for_references(replace.selected_hook - NF_BR_NUMHOOKS);
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001763 flush_chains();
1764 entries = to_chain();
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001765 cl2 = &(replace.udc);
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001766 while ((*cl2)->udc != entries)
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001767 cl2 = &((*cl2)->next);
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001768 cl = (*cl2);
1769 (*cl2) = (*cl2)->next;
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001770 free(cl->udc);
1771 free(cl);
1772 break;
1773 }
1774
Bart De Schuymercc440052002-11-06 21:10:33 +00001775 if (c == 'D' && optind < argc &&
Bart De Schuymerc3b97f52003-04-17 17:03:49 +00001776 (argv[optind][0] != '-' ||
1777 (argv[optind][1] >= '0' && argv[optind][1] <= '9'))) {
Bart De Schuymercc440052002-11-06 21:10:33 +00001778 if (parse_delete_rule(argv[optind],
1779 &rule_nr, &rule_nr_end))
1780 print_error("Problem with the "
1781 "specified rule number(s)");
1782 optind++;
1783 }
1784 if (c == 'I') {
Bart De Schuymerc3b97f52003-04-17 17:03:49 +00001785 if (optind >= argc || (argv[optind][0] == '-' &&
1786 (argv[optind][1] < '0' || argv[optind][1] > '9')))
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001787 print_error("No rulenr for -I"
1788 " specified");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001789 rule_nr = strtol(argv[optind], &buffer, 10);
Bart De Schuymerc3b97f52003-04-17 17:03:49 +00001790 if (*buffer != '\0')
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001791 print_error("Problem with the "
1792 "specified rule number");
1793 optind++;
1794 }
1795 if (c == 'P') {
1796 if (optind >= argc)
1797 print_error("No policy specified");
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001798 policy = 0;
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001799 for (i = 0; i < NUM_STANDARD_TARGETS; i++)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001800 if (!strcmp(argv[optind],
1801 standard_targets[i])) {
Bart De Schuymer60332e02002-06-23 08:01:47 +00001802 policy = -i -1;
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001803 if (policy == EBT_CONTINUE)
1804 policy = 0;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001805 break;
1806 }
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001807 if (policy == 0)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001808 print_error("Wrong policy");
1809 optind++;
1810 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001811 break;
1812
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001813 case 'L': /* list */
1814 case 'F': /* flush */
1815 case 'Z': /* zero counters */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001816 if (c == 'Z') {
1817 if (replace.flags & OPT_ZERO)
1818 print_error("Multiple commands"
1819 " not allowed");
1820 if ( (replace.flags & OPT_COMMAND &&
1821 replace.command != 'L'))
1822 print_error("command -Z only allowed "
1823 "together with command -L");
1824 replace.flags |= OPT_ZERO;
1825 } else {
1826 replace.command = c;
1827 if (replace.flags & OPT_COMMAND)
1828 print_error("Multiple commands"
1829 " not allowed");
1830 replace.flags |= OPT_COMMAND;
1831 }
Bart De Schuymer0cb01792003-05-04 16:52:04 +00001832 get_kernel_table();
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001833 i = -1;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001834 if (optarg) {
1835 if ( (i = get_hooknr(optarg)) == -1 )
1836 print_error("Bad chain");
1837 } else
1838 if (optind < argc && argv[optind][0] != '-') {
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001839 if ((i = get_hooknr(argv[optind])) == -1)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001840 print_error("Bad chain");
1841 optind++;
1842 }
1843 if (i != -1) {
1844 if (c == 'Z')
1845 zerochain = i;
1846 else
1847 replace.selected_hook = i;
1848 }
1849 break;
1850
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001851 case 'V': /* version */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001852 replace.command = 'V';
1853 if (replace.flags & OPT_COMMAND)
1854 print_error("Multiple commands not allowed");
Bart De Schuymer57a3f6a2003-04-01 16:59:33 +00001855 PRINT_VERSION;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001856 exit(0);
1857
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001858 case 'M': /* modprobe */
Bart De Schuymer60332e02002-06-23 08:01:47 +00001859 if (replace.command != 'h')
1860 print_error("Please put the -M option earlier");
Bart De Schuymerc8531032002-06-14 21:55:29 +00001861 modprobe = optarg;
1862 break;
1863
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001864 case 'h': /* help */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001865 if (replace.flags & OPT_COMMAND)
1866 print_error("Multiple commands not allowed");
1867 replace.command = 'h';
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001868 /*
1869 * All other arguments should be extension names
1870 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001871 while (optind < argc) {
1872 struct ebt_u_match *m;
1873 struct ebt_u_watcher *w;
1874
Bart De Schuymer9a0fbf22003-01-11 16:16:54 +00001875 if (!strcasecmp("list_extensions",
1876 argv[optind]))
1877 list_extensions();
1878
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001879 if ((m = find_match(argv[optind])))
1880 add_match(m);
1881 else if ((w = find_watcher(argv[optind])))
1882 add_watcher(w);
1883 else {
1884 if (!(t = find_target(argv[optind])))
1885 print_error("Extension %s "
1886 "not found", argv[optind]);
1887 if (replace.flags & OPT_JUMP)
1888 print_error("Sorry, you can "
1889 "only see help for one "
1890 "target extension each time");
1891 replace.flags |= OPT_JUMP;
1892 new_entry->t =
1893 (struct ebt_entry_target *)t;
1894 }
1895 optind++;
1896 }
1897 break;
1898
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001899 case 't': /* table */
Bart De Schuymer60332e02002-06-23 08:01:47 +00001900 if (replace.command != 'h')
1901 print_error("Please put the -t option first");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001902 check_option(&replace.flags, OPT_TABLE);
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001903 if (strlen(optarg) > EBT_TABLE_MAXNAMELEN - 1)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001904 print_error("Table name too long");
1905 strcpy(replace.name, optarg);
1906 break;
1907
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001908 case 'i': /* input interface */
1909 case 2 : /* logical input interface */
1910 case 'o': /* output interface */
1911 case 3 : /* logical output interface */
1912 case 'j': /* target */
1913 case 'p': /* net family protocol */
1914 case 's': /* source mac */
1915 case 'd': /* destination mac */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001916 if ((replace.flags & OPT_COMMAND) == 0)
1917 print_error("No command specified");
1918 if ( replace.command != 'A' &&
1919 replace.command != 'D' && replace.command != 'I')
1920 print_error("Command and option do not match");
1921 if (c == 'i') {
1922 check_option(&replace.flags, OPT_IN);
1923 if (replace.selected_hook > 2 &&
1924 replace.selected_hook < NF_BR_BROUTING)
1925 print_error("Use in-interface only in "
1926 "INPUT, FORWARD, PREROUTING and"
1927 "BROUTING chains");
1928 if (check_inverse(optarg))
1929 new_entry->invflags |= EBT_IIN;
1930
1931 if (optind > argc)
1932 print_error("No in-interface "
1933 "specified");
1934 if (strlen(argv[optind - 1]) >= IFNAMSIZ)
Bart De Schuymerc5075142002-08-18 14:21:19 +00001935 print_if_l_error;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001936 strcpy(new_entry->in, argv[optind - 1]);
1937 break;
1938 }
1939 if (c == 2) {
1940 check_option(&replace.flags, OPT_LOGICALIN);
1941 if (replace.selected_hook > 2 &&
1942 replace.selected_hook < NF_BR_BROUTING)
1943 print_error("Use logical in-interface "
1944 "only in INPUT, FORWARD, "
1945 "PREROUTING and BROUTING chains");
1946 if (check_inverse(optarg))
1947 new_entry->invflags |= EBT_ILOGICALIN;
1948
1949 if (optind > argc)
1950 print_error("No logical in-interface "
1951 "specified");
1952 if (strlen(argv[optind - 1]) >= IFNAMSIZ)
Bart De Schuymerc5075142002-08-18 14:21:19 +00001953 print_if_l_error;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001954 strcpy(new_entry->logical_in, argv[optind - 1]);
1955 break;
1956 }
1957 if (c == 'o') {
1958 check_option(&replace.flags, OPT_OUT);
1959 if (replace.selected_hook < 2)
1960 print_error("Use out-interface only"
1961 " in OUTPUT, FORWARD and "
1962 "POSTROUTING chains");
1963 if (check_inverse(optarg))
1964 new_entry->invflags |= EBT_IOUT;
1965
1966 if (optind > argc)
1967 print_error("No out-interface "
1968 "specified");
1969
1970 if (strlen(argv[optind - 1]) >= IFNAMSIZ)
Bart De Schuymerc5075142002-08-18 14:21:19 +00001971 print_if_l_error;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001972 strcpy(new_entry->out, argv[optind - 1]);
1973 break;
1974 }
1975 if (c == 3) {
1976 check_option(&replace.flags, OPT_LOGICALOUT);
1977 if (replace.selected_hook < 2)
1978 print_error("Use logical out-interface "
1979 "only in OUTPUT, FORWARD and "
1980 "POSTROUTING chains");
1981 if (check_inverse(optarg))
1982 new_entry->invflags |= EBT_ILOGICALOUT;
1983
1984 if (optind > argc)
1985 print_error("No logical out-interface "
1986 "specified");
1987
1988 if (strlen(argv[optind - 1]) >= IFNAMSIZ)
Bart De Schuymerc5075142002-08-18 14:21:19 +00001989 print_if_l_error;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001990 strcpy(new_entry->logical_out,
1991 argv[optind - 1]);
1992 break;
1993 }
1994 if (c == 'j') {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001995 check_option(&replace.flags, OPT_JUMP);
1996 for (i = 0; i < NUM_STANDARD_TARGETS; i++)
1997 if (!strcmp(optarg,
1998 standard_targets[i])) {
1999 t = find_target(
2000 EBT_STANDARD_TARGET);
2001 ((struct ebt_standard_target *)
Bart De Schuymer60332e02002-06-23 08:01:47 +00002002 t->t)->verdict = -i - 1;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002003 break;
2004 }
Bart De Schuymer60332e02002-06-23 08:01:47 +00002005 if (-i - 1 == EBT_RETURN) {
2006 if (replace.selected_hook < NF_BR_NUMHOOKS)
2007 print_error("Return target"
2008 " only for user defined chains");
2009 }
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +00002010 if (i != NUM_STANDARD_TARGETS)
2011 break;
Bart De Schuymer1ab41562002-06-23 17:09:54 +00002012 if ((i = get_hooknr(optarg)) != -1) {
2013 if (i < NF_BR_NUMHOOKS)
2014 print_error("don't jump"
2015 " to a standard chain");
2016 t = find_target(
2017 EBT_STANDARD_TARGET);
2018 ((struct ebt_standard_target *)
2019 t->t)->verdict = i - NF_BR_NUMHOOKS;
2020 break;
2021 }
2022 else {
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002023 /*
2024 * must be an extension then
2025 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002026 struct ebt_u_target *t;
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00002027
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002028 t = find_target(optarg);
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002029 /*
2030 * -j standard not allowed either
2031 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002032 if (!t || t ==
2033 (struct ebt_u_target *)new_entry->t)
2034 print_error("Illegal target "
2035 "name");
2036 new_entry->t =
2037 (struct ebt_entry_target *)t;
2038 }
2039 break;
2040 }
2041 if (c == 's') {
2042 check_option(&replace.flags, OPT_SOURCE);
2043 if (check_inverse(optarg))
2044 new_entry->invflags |= EBT_ISOURCE;
2045
2046 if (optind > argc)
2047 print_error("No source mac "
2048 "specified");
2049 if (getmac_and_mask(argv[optind - 1],
2050 new_entry->sourcemac, new_entry->sourcemsk))
2051 print_error("Problem with specified "
2052 "source mac");
2053 new_entry->bitmask |= EBT_SOURCEMAC;
2054 break;
2055 }
2056 if (c == 'd') {
2057 check_option(&replace.flags, OPT_DEST);
2058 if (check_inverse(optarg))
2059 new_entry->invflags |= EBT_IDEST;
2060
2061 if (optind > argc)
2062 print_error("No destination mac "
2063 "specified");
2064 if (getmac_and_mask(argv[optind - 1],
2065 new_entry->destmac, new_entry->destmsk))
2066 print_error("Problem with specified "
2067 "destination mac");
2068 new_entry->bitmask |= EBT_DESTMAC;
2069 break;
2070 }
2071 check_option(&replace.flags, OPT_PROTOCOL);
2072 if (check_inverse(optarg))
2073 new_entry->invflags |= EBT_IPROTO;
2074
2075 if (optind > argc)
2076 print_error("No protocol specified");
2077 new_entry->bitmask &= ~((unsigned int)EBT_NOPROTO);
2078 i = strtol(argv[optind - 1], &buffer, 16);
2079 if (*buffer == '\0' && (i < 0 || i > 0xFFFF))
2080 print_error("Problem with the specified "
2081 "protocol");
2082 new_entry->ethproto = i;
Bart De Schuymer28bf6f62002-06-26 18:57:24 +00002083 if (*buffer != '\0') {
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002084 struct ethertypeent *ent;
2085
2086 if (!strcasecmp(argv[optind - 1], "LENGTH")) {
2087 new_entry->bitmask |= EBT_802_3;
2088 break;
2089 }
2090 ent = getethertypebyname(argv[optind - 1]);
2091 if (!ent)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002092 print_error("Problem with the specified"
2093 " protocol");
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002094 new_entry->ethproto = ent->e_ethertype;
Bart De Schuymer28bf6f62002-06-26 18:57:24 +00002095 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002096 if (new_entry->ethproto < 1536 &&
2097 !(new_entry->bitmask & EBT_802_3))
2098 print_error("Sorry, protocols have values above"
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00002099 " or equal to 0x0600");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002100 break;
2101
Bart De Schuymer9895a8e2003-01-11 10:14:24 +00002102 case 4 : /* Lc */
Bart De Schuymer9af14f92002-07-10 20:49:10 +00002103 check_option(&replace.flags, LIST_C);
Bart De Schuymer9af14f92002-07-10 20:49:10 +00002104 if (replace.command != 'L')
2105 print_error("Use --Lc with -L");
2106 if (replace.flags & LIST_X)
2107 print_error("--Lx not compatible with --Lc");
2108 replace.flags |= LIST_C;
2109 break;
Bart De Schuymer9895a8e2003-01-11 10:14:24 +00002110 case 5 : /* Ln */
Bart De Schuymer9af14f92002-07-10 20:49:10 +00002111 check_option(&replace.flags, LIST_N);
Bart De Schuymer9af14f92002-07-10 20:49:10 +00002112 if (replace.command != 'L')
2113 print_error("Use --Ln with -L");
2114 if (replace.flags & LIST_X)
2115 print_error("--Lx not compatible with --Ln");
2116 replace.flags |= LIST_N;
2117 break;
Bart De Schuymer9895a8e2003-01-11 10:14:24 +00002118 case 6 : /* Lx */
Bart De Schuymer9af14f92002-07-10 20:49:10 +00002119 check_option(&replace.flags, LIST_X);
Bart De Schuymer9af14f92002-07-10 20:49:10 +00002120 if (replace.command != 'L')
2121 print_error("Use --Lx with -L");
2122 if (replace.flags & LIST_C)
2123 print_error("--Lx not compatible with --Lc");
2124 if (replace.flags & LIST_N)
2125 print_error("--Lx not compatible with --Ln");
2126 replace.flags |= LIST_X;
2127 break;
Bart De Schuymer22d03a22003-05-03 20:28:22 +00002128 case 12 : /* Lmac2 */
2129 check_option(&replace.flags, LIST_MAC2);
2130 if (replace.command != 'L')
2131 print_error("Use --Lmac2 with -L");
2132 replace.flags |= LIST_MAC2;
2133 break;
Bart De Schuymer9895a8e2003-01-11 10:14:24 +00002134 case 8 : /* atomic-commit */
Bart De Schuymer62423742002-07-14 19:06:20 +00002135 replace.command = c;
2136 if (replace.flags & OPT_COMMAND)
2137 print_error("Multiple commands not allowed");
2138 replace.flags |= OPT_COMMAND;
Bart De Schuymer5885b362002-12-03 20:51:36 +00002139 if (!replace.filename)
2140 print_error("No atomic file specified");
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002141 /*
2142 * get the information from the file
2143 */
Bart De Schuymer62423742002-07-14 19:06:20 +00002144 get_table(&replace);
Bart De Schuymer868bf642002-07-16 18:14:20 +00002145 if (replace.nentries) {
Bart De Schuymered053432002-07-21 19:35:39 +00002146 replace.counterchanges = (unsigned short *)
Bart De Schuymer868bf642002-07-16 18:14:20 +00002147 malloc(sizeof(unsigned short) * (replace.nentries + 1));
2148 for (i = 0; i < replace.nentries; i++)
Bart De Schuymered053432002-07-21 19:35:39 +00002149 replace.counterchanges[i] = CNT_NORM;
2150 replace.counterchanges[i] = CNT_END;
Bart De Schuymer868bf642002-07-16 18:14:20 +00002151 }
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002152 /*
2153 * we don't want the kernel giving us its counters, they would
2154 * overwrite the counters extracted from the file
2155 */
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00002156 replace.num_counters = 0;
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002157 /*
2158 * make sure the table will be written to the kernel
Bart De Schuymer5885b362002-12-03 20:51:36 +00002159 * possible memory leak here
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002160 */
Bart De Schuymer62423742002-07-14 19:06:20 +00002161 replace.filename = NULL;
2162 break;
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002163 case 7 : /* atomic-init */
2164 case 10: /* atomic-save */
2165 case 11: /* init-table */
Bart De Schuymer62423742002-07-14 19:06:20 +00002166 replace.command = c;
2167 if (replace.flags & OPT_COMMAND)
2168 print_error("Multiple commands not allowed");
Bart De Schuymer5885b362002-12-03 20:51:36 +00002169 if (c != 11 && !replace.filename)
2170 print_error("No atomic file specified");
Bart De Schuymer62423742002-07-14 19:06:20 +00002171 replace.flags |= OPT_COMMAND;
Bart De Schuymer5885b362002-12-03 20:51:36 +00002172 {
2173 char *tmp = replace.filename;
2174
2175 tmp = replace.filename;
2176 /* get the kernel table */
2177 replace.filename = NULL;
Bart De Schuymer0cb01792003-05-04 16:52:04 +00002178 get_kernel_table();
Bart De Schuymer5885b362002-12-03 20:51:36 +00002179 replace.filename = tmp;
2180 }
Bart De Schuymera8d920b2002-07-16 18:30:44 +00002181 if (replace.nentries) {
Bart De Schuymered053432002-07-21 19:35:39 +00002182 replace.counterchanges = (unsigned short *)
Bart De Schuymer5f16dc72002-07-16 18:08:36 +00002183 malloc(sizeof(unsigned short) * (replace.nentries + 1));
2184 for (i = 0; i < replace.nentries; i++)
Bart De Schuymered053432002-07-21 19:35:39 +00002185 replace.counterchanges[i] = CNT_NORM;
2186 replace.counterchanges[i] = CNT_END;
Bart De Schuymer5f16dc72002-07-16 18:08:36 +00002187 }
Bart De Schuymer5885b362002-12-03 20:51:36 +00002188 break;
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002189 case 9 : /* atomic */
Bart De Schuymer5885b362002-12-03 20:51:36 +00002190 if (replace.flags & OPT_COMMAND)
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00002191 print_error("--atomic has to come before"
2192 " the command");
Bart De Schuymer5885b362002-12-03 20:51:36 +00002193 /* another possible memory leak here */
Bart De Schuymer62423742002-07-14 19:06:20 +00002194 replace.filename = (char *)malloc(strlen(optarg) + 1);
2195 strcpy(replace.filename, optarg);
2196 break;
Bart De Schuymera615b962002-11-03 14:54:09 +00002197 case 1 :
2198 if (!strcmp(optarg, "!"))
2199 check_inverse(optarg);
2200 else
2201 print_error("Bad argument : %s", optarg);
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002202 /*
2203 * check_inverse() did optind++
2204 */
Bart De Schuymera615b962002-11-03 14:54:09 +00002205 optind--;
2206 continue;
Bart De Schuymer9af14f92002-07-10 20:49:10 +00002207 default:
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002208 /*
2209 * is it a target option?
2210 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002211 t = (struct ebt_u_target *)new_entry->t;
2212 if ((t->parse(c - t->option_offset, argv, argc,
2213 new_entry, &t->flags, &t->t)))
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00002214 goto check_extension;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002215
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002216 /*
2217 * is it a match_option?
2218 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002219 for (m = matches; m; m = m->next)
2220 if (m->parse(c - m->option_offset, argv,
2221 argc, new_entry, &m->flags, &m->m))
2222 break;
2223
2224 if (m != NULL) {
2225 if (m->used == 0)
2226 add_match(m);
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00002227 goto check_extension;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002228 }
2229
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002230 /*
2231 * is it a watcher option?
2232 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002233 for (w = watchers; w; w = w->next)
2234 if (w->parse(c-w->option_offset, argv,
2235 argc, new_entry, &w->flags, &w->w))
2236 break;
2237
2238 if (w == NULL)
2239 print_error("Unknown argument");
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00002240 if (w->used == 0)
2241 add_watcher(w);
2242check_extension:
Bart De Schuymer60332e02002-06-23 08:01:47 +00002243 if (replace.command != 'A' && replace.command != 'I' &&
2244 replace.command != 'D')
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00002245 print_error("Extensions only for -A, -I and -D");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002246 }
Bart De Schuymera615b962002-11-03 14:54:09 +00002247 invert = 0;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002248 }
2249
Bart De Schuymer25c741d2002-06-23 18:54:34 +00002250 if ( !table && !(table = find_table(replace.name)) )
2251 print_error("Bad table name");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002252
2253 if ( (replace.flags & OPT_COMMAND) && replace.command != 'L' &&
2254 replace.flags & OPT_ZERO )
2255 print_error("Command -Z only allowed together with command -L");
2256
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002257 /*
2258 * do this after parsing everything, so we can print specific info
2259 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002260 if (replace.command == 'h' && !(replace.flags & OPT_ZERO))
2261 print_help();
2262
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002263 /*
2264 * do the final checks
2265 */
Bart De Schuymer60332e02002-06-23 08:01:47 +00002266 if (replace.command == 'A' || replace.command == 'I' ||
2267 replace.command == 'D') {
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002268 /*
2269 * this will put the hook_mask right for the chains
2270 */
Bart De Schuymer60332e02002-06-23 08:01:47 +00002271 check_for_loops();
2272 entries = to_chain();
2273 m_l = new_entry->m_list;
2274 w_l = new_entry->w_list;
2275 t = (struct ebt_u_target *)new_entry->t;
2276 while (m_l) {
2277 m = (struct ebt_u_match *)(m_l->m);
2278 m->final_check(new_entry, m->m, replace.name,
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +00002279 entries->hook_mask, 0);
Bart De Schuymer60332e02002-06-23 08:01:47 +00002280 m_l = m_l->next;
2281 }
2282 while (w_l) {
2283 w = (struct ebt_u_watcher *)(w_l->w);
2284 w->final_check(new_entry, w->w, replace.name,
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +00002285 entries->hook_mask, 0);
Bart De Schuymer60332e02002-06-23 08:01:47 +00002286 w_l = w_l->next;
2287 }
2288 t->final_check(new_entry, t->t, replace.name,
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +00002289 entries->hook_mask, 0);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002290 }
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002291 /*
2292 * so, the extensions can work with the host endian
2293 * the kernel does not have to do this ofcourse
2294 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002295 new_entry->ethproto = htons(new_entry->ethproto);
2296
Bart De Schuymerc34f4672002-08-18 18:03:52 +00002297 if (replace.command == 'P') {
2298 if (replace.selected_hook < NF_BR_NUMHOOKS &&
2299 policy == EBT_RETURN)
2300 print_error("Policy RETURN only allowed for user "
2301 "defined chains");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002302 change_policy(policy);
Bart De Schuymerc34f4672002-08-18 18:03:52 +00002303 } else if (replace.command == 'L') {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002304 list_rules();
2305 if (replace.flags & OPT_ZERO)
2306 zero_counters(zerochain);
2307 else
2308 exit(0);
2309 }
2310 if (replace.flags & OPT_ZERO)
2311 zero_counters(zerochain);
Bart De Schuymer1ab41562002-06-23 17:09:54 +00002312 else if (replace.command == 'F') {
2313 if (flush_chains() == -1)
2314 exit(0);
2315 } else if (replace.command == 'A' || replace.command == 'I') {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002316 add_rule(rule_nr);
Bart De Schuymer1ab41562002-06-23 17:09:54 +00002317 check_for_loops();
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002318 /*
2319 * do the final_check(), for all entries
2320 * needed when adding a rule that has a chain target
2321 */
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +00002322 i = -1;
2323 while (1) {
2324 struct ebt_u_entry *e;
2325
2326 i++;
2327 entries = nr_to_chain(i);
2328 if (!entries) {
2329 if (i < NF_BR_NUMHOOKS)
2330 continue;
2331 else
2332 break;
2333 }
2334 e = entries->entries;
2335 while (e) {
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002336 /*
2337 * userspace extensions use host endian
2338 */
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +00002339 e->ethproto = ntohs(e->ethproto);
2340 do_final_checks(e, entries);
2341 e->ethproto = htons(e->ethproto);
2342 e = e->next;
2343 }
2344 }
Bart De Schuymerc3b97f52003-04-17 17:03:49 +00002345 } else if (replace.command == 'D')
Bart De Schuymercc440052002-11-06 21:10:33 +00002346 delete_rule(rule_nr, rule_nr_end);
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002347 /*
2348 * commands -N, -E, -X, --atomic-commit, --atomic-commit, --atomic-save,
2349 * --init-table fall through
2350 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002351
2352 if (table->check)
2353 table->check(&replace);
2354
2355 deliver_table(&replace);
2356
Bart De Schuymered053432002-07-21 19:35:39 +00002357 if (replace.counterchanges)
2358 deliver_counters(&replace);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002359 return 0;
2360}