blob: a5f984de4a74e511b1cf664df2db9dcbd7caf366 [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
54
Bart De Schuymer60332e02002-06-23 08:01:47 +000055char *hooknames[NF_BR_NUMHOOKS] =
56{
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000057 [NF_BR_PRE_ROUTING]"PREROUTING",
58 [NF_BR_LOCAL_IN]"INPUT",
59 [NF_BR_FORWARD]"FORWARD",
60 [NF_BR_LOCAL_OUT]"OUTPUT",
61 [NF_BR_POST_ROUTING]"POSTROUTING",
62 [NF_BR_BROUTING]"BROUTING"
63};
64
Bart De Schuymerc7bfa272002-11-20 19:40:13 +000065/*
66 * default command line options
67 * do not mess around with the already assigned numbers unless
68 * you know what you are doing
69 */
Bart De Schuymer62423742002-07-14 19:06:20 +000070static struct option ebt_original_options[] =
71{
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000072 { "append" , required_argument, 0, 'A' },
73 { "insert" , required_argument, 0, 'I' },
74 { "delete" , required_argument, 0, 'D' },
75 { "list" , optional_argument, 0, 'L' },
Bart De Schuymer9af14f92002-07-10 20:49:10 +000076 { "Lc" , no_argument , 0, 4 },
77 { "Ln" , no_argument , 0, 5 },
78 { "Lx" , no_argument , 0, 6 },
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000079 { "zero" , optional_argument, 0, 'Z' },
80 { "flush" , optional_argument, 0, 'F' },
81 { "policy" , required_argument, 0, 'P' },
82 { "in-interface" , required_argument, 0, 'i' },
83 { "in-if" , required_argument, 0, 'i' },
84 { "logical-in" , required_argument, 0, 2 },
85 { "logical-out" , required_argument, 0, 3 },
86 { "out-interface" , required_argument, 0, 'o' },
87 { "out-if" , required_argument, 0, 'o' },
88 { "version" , no_argument , 0, 'V' },
89 { "help" , no_argument , 0, 'h' },
90 { "jump" , required_argument, 0, 'j' },
91 { "proto" , required_argument, 0, 'p' },
92 { "protocol" , required_argument, 0, 'p' },
93 { "db" , required_argument, 0, 'b' },
94 { "source" , required_argument, 0, 's' },
95 { "src" , required_argument, 0, 's' },
96 { "destination" , required_argument, 0, 'd' },
97 { "dst" , required_argument, 0, 'd' },
98 { "table" , required_argument, 0, 't' },
Bart De Schuymerc8531032002-06-14 21:55:29 +000099 { "modprobe" , required_argument, 0, 'M' },
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000100 { "new-chain" , required_argument, 0, 'N' },
101 { "rename-chain" , required_argument, 0, 'E' },
102 { "delete-chain" , required_argument, 0, 'X' },
Bart De Schuymer62423742002-07-14 19:06:20 +0000103 { "atomic-init" , required_argument, 0, 7 },
Bart De Schuymer62423742002-07-14 19:06:20 +0000104 { "atomic-commit" , required_argument, 0, 8 },
105 { "atomic" , required_argument, 0, 9 },
106 { "atomic-save" , required_argument, 0, 10 },
Bart De Schuymer8d1d8942002-07-15 20:09:09 +0000107 { "init-table" , no_argument , 0, 11 },
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000108 { 0 }
109};
110
111static struct option *ebt_options = ebt_original_options;
112
Bart De Schuymer62423742002-07-14 19:06:20 +0000113char* standard_targets[NUM_STANDARD_TARGETS] =
114{
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000115 "ACCEPT",
116 "DROP",
117 "CONTINUE",
Bart De Schuymer60332e02002-06-23 08:01:47 +0000118 "RETURN",
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000119};
120
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000121unsigned char mac_type_unicast[ETH_ALEN] = {0,0,0,0,0,0};
122unsigned char msk_type_unicast[ETH_ALEN] = {1,0,0,0,0,0};
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000123unsigned char mac_type_multicast[ETH_ALEN] = {1,0,0,0,0,0};
124unsigned char msk_type_multicast[ETH_ALEN] = {1,0,0,0,0,0};
125unsigned char mac_type_broadcast[ETH_ALEN] = {255,255,255,255,255,255};
126unsigned char msk_type_broadcast[ETH_ALEN] = {255,255,255,255,255,255};
127
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000128/*
129 * holds all the data
130 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000131static struct ebt_u_replace replace;
132
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000133/*
134 * the chosen table
135 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000136static struct ebt_u_table *table = NULL;
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000137/*
138 * the lists of supported tables, matches, watchers and targets
139 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000140static struct ebt_u_table *tables = NULL;
141static struct ebt_u_match *matches = NULL;
142static struct ebt_u_watcher *watchers = NULL;
143static struct ebt_u_target *targets = NULL;
144
145struct ebt_u_target *find_target(const char *name)
146{
147 struct ebt_u_target *t = targets;
148
149 while(t && strcmp(t->name, name))
150 t = t->next;
151 return t;
152}
153
154struct ebt_u_match *find_match(const char *name)
155{
156 struct ebt_u_match *m = matches;
157
158 while(m && strcmp(m->name, name))
159 m = m->next;
160 return m;
161}
162
163struct ebt_u_watcher *find_watcher(const char *name)
164{
165 struct ebt_u_watcher *w = watchers;
166
167 while(w && strcmp(w->name, name))
168 w = w->next;
169 return w;
170}
171
172struct ebt_u_table *find_table(char *name)
173{
174 struct ebt_u_table *t = tables;
175
176 while (t && strcmp(t->name, name))
177 t = t->next;
178 return t;
179}
180
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000181/*
182 * The pointers in here are special:
183 * The struct ebt_target * pointer is actually a struct ebt_u_target * pointer.
184 * instead of making yet a few other structs, we just do a cast.
185 * We need a struct ebt_u_target pointer because we know the address of the data
186 * they point to won't change. We want to allow that the struct ebt_u_target.t
187 * member can change.
188 * Same holds for the struct ebt_match and struct ebt_watcher pointers
189 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000190struct ebt_u_entry *new_entry;
191
Bart De Schuymer62423742002-07-14 19:06:20 +0000192static void initialize_entry(struct ebt_u_entry *e)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000193{
194 e->bitmask = EBT_NOPROTO;
195 e->invflags = 0;
196 e->ethproto = 0;
197 strcpy(e->in, "");
198 strcpy(e->out, "");
199 strcpy(e->logical_in, "");
200 strcpy(e->logical_out, "");
201 e->m_list = NULL;
202 e->w_list = NULL;
203 // the init function of the standard target should have put the verdict
204 // on CONTINUE
205 e->t = (struct ebt_entry_target *)find_target(EBT_STANDARD_TARGET);
206 if (!e->t)
Bart De Schuymerd4586482002-08-11 16:15:55 +0000207 print_bug("Couldn't load standard target");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000208}
209
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000210/*
211 * this doesn't free e, becoz the calling function might need e->next
212 */
Bart De Schuymer62423742002-07-14 19:06:20 +0000213static void free_u_entry(struct ebt_u_entry *e)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000214{
215 struct ebt_u_match_list *m_l, *m_l2;
216 struct ebt_u_watcher_list *w_l, *w_l2;
217
218 m_l = e->m_list;
219 while (m_l) {
220 m_l2 = m_l->next;
221 free(m_l->m);
222 free(m_l);
223 m_l = m_l2;
224 }
225 w_l = e->w_list;
226 while (w_l) {
227 w_l2 = w_l->next;
228 free(w_l->w);
229 free(w_l);
230 w_l = w_l2;
231 }
232 free(e->t);
233}
234
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000235/*
236 * the user will use the match, so put it in new_entry
237 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000238static void add_match(struct ebt_u_match *m)
239{
240 struct ebt_u_match_list **m_list, *new;
241
242 m->used = 1;
Bart De Schuymerc56a31a2002-07-25 08:16:08 +0000243 for (m_list = &new_entry->m_list; *m_list; m_list = &(*m_list)->next);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000244 new = (struct ebt_u_match_list *)
245 malloc(sizeof(struct ebt_u_match_list));
246 if (!new)
247 print_memory();
248 *m_list = new;
249 new->next = NULL;
250 new->m = (struct ebt_entry_match *)m;
251}
252
253static void add_watcher(struct ebt_u_watcher *w)
254{
255 struct ebt_u_watcher_list **w_list;
256 struct ebt_u_watcher_list *new;
257
258 w->used = 1;
Bart De Schuymerc56a31a2002-07-25 08:16:08 +0000259 for (w_list = &new_entry->w_list; *w_list; w_list = &(*w_list)->next);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000260 new = (struct ebt_u_watcher_list *)
261 malloc(sizeof(struct ebt_u_watcher_list));
262 if (!new)
263 print_memory();
264 *w_list = new;
265 new->next = NULL;
266 new->w = (struct ebt_entry_watcher *)w;
267}
268
269static int global_option_offset = 0;
270#define OPTION_OFFSET 256
271static struct option *
272merge_options(struct option *oldopts, const struct option *newopts,
273 unsigned int *options_offset)
274{
275 unsigned int num_old, num_new, i;
276 struct option *merge;
277
278 if (!newopts || !oldopts || !options_offset)
279 print_bug("merge wrong");
280 for (num_old = 0; oldopts[num_old].name; num_old++);
281 for (num_new = 0; newopts[num_new].name; num_new++);
282
283 global_option_offset += OPTION_OFFSET;
284 *options_offset = global_option_offset;
285
286 merge = malloc(sizeof(struct option) * (num_new + num_old + 1));
287 if (!merge)
288 print_memory();
289 memcpy(merge, oldopts, num_old * sizeof(struct option));
290 for (i = 0; i < num_new; i++) {
291 merge[num_old + i] = newopts[i];
292 merge[num_old + i].val += *options_offset;
293 }
294 memset(merge + num_old + num_new, 0, sizeof(struct option));
295 // only free dynamically allocated stuff
296 if (oldopts != ebt_original_options)
297 free(oldopts);
298
299 return merge;
300}
301
302void register_match(struct ebt_u_match *m)
303{
304 int size = m->size + sizeof(struct ebt_entry_match);
305 struct ebt_u_match **i;
306
307 m->m = (struct ebt_entry_match *)malloc(size);
308 if (!m->m)
309 print_memory();
310 strcpy(m->m->u.name, m->name);
311 m->m->match_size = m->size;
312 ebt_options = merge_options
313 (ebt_options, m->extra_ops, &(m->option_offset));
314 m->init(m->m);
315
316 for (i = &matches; *i; i = &((*i)->next));
317 m->next = NULL;
318 *i = m;
319}
320
321void register_watcher(struct ebt_u_watcher *w)
322{
323 int size = w->size + sizeof(struct ebt_entry_watcher);
324 struct ebt_u_watcher **i;
325
326 w->w = (struct ebt_entry_watcher *)malloc(size);
327 if (!w->w)
328 print_memory();
329 strcpy(w->w->u.name, w->name);
330 w->w->watcher_size = w->size;
331 ebt_options = merge_options
332 (ebt_options, w->extra_ops, &(w->option_offset));
333 w->init(w->w);
334
335 for (i = &watchers; *i; i = &((*i)->next));
336 w->next = NULL;
337 *i = w;
338}
339
340void register_target(struct ebt_u_target *t)
341{
342 int size = t->size + sizeof(struct ebt_entry_target);
343 struct ebt_u_target **i;
344
345 t->t = (struct ebt_entry_target *)malloc(size);
346 if (!t->t)
347 print_memory();
348 strcpy(t->t->u.name, t->name);
349 t->t->target_size = t->size;
350 ebt_options = merge_options
351 (ebt_options, t->extra_ops, &(t->option_offset));
352 t->init(t->t);
Bart De Schuymerc56a31a2002-07-25 08:16:08 +0000353
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000354 for (i = &targets; *i; i = &((*i)->next));
355 t->next = NULL;
356 *i = t;
357}
358
359void register_table(struct ebt_u_table *t)
360{
361 t->next = tables;
362 tables = t;
363}
364
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000365/*
366 * blatently stolen (again) from iptables.c userspace program
367 * find out where the modprobe utility is located
368 */
Bart De Schuymerc8531032002-06-14 21:55:29 +0000369static char *get_modprobe(void)
370{
371 int procfile;
372 char *ret;
373
374 procfile = open(PROC_SYS_MODPROBE, O_RDONLY);
375 if (procfile < 0)
376 return NULL;
377
378 ret = malloc(1024);
379 if (ret) {
380 switch (read(procfile, ret, 1024)) {
381 case -1: goto fail;
382 case 1024: goto fail; /* Partial read. Wierd */
383 }
384 if (ret[strlen(ret)-1]=='\n')
385 ret[strlen(ret)-1]=0;
386 close(procfile);
387 return ret;
388 }
389 fail:
390 free(ret);
391 close(procfile);
392 return NULL;
393}
394
Bart De Schuymerc8531032002-06-14 21:55:29 +0000395int ebtables_insmod(const char *modname, const char *modprobe)
396{
397 char *buf = NULL;
398 char *argv[3];
399
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000400 // If they don't explicitly set it, read out of kernel
Bart De Schuymerc8531032002-06-14 21:55:29 +0000401 if (!modprobe) {
402 buf = get_modprobe();
403 if (!buf)
404 return -1;
405 modprobe = buf;
406 }
407
408 switch (fork()) {
409 case 0:
410 argv[0] = (char *)modprobe;
411 argv[1] = (char *)modname;
412 argv[2] = NULL;
413 execv(argv[0], argv);
414
415 /* not usually reached */
416 exit(0);
417 case -1:
418 return -1;
419
420 default: /* parent */
421 wait(NULL);
422 }
423
424 free(buf);
425 return 0;
426}
427
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000428/*
429 * we use replace.flags, so we can't use the following values:
430 * 0x01 == OPT_COMMAND, 0x02 == OPT_TABLE, 0x100 == OPT_ZERO
431 */
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000432#define LIST_N 0x04
433#define LIST_C 0x08
434#define LIST_X 0x10
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000435/*
436 * helper function for list_rules()
437 */
Bart De Schuymer60332e02002-06-23 08:01:47 +0000438static void list_em(struct ebt_u_entries *entries)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000439{
440 int i, j, space = 0, digits;
441 struct ebt_u_entry *hlp;
442 struct ebt_u_match_list *m_l;
443 struct ebt_u_watcher_list *w_l;
444 struct ebt_u_match *m;
445 struct ebt_u_watcher *w;
446 struct ebt_u_target *t;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000447
Bart De Schuymer60332e02002-06-23 08:01:47 +0000448 hlp = entries->entries;
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000449 if (replace.flags & LIST_X && entries->policy != EBT_ACCEPT) {
450 printf("ebtables -t %s -P %s %s\n", replace.name,
451 entries->name, standard_targets[-entries->policy - 1]);
452 } else if (!(replace.flags & LIST_X)) {
Bart De Schuymerc87c9642002-08-01 15:34:16 +0000453 printf("\nBridge chain: %s, entries: %d, policy: %s\n",
454 entries->name, entries->nentries,
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000455 standard_targets[-entries->policy - 1]);
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000456 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000457
Bart De Schuymer60332e02002-06-23 08:01:47 +0000458 i = entries->nentries;
Bart De Schuymerf8f8f292002-06-25 15:43:57 +0000459 while (i > 9) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000460 space++;
461 i /= 10;
462 }
463
Bart De Schuymer60332e02002-06-23 08:01:47 +0000464 for (i = 0; i < entries->nentries; i++) {
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000465 if (replace.flags & LIST_N) {
466 digits = 0;
467 // A little work to get nice rule numbers.
468 j = i + 1;
469 while (j > 9) {
470 digits++;
471 j /= 10;
472 }
473 for (j = 0; j < space - digits; j++)
474 printf(" ");
475 printf("%d. ", i + 1);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000476 }
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000477 if (replace.flags & LIST_X)
478 printf("ebtables -t %s -A %s ",
479 replace.name, entries->name);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000480
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000481 /*
482 * Don't print anything about the protocol if no protocol was
483 * specified, obviously this means any protocol will do.
484 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000485 if (!(hlp->bitmask & EBT_NOPROTO)) {
Bart De Schuymer60332e02002-06-23 08:01:47 +0000486 printf("-p ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000487 if (hlp->invflags & EBT_IPROTO)
488 printf("! ");
489 if (hlp->bitmask & EBT_802_3)
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000490 printf("Length ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000491 else {
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000492 struct ethertypeent *ent;
493
494 ent = getethertypebynumber(ntohs(hlp->ethproto));
495 if (!ent)
Bart De Schuymer60332e02002-06-23 08:01:47 +0000496 printf("0x%x ", ntohs(hlp->ethproto));
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000497 else
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000498 printf("%s ", ent->e_name);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000499 }
500 }
501 if (hlp->bitmask & EBT_SOURCEMAC) {
502 char hlpmsk[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
503
Bart De Schuymer60332e02002-06-23 08:01:47 +0000504 printf("-s ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000505 if (hlp->invflags & EBT_ISOURCE)
506 printf("! ");
507 if (!memcmp(hlp->sourcemac, mac_type_unicast, 6) &&
508 !memcmp(hlp->sourcemsk, msk_type_unicast, 6)) {
509 printf("Unicast");
510 goto endsrc;
511 }
512 if (!memcmp(hlp->sourcemac, mac_type_multicast, 6) &&
513 !memcmp(hlp->sourcemsk, msk_type_multicast, 6)) {
514 printf("Multicast");
515 goto endsrc;
516 }
517 if (!memcmp(hlp->sourcemac, mac_type_broadcast, 6) &&
518 !memcmp(hlp->sourcemsk, msk_type_broadcast, 6)) {
519 printf("Broadcast");
520 goto endsrc;
521 }
Bart De Schuymer41830412002-06-05 19:41:28 +0000522 printf("%s", ether_ntoa((struct ether_addr *)
523 hlp->sourcemac));
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000524 if (memcmp(hlp->sourcemsk, hlpmsk, 6)) {
525 printf("/");
Bart De Schuymer41830412002-06-05 19:41:28 +0000526 printf("%s", ether_ntoa((struct ether_addr *)
527 hlp->sourcemsk));
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000528 }
529endsrc:
Bart De Schuymer60332e02002-06-23 08:01:47 +0000530 printf(" ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000531 }
532 if (hlp->bitmask & EBT_DESTMAC) {
533 char hlpmsk[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
534
Bart De Schuymer60332e02002-06-23 08:01:47 +0000535 printf("-d ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000536 if (hlp->invflags & EBT_IDEST)
537 printf("! ");
538 if (!memcmp(hlp->destmac, mac_type_unicast, 6) &&
539 !memcmp(hlp->destmsk, msk_type_unicast, 6)) {
540 printf("Unicast");
541 goto enddst;
542 }
543 if (!memcmp(hlp->destmac, mac_type_multicast, 6) &&
544 !memcmp(hlp->destmsk, msk_type_multicast, 6)) {
545 printf("Multicast");
546 goto enddst;
547 }
548 if (!memcmp(hlp->destmac, mac_type_broadcast, 6) &&
549 !memcmp(hlp->destmsk, msk_type_broadcast, 6)) {
550 printf("Broadcast");
551 goto enddst;
552 }
Bart De Schuymer41830412002-06-05 19:41:28 +0000553 printf("%s", ether_ntoa((struct ether_addr *)
554 hlp->destmac));
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000555 if (memcmp(hlp->destmsk, hlpmsk, 6)) {
556 printf("/");
Bart De Schuymer41830412002-06-05 19:41:28 +0000557 printf("%s", ether_ntoa((struct ether_addr *)
558 hlp->destmsk));
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000559 }
560enddst:
Bart De Schuymer60332e02002-06-23 08:01:47 +0000561 printf(" ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000562 }
563 if (hlp->in[0] != '\0') {
Bart De Schuymer60332e02002-06-23 08:01:47 +0000564 printf("-i ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000565 if (hlp->invflags & EBT_IIN)
566 printf("! ");
Bart De Schuymer60332e02002-06-23 08:01:47 +0000567 printf("%s ", hlp->in);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000568 }
569 if (hlp->logical_in[0] != '\0') {
Bart De Schuymer60332e02002-06-23 08:01:47 +0000570 printf("--logical-in ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000571 if (hlp->invflags & EBT_ILOGICALIN)
572 printf("! ");
Bart De Schuymer60332e02002-06-23 08:01:47 +0000573 printf("%s ", hlp->logical_in);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000574 }
575 if (hlp->logical_out[0] != '\0') {
Bart De Schuymer60332e02002-06-23 08:01:47 +0000576 printf("--logical-out ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000577 if (hlp->invflags & EBT_ILOGICALOUT)
578 printf("! ");
Bart De Schuymerb3d8f262002-07-07 14:26:15 +0000579 printf("%s ", hlp->logical_out);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000580 }
581 if (hlp->out[0] != '\0') {
Bart De Schuymer60332e02002-06-23 08:01:47 +0000582 printf("-o ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000583 if (hlp->invflags & EBT_IOUT)
584 printf("! ");
Bart De Schuymerb3d8f262002-07-07 14:26:15 +0000585 printf("%s ", hlp->out);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000586 }
587
588 m_l = hlp->m_list;
589 while (m_l) {
590 m = find_match(m_l->m->u.name);
591 if (!m)
592 print_bug("Match not found");
593 m->print(hlp, m_l->m);
594 m_l = m_l->next;
595 }
596 w_l = hlp->w_list;
597 while (w_l) {
598 w = find_watcher(w_l->w->u.name);
599 if (!w)
600 print_bug("Watcher not found");
601 w->print(hlp, w_l->w);
602 w_l = w_l->next;
603 }
604
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000605 printf("-j ");
606 if (strcmp(hlp->t->u.name, EBT_STANDARD_TARGET))
607 printf("%s ", hlp->t->u.name);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000608 t = find_target(hlp->t->u.name);
609 if (!t)
610 print_bug("Target not found");
611 t->print(hlp, hlp->t);
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000612 if (replace.flags & LIST_C)
Bart De Schuymer73fccca2002-10-17 22:00:23 +0000613 printf(", pcnt = %llu -- bcnt = %llu",
614 replace.counters[entries->counter_offset + i].pcnt,
615 replace.counters[entries->counter_offset + i].bcnt);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000616 printf("\n");
617 hlp = hlp->next;
618 }
619}
620
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000621struct ebt_u_entries *nr_to_chain(int nr)
Bart De Schuymer60332e02002-06-23 08:01:47 +0000622{
623 if (nr == -1)
624 return NULL;
625 if (nr < NF_BR_NUMHOOKS)
626 return replace.hook_entry[nr];
627 else {
628 int i;
629 struct ebt_u_chain_list *cl = replace.udc;
630
631 i = nr - NF_BR_NUMHOOKS;
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000632 while (i > 0 && cl) {
Bart De Schuymer60332e02002-06-23 08:01:47 +0000633 cl = cl->next;
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000634 i--;
635 }
Bart De Schuymer60332e02002-06-23 08:01:47 +0000636 if (cl)
637 return cl->udc;
638 else
639 return NULL;
640 }
641}
642
Bart De Schuymercc440052002-11-06 21:10:33 +0000643static inline struct ebt_u_entries *to_chain()
Bart De Schuymer60332e02002-06-23 08:01:47 +0000644{
645 return nr_to_chain(replace.selected_hook);
646}
647
648struct ebt_u_stack
649{
650 int chain_nr;
651 int n;
652 struct ebt_u_entry *e;
653 struct ebt_u_entries *entries;
654};
655
Bart De Schuymer62423742002-07-14 19:06:20 +0000656static void check_for_loops()
Bart De Schuymer60332e02002-06-23 08:01:47 +0000657{
658 int chain_nr , i, j , k, sp = 0, verdict;
659 struct ebt_u_entries *entries, *entries2;
660 struct ebt_u_stack *stack = NULL;
661 struct ebt_u_entry *e;
662
663 i = -1;
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000664 /*
665 * initialize hook_mask to 0
666 */
Bart De Schuymer60332e02002-06-23 08:01:47 +0000667 while (1) {
668 i++;
669 if (i < NF_BR_NUMHOOKS && !(replace.valid_hooks & (1 << i)))
670 continue;
671 entries = nr_to_chain(i);
672 if (!entries)
673 break;
674 entries->hook_mask = 0;
675 }
676 if (i > NF_BR_NUMHOOKS) {
677 stack = (struct ebt_u_stack *)malloc((i - NF_BR_NUMHOOKS) *
678 sizeof(struct ebt_u_stack));
679 if (!stack)
680 print_memory();
681 }
682
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000683 /*
684 * check for loops, starting from every base chain
685 */
Bart De Schuymer60332e02002-06-23 08:01:47 +0000686 for (i = 0; i < NF_BR_NUMHOOKS; i++) {
687 if (!(replace.valid_hooks & (1 << i)))
688 continue;
689 entries = nr_to_chain(i);
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000690 /*
691 * (1 << NF_BR_NUMHOOKS) implies it's a standard chain
692 * (usefull in the final_check() funtions)
693 */
Bart De Schuymerb26649e2002-07-25 14:51:54 +0000694 entries->hook_mask = (1 << i) | (1 << NF_BR_NUMHOOKS);
Bart De Schuymer60332e02002-06-23 08:01:47 +0000695 chain_nr = i;
696
697 e = entries->entries;
698 for (j = 0; j < entries->nentries; j++) {
699 if (strcmp(e->t->u.name, EBT_STANDARD_TARGET))
700 goto letscontinue;
701 verdict = ((struct ebt_standard_target *)(e->t))->verdict;
702 if (verdict < 0)
703 goto letscontinue;
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000704 entries2 = nr_to_chain(verdict + NF_BR_NUMHOOKS);
Bart De Schuymer60332e02002-06-23 08:01:47 +0000705 entries2->hook_mask |= entries->hook_mask;
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000706 /*
707 * now see if we've been here before
708 */
Bart De Schuymer60332e02002-06-23 08:01:47 +0000709 for (k = 0; k < sp; k++)
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000710 if (stack[k].chain_nr == verdict + NF_BR_NUMHOOKS)
Bart De Schuymer1a0a9c32002-06-24 21:10:16 +0000711 print_error("Loop from chain %s to chain %s",
Bart De Schuymerc56a31a2002-07-25 08:16:08 +0000712 nr_to_chain(chain_nr)->name,
713 nr_to_chain(stack[k].chain_nr)->name);
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000714 /*
715 * jump to the chain, make sure we know how to get back
716 */
Bart De Schuymer60332e02002-06-23 08:01:47 +0000717 stack[sp].chain_nr = chain_nr;
718 stack[sp].n = j;
719 stack[sp].entries = entries;
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000720 stack[sp].e = e;
721 sp++;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000722 j = -1;
723 e = entries2->entries;
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000724 chain_nr = verdict + NF_BR_NUMHOOKS;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000725 entries = entries2;
726 continue;
727letscontinue:
728 e = e->next;
729 }
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000730 /*
731 * we are at the end of a standard chain
732 */
Bart De Schuymer60332e02002-06-23 08:01:47 +0000733 if (sp == 0)
734 continue;
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000735 /*
736 * go back to the chain one level higher
737 */
Bart De Schuymer60332e02002-06-23 08:01:47 +0000738 sp--;
739 j = stack[sp].n;
740 chain_nr = stack[sp].chain_nr;
741 e = stack[sp].e;
742 entries = stack[sp].entries;
743 goto letscontinue;
744 }
745 free(stack);
746 return;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000747}
748
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000749/*
750 * parse the chain name and return the corresponding nr
751 * returns -1 on failure
752 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000753int get_hooknr(char* arg)
754{
755 int i;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000756 struct ebt_u_chain_list *cl = replace.udc;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000757
Bart De Schuymer60332e02002-06-23 08:01:47 +0000758 for (i = 0; i < NF_BR_NUMHOOKS; i++) {
759 if (!(replace.valid_hooks & (1 << i)))
760 continue;
761 if (!strcmp(arg, replace.hook_entry[i]->name))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000762 return i;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000763 }
764 while(cl) {
765 if (!strcmp(arg, cl->udc->name))
766 return i;
767 i++;
768 cl = cl->next;
769 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000770 return -1;
771}
772
Bart De Schuymer62423742002-07-14 19:06:20 +0000773static void print_help()
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000774{
775 struct ebt_u_match_list *m_l;
776 struct ebt_u_watcher_list *w_l;
777
Bart De Schuymerd4586482002-08-11 16:15:55 +0000778 printf(PROGNAME" v"PROGVERSION" ("PROGDATE")\n"
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000779"Usage:\n"
780"ebtables -[ADI] chain rule-specification [options]\n"
781"ebtables -P chain target\n"
782"ebtables -[LFZ] [chain]\n"
783"ebtables -[b] [y,n]\n"
784"Commands:\n"
Bart De Schuymer23f6dcf2002-08-17 09:14:07 +0000785"--append -A chain : append to chain\n"
786"--delete -D chain : delete matching rule from chain\n"
787"--delete -D chain rulenum : delete rule at position rulenum from chain\n"
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000788"--insert -I chain rulenum : insert rule at position rulenum in chain\n"
Bart De Schuymer23f6dcf2002-08-17 09:14:07 +0000789"--list -L [chain] : list the rules in a chain or in all chains\n"
790"--flush -F [chain] : delete all rules in chain or in all chains\n"
791"--init-table : replace the kernel table with the initial table\n"
792"--zero -Z [chain] : put counters on zero in chain or in all chains\n"
793"--policy -P chain target : change policy on chain to target\n"
794"--new-chain -N chain : create a user defined chain\n"
795"--rename-chain -E old new : rename a chain\n"
796"--delete-chain -X chain : delete a user defined chain\n"
Bart De Schuymer62423742002-07-14 19:06:20 +0000797"--atomic-commit file : update the kernel w/ the table contained in file\n"
798"--atomic-init file : put the initial kernel table into file\n"
799"--atomic-save file : put the current kernel table into file\n"
800"--atomic file : write changes to file instead of kernel\n"
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000801"Options:\n"
802"--proto -p [!] proto : protocol hexadecimal, by name or LENGTH\n"
803"--src -s [!] address[/mask]: source mac address\n"
804"--dst -d [!] address[/mask]: destination mac address\n"
805"--in-if -i [!] name : network input interface name\n"
806"--out-if -o [!] name : network output interface name\n"
807"--logical-in [!] name : logical bridge input interface name\n"
808"--logical-out [!] name : logical bridge output interface name\n"
Bart De Schuymer5cbc8e02002-07-14 21:15:28 +0000809"--modprobe -M program : try to insert modules using this program\n"
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000810"--version -V : print package version\n"
Bart De Schuymerd4586482002-08-11 16:15:55 +0000811"\n");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000812
813 m_l = new_entry->m_list;
814 while (m_l) {
815 ((struct ebt_u_match *)m_l->m)->help();
816 printf("\n");
817 m_l = m_l->next;
818 }
819 w_l = new_entry->w_list;
820 while (w_l) {
821 ((struct ebt_u_watcher *)w_l->w)->help();
822 printf("\n");
823 w_l = w_l->next;
824 }
825 ((struct ebt_u_target *)new_entry->t)->help();
826 printf("\n");
827 if (table->help)
828 table->help(hooknames);
829 exit(0);
830}
831
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000832/*
833 * execute command L
834 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000835static void list_rules()
836{
837 int i;
838
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000839 if (!(replace.flags & LIST_X))
840 printf("Bridge table: %s\n", table->name);
Bart De Schuymer60332e02002-06-23 08:01:47 +0000841 if (replace.selected_hook != -1) {
842 list_em(to_chain());
843 } else {
844 struct ebt_u_chain_list *cl = replace.udc;
845
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000846 /*
847 * create new chains and rename standard chains when necessary
848 */
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000849 if (replace.flags & LIST_X) {
850 while (cl) {
851 printf("ebtables -t %s -N %s\n", replace.name,
852 cl->udc->name);
853 cl = cl->next;
854 }
855 cl = replace.udc;
856 for (i = 0; i < NF_BR_NUMHOOKS; i++)
857 if (replace.valid_hooks & (1 << i) &&
858 strcmp(replace.hook_entry[i]->name, hooknames[i]))
859 printf("ebtables -t %s -E %s %s\n",
860 replace.name, hooknames[i],
861 replace.hook_entry[i]->name);
862 }
Bart De Schuymer60332e02002-06-23 08:01:47 +0000863 i = 0;
864 while (1) {
865 if (i < NF_BR_NUMHOOKS) {
866 if (replace.valid_hooks & (1 << i))
867 list_em(replace.hook_entry[i]);
868 i++;
869 continue;
870 } else {
871 if (!cl)
872 break;
873 list_em(cl->udc);
874 cl = cl->next;
875 }
876 }
877 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000878}
879
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000880/*
881 * execute command P
882 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000883static void change_policy(int policy)
884{
885 int i;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000886 struct ebt_u_entries *entries = to_chain();
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000887
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000888 /*
889 * don't do anything if the policy is the same
890 */
Bart De Schuymer60332e02002-06-23 08:01:47 +0000891 if (entries->policy != policy) {
892 entries->policy = policy;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000893 replace.num_counters = replace.nentries;
894 if (replace.nentries) {
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000895 /*
896 * '+ 1' for the CNT_END
897 */
Bart De Schuymered053432002-07-21 19:35:39 +0000898 if (!(replace.counterchanges = (unsigned short *) malloc(
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000899 (replace.nentries + 1) * sizeof(unsigned short))))
900 print_memory();
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000901 /*
902 * done nothing special to the rules
903 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000904 for (i = 0; i < replace.nentries; i++)
Bart De Schuymered053432002-07-21 19:35:39 +0000905 replace.counterchanges[i] = CNT_NORM;
906 replace.counterchanges[replace.nentries] = CNT_END;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000907 }
908 else
Bart De Schuymered053432002-07-21 19:35:39 +0000909 replace.counterchanges = NULL;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000910 }
911 else
912 exit(0);
913}
914
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000915/*
916 * flush one chain or the complete table
917 * -1 == nothing to do
918 * 0 == give back to kernel
919 */
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000920static int flush_chains()
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000921{
Bart De Schuymer60332e02002-06-23 08:01:47 +0000922 int i, j, oldnentries, numdel;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000923 unsigned short *cnt;
924 struct ebt_u_entry *u_e, *tmp;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000925 struct ebt_u_entries *entries = to_chain();
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000926
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000927 /*
928 * flush whole table
929 */
Bart De Schuymer60332e02002-06-23 08:01:47 +0000930 if (!entries) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000931 if (replace.nentries == 0)
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000932 return -1;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000933 replace.nentries = 0;
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000934 /*
935 * no need for the kernel to give us counters back
936 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000937 replace.num_counters = 0;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000938
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000939 /*
940 * free everything and zero (n)entries
941 */
Bart De Schuymer60332e02002-06-23 08:01:47 +0000942 i = -1;
943 while (1) {
944 i++;
945 entries = nr_to_chain(i);
946 if (!entries) {
947 if (i < NF_BR_NUMHOOKS)
948 continue;
949 else
950 break;
951 }
952 entries->nentries = 0;
953 entries->counter_offset = 0;
954 u_e = entries->entries;
955 entries->entries = NULL;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000956 while (u_e) {
957 free_u_entry(u_e);
958 tmp = u_e->next;
959 free(u_e);
960 u_e = tmp;
961 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000962 }
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000963 return 0;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000964 }
965
Bart De Schuymer60332e02002-06-23 08:01:47 +0000966 if (entries->nentries == 0)
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000967 return -1;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000968 oldnentries = replace.nentries;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000969 replace.nentries -= entries->nentries;
970 numdel = entries->nentries;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000971
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000972 if (replace.nentries) {
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000973 /*
974 * +1 for CNT_END
975 */
Bart De Schuymered053432002-07-21 19:35:39 +0000976 if ( !(replace.counterchanges = (unsigned short *)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000977 malloc((oldnentries + 1) * sizeof(unsigned short))) )
978 print_memory();
Bart De Schuymer60332e02002-06-23 08:01:47 +0000979 }
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000980 /*
981 * delete the counters belonging to the specified chain,
982 * update counter_offset
983 */
Bart De Schuymer60332e02002-06-23 08:01:47 +0000984 i = -1;
Bart De Schuymered053432002-07-21 19:35:39 +0000985 cnt = replace.counterchanges;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000986 while (1) {
987 i++;
988 entries = nr_to_chain(i);
989 if (!entries) {
990 if (i < NF_BR_NUMHOOKS)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000991 continue;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000992 else
993 break;
994 }
995 if (i > replace.selected_hook)
996 entries->counter_offset -= numdel;
997 if (replace.nentries) {
998 for (j = 0; j < entries->nentries; j++) {
999 if (i == replace.selected_hook)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001000 *cnt = CNT_DEL;
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001001 else
1002 *cnt = CNT_NORM;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001003 cnt++;
1004 }
1005 }
Bart De Schuymer60332e02002-06-23 08:01:47 +00001006 }
1007
1008 if (replace.nentries) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001009 *cnt = CNT_END;
1010 replace.num_counters = oldnentries;
Bart De Schuymercc440052002-11-06 21:10:33 +00001011 } else
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001012 replace.num_counters = 0;
1013
Bart De Schuymer60332e02002-06-23 08:01:47 +00001014 entries = to_chain();
1015 entries->nentries = 0;
1016 u_e = entries->entries;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001017 while (u_e) {
1018 free_u_entry(u_e);
1019 tmp = u_e->next;
1020 free(u_e);
1021 u_e = tmp;
1022 }
Bart De Schuymer60332e02002-06-23 08:01:47 +00001023 entries->entries = NULL;
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001024 return 0;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001025}
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001026
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001027/*
1028 * -1 == no match
1029 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001030static int check_rule_exists(int rule_nr)
1031{
1032 struct ebt_u_entry *u_e;
1033 struct ebt_u_match_list *m_l, *m_l2;
1034 struct ebt_u_match *m;
1035 struct ebt_u_watcher_list *w_l, *w_l2;
1036 struct ebt_u_watcher *w;
1037 struct ebt_u_target *t = (struct ebt_u_target *)new_entry->t;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001038 struct ebt_u_entries *entries = to_chain();
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001039 int i, j, k;
1040
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001041 /*
1042 * handle '-D chain rulenr' command
1043 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001044 if (rule_nr != -1) {
Bart De Schuymer60332e02002-06-23 08:01:47 +00001045 if (rule_nr > entries->nentries)
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001046 return -1;
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001047 /*
1048 * user starts counting from 1
1049 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001050 return rule_nr - 1;
1051 }
Bart De Schuymer60332e02002-06-23 08:01:47 +00001052 u_e = entries->entries;
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001053 /*
1054 * check for an existing rule (if there are duplicate rules,
1055 * take the first occurance)
1056 */
Bart De Schuymer60332e02002-06-23 08:01:47 +00001057 for (i = 0; i < entries->nentries; i++, u_e = u_e->next) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001058 if (!u_e)
1059 print_bug("Hmm, trouble");
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001060 if (u_e->ethproto != new_entry->ethproto)
1061 continue;
1062 if (strcmp(u_e->in, new_entry->in))
1063 continue;
1064 if (strcmp(u_e->out, new_entry->out))
1065 continue;
1066 if (strcmp(u_e->logical_in, new_entry->logical_in))
1067 continue;
1068 if (strcmp(u_e->logical_out, new_entry->logical_out))
1069 continue;
1070 if (new_entry->bitmask & EBT_SOURCEMAC &&
1071 memcmp(u_e->sourcemac, new_entry->sourcemac, ETH_ALEN))
1072 continue;
1073 if (new_entry->bitmask & EBT_DESTMAC &&
1074 memcmp(u_e->destmac, new_entry->destmac, ETH_ALEN))
1075 continue;
1076 if (new_entry->bitmask != u_e->bitmask ||
1077 new_entry->invflags != u_e->invflags)
1078 continue;
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001079 /*
1080 * compare all matches
1081 */
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001082 m_l = new_entry->m_list;
1083 j = 0;
1084 while (m_l) {
1085 m = (struct ebt_u_match *)(m_l->m);
1086 m_l2 = u_e->m_list;
1087 while (m_l2 && strcmp(m_l2->m->u.name, m->m->u.name))
1088 m_l2 = m_l2->next;
1089 if (!m_l2 || !m->compare(m->m, m_l2->m))
1090 goto letscontinue;
1091 j++;
1092 m_l = m_l->next;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001093 }
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001094 /*
1095 * now be sure they have the same nr of matches
1096 */
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001097 k = 0;
1098 m_l = u_e->m_list;
1099 while (m_l) {
1100 k++;
1101 m_l = m_l->next;
1102 }
1103 if (j != k)
1104 continue;
1105
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001106 /*
1107 * compare all watchers
1108 */
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001109 w_l = new_entry->w_list;
1110 j = 0;
1111 while (w_l) {
1112 w = (struct ebt_u_watcher *)(w_l->w);
1113 w_l2 = u_e->w_list;
1114 while (w_l2 && strcmp(w_l2->w->u.name, w->w->u.name))
1115 w_l2 = w_l2->next;
1116 if (!w_l2 || !w->compare(w->w, w_l2->w))
1117 goto letscontinue;
1118 j++;
1119 w_l = w_l->next;
1120 }
1121 k = 0;
1122 w_l = u_e->w_list;
1123 while (w_l) {
1124 k++;
1125 w_l = w_l->next;
1126 }
1127 if (j != k)
1128 continue;
1129 if (strcmp(t->t->u.name, u_e->t->u.name))
1130 continue;
1131 if (!t->compare(t->t, u_e->t))
1132 continue;
1133 return i;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001134letscontinue:
1135 }
1136 return -1;
1137}
1138
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001139// execute command A or I
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001140static void add_rule(int rule_nr)
1141{
1142 int i, j;
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001143 struct ebt_u_entry **u_e;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001144 unsigned short *cnt;
1145 struct ebt_u_match_list *m_l;
1146 struct ebt_u_watcher_list *w_l;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001147 struct ebt_u_entries *entries = to_chain(), *entries2;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001148
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001149 if (rule_nr != -1) { /* command -I */
Bart De Schuymer60332e02002-06-23 08:01:47 +00001150 if (--rule_nr > entries->nentries)
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001151 print_error("rule nr too high: %d > %d", rule_nr + 1,
1152 entries->nentries + 1);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001153 } else
Bart De Schuymer60332e02002-06-23 08:01:47 +00001154 rule_nr = entries->nentries;
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001155 /*
1156 * we're adding one rule
1157 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001158 replace.num_counters = replace.nentries;
1159 replace.nentries++;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001160 entries->nentries++;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001161
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001162 /*
1163 * handle counter stuff
1164 * +1 for CNT_END
1165 */
Bart De Schuymered053432002-07-21 19:35:39 +00001166 if ( !(replace.counterchanges = (unsigned short *)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001167 malloc((replace.nentries + 1) * sizeof(unsigned short))) )
1168 print_memory();
Bart De Schuymered053432002-07-21 19:35:39 +00001169 cnt = replace.counterchanges;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001170 for (i = 0; i < replace.selected_hook; i++) {
Bart De Schuymer60332e02002-06-23 08:01:47 +00001171 if (i < NF_BR_NUMHOOKS && !(replace.valid_hooks & (1 << i)))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001172 continue;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001173 entries2 = nr_to_chain(i);
1174 for (j = 0; j < entries2->nentries; j++) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001175 *cnt = CNT_NORM;
1176 cnt++;
1177 }
1178 }
1179 for (i = 0; i < rule_nr; i++) {
1180 *cnt = CNT_NORM;
1181 cnt++;
1182 }
1183 *cnt = CNT_ADD;
1184 cnt++;
Bart De Schuymered053432002-07-21 19:35:39 +00001185 while (cnt != replace.counterchanges + replace.nentries) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001186 *cnt = CNT_NORM;
1187 cnt++;
1188 }
1189 *cnt = CNT_END;
1190
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001191 /*
1192 * go to the right position in the chain
1193 */
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001194 u_e = &entries->entries;
1195 for (i = 0; i < rule_nr; i++)
1196 u_e = &(*u_e)->next;
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001197 /*
1198 * insert the rule
1199 */
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001200 new_entry->next = *u_e;
1201 *u_e = new_entry;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001202
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001203 /*
1204 * put the ebt_[match, watcher, target] pointers in place
1205 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001206 m_l = new_entry->m_list;
1207 while (m_l) {
1208 m_l->m = ((struct ebt_u_match *)m_l->m)->m;
1209 m_l = m_l->next;
1210 }
1211 w_l = new_entry->w_list;
1212 while (w_l) {
1213 w_l->w = ((struct ebt_u_watcher *)w_l->w)->w;
1214 w_l = w_l->next;
1215 }
1216 new_entry->t = ((struct ebt_u_target *)new_entry->t)->t;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001217
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001218 /*
1219 * update the counter_offset of chains behind this one
1220 */
Bart De Schuymer60332e02002-06-23 08:01:47 +00001221 i = replace.selected_hook;
1222 while (1) {
1223 i++;
1224 entries = nr_to_chain(i);
1225 if (!entries) {
1226 if (i < NF_BR_NUMHOOKS)
1227 continue;
1228 else
1229 break;
1230 } else
1231 entries->counter_offset++;
1232 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001233}
1234
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001235/*
1236 * execute command D
1237 */
Bart De Schuymercc440052002-11-06 21:10:33 +00001238static void delete_rule(int begin, int end)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001239{
Bart De Schuymercc440052002-11-06 21:10:33 +00001240 int j, lentmp = 0, nr_deletes;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001241 unsigned short *cnt;
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001242 struct ebt_u_entry **u_e, *u_e2;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001243 struct ebt_u_entries *entries = to_chain(), *entries2;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001244
Bart De Schuymercc440052002-11-06 21:10:33 +00001245 if ((begin = check_rule_exists(begin)) == -1 ||
1246 (end = check_rule_exists(end)) == -1)
Bart De Schuymer60332e02002-06-23 08:01:47 +00001247 print_error("Sorry, rule does not exist");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001248
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001249 /*
1250 * we're deleting rules
1251 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001252 replace.num_counters = replace.nentries;
Bart De Schuymercc440052002-11-06 21:10:33 +00001253 nr_deletes = end - begin + 1;
1254 replace.nentries -= nr_deletes;
1255 entries->nentries -= nr_deletes;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001256
1257 if (replace.nentries) {
1258 for (j = 0; j < replace.selected_hook; j++) {
Bart De Schuymer60332e02002-06-23 08:01:47 +00001259 if (j < NF_BR_NUMHOOKS &&
1260 !(replace.valid_hooks & (1 << j)))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001261 continue;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001262 entries2 = nr_to_chain(j);
1263 lentmp += entries2->nentries;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001264 }
Bart De Schuymercc440052002-11-06 21:10:33 +00001265 lentmp += begin;
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001266 /*
1267 * +1 for CNT_END
1268 */
Bart De Schuymered053432002-07-21 19:35:39 +00001269 if ( !(replace.counterchanges = (unsigned short *)malloc(
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001270 (replace.num_counters + 1) * sizeof(unsigned short))) )
1271 print_memory();
Bart De Schuymered053432002-07-21 19:35:39 +00001272 cnt = replace.counterchanges;
Bart De Schuymercc440052002-11-06 21:10:33 +00001273 for (j = 0; j < lentmp; j++, cnt++)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001274 *cnt = CNT_NORM;
Bart De Schuymercc440052002-11-06 21:10:33 +00001275 for (j = 0; j < nr_deletes; j++, cnt++)
1276 *cnt = CNT_DEL;
1277
1278 for (j = 0; j < replace.num_counters - lentmp - nr_deletes;
1279 j++, cnt++)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001280 *cnt = CNT_NORM;
Bart De Schuymercc440052002-11-06 21:10:33 +00001281
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001282 *cnt = CNT_END;
1283 }
1284 else
1285 replace.num_counters = 0;
1286
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001287 /*
1288 * go to the right position in the chain
1289 */
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001290 u_e = &entries->entries;
Bart De Schuymercc440052002-11-06 21:10:33 +00001291 for (j = 0; j < begin; j++)
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001292 u_e = &(*u_e)->next;
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001293 /*
1294 * remove the rules
1295 */
Bart De Schuymercc440052002-11-06 21:10:33 +00001296 j = nr_deletes;
1297 while(j--) {
1298 u_e2 = *u_e;
1299 *u_e = (*u_e)->next;
1300 // free everything
1301 free_u_entry(u_e2);
1302 free(u_e2);
1303 }
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001304
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001305 /*
1306 * update the counter_offset of chains behind this one
1307 */
Bart De Schuymercc440052002-11-06 21:10:33 +00001308 j = replace.selected_hook;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001309 while (1) {
Bart De Schuymercc440052002-11-06 21:10:33 +00001310 j++;
1311 entries = nr_to_chain(j);
Bart De Schuymer60332e02002-06-23 08:01:47 +00001312 if (!entries) {
Bart De Schuymercc440052002-11-06 21:10:33 +00001313 if (j < NF_BR_NUMHOOKS)
Bart De Schuymer60332e02002-06-23 08:01:47 +00001314 continue;
1315 else
1316 break;
Bart De Schuymercc440052002-11-06 21:10:33 +00001317 } else
1318 entries->counter_offset -= nr_deletes;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001319 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001320}
1321
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001322/*
1323 * execute command Z
1324 */
Bart De Schuymer62423742002-07-14 19:06:20 +00001325static void zero_counters(int zerochain)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001326{
1327
1328 if (zerochain == -1) {
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001329 /*
1330 * tell main() we don't update the counters
1331 * this results in tricking the kernel to zero its counters,
1332 * naively expecting userspace to update its counters. Muahahaha
1333 */
Bart De Schuymered053432002-07-21 19:35:39 +00001334 replace.counterchanges = NULL;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001335 replace.num_counters = 0;
1336 } else {
1337 int i, j;
1338 unsigned short *cnt;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001339 struct ebt_u_entries *entries = nr_to_chain(zerochain), *e2;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001340
Bart De Schuymer60332e02002-06-23 08:01:47 +00001341 if (entries->nentries == 0)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001342 exit(0);
Bart De Schuymered053432002-07-21 19:35:39 +00001343 replace.counterchanges = (unsigned short *)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001344 malloc((replace.nentries + 1) * sizeof(unsigned short));
Bart De Schuymered053432002-07-21 19:35:39 +00001345 if (!replace.counterchanges)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001346 print_memory();
Bart De Schuymered053432002-07-21 19:35:39 +00001347 cnt = replace.counterchanges;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001348 for (i = 0; i < zerochain; i++) {
Bart De Schuymer60332e02002-06-23 08:01:47 +00001349 if (i < NF_BR_NUMHOOKS &&
1350 !(replace.valid_hooks & (1 << i)))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001351 continue;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001352 e2 = nr_to_chain(i);
1353 for (j = 0; j < e2->nentries; j++) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001354 *cnt = CNT_NORM;
1355 cnt++;
1356 }
1357 }
Bart De Schuymer60332e02002-06-23 08:01:47 +00001358 for (i = 0; i < entries->nentries; i++) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001359 *cnt = CNT_ZERO;
1360 cnt++;
1361 }
Bart De Schuymered053432002-07-21 19:35:39 +00001362 while (cnt != replace.counterchanges + replace.nentries) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001363 *cnt = CNT_NORM;
1364 cnt++;
1365 }
1366 *cnt = CNT_END;
1367 }
1368}
1369
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001370/*
1371 * Checks the type for validity and calls getethertypebynumber()
1372 */
1373struct ethertypeent *parseethertypebynumber(int type)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001374{
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001375 if (type < 1536)
1376 print_error("Ethernet protocols have values >= 0x0600");
1377 if (type > 0xffff)
1378 print_error("Ethernet protocols have values <= 0xffff");
1379 return getethertypebynumber(type);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001380}
1381
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001382/*
1383 * put the mac address into 6 (ETH_ALEN) bytes
1384 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001385int getmac_and_mask(char *from, char *to, char *mask)
1386{
1387 char *p;
1388 int i;
Bart De Schuymer41830412002-06-05 19:41:28 +00001389 struct ether_addr *addr;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001390
1391 if (strcasecmp(from, "Unicast") == 0) {
1392 memcpy(to, mac_type_unicast, ETH_ALEN);
1393 memcpy(mask, msk_type_unicast, ETH_ALEN);
1394 return 0;
1395 }
1396 if (strcasecmp(from, "Multicast") == 0) {
1397 memcpy(to, mac_type_multicast, ETH_ALEN);
1398 memcpy(mask, msk_type_multicast, ETH_ALEN);
1399 return 0;
1400 }
1401 if (strcasecmp(from, "Broadcast") == 0) {
1402 memcpy(to, mac_type_broadcast, ETH_ALEN);
1403 memcpy(mask, msk_type_broadcast, ETH_ALEN);
1404 return 0;
1405 }
1406 if ( (p = strrchr(from, '/')) != NULL) {
1407 *p = '\0';
Bart De Schuymer41830412002-06-05 19:41:28 +00001408 if (!(addr = ether_aton(p + 1)))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001409 return -1;
Bart De Schuymer41830412002-06-05 19:41:28 +00001410 memcpy(mask, addr, ETH_ALEN);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001411 } else
1412 memset(mask, 0xff, ETH_ALEN);
Bart De Schuymer41830412002-06-05 19:41:28 +00001413 if (!(addr = ether_aton(from)))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001414 return -1;
Bart De Schuymer41830412002-06-05 19:41:28 +00001415 memcpy(to, addr, ETH_ALEN);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001416 for (i = 0; i < ETH_ALEN; i++)
1417 to[i] &= mask[i];
1418 return 0;
1419}
1420
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001421/*
1422 * executes the final_check() function for all extensions used by the rule
1423 */
Bart De Schuymer62423742002-07-14 19:06:20 +00001424static void do_final_checks(struct ebt_u_entry *e, struct ebt_u_entries *entries)
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +00001425{
1426 struct ebt_u_match_list *m_l;
1427 struct ebt_u_watcher_list *w_l;
1428 struct ebt_u_target *t;
1429 struct ebt_u_match *m;
1430 struct ebt_u_watcher *w;
1431
1432 m_l = e->m_list;
1433 w_l = e->w_list;
1434 while (m_l) {
1435 m = find_match(m_l->m->u.name);
1436 m->final_check(e, m_l->m, replace.name,
1437 entries->hook_mask, 1);
1438 m_l = m_l->next;
1439 }
1440 while (w_l) {
1441 w = find_watcher(w_l->w->u.name);
1442 w->final_check(e, w_l->w, replace.name,
1443 entries->hook_mask, 1);
1444 w_l = w_l->next;
1445 }
1446 t = find_target(e->t->u.name);
1447 t->final_check(e, e->t, replace.name,
1448 entries->hook_mask, 1);
1449}
1450
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001451/*
1452 * used for the -X command
1453 */
Bart De Schuymer62423742002-07-14 19:06:20 +00001454static void check_for_references(int chain_nr)
Bart De Schuymerb909f9b2002-06-26 18:35:31 +00001455{
1456 int i = -1, j;
1457 struct ebt_u_entries *entries;
1458 struct ebt_u_entry *e;
1459
1460 while (1) {
1461 i++;
1462 entries = nr_to_chain(i);
1463 if (!entries) {
1464 if (i < NF_BR_NUMHOOKS)
1465 continue;
1466 else
1467 break;
1468 }
1469 e = entries->entries;
1470 j = 0;
1471 while (e) {
1472 j++;
1473 if (strcmp(e->t->u.name, EBT_STANDARD_TARGET)) {
1474 e = e->next;
1475 continue;
1476 }
1477 if (((struct ebt_standard_target *)e->t)->verdict == chain_nr)
1478 print_error("Can't delete the chain, it's referenced "
1479 "in chain %s, rule %d", entries->name, j);
1480 e = e->next;
1481 }
1482 }
1483}
1484
Bart De Schuymercc440052002-11-06 21:10:33 +00001485static int parse_delete_rule(const char *argv, int *rule_nr, int *rule_nr_end)
1486{
1487 char *colon = strchr(argv, ':'), *buffer;
1488
1489 if (colon) {
1490 *colon = '\0';
1491 if (*(colon + 1) == '\0')
1492 *rule_nr_end = -1;
1493 else {
1494 *rule_nr_end = strtol(colon + 1, &buffer, 10);
1495 if (*buffer != '\0' || *rule_nr_end < 0)
1496 return -1;
1497 }
1498 }
1499 if (colon == argv)
1500 *rule_nr = 1;
1501 else {
1502 *rule_nr = strtol(argv, &buffer, 10);
1503 if (*buffer != '\0' || *rule_nr < 0)
1504 return -1;
1505 }
1506 if (!colon)
1507 *rule_nr_end = *rule_nr;
1508 if (*rule_nr_end != -1 && *rule_nr > *rule_nr_end)
1509 return -1;
1510 return 0;
1511}
1512
Bart De Schuymera615b962002-11-03 14:54:09 +00001513static int invert = 0;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001514int check_inverse(const char option[])
1515{
1516 if (strcmp(option, "!") == 0) {
Bart De Schuymera615b962002-11-03 14:54:09 +00001517 if (invert == 1)
1518 print_error("double use of '!' not allowed");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001519 optind++;
Bart De Schuymera615b962002-11-03 14:54:09 +00001520 invert = 1;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001521 return 1;
1522 }
Bart De Schuymera615b962002-11-03 14:54:09 +00001523 return invert;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001524}
1525
1526void check_option(unsigned int *flags, unsigned int mask)
1527{
1528 if (*flags & mask)
1529 print_error("Multiple use of same option not allowed");
1530 *flags |= mask;
1531}
1532
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001533static void get_kernel_table(const char *modprobe)
1534{
1535 if ( !(table = find_table(replace.name)) )
1536 print_error("Bad table name");
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001537 /*
1538 * get the kernel's information
1539 */
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001540 if (get_table(&replace)) {
1541 ebtables_insmod("ebtables", modprobe);
1542 if (get_table(&replace))
1543 print_error("The kernel doesn't support the ebtables "
1544 "%s table", replace.name);
1545 }
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001546 /*
1547 * when listing a table contained in a file, we don't expect the user
1548 * to know what the table's name is
1549 */
Bart De Schuymer62a7fdb2002-08-24 21:01:21 +00001550 if ( !(table = find_table(replace.name)) )
1551 print_error("Bad table name");
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001552}
1553
Bart De Schuymerc5075142002-08-18 14:21:19 +00001554#define print_if_l_error print_error("Interface name length must be less " \
1555 "than %d", IFNAMSIZ)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001556#define OPT_COMMAND 0x01
1557#define OPT_TABLE 0x02
1558#define OPT_IN 0x04
1559#define OPT_OUT 0x08
1560#define OPT_JUMP 0x10
1561#define OPT_PROTOCOL 0x20
1562#define OPT_SOURCE 0x40
1563#define OPT_DEST 0x80
1564#define OPT_ZERO 0x100
1565#define OPT_LOGICALIN 0x200
1566#define OPT_LOGICALOUT 0x400
1567// the main thing
1568int main(int argc, char *argv[])
1569{
Bart De Schuymer923a5732002-08-11 12:01:33 +00001570 char *buffer;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001571 int c, i;
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001572 /*
1573 * this special one for the -Z option (we can have -Z <this> -L <that>)
1574 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001575 int zerochain = -1;
Bart De Schuymerf8f8f292002-06-25 15:43:57 +00001576 int policy = 0;
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001577 int rule_nr = -1; /* used for -[D,I] */
1578 int rule_nr_end = -1; /* used for -I */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001579 struct ebt_u_target *t;
1580 struct ebt_u_match *m;
1581 struct ebt_u_watcher *w;
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001582 struct ebt_u_match_list *m_l;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001583 struct ebt_u_watcher_list *w_l;
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001584 struct ebt_u_entries *entries;
Bart De Schuymerc8531032002-06-14 21:55:29 +00001585 const char *modprobe = NULL;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001586
Bart De Schuymera615b962002-11-03 14:54:09 +00001587 opterr = 0;
1588
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001589 /*
1590 * initialize the table name, OPT_ flags, selected hook and command
1591 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001592 strcpy(replace.name, "filter");
1593 replace.flags = 0;
1594 replace.selected_hook = -1;
1595 replace.command = 'h';
Bart De Schuymer62423742002-07-14 19:06:20 +00001596 replace.filename = NULL;
Bart De Schuymered053432002-07-21 19:35:39 +00001597 replace.counterchanges = NULL;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001598
1599 new_entry = (struct ebt_u_entry *)malloc(sizeof(struct ebt_u_entry));
1600 if (!new_entry)
1601 print_memory();
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001602 /*
1603 * put some sane values in our new entry
1604 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001605 initialize_entry(new_entry);
1606
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001607 /*
1608 * The scenario induced by this loop makes that:
1609 * '-t' ,'-M' and --atomic (if specified) have to come
1610 * before '-A' and the like
1611 */
Bart De Schuymer60332e02002-06-23 08:01:47 +00001612
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001613 /*
1614 * getopt saves the day
1615 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001616 while ((c = getopt_long(argc, argv,
Bart De Schuymeraac31142002-08-11 11:57:52 +00001617 "-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 +00001618 switch (c) {
1619
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001620 case 'A': /* add a rule */
1621 case 'D': /* delete a rule */
1622 case 'P': /* define policy */
1623 case 'I': /* insert a rule */
1624 case 'N': /* make a user defined chain */
1625 case 'E': /* rename chain */
1626 case 'X': /* delete chain */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001627 replace.command = c;
1628 if (replace.flags & OPT_COMMAND)
1629 print_error("Multiple commands not allowed");
1630 replace.flags |= OPT_COMMAND;
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001631 get_kernel_table(modprobe);
1632 if (optarg[0] == '-' || !strcmp(optarg, "!"))
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001633 print_error("No chain name specified");
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001634 if (c == 'N') {
1635 struct ebt_u_chain_list *cl, **cl2;
1636
1637 if (get_hooknr(optarg) != -1)
1638 print_error("Chain %s already exists",
1639 optarg);
1640 if (find_target(optarg))
1641 print_error("Target with name %s exists"
1642 , optarg);
1643 if (strlen(optarg) >= EBT_CHAIN_MAXNAMELEN)
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001644 print_error("Chain name length can't exceed %d",
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001645 EBT_CHAIN_MAXNAMELEN - 1);
1646 cl = (struct ebt_u_chain_list *)
1647 malloc(sizeof(struct ebt_u_chain_list));
1648 if (!cl)
1649 print_memory();
1650 cl->next = NULL;
1651 cl->udc = (struct ebt_u_entries *)
1652 malloc(sizeof(struct ebt_u_entries));
1653 if (!cl->udc)
1654 print_memory();
1655 cl->udc->nentries = 0;
1656 cl->udc->policy = EBT_ACCEPT;
1657 cl->udc->counter_offset = replace.nentries;
1658 cl->udc->hook_mask = 0;
1659 strcpy(cl->udc->name, optarg);
1660 cl->udc->entries = NULL;
1661 cl->kernel_start = NULL;
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001662 /*
1663 * put the new chain at the end
1664 */
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001665 cl2 = &replace.udc;
1666 while (*cl2)
1667 cl2 = &((*cl2)->next);
1668 *cl2 = cl;
1669 break;
1670 }
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001671 if ((replace.selected_hook = get_hooknr(optarg)) == -1)
1672 print_error("Chain %s doesn't exist", optarg);
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001673 if (c == 'E') {
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001674 if (optind >= argc || argv[optind][0] == '-' ||
1675 !strcmp(argv[optind], "!"))
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001676 print_error("No new chain name specified");
1677 if (strlen(argv[optind]) >= EBT_CHAIN_MAXNAMELEN)
1678 print_error("Chain name len can't exceed %d",
1679 EBT_CHAIN_MAXNAMELEN - 1);
1680 if (get_hooknr(argv[optind]) != -1)
1681 print_error("Chain %s already exists",
1682 argv[optind]);
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001683 if (find_target(argv[optind]))
1684 print_error("Target with name %s exists"
1685 , argv[optind]);
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001686 entries = to_chain();
1687 strcpy(entries->name, argv[optind]);
1688 optind++;
1689 break;
1690 }
1691 if (c == 'X') {
1692 struct ebt_u_chain_list *cl, **cl2;
1693
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001694 if (replace.selected_hook < NF_BR_NUMHOOKS)
1695 print_error("You can't remove a standard chain");
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001696 /*
1697 * if the chain is referenced, don't delete it
1698 */
Bart De Schuymerb909f9b2002-06-26 18:35:31 +00001699 check_for_references(replace.selected_hook - NF_BR_NUMHOOKS);
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001700 flush_chains();
1701 entries = to_chain();
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001702 cl2 = &(replace.udc);
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001703 while ((*cl2)->udc != entries)
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001704 cl2 = &((*cl2)->next);
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001705 cl = (*cl2);
1706 (*cl2) = (*cl2)->next;
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001707 free(cl->udc);
1708 free(cl);
1709 break;
1710 }
1711
Bart De Schuymercc440052002-11-06 21:10:33 +00001712 if (c == 'D' && optind < argc &&
1713 argv[optind][0] != '-') {
1714 if (parse_delete_rule(argv[optind],
1715 &rule_nr, &rule_nr_end))
1716 print_error("Problem with the "
1717 "specified rule number(s)");
1718 optind++;
1719 }
1720 if (c == 'I') {
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001721 if (optind >= argc || argv[optind][0] == '-')
1722 print_error("No rulenr for -I"
1723 " specified");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001724 rule_nr = strtol(argv[optind], &buffer, 10);
1725 if (*buffer != '\0' || rule_nr < 0)
1726 print_error("Problem with the "
1727 "specified rule number");
1728 optind++;
1729 }
1730 if (c == 'P') {
1731 if (optind >= argc)
1732 print_error("No policy specified");
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001733 policy = 0;
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001734 for (i = 0; i < NUM_STANDARD_TARGETS; i++)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001735 if (!strcmp(argv[optind],
1736 standard_targets[i])) {
Bart De Schuymer60332e02002-06-23 08:01:47 +00001737 policy = -i -1;
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001738 if (policy == EBT_CONTINUE)
1739 policy = 0;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001740 break;
1741 }
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001742 if (policy == 0)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001743 print_error("Wrong policy");
1744 optind++;
1745 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001746 break;
1747
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001748 case 'L': /* list */
1749 case 'F': /* flush */
1750 case 'Z': /* zero counters */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001751 if (c == 'Z') {
1752 if (replace.flags & OPT_ZERO)
1753 print_error("Multiple commands"
1754 " not allowed");
1755 if ( (replace.flags & OPT_COMMAND &&
1756 replace.command != 'L'))
1757 print_error("command -Z only allowed "
1758 "together with command -L");
1759 replace.flags |= OPT_ZERO;
1760 } else {
1761 replace.command = c;
1762 if (replace.flags & OPT_COMMAND)
1763 print_error("Multiple commands"
1764 " not allowed");
1765 replace.flags |= OPT_COMMAND;
1766 }
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001767 get_kernel_table(modprobe);
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001768 i = -1;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001769 if (optarg) {
1770 if ( (i = get_hooknr(optarg)) == -1 )
1771 print_error("Bad chain");
1772 } else
1773 if (optind < argc && argv[optind][0] != '-') {
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001774 if ((i = get_hooknr(argv[optind])) == -1)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001775 print_error("Bad chain");
1776 optind++;
1777 }
1778 if (i != -1) {
1779 if (c == 'Z')
1780 zerochain = i;
1781 else
1782 replace.selected_hook = i;
1783 }
1784 break;
1785
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001786 case 'V': /* version */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001787 replace.command = 'V';
1788 if (replace.flags & OPT_COMMAND)
1789 print_error("Multiple commands not allowed");
Bart De Schuymerd4586482002-08-11 16:15:55 +00001790 printf(PROGNAME" v"PROGVERSION" ("PROGDATE")\n");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001791 exit(0);
1792
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001793 case 'M': /* modprobe */
Bart De Schuymer60332e02002-06-23 08:01:47 +00001794 if (replace.command != 'h')
1795 print_error("Please put the -M option earlier");
Bart De Schuymerc8531032002-06-14 21:55:29 +00001796 modprobe = optarg;
1797 break;
1798
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001799 case 'h': /* help */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001800 if (replace.flags & OPT_COMMAND)
1801 print_error("Multiple commands not allowed");
1802 replace.command = 'h';
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001803 /*
1804 * All other arguments should be extension names
1805 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001806 while (optind < argc) {
1807 struct ebt_u_match *m;
1808 struct ebt_u_watcher *w;
1809
1810 if ((m = find_match(argv[optind])))
1811 add_match(m);
1812 else if ((w = find_watcher(argv[optind])))
1813 add_watcher(w);
1814 else {
1815 if (!(t = find_target(argv[optind])))
1816 print_error("Extension %s "
1817 "not found", argv[optind]);
1818 if (replace.flags & OPT_JUMP)
1819 print_error("Sorry, you can "
1820 "only see help for one "
1821 "target extension each time");
1822 replace.flags |= OPT_JUMP;
1823 new_entry->t =
1824 (struct ebt_entry_target *)t;
1825 }
1826 optind++;
1827 }
1828 break;
1829
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001830 case 't': /* table */
Bart De Schuymer60332e02002-06-23 08:01:47 +00001831 if (replace.command != 'h')
1832 print_error("Please put the -t option first");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001833 check_option(&replace.flags, OPT_TABLE);
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001834 if (strlen(optarg) > EBT_TABLE_MAXNAMELEN - 1)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001835 print_error("Table name too long");
1836 strcpy(replace.name, optarg);
1837 break;
1838
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001839 case 'i': /* input interface */
1840 case 2 : /* logical input interface */
1841 case 'o': /* output interface */
1842 case 3 : /* logical output interface */
1843 case 'j': /* target */
1844 case 'p': /* net family protocol */
1845 case 's': /* source mac */
1846 case 'd': /* destination mac */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001847 if ((replace.flags & OPT_COMMAND) == 0)
1848 print_error("No command specified");
1849 if ( replace.command != 'A' &&
1850 replace.command != 'D' && replace.command != 'I')
1851 print_error("Command and option do not match");
1852 if (c == 'i') {
1853 check_option(&replace.flags, OPT_IN);
1854 if (replace.selected_hook > 2 &&
1855 replace.selected_hook < NF_BR_BROUTING)
1856 print_error("Use in-interface only in "
1857 "INPUT, FORWARD, PREROUTING and"
1858 "BROUTING chains");
1859 if (check_inverse(optarg))
1860 new_entry->invflags |= EBT_IIN;
1861
1862 if (optind > argc)
1863 print_error("No in-interface "
1864 "specified");
1865 if (strlen(argv[optind - 1]) >= IFNAMSIZ)
Bart De Schuymerc5075142002-08-18 14:21:19 +00001866 print_if_l_error;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001867 strcpy(new_entry->in, argv[optind - 1]);
1868 break;
1869 }
1870 if (c == 2) {
1871 check_option(&replace.flags, OPT_LOGICALIN);
1872 if (replace.selected_hook > 2 &&
1873 replace.selected_hook < NF_BR_BROUTING)
1874 print_error("Use logical in-interface "
1875 "only in INPUT, FORWARD, "
1876 "PREROUTING and BROUTING chains");
1877 if (check_inverse(optarg))
1878 new_entry->invflags |= EBT_ILOGICALIN;
1879
1880 if (optind > argc)
1881 print_error("No logical in-interface "
1882 "specified");
1883 if (strlen(argv[optind - 1]) >= IFNAMSIZ)
Bart De Schuymerc5075142002-08-18 14:21:19 +00001884 print_if_l_error;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001885 strcpy(new_entry->logical_in, argv[optind - 1]);
1886 break;
1887 }
1888 if (c == 'o') {
1889 check_option(&replace.flags, OPT_OUT);
1890 if (replace.selected_hook < 2)
1891 print_error("Use out-interface only"
1892 " in OUTPUT, FORWARD and "
1893 "POSTROUTING chains");
1894 if (check_inverse(optarg))
1895 new_entry->invflags |= EBT_IOUT;
1896
1897 if (optind > argc)
1898 print_error("No out-interface "
1899 "specified");
1900
1901 if (strlen(argv[optind - 1]) >= IFNAMSIZ)
Bart De Schuymerc5075142002-08-18 14:21:19 +00001902 print_if_l_error;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001903 strcpy(new_entry->out, argv[optind - 1]);
1904 break;
1905 }
1906 if (c == 3) {
1907 check_option(&replace.flags, OPT_LOGICALOUT);
1908 if (replace.selected_hook < 2)
1909 print_error("Use logical out-interface "
1910 "only in OUTPUT, FORWARD and "
1911 "POSTROUTING chains");
1912 if (check_inverse(optarg))
1913 new_entry->invflags |= EBT_ILOGICALOUT;
1914
1915 if (optind > argc)
1916 print_error("No logical out-interface "
1917 "specified");
1918
1919 if (strlen(argv[optind - 1]) >= IFNAMSIZ)
Bart De Schuymerc5075142002-08-18 14:21:19 +00001920 print_if_l_error;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001921 strcpy(new_entry->logical_out,
1922 argv[optind - 1]);
1923 break;
1924 }
1925 if (c == 'j') {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001926 check_option(&replace.flags, OPT_JUMP);
1927 for (i = 0; i < NUM_STANDARD_TARGETS; i++)
1928 if (!strcmp(optarg,
1929 standard_targets[i])) {
1930 t = find_target(
1931 EBT_STANDARD_TARGET);
1932 ((struct ebt_standard_target *)
Bart De Schuymer60332e02002-06-23 08:01:47 +00001933 t->t)->verdict = -i - 1;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001934 break;
1935 }
Bart De Schuymer60332e02002-06-23 08:01:47 +00001936 if (-i - 1 == EBT_RETURN) {
1937 if (replace.selected_hook < NF_BR_NUMHOOKS)
1938 print_error("Return target"
1939 " only for user defined chains");
1940 }
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +00001941 if (i != NUM_STANDARD_TARGETS)
1942 break;
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001943 if ((i = get_hooknr(optarg)) != -1) {
1944 if (i < NF_BR_NUMHOOKS)
1945 print_error("don't jump"
1946 " to a standard chain");
1947 t = find_target(
1948 EBT_STANDARD_TARGET);
1949 ((struct ebt_standard_target *)
1950 t->t)->verdict = i - NF_BR_NUMHOOKS;
1951 break;
1952 }
1953 else {
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001954 /*
1955 * must be an extension then
1956 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001957 struct ebt_u_target *t;
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001958
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001959 t = find_target(optarg);
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001960 /*
1961 * -j standard not allowed either
1962 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001963 if (!t || t ==
1964 (struct ebt_u_target *)new_entry->t)
1965 print_error("Illegal target "
1966 "name");
1967 new_entry->t =
1968 (struct ebt_entry_target *)t;
1969 }
1970 break;
1971 }
1972 if (c == 's') {
1973 check_option(&replace.flags, OPT_SOURCE);
1974 if (check_inverse(optarg))
1975 new_entry->invflags |= EBT_ISOURCE;
1976
1977 if (optind > argc)
1978 print_error("No source mac "
1979 "specified");
1980 if (getmac_and_mask(argv[optind - 1],
1981 new_entry->sourcemac, new_entry->sourcemsk))
1982 print_error("Problem with specified "
1983 "source mac");
1984 new_entry->bitmask |= EBT_SOURCEMAC;
1985 break;
1986 }
1987 if (c == 'd') {
1988 check_option(&replace.flags, OPT_DEST);
1989 if (check_inverse(optarg))
1990 new_entry->invflags |= EBT_IDEST;
1991
1992 if (optind > argc)
1993 print_error("No destination mac "
1994 "specified");
1995 if (getmac_and_mask(argv[optind - 1],
1996 new_entry->destmac, new_entry->destmsk))
1997 print_error("Problem with specified "
1998 "destination mac");
1999 new_entry->bitmask |= EBT_DESTMAC;
2000 break;
2001 }
2002 check_option(&replace.flags, OPT_PROTOCOL);
2003 if (check_inverse(optarg))
2004 new_entry->invflags |= EBT_IPROTO;
2005
2006 if (optind > argc)
2007 print_error("No protocol specified");
2008 new_entry->bitmask &= ~((unsigned int)EBT_NOPROTO);
2009 i = strtol(argv[optind - 1], &buffer, 16);
2010 if (*buffer == '\0' && (i < 0 || i > 0xFFFF))
2011 print_error("Problem with the specified "
2012 "protocol");
2013 new_entry->ethproto = i;
Bart De Schuymer28bf6f62002-06-26 18:57:24 +00002014 if (*buffer != '\0') {
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002015 struct ethertypeent *ent;
2016
2017 if (!strcasecmp(argv[optind - 1], "LENGTH")) {
2018 new_entry->bitmask |= EBT_802_3;
2019 break;
2020 }
2021 ent = getethertypebyname(argv[optind - 1]);
2022 if (!ent)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002023 print_error("Problem with the specified"
2024 " protocol");
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002025 new_entry->ethproto = ent->e_ethertype;
Bart De Schuymer28bf6f62002-06-26 18:57:24 +00002026 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002027 if (new_entry->ethproto < 1536 &&
2028 !(new_entry->bitmask & EBT_802_3))
2029 print_error("Sorry, protocols have values above"
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00002030 " or equal to 0x0600");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002031 break;
2032
Bart De Schuymer9af14f92002-07-10 20:49:10 +00002033 case 4 : // Lc
2034 check_option(&replace.flags, LIST_C);
Bart De Schuymer9af14f92002-07-10 20:49:10 +00002035 if (replace.command != 'L')
2036 print_error("Use --Lc with -L");
2037 if (replace.flags & LIST_X)
2038 print_error("--Lx not compatible with --Lc");
2039 replace.flags |= LIST_C;
2040 break;
2041 case 5 : // Ln
2042 check_option(&replace.flags, LIST_N);
Bart De Schuymer9af14f92002-07-10 20:49:10 +00002043 if (replace.command != 'L')
2044 print_error("Use --Ln with -L");
2045 if (replace.flags & LIST_X)
2046 print_error("--Lx not compatible with --Ln");
2047 replace.flags |= LIST_N;
2048 break;
2049 case 6 : // Lx
2050 check_option(&replace.flags, LIST_X);
Bart De Schuymer9af14f92002-07-10 20:49:10 +00002051 if (replace.command != 'L')
2052 print_error("Use --Lx with -L");
2053 if (replace.flags & LIST_C)
2054 print_error("--Lx not compatible with --Lc");
2055 if (replace.flags & LIST_N)
2056 print_error("--Lx not compatible with --Ln");
2057 replace.flags |= LIST_X;
2058 break;
Bart De Schuymer62423742002-07-14 19:06:20 +00002059 case 8 : // atomic-commit
2060 replace.command = c;
2061 if (replace.flags & OPT_COMMAND)
2062 print_error("Multiple commands not allowed");
2063 replace.flags |= OPT_COMMAND;
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00002064 if (replace.filename)
2065 print_error("--atomic incompatible with "
2066 "command");
Bart De Schuymer62423742002-07-14 19:06:20 +00002067 replace.filename = (char *)malloc(strlen(optarg) + 1);
2068 strcpy(replace.filename, optarg);
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002069 /*
2070 * get the information from the file
2071 */
Bart De Schuymer62423742002-07-14 19:06:20 +00002072 get_table(&replace);
Bart De Schuymer868bf642002-07-16 18:14:20 +00002073 if (replace.nentries) {
Bart De Schuymered053432002-07-21 19:35:39 +00002074 replace.counterchanges = (unsigned short *)
Bart De Schuymer868bf642002-07-16 18:14:20 +00002075 malloc(sizeof(unsigned short) * (replace.nentries + 1));
2076 for (i = 0; i < replace.nentries; i++)
Bart De Schuymered053432002-07-21 19:35:39 +00002077 replace.counterchanges[i] = CNT_NORM;
2078 replace.counterchanges[i] = CNT_END;
Bart De Schuymer868bf642002-07-16 18:14:20 +00002079 }
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002080 /*
2081 * we don't want the kernel giving us its counters, they would
2082 * overwrite the counters extracted from the file
2083 */
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00002084 replace.num_counters = 0;
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002085 /*
2086 * make sure the table will be written to the kernel
2087 */
Bart De Schuymer62423742002-07-14 19:06:20 +00002088 free(replace.filename);
2089 replace.filename = NULL;
Bart De Schuymerc5c3c2d2002-08-16 19:48:03 +00002090 ebtables_insmod("ebtables", modprobe);
Bart De Schuymer62423742002-07-14 19:06:20 +00002091 break;
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002092 case 7 : /* atomic-init */
2093 case 10: /* atomic-save */
2094 case 11: /* init-table */
Bart De Schuymer62423742002-07-14 19:06:20 +00002095 replace.command = c;
2096 if (replace.flags & OPT_COMMAND)
2097 print_error("Multiple commands not allowed");
2098 replace.flags |= OPT_COMMAND;
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00002099 if (replace.filename)
2100 print_error("--atomic incompatible with "
2101 "command");
2102 get_kernel_table(modprobe);
Bart De Schuymera8d920b2002-07-16 18:30:44 +00002103 if (replace.nentries) {
Bart De Schuymered053432002-07-21 19:35:39 +00002104 replace.counterchanges = (unsigned short *)
Bart De Schuymer5f16dc72002-07-16 18:08:36 +00002105 malloc(sizeof(unsigned short) * (replace.nentries + 1));
2106 for (i = 0; i < replace.nentries; i++)
Bart De Schuymered053432002-07-21 19:35:39 +00002107 replace.counterchanges[i] = CNT_NORM;
2108 replace.counterchanges[i] = CNT_END;
Bart De Schuymer5f16dc72002-07-16 18:08:36 +00002109 }
Bart De Schuymer8d1d8942002-07-15 20:09:09 +00002110 if (c == 11)
2111 break;
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002112 case 9 : /* atomic */
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00002113 if (c == 9 && (replace.flags & OPT_COMMAND))
2114 print_error("--atomic has to come before"
2115 " the command");
Bart De Schuymer62423742002-07-14 19:06:20 +00002116 replace.filename = (char *)malloc(strlen(optarg) + 1);
2117 strcpy(replace.filename, optarg);
2118 break;
Bart De Schuymera615b962002-11-03 14:54:09 +00002119 case 1 :
2120 if (!strcmp(optarg, "!"))
2121 check_inverse(optarg);
2122 else
2123 print_error("Bad argument : %s", optarg);
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002124 /*
2125 * check_inverse() did optind++
2126 */
Bart De Schuymera615b962002-11-03 14:54:09 +00002127 optind--;
2128 continue;
Bart De Schuymer9af14f92002-07-10 20:49:10 +00002129 default:
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002130 /*
2131 * is it a target option?
2132 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002133 t = (struct ebt_u_target *)new_entry->t;
2134 if ((t->parse(c - t->option_offset, argv, argc,
2135 new_entry, &t->flags, &t->t)))
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00002136 goto check_extension;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002137
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002138 /*
2139 * is it a match_option?
2140 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002141 for (m = matches; m; m = m->next)
2142 if (m->parse(c - m->option_offset, argv,
2143 argc, new_entry, &m->flags, &m->m))
2144 break;
2145
2146 if (m != NULL) {
2147 if (m->used == 0)
2148 add_match(m);
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00002149 goto check_extension;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002150 }
2151
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002152 /*
2153 * is it a watcher option?
2154 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002155 for (w = watchers; w; w = w->next)
2156 if (w->parse(c-w->option_offset, argv,
2157 argc, new_entry, &w->flags, &w->w))
2158 break;
2159
2160 if (w == NULL)
2161 print_error("Unknown argument");
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00002162 if (w->used == 0)
2163 add_watcher(w);
2164check_extension:
Bart De Schuymer60332e02002-06-23 08:01:47 +00002165 if (replace.command != 'A' && replace.command != 'I' &&
2166 replace.command != 'D')
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00002167 print_error("Extensions only for -A, -I and -D");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002168 }
Bart De Schuymera615b962002-11-03 14:54:09 +00002169 invert = 0;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002170 }
2171
Bart De Schuymer25c741d2002-06-23 18:54:34 +00002172 if ( !table && !(table = find_table(replace.name)) )
2173 print_error("Bad table name");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002174
2175 if ( (replace.flags & OPT_COMMAND) && replace.command != 'L' &&
2176 replace.flags & OPT_ZERO )
2177 print_error("Command -Z only allowed together with command -L");
2178
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002179 /*
2180 * do this after parsing everything, so we can print specific info
2181 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002182 if (replace.command == 'h' && !(replace.flags & OPT_ZERO))
2183 print_help();
2184
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002185 /*
2186 * do the final checks
2187 */
Bart De Schuymer60332e02002-06-23 08:01:47 +00002188 if (replace.command == 'A' || replace.command == 'I' ||
2189 replace.command == 'D') {
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002190 /*
2191 * this will put the hook_mask right for the chains
2192 */
Bart De Schuymer60332e02002-06-23 08:01:47 +00002193 check_for_loops();
2194 entries = to_chain();
2195 m_l = new_entry->m_list;
2196 w_l = new_entry->w_list;
2197 t = (struct ebt_u_target *)new_entry->t;
2198 while (m_l) {
2199 m = (struct ebt_u_match *)(m_l->m);
2200 m->final_check(new_entry, m->m, replace.name,
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +00002201 entries->hook_mask, 0);
Bart De Schuymer60332e02002-06-23 08:01:47 +00002202 m_l = m_l->next;
2203 }
2204 while (w_l) {
2205 w = (struct ebt_u_watcher *)(w_l->w);
2206 w->final_check(new_entry, w->w, replace.name,
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +00002207 entries->hook_mask, 0);
Bart De Schuymer60332e02002-06-23 08:01:47 +00002208 w_l = w_l->next;
2209 }
2210 t->final_check(new_entry, t->t, replace.name,
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +00002211 entries->hook_mask, 0);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002212 }
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002213 /*
2214 * so, the extensions can work with the host endian
2215 * the kernel does not have to do this ofcourse
2216 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002217 new_entry->ethproto = htons(new_entry->ethproto);
2218
Bart De Schuymerc34f4672002-08-18 18:03:52 +00002219 if (replace.command == 'P') {
2220 if (replace.selected_hook < NF_BR_NUMHOOKS &&
2221 policy == EBT_RETURN)
2222 print_error("Policy RETURN only allowed for user "
2223 "defined chains");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002224 change_policy(policy);
Bart De Schuymerc34f4672002-08-18 18:03:52 +00002225 } else if (replace.command == 'L') {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002226 list_rules();
2227 if (replace.flags & OPT_ZERO)
2228 zero_counters(zerochain);
2229 else
2230 exit(0);
2231 }
2232 if (replace.flags & OPT_ZERO)
2233 zero_counters(zerochain);
Bart De Schuymer1ab41562002-06-23 17:09:54 +00002234 else if (replace.command == 'F') {
2235 if (flush_chains() == -1)
2236 exit(0);
2237 } else if (replace.command == 'A' || replace.command == 'I') {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002238 add_rule(rule_nr);
Bart De Schuymer1ab41562002-06-23 17:09:54 +00002239 check_for_loops();
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002240 /*
2241 * do the final_check(), for all entries
2242 * needed when adding a rule that has a chain target
2243 */
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +00002244 i = -1;
2245 while (1) {
2246 struct ebt_u_entry *e;
2247
2248 i++;
2249 entries = nr_to_chain(i);
2250 if (!entries) {
2251 if (i < NF_BR_NUMHOOKS)
2252 continue;
2253 else
2254 break;
2255 }
2256 e = entries->entries;
2257 while (e) {
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002258 /*
2259 * userspace extensions use host endian
2260 */
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +00002261 e->ethproto = ntohs(e->ethproto);
2262 do_final_checks(e, entries);
2263 e->ethproto = htons(e->ethproto);
2264 e = e->next;
2265 }
2266 }
Bart De Schuymercc440052002-11-06 21:10:33 +00002267 } else if (replace.command == 'D') {
2268 if (rule_nr != -1 && rule_nr_end == -1)
2269 rule_nr_end = entries->nentries;
2270 delete_rule(rule_nr, rule_nr_end);
2271 }
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002272 /*
2273 * commands -N, -E, -X, --atomic-commit, --atomic-commit, --atomic-save,
2274 * --init-table fall through
2275 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002276
2277 if (table->check)
2278 table->check(&replace);
2279
2280 deliver_table(&replace);
2281
Bart De Schuymered053432002-07-21 19:35:39 +00002282 if (replace.counterchanges)
2283 deliver_counters(&replace);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002284 return 0;
2285}