blob: 27f2ff9c18289952d8747d146d9eced1a9c6557d [file] [log] [blame]
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001/*
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00002 * ebtables.c, v2.0 July 2002
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00003 *
4 * Author: Bart De Schuymer
5 *
6 * This code is stongly inspired on the iptables code which is
7 * Copyright (C) 1999 Paul `Rusty' Russell & Michael J. Neuling
8 *
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License as
11 * published by the Free Software Foundation; either version 2 of the
12 * License, or (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 */
23
24#include <getopt.h>
25#include <string.h>
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000026#include <stdio.h>
27#include <stdlib.h>
Bart De Schuymerd4586482002-08-11 16:15:55 +000028#include <stdarg.h>
Bart De Schuymer41830412002-06-05 19:41:28 +000029#include <netinet/ether.h>
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000030#include "include/ebtables_u.h"
Bart De Schuymerc7bfa272002-11-20 19:40:13 +000031#include "include/ethernetdb.h"
Bart De Schuymerc8531032002-06-14 21:55:29 +000032#include <unistd.h>
33#include <fcntl.h>
34#include <sys/wait.h>
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000035
Bart De Schuymerc7bfa272002-11-20 19:40:13 +000036/*
37 * Don't use this function, use print_bug()
38 */
Bart De Schuymerd4586482002-08-11 16:15:55 +000039void __print_bug(char *file, int line, char *format, ...)
40{
41 va_list l;
42
43 va_start(l, format);
44 printf(PROGNAME" v"PROGVERSION":%s:%d:--BUG--: \n", file, line);
45 vprintf(format, l);
46 printf("\n");
47 va_end(l);
48 exit (-1);
49}
50
Bart De Schuymerc8531032002-06-14 21:55:29 +000051#ifndef PROC_SYS_MODPROBE
52#define PROC_SYS_MODPROBE "/proc/sys/kernel/modprobe"
53#endif
Bart De Schuymer5885b362002-12-03 20:51:36 +000054#define ATOMIC_ENV_VARIABLE "EBTABLES_ATOMIC_FILE"
Bart De Schuymer57a3f6a2003-04-01 16:59:33 +000055#define PRINT_VERSION printf(PROGNAME" v"PROGVERSION" ("PROGDATE")\n")
56
Bart De Schuymerc8531032002-06-14 21:55:29 +000057
Bart De Schuymer60332e02002-06-23 08:01:47 +000058char *hooknames[NF_BR_NUMHOOKS] =
59{
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000060 [NF_BR_PRE_ROUTING]"PREROUTING",
61 [NF_BR_LOCAL_IN]"INPUT",
62 [NF_BR_FORWARD]"FORWARD",
63 [NF_BR_LOCAL_OUT]"OUTPUT",
64 [NF_BR_POST_ROUTING]"POSTROUTING",
65 [NF_BR_BROUTING]"BROUTING"
66};
67
Bart De Schuymerc7bfa272002-11-20 19:40:13 +000068/*
69 * default command line options
70 * do not mess around with the already assigned numbers unless
71 * you know what you are doing
72 */
Bart De Schuymer62423742002-07-14 19:06:20 +000073static struct option ebt_original_options[] =
74{
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000075 { "append" , required_argument, 0, 'A' },
76 { "insert" , required_argument, 0, 'I' },
77 { "delete" , required_argument, 0, 'D' },
78 { "list" , optional_argument, 0, 'L' },
Bart De Schuymer9af14f92002-07-10 20:49:10 +000079 { "Lc" , no_argument , 0, 4 },
80 { "Ln" , no_argument , 0, 5 },
81 { "Lx" , no_argument , 0, 6 },
Bart De Schuymer22d03a22003-05-03 20:28:22 +000082 { "Lmac2" , no_argument , 0, 12 },
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000083 { "zero" , optional_argument, 0, 'Z' },
84 { "flush" , optional_argument, 0, 'F' },
85 { "policy" , required_argument, 0, 'P' },
86 { "in-interface" , required_argument, 0, 'i' },
87 { "in-if" , required_argument, 0, 'i' },
88 { "logical-in" , required_argument, 0, 2 },
89 { "logical-out" , required_argument, 0, 3 },
90 { "out-interface" , required_argument, 0, 'o' },
91 { "out-if" , required_argument, 0, 'o' },
92 { "version" , no_argument , 0, 'V' },
93 { "help" , no_argument , 0, 'h' },
94 { "jump" , required_argument, 0, 'j' },
95 { "proto" , required_argument, 0, 'p' },
96 { "protocol" , required_argument, 0, 'p' },
97 { "db" , required_argument, 0, 'b' },
98 { "source" , required_argument, 0, 's' },
99 { "src" , required_argument, 0, 's' },
100 { "destination" , required_argument, 0, 'd' },
101 { "dst" , required_argument, 0, 'd' },
102 { "table" , required_argument, 0, 't' },
Bart De Schuymerc8531032002-06-14 21:55:29 +0000103 { "modprobe" , required_argument, 0, 'M' },
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000104 { "new-chain" , required_argument, 0, 'N' },
105 { "rename-chain" , required_argument, 0, 'E' },
106 { "delete-chain" , required_argument, 0, 'X' },
Bart De Schuymer5885b362002-12-03 20:51:36 +0000107 { "atomic-init" , no_argument , 0, 7 },
108 { "atomic-commit" , no_argument , 0, 8 },
109 { "atomic-file" , required_argument, 0, 9 },
110 { "atomic-save" , no_argument , 0, 10 },
Bart De Schuymer8d1d8942002-07-15 20:09:09 +0000111 { "init-table" , no_argument , 0, 11 },
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000112 { 0 }
113};
114
115static struct option *ebt_options = ebt_original_options;
116
Bart De Schuymer62423742002-07-14 19:06:20 +0000117char* standard_targets[NUM_STANDARD_TARGETS] =
118{
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000119 "ACCEPT",
120 "DROP",
121 "CONTINUE",
Bart De Schuymer60332e02002-06-23 08:01:47 +0000122 "RETURN",
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000123};
124
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000125unsigned char mac_type_unicast[ETH_ALEN] = {0,0,0,0,0,0};
126unsigned char msk_type_unicast[ETH_ALEN] = {1,0,0,0,0,0};
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000127unsigned char mac_type_multicast[ETH_ALEN] = {1,0,0,0,0,0};
128unsigned char msk_type_multicast[ETH_ALEN] = {1,0,0,0,0,0};
129unsigned char mac_type_broadcast[ETH_ALEN] = {255,255,255,255,255,255};
130unsigned char msk_type_broadcast[ETH_ALEN] = {255,255,255,255,255,255};
131
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000132/*
133 * holds all the data
134 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000135static struct ebt_u_replace replace;
136
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000137/*
138 * the chosen table
139 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000140static struct ebt_u_table *table = NULL;
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000141/*
142 * the lists of supported tables, matches, watchers and targets
143 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000144static struct ebt_u_table *tables = NULL;
145static struct ebt_u_match *matches = NULL;
146static struct ebt_u_watcher *watchers = NULL;
147static struct ebt_u_target *targets = NULL;
148
149struct ebt_u_target *find_target(const char *name)
150{
151 struct ebt_u_target *t = targets;
152
153 while(t && strcmp(t->name, name))
154 t = t->next;
155 return t;
156}
157
158struct ebt_u_match *find_match(const char *name)
159{
160 struct ebt_u_match *m = matches;
161
162 while(m && strcmp(m->name, name))
163 m = m->next;
164 return m;
165}
166
167struct ebt_u_watcher *find_watcher(const char *name)
168{
169 struct ebt_u_watcher *w = watchers;
170
171 while(w && strcmp(w->name, name))
172 w = w->next;
173 return w;
174}
175
176struct ebt_u_table *find_table(char *name)
177{
178 struct ebt_u_table *t = tables;
179
180 while (t && strcmp(t->name, name))
181 t = t->next;
182 return t;
183}
184
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000185/*
186 * The pointers in here are special:
187 * The struct ebt_target * pointer is actually a struct ebt_u_target * pointer.
188 * instead of making yet a few other structs, we just do a cast.
189 * We need a struct ebt_u_target pointer because we know the address of the data
190 * they point to won't change. We want to allow that the struct ebt_u_target.t
191 * member can change.
192 * Same holds for the struct ebt_match and struct ebt_watcher pointers
193 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000194struct ebt_u_entry *new_entry;
195
Bart De Schuymer62423742002-07-14 19:06:20 +0000196static void initialize_entry(struct ebt_u_entry *e)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000197{
198 e->bitmask = EBT_NOPROTO;
199 e->invflags = 0;
200 e->ethproto = 0;
201 strcpy(e->in, "");
202 strcpy(e->out, "");
203 strcpy(e->logical_in, "");
204 strcpy(e->logical_out, "");
205 e->m_list = NULL;
206 e->w_list = NULL;
Bart De Schuymerc27432e2003-01-09 22:01:07 +0000207 /*
208 * the init function of the standard target should have put the verdict
209 * on CONTINUE
210 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000211 e->t = (struct ebt_entry_target *)find_target(EBT_STANDARD_TARGET);
212 if (!e->t)
Bart De Schuymerd4586482002-08-11 16:15:55 +0000213 print_bug("Couldn't load standard target");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000214}
215
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000216/*
217 * this doesn't free e, becoz the calling function might need e->next
218 */
Bart De Schuymer62423742002-07-14 19:06:20 +0000219static void free_u_entry(struct ebt_u_entry *e)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000220{
221 struct ebt_u_match_list *m_l, *m_l2;
222 struct ebt_u_watcher_list *w_l, *w_l2;
223
224 m_l = e->m_list;
225 while (m_l) {
226 m_l2 = m_l->next;
227 free(m_l->m);
228 free(m_l);
229 m_l = m_l2;
230 }
231 w_l = e->w_list;
232 while (w_l) {
233 w_l2 = w_l->next;
234 free(w_l->w);
235 free(w_l);
236 w_l = w_l2;
237 }
238 free(e->t);
239}
240
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000241/*
242 * the user will use the match, so put it in new_entry
243 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000244static void add_match(struct ebt_u_match *m)
245{
246 struct ebt_u_match_list **m_list, *new;
247
248 m->used = 1;
Bart De Schuymerc56a31a2002-07-25 08:16:08 +0000249 for (m_list = &new_entry->m_list; *m_list; m_list = &(*m_list)->next);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000250 new = (struct ebt_u_match_list *)
251 malloc(sizeof(struct ebt_u_match_list));
252 if (!new)
253 print_memory();
254 *m_list = new;
255 new->next = NULL;
256 new->m = (struct ebt_entry_match *)m;
257}
258
259static void add_watcher(struct ebt_u_watcher *w)
260{
261 struct ebt_u_watcher_list **w_list;
262 struct ebt_u_watcher_list *new;
263
264 w->used = 1;
Bart De Schuymerc56a31a2002-07-25 08:16:08 +0000265 for (w_list = &new_entry->w_list; *w_list; w_list = &(*w_list)->next);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000266 new = (struct ebt_u_watcher_list *)
267 malloc(sizeof(struct ebt_u_watcher_list));
268 if (!new)
269 print_memory();
270 *w_list = new;
271 new->next = NULL;
272 new->w = (struct ebt_entry_watcher *)w;
273}
274
275static int global_option_offset = 0;
276#define OPTION_OFFSET 256
277static struct option *
278merge_options(struct option *oldopts, const struct option *newopts,
279 unsigned int *options_offset)
280{
281 unsigned int num_old, num_new, i;
282 struct option *merge;
283
284 if (!newopts || !oldopts || !options_offset)
285 print_bug("merge wrong");
286 for (num_old = 0; oldopts[num_old].name; num_old++);
287 for (num_new = 0; newopts[num_new].name; num_new++);
288
289 global_option_offset += OPTION_OFFSET;
290 *options_offset = global_option_offset;
291
292 merge = malloc(sizeof(struct option) * (num_new + num_old + 1));
293 if (!merge)
294 print_memory();
295 memcpy(merge, oldopts, num_old * sizeof(struct option));
296 for (i = 0; i < num_new; i++) {
297 merge[num_old + i] = newopts[i];
298 merge[num_old + i].val += *options_offset;
299 }
300 memset(merge + num_old + num_new, 0, sizeof(struct option));
Bart De Schuymer9895a8e2003-01-11 10:14:24 +0000301 /* only free dynamically allocated stuff */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000302 if (oldopts != ebt_original_options)
303 free(oldopts);
304
305 return merge;
306}
307
308void register_match(struct ebt_u_match *m)
309{
310 int size = m->size + sizeof(struct ebt_entry_match);
311 struct ebt_u_match **i;
312
313 m->m = (struct ebt_entry_match *)malloc(size);
314 if (!m->m)
315 print_memory();
316 strcpy(m->m->u.name, m->name);
317 m->m->match_size = m->size;
318 ebt_options = merge_options
319 (ebt_options, m->extra_ops, &(m->option_offset));
320 m->init(m->m);
321
322 for (i = &matches; *i; i = &((*i)->next));
323 m->next = NULL;
324 *i = m;
325}
326
327void register_watcher(struct ebt_u_watcher *w)
328{
329 int size = w->size + sizeof(struct ebt_entry_watcher);
330 struct ebt_u_watcher **i;
331
332 w->w = (struct ebt_entry_watcher *)malloc(size);
333 if (!w->w)
334 print_memory();
335 strcpy(w->w->u.name, w->name);
336 w->w->watcher_size = w->size;
337 ebt_options = merge_options
338 (ebt_options, w->extra_ops, &(w->option_offset));
339 w->init(w->w);
340
341 for (i = &watchers; *i; i = &((*i)->next));
342 w->next = NULL;
343 *i = w;
344}
345
346void register_target(struct ebt_u_target *t)
347{
348 int size = t->size + sizeof(struct ebt_entry_target);
349 struct ebt_u_target **i;
350
351 t->t = (struct ebt_entry_target *)malloc(size);
352 if (!t->t)
353 print_memory();
354 strcpy(t->t->u.name, t->name);
355 t->t->target_size = t->size;
356 ebt_options = merge_options
357 (ebt_options, t->extra_ops, &(t->option_offset));
358 t->init(t->t);
Bart De Schuymerc56a31a2002-07-25 08:16:08 +0000359
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000360 for (i = &targets; *i; i = &((*i)->next));
361 t->next = NULL;
362 *i = t;
363}
364
365void register_table(struct ebt_u_table *t)
366{
367 t->next = tables;
368 tables = t;
369}
370
Bart De Schuymer0cb01792003-05-04 16:52:04 +0000371const char *modprobe = NULL;
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000372/*
373 * blatently stolen (again) from iptables.c userspace program
374 * find out where the modprobe utility is located
375 */
Bart De Schuymerc8531032002-06-14 21:55:29 +0000376static char *get_modprobe(void)
377{
378 int procfile;
379 char *ret;
380
381 procfile = open(PROC_SYS_MODPROBE, O_RDONLY);
382 if (procfile < 0)
383 return NULL;
384
385 ret = malloc(1024);
386 if (ret) {
387 switch (read(procfile, ret, 1024)) {
388 case -1: goto fail;
389 case 1024: goto fail; /* Partial read. Wierd */
390 }
391 if (ret[strlen(ret)-1]=='\n')
392 ret[strlen(ret)-1]=0;
393 close(procfile);
394 return ret;
395 }
396 fail:
397 free(ret);
398 close(procfile);
399 return NULL;
400}
401
Bart De Schuymer0cb01792003-05-04 16:52:04 +0000402int ebtables_insmod(const char *modname)
Bart De Schuymerc8531032002-06-14 21:55:29 +0000403{
404 char *buf = NULL;
405 char *argv[3];
406
Bart De Schuymer9895a8e2003-01-11 10:14:24 +0000407 /* If they don't explicitly set it, read out of kernel */
Bart De Schuymerc8531032002-06-14 21:55:29 +0000408 if (!modprobe) {
409 buf = get_modprobe();
410 if (!buf)
411 return -1;
412 modprobe = buf;
413 }
414
415 switch (fork()) {
416 case 0:
417 argv[0] = (char *)modprobe;
418 argv[1] = (char *)modname;
419 argv[2] = NULL;
420 execv(argv[0], argv);
421
422 /* not usually reached */
423 exit(0);
424 case -1:
425 return -1;
426
427 default: /* parent */
428 wait(NULL);
429 }
430
431 free(buf);
432 return 0;
433}
434
Bart De Schuymer9a0fbf22003-01-11 16:16:54 +0000435static void list_extensions()
436{
437 struct ebt_u_table *tbl = tables;
438 struct ebt_u_target *t = targets;
439 struct ebt_u_match *m = matches;
440 struct ebt_u_watcher *w = watchers;
441
Bart De Schuymer57a3f6a2003-04-01 16:59:33 +0000442 PRINT_VERSION;
Bart De Schuymer9a0fbf22003-01-11 16:16:54 +0000443 printf("Supported userspace extensions:\n\nSupported tables:\n");
444 while(tbl) {
445 printf("%s\n", tbl->name);
446 tbl = tbl->next;
447 }
448 printf("\nSupported targets:\n");
449 while(t) {
450 printf("%s\n", t->name);
451 t = t->next;
452 }
453 printf("\nSupported matches:\n");
454 while(m) {
455 printf("%s\n", m->name);
456 m = m->next;
457 }
458 printf("\nSupported watchers:\n");
459 while(w) {
460 printf("%s\n", w->name);
461 w = w->next;
462 }
463 exit(0);
464}
465
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000466/*
467 * we use replace.flags, so we can't use the following values:
468 * 0x01 == OPT_COMMAND, 0x02 == OPT_TABLE, 0x100 == OPT_ZERO
469 */
Bart De Schuymer22d03a22003-05-03 20:28:22 +0000470#define LIST_N 0x04
471#define LIST_C 0x08
472#define LIST_X 0x10
473#define LIST_MAC2 0x20
474
475void print_mac(const char *mac)
476{
477 if (replace.flags & LIST_MAC2) {
478 int j;
479 for (j = 0; j < ETH_ALEN; j++)
480 printf("%02x%s", (unsigned char)mac[j],
481 (j==ETH_ALEN-1) ? "" : ":");
482 } else
483 printf("%s", ether_ntoa((struct ether_addr *) mac));
484}
485
486void print_mac_and_mask(const char *mac, const char *mask)
487{
488 char hlpmsk[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
489
490 print_mac(mac);
491 if (memcmp(mask, hlpmsk, 6)) {
492 printf("/");
493 print_mac(mask);
494 }
495}
496
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000497/*
498 * helper function for list_rules()
499 */
Bart De Schuymer60332e02002-06-23 08:01:47 +0000500static void list_em(struct ebt_u_entries *entries)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000501{
502 int i, j, space = 0, digits;
503 struct ebt_u_entry *hlp;
504 struct ebt_u_match_list *m_l;
505 struct ebt_u_watcher_list *w_l;
506 struct ebt_u_match *m;
507 struct ebt_u_watcher *w;
508 struct ebt_u_target *t;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000509
Bart De Schuymer60332e02002-06-23 08:01:47 +0000510 hlp = entries->entries;
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000511 if (replace.flags & LIST_X && entries->policy != EBT_ACCEPT) {
512 printf("ebtables -t %s -P %s %s\n", replace.name,
513 entries->name, standard_targets[-entries->policy - 1]);
514 } else if (!(replace.flags & LIST_X)) {
Bart De Schuymerc87c9642002-08-01 15:34:16 +0000515 printf("\nBridge chain: %s, entries: %d, policy: %s\n",
516 entries->name, entries->nentries,
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000517 standard_targets[-entries->policy - 1]);
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000518 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000519
Bart De Schuymer60332e02002-06-23 08:01:47 +0000520 i = entries->nentries;
Bart De Schuymerf8f8f292002-06-25 15:43:57 +0000521 while (i > 9) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000522 space++;
523 i /= 10;
524 }
525
Bart De Schuymer60332e02002-06-23 08:01:47 +0000526 for (i = 0; i < entries->nentries; i++) {
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000527 if (replace.flags & LIST_N) {
528 digits = 0;
Bart De Schuymer9895a8e2003-01-11 10:14:24 +0000529 /* A little work to get nice rule numbers. */
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000530 j = i + 1;
531 while (j > 9) {
532 digits++;
533 j /= 10;
534 }
535 for (j = 0; j < space - digits; j++)
536 printf(" ");
537 printf("%d. ", i + 1);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000538 }
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000539 if (replace.flags & LIST_X)
540 printf("ebtables -t %s -A %s ",
541 replace.name, entries->name);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000542
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000543 /*
544 * Don't print anything about the protocol if no protocol was
545 * specified, obviously this means any protocol will do.
546 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000547 if (!(hlp->bitmask & EBT_NOPROTO)) {
Bart De Schuymer60332e02002-06-23 08:01:47 +0000548 printf("-p ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000549 if (hlp->invflags & EBT_IPROTO)
550 printf("! ");
551 if (hlp->bitmask & EBT_802_3)
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000552 printf("Length ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000553 else {
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000554 struct ethertypeent *ent;
555
556 ent = getethertypebynumber(ntohs(hlp->ethproto));
557 if (!ent)
Bart De Schuymer60332e02002-06-23 08:01:47 +0000558 printf("0x%x ", ntohs(hlp->ethproto));
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000559 else
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000560 printf("%s ", ent->e_name);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000561 }
562 }
563 if (hlp->bitmask & EBT_SOURCEMAC) {
Bart De Schuymer60332e02002-06-23 08:01:47 +0000564 printf("-s ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000565 if (hlp->invflags & EBT_ISOURCE)
566 printf("! ");
567 if (!memcmp(hlp->sourcemac, mac_type_unicast, 6) &&
568 !memcmp(hlp->sourcemsk, msk_type_unicast, 6)) {
569 printf("Unicast");
570 goto endsrc;
571 }
572 if (!memcmp(hlp->sourcemac, mac_type_multicast, 6) &&
573 !memcmp(hlp->sourcemsk, msk_type_multicast, 6)) {
574 printf("Multicast");
575 goto endsrc;
576 }
577 if (!memcmp(hlp->sourcemac, mac_type_broadcast, 6) &&
578 !memcmp(hlp->sourcemsk, msk_type_broadcast, 6)) {
579 printf("Broadcast");
580 goto endsrc;
581 }
Bart De Schuymer22d03a22003-05-03 20:28:22 +0000582 print_mac_and_mask(hlp->sourcemac, hlp->sourcemsk);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000583endsrc:
Bart De Schuymer60332e02002-06-23 08:01:47 +0000584 printf(" ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000585 }
586 if (hlp->bitmask & EBT_DESTMAC) {
Bart De Schuymer60332e02002-06-23 08:01:47 +0000587 printf("-d ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000588 if (hlp->invflags & EBT_IDEST)
589 printf("! ");
590 if (!memcmp(hlp->destmac, mac_type_unicast, 6) &&
591 !memcmp(hlp->destmsk, msk_type_unicast, 6)) {
592 printf("Unicast");
593 goto enddst;
594 }
595 if (!memcmp(hlp->destmac, mac_type_multicast, 6) &&
596 !memcmp(hlp->destmsk, msk_type_multicast, 6)) {
597 printf("Multicast");
598 goto enddst;
599 }
600 if (!memcmp(hlp->destmac, mac_type_broadcast, 6) &&
601 !memcmp(hlp->destmsk, msk_type_broadcast, 6)) {
602 printf("Broadcast");
603 goto enddst;
604 }
Bart De Schuymer22d03a22003-05-03 20:28:22 +0000605 print_mac_and_mask(hlp->destmac, hlp->destmsk);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000606enddst:
Bart De Schuymer60332e02002-06-23 08:01:47 +0000607 printf(" ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000608 }
609 if (hlp->in[0] != '\0') {
Bart De Schuymer60332e02002-06-23 08:01:47 +0000610 printf("-i ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000611 if (hlp->invflags & EBT_IIN)
612 printf("! ");
Bart De Schuymer60332e02002-06-23 08:01:47 +0000613 printf("%s ", hlp->in);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000614 }
615 if (hlp->logical_in[0] != '\0') {
Bart De Schuymer60332e02002-06-23 08:01:47 +0000616 printf("--logical-in ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000617 if (hlp->invflags & EBT_ILOGICALIN)
618 printf("! ");
Bart De Schuymer60332e02002-06-23 08:01:47 +0000619 printf("%s ", hlp->logical_in);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000620 }
621 if (hlp->logical_out[0] != '\0') {
Bart De Schuymer60332e02002-06-23 08:01:47 +0000622 printf("--logical-out ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000623 if (hlp->invflags & EBT_ILOGICALOUT)
624 printf("! ");
Bart De Schuymerb3d8f262002-07-07 14:26:15 +0000625 printf("%s ", hlp->logical_out);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000626 }
627 if (hlp->out[0] != '\0') {
Bart De Schuymer60332e02002-06-23 08:01:47 +0000628 printf("-o ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000629 if (hlp->invflags & EBT_IOUT)
630 printf("! ");
Bart De Schuymerb3d8f262002-07-07 14:26:15 +0000631 printf("%s ", hlp->out);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000632 }
633
634 m_l = hlp->m_list;
635 while (m_l) {
636 m = find_match(m_l->m->u.name);
637 if (!m)
638 print_bug("Match not found");
639 m->print(hlp, m_l->m);
640 m_l = m_l->next;
641 }
642 w_l = hlp->w_list;
643 while (w_l) {
644 w = find_watcher(w_l->w->u.name);
645 if (!w)
646 print_bug("Watcher not found");
647 w->print(hlp, w_l->w);
648 w_l = w_l->next;
649 }
650
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000651 printf("-j ");
652 if (strcmp(hlp->t->u.name, EBT_STANDARD_TARGET))
653 printf("%s ", hlp->t->u.name);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000654 t = find_target(hlp->t->u.name);
655 if (!t)
656 print_bug("Target not found");
657 t->print(hlp, hlp->t);
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000658 if (replace.flags & LIST_C)
Bart De Schuymer73fccca2002-10-17 22:00:23 +0000659 printf(", pcnt = %llu -- bcnt = %llu",
660 replace.counters[entries->counter_offset + i].pcnt,
661 replace.counters[entries->counter_offset + i].bcnt);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000662 printf("\n");
663 hlp = hlp->next;
664 }
665}
666
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000667struct ebt_u_entries *nr_to_chain(int nr)
Bart De Schuymer60332e02002-06-23 08:01:47 +0000668{
669 if (nr == -1)
670 return NULL;
671 if (nr < NF_BR_NUMHOOKS)
672 return replace.hook_entry[nr];
673 else {
674 int i;
675 struct ebt_u_chain_list *cl = replace.udc;
676
677 i = nr - NF_BR_NUMHOOKS;
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000678 while (i > 0 && cl) {
Bart De Schuymer60332e02002-06-23 08:01:47 +0000679 cl = cl->next;
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000680 i--;
681 }
Bart De Schuymer60332e02002-06-23 08:01:47 +0000682 if (cl)
683 return cl->udc;
684 else
685 return NULL;
686 }
687}
688
Bart De Schuymercc440052002-11-06 21:10:33 +0000689static inline struct ebt_u_entries *to_chain()
Bart De Schuymer60332e02002-06-23 08:01:47 +0000690{
691 return nr_to_chain(replace.selected_hook);
692}
693
694struct ebt_u_stack
695{
696 int chain_nr;
697 int n;
698 struct ebt_u_entry *e;
699 struct ebt_u_entries *entries;
700};
701
Bart De Schuymer62423742002-07-14 19:06:20 +0000702static void check_for_loops()
Bart De Schuymer60332e02002-06-23 08:01:47 +0000703{
704 int chain_nr , i, j , k, sp = 0, verdict;
705 struct ebt_u_entries *entries, *entries2;
706 struct ebt_u_stack *stack = NULL;
707 struct ebt_u_entry *e;
708
709 i = -1;
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000710 /*
711 * initialize hook_mask to 0
712 */
Bart De Schuymer60332e02002-06-23 08:01:47 +0000713 while (1) {
714 i++;
715 if (i < NF_BR_NUMHOOKS && !(replace.valid_hooks & (1 << i)))
716 continue;
717 entries = nr_to_chain(i);
718 if (!entries)
719 break;
720 entries->hook_mask = 0;
721 }
722 if (i > NF_BR_NUMHOOKS) {
723 stack = (struct ebt_u_stack *)malloc((i - NF_BR_NUMHOOKS) *
724 sizeof(struct ebt_u_stack));
725 if (!stack)
726 print_memory();
727 }
728
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000729 /*
730 * check for loops, starting from every base chain
731 */
Bart De Schuymer60332e02002-06-23 08:01:47 +0000732 for (i = 0; i < NF_BR_NUMHOOKS; i++) {
733 if (!(replace.valid_hooks & (1 << i)))
734 continue;
735 entries = nr_to_chain(i);
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000736 /*
737 * (1 << NF_BR_NUMHOOKS) implies it's a standard chain
738 * (usefull in the final_check() funtions)
739 */
Bart De Schuymerb26649e2002-07-25 14:51:54 +0000740 entries->hook_mask = (1 << i) | (1 << NF_BR_NUMHOOKS);
Bart De Schuymer60332e02002-06-23 08:01:47 +0000741 chain_nr = i;
742
743 e = entries->entries;
744 for (j = 0; j < entries->nentries; j++) {
745 if (strcmp(e->t->u.name, EBT_STANDARD_TARGET))
746 goto letscontinue;
747 verdict = ((struct ebt_standard_target *)(e->t))->verdict;
748 if (verdict < 0)
749 goto letscontinue;
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000750 entries2 = nr_to_chain(verdict + NF_BR_NUMHOOKS);
Bart De Schuymer60332e02002-06-23 08:01:47 +0000751 entries2->hook_mask |= entries->hook_mask;
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000752 /*
753 * now see if we've been here before
754 */
Bart De Schuymer60332e02002-06-23 08:01:47 +0000755 for (k = 0; k < sp; k++)
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000756 if (stack[k].chain_nr == verdict + NF_BR_NUMHOOKS)
Bart De Schuymer1a0a9c32002-06-24 21:10:16 +0000757 print_error("Loop from chain %s to chain %s",
Bart De Schuymerc56a31a2002-07-25 08:16:08 +0000758 nr_to_chain(chain_nr)->name,
759 nr_to_chain(stack[k].chain_nr)->name);
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000760 /*
761 * jump to the chain, make sure we know how to get back
762 */
Bart De Schuymer60332e02002-06-23 08:01:47 +0000763 stack[sp].chain_nr = chain_nr;
764 stack[sp].n = j;
765 stack[sp].entries = entries;
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000766 stack[sp].e = e;
767 sp++;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000768 j = -1;
769 e = entries2->entries;
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000770 chain_nr = verdict + NF_BR_NUMHOOKS;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000771 entries = entries2;
772 continue;
773letscontinue:
774 e = e->next;
775 }
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000776 /*
777 * we are at the end of a standard chain
778 */
Bart De Schuymer60332e02002-06-23 08:01:47 +0000779 if (sp == 0)
780 continue;
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000781 /*
782 * go back to the chain one level higher
783 */
Bart De Schuymer60332e02002-06-23 08:01:47 +0000784 sp--;
785 j = stack[sp].n;
786 chain_nr = stack[sp].chain_nr;
787 e = stack[sp].e;
788 entries = stack[sp].entries;
789 goto letscontinue;
790 }
791 free(stack);
792 return;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000793}
794
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000795/*
796 * parse the chain name and return the corresponding nr
797 * returns -1 on failure
798 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000799int get_hooknr(char* arg)
800{
801 int i;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000802 struct ebt_u_chain_list *cl = replace.udc;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000803
Bart De Schuymer60332e02002-06-23 08:01:47 +0000804 for (i = 0; i < NF_BR_NUMHOOKS; i++) {
805 if (!(replace.valid_hooks & (1 << i)))
806 continue;
807 if (!strcmp(arg, replace.hook_entry[i]->name))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000808 return i;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000809 }
810 while(cl) {
811 if (!strcmp(arg, cl->udc->name))
812 return i;
813 i++;
814 cl = cl->next;
815 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000816 return -1;
817}
818
Bart De Schuymer62423742002-07-14 19:06:20 +0000819static void print_help()
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000820{
821 struct ebt_u_match_list *m_l;
822 struct ebt_u_watcher_list *w_l;
823
Bart De Schuymer57a3f6a2003-04-01 16:59:33 +0000824 PRINT_VERSION;
825 printf(
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000826"Usage:\n"
827"ebtables -[ADI] chain rule-specification [options]\n"
828"ebtables -P chain target\n"
829"ebtables -[LFZ] [chain]\n"
Bart De Schuymer5885b362002-12-03 20:51:36 +0000830"ebtables -[NX] [chain]\n"
831"ebtables -E old-chain-name new-chain-name\n\n"
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000832"Commands:\n"
Bart De Schuymer23f6dcf2002-08-17 09:14:07 +0000833"--append -A chain : append to chain\n"
834"--delete -D chain : delete matching rule from chain\n"
835"--delete -D chain rulenum : delete rule at position rulenum from chain\n"
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000836"--insert -I chain rulenum : insert rule at position rulenum in chain\n"
Bart De Schuymer23f6dcf2002-08-17 09:14:07 +0000837"--list -L [chain] : list the rules in a chain or in all chains\n"
838"--flush -F [chain] : delete all rules in chain or in all chains\n"
839"--init-table : replace the kernel table with the initial table\n"
840"--zero -Z [chain] : put counters on zero in chain or in all chains\n"
841"--policy -P chain target : change policy on chain to target\n"
842"--new-chain -N chain : create a user defined chain\n"
843"--rename-chain -E old new : rename a chain\n"
844"--delete-chain -X chain : delete a user defined chain\n"
Bart De Schuymer5885b362002-12-03 20:51:36 +0000845"--atomic-commit : update the kernel w/t table contained in <FILE>\n"
846"--atomic-init : put the initial kernel table into <FILE>\n"
847"--atomic-save : put the current kernel table into <FILE>\n"
Bart De Schuymer97819962002-12-11 21:23:07 +0000848"--atomic-file file : set <FILE> to file\n\n"
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000849"Options:\n"
850"--proto -p [!] proto : protocol hexadecimal, by name or LENGTH\n"
851"--src -s [!] address[/mask]: source mac address\n"
852"--dst -d [!] address[/mask]: destination mac address\n"
853"--in-if -i [!] name : network input interface name\n"
854"--out-if -o [!] name : network output interface name\n"
855"--logical-in [!] name : logical bridge input interface name\n"
856"--logical-out [!] name : logical bridge output interface name\n"
Bart De Schuymer5cbc8e02002-07-14 21:15:28 +0000857"--modprobe -M program : try to insert modules using this program\n"
Bart De Schuymer5885b362002-12-03 20:51:36 +0000858"--version -V : print package version\n\n"
859"Environment variable:\n"
860ATOMIC_ENV_VARIABLE " : if set <FILE> (see above) will equal its value"
861"\n\n");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000862
863 m_l = new_entry->m_list;
864 while (m_l) {
865 ((struct ebt_u_match *)m_l->m)->help();
866 printf("\n");
867 m_l = m_l->next;
868 }
869 w_l = new_entry->w_list;
870 while (w_l) {
871 ((struct ebt_u_watcher *)w_l->w)->help();
872 printf("\n");
873 w_l = w_l->next;
874 }
875 ((struct ebt_u_target *)new_entry->t)->help();
876 printf("\n");
877 if (table->help)
878 table->help(hooknames);
879 exit(0);
880}
881
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000882/*
883 * execute command L
884 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000885static void list_rules()
886{
887 int i;
888
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000889 if (!(replace.flags & LIST_X))
890 printf("Bridge table: %s\n", table->name);
Bart De Schuymer60332e02002-06-23 08:01:47 +0000891 if (replace.selected_hook != -1) {
892 list_em(to_chain());
893 } else {
894 struct ebt_u_chain_list *cl = replace.udc;
895
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000896 /*
897 * create new chains and rename standard chains when necessary
898 */
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000899 if (replace.flags & LIST_X) {
900 while (cl) {
901 printf("ebtables -t %s -N %s\n", replace.name,
902 cl->udc->name);
903 cl = cl->next;
904 }
905 cl = replace.udc;
906 for (i = 0; i < NF_BR_NUMHOOKS; i++)
907 if (replace.valid_hooks & (1 << i) &&
908 strcmp(replace.hook_entry[i]->name, hooknames[i]))
909 printf("ebtables -t %s -E %s %s\n",
910 replace.name, hooknames[i],
911 replace.hook_entry[i]->name);
912 }
Bart De Schuymer60332e02002-06-23 08:01:47 +0000913 i = 0;
914 while (1) {
915 if (i < NF_BR_NUMHOOKS) {
916 if (replace.valid_hooks & (1 << i))
917 list_em(replace.hook_entry[i]);
918 i++;
919 continue;
920 } else {
921 if (!cl)
922 break;
923 list_em(cl->udc);
924 cl = cl->next;
925 }
926 }
927 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000928}
929
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000930/*
931 * execute command P
932 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000933static void change_policy(int policy)
934{
935 int i;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000936 struct ebt_u_entries *entries = to_chain();
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000937
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000938 /*
939 * don't do anything if the policy is the same
940 */
Bart De Schuymer60332e02002-06-23 08:01:47 +0000941 if (entries->policy != policy) {
942 entries->policy = policy;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000943 replace.num_counters = replace.nentries;
944 if (replace.nentries) {
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000945 /*
946 * '+ 1' for the CNT_END
947 */
Bart De Schuymered053432002-07-21 19:35:39 +0000948 if (!(replace.counterchanges = (unsigned short *) malloc(
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000949 (replace.nentries + 1) * sizeof(unsigned short))))
950 print_memory();
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000951 /*
952 * done nothing special to the rules
953 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000954 for (i = 0; i < replace.nentries; i++)
Bart De Schuymered053432002-07-21 19:35:39 +0000955 replace.counterchanges[i] = CNT_NORM;
956 replace.counterchanges[replace.nentries] = CNT_END;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000957 }
958 else
Bart De Schuymered053432002-07-21 19:35:39 +0000959 replace.counterchanges = NULL;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000960 }
961 else
962 exit(0);
963}
964
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000965/*
966 * flush one chain or the complete table
967 * -1 == nothing to do
968 * 0 == give back to kernel
969 */
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000970static int flush_chains()
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000971{
Bart De Schuymer60332e02002-06-23 08:01:47 +0000972 int i, j, oldnentries, numdel;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000973 unsigned short *cnt;
974 struct ebt_u_entry *u_e, *tmp;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000975 struct ebt_u_entries *entries = to_chain();
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000976
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000977 /*
978 * flush whole table
979 */
Bart De Schuymer60332e02002-06-23 08:01:47 +0000980 if (!entries) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000981 if (replace.nentries == 0)
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000982 return -1;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000983 replace.nentries = 0;
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000984 /*
985 * no need for the kernel to give us counters back
986 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000987 replace.num_counters = 0;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000988
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000989 /*
990 * free everything and zero (n)entries
991 */
Bart De Schuymer60332e02002-06-23 08:01:47 +0000992 i = -1;
993 while (1) {
994 i++;
995 entries = nr_to_chain(i);
996 if (!entries) {
997 if (i < NF_BR_NUMHOOKS)
998 continue;
999 else
1000 break;
1001 }
1002 entries->nentries = 0;
1003 entries->counter_offset = 0;
1004 u_e = entries->entries;
1005 entries->entries = NULL;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001006 while (u_e) {
1007 free_u_entry(u_e);
1008 tmp = u_e->next;
1009 free(u_e);
1010 u_e = tmp;
1011 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001012 }
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001013 return 0;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001014 }
1015
Bart De Schuymer60332e02002-06-23 08:01:47 +00001016 if (entries->nentries == 0)
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001017 return -1;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001018 oldnentries = replace.nentries;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001019 replace.nentries -= entries->nentries;
1020 numdel = entries->nentries;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001021
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001022 if (replace.nentries) {
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001023 /*
1024 * +1 for CNT_END
1025 */
Bart De Schuymered053432002-07-21 19:35:39 +00001026 if ( !(replace.counterchanges = (unsigned short *)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001027 malloc((oldnentries + 1) * sizeof(unsigned short))) )
1028 print_memory();
Bart De Schuymer60332e02002-06-23 08:01:47 +00001029 }
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001030 /*
1031 * delete the counters belonging to the specified chain,
1032 * update counter_offset
1033 */
Bart De Schuymer60332e02002-06-23 08:01:47 +00001034 i = -1;
Bart De Schuymered053432002-07-21 19:35:39 +00001035 cnt = replace.counterchanges;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001036 while (1) {
1037 i++;
1038 entries = nr_to_chain(i);
1039 if (!entries) {
1040 if (i < NF_BR_NUMHOOKS)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001041 continue;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001042 else
1043 break;
1044 }
1045 if (i > replace.selected_hook)
1046 entries->counter_offset -= numdel;
1047 if (replace.nentries) {
1048 for (j = 0; j < entries->nentries; j++) {
1049 if (i == replace.selected_hook)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001050 *cnt = CNT_DEL;
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001051 else
1052 *cnt = CNT_NORM;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001053 cnt++;
1054 }
1055 }
Bart De Schuymer60332e02002-06-23 08:01:47 +00001056 }
1057
1058 if (replace.nentries) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001059 *cnt = CNT_END;
1060 replace.num_counters = oldnentries;
Bart De Schuymercc440052002-11-06 21:10:33 +00001061 } else
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001062 replace.num_counters = 0;
1063
Bart De Schuymer60332e02002-06-23 08:01:47 +00001064 entries = to_chain();
1065 entries->nentries = 0;
1066 u_e = entries->entries;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001067 while (u_e) {
1068 free_u_entry(u_e);
1069 tmp = u_e->next;
1070 free(u_e);
1071 u_e = tmp;
1072 }
Bart De Schuymer60332e02002-06-23 08:01:47 +00001073 entries->entries = NULL;
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001074 return 0;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001075}
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001076
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001077/*
1078 * -1 == no match
1079 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001080static int check_rule_exists(int rule_nr)
1081{
1082 struct ebt_u_entry *u_e;
1083 struct ebt_u_match_list *m_l, *m_l2;
1084 struct ebt_u_match *m;
1085 struct ebt_u_watcher_list *w_l, *w_l2;
1086 struct ebt_u_watcher *w;
1087 struct ebt_u_target *t = (struct ebt_u_target *)new_entry->t;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001088 struct ebt_u_entries *entries = to_chain();
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001089 int i, j, k;
1090
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001091 /*
1092 * handle '-D chain rulenr' command
1093 */
Bart De Schuymerc3b97f52003-04-17 17:03:49 +00001094 if (rule_nr != 0) {
Bart De Schuymer60332e02002-06-23 08:01:47 +00001095 if (rule_nr > entries->nentries)
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001096 return -1;
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001097 /*
1098 * user starts counting from 1
1099 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001100 return rule_nr - 1;
1101 }
Bart De Schuymer60332e02002-06-23 08:01:47 +00001102 u_e = entries->entries;
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001103 /*
1104 * check for an existing rule (if there are duplicate rules,
1105 * take the first occurance)
1106 */
Bart De Schuymer60332e02002-06-23 08:01:47 +00001107 for (i = 0; i < entries->nentries; i++, u_e = u_e->next) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001108 if (!u_e)
1109 print_bug("Hmm, trouble");
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001110 if (u_e->ethproto != new_entry->ethproto)
1111 continue;
1112 if (strcmp(u_e->in, new_entry->in))
1113 continue;
1114 if (strcmp(u_e->out, new_entry->out))
1115 continue;
1116 if (strcmp(u_e->logical_in, new_entry->logical_in))
1117 continue;
1118 if (strcmp(u_e->logical_out, new_entry->logical_out))
1119 continue;
1120 if (new_entry->bitmask & EBT_SOURCEMAC &&
1121 memcmp(u_e->sourcemac, new_entry->sourcemac, ETH_ALEN))
1122 continue;
1123 if (new_entry->bitmask & EBT_DESTMAC &&
1124 memcmp(u_e->destmac, new_entry->destmac, ETH_ALEN))
1125 continue;
1126 if (new_entry->bitmask != u_e->bitmask ||
1127 new_entry->invflags != u_e->invflags)
1128 continue;
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001129 /*
1130 * compare all matches
1131 */
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001132 m_l = new_entry->m_list;
1133 j = 0;
1134 while (m_l) {
1135 m = (struct ebt_u_match *)(m_l->m);
1136 m_l2 = u_e->m_list;
1137 while (m_l2 && strcmp(m_l2->m->u.name, m->m->u.name))
1138 m_l2 = m_l2->next;
1139 if (!m_l2 || !m->compare(m->m, m_l2->m))
1140 goto letscontinue;
1141 j++;
1142 m_l = m_l->next;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001143 }
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001144 /*
1145 * now be sure they have the same nr of matches
1146 */
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001147 k = 0;
1148 m_l = u_e->m_list;
1149 while (m_l) {
1150 k++;
1151 m_l = m_l->next;
1152 }
1153 if (j != k)
1154 continue;
1155
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001156 /*
1157 * compare all watchers
1158 */
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001159 w_l = new_entry->w_list;
1160 j = 0;
1161 while (w_l) {
1162 w = (struct ebt_u_watcher *)(w_l->w);
1163 w_l2 = u_e->w_list;
1164 while (w_l2 && strcmp(w_l2->w->u.name, w->w->u.name))
1165 w_l2 = w_l2->next;
1166 if (!w_l2 || !w->compare(w->w, w_l2->w))
1167 goto letscontinue;
1168 j++;
1169 w_l = w_l->next;
1170 }
1171 k = 0;
1172 w_l = u_e->w_list;
1173 while (w_l) {
1174 k++;
1175 w_l = w_l->next;
1176 }
1177 if (j != k)
1178 continue;
1179 if (strcmp(t->t->u.name, u_e->t->u.name))
1180 continue;
1181 if (!t->compare(t->t, u_e->t))
1182 continue;
1183 return i;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001184letscontinue:
1185 }
1186 return -1;
1187}
1188
Bart De Schuymer9895a8e2003-01-11 10:14:24 +00001189/* execute command A or I */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001190static void add_rule(int rule_nr)
1191{
1192 int i, j;
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001193 struct ebt_u_entry **u_e;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001194 unsigned short *cnt;
1195 struct ebt_u_match_list *m_l;
1196 struct ebt_u_watcher_list *w_l;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001197 struct ebt_u_entries *entries = to_chain(), *entries2;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001198
Bart De Schuymerc3b97f52003-04-17 17:03:49 +00001199 if (rule_nr <= 0)
1200 rule_nr += entries->nentries;
1201 else
1202 rule_nr--;
1203 if (rule_nr > entries->nentries || rule_nr < 0)
1204 print_error("The specified rule number is incorrect");
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001205 /*
1206 * we're adding one rule
1207 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001208 replace.num_counters = replace.nentries;
1209 replace.nentries++;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001210 entries->nentries++;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001211
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001212 /*
1213 * handle counter stuff
1214 * +1 for CNT_END
1215 */
Bart De Schuymered053432002-07-21 19:35:39 +00001216 if ( !(replace.counterchanges = (unsigned short *)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001217 malloc((replace.nentries + 1) * sizeof(unsigned short))) )
1218 print_memory();
Bart De Schuymered053432002-07-21 19:35:39 +00001219 cnt = replace.counterchanges;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001220 for (i = 0; i < replace.selected_hook; i++) {
Bart De Schuymer60332e02002-06-23 08:01:47 +00001221 if (i < NF_BR_NUMHOOKS && !(replace.valid_hooks & (1 << i)))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001222 continue;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001223 entries2 = nr_to_chain(i);
1224 for (j = 0; j < entries2->nentries; j++) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001225 *cnt = CNT_NORM;
1226 cnt++;
1227 }
1228 }
1229 for (i = 0; i < rule_nr; i++) {
1230 *cnt = CNT_NORM;
1231 cnt++;
1232 }
1233 *cnt = CNT_ADD;
1234 cnt++;
Bart De Schuymered053432002-07-21 19:35:39 +00001235 while (cnt != replace.counterchanges + replace.nentries) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001236 *cnt = CNT_NORM;
1237 cnt++;
1238 }
1239 *cnt = CNT_END;
1240
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001241 /*
1242 * go to the right position in the chain
1243 */
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001244 u_e = &entries->entries;
1245 for (i = 0; i < rule_nr; i++)
1246 u_e = &(*u_e)->next;
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001247 /*
1248 * insert the rule
1249 */
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001250 new_entry->next = *u_e;
1251 *u_e = new_entry;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001252
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001253 /*
1254 * put the ebt_[match, watcher, target] pointers in place
1255 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001256 m_l = new_entry->m_list;
1257 while (m_l) {
1258 m_l->m = ((struct ebt_u_match *)m_l->m)->m;
1259 m_l = m_l->next;
1260 }
1261 w_l = new_entry->w_list;
1262 while (w_l) {
1263 w_l->w = ((struct ebt_u_watcher *)w_l->w)->w;
1264 w_l = w_l->next;
1265 }
1266 new_entry->t = ((struct ebt_u_target *)new_entry->t)->t;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001267
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001268 /*
1269 * update the counter_offset of chains behind this one
1270 */
Bart De Schuymer60332e02002-06-23 08:01:47 +00001271 i = replace.selected_hook;
1272 while (1) {
1273 i++;
1274 entries = nr_to_chain(i);
1275 if (!entries) {
1276 if (i < NF_BR_NUMHOOKS)
1277 continue;
1278 else
1279 break;
1280 } else
1281 entries->counter_offset++;
1282 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001283}
1284
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001285/*
1286 * execute command D
1287 */
Bart De Schuymercc440052002-11-06 21:10:33 +00001288static void delete_rule(int begin, int end)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001289{
Bart De Schuymercc440052002-11-06 21:10:33 +00001290 int j, lentmp = 0, nr_deletes;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001291 unsigned short *cnt;
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001292 struct ebt_u_entry **u_e, *u_e2;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001293 struct ebt_u_entries *entries = to_chain(), *entries2;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001294
Bart De Schuymerc3b97f52003-04-17 17:03:49 +00001295 if (begin < 0) {
1296 if (begin < entries->nentries)
1297 goto rule_error;
1298 begin += entries->nentries + 1;
1299 }
1300 if (end < 0)
1301 end += entries->nentries + 1;
1302 if (begin > end)
1303rule_error:
1304 print_error("Sorry, wrong rule numbers");
Bart De Schuymercc440052002-11-06 21:10:33 +00001305 if ((begin = check_rule_exists(begin)) == -1 ||
1306 (end = check_rule_exists(end)) == -1)
Bart De Schuymer60332e02002-06-23 08:01:47 +00001307 print_error("Sorry, rule does not exist");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001308
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001309 /*
1310 * we're deleting rules
1311 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001312 replace.num_counters = replace.nentries;
Bart De Schuymercc440052002-11-06 21:10:33 +00001313 nr_deletes = end - begin + 1;
1314 replace.nentries -= nr_deletes;
1315 entries->nentries -= nr_deletes;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001316
1317 if (replace.nentries) {
1318 for (j = 0; j < replace.selected_hook; j++) {
Bart De Schuymer60332e02002-06-23 08:01:47 +00001319 if (j < NF_BR_NUMHOOKS &&
1320 !(replace.valid_hooks & (1 << j)))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001321 continue;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001322 entries2 = nr_to_chain(j);
1323 lentmp += entries2->nentries;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001324 }
Bart De Schuymercc440052002-11-06 21:10:33 +00001325 lentmp += begin;
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001326 /*
1327 * +1 for CNT_END
1328 */
Bart De Schuymered053432002-07-21 19:35:39 +00001329 if ( !(replace.counterchanges = (unsigned short *)malloc(
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001330 (replace.num_counters + 1) * sizeof(unsigned short))) )
1331 print_memory();
Bart De Schuymered053432002-07-21 19:35:39 +00001332 cnt = replace.counterchanges;
Bart De Schuymercc440052002-11-06 21:10:33 +00001333 for (j = 0; j < lentmp; j++, cnt++)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001334 *cnt = CNT_NORM;
Bart De Schuymercc440052002-11-06 21:10:33 +00001335 for (j = 0; j < nr_deletes; j++, cnt++)
1336 *cnt = CNT_DEL;
1337
1338 for (j = 0; j < replace.num_counters - lentmp - nr_deletes;
1339 j++, cnt++)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001340 *cnt = CNT_NORM;
Bart De Schuymercc440052002-11-06 21:10:33 +00001341
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001342 *cnt = CNT_END;
1343 }
1344 else
1345 replace.num_counters = 0;
1346
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001347 /*
1348 * go to the right position in the chain
1349 */
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001350 u_e = &entries->entries;
Bart De Schuymercc440052002-11-06 21:10:33 +00001351 for (j = 0; j < begin; j++)
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001352 u_e = &(*u_e)->next;
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001353 /*
1354 * remove the rules
1355 */
Bart De Schuymercc440052002-11-06 21:10:33 +00001356 j = nr_deletes;
1357 while(j--) {
1358 u_e2 = *u_e;
1359 *u_e = (*u_e)->next;
Bart De Schuymer9895a8e2003-01-11 10:14:24 +00001360 /* free everything */
Bart De Schuymercc440052002-11-06 21:10:33 +00001361 free_u_entry(u_e2);
1362 free(u_e2);
1363 }
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001364
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001365 /*
1366 * update the counter_offset of chains behind this one
1367 */
Bart De Schuymercc440052002-11-06 21:10:33 +00001368 j = replace.selected_hook;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001369 while (1) {
Bart De Schuymercc440052002-11-06 21:10:33 +00001370 j++;
1371 entries = nr_to_chain(j);
Bart De Schuymer60332e02002-06-23 08:01:47 +00001372 if (!entries) {
Bart De Schuymercc440052002-11-06 21:10:33 +00001373 if (j < NF_BR_NUMHOOKS)
Bart De Schuymer60332e02002-06-23 08:01:47 +00001374 continue;
1375 else
1376 break;
Bart De Schuymercc440052002-11-06 21:10:33 +00001377 } else
1378 entries->counter_offset -= nr_deletes;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001379 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001380}
1381
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001382/*
1383 * execute command Z
1384 */
Bart De Schuymer62423742002-07-14 19:06:20 +00001385static void zero_counters(int zerochain)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001386{
1387
1388 if (zerochain == -1) {
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001389 /*
1390 * tell main() we don't update the counters
1391 * this results in tricking the kernel to zero its counters,
1392 * naively expecting userspace to update its counters. Muahahaha
1393 */
Bart De Schuymered053432002-07-21 19:35:39 +00001394 replace.counterchanges = NULL;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001395 replace.num_counters = 0;
1396 } else {
1397 int i, j;
1398 unsigned short *cnt;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001399 struct ebt_u_entries *entries = nr_to_chain(zerochain), *e2;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001400
Bart De Schuymer60332e02002-06-23 08:01:47 +00001401 if (entries->nentries == 0)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001402 exit(0);
Bart De Schuymered053432002-07-21 19:35:39 +00001403 replace.counterchanges = (unsigned short *)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001404 malloc((replace.nentries + 1) * sizeof(unsigned short));
Bart De Schuymered053432002-07-21 19:35:39 +00001405 if (!replace.counterchanges)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001406 print_memory();
Bart De Schuymered053432002-07-21 19:35:39 +00001407 cnt = replace.counterchanges;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001408 for (i = 0; i < zerochain; i++) {
Bart De Schuymer60332e02002-06-23 08:01:47 +00001409 if (i < NF_BR_NUMHOOKS &&
1410 !(replace.valid_hooks & (1 << i)))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001411 continue;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001412 e2 = nr_to_chain(i);
1413 for (j = 0; j < e2->nentries; j++) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001414 *cnt = CNT_NORM;
1415 cnt++;
1416 }
1417 }
Bart De Schuymer60332e02002-06-23 08:01:47 +00001418 for (i = 0; i < entries->nentries; i++) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001419 *cnt = CNT_ZERO;
1420 cnt++;
1421 }
Bart De Schuymered053432002-07-21 19:35:39 +00001422 while (cnt != replace.counterchanges + replace.nentries) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001423 *cnt = CNT_NORM;
1424 cnt++;
1425 }
1426 *cnt = CNT_END;
1427 }
1428}
1429
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001430/*
1431 * Checks the type for validity and calls getethertypebynumber()
1432 */
1433struct ethertypeent *parseethertypebynumber(int type)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001434{
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001435 if (type < 1536)
1436 print_error("Ethernet protocols have values >= 0x0600");
1437 if (type > 0xffff)
1438 print_error("Ethernet protocols have values <= 0xffff");
1439 return getethertypebynumber(type);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001440}
1441
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001442/*
1443 * put the mac address into 6 (ETH_ALEN) bytes
1444 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001445int getmac_and_mask(char *from, char *to, char *mask)
1446{
1447 char *p;
1448 int i;
Bart De Schuymer41830412002-06-05 19:41:28 +00001449 struct ether_addr *addr;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001450
1451 if (strcasecmp(from, "Unicast") == 0) {
1452 memcpy(to, mac_type_unicast, ETH_ALEN);
1453 memcpy(mask, msk_type_unicast, ETH_ALEN);
1454 return 0;
1455 }
1456 if (strcasecmp(from, "Multicast") == 0) {
1457 memcpy(to, mac_type_multicast, ETH_ALEN);
1458 memcpy(mask, msk_type_multicast, ETH_ALEN);
1459 return 0;
1460 }
1461 if (strcasecmp(from, "Broadcast") == 0) {
1462 memcpy(to, mac_type_broadcast, ETH_ALEN);
1463 memcpy(mask, msk_type_broadcast, ETH_ALEN);
1464 return 0;
1465 }
1466 if ( (p = strrchr(from, '/')) != NULL) {
1467 *p = '\0';
Bart De Schuymer41830412002-06-05 19:41:28 +00001468 if (!(addr = ether_aton(p + 1)))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001469 return -1;
Bart De Schuymer41830412002-06-05 19:41:28 +00001470 memcpy(mask, addr, ETH_ALEN);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001471 } else
1472 memset(mask, 0xff, ETH_ALEN);
Bart De Schuymer41830412002-06-05 19:41:28 +00001473 if (!(addr = ether_aton(from)))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001474 return -1;
Bart De Schuymer41830412002-06-05 19:41:28 +00001475 memcpy(to, addr, ETH_ALEN);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001476 for (i = 0; i < ETH_ALEN; i++)
1477 to[i] &= mask[i];
1478 return 0;
1479}
1480
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001481/*
1482 * executes the final_check() function for all extensions used by the rule
1483 */
Bart De Schuymer62423742002-07-14 19:06:20 +00001484static void do_final_checks(struct ebt_u_entry *e, struct ebt_u_entries *entries)
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +00001485{
1486 struct ebt_u_match_list *m_l;
1487 struct ebt_u_watcher_list *w_l;
1488 struct ebt_u_target *t;
1489 struct ebt_u_match *m;
1490 struct ebt_u_watcher *w;
1491
1492 m_l = e->m_list;
1493 w_l = e->w_list;
1494 while (m_l) {
1495 m = find_match(m_l->m->u.name);
1496 m->final_check(e, m_l->m, replace.name,
1497 entries->hook_mask, 1);
1498 m_l = m_l->next;
1499 }
1500 while (w_l) {
1501 w = find_watcher(w_l->w->u.name);
1502 w->final_check(e, w_l->w, replace.name,
1503 entries->hook_mask, 1);
1504 w_l = w_l->next;
1505 }
1506 t = find_target(e->t->u.name);
1507 t->final_check(e, e->t, replace.name,
1508 entries->hook_mask, 1);
1509}
1510
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001511/*
1512 * used for the -X command
1513 */
Bart De Schuymer62423742002-07-14 19:06:20 +00001514static void check_for_references(int chain_nr)
Bart De Schuymerb909f9b2002-06-26 18:35:31 +00001515{
1516 int i = -1, j;
1517 struct ebt_u_entries *entries;
1518 struct ebt_u_entry *e;
1519
1520 while (1) {
1521 i++;
1522 entries = nr_to_chain(i);
1523 if (!entries) {
1524 if (i < NF_BR_NUMHOOKS)
1525 continue;
1526 else
1527 break;
1528 }
1529 e = entries->entries;
1530 j = 0;
1531 while (e) {
Bart De Schuymerc27432e2003-01-09 22:01:07 +00001532 int chain_jmp;
1533
Bart De Schuymerb909f9b2002-06-26 18:35:31 +00001534 j++;
1535 if (strcmp(e->t->u.name, EBT_STANDARD_TARGET)) {
1536 e = e->next;
1537 continue;
1538 }
Bart De Schuymerc27432e2003-01-09 22:01:07 +00001539 chain_jmp = ((struct ebt_standard_target *)e->t)->verdict;
1540 if (chain_jmp == chain_nr)
Bart De Schuymerb909f9b2002-06-26 18:35:31 +00001541 print_error("Can't delete the chain, it's referenced "
1542 "in chain %s, rule %d", entries->name, j);
Bart De Schuymerc27432e2003-01-09 22:01:07 +00001543 /* adjust the chain jumps when necessary */
1544 if (chain_jmp > chain_nr)
1545 ((struct ebt_standard_target *)e->t)->verdict--;
Bart De Schuymerb909f9b2002-06-26 18:35:31 +00001546 e = e->next;
1547 }
1548 }
1549}
1550
Bart De Schuymercc440052002-11-06 21:10:33 +00001551static int parse_delete_rule(const char *argv, int *rule_nr, int *rule_nr_end)
1552{
1553 char *colon = strchr(argv, ':'), *buffer;
1554
1555 if (colon) {
1556 *colon = '\0';
1557 if (*(colon + 1) == '\0')
Bart De Schuymerc3b97f52003-04-17 17:03:49 +00001558 *rule_nr_end = -1; /* until the last rule */
Bart De Schuymercc440052002-11-06 21:10:33 +00001559 else {
1560 *rule_nr_end = strtol(colon + 1, &buffer, 10);
Bart De Schuymerc3b97f52003-04-17 17:03:49 +00001561 if (*buffer != '\0' || *rule_nr_end == 0)
Bart De Schuymercc440052002-11-06 21:10:33 +00001562 return -1;
1563 }
1564 }
1565 if (colon == argv)
Bart De Schuymerc3b97f52003-04-17 17:03:49 +00001566 *rule_nr = 1; /* beginning with the first rule */
Bart De Schuymercc440052002-11-06 21:10:33 +00001567 else {
1568 *rule_nr = strtol(argv, &buffer, 10);
Bart De Schuymerc3b97f52003-04-17 17:03:49 +00001569 if (*buffer != '\0' || *rule_nr == 0)
Bart De Schuymercc440052002-11-06 21:10:33 +00001570 return -1;
1571 }
1572 if (!colon)
1573 *rule_nr_end = *rule_nr;
Bart De Schuymercc440052002-11-06 21:10:33 +00001574 return 0;
1575}
1576
Bart De Schuymera615b962002-11-03 14:54:09 +00001577static int invert = 0;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001578int check_inverse(const char option[])
1579{
1580 if (strcmp(option, "!") == 0) {
Bart De Schuymera615b962002-11-03 14:54:09 +00001581 if (invert == 1)
1582 print_error("double use of '!' not allowed");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001583 optind++;
Bart De Schuymera615b962002-11-03 14:54:09 +00001584 invert = 1;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001585 return 1;
1586 }
Bart De Schuymera615b962002-11-03 14:54:09 +00001587 return invert;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001588}
1589
1590void check_option(unsigned int *flags, unsigned int mask)
1591{
1592 if (*flags & mask)
1593 print_error("Multiple use of same option not allowed");
1594 *flags |= mask;
1595}
1596
Bart De Schuymer0cb01792003-05-04 16:52:04 +00001597static void get_kernel_table()
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001598{
1599 if ( !(table = find_table(replace.name)) )
1600 print_error("Bad table name");
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001601 /*
1602 * get the kernel's information
1603 */
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001604 if (get_table(&replace)) {
Bart De Schuymer0cb01792003-05-04 16:52:04 +00001605 ebtables_insmod("ebtables");
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001606 if (get_table(&replace))
1607 print_error("The kernel doesn't support the ebtables "
1608 "%s table", replace.name);
1609 }
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001610 /*
Bart De Schuymer5885b362002-12-03 20:51:36 +00001611 * when listing a table contained in a file, we don't demand that
1612 * the user knows the table's name
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001613 */
Bart De Schuymer62a7fdb2002-08-24 21:01:21 +00001614 if ( !(table = find_table(replace.name)) )
1615 print_error("Bad table name");
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001616}
1617
Bart De Schuymerc5075142002-08-18 14:21:19 +00001618#define print_if_l_error print_error("Interface name length must be less " \
1619 "than %d", IFNAMSIZ)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001620#define OPT_COMMAND 0x01
1621#define OPT_TABLE 0x02
1622#define OPT_IN 0x04
1623#define OPT_OUT 0x08
1624#define OPT_JUMP 0x10
1625#define OPT_PROTOCOL 0x20
1626#define OPT_SOURCE 0x40
1627#define OPT_DEST 0x80
1628#define OPT_ZERO 0x100
1629#define OPT_LOGICALIN 0x200
1630#define OPT_LOGICALOUT 0x400
Bart De Schuymer5885b362002-12-03 20:51:36 +00001631/* the main thing */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001632int main(int argc, char *argv[])
1633{
Bart De Schuymer923a5732002-08-11 12:01:33 +00001634 char *buffer;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001635 int c, i;
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001636 /*
1637 * this special one for the -Z option (we can have -Z <this> -L <that>)
1638 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001639 int zerochain = -1;
Bart De Schuymerf8f8f292002-06-25 15:43:57 +00001640 int policy = 0;
Bart De Schuymerc3b97f52003-04-17 17:03:49 +00001641 int rule_nr = 0; /* used for -[D,I] */
1642 int rule_nr_end = 0; /* used for -I */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001643 struct ebt_u_target *t;
1644 struct ebt_u_match *m;
1645 struct ebt_u_watcher *w;
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001646 struct ebt_u_match_list *m_l;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001647 struct ebt_u_watcher_list *w_l;
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001648 struct ebt_u_entries *entries;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001649
Bart De Schuymera615b962002-11-03 14:54:09 +00001650 opterr = 0;
1651
Bart De Schuymer5885b362002-12-03 20:51:36 +00001652 replace.filename = getenv(ATOMIC_ENV_VARIABLE);
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001653 /*
1654 * initialize the table name, OPT_ flags, selected hook and command
1655 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001656 strcpy(replace.name, "filter");
1657 replace.flags = 0;
1658 replace.selected_hook = -1;
1659 replace.command = 'h';
Bart De Schuymered053432002-07-21 19:35:39 +00001660 replace.counterchanges = NULL;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001661
1662 new_entry = (struct ebt_u_entry *)malloc(sizeof(struct ebt_u_entry));
1663 if (!new_entry)
1664 print_memory();
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001665 /*
1666 * put some sane values in our new entry
1667 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001668 initialize_entry(new_entry);
1669
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001670 /*
1671 * The scenario induced by this loop makes that:
1672 * '-t' ,'-M' and --atomic (if specified) have to come
1673 * before '-A' and the like
1674 */
Bart De Schuymer60332e02002-06-23 08:01:47 +00001675
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001676 /*
1677 * getopt saves the day
1678 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001679 while ((c = getopt_long(argc, argv,
Bart De Schuymeraac31142002-08-11 11:57:52 +00001680 "-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 +00001681 switch (c) {
1682
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001683 case 'A': /* add a rule */
1684 case 'D': /* delete a rule */
1685 case 'P': /* define policy */
1686 case 'I': /* insert a rule */
1687 case 'N': /* make a user defined chain */
1688 case 'E': /* rename chain */
1689 case 'X': /* delete chain */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001690 replace.command = c;
1691 if (replace.flags & OPT_COMMAND)
1692 print_error("Multiple commands not allowed");
1693 replace.flags |= OPT_COMMAND;
Bart De Schuymer0cb01792003-05-04 16:52:04 +00001694 get_kernel_table();
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001695 if (optarg[0] == '-' || !strcmp(optarg, "!"))
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001696 print_error("No chain name specified");
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001697 if (c == 'N') {
1698 struct ebt_u_chain_list *cl, **cl2;
1699
1700 if (get_hooknr(optarg) != -1)
1701 print_error("Chain %s already exists",
1702 optarg);
1703 if (find_target(optarg))
1704 print_error("Target with name %s exists"
1705 , optarg);
1706 if (strlen(optarg) >= EBT_CHAIN_MAXNAMELEN)
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001707 print_error("Chain name length can't exceed %d",
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001708 EBT_CHAIN_MAXNAMELEN - 1);
1709 cl = (struct ebt_u_chain_list *)
1710 malloc(sizeof(struct ebt_u_chain_list));
1711 if (!cl)
1712 print_memory();
1713 cl->next = NULL;
1714 cl->udc = (struct ebt_u_entries *)
1715 malloc(sizeof(struct ebt_u_entries));
1716 if (!cl->udc)
1717 print_memory();
1718 cl->udc->nentries = 0;
1719 cl->udc->policy = EBT_ACCEPT;
1720 cl->udc->counter_offset = replace.nentries;
1721 cl->udc->hook_mask = 0;
1722 strcpy(cl->udc->name, optarg);
1723 cl->udc->entries = NULL;
1724 cl->kernel_start = NULL;
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001725 /*
1726 * put the new chain at the end
1727 */
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001728 cl2 = &replace.udc;
1729 while (*cl2)
1730 cl2 = &((*cl2)->next);
1731 *cl2 = cl;
1732 break;
1733 }
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001734 if ((replace.selected_hook = get_hooknr(optarg)) == -1)
1735 print_error("Chain %s doesn't exist", optarg);
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001736 if (c == 'E') {
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001737 if (optind >= argc || argv[optind][0] == '-' ||
1738 !strcmp(argv[optind], "!"))
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001739 print_error("No new chain name specified");
1740 if (strlen(argv[optind]) >= EBT_CHAIN_MAXNAMELEN)
1741 print_error("Chain name len can't exceed %d",
1742 EBT_CHAIN_MAXNAMELEN - 1);
1743 if (get_hooknr(argv[optind]) != -1)
1744 print_error("Chain %s already exists",
1745 argv[optind]);
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001746 if (find_target(argv[optind]))
1747 print_error("Target with name %s exists"
1748 , argv[optind]);
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001749 entries = to_chain();
1750 strcpy(entries->name, argv[optind]);
1751 optind++;
1752 break;
1753 }
1754 if (c == 'X') {
1755 struct ebt_u_chain_list *cl, **cl2;
1756
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001757 if (replace.selected_hook < NF_BR_NUMHOOKS)
1758 print_error("You can't remove a standard chain");
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001759 /*
Bart De Schuymerc27432e2003-01-09 22:01:07 +00001760 * if the chain is referenced, don't delete it,
1761 * also decrement jumps to a chain behind the
1762 * one we're deleting
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001763 */
Bart De Schuymerb909f9b2002-06-26 18:35:31 +00001764 check_for_references(replace.selected_hook - NF_BR_NUMHOOKS);
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001765 flush_chains();
1766 entries = to_chain();
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001767 cl2 = &(replace.udc);
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001768 while ((*cl2)->udc != entries)
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001769 cl2 = &((*cl2)->next);
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001770 cl = (*cl2);
1771 (*cl2) = (*cl2)->next;
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001772 free(cl->udc);
1773 free(cl);
1774 break;
1775 }
1776
Bart De Schuymercc440052002-11-06 21:10:33 +00001777 if (c == 'D' && optind < argc &&
Bart De Schuymerc3b97f52003-04-17 17:03:49 +00001778 (argv[optind][0] != '-' ||
1779 (argv[optind][1] >= '0' && argv[optind][1] <= '9'))) {
Bart De Schuymercc440052002-11-06 21:10:33 +00001780 if (parse_delete_rule(argv[optind],
1781 &rule_nr, &rule_nr_end))
1782 print_error("Problem with the "
1783 "specified rule number(s)");
1784 optind++;
1785 }
1786 if (c == 'I') {
Bart De Schuymerc3b97f52003-04-17 17:03:49 +00001787 if (optind >= argc || (argv[optind][0] == '-' &&
1788 (argv[optind][1] < '0' || argv[optind][1] > '9')))
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001789 print_error("No rulenr for -I"
1790 " specified");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001791 rule_nr = strtol(argv[optind], &buffer, 10);
Bart De Schuymerc3b97f52003-04-17 17:03:49 +00001792 if (*buffer != '\0')
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001793 print_error("Problem with the "
1794 "specified rule number");
1795 optind++;
1796 }
1797 if (c == 'P') {
1798 if (optind >= argc)
1799 print_error("No policy specified");
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001800 policy = 0;
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001801 for (i = 0; i < NUM_STANDARD_TARGETS; i++)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001802 if (!strcmp(argv[optind],
1803 standard_targets[i])) {
Bart De Schuymer60332e02002-06-23 08:01:47 +00001804 policy = -i -1;
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001805 if (policy == EBT_CONTINUE)
1806 policy = 0;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001807 break;
1808 }
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001809 if (policy == 0)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001810 print_error("Wrong policy");
1811 optind++;
1812 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001813 break;
1814
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001815 case 'L': /* list */
1816 case 'F': /* flush */
1817 case 'Z': /* zero counters */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001818 if (c == 'Z') {
1819 if (replace.flags & OPT_ZERO)
1820 print_error("Multiple commands"
1821 " not allowed");
1822 if ( (replace.flags & OPT_COMMAND &&
1823 replace.command != 'L'))
1824 print_error("command -Z only allowed "
1825 "together with command -L");
1826 replace.flags |= OPT_ZERO;
1827 } else {
1828 replace.command = c;
1829 if (replace.flags & OPT_COMMAND)
1830 print_error("Multiple commands"
1831 " not allowed");
1832 replace.flags |= OPT_COMMAND;
1833 }
Bart De Schuymer0cb01792003-05-04 16:52:04 +00001834 get_kernel_table();
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001835 i = -1;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001836 if (optarg) {
1837 if ( (i = get_hooknr(optarg)) == -1 )
1838 print_error("Bad chain");
1839 } else
1840 if (optind < argc && argv[optind][0] != '-') {
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001841 if ((i = get_hooknr(argv[optind])) == -1)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001842 print_error("Bad chain");
1843 optind++;
1844 }
1845 if (i != -1) {
1846 if (c == 'Z')
1847 zerochain = i;
1848 else
1849 replace.selected_hook = i;
1850 }
1851 break;
1852
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001853 case 'V': /* version */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001854 replace.command = 'V';
1855 if (replace.flags & OPT_COMMAND)
1856 print_error("Multiple commands not allowed");
Bart De Schuymer57a3f6a2003-04-01 16:59:33 +00001857 PRINT_VERSION;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001858 exit(0);
1859
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001860 case 'M': /* modprobe */
Bart De Schuymer60332e02002-06-23 08:01:47 +00001861 if (replace.command != 'h')
1862 print_error("Please put the -M option earlier");
Bart De Schuymerc8531032002-06-14 21:55:29 +00001863 modprobe = optarg;
1864 break;
1865
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001866 case 'h': /* help */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001867 if (replace.flags & OPT_COMMAND)
1868 print_error("Multiple commands not allowed");
1869 replace.command = 'h';
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001870 /*
1871 * All other arguments should be extension names
1872 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001873 while (optind < argc) {
1874 struct ebt_u_match *m;
1875 struct ebt_u_watcher *w;
1876
Bart De Schuymer9a0fbf22003-01-11 16:16:54 +00001877 if (!strcasecmp("list_extensions",
1878 argv[optind]))
1879 list_extensions();
1880
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001881 if ((m = find_match(argv[optind])))
1882 add_match(m);
1883 else if ((w = find_watcher(argv[optind])))
1884 add_watcher(w);
1885 else {
1886 if (!(t = find_target(argv[optind])))
1887 print_error("Extension %s "
1888 "not found", argv[optind]);
1889 if (replace.flags & OPT_JUMP)
1890 print_error("Sorry, you can "
1891 "only see help for one "
1892 "target extension each time");
1893 replace.flags |= OPT_JUMP;
1894 new_entry->t =
1895 (struct ebt_entry_target *)t;
1896 }
1897 optind++;
1898 }
1899 break;
1900
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001901 case 't': /* table */
Bart De Schuymer60332e02002-06-23 08:01:47 +00001902 if (replace.command != 'h')
1903 print_error("Please put the -t option first");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001904 check_option(&replace.flags, OPT_TABLE);
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001905 if (strlen(optarg) > EBT_TABLE_MAXNAMELEN - 1)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001906 print_error("Table name too long");
1907 strcpy(replace.name, optarg);
1908 break;
1909
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001910 case 'i': /* input interface */
1911 case 2 : /* logical input interface */
1912 case 'o': /* output interface */
1913 case 3 : /* logical output interface */
1914 case 'j': /* target */
1915 case 'p': /* net family protocol */
1916 case 's': /* source mac */
1917 case 'd': /* destination mac */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001918 if ((replace.flags & OPT_COMMAND) == 0)
1919 print_error("No command specified");
1920 if ( replace.command != 'A' &&
1921 replace.command != 'D' && replace.command != 'I')
1922 print_error("Command and option do not match");
1923 if (c == 'i') {
1924 check_option(&replace.flags, OPT_IN);
1925 if (replace.selected_hook > 2 &&
1926 replace.selected_hook < NF_BR_BROUTING)
1927 print_error("Use in-interface only in "
1928 "INPUT, FORWARD, PREROUTING and"
1929 "BROUTING chains");
1930 if (check_inverse(optarg))
1931 new_entry->invflags |= EBT_IIN;
1932
1933 if (optind > argc)
1934 print_error("No in-interface "
1935 "specified");
1936 if (strlen(argv[optind - 1]) >= IFNAMSIZ)
Bart De Schuymerc5075142002-08-18 14:21:19 +00001937 print_if_l_error;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001938 strcpy(new_entry->in, argv[optind - 1]);
1939 break;
1940 }
1941 if (c == 2) {
1942 check_option(&replace.flags, OPT_LOGICALIN);
1943 if (replace.selected_hook > 2 &&
1944 replace.selected_hook < NF_BR_BROUTING)
1945 print_error("Use logical in-interface "
1946 "only in INPUT, FORWARD, "
1947 "PREROUTING and BROUTING chains");
1948 if (check_inverse(optarg))
1949 new_entry->invflags |= EBT_ILOGICALIN;
1950
1951 if (optind > argc)
1952 print_error("No logical in-interface "
1953 "specified");
1954 if (strlen(argv[optind - 1]) >= IFNAMSIZ)
Bart De Schuymerc5075142002-08-18 14:21:19 +00001955 print_if_l_error;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001956 strcpy(new_entry->logical_in, argv[optind - 1]);
1957 break;
1958 }
1959 if (c == 'o') {
1960 check_option(&replace.flags, OPT_OUT);
1961 if (replace.selected_hook < 2)
1962 print_error("Use out-interface only"
1963 " in OUTPUT, FORWARD and "
1964 "POSTROUTING chains");
1965 if (check_inverse(optarg))
1966 new_entry->invflags |= EBT_IOUT;
1967
1968 if (optind > argc)
1969 print_error("No out-interface "
1970 "specified");
1971
1972 if (strlen(argv[optind - 1]) >= IFNAMSIZ)
Bart De Schuymerc5075142002-08-18 14:21:19 +00001973 print_if_l_error;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001974 strcpy(new_entry->out, argv[optind - 1]);
1975 break;
1976 }
1977 if (c == 3) {
1978 check_option(&replace.flags, OPT_LOGICALOUT);
1979 if (replace.selected_hook < 2)
1980 print_error("Use logical out-interface "
1981 "only in OUTPUT, FORWARD and "
1982 "POSTROUTING chains");
1983 if (check_inverse(optarg))
1984 new_entry->invflags |= EBT_ILOGICALOUT;
1985
1986 if (optind > argc)
1987 print_error("No logical out-interface "
1988 "specified");
1989
1990 if (strlen(argv[optind - 1]) >= IFNAMSIZ)
Bart De Schuymerc5075142002-08-18 14:21:19 +00001991 print_if_l_error;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001992 strcpy(new_entry->logical_out,
1993 argv[optind - 1]);
1994 break;
1995 }
1996 if (c == 'j') {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001997 check_option(&replace.flags, OPT_JUMP);
1998 for (i = 0; i < NUM_STANDARD_TARGETS; i++)
1999 if (!strcmp(optarg,
2000 standard_targets[i])) {
2001 t = find_target(
2002 EBT_STANDARD_TARGET);
2003 ((struct ebt_standard_target *)
Bart De Schuymer60332e02002-06-23 08:01:47 +00002004 t->t)->verdict = -i - 1;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002005 break;
2006 }
Bart De Schuymer60332e02002-06-23 08:01:47 +00002007 if (-i - 1 == EBT_RETURN) {
2008 if (replace.selected_hook < NF_BR_NUMHOOKS)
2009 print_error("Return target"
2010 " only for user defined chains");
2011 }
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +00002012 if (i != NUM_STANDARD_TARGETS)
2013 break;
Bart De Schuymer1ab41562002-06-23 17:09:54 +00002014 if ((i = get_hooknr(optarg)) != -1) {
2015 if (i < NF_BR_NUMHOOKS)
2016 print_error("don't jump"
2017 " to a standard chain");
2018 t = find_target(
2019 EBT_STANDARD_TARGET);
2020 ((struct ebt_standard_target *)
2021 t->t)->verdict = i - NF_BR_NUMHOOKS;
2022 break;
2023 }
2024 else {
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002025 /*
2026 * must be an extension then
2027 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002028 struct ebt_u_target *t;
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00002029
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002030 t = find_target(optarg);
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002031 /*
2032 * -j standard not allowed either
2033 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002034 if (!t || t ==
2035 (struct ebt_u_target *)new_entry->t)
2036 print_error("Illegal target "
2037 "name");
2038 new_entry->t =
2039 (struct ebt_entry_target *)t;
2040 }
2041 break;
2042 }
2043 if (c == 's') {
2044 check_option(&replace.flags, OPT_SOURCE);
2045 if (check_inverse(optarg))
2046 new_entry->invflags |= EBT_ISOURCE;
2047
2048 if (optind > argc)
2049 print_error("No source mac "
2050 "specified");
2051 if (getmac_and_mask(argv[optind - 1],
2052 new_entry->sourcemac, new_entry->sourcemsk))
2053 print_error("Problem with specified "
2054 "source mac");
2055 new_entry->bitmask |= EBT_SOURCEMAC;
2056 break;
2057 }
2058 if (c == 'd') {
2059 check_option(&replace.flags, OPT_DEST);
2060 if (check_inverse(optarg))
2061 new_entry->invflags |= EBT_IDEST;
2062
2063 if (optind > argc)
2064 print_error("No destination mac "
2065 "specified");
2066 if (getmac_and_mask(argv[optind - 1],
2067 new_entry->destmac, new_entry->destmsk))
2068 print_error("Problem with specified "
2069 "destination mac");
2070 new_entry->bitmask |= EBT_DESTMAC;
2071 break;
2072 }
2073 check_option(&replace.flags, OPT_PROTOCOL);
2074 if (check_inverse(optarg))
2075 new_entry->invflags |= EBT_IPROTO;
2076
2077 if (optind > argc)
2078 print_error("No protocol specified");
2079 new_entry->bitmask &= ~((unsigned int)EBT_NOPROTO);
2080 i = strtol(argv[optind - 1], &buffer, 16);
2081 if (*buffer == '\0' && (i < 0 || i > 0xFFFF))
2082 print_error("Problem with the specified "
2083 "protocol");
2084 new_entry->ethproto = i;
Bart De Schuymer28bf6f62002-06-26 18:57:24 +00002085 if (*buffer != '\0') {
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002086 struct ethertypeent *ent;
2087
2088 if (!strcasecmp(argv[optind - 1], "LENGTH")) {
2089 new_entry->bitmask |= EBT_802_3;
2090 break;
2091 }
2092 ent = getethertypebyname(argv[optind - 1]);
2093 if (!ent)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002094 print_error("Problem with the specified"
2095 " protocol");
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002096 new_entry->ethproto = ent->e_ethertype;
Bart De Schuymer28bf6f62002-06-26 18:57:24 +00002097 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002098 if (new_entry->ethproto < 1536 &&
2099 !(new_entry->bitmask & EBT_802_3))
2100 print_error("Sorry, protocols have values above"
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00002101 " or equal to 0x0600");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002102 break;
2103
Bart De Schuymer9895a8e2003-01-11 10:14:24 +00002104 case 4 : /* Lc */
Bart De Schuymer9af14f92002-07-10 20:49:10 +00002105 check_option(&replace.flags, LIST_C);
Bart De Schuymer9af14f92002-07-10 20:49:10 +00002106 if (replace.command != 'L')
2107 print_error("Use --Lc with -L");
2108 if (replace.flags & LIST_X)
2109 print_error("--Lx not compatible with --Lc");
2110 replace.flags |= LIST_C;
2111 break;
Bart De Schuymer9895a8e2003-01-11 10:14:24 +00002112 case 5 : /* Ln */
Bart De Schuymer9af14f92002-07-10 20:49:10 +00002113 check_option(&replace.flags, LIST_N);
Bart De Schuymer9af14f92002-07-10 20:49:10 +00002114 if (replace.command != 'L')
2115 print_error("Use --Ln with -L");
2116 if (replace.flags & LIST_X)
2117 print_error("--Lx not compatible with --Ln");
2118 replace.flags |= LIST_N;
2119 break;
Bart De Schuymer9895a8e2003-01-11 10:14:24 +00002120 case 6 : /* Lx */
Bart De Schuymer9af14f92002-07-10 20:49:10 +00002121 check_option(&replace.flags, LIST_X);
Bart De Schuymer9af14f92002-07-10 20:49:10 +00002122 if (replace.command != 'L')
2123 print_error("Use --Lx with -L");
2124 if (replace.flags & LIST_C)
2125 print_error("--Lx not compatible with --Lc");
2126 if (replace.flags & LIST_N)
2127 print_error("--Lx not compatible with --Ln");
2128 replace.flags |= LIST_X;
2129 break;
Bart De Schuymer22d03a22003-05-03 20:28:22 +00002130 case 12 : /* Lmac2 */
2131 check_option(&replace.flags, LIST_MAC2);
2132 if (replace.command != 'L')
2133 print_error("Use --Lmac2 with -L");
2134 replace.flags |= LIST_MAC2;
2135 break;
Bart De Schuymer9895a8e2003-01-11 10:14:24 +00002136 case 8 : /* atomic-commit */
Bart De Schuymer62423742002-07-14 19:06:20 +00002137 replace.command = c;
2138 if (replace.flags & OPT_COMMAND)
2139 print_error("Multiple commands not allowed");
2140 replace.flags |= OPT_COMMAND;
Bart De Schuymer5885b362002-12-03 20:51:36 +00002141 if (!replace.filename)
2142 print_error("No atomic file specified");
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002143 /*
2144 * get the information from the file
2145 */
Bart De Schuymer62423742002-07-14 19:06:20 +00002146 get_table(&replace);
Bart De Schuymer868bf642002-07-16 18:14:20 +00002147 if (replace.nentries) {
Bart De Schuymered053432002-07-21 19:35:39 +00002148 replace.counterchanges = (unsigned short *)
Bart De Schuymer868bf642002-07-16 18:14:20 +00002149 malloc(sizeof(unsigned short) * (replace.nentries + 1));
2150 for (i = 0; i < replace.nentries; i++)
Bart De Schuymered053432002-07-21 19:35:39 +00002151 replace.counterchanges[i] = CNT_NORM;
2152 replace.counterchanges[i] = CNT_END;
Bart De Schuymer868bf642002-07-16 18:14:20 +00002153 }
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002154 /*
2155 * we don't want the kernel giving us its counters, they would
2156 * overwrite the counters extracted from the file
2157 */
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00002158 replace.num_counters = 0;
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002159 /*
2160 * make sure the table will be written to the kernel
Bart De Schuymer5885b362002-12-03 20:51:36 +00002161 * possible memory leak here
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002162 */
Bart De Schuymer62423742002-07-14 19:06:20 +00002163 replace.filename = NULL;
2164 break;
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002165 case 7 : /* atomic-init */
2166 case 10: /* atomic-save */
2167 case 11: /* init-table */
Bart De Schuymer62423742002-07-14 19:06:20 +00002168 replace.command = c;
2169 if (replace.flags & OPT_COMMAND)
2170 print_error("Multiple commands not allowed");
Bart De Schuymer5885b362002-12-03 20:51:36 +00002171 if (c != 11 && !replace.filename)
2172 print_error("No atomic file specified");
Bart De Schuymer62423742002-07-14 19:06:20 +00002173 replace.flags |= OPT_COMMAND;
Bart De Schuymer5885b362002-12-03 20:51:36 +00002174 {
2175 char *tmp = replace.filename;
2176
2177 tmp = replace.filename;
2178 /* get the kernel table */
2179 replace.filename = NULL;
Bart De Schuymer0cb01792003-05-04 16:52:04 +00002180 get_kernel_table();
Bart De Schuymer5885b362002-12-03 20:51:36 +00002181 replace.filename = tmp;
2182 }
Bart De Schuymera8d920b2002-07-16 18:30:44 +00002183 if (replace.nentries) {
Bart De Schuymered053432002-07-21 19:35:39 +00002184 replace.counterchanges = (unsigned short *)
Bart De Schuymer5f16dc72002-07-16 18:08:36 +00002185 malloc(sizeof(unsigned short) * (replace.nentries + 1));
2186 for (i = 0; i < replace.nentries; i++)
Bart De Schuymered053432002-07-21 19:35:39 +00002187 replace.counterchanges[i] = CNT_NORM;
2188 replace.counterchanges[i] = CNT_END;
Bart De Schuymer5f16dc72002-07-16 18:08:36 +00002189 }
Bart De Schuymer5885b362002-12-03 20:51:36 +00002190 break;
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002191 case 9 : /* atomic */
Bart De Schuymer5885b362002-12-03 20:51:36 +00002192 if (replace.flags & OPT_COMMAND)
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00002193 print_error("--atomic has to come before"
2194 " the command");
Bart De Schuymer5885b362002-12-03 20:51:36 +00002195 /* another possible memory leak here */
Bart De Schuymer62423742002-07-14 19:06:20 +00002196 replace.filename = (char *)malloc(strlen(optarg) + 1);
2197 strcpy(replace.filename, optarg);
2198 break;
Bart De Schuymera615b962002-11-03 14:54:09 +00002199 case 1 :
2200 if (!strcmp(optarg, "!"))
2201 check_inverse(optarg);
2202 else
2203 print_error("Bad argument : %s", optarg);
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002204 /*
2205 * check_inverse() did optind++
2206 */
Bart De Schuymera615b962002-11-03 14:54:09 +00002207 optind--;
2208 continue;
Bart De Schuymer9af14f92002-07-10 20:49:10 +00002209 default:
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002210 /*
2211 * is it a target option?
2212 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002213 t = (struct ebt_u_target *)new_entry->t;
2214 if ((t->parse(c - t->option_offset, argv, argc,
2215 new_entry, &t->flags, &t->t)))
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00002216 goto check_extension;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002217
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002218 /*
2219 * is it a match_option?
2220 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002221 for (m = matches; m; m = m->next)
2222 if (m->parse(c - m->option_offset, argv,
2223 argc, new_entry, &m->flags, &m->m))
2224 break;
2225
2226 if (m != NULL) {
2227 if (m->used == 0)
2228 add_match(m);
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00002229 goto check_extension;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002230 }
2231
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002232 /*
2233 * is it a watcher option?
2234 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002235 for (w = watchers; w; w = w->next)
2236 if (w->parse(c-w->option_offset, argv,
2237 argc, new_entry, &w->flags, &w->w))
2238 break;
2239
2240 if (w == NULL)
2241 print_error("Unknown argument");
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00002242 if (w->used == 0)
2243 add_watcher(w);
2244check_extension:
Bart De Schuymer60332e02002-06-23 08:01:47 +00002245 if (replace.command != 'A' && replace.command != 'I' &&
2246 replace.command != 'D')
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00002247 print_error("Extensions only for -A, -I and -D");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002248 }
Bart De Schuymera615b962002-11-03 14:54:09 +00002249 invert = 0;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002250 }
2251
Bart De Schuymer25c741d2002-06-23 18:54:34 +00002252 if ( !table && !(table = find_table(replace.name)) )
2253 print_error("Bad table name");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002254
2255 if ( (replace.flags & OPT_COMMAND) && replace.command != 'L' &&
2256 replace.flags & OPT_ZERO )
2257 print_error("Command -Z only allowed together with command -L");
2258
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002259 /*
2260 * do this after parsing everything, so we can print specific info
2261 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002262 if (replace.command == 'h' && !(replace.flags & OPT_ZERO))
2263 print_help();
2264
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002265 /*
2266 * do the final checks
2267 */
Bart De Schuymer60332e02002-06-23 08:01:47 +00002268 if (replace.command == 'A' || replace.command == 'I' ||
2269 replace.command == 'D') {
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002270 /*
2271 * this will put the hook_mask right for the chains
2272 */
Bart De Schuymer60332e02002-06-23 08:01:47 +00002273 check_for_loops();
2274 entries = to_chain();
2275 m_l = new_entry->m_list;
2276 w_l = new_entry->w_list;
2277 t = (struct ebt_u_target *)new_entry->t;
2278 while (m_l) {
2279 m = (struct ebt_u_match *)(m_l->m);
2280 m->final_check(new_entry, m->m, replace.name,
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +00002281 entries->hook_mask, 0);
Bart De Schuymer60332e02002-06-23 08:01:47 +00002282 m_l = m_l->next;
2283 }
2284 while (w_l) {
2285 w = (struct ebt_u_watcher *)(w_l->w);
2286 w->final_check(new_entry, w->w, replace.name,
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +00002287 entries->hook_mask, 0);
Bart De Schuymer60332e02002-06-23 08:01:47 +00002288 w_l = w_l->next;
2289 }
2290 t->final_check(new_entry, t->t, replace.name,
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +00002291 entries->hook_mask, 0);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002292 }
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002293 /*
2294 * so, the extensions can work with the host endian
2295 * the kernel does not have to do this ofcourse
2296 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002297 new_entry->ethproto = htons(new_entry->ethproto);
2298
Bart De Schuymerc34f4672002-08-18 18:03:52 +00002299 if (replace.command == 'P') {
2300 if (replace.selected_hook < NF_BR_NUMHOOKS &&
2301 policy == EBT_RETURN)
2302 print_error("Policy RETURN only allowed for user "
2303 "defined chains");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002304 change_policy(policy);
Bart De Schuymerc34f4672002-08-18 18:03:52 +00002305 } else if (replace.command == 'L') {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002306 list_rules();
2307 if (replace.flags & OPT_ZERO)
2308 zero_counters(zerochain);
2309 else
2310 exit(0);
2311 }
2312 if (replace.flags & OPT_ZERO)
2313 zero_counters(zerochain);
Bart De Schuymer1ab41562002-06-23 17:09:54 +00002314 else if (replace.command == 'F') {
2315 if (flush_chains() == -1)
2316 exit(0);
2317 } else if (replace.command == 'A' || replace.command == 'I') {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002318 add_rule(rule_nr);
Bart De Schuymer1ab41562002-06-23 17:09:54 +00002319 check_for_loops();
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002320 /*
2321 * do the final_check(), for all entries
2322 * needed when adding a rule that has a chain target
2323 */
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +00002324 i = -1;
2325 while (1) {
2326 struct ebt_u_entry *e;
2327
2328 i++;
2329 entries = nr_to_chain(i);
2330 if (!entries) {
2331 if (i < NF_BR_NUMHOOKS)
2332 continue;
2333 else
2334 break;
2335 }
2336 e = entries->entries;
2337 while (e) {
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002338 /*
2339 * userspace extensions use host endian
2340 */
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +00002341 e->ethproto = ntohs(e->ethproto);
2342 do_final_checks(e, entries);
2343 e->ethproto = htons(e->ethproto);
2344 e = e->next;
2345 }
2346 }
Bart De Schuymerc3b97f52003-04-17 17:03:49 +00002347 } else if (replace.command == 'D')
Bart De Schuymercc440052002-11-06 21:10:33 +00002348 delete_rule(rule_nr, rule_nr_end);
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002349 /*
2350 * commands -N, -E, -X, --atomic-commit, --atomic-commit, --atomic-save,
2351 * --init-table fall through
2352 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002353
2354 if (table->check)
2355 table->check(&replace);
2356
2357 deliver_table(&replace);
2358
Bart De Schuymered053432002-07-21 19:35:39 +00002359 if (replace.counterchanges)
2360 deliver_counters(&replace);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002361 return 0;
2362}