blob: f33d2702bdb69bebd1b576a07e727ab66fc210db [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 Schuymer1abc55d2002-06-01 19:23:47 +000082 { "zero" , optional_argument, 0, 'Z' },
83 { "flush" , optional_argument, 0, 'F' },
84 { "policy" , required_argument, 0, 'P' },
85 { "in-interface" , required_argument, 0, 'i' },
86 { "in-if" , required_argument, 0, 'i' },
87 { "logical-in" , required_argument, 0, 2 },
88 { "logical-out" , required_argument, 0, 3 },
89 { "out-interface" , required_argument, 0, 'o' },
90 { "out-if" , required_argument, 0, 'o' },
91 { "version" , no_argument , 0, 'V' },
92 { "help" , no_argument , 0, 'h' },
93 { "jump" , required_argument, 0, 'j' },
94 { "proto" , required_argument, 0, 'p' },
95 { "protocol" , required_argument, 0, 'p' },
96 { "db" , required_argument, 0, 'b' },
97 { "source" , required_argument, 0, 's' },
98 { "src" , required_argument, 0, 's' },
99 { "destination" , required_argument, 0, 'd' },
100 { "dst" , required_argument, 0, 'd' },
101 { "table" , required_argument, 0, 't' },
Bart De Schuymerc8531032002-06-14 21:55:29 +0000102 { "modprobe" , required_argument, 0, 'M' },
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000103 { "new-chain" , required_argument, 0, 'N' },
104 { "rename-chain" , required_argument, 0, 'E' },
105 { "delete-chain" , required_argument, 0, 'X' },
Bart De Schuymer5885b362002-12-03 20:51:36 +0000106 { "atomic-init" , no_argument , 0, 7 },
107 { "atomic-commit" , no_argument , 0, 8 },
108 { "atomic-file" , required_argument, 0, 9 },
109 { "atomic-save" , no_argument , 0, 10 },
Bart De Schuymer8d1d8942002-07-15 20:09:09 +0000110 { "init-table" , no_argument , 0, 11 },
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000111 { 0 }
112};
113
114static struct option *ebt_options = ebt_original_options;
115
Bart De Schuymer62423742002-07-14 19:06:20 +0000116char* standard_targets[NUM_STANDARD_TARGETS] =
117{
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000118 "ACCEPT",
119 "DROP",
120 "CONTINUE",
Bart De Schuymer60332e02002-06-23 08:01:47 +0000121 "RETURN",
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000122};
123
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000124unsigned char mac_type_unicast[ETH_ALEN] = {0,0,0,0,0,0};
125unsigned char msk_type_unicast[ETH_ALEN] = {1,0,0,0,0,0};
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000126unsigned char mac_type_multicast[ETH_ALEN] = {1,0,0,0,0,0};
127unsigned char msk_type_multicast[ETH_ALEN] = {1,0,0,0,0,0};
128unsigned char mac_type_broadcast[ETH_ALEN] = {255,255,255,255,255,255};
129unsigned char msk_type_broadcast[ETH_ALEN] = {255,255,255,255,255,255};
130
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000131/*
132 * holds all the data
133 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000134static struct ebt_u_replace replace;
135
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000136/*
137 * the chosen table
138 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000139static struct ebt_u_table *table = NULL;
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000140/*
141 * the lists of supported tables, matches, watchers and targets
142 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000143static struct ebt_u_table *tables = NULL;
144static struct ebt_u_match *matches = NULL;
145static struct ebt_u_watcher *watchers = NULL;
146static struct ebt_u_target *targets = NULL;
147
148struct ebt_u_target *find_target(const char *name)
149{
150 struct ebt_u_target *t = targets;
151
152 while(t && strcmp(t->name, name))
153 t = t->next;
154 return t;
155}
156
157struct ebt_u_match *find_match(const char *name)
158{
159 struct ebt_u_match *m = matches;
160
161 while(m && strcmp(m->name, name))
162 m = m->next;
163 return m;
164}
165
166struct ebt_u_watcher *find_watcher(const char *name)
167{
168 struct ebt_u_watcher *w = watchers;
169
170 while(w && strcmp(w->name, name))
171 w = w->next;
172 return w;
173}
174
175struct ebt_u_table *find_table(char *name)
176{
177 struct ebt_u_table *t = tables;
178
179 while (t && strcmp(t->name, name))
180 t = t->next;
181 return t;
182}
183
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000184/*
185 * The pointers in here are special:
186 * The struct ebt_target * pointer is actually a struct ebt_u_target * pointer.
187 * instead of making yet a few other structs, we just do a cast.
188 * We need a struct ebt_u_target pointer because we know the address of the data
189 * they point to won't change. We want to allow that the struct ebt_u_target.t
190 * member can change.
191 * Same holds for the struct ebt_match and struct ebt_watcher pointers
192 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000193struct ebt_u_entry *new_entry;
194
Bart De Schuymer62423742002-07-14 19:06:20 +0000195static void initialize_entry(struct ebt_u_entry *e)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000196{
197 e->bitmask = EBT_NOPROTO;
198 e->invflags = 0;
199 e->ethproto = 0;
200 strcpy(e->in, "");
201 strcpy(e->out, "");
202 strcpy(e->logical_in, "");
203 strcpy(e->logical_out, "");
204 e->m_list = NULL;
205 e->w_list = NULL;
Bart De Schuymerc27432e2003-01-09 22:01:07 +0000206 /*
207 * the init function of the standard target should have put the verdict
208 * on CONTINUE
209 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000210 e->t = (struct ebt_entry_target *)find_target(EBT_STANDARD_TARGET);
211 if (!e->t)
Bart De Schuymerd4586482002-08-11 16:15:55 +0000212 print_bug("Couldn't load standard target");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000213}
214
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000215/*
216 * this doesn't free e, becoz the calling function might need e->next
217 */
Bart De Schuymer62423742002-07-14 19:06:20 +0000218static void free_u_entry(struct ebt_u_entry *e)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000219{
220 struct ebt_u_match_list *m_l, *m_l2;
221 struct ebt_u_watcher_list *w_l, *w_l2;
222
223 m_l = e->m_list;
224 while (m_l) {
225 m_l2 = m_l->next;
226 free(m_l->m);
227 free(m_l);
228 m_l = m_l2;
229 }
230 w_l = e->w_list;
231 while (w_l) {
232 w_l2 = w_l->next;
233 free(w_l->w);
234 free(w_l);
235 w_l = w_l2;
236 }
237 free(e->t);
238}
239
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000240/*
241 * the user will use the match, so put it in new_entry
242 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000243static void add_match(struct ebt_u_match *m)
244{
245 struct ebt_u_match_list **m_list, *new;
246
247 m->used = 1;
Bart De Schuymerc56a31a2002-07-25 08:16:08 +0000248 for (m_list = &new_entry->m_list; *m_list; m_list = &(*m_list)->next);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000249 new = (struct ebt_u_match_list *)
250 malloc(sizeof(struct ebt_u_match_list));
251 if (!new)
252 print_memory();
253 *m_list = new;
254 new->next = NULL;
255 new->m = (struct ebt_entry_match *)m;
256}
257
258static void add_watcher(struct ebt_u_watcher *w)
259{
260 struct ebt_u_watcher_list **w_list;
261 struct ebt_u_watcher_list *new;
262
263 w->used = 1;
Bart De Schuymerc56a31a2002-07-25 08:16:08 +0000264 for (w_list = &new_entry->w_list; *w_list; w_list = &(*w_list)->next);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000265 new = (struct ebt_u_watcher_list *)
266 malloc(sizeof(struct ebt_u_watcher_list));
267 if (!new)
268 print_memory();
269 *w_list = new;
270 new->next = NULL;
271 new->w = (struct ebt_entry_watcher *)w;
272}
273
274static int global_option_offset = 0;
275#define OPTION_OFFSET 256
276static struct option *
277merge_options(struct option *oldopts, const struct option *newopts,
278 unsigned int *options_offset)
279{
280 unsigned int num_old, num_new, i;
281 struct option *merge;
282
283 if (!newopts || !oldopts || !options_offset)
284 print_bug("merge wrong");
285 for (num_old = 0; oldopts[num_old].name; num_old++);
286 for (num_new = 0; newopts[num_new].name; num_new++);
287
288 global_option_offset += OPTION_OFFSET;
289 *options_offset = global_option_offset;
290
291 merge = malloc(sizeof(struct option) * (num_new + num_old + 1));
292 if (!merge)
293 print_memory();
294 memcpy(merge, oldopts, num_old * sizeof(struct option));
295 for (i = 0; i < num_new; i++) {
296 merge[num_old + i] = newopts[i];
297 merge[num_old + i].val += *options_offset;
298 }
299 memset(merge + num_old + num_new, 0, sizeof(struct option));
Bart De Schuymer9895a8e2003-01-11 10:14:24 +0000300 /* only free dynamically allocated stuff */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000301 if (oldopts != ebt_original_options)
302 free(oldopts);
303
304 return merge;
305}
306
307void register_match(struct ebt_u_match *m)
308{
309 int size = m->size + sizeof(struct ebt_entry_match);
310 struct ebt_u_match **i;
311
312 m->m = (struct ebt_entry_match *)malloc(size);
313 if (!m->m)
314 print_memory();
315 strcpy(m->m->u.name, m->name);
316 m->m->match_size = m->size;
317 ebt_options = merge_options
318 (ebt_options, m->extra_ops, &(m->option_offset));
319 m->init(m->m);
320
321 for (i = &matches; *i; i = &((*i)->next));
322 m->next = NULL;
323 *i = m;
324}
325
326void register_watcher(struct ebt_u_watcher *w)
327{
328 int size = w->size + sizeof(struct ebt_entry_watcher);
329 struct ebt_u_watcher **i;
330
331 w->w = (struct ebt_entry_watcher *)malloc(size);
332 if (!w->w)
333 print_memory();
334 strcpy(w->w->u.name, w->name);
335 w->w->watcher_size = w->size;
336 ebt_options = merge_options
337 (ebt_options, w->extra_ops, &(w->option_offset));
338 w->init(w->w);
339
340 for (i = &watchers; *i; i = &((*i)->next));
341 w->next = NULL;
342 *i = w;
343}
344
345void register_target(struct ebt_u_target *t)
346{
347 int size = t->size + sizeof(struct ebt_entry_target);
348 struct ebt_u_target **i;
349
350 t->t = (struct ebt_entry_target *)malloc(size);
351 if (!t->t)
352 print_memory();
353 strcpy(t->t->u.name, t->name);
354 t->t->target_size = t->size;
355 ebt_options = merge_options
356 (ebt_options, t->extra_ops, &(t->option_offset));
357 t->init(t->t);
Bart De Schuymerc56a31a2002-07-25 08:16:08 +0000358
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000359 for (i = &targets; *i; i = &((*i)->next));
360 t->next = NULL;
361 *i = t;
362}
363
364void register_table(struct ebt_u_table *t)
365{
366 t->next = tables;
367 tables = t;
368}
369
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000370/*
371 * blatently stolen (again) from iptables.c userspace program
372 * find out where the modprobe utility is located
373 */
Bart De Schuymerc8531032002-06-14 21:55:29 +0000374static char *get_modprobe(void)
375{
376 int procfile;
377 char *ret;
378
379 procfile = open(PROC_SYS_MODPROBE, O_RDONLY);
380 if (procfile < 0)
381 return NULL;
382
383 ret = malloc(1024);
384 if (ret) {
385 switch (read(procfile, ret, 1024)) {
386 case -1: goto fail;
387 case 1024: goto fail; /* Partial read. Wierd */
388 }
389 if (ret[strlen(ret)-1]=='\n')
390 ret[strlen(ret)-1]=0;
391 close(procfile);
392 return ret;
393 }
394 fail:
395 free(ret);
396 close(procfile);
397 return NULL;
398}
399
Bart De Schuymerc8531032002-06-14 21:55:29 +0000400int ebtables_insmod(const char *modname, const char *modprobe)
401{
402 char *buf = NULL;
403 char *argv[3];
404
Bart De Schuymer9895a8e2003-01-11 10:14:24 +0000405 /* If they don't explicitly set it, read out of kernel */
Bart De Schuymerc8531032002-06-14 21:55:29 +0000406 if (!modprobe) {
407 buf = get_modprobe();
408 if (!buf)
409 return -1;
410 modprobe = buf;
411 }
412
413 switch (fork()) {
414 case 0:
415 argv[0] = (char *)modprobe;
416 argv[1] = (char *)modname;
417 argv[2] = NULL;
418 execv(argv[0], argv);
419
420 /* not usually reached */
421 exit(0);
422 case -1:
423 return -1;
424
425 default: /* parent */
426 wait(NULL);
427 }
428
429 free(buf);
430 return 0;
431}
432
Bart De Schuymer9a0fbf22003-01-11 16:16:54 +0000433static void list_extensions()
434{
435 struct ebt_u_table *tbl = tables;
436 struct ebt_u_target *t = targets;
437 struct ebt_u_match *m = matches;
438 struct ebt_u_watcher *w = watchers;
439
Bart De Schuymer57a3f6a2003-04-01 16:59:33 +0000440 PRINT_VERSION;
Bart De Schuymer9a0fbf22003-01-11 16:16:54 +0000441 printf("Supported userspace extensions:\n\nSupported tables:\n");
442 while(tbl) {
443 printf("%s\n", tbl->name);
444 tbl = tbl->next;
445 }
446 printf("\nSupported targets:\n");
447 while(t) {
448 printf("%s\n", t->name);
449 t = t->next;
450 }
451 printf("\nSupported matches:\n");
452 while(m) {
453 printf("%s\n", m->name);
454 m = m->next;
455 }
456 printf("\nSupported watchers:\n");
457 while(w) {
458 printf("%s\n", w->name);
459 w = w->next;
460 }
461 exit(0);
462}
463
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000464/*
465 * we use replace.flags, so we can't use the following values:
466 * 0x01 == OPT_COMMAND, 0x02 == OPT_TABLE, 0x100 == OPT_ZERO
467 */
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000468#define LIST_N 0x04
469#define LIST_C 0x08
470#define LIST_X 0x10
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000471/*
472 * helper function for list_rules()
473 */
Bart De Schuymer60332e02002-06-23 08:01:47 +0000474static void list_em(struct ebt_u_entries *entries)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000475{
476 int i, j, space = 0, digits;
477 struct ebt_u_entry *hlp;
478 struct ebt_u_match_list *m_l;
479 struct ebt_u_watcher_list *w_l;
480 struct ebt_u_match *m;
481 struct ebt_u_watcher *w;
482 struct ebt_u_target *t;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000483
Bart De Schuymer60332e02002-06-23 08:01:47 +0000484 hlp = entries->entries;
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000485 if (replace.flags & LIST_X && entries->policy != EBT_ACCEPT) {
486 printf("ebtables -t %s -P %s %s\n", replace.name,
487 entries->name, standard_targets[-entries->policy - 1]);
488 } else if (!(replace.flags & LIST_X)) {
Bart De Schuymerc87c9642002-08-01 15:34:16 +0000489 printf("\nBridge chain: %s, entries: %d, policy: %s\n",
490 entries->name, entries->nentries,
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000491 standard_targets[-entries->policy - 1]);
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000492 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000493
Bart De Schuymer60332e02002-06-23 08:01:47 +0000494 i = entries->nentries;
Bart De Schuymerf8f8f292002-06-25 15:43:57 +0000495 while (i > 9) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000496 space++;
497 i /= 10;
498 }
499
Bart De Schuymer60332e02002-06-23 08:01:47 +0000500 for (i = 0; i < entries->nentries; i++) {
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000501 if (replace.flags & LIST_N) {
502 digits = 0;
Bart De Schuymer9895a8e2003-01-11 10:14:24 +0000503 /* A little work to get nice rule numbers. */
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000504 j = i + 1;
505 while (j > 9) {
506 digits++;
507 j /= 10;
508 }
509 for (j = 0; j < space - digits; j++)
510 printf(" ");
511 printf("%d. ", i + 1);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000512 }
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000513 if (replace.flags & LIST_X)
514 printf("ebtables -t %s -A %s ",
515 replace.name, entries->name);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000516
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000517 /*
518 * Don't print anything about the protocol if no protocol was
519 * specified, obviously this means any protocol will do.
520 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000521 if (!(hlp->bitmask & EBT_NOPROTO)) {
Bart De Schuymer60332e02002-06-23 08:01:47 +0000522 printf("-p ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000523 if (hlp->invflags & EBT_IPROTO)
524 printf("! ");
525 if (hlp->bitmask & EBT_802_3)
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000526 printf("Length ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000527 else {
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000528 struct ethertypeent *ent;
529
530 ent = getethertypebynumber(ntohs(hlp->ethproto));
531 if (!ent)
Bart De Schuymer60332e02002-06-23 08:01:47 +0000532 printf("0x%x ", ntohs(hlp->ethproto));
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000533 else
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000534 printf("%s ", ent->e_name);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000535 }
536 }
537 if (hlp->bitmask & EBT_SOURCEMAC) {
538 char hlpmsk[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
539
Bart De Schuymer60332e02002-06-23 08:01:47 +0000540 printf("-s ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000541 if (hlp->invflags & EBT_ISOURCE)
542 printf("! ");
543 if (!memcmp(hlp->sourcemac, mac_type_unicast, 6) &&
544 !memcmp(hlp->sourcemsk, msk_type_unicast, 6)) {
545 printf("Unicast");
546 goto endsrc;
547 }
548 if (!memcmp(hlp->sourcemac, mac_type_multicast, 6) &&
549 !memcmp(hlp->sourcemsk, msk_type_multicast, 6)) {
550 printf("Multicast");
551 goto endsrc;
552 }
553 if (!memcmp(hlp->sourcemac, mac_type_broadcast, 6) &&
554 !memcmp(hlp->sourcemsk, msk_type_broadcast, 6)) {
555 printf("Broadcast");
556 goto endsrc;
557 }
Bart De Schuymer41830412002-06-05 19:41:28 +0000558 printf("%s", ether_ntoa((struct ether_addr *)
559 hlp->sourcemac));
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000560 if (memcmp(hlp->sourcemsk, hlpmsk, 6)) {
561 printf("/");
Bart De Schuymer41830412002-06-05 19:41:28 +0000562 printf("%s", ether_ntoa((struct ether_addr *)
563 hlp->sourcemsk));
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000564 }
565endsrc:
Bart De Schuymer60332e02002-06-23 08:01:47 +0000566 printf(" ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000567 }
568 if (hlp->bitmask & EBT_DESTMAC) {
569 char hlpmsk[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
570
Bart De Schuymer60332e02002-06-23 08:01:47 +0000571 printf("-d ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000572 if (hlp->invflags & EBT_IDEST)
573 printf("! ");
574 if (!memcmp(hlp->destmac, mac_type_unicast, 6) &&
575 !memcmp(hlp->destmsk, msk_type_unicast, 6)) {
576 printf("Unicast");
577 goto enddst;
578 }
579 if (!memcmp(hlp->destmac, mac_type_multicast, 6) &&
580 !memcmp(hlp->destmsk, msk_type_multicast, 6)) {
581 printf("Multicast");
582 goto enddst;
583 }
584 if (!memcmp(hlp->destmac, mac_type_broadcast, 6) &&
585 !memcmp(hlp->destmsk, msk_type_broadcast, 6)) {
586 printf("Broadcast");
587 goto enddst;
588 }
Bart De Schuymer41830412002-06-05 19:41:28 +0000589 printf("%s", ether_ntoa((struct ether_addr *)
590 hlp->destmac));
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000591 if (memcmp(hlp->destmsk, hlpmsk, 6)) {
592 printf("/");
Bart De Schuymer41830412002-06-05 19:41:28 +0000593 printf("%s", ether_ntoa((struct ether_addr *)
594 hlp->destmsk));
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000595 }
596enddst:
Bart De Schuymer60332e02002-06-23 08:01:47 +0000597 printf(" ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000598 }
599 if (hlp->in[0] != '\0') {
Bart De Schuymer60332e02002-06-23 08:01:47 +0000600 printf("-i ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000601 if (hlp->invflags & EBT_IIN)
602 printf("! ");
Bart De Schuymer60332e02002-06-23 08:01:47 +0000603 printf("%s ", hlp->in);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000604 }
605 if (hlp->logical_in[0] != '\0') {
Bart De Schuymer60332e02002-06-23 08:01:47 +0000606 printf("--logical-in ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000607 if (hlp->invflags & EBT_ILOGICALIN)
608 printf("! ");
Bart De Schuymer60332e02002-06-23 08:01:47 +0000609 printf("%s ", hlp->logical_in);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000610 }
611 if (hlp->logical_out[0] != '\0') {
Bart De Schuymer60332e02002-06-23 08:01:47 +0000612 printf("--logical-out ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000613 if (hlp->invflags & EBT_ILOGICALOUT)
614 printf("! ");
Bart De Schuymerb3d8f262002-07-07 14:26:15 +0000615 printf("%s ", hlp->logical_out);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000616 }
617 if (hlp->out[0] != '\0') {
Bart De Schuymer60332e02002-06-23 08:01:47 +0000618 printf("-o ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000619 if (hlp->invflags & EBT_IOUT)
620 printf("! ");
Bart De Schuymerb3d8f262002-07-07 14:26:15 +0000621 printf("%s ", hlp->out);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000622 }
623
624 m_l = hlp->m_list;
625 while (m_l) {
626 m = find_match(m_l->m->u.name);
627 if (!m)
628 print_bug("Match not found");
629 m->print(hlp, m_l->m);
630 m_l = m_l->next;
631 }
632 w_l = hlp->w_list;
633 while (w_l) {
634 w = find_watcher(w_l->w->u.name);
635 if (!w)
636 print_bug("Watcher not found");
637 w->print(hlp, w_l->w);
638 w_l = w_l->next;
639 }
640
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000641 printf("-j ");
642 if (strcmp(hlp->t->u.name, EBT_STANDARD_TARGET))
643 printf("%s ", hlp->t->u.name);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000644 t = find_target(hlp->t->u.name);
645 if (!t)
646 print_bug("Target not found");
647 t->print(hlp, hlp->t);
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000648 if (replace.flags & LIST_C)
Bart De Schuymer73fccca2002-10-17 22:00:23 +0000649 printf(", pcnt = %llu -- bcnt = %llu",
650 replace.counters[entries->counter_offset + i].pcnt,
651 replace.counters[entries->counter_offset + i].bcnt);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000652 printf("\n");
653 hlp = hlp->next;
654 }
655}
656
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000657struct ebt_u_entries *nr_to_chain(int nr)
Bart De Schuymer60332e02002-06-23 08:01:47 +0000658{
659 if (nr == -1)
660 return NULL;
661 if (nr < NF_BR_NUMHOOKS)
662 return replace.hook_entry[nr];
663 else {
664 int i;
665 struct ebt_u_chain_list *cl = replace.udc;
666
667 i = nr - NF_BR_NUMHOOKS;
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000668 while (i > 0 && cl) {
Bart De Schuymer60332e02002-06-23 08:01:47 +0000669 cl = cl->next;
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000670 i--;
671 }
Bart De Schuymer60332e02002-06-23 08:01:47 +0000672 if (cl)
673 return cl->udc;
674 else
675 return NULL;
676 }
677}
678
Bart De Schuymercc440052002-11-06 21:10:33 +0000679static inline struct ebt_u_entries *to_chain()
Bart De Schuymer60332e02002-06-23 08:01:47 +0000680{
681 return nr_to_chain(replace.selected_hook);
682}
683
684struct ebt_u_stack
685{
686 int chain_nr;
687 int n;
688 struct ebt_u_entry *e;
689 struct ebt_u_entries *entries;
690};
691
Bart De Schuymer62423742002-07-14 19:06:20 +0000692static void check_for_loops()
Bart De Schuymer60332e02002-06-23 08:01:47 +0000693{
694 int chain_nr , i, j , k, sp = 0, verdict;
695 struct ebt_u_entries *entries, *entries2;
696 struct ebt_u_stack *stack = NULL;
697 struct ebt_u_entry *e;
698
699 i = -1;
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000700 /*
701 * initialize hook_mask to 0
702 */
Bart De Schuymer60332e02002-06-23 08:01:47 +0000703 while (1) {
704 i++;
705 if (i < NF_BR_NUMHOOKS && !(replace.valid_hooks & (1 << i)))
706 continue;
707 entries = nr_to_chain(i);
708 if (!entries)
709 break;
710 entries->hook_mask = 0;
711 }
712 if (i > NF_BR_NUMHOOKS) {
713 stack = (struct ebt_u_stack *)malloc((i - NF_BR_NUMHOOKS) *
714 sizeof(struct ebt_u_stack));
715 if (!stack)
716 print_memory();
717 }
718
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000719 /*
720 * check for loops, starting from every base chain
721 */
Bart De Schuymer60332e02002-06-23 08:01:47 +0000722 for (i = 0; i < NF_BR_NUMHOOKS; i++) {
723 if (!(replace.valid_hooks & (1 << i)))
724 continue;
725 entries = nr_to_chain(i);
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000726 /*
727 * (1 << NF_BR_NUMHOOKS) implies it's a standard chain
728 * (usefull in the final_check() funtions)
729 */
Bart De Schuymerb26649e2002-07-25 14:51:54 +0000730 entries->hook_mask = (1 << i) | (1 << NF_BR_NUMHOOKS);
Bart De Schuymer60332e02002-06-23 08:01:47 +0000731 chain_nr = i;
732
733 e = entries->entries;
734 for (j = 0; j < entries->nentries; j++) {
735 if (strcmp(e->t->u.name, EBT_STANDARD_TARGET))
736 goto letscontinue;
737 verdict = ((struct ebt_standard_target *)(e->t))->verdict;
738 if (verdict < 0)
739 goto letscontinue;
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000740 entries2 = nr_to_chain(verdict + NF_BR_NUMHOOKS);
Bart De Schuymer60332e02002-06-23 08:01:47 +0000741 entries2->hook_mask |= entries->hook_mask;
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000742 /*
743 * now see if we've been here before
744 */
Bart De Schuymer60332e02002-06-23 08:01:47 +0000745 for (k = 0; k < sp; k++)
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000746 if (stack[k].chain_nr == verdict + NF_BR_NUMHOOKS)
Bart De Schuymer1a0a9c32002-06-24 21:10:16 +0000747 print_error("Loop from chain %s to chain %s",
Bart De Schuymerc56a31a2002-07-25 08:16:08 +0000748 nr_to_chain(chain_nr)->name,
749 nr_to_chain(stack[k].chain_nr)->name);
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000750 /*
751 * jump to the chain, make sure we know how to get back
752 */
Bart De Schuymer60332e02002-06-23 08:01:47 +0000753 stack[sp].chain_nr = chain_nr;
754 stack[sp].n = j;
755 stack[sp].entries = entries;
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000756 stack[sp].e = e;
757 sp++;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000758 j = -1;
759 e = entries2->entries;
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000760 chain_nr = verdict + NF_BR_NUMHOOKS;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000761 entries = entries2;
762 continue;
763letscontinue:
764 e = e->next;
765 }
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000766 /*
767 * we are at the end of a standard chain
768 */
Bart De Schuymer60332e02002-06-23 08:01:47 +0000769 if (sp == 0)
770 continue;
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000771 /*
772 * go back to the chain one level higher
773 */
Bart De Schuymer60332e02002-06-23 08:01:47 +0000774 sp--;
775 j = stack[sp].n;
776 chain_nr = stack[sp].chain_nr;
777 e = stack[sp].e;
778 entries = stack[sp].entries;
779 goto letscontinue;
780 }
781 free(stack);
782 return;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000783}
784
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000785/*
786 * parse the chain name and return the corresponding nr
787 * returns -1 on failure
788 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000789int get_hooknr(char* arg)
790{
791 int i;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000792 struct ebt_u_chain_list *cl = replace.udc;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000793
Bart De Schuymer60332e02002-06-23 08:01:47 +0000794 for (i = 0; i < NF_BR_NUMHOOKS; i++) {
795 if (!(replace.valid_hooks & (1 << i)))
796 continue;
797 if (!strcmp(arg, replace.hook_entry[i]->name))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000798 return i;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000799 }
800 while(cl) {
801 if (!strcmp(arg, cl->udc->name))
802 return i;
803 i++;
804 cl = cl->next;
805 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000806 return -1;
807}
808
Bart De Schuymer62423742002-07-14 19:06:20 +0000809static void print_help()
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000810{
811 struct ebt_u_match_list *m_l;
812 struct ebt_u_watcher_list *w_l;
813
Bart De Schuymer57a3f6a2003-04-01 16:59:33 +0000814 PRINT_VERSION;
815 printf(
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000816"Usage:\n"
817"ebtables -[ADI] chain rule-specification [options]\n"
818"ebtables -P chain target\n"
819"ebtables -[LFZ] [chain]\n"
Bart De Schuymer5885b362002-12-03 20:51:36 +0000820"ebtables -[NX] [chain]\n"
821"ebtables -E old-chain-name new-chain-name\n\n"
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000822"Commands:\n"
Bart De Schuymer23f6dcf2002-08-17 09:14:07 +0000823"--append -A chain : append to chain\n"
824"--delete -D chain : delete matching rule from chain\n"
825"--delete -D chain rulenum : delete rule at position rulenum from chain\n"
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000826"--insert -I chain rulenum : insert rule at position rulenum in chain\n"
Bart De Schuymer23f6dcf2002-08-17 09:14:07 +0000827"--list -L [chain] : list the rules in a chain or in all chains\n"
828"--flush -F [chain] : delete all rules in chain or in all chains\n"
829"--init-table : replace the kernel table with the initial table\n"
830"--zero -Z [chain] : put counters on zero in chain or in all chains\n"
831"--policy -P chain target : change policy on chain to target\n"
832"--new-chain -N chain : create a user defined chain\n"
833"--rename-chain -E old new : rename a chain\n"
834"--delete-chain -X chain : delete a user defined chain\n"
Bart De Schuymer5885b362002-12-03 20:51:36 +0000835"--atomic-commit : update the kernel w/t table contained in <FILE>\n"
836"--atomic-init : put the initial kernel table into <FILE>\n"
837"--atomic-save : put the current kernel table into <FILE>\n"
Bart De Schuymer97819962002-12-11 21:23:07 +0000838"--atomic-file file : set <FILE> to file\n\n"
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000839"Options:\n"
840"--proto -p [!] proto : protocol hexadecimal, by name or LENGTH\n"
841"--src -s [!] address[/mask]: source mac address\n"
842"--dst -d [!] address[/mask]: destination mac address\n"
843"--in-if -i [!] name : network input interface name\n"
844"--out-if -o [!] name : network output interface name\n"
845"--logical-in [!] name : logical bridge input interface name\n"
846"--logical-out [!] name : logical bridge output interface name\n"
Bart De Schuymer5cbc8e02002-07-14 21:15:28 +0000847"--modprobe -M program : try to insert modules using this program\n"
Bart De Schuymer5885b362002-12-03 20:51:36 +0000848"--version -V : print package version\n\n"
849"Environment variable:\n"
850ATOMIC_ENV_VARIABLE " : if set <FILE> (see above) will equal its value"
851"\n\n");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000852
853 m_l = new_entry->m_list;
854 while (m_l) {
855 ((struct ebt_u_match *)m_l->m)->help();
856 printf("\n");
857 m_l = m_l->next;
858 }
859 w_l = new_entry->w_list;
860 while (w_l) {
861 ((struct ebt_u_watcher *)w_l->w)->help();
862 printf("\n");
863 w_l = w_l->next;
864 }
865 ((struct ebt_u_target *)new_entry->t)->help();
866 printf("\n");
867 if (table->help)
868 table->help(hooknames);
869 exit(0);
870}
871
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000872/*
873 * execute command L
874 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000875static void list_rules()
876{
877 int i;
878
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000879 if (!(replace.flags & LIST_X))
880 printf("Bridge table: %s\n", table->name);
Bart De Schuymer60332e02002-06-23 08:01:47 +0000881 if (replace.selected_hook != -1) {
882 list_em(to_chain());
883 } else {
884 struct ebt_u_chain_list *cl = replace.udc;
885
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000886 /*
887 * create new chains and rename standard chains when necessary
888 */
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000889 if (replace.flags & LIST_X) {
890 while (cl) {
891 printf("ebtables -t %s -N %s\n", replace.name,
892 cl->udc->name);
893 cl = cl->next;
894 }
895 cl = replace.udc;
896 for (i = 0; i < NF_BR_NUMHOOKS; i++)
897 if (replace.valid_hooks & (1 << i) &&
898 strcmp(replace.hook_entry[i]->name, hooknames[i]))
899 printf("ebtables -t %s -E %s %s\n",
900 replace.name, hooknames[i],
901 replace.hook_entry[i]->name);
902 }
Bart De Schuymer60332e02002-06-23 08:01:47 +0000903 i = 0;
904 while (1) {
905 if (i < NF_BR_NUMHOOKS) {
906 if (replace.valid_hooks & (1 << i))
907 list_em(replace.hook_entry[i]);
908 i++;
909 continue;
910 } else {
911 if (!cl)
912 break;
913 list_em(cl->udc);
914 cl = cl->next;
915 }
916 }
917 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000918}
919
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000920/*
921 * execute command P
922 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000923static void change_policy(int policy)
924{
925 int i;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000926 struct ebt_u_entries *entries = to_chain();
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000927
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000928 /*
929 * don't do anything if the policy is the same
930 */
Bart De Schuymer60332e02002-06-23 08:01:47 +0000931 if (entries->policy != policy) {
932 entries->policy = policy;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000933 replace.num_counters = replace.nentries;
934 if (replace.nentries) {
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000935 /*
936 * '+ 1' for the CNT_END
937 */
Bart De Schuymered053432002-07-21 19:35:39 +0000938 if (!(replace.counterchanges = (unsigned short *) malloc(
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000939 (replace.nentries + 1) * sizeof(unsigned short))))
940 print_memory();
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000941 /*
942 * done nothing special to the rules
943 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000944 for (i = 0; i < replace.nentries; i++)
Bart De Schuymered053432002-07-21 19:35:39 +0000945 replace.counterchanges[i] = CNT_NORM;
946 replace.counterchanges[replace.nentries] = CNT_END;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000947 }
948 else
Bart De Schuymered053432002-07-21 19:35:39 +0000949 replace.counterchanges = NULL;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000950 }
951 else
952 exit(0);
953}
954
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000955/*
956 * flush one chain or the complete table
957 * -1 == nothing to do
958 * 0 == give back to kernel
959 */
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000960static int flush_chains()
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000961{
Bart De Schuymer60332e02002-06-23 08:01:47 +0000962 int i, j, oldnentries, numdel;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000963 unsigned short *cnt;
964 struct ebt_u_entry *u_e, *tmp;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000965 struct ebt_u_entries *entries = to_chain();
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000966
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000967 /*
968 * flush whole table
969 */
Bart De Schuymer60332e02002-06-23 08:01:47 +0000970 if (!entries) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000971 if (replace.nentries == 0)
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000972 return -1;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000973 replace.nentries = 0;
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000974 /*
975 * no need for the kernel to give us counters back
976 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000977 replace.num_counters = 0;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000978
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000979 /*
980 * free everything and zero (n)entries
981 */
Bart De Schuymer60332e02002-06-23 08:01:47 +0000982 i = -1;
983 while (1) {
984 i++;
985 entries = nr_to_chain(i);
986 if (!entries) {
987 if (i < NF_BR_NUMHOOKS)
988 continue;
989 else
990 break;
991 }
992 entries->nentries = 0;
993 entries->counter_offset = 0;
994 u_e = entries->entries;
995 entries->entries = NULL;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000996 while (u_e) {
997 free_u_entry(u_e);
998 tmp = u_e->next;
999 free(u_e);
1000 u_e = tmp;
1001 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001002 }
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001003 return 0;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001004 }
1005
Bart De Schuymer60332e02002-06-23 08:01:47 +00001006 if (entries->nentries == 0)
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001007 return -1;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001008 oldnentries = replace.nentries;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001009 replace.nentries -= entries->nentries;
1010 numdel = entries->nentries;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001011
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001012 if (replace.nentries) {
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001013 /*
1014 * +1 for CNT_END
1015 */
Bart De Schuymered053432002-07-21 19:35:39 +00001016 if ( !(replace.counterchanges = (unsigned short *)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001017 malloc((oldnentries + 1) * sizeof(unsigned short))) )
1018 print_memory();
Bart De Schuymer60332e02002-06-23 08:01:47 +00001019 }
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001020 /*
1021 * delete the counters belonging to the specified chain,
1022 * update counter_offset
1023 */
Bart De Schuymer60332e02002-06-23 08:01:47 +00001024 i = -1;
Bart De Schuymered053432002-07-21 19:35:39 +00001025 cnt = replace.counterchanges;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001026 while (1) {
1027 i++;
1028 entries = nr_to_chain(i);
1029 if (!entries) {
1030 if (i < NF_BR_NUMHOOKS)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001031 continue;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001032 else
1033 break;
1034 }
1035 if (i > replace.selected_hook)
1036 entries->counter_offset -= numdel;
1037 if (replace.nentries) {
1038 for (j = 0; j < entries->nentries; j++) {
1039 if (i == replace.selected_hook)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001040 *cnt = CNT_DEL;
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001041 else
1042 *cnt = CNT_NORM;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001043 cnt++;
1044 }
1045 }
Bart De Schuymer60332e02002-06-23 08:01:47 +00001046 }
1047
1048 if (replace.nentries) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001049 *cnt = CNT_END;
1050 replace.num_counters = oldnentries;
Bart De Schuymercc440052002-11-06 21:10:33 +00001051 } else
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001052 replace.num_counters = 0;
1053
Bart De Schuymer60332e02002-06-23 08:01:47 +00001054 entries = to_chain();
1055 entries->nentries = 0;
1056 u_e = entries->entries;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001057 while (u_e) {
1058 free_u_entry(u_e);
1059 tmp = u_e->next;
1060 free(u_e);
1061 u_e = tmp;
1062 }
Bart De Schuymer60332e02002-06-23 08:01:47 +00001063 entries->entries = NULL;
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001064 return 0;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001065}
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001066
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001067/*
1068 * -1 == no match
1069 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001070static int check_rule_exists(int rule_nr)
1071{
1072 struct ebt_u_entry *u_e;
1073 struct ebt_u_match_list *m_l, *m_l2;
1074 struct ebt_u_match *m;
1075 struct ebt_u_watcher_list *w_l, *w_l2;
1076 struct ebt_u_watcher *w;
1077 struct ebt_u_target *t = (struct ebt_u_target *)new_entry->t;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001078 struct ebt_u_entries *entries = to_chain();
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001079 int i, j, k;
1080
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001081 /*
1082 * handle '-D chain rulenr' command
1083 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001084 if (rule_nr != -1) {
Bart De Schuymer60332e02002-06-23 08:01:47 +00001085 if (rule_nr > entries->nentries)
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001086 return -1;
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001087 /*
1088 * user starts counting from 1
1089 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001090 return rule_nr - 1;
1091 }
Bart De Schuymer60332e02002-06-23 08:01:47 +00001092 u_e = entries->entries;
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001093 /*
1094 * check for an existing rule (if there are duplicate rules,
1095 * take the first occurance)
1096 */
Bart De Schuymer60332e02002-06-23 08:01:47 +00001097 for (i = 0; i < entries->nentries; i++, u_e = u_e->next) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001098 if (!u_e)
1099 print_bug("Hmm, trouble");
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001100 if (u_e->ethproto != new_entry->ethproto)
1101 continue;
1102 if (strcmp(u_e->in, new_entry->in))
1103 continue;
1104 if (strcmp(u_e->out, new_entry->out))
1105 continue;
1106 if (strcmp(u_e->logical_in, new_entry->logical_in))
1107 continue;
1108 if (strcmp(u_e->logical_out, new_entry->logical_out))
1109 continue;
1110 if (new_entry->bitmask & EBT_SOURCEMAC &&
1111 memcmp(u_e->sourcemac, new_entry->sourcemac, ETH_ALEN))
1112 continue;
1113 if (new_entry->bitmask & EBT_DESTMAC &&
1114 memcmp(u_e->destmac, new_entry->destmac, ETH_ALEN))
1115 continue;
1116 if (new_entry->bitmask != u_e->bitmask ||
1117 new_entry->invflags != u_e->invflags)
1118 continue;
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001119 /*
1120 * compare all matches
1121 */
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001122 m_l = new_entry->m_list;
1123 j = 0;
1124 while (m_l) {
1125 m = (struct ebt_u_match *)(m_l->m);
1126 m_l2 = u_e->m_list;
1127 while (m_l2 && strcmp(m_l2->m->u.name, m->m->u.name))
1128 m_l2 = m_l2->next;
1129 if (!m_l2 || !m->compare(m->m, m_l2->m))
1130 goto letscontinue;
1131 j++;
1132 m_l = m_l->next;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001133 }
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001134 /*
1135 * now be sure they have the same nr of matches
1136 */
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001137 k = 0;
1138 m_l = u_e->m_list;
1139 while (m_l) {
1140 k++;
1141 m_l = m_l->next;
1142 }
1143 if (j != k)
1144 continue;
1145
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001146 /*
1147 * compare all watchers
1148 */
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001149 w_l = new_entry->w_list;
1150 j = 0;
1151 while (w_l) {
1152 w = (struct ebt_u_watcher *)(w_l->w);
1153 w_l2 = u_e->w_list;
1154 while (w_l2 && strcmp(w_l2->w->u.name, w->w->u.name))
1155 w_l2 = w_l2->next;
1156 if (!w_l2 || !w->compare(w->w, w_l2->w))
1157 goto letscontinue;
1158 j++;
1159 w_l = w_l->next;
1160 }
1161 k = 0;
1162 w_l = u_e->w_list;
1163 while (w_l) {
1164 k++;
1165 w_l = w_l->next;
1166 }
1167 if (j != k)
1168 continue;
1169 if (strcmp(t->t->u.name, u_e->t->u.name))
1170 continue;
1171 if (!t->compare(t->t, u_e->t))
1172 continue;
1173 return i;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001174letscontinue:
1175 }
1176 return -1;
1177}
1178
Bart De Schuymer9895a8e2003-01-11 10:14:24 +00001179/* execute command A or I */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001180static void add_rule(int rule_nr)
1181{
1182 int i, j;
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001183 struct ebt_u_entry **u_e;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001184 unsigned short *cnt;
1185 struct ebt_u_match_list *m_l;
1186 struct ebt_u_watcher_list *w_l;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001187 struct ebt_u_entries *entries = to_chain(), *entries2;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001188
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001189 if (rule_nr != -1) { /* command -I */
Bart De Schuymer60332e02002-06-23 08:01:47 +00001190 if (--rule_nr > entries->nentries)
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001191 print_error("rule nr too high: %d > %d", rule_nr + 1,
1192 entries->nentries + 1);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001193 } else
Bart De Schuymer60332e02002-06-23 08:01:47 +00001194 rule_nr = entries->nentries;
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001195 /*
1196 * we're adding one rule
1197 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001198 replace.num_counters = replace.nentries;
1199 replace.nentries++;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001200 entries->nentries++;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001201
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001202 /*
1203 * handle counter stuff
1204 * +1 for CNT_END
1205 */
Bart De Schuymered053432002-07-21 19:35:39 +00001206 if ( !(replace.counterchanges = (unsigned short *)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001207 malloc((replace.nentries + 1) * sizeof(unsigned short))) )
1208 print_memory();
Bart De Schuymered053432002-07-21 19:35:39 +00001209 cnt = replace.counterchanges;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001210 for (i = 0; i < replace.selected_hook; i++) {
Bart De Schuymer60332e02002-06-23 08:01:47 +00001211 if (i < NF_BR_NUMHOOKS && !(replace.valid_hooks & (1 << i)))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001212 continue;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001213 entries2 = nr_to_chain(i);
1214 for (j = 0; j < entries2->nentries; j++) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001215 *cnt = CNT_NORM;
1216 cnt++;
1217 }
1218 }
1219 for (i = 0; i < rule_nr; i++) {
1220 *cnt = CNT_NORM;
1221 cnt++;
1222 }
1223 *cnt = CNT_ADD;
1224 cnt++;
Bart De Schuymered053432002-07-21 19:35:39 +00001225 while (cnt != replace.counterchanges + replace.nentries) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001226 *cnt = CNT_NORM;
1227 cnt++;
1228 }
1229 *cnt = CNT_END;
1230
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001231 /*
1232 * go to the right position in the chain
1233 */
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001234 u_e = &entries->entries;
1235 for (i = 0; i < rule_nr; i++)
1236 u_e = &(*u_e)->next;
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001237 /*
1238 * insert the rule
1239 */
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001240 new_entry->next = *u_e;
1241 *u_e = new_entry;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001242
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001243 /*
1244 * put the ebt_[match, watcher, target] pointers in place
1245 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001246 m_l = new_entry->m_list;
1247 while (m_l) {
1248 m_l->m = ((struct ebt_u_match *)m_l->m)->m;
1249 m_l = m_l->next;
1250 }
1251 w_l = new_entry->w_list;
1252 while (w_l) {
1253 w_l->w = ((struct ebt_u_watcher *)w_l->w)->w;
1254 w_l = w_l->next;
1255 }
1256 new_entry->t = ((struct ebt_u_target *)new_entry->t)->t;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001257
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001258 /*
1259 * update the counter_offset of chains behind this one
1260 */
Bart De Schuymer60332e02002-06-23 08:01:47 +00001261 i = replace.selected_hook;
1262 while (1) {
1263 i++;
1264 entries = nr_to_chain(i);
1265 if (!entries) {
1266 if (i < NF_BR_NUMHOOKS)
1267 continue;
1268 else
1269 break;
1270 } else
1271 entries->counter_offset++;
1272 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001273}
1274
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001275/*
1276 * execute command D
1277 */
Bart De Schuymercc440052002-11-06 21:10:33 +00001278static void delete_rule(int begin, int end)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001279{
Bart De Schuymercc440052002-11-06 21:10:33 +00001280 int j, lentmp = 0, nr_deletes;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001281 unsigned short *cnt;
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001282 struct ebt_u_entry **u_e, *u_e2;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001283 struct ebt_u_entries *entries = to_chain(), *entries2;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001284
Bart De Schuymercc440052002-11-06 21:10:33 +00001285 if ((begin = check_rule_exists(begin)) == -1 ||
1286 (end = check_rule_exists(end)) == -1)
Bart De Schuymer60332e02002-06-23 08:01:47 +00001287 print_error("Sorry, rule does not exist");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001288
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001289 /*
1290 * we're deleting rules
1291 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001292 replace.num_counters = replace.nentries;
Bart De Schuymercc440052002-11-06 21:10:33 +00001293 nr_deletes = end - begin + 1;
1294 replace.nentries -= nr_deletes;
1295 entries->nentries -= nr_deletes;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001296
1297 if (replace.nentries) {
1298 for (j = 0; j < replace.selected_hook; j++) {
Bart De Schuymer60332e02002-06-23 08:01:47 +00001299 if (j < NF_BR_NUMHOOKS &&
1300 !(replace.valid_hooks & (1 << j)))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001301 continue;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001302 entries2 = nr_to_chain(j);
1303 lentmp += entries2->nentries;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001304 }
Bart De Schuymercc440052002-11-06 21:10:33 +00001305 lentmp += begin;
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001306 /*
1307 * +1 for CNT_END
1308 */
Bart De Schuymered053432002-07-21 19:35:39 +00001309 if ( !(replace.counterchanges = (unsigned short *)malloc(
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001310 (replace.num_counters + 1) * sizeof(unsigned short))) )
1311 print_memory();
Bart De Schuymered053432002-07-21 19:35:39 +00001312 cnt = replace.counterchanges;
Bart De Schuymercc440052002-11-06 21:10:33 +00001313 for (j = 0; j < lentmp; j++, cnt++)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001314 *cnt = CNT_NORM;
Bart De Schuymercc440052002-11-06 21:10:33 +00001315 for (j = 0; j < nr_deletes; j++, cnt++)
1316 *cnt = CNT_DEL;
1317
1318 for (j = 0; j < replace.num_counters - lentmp - nr_deletes;
1319 j++, cnt++)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001320 *cnt = CNT_NORM;
Bart De Schuymercc440052002-11-06 21:10:33 +00001321
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001322 *cnt = CNT_END;
1323 }
1324 else
1325 replace.num_counters = 0;
1326
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001327 /*
1328 * go to the right position in the chain
1329 */
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001330 u_e = &entries->entries;
Bart De Schuymercc440052002-11-06 21:10:33 +00001331 for (j = 0; j < begin; j++)
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001332 u_e = &(*u_e)->next;
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001333 /*
1334 * remove the rules
1335 */
Bart De Schuymercc440052002-11-06 21:10:33 +00001336 j = nr_deletes;
1337 while(j--) {
1338 u_e2 = *u_e;
1339 *u_e = (*u_e)->next;
Bart De Schuymer9895a8e2003-01-11 10:14:24 +00001340 /* free everything */
Bart De Schuymercc440052002-11-06 21:10:33 +00001341 free_u_entry(u_e2);
1342 free(u_e2);
1343 }
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001344
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001345 /*
1346 * update the counter_offset of chains behind this one
1347 */
Bart De Schuymercc440052002-11-06 21:10:33 +00001348 j = replace.selected_hook;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001349 while (1) {
Bart De Schuymercc440052002-11-06 21:10:33 +00001350 j++;
1351 entries = nr_to_chain(j);
Bart De Schuymer60332e02002-06-23 08:01:47 +00001352 if (!entries) {
Bart De Schuymercc440052002-11-06 21:10:33 +00001353 if (j < NF_BR_NUMHOOKS)
Bart De Schuymer60332e02002-06-23 08:01:47 +00001354 continue;
1355 else
1356 break;
Bart De Schuymercc440052002-11-06 21:10:33 +00001357 } else
1358 entries->counter_offset -= nr_deletes;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001359 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001360}
1361
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001362/*
1363 * execute command Z
1364 */
Bart De Schuymer62423742002-07-14 19:06:20 +00001365static void zero_counters(int zerochain)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001366{
1367
1368 if (zerochain == -1) {
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001369 /*
1370 * tell main() we don't update the counters
1371 * this results in tricking the kernel to zero its counters,
1372 * naively expecting userspace to update its counters. Muahahaha
1373 */
Bart De Schuymered053432002-07-21 19:35:39 +00001374 replace.counterchanges = NULL;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001375 replace.num_counters = 0;
1376 } else {
1377 int i, j;
1378 unsigned short *cnt;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001379 struct ebt_u_entries *entries = nr_to_chain(zerochain), *e2;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001380
Bart De Schuymer60332e02002-06-23 08:01:47 +00001381 if (entries->nentries == 0)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001382 exit(0);
Bart De Schuymered053432002-07-21 19:35:39 +00001383 replace.counterchanges = (unsigned short *)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001384 malloc((replace.nentries + 1) * sizeof(unsigned short));
Bart De Schuymered053432002-07-21 19:35:39 +00001385 if (!replace.counterchanges)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001386 print_memory();
Bart De Schuymered053432002-07-21 19:35:39 +00001387 cnt = replace.counterchanges;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001388 for (i = 0; i < zerochain; i++) {
Bart De Schuymer60332e02002-06-23 08:01:47 +00001389 if (i < NF_BR_NUMHOOKS &&
1390 !(replace.valid_hooks & (1 << i)))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001391 continue;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001392 e2 = nr_to_chain(i);
1393 for (j = 0; j < e2->nentries; j++) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001394 *cnt = CNT_NORM;
1395 cnt++;
1396 }
1397 }
Bart De Schuymer60332e02002-06-23 08:01:47 +00001398 for (i = 0; i < entries->nentries; i++) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001399 *cnt = CNT_ZERO;
1400 cnt++;
1401 }
Bart De Schuymered053432002-07-21 19:35:39 +00001402 while (cnt != replace.counterchanges + replace.nentries) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001403 *cnt = CNT_NORM;
1404 cnt++;
1405 }
1406 *cnt = CNT_END;
1407 }
1408}
1409
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001410/*
1411 * Checks the type for validity and calls getethertypebynumber()
1412 */
1413struct ethertypeent *parseethertypebynumber(int type)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001414{
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001415 if (type < 1536)
1416 print_error("Ethernet protocols have values >= 0x0600");
1417 if (type > 0xffff)
1418 print_error("Ethernet protocols have values <= 0xffff");
1419 return getethertypebynumber(type);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001420}
1421
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001422/*
1423 * put the mac address into 6 (ETH_ALEN) bytes
1424 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001425int getmac_and_mask(char *from, char *to, char *mask)
1426{
1427 char *p;
1428 int i;
Bart De Schuymer41830412002-06-05 19:41:28 +00001429 struct ether_addr *addr;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001430
1431 if (strcasecmp(from, "Unicast") == 0) {
1432 memcpy(to, mac_type_unicast, ETH_ALEN);
1433 memcpy(mask, msk_type_unicast, ETH_ALEN);
1434 return 0;
1435 }
1436 if (strcasecmp(from, "Multicast") == 0) {
1437 memcpy(to, mac_type_multicast, ETH_ALEN);
1438 memcpy(mask, msk_type_multicast, ETH_ALEN);
1439 return 0;
1440 }
1441 if (strcasecmp(from, "Broadcast") == 0) {
1442 memcpy(to, mac_type_broadcast, ETH_ALEN);
1443 memcpy(mask, msk_type_broadcast, ETH_ALEN);
1444 return 0;
1445 }
1446 if ( (p = strrchr(from, '/')) != NULL) {
1447 *p = '\0';
Bart De Schuymer41830412002-06-05 19:41:28 +00001448 if (!(addr = ether_aton(p + 1)))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001449 return -1;
Bart De Schuymer41830412002-06-05 19:41:28 +00001450 memcpy(mask, addr, ETH_ALEN);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001451 } else
1452 memset(mask, 0xff, ETH_ALEN);
Bart De Schuymer41830412002-06-05 19:41:28 +00001453 if (!(addr = ether_aton(from)))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001454 return -1;
Bart De Schuymer41830412002-06-05 19:41:28 +00001455 memcpy(to, addr, ETH_ALEN);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001456 for (i = 0; i < ETH_ALEN; i++)
1457 to[i] &= mask[i];
1458 return 0;
1459}
1460
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001461/*
1462 * executes the final_check() function for all extensions used by the rule
1463 */
Bart De Schuymer62423742002-07-14 19:06:20 +00001464static void do_final_checks(struct ebt_u_entry *e, struct ebt_u_entries *entries)
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +00001465{
1466 struct ebt_u_match_list *m_l;
1467 struct ebt_u_watcher_list *w_l;
1468 struct ebt_u_target *t;
1469 struct ebt_u_match *m;
1470 struct ebt_u_watcher *w;
1471
1472 m_l = e->m_list;
1473 w_l = e->w_list;
1474 while (m_l) {
1475 m = find_match(m_l->m->u.name);
1476 m->final_check(e, m_l->m, replace.name,
1477 entries->hook_mask, 1);
1478 m_l = m_l->next;
1479 }
1480 while (w_l) {
1481 w = find_watcher(w_l->w->u.name);
1482 w->final_check(e, w_l->w, replace.name,
1483 entries->hook_mask, 1);
1484 w_l = w_l->next;
1485 }
1486 t = find_target(e->t->u.name);
1487 t->final_check(e, e->t, replace.name,
1488 entries->hook_mask, 1);
1489}
1490
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001491/*
1492 * used for the -X command
1493 */
Bart De Schuymer62423742002-07-14 19:06:20 +00001494static void check_for_references(int chain_nr)
Bart De Schuymerb909f9b2002-06-26 18:35:31 +00001495{
1496 int i = -1, j;
1497 struct ebt_u_entries *entries;
1498 struct ebt_u_entry *e;
1499
1500 while (1) {
1501 i++;
1502 entries = nr_to_chain(i);
1503 if (!entries) {
1504 if (i < NF_BR_NUMHOOKS)
1505 continue;
1506 else
1507 break;
1508 }
1509 e = entries->entries;
1510 j = 0;
1511 while (e) {
Bart De Schuymerc27432e2003-01-09 22:01:07 +00001512 int chain_jmp;
1513
Bart De Schuymerb909f9b2002-06-26 18:35:31 +00001514 j++;
1515 if (strcmp(e->t->u.name, EBT_STANDARD_TARGET)) {
1516 e = e->next;
1517 continue;
1518 }
Bart De Schuymerc27432e2003-01-09 22:01:07 +00001519 chain_jmp = ((struct ebt_standard_target *)e->t)->verdict;
1520 if (chain_jmp == chain_nr)
Bart De Schuymerb909f9b2002-06-26 18:35:31 +00001521 print_error("Can't delete the chain, it's referenced "
1522 "in chain %s, rule %d", entries->name, j);
Bart De Schuymerc27432e2003-01-09 22:01:07 +00001523 /* adjust the chain jumps when necessary */
1524 if (chain_jmp > chain_nr)
1525 ((struct ebt_standard_target *)e->t)->verdict--;
Bart De Schuymerb909f9b2002-06-26 18:35:31 +00001526 e = e->next;
1527 }
1528 }
1529}
1530
Bart De Schuymercc440052002-11-06 21:10:33 +00001531static int parse_delete_rule(const char *argv, int *rule_nr, int *rule_nr_end)
1532{
1533 char *colon = strchr(argv, ':'), *buffer;
1534
1535 if (colon) {
1536 *colon = '\0';
1537 if (*(colon + 1) == '\0')
1538 *rule_nr_end = -1;
1539 else {
1540 *rule_nr_end = strtol(colon + 1, &buffer, 10);
1541 if (*buffer != '\0' || *rule_nr_end < 0)
1542 return -1;
1543 }
1544 }
1545 if (colon == argv)
1546 *rule_nr = 1;
1547 else {
1548 *rule_nr = strtol(argv, &buffer, 10);
1549 if (*buffer != '\0' || *rule_nr < 0)
1550 return -1;
1551 }
1552 if (!colon)
1553 *rule_nr_end = *rule_nr;
1554 if (*rule_nr_end != -1 && *rule_nr > *rule_nr_end)
1555 return -1;
1556 return 0;
1557}
1558
Bart De Schuymera615b962002-11-03 14:54:09 +00001559static int invert = 0;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001560int check_inverse(const char option[])
1561{
1562 if (strcmp(option, "!") == 0) {
Bart De Schuymera615b962002-11-03 14:54:09 +00001563 if (invert == 1)
1564 print_error("double use of '!' not allowed");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001565 optind++;
Bart De Schuymera615b962002-11-03 14:54:09 +00001566 invert = 1;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001567 return 1;
1568 }
Bart De Schuymera615b962002-11-03 14:54:09 +00001569 return invert;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001570}
1571
1572void check_option(unsigned int *flags, unsigned int mask)
1573{
1574 if (*flags & mask)
1575 print_error("Multiple use of same option not allowed");
1576 *flags |= mask;
1577}
1578
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001579static void get_kernel_table(const char *modprobe)
1580{
1581 if ( !(table = find_table(replace.name)) )
1582 print_error("Bad table name");
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001583 /*
1584 * get the kernel's information
1585 */
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001586 if (get_table(&replace)) {
1587 ebtables_insmod("ebtables", modprobe);
1588 if (get_table(&replace))
1589 print_error("The kernel doesn't support the ebtables "
1590 "%s table", replace.name);
1591 }
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001592 /*
Bart De Schuymer5885b362002-12-03 20:51:36 +00001593 * when listing a table contained in a file, we don't demand that
1594 * the user knows the table's name
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001595 */
Bart De Schuymer62a7fdb2002-08-24 21:01:21 +00001596 if ( !(table = find_table(replace.name)) )
1597 print_error("Bad table name");
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001598}
1599
Bart De Schuymerc5075142002-08-18 14:21:19 +00001600#define print_if_l_error print_error("Interface name length must be less " \
1601 "than %d", IFNAMSIZ)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001602#define OPT_COMMAND 0x01
1603#define OPT_TABLE 0x02
1604#define OPT_IN 0x04
1605#define OPT_OUT 0x08
1606#define OPT_JUMP 0x10
1607#define OPT_PROTOCOL 0x20
1608#define OPT_SOURCE 0x40
1609#define OPT_DEST 0x80
1610#define OPT_ZERO 0x100
1611#define OPT_LOGICALIN 0x200
1612#define OPT_LOGICALOUT 0x400
Bart De Schuymer5885b362002-12-03 20:51:36 +00001613/* the main thing */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001614int main(int argc, char *argv[])
1615{
Bart De Schuymer923a5732002-08-11 12:01:33 +00001616 char *buffer;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001617 int c, i;
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001618 /*
1619 * this special one for the -Z option (we can have -Z <this> -L <that>)
1620 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001621 int zerochain = -1;
Bart De Schuymerf8f8f292002-06-25 15:43:57 +00001622 int policy = 0;
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001623 int rule_nr = -1; /* used for -[D,I] */
1624 int rule_nr_end = -1; /* used for -I */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001625 struct ebt_u_target *t;
1626 struct ebt_u_match *m;
1627 struct ebt_u_watcher *w;
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001628 struct ebt_u_match_list *m_l;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001629 struct ebt_u_watcher_list *w_l;
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001630 struct ebt_u_entries *entries;
Bart De Schuymerc8531032002-06-14 21:55:29 +00001631 const char *modprobe = NULL;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001632
Bart De Schuymera615b962002-11-03 14:54:09 +00001633 opterr = 0;
1634
Bart De Schuymer5885b362002-12-03 20:51:36 +00001635 replace.filename = getenv(ATOMIC_ENV_VARIABLE);
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001636 /*
1637 * initialize the table name, OPT_ flags, selected hook and command
1638 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001639 strcpy(replace.name, "filter");
1640 replace.flags = 0;
1641 replace.selected_hook = -1;
1642 replace.command = 'h';
Bart De Schuymered053432002-07-21 19:35:39 +00001643 replace.counterchanges = NULL;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001644
1645 new_entry = (struct ebt_u_entry *)malloc(sizeof(struct ebt_u_entry));
1646 if (!new_entry)
1647 print_memory();
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001648 /*
1649 * put some sane values in our new entry
1650 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001651 initialize_entry(new_entry);
1652
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001653 /*
1654 * The scenario induced by this loop makes that:
1655 * '-t' ,'-M' and --atomic (if specified) have to come
1656 * before '-A' and the like
1657 */
Bart De Schuymer60332e02002-06-23 08:01:47 +00001658
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001659 /*
1660 * getopt saves the day
1661 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001662 while ((c = getopt_long(argc, argv,
Bart De Schuymeraac31142002-08-11 11:57:52 +00001663 "-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 +00001664 switch (c) {
1665
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001666 case 'A': /* add a rule */
1667 case 'D': /* delete a rule */
1668 case 'P': /* define policy */
1669 case 'I': /* insert a rule */
1670 case 'N': /* make a user defined chain */
1671 case 'E': /* rename chain */
1672 case 'X': /* delete chain */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001673 replace.command = c;
1674 if (replace.flags & OPT_COMMAND)
1675 print_error("Multiple commands not allowed");
1676 replace.flags |= OPT_COMMAND;
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001677 get_kernel_table(modprobe);
1678 if (optarg[0] == '-' || !strcmp(optarg, "!"))
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001679 print_error("No chain name specified");
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001680 if (c == 'N') {
1681 struct ebt_u_chain_list *cl, **cl2;
1682
1683 if (get_hooknr(optarg) != -1)
1684 print_error("Chain %s already exists",
1685 optarg);
1686 if (find_target(optarg))
1687 print_error("Target with name %s exists"
1688 , optarg);
1689 if (strlen(optarg) >= EBT_CHAIN_MAXNAMELEN)
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001690 print_error("Chain name length can't exceed %d",
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001691 EBT_CHAIN_MAXNAMELEN - 1);
1692 cl = (struct ebt_u_chain_list *)
1693 malloc(sizeof(struct ebt_u_chain_list));
1694 if (!cl)
1695 print_memory();
1696 cl->next = NULL;
1697 cl->udc = (struct ebt_u_entries *)
1698 malloc(sizeof(struct ebt_u_entries));
1699 if (!cl->udc)
1700 print_memory();
1701 cl->udc->nentries = 0;
1702 cl->udc->policy = EBT_ACCEPT;
1703 cl->udc->counter_offset = replace.nentries;
1704 cl->udc->hook_mask = 0;
1705 strcpy(cl->udc->name, optarg);
1706 cl->udc->entries = NULL;
1707 cl->kernel_start = NULL;
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001708 /*
1709 * put the new chain at the end
1710 */
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001711 cl2 = &replace.udc;
1712 while (*cl2)
1713 cl2 = &((*cl2)->next);
1714 *cl2 = cl;
1715 break;
1716 }
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001717 if ((replace.selected_hook = get_hooknr(optarg)) == -1)
1718 print_error("Chain %s doesn't exist", optarg);
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001719 if (c == 'E') {
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001720 if (optind >= argc || argv[optind][0] == '-' ||
1721 !strcmp(argv[optind], "!"))
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001722 print_error("No new chain name specified");
1723 if (strlen(argv[optind]) >= EBT_CHAIN_MAXNAMELEN)
1724 print_error("Chain name len can't exceed %d",
1725 EBT_CHAIN_MAXNAMELEN - 1);
1726 if (get_hooknr(argv[optind]) != -1)
1727 print_error("Chain %s already exists",
1728 argv[optind]);
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001729 if (find_target(argv[optind]))
1730 print_error("Target with name %s exists"
1731 , argv[optind]);
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001732 entries = to_chain();
1733 strcpy(entries->name, argv[optind]);
1734 optind++;
1735 break;
1736 }
1737 if (c == 'X') {
1738 struct ebt_u_chain_list *cl, **cl2;
1739
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001740 if (replace.selected_hook < NF_BR_NUMHOOKS)
1741 print_error("You can't remove a standard chain");
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001742 /*
Bart De Schuymerc27432e2003-01-09 22:01:07 +00001743 * if the chain is referenced, don't delete it,
1744 * also decrement jumps to a chain behind the
1745 * one we're deleting
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001746 */
Bart De Schuymerb909f9b2002-06-26 18:35:31 +00001747 check_for_references(replace.selected_hook - NF_BR_NUMHOOKS);
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001748 flush_chains();
1749 entries = to_chain();
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001750 cl2 = &(replace.udc);
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001751 while ((*cl2)->udc != entries)
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001752 cl2 = &((*cl2)->next);
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001753 cl = (*cl2);
1754 (*cl2) = (*cl2)->next;
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001755 free(cl->udc);
1756 free(cl);
1757 break;
1758 }
1759
Bart De Schuymercc440052002-11-06 21:10:33 +00001760 if (c == 'D' && optind < argc &&
1761 argv[optind][0] != '-') {
1762 if (parse_delete_rule(argv[optind],
1763 &rule_nr, &rule_nr_end))
1764 print_error("Problem with the "
1765 "specified rule number(s)");
1766 optind++;
1767 }
1768 if (c == 'I') {
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001769 if (optind >= argc || argv[optind][0] == '-')
1770 print_error("No rulenr for -I"
1771 " specified");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001772 rule_nr = strtol(argv[optind], &buffer, 10);
1773 if (*buffer != '\0' || rule_nr < 0)
1774 print_error("Problem with the "
1775 "specified rule number");
1776 optind++;
1777 }
1778 if (c == 'P') {
1779 if (optind >= argc)
1780 print_error("No policy specified");
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001781 policy = 0;
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001782 for (i = 0; i < NUM_STANDARD_TARGETS; i++)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001783 if (!strcmp(argv[optind],
1784 standard_targets[i])) {
Bart De Schuymer60332e02002-06-23 08:01:47 +00001785 policy = -i -1;
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001786 if (policy == EBT_CONTINUE)
1787 policy = 0;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001788 break;
1789 }
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001790 if (policy == 0)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001791 print_error("Wrong policy");
1792 optind++;
1793 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001794 break;
1795
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001796 case 'L': /* list */
1797 case 'F': /* flush */
1798 case 'Z': /* zero counters */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001799 if (c == 'Z') {
1800 if (replace.flags & OPT_ZERO)
1801 print_error("Multiple commands"
1802 " not allowed");
1803 if ( (replace.flags & OPT_COMMAND &&
1804 replace.command != 'L'))
1805 print_error("command -Z only allowed "
1806 "together with command -L");
1807 replace.flags |= OPT_ZERO;
1808 } else {
1809 replace.command = c;
1810 if (replace.flags & OPT_COMMAND)
1811 print_error("Multiple commands"
1812 " not allowed");
1813 replace.flags |= OPT_COMMAND;
1814 }
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001815 get_kernel_table(modprobe);
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001816 i = -1;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001817 if (optarg) {
1818 if ( (i = get_hooknr(optarg)) == -1 )
1819 print_error("Bad chain");
1820 } else
1821 if (optind < argc && argv[optind][0] != '-') {
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001822 if ((i = get_hooknr(argv[optind])) == -1)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001823 print_error("Bad chain");
1824 optind++;
1825 }
1826 if (i != -1) {
1827 if (c == 'Z')
1828 zerochain = i;
1829 else
1830 replace.selected_hook = i;
1831 }
1832 break;
1833
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001834 case 'V': /* version */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001835 replace.command = 'V';
1836 if (replace.flags & OPT_COMMAND)
1837 print_error("Multiple commands not allowed");
Bart De Schuymer57a3f6a2003-04-01 16:59:33 +00001838 PRINT_VERSION;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001839 exit(0);
1840
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001841 case 'M': /* modprobe */
Bart De Schuymer60332e02002-06-23 08:01:47 +00001842 if (replace.command != 'h')
1843 print_error("Please put the -M option earlier");
Bart De Schuymerc8531032002-06-14 21:55:29 +00001844 modprobe = optarg;
1845 break;
1846
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001847 case 'h': /* help */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001848 if (replace.flags & OPT_COMMAND)
1849 print_error("Multiple commands not allowed");
1850 replace.command = 'h';
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001851 /*
1852 * All other arguments should be extension names
1853 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001854 while (optind < argc) {
1855 struct ebt_u_match *m;
1856 struct ebt_u_watcher *w;
1857
Bart De Schuymer9a0fbf22003-01-11 16:16:54 +00001858 if (!strcasecmp("list_extensions",
1859 argv[optind]))
1860 list_extensions();
1861
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001862 if ((m = find_match(argv[optind])))
1863 add_match(m);
1864 else if ((w = find_watcher(argv[optind])))
1865 add_watcher(w);
1866 else {
1867 if (!(t = find_target(argv[optind])))
1868 print_error("Extension %s "
1869 "not found", argv[optind]);
1870 if (replace.flags & OPT_JUMP)
1871 print_error("Sorry, you can "
1872 "only see help for one "
1873 "target extension each time");
1874 replace.flags |= OPT_JUMP;
1875 new_entry->t =
1876 (struct ebt_entry_target *)t;
1877 }
1878 optind++;
1879 }
1880 break;
1881
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001882 case 't': /* table */
Bart De Schuymer60332e02002-06-23 08:01:47 +00001883 if (replace.command != 'h')
1884 print_error("Please put the -t option first");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001885 check_option(&replace.flags, OPT_TABLE);
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001886 if (strlen(optarg) > EBT_TABLE_MAXNAMELEN - 1)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001887 print_error("Table name too long");
1888 strcpy(replace.name, optarg);
1889 break;
1890
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001891 case 'i': /* input interface */
1892 case 2 : /* logical input interface */
1893 case 'o': /* output interface */
1894 case 3 : /* logical output interface */
1895 case 'j': /* target */
1896 case 'p': /* net family protocol */
1897 case 's': /* source mac */
1898 case 'd': /* destination mac */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001899 if ((replace.flags & OPT_COMMAND) == 0)
1900 print_error("No command specified");
1901 if ( replace.command != 'A' &&
1902 replace.command != 'D' && replace.command != 'I')
1903 print_error("Command and option do not match");
1904 if (c == 'i') {
1905 check_option(&replace.flags, OPT_IN);
1906 if (replace.selected_hook > 2 &&
1907 replace.selected_hook < NF_BR_BROUTING)
1908 print_error("Use in-interface only in "
1909 "INPUT, FORWARD, PREROUTING and"
1910 "BROUTING chains");
1911 if (check_inverse(optarg))
1912 new_entry->invflags |= EBT_IIN;
1913
1914 if (optind > argc)
1915 print_error("No in-interface "
1916 "specified");
1917 if (strlen(argv[optind - 1]) >= IFNAMSIZ)
Bart De Schuymerc5075142002-08-18 14:21:19 +00001918 print_if_l_error;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001919 strcpy(new_entry->in, argv[optind - 1]);
1920 break;
1921 }
1922 if (c == 2) {
1923 check_option(&replace.flags, OPT_LOGICALIN);
1924 if (replace.selected_hook > 2 &&
1925 replace.selected_hook < NF_BR_BROUTING)
1926 print_error("Use logical in-interface "
1927 "only in INPUT, FORWARD, "
1928 "PREROUTING and BROUTING chains");
1929 if (check_inverse(optarg))
1930 new_entry->invflags |= EBT_ILOGICALIN;
1931
1932 if (optind > argc)
1933 print_error("No logical in-interface "
1934 "specified");
1935 if (strlen(argv[optind - 1]) >= IFNAMSIZ)
Bart De Schuymerc5075142002-08-18 14:21:19 +00001936 print_if_l_error;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001937 strcpy(new_entry->logical_in, argv[optind - 1]);
1938 break;
1939 }
1940 if (c == 'o') {
1941 check_option(&replace.flags, OPT_OUT);
1942 if (replace.selected_hook < 2)
1943 print_error("Use out-interface only"
1944 " in OUTPUT, FORWARD and "
1945 "POSTROUTING chains");
1946 if (check_inverse(optarg))
1947 new_entry->invflags |= EBT_IOUT;
1948
1949 if (optind > argc)
1950 print_error("No out-interface "
1951 "specified");
1952
1953 if (strlen(argv[optind - 1]) >= IFNAMSIZ)
Bart De Schuymerc5075142002-08-18 14:21:19 +00001954 print_if_l_error;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001955 strcpy(new_entry->out, argv[optind - 1]);
1956 break;
1957 }
1958 if (c == 3) {
1959 check_option(&replace.flags, OPT_LOGICALOUT);
1960 if (replace.selected_hook < 2)
1961 print_error("Use logical out-interface "
1962 "only in OUTPUT, FORWARD and "
1963 "POSTROUTING chains");
1964 if (check_inverse(optarg))
1965 new_entry->invflags |= EBT_ILOGICALOUT;
1966
1967 if (optind > argc)
1968 print_error("No logical out-interface "
1969 "specified");
1970
1971 if (strlen(argv[optind - 1]) >= IFNAMSIZ)
Bart De Schuymerc5075142002-08-18 14:21:19 +00001972 print_if_l_error;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001973 strcpy(new_entry->logical_out,
1974 argv[optind - 1]);
1975 break;
1976 }
1977 if (c == 'j') {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001978 check_option(&replace.flags, OPT_JUMP);
1979 for (i = 0; i < NUM_STANDARD_TARGETS; i++)
1980 if (!strcmp(optarg,
1981 standard_targets[i])) {
1982 t = find_target(
1983 EBT_STANDARD_TARGET);
1984 ((struct ebt_standard_target *)
Bart De Schuymer60332e02002-06-23 08:01:47 +00001985 t->t)->verdict = -i - 1;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001986 break;
1987 }
Bart De Schuymer60332e02002-06-23 08:01:47 +00001988 if (-i - 1 == EBT_RETURN) {
1989 if (replace.selected_hook < NF_BR_NUMHOOKS)
1990 print_error("Return target"
1991 " only for user defined chains");
1992 }
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +00001993 if (i != NUM_STANDARD_TARGETS)
1994 break;
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001995 if ((i = get_hooknr(optarg)) != -1) {
1996 if (i < NF_BR_NUMHOOKS)
1997 print_error("don't jump"
1998 " to a standard chain");
1999 t = find_target(
2000 EBT_STANDARD_TARGET);
2001 ((struct ebt_standard_target *)
2002 t->t)->verdict = i - NF_BR_NUMHOOKS;
2003 break;
2004 }
2005 else {
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002006 /*
2007 * must be an extension then
2008 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002009 struct ebt_u_target *t;
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00002010
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002011 t = find_target(optarg);
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002012 /*
2013 * -j standard not allowed either
2014 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002015 if (!t || t ==
2016 (struct ebt_u_target *)new_entry->t)
2017 print_error("Illegal target "
2018 "name");
2019 new_entry->t =
2020 (struct ebt_entry_target *)t;
2021 }
2022 break;
2023 }
2024 if (c == 's') {
2025 check_option(&replace.flags, OPT_SOURCE);
2026 if (check_inverse(optarg))
2027 new_entry->invflags |= EBT_ISOURCE;
2028
2029 if (optind > argc)
2030 print_error("No source mac "
2031 "specified");
2032 if (getmac_and_mask(argv[optind - 1],
2033 new_entry->sourcemac, new_entry->sourcemsk))
2034 print_error("Problem with specified "
2035 "source mac");
2036 new_entry->bitmask |= EBT_SOURCEMAC;
2037 break;
2038 }
2039 if (c == 'd') {
2040 check_option(&replace.flags, OPT_DEST);
2041 if (check_inverse(optarg))
2042 new_entry->invflags |= EBT_IDEST;
2043
2044 if (optind > argc)
2045 print_error("No destination mac "
2046 "specified");
2047 if (getmac_and_mask(argv[optind - 1],
2048 new_entry->destmac, new_entry->destmsk))
2049 print_error("Problem with specified "
2050 "destination mac");
2051 new_entry->bitmask |= EBT_DESTMAC;
2052 break;
2053 }
2054 check_option(&replace.flags, OPT_PROTOCOL);
2055 if (check_inverse(optarg))
2056 new_entry->invflags |= EBT_IPROTO;
2057
2058 if (optind > argc)
2059 print_error("No protocol specified");
2060 new_entry->bitmask &= ~((unsigned int)EBT_NOPROTO);
2061 i = strtol(argv[optind - 1], &buffer, 16);
2062 if (*buffer == '\0' && (i < 0 || i > 0xFFFF))
2063 print_error("Problem with the specified "
2064 "protocol");
2065 new_entry->ethproto = i;
Bart De Schuymer28bf6f62002-06-26 18:57:24 +00002066 if (*buffer != '\0') {
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002067 struct ethertypeent *ent;
2068
2069 if (!strcasecmp(argv[optind - 1], "LENGTH")) {
2070 new_entry->bitmask |= EBT_802_3;
2071 break;
2072 }
2073 ent = getethertypebyname(argv[optind - 1]);
2074 if (!ent)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002075 print_error("Problem with the specified"
2076 " protocol");
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002077 new_entry->ethproto = ent->e_ethertype;
Bart De Schuymer28bf6f62002-06-26 18:57:24 +00002078 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002079 if (new_entry->ethproto < 1536 &&
2080 !(new_entry->bitmask & EBT_802_3))
2081 print_error("Sorry, protocols have values above"
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00002082 " or equal to 0x0600");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002083 break;
2084
Bart De Schuymer9895a8e2003-01-11 10:14:24 +00002085 case 4 : /* Lc */
Bart De Schuymer9af14f92002-07-10 20:49:10 +00002086 check_option(&replace.flags, LIST_C);
Bart De Schuymer9af14f92002-07-10 20:49:10 +00002087 if (replace.command != 'L')
2088 print_error("Use --Lc with -L");
2089 if (replace.flags & LIST_X)
2090 print_error("--Lx not compatible with --Lc");
2091 replace.flags |= LIST_C;
2092 break;
Bart De Schuymer9895a8e2003-01-11 10:14:24 +00002093 case 5 : /* Ln */
Bart De Schuymer9af14f92002-07-10 20:49:10 +00002094 check_option(&replace.flags, LIST_N);
Bart De Schuymer9af14f92002-07-10 20:49:10 +00002095 if (replace.command != 'L')
2096 print_error("Use --Ln with -L");
2097 if (replace.flags & LIST_X)
2098 print_error("--Lx not compatible with --Ln");
2099 replace.flags |= LIST_N;
2100 break;
Bart De Schuymer9895a8e2003-01-11 10:14:24 +00002101 case 6 : /* Lx */
Bart De Schuymer9af14f92002-07-10 20:49:10 +00002102 check_option(&replace.flags, LIST_X);
Bart De Schuymer9af14f92002-07-10 20:49:10 +00002103 if (replace.command != 'L')
2104 print_error("Use --Lx with -L");
2105 if (replace.flags & LIST_C)
2106 print_error("--Lx not compatible with --Lc");
2107 if (replace.flags & LIST_N)
2108 print_error("--Lx not compatible with --Ln");
2109 replace.flags |= LIST_X;
2110 break;
Bart De Schuymer9895a8e2003-01-11 10:14:24 +00002111 case 8 : /* atomic-commit */
Bart De Schuymer62423742002-07-14 19:06:20 +00002112 replace.command = c;
2113 if (replace.flags & OPT_COMMAND)
2114 print_error("Multiple commands not allowed");
2115 replace.flags |= OPT_COMMAND;
Bart De Schuymer5885b362002-12-03 20:51:36 +00002116 if (!replace.filename)
2117 print_error("No atomic file specified");
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002118 /*
2119 * get the information from the file
2120 */
Bart De Schuymer62423742002-07-14 19:06:20 +00002121 get_table(&replace);
Bart De Schuymer868bf642002-07-16 18:14:20 +00002122 if (replace.nentries) {
Bart De Schuymered053432002-07-21 19:35:39 +00002123 replace.counterchanges = (unsigned short *)
Bart De Schuymer868bf642002-07-16 18:14:20 +00002124 malloc(sizeof(unsigned short) * (replace.nentries + 1));
2125 for (i = 0; i < replace.nentries; i++)
Bart De Schuymered053432002-07-21 19:35:39 +00002126 replace.counterchanges[i] = CNT_NORM;
2127 replace.counterchanges[i] = CNT_END;
Bart De Schuymer868bf642002-07-16 18:14:20 +00002128 }
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002129 /*
2130 * we don't want the kernel giving us its counters, they would
2131 * overwrite the counters extracted from the file
2132 */
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00002133 replace.num_counters = 0;
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002134 /*
2135 * make sure the table will be written to the kernel
Bart De Schuymer5885b362002-12-03 20:51:36 +00002136 * possible memory leak here
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002137 */
Bart De Schuymer62423742002-07-14 19:06:20 +00002138 replace.filename = NULL;
Bart De Schuymerc5c3c2d2002-08-16 19:48:03 +00002139 ebtables_insmod("ebtables", modprobe);
Bart De Schuymer62423742002-07-14 19:06:20 +00002140 break;
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002141 case 7 : /* atomic-init */
2142 case 10: /* atomic-save */
2143 case 11: /* init-table */
Bart De Schuymer62423742002-07-14 19:06:20 +00002144 replace.command = c;
2145 if (replace.flags & OPT_COMMAND)
2146 print_error("Multiple commands not allowed");
Bart De Schuymer5885b362002-12-03 20:51:36 +00002147 if (c != 11 && !replace.filename)
2148 print_error("No atomic file specified");
Bart De Schuymer62423742002-07-14 19:06:20 +00002149 replace.flags |= OPT_COMMAND;
Bart De Schuymer5885b362002-12-03 20:51:36 +00002150 {
2151 char *tmp = replace.filename;
2152
2153 tmp = replace.filename;
2154 /* get the kernel table */
2155 replace.filename = NULL;
2156 get_kernel_table(modprobe);
2157 replace.filename = tmp;
2158 }
Bart De Schuymera8d920b2002-07-16 18:30:44 +00002159 if (replace.nentries) {
Bart De Schuymered053432002-07-21 19:35:39 +00002160 replace.counterchanges = (unsigned short *)
Bart De Schuymer5f16dc72002-07-16 18:08:36 +00002161 malloc(sizeof(unsigned short) * (replace.nentries + 1));
2162 for (i = 0; i < replace.nentries; i++)
Bart De Schuymered053432002-07-21 19:35:39 +00002163 replace.counterchanges[i] = CNT_NORM;
2164 replace.counterchanges[i] = CNT_END;
Bart De Schuymer5f16dc72002-07-16 18:08:36 +00002165 }
Bart De Schuymer5885b362002-12-03 20:51:36 +00002166 break;
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002167 case 9 : /* atomic */
Bart De Schuymer5885b362002-12-03 20:51:36 +00002168 if (replace.flags & OPT_COMMAND)
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00002169 print_error("--atomic has to come before"
2170 " the command");
Bart De Schuymer5885b362002-12-03 20:51:36 +00002171 /* another possible memory leak here */
Bart De Schuymer62423742002-07-14 19:06:20 +00002172 replace.filename = (char *)malloc(strlen(optarg) + 1);
2173 strcpy(replace.filename, optarg);
2174 break;
Bart De Schuymera615b962002-11-03 14:54:09 +00002175 case 1 :
2176 if (!strcmp(optarg, "!"))
2177 check_inverse(optarg);
2178 else
2179 print_error("Bad argument : %s", optarg);
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002180 /*
2181 * check_inverse() did optind++
2182 */
Bart De Schuymera615b962002-11-03 14:54:09 +00002183 optind--;
2184 continue;
Bart De Schuymer9af14f92002-07-10 20:49:10 +00002185 default:
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002186 /*
2187 * is it a target option?
2188 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002189 t = (struct ebt_u_target *)new_entry->t;
2190 if ((t->parse(c - t->option_offset, argv, argc,
2191 new_entry, &t->flags, &t->t)))
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00002192 goto check_extension;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002193
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002194 /*
2195 * is it a match_option?
2196 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002197 for (m = matches; m; m = m->next)
2198 if (m->parse(c - m->option_offset, argv,
2199 argc, new_entry, &m->flags, &m->m))
2200 break;
2201
2202 if (m != NULL) {
2203 if (m->used == 0)
2204 add_match(m);
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00002205 goto check_extension;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002206 }
2207
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002208 /*
2209 * is it a watcher option?
2210 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002211 for (w = watchers; w; w = w->next)
2212 if (w->parse(c-w->option_offset, argv,
2213 argc, new_entry, &w->flags, &w->w))
2214 break;
2215
2216 if (w == NULL)
2217 print_error("Unknown argument");
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00002218 if (w->used == 0)
2219 add_watcher(w);
2220check_extension:
Bart De Schuymer60332e02002-06-23 08:01:47 +00002221 if (replace.command != 'A' && replace.command != 'I' &&
2222 replace.command != 'D')
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00002223 print_error("Extensions only for -A, -I and -D");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002224 }
Bart De Schuymera615b962002-11-03 14:54:09 +00002225 invert = 0;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002226 }
2227
Bart De Schuymer25c741d2002-06-23 18:54:34 +00002228 if ( !table && !(table = find_table(replace.name)) )
2229 print_error("Bad table name");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002230
2231 if ( (replace.flags & OPT_COMMAND) && replace.command != 'L' &&
2232 replace.flags & OPT_ZERO )
2233 print_error("Command -Z only allowed together with command -L");
2234
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002235 /*
2236 * do this after parsing everything, so we can print specific info
2237 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002238 if (replace.command == 'h' && !(replace.flags & OPT_ZERO))
2239 print_help();
2240
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002241 /*
2242 * do the final checks
2243 */
Bart De Schuymer60332e02002-06-23 08:01:47 +00002244 if (replace.command == 'A' || replace.command == 'I' ||
2245 replace.command == 'D') {
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002246 /*
2247 * this will put the hook_mask right for the chains
2248 */
Bart De Schuymer60332e02002-06-23 08:01:47 +00002249 check_for_loops();
2250 entries = to_chain();
2251 m_l = new_entry->m_list;
2252 w_l = new_entry->w_list;
2253 t = (struct ebt_u_target *)new_entry->t;
2254 while (m_l) {
2255 m = (struct ebt_u_match *)(m_l->m);
2256 m->final_check(new_entry, m->m, replace.name,
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +00002257 entries->hook_mask, 0);
Bart De Schuymer60332e02002-06-23 08:01:47 +00002258 m_l = m_l->next;
2259 }
2260 while (w_l) {
2261 w = (struct ebt_u_watcher *)(w_l->w);
2262 w->final_check(new_entry, w->w, replace.name,
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +00002263 entries->hook_mask, 0);
Bart De Schuymer60332e02002-06-23 08:01:47 +00002264 w_l = w_l->next;
2265 }
2266 t->final_check(new_entry, t->t, replace.name,
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +00002267 entries->hook_mask, 0);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002268 }
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002269 /*
2270 * so, the extensions can work with the host endian
2271 * the kernel does not have to do this ofcourse
2272 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002273 new_entry->ethproto = htons(new_entry->ethproto);
2274
Bart De Schuymerc34f4672002-08-18 18:03:52 +00002275 if (replace.command == 'P') {
2276 if (replace.selected_hook < NF_BR_NUMHOOKS &&
2277 policy == EBT_RETURN)
2278 print_error("Policy RETURN only allowed for user "
2279 "defined chains");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002280 change_policy(policy);
Bart De Schuymerc34f4672002-08-18 18:03:52 +00002281 } else if (replace.command == 'L') {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002282 list_rules();
2283 if (replace.flags & OPT_ZERO)
2284 zero_counters(zerochain);
2285 else
2286 exit(0);
2287 }
2288 if (replace.flags & OPT_ZERO)
2289 zero_counters(zerochain);
Bart De Schuymer1ab41562002-06-23 17:09:54 +00002290 else if (replace.command == 'F') {
2291 if (flush_chains() == -1)
2292 exit(0);
2293 } else if (replace.command == 'A' || replace.command == 'I') {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002294 add_rule(rule_nr);
Bart De Schuymer1ab41562002-06-23 17:09:54 +00002295 check_for_loops();
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002296 /*
2297 * do the final_check(), for all entries
2298 * needed when adding a rule that has a chain target
2299 */
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +00002300 i = -1;
2301 while (1) {
2302 struct ebt_u_entry *e;
2303
2304 i++;
2305 entries = nr_to_chain(i);
2306 if (!entries) {
2307 if (i < NF_BR_NUMHOOKS)
2308 continue;
2309 else
2310 break;
2311 }
2312 e = entries->entries;
2313 while (e) {
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002314 /*
2315 * userspace extensions use host endian
2316 */
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +00002317 e->ethproto = ntohs(e->ethproto);
2318 do_final_checks(e, entries);
2319 e->ethproto = htons(e->ethproto);
2320 e = e->next;
2321 }
2322 }
Bart De Schuymercc440052002-11-06 21:10:33 +00002323 } else if (replace.command == 'D') {
2324 if (rule_nr != -1 && rule_nr_end == -1)
2325 rule_nr_end = entries->nentries;
2326 delete_rule(rule_nr, rule_nr_end);
2327 }
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002328 /*
2329 * commands -N, -E, -X, --atomic-commit, --atomic-commit, --atomic-save,
2330 * --init-table fall through
2331 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002332
2333 if (table->check)
2334 table->check(&replace);
2335
2336 deliver_table(&replace);
2337
Bart De Schuymered053432002-07-21 19:35:39 +00002338 if (replace.counterchanges)
2339 deliver_counters(&replace);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002340 return 0;
2341}