blob: 93ec90f91016de27fa283a0a6f2d923a0e01ab2f [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 Schuymerb6c94f92003-06-14 13:08:03 +0000930static void counters_nochange()
931{
932 int i;
933
934 replace.num_counters = replace.nentries;
935 if (replace.nentries) {
936 /*
937 * '+ 1' for the CNT_END
938 */
939 if (!(replace.counterchanges = (unsigned short *) malloc(
940 (replace.nentries + 1) * sizeof(unsigned short))))
941 print_memory();
942 /*
943 * done nothing special to the rules
944 */
945 for (i = 0; i < replace.nentries; i++)
946 replace.counterchanges[i] = CNT_NORM;
947 replace.counterchanges[replace.nentries] = CNT_END;
948 }
949 else
950 replace.counterchanges = NULL;
951}
952
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000953/*
954 * execute command P
955 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000956static void change_policy(int policy)
957{
Bart De Schuymer60332e02002-06-23 08:01:47 +0000958 struct ebt_u_entries *entries = to_chain();
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000959
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000960 /*
961 * don't do anything if the policy is the same
962 */
Bart De Schuymer60332e02002-06-23 08:01:47 +0000963 if (entries->policy != policy) {
964 entries->policy = policy;
Bart De Schuymerb6c94f92003-06-14 13:08:03 +0000965 counters_nochange();
966 } else
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000967 exit(0);
968}
969
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000970/*
971 * flush one chain or the complete table
972 * -1 == nothing to do
973 * 0 == give back to kernel
974 */
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000975static int flush_chains()
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000976{
Bart De Schuymer60332e02002-06-23 08:01:47 +0000977 int i, j, oldnentries, numdel;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000978 unsigned short *cnt;
979 struct ebt_u_entry *u_e, *tmp;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000980 struct ebt_u_entries *entries = to_chain();
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000981
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000982 /*
983 * flush whole table
984 */
Bart De Schuymer60332e02002-06-23 08:01:47 +0000985 if (!entries) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000986 if (replace.nentries == 0)
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000987 return -1;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000988 replace.nentries = 0;
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000989 /*
990 * no need for the kernel to give us counters back
991 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000992 replace.num_counters = 0;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000993
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000994 /*
995 * free everything and zero (n)entries
996 */
Bart De Schuymer60332e02002-06-23 08:01:47 +0000997 i = -1;
998 while (1) {
999 i++;
1000 entries = nr_to_chain(i);
1001 if (!entries) {
1002 if (i < NF_BR_NUMHOOKS)
1003 continue;
1004 else
1005 break;
1006 }
1007 entries->nentries = 0;
1008 entries->counter_offset = 0;
1009 u_e = entries->entries;
1010 entries->entries = NULL;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001011 while (u_e) {
1012 free_u_entry(u_e);
1013 tmp = u_e->next;
1014 free(u_e);
1015 u_e = tmp;
1016 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001017 }
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001018 return 0;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001019 }
1020
Bart De Schuymer60332e02002-06-23 08:01:47 +00001021 if (entries->nentries == 0)
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001022 return -1;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001023 oldnentries = replace.nentries;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001024 replace.nentries -= entries->nentries;
1025 numdel = entries->nentries;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001026
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001027 if (replace.nentries) {
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001028 /*
1029 * +1 for CNT_END
1030 */
Bart De Schuymered053432002-07-21 19:35:39 +00001031 if ( !(replace.counterchanges = (unsigned short *)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001032 malloc((oldnentries + 1) * sizeof(unsigned short))) )
1033 print_memory();
Bart De Schuymer60332e02002-06-23 08:01:47 +00001034 }
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001035 /*
1036 * delete the counters belonging to the specified chain,
1037 * update counter_offset
1038 */
Bart De Schuymer60332e02002-06-23 08:01:47 +00001039 i = -1;
Bart De Schuymered053432002-07-21 19:35:39 +00001040 cnt = replace.counterchanges;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001041 while (1) {
1042 i++;
1043 entries = nr_to_chain(i);
1044 if (!entries) {
1045 if (i < NF_BR_NUMHOOKS)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001046 continue;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001047 else
1048 break;
1049 }
1050 if (i > replace.selected_hook)
1051 entries->counter_offset -= numdel;
1052 if (replace.nentries) {
1053 for (j = 0; j < entries->nentries; j++) {
1054 if (i == replace.selected_hook)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001055 *cnt = CNT_DEL;
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001056 else
1057 *cnt = CNT_NORM;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001058 cnt++;
1059 }
1060 }
Bart De Schuymer60332e02002-06-23 08:01:47 +00001061 }
1062
1063 if (replace.nentries) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001064 *cnt = CNT_END;
1065 replace.num_counters = oldnentries;
Bart De Schuymercc440052002-11-06 21:10:33 +00001066 } else
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001067 replace.num_counters = 0;
1068
Bart De Schuymer60332e02002-06-23 08:01:47 +00001069 entries = to_chain();
1070 entries->nentries = 0;
1071 u_e = entries->entries;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001072 while (u_e) {
1073 free_u_entry(u_e);
1074 tmp = u_e->next;
1075 free(u_e);
1076 u_e = tmp;
1077 }
Bart De Schuymer60332e02002-06-23 08:01:47 +00001078 entries->entries = NULL;
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001079 return 0;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001080}
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001081
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001082/*
1083 * -1 == no match
1084 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001085static int check_rule_exists(int rule_nr)
1086{
1087 struct ebt_u_entry *u_e;
1088 struct ebt_u_match_list *m_l, *m_l2;
1089 struct ebt_u_match *m;
1090 struct ebt_u_watcher_list *w_l, *w_l2;
1091 struct ebt_u_watcher *w;
1092 struct ebt_u_target *t = (struct ebt_u_target *)new_entry->t;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001093 struct ebt_u_entries *entries = to_chain();
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001094 int i, j, k;
1095
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001096 /*
1097 * handle '-D chain rulenr' command
1098 */
Bart De Schuymerc3b97f52003-04-17 17:03:49 +00001099 if (rule_nr != 0) {
Bart De Schuymer60332e02002-06-23 08:01:47 +00001100 if (rule_nr > entries->nentries)
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001101 return -1;
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001102 /*
1103 * user starts counting from 1
1104 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001105 return rule_nr - 1;
1106 }
Bart De Schuymer60332e02002-06-23 08:01:47 +00001107 u_e = entries->entries;
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001108 /*
1109 * check for an existing rule (if there are duplicate rules,
1110 * take the first occurance)
1111 */
Bart De Schuymer60332e02002-06-23 08:01:47 +00001112 for (i = 0; i < entries->nentries; i++, u_e = u_e->next) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001113 if (!u_e)
1114 print_bug("Hmm, trouble");
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001115 if (u_e->ethproto != new_entry->ethproto)
1116 continue;
1117 if (strcmp(u_e->in, new_entry->in))
1118 continue;
1119 if (strcmp(u_e->out, new_entry->out))
1120 continue;
1121 if (strcmp(u_e->logical_in, new_entry->logical_in))
1122 continue;
1123 if (strcmp(u_e->logical_out, new_entry->logical_out))
1124 continue;
1125 if (new_entry->bitmask & EBT_SOURCEMAC &&
1126 memcmp(u_e->sourcemac, new_entry->sourcemac, ETH_ALEN))
1127 continue;
1128 if (new_entry->bitmask & EBT_DESTMAC &&
1129 memcmp(u_e->destmac, new_entry->destmac, ETH_ALEN))
1130 continue;
1131 if (new_entry->bitmask != u_e->bitmask ||
1132 new_entry->invflags != u_e->invflags)
1133 continue;
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001134 /*
1135 * compare all matches
1136 */
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001137 m_l = new_entry->m_list;
1138 j = 0;
1139 while (m_l) {
1140 m = (struct ebt_u_match *)(m_l->m);
1141 m_l2 = u_e->m_list;
1142 while (m_l2 && strcmp(m_l2->m->u.name, m->m->u.name))
1143 m_l2 = m_l2->next;
1144 if (!m_l2 || !m->compare(m->m, m_l2->m))
1145 goto letscontinue;
1146 j++;
1147 m_l = m_l->next;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001148 }
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001149 /*
1150 * now be sure they have the same nr of matches
1151 */
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001152 k = 0;
1153 m_l = u_e->m_list;
1154 while (m_l) {
1155 k++;
1156 m_l = m_l->next;
1157 }
1158 if (j != k)
1159 continue;
1160
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001161 /*
1162 * compare all watchers
1163 */
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001164 w_l = new_entry->w_list;
1165 j = 0;
1166 while (w_l) {
1167 w = (struct ebt_u_watcher *)(w_l->w);
1168 w_l2 = u_e->w_list;
1169 while (w_l2 && strcmp(w_l2->w->u.name, w->w->u.name))
1170 w_l2 = w_l2->next;
1171 if (!w_l2 || !w->compare(w->w, w_l2->w))
1172 goto letscontinue;
1173 j++;
1174 w_l = w_l->next;
1175 }
1176 k = 0;
1177 w_l = u_e->w_list;
1178 while (w_l) {
1179 k++;
1180 w_l = w_l->next;
1181 }
1182 if (j != k)
1183 continue;
1184 if (strcmp(t->t->u.name, u_e->t->u.name))
1185 continue;
1186 if (!t->compare(t->t, u_e->t))
1187 continue;
1188 return i;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001189letscontinue:
1190 }
1191 return -1;
1192}
1193
Bart De Schuymer9895a8e2003-01-11 10:14:24 +00001194/* execute command A or I */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001195static void add_rule(int rule_nr)
1196{
1197 int i, j;
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001198 struct ebt_u_entry **u_e;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001199 unsigned short *cnt;
1200 struct ebt_u_match_list *m_l;
1201 struct ebt_u_watcher_list *w_l;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001202 struct ebt_u_entries *entries = to_chain(), *entries2;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001203
Bart De Schuymerc3b97f52003-04-17 17:03:49 +00001204 if (rule_nr <= 0)
1205 rule_nr += entries->nentries;
1206 else
1207 rule_nr--;
1208 if (rule_nr > entries->nentries || rule_nr < 0)
1209 print_error("The specified rule number is incorrect");
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001210 /*
1211 * we're adding one rule
1212 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001213 replace.num_counters = replace.nentries;
1214 replace.nentries++;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001215 entries->nentries++;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001216
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001217 /*
1218 * handle counter stuff
1219 * +1 for CNT_END
1220 */
Bart De Schuymered053432002-07-21 19:35:39 +00001221 if ( !(replace.counterchanges = (unsigned short *)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001222 malloc((replace.nentries + 1) * sizeof(unsigned short))) )
1223 print_memory();
Bart De Schuymered053432002-07-21 19:35:39 +00001224 cnt = replace.counterchanges;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001225 for (i = 0; i < replace.selected_hook; i++) {
Bart De Schuymer60332e02002-06-23 08:01:47 +00001226 if (i < NF_BR_NUMHOOKS && !(replace.valid_hooks & (1 << i)))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001227 continue;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001228 entries2 = nr_to_chain(i);
1229 for (j = 0; j < entries2->nentries; j++) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001230 *cnt = CNT_NORM;
1231 cnt++;
1232 }
1233 }
1234 for (i = 0; i < rule_nr; i++) {
1235 *cnt = CNT_NORM;
1236 cnt++;
1237 }
1238 *cnt = CNT_ADD;
1239 cnt++;
Bart De Schuymered053432002-07-21 19:35:39 +00001240 while (cnt != replace.counterchanges + replace.nentries) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001241 *cnt = CNT_NORM;
1242 cnt++;
1243 }
1244 *cnt = CNT_END;
1245
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001246 /*
1247 * go to the right position in the chain
1248 */
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001249 u_e = &entries->entries;
1250 for (i = 0; i < rule_nr; i++)
1251 u_e = &(*u_e)->next;
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001252 /*
1253 * insert the rule
1254 */
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001255 new_entry->next = *u_e;
1256 *u_e = new_entry;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001257
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001258 /*
1259 * put the ebt_[match, watcher, target] pointers in place
1260 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001261 m_l = new_entry->m_list;
1262 while (m_l) {
1263 m_l->m = ((struct ebt_u_match *)m_l->m)->m;
1264 m_l = m_l->next;
1265 }
1266 w_l = new_entry->w_list;
1267 while (w_l) {
1268 w_l->w = ((struct ebt_u_watcher *)w_l->w)->w;
1269 w_l = w_l->next;
1270 }
1271 new_entry->t = ((struct ebt_u_target *)new_entry->t)->t;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001272
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001273 /*
1274 * update the counter_offset of chains behind this one
1275 */
Bart De Schuymer60332e02002-06-23 08:01:47 +00001276 i = replace.selected_hook;
1277 while (1) {
1278 i++;
1279 entries = nr_to_chain(i);
1280 if (!entries) {
1281 if (i < NF_BR_NUMHOOKS)
1282 continue;
1283 else
1284 break;
1285 } else
1286 entries->counter_offset++;
1287 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001288}
1289
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001290/*
1291 * execute command D
1292 */
Bart De Schuymercc440052002-11-06 21:10:33 +00001293static void delete_rule(int begin, int end)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001294{
Bart De Schuymercc440052002-11-06 21:10:33 +00001295 int j, lentmp = 0, nr_deletes;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001296 unsigned short *cnt;
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001297 struct ebt_u_entry **u_e, *u_e2;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001298 struct ebt_u_entries *entries = to_chain(), *entries2;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001299
Bart De Schuymer336f35e2003-05-22 20:53:12 +00001300 if (begin < 0)
Bart De Schuymerc3b97f52003-04-17 17:03:49 +00001301 begin += entries->nentries + 1;
Bart De Schuymerc3b97f52003-04-17 17:03:49 +00001302 if (end < 0)
1303 end += entries->nentries + 1;
Bart De Schuymer1446c292003-05-25 09:47:01 +00001304
1305 if (begin < 0 || begin > end || end > entries->nentries)
Bart De Schuymerc3b97f52003-04-17 17:03:49 +00001306 print_error("Sorry, wrong rule numbers");
Bart De Schuymer336f35e2003-05-22 20:53:12 +00001307
Bart De Schuymercc440052002-11-06 21:10:33 +00001308 if ((begin = check_rule_exists(begin)) == -1 ||
1309 (end = check_rule_exists(end)) == -1)
Bart De Schuymer60332e02002-06-23 08:01:47 +00001310 print_error("Sorry, rule does not exist");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001311
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001312 /*
1313 * we're deleting rules
1314 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001315 replace.num_counters = replace.nentries;
Bart De Schuymercc440052002-11-06 21:10:33 +00001316 nr_deletes = end - begin + 1;
1317 replace.nentries -= nr_deletes;
1318 entries->nentries -= nr_deletes;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001319
1320 if (replace.nentries) {
1321 for (j = 0; j < replace.selected_hook; j++) {
Bart De Schuymer60332e02002-06-23 08:01:47 +00001322 if (j < NF_BR_NUMHOOKS &&
1323 !(replace.valid_hooks & (1 << j)))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001324 continue;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001325 entries2 = nr_to_chain(j);
1326 lentmp += entries2->nentries;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001327 }
Bart De Schuymercc440052002-11-06 21:10:33 +00001328 lentmp += begin;
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001329 /*
1330 * +1 for CNT_END
1331 */
Bart De Schuymered053432002-07-21 19:35:39 +00001332 if ( !(replace.counterchanges = (unsigned short *)malloc(
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001333 (replace.num_counters + 1) * sizeof(unsigned short))) )
1334 print_memory();
Bart De Schuymered053432002-07-21 19:35:39 +00001335 cnt = replace.counterchanges;
Bart De Schuymercc440052002-11-06 21:10:33 +00001336 for (j = 0; j < lentmp; j++, cnt++)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001337 *cnt = CNT_NORM;
Bart De Schuymercc440052002-11-06 21:10:33 +00001338 for (j = 0; j < nr_deletes; j++, cnt++)
1339 *cnt = CNT_DEL;
1340
1341 for (j = 0; j < replace.num_counters - lentmp - nr_deletes;
1342 j++, cnt++)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001343 *cnt = CNT_NORM;
Bart De Schuymercc440052002-11-06 21:10:33 +00001344
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001345 *cnt = CNT_END;
1346 }
1347 else
1348 replace.num_counters = 0;
1349
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001350 /*
1351 * go to the right position in the chain
1352 */
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001353 u_e = &entries->entries;
Bart De Schuymercc440052002-11-06 21:10:33 +00001354 for (j = 0; j < begin; j++)
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001355 u_e = &(*u_e)->next;
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001356 /*
1357 * remove the rules
1358 */
Bart De Schuymercc440052002-11-06 21:10:33 +00001359 j = nr_deletes;
1360 while(j--) {
1361 u_e2 = *u_e;
1362 *u_e = (*u_e)->next;
Bart De Schuymer9895a8e2003-01-11 10:14:24 +00001363 /* free everything */
Bart De Schuymercc440052002-11-06 21:10:33 +00001364 free_u_entry(u_e2);
1365 free(u_e2);
1366 }
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001367
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001368 /*
1369 * update the counter_offset of chains behind this one
1370 */
Bart De Schuymercc440052002-11-06 21:10:33 +00001371 j = replace.selected_hook;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001372 while (1) {
Bart De Schuymercc440052002-11-06 21:10:33 +00001373 j++;
1374 entries = nr_to_chain(j);
Bart De Schuymer60332e02002-06-23 08:01:47 +00001375 if (!entries) {
Bart De Schuymercc440052002-11-06 21:10:33 +00001376 if (j < NF_BR_NUMHOOKS)
Bart De Schuymer60332e02002-06-23 08:01:47 +00001377 continue;
1378 else
1379 break;
Bart De Schuymercc440052002-11-06 21:10:33 +00001380 } else
1381 entries->counter_offset -= nr_deletes;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001382 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001383}
1384
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001385/*
1386 * execute command Z
1387 */
Bart De Schuymer62423742002-07-14 19:06:20 +00001388static void zero_counters(int zerochain)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001389{
1390
1391 if (zerochain == -1) {
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001392 /*
1393 * tell main() we don't update the counters
1394 * this results in tricking the kernel to zero its counters,
1395 * naively expecting userspace to update its counters. Muahahaha
1396 */
Bart De Schuymered053432002-07-21 19:35:39 +00001397 replace.counterchanges = NULL;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001398 replace.num_counters = 0;
1399 } else {
1400 int i, j;
1401 unsigned short *cnt;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001402 struct ebt_u_entries *entries = nr_to_chain(zerochain), *e2;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001403
Bart De Schuymer60332e02002-06-23 08:01:47 +00001404 if (entries->nentries == 0)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001405 exit(0);
Bart De Schuymered053432002-07-21 19:35:39 +00001406 replace.counterchanges = (unsigned short *)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001407 malloc((replace.nentries + 1) * sizeof(unsigned short));
Bart De Schuymered053432002-07-21 19:35:39 +00001408 if (!replace.counterchanges)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001409 print_memory();
Bart De Schuymered053432002-07-21 19:35:39 +00001410 cnt = replace.counterchanges;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001411 for (i = 0; i < zerochain; i++) {
Bart De Schuymer60332e02002-06-23 08:01:47 +00001412 if (i < NF_BR_NUMHOOKS &&
1413 !(replace.valid_hooks & (1 << i)))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001414 continue;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001415 e2 = nr_to_chain(i);
1416 for (j = 0; j < e2->nentries; j++) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001417 *cnt = CNT_NORM;
1418 cnt++;
1419 }
1420 }
Bart De Schuymer60332e02002-06-23 08:01:47 +00001421 for (i = 0; i < entries->nentries; i++) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001422 *cnt = CNT_ZERO;
1423 cnt++;
1424 }
Bart De Schuymered053432002-07-21 19:35:39 +00001425 while (cnt != replace.counterchanges + replace.nentries) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001426 *cnt = CNT_NORM;
1427 cnt++;
1428 }
1429 *cnt = CNT_END;
1430 }
1431}
1432
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001433/*
1434 * Checks the type for validity and calls getethertypebynumber()
1435 */
1436struct ethertypeent *parseethertypebynumber(int type)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001437{
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001438 if (type < 1536)
1439 print_error("Ethernet protocols have values >= 0x0600");
1440 if (type > 0xffff)
1441 print_error("Ethernet protocols have values <= 0xffff");
1442 return getethertypebynumber(type);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001443}
1444
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001445/*
1446 * put the mac address into 6 (ETH_ALEN) bytes
1447 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001448int getmac_and_mask(char *from, char *to, char *mask)
1449{
1450 char *p;
1451 int i;
Bart De Schuymer41830412002-06-05 19:41:28 +00001452 struct ether_addr *addr;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001453
1454 if (strcasecmp(from, "Unicast") == 0) {
1455 memcpy(to, mac_type_unicast, ETH_ALEN);
1456 memcpy(mask, msk_type_unicast, ETH_ALEN);
1457 return 0;
1458 }
1459 if (strcasecmp(from, "Multicast") == 0) {
1460 memcpy(to, mac_type_multicast, ETH_ALEN);
1461 memcpy(mask, msk_type_multicast, ETH_ALEN);
1462 return 0;
1463 }
1464 if (strcasecmp(from, "Broadcast") == 0) {
1465 memcpy(to, mac_type_broadcast, ETH_ALEN);
1466 memcpy(mask, msk_type_broadcast, ETH_ALEN);
1467 return 0;
1468 }
1469 if ( (p = strrchr(from, '/')) != NULL) {
1470 *p = '\0';
Bart De Schuymer41830412002-06-05 19:41:28 +00001471 if (!(addr = ether_aton(p + 1)))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001472 return -1;
Bart De Schuymer41830412002-06-05 19:41:28 +00001473 memcpy(mask, addr, ETH_ALEN);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001474 } else
1475 memset(mask, 0xff, ETH_ALEN);
Bart De Schuymer41830412002-06-05 19:41:28 +00001476 if (!(addr = ether_aton(from)))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001477 return -1;
Bart De Schuymer41830412002-06-05 19:41:28 +00001478 memcpy(to, addr, ETH_ALEN);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001479 for (i = 0; i < ETH_ALEN; i++)
1480 to[i] &= mask[i];
1481 return 0;
1482}
1483
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001484/*
1485 * executes the final_check() function for all extensions used by the rule
1486 */
Bart De Schuymer62423742002-07-14 19:06:20 +00001487static void do_final_checks(struct ebt_u_entry *e, struct ebt_u_entries *entries)
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +00001488{
1489 struct ebt_u_match_list *m_l;
1490 struct ebt_u_watcher_list *w_l;
1491 struct ebt_u_target *t;
1492 struct ebt_u_match *m;
1493 struct ebt_u_watcher *w;
1494
1495 m_l = e->m_list;
1496 w_l = e->w_list;
1497 while (m_l) {
1498 m = find_match(m_l->m->u.name);
1499 m->final_check(e, m_l->m, replace.name,
1500 entries->hook_mask, 1);
1501 m_l = m_l->next;
1502 }
1503 while (w_l) {
1504 w = find_watcher(w_l->w->u.name);
1505 w->final_check(e, w_l->w, replace.name,
1506 entries->hook_mask, 1);
1507 w_l = w_l->next;
1508 }
1509 t = find_target(e->t->u.name);
1510 t->final_check(e, e->t, replace.name,
1511 entries->hook_mask, 1);
1512}
1513
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001514/*
1515 * used for the -X command
1516 */
Bart De Schuymer62423742002-07-14 19:06:20 +00001517static void check_for_references(int chain_nr)
Bart De Schuymerb909f9b2002-06-26 18:35:31 +00001518{
1519 int i = -1, j;
1520 struct ebt_u_entries *entries;
1521 struct ebt_u_entry *e;
1522
1523 while (1) {
1524 i++;
1525 entries = nr_to_chain(i);
1526 if (!entries) {
1527 if (i < NF_BR_NUMHOOKS)
1528 continue;
1529 else
1530 break;
1531 }
1532 e = entries->entries;
1533 j = 0;
1534 while (e) {
Bart De Schuymerc27432e2003-01-09 22:01:07 +00001535 int chain_jmp;
1536
Bart De Schuymerb909f9b2002-06-26 18:35:31 +00001537 j++;
1538 if (strcmp(e->t->u.name, EBT_STANDARD_TARGET)) {
1539 e = e->next;
1540 continue;
1541 }
Bart De Schuymerc27432e2003-01-09 22:01:07 +00001542 chain_jmp = ((struct ebt_standard_target *)e->t)->verdict;
1543 if (chain_jmp == chain_nr)
Bart De Schuymerb909f9b2002-06-26 18:35:31 +00001544 print_error("Can't delete the chain, it's referenced "
1545 "in chain %s, rule %d", entries->name, j);
Bart De Schuymerc27432e2003-01-09 22:01:07 +00001546 /* adjust the chain jumps when necessary */
1547 if (chain_jmp > chain_nr)
1548 ((struct ebt_standard_target *)e->t)->verdict--;
Bart De Schuymerb909f9b2002-06-26 18:35:31 +00001549 e = e->next;
1550 }
1551 }
1552}
1553
Bart De Schuymercc440052002-11-06 21:10:33 +00001554static int parse_delete_rule(const char *argv, int *rule_nr, int *rule_nr_end)
1555{
1556 char *colon = strchr(argv, ':'), *buffer;
1557
1558 if (colon) {
1559 *colon = '\0';
1560 if (*(colon + 1) == '\0')
Bart De Schuymerc3b97f52003-04-17 17:03:49 +00001561 *rule_nr_end = -1; /* until the last rule */
Bart De Schuymercc440052002-11-06 21:10:33 +00001562 else {
1563 *rule_nr_end = strtol(colon + 1, &buffer, 10);
Bart De Schuymerc3b97f52003-04-17 17:03:49 +00001564 if (*buffer != '\0' || *rule_nr_end == 0)
Bart De Schuymercc440052002-11-06 21:10:33 +00001565 return -1;
1566 }
1567 }
1568 if (colon == argv)
Bart De Schuymerc3b97f52003-04-17 17:03:49 +00001569 *rule_nr = 1; /* beginning with the first rule */
Bart De Schuymercc440052002-11-06 21:10:33 +00001570 else {
1571 *rule_nr = strtol(argv, &buffer, 10);
Bart De Schuymerc3b97f52003-04-17 17:03:49 +00001572 if (*buffer != '\0' || *rule_nr == 0)
Bart De Schuymercc440052002-11-06 21:10:33 +00001573 return -1;
1574 }
1575 if (!colon)
1576 *rule_nr_end = *rule_nr;
Bart De Schuymercc440052002-11-06 21:10:33 +00001577 return 0;
1578}
1579
Bart De Schuymera615b962002-11-03 14:54:09 +00001580static int invert = 0;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001581int check_inverse(const char option[])
1582{
1583 if (strcmp(option, "!") == 0) {
Bart De Schuymera615b962002-11-03 14:54:09 +00001584 if (invert == 1)
1585 print_error("double use of '!' not allowed");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001586 optind++;
Bart De Schuymera615b962002-11-03 14:54:09 +00001587 invert = 1;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001588 return 1;
1589 }
Bart De Schuymera615b962002-11-03 14:54:09 +00001590 return invert;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001591}
1592
1593void check_option(unsigned int *flags, unsigned int mask)
1594{
1595 if (*flags & mask)
1596 print_error("Multiple use of same option not allowed");
1597 *flags |= mask;
1598}
1599
Bart De Schuymer0cb01792003-05-04 16:52:04 +00001600static void get_kernel_table()
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001601{
1602 if ( !(table = find_table(replace.name)) )
1603 print_error("Bad table name");
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001604 /*
1605 * get the kernel's information
1606 */
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001607 if (get_table(&replace)) {
Bart De Schuymer0cb01792003-05-04 16:52:04 +00001608 ebtables_insmod("ebtables");
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001609 if (get_table(&replace))
1610 print_error("The kernel doesn't support the ebtables "
1611 "%s table", replace.name);
1612 }
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001613 /*
Bart De Schuymer5885b362002-12-03 20:51:36 +00001614 * when listing a table contained in a file, we don't demand that
1615 * the user knows the table's name
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001616 */
Bart De Schuymer62a7fdb2002-08-24 21:01:21 +00001617 if ( !(table = find_table(replace.name)) )
1618 print_error("Bad table name");
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001619}
1620
Bart De Schuymerc5075142002-08-18 14:21:19 +00001621#define print_if_l_error print_error("Interface name length must be less " \
1622 "than %d", IFNAMSIZ)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001623#define OPT_COMMAND 0x01
1624#define OPT_TABLE 0x02
1625#define OPT_IN 0x04
1626#define OPT_OUT 0x08
1627#define OPT_JUMP 0x10
1628#define OPT_PROTOCOL 0x20
1629#define OPT_SOURCE 0x40
1630#define OPT_DEST 0x80
1631#define OPT_ZERO 0x100
1632#define OPT_LOGICALIN 0x200
1633#define OPT_LOGICALOUT 0x400
Bart De Schuymer5885b362002-12-03 20:51:36 +00001634/* the main thing */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001635int main(int argc, char *argv[])
1636{
Bart De Schuymer923a5732002-08-11 12:01:33 +00001637 char *buffer;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001638 int c, i;
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001639 /*
1640 * this special one for the -Z option (we can have -Z <this> -L <that>)
1641 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001642 int zerochain = -1;
Bart De Schuymerf8f8f292002-06-25 15:43:57 +00001643 int policy = 0;
Bart De Schuymerc3b97f52003-04-17 17:03:49 +00001644 int rule_nr = 0; /* used for -[D,I] */
1645 int rule_nr_end = 0; /* used for -I */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001646 struct ebt_u_target *t;
1647 struct ebt_u_match *m;
1648 struct ebt_u_watcher *w;
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001649 struct ebt_u_match_list *m_l;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001650 struct ebt_u_watcher_list *w_l;
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001651 struct ebt_u_entries *entries;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001652
Bart De Schuymera615b962002-11-03 14:54:09 +00001653 opterr = 0;
1654
Bart De Schuymer5885b362002-12-03 20:51:36 +00001655 replace.filename = getenv(ATOMIC_ENV_VARIABLE);
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001656 /*
1657 * initialize the table name, OPT_ flags, selected hook and command
1658 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001659 strcpy(replace.name, "filter");
1660 replace.flags = 0;
1661 replace.selected_hook = -1;
1662 replace.command = 'h';
Bart De Schuymered053432002-07-21 19:35:39 +00001663 replace.counterchanges = NULL;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001664
1665 new_entry = (struct ebt_u_entry *)malloc(sizeof(struct ebt_u_entry));
1666 if (!new_entry)
1667 print_memory();
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001668 /*
1669 * put some sane values in our new entry
1670 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001671 initialize_entry(new_entry);
1672
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001673 /*
1674 * The scenario induced by this loop makes that:
1675 * '-t' ,'-M' and --atomic (if specified) have to come
1676 * before '-A' and the like
1677 */
Bart De Schuymer60332e02002-06-23 08:01:47 +00001678
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001679 /*
1680 * getopt saves the day
1681 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001682 while ((c = getopt_long(argc, argv,
Bart De Schuymeraac31142002-08-11 11:57:52 +00001683 "-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 +00001684 switch (c) {
1685
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001686 case 'A': /* add a rule */
1687 case 'D': /* delete a rule */
1688 case 'P': /* define policy */
1689 case 'I': /* insert a rule */
1690 case 'N': /* make a user defined chain */
1691 case 'E': /* rename chain */
1692 case 'X': /* delete chain */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001693 replace.command = c;
1694 if (replace.flags & OPT_COMMAND)
1695 print_error("Multiple commands not allowed");
1696 replace.flags |= OPT_COMMAND;
Bart De Schuymer0cb01792003-05-04 16:52:04 +00001697 get_kernel_table();
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001698 if (optarg[0] == '-' || !strcmp(optarg, "!"))
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001699 print_error("No chain name specified");
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001700 if (c == 'N') {
1701 struct ebt_u_chain_list *cl, **cl2;
1702
1703 if (get_hooknr(optarg) != -1)
1704 print_error("Chain %s already exists",
1705 optarg);
1706 if (find_target(optarg))
1707 print_error("Target with name %s exists"
1708 , optarg);
1709 if (strlen(optarg) >= EBT_CHAIN_MAXNAMELEN)
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001710 print_error("Chain name length can't exceed %d",
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001711 EBT_CHAIN_MAXNAMELEN - 1);
1712 cl = (struct ebt_u_chain_list *)
1713 malloc(sizeof(struct ebt_u_chain_list));
1714 if (!cl)
1715 print_memory();
1716 cl->next = NULL;
1717 cl->udc = (struct ebt_u_entries *)
1718 malloc(sizeof(struct ebt_u_entries));
1719 if (!cl->udc)
1720 print_memory();
1721 cl->udc->nentries = 0;
1722 cl->udc->policy = EBT_ACCEPT;
1723 cl->udc->counter_offset = replace.nentries;
1724 cl->udc->hook_mask = 0;
1725 strcpy(cl->udc->name, optarg);
1726 cl->udc->entries = NULL;
1727 cl->kernel_start = NULL;
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001728 /*
1729 * put the new chain at the end
1730 */
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001731 cl2 = &replace.udc;
1732 while (*cl2)
1733 cl2 = &((*cl2)->next);
1734 *cl2 = cl;
Bart De Schuymerb6c94f92003-06-14 13:08:03 +00001735 counters_nochange();
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001736 break;
1737 }
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001738 if ((replace.selected_hook = get_hooknr(optarg)) == -1)
1739 print_error("Chain %s doesn't exist", optarg);
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001740 if (c == 'E') {
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001741 if (optind >= argc || argv[optind][0] == '-' ||
1742 !strcmp(argv[optind], "!"))
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001743 print_error("No new chain name specified");
1744 if (strlen(argv[optind]) >= EBT_CHAIN_MAXNAMELEN)
1745 print_error("Chain name len can't exceed %d",
1746 EBT_CHAIN_MAXNAMELEN - 1);
1747 if (get_hooknr(argv[optind]) != -1)
1748 print_error("Chain %s already exists",
1749 argv[optind]);
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001750 if (find_target(argv[optind]))
1751 print_error("Target with name %s exists"
1752 , argv[optind]);
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001753 entries = to_chain();
1754 strcpy(entries->name, argv[optind]);
Bart De Schuymerb6c94f92003-06-14 13:08:03 +00001755 counters_nochange();
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001756 optind++;
1757 break;
1758 }
1759 if (c == 'X') {
1760 struct ebt_u_chain_list *cl, **cl2;
1761
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001762 if (replace.selected_hook < NF_BR_NUMHOOKS)
1763 print_error("You can't remove a standard chain");
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001764 /*
Bart De Schuymerc27432e2003-01-09 22:01:07 +00001765 * if the chain is referenced, don't delete it,
1766 * also decrement jumps to a chain behind the
1767 * one we're deleting
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001768 */
Bart De Schuymerb909f9b2002-06-26 18:35:31 +00001769 check_for_references(replace.selected_hook - NF_BR_NUMHOOKS);
Bart De Schuymerb6c94f92003-06-14 13:08:03 +00001770 if (flush_chains() == -1)
1771 counters_nochange();
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001772 entries = to_chain();
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001773 cl2 = &(replace.udc);
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001774 while ((*cl2)->udc != entries)
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001775 cl2 = &((*cl2)->next);
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001776 cl = (*cl2);
1777 (*cl2) = (*cl2)->next;
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001778 free(cl->udc);
1779 free(cl);
1780 break;
1781 }
1782
Bart De Schuymercc440052002-11-06 21:10:33 +00001783 if (c == 'D' && optind < argc &&
Bart De Schuymerc3b97f52003-04-17 17:03:49 +00001784 (argv[optind][0] != '-' ||
1785 (argv[optind][1] >= '0' && argv[optind][1] <= '9'))) {
Bart De Schuymercc440052002-11-06 21:10:33 +00001786 if (parse_delete_rule(argv[optind],
1787 &rule_nr, &rule_nr_end))
1788 print_error("Problem with the "
1789 "specified rule number(s)");
1790 optind++;
1791 }
1792 if (c == 'I') {
Bart De Schuymerc3b97f52003-04-17 17:03:49 +00001793 if (optind >= argc || (argv[optind][0] == '-' &&
1794 (argv[optind][1] < '0' || argv[optind][1] > '9')))
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001795 print_error("No rulenr for -I"
1796 " specified");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001797 rule_nr = strtol(argv[optind], &buffer, 10);
Bart De Schuymerc3b97f52003-04-17 17:03:49 +00001798 if (*buffer != '\0')
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001799 print_error("Problem with the "
1800 "specified rule number");
1801 optind++;
1802 }
1803 if (c == 'P') {
1804 if (optind >= argc)
1805 print_error("No policy specified");
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001806 policy = 0;
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001807 for (i = 0; i < NUM_STANDARD_TARGETS; i++)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001808 if (!strcmp(argv[optind],
1809 standard_targets[i])) {
Bart De Schuymer60332e02002-06-23 08:01:47 +00001810 policy = -i -1;
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001811 if (policy == EBT_CONTINUE)
1812 policy = 0;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001813 break;
1814 }
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001815 if (policy == 0)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001816 print_error("Wrong policy");
1817 optind++;
1818 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001819 break;
1820
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001821 case 'L': /* list */
1822 case 'F': /* flush */
1823 case 'Z': /* zero counters */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001824 if (c == 'Z') {
1825 if (replace.flags & OPT_ZERO)
1826 print_error("Multiple commands"
1827 " not allowed");
1828 if ( (replace.flags & OPT_COMMAND &&
1829 replace.command != 'L'))
1830 print_error("command -Z only allowed "
1831 "together with command -L");
1832 replace.flags |= OPT_ZERO;
1833 } else {
1834 replace.command = c;
1835 if (replace.flags & OPT_COMMAND)
1836 print_error("Multiple commands"
1837 " not allowed");
1838 replace.flags |= OPT_COMMAND;
1839 }
Bart De Schuymer0cb01792003-05-04 16:52:04 +00001840 get_kernel_table();
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001841 i = -1;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001842 if (optarg) {
1843 if ( (i = get_hooknr(optarg)) == -1 )
1844 print_error("Bad chain");
1845 } else
1846 if (optind < argc && argv[optind][0] != '-') {
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001847 if ((i = get_hooknr(argv[optind])) == -1)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001848 print_error("Bad chain");
1849 optind++;
1850 }
1851 if (i != -1) {
1852 if (c == 'Z')
1853 zerochain = i;
1854 else
1855 replace.selected_hook = i;
1856 }
1857 break;
1858
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001859 case 'V': /* version */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001860 replace.command = 'V';
1861 if (replace.flags & OPT_COMMAND)
1862 print_error("Multiple commands not allowed");
Bart De Schuymer57a3f6a2003-04-01 16:59:33 +00001863 PRINT_VERSION;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001864 exit(0);
1865
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001866 case 'M': /* modprobe */
Bart De Schuymer60332e02002-06-23 08:01:47 +00001867 if (replace.command != 'h')
1868 print_error("Please put the -M option earlier");
Bart De Schuymerc8531032002-06-14 21:55:29 +00001869 modprobe = optarg;
1870 break;
1871
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001872 case 'h': /* help */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001873 if (replace.flags & OPT_COMMAND)
1874 print_error("Multiple commands not allowed");
1875 replace.command = 'h';
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001876 /*
1877 * All other arguments should be extension names
1878 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001879 while (optind < argc) {
1880 struct ebt_u_match *m;
1881 struct ebt_u_watcher *w;
1882
Bart De Schuymer9a0fbf22003-01-11 16:16:54 +00001883 if (!strcasecmp("list_extensions",
1884 argv[optind]))
1885 list_extensions();
1886
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001887 if ((m = find_match(argv[optind])))
1888 add_match(m);
1889 else if ((w = find_watcher(argv[optind])))
1890 add_watcher(w);
1891 else {
1892 if (!(t = find_target(argv[optind])))
1893 print_error("Extension %s "
1894 "not found", argv[optind]);
1895 if (replace.flags & OPT_JUMP)
1896 print_error("Sorry, you can "
1897 "only see help for one "
1898 "target extension each time");
1899 replace.flags |= OPT_JUMP;
1900 new_entry->t =
1901 (struct ebt_entry_target *)t;
1902 }
1903 optind++;
1904 }
1905 break;
1906
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001907 case 't': /* table */
Bart De Schuymer60332e02002-06-23 08:01:47 +00001908 if (replace.command != 'h')
1909 print_error("Please put the -t option first");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001910 check_option(&replace.flags, OPT_TABLE);
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001911 if (strlen(optarg) > EBT_TABLE_MAXNAMELEN - 1)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001912 print_error("Table name too long");
1913 strcpy(replace.name, optarg);
1914 break;
1915
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001916 case 'i': /* input interface */
1917 case 2 : /* logical input interface */
1918 case 'o': /* output interface */
1919 case 3 : /* logical output interface */
1920 case 'j': /* target */
1921 case 'p': /* net family protocol */
1922 case 's': /* source mac */
1923 case 'd': /* destination mac */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001924 if ((replace.flags & OPT_COMMAND) == 0)
1925 print_error("No command specified");
1926 if ( replace.command != 'A' &&
1927 replace.command != 'D' && replace.command != 'I')
1928 print_error("Command and option do not match");
1929 if (c == 'i') {
1930 check_option(&replace.flags, OPT_IN);
1931 if (replace.selected_hook > 2 &&
1932 replace.selected_hook < NF_BR_BROUTING)
1933 print_error("Use in-interface only in "
1934 "INPUT, FORWARD, PREROUTING and"
1935 "BROUTING chains");
1936 if (check_inverse(optarg))
1937 new_entry->invflags |= EBT_IIN;
1938
1939 if (optind > argc)
1940 print_error("No in-interface "
1941 "specified");
1942 if (strlen(argv[optind - 1]) >= IFNAMSIZ)
Bart De Schuymerc5075142002-08-18 14:21:19 +00001943 print_if_l_error;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001944 strcpy(new_entry->in, argv[optind - 1]);
1945 break;
1946 }
1947 if (c == 2) {
1948 check_option(&replace.flags, OPT_LOGICALIN);
1949 if (replace.selected_hook > 2 &&
1950 replace.selected_hook < NF_BR_BROUTING)
1951 print_error("Use logical in-interface "
1952 "only in INPUT, FORWARD, "
1953 "PREROUTING and BROUTING chains");
1954 if (check_inverse(optarg))
1955 new_entry->invflags |= EBT_ILOGICALIN;
1956
1957 if (optind > argc)
1958 print_error("No logical in-interface "
1959 "specified");
1960 if (strlen(argv[optind - 1]) >= IFNAMSIZ)
Bart De Schuymerc5075142002-08-18 14:21:19 +00001961 print_if_l_error;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001962 strcpy(new_entry->logical_in, argv[optind - 1]);
1963 break;
1964 }
1965 if (c == 'o') {
1966 check_option(&replace.flags, OPT_OUT);
1967 if (replace.selected_hook < 2)
1968 print_error("Use out-interface only"
1969 " in OUTPUT, FORWARD and "
1970 "POSTROUTING chains");
1971 if (check_inverse(optarg))
1972 new_entry->invflags |= EBT_IOUT;
1973
1974 if (optind > argc)
1975 print_error("No out-interface "
1976 "specified");
1977
1978 if (strlen(argv[optind - 1]) >= IFNAMSIZ)
Bart De Schuymerc5075142002-08-18 14:21:19 +00001979 print_if_l_error;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001980 strcpy(new_entry->out, argv[optind - 1]);
1981 break;
1982 }
1983 if (c == 3) {
1984 check_option(&replace.flags, OPT_LOGICALOUT);
1985 if (replace.selected_hook < 2)
1986 print_error("Use logical out-interface "
1987 "only in OUTPUT, FORWARD and "
1988 "POSTROUTING chains");
1989 if (check_inverse(optarg))
1990 new_entry->invflags |= EBT_ILOGICALOUT;
1991
1992 if (optind > argc)
1993 print_error("No logical out-interface "
1994 "specified");
1995
1996 if (strlen(argv[optind - 1]) >= IFNAMSIZ)
Bart De Schuymerc5075142002-08-18 14:21:19 +00001997 print_if_l_error;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001998 strcpy(new_entry->logical_out,
1999 argv[optind - 1]);
2000 break;
2001 }
2002 if (c == 'j') {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002003 check_option(&replace.flags, OPT_JUMP);
2004 for (i = 0; i < NUM_STANDARD_TARGETS; i++)
2005 if (!strcmp(optarg,
2006 standard_targets[i])) {
2007 t = find_target(
2008 EBT_STANDARD_TARGET);
2009 ((struct ebt_standard_target *)
Bart De Schuymer60332e02002-06-23 08:01:47 +00002010 t->t)->verdict = -i - 1;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002011 break;
2012 }
Bart De Schuymer60332e02002-06-23 08:01:47 +00002013 if (-i - 1 == EBT_RETURN) {
2014 if (replace.selected_hook < NF_BR_NUMHOOKS)
2015 print_error("Return target"
2016 " only for user defined chains");
2017 }
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +00002018 if (i != NUM_STANDARD_TARGETS)
2019 break;
Bart De Schuymer1ab41562002-06-23 17:09:54 +00002020 if ((i = get_hooknr(optarg)) != -1) {
2021 if (i < NF_BR_NUMHOOKS)
2022 print_error("don't jump"
2023 " to a standard chain");
2024 t = find_target(
2025 EBT_STANDARD_TARGET);
2026 ((struct ebt_standard_target *)
2027 t->t)->verdict = i - NF_BR_NUMHOOKS;
2028 break;
2029 }
2030 else {
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002031 /*
2032 * must be an extension then
2033 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002034 struct ebt_u_target *t;
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00002035
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002036 t = find_target(optarg);
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002037 /*
2038 * -j standard not allowed either
2039 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002040 if (!t || t ==
2041 (struct ebt_u_target *)new_entry->t)
2042 print_error("Illegal target "
2043 "name");
2044 new_entry->t =
2045 (struct ebt_entry_target *)t;
2046 }
2047 break;
2048 }
2049 if (c == 's') {
2050 check_option(&replace.flags, OPT_SOURCE);
2051 if (check_inverse(optarg))
2052 new_entry->invflags |= EBT_ISOURCE;
2053
2054 if (optind > argc)
2055 print_error("No source mac "
2056 "specified");
2057 if (getmac_and_mask(argv[optind - 1],
2058 new_entry->sourcemac, new_entry->sourcemsk))
2059 print_error("Problem with specified "
2060 "source mac");
2061 new_entry->bitmask |= EBT_SOURCEMAC;
2062 break;
2063 }
2064 if (c == 'd') {
2065 check_option(&replace.flags, OPT_DEST);
2066 if (check_inverse(optarg))
2067 new_entry->invflags |= EBT_IDEST;
2068
2069 if (optind > argc)
2070 print_error("No destination mac "
2071 "specified");
2072 if (getmac_and_mask(argv[optind - 1],
2073 new_entry->destmac, new_entry->destmsk))
2074 print_error("Problem with specified "
2075 "destination mac");
2076 new_entry->bitmask |= EBT_DESTMAC;
2077 break;
2078 }
2079 check_option(&replace.flags, OPT_PROTOCOL);
2080 if (check_inverse(optarg))
2081 new_entry->invflags |= EBT_IPROTO;
2082
2083 if (optind > argc)
2084 print_error("No protocol specified");
2085 new_entry->bitmask &= ~((unsigned int)EBT_NOPROTO);
2086 i = strtol(argv[optind - 1], &buffer, 16);
2087 if (*buffer == '\0' && (i < 0 || i > 0xFFFF))
2088 print_error("Problem with the specified "
2089 "protocol");
2090 new_entry->ethproto = i;
Bart De Schuymer28bf6f62002-06-26 18:57:24 +00002091 if (*buffer != '\0') {
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002092 struct ethertypeent *ent;
2093
2094 if (!strcasecmp(argv[optind - 1], "LENGTH")) {
2095 new_entry->bitmask |= EBT_802_3;
2096 break;
2097 }
2098 ent = getethertypebyname(argv[optind - 1]);
2099 if (!ent)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002100 print_error("Problem with the specified"
2101 " protocol");
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002102 new_entry->ethproto = ent->e_ethertype;
Bart De Schuymer28bf6f62002-06-26 18:57:24 +00002103 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002104 if (new_entry->ethproto < 1536 &&
2105 !(new_entry->bitmask & EBT_802_3))
2106 print_error("Sorry, protocols have values above"
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00002107 " or equal to 0x0600");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002108 break;
2109
Bart De Schuymer9895a8e2003-01-11 10:14:24 +00002110 case 4 : /* Lc */
Bart De Schuymer9af14f92002-07-10 20:49:10 +00002111 check_option(&replace.flags, LIST_C);
Bart De Schuymer9af14f92002-07-10 20:49:10 +00002112 if (replace.command != 'L')
2113 print_error("Use --Lc with -L");
2114 if (replace.flags & LIST_X)
2115 print_error("--Lx not compatible with --Lc");
2116 replace.flags |= LIST_C;
2117 break;
Bart De Schuymer9895a8e2003-01-11 10:14:24 +00002118 case 5 : /* Ln */
Bart De Schuymer9af14f92002-07-10 20:49:10 +00002119 check_option(&replace.flags, LIST_N);
Bart De Schuymer9af14f92002-07-10 20:49:10 +00002120 if (replace.command != 'L')
2121 print_error("Use --Ln with -L");
2122 if (replace.flags & LIST_X)
2123 print_error("--Lx not compatible with --Ln");
2124 replace.flags |= LIST_N;
2125 break;
Bart De Schuymer9895a8e2003-01-11 10:14:24 +00002126 case 6 : /* Lx */
Bart De Schuymer9af14f92002-07-10 20:49:10 +00002127 check_option(&replace.flags, LIST_X);
Bart De Schuymer9af14f92002-07-10 20:49:10 +00002128 if (replace.command != 'L')
2129 print_error("Use --Lx with -L");
2130 if (replace.flags & LIST_C)
2131 print_error("--Lx not compatible with --Lc");
2132 if (replace.flags & LIST_N)
2133 print_error("--Lx not compatible with --Ln");
2134 replace.flags |= LIST_X;
2135 break;
Bart De Schuymer22d03a22003-05-03 20:28:22 +00002136 case 12 : /* Lmac2 */
2137 check_option(&replace.flags, LIST_MAC2);
2138 if (replace.command != 'L')
2139 print_error("Use --Lmac2 with -L");
2140 replace.flags |= LIST_MAC2;
2141 break;
Bart De Schuymer9895a8e2003-01-11 10:14:24 +00002142 case 8 : /* atomic-commit */
Bart De Schuymer62423742002-07-14 19:06:20 +00002143 replace.command = c;
2144 if (replace.flags & OPT_COMMAND)
2145 print_error("Multiple commands not allowed");
2146 replace.flags |= OPT_COMMAND;
Bart De Schuymer5885b362002-12-03 20:51:36 +00002147 if (!replace.filename)
2148 print_error("No atomic file specified");
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002149 /*
2150 * get the information from the file
2151 */
Bart De Schuymer62423742002-07-14 19:06:20 +00002152 get_table(&replace);
Bart De Schuymer868bf642002-07-16 18:14:20 +00002153 if (replace.nentries) {
Bart De Schuymered053432002-07-21 19:35:39 +00002154 replace.counterchanges = (unsigned short *)
Bart De Schuymer868bf642002-07-16 18:14:20 +00002155 malloc(sizeof(unsigned short) * (replace.nentries + 1));
2156 for (i = 0; i < replace.nentries; i++)
Bart De Schuymered053432002-07-21 19:35:39 +00002157 replace.counterchanges[i] = CNT_NORM;
2158 replace.counterchanges[i] = CNT_END;
Bart De Schuymer868bf642002-07-16 18:14:20 +00002159 }
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002160 /*
2161 * we don't want the kernel giving us its counters, they would
2162 * overwrite the counters extracted from the file
2163 */
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00002164 replace.num_counters = 0;
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002165 /*
2166 * make sure the table will be written to the kernel
Bart De Schuymer5885b362002-12-03 20:51:36 +00002167 * possible memory leak here
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002168 */
Bart De Schuymer62423742002-07-14 19:06:20 +00002169 replace.filename = NULL;
2170 break;
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002171 case 7 : /* atomic-init */
2172 case 10: /* atomic-save */
2173 case 11: /* init-table */
Bart De Schuymer62423742002-07-14 19:06:20 +00002174 replace.command = c;
2175 if (replace.flags & OPT_COMMAND)
2176 print_error("Multiple commands not allowed");
Bart De Schuymer5885b362002-12-03 20:51:36 +00002177 if (c != 11 && !replace.filename)
2178 print_error("No atomic file specified");
Bart De Schuymer62423742002-07-14 19:06:20 +00002179 replace.flags |= OPT_COMMAND;
Bart De Schuymer5885b362002-12-03 20:51:36 +00002180 {
2181 char *tmp = replace.filename;
2182
2183 tmp = replace.filename;
2184 /* get the kernel table */
2185 replace.filename = NULL;
Bart De Schuymer0cb01792003-05-04 16:52:04 +00002186 get_kernel_table();
Bart De Schuymer5885b362002-12-03 20:51:36 +00002187 replace.filename = tmp;
2188 }
Bart De Schuymera8d920b2002-07-16 18:30:44 +00002189 if (replace.nentries) {
Bart De Schuymered053432002-07-21 19:35:39 +00002190 replace.counterchanges = (unsigned short *)
Bart De Schuymer5f16dc72002-07-16 18:08:36 +00002191 malloc(sizeof(unsigned short) * (replace.nentries + 1));
2192 for (i = 0; i < replace.nentries; i++)
Bart De Schuymered053432002-07-21 19:35:39 +00002193 replace.counterchanges[i] = CNT_NORM;
2194 replace.counterchanges[i] = CNT_END;
Bart De Schuymer5f16dc72002-07-16 18:08:36 +00002195 }
Bart De Schuymer5885b362002-12-03 20:51:36 +00002196 break;
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002197 case 9 : /* atomic */
Bart De Schuymer5885b362002-12-03 20:51:36 +00002198 if (replace.flags & OPT_COMMAND)
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00002199 print_error("--atomic has to come before"
2200 " the command");
Bart De Schuymer5885b362002-12-03 20:51:36 +00002201 /* another possible memory leak here */
Bart De Schuymer62423742002-07-14 19:06:20 +00002202 replace.filename = (char *)malloc(strlen(optarg) + 1);
2203 strcpy(replace.filename, optarg);
2204 break;
Bart De Schuymera615b962002-11-03 14:54:09 +00002205 case 1 :
2206 if (!strcmp(optarg, "!"))
2207 check_inverse(optarg);
2208 else
2209 print_error("Bad argument : %s", optarg);
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002210 /*
2211 * check_inverse() did optind++
2212 */
Bart De Schuymera615b962002-11-03 14:54:09 +00002213 optind--;
2214 continue;
Bart De Schuymer9af14f92002-07-10 20:49:10 +00002215 default:
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002216 /*
2217 * is it a target option?
2218 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002219 t = (struct ebt_u_target *)new_entry->t;
2220 if ((t->parse(c - t->option_offset, argv, argc,
2221 new_entry, &t->flags, &t->t)))
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00002222 goto check_extension;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002223
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002224 /*
2225 * is it a match_option?
2226 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002227 for (m = matches; m; m = m->next)
2228 if (m->parse(c - m->option_offset, argv,
2229 argc, new_entry, &m->flags, &m->m))
2230 break;
2231
2232 if (m != NULL) {
2233 if (m->used == 0)
2234 add_match(m);
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00002235 goto check_extension;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002236 }
2237
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002238 /*
2239 * is it a watcher option?
2240 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002241 for (w = watchers; w; w = w->next)
2242 if (w->parse(c-w->option_offset, argv,
2243 argc, new_entry, &w->flags, &w->w))
2244 break;
2245
2246 if (w == NULL)
2247 print_error("Unknown argument");
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00002248 if (w->used == 0)
2249 add_watcher(w);
2250check_extension:
Bart De Schuymer60332e02002-06-23 08:01:47 +00002251 if (replace.command != 'A' && replace.command != 'I' &&
2252 replace.command != 'D')
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00002253 print_error("Extensions only for -A, -I and -D");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002254 }
Bart De Schuymera615b962002-11-03 14:54:09 +00002255 invert = 0;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002256 }
2257
Bart De Schuymer25c741d2002-06-23 18:54:34 +00002258 if ( !table && !(table = find_table(replace.name)) )
2259 print_error("Bad table name");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002260
2261 if ( (replace.flags & OPT_COMMAND) && replace.command != 'L' &&
2262 replace.flags & OPT_ZERO )
2263 print_error("Command -Z only allowed together with command -L");
2264
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002265 /*
2266 * do this after parsing everything, so we can print specific info
2267 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002268 if (replace.command == 'h' && !(replace.flags & OPT_ZERO))
2269 print_help();
2270
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002271 /*
2272 * do the final checks
2273 */
Bart De Schuymer60332e02002-06-23 08:01:47 +00002274 if (replace.command == 'A' || replace.command == 'I' ||
2275 replace.command == 'D') {
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002276 /*
2277 * this will put the hook_mask right for the chains
2278 */
Bart De Schuymer60332e02002-06-23 08:01:47 +00002279 check_for_loops();
2280 entries = to_chain();
2281 m_l = new_entry->m_list;
2282 w_l = new_entry->w_list;
2283 t = (struct ebt_u_target *)new_entry->t;
2284 while (m_l) {
2285 m = (struct ebt_u_match *)(m_l->m);
2286 m->final_check(new_entry, m->m, replace.name,
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +00002287 entries->hook_mask, 0);
Bart De Schuymer60332e02002-06-23 08:01:47 +00002288 m_l = m_l->next;
2289 }
2290 while (w_l) {
2291 w = (struct ebt_u_watcher *)(w_l->w);
2292 w->final_check(new_entry, w->w, replace.name,
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +00002293 entries->hook_mask, 0);
Bart De Schuymer60332e02002-06-23 08:01:47 +00002294 w_l = w_l->next;
2295 }
2296 t->final_check(new_entry, t->t, replace.name,
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +00002297 entries->hook_mask, 0);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002298 }
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002299 /*
2300 * so, the extensions can work with the host endian
2301 * the kernel does not have to do this ofcourse
2302 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002303 new_entry->ethproto = htons(new_entry->ethproto);
2304
Bart De Schuymerc34f4672002-08-18 18:03:52 +00002305 if (replace.command == 'P') {
2306 if (replace.selected_hook < NF_BR_NUMHOOKS &&
2307 policy == EBT_RETURN)
2308 print_error("Policy RETURN only allowed for user "
2309 "defined chains");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002310 change_policy(policy);
Bart De Schuymerc34f4672002-08-18 18:03:52 +00002311 } else if (replace.command == 'L') {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002312 list_rules();
2313 if (replace.flags & OPT_ZERO)
2314 zero_counters(zerochain);
2315 else
2316 exit(0);
2317 }
2318 if (replace.flags & OPT_ZERO)
2319 zero_counters(zerochain);
Bart De Schuymer1ab41562002-06-23 17:09:54 +00002320 else if (replace.command == 'F') {
2321 if (flush_chains() == -1)
2322 exit(0);
2323 } else if (replace.command == 'A' || replace.command == 'I') {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002324 add_rule(rule_nr);
Bart De Schuymer1ab41562002-06-23 17:09:54 +00002325 check_for_loops();
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002326 /*
2327 * do the final_check(), for all entries
2328 * needed when adding a rule that has a chain target
2329 */
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +00002330 i = -1;
2331 while (1) {
2332 struct ebt_u_entry *e;
2333
2334 i++;
2335 entries = nr_to_chain(i);
2336 if (!entries) {
2337 if (i < NF_BR_NUMHOOKS)
2338 continue;
2339 else
2340 break;
2341 }
2342 e = entries->entries;
2343 while (e) {
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002344 /*
2345 * userspace extensions use host endian
2346 */
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +00002347 e->ethproto = ntohs(e->ethproto);
2348 do_final_checks(e, entries);
2349 e->ethproto = htons(e->ethproto);
2350 e = e->next;
2351 }
2352 }
Bart De Schuymerc3b97f52003-04-17 17:03:49 +00002353 } else if (replace.command == 'D')
Bart De Schuymercc440052002-11-06 21:10:33 +00002354 delete_rule(rule_nr, rule_nr_end);
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002355 /*
2356 * commands -N, -E, -X, --atomic-commit, --atomic-commit, --atomic-save,
2357 * --init-table fall through
2358 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002359
2360 if (table->check)
2361 table->check(&replace);
2362
2363 deliver_table(&replace);
2364
Bart De Schuymered053432002-07-21 19:35:39 +00002365 if (replace.counterchanges)
2366 deliver_counters(&replace);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002367 return 0;
2368}