blob: f0e0ab9523299745cc5fb839c92a6d3450a0a7dd [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' },
Bart De Schuymer90f2c2e2003-07-13 18:48:02 +0000106 { "delete-chain" , optional_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};
Bart De Schuymer09441f72003-07-17 20:09:22 +0000131unsigned char mac_type_bridge_group[ETH_ALEN] = {0x01,0x80,0xc2,0,0,0};
132unsigned char msk_type_bridge_group[ETH_ALEN] = {255,255,255,255,255,255};
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000133
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000134/*
135 * holds all the data
136 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000137static struct ebt_u_replace replace;
138
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000139/*
140 * the chosen table
141 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000142static struct ebt_u_table *table = NULL;
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000143/*
144 * the lists of supported tables, matches, watchers and targets
145 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000146static struct ebt_u_table *tables = NULL;
147static struct ebt_u_match *matches = NULL;
148static struct ebt_u_watcher *watchers = NULL;
149static struct ebt_u_target *targets = NULL;
150
151struct ebt_u_target *find_target(const char *name)
152{
153 struct ebt_u_target *t = targets;
154
155 while(t && strcmp(t->name, name))
156 t = t->next;
157 return t;
158}
159
160struct ebt_u_match *find_match(const char *name)
161{
162 struct ebt_u_match *m = matches;
163
164 while(m && strcmp(m->name, name))
165 m = m->next;
166 return m;
167}
168
169struct ebt_u_watcher *find_watcher(const char *name)
170{
171 struct ebt_u_watcher *w = watchers;
172
173 while(w && strcmp(w->name, name))
174 w = w->next;
175 return w;
176}
177
178struct ebt_u_table *find_table(char *name)
179{
180 struct ebt_u_table *t = tables;
181
182 while (t && strcmp(t->name, name))
183 t = t->next;
184 return t;
185}
186
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000187/*
188 * The pointers in here are special:
189 * The struct ebt_target * pointer is actually a struct ebt_u_target * pointer.
190 * instead of making yet a few other structs, we just do a cast.
191 * We need a struct ebt_u_target pointer because we know the address of the data
192 * they point to won't change. We want to allow that the struct ebt_u_target.t
193 * member can change.
194 * Same holds for the struct ebt_match and struct ebt_watcher pointers
195 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000196struct ebt_u_entry *new_entry;
197
Bart De Schuymer62423742002-07-14 19:06:20 +0000198static void initialize_entry(struct ebt_u_entry *e)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000199{
200 e->bitmask = EBT_NOPROTO;
201 e->invflags = 0;
202 e->ethproto = 0;
203 strcpy(e->in, "");
204 strcpy(e->out, "");
205 strcpy(e->logical_in, "");
206 strcpy(e->logical_out, "");
207 e->m_list = NULL;
208 e->w_list = NULL;
Bart De Schuymerc27432e2003-01-09 22:01:07 +0000209 /*
210 * the init function of the standard target should have put the verdict
211 * on CONTINUE
212 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000213 e->t = (struct ebt_entry_target *)find_target(EBT_STANDARD_TARGET);
214 if (!e->t)
Bart De Schuymerd4586482002-08-11 16:15:55 +0000215 print_bug("Couldn't load standard target");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000216}
217
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000218/*
219 * this doesn't free e, becoz the calling function might need e->next
220 */
Bart De Schuymer62423742002-07-14 19:06:20 +0000221static void free_u_entry(struct ebt_u_entry *e)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000222{
223 struct ebt_u_match_list *m_l, *m_l2;
224 struct ebt_u_watcher_list *w_l, *w_l2;
225
226 m_l = e->m_list;
227 while (m_l) {
228 m_l2 = m_l->next;
229 free(m_l->m);
230 free(m_l);
231 m_l = m_l2;
232 }
233 w_l = e->w_list;
234 while (w_l) {
235 w_l2 = w_l->next;
236 free(w_l->w);
237 free(w_l);
238 w_l = w_l2;
239 }
240 free(e->t);
241}
242
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000243/*
244 * the user will use the match, so put it in new_entry
245 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000246static void add_match(struct ebt_u_match *m)
247{
248 struct ebt_u_match_list **m_list, *new;
249
250 m->used = 1;
Bart De Schuymerc56a31a2002-07-25 08:16:08 +0000251 for (m_list = &new_entry->m_list; *m_list; m_list = &(*m_list)->next);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000252 new = (struct ebt_u_match_list *)
253 malloc(sizeof(struct ebt_u_match_list));
254 if (!new)
255 print_memory();
256 *m_list = new;
257 new->next = NULL;
258 new->m = (struct ebt_entry_match *)m;
259}
260
261static void add_watcher(struct ebt_u_watcher *w)
262{
263 struct ebt_u_watcher_list **w_list;
264 struct ebt_u_watcher_list *new;
265
266 w->used = 1;
Bart De Schuymerc56a31a2002-07-25 08:16:08 +0000267 for (w_list = &new_entry->w_list; *w_list; w_list = &(*w_list)->next);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000268 new = (struct ebt_u_watcher_list *)
269 malloc(sizeof(struct ebt_u_watcher_list));
270 if (!new)
271 print_memory();
272 *w_list = new;
273 new->next = NULL;
274 new->w = (struct ebt_entry_watcher *)w;
275}
276
277static int global_option_offset = 0;
278#define OPTION_OFFSET 256
279static struct option *
280merge_options(struct option *oldopts, const struct option *newopts,
281 unsigned int *options_offset)
282{
283 unsigned int num_old, num_new, i;
284 struct option *merge;
285
286 if (!newopts || !oldopts || !options_offset)
287 print_bug("merge wrong");
288 for (num_old = 0; oldopts[num_old].name; num_old++);
289 for (num_new = 0; newopts[num_new].name; num_new++);
290
291 global_option_offset += OPTION_OFFSET;
292 *options_offset = global_option_offset;
293
294 merge = malloc(sizeof(struct option) * (num_new + num_old + 1));
295 if (!merge)
296 print_memory();
297 memcpy(merge, oldopts, num_old * sizeof(struct option));
298 for (i = 0; i < num_new; i++) {
299 merge[num_old + i] = newopts[i];
300 merge[num_old + i].val += *options_offset;
301 }
302 memset(merge + num_old + num_new, 0, sizeof(struct option));
Bart De Schuymer9895a8e2003-01-11 10:14:24 +0000303 /* only free dynamically allocated stuff */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000304 if (oldopts != ebt_original_options)
305 free(oldopts);
306
307 return merge;
308}
309
310void register_match(struct ebt_u_match *m)
311{
Bart De Schuymerf81c2702003-07-23 21:07:04 +0000312 int size = EBT_ALIGN(m->size) + sizeof(struct ebt_entry_match);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000313 struct ebt_u_match **i;
314
315 m->m = (struct ebt_entry_match *)malloc(size);
316 if (!m->m)
317 print_memory();
318 strcpy(m->m->u.name, m->name);
Bart De Schuymerf81c2702003-07-23 21:07:04 +0000319 m->m->match_size = EBT_ALIGN(m->size);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000320 ebt_options = merge_options
321 (ebt_options, m->extra_ops, &(m->option_offset));
322 m->init(m->m);
323
324 for (i = &matches; *i; i = &((*i)->next));
325 m->next = NULL;
326 *i = m;
327}
328
329void register_watcher(struct ebt_u_watcher *w)
330{
Bart De Schuymerf81c2702003-07-23 21:07:04 +0000331 int size = EBT_ALIGN(w->size) + sizeof(struct ebt_entry_watcher);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000332 struct ebt_u_watcher **i;
333
334 w->w = (struct ebt_entry_watcher *)malloc(size);
335 if (!w->w)
336 print_memory();
337 strcpy(w->w->u.name, w->name);
Bart De Schuymerf81c2702003-07-23 21:07:04 +0000338 w->w->watcher_size = EBT_ALIGN(w->size);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000339 ebt_options = merge_options
340 (ebt_options, w->extra_ops, &(w->option_offset));
341 w->init(w->w);
342
343 for (i = &watchers; *i; i = &((*i)->next));
344 w->next = NULL;
345 *i = w;
346}
347
348void register_target(struct ebt_u_target *t)
349{
Bart De Schuymerf81c2702003-07-23 21:07:04 +0000350 int size = EBT_ALIGN(t->size) + sizeof(struct ebt_entry_target);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000351 struct ebt_u_target **i;
352
353 t->t = (struct ebt_entry_target *)malloc(size);
354 if (!t->t)
355 print_memory();
356 strcpy(t->t->u.name, t->name);
Bart De Schuymerf81c2702003-07-23 21:07:04 +0000357 t->t->target_size = EBT_ALIGN(t->size);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000358 ebt_options = merge_options
359 (ebt_options, t->extra_ops, &(t->option_offset));
360 t->init(t->t);
Bart De Schuymerc56a31a2002-07-25 08:16:08 +0000361
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000362 for (i = &targets; *i; i = &((*i)->next));
363 t->next = NULL;
364 *i = t;
365}
366
367void register_table(struct ebt_u_table *t)
368{
369 t->next = tables;
370 tables = t;
371}
372
Bart De Schuymer0cb01792003-05-04 16:52:04 +0000373const char *modprobe = NULL;
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000374/*
375 * blatently stolen (again) from iptables.c userspace program
376 * find out where the modprobe utility is located
377 */
Bart De Schuymerc8531032002-06-14 21:55:29 +0000378static char *get_modprobe(void)
379{
380 int procfile;
381 char *ret;
382
383 procfile = open(PROC_SYS_MODPROBE, O_RDONLY);
384 if (procfile < 0)
385 return NULL;
386
387 ret = malloc(1024);
388 if (ret) {
389 switch (read(procfile, ret, 1024)) {
390 case -1: goto fail;
391 case 1024: goto fail; /* Partial read. Wierd */
392 }
393 if (ret[strlen(ret)-1]=='\n')
394 ret[strlen(ret)-1]=0;
395 close(procfile);
396 return ret;
397 }
398 fail:
399 free(ret);
400 close(procfile);
401 return NULL;
402}
403
Bart De Schuymer0cb01792003-05-04 16:52:04 +0000404int ebtables_insmod(const char *modname)
Bart De Schuymerc8531032002-06-14 21:55:29 +0000405{
406 char *buf = NULL;
407 char *argv[3];
408
Bart De Schuymer9895a8e2003-01-11 10:14:24 +0000409 /* If they don't explicitly set it, read out of kernel */
Bart De Schuymerc8531032002-06-14 21:55:29 +0000410 if (!modprobe) {
411 buf = get_modprobe();
412 if (!buf)
413 return -1;
414 modprobe = buf;
415 }
416
417 switch (fork()) {
418 case 0:
419 argv[0] = (char *)modprobe;
420 argv[1] = (char *)modname;
421 argv[2] = NULL;
422 execv(argv[0], argv);
423
424 /* not usually reached */
425 exit(0);
426 case -1:
427 return -1;
428
429 default: /* parent */
430 wait(NULL);
431 }
432
433 free(buf);
434 return 0;
435}
436
Bart De Schuymer9a0fbf22003-01-11 16:16:54 +0000437static void list_extensions()
438{
439 struct ebt_u_table *tbl = tables;
440 struct ebt_u_target *t = targets;
441 struct ebt_u_match *m = matches;
442 struct ebt_u_watcher *w = watchers;
443
Bart De Schuymer57a3f6a2003-04-01 16:59:33 +0000444 PRINT_VERSION;
Bart De Schuymer9a0fbf22003-01-11 16:16:54 +0000445 printf("Supported userspace extensions:\n\nSupported tables:\n");
446 while(tbl) {
447 printf("%s\n", tbl->name);
448 tbl = tbl->next;
449 }
450 printf("\nSupported targets:\n");
451 while(t) {
452 printf("%s\n", t->name);
453 t = t->next;
454 }
455 printf("\nSupported matches:\n");
456 while(m) {
457 printf("%s\n", m->name);
458 m = m->next;
459 }
460 printf("\nSupported watchers:\n");
461 while(w) {
462 printf("%s\n", w->name);
463 w = w->next;
464 }
465 exit(0);
466}
467
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000468/*
469 * we use replace.flags, so we can't use the following values:
470 * 0x01 == OPT_COMMAND, 0x02 == OPT_TABLE, 0x100 == OPT_ZERO
471 */
Bart De Schuymer22d03a22003-05-03 20:28:22 +0000472#define LIST_N 0x04
473#define LIST_C 0x08
474#define LIST_X 0x10
475#define LIST_MAC2 0x20
476
477void print_mac(const char *mac)
478{
479 if (replace.flags & LIST_MAC2) {
480 int j;
481 for (j = 0; j < ETH_ALEN; j++)
482 printf("%02x%s", (unsigned char)mac[j],
483 (j==ETH_ALEN-1) ? "" : ":");
484 } else
485 printf("%s", ether_ntoa((struct ether_addr *) mac));
486}
487
488void print_mac_and_mask(const char *mac, const char *mask)
489{
490 char hlpmsk[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
491
Bart De Schuymer09441f72003-07-17 20:09:22 +0000492 if (!memcmp(mac, mac_type_unicast, 6) &&
493 !memcmp(mask, msk_type_unicast, 6))
494 printf("Unicast");
495 else if (!memcmp(mac, mac_type_multicast, 6) &&
496 !memcmp(mask, msk_type_multicast, 6))
497 printf("Multicast");
498 else if (!memcmp(mac, mac_type_broadcast, 6) &&
499 !memcmp(mask, msk_type_broadcast, 6))
500 printf("Broadcast");
501 else if (!memcmp(mac, mac_type_bridge_group, 6) &&
502 !memcmp(mask, msk_type_bridge_group, 6))
503 printf("BGA");
504 else {
505 print_mac(mac);
506 if (memcmp(mask, hlpmsk, 6)) {
507 printf("/");
508 print_mac(mask);
509 }
Bart De Schuymer22d03a22003-05-03 20:28:22 +0000510 }
511}
512
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000513/*
514 * helper function for list_rules()
515 */
Bart De Schuymer60332e02002-06-23 08:01:47 +0000516static void list_em(struct ebt_u_entries *entries)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000517{
518 int i, j, space = 0, digits;
519 struct ebt_u_entry *hlp;
520 struct ebt_u_match_list *m_l;
521 struct ebt_u_watcher_list *w_l;
522 struct ebt_u_match *m;
523 struct ebt_u_watcher *w;
524 struct ebt_u_target *t;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000525
Bart De Schuymer60332e02002-06-23 08:01:47 +0000526 hlp = entries->entries;
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000527 if (replace.flags & LIST_X && entries->policy != EBT_ACCEPT) {
528 printf("ebtables -t %s -P %s %s\n", replace.name,
529 entries->name, standard_targets[-entries->policy - 1]);
530 } else if (!(replace.flags & LIST_X)) {
Bart De Schuymerc87c9642002-08-01 15:34:16 +0000531 printf("\nBridge chain: %s, entries: %d, policy: %s\n",
532 entries->name, entries->nentries,
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000533 standard_targets[-entries->policy - 1]);
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000534 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000535
Bart De Schuymer60332e02002-06-23 08:01:47 +0000536 i = entries->nentries;
Bart De Schuymerf8f8f292002-06-25 15:43:57 +0000537 while (i > 9) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000538 space++;
539 i /= 10;
540 }
541
Bart De Schuymer60332e02002-06-23 08:01:47 +0000542 for (i = 0; i < entries->nentries; i++) {
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000543 if (replace.flags & LIST_N) {
544 digits = 0;
Bart De Schuymer9895a8e2003-01-11 10:14:24 +0000545 /* A little work to get nice rule numbers. */
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000546 j = i + 1;
547 while (j > 9) {
548 digits++;
549 j /= 10;
550 }
551 for (j = 0; j < space - digits; j++)
552 printf(" ");
553 printf("%d. ", i + 1);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000554 }
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000555 if (replace.flags & LIST_X)
556 printf("ebtables -t %s -A %s ",
557 replace.name, entries->name);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000558
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000559 /*
560 * Don't print anything about the protocol if no protocol was
561 * specified, obviously this means any protocol will do.
562 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000563 if (!(hlp->bitmask & EBT_NOPROTO)) {
Bart De Schuymer60332e02002-06-23 08:01:47 +0000564 printf("-p ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000565 if (hlp->invflags & EBT_IPROTO)
566 printf("! ");
567 if (hlp->bitmask & EBT_802_3)
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000568 printf("Length ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000569 else {
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000570 struct ethertypeent *ent;
571
572 ent = getethertypebynumber(ntohs(hlp->ethproto));
573 if (!ent)
Bart De Schuymer60332e02002-06-23 08:01:47 +0000574 printf("0x%x ", ntohs(hlp->ethproto));
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000575 else
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000576 printf("%s ", ent->e_name);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000577 }
578 }
579 if (hlp->bitmask & EBT_SOURCEMAC) {
Bart De Schuymer60332e02002-06-23 08:01:47 +0000580 printf("-s ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000581 if (hlp->invflags & EBT_ISOURCE)
582 printf("! ");
Bart De Schuymer22d03a22003-05-03 20:28:22 +0000583 print_mac_and_mask(hlp->sourcemac, hlp->sourcemsk);
Bart De Schuymer60332e02002-06-23 08:01:47 +0000584 printf(" ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000585 }
586 if (hlp->bitmask & EBT_DESTMAC) {
Bart De Schuymer60332e02002-06-23 08:01:47 +0000587 printf("-d ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000588 if (hlp->invflags & EBT_IDEST)
589 printf("! ");
Bart De Schuymer22d03a22003-05-03 20:28:22 +0000590 print_mac_and_mask(hlp->destmac, hlp->destmsk);
Bart De Schuymer60332e02002-06-23 08:01:47 +0000591 printf(" ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000592 }
593 if (hlp->in[0] != '\0') {
Bart De Schuymer60332e02002-06-23 08:01:47 +0000594 printf("-i ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000595 if (hlp->invflags & EBT_IIN)
596 printf("! ");
Bart De Schuymer60332e02002-06-23 08:01:47 +0000597 printf("%s ", hlp->in);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000598 }
599 if (hlp->logical_in[0] != '\0') {
Bart De Schuymer60332e02002-06-23 08:01:47 +0000600 printf("--logical-in ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000601 if (hlp->invflags & EBT_ILOGICALIN)
602 printf("! ");
Bart De Schuymer60332e02002-06-23 08:01:47 +0000603 printf("%s ", hlp->logical_in);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000604 }
605 if (hlp->logical_out[0] != '\0') {
Bart De Schuymer60332e02002-06-23 08:01:47 +0000606 printf("--logical-out ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000607 if (hlp->invflags & EBT_ILOGICALOUT)
608 printf("! ");
Bart De Schuymerb3d8f262002-07-07 14:26:15 +0000609 printf("%s ", hlp->logical_out);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000610 }
611 if (hlp->out[0] != '\0') {
Bart De Schuymer60332e02002-06-23 08:01:47 +0000612 printf("-o ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000613 if (hlp->invflags & EBT_IOUT)
614 printf("! ");
Bart De Schuymerb3d8f262002-07-07 14:26:15 +0000615 printf("%s ", hlp->out);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000616 }
617
618 m_l = hlp->m_list;
619 while (m_l) {
620 m = find_match(m_l->m->u.name);
621 if (!m)
622 print_bug("Match not found");
623 m->print(hlp, m_l->m);
624 m_l = m_l->next;
625 }
626 w_l = hlp->w_list;
627 while (w_l) {
628 w = find_watcher(w_l->w->u.name);
629 if (!w)
630 print_bug("Watcher not found");
631 w->print(hlp, w_l->w);
632 w_l = w_l->next;
633 }
634
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000635 printf("-j ");
636 if (strcmp(hlp->t->u.name, EBT_STANDARD_TARGET))
637 printf("%s ", hlp->t->u.name);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000638 t = find_target(hlp->t->u.name);
639 if (!t)
640 print_bug("Target not found");
641 t->print(hlp, hlp->t);
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000642 if (replace.flags & LIST_C)
Bart De Schuymer73fccca2002-10-17 22:00:23 +0000643 printf(", pcnt = %llu -- bcnt = %llu",
644 replace.counters[entries->counter_offset + i].pcnt,
645 replace.counters[entries->counter_offset + i].bcnt);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000646 printf("\n");
647 hlp = hlp->next;
648 }
649}
650
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000651struct ebt_u_entries *nr_to_chain(int nr)
Bart De Schuymer60332e02002-06-23 08:01:47 +0000652{
653 if (nr == -1)
654 return NULL;
655 if (nr < NF_BR_NUMHOOKS)
656 return replace.hook_entry[nr];
657 else {
658 int i;
659 struct ebt_u_chain_list *cl = replace.udc;
660
661 i = nr - NF_BR_NUMHOOKS;
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000662 while (i > 0 && cl) {
Bart De Schuymer60332e02002-06-23 08:01:47 +0000663 cl = cl->next;
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000664 i--;
665 }
Bart De Schuymer60332e02002-06-23 08:01:47 +0000666 if (cl)
667 return cl->udc;
668 else
669 return NULL;
670 }
671}
672
Bart De Schuymercc440052002-11-06 21:10:33 +0000673static inline struct ebt_u_entries *to_chain()
Bart De Schuymer60332e02002-06-23 08:01:47 +0000674{
675 return nr_to_chain(replace.selected_hook);
676}
677
678struct ebt_u_stack
679{
680 int chain_nr;
681 int n;
682 struct ebt_u_entry *e;
683 struct ebt_u_entries *entries;
684};
685
Bart De Schuymer62423742002-07-14 19:06:20 +0000686static void check_for_loops()
Bart De Schuymer60332e02002-06-23 08:01:47 +0000687{
688 int chain_nr , i, j , k, sp = 0, verdict;
689 struct ebt_u_entries *entries, *entries2;
690 struct ebt_u_stack *stack = NULL;
691 struct ebt_u_entry *e;
692
693 i = -1;
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000694 /*
695 * initialize hook_mask to 0
696 */
Bart De Schuymer60332e02002-06-23 08:01:47 +0000697 while (1) {
698 i++;
699 if (i < NF_BR_NUMHOOKS && !(replace.valid_hooks & (1 << i)))
700 continue;
701 entries = nr_to_chain(i);
702 if (!entries)
703 break;
704 entries->hook_mask = 0;
705 }
706 if (i > NF_BR_NUMHOOKS) {
707 stack = (struct ebt_u_stack *)malloc((i - NF_BR_NUMHOOKS) *
708 sizeof(struct ebt_u_stack));
709 if (!stack)
710 print_memory();
711 }
712
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000713 /*
714 * check for loops, starting from every base chain
715 */
Bart De Schuymer60332e02002-06-23 08:01:47 +0000716 for (i = 0; i < NF_BR_NUMHOOKS; i++) {
717 if (!(replace.valid_hooks & (1 << i)))
718 continue;
719 entries = nr_to_chain(i);
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000720 /*
721 * (1 << NF_BR_NUMHOOKS) implies it's a standard chain
722 * (usefull in the final_check() funtions)
723 */
Bart De Schuymerb26649e2002-07-25 14:51:54 +0000724 entries->hook_mask = (1 << i) | (1 << NF_BR_NUMHOOKS);
Bart De Schuymer60332e02002-06-23 08:01:47 +0000725 chain_nr = i;
726
727 e = entries->entries;
728 for (j = 0; j < entries->nentries; j++) {
729 if (strcmp(e->t->u.name, EBT_STANDARD_TARGET))
730 goto letscontinue;
731 verdict = ((struct ebt_standard_target *)(e->t))->verdict;
732 if (verdict < 0)
733 goto letscontinue;
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000734 entries2 = nr_to_chain(verdict + NF_BR_NUMHOOKS);
Bart De Schuymer60332e02002-06-23 08:01:47 +0000735 entries2->hook_mask |= entries->hook_mask;
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000736 /*
737 * now see if we've been here before
738 */
Bart De Schuymer60332e02002-06-23 08:01:47 +0000739 for (k = 0; k < sp; k++)
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000740 if (stack[k].chain_nr == verdict + NF_BR_NUMHOOKS)
Bart De Schuymer1a0a9c32002-06-24 21:10:16 +0000741 print_error("Loop from chain %s to chain %s",
Bart De Schuymerc56a31a2002-07-25 08:16:08 +0000742 nr_to_chain(chain_nr)->name,
743 nr_to_chain(stack[k].chain_nr)->name);
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000744 /*
745 * jump to the chain, make sure we know how to get back
746 */
Bart De Schuymer60332e02002-06-23 08:01:47 +0000747 stack[sp].chain_nr = chain_nr;
748 stack[sp].n = j;
749 stack[sp].entries = entries;
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000750 stack[sp].e = e;
751 sp++;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000752 j = -1;
753 e = entries2->entries;
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000754 chain_nr = verdict + NF_BR_NUMHOOKS;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000755 entries = entries2;
756 continue;
757letscontinue:
758 e = e->next;
759 }
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000760 /*
761 * we are at the end of a standard chain
762 */
Bart De Schuymer60332e02002-06-23 08:01:47 +0000763 if (sp == 0)
764 continue;
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000765 /*
766 * go back to the chain one level higher
767 */
Bart De Schuymer60332e02002-06-23 08:01:47 +0000768 sp--;
769 j = stack[sp].n;
770 chain_nr = stack[sp].chain_nr;
771 e = stack[sp].e;
772 entries = stack[sp].entries;
773 goto letscontinue;
774 }
775 free(stack);
776 return;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000777}
778
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000779/*
780 * parse the chain name and return the corresponding nr
781 * returns -1 on failure
782 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000783int get_hooknr(char* arg)
784{
785 int i;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000786 struct ebt_u_chain_list *cl = replace.udc;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000787
Bart De Schuymer60332e02002-06-23 08:01:47 +0000788 for (i = 0; i < NF_BR_NUMHOOKS; i++) {
789 if (!(replace.valid_hooks & (1 << i)))
790 continue;
791 if (!strcmp(arg, replace.hook_entry[i]->name))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000792 return i;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000793 }
794 while(cl) {
795 if (!strcmp(arg, cl->udc->name))
796 return i;
797 i++;
798 cl = cl->next;
799 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000800 return -1;
801}
802
Bart De Schuymer62423742002-07-14 19:06:20 +0000803static void print_help()
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000804{
805 struct ebt_u_match_list *m_l;
806 struct ebt_u_watcher_list *w_l;
807
Bart De Schuymer57a3f6a2003-04-01 16:59:33 +0000808 PRINT_VERSION;
809 printf(
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000810"Usage:\n"
811"ebtables -[ADI] chain rule-specification [options]\n"
812"ebtables -P chain target\n"
813"ebtables -[LFZ] [chain]\n"
Bart De Schuymer5885b362002-12-03 20:51:36 +0000814"ebtables -[NX] [chain]\n"
815"ebtables -E old-chain-name new-chain-name\n\n"
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000816"Commands:\n"
Bart De Schuymer23f6dcf2002-08-17 09:14:07 +0000817"--append -A chain : append to chain\n"
818"--delete -D chain : delete matching rule from chain\n"
819"--delete -D chain rulenum : delete rule at position rulenum from chain\n"
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000820"--insert -I chain rulenum : insert rule at position rulenum in chain\n"
Bart De Schuymer23f6dcf2002-08-17 09:14:07 +0000821"--list -L [chain] : list the rules in a chain or in all chains\n"
822"--flush -F [chain] : delete all rules in chain or in all chains\n"
823"--init-table : replace the kernel table with the initial table\n"
824"--zero -Z [chain] : put counters on zero in chain or in all chains\n"
825"--policy -P chain target : change policy on chain to target\n"
826"--new-chain -N chain : create a user defined chain\n"
827"--rename-chain -E old new : rename a chain\n"
Bart De Schuymer90f2c2e2003-07-13 18:48:02 +0000828"--delete-chain -X [chain] : delete a user defined chain\n"
Bart De Schuymer5885b362002-12-03 20:51:36 +0000829"--atomic-commit : update the kernel w/t table contained in <FILE>\n"
830"--atomic-init : put the initial kernel table into <FILE>\n"
831"--atomic-save : put the current kernel table into <FILE>\n"
Bart De Schuymer97819962002-12-11 21:23:07 +0000832"--atomic-file file : set <FILE> to file\n\n"
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000833"Options:\n"
834"--proto -p [!] proto : protocol hexadecimal, by name or LENGTH\n"
835"--src -s [!] address[/mask]: source mac address\n"
836"--dst -d [!] address[/mask]: destination mac address\n"
837"--in-if -i [!] name : network input interface name\n"
838"--out-if -o [!] name : network output interface name\n"
839"--logical-in [!] name : logical bridge input interface name\n"
840"--logical-out [!] name : logical bridge output interface name\n"
Bart De Schuymer5cbc8e02002-07-14 21:15:28 +0000841"--modprobe -M program : try to insert modules using this program\n"
Bart De Schuymer5885b362002-12-03 20:51:36 +0000842"--version -V : print package version\n\n"
843"Environment variable:\n"
844ATOMIC_ENV_VARIABLE " : if set <FILE> (see above) will equal its value"
845"\n\n");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000846
847 m_l = new_entry->m_list;
848 while (m_l) {
849 ((struct ebt_u_match *)m_l->m)->help();
850 printf("\n");
851 m_l = m_l->next;
852 }
853 w_l = new_entry->w_list;
854 while (w_l) {
855 ((struct ebt_u_watcher *)w_l->w)->help();
856 printf("\n");
857 w_l = w_l->next;
858 }
859 ((struct ebt_u_target *)new_entry->t)->help();
860 printf("\n");
861 if (table->help)
862 table->help(hooknames);
863 exit(0);
864}
865
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000866/*
867 * execute command L
868 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000869static void list_rules()
870{
871 int i;
872
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000873 if (!(replace.flags & LIST_X))
874 printf("Bridge table: %s\n", table->name);
Bart De Schuymer60332e02002-06-23 08:01:47 +0000875 if (replace.selected_hook != -1) {
876 list_em(to_chain());
877 } else {
878 struct ebt_u_chain_list *cl = replace.udc;
879
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000880 /*
881 * create new chains and rename standard chains when necessary
882 */
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000883 if (replace.flags & LIST_X) {
884 while (cl) {
885 printf("ebtables -t %s -N %s\n", replace.name,
886 cl->udc->name);
887 cl = cl->next;
888 }
889 cl = replace.udc;
890 for (i = 0; i < NF_BR_NUMHOOKS; i++)
891 if (replace.valid_hooks & (1 << i) &&
892 strcmp(replace.hook_entry[i]->name, hooknames[i]))
893 printf("ebtables -t %s -E %s %s\n",
894 replace.name, hooknames[i],
895 replace.hook_entry[i]->name);
896 }
Bart De Schuymer60332e02002-06-23 08:01:47 +0000897 i = 0;
898 while (1) {
899 if (i < NF_BR_NUMHOOKS) {
900 if (replace.valid_hooks & (1 << i))
901 list_em(replace.hook_entry[i]);
902 i++;
903 continue;
904 } else {
905 if (!cl)
906 break;
907 list_em(cl->udc);
908 cl = cl->next;
909 }
910 }
911 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000912}
913
Bart De Schuymerb6c94f92003-06-14 13:08:03 +0000914static void counters_nochange()
915{
916 int i;
917
918 replace.num_counters = replace.nentries;
919 if (replace.nentries) {
920 /*
921 * '+ 1' for the CNT_END
922 */
923 if (!(replace.counterchanges = (unsigned short *) malloc(
924 (replace.nentries + 1) * sizeof(unsigned short))))
925 print_memory();
926 /*
927 * done nothing special to the rules
928 */
929 for (i = 0; i < replace.nentries; i++)
930 replace.counterchanges[i] = CNT_NORM;
931 replace.counterchanges[replace.nentries] = CNT_END;
932 }
933 else
934 replace.counterchanges = NULL;
935}
936
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000937/*
938 * execute command P
939 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000940static void change_policy(int policy)
941{
Bart De Schuymer60332e02002-06-23 08:01:47 +0000942 struct ebt_u_entries *entries = to_chain();
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000943
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000944 /*
945 * don't do anything if the policy is the same
946 */
Bart De Schuymer60332e02002-06-23 08:01:47 +0000947 if (entries->policy != policy) {
948 entries->policy = policy;
Bart De Schuymerb6c94f92003-06-14 13:08:03 +0000949 counters_nochange();
950 } else
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000951 exit(0);
952}
953
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000954/*
955 * flush one chain or the complete table
956 * -1 == nothing to do
957 * 0 == give back to kernel
958 */
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000959static int flush_chains()
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000960{
Bart De Schuymer60332e02002-06-23 08:01:47 +0000961 int i, j, oldnentries, numdel;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000962 unsigned short *cnt;
963 struct ebt_u_entry *u_e, *tmp;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000964 struct ebt_u_entries *entries = to_chain();
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000965
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000966 /*
967 * flush whole table
968 */
Bart De Schuymer60332e02002-06-23 08:01:47 +0000969 if (!entries) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000970 if (replace.nentries == 0)
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000971 return -1;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000972 replace.nentries = 0;
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000973 /*
974 * no need for the kernel to give us counters back
975 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000976 replace.num_counters = 0;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000977
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000978 /*
979 * free everything and zero (n)entries
980 */
Bart De Schuymer60332e02002-06-23 08:01:47 +0000981 i = -1;
982 while (1) {
983 i++;
984 entries = nr_to_chain(i);
985 if (!entries) {
986 if (i < NF_BR_NUMHOOKS)
987 continue;
988 else
989 break;
990 }
991 entries->nentries = 0;
992 entries->counter_offset = 0;
993 u_e = entries->entries;
994 entries->entries = NULL;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000995 while (u_e) {
996 free_u_entry(u_e);
997 tmp = u_e->next;
998 free(u_e);
999 u_e = tmp;
1000 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001001 }
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001002 return 0;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001003 }
1004
Bart De Schuymer60332e02002-06-23 08:01:47 +00001005 if (entries->nentries == 0)
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001006 return -1;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001007 oldnentries = replace.nentries;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001008 replace.nentries -= entries->nentries;
1009 numdel = entries->nentries;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001010
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001011 if (replace.nentries) {
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001012 /*
1013 * +1 for CNT_END
1014 */
Bart De Schuymered053432002-07-21 19:35:39 +00001015 if ( !(replace.counterchanges = (unsigned short *)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001016 malloc((oldnentries + 1) * sizeof(unsigned short))) )
1017 print_memory();
Bart De Schuymer60332e02002-06-23 08:01:47 +00001018 }
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001019 /*
1020 * delete the counters belonging to the specified chain,
1021 * update counter_offset
1022 */
Bart De Schuymer60332e02002-06-23 08:01:47 +00001023 i = -1;
Bart De Schuymered053432002-07-21 19:35:39 +00001024 cnt = replace.counterchanges;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001025 while (1) {
1026 i++;
1027 entries = nr_to_chain(i);
1028 if (!entries) {
1029 if (i < NF_BR_NUMHOOKS)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001030 continue;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001031 else
1032 break;
1033 }
1034 if (i > replace.selected_hook)
1035 entries->counter_offset -= numdel;
1036 if (replace.nentries) {
1037 for (j = 0; j < entries->nentries; j++) {
1038 if (i == replace.selected_hook)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001039 *cnt = CNT_DEL;
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001040 else
1041 *cnt = CNT_NORM;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001042 cnt++;
1043 }
1044 }
Bart De Schuymer60332e02002-06-23 08:01:47 +00001045 }
1046
1047 if (replace.nentries) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001048 *cnt = CNT_END;
1049 replace.num_counters = oldnentries;
Bart De Schuymercc440052002-11-06 21:10:33 +00001050 } else
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001051 replace.num_counters = 0;
1052
Bart De Schuymer60332e02002-06-23 08:01:47 +00001053 entries = to_chain();
1054 entries->nentries = 0;
1055 u_e = entries->entries;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001056 while (u_e) {
1057 free_u_entry(u_e);
1058 tmp = u_e->next;
1059 free(u_e);
1060 u_e = tmp;
1061 }
Bart De Schuymer60332e02002-06-23 08:01:47 +00001062 entries->entries = NULL;
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001063 return 0;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001064}
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001065
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001066/*
1067 * -1 == no match
1068 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001069static int check_rule_exists(int rule_nr)
1070{
1071 struct ebt_u_entry *u_e;
1072 struct ebt_u_match_list *m_l, *m_l2;
1073 struct ebt_u_match *m;
1074 struct ebt_u_watcher_list *w_l, *w_l2;
1075 struct ebt_u_watcher *w;
1076 struct ebt_u_target *t = (struct ebt_u_target *)new_entry->t;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001077 struct ebt_u_entries *entries = to_chain();
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001078 int i, j, k;
1079
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001080 /*
1081 * handle '-D chain rulenr' command
1082 */
Bart De Schuymerc3b97f52003-04-17 17:03:49 +00001083 if (rule_nr != 0) {
Bart De Schuymer60332e02002-06-23 08:01:47 +00001084 if (rule_nr > entries->nentries)
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001085 return -1;
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001086 /*
1087 * user starts counting from 1
1088 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001089 return rule_nr - 1;
1090 }
Bart De Schuymer60332e02002-06-23 08:01:47 +00001091 u_e = entries->entries;
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001092 /*
1093 * check for an existing rule (if there are duplicate rules,
1094 * take the first occurance)
1095 */
Bart De Schuymer60332e02002-06-23 08:01:47 +00001096 for (i = 0; i < entries->nentries; i++, u_e = u_e->next) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001097 if (!u_e)
1098 print_bug("Hmm, trouble");
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001099 if (u_e->ethproto != new_entry->ethproto)
1100 continue;
1101 if (strcmp(u_e->in, new_entry->in))
1102 continue;
1103 if (strcmp(u_e->out, new_entry->out))
1104 continue;
1105 if (strcmp(u_e->logical_in, new_entry->logical_in))
1106 continue;
1107 if (strcmp(u_e->logical_out, new_entry->logical_out))
1108 continue;
1109 if (new_entry->bitmask & EBT_SOURCEMAC &&
1110 memcmp(u_e->sourcemac, new_entry->sourcemac, ETH_ALEN))
1111 continue;
1112 if (new_entry->bitmask & EBT_DESTMAC &&
1113 memcmp(u_e->destmac, new_entry->destmac, ETH_ALEN))
1114 continue;
1115 if (new_entry->bitmask != u_e->bitmask ||
1116 new_entry->invflags != u_e->invflags)
1117 continue;
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001118 /*
1119 * compare all matches
1120 */
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001121 m_l = new_entry->m_list;
1122 j = 0;
1123 while (m_l) {
1124 m = (struct ebt_u_match *)(m_l->m);
1125 m_l2 = u_e->m_list;
1126 while (m_l2 && strcmp(m_l2->m->u.name, m->m->u.name))
1127 m_l2 = m_l2->next;
1128 if (!m_l2 || !m->compare(m->m, m_l2->m))
1129 goto letscontinue;
1130 j++;
1131 m_l = m_l->next;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001132 }
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001133 /*
1134 * now be sure they have the same nr of matches
1135 */
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001136 k = 0;
1137 m_l = u_e->m_list;
1138 while (m_l) {
1139 k++;
1140 m_l = m_l->next;
1141 }
1142 if (j != k)
1143 continue;
1144
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001145 /*
1146 * compare all watchers
1147 */
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001148 w_l = new_entry->w_list;
1149 j = 0;
1150 while (w_l) {
1151 w = (struct ebt_u_watcher *)(w_l->w);
1152 w_l2 = u_e->w_list;
1153 while (w_l2 && strcmp(w_l2->w->u.name, w->w->u.name))
1154 w_l2 = w_l2->next;
1155 if (!w_l2 || !w->compare(w->w, w_l2->w))
1156 goto letscontinue;
1157 j++;
1158 w_l = w_l->next;
1159 }
1160 k = 0;
1161 w_l = u_e->w_list;
1162 while (w_l) {
1163 k++;
1164 w_l = w_l->next;
1165 }
1166 if (j != k)
1167 continue;
1168 if (strcmp(t->t->u.name, u_e->t->u.name))
1169 continue;
1170 if (!t->compare(t->t, u_e->t))
1171 continue;
1172 return i;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001173letscontinue:
1174 }
1175 return -1;
1176}
1177
Bart De Schuymer9895a8e2003-01-11 10:14:24 +00001178/* execute command A or I */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001179static void add_rule(int rule_nr)
1180{
1181 int i, j;
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001182 struct ebt_u_entry **u_e;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001183 unsigned short *cnt;
1184 struct ebt_u_match_list *m_l;
1185 struct ebt_u_watcher_list *w_l;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001186 struct ebt_u_entries *entries = to_chain(), *entries2;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001187
Bart De Schuymerc3b97f52003-04-17 17:03:49 +00001188 if (rule_nr <= 0)
1189 rule_nr += entries->nentries;
1190 else
1191 rule_nr--;
1192 if (rule_nr > entries->nentries || rule_nr < 0)
1193 print_error("The specified rule number is incorrect");
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001194 /*
1195 * we're adding one rule
1196 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001197 replace.num_counters = replace.nentries;
1198 replace.nentries++;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001199 entries->nentries++;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001200
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001201 /*
1202 * handle counter stuff
1203 * +1 for CNT_END
1204 */
Bart De Schuymered053432002-07-21 19:35:39 +00001205 if ( !(replace.counterchanges = (unsigned short *)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001206 malloc((replace.nentries + 1) * sizeof(unsigned short))) )
1207 print_memory();
Bart De Schuymered053432002-07-21 19:35:39 +00001208 cnt = replace.counterchanges;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001209 for (i = 0; i < replace.selected_hook; i++) {
Bart De Schuymer60332e02002-06-23 08:01:47 +00001210 if (i < NF_BR_NUMHOOKS && !(replace.valid_hooks & (1 << i)))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001211 continue;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001212 entries2 = nr_to_chain(i);
1213 for (j = 0; j < entries2->nentries; j++) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001214 *cnt = CNT_NORM;
1215 cnt++;
1216 }
1217 }
1218 for (i = 0; i < rule_nr; i++) {
1219 *cnt = CNT_NORM;
1220 cnt++;
1221 }
1222 *cnt = CNT_ADD;
1223 cnt++;
Bart De Schuymered053432002-07-21 19:35:39 +00001224 while (cnt != replace.counterchanges + replace.nentries) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001225 *cnt = CNT_NORM;
1226 cnt++;
1227 }
1228 *cnt = CNT_END;
1229
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001230 /*
1231 * go to the right position in the chain
1232 */
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001233 u_e = &entries->entries;
1234 for (i = 0; i < rule_nr; i++)
1235 u_e = &(*u_e)->next;
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001236 /*
1237 * insert the rule
1238 */
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001239 new_entry->next = *u_e;
1240 *u_e = new_entry;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001241
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001242 /*
1243 * put the ebt_[match, watcher, target] pointers in place
1244 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001245 m_l = new_entry->m_list;
1246 while (m_l) {
1247 m_l->m = ((struct ebt_u_match *)m_l->m)->m;
1248 m_l = m_l->next;
1249 }
1250 w_l = new_entry->w_list;
1251 while (w_l) {
1252 w_l->w = ((struct ebt_u_watcher *)w_l->w)->w;
1253 w_l = w_l->next;
1254 }
1255 new_entry->t = ((struct ebt_u_target *)new_entry->t)->t;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001256
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001257 /*
1258 * update the counter_offset of chains behind this one
1259 */
Bart De Schuymer60332e02002-06-23 08:01:47 +00001260 i = replace.selected_hook;
1261 while (1) {
1262 i++;
1263 entries = nr_to_chain(i);
1264 if (!entries) {
1265 if (i < NF_BR_NUMHOOKS)
1266 continue;
1267 else
1268 break;
1269 } else
1270 entries->counter_offset++;
1271 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001272}
1273
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001274/*
1275 * execute command D
1276 */
Bart De Schuymercc440052002-11-06 21:10:33 +00001277static void delete_rule(int begin, int end)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001278{
Bart De Schuymercc440052002-11-06 21:10:33 +00001279 int j, lentmp = 0, nr_deletes;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001280 unsigned short *cnt;
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001281 struct ebt_u_entry **u_e, *u_e2;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001282 struct ebt_u_entries *entries = to_chain(), *entries2;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001283
Bart De Schuymer336f35e2003-05-22 20:53:12 +00001284 if (begin < 0)
Bart De Schuymerc3b97f52003-04-17 17:03:49 +00001285 begin += entries->nentries + 1;
Bart De Schuymerc3b97f52003-04-17 17:03:49 +00001286 if (end < 0)
1287 end += entries->nentries + 1;
Bart De Schuymer1446c292003-05-25 09:47:01 +00001288
1289 if (begin < 0 || begin > end || end > entries->nentries)
Bart De Schuymerc3b97f52003-04-17 17:03:49 +00001290 print_error("Sorry, wrong rule numbers");
Bart De Schuymer336f35e2003-05-22 20:53:12 +00001291
Bart De Schuymercc440052002-11-06 21:10:33 +00001292 if ((begin = check_rule_exists(begin)) == -1 ||
1293 (end = check_rule_exists(end)) == -1)
Bart De Schuymer60332e02002-06-23 08:01:47 +00001294 print_error("Sorry, rule does not exist");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001295
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001296 /*
1297 * we're deleting rules
1298 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001299 replace.num_counters = replace.nentries;
Bart De Schuymercc440052002-11-06 21:10:33 +00001300 nr_deletes = end - begin + 1;
1301 replace.nentries -= nr_deletes;
1302 entries->nentries -= nr_deletes;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001303
1304 if (replace.nentries) {
1305 for (j = 0; j < replace.selected_hook; j++) {
Bart De Schuymer60332e02002-06-23 08:01:47 +00001306 if (j < NF_BR_NUMHOOKS &&
1307 !(replace.valid_hooks & (1 << j)))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001308 continue;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001309 entries2 = nr_to_chain(j);
1310 lentmp += entries2->nentries;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001311 }
Bart De Schuymercc440052002-11-06 21:10:33 +00001312 lentmp += begin;
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001313 /*
1314 * +1 for CNT_END
1315 */
Bart De Schuymered053432002-07-21 19:35:39 +00001316 if ( !(replace.counterchanges = (unsigned short *)malloc(
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001317 (replace.num_counters + 1) * sizeof(unsigned short))) )
1318 print_memory();
Bart De Schuymered053432002-07-21 19:35:39 +00001319 cnt = replace.counterchanges;
Bart De Schuymercc440052002-11-06 21:10:33 +00001320 for (j = 0; j < lentmp; j++, cnt++)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001321 *cnt = CNT_NORM;
Bart De Schuymercc440052002-11-06 21:10:33 +00001322 for (j = 0; j < nr_deletes; j++, cnt++)
1323 *cnt = CNT_DEL;
1324
1325 for (j = 0; j < replace.num_counters - lentmp - nr_deletes;
1326 j++, cnt++)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001327 *cnt = CNT_NORM;
Bart De Schuymercc440052002-11-06 21:10:33 +00001328
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001329 *cnt = CNT_END;
1330 }
1331 else
1332 replace.num_counters = 0;
1333
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001334 /*
1335 * go to the right position in the chain
1336 */
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001337 u_e = &entries->entries;
Bart De Schuymercc440052002-11-06 21:10:33 +00001338 for (j = 0; j < begin; j++)
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001339 u_e = &(*u_e)->next;
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001340 /*
1341 * remove the rules
1342 */
Bart De Schuymercc440052002-11-06 21:10:33 +00001343 j = nr_deletes;
1344 while(j--) {
1345 u_e2 = *u_e;
1346 *u_e = (*u_e)->next;
Bart De Schuymer9895a8e2003-01-11 10:14:24 +00001347 /* free everything */
Bart De Schuymercc440052002-11-06 21:10:33 +00001348 free_u_entry(u_e2);
1349 free(u_e2);
1350 }
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001351
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001352 /*
1353 * update the counter_offset of chains behind this one
1354 */
Bart De Schuymercc440052002-11-06 21:10:33 +00001355 j = replace.selected_hook;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001356 while (1) {
Bart De Schuymercc440052002-11-06 21:10:33 +00001357 j++;
1358 entries = nr_to_chain(j);
Bart De Schuymer60332e02002-06-23 08:01:47 +00001359 if (!entries) {
Bart De Schuymercc440052002-11-06 21:10:33 +00001360 if (j < NF_BR_NUMHOOKS)
Bart De Schuymer60332e02002-06-23 08:01:47 +00001361 continue;
1362 else
1363 break;
Bart De Schuymercc440052002-11-06 21:10:33 +00001364 } else
1365 entries->counter_offset -= nr_deletes;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001366 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001367}
1368
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001369/*
1370 * execute command Z
1371 */
Bart De Schuymer62423742002-07-14 19:06:20 +00001372static void zero_counters(int zerochain)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001373{
1374
1375 if (zerochain == -1) {
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001376 /*
1377 * tell main() we don't update the counters
1378 * this results in tricking the kernel to zero its counters,
1379 * naively expecting userspace to update its counters. Muahahaha
1380 */
Bart De Schuymered053432002-07-21 19:35:39 +00001381 replace.counterchanges = NULL;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001382 replace.num_counters = 0;
1383 } else {
1384 int i, j;
1385 unsigned short *cnt;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001386 struct ebt_u_entries *entries = nr_to_chain(zerochain), *e2;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001387
Bart De Schuymer60332e02002-06-23 08:01:47 +00001388 if (entries->nentries == 0)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001389 exit(0);
Bart De Schuymered053432002-07-21 19:35:39 +00001390 replace.counterchanges = (unsigned short *)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001391 malloc((replace.nentries + 1) * sizeof(unsigned short));
Bart De Schuymered053432002-07-21 19:35:39 +00001392 if (!replace.counterchanges)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001393 print_memory();
Bart De Schuymered053432002-07-21 19:35:39 +00001394 cnt = replace.counterchanges;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001395 for (i = 0; i < zerochain; i++) {
Bart De Schuymer60332e02002-06-23 08:01:47 +00001396 if (i < NF_BR_NUMHOOKS &&
1397 !(replace.valid_hooks & (1 << i)))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001398 continue;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001399 e2 = nr_to_chain(i);
1400 for (j = 0; j < e2->nentries; j++) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001401 *cnt = CNT_NORM;
1402 cnt++;
1403 }
1404 }
Bart De Schuymer60332e02002-06-23 08:01:47 +00001405 for (i = 0; i < entries->nentries; i++) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001406 *cnt = CNT_ZERO;
1407 cnt++;
1408 }
Bart De Schuymered053432002-07-21 19:35:39 +00001409 while (cnt != replace.counterchanges + replace.nentries) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001410 *cnt = CNT_NORM;
1411 cnt++;
1412 }
1413 *cnt = CNT_END;
1414 }
1415}
1416
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001417/*
1418 * Checks the type for validity and calls getethertypebynumber()
1419 */
1420struct ethertypeent *parseethertypebynumber(int type)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001421{
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001422 if (type < 1536)
1423 print_error("Ethernet protocols have values >= 0x0600");
1424 if (type > 0xffff)
1425 print_error("Ethernet protocols have values <= 0xffff");
1426 return getethertypebynumber(type);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001427}
1428
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001429/*
1430 * put the mac address into 6 (ETH_ALEN) bytes
Bart De Schuymer09441f72003-07-17 20:09:22 +00001431 * returns 0 on success
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001432 */
Bart De Schuymer09441f72003-07-17 20:09:22 +00001433int get_mac_and_mask(char *from, char *to, char *mask)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001434{
1435 char *p;
1436 int i;
Bart De Schuymer41830412002-06-05 19:41:28 +00001437 struct ether_addr *addr;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001438
1439 if (strcasecmp(from, "Unicast") == 0) {
1440 memcpy(to, mac_type_unicast, ETH_ALEN);
1441 memcpy(mask, msk_type_unicast, ETH_ALEN);
1442 return 0;
1443 }
1444 if (strcasecmp(from, "Multicast") == 0) {
1445 memcpy(to, mac_type_multicast, ETH_ALEN);
1446 memcpy(mask, msk_type_multicast, ETH_ALEN);
1447 return 0;
1448 }
1449 if (strcasecmp(from, "Broadcast") == 0) {
1450 memcpy(to, mac_type_broadcast, ETH_ALEN);
1451 memcpy(mask, msk_type_broadcast, ETH_ALEN);
1452 return 0;
1453 }
Bart De Schuymer09441f72003-07-17 20:09:22 +00001454 if (strcasecmp(from, "BGA") == 0) {
1455 memcpy(to, mac_type_bridge_group, ETH_ALEN);
1456 memcpy(mask, msk_type_bridge_group, ETH_ALEN);
1457 return 0;
1458 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001459 if ( (p = strrchr(from, '/')) != NULL) {
1460 *p = '\0';
Bart De Schuymer41830412002-06-05 19:41:28 +00001461 if (!(addr = ether_aton(p + 1)))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001462 return -1;
Bart De Schuymer41830412002-06-05 19:41:28 +00001463 memcpy(mask, addr, ETH_ALEN);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001464 } else
1465 memset(mask, 0xff, ETH_ALEN);
Bart De Schuymer41830412002-06-05 19:41:28 +00001466 if (!(addr = ether_aton(from)))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001467 return -1;
Bart De Schuymer41830412002-06-05 19:41:28 +00001468 memcpy(to, addr, ETH_ALEN);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001469 for (i = 0; i < ETH_ALEN; i++)
1470 to[i] &= mask[i];
1471 return 0;
1472}
1473
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001474/*
1475 * executes the final_check() function for all extensions used by the rule
1476 */
Bart De Schuymer62423742002-07-14 19:06:20 +00001477static void do_final_checks(struct ebt_u_entry *e, struct ebt_u_entries *entries)
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +00001478{
1479 struct ebt_u_match_list *m_l;
1480 struct ebt_u_watcher_list *w_l;
1481 struct ebt_u_target *t;
1482 struct ebt_u_match *m;
1483 struct ebt_u_watcher *w;
1484
1485 m_l = e->m_list;
1486 w_l = e->w_list;
1487 while (m_l) {
1488 m = find_match(m_l->m->u.name);
1489 m->final_check(e, m_l->m, replace.name,
1490 entries->hook_mask, 1);
1491 m_l = m_l->next;
1492 }
1493 while (w_l) {
1494 w = find_watcher(w_l->w->u.name);
1495 w->final_check(e, w_l->w, replace.name,
1496 entries->hook_mask, 1);
1497 w_l = w_l->next;
1498 }
1499 t = find_target(e->t->u.name);
1500 t->final_check(e, e->t, replace.name,
1501 entries->hook_mask, 1);
1502}
1503
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001504/*
1505 * used for the -X command
Bart De Schuymer90f2c2e2003-07-13 18:48:02 +00001506 * type = 0 => update chain jumps
1507 * type = 1 => check for reference
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001508 */
Bart De Schuymer90f2c2e2003-07-13 18:48:02 +00001509static int iterate_entries(int chain_nr, int silent, int type)
Bart De Schuymerb909f9b2002-06-26 18:35:31 +00001510{
1511 int i = -1, j;
1512 struct ebt_u_entries *entries;
1513 struct ebt_u_entry *e;
1514
1515 while (1) {
1516 i++;
1517 entries = nr_to_chain(i);
1518 if (!entries) {
1519 if (i < NF_BR_NUMHOOKS)
1520 continue;
1521 else
1522 break;
1523 }
1524 e = entries->entries;
1525 j = 0;
1526 while (e) {
Bart De Schuymerc27432e2003-01-09 22:01:07 +00001527 int chain_jmp;
1528
Bart De Schuymerb909f9b2002-06-26 18:35:31 +00001529 j++;
1530 if (strcmp(e->t->u.name, EBT_STANDARD_TARGET)) {
1531 e = e->next;
1532 continue;
1533 }
Bart De Schuymerc27432e2003-01-09 22:01:07 +00001534 chain_jmp = ((struct ebt_standard_target *)e->t)->verdict;
Bart De Schuymer90f2c2e2003-07-13 18:48:02 +00001535 switch (type) {
1536 case 1:
1537 if (chain_jmp == chain_nr) {
1538 if (silent)
1539 return 1;
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 Schuymer90f2c2e2003-07-13 18:48:02 +00001542 }
1543 break;
1544 case 0:
Bart De Schuymerc27432e2003-01-09 22:01:07 +00001545 /* adjust the chain jumps when necessary */
1546 if (chain_jmp > chain_nr)
1547 ((struct ebt_standard_target *)e->t)->verdict--;
Bart De Schuymer90f2c2e2003-07-13 18:48:02 +00001548 break;
1549 } /* end switch */
Bart De Schuymerb909f9b2002-06-26 18:35:31 +00001550 e = e->next;
1551 }
1552 }
Bart De Schuymer90f2c2e2003-07-13 18:48:02 +00001553 return 0;
1554}
1555
1556static void decrease_chain_jumps(int chain_nr)
1557{
1558 iterate_entries(chain_nr, 1, 0);
1559}
1560
1561static int check_for_references(int chain_nr, int silent)
1562{
1563 return iterate_entries(chain_nr, silent, 1);
1564}
1565
1566static int *determine_referenced_chains(int *n)
1567{
1568 int *nrs, i = 0, j = 0;
1569
1570 *n = 0;
1571 while (nr_to_chain(i + NF_BR_NUMHOOKS)) {
1572 if (check_for_references(i, 1))
1573 (*n)++;
1574 i++;
1575 }
1576 if (*n == 0)
1577 return NULL;
1578 nrs = malloc(*n * sizeof(int));
1579 i = 0;
1580 while (nr_to_chain(i + NF_BR_NUMHOOKS)) {
1581 if (check_for_references(i, 1)) {
1582 nrs[j] = i;
1583 j++;
1584 }
1585 i++;
1586 }
1587 return nrs;
1588}
1589
1590static void remove_udc(int udc_nr)
1591{
1592 struct ebt_u_chain_list *cl, **cl2;
1593 struct ebt_u_entries *entries;
1594 struct ebt_u_entry *u_e, *tmp;
1595
1596 /* first free the rules */
1597 entries = nr_to_chain(udc_nr + NF_BR_NUMHOOKS);
1598 u_e = entries->entries;
1599 while (u_e) {
1600 free_u_entry(u_e);
1601 tmp = u_e->next;
1602 free(u_e);
1603 u_e = tmp;
1604 }
1605
1606 /* next, remove the chain */
1607 cl2 = &(replace.udc);
1608 while ((*cl2)->udc != entries)
1609 cl2 = &((*cl2)->next);
1610 cl = (*cl2);
1611 (*cl2) = (*cl2)->next;
1612 free(cl->udc);
1613 free(cl);
1614}
1615
1616/* Removes all udc that aren't referenced at the time of execution */
1617static void delete_all_user_chains()
1618{
1619 struct ebt_u_chain_list *chain;
1620 int *ref, nr_ref, chain_nr = 0, counter_offset, i;
1621 struct ebt_u_entries *entries;
1622
1623 /* initialize counterchanges */
1624 counters_nochange();
1625
1626 ref = determine_referenced_chains(&nr_ref);
1627
1628 chain = replace.udc;
1629 counter_offset = 0;
1630 /* skip the standard chains */
1631 for (i = 0; i < NF_BR_NUMHOOKS; i++)
1632 if ((entries = nr_to_chain(i)) != NULL)
1633 counter_offset += entries->nentries;
1634
1635 /* first update chain jumps and counterchanges */
1636 while (chain) {
1637 int nentries;
1638
1639 nentries = chain->udc->nentries;
1640 for (i = 0; i < nr_ref; i++)
1641 if (ref[i] == chain_nr)
1642 goto letscontinue;
1643 decrease_chain_jumps(chain_nr);
1644 for (i = counter_offset; i < counter_offset + nentries; i++)
1645 replace.counterchanges[i] = CNT_DEL;
1646 replace.nentries -= nentries;
1647letscontinue:
1648 counter_offset += nentries;
1649 chain = chain->next;
1650 chain_nr++;
1651 }
1652 chain = replace.udc;
1653 chain_nr = -1;
1654 /* next, remove the chains, update the counter offset of
1655 * non-removed chains */
1656 counter_offset = 0;
1657 while (chain) {
1658 int real_cn = 0;
1659
1660 chain_nr++;
1661 for (i = 0; i < nr_ref; i++)
1662 if (ref[i] == chain_nr)
1663 break;
1664 if (i != nr_ref) {
1665 real_cn++;
1666 chain->udc->counter_offset -= counter_offset;
1667 chain = chain->next;
1668 continue;
1669 }
1670 counter_offset += chain->udc->nentries;
1671 chain = chain->next;
1672 remove_udc(real_cn);
1673 }
Bart De Schuymerb909f9b2002-06-26 18:35:31 +00001674}
1675
Bart De Schuymercc440052002-11-06 21:10:33 +00001676static int parse_delete_rule(const char *argv, int *rule_nr, int *rule_nr_end)
1677{
1678 char *colon = strchr(argv, ':'), *buffer;
1679
1680 if (colon) {
1681 *colon = '\0';
1682 if (*(colon + 1) == '\0')
Bart De Schuymerc3b97f52003-04-17 17:03:49 +00001683 *rule_nr_end = -1; /* until the last rule */
Bart De Schuymercc440052002-11-06 21:10:33 +00001684 else {
1685 *rule_nr_end = strtol(colon + 1, &buffer, 10);
Bart De Schuymerc3b97f52003-04-17 17:03:49 +00001686 if (*buffer != '\0' || *rule_nr_end == 0)
Bart De Schuymercc440052002-11-06 21:10:33 +00001687 return -1;
1688 }
1689 }
1690 if (colon == argv)
Bart De Schuymerc3b97f52003-04-17 17:03:49 +00001691 *rule_nr = 1; /* beginning with the first rule */
Bart De Schuymercc440052002-11-06 21:10:33 +00001692 else {
1693 *rule_nr = strtol(argv, &buffer, 10);
Bart De Schuymerc3b97f52003-04-17 17:03:49 +00001694 if (*buffer != '\0' || *rule_nr == 0)
Bart De Schuymercc440052002-11-06 21:10:33 +00001695 return -1;
1696 }
1697 if (!colon)
1698 *rule_nr_end = *rule_nr;
Bart De Schuymercc440052002-11-06 21:10:33 +00001699 return 0;
1700}
1701
Bart De Schuymera615b962002-11-03 14:54:09 +00001702static int invert = 0;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001703int check_inverse(const char option[])
1704{
1705 if (strcmp(option, "!") == 0) {
Bart De Schuymera615b962002-11-03 14:54:09 +00001706 if (invert == 1)
1707 print_error("double use of '!' not allowed");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001708 optind++;
Bart De Schuymera615b962002-11-03 14:54:09 +00001709 invert = 1;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001710 return 1;
1711 }
Bart De Schuymera615b962002-11-03 14:54:09 +00001712 return invert;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001713}
1714
1715void check_option(unsigned int *flags, unsigned int mask)
1716{
1717 if (*flags & mask)
1718 print_error("Multiple use of same option not allowed");
1719 *flags |= mask;
1720}
1721
Bart De Schuymer0cb01792003-05-04 16:52:04 +00001722static void get_kernel_table()
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001723{
1724 if ( !(table = find_table(replace.name)) )
1725 print_error("Bad table name");
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001726 /*
1727 * get the kernel's information
1728 */
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001729 if (get_table(&replace)) {
Bart De Schuymer0cb01792003-05-04 16:52:04 +00001730 ebtables_insmod("ebtables");
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001731 if (get_table(&replace))
1732 print_error("The kernel doesn't support the ebtables "
1733 "%s table", replace.name);
1734 }
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001735 /*
Bart De Schuymer5885b362002-12-03 20:51:36 +00001736 * when listing a table contained in a file, we don't demand that
1737 * the user knows the table's name
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001738 */
Bart De Schuymer62a7fdb2002-08-24 21:01:21 +00001739 if ( !(table = find_table(replace.name)) )
1740 print_error("Bad table name");
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001741}
1742
Bart De Schuymerc5075142002-08-18 14:21:19 +00001743#define print_if_l_error print_error("Interface name length must be less " \
1744 "than %d", IFNAMSIZ)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001745#define OPT_COMMAND 0x01
1746#define OPT_TABLE 0x02
1747#define OPT_IN 0x04
1748#define OPT_OUT 0x08
1749#define OPT_JUMP 0x10
1750#define OPT_PROTOCOL 0x20
1751#define OPT_SOURCE 0x40
1752#define OPT_DEST 0x80
1753#define OPT_ZERO 0x100
1754#define OPT_LOGICALIN 0x200
1755#define OPT_LOGICALOUT 0x400
Bart De Schuymer5885b362002-12-03 20:51:36 +00001756/* the main thing */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001757int main(int argc, char *argv[])
1758{
Bart De Schuymer923a5732002-08-11 12:01:33 +00001759 char *buffer;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001760 int c, i;
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001761 /*
1762 * this special one for the -Z option (we can have -Z <this> -L <that>)
1763 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001764 int zerochain = -1;
Bart De Schuymerf8f8f292002-06-25 15:43:57 +00001765 int policy = 0;
Bart De Schuymerc3b97f52003-04-17 17:03:49 +00001766 int rule_nr = 0; /* used for -[D,I] */
1767 int rule_nr_end = 0; /* used for -I */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001768 struct ebt_u_target *t;
1769 struct ebt_u_match *m;
1770 struct ebt_u_watcher *w;
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001771 struct ebt_u_match_list *m_l;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001772 struct ebt_u_watcher_list *w_l;
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001773 struct ebt_u_entries *entries;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001774
Bart De Schuymera615b962002-11-03 14:54:09 +00001775 opterr = 0;
1776
Bart De Schuymer5885b362002-12-03 20:51:36 +00001777 replace.filename = getenv(ATOMIC_ENV_VARIABLE);
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001778 /*
1779 * initialize the table name, OPT_ flags, selected hook and command
1780 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001781 strcpy(replace.name, "filter");
1782 replace.flags = 0;
1783 replace.selected_hook = -1;
1784 replace.command = 'h';
Bart De Schuymered053432002-07-21 19:35:39 +00001785 replace.counterchanges = NULL;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001786
1787 new_entry = (struct ebt_u_entry *)malloc(sizeof(struct ebt_u_entry));
1788 if (!new_entry)
1789 print_memory();
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001790 /*
1791 * put some sane values in our new entry
1792 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001793 initialize_entry(new_entry);
1794
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001795 /*
1796 * The scenario induced by this loop makes that:
1797 * '-t' ,'-M' and --atomic (if specified) have to come
1798 * before '-A' and the like
1799 */
Bart De Schuymer60332e02002-06-23 08:01:47 +00001800
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001801 /*
1802 * getopt saves the day
1803 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001804 while ((c = getopt_long(argc, argv,
Bart De Schuymer90f2c2e2003-07-13 18:48:02 +00001805 "-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 +00001806 switch (c) {
1807
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001808 case 'A': /* add a rule */
1809 case 'D': /* delete a rule */
1810 case 'P': /* define policy */
1811 case 'I': /* insert a rule */
1812 case 'N': /* make a user defined chain */
1813 case 'E': /* rename chain */
1814 case 'X': /* delete chain */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001815 replace.command = c;
1816 if (replace.flags & OPT_COMMAND)
1817 print_error("Multiple commands not allowed");
1818 replace.flags |= OPT_COMMAND;
Bart De Schuymer0cb01792003-05-04 16:52:04 +00001819 get_kernel_table();
Bart De Schuymer90f2c2e2003-07-13 18:48:02 +00001820 if (optarg && (optarg[0] == '-' ||
1821 !strcmp(optarg, "!")))
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001822 print_error("No chain name specified");
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001823 if (c == 'N') {
1824 struct ebt_u_chain_list *cl, **cl2;
1825
1826 if (get_hooknr(optarg) != -1)
1827 print_error("Chain %s already exists",
1828 optarg);
1829 if (find_target(optarg))
1830 print_error("Target with name %s exists"
1831 , optarg);
1832 if (strlen(optarg) >= EBT_CHAIN_MAXNAMELEN)
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001833 print_error("Chain name length can't exceed %d",
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001834 EBT_CHAIN_MAXNAMELEN - 1);
1835 cl = (struct ebt_u_chain_list *)
1836 malloc(sizeof(struct ebt_u_chain_list));
1837 if (!cl)
1838 print_memory();
1839 cl->next = NULL;
1840 cl->udc = (struct ebt_u_entries *)
1841 malloc(sizeof(struct ebt_u_entries));
1842 if (!cl->udc)
1843 print_memory();
1844 cl->udc->nentries = 0;
1845 cl->udc->policy = EBT_ACCEPT;
1846 cl->udc->counter_offset = replace.nentries;
1847 cl->udc->hook_mask = 0;
1848 strcpy(cl->udc->name, optarg);
1849 cl->udc->entries = NULL;
1850 cl->kernel_start = NULL;
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001851 /*
1852 * put the new chain at the end
1853 */
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001854 cl2 = &replace.udc;
1855 while (*cl2)
1856 cl2 = &((*cl2)->next);
1857 *cl2 = cl;
Bart De Schuymerb6c94f92003-06-14 13:08:03 +00001858 counters_nochange();
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001859 break;
1860 }
Bart De Schuymer90f2c2e2003-07-13 18:48:02 +00001861 if (c == 'X') {
1862 char *opt;
1863 int udc_nr;
1864
1865 if (!optarg && (optind >= argc ||
Bart De Schuymerf3196482003-07-25 12:53:17 +00001866 (argv[optind][0] == '-'
Bart De Schuymer90f2c2e2003-07-13 18:48:02 +00001867 && strcmp(argv[optind], "!")))) {
1868 delete_all_user_chains();
1869 break;
1870 }
1871 if (optarg)
1872 opt = optarg;
1873 else {
1874 opt = argv[optind];
1875 optind++;
1876 }
1877 if ((replace.selected_hook = get_hooknr(opt)) == -1)
1878 print_error("Chain %s doesn't exist", optarg);
1879 if (replace.selected_hook < NF_BR_NUMHOOKS)
1880 print_error("You can't remove a standard chain");
1881 /*
1882 * if the chain is referenced, don't delete it,
1883 * also decrement jumps to a chain behind the
1884 * one we're deleting
1885 */
1886 udc_nr=replace.selected_hook-NF_BR_NUMHOOKS;
1887 check_for_references(udc_nr, 0);
1888 decrease_chain_jumps(udc_nr);
1889 if (flush_chains() == -1)
1890 counters_nochange();
1891 remove_udc(udc_nr);
1892 break;
1893 }
1894
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001895 if ((replace.selected_hook = get_hooknr(optarg)) == -1)
1896 print_error("Chain %s doesn't exist", optarg);
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001897 if (c == 'E') {
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001898 if (optind >= argc || argv[optind][0] == '-' ||
1899 !strcmp(argv[optind], "!"))
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001900 print_error("No new chain name specified");
1901 if (strlen(argv[optind]) >= EBT_CHAIN_MAXNAMELEN)
1902 print_error("Chain name len can't exceed %d",
1903 EBT_CHAIN_MAXNAMELEN - 1);
1904 if (get_hooknr(argv[optind]) != -1)
1905 print_error("Chain %s already exists",
1906 argv[optind]);
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001907 if (find_target(argv[optind]))
1908 print_error("Target with name %s exists"
1909 , argv[optind]);
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001910 entries = to_chain();
1911 strcpy(entries->name, argv[optind]);
Bart De Schuymerb6c94f92003-06-14 13:08:03 +00001912 counters_nochange();
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001913 optind++;
1914 break;
1915 }
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001916
Bart De Schuymercc440052002-11-06 21:10:33 +00001917 if (c == 'D' && optind < argc &&
Bart De Schuymerc3b97f52003-04-17 17:03:49 +00001918 (argv[optind][0] != '-' ||
1919 (argv[optind][1] >= '0' && argv[optind][1] <= '9'))) {
Bart De Schuymercc440052002-11-06 21:10:33 +00001920 if (parse_delete_rule(argv[optind],
1921 &rule_nr, &rule_nr_end))
1922 print_error("Problem with the "
1923 "specified rule number(s)");
1924 optind++;
1925 }
1926 if (c == 'I') {
Bart De Schuymerc3b97f52003-04-17 17:03:49 +00001927 if (optind >= argc || (argv[optind][0] == '-' &&
1928 (argv[optind][1] < '0' || argv[optind][1] > '9')))
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001929 print_error("No rulenr for -I"
1930 " specified");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001931 rule_nr = strtol(argv[optind], &buffer, 10);
Bart De Schuymerc3b97f52003-04-17 17:03:49 +00001932 if (*buffer != '\0')
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001933 print_error("Problem with the "
1934 "specified rule number");
1935 optind++;
1936 }
1937 if (c == 'P') {
1938 if (optind >= argc)
1939 print_error("No policy specified");
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001940 policy = 0;
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001941 for (i = 0; i < NUM_STANDARD_TARGETS; i++)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001942 if (!strcmp(argv[optind],
1943 standard_targets[i])) {
Bart De Schuymer60332e02002-06-23 08:01:47 +00001944 policy = -i -1;
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001945 if (policy == EBT_CONTINUE)
1946 policy = 0;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001947 break;
1948 }
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001949 if (policy == 0)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001950 print_error("Wrong policy");
1951 optind++;
1952 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001953 break;
1954
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001955 case 'L': /* list */
1956 case 'F': /* flush */
1957 case 'Z': /* zero counters */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001958 if (c == 'Z') {
1959 if (replace.flags & OPT_ZERO)
1960 print_error("Multiple commands"
1961 " not allowed");
1962 if ( (replace.flags & OPT_COMMAND &&
1963 replace.command != 'L'))
1964 print_error("command -Z only allowed "
1965 "together with command -L");
1966 replace.flags |= OPT_ZERO;
1967 } else {
1968 replace.command = c;
1969 if (replace.flags & OPT_COMMAND)
1970 print_error("Multiple commands"
1971 " not allowed");
1972 replace.flags |= OPT_COMMAND;
1973 }
Bart De Schuymer0cb01792003-05-04 16:52:04 +00001974 get_kernel_table();
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001975 i = -1;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001976 if (optarg) {
1977 if ( (i = get_hooknr(optarg)) == -1 )
1978 print_error("Bad chain");
1979 } else
1980 if (optind < argc && argv[optind][0] != '-') {
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001981 if ((i = get_hooknr(argv[optind])) == -1)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001982 print_error("Bad chain");
1983 optind++;
1984 }
1985 if (i != -1) {
1986 if (c == 'Z')
1987 zerochain = i;
1988 else
1989 replace.selected_hook = i;
1990 }
1991 break;
1992
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001993 case 'V': /* version */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001994 replace.command = 'V';
1995 if (replace.flags & OPT_COMMAND)
1996 print_error("Multiple commands not allowed");
Bart De Schuymer57a3f6a2003-04-01 16:59:33 +00001997 PRINT_VERSION;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001998 exit(0);
1999
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002000 case 'M': /* modprobe */
Bart De Schuymer60332e02002-06-23 08:01:47 +00002001 if (replace.command != 'h')
2002 print_error("Please put the -M option earlier");
Bart De Schuymerc8531032002-06-14 21:55:29 +00002003 modprobe = optarg;
2004 break;
2005
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002006 case 'h': /* help */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002007 if (replace.flags & OPT_COMMAND)
2008 print_error("Multiple commands not allowed");
2009 replace.command = 'h';
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002010 /*
2011 * All other arguments should be extension names
2012 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002013 while (optind < argc) {
2014 struct ebt_u_match *m;
2015 struct ebt_u_watcher *w;
2016
Bart De Schuymer9a0fbf22003-01-11 16:16:54 +00002017 if (!strcasecmp("list_extensions",
2018 argv[optind]))
2019 list_extensions();
2020
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002021 if ((m = find_match(argv[optind])))
2022 add_match(m);
2023 else if ((w = find_watcher(argv[optind])))
2024 add_watcher(w);
2025 else {
2026 if (!(t = find_target(argv[optind])))
2027 print_error("Extension %s "
2028 "not found", argv[optind]);
2029 if (replace.flags & OPT_JUMP)
2030 print_error("Sorry, you can "
2031 "only see help for one "
2032 "target extension each time");
2033 replace.flags |= OPT_JUMP;
2034 new_entry->t =
2035 (struct ebt_entry_target *)t;
2036 }
2037 optind++;
2038 }
2039 break;
2040
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002041 case 't': /* table */
Bart De Schuymer60332e02002-06-23 08:01:47 +00002042 if (replace.command != 'h')
2043 print_error("Please put the -t option first");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002044 check_option(&replace.flags, OPT_TABLE);
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00002045 if (strlen(optarg) > EBT_TABLE_MAXNAMELEN - 1)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002046 print_error("Table name too long");
2047 strcpy(replace.name, optarg);
2048 break;
2049
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002050 case 'i': /* input interface */
2051 case 2 : /* logical input interface */
2052 case 'o': /* output interface */
2053 case 3 : /* logical output interface */
2054 case 'j': /* target */
2055 case 'p': /* net family protocol */
2056 case 's': /* source mac */
2057 case 'd': /* destination mac */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002058 if ((replace.flags & OPT_COMMAND) == 0)
2059 print_error("No command specified");
2060 if ( replace.command != 'A' &&
2061 replace.command != 'D' && replace.command != 'I')
2062 print_error("Command and option do not match");
2063 if (c == 'i') {
2064 check_option(&replace.flags, OPT_IN);
2065 if (replace.selected_hook > 2 &&
2066 replace.selected_hook < NF_BR_BROUTING)
2067 print_error("Use in-interface only in "
2068 "INPUT, FORWARD, PREROUTING and"
2069 "BROUTING chains");
2070 if (check_inverse(optarg))
2071 new_entry->invflags |= EBT_IIN;
2072
2073 if (optind > argc)
2074 print_error("No in-interface "
2075 "specified");
2076 if (strlen(argv[optind - 1]) >= IFNAMSIZ)
Bart De Schuymerc5075142002-08-18 14:21:19 +00002077 print_if_l_error;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002078 strcpy(new_entry->in, argv[optind - 1]);
2079 break;
2080 }
2081 if (c == 2) {
2082 check_option(&replace.flags, OPT_LOGICALIN);
2083 if (replace.selected_hook > 2 &&
2084 replace.selected_hook < NF_BR_BROUTING)
2085 print_error("Use logical in-interface "
2086 "only in INPUT, FORWARD, "
2087 "PREROUTING and BROUTING chains");
2088 if (check_inverse(optarg))
2089 new_entry->invflags |= EBT_ILOGICALIN;
2090
2091 if (optind > argc)
2092 print_error("No logical in-interface "
2093 "specified");
2094 if (strlen(argv[optind - 1]) >= IFNAMSIZ)
Bart De Schuymerc5075142002-08-18 14:21:19 +00002095 print_if_l_error;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002096 strcpy(new_entry->logical_in, argv[optind - 1]);
2097 break;
2098 }
2099 if (c == 'o') {
2100 check_option(&replace.flags, OPT_OUT);
2101 if (replace.selected_hook < 2)
2102 print_error("Use out-interface only"
2103 " in OUTPUT, FORWARD and "
2104 "POSTROUTING chains");
2105 if (check_inverse(optarg))
2106 new_entry->invflags |= EBT_IOUT;
2107
2108 if (optind > argc)
2109 print_error("No out-interface "
2110 "specified");
2111
2112 if (strlen(argv[optind - 1]) >= IFNAMSIZ)
Bart De Schuymerc5075142002-08-18 14:21:19 +00002113 print_if_l_error;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002114 strcpy(new_entry->out, argv[optind - 1]);
2115 break;
2116 }
2117 if (c == 3) {
2118 check_option(&replace.flags, OPT_LOGICALOUT);
2119 if (replace.selected_hook < 2)
2120 print_error("Use logical out-interface "
2121 "only in OUTPUT, FORWARD and "
2122 "POSTROUTING chains");
2123 if (check_inverse(optarg))
2124 new_entry->invflags |= EBT_ILOGICALOUT;
2125
2126 if (optind > argc)
2127 print_error("No logical out-interface "
2128 "specified");
2129
2130 if (strlen(argv[optind - 1]) >= IFNAMSIZ)
Bart De Schuymerc5075142002-08-18 14:21:19 +00002131 print_if_l_error;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002132 strcpy(new_entry->logical_out,
2133 argv[optind - 1]);
2134 break;
2135 }
2136 if (c == 'j') {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002137 check_option(&replace.flags, OPT_JUMP);
2138 for (i = 0; i < NUM_STANDARD_TARGETS; i++)
2139 if (!strcmp(optarg,
2140 standard_targets[i])) {
2141 t = find_target(
2142 EBT_STANDARD_TARGET);
2143 ((struct ebt_standard_target *)
Bart De Schuymer60332e02002-06-23 08:01:47 +00002144 t->t)->verdict = -i - 1;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002145 break;
2146 }
Bart De Schuymer60332e02002-06-23 08:01:47 +00002147 if (-i - 1 == EBT_RETURN) {
2148 if (replace.selected_hook < NF_BR_NUMHOOKS)
2149 print_error("Return target"
2150 " only for user defined chains");
2151 }
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +00002152 if (i != NUM_STANDARD_TARGETS)
2153 break;
Bart De Schuymer1ab41562002-06-23 17:09:54 +00002154 if ((i = get_hooknr(optarg)) != -1) {
2155 if (i < NF_BR_NUMHOOKS)
2156 print_error("don't jump"
2157 " to a standard chain");
2158 t = find_target(
2159 EBT_STANDARD_TARGET);
2160 ((struct ebt_standard_target *)
2161 t->t)->verdict = i - NF_BR_NUMHOOKS;
2162 break;
2163 }
2164 else {
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002165 /*
2166 * must be an extension then
2167 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002168 struct ebt_u_target *t;
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00002169
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002170 t = find_target(optarg);
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002171 /*
2172 * -j standard not allowed either
2173 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002174 if (!t || t ==
2175 (struct ebt_u_target *)new_entry->t)
2176 print_error("Illegal target "
2177 "name");
2178 new_entry->t =
2179 (struct ebt_entry_target *)t;
2180 }
2181 break;
2182 }
2183 if (c == 's') {
2184 check_option(&replace.flags, OPT_SOURCE);
2185 if (check_inverse(optarg))
2186 new_entry->invflags |= EBT_ISOURCE;
2187
2188 if (optind > argc)
2189 print_error("No source mac "
2190 "specified");
Bart De Schuymer09441f72003-07-17 20:09:22 +00002191 if (get_mac_and_mask(argv[optind - 1],
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002192 new_entry->sourcemac, new_entry->sourcemsk))
2193 print_error("Problem with specified "
2194 "source mac");
2195 new_entry->bitmask |= EBT_SOURCEMAC;
2196 break;
2197 }
2198 if (c == 'd') {
2199 check_option(&replace.flags, OPT_DEST);
2200 if (check_inverse(optarg))
2201 new_entry->invflags |= EBT_IDEST;
2202
2203 if (optind > argc)
2204 print_error("No destination mac "
2205 "specified");
Bart De Schuymer09441f72003-07-17 20:09:22 +00002206 if (get_mac_and_mask(argv[optind - 1],
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002207 new_entry->destmac, new_entry->destmsk))
2208 print_error("Problem with specified "
2209 "destination mac");
2210 new_entry->bitmask |= EBT_DESTMAC;
2211 break;
2212 }
2213 check_option(&replace.flags, OPT_PROTOCOL);
2214 if (check_inverse(optarg))
2215 new_entry->invflags |= EBT_IPROTO;
2216
2217 if (optind > argc)
2218 print_error("No protocol specified");
2219 new_entry->bitmask &= ~((unsigned int)EBT_NOPROTO);
2220 i = strtol(argv[optind - 1], &buffer, 16);
2221 if (*buffer == '\0' && (i < 0 || i > 0xFFFF))
2222 print_error("Problem with the specified "
2223 "protocol");
2224 new_entry->ethproto = i;
Bart De Schuymer28bf6f62002-06-26 18:57:24 +00002225 if (*buffer != '\0') {
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002226 struct ethertypeent *ent;
2227
2228 if (!strcasecmp(argv[optind - 1], "LENGTH")) {
2229 new_entry->bitmask |= EBT_802_3;
2230 break;
2231 }
2232 ent = getethertypebyname(argv[optind - 1]);
2233 if (!ent)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002234 print_error("Problem with the specified"
2235 " protocol");
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002236 new_entry->ethproto = ent->e_ethertype;
Bart De Schuymer28bf6f62002-06-26 18:57:24 +00002237 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002238 if (new_entry->ethproto < 1536 &&
2239 !(new_entry->bitmask & EBT_802_3))
2240 print_error("Sorry, protocols have values above"
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00002241 " or equal to 0x0600");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002242 break;
2243
Bart De Schuymer9895a8e2003-01-11 10:14:24 +00002244 case 4 : /* Lc */
Bart De Schuymer9af14f92002-07-10 20:49:10 +00002245 check_option(&replace.flags, LIST_C);
Bart De Schuymer9af14f92002-07-10 20:49:10 +00002246 if (replace.command != 'L')
2247 print_error("Use --Lc with -L");
2248 if (replace.flags & LIST_X)
2249 print_error("--Lx not compatible with --Lc");
2250 replace.flags |= LIST_C;
2251 break;
Bart De Schuymer9895a8e2003-01-11 10:14:24 +00002252 case 5 : /* Ln */
Bart De Schuymer9af14f92002-07-10 20:49:10 +00002253 check_option(&replace.flags, LIST_N);
Bart De Schuymer9af14f92002-07-10 20:49:10 +00002254 if (replace.command != 'L')
2255 print_error("Use --Ln with -L");
2256 if (replace.flags & LIST_X)
2257 print_error("--Lx not compatible with --Ln");
2258 replace.flags |= LIST_N;
2259 break;
Bart De Schuymer9895a8e2003-01-11 10:14:24 +00002260 case 6 : /* Lx */
Bart De Schuymer9af14f92002-07-10 20:49:10 +00002261 check_option(&replace.flags, LIST_X);
Bart De Schuymer9af14f92002-07-10 20:49:10 +00002262 if (replace.command != 'L')
2263 print_error("Use --Lx with -L");
2264 if (replace.flags & LIST_C)
2265 print_error("--Lx not compatible with --Lc");
2266 if (replace.flags & LIST_N)
2267 print_error("--Lx not compatible with --Ln");
2268 replace.flags |= LIST_X;
2269 break;
Bart De Schuymer22d03a22003-05-03 20:28:22 +00002270 case 12 : /* Lmac2 */
2271 check_option(&replace.flags, LIST_MAC2);
2272 if (replace.command != 'L')
2273 print_error("Use --Lmac2 with -L");
2274 replace.flags |= LIST_MAC2;
2275 break;
Bart De Schuymer9895a8e2003-01-11 10:14:24 +00002276 case 8 : /* atomic-commit */
Bart De Schuymer62423742002-07-14 19:06:20 +00002277 replace.command = c;
2278 if (replace.flags & OPT_COMMAND)
2279 print_error("Multiple commands not allowed");
2280 replace.flags |= OPT_COMMAND;
Bart De Schuymer5885b362002-12-03 20:51:36 +00002281 if (!replace.filename)
2282 print_error("No atomic file specified");
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002283 /*
2284 * get the information from the file
2285 */
Bart De Schuymer62423742002-07-14 19:06:20 +00002286 get_table(&replace);
Bart De Schuymer868bf642002-07-16 18:14:20 +00002287 if (replace.nentries) {
Bart De Schuymered053432002-07-21 19:35:39 +00002288 replace.counterchanges = (unsigned short *)
Bart De Schuymer868bf642002-07-16 18:14:20 +00002289 malloc(sizeof(unsigned short) * (replace.nentries + 1));
2290 for (i = 0; i < replace.nentries; i++)
Bart De Schuymered053432002-07-21 19:35:39 +00002291 replace.counterchanges[i] = CNT_NORM;
2292 replace.counterchanges[i] = CNT_END;
Bart De Schuymer868bf642002-07-16 18:14:20 +00002293 }
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002294 /*
2295 * we don't want the kernel giving us its counters, they would
2296 * overwrite the counters extracted from the file
2297 */
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00002298 replace.num_counters = 0;
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002299 /*
2300 * make sure the table will be written to the kernel
Bart De Schuymer5885b362002-12-03 20:51:36 +00002301 * possible memory leak here
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002302 */
Bart De Schuymer62423742002-07-14 19:06:20 +00002303 replace.filename = NULL;
2304 break;
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002305 case 7 : /* atomic-init */
2306 case 10: /* atomic-save */
2307 case 11: /* init-table */
Bart De Schuymer62423742002-07-14 19:06:20 +00002308 replace.command = c;
2309 if (replace.flags & OPT_COMMAND)
2310 print_error("Multiple commands not allowed");
Bart De Schuymer5885b362002-12-03 20:51:36 +00002311 if (c != 11 && !replace.filename)
2312 print_error("No atomic file specified");
Bart De Schuymer62423742002-07-14 19:06:20 +00002313 replace.flags |= OPT_COMMAND;
Bart De Schuymer5885b362002-12-03 20:51:36 +00002314 {
2315 char *tmp = replace.filename;
2316
2317 tmp = replace.filename;
2318 /* get the kernel table */
2319 replace.filename = NULL;
Bart De Schuymer0cb01792003-05-04 16:52:04 +00002320 get_kernel_table();
Bart De Schuymer5885b362002-12-03 20:51:36 +00002321 replace.filename = tmp;
2322 }
Bart De Schuymera8d920b2002-07-16 18:30:44 +00002323 if (replace.nentries) {
Bart De Schuymered053432002-07-21 19:35:39 +00002324 replace.counterchanges = (unsigned short *)
Bart De Schuymer5f16dc72002-07-16 18:08:36 +00002325 malloc(sizeof(unsigned short) * (replace.nentries + 1));
2326 for (i = 0; i < replace.nentries; i++)
Bart De Schuymered053432002-07-21 19:35:39 +00002327 replace.counterchanges[i] = CNT_NORM;
2328 replace.counterchanges[i] = CNT_END;
Bart De Schuymer5f16dc72002-07-16 18:08:36 +00002329 }
Bart De Schuymer5885b362002-12-03 20:51:36 +00002330 break;
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002331 case 9 : /* atomic */
Bart De Schuymer5885b362002-12-03 20:51:36 +00002332 if (replace.flags & OPT_COMMAND)
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00002333 print_error("--atomic has to come before"
2334 " the command");
Bart De Schuymer5885b362002-12-03 20:51:36 +00002335 /* another possible memory leak here */
Bart De Schuymer62423742002-07-14 19:06:20 +00002336 replace.filename = (char *)malloc(strlen(optarg) + 1);
2337 strcpy(replace.filename, optarg);
2338 break;
Bart De Schuymera615b962002-11-03 14:54:09 +00002339 case 1 :
2340 if (!strcmp(optarg, "!"))
2341 check_inverse(optarg);
2342 else
2343 print_error("Bad argument : %s", optarg);
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002344 /*
2345 * check_inverse() did optind++
2346 */
Bart De Schuymera615b962002-11-03 14:54:09 +00002347 optind--;
2348 continue;
Bart De Schuymer9af14f92002-07-10 20:49:10 +00002349 default:
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002350 /*
2351 * is it a target option?
2352 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002353 t = (struct ebt_u_target *)new_entry->t;
2354 if ((t->parse(c - t->option_offset, argv, argc,
2355 new_entry, &t->flags, &t->t)))
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00002356 goto check_extension;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002357
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002358 /*
2359 * is it a match_option?
2360 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002361 for (m = matches; m; m = m->next)
2362 if (m->parse(c - m->option_offset, argv,
2363 argc, new_entry, &m->flags, &m->m))
2364 break;
2365
2366 if (m != NULL) {
2367 if (m->used == 0)
2368 add_match(m);
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00002369 goto check_extension;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002370 }
2371
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002372 /*
2373 * is it a watcher option?
2374 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002375 for (w = watchers; w; w = w->next)
2376 if (w->parse(c-w->option_offset, argv,
2377 argc, new_entry, &w->flags, &w->w))
2378 break;
2379
2380 if (w == NULL)
2381 print_error("Unknown argument");
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00002382 if (w->used == 0)
2383 add_watcher(w);
2384check_extension:
Bart De Schuymer60332e02002-06-23 08:01:47 +00002385 if (replace.command != 'A' && replace.command != 'I' &&
2386 replace.command != 'D')
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00002387 print_error("Extensions only for -A, -I and -D");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002388 }
Bart De Schuymera615b962002-11-03 14:54:09 +00002389 invert = 0;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002390 }
2391
Bart De Schuymer25c741d2002-06-23 18:54:34 +00002392 if ( !table && !(table = find_table(replace.name)) )
2393 print_error("Bad table name");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002394
2395 if ( (replace.flags & OPT_COMMAND) && replace.command != 'L' &&
2396 replace.flags & OPT_ZERO )
2397 print_error("Command -Z only allowed together with command -L");
2398
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002399 /*
2400 * do this after parsing everything, so we can print specific info
2401 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002402 if (replace.command == 'h' && !(replace.flags & OPT_ZERO))
2403 print_help();
2404
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002405 /*
2406 * do the final checks
2407 */
Bart De Schuymer60332e02002-06-23 08:01:47 +00002408 if (replace.command == 'A' || replace.command == 'I' ||
2409 replace.command == 'D') {
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002410 /*
2411 * this will put the hook_mask right for the chains
2412 */
Bart De Schuymer60332e02002-06-23 08:01:47 +00002413 check_for_loops();
2414 entries = to_chain();
2415 m_l = new_entry->m_list;
2416 w_l = new_entry->w_list;
2417 t = (struct ebt_u_target *)new_entry->t;
2418 while (m_l) {
2419 m = (struct ebt_u_match *)(m_l->m);
2420 m->final_check(new_entry, m->m, replace.name,
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +00002421 entries->hook_mask, 0);
Bart De Schuymer60332e02002-06-23 08:01:47 +00002422 m_l = m_l->next;
2423 }
2424 while (w_l) {
2425 w = (struct ebt_u_watcher *)(w_l->w);
2426 w->final_check(new_entry, w->w, replace.name,
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +00002427 entries->hook_mask, 0);
Bart De Schuymer60332e02002-06-23 08:01:47 +00002428 w_l = w_l->next;
2429 }
2430 t->final_check(new_entry, t->t, replace.name,
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +00002431 entries->hook_mask, 0);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002432 }
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002433 /*
2434 * so, the extensions can work with the host endian
2435 * the kernel does not have to do this ofcourse
2436 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002437 new_entry->ethproto = htons(new_entry->ethproto);
2438
Bart De Schuymerc34f4672002-08-18 18:03:52 +00002439 if (replace.command == 'P') {
2440 if (replace.selected_hook < NF_BR_NUMHOOKS &&
2441 policy == EBT_RETURN)
2442 print_error("Policy RETURN only allowed for user "
2443 "defined chains");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002444 change_policy(policy);
Bart De Schuymerc34f4672002-08-18 18:03:52 +00002445 } else if (replace.command == 'L') {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002446 list_rules();
2447 if (replace.flags & OPT_ZERO)
2448 zero_counters(zerochain);
2449 else
2450 exit(0);
2451 }
2452 if (replace.flags & OPT_ZERO)
2453 zero_counters(zerochain);
Bart De Schuymer1ab41562002-06-23 17:09:54 +00002454 else if (replace.command == 'F') {
2455 if (flush_chains() == -1)
2456 exit(0);
2457 } else if (replace.command == 'A' || replace.command == 'I') {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002458 add_rule(rule_nr);
Bart De Schuymer1ab41562002-06-23 17:09:54 +00002459 check_for_loops();
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002460 /*
2461 * do the final_check(), for all entries
2462 * needed when adding a rule that has a chain target
2463 */
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +00002464 i = -1;
2465 while (1) {
2466 struct ebt_u_entry *e;
2467
2468 i++;
2469 entries = nr_to_chain(i);
2470 if (!entries) {
2471 if (i < NF_BR_NUMHOOKS)
2472 continue;
2473 else
2474 break;
2475 }
2476 e = entries->entries;
2477 while (e) {
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002478 /*
2479 * userspace extensions use host endian
2480 */
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +00002481 e->ethproto = ntohs(e->ethproto);
2482 do_final_checks(e, entries);
2483 e->ethproto = htons(e->ethproto);
2484 e = e->next;
2485 }
2486 }
Bart De Schuymerc3b97f52003-04-17 17:03:49 +00002487 } else if (replace.command == 'D')
Bart De Schuymercc440052002-11-06 21:10:33 +00002488 delete_rule(rule_nr, rule_nr_end);
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002489 /*
2490 * commands -N, -E, -X, --atomic-commit, --atomic-commit, --atomic-save,
2491 * --init-table fall through
2492 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002493
2494 if (table->check)
2495 table->check(&replace);
2496
2497 deliver_table(&replace);
2498
Bart De Schuymered053432002-07-21 19:35:39 +00002499 if (replace.counterchanges)
2500 deliver_counters(&replace);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002501 return 0;
2502}