blob: 271415c05ea1345a901b824930909458fac1660e [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 Schuymer336f35e2003-05-22 20:53:12 +00001299 if (begin <= 0 || begin > end || end > entries->nentries)
Bart De Schuymerc3b97f52003-04-17 17:03:49 +00001300 print_error("Sorry, wrong rule numbers");
Bart De Schuymer336f35e2003-05-22 20:53:12 +00001301
Bart De Schuymercc440052002-11-06 21:10:33 +00001302 if ((begin = check_rule_exists(begin)) == -1 ||
1303 (end = check_rule_exists(end)) == -1)
Bart De Schuymer60332e02002-06-23 08:01:47 +00001304 print_error("Sorry, rule does not exist");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001305
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001306 /*
1307 * we're deleting rules
1308 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001309 replace.num_counters = replace.nentries;
Bart De Schuymercc440052002-11-06 21:10:33 +00001310 nr_deletes = end - begin + 1;
1311 replace.nentries -= nr_deletes;
1312 entries->nentries -= nr_deletes;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001313
1314 if (replace.nentries) {
1315 for (j = 0; j < replace.selected_hook; j++) {
Bart De Schuymer60332e02002-06-23 08:01:47 +00001316 if (j < NF_BR_NUMHOOKS &&
1317 !(replace.valid_hooks & (1 << j)))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001318 continue;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001319 entries2 = nr_to_chain(j);
1320 lentmp += entries2->nentries;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001321 }
Bart De Schuymercc440052002-11-06 21:10:33 +00001322 lentmp += begin;
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001323 /*
1324 * +1 for CNT_END
1325 */
Bart De Schuymered053432002-07-21 19:35:39 +00001326 if ( !(replace.counterchanges = (unsigned short *)malloc(
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001327 (replace.num_counters + 1) * sizeof(unsigned short))) )
1328 print_memory();
Bart De Schuymered053432002-07-21 19:35:39 +00001329 cnt = replace.counterchanges;
Bart De Schuymercc440052002-11-06 21:10:33 +00001330 for (j = 0; j < lentmp; j++, cnt++)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001331 *cnt = CNT_NORM;
Bart De Schuymercc440052002-11-06 21:10:33 +00001332 for (j = 0; j < nr_deletes; j++, cnt++)
1333 *cnt = CNT_DEL;
1334
1335 for (j = 0; j < replace.num_counters - lentmp - nr_deletes;
1336 j++, cnt++)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001337 *cnt = CNT_NORM;
Bart De Schuymercc440052002-11-06 21:10:33 +00001338
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001339 *cnt = CNT_END;
1340 }
1341 else
1342 replace.num_counters = 0;
1343
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001344 /*
1345 * go to the right position in the chain
1346 */
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001347 u_e = &entries->entries;
Bart De Schuymercc440052002-11-06 21:10:33 +00001348 for (j = 0; j < begin; j++)
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001349 u_e = &(*u_e)->next;
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001350 /*
1351 * remove the rules
1352 */
Bart De Schuymercc440052002-11-06 21:10:33 +00001353 j = nr_deletes;
1354 while(j--) {
1355 u_e2 = *u_e;
1356 *u_e = (*u_e)->next;
Bart De Schuymer9895a8e2003-01-11 10:14:24 +00001357 /* free everything */
Bart De Schuymercc440052002-11-06 21:10:33 +00001358 free_u_entry(u_e2);
1359 free(u_e2);
1360 }
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001361
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001362 /*
1363 * update the counter_offset of chains behind this one
1364 */
Bart De Schuymercc440052002-11-06 21:10:33 +00001365 j = replace.selected_hook;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001366 while (1) {
Bart De Schuymercc440052002-11-06 21:10:33 +00001367 j++;
1368 entries = nr_to_chain(j);
Bart De Schuymer60332e02002-06-23 08:01:47 +00001369 if (!entries) {
Bart De Schuymercc440052002-11-06 21:10:33 +00001370 if (j < NF_BR_NUMHOOKS)
Bart De Schuymer60332e02002-06-23 08:01:47 +00001371 continue;
1372 else
1373 break;
Bart De Schuymercc440052002-11-06 21:10:33 +00001374 } else
1375 entries->counter_offset -= nr_deletes;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001376 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001377}
1378
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001379/*
1380 * execute command Z
1381 */
Bart De Schuymer62423742002-07-14 19:06:20 +00001382static void zero_counters(int zerochain)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001383{
1384
1385 if (zerochain == -1) {
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001386 /*
1387 * tell main() we don't update the counters
1388 * this results in tricking the kernel to zero its counters,
1389 * naively expecting userspace to update its counters. Muahahaha
1390 */
Bart De Schuymered053432002-07-21 19:35:39 +00001391 replace.counterchanges = NULL;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001392 replace.num_counters = 0;
1393 } else {
1394 int i, j;
1395 unsigned short *cnt;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001396 struct ebt_u_entries *entries = nr_to_chain(zerochain), *e2;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001397
Bart De Schuymer60332e02002-06-23 08:01:47 +00001398 if (entries->nentries == 0)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001399 exit(0);
Bart De Schuymered053432002-07-21 19:35:39 +00001400 replace.counterchanges = (unsigned short *)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001401 malloc((replace.nentries + 1) * sizeof(unsigned short));
Bart De Schuymered053432002-07-21 19:35:39 +00001402 if (!replace.counterchanges)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001403 print_memory();
Bart De Schuymered053432002-07-21 19:35:39 +00001404 cnt = replace.counterchanges;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001405 for (i = 0; i < zerochain; i++) {
Bart De Schuymer60332e02002-06-23 08:01:47 +00001406 if (i < NF_BR_NUMHOOKS &&
1407 !(replace.valid_hooks & (1 << i)))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001408 continue;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001409 e2 = nr_to_chain(i);
1410 for (j = 0; j < e2->nentries; j++) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001411 *cnt = CNT_NORM;
1412 cnt++;
1413 }
1414 }
Bart De Schuymer60332e02002-06-23 08:01:47 +00001415 for (i = 0; i < entries->nentries; i++) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001416 *cnt = CNT_ZERO;
1417 cnt++;
1418 }
Bart De Schuymered053432002-07-21 19:35:39 +00001419 while (cnt != replace.counterchanges + replace.nentries) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001420 *cnt = CNT_NORM;
1421 cnt++;
1422 }
1423 *cnt = CNT_END;
1424 }
1425}
1426
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001427/*
1428 * Checks the type for validity and calls getethertypebynumber()
1429 */
1430struct ethertypeent *parseethertypebynumber(int type)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001431{
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001432 if (type < 1536)
1433 print_error("Ethernet protocols have values >= 0x0600");
1434 if (type > 0xffff)
1435 print_error("Ethernet protocols have values <= 0xffff");
1436 return getethertypebynumber(type);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001437}
1438
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001439/*
1440 * put the mac address into 6 (ETH_ALEN) bytes
1441 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001442int getmac_and_mask(char *from, char *to, char *mask)
1443{
1444 char *p;
1445 int i;
Bart De Schuymer41830412002-06-05 19:41:28 +00001446 struct ether_addr *addr;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001447
1448 if (strcasecmp(from, "Unicast") == 0) {
1449 memcpy(to, mac_type_unicast, ETH_ALEN);
1450 memcpy(mask, msk_type_unicast, ETH_ALEN);
1451 return 0;
1452 }
1453 if (strcasecmp(from, "Multicast") == 0) {
1454 memcpy(to, mac_type_multicast, ETH_ALEN);
1455 memcpy(mask, msk_type_multicast, ETH_ALEN);
1456 return 0;
1457 }
1458 if (strcasecmp(from, "Broadcast") == 0) {
1459 memcpy(to, mac_type_broadcast, ETH_ALEN);
1460 memcpy(mask, msk_type_broadcast, ETH_ALEN);
1461 return 0;
1462 }
1463 if ( (p = strrchr(from, '/')) != NULL) {
1464 *p = '\0';
Bart De Schuymer41830412002-06-05 19:41:28 +00001465 if (!(addr = ether_aton(p + 1)))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001466 return -1;
Bart De Schuymer41830412002-06-05 19:41:28 +00001467 memcpy(mask, addr, ETH_ALEN);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001468 } else
1469 memset(mask, 0xff, ETH_ALEN);
Bart De Schuymer41830412002-06-05 19:41:28 +00001470 if (!(addr = ether_aton(from)))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001471 return -1;
Bart De Schuymer41830412002-06-05 19:41:28 +00001472 memcpy(to, addr, ETH_ALEN);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001473 for (i = 0; i < ETH_ALEN; i++)
1474 to[i] &= mask[i];
1475 return 0;
1476}
1477
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001478/*
1479 * executes the final_check() function for all extensions used by the rule
1480 */
Bart De Schuymer62423742002-07-14 19:06:20 +00001481static void do_final_checks(struct ebt_u_entry *e, struct ebt_u_entries *entries)
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +00001482{
1483 struct ebt_u_match_list *m_l;
1484 struct ebt_u_watcher_list *w_l;
1485 struct ebt_u_target *t;
1486 struct ebt_u_match *m;
1487 struct ebt_u_watcher *w;
1488
1489 m_l = e->m_list;
1490 w_l = e->w_list;
1491 while (m_l) {
1492 m = find_match(m_l->m->u.name);
1493 m->final_check(e, m_l->m, replace.name,
1494 entries->hook_mask, 1);
1495 m_l = m_l->next;
1496 }
1497 while (w_l) {
1498 w = find_watcher(w_l->w->u.name);
1499 w->final_check(e, w_l->w, replace.name,
1500 entries->hook_mask, 1);
1501 w_l = w_l->next;
1502 }
1503 t = find_target(e->t->u.name);
1504 t->final_check(e, e->t, replace.name,
1505 entries->hook_mask, 1);
1506}
1507
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001508/*
1509 * used for the -X command
1510 */
Bart De Schuymer62423742002-07-14 19:06:20 +00001511static void check_for_references(int chain_nr)
Bart De Schuymerb909f9b2002-06-26 18:35:31 +00001512{
1513 int i = -1, j;
1514 struct ebt_u_entries *entries;
1515 struct ebt_u_entry *e;
1516
1517 while (1) {
1518 i++;
1519 entries = nr_to_chain(i);
1520 if (!entries) {
1521 if (i < NF_BR_NUMHOOKS)
1522 continue;
1523 else
1524 break;
1525 }
1526 e = entries->entries;
1527 j = 0;
1528 while (e) {
Bart De Schuymerc27432e2003-01-09 22:01:07 +00001529 int chain_jmp;
1530
Bart De Schuymerb909f9b2002-06-26 18:35:31 +00001531 j++;
1532 if (strcmp(e->t->u.name, EBT_STANDARD_TARGET)) {
1533 e = e->next;
1534 continue;
1535 }
Bart De Schuymerc27432e2003-01-09 22:01:07 +00001536 chain_jmp = ((struct ebt_standard_target *)e->t)->verdict;
1537 if (chain_jmp == chain_nr)
Bart De Schuymerb909f9b2002-06-26 18:35:31 +00001538 print_error("Can't delete the chain, it's referenced "
1539 "in chain %s, rule %d", entries->name, j);
Bart De Schuymerc27432e2003-01-09 22:01:07 +00001540 /* adjust the chain jumps when necessary */
1541 if (chain_jmp > chain_nr)
1542 ((struct ebt_standard_target *)e->t)->verdict--;
Bart De Schuymerb909f9b2002-06-26 18:35:31 +00001543 e = e->next;
1544 }
1545 }
1546}
1547
Bart De Schuymercc440052002-11-06 21:10:33 +00001548static int parse_delete_rule(const char *argv, int *rule_nr, int *rule_nr_end)
1549{
1550 char *colon = strchr(argv, ':'), *buffer;
1551
1552 if (colon) {
1553 *colon = '\0';
1554 if (*(colon + 1) == '\0')
Bart De Schuymerc3b97f52003-04-17 17:03:49 +00001555 *rule_nr_end = -1; /* until the last rule */
Bart De Schuymercc440052002-11-06 21:10:33 +00001556 else {
1557 *rule_nr_end = strtol(colon + 1, &buffer, 10);
Bart De Schuymerc3b97f52003-04-17 17:03:49 +00001558 if (*buffer != '\0' || *rule_nr_end == 0)
Bart De Schuymercc440052002-11-06 21:10:33 +00001559 return -1;
1560 }
1561 }
1562 if (colon == argv)
Bart De Schuymerc3b97f52003-04-17 17:03:49 +00001563 *rule_nr = 1; /* beginning with the first rule */
Bart De Schuymercc440052002-11-06 21:10:33 +00001564 else {
1565 *rule_nr = strtol(argv, &buffer, 10);
Bart De Schuymerc3b97f52003-04-17 17:03:49 +00001566 if (*buffer != '\0' || *rule_nr == 0)
Bart De Schuymercc440052002-11-06 21:10:33 +00001567 return -1;
1568 }
1569 if (!colon)
1570 *rule_nr_end = *rule_nr;
Bart De Schuymercc440052002-11-06 21:10:33 +00001571 return 0;
1572}
1573
Bart De Schuymera615b962002-11-03 14:54:09 +00001574static int invert = 0;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001575int check_inverse(const char option[])
1576{
1577 if (strcmp(option, "!") == 0) {
Bart De Schuymera615b962002-11-03 14:54:09 +00001578 if (invert == 1)
1579 print_error("double use of '!' not allowed");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001580 optind++;
Bart De Schuymera615b962002-11-03 14:54:09 +00001581 invert = 1;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001582 return 1;
1583 }
Bart De Schuymera615b962002-11-03 14:54:09 +00001584 return invert;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001585}
1586
1587void check_option(unsigned int *flags, unsigned int mask)
1588{
1589 if (*flags & mask)
1590 print_error("Multiple use of same option not allowed");
1591 *flags |= mask;
1592}
1593
Bart De Schuymer0cb01792003-05-04 16:52:04 +00001594static void get_kernel_table()
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001595{
1596 if ( !(table = find_table(replace.name)) )
1597 print_error("Bad table name");
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001598 /*
1599 * get the kernel's information
1600 */
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001601 if (get_table(&replace)) {
Bart De Schuymer0cb01792003-05-04 16:52:04 +00001602 ebtables_insmod("ebtables");
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001603 if (get_table(&replace))
1604 print_error("The kernel doesn't support the ebtables "
1605 "%s table", replace.name);
1606 }
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001607 /*
Bart De Schuymer5885b362002-12-03 20:51:36 +00001608 * when listing a table contained in a file, we don't demand that
1609 * the user knows the table's name
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001610 */
Bart De Schuymer62a7fdb2002-08-24 21:01:21 +00001611 if ( !(table = find_table(replace.name)) )
1612 print_error("Bad table name");
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001613}
1614
Bart De Schuymerc5075142002-08-18 14:21:19 +00001615#define print_if_l_error print_error("Interface name length must be less " \
1616 "than %d", IFNAMSIZ)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001617#define OPT_COMMAND 0x01
1618#define OPT_TABLE 0x02
1619#define OPT_IN 0x04
1620#define OPT_OUT 0x08
1621#define OPT_JUMP 0x10
1622#define OPT_PROTOCOL 0x20
1623#define OPT_SOURCE 0x40
1624#define OPT_DEST 0x80
1625#define OPT_ZERO 0x100
1626#define OPT_LOGICALIN 0x200
1627#define OPT_LOGICALOUT 0x400
Bart De Schuymer5885b362002-12-03 20:51:36 +00001628/* the main thing */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001629int main(int argc, char *argv[])
1630{
Bart De Schuymer923a5732002-08-11 12:01:33 +00001631 char *buffer;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001632 int c, i;
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001633 /*
1634 * this special one for the -Z option (we can have -Z <this> -L <that>)
1635 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001636 int zerochain = -1;
Bart De Schuymerf8f8f292002-06-25 15:43:57 +00001637 int policy = 0;
Bart De Schuymerc3b97f52003-04-17 17:03:49 +00001638 int rule_nr = 0; /* used for -[D,I] */
1639 int rule_nr_end = 0; /* used for -I */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001640 struct ebt_u_target *t;
1641 struct ebt_u_match *m;
1642 struct ebt_u_watcher *w;
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001643 struct ebt_u_match_list *m_l;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001644 struct ebt_u_watcher_list *w_l;
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001645 struct ebt_u_entries *entries;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001646
Bart De Schuymera615b962002-11-03 14:54:09 +00001647 opterr = 0;
1648
Bart De Schuymer5885b362002-12-03 20:51:36 +00001649 replace.filename = getenv(ATOMIC_ENV_VARIABLE);
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001650 /*
1651 * initialize the table name, OPT_ flags, selected hook and command
1652 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001653 strcpy(replace.name, "filter");
1654 replace.flags = 0;
1655 replace.selected_hook = -1;
1656 replace.command = 'h';
Bart De Schuymered053432002-07-21 19:35:39 +00001657 replace.counterchanges = NULL;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001658
1659 new_entry = (struct ebt_u_entry *)malloc(sizeof(struct ebt_u_entry));
1660 if (!new_entry)
1661 print_memory();
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001662 /*
1663 * put some sane values in our new entry
1664 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001665 initialize_entry(new_entry);
1666
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001667 /*
1668 * The scenario induced by this loop makes that:
1669 * '-t' ,'-M' and --atomic (if specified) have to come
1670 * before '-A' and the like
1671 */
Bart De Schuymer60332e02002-06-23 08:01:47 +00001672
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001673 /*
1674 * getopt saves the day
1675 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001676 while ((c = getopt_long(argc, argv,
Bart De Schuymeraac31142002-08-11 11:57:52 +00001677 "-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 +00001678 switch (c) {
1679
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001680 case 'A': /* add a rule */
1681 case 'D': /* delete a rule */
1682 case 'P': /* define policy */
1683 case 'I': /* insert a rule */
1684 case 'N': /* make a user defined chain */
1685 case 'E': /* rename chain */
1686 case 'X': /* delete chain */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001687 replace.command = c;
1688 if (replace.flags & OPT_COMMAND)
1689 print_error("Multiple commands not allowed");
1690 replace.flags |= OPT_COMMAND;
Bart De Schuymer0cb01792003-05-04 16:52:04 +00001691 get_kernel_table();
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001692 if (optarg[0] == '-' || !strcmp(optarg, "!"))
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001693 print_error("No chain name specified");
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001694 if (c == 'N') {
1695 struct ebt_u_chain_list *cl, **cl2;
1696
1697 if (get_hooknr(optarg) != -1)
1698 print_error("Chain %s already exists",
1699 optarg);
1700 if (find_target(optarg))
1701 print_error("Target with name %s exists"
1702 , optarg);
1703 if (strlen(optarg) >= EBT_CHAIN_MAXNAMELEN)
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001704 print_error("Chain name length can't exceed %d",
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001705 EBT_CHAIN_MAXNAMELEN - 1);
1706 cl = (struct ebt_u_chain_list *)
1707 malloc(sizeof(struct ebt_u_chain_list));
1708 if (!cl)
1709 print_memory();
1710 cl->next = NULL;
1711 cl->udc = (struct ebt_u_entries *)
1712 malloc(sizeof(struct ebt_u_entries));
1713 if (!cl->udc)
1714 print_memory();
1715 cl->udc->nentries = 0;
1716 cl->udc->policy = EBT_ACCEPT;
1717 cl->udc->counter_offset = replace.nentries;
1718 cl->udc->hook_mask = 0;
1719 strcpy(cl->udc->name, optarg);
1720 cl->udc->entries = NULL;
1721 cl->kernel_start = NULL;
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001722 /*
1723 * put the new chain at the end
1724 */
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001725 cl2 = &replace.udc;
1726 while (*cl2)
1727 cl2 = &((*cl2)->next);
1728 *cl2 = cl;
1729 break;
1730 }
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001731 if ((replace.selected_hook = get_hooknr(optarg)) == -1)
1732 print_error("Chain %s doesn't exist", optarg);
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001733 if (c == 'E') {
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001734 if (optind >= argc || argv[optind][0] == '-' ||
1735 !strcmp(argv[optind], "!"))
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001736 print_error("No new chain name specified");
1737 if (strlen(argv[optind]) >= EBT_CHAIN_MAXNAMELEN)
1738 print_error("Chain name len can't exceed %d",
1739 EBT_CHAIN_MAXNAMELEN - 1);
1740 if (get_hooknr(argv[optind]) != -1)
1741 print_error("Chain %s already exists",
1742 argv[optind]);
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001743 if (find_target(argv[optind]))
1744 print_error("Target with name %s exists"
1745 , argv[optind]);
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001746 entries = to_chain();
1747 strcpy(entries->name, argv[optind]);
1748 optind++;
1749 break;
1750 }
1751 if (c == 'X') {
1752 struct ebt_u_chain_list *cl, **cl2;
1753
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001754 if (replace.selected_hook < NF_BR_NUMHOOKS)
1755 print_error("You can't remove a standard chain");
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001756 /*
Bart De Schuymerc27432e2003-01-09 22:01:07 +00001757 * if the chain is referenced, don't delete it,
1758 * also decrement jumps to a chain behind the
1759 * one we're deleting
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001760 */
Bart De Schuymerb909f9b2002-06-26 18:35:31 +00001761 check_for_references(replace.selected_hook - NF_BR_NUMHOOKS);
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001762 flush_chains();
1763 entries = to_chain();
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001764 cl2 = &(replace.udc);
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001765 while ((*cl2)->udc != entries)
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001766 cl2 = &((*cl2)->next);
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001767 cl = (*cl2);
1768 (*cl2) = (*cl2)->next;
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001769 free(cl->udc);
1770 free(cl);
1771 break;
1772 }
1773
Bart De Schuymercc440052002-11-06 21:10:33 +00001774 if (c == 'D' && optind < argc &&
Bart De Schuymerc3b97f52003-04-17 17:03:49 +00001775 (argv[optind][0] != '-' ||
1776 (argv[optind][1] >= '0' && argv[optind][1] <= '9'))) {
Bart De Schuymercc440052002-11-06 21:10:33 +00001777 if (parse_delete_rule(argv[optind],
1778 &rule_nr, &rule_nr_end))
1779 print_error("Problem with the "
1780 "specified rule number(s)");
1781 optind++;
1782 }
1783 if (c == 'I') {
Bart De Schuymerc3b97f52003-04-17 17:03:49 +00001784 if (optind >= argc || (argv[optind][0] == '-' &&
1785 (argv[optind][1] < '0' || argv[optind][1] > '9')))
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001786 print_error("No rulenr for -I"
1787 " specified");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001788 rule_nr = strtol(argv[optind], &buffer, 10);
Bart De Schuymerc3b97f52003-04-17 17:03:49 +00001789 if (*buffer != '\0')
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001790 print_error("Problem with the "
1791 "specified rule number");
1792 optind++;
1793 }
1794 if (c == 'P') {
1795 if (optind >= argc)
1796 print_error("No policy specified");
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001797 policy = 0;
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001798 for (i = 0; i < NUM_STANDARD_TARGETS; i++)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001799 if (!strcmp(argv[optind],
1800 standard_targets[i])) {
Bart De Schuymer60332e02002-06-23 08:01:47 +00001801 policy = -i -1;
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001802 if (policy == EBT_CONTINUE)
1803 policy = 0;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001804 break;
1805 }
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001806 if (policy == 0)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001807 print_error("Wrong policy");
1808 optind++;
1809 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001810 break;
1811
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001812 case 'L': /* list */
1813 case 'F': /* flush */
1814 case 'Z': /* zero counters */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001815 if (c == 'Z') {
1816 if (replace.flags & OPT_ZERO)
1817 print_error("Multiple commands"
1818 " not allowed");
1819 if ( (replace.flags & OPT_COMMAND &&
1820 replace.command != 'L'))
1821 print_error("command -Z only allowed "
1822 "together with command -L");
1823 replace.flags |= OPT_ZERO;
1824 } else {
1825 replace.command = c;
1826 if (replace.flags & OPT_COMMAND)
1827 print_error("Multiple commands"
1828 " not allowed");
1829 replace.flags |= OPT_COMMAND;
1830 }
Bart De Schuymer0cb01792003-05-04 16:52:04 +00001831 get_kernel_table();
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001832 i = -1;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001833 if (optarg) {
1834 if ( (i = get_hooknr(optarg)) == -1 )
1835 print_error("Bad chain");
1836 } else
1837 if (optind < argc && argv[optind][0] != '-') {
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001838 if ((i = get_hooknr(argv[optind])) == -1)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001839 print_error("Bad chain");
1840 optind++;
1841 }
1842 if (i != -1) {
1843 if (c == 'Z')
1844 zerochain = i;
1845 else
1846 replace.selected_hook = i;
1847 }
1848 break;
1849
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001850 case 'V': /* version */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001851 replace.command = 'V';
1852 if (replace.flags & OPT_COMMAND)
1853 print_error("Multiple commands not allowed");
Bart De Schuymer57a3f6a2003-04-01 16:59:33 +00001854 PRINT_VERSION;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001855 exit(0);
1856
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001857 case 'M': /* modprobe */
Bart De Schuymer60332e02002-06-23 08:01:47 +00001858 if (replace.command != 'h')
1859 print_error("Please put the -M option earlier");
Bart De Schuymerc8531032002-06-14 21:55:29 +00001860 modprobe = optarg;
1861 break;
1862
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001863 case 'h': /* help */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001864 if (replace.flags & OPT_COMMAND)
1865 print_error("Multiple commands not allowed");
1866 replace.command = 'h';
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001867 /*
1868 * All other arguments should be extension names
1869 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001870 while (optind < argc) {
1871 struct ebt_u_match *m;
1872 struct ebt_u_watcher *w;
1873
Bart De Schuymer9a0fbf22003-01-11 16:16:54 +00001874 if (!strcasecmp("list_extensions",
1875 argv[optind]))
1876 list_extensions();
1877
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001878 if ((m = find_match(argv[optind])))
1879 add_match(m);
1880 else if ((w = find_watcher(argv[optind])))
1881 add_watcher(w);
1882 else {
1883 if (!(t = find_target(argv[optind])))
1884 print_error("Extension %s "
1885 "not found", argv[optind]);
1886 if (replace.flags & OPT_JUMP)
1887 print_error("Sorry, you can "
1888 "only see help for one "
1889 "target extension each time");
1890 replace.flags |= OPT_JUMP;
1891 new_entry->t =
1892 (struct ebt_entry_target *)t;
1893 }
1894 optind++;
1895 }
1896 break;
1897
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001898 case 't': /* table */
Bart De Schuymer60332e02002-06-23 08:01:47 +00001899 if (replace.command != 'h')
1900 print_error("Please put the -t option first");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001901 check_option(&replace.flags, OPT_TABLE);
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001902 if (strlen(optarg) > EBT_TABLE_MAXNAMELEN - 1)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001903 print_error("Table name too long");
1904 strcpy(replace.name, optarg);
1905 break;
1906
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001907 case 'i': /* input interface */
1908 case 2 : /* logical input interface */
1909 case 'o': /* output interface */
1910 case 3 : /* logical output interface */
1911 case 'j': /* target */
1912 case 'p': /* net family protocol */
1913 case 's': /* source mac */
1914 case 'd': /* destination mac */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001915 if ((replace.flags & OPT_COMMAND) == 0)
1916 print_error("No command specified");
1917 if ( replace.command != 'A' &&
1918 replace.command != 'D' && replace.command != 'I')
1919 print_error("Command and option do not match");
1920 if (c == 'i') {
1921 check_option(&replace.flags, OPT_IN);
1922 if (replace.selected_hook > 2 &&
1923 replace.selected_hook < NF_BR_BROUTING)
1924 print_error("Use in-interface only in "
1925 "INPUT, FORWARD, PREROUTING and"
1926 "BROUTING chains");
1927 if (check_inverse(optarg))
1928 new_entry->invflags |= EBT_IIN;
1929
1930 if (optind > argc)
1931 print_error("No in-interface "
1932 "specified");
1933 if (strlen(argv[optind - 1]) >= IFNAMSIZ)
Bart De Schuymerc5075142002-08-18 14:21:19 +00001934 print_if_l_error;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001935 strcpy(new_entry->in, argv[optind - 1]);
1936 break;
1937 }
1938 if (c == 2) {
1939 check_option(&replace.flags, OPT_LOGICALIN);
1940 if (replace.selected_hook > 2 &&
1941 replace.selected_hook < NF_BR_BROUTING)
1942 print_error("Use logical in-interface "
1943 "only in INPUT, FORWARD, "
1944 "PREROUTING and BROUTING chains");
1945 if (check_inverse(optarg))
1946 new_entry->invflags |= EBT_ILOGICALIN;
1947
1948 if (optind > argc)
1949 print_error("No logical in-interface "
1950 "specified");
1951 if (strlen(argv[optind - 1]) >= IFNAMSIZ)
Bart De Schuymerc5075142002-08-18 14:21:19 +00001952 print_if_l_error;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001953 strcpy(new_entry->logical_in, argv[optind - 1]);
1954 break;
1955 }
1956 if (c == 'o') {
1957 check_option(&replace.flags, OPT_OUT);
1958 if (replace.selected_hook < 2)
1959 print_error("Use out-interface only"
1960 " in OUTPUT, FORWARD and "
1961 "POSTROUTING chains");
1962 if (check_inverse(optarg))
1963 new_entry->invflags |= EBT_IOUT;
1964
1965 if (optind > argc)
1966 print_error("No out-interface "
1967 "specified");
1968
1969 if (strlen(argv[optind - 1]) >= IFNAMSIZ)
Bart De Schuymerc5075142002-08-18 14:21:19 +00001970 print_if_l_error;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001971 strcpy(new_entry->out, argv[optind - 1]);
1972 break;
1973 }
1974 if (c == 3) {
1975 check_option(&replace.flags, OPT_LOGICALOUT);
1976 if (replace.selected_hook < 2)
1977 print_error("Use logical out-interface "
1978 "only in OUTPUT, FORWARD and "
1979 "POSTROUTING chains");
1980 if (check_inverse(optarg))
1981 new_entry->invflags |= EBT_ILOGICALOUT;
1982
1983 if (optind > argc)
1984 print_error("No logical out-interface "
1985 "specified");
1986
1987 if (strlen(argv[optind - 1]) >= IFNAMSIZ)
Bart De Schuymerc5075142002-08-18 14:21:19 +00001988 print_if_l_error;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001989 strcpy(new_entry->logical_out,
1990 argv[optind - 1]);
1991 break;
1992 }
1993 if (c == 'j') {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001994 check_option(&replace.flags, OPT_JUMP);
1995 for (i = 0; i < NUM_STANDARD_TARGETS; i++)
1996 if (!strcmp(optarg,
1997 standard_targets[i])) {
1998 t = find_target(
1999 EBT_STANDARD_TARGET);
2000 ((struct ebt_standard_target *)
Bart De Schuymer60332e02002-06-23 08:01:47 +00002001 t->t)->verdict = -i - 1;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002002 break;
2003 }
Bart De Schuymer60332e02002-06-23 08:01:47 +00002004 if (-i - 1 == EBT_RETURN) {
2005 if (replace.selected_hook < NF_BR_NUMHOOKS)
2006 print_error("Return target"
2007 " only for user defined chains");
2008 }
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +00002009 if (i != NUM_STANDARD_TARGETS)
2010 break;
Bart De Schuymer1ab41562002-06-23 17:09:54 +00002011 if ((i = get_hooknr(optarg)) != -1) {
2012 if (i < NF_BR_NUMHOOKS)
2013 print_error("don't jump"
2014 " to a standard chain");
2015 t = find_target(
2016 EBT_STANDARD_TARGET);
2017 ((struct ebt_standard_target *)
2018 t->t)->verdict = i - NF_BR_NUMHOOKS;
2019 break;
2020 }
2021 else {
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002022 /*
2023 * must be an extension then
2024 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002025 struct ebt_u_target *t;
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00002026
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002027 t = find_target(optarg);
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002028 /*
2029 * -j standard not allowed either
2030 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002031 if (!t || t ==
2032 (struct ebt_u_target *)new_entry->t)
2033 print_error("Illegal target "
2034 "name");
2035 new_entry->t =
2036 (struct ebt_entry_target *)t;
2037 }
2038 break;
2039 }
2040 if (c == 's') {
2041 check_option(&replace.flags, OPT_SOURCE);
2042 if (check_inverse(optarg))
2043 new_entry->invflags |= EBT_ISOURCE;
2044
2045 if (optind > argc)
2046 print_error("No source mac "
2047 "specified");
2048 if (getmac_and_mask(argv[optind - 1],
2049 new_entry->sourcemac, new_entry->sourcemsk))
2050 print_error("Problem with specified "
2051 "source mac");
2052 new_entry->bitmask |= EBT_SOURCEMAC;
2053 break;
2054 }
2055 if (c == 'd') {
2056 check_option(&replace.flags, OPT_DEST);
2057 if (check_inverse(optarg))
2058 new_entry->invflags |= EBT_IDEST;
2059
2060 if (optind > argc)
2061 print_error("No destination mac "
2062 "specified");
2063 if (getmac_and_mask(argv[optind - 1],
2064 new_entry->destmac, new_entry->destmsk))
2065 print_error("Problem with specified "
2066 "destination mac");
2067 new_entry->bitmask |= EBT_DESTMAC;
2068 break;
2069 }
2070 check_option(&replace.flags, OPT_PROTOCOL);
2071 if (check_inverse(optarg))
2072 new_entry->invflags |= EBT_IPROTO;
2073
2074 if (optind > argc)
2075 print_error("No protocol specified");
2076 new_entry->bitmask &= ~((unsigned int)EBT_NOPROTO);
2077 i = strtol(argv[optind - 1], &buffer, 16);
2078 if (*buffer == '\0' && (i < 0 || i > 0xFFFF))
2079 print_error("Problem with the specified "
2080 "protocol");
2081 new_entry->ethproto = i;
Bart De Schuymer28bf6f62002-06-26 18:57:24 +00002082 if (*buffer != '\0') {
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002083 struct ethertypeent *ent;
2084
2085 if (!strcasecmp(argv[optind - 1], "LENGTH")) {
2086 new_entry->bitmask |= EBT_802_3;
2087 break;
2088 }
2089 ent = getethertypebyname(argv[optind - 1]);
2090 if (!ent)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002091 print_error("Problem with the specified"
2092 " protocol");
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002093 new_entry->ethproto = ent->e_ethertype;
Bart De Schuymer28bf6f62002-06-26 18:57:24 +00002094 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002095 if (new_entry->ethproto < 1536 &&
2096 !(new_entry->bitmask & EBT_802_3))
2097 print_error("Sorry, protocols have values above"
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00002098 " or equal to 0x0600");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002099 break;
2100
Bart De Schuymer9895a8e2003-01-11 10:14:24 +00002101 case 4 : /* Lc */
Bart De Schuymer9af14f92002-07-10 20:49:10 +00002102 check_option(&replace.flags, LIST_C);
Bart De Schuymer9af14f92002-07-10 20:49:10 +00002103 if (replace.command != 'L')
2104 print_error("Use --Lc with -L");
2105 if (replace.flags & LIST_X)
2106 print_error("--Lx not compatible with --Lc");
2107 replace.flags |= LIST_C;
2108 break;
Bart De Schuymer9895a8e2003-01-11 10:14:24 +00002109 case 5 : /* Ln */
Bart De Schuymer9af14f92002-07-10 20:49:10 +00002110 check_option(&replace.flags, LIST_N);
Bart De Schuymer9af14f92002-07-10 20:49:10 +00002111 if (replace.command != 'L')
2112 print_error("Use --Ln with -L");
2113 if (replace.flags & LIST_X)
2114 print_error("--Lx not compatible with --Ln");
2115 replace.flags |= LIST_N;
2116 break;
Bart De Schuymer9895a8e2003-01-11 10:14:24 +00002117 case 6 : /* Lx */
Bart De Schuymer9af14f92002-07-10 20:49:10 +00002118 check_option(&replace.flags, LIST_X);
Bart De Schuymer9af14f92002-07-10 20:49:10 +00002119 if (replace.command != 'L')
2120 print_error("Use --Lx with -L");
2121 if (replace.flags & LIST_C)
2122 print_error("--Lx not compatible with --Lc");
2123 if (replace.flags & LIST_N)
2124 print_error("--Lx not compatible with --Ln");
2125 replace.flags |= LIST_X;
2126 break;
Bart De Schuymer22d03a22003-05-03 20:28:22 +00002127 case 12 : /* Lmac2 */
2128 check_option(&replace.flags, LIST_MAC2);
2129 if (replace.command != 'L')
2130 print_error("Use --Lmac2 with -L");
2131 replace.flags |= LIST_MAC2;
2132 break;
Bart De Schuymer9895a8e2003-01-11 10:14:24 +00002133 case 8 : /* atomic-commit */
Bart De Schuymer62423742002-07-14 19:06:20 +00002134 replace.command = c;
2135 if (replace.flags & OPT_COMMAND)
2136 print_error("Multiple commands not allowed");
2137 replace.flags |= OPT_COMMAND;
Bart De Schuymer5885b362002-12-03 20:51:36 +00002138 if (!replace.filename)
2139 print_error("No atomic file specified");
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002140 /*
2141 * get the information from the file
2142 */
Bart De Schuymer62423742002-07-14 19:06:20 +00002143 get_table(&replace);
Bart De Schuymer868bf642002-07-16 18:14:20 +00002144 if (replace.nentries) {
Bart De Schuymered053432002-07-21 19:35:39 +00002145 replace.counterchanges = (unsigned short *)
Bart De Schuymer868bf642002-07-16 18:14:20 +00002146 malloc(sizeof(unsigned short) * (replace.nentries + 1));
2147 for (i = 0; i < replace.nentries; i++)
Bart De Schuymered053432002-07-21 19:35:39 +00002148 replace.counterchanges[i] = CNT_NORM;
2149 replace.counterchanges[i] = CNT_END;
Bart De Schuymer868bf642002-07-16 18:14:20 +00002150 }
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002151 /*
2152 * we don't want the kernel giving us its counters, they would
2153 * overwrite the counters extracted from the file
2154 */
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00002155 replace.num_counters = 0;
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002156 /*
2157 * make sure the table will be written to the kernel
Bart De Schuymer5885b362002-12-03 20:51:36 +00002158 * possible memory leak here
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002159 */
Bart De Schuymer62423742002-07-14 19:06:20 +00002160 replace.filename = NULL;
2161 break;
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002162 case 7 : /* atomic-init */
2163 case 10: /* atomic-save */
2164 case 11: /* init-table */
Bart De Schuymer62423742002-07-14 19:06:20 +00002165 replace.command = c;
2166 if (replace.flags & OPT_COMMAND)
2167 print_error("Multiple commands not allowed");
Bart De Schuymer5885b362002-12-03 20:51:36 +00002168 if (c != 11 && !replace.filename)
2169 print_error("No atomic file specified");
Bart De Schuymer62423742002-07-14 19:06:20 +00002170 replace.flags |= OPT_COMMAND;
Bart De Schuymer5885b362002-12-03 20:51:36 +00002171 {
2172 char *tmp = replace.filename;
2173
2174 tmp = replace.filename;
2175 /* get the kernel table */
2176 replace.filename = NULL;
Bart De Schuymer0cb01792003-05-04 16:52:04 +00002177 get_kernel_table();
Bart De Schuymer5885b362002-12-03 20:51:36 +00002178 replace.filename = tmp;
2179 }
Bart De Schuymera8d920b2002-07-16 18:30:44 +00002180 if (replace.nentries) {
Bart De Schuymered053432002-07-21 19:35:39 +00002181 replace.counterchanges = (unsigned short *)
Bart De Schuymer5f16dc72002-07-16 18:08:36 +00002182 malloc(sizeof(unsigned short) * (replace.nentries + 1));
2183 for (i = 0; i < replace.nentries; i++)
Bart De Schuymered053432002-07-21 19:35:39 +00002184 replace.counterchanges[i] = CNT_NORM;
2185 replace.counterchanges[i] = CNT_END;
Bart De Schuymer5f16dc72002-07-16 18:08:36 +00002186 }
Bart De Schuymer5885b362002-12-03 20:51:36 +00002187 break;
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002188 case 9 : /* atomic */
Bart De Schuymer5885b362002-12-03 20:51:36 +00002189 if (replace.flags & OPT_COMMAND)
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00002190 print_error("--atomic has to come before"
2191 " the command");
Bart De Schuymer5885b362002-12-03 20:51:36 +00002192 /* another possible memory leak here */
Bart De Schuymer62423742002-07-14 19:06:20 +00002193 replace.filename = (char *)malloc(strlen(optarg) + 1);
2194 strcpy(replace.filename, optarg);
2195 break;
Bart De Schuymera615b962002-11-03 14:54:09 +00002196 case 1 :
2197 if (!strcmp(optarg, "!"))
2198 check_inverse(optarg);
2199 else
2200 print_error("Bad argument : %s", optarg);
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002201 /*
2202 * check_inverse() did optind++
2203 */
Bart De Schuymera615b962002-11-03 14:54:09 +00002204 optind--;
2205 continue;
Bart De Schuymer9af14f92002-07-10 20:49:10 +00002206 default:
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002207 /*
2208 * is it a target option?
2209 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002210 t = (struct ebt_u_target *)new_entry->t;
2211 if ((t->parse(c - t->option_offset, argv, argc,
2212 new_entry, &t->flags, &t->t)))
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00002213 goto check_extension;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002214
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002215 /*
2216 * is it a match_option?
2217 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002218 for (m = matches; m; m = m->next)
2219 if (m->parse(c - m->option_offset, argv,
2220 argc, new_entry, &m->flags, &m->m))
2221 break;
2222
2223 if (m != NULL) {
2224 if (m->used == 0)
2225 add_match(m);
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00002226 goto check_extension;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002227 }
2228
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002229 /*
2230 * is it a watcher option?
2231 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002232 for (w = watchers; w; w = w->next)
2233 if (w->parse(c-w->option_offset, argv,
2234 argc, new_entry, &w->flags, &w->w))
2235 break;
2236
2237 if (w == NULL)
2238 print_error("Unknown argument");
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00002239 if (w->used == 0)
2240 add_watcher(w);
2241check_extension:
Bart De Schuymer60332e02002-06-23 08:01:47 +00002242 if (replace.command != 'A' && replace.command != 'I' &&
2243 replace.command != 'D')
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00002244 print_error("Extensions only for -A, -I and -D");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002245 }
Bart De Schuymera615b962002-11-03 14:54:09 +00002246 invert = 0;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002247 }
2248
Bart De Schuymer25c741d2002-06-23 18:54:34 +00002249 if ( !table && !(table = find_table(replace.name)) )
2250 print_error("Bad table name");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002251
2252 if ( (replace.flags & OPT_COMMAND) && replace.command != 'L' &&
2253 replace.flags & OPT_ZERO )
2254 print_error("Command -Z only allowed together with command -L");
2255
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002256 /*
2257 * do this after parsing everything, so we can print specific info
2258 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002259 if (replace.command == 'h' && !(replace.flags & OPT_ZERO))
2260 print_help();
2261
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002262 /*
2263 * do the final checks
2264 */
Bart De Schuymer60332e02002-06-23 08:01:47 +00002265 if (replace.command == 'A' || replace.command == 'I' ||
2266 replace.command == 'D') {
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002267 /*
2268 * this will put the hook_mask right for the chains
2269 */
Bart De Schuymer60332e02002-06-23 08:01:47 +00002270 check_for_loops();
2271 entries = to_chain();
2272 m_l = new_entry->m_list;
2273 w_l = new_entry->w_list;
2274 t = (struct ebt_u_target *)new_entry->t;
2275 while (m_l) {
2276 m = (struct ebt_u_match *)(m_l->m);
2277 m->final_check(new_entry, m->m, replace.name,
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +00002278 entries->hook_mask, 0);
Bart De Schuymer60332e02002-06-23 08:01:47 +00002279 m_l = m_l->next;
2280 }
2281 while (w_l) {
2282 w = (struct ebt_u_watcher *)(w_l->w);
2283 w->final_check(new_entry, w->w, replace.name,
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +00002284 entries->hook_mask, 0);
Bart De Schuymer60332e02002-06-23 08:01:47 +00002285 w_l = w_l->next;
2286 }
2287 t->final_check(new_entry, t->t, replace.name,
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +00002288 entries->hook_mask, 0);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002289 }
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002290 /*
2291 * so, the extensions can work with the host endian
2292 * the kernel does not have to do this ofcourse
2293 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002294 new_entry->ethproto = htons(new_entry->ethproto);
2295
Bart De Schuymerc34f4672002-08-18 18:03:52 +00002296 if (replace.command == 'P') {
2297 if (replace.selected_hook < NF_BR_NUMHOOKS &&
2298 policy == EBT_RETURN)
2299 print_error("Policy RETURN only allowed for user "
2300 "defined chains");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002301 change_policy(policy);
Bart De Schuymerc34f4672002-08-18 18:03:52 +00002302 } else if (replace.command == 'L') {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002303 list_rules();
2304 if (replace.flags & OPT_ZERO)
2305 zero_counters(zerochain);
2306 else
2307 exit(0);
2308 }
2309 if (replace.flags & OPT_ZERO)
2310 zero_counters(zerochain);
Bart De Schuymer1ab41562002-06-23 17:09:54 +00002311 else if (replace.command == 'F') {
2312 if (flush_chains() == -1)
2313 exit(0);
2314 } else if (replace.command == 'A' || replace.command == 'I') {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002315 add_rule(rule_nr);
Bart De Schuymer1ab41562002-06-23 17:09:54 +00002316 check_for_loops();
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002317 /*
2318 * do the final_check(), for all entries
2319 * needed when adding a rule that has a chain target
2320 */
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +00002321 i = -1;
2322 while (1) {
2323 struct ebt_u_entry *e;
2324
2325 i++;
2326 entries = nr_to_chain(i);
2327 if (!entries) {
2328 if (i < NF_BR_NUMHOOKS)
2329 continue;
2330 else
2331 break;
2332 }
2333 e = entries->entries;
2334 while (e) {
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002335 /*
2336 * userspace extensions use host endian
2337 */
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +00002338 e->ethproto = ntohs(e->ethproto);
2339 do_final_checks(e, entries);
2340 e->ethproto = htons(e->ethproto);
2341 e = e->next;
2342 }
2343 }
Bart De Schuymerc3b97f52003-04-17 17:03:49 +00002344 } else if (replace.command == 'D')
Bart De Schuymercc440052002-11-06 21:10:33 +00002345 delete_rule(rule_nr, rule_nr_end);
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002346 /*
2347 * commands -N, -E, -X, --atomic-commit, --atomic-commit, --atomic-save,
2348 * --init-table fall through
2349 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002350
2351 if (table->check)
2352 table->check(&replace);
2353
2354 deliver_table(&replace);
2355
Bart De Schuymered053432002-07-21 19:35:39 +00002356 if (replace.counterchanges)
2357 deliver_counters(&replace);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002358 return 0;
2359}