blob: 29bccfe232753d80debd6e278da39ee6d8f4c8e4 [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 Schuymerc7bfa272002-11-20 19:40:13 +0000371/*
372 * blatently stolen (again) from iptables.c userspace program
373 * find out where the modprobe utility is located
374 */
Bart De Schuymerc8531032002-06-14 21:55:29 +0000375static char *get_modprobe(void)
376{
377 int procfile;
378 char *ret;
379
380 procfile = open(PROC_SYS_MODPROBE, O_RDONLY);
381 if (procfile < 0)
382 return NULL;
383
384 ret = malloc(1024);
385 if (ret) {
386 switch (read(procfile, ret, 1024)) {
387 case -1: goto fail;
388 case 1024: goto fail; /* Partial read. Wierd */
389 }
390 if (ret[strlen(ret)-1]=='\n')
391 ret[strlen(ret)-1]=0;
392 close(procfile);
393 return ret;
394 }
395 fail:
396 free(ret);
397 close(procfile);
398 return NULL;
399}
400
Bart De Schuymerc8531032002-06-14 21:55:29 +0000401int ebtables_insmod(const char *modname, const char *modprobe)
402{
403 char *buf = NULL;
404 char *argv[3];
405
Bart De Schuymer9895a8e2003-01-11 10:14:24 +0000406 /* If they don't explicitly set it, read out of kernel */
Bart De Schuymerc8531032002-06-14 21:55:29 +0000407 if (!modprobe) {
408 buf = get_modprobe();
409 if (!buf)
410 return -1;
411 modprobe = buf;
412 }
413
414 switch (fork()) {
415 case 0:
416 argv[0] = (char *)modprobe;
417 argv[1] = (char *)modname;
418 argv[2] = NULL;
419 execv(argv[0], argv);
420
421 /* not usually reached */
422 exit(0);
423 case -1:
424 return -1;
425
426 default: /* parent */
427 wait(NULL);
428 }
429
430 free(buf);
431 return 0;
432}
433
Bart De Schuymer9a0fbf22003-01-11 16:16:54 +0000434static void list_extensions()
435{
436 struct ebt_u_table *tbl = tables;
437 struct ebt_u_target *t = targets;
438 struct ebt_u_match *m = matches;
439 struct ebt_u_watcher *w = watchers;
440
Bart De Schuymer57a3f6a2003-04-01 16:59:33 +0000441 PRINT_VERSION;
Bart De Schuymer9a0fbf22003-01-11 16:16:54 +0000442 printf("Supported userspace extensions:\n\nSupported tables:\n");
443 while(tbl) {
444 printf("%s\n", tbl->name);
445 tbl = tbl->next;
446 }
447 printf("\nSupported targets:\n");
448 while(t) {
449 printf("%s\n", t->name);
450 t = t->next;
451 }
452 printf("\nSupported matches:\n");
453 while(m) {
454 printf("%s\n", m->name);
455 m = m->next;
456 }
457 printf("\nSupported watchers:\n");
458 while(w) {
459 printf("%s\n", w->name);
460 w = w->next;
461 }
462 exit(0);
463}
464
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000465/*
466 * we use replace.flags, so we can't use the following values:
467 * 0x01 == OPT_COMMAND, 0x02 == OPT_TABLE, 0x100 == OPT_ZERO
468 */
Bart De Schuymer22d03a22003-05-03 20:28:22 +0000469#define LIST_N 0x04
470#define LIST_C 0x08
471#define LIST_X 0x10
472#define LIST_MAC2 0x20
473
474void print_mac(const char *mac)
475{
476 if (replace.flags & LIST_MAC2) {
477 int j;
478 for (j = 0; j < ETH_ALEN; j++)
479 printf("%02x%s", (unsigned char)mac[j],
480 (j==ETH_ALEN-1) ? "" : ":");
481 } else
482 printf("%s", ether_ntoa((struct ether_addr *) mac));
483}
484
485void print_mac_and_mask(const char *mac, const char *mask)
486{
487 char hlpmsk[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
488
489 print_mac(mac);
490 if (memcmp(mask, hlpmsk, 6)) {
491 printf("/");
492 print_mac(mask);
493 }
494}
495
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000496/*
497 * helper function for list_rules()
498 */
Bart De Schuymer60332e02002-06-23 08:01:47 +0000499static void list_em(struct ebt_u_entries *entries)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000500{
501 int i, j, space = 0, digits;
502 struct ebt_u_entry *hlp;
503 struct ebt_u_match_list *m_l;
504 struct ebt_u_watcher_list *w_l;
505 struct ebt_u_match *m;
506 struct ebt_u_watcher *w;
507 struct ebt_u_target *t;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000508
Bart De Schuymer60332e02002-06-23 08:01:47 +0000509 hlp = entries->entries;
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000510 if (replace.flags & LIST_X && entries->policy != EBT_ACCEPT) {
511 printf("ebtables -t %s -P %s %s\n", replace.name,
512 entries->name, standard_targets[-entries->policy - 1]);
513 } else if (!(replace.flags & LIST_X)) {
Bart De Schuymerc87c9642002-08-01 15:34:16 +0000514 printf("\nBridge chain: %s, entries: %d, policy: %s\n",
515 entries->name, entries->nentries,
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000516 standard_targets[-entries->policy - 1]);
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000517 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000518
Bart De Schuymer60332e02002-06-23 08:01:47 +0000519 i = entries->nentries;
Bart De Schuymerf8f8f292002-06-25 15:43:57 +0000520 while (i > 9) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000521 space++;
522 i /= 10;
523 }
524
Bart De Schuymer60332e02002-06-23 08:01:47 +0000525 for (i = 0; i < entries->nentries; i++) {
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000526 if (replace.flags & LIST_N) {
527 digits = 0;
Bart De Schuymer9895a8e2003-01-11 10:14:24 +0000528 /* A little work to get nice rule numbers. */
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000529 j = i + 1;
530 while (j > 9) {
531 digits++;
532 j /= 10;
533 }
534 for (j = 0; j < space - digits; j++)
535 printf(" ");
536 printf("%d. ", i + 1);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000537 }
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000538 if (replace.flags & LIST_X)
539 printf("ebtables -t %s -A %s ",
540 replace.name, entries->name);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000541
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000542 /*
543 * Don't print anything about the protocol if no protocol was
544 * specified, obviously this means any protocol will do.
545 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000546 if (!(hlp->bitmask & EBT_NOPROTO)) {
Bart De Schuymer60332e02002-06-23 08:01:47 +0000547 printf("-p ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000548 if (hlp->invflags & EBT_IPROTO)
549 printf("! ");
550 if (hlp->bitmask & EBT_802_3)
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000551 printf("Length ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000552 else {
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000553 struct ethertypeent *ent;
554
555 ent = getethertypebynumber(ntohs(hlp->ethproto));
556 if (!ent)
Bart De Schuymer60332e02002-06-23 08:01:47 +0000557 printf("0x%x ", ntohs(hlp->ethproto));
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000558 else
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000559 printf("%s ", ent->e_name);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000560 }
561 }
562 if (hlp->bitmask & EBT_SOURCEMAC) {
Bart De Schuymer60332e02002-06-23 08:01:47 +0000563 printf("-s ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000564 if (hlp->invflags & EBT_ISOURCE)
565 printf("! ");
566 if (!memcmp(hlp->sourcemac, mac_type_unicast, 6) &&
567 !memcmp(hlp->sourcemsk, msk_type_unicast, 6)) {
568 printf("Unicast");
569 goto endsrc;
570 }
571 if (!memcmp(hlp->sourcemac, mac_type_multicast, 6) &&
572 !memcmp(hlp->sourcemsk, msk_type_multicast, 6)) {
573 printf("Multicast");
574 goto endsrc;
575 }
576 if (!memcmp(hlp->sourcemac, mac_type_broadcast, 6) &&
577 !memcmp(hlp->sourcemsk, msk_type_broadcast, 6)) {
578 printf("Broadcast");
579 goto endsrc;
580 }
Bart De Schuymer22d03a22003-05-03 20:28:22 +0000581 print_mac_and_mask(hlp->sourcemac, hlp->sourcemsk);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000582endsrc:
Bart De Schuymer60332e02002-06-23 08:01:47 +0000583 printf(" ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000584 }
585 if (hlp->bitmask & EBT_DESTMAC) {
Bart De Schuymer60332e02002-06-23 08:01:47 +0000586 printf("-d ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000587 if (hlp->invflags & EBT_IDEST)
588 printf("! ");
589 if (!memcmp(hlp->destmac, mac_type_unicast, 6) &&
590 !memcmp(hlp->destmsk, msk_type_unicast, 6)) {
591 printf("Unicast");
592 goto enddst;
593 }
594 if (!memcmp(hlp->destmac, mac_type_multicast, 6) &&
595 !memcmp(hlp->destmsk, msk_type_multicast, 6)) {
596 printf("Multicast");
597 goto enddst;
598 }
599 if (!memcmp(hlp->destmac, mac_type_broadcast, 6) &&
600 !memcmp(hlp->destmsk, msk_type_broadcast, 6)) {
601 printf("Broadcast");
602 goto enddst;
603 }
Bart De Schuymer22d03a22003-05-03 20:28:22 +0000604 print_mac_and_mask(hlp->destmac, hlp->destmsk);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000605enddst:
Bart De Schuymer60332e02002-06-23 08:01:47 +0000606 printf(" ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000607 }
608 if (hlp->in[0] != '\0') {
Bart De Schuymer60332e02002-06-23 08:01:47 +0000609 printf("-i ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000610 if (hlp->invflags & EBT_IIN)
611 printf("! ");
Bart De Schuymer60332e02002-06-23 08:01:47 +0000612 printf("%s ", hlp->in);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000613 }
614 if (hlp->logical_in[0] != '\0') {
Bart De Schuymer60332e02002-06-23 08:01:47 +0000615 printf("--logical-in ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000616 if (hlp->invflags & EBT_ILOGICALIN)
617 printf("! ");
Bart De Schuymer60332e02002-06-23 08:01:47 +0000618 printf("%s ", hlp->logical_in);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000619 }
620 if (hlp->logical_out[0] != '\0') {
Bart De Schuymer60332e02002-06-23 08:01:47 +0000621 printf("--logical-out ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000622 if (hlp->invflags & EBT_ILOGICALOUT)
623 printf("! ");
Bart De Schuymerb3d8f262002-07-07 14:26:15 +0000624 printf("%s ", hlp->logical_out);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000625 }
626 if (hlp->out[0] != '\0') {
Bart De Schuymer60332e02002-06-23 08:01:47 +0000627 printf("-o ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000628 if (hlp->invflags & EBT_IOUT)
629 printf("! ");
Bart De Schuymerb3d8f262002-07-07 14:26:15 +0000630 printf("%s ", hlp->out);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000631 }
632
633 m_l = hlp->m_list;
634 while (m_l) {
635 m = find_match(m_l->m->u.name);
636 if (!m)
637 print_bug("Match not found");
638 m->print(hlp, m_l->m);
639 m_l = m_l->next;
640 }
641 w_l = hlp->w_list;
642 while (w_l) {
643 w = find_watcher(w_l->w->u.name);
644 if (!w)
645 print_bug("Watcher not found");
646 w->print(hlp, w_l->w);
647 w_l = w_l->next;
648 }
649
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000650 printf("-j ");
651 if (strcmp(hlp->t->u.name, EBT_STANDARD_TARGET))
652 printf("%s ", hlp->t->u.name);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000653 t = find_target(hlp->t->u.name);
654 if (!t)
655 print_bug("Target not found");
656 t->print(hlp, hlp->t);
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000657 if (replace.flags & LIST_C)
Bart De Schuymer73fccca2002-10-17 22:00:23 +0000658 printf(", pcnt = %llu -- bcnt = %llu",
659 replace.counters[entries->counter_offset + i].pcnt,
660 replace.counters[entries->counter_offset + i].bcnt);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000661 printf("\n");
662 hlp = hlp->next;
663 }
664}
665
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000666struct ebt_u_entries *nr_to_chain(int nr)
Bart De Schuymer60332e02002-06-23 08:01:47 +0000667{
668 if (nr == -1)
669 return NULL;
670 if (nr < NF_BR_NUMHOOKS)
671 return replace.hook_entry[nr];
672 else {
673 int i;
674 struct ebt_u_chain_list *cl = replace.udc;
675
676 i = nr - NF_BR_NUMHOOKS;
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000677 while (i > 0 && cl) {
Bart De Schuymer60332e02002-06-23 08:01:47 +0000678 cl = cl->next;
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000679 i--;
680 }
Bart De Schuymer60332e02002-06-23 08:01:47 +0000681 if (cl)
682 return cl->udc;
683 else
684 return NULL;
685 }
686}
687
Bart De Schuymercc440052002-11-06 21:10:33 +0000688static inline struct ebt_u_entries *to_chain()
Bart De Schuymer60332e02002-06-23 08:01:47 +0000689{
690 return nr_to_chain(replace.selected_hook);
691}
692
693struct ebt_u_stack
694{
695 int chain_nr;
696 int n;
697 struct ebt_u_entry *e;
698 struct ebt_u_entries *entries;
699};
700
Bart De Schuymer62423742002-07-14 19:06:20 +0000701static void check_for_loops()
Bart De Schuymer60332e02002-06-23 08:01:47 +0000702{
703 int chain_nr , i, j , k, sp = 0, verdict;
704 struct ebt_u_entries *entries, *entries2;
705 struct ebt_u_stack *stack = NULL;
706 struct ebt_u_entry *e;
707
708 i = -1;
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000709 /*
710 * initialize hook_mask to 0
711 */
Bart De Schuymer60332e02002-06-23 08:01:47 +0000712 while (1) {
713 i++;
714 if (i < NF_BR_NUMHOOKS && !(replace.valid_hooks & (1 << i)))
715 continue;
716 entries = nr_to_chain(i);
717 if (!entries)
718 break;
719 entries->hook_mask = 0;
720 }
721 if (i > NF_BR_NUMHOOKS) {
722 stack = (struct ebt_u_stack *)malloc((i - NF_BR_NUMHOOKS) *
723 sizeof(struct ebt_u_stack));
724 if (!stack)
725 print_memory();
726 }
727
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000728 /*
729 * check for loops, starting from every base chain
730 */
Bart De Schuymer60332e02002-06-23 08:01:47 +0000731 for (i = 0; i < NF_BR_NUMHOOKS; i++) {
732 if (!(replace.valid_hooks & (1 << i)))
733 continue;
734 entries = nr_to_chain(i);
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000735 /*
736 * (1 << NF_BR_NUMHOOKS) implies it's a standard chain
737 * (usefull in the final_check() funtions)
738 */
Bart De Schuymerb26649e2002-07-25 14:51:54 +0000739 entries->hook_mask = (1 << i) | (1 << NF_BR_NUMHOOKS);
Bart De Schuymer60332e02002-06-23 08:01:47 +0000740 chain_nr = i;
741
742 e = entries->entries;
743 for (j = 0; j < entries->nentries; j++) {
744 if (strcmp(e->t->u.name, EBT_STANDARD_TARGET))
745 goto letscontinue;
746 verdict = ((struct ebt_standard_target *)(e->t))->verdict;
747 if (verdict < 0)
748 goto letscontinue;
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000749 entries2 = nr_to_chain(verdict + NF_BR_NUMHOOKS);
Bart De Schuymer60332e02002-06-23 08:01:47 +0000750 entries2->hook_mask |= entries->hook_mask;
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000751 /*
752 * now see if we've been here before
753 */
Bart De Schuymer60332e02002-06-23 08:01:47 +0000754 for (k = 0; k < sp; k++)
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000755 if (stack[k].chain_nr == verdict + NF_BR_NUMHOOKS)
Bart De Schuymer1a0a9c32002-06-24 21:10:16 +0000756 print_error("Loop from chain %s to chain %s",
Bart De Schuymerc56a31a2002-07-25 08:16:08 +0000757 nr_to_chain(chain_nr)->name,
758 nr_to_chain(stack[k].chain_nr)->name);
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000759 /*
760 * jump to the chain, make sure we know how to get back
761 */
Bart De Schuymer60332e02002-06-23 08:01:47 +0000762 stack[sp].chain_nr = chain_nr;
763 stack[sp].n = j;
764 stack[sp].entries = entries;
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000765 stack[sp].e = e;
766 sp++;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000767 j = -1;
768 e = entries2->entries;
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000769 chain_nr = verdict + NF_BR_NUMHOOKS;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000770 entries = entries2;
771 continue;
772letscontinue:
773 e = e->next;
774 }
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000775 /*
776 * we are at the end of a standard chain
777 */
Bart De Schuymer60332e02002-06-23 08:01:47 +0000778 if (sp == 0)
779 continue;
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000780 /*
781 * go back to the chain one level higher
782 */
Bart De Schuymer60332e02002-06-23 08:01:47 +0000783 sp--;
784 j = stack[sp].n;
785 chain_nr = stack[sp].chain_nr;
786 e = stack[sp].e;
787 entries = stack[sp].entries;
788 goto letscontinue;
789 }
790 free(stack);
791 return;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000792}
793
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000794/*
795 * parse the chain name and return the corresponding nr
796 * returns -1 on failure
797 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000798int get_hooknr(char* arg)
799{
800 int i;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000801 struct ebt_u_chain_list *cl = replace.udc;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000802
Bart De Schuymer60332e02002-06-23 08:01:47 +0000803 for (i = 0; i < NF_BR_NUMHOOKS; i++) {
804 if (!(replace.valid_hooks & (1 << i)))
805 continue;
806 if (!strcmp(arg, replace.hook_entry[i]->name))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000807 return i;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000808 }
809 while(cl) {
810 if (!strcmp(arg, cl->udc->name))
811 return i;
812 i++;
813 cl = cl->next;
814 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000815 return -1;
816}
817
Bart De Schuymer62423742002-07-14 19:06:20 +0000818static void print_help()
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000819{
820 struct ebt_u_match_list *m_l;
821 struct ebt_u_watcher_list *w_l;
822
Bart De Schuymer57a3f6a2003-04-01 16:59:33 +0000823 PRINT_VERSION;
824 printf(
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000825"Usage:\n"
826"ebtables -[ADI] chain rule-specification [options]\n"
827"ebtables -P chain target\n"
828"ebtables -[LFZ] [chain]\n"
Bart De Schuymer5885b362002-12-03 20:51:36 +0000829"ebtables -[NX] [chain]\n"
830"ebtables -E old-chain-name new-chain-name\n\n"
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000831"Commands:\n"
Bart De Schuymer23f6dcf2002-08-17 09:14:07 +0000832"--append -A chain : append to chain\n"
833"--delete -D chain : delete matching rule from chain\n"
834"--delete -D chain rulenum : delete rule at position rulenum from chain\n"
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000835"--insert -I chain rulenum : insert rule at position rulenum in chain\n"
Bart De Schuymer23f6dcf2002-08-17 09:14:07 +0000836"--list -L [chain] : list the rules in a chain or in all chains\n"
837"--flush -F [chain] : delete all rules in chain or in all chains\n"
838"--init-table : replace the kernel table with the initial table\n"
839"--zero -Z [chain] : put counters on zero in chain or in all chains\n"
840"--policy -P chain target : change policy on chain to target\n"
841"--new-chain -N chain : create a user defined chain\n"
842"--rename-chain -E old new : rename a chain\n"
843"--delete-chain -X chain : delete a user defined chain\n"
Bart De Schuymer5885b362002-12-03 20:51:36 +0000844"--atomic-commit : update the kernel w/t table contained in <FILE>\n"
845"--atomic-init : put the initial kernel table into <FILE>\n"
846"--atomic-save : put the current kernel table into <FILE>\n"
Bart De Schuymer97819962002-12-11 21:23:07 +0000847"--atomic-file file : set <FILE> to file\n\n"
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000848"Options:\n"
849"--proto -p [!] proto : protocol hexadecimal, by name or LENGTH\n"
850"--src -s [!] address[/mask]: source mac address\n"
851"--dst -d [!] address[/mask]: destination mac address\n"
852"--in-if -i [!] name : network input interface name\n"
853"--out-if -o [!] name : network output interface name\n"
854"--logical-in [!] name : logical bridge input interface name\n"
855"--logical-out [!] name : logical bridge output interface name\n"
Bart De Schuymer5cbc8e02002-07-14 21:15:28 +0000856"--modprobe -M program : try to insert modules using this program\n"
Bart De Schuymer5885b362002-12-03 20:51:36 +0000857"--version -V : print package version\n\n"
858"Environment variable:\n"
859ATOMIC_ENV_VARIABLE " : if set <FILE> (see above) will equal its value"
860"\n\n");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000861
862 m_l = new_entry->m_list;
863 while (m_l) {
864 ((struct ebt_u_match *)m_l->m)->help();
865 printf("\n");
866 m_l = m_l->next;
867 }
868 w_l = new_entry->w_list;
869 while (w_l) {
870 ((struct ebt_u_watcher *)w_l->w)->help();
871 printf("\n");
872 w_l = w_l->next;
873 }
874 ((struct ebt_u_target *)new_entry->t)->help();
875 printf("\n");
876 if (table->help)
877 table->help(hooknames);
878 exit(0);
879}
880
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000881/*
882 * execute command L
883 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000884static void list_rules()
885{
886 int i;
887
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000888 if (!(replace.flags & LIST_X))
889 printf("Bridge table: %s\n", table->name);
Bart De Schuymer60332e02002-06-23 08:01:47 +0000890 if (replace.selected_hook != -1) {
891 list_em(to_chain());
892 } else {
893 struct ebt_u_chain_list *cl = replace.udc;
894
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000895 /*
896 * create new chains and rename standard chains when necessary
897 */
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000898 if (replace.flags & LIST_X) {
899 while (cl) {
900 printf("ebtables -t %s -N %s\n", replace.name,
901 cl->udc->name);
902 cl = cl->next;
903 }
904 cl = replace.udc;
905 for (i = 0; i < NF_BR_NUMHOOKS; i++)
906 if (replace.valid_hooks & (1 << i) &&
907 strcmp(replace.hook_entry[i]->name, hooknames[i]))
908 printf("ebtables -t %s -E %s %s\n",
909 replace.name, hooknames[i],
910 replace.hook_entry[i]->name);
911 }
Bart De Schuymer60332e02002-06-23 08:01:47 +0000912 i = 0;
913 while (1) {
914 if (i < NF_BR_NUMHOOKS) {
915 if (replace.valid_hooks & (1 << i))
916 list_em(replace.hook_entry[i]);
917 i++;
918 continue;
919 } else {
920 if (!cl)
921 break;
922 list_em(cl->udc);
923 cl = cl->next;
924 }
925 }
926 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000927}
928
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000929/*
930 * execute command P
931 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000932static void change_policy(int policy)
933{
934 int i;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000935 struct ebt_u_entries *entries = to_chain();
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000936
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000937 /*
938 * don't do anything if the policy is the same
939 */
Bart De Schuymer60332e02002-06-23 08:01:47 +0000940 if (entries->policy != policy) {
941 entries->policy = policy;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000942 replace.num_counters = replace.nentries;
943 if (replace.nentries) {
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000944 /*
945 * '+ 1' for the CNT_END
946 */
Bart De Schuymered053432002-07-21 19:35:39 +0000947 if (!(replace.counterchanges = (unsigned short *) malloc(
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000948 (replace.nentries + 1) * sizeof(unsigned short))))
949 print_memory();
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000950 /*
951 * done nothing special to the rules
952 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000953 for (i = 0; i < replace.nentries; i++)
Bart De Schuymered053432002-07-21 19:35:39 +0000954 replace.counterchanges[i] = CNT_NORM;
955 replace.counterchanges[replace.nentries] = CNT_END;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000956 }
957 else
Bart De Schuymered053432002-07-21 19:35:39 +0000958 replace.counterchanges = NULL;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000959 }
960 else
961 exit(0);
962}
963
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000964/*
965 * flush one chain or the complete table
966 * -1 == nothing to do
967 * 0 == give back to kernel
968 */
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000969static int flush_chains()
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000970{
Bart De Schuymer60332e02002-06-23 08:01:47 +0000971 int i, j, oldnentries, numdel;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000972 unsigned short *cnt;
973 struct ebt_u_entry *u_e, *tmp;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000974 struct ebt_u_entries *entries = to_chain();
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000975
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000976 /*
977 * flush whole table
978 */
Bart De Schuymer60332e02002-06-23 08:01:47 +0000979 if (!entries) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000980 if (replace.nentries == 0)
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000981 return -1;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000982 replace.nentries = 0;
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000983 /*
984 * no need for the kernel to give us counters back
985 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000986 replace.num_counters = 0;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000987
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000988 /*
989 * free everything and zero (n)entries
990 */
Bart De Schuymer60332e02002-06-23 08:01:47 +0000991 i = -1;
992 while (1) {
993 i++;
994 entries = nr_to_chain(i);
995 if (!entries) {
996 if (i < NF_BR_NUMHOOKS)
997 continue;
998 else
999 break;
1000 }
1001 entries->nentries = 0;
1002 entries->counter_offset = 0;
1003 u_e = entries->entries;
1004 entries->entries = NULL;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001005 while (u_e) {
1006 free_u_entry(u_e);
1007 tmp = u_e->next;
1008 free(u_e);
1009 u_e = tmp;
1010 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001011 }
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001012 return 0;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001013 }
1014
Bart De Schuymer60332e02002-06-23 08:01:47 +00001015 if (entries->nentries == 0)
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001016 return -1;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001017 oldnentries = replace.nentries;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001018 replace.nentries -= entries->nentries;
1019 numdel = entries->nentries;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001020
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001021 if (replace.nentries) {
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001022 /*
1023 * +1 for CNT_END
1024 */
Bart De Schuymered053432002-07-21 19:35:39 +00001025 if ( !(replace.counterchanges = (unsigned short *)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001026 malloc((oldnentries + 1) * sizeof(unsigned short))) )
1027 print_memory();
Bart De Schuymer60332e02002-06-23 08:01:47 +00001028 }
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001029 /*
1030 * delete the counters belonging to the specified chain,
1031 * update counter_offset
1032 */
Bart De Schuymer60332e02002-06-23 08:01:47 +00001033 i = -1;
Bart De Schuymered053432002-07-21 19:35:39 +00001034 cnt = replace.counterchanges;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001035 while (1) {
1036 i++;
1037 entries = nr_to_chain(i);
1038 if (!entries) {
1039 if (i < NF_BR_NUMHOOKS)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001040 continue;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001041 else
1042 break;
1043 }
1044 if (i > replace.selected_hook)
1045 entries->counter_offset -= numdel;
1046 if (replace.nentries) {
1047 for (j = 0; j < entries->nentries; j++) {
1048 if (i == replace.selected_hook)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001049 *cnt = CNT_DEL;
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001050 else
1051 *cnt = CNT_NORM;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001052 cnt++;
1053 }
1054 }
Bart De Schuymer60332e02002-06-23 08:01:47 +00001055 }
1056
1057 if (replace.nentries) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001058 *cnt = CNT_END;
1059 replace.num_counters = oldnentries;
Bart De Schuymercc440052002-11-06 21:10:33 +00001060 } else
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001061 replace.num_counters = 0;
1062
Bart De Schuymer60332e02002-06-23 08:01:47 +00001063 entries = to_chain();
1064 entries->nentries = 0;
1065 u_e = entries->entries;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001066 while (u_e) {
1067 free_u_entry(u_e);
1068 tmp = u_e->next;
1069 free(u_e);
1070 u_e = tmp;
1071 }
Bart De Schuymer60332e02002-06-23 08:01:47 +00001072 entries->entries = NULL;
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001073 return 0;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001074}
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001075
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001076/*
1077 * -1 == no match
1078 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001079static int check_rule_exists(int rule_nr)
1080{
1081 struct ebt_u_entry *u_e;
1082 struct ebt_u_match_list *m_l, *m_l2;
1083 struct ebt_u_match *m;
1084 struct ebt_u_watcher_list *w_l, *w_l2;
1085 struct ebt_u_watcher *w;
1086 struct ebt_u_target *t = (struct ebt_u_target *)new_entry->t;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001087 struct ebt_u_entries *entries = to_chain();
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001088 int i, j, k;
1089
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001090 /*
1091 * handle '-D chain rulenr' command
1092 */
Bart De Schuymerc3b97f52003-04-17 17:03:49 +00001093 if (rule_nr != 0) {
Bart De Schuymer60332e02002-06-23 08:01:47 +00001094 if (rule_nr > entries->nentries)
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001095 return -1;
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001096 /*
1097 * user starts counting from 1
1098 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001099 return rule_nr - 1;
1100 }
Bart De Schuymer60332e02002-06-23 08:01:47 +00001101 u_e = entries->entries;
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001102 /*
1103 * check for an existing rule (if there are duplicate rules,
1104 * take the first occurance)
1105 */
Bart De Schuymer60332e02002-06-23 08:01:47 +00001106 for (i = 0; i < entries->nentries; i++, u_e = u_e->next) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001107 if (!u_e)
1108 print_bug("Hmm, trouble");
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001109 if (u_e->ethproto != new_entry->ethproto)
1110 continue;
1111 if (strcmp(u_e->in, new_entry->in))
1112 continue;
1113 if (strcmp(u_e->out, new_entry->out))
1114 continue;
1115 if (strcmp(u_e->logical_in, new_entry->logical_in))
1116 continue;
1117 if (strcmp(u_e->logical_out, new_entry->logical_out))
1118 continue;
1119 if (new_entry->bitmask & EBT_SOURCEMAC &&
1120 memcmp(u_e->sourcemac, new_entry->sourcemac, ETH_ALEN))
1121 continue;
1122 if (new_entry->bitmask & EBT_DESTMAC &&
1123 memcmp(u_e->destmac, new_entry->destmac, ETH_ALEN))
1124 continue;
1125 if (new_entry->bitmask != u_e->bitmask ||
1126 new_entry->invflags != u_e->invflags)
1127 continue;
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001128 /*
1129 * compare all matches
1130 */
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001131 m_l = new_entry->m_list;
1132 j = 0;
1133 while (m_l) {
1134 m = (struct ebt_u_match *)(m_l->m);
1135 m_l2 = u_e->m_list;
1136 while (m_l2 && strcmp(m_l2->m->u.name, m->m->u.name))
1137 m_l2 = m_l2->next;
1138 if (!m_l2 || !m->compare(m->m, m_l2->m))
1139 goto letscontinue;
1140 j++;
1141 m_l = m_l->next;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001142 }
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001143 /*
1144 * now be sure they have the same nr of matches
1145 */
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001146 k = 0;
1147 m_l = u_e->m_list;
1148 while (m_l) {
1149 k++;
1150 m_l = m_l->next;
1151 }
1152 if (j != k)
1153 continue;
1154
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001155 /*
1156 * compare all watchers
1157 */
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001158 w_l = new_entry->w_list;
1159 j = 0;
1160 while (w_l) {
1161 w = (struct ebt_u_watcher *)(w_l->w);
1162 w_l2 = u_e->w_list;
1163 while (w_l2 && strcmp(w_l2->w->u.name, w->w->u.name))
1164 w_l2 = w_l2->next;
1165 if (!w_l2 || !w->compare(w->w, w_l2->w))
1166 goto letscontinue;
1167 j++;
1168 w_l = w_l->next;
1169 }
1170 k = 0;
1171 w_l = u_e->w_list;
1172 while (w_l) {
1173 k++;
1174 w_l = w_l->next;
1175 }
1176 if (j != k)
1177 continue;
1178 if (strcmp(t->t->u.name, u_e->t->u.name))
1179 continue;
1180 if (!t->compare(t->t, u_e->t))
1181 continue;
1182 return i;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001183letscontinue:
1184 }
1185 return -1;
1186}
1187
Bart De Schuymer9895a8e2003-01-11 10:14:24 +00001188/* execute command A or I */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001189static void add_rule(int rule_nr)
1190{
1191 int i, j;
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001192 struct ebt_u_entry **u_e;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001193 unsigned short *cnt;
1194 struct ebt_u_match_list *m_l;
1195 struct ebt_u_watcher_list *w_l;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001196 struct ebt_u_entries *entries = to_chain(), *entries2;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001197
Bart De Schuymerc3b97f52003-04-17 17:03:49 +00001198 if (rule_nr <= 0)
1199 rule_nr += entries->nentries;
1200 else
1201 rule_nr--;
1202 if (rule_nr > entries->nentries || rule_nr < 0)
1203 print_error("The specified rule number is incorrect");
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001204 /*
1205 * we're adding one rule
1206 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001207 replace.num_counters = replace.nentries;
1208 replace.nentries++;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001209 entries->nentries++;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001210
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001211 /*
1212 * handle counter stuff
1213 * +1 for CNT_END
1214 */
Bart De Schuymered053432002-07-21 19:35:39 +00001215 if ( !(replace.counterchanges = (unsigned short *)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001216 malloc((replace.nentries + 1) * sizeof(unsigned short))) )
1217 print_memory();
Bart De Schuymered053432002-07-21 19:35:39 +00001218 cnt = replace.counterchanges;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001219 for (i = 0; i < replace.selected_hook; i++) {
Bart De Schuymer60332e02002-06-23 08:01:47 +00001220 if (i < NF_BR_NUMHOOKS && !(replace.valid_hooks & (1 << i)))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001221 continue;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001222 entries2 = nr_to_chain(i);
1223 for (j = 0; j < entries2->nentries; j++) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001224 *cnt = CNT_NORM;
1225 cnt++;
1226 }
1227 }
1228 for (i = 0; i < rule_nr; i++) {
1229 *cnt = CNT_NORM;
1230 cnt++;
1231 }
1232 *cnt = CNT_ADD;
1233 cnt++;
Bart De Schuymered053432002-07-21 19:35:39 +00001234 while (cnt != replace.counterchanges + replace.nentries) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001235 *cnt = CNT_NORM;
1236 cnt++;
1237 }
1238 *cnt = CNT_END;
1239
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001240 /*
1241 * go to the right position in the chain
1242 */
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001243 u_e = &entries->entries;
1244 for (i = 0; i < rule_nr; i++)
1245 u_e = &(*u_e)->next;
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001246 /*
1247 * insert the rule
1248 */
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001249 new_entry->next = *u_e;
1250 *u_e = new_entry;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001251
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001252 /*
1253 * put the ebt_[match, watcher, target] pointers in place
1254 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001255 m_l = new_entry->m_list;
1256 while (m_l) {
1257 m_l->m = ((struct ebt_u_match *)m_l->m)->m;
1258 m_l = m_l->next;
1259 }
1260 w_l = new_entry->w_list;
1261 while (w_l) {
1262 w_l->w = ((struct ebt_u_watcher *)w_l->w)->w;
1263 w_l = w_l->next;
1264 }
1265 new_entry->t = ((struct ebt_u_target *)new_entry->t)->t;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001266
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001267 /*
1268 * update the counter_offset of chains behind this one
1269 */
Bart De Schuymer60332e02002-06-23 08:01:47 +00001270 i = replace.selected_hook;
1271 while (1) {
1272 i++;
1273 entries = nr_to_chain(i);
1274 if (!entries) {
1275 if (i < NF_BR_NUMHOOKS)
1276 continue;
1277 else
1278 break;
1279 } else
1280 entries->counter_offset++;
1281 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001282}
1283
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001284/*
1285 * execute command D
1286 */
Bart De Schuymercc440052002-11-06 21:10:33 +00001287static void delete_rule(int begin, int end)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001288{
Bart De Schuymercc440052002-11-06 21:10:33 +00001289 int j, lentmp = 0, nr_deletes;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001290 unsigned short *cnt;
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001291 struct ebt_u_entry **u_e, *u_e2;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001292 struct ebt_u_entries *entries = to_chain(), *entries2;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001293
Bart De Schuymerc3b97f52003-04-17 17:03:49 +00001294 if (begin < 0) {
1295 if (begin < entries->nentries)
1296 goto rule_error;
1297 begin += entries->nentries + 1;
1298 }
1299 if (end < 0)
1300 end += entries->nentries + 1;
1301 if (begin > end)
1302rule_error:
1303 print_error("Sorry, wrong rule numbers");
Bart De Schuymercc440052002-11-06 21:10:33 +00001304 if ((begin = check_rule_exists(begin)) == -1 ||
1305 (end = check_rule_exists(end)) == -1)
Bart De Schuymer60332e02002-06-23 08:01:47 +00001306 print_error("Sorry, rule does not exist");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001307
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001308 /*
1309 * we're deleting rules
1310 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001311 replace.num_counters = replace.nentries;
Bart De Schuymercc440052002-11-06 21:10:33 +00001312 nr_deletes = end - begin + 1;
1313 replace.nentries -= nr_deletes;
1314 entries->nentries -= nr_deletes;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001315
1316 if (replace.nentries) {
1317 for (j = 0; j < replace.selected_hook; j++) {
Bart De Schuymer60332e02002-06-23 08:01:47 +00001318 if (j < NF_BR_NUMHOOKS &&
1319 !(replace.valid_hooks & (1 << j)))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001320 continue;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001321 entries2 = nr_to_chain(j);
1322 lentmp += entries2->nentries;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001323 }
Bart De Schuymercc440052002-11-06 21:10:33 +00001324 lentmp += begin;
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001325 /*
1326 * +1 for CNT_END
1327 */
Bart De Schuymered053432002-07-21 19:35:39 +00001328 if ( !(replace.counterchanges = (unsigned short *)malloc(
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001329 (replace.num_counters + 1) * sizeof(unsigned short))) )
1330 print_memory();
Bart De Schuymered053432002-07-21 19:35:39 +00001331 cnt = replace.counterchanges;
Bart De Schuymercc440052002-11-06 21:10:33 +00001332 for (j = 0; j < lentmp; j++, cnt++)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001333 *cnt = CNT_NORM;
Bart De Schuymercc440052002-11-06 21:10:33 +00001334 for (j = 0; j < nr_deletes; j++, cnt++)
1335 *cnt = CNT_DEL;
1336
1337 for (j = 0; j < replace.num_counters - lentmp - nr_deletes;
1338 j++, cnt++)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001339 *cnt = CNT_NORM;
Bart De Schuymercc440052002-11-06 21:10:33 +00001340
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001341 *cnt = CNT_END;
1342 }
1343 else
1344 replace.num_counters = 0;
1345
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001346 /*
1347 * go to the right position in the chain
1348 */
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001349 u_e = &entries->entries;
Bart De Schuymercc440052002-11-06 21:10:33 +00001350 for (j = 0; j < begin; j++)
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001351 u_e = &(*u_e)->next;
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001352 /*
1353 * remove the rules
1354 */
Bart De Schuymercc440052002-11-06 21:10:33 +00001355 j = nr_deletes;
1356 while(j--) {
1357 u_e2 = *u_e;
1358 *u_e = (*u_e)->next;
Bart De Schuymer9895a8e2003-01-11 10:14:24 +00001359 /* free everything */
Bart De Schuymercc440052002-11-06 21:10:33 +00001360 free_u_entry(u_e2);
1361 free(u_e2);
1362 }
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001363
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001364 /*
1365 * update the counter_offset of chains behind this one
1366 */
Bart De Schuymercc440052002-11-06 21:10:33 +00001367 j = replace.selected_hook;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001368 while (1) {
Bart De Schuymercc440052002-11-06 21:10:33 +00001369 j++;
1370 entries = nr_to_chain(j);
Bart De Schuymer60332e02002-06-23 08:01:47 +00001371 if (!entries) {
Bart De Schuymercc440052002-11-06 21:10:33 +00001372 if (j < NF_BR_NUMHOOKS)
Bart De Schuymer60332e02002-06-23 08:01:47 +00001373 continue;
1374 else
1375 break;
Bart De Schuymercc440052002-11-06 21:10:33 +00001376 } else
1377 entries->counter_offset -= nr_deletes;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001378 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001379}
1380
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001381/*
1382 * execute command Z
1383 */
Bart De Schuymer62423742002-07-14 19:06:20 +00001384static void zero_counters(int zerochain)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001385{
1386
1387 if (zerochain == -1) {
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001388 /*
1389 * tell main() we don't update the counters
1390 * this results in tricking the kernel to zero its counters,
1391 * naively expecting userspace to update its counters. Muahahaha
1392 */
Bart De Schuymered053432002-07-21 19:35:39 +00001393 replace.counterchanges = NULL;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001394 replace.num_counters = 0;
1395 } else {
1396 int i, j;
1397 unsigned short *cnt;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001398 struct ebt_u_entries *entries = nr_to_chain(zerochain), *e2;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001399
Bart De Schuymer60332e02002-06-23 08:01:47 +00001400 if (entries->nentries == 0)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001401 exit(0);
Bart De Schuymered053432002-07-21 19:35:39 +00001402 replace.counterchanges = (unsigned short *)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001403 malloc((replace.nentries + 1) * sizeof(unsigned short));
Bart De Schuymered053432002-07-21 19:35:39 +00001404 if (!replace.counterchanges)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001405 print_memory();
Bart De Schuymered053432002-07-21 19:35:39 +00001406 cnt = replace.counterchanges;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001407 for (i = 0; i < zerochain; i++) {
Bart De Schuymer60332e02002-06-23 08:01:47 +00001408 if (i < NF_BR_NUMHOOKS &&
1409 !(replace.valid_hooks & (1 << i)))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001410 continue;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001411 e2 = nr_to_chain(i);
1412 for (j = 0; j < e2->nentries; j++) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001413 *cnt = CNT_NORM;
1414 cnt++;
1415 }
1416 }
Bart De Schuymer60332e02002-06-23 08:01:47 +00001417 for (i = 0; i < entries->nentries; i++) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001418 *cnt = CNT_ZERO;
1419 cnt++;
1420 }
Bart De Schuymered053432002-07-21 19:35:39 +00001421 while (cnt != replace.counterchanges + replace.nentries) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001422 *cnt = CNT_NORM;
1423 cnt++;
1424 }
1425 *cnt = CNT_END;
1426 }
1427}
1428
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001429/*
1430 * Checks the type for validity and calls getethertypebynumber()
1431 */
1432struct ethertypeent *parseethertypebynumber(int type)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001433{
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001434 if (type < 1536)
1435 print_error("Ethernet protocols have values >= 0x0600");
1436 if (type > 0xffff)
1437 print_error("Ethernet protocols have values <= 0xffff");
1438 return getethertypebynumber(type);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001439}
1440
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001441/*
1442 * put the mac address into 6 (ETH_ALEN) bytes
1443 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001444int getmac_and_mask(char *from, char *to, char *mask)
1445{
1446 char *p;
1447 int i;
Bart De Schuymer41830412002-06-05 19:41:28 +00001448 struct ether_addr *addr;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001449
1450 if (strcasecmp(from, "Unicast") == 0) {
1451 memcpy(to, mac_type_unicast, ETH_ALEN);
1452 memcpy(mask, msk_type_unicast, ETH_ALEN);
1453 return 0;
1454 }
1455 if (strcasecmp(from, "Multicast") == 0) {
1456 memcpy(to, mac_type_multicast, ETH_ALEN);
1457 memcpy(mask, msk_type_multicast, ETH_ALEN);
1458 return 0;
1459 }
1460 if (strcasecmp(from, "Broadcast") == 0) {
1461 memcpy(to, mac_type_broadcast, ETH_ALEN);
1462 memcpy(mask, msk_type_broadcast, ETH_ALEN);
1463 return 0;
1464 }
1465 if ( (p = strrchr(from, '/')) != NULL) {
1466 *p = '\0';
Bart De Schuymer41830412002-06-05 19:41:28 +00001467 if (!(addr = ether_aton(p + 1)))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001468 return -1;
Bart De Schuymer41830412002-06-05 19:41:28 +00001469 memcpy(mask, addr, ETH_ALEN);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001470 } else
1471 memset(mask, 0xff, ETH_ALEN);
Bart De Schuymer41830412002-06-05 19:41:28 +00001472 if (!(addr = ether_aton(from)))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001473 return -1;
Bart De Schuymer41830412002-06-05 19:41:28 +00001474 memcpy(to, addr, ETH_ALEN);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001475 for (i = 0; i < ETH_ALEN; i++)
1476 to[i] &= mask[i];
1477 return 0;
1478}
1479
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001480/*
1481 * executes the final_check() function for all extensions used by the rule
1482 */
Bart De Schuymer62423742002-07-14 19:06:20 +00001483static void do_final_checks(struct ebt_u_entry *e, struct ebt_u_entries *entries)
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +00001484{
1485 struct ebt_u_match_list *m_l;
1486 struct ebt_u_watcher_list *w_l;
1487 struct ebt_u_target *t;
1488 struct ebt_u_match *m;
1489 struct ebt_u_watcher *w;
1490
1491 m_l = e->m_list;
1492 w_l = e->w_list;
1493 while (m_l) {
1494 m = find_match(m_l->m->u.name);
1495 m->final_check(e, m_l->m, replace.name,
1496 entries->hook_mask, 1);
1497 m_l = m_l->next;
1498 }
1499 while (w_l) {
1500 w = find_watcher(w_l->w->u.name);
1501 w->final_check(e, w_l->w, replace.name,
1502 entries->hook_mask, 1);
1503 w_l = w_l->next;
1504 }
1505 t = find_target(e->t->u.name);
1506 t->final_check(e, e->t, replace.name,
1507 entries->hook_mask, 1);
1508}
1509
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001510/*
1511 * used for the -X command
1512 */
Bart De Schuymer62423742002-07-14 19:06:20 +00001513static void check_for_references(int chain_nr)
Bart De Schuymerb909f9b2002-06-26 18:35:31 +00001514{
1515 int i = -1, j;
1516 struct ebt_u_entries *entries;
1517 struct ebt_u_entry *e;
1518
1519 while (1) {
1520 i++;
1521 entries = nr_to_chain(i);
1522 if (!entries) {
1523 if (i < NF_BR_NUMHOOKS)
1524 continue;
1525 else
1526 break;
1527 }
1528 e = entries->entries;
1529 j = 0;
1530 while (e) {
Bart De Schuymerc27432e2003-01-09 22:01:07 +00001531 int chain_jmp;
1532
Bart De Schuymerb909f9b2002-06-26 18:35:31 +00001533 j++;
1534 if (strcmp(e->t->u.name, EBT_STANDARD_TARGET)) {
1535 e = e->next;
1536 continue;
1537 }
Bart De Schuymerc27432e2003-01-09 22:01:07 +00001538 chain_jmp = ((struct ebt_standard_target *)e->t)->verdict;
1539 if (chain_jmp == chain_nr)
Bart De Schuymerb909f9b2002-06-26 18:35:31 +00001540 print_error("Can't delete the chain, it's referenced "
1541 "in chain %s, rule %d", entries->name, j);
Bart De Schuymerc27432e2003-01-09 22:01:07 +00001542 /* adjust the chain jumps when necessary */
1543 if (chain_jmp > chain_nr)
1544 ((struct ebt_standard_target *)e->t)->verdict--;
Bart De Schuymerb909f9b2002-06-26 18:35:31 +00001545 e = e->next;
1546 }
1547 }
1548}
1549
Bart De Schuymercc440052002-11-06 21:10:33 +00001550static int parse_delete_rule(const char *argv, int *rule_nr, int *rule_nr_end)
1551{
1552 char *colon = strchr(argv, ':'), *buffer;
1553
1554 if (colon) {
1555 *colon = '\0';
1556 if (*(colon + 1) == '\0')
Bart De Schuymerc3b97f52003-04-17 17:03:49 +00001557 *rule_nr_end = -1; /* until the last rule */
Bart De Schuymercc440052002-11-06 21:10:33 +00001558 else {
1559 *rule_nr_end = strtol(colon + 1, &buffer, 10);
Bart De Schuymerc3b97f52003-04-17 17:03:49 +00001560 if (*buffer != '\0' || *rule_nr_end == 0)
Bart De Schuymercc440052002-11-06 21:10:33 +00001561 return -1;
1562 }
1563 }
1564 if (colon == argv)
Bart De Schuymerc3b97f52003-04-17 17:03:49 +00001565 *rule_nr = 1; /* beginning with the first rule */
Bart De Schuymercc440052002-11-06 21:10:33 +00001566 else {
1567 *rule_nr = strtol(argv, &buffer, 10);
Bart De Schuymerc3b97f52003-04-17 17:03:49 +00001568 if (*buffer != '\0' || *rule_nr == 0)
Bart De Schuymercc440052002-11-06 21:10:33 +00001569 return -1;
1570 }
1571 if (!colon)
1572 *rule_nr_end = *rule_nr;
Bart De Schuymercc440052002-11-06 21:10:33 +00001573 return 0;
1574}
1575
Bart De Schuymera615b962002-11-03 14:54:09 +00001576static int invert = 0;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001577int check_inverse(const char option[])
1578{
1579 if (strcmp(option, "!") == 0) {
Bart De Schuymera615b962002-11-03 14:54:09 +00001580 if (invert == 1)
1581 print_error("double use of '!' not allowed");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001582 optind++;
Bart De Schuymera615b962002-11-03 14:54:09 +00001583 invert = 1;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001584 return 1;
1585 }
Bart De Schuymera615b962002-11-03 14:54:09 +00001586 return invert;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001587}
1588
1589void check_option(unsigned int *flags, unsigned int mask)
1590{
1591 if (*flags & mask)
1592 print_error("Multiple use of same option not allowed");
1593 *flags |= mask;
1594}
1595
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001596static void get_kernel_table(const char *modprobe)
1597{
1598 if ( !(table = find_table(replace.name)) )
1599 print_error("Bad table name");
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001600 /*
1601 * get the kernel's information
1602 */
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001603 if (get_table(&replace)) {
1604 ebtables_insmod("ebtables", modprobe);
1605 if (get_table(&replace))
1606 print_error("The kernel doesn't support the ebtables "
1607 "%s table", replace.name);
1608 }
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001609 /*
Bart De Schuymer5885b362002-12-03 20:51:36 +00001610 * when listing a table contained in a file, we don't demand that
1611 * the user knows the table's name
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001612 */
Bart De Schuymer62a7fdb2002-08-24 21:01:21 +00001613 if ( !(table = find_table(replace.name)) )
1614 print_error("Bad table name");
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001615}
1616
Bart De Schuymerc5075142002-08-18 14:21:19 +00001617#define print_if_l_error print_error("Interface name length must be less " \
1618 "than %d", IFNAMSIZ)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001619#define OPT_COMMAND 0x01
1620#define OPT_TABLE 0x02
1621#define OPT_IN 0x04
1622#define OPT_OUT 0x08
1623#define OPT_JUMP 0x10
1624#define OPT_PROTOCOL 0x20
1625#define OPT_SOURCE 0x40
1626#define OPT_DEST 0x80
1627#define OPT_ZERO 0x100
1628#define OPT_LOGICALIN 0x200
1629#define OPT_LOGICALOUT 0x400
Bart De Schuymer5885b362002-12-03 20:51:36 +00001630/* the main thing */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001631int main(int argc, char *argv[])
1632{
Bart De Schuymer923a5732002-08-11 12:01:33 +00001633 char *buffer;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001634 int c, i;
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001635 /*
1636 * this special one for the -Z option (we can have -Z <this> -L <that>)
1637 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001638 int zerochain = -1;
Bart De Schuymerf8f8f292002-06-25 15:43:57 +00001639 int policy = 0;
Bart De Schuymerc3b97f52003-04-17 17:03:49 +00001640 int rule_nr = 0; /* used for -[D,I] */
1641 int rule_nr_end = 0; /* used for -I */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001642 struct ebt_u_target *t;
1643 struct ebt_u_match *m;
1644 struct ebt_u_watcher *w;
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001645 struct ebt_u_match_list *m_l;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001646 struct ebt_u_watcher_list *w_l;
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001647 struct ebt_u_entries *entries;
Bart De Schuymerc8531032002-06-14 21:55:29 +00001648 const char *modprobe = NULL;
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 Schuymerc56a31a2002-07-25 08:16:08 +00001694 get_kernel_table(modprobe);
1695 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 Schuymerc56a31a2002-07-25 08:16:08 +00001834 get_kernel_table(modprobe);
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;
Bart De Schuymerc5c3c2d2002-08-16 19:48:03 +00002164 ebtables_insmod("ebtables", modprobe);
Bart De Schuymer62423742002-07-14 19:06:20 +00002165 break;
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002166 case 7 : /* atomic-init */
2167 case 10: /* atomic-save */
2168 case 11: /* init-table */
Bart De Schuymer62423742002-07-14 19:06:20 +00002169 replace.command = c;
2170 if (replace.flags & OPT_COMMAND)
2171 print_error("Multiple commands not allowed");
Bart De Schuymer5885b362002-12-03 20:51:36 +00002172 if (c != 11 && !replace.filename)
2173 print_error("No atomic file specified");
Bart De Schuymer62423742002-07-14 19:06:20 +00002174 replace.flags |= OPT_COMMAND;
Bart De Schuymer5885b362002-12-03 20:51:36 +00002175 {
2176 char *tmp = replace.filename;
2177
2178 tmp = replace.filename;
2179 /* get the kernel table */
2180 replace.filename = NULL;
2181 get_kernel_table(modprobe);
2182 replace.filename = tmp;
2183 }
Bart De Schuymera8d920b2002-07-16 18:30:44 +00002184 if (replace.nentries) {
Bart De Schuymered053432002-07-21 19:35:39 +00002185 replace.counterchanges = (unsigned short *)
Bart De Schuymer5f16dc72002-07-16 18:08:36 +00002186 malloc(sizeof(unsigned short) * (replace.nentries + 1));
2187 for (i = 0; i < replace.nentries; i++)
Bart De Schuymered053432002-07-21 19:35:39 +00002188 replace.counterchanges[i] = CNT_NORM;
2189 replace.counterchanges[i] = CNT_END;
Bart De Schuymer5f16dc72002-07-16 18:08:36 +00002190 }
Bart De Schuymer5885b362002-12-03 20:51:36 +00002191 break;
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002192 case 9 : /* atomic */
Bart De Schuymer5885b362002-12-03 20:51:36 +00002193 if (replace.flags & OPT_COMMAND)
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00002194 print_error("--atomic has to come before"
2195 " the command");
Bart De Schuymer5885b362002-12-03 20:51:36 +00002196 /* another possible memory leak here */
Bart De Schuymer62423742002-07-14 19:06:20 +00002197 replace.filename = (char *)malloc(strlen(optarg) + 1);
2198 strcpy(replace.filename, optarg);
2199 break;
Bart De Schuymera615b962002-11-03 14:54:09 +00002200 case 1 :
2201 if (!strcmp(optarg, "!"))
2202 check_inverse(optarg);
2203 else
2204 print_error("Bad argument : %s", optarg);
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002205 /*
2206 * check_inverse() did optind++
2207 */
Bart De Schuymera615b962002-11-03 14:54:09 +00002208 optind--;
2209 continue;
Bart De Schuymer9af14f92002-07-10 20:49:10 +00002210 default:
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002211 /*
2212 * is it a target option?
2213 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002214 t = (struct ebt_u_target *)new_entry->t;
2215 if ((t->parse(c - t->option_offset, argv, argc,
2216 new_entry, &t->flags, &t->t)))
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00002217 goto check_extension;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002218
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002219 /*
2220 * is it a match_option?
2221 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002222 for (m = matches; m; m = m->next)
2223 if (m->parse(c - m->option_offset, argv,
2224 argc, new_entry, &m->flags, &m->m))
2225 break;
2226
2227 if (m != NULL) {
2228 if (m->used == 0)
2229 add_match(m);
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00002230 goto check_extension;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002231 }
2232
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002233 /*
2234 * is it a watcher option?
2235 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002236 for (w = watchers; w; w = w->next)
2237 if (w->parse(c-w->option_offset, argv,
2238 argc, new_entry, &w->flags, &w->w))
2239 break;
2240
2241 if (w == NULL)
2242 print_error("Unknown argument");
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00002243 if (w->used == 0)
2244 add_watcher(w);
2245check_extension:
Bart De Schuymer60332e02002-06-23 08:01:47 +00002246 if (replace.command != 'A' && replace.command != 'I' &&
2247 replace.command != 'D')
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00002248 print_error("Extensions only for -A, -I and -D");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002249 }
Bart De Schuymera615b962002-11-03 14:54:09 +00002250 invert = 0;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002251 }
2252
Bart De Schuymer25c741d2002-06-23 18:54:34 +00002253 if ( !table && !(table = find_table(replace.name)) )
2254 print_error("Bad table name");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002255
2256 if ( (replace.flags & OPT_COMMAND) && replace.command != 'L' &&
2257 replace.flags & OPT_ZERO )
2258 print_error("Command -Z only allowed together with command -L");
2259
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002260 /*
2261 * do this after parsing everything, so we can print specific info
2262 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002263 if (replace.command == 'h' && !(replace.flags & OPT_ZERO))
2264 print_help();
2265
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002266 /*
2267 * do the final checks
2268 */
Bart De Schuymer60332e02002-06-23 08:01:47 +00002269 if (replace.command == 'A' || replace.command == 'I' ||
2270 replace.command == 'D') {
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002271 /*
2272 * this will put the hook_mask right for the chains
2273 */
Bart De Schuymer60332e02002-06-23 08:01:47 +00002274 check_for_loops();
2275 entries = to_chain();
2276 m_l = new_entry->m_list;
2277 w_l = new_entry->w_list;
2278 t = (struct ebt_u_target *)new_entry->t;
2279 while (m_l) {
2280 m = (struct ebt_u_match *)(m_l->m);
2281 m->final_check(new_entry, m->m, replace.name,
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +00002282 entries->hook_mask, 0);
Bart De Schuymer60332e02002-06-23 08:01:47 +00002283 m_l = m_l->next;
2284 }
2285 while (w_l) {
2286 w = (struct ebt_u_watcher *)(w_l->w);
2287 w->final_check(new_entry, w->w, replace.name,
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +00002288 entries->hook_mask, 0);
Bart De Schuymer60332e02002-06-23 08:01:47 +00002289 w_l = w_l->next;
2290 }
2291 t->final_check(new_entry, t->t, replace.name,
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +00002292 entries->hook_mask, 0);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002293 }
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002294 /*
2295 * so, the extensions can work with the host endian
2296 * the kernel does not have to do this ofcourse
2297 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002298 new_entry->ethproto = htons(new_entry->ethproto);
2299
Bart De Schuymerc34f4672002-08-18 18:03:52 +00002300 if (replace.command == 'P') {
2301 if (replace.selected_hook < NF_BR_NUMHOOKS &&
2302 policy == EBT_RETURN)
2303 print_error("Policy RETURN only allowed for user "
2304 "defined chains");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002305 change_policy(policy);
Bart De Schuymerc34f4672002-08-18 18:03:52 +00002306 } else if (replace.command == 'L') {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002307 list_rules();
2308 if (replace.flags & OPT_ZERO)
2309 zero_counters(zerochain);
2310 else
2311 exit(0);
2312 }
2313 if (replace.flags & OPT_ZERO)
2314 zero_counters(zerochain);
Bart De Schuymer1ab41562002-06-23 17:09:54 +00002315 else if (replace.command == 'F') {
2316 if (flush_chains() == -1)
2317 exit(0);
2318 } else if (replace.command == 'A' || replace.command == 'I') {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002319 add_rule(rule_nr);
Bart De Schuymer1ab41562002-06-23 17:09:54 +00002320 check_for_loops();
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002321 /*
2322 * do the final_check(), for all entries
2323 * needed when adding a rule that has a chain target
2324 */
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +00002325 i = -1;
2326 while (1) {
2327 struct ebt_u_entry *e;
2328
2329 i++;
2330 entries = nr_to_chain(i);
2331 if (!entries) {
2332 if (i < NF_BR_NUMHOOKS)
2333 continue;
2334 else
2335 break;
2336 }
2337 e = entries->entries;
2338 while (e) {
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002339 /*
2340 * userspace extensions use host endian
2341 */
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +00002342 e->ethproto = ntohs(e->ethproto);
2343 do_final_checks(e, entries);
2344 e->ethproto = htons(e->ethproto);
2345 e = e->next;
2346 }
2347 }
Bart De Schuymerc3b97f52003-04-17 17:03:49 +00002348 } else if (replace.command == 'D')
Bart De Schuymercc440052002-11-06 21:10:33 +00002349 delete_rule(rule_nr, rule_nr_end);
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002350 /*
2351 * commands -N, -E, -X, --atomic-commit, --atomic-commit, --atomic-save,
2352 * --init-table fall through
2353 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002354
2355 if (table->check)
2356 table->check(&replace);
2357
2358 deliver_table(&replace);
2359
Bart De Schuymered053432002-07-21 19:35:39 +00002360 if (replace.counterchanges)
2361 deliver_counters(&replace);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002362 return 0;
2363}