blob: b1027f5f27c86c6624491d3090d3143ba91ff48b [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 Schuymerc8531032002-06-14 21:55:29 +000055
Bart De Schuymer60332e02002-06-23 08:01:47 +000056char *hooknames[NF_BR_NUMHOOKS] =
57{
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000058 [NF_BR_PRE_ROUTING]"PREROUTING",
59 [NF_BR_LOCAL_IN]"INPUT",
60 [NF_BR_FORWARD]"FORWARD",
61 [NF_BR_LOCAL_OUT]"OUTPUT",
62 [NF_BR_POST_ROUTING]"POSTROUTING",
63 [NF_BR_BROUTING]"BROUTING"
64};
65
Bart De Schuymerc7bfa272002-11-20 19:40:13 +000066/*
67 * default command line options
68 * do not mess around with the already assigned numbers unless
69 * you know what you are doing
70 */
Bart De Schuymer62423742002-07-14 19:06:20 +000071static struct option ebt_original_options[] =
72{
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000073 { "append" , required_argument, 0, 'A' },
74 { "insert" , required_argument, 0, 'I' },
75 { "delete" , required_argument, 0, 'D' },
76 { "list" , optional_argument, 0, 'L' },
Bart De Schuymer9af14f92002-07-10 20:49:10 +000077 { "Lc" , no_argument , 0, 4 },
78 { "Ln" , no_argument , 0, 5 },
79 { "Lx" , no_argument , 0, 6 },
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000080 { "zero" , optional_argument, 0, 'Z' },
81 { "flush" , optional_argument, 0, 'F' },
82 { "policy" , required_argument, 0, 'P' },
83 { "in-interface" , required_argument, 0, 'i' },
84 { "in-if" , required_argument, 0, 'i' },
85 { "logical-in" , required_argument, 0, 2 },
86 { "logical-out" , required_argument, 0, 3 },
87 { "out-interface" , required_argument, 0, 'o' },
88 { "out-if" , required_argument, 0, 'o' },
89 { "version" , no_argument , 0, 'V' },
90 { "help" , no_argument , 0, 'h' },
91 { "jump" , required_argument, 0, 'j' },
92 { "proto" , required_argument, 0, 'p' },
93 { "protocol" , required_argument, 0, 'p' },
94 { "db" , required_argument, 0, 'b' },
95 { "source" , required_argument, 0, 's' },
96 { "src" , required_argument, 0, 's' },
97 { "destination" , required_argument, 0, 'd' },
98 { "dst" , required_argument, 0, 'd' },
99 { "table" , required_argument, 0, 't' },
Bart De Schuymerc8531032002-06-14 21:55:29 +0000100 { "modprobe" , required_argument, 0, 'M' },
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000101 { "new-chain" , required_argument, 0, 'N' },
102 { "rename-chain" , required_argument, 0, 'E' },
103 { "delete-chain" , required_argument, 0, 'X' },
Bart De Schuymer5885b362002-12-03 20:51:36 +0000104 { "atomic-init" , no_argument , 0, 7 },
105 { "atomic-commit" , no_argument , 0, 8 },
106 { "atomic-file" , required_argument, 0, 9 },
107 { "atomic-save" , no_argument , 0, 10 },
Bart De Schuymer8d1d8942002-07-15 20:09:09 +0000108 { "init-table" , no_argument , 0, 11 },
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000109 { 0 }
110};
111
112static struct option *ebt_options = ebt_original_options;
113
Bart De Schuymer62423742002-07-14 19:06:20 +0000114char* standard_targets[NUM_STANDARD_TARGETS] =
115{
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000116 "ACCEPT",
117 "DROP",
118 "CONTINUE",
Bart De Schuymer60332e02002-06-23 08:01:47 +0000119 "RETURN",
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000120};
121
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000122unsigned char mac_type_unicast[ETH_ALEN] = {0,0,0,0,0,0};
123unsigned char msk_type_unicast[ETH_ALEN] = {1,0,0,0,0,0};
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000124unsigned char mac_type_multicast[ETH_ALEN] = {1,0,0,0,0,0};
125unsigned char msk_type_multicast[ETH_ALEN] = {1,0,0,0,0,0};
126unsigned char mac_type_broadcast[ETH_ALEN] = {255,255,255,255,255,255};
127unsigned char msk_type_broadcast[ETH_ALEN] = {255,255,255,255,255,255};
128
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000129/*
130 * holds all the data
131 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000132static struct ebt_u_replace replace;
133
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000134/*
135 * the chosen table
136 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000137static struct ebt_u_table *table = NULL;
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000138/*
139 * the lists of supported tables, matches, watchers and targets
140 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000141static struct ebt_u_table *tables = NULL;
142static struct ebt_u_match *matches = NULL;
143static struct ebt_u_watcher *watchers = NULL;
144static struct ebt_u_target *targets = NULL;
145
146struct ebt_u_target *find_target(const char *name)
147{
148 struct ebt_u_target *t = targets;
149
150 while(t && strcmp(t->name, name))
151 t = t->next;
152 return t;
153}
154
155struct ebt_u_match *find_match(const char *name)
156{
157 struct ebt_u_match *m = matches;
158
159 while(m && strcmp(m->name, name))
160 m = m->next;
161 return m;
162}
163
164struct ebt_u_watcher *find_watcher(const char *name)
165{
166 struct ebt_u_watcher *w = watchers;
167
168 while(w && strcmp(w->name, name))
169 w = w->next;
170 return w;
171}
172
173struct ebt_u_table *find_table(char *name)
174{
175 struct ebt_u_table *t = tables;
176
177 while (t && strcmp(t->name, name))
178 t = t->next;
179 return t;
180}
181
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000182/*
183 * The pointers in here are special:
184 * The struct ebt_target * pointer is actually a struct ebt_u_target * pointer.
185 * instead of making yet a few other structs, we just do a cast.
186 * We need a struct ebt_u_target pointer because we know the address of the data
187 * they point to won't change. We want to allow that the struct ebt_u_target.t
188 * member can change.
189 * Same holds for the struct ebt_match and struct ebt_watcher pointers
190 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000191struct ebt_u_entry *new_entry;
192
Bart De Schuymer62423742002-07-14 19:06:20 +0000193static void initialize_entry(struct ebt_u_entry *e)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000194{
195 e->bitmask = EBT_NOPROTO;
196 e->invflags = 0;
197 e->ethproto = 0;
198 strcpy(e->in, "");
199 strcpy(e->out, "");
200 strcpy(e->logical_in, "");
201 strcpy(e->logical_out, "");
202 e->m_list = NULL;
203 e->w_list = NULL;
Bart De Schuymerc27432e2003-01-09 22:01:07 +0000204 /*
205 * the init function of the standard target should have put the verdict
206 * on CONTINUE
207 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000208 e->t = (struct ebt_entry_target *)find_target(EBT_STANDARD_TARGET);
209 if (!e->t)
Bart De Schuymerd4586482002-08-11 16:15:55 +0000210 print_bug("Couldn't load standard target");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000211}
212
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000213/*
214 * this doesn't free e, becoz the calling function might need e->next
215 */
Bart De Schuymer62423742002-07-14 19:06:20 +0000216static void free_u_entry(struct ebt_u_entry *e)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000217{
218 struct ebt_u_match_list *m_l, *m_l2;
219 struct ebt_u_watcher_list *w_l, *w_l2;
220
221 m_l = e->m_list;
222 while (m_l) {
223 m_l2 = m_l->next;
224 free(m_l->m);
225 free(m_l);
226 m_l = m_l2;
227 }
228 w_l = e->w_list;
229 while (w_l) {
230 w_l2 = w_l->next;
231 free(w_l->w);
232 free(w_l);
233 w_l = w_l2;
234 }
235 free(e->t);
236}
237
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000238/*
239 * the user will use the match, so put it in new_entry
240 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000241static void add_match(struct ebt_u_match *m)
242{
243 struct ebt_u_match_list **m_list, *new;
244
245 m->used = 1;
Bart De Schuymerc56a31a2002-07-25 08:16:08 +0000246 for (m_list = &new_entry->m_list; *m_list; m_list = &(*m_list)->next);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000247 new = (struct ebt_u_match_list *)
248 malloc(sizeof(struct ebt_u_match_list));
249 if (!new)
250 print_memory();
251 *m_list = new;
252 new->next = NULL;
253 new->m = (struct ebt_entry_match *)m;
254}
255
256static void add_watcher(struct ebt_u_watcher *w)
257{
258 struct ebt_u_watcher_list **w_list;
259 struct ebt_u_watcher_list *new;
260
261 w->used = 1;
Bart De Schuymerc56a31a2002-07-25 08:16:08 +0000262 for (w_list = &new_entry->w_list; *w_list; w_list = &(*w_list)->next);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000263 new = (struct ebt_u_watcher_list *)
264 malloc(sizeof(struct ebt_u_watcher_list));
265 if (!new)
266 print_memory();
267 *w_list = new;
268 new->next = NULL;
269 new->w = (struct ebt_entry_watcher *)w;
270}
271
272static int global_option_offset = 0;
273#define OPTION_OFFSET 256
274static struct option *
275merge_options(struct option *oldopts, const struct option *newopts,
276 unsigned int *options_offset)
277{
278 unsigned int num_old, num_new, i;
279 struct option *merge;
280
281 if (!newopts || !oldopts || !options_offset)
282 print_bug("merge wrong");
283 for (num_old = 0; oldopts[num_old].name; num_old++);
284 for (num_new = 0; newopts[num_new].name; num_new++);
285
286 global_option_offset += OPTION_OFFSET;
287 *options_offset = global_option_offset;
288
289 merge = malloc(sizeof(struct option) * (num_new + num_old + 1));
290 if (!merge)
291 print_memory();
292 memcpy(merge, oldopts, num_old * sizeof(struct option));
293 for (i = 0; i < num_new; i++) {
294 merge[num_old + i] = newopts[i];
295 merge[num_old + i].val += *options_offset;
296 }
297 memset(merge + num_old + num_new, 0, sizeof(struct option));
298 // only free dynamically allocated stuff
299 if (oldopts != ebt_original_options)
300 free(oldopts);
301
302 return merge;
303}
304
305void register_match(struct ebt_u_match *m)
306{
307 int size = m->size + sizeof(struct ebt_entry_match);
308 struct ebt_u_match **i;
309
310 m->m = (struct ebt_entry_match *)malloc(size);
311 if (!m->m)
312 print_memory();
313 strcpy(m->m->u.name, m->name);
314 m->m->match_size = m->size;
315 ebt_options = merge_options
316 (ebt_options, m->extra_ops, &(m->option_offset));
317 m->init(m->m);
318
319 for (i = &matches; *i; i = &((*i)->next));
320 m->next = NULL;
321 *i = m;
322}
323
324void register_watcher(struct ebt_u_watcher *w)
325{
326 int size = w->size + sizeof(struct ebt_entry_watcher);
327 struct ebt_u_watcher **i;
328
329 w->w = (struct ebt_entry_watcher *)malloc(size);
330 if (!w->w)
331 print_memory();
332 strcpy(w->w->u.name, w->name);
333 w->w->watcher_size = w->size;
334 ebt_options = merge_options
335 (ebt_options, w->extra_ops, &(w->option_offset));
336 w->init(w->w);
337
338 for (i = &watchers; *i; i = &((*i)->next));
339 w->next = NULL;
340 *i = w;
341}
342
343void register_target(struct ebt_u_target *t)
344{
345 int size = t->size + sizeof(struct ebt_entry_target);
346 struct ebt_u_target **i;
347
348 t->t = (struct ebt_entry_target *)malloc(size);
349 if (!t->t)
350 print_memory();
351 strcpy(t->t->u.name, t->name);
352 t->t->target_size = t->size;
353 ebt_options = merge_options
354 (ebt_options, t->extra_ops, &(t->option_offset));
355 t->init(t->t);
Bart De Schuymerc56a31a2002-07-25 08:16:08 +0000356
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000357 for (i = &targets; *i; i = &((*i)->next));
358 t->next = NULL;
359 *i = t;
360}
361
362void register_table(struct ebt_u_table *t)
363{
364 t->next = tables;
365 tables = t;
366}
367
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000368/*
369 * blatently stolen (again) from iptables.c userspace program
370 * find out where the modprobe utility is located
371 */
Bart De Schuymerc8531032002-06-14 21:55:29 +0000372static char *get_modprobe(void)
373{
374 int procfile;
375 char *ret;
376
377 procfile = open(PROC_SYS_MODPROBE, O_RDONLY);
378 if (procfile < 0)
379 return NULL;
380
381 ret = malloc(1024);
382 if (ret) {
383 switch (read(procfile, ret, 1024)) {
384 case -1: goto fail;
385 case 1024: goto fail; /* Partial read. Wierd */
386 }
387 if (ret[strlen(ret)-1]=='\n')
388 ret[strlen(ret)-1]=0;
389 close(procfile);
390 return ret;
391 }
392 fail:
393 free(ret);
394 close(procfile);
395 return NULL;
396}
397
Bart De Schuymerc8531032002-06-14 21:55:29 +0000398int ebtables_insmod(const char *modname, const char *modprobe)
399{
400 char *buf = NULL;
401 char *argv[3];
402
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000403 // If they don't explicitly set it, read out of kernel
Bart De Schuymerc8531032002-06-14 21:55:29 +0000404 if (!modprobe) {
405 buf = get_modprobe();
406 if (!buf)
407 return -1;
408 modprobe = buf;
409 }
410
411 switch (fork()) {
412 case 0:
413 argv[0] = (char *)modprobe;
414 argv[1] = (char *)modname;
415 argv[2] = NULL;
416 execv(argv[0], argv);
417
418 /* not usually reached */
419 exit(0);
420 case -1:
421 return -1;
422
423 default: /* parent */
424 wait(NULL);
425 }
426
427 free(buf);
428 return 0;
429}
430
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000431/*
432 * we use replace.flags, so we can't use the following values:
433 * 0x01 == OPT_COMMAND, 0x02 == OPT_TABLE, 0x100 == OPT_ZERO
434 */
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000435#define LIST_N 0x04
436#define LIST_C 0x08
437#define LIST_X 0x10
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000438/*
439 * helper function for list_rules()
440 */
Bart De Schuymer60332e02002-06-23 08:01:47 +0000441static void list_em(struct ebt_u_entries *entries)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000442{
443 int i, j, space = 0, digits;
444 struct ebt_u_entry *hlp;
445 struct ebt_u_match_list *m_l;
446 struct ebt_u_watcher_list *w_l;
447 struct ebt_u_match *m;
448 struct ebt_u_watcher *w;
449 struct ebt_u_target *t;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000450
Bart De Schuymer60332e02002-06-23 08:01:47 +0000451 hlp = entries->entries;
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000452 if (replace.flags & LIST_X && entries->policy != EBT_ACCEPT) {
453 printf("ebtables -t %s -P %s %s\n", replace.name,
454 entries->name, standard_targets[-entries->policy - 1]);
455 } else if (!(replace.flags & LIST_X)) {
Bart De Schuymerc87c9642002-08-01 15:34:16 +0000456 printf("\nBridge chain: %s, entries: %d, policy: %s\n",
457 entries->name, entries->nentries,
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000458 standard_targets[-entries->policy - 1]);
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000459 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000460
Bart De Schuymer60332e02002-06-23 08:01:47 +0000461 i = entries->nentries;
Bart De Schuymerf8f8f292002-06-25 15:43:57 +0000462 while (i > 9) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000463 space++;
464 i /= 10;
465 }
466
Bart De Schuymer60332e02002-06-23 08:01:47 +0000467 for (i = 0; i < entries->nentries; i++) {
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000468 if (replace.flags & LIST_N) {
469 digits = 0;
470 // A little work to get nice rule numbers.
471 j = i + 1;
472 while (j > 9) {
473 digits++;
474 j /= 10;
475 }
476 for (j = 0; j < space - digits; j++)
477 printf(" ");
478 printf("%d. ", i + 1);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000479 }
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000480 if (replace.flags & LIST_X)
481 printf("ebtables -t %s -A %s ",
482 replace.name, entries->name);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000483
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000484 /*
485 * Don't print anything about the protocol if no protocol was
486 * specified, obviously this means any protocol will do.
487 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000488 if (!(hlp->bitmask & EBT_NOPROTO)) {
Bart De Schuymer60332e02002-06-23 08:01:47 +0000489 printf("-p ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000490 if (hlp->invflags & EBT_IPROTO)
491 printf("! ");
492 if (hlp->bitmask & EBT_802_3)
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000493 printf("Length ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000494 else {
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000495 struct ethertypeent *ent;
496
497 ent = getethertypebynumber(ntohs(hlp->ethproto));
498 if (!ent)
Bart De Schuymer60332e02002-06-23 08:01:47 +0000499 printf("0x%x ", ntohs(hlp->ethproto));
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000500 else
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000501 printf("%s ", ent->e_name);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000502 }
503 }
504 if (hlp->bitmask & EBT_SOURCEMAC) {
505 char hlpmsk[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
506
Bart De Schuymer60332e02002-06-23 08:01:47 +0000507 printf("-s ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000508 if (hlp->invflags & EBT_ISOURCE)
509 printf("! ");
510 if (!memcmp(hlp->sourcemac, mac_type_unicast, 6) &&
511 !memcmp(hlp->sourcemsk, msk_type_unicast, 6)) {
512 printf("Unicast");
513 goto endsrc;
514 }
515 if (!memcmp(hlp->sourcemac, mac_type_multicast, 6) &&
516 !memcmp(hlp->sourcemsk, msk_type_multicast, 6)) {
517 printf("Multicast");
518 goto endsrc;
519 }
520 if (!memcmp(hlp->sourcemac, mac_type_broadcast, 6) &&
521 !memcmp(hlp->sourcemsk, msk_type_broadcast, 6)) {
522 printf("Broadcast");
523 goto endsrc;
524 }
Bart De Schuymer41830412002-06-05 19:41:28 +0000525 printf("%s", ether_ntoa((struct ether_addr *)
526 hlp->sourcemac));
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000527 if (memcmp(hlp->sourcemsk, hlpmsk, 6)) {
528 printf("/");
Bart De Schuymer41830412002-06-05 19:41:28 +0000529 printf("%s", ether_ntoa((struct ether_addr *)
530 hlp->sourcemsk));
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000531 }
532endsrc:
Bart De Schuymer60332e02002-06-23 08:01:47 +0000533 printf(" ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000534 }
535 if (hlp->bitmask & EBT_DESTMAC) {
536 char hlpmsk[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
537
Bart De Schuymer60332e02002-06-23 08:01:47 +0000538 printf("-d ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000539 if (hlp->invflags & EBT_IDEST)
540 printf("! ");
541 if (!memcmp(hlp->destmac, mac_type_unicast, 6) &&
542 !memcmp(hlp->destmsk, msk_type_unicast, 6)) {
543 printf("Unicast");
544 goto enddst;
545 }
546 if (!memcmp(hlp->destmac, mac_type_multicast, 6) &&
547 !memcmp(hlp->destmsk, msk_type_multicast, 6)) {
548 printf("Multicast");
549 goto enddst;
550 }
551 if (!memcmp(hlp->destmac, mac_type_broadcast, 6) &&
552 !memcmp(hlp->destmsk, msk_type_broadcast, 6)) {
553 printf("Broadcast");
554 goto enddst;
555 }
Bart De Schuymer41830412002-06-05 19:41:28 +0000556 printf("%s", ether_ntoa((struct ether_addr *)
557 hlp->destmac));
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000558 if (memcmp(hlp->destmsk, hlpmsk, 6)) {
559 printf("/");
Bart De Schuymer41830412002-06-05 19:41:28 +0000560 printf("%s", ether_ntoa((struct ether_addr *)
561 hlp->destmsk));
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000562 }
563enddst:
Bart De Schuymer60332e02002-06-23 08:01:47 +0000564 printf(" ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000565 }
566 if (hlp->in[0] != '\0') {
Bart De Schuymer60332e02002-06-23 08:01:47 +0000567 printf("-i ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000568 if (hlp->invflags & EBT_IIN)
569 printf("! ");
Bart De Schuymer60332e02002-06-23 08:01:47 +0000570 printf("%s ", hlp->in);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000571 }
572 if (hlp->logical_in[0] != '\0') {
Bart De Schuymer60332e02002-06-23 08:01:47 +0000573 printf("--logical-in ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000574 if (hlp->invflags & EBT_ILOGICALIN)
575 printf("! ");
Bart De Schuymer60332e02002-06-23 08:01:47 +0000576 printf("%s ", hlp->logical_in);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000577 }
578 if (hlp->logical_out[0] != '\0') {
Bart De Schuymer60332e02002-06-23 08:01:47 +0000579 printf("--logical-out ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000580 if (hlp->invflags & EBT_ILOGICALOUT)
581 printf("! ");
Bart De Schuymerb3d8f262002-07-07 14:26:15 +0000582 printf("%s ", hlp->logical_out);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000583 }
584 if (hlp->out[0] != '\0') {
Bart De Schuymer60332e02002-06-23 08:01:47 +0000585 printf("-o ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000586 if (hlp->invflags & EBT_IOUT)
587 printf("! ");
Bart De Schuymerb3d8f262002-07-07 14:26:15 +0000588 printf("%s ", hlp->out);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000589 }
590
591 m_l = hlp->m_list;
592 while (m_l) {
593 m = find_match(m_l->m->u.name);
594 if (!m)
595 print_bug("Match not found");
596 m->print(hlp, m_l->m);
597 m_l = m_l->next;
598 }
599 w_l = hlp->w_list;
600 while (w_l) {
601 w = find_watcher(w_l->w->u.name);
602 if (!w)
603 print_bug("Watcher not found");
604 w->print(hlp, w_l->w);
605 w_l = w_l->next;
606 }
607
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000608 printf("-j ");
609 if (strcmp(hlp->t->u.name, EBT_STANDARD_TARGET))
610 printf("%s ", hlp->t->u.name);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000611 t = find_target(hlp->t->u.name);
612 if (!t)
613 print_bug("Target not found");
614 t->print(hlp, hlp->t);
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000615 if (replace.flags & LIST_C)
Bart De Schuymer73fccca2002-10-17 22:00:23 +0000616 printf(", pcnt = %llu -- bcnt = %llu",
617 replace.counters[entries->counter_offset + i].pcnt,
618 replace.counters[entries->counter_offset + i].bcnt);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000619 printf("\n");
620 hlp = hlp->next;
621 }
622}
623
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000624struct ebt_u_entries *nr_to_chain(int nr)
Bart De Schuymer60332e02002-06-23 08:01:47 +0000625{
626 if (nr == -1)
627 return NULL;
628 if (nr < NF_BR_NUMHOOKS)
629 return replace.hook_entry[nr];
630 else {
631 int i;
632 struct ebt_u_chain_list *cl = replace.udc;
633
634 i = nr - NF_BR_NUMHOOKS;
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000635 while (i > 0 && cl) {
Bart De Schuymer60332e02002-06-23 08:01:47 +0000636 cl = cl->next;
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000637 i--;
638 }
Bart De Schuymer60332e02002-06-23 08:01:47 +0000639 if (cl)
640 return cl->udc;
641 else
642 return NULL;
643 }
644}
645
Bart De Schuymercc440052002-11-06 21:10:33 +0000646static inline struct ebt_u_entries *to_chain()
Bart De Schuymer60332e02002-06-23 08:01:47 +0000647{
648 return nr_to_chain(replace.selected_hook);
649}
650
651struct ebt_u_stack
652{
653 int chain_nr;
654 int n;
655 struct ebt_u_entry *e;
656 struct ebt_u_entries *entries;
657};
658
Bart De Schuymer62423742002-07-14 19:06:20 +0000659static void check_for_loops()
Bart De Schuymer60332e02002-06-23 08:01:47 +0000660{
661 int chain_nr , i, j , k, sp = 0, verdict;
662 struct ebt_u_entries *entries, *entries2;
663 struct ebt_u_stack *stack = NULL;
664 struct ebt_u_entry *e;
665
666 i = -1;
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000667 /*
668 * initialize hook_mask to 0
669 */
Bart De Schuymer60332e02002-06-23 08:01:47 +0000670 while (1) {
671 i++;
672 if (i < NF_BR_NUMHOOKS && !(replace.valid_hooks & (1 << i)))
673 continue;
674 entries = nr_to_chain(i);
675 if (!entries)
676 break;
677 entries->hook_mask = 0;
678 }
679 if (i > NF_BR_NUMHOOKS) {
680 stack = (struct ebt_u_stack *)malloc((i - NF_BR_NUMHOOKS) *
681 sizeof(struct ebt_u_stack));
682 if (!stack)
683 print_memory();
684 }
685
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000686 /*
687 * check for loops, starting from every base chain
688 */
Bart De Schuymer60332e02002-06-23 08:01:47 +0000689 for (i = 0; i < NF_BR_NUMHOOKS; i++) {
690 if (!(replace.valid_hooks & (1 << i)))
691 continue;
692 entries = nr_to_chain(i);
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000693 /*
694 * (1 << NF_BR_NUMHOOKS) implies it's a standard chain
695 * (usefull in the final_check() funtions)
696 */
Bart De Schuymerb26649e2002-07-25 14:51:54 +0000697 entries->hook_mask = (1 << i) | (1 << NF_BR_NUMHOOKS);
Bart De Schuymer60332e02002-06-23 08:01:47 +0000698 chain_nr = i;
699
700 e = entries->entries;
701 for (j = 0; j < entries->nentries; j++) {
702 if (strcmp(e->t->u.name, EBT_STANDARD_TARGET))
703 goto letscontinue;
704 verdict = ((struct ebt_standard_target *)(e->t))->verdict;
705 if (verdict < 0)
706 goto letscontinue;
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000707 entries2 = nr_to_chain(verdict + NF_BR_NUMHOOKS);
Bart De Schuymer60332e02002-06-23 08:01:47 +0000708 entries2->hook_mask |= entries->hook_mask;
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000709 /*
710 * now see if we've been here before
711 */
Bart De Schuymer60332e02002-06-23 08:01:47 +0000712 for (k = 0; k < sp; k++)
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000713 if (stack[k].chain_nr == verdict + NF_BR_NUMHOOKS)
Bart De Schuymer1a0a9c32002-06-24 21:10:16 +0000714 print_error("Loop from chain %s to chain %s",
Bart De Schuymerc56a31a2002-07-25 08:16:08 +0000715 nr_to_chain(chain_nr)->name,
716 nr_to_chain(stack[k].chain_nr)->name);
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000717 /*
718 * jump to the chain, make sure we know how to get back
719 */
Bart De Schuymer60332e02002-06-23 08:01:47 +0000720 stack[sp].chain_nr = chain_nr;
721 stack[sp].n = j;
722 stack[sp].entries = entries;
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000723 stack[sp].e = e;
724 sp++;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000725 j = -1;
726 e = entries2->entries;
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000727 chain_nr = verdict + NF_BR_NUMHOOKS;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000728 entries = entries2;
729 continue;
730letscontinue:
731 e = e->next;
732 }
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000733 /*
734 * we are at the end of a standard chain
735 */
Bart De Schuymer60332e02002-06-23 08:01:47 +0000736 if (sp == 0)
737 continue;
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000738 /*
739 * go back to the chain one level higher
740 */
Bart De Schuymer60332e02002-06-23 08:01:47 +0000741 sp--;
742 j = stack[sp].n;
743 chain_nr = stack[sp].chain_nr;
744 e = stack[sp].e;
745 entries = stack[sp].entries;
746 goto letscontinue;
747 }
748 free(stack);
749 return;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000750}
751
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000752/*
753 * parse the chain name and return the corresponding nr
754 * returns -1 on failure
755 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000756int get_hooknr(char* arg)
757{
758 int i;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000759 struct ebt_u_chain_list *cl = replace.udc;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000760
Bart De Schuymer60332e02002-06-23 08:01:47 +0000761 for (i = 0; i < NF_BR_NUMHOOKS; i++) {
762 if (!(replace.valid_hooks & (1 << i)))
763 continue;
764 if (!strcmp(arg, replace.hook_entry[i]->name))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000765 return i;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000766 }
767 while(cl) {
768 if (!strcmp(arg, cl->udc->name))
769 return i;
770 i++;
771 cl = cl->next;
772 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000773 return -1;
774}
775
Bart De Schuymer62423742002-07-14 19:06:20 +0000776static void print_help()
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000777{
778 struct ebt_u_match_list *m_l;
779 struct ebt_u_watcher_list *w_l;
780
Bart De Schuymerd4586482002-08-11 16:15:55 +0000781 printf(PROGNAME" v"PROGVERSION" ("PROGDATE")\n"
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000782"Usage:\n"
783"ebtables -[ADI] chain rule-specification [options]\n"
784"ebtables -P chain target\n"
785"ebtables -[LFZ] [chain]\n"
Bart De Schuymer5885b362002-12-03 20:51:36 +0000786"ebtables -[NX] [chain]\n"
787"ebtables -E old-chain-name new-chain-name\n\n"
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000788"Commands:\n"
Bart De Schuymer23f6dcf2002-08-17 09:14:07 +0000789"--append -A chain : append to chain\n"
790"--delete -D chain : delete matching rule from chain\n"
791"--delete -D chain rulenum : delete rule at position rulenum from chain\n"
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000792"--insert -I chain rulenum : insert rule at position rulenum in chain\n"
Bart De Schuymer23f6dcf2002-08-17 09:14:07 +0000793"--list -L [chain] : list the rules in a chain or in all chains\n"
794"--flush -F [chain] : delete all rules in chain or in all chains\n"
795"--init-table : replace the kernel table with the initial table\n"
796"--zero -Z [chain] : put counters on zero in chain or in all chains\n"
797"--policy -P chain target : change policy on chain to target\n"
798"--new-chain -N chain : create a user defined chain\n"
799"--rename-chain -E old new : rename a chain\n"
800"--delete-chain -X chain : delete a user defined chain\n"
Bart De Schuymer5885b362002-12-03 20:51:36 +0000801"--atomic-commit : update the kernel w/t table contained in <FILE>\n"
802"--atomic-init : put the initial kernel table into <FILE>\n"
803"--atomic-save : put the current kernel table into <FILE>\n"
Bart De Schuymer97819962002-12-11 21:23:07 +0000804"--atomic-file file : set <FILE> to file\n\n"
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000805"Options:\n"
806"--proto -p [!] proto : protocol hexadecimal, by name or LENGTH\n"
807"--src -s [!] address[/mask]: source mac address\n"
808"--dst -d [!] address[/mask]: destination mac address\n"
809"--in-if -i [!] name : network input interface name\n"
810"--out-if -o [!] name : network output interface name\n"
811"--logical-in [!] name : logical bridge input interface name\n"
812"--logical-out [!] name : logical bridge output interface name\n"
Bart De Schuymer5cbc8e02002-07-14 21:15:28 +0000813"--modprobe -M program : try to insert modules using this program\n"
Bart De Schuymer5885b362002-12-03 20:51:36 +0000814"--version -V : print package version\n\n"
815"Environment variable:\n"
816ATOMIC_ENV_VARIABLE " : if set <FILE> (see above) will equal its value"
817"\n\n");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000818
819 m_l = new_entry->m_list;
820 while (m_l) {
821 ((struct ebt_u_match *)m_l->m)->help();
822 printf("\n");
823 m_l = m_l->next;
824 }
825 w_l = new_entry->w_list;
826 while (w_l) {
827 ((struct ebt_u_watcher *)w_l->w)->help();
828 printf("\n");
829 w_l = w_l->next;
830 }
831 ((struct ebt_u_target *)new_entry->t)->help();
832 printf("\n");
833 if (table->help)
834 table->help(hooknames);
835 exit(0);
836}
837
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000838/*
839 * execute command L
840 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000841static void list_rules()
842{
843 int i;
844
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000845 if (!(replace.flags & LIST_X))
846 printf("Bridge table: %s\n", table->name);
Bart De Schuymer60332e02002-06-23 08:01:47 +0000847 if (replace.selected_hook != -1) {
848 list_em(to_chain());
849 } else {
850 struct ebt_u_chain_list *cl = replace.udc;
851
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000852 /*
853 * create new chains and rename standard chains when necessary
854 */
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000855 if (replace.flags & LIST_X) {
856 while (cl) {
857 printf("ebtables -t %s -N %s\n", replace.name,
858 cl->udc->name);
859 cl = cl->next;
860 }
861 cl = replace.udc;
862 for (i = 0; i < NF_BR_NUMHOOKS; i++)
863 if (replace.valid_hooks & (1 << i) &&
864 strcmp(replace.hook_entry[i]->name, hooknames[i]))
865 printf("ebtables -t %s -E %s %s\n",
866 replace.name, hooknames[i],
867 replace.hook_entry[i]->name);
868 }
Bart De Schuymer60332e02002-06-23 08:01:47 +0000869 i = 0;
870 while (1) {
871 if (i < NF_BR_NUMHOOKS) {
872 if (replace.valid_hooks & (1 << i))
873 list_em(replace.hook_entry[i]);
874 i++;
875 continue;
876 } else {
877 if (!cl)
878 break;
879 list_em(cl->udc);
880 cl = cl->next;
881 }
882 }
883 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000884}
885
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000886/*
887 * execute command P
888 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000889static void change_policy(int policy)
890{
891 int i;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000892 struct ebt_u_entries *entries = to_chain();
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000893
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000894 /*
895 * don't do anything if the policy is the same
896 */
Bart De Schuymer60332e02002-06-23 08:01:47 +0000897 if (entries->policy != policy) {
898 entries->policy = policy;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000899 replace.num_counters = replace.nentries;
900 if (replace.nentries) {
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000901 /*
902 * '+ 1' for the CNT_END
903 */
Bart De Schuymered053432002-07-21 19:35:39 +0000904 if (!(replace.counterchanges = (unsigned short *) malloc(
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000905 (replace.nentries + 1) * sizeof(unsigned short))))
906 print_memory();
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000907 /*
908 * done nothing special to the rules
909 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000910 for (i = 0; i < replace.nentries; i++)
Bart De Schuymered053432002-07-21 19:35:39 +0000911 replace.counterchanges[i] = CNT_NORM;
912 replace.counterchanges[replace.nentries] = CNT_END;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000913 }
914 else
Bart De Schuymered053432002-07-21 19:35:39 +0000915 replace.counterchanges = NULL;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000916 }
917 else
918 exit(0);
919}
920
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000921/*
922 * flush one chain or the complete table
923 * -1 == nothing to do
924 * 0 == give back to kernel
925 */
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000926static int flush_chains()
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000927{
Bart De Schuymer60332e02002-06-23 08:01:47 +0000928 int i, j, oldnentries, numdel;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000929 unsigned short *cnt;
930 struct ebt_u_entry *u_e, *tmp;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000931 struct ebt_u_entries *entries = to_chain();
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000932
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000933 /*
934 * flush whole table
935 */
Bart De Schuymer60332e02002-06-23 08:01:47 +0000936 if (!entries) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000937 if (replace.nentries == 0)
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000938 return -1;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000939 replace.nentries = 0;
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000940 /*
941 * no need for the kernel to give us counters back
942 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000943 replace.num_counters = 0;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000944
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000945 /*
946 * free everything and zero (n)entries
947 */
Bart De Schuymer60332e02002-06-23 08:01:47 +0000948 i = -1;
949 while (1) {
950 i++;
951 entries = nr_to_chain(i);
952 if (!entries) {
953 if (i < NF_BR_NUMHOOKS)
954 continue;
955 else
956 break;
957 }
958 entries->nentries = 0;
959 entries->counter_offset = 0;
960 u_e = entries->entries;
961 entries->entries = NULL;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000962 while (u_e) {
963 free_u_entry(u_e);
964 tmp = u_e->next;
965 free(u_e);
966 u_e = tmp;
967 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000968 }
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000969 return 0;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000970 }
971
Bart De Schuymer60332e02002-06-23 08:01:47 +0000972 if (entries->nentries == 0)
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000973 return -1;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000974 oldnentries = replace.nentries;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000975 replace.nentries -= entries->nentries;
976 numdel = entries->nentries;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000977
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000978 if (replace.nentries) {
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000979 /*
980 * +1 for CNT_END
981 */
Bart De Schuymered053432002-07-21 19:35:39 +0000982 if ( !(replace.counterchanges = (unsigned short *)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000983 malloc((oldnentries + 1) * sizeof(unsigned short))) )
984 print_memory();
Bart De Schuymer60332e02002-06-23 08:01:47 +0000985 }
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000986 /*
987 * delete the counters belonging to the specified chain,
988 * update counter_offset
989 */
Bart De Schuymer60332e02002-06-23 08:01:47 +0000990 i = -1;
Bart De Schuymered053432002-07-21 19:35:39 +0000991 cnt = replace.counterchanges;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000992 while (1) {
993 i++;
994 entries = nr_to_chain(i);
995 if (!entries) {
996 if (i < NF_BR_NUMHOOKS)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000997 continue;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000998 else
999 break;
1000 }
1001 if (i > replace.selected_hook)
1002 entries->counter_offset -= numdel;
1003 if (replace.nentries) {
1004 for (j = 0; j < entries->nentries; j++) {
1005 if (i == replace.selected_hook)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001006 *cnt = CNT_DEL;
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001007 else
1008 *cnt = CNT_NORM;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001009 cnt++;
1010 }
1011 }
Bart De Schuymer60332e02002-06-23 08:01:47 +00001012 }
1013
1014 if (replace.nentries) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001015 *cnt = CNT_END;
1016 replace.num_counters = oldnentries;
Bart De Schuymercc440052002-11-06 21:10:33 +00001017 } else
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001018 replace.num_counters = 0;
1019
Bart De Schuymer60332e02002-06-23 08:01:47 +00001020 entries = to_chain();
1021 entries->nentries = 0;
1022 u_e = entries->entries;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001023 while (u_e) {
1024 free_u_entry(u_e);
1025 tmp = u_e->next;
1026 free(u_e);
1027 u_e = tmp;
1028 }
Bart De Schuymer60332e02002-06-23 08:01:47 +00001029 entries->entries = NULL;
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001030 return 0;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001031}
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001032
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001033/*
1034 * -1 == no match
1035 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001036static int check_rule_exists(int rule_nr)
1037{
1038 struct ebt_u_entry *u_e;
1039 struct ebt_u_match_list *m_l, *m_l2;
1040 struct ebt_u_match *m;
1041 struct ebt_u_watcher_list *w_l, *w_l2;
1042 struct ebt_u_watcher *w;
1043 struct ebt_u_target *t = (struct ebt_u_target *)new_entry->t;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001044 struct ebt_u_entries *entries = to_chain();
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001045 int i, j, k;
1046
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001047 /*
1048 * handle '-D chain rulenr' command
1049 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001050 if (rule_nr != -1) {
Bart De Schuymer60332e02002-06-23 08:01:47 +00001051 if (rule_nr > entries->nentries)
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001052 return -1;
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001053 /*
1054 * user starts counting from 1
1055 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001056 return rule_nr - 1;
1057 }
Bart De Schuymer60332e02002-06-23 08:01:47 +00001058 u_e = entries->entries;
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001059 /*
1060 * check for an existing rule (if there are duplicate rules,
1061 * take the first occurance)
1062 */
Bart De Schuymer60332e02002-06-23 08:01:47 +00001063 for (i = 0; i < entries->nentries; i++, u_e = u_e->next) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001064 if (!u_e)
1065 print_bug("Hmm, trouble");
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001066 if (u_e->ethproto != new_entry->ethproto)
1067 continue;
1068 if (strcmp(u_e->in, new_entry->in))
1069 continue;
1070 if (strcmp(u_e->out, new_entry->out))
1071 continue;
1072 if (strcmp(u_e->logical_in, new_entry->logical_in))
1073 continue;
1074 if (strcmp(u_e->logical_out, new_entry->logical_out))
1075 continue;
1076 if (new_entry->bitmask & EBT_SOURCEMAC &&
1077 memcmp(u_e->sourcemac, new_entry->sourcemac, ETH_ALEN))
1078 continue;
1079 if (new_entry->bitmask & EBT_DESTMAC &&
1080 memcmp(u_e->destmac, new_entry->destmac, ETH_ALEN))
1081 continue;
1082 if (new_entry->bitmask != u_e->bitmask ||
1083 new_entry->invflags != u_e->invflags)
1084 continue;
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001085 /*
1086 * compare all matches
1087 */
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001088 m_l = new_entry->m_list;
1089 j = 0;
1090 while (m_l) {
1091 m = (struct ebt_u_match *)(m_l->m);
1092 m_l2 = u_e->m_list;
1093 while (m_l2 && strcmp(m_l2->m->u.name, m->m->u.name))
1094 m_l2 = m_l2->next;
1095 if (!m_l2 || !m->compare(m->m, m_l2->m))
1096 goto letscontinue;
1097 j++;
1098 m_l = m_l->next;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001099 }
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001100 /*
1101 * now be sure they have the same nr of matches
1102 */
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001103 k = 0;
1104 m_l = u_e->m_list;
1105 while (m_l) {
1106 k++;
1107 m_l = m_l->next;
1108 }
1109 if (j != k)
1110 continue;
1111
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001112 /*
1113 * compare all watchers
1114 */
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001115 w_l = new_entry->w_list;
1116 j = 0;
1117 while (w_l) {
1118 w = (struct ebt_u_watcher *)(w_l->w);
1119 w_l2 = u_e->w_list;
1120 while (w_l2 && strcmp(w_l2->w->u.name, w->w->u.name))
1121 w_l2 = w_l2->next;
1122 if (!w_l2 || !w->compare(w->w, w_l2->w))
1123 goto letscontinue;
1124 j++;
1125 w_l = w_l->next;
1126 }
1127 k = 0;
1128 w_l = u_e->w_list;
1129 while (w_l) {
1130 k++;
1131 w_l = w_l->next;
1132 }
1133 if (j != k)
1134 continue;
1135 if (strcmp(t->t->u.name, u_e->t->u.name))
1136 continue;
1137 if (!t->compare(t->t, u_e->t))
1138 continue;
1139 return i;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001140letscontinue:
1141 }
1142 return -1;
1143}
1144
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001145// execute command A or I
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001146static void add_rule(int rule_nr)
1147{
1148 int i, j;
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001149 struct ebt_u_entry **u_e;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001150 unsigned short *cnt;
1151 struct ebt_u_match_list *m_l;
1152 struct ebt_u_watcher_list *w_l;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001153 struct ebt_u_entries *entries = to_chain(), *entries2;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001154
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001155 if (rule_nr != -1) { /* command -I */
Bart De Schuymer60332e02002-06-23 08:01:47 +00001156 if (--rule_nr > entries->nentries)
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001157 print_error("rule nr too high: %d > %d", rule_nr + 1,
1158 entries->nentries + 1);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001159 } else
Bart De Schuymer60332e02002-06-23 08:01:47 +00001160 rule_nr = entries->nentries;
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001161 /*
1162 * we're adding one rule
1163 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001164 replace.num_counters = replace.nentries;
1165 replace.nentries++;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001166 entries->nentries++;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001167
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001168 /*
1169 * handle counter stuff
1170 * +1 for CNT_END
1171 */
Bart De Schuymered053432002-07-21 19:35:39 +00001172 if ( !(replace.counterchanges = (unsigned short *)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001173 malloc((replace.nentries + 1) * sizeof(unsigned short))) )
1174 print_memory();
Bart De Schuymered053432002-07-21 19:35:39 +00001175 cnt = replace.counterchanges;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001176 for (i = 0; i < replace.selected_hook; i++) {
Bart De Schuymer60332e02002-06-23 08:01:47 +00001177 if (i < NF_BR_NUMHOOKS && !(replace.valid_hooks & (1 << i)))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001178 continue;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001179 entries2 = nr_to_chain(i);
1180 for (j = 0; j < entries2->nentries; j++) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001181 *cnt = CNT_NORM;
1182 cnt++;
1183 }
1184 }
1185 for (i = 0; i < rule_nr; i++) {
1186 *cnt = CNT_NORM;
1187 cnt++;
1188 }
1189 *cnt = CNT_ADD;
1190 cnt++;
Bart De Schuymered053432002-07-21 19:35:39 +00001191 while (cnt != replace.counterchanges + replace.nentries) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001192 *cnt = CNT_NORM;
1193 cnt++;
1194 }
1195 *cnt = CNT_END;
1196
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001197 /*
1198 * go to the right position in the chain
1199 */
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001200 u_e = &entries->entries;
1201 for (i = 0; i < rule_nr; i++)
1202 u_e = &(*u_e)->next;
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001203 /*
1204 * insert the rule
1205 */
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001206 new_entry->next = *u_e;
1207 *u_e = new_entry;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001208
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001209 /*
1210 * put the ebt_[match, watcher, target] pointers in place
1211 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001212 m_l = new_entry->m_list;
1213 while (m_l) {
1214 m_l->m = ((struct ebt_u_match *)m_l->m)->m;
1215 m_l = m_l->next;
1216 }
1217 w_l = new_entry->w_list;
1218 while (w_l) {
1219 w_l->w = ((struct ebt_u_watcher *)w_l->w)->w;
1220 w_l = w_l->next;
1221 }
1222 new_entry->t = ((struct ebt_u_target *)new_entry->t)->t;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001223
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001224 /*
1225 * update the counter_offset of chains behind this one
1226 */
Bart De Schuymer60332e02002-06-23 08:01:47 +00001227 i = replace.selected_hook;
1228 while (1) {
1229 i++;
1230 entries = nr_to_chain(i);
1231 if (!entries) {
1232 if (i < NF_BR_NUMHOOKS)
1233 continue;
1234 else
1235 break;
1236 } else
1237 entries->counter_offset++;
1238 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001239}
1240
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001241/*
1242 * execute command D
1243 */
Bart De Schuymercc440052002-11-06 21:10:33 +00001244static void delete_rule(int begin, int end)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001245{
Bart De Schuymercc440052002-11-06 21:10:33 +00001246 int j, lentmp = 0, nr_deletes;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001247 unsigned short *cnt;
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001248 struct ebt_u_entry **u_e, *u_e2;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001249 struct ebt_u_entries *entries = to_chain(), *entries2;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001250
Bart De Schuymercc440052002-11-06 21:10:33 +00001251 if ((begin = check_rule_exists(begin)) == -1 ||
1252 (end = check_rule_exists(end)) == -1)
Bart De Schuymer60332e02002-06-23 08:01:47 +00001253 print_error("Sorry, rule does not exist");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001254
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001255 /*
1256 * we're deleting rules
1257 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001258 replace.num_counters = replace.nentries;
Bart De Schuymercc440052002-11-06 21:10:33 +00001259 nr_deletes = end - begin + 1;
1260 replace.nentries -= nr_deletes;
1261 entries->nentries -= nr_deletes;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001262
1263 if (replace.nentries) {
1264 for (j = 0; j < replace.selected_hook; j++) {
Bart De Schuymer60332e02002-06-23 08:01:47 +00001265 if (j < NF_BR_NUMHOOKS &&
1266 !(replace.valid_hooks & (1 << j)))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001267 continue;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001268 entries2 = nr_to_chain(j);
1269 lentmp += entries2->nentries;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001270 }
Bart De Schuymercc440052002-11-06 21:10:33 +00001271 lentmp += begin;
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001272 /*
1273 * +1 for CNT_END
1274 */
Bart De Schuymered053432002-07-21 19:35:39 +00001275 if ( !(replace.counterchanges = (unsigned short *)malloc(
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001276 (replace.num_counters + 1) * sizeof(unsigned short))) )
1277 print_memory();
Bart De Schuymered053432002-07-21 19:35:39 +00001278 cnt = replace.counterchanges;
Bart De Schuymercc440052002-11-06 21:10:33 +00001279 for (j = 0; j < lentmp; j++, cnt++)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001280 *cnt = CNT_NORM;
Bart De Schuymercc440052002-11-06 21:10:33 +00001281 for (j = 0; j < nr_deletes; j++, cnt++)
1282 *cnt = CNT_DEL;
1283
1284 for (j = 0; j < replace.num_counters - lentmp - nr_deletes;
1285 j++, cnt++)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001286 *cnt = CNT_NORM;
Bart De Schuymercc440052002-11-06 21:10:33 +00001287
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001288 *cnt = CNT_END;
1289 }
1290 else
1291 replace.num_counters = 0;
1292
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001293 /*
1294 * go to the right position in the chain
1295 */
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001296 u_e = &entries->entries;
Bart De Schuymercc440052002-11-06 21:10:33 +00001297 for (j = 0; j < begin; j++)
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001298 u_e = &(*u_e)->next;
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001299 /*
1300 * remove the rules
1301 */
Bart De Schuymercc440052002-11-06 21:10:33 +00001302 j = nr_deletes;
1303 while(j--) {
1304 u_e2 = *u_e;
1305 *u_e = (*u_e)->next;
1306 // free everything
1307 free_u_entry(u_e2);
1308 free(u_e2);
1309 }
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001310
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001311 /*
1312 * update the counter_offset of chains behind this one
1313 */
Bart De Schuymercc440052002-11-06 21:10:33 +00001314 j = replace.selected_hook;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001315 while (1) {
Bart De Schuymercc440052002-11-06 21:10:33 +00001316 j++;
1317 entries = nr_to_chain(j);
Bart De Schuymer60332e02002-06-23 08:01:47 +00001318 if (!entries) {
Bart De Schuymercc440052002-11-06 21:10:33 +00001319 if (j < NF_BR_NUMHOOKS)
Bart De Schuymer60332e02002-06-23 08:01:47 +00001320 continue;
1321 else
1322 break;
Bart De Schuymercc440052002-11-06 21:10:33 +00001323 } else
1324 entries->counter_offset -= nr_deletes;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001325 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001326}
1327
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001328/*
1329 * execute command Z
1330 */
Bart De Schuymer62423742002-07-14 19:06:20 +00001331static void zero_counters(int zerochain)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001332{
1333
1334 if (zerochain == -1) {
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001335 /*
1336 * tell main() we don't update the counters
1337 * this results in tricking the kernel to zero its counters,
1338 * naively expecting userspace to update its counters. Muahahaha
1339 */
Bart De Schuymered053432002-07-21 19:35:39 +00001340 replace.counterchanges = NULL;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001341 replace.num_counters = 0;
1342 } else {
1343 int i, j;
1344 unsigned short *cnt;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001345 struct ebt_u_entries *entries = nr_to_chain(zerochain), *e2;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001346
Bart De Schuymer60332e02002-06-23 08:01:47 +00001347 if (entries->nentries == 0)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001348 exit(0);
Bart De Schuymered053432002-07-21 19:35:39 +00001349 replace.counterchanges = (unsigned short *)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001350 malloc((replace.nentries + 1) * sizeof(unsigned short));
Bart De Schuymered053432002-07-21 19:35:39 +00001351 if (!replace.counterchanges)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001352 print_memory();
Bart De Schuymered053432002-07-21 19:35:39 +00001353 cnt = replace.counterchanges;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001354 for (i = 0; i < zerochain; i++) {
Bart De Schuymer60332e02002-06-23 08:01:47 +00001355 if (i < NF_BR_NUMHOOKS &&
1356 !(replace.valid_hooks & (1 << i)))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001357 continue;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001358 e2 = nr_to_chain(i);
1359 for (j = 0; j < e2->nentries; j++) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001360 *cnt = CNT_NORM;
1361 cnt++;
1362 }
1363 }
Bart De Schuymer60332e02002-06-23 08:01:47 +00001364 for (i = 0; i < entries->nentries; i++) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001365 *cnt = CNT_ZERO;
1366 cnt++;
1367 }
Bart De Schuymered053432002-07-21 19:35:39 +00001368 while (cnt != replace.counterchanges + replace.nentries) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001369 *cnt = CNT_NORM;
1370 cnt++;
1371 }
1372 *cnt = CNT_END;
1373 }
1374}
1375
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001376/*
1377 * Checks the type for validity and calls getethertypebynumber()
1378 */
1379struct ethertypeent *parseethertypebynumber(int type)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001380{
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001381 if (type < 1536)
1382 print_error("Ethernet protocols have values >= 0x0600");
1383 if (type > 0xffff)
1384 print_error("Ethernet protocols have values <= 0xffff");
1385 return getethertypebynumber(type);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001386}
1387
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001388/*
1389 * put the mac address into 6 (ETH_ALEN) bytes
1390 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001391int getmac_and_mask(char *from, char *to, char *mask)
1392{
1393 char *p;
1394 int i;
Bart De Schuymer41830412002-06-05 19:41:28 +00001395 struct ether_addr *addr;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001396
1397 if (strcasecmp(from, "Unicast") == 0) {
1398 memcpy(to, mac_type_unicast, ETH_ALEN);
1399 memcpy(mask, msk_type_unicast, ETH_ALEN);
1400 return 0;
1401 }
1402 if (strcasecmp(from, "Multicast") == 0) {
1403 memcpy(to, mac_type_multicast, ETH_ALEN);
1404 memcpy(mask, msk_type_multicast, ETH_ALEN);
1405 return 0;
1406 }
1407 if (strcasecmp(from, "Broadcast") == 0) {
1408 memcpy(to, mac_type_broadcast, ETH_ALEN);
1409 memcpy(mask, msk_type_broadcast, ETH_ALEN);
1410 return 0;
1411 }
1412 if ( (p = strrchr(from, '/')) != NULL) {
1413 *p = '\0';
Bart De Schuymer41830412002-06-05 19:41:28 +00001414 if (!(addr = ether_aton(p + 1)))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001415 return -1;
Bart De Schuymer41830412002-06-05 19:41:28 +00001416 memcpy(mask, addr, ETH_ALEN);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001417 } else
1418 memset(mask, 0xff, ETH_ALEN);
Bart De Schuymer41830412002-06-05 19:41:28 +00001419 if (!(addr = ether_aton(from)))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001420 return -1;
Bart De Schuymer41830412002-06-05 19:41:28 +00001421 memcpy(to, addr, ETH_ALEN);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001422 for (i = 0; i < ETH_ALEN; i++)
1423 to[i] &= mask[i];
1424 return 0;
1425}
1426
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001427/*
1428 * executes the final_check() function for all extensions used by the rule
1429 */
Bart De Schuymer62423742002-07-14 19:06:20 +00001430static void do_final_checks(struct ebt_u_entry *e, struct ebt_u_entries *entries)
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +00001431{
1432 struct ebt_u_match_list *m_l;
1433 struct ebt_u_watcher_list *w_l;
1434 struct ebt_u_target *t;
1435 struct ebt_u_match *m;
1436 struct ebt_u_watcher *w;
1437
1438 m_l = e->m_list;
1439 w_l = e->w_list;
1440 while (m_l) {
1441 m = find_match(m_l->m->u.name);
1442 m->final_check(e, m_l->m, replace.name,
1443 entries->hook_mask, 1);
1444 m_l = m_l->next;
1445 }
1446 while (w_l) {
1447 w = find_watcher(w_l->w->u.name);
1448 w->final_check(e, w_l->w, replace.name,
1449 entries->hook_mask, 1);
1450 w_l = w_l->next;
1451 }
1452 t = find_target(e->t->u.name);
1453 t->final_check(e, e->t, replace.name,
1454 entries->hook_mask, 1);
1455}
1456
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001457/*
1458 * used for the -X command
1459 */
Bart De Schuymer62423742002-07-14 19:06:20 +00001460static void check_for_references(int chain_nr)
Bart De Schuymerb909f9b2002-06-26 18:35:31 +00001461{
1462 int i = -1, j;
1463 struct ebt_u_entries *entries;
1464 struct ebt_u_entry *e;
1465
1466 while (1) {
1467 i++;
1468 entries = nr_to_chain(i);
1469 if (!entries) {
1470 if (i < NF_BR_NUMHOOKS)
1471 continue;
1472 else
1473 break;
1474 }
1475 e = entries->entries;
1476 j = 0;
1477 while (e) {
Bart De Schuymerc27432e2003-01-09 22:01:07 +00001478 int chain_jmp;
1479
Bart De Schuymerb909f9b2002-06-26 18:35:31 +00001480 j++;
1481 if (strcmp(e->t->u.name, EBT_STANDARD_TARGET)) {
1482 e = e->next;
1483 continue;
1484 }
Bart De Schuymerc27432e2003-01-09 22:01:07 +00001485 chain_jmp = ((struct ebt_standard_target *)e->t)->verdict;
1486 if (chain_jmp == chain_nr)
Bart De Schuymerb909f9b2002-06-26 18:35:31 +00001487 print_error("Can't delete the chain, it's referenced "
1488 "in chain %s, rule %d", entries->name, j);
Bart De Schuymerc27432e2003-01-09 22:01:07 +00001489 /* adjust the chain jumps when necessary */
1490 if (chain_jmp > chain_nr)
1491 ((struct ebt_standard_target *)e->t)->verdict--;
Bart De Schuymerb909f9b2002-06-26 18:35:31 +00001492 e = e->next;
1493 }
1494 }
1495}
1496
Bart De Schuymercc440052002-11-06 21:10:33 +00001497static int parse_delete_rule(const char *argv, int *rule_nr, int *rule_nr_end)
1498{
1499 char *colon = strchr(argv, ':'), *buffer;
1500
1501 if (colon) {
1502 *colon = '\0';
1503 if (*(colon + 1) == '\0')
1504 *rule_nr_end = -1;
1505 else {
1506 *rule_nr_end = strtol(colon + 1, &buffer, 10);
1507 if (*buffer != '\0' || *rule_nr_end < 0)
1508 return -1;
1509 }
1510 }
1511 if (colon == argv)
1512 *rule_nr = 1;
1513 else {
1514 *rule_nr = strtol(argv, &buffer, 10);
1515 if (*buffer != '\0' || *rule_nr < 0)
1516 return -1;
1517 }
1518 if (!colon)
1519 *rule_nr_end = *rule_nr;
1520 if (*rule_nr_end != -1 && *rule_nr > *rule_nr_end)
1521 return -1;
1522 return 0;
1523}
1524
Bart De Schuymera615b962002-11-03 14:54:09 +00001525static int invert = 0;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001526int check_inverse(const char option[])
1527{
1528 if (strcmp(option, "!") == 0) {
Bart De Schuymera615b962002-11-03 14:54:09 +00001529 if (invert == 1)
1530 print_error("double use of '!' not allowed");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001531 optind++;
Bart De Schuymera615b962002-11-03 14:54:09 +00001532 invert = 1;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001533 return 1;
1534 }
Bart De Schuymera615b962002-11-03 14:54:09 +00001535 return invert;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001536}
1537
1538void check_option(unsigned int *flags, unsigned int mask)
1539{
1540 if (*flags & mask)
1541 print_error("Multiple use of same option not allowed");
1542 *flags |= mask;
1543}
1544
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001545static void get_kernel_table(const char *modprobe)
1546{
1547 if ( !(table = find_table(replace.name)) )
1548 print_error("Bad table name");
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001549 /*
1550 * get the kernel's information
1551 */
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001552 if (get_table(&replace)) {
1553 ebtables_insmod("ebtables", modprobe);
1554 if (get_table(&replace))
1555 print_error("The kernel doesn't support the ebtables "
1556 "%s table", replace.name);
1557 }
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001558 /*
Bart De Schuymer5885b362002-12-03 20:51:36 +00001559 * when listing a table contained in a file, we don't demand that
1560 * the user knows the table's name
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001561 */
Bart De Schuymer62a7fdb2002-08-24 21:01:21 +00001562 if ( !(table = find_table(replace.name)) )
1563 print_error("Bad table name");
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001564}
1565
Bart De Schuymerc5075142002-08-18 14:21:19 +00001566#define print_if_l_error print_error("Interface name length must be less " \
1567 "than %d", IFNAMSIZ)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001568#define OPT_COMMAND 0x01
1569#define OPT_TABLE 0x02
1570#define OPT_IN 0x04
1571#define OPT_OUT 0x08
1572#define OPT_JUMP 0x10
1573#define OPT_PROTOCOL 0x20
1574#define OPT_SOURCE 0x40
1575#define OPT_DEST 0x80
1576#define OPT_ZERO 0x100
1577#define OPT_LOGICALIN 0x200
1578#define OPT_LOGICALOUT 0x400
Bart De Schuymer5885b362002-12-03 20:51:36 +00001579/* the main thing */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001580int main(int argc, char *argv[])
1581{
Bart De Schuymer923a5732002-08-11 12:01:33 +00001582 char *buffer;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001583 int c, i;
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001584 /*
1585 * this special one for the -Z option (we can have -Z <this> -L <that>)
1586 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001587 int zerochain = -1;
Bart De Schuymerf8f8f292002-06-25 15:43:57 +00001588 int policy = 0;
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001589 int rule_nr = -1; /* used for -[D,I] */
1590 int rule_nr_end = -1; /* used for -I */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001591 struct ebt_u_target *t;
1592 struct ebt_u_match *m;
1593 struct ebt_u_watcher *w;
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001594 struct ebt_u_match_list *m_l;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001595 struct ebt_u_watcher_list *w_l;
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001596 struct ebt_u_entries *entries;
Bart De Schuymerc8531032002-06-14 21:55:29 +00001597 const char *modprobe = NULL;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001598
Bart De Schuymera615b962002-11-03 14:54:09 +00001599 opterr = 0;
1600
Bart De Schuymer5885b362002-12-03 20:51:36 +00001601 replace.filename = getenv(ATOMIC_ENV_VARIABLE);
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001602 /*
1603 * initialize the table name, OPT_ flags, selected hook and command
1604 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001605 strcpy(replace.name, "filter");
1606 replace.flags = 0;
1607 replace.selected_hook = -1;
1608 replace.command = 'h';
Bart De Schuymered053432002-07-21 19:35:39 +00001609 replace.counterchanges = NULL;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001610
1611 new_entry = (struct ebt_u_entry *)malloc(sizeof(struct ebt_u_entry));
1612 if (!new_entry)
1613 print_memory();
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001614 /*
1615 * put some sane values in our new entry
1616 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001617 initialize_entry(new_entry);
1618
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001619 /*
1620 * The scenario induced by this loop makes that:
1621 * '-t' ,'-M' and --atomic (if specified) have to come
1622 * before '-A' and the like
1623 */
Bart De Schuymer60332e02002-06-23 08:01:47 +00001624
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001625 /*
1626 * getopt saves the day
1627 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001628 while ((c = getopt_long(argc, argv,
Bart De Schuymeraac31142002-08-11 11:57:52 +00001629 "-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 +00001630 switch (c) {
1631
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001632 case 'A': /* add a rule */
1633 case 'D': /* delete a rule */
1634 case 'P': /* define policy */
1635 case 'I': /* insert a rule */
1636 case 'N': /* make a user defined chain */
1637 case 'E': /* rename chain */
1638 case 'X': /* delete chain */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001639 replace.command = c;
1640 if (replace.flags & OPT_COMMAND)
1641 print_error("Multiple commands not allowed");
1642 replace.flags |= OPT_COMMAND;
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001643 get_kernel_table(modprobe);
1644 if (optarg[0] == '-' || !strcmp(optarg, "!"))
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001645 print_error("No chain name specified");
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001646 if (c == 'N') {
1647 struct ebt_u_chain_list *cl, **cl2;
1648
1649 if (get_hooknr(optarg) != -1)
1650 print_error("Chain %s already exists",
1651 optarg);
1652 if (find_target(optarg))
1653 print_error("Target with name %s exists"
1654 , optarg);
1655 if (strlen(optarg) >= EBT_CHAIN_MAXNAMELEN)
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001656 print_error("Chain name length can't exceed %d",
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001657 EBT_CHAIN_MAXNAMELEN - 1);
1658 cl = (struct ebt_u_chain_list *)
1659 malloc(sizeof(struct ebt_u_chain_list));
1660 if (!cl)
1661 print_memory();
1662 cl->next = NULL;
1663 cl->udc = (struct ebt_u_entries *)
1664 malloc(sizeof(struct ebt_u_entries));
1665 if (!cl->udc)
1666 print_memory();
1667 cl->udc->nentries = 0;
1668 cl->udc->policy = EBT_ACCEPT;
1669 cl->udc->counter_offset = replace.nentries;
1670 cl->udc->hook_mask = 0;
1671 strcpy(cl->udc->name, optarg);
1672 cl->udc->entries = NULL;
1673 cl->kernel_start = NULL;
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001674 /*
1675 * put the new chain at the end
1676 */
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001677 cl2 = &replace.udc;
1678 while (*cl2)
1679 cl2 = &((*cl2)->next);
1680 *cl2 = cl;
1681 break;
1682 }
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001683 if ((replace.selected_hook = get_hooknr(optarg)) == -1)
1684 print_error("Chain %s doesn't exist", optarg);
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001685 if (c == 'E') {
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001686 if (optind >= argc || argv[optind][0] == '-' ||
1687 !strcmp(argv[optind], "!"))
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001688 print_error("No new chain name specified");
1689 if (strlen(argv[optind]) >= EBT_CHAIN_MAXNAMELEN)
1690 print_error("Chain name len can't exceed %d",
1691 EBT_CHAIN_MAXNAMELEN - 1);
1692 if (get_hooknr(argv[optind]) != -1)
1693 print_error("Chain %s already exists",
1694 argv[optind]);
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001695 if (find_target(argv[optind]))
1696 print_error("Target with name %s exists"
1697 , argv[optind]);
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001698 entries = to_chain();
1699 strcpy(entries->name, argv[optind]);
1700 optind++;
1701 break;
1702 }
1703 if (c == 'X') {
1704 struct ebt_u_chain_list *cl, **cl2;
1705
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001706 if (replace.selected_hook < NF_BR_NUMHOOKS)
1707 print_error("You can't remove a standard chain");
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001708 /*
Bart De Schuymerc27432e2003-01-09 22:01:07 +00001709 * if the chain is referenced, don't delete it,
1710 * also decrement jumps to a chain behind the
1711 * one we're deleting
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001712 */
Bart De Schuymerb909f9b2002-06-26 18:35:31 +00001713 check_for_references(replace.selected_hook - NF_BR_NUMHOOKS);
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001714 flush_chains();
1715 entries = to_chain();
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001716 cl2 = &(replace.udc);
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001717 while ((*cl2)->udc != entries)
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001718 cl2 = &((*cl2)->next);
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001719 cl = (*cl2);
1720 (*cl2) = (*cl2)->next;
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001721 free(cl->udc);
1722 free(cl);
1723 break;
1724 }
1725
Bart De Schuymercc440052002-11-06 21:10:33 +00001726 if (c == 'D' && optind < argc &&
1727 argv[optind][0] != '-') {
1728 if (parse_delete_rule(argv[optind],
1729 &rule_nr, &rule_nr_end))
1730 print_error("Problem with the "
1731 "specified rule number(s)");
1732 optind++;
1733 }
1734 if (c == 'I') {
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001735 if (optind >= argc || argv[optind][0] == '-')
1736 print_error("No rulenr for -I"
1737 " specified");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001738 rule_nr = strtol(argv[optind], &buffer, 10);
1739 if (*buffer != '\0' || rule_nr < 0)
1740 print_error("Problem with the "
1741 "specified rule number");
1742 optind++;
1743 }
1744 if (c == 'P') {
1745 if (optind >= argc)
1746 print_error("No policy specified");
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001747 policy = 0;
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001748 for (i = 0; i < NUM_STANDARD_TARGETS; i++)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001749 if (!strcmp(argv[optind],
1750 standard_targets[i])) {
Bart De Schuymer60332e02002-06-23 08:01:47 +00001751 policy = -i -1;
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001752 if (policy == EBT_CONTINUE)
1753 policy = 0;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001754 break;
1755 }
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001756 if (policy == 0)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001757 print_error("Wrong policy");
1758 optind++;
1759 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001760 break;
1761
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001762 case 'L': /* list */
1763 case 'F': /* flush */
1764 case 'Z': /* zero counters */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001765 if (c == 'Z') {
1766 if (replace.flags & OPT_ZERO)
1767 print_error("Multiple commands"
1768 " not allowed");
1769 if ( (replace.flags & OPT_COMMAND &&
1770 replace.command != 'L'))
1771 print_error("command -Z only allowed "
1772 "together with command -L");
1773 replace.flags |= OPT_ZERO;
1774 } else {
1775 replace.command = c;
1776 if (replace.flags & OPT_COMMAND)
1777 print_error("Multiple commands"
1778 " not allowed");
1779 replace.flags |= OPT_COMMAND;
1780 }
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001781 get_kernel_table(modprobe);
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001782 i = -1;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001783 if (optarg) {
1784 if ( (i = get_hooknr(optarg)) == -1 )
1785 print_error("Bad chain");
1786 } else
1787 if (optind < argc && argv[optind][0] != '-') {
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001788 if ((i = get_hooknr(argv[optind])) == -1)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001789 print_error("Bad chain");
1790 optind++;
1791 }
1792 if (i != -1) {
1793 if (c == 'Z')
1794 zerochain = i;
1795 else
1796 replace.selected_hook = i;
1797 }
1798 break;
1799
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001800 case 'V': /* version */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001801 replace.command = 'V';
1802 if (replace.flags & OPT_COMMAND)
1803 print_error("Multiple commands not allowed");
Bart De Schuymerd4586482002-08-11 16:15:55 +00001804 printf(PROGNAME" v"PROGVERSION" ("PROGDATE")\n");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001805 exit(0);
1806
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001807 case 'M': /* modprobe */
Bart De Schuymer60332e02002-06-23 08:01:47 +00001808 if (replace.command != 'h')
1809 print_error("Please put the -M option earlier");
Bart De Schuymerc8531032002-06-14 21:55:29 +00001810 modprobe = optarg;
1811 break;
1812
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001813 case 'h': /* help */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001814 if (replace.flags & OPT_COMMAND)
1815 print_error("Multiple commands not allowed");
1816 replace.command = 'h';
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001817 /*
1818 * All other arguments should be extension names
1819 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001820 while (optind < argc) {
1821 struct ebt_u_match *m;
1822 struct ebt_u_watcher *w;
1823
1824 if ((m = find_match(argv[optind])))
1825 add_match(m);
1826 else if ((w = find_watcher(argv[optind])))
1827 add_watcher(w);
1828 else {
1829 if (!(t = find_target(argv[optind])))
1830 print_error("Extension %s "
1831 "not found", argv[optind]);
1832 if (replace.flags & OPT_JUMP)
1833 print_error("Sorry, you can "
1834 "only see help for one "
1835 "target extension each time");
1836 replace.flags |= OPT_JUMP;
1837 new_entry->t =
1838 (struct ebt_entry_target *)t;
1839 }
1840 optind++;
1841 }
1842 break;
1843
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001844 case 't': /* table */
Bart De Schuymer60332e02002-06-23 08:01:47 +00001845 if (replace.command != 'h')
1846 print_error("Please put the -t option first");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001847 check_option(&replace.flags, OPT_TABLE);
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001848 if (strlen(optarg) > EBT_TABLE_MAXNAMELEN - 1)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001849 print_error("Table name too long");
1850 strcpy(replace.name, optarg);
1851 break;
1852
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001853 case 'i': /* input interface */
1854 case 2 : /* logical input interface */
1855 case 'o': /* output interface */
1856 case 3 : /* logical output interface */
1857 case 'j': /* target */
1858 case 'p': /* net family protocol */
1859 case 's': /* source mac */
1860 case 'd': /* destination mac */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001861 if ((replace.flags & OPT_COMMAND) == 0)
1862 print_error("No command specified");
1863 if ( replace.command != 'A' &&
1864 replace.command != 'D' && replace.command != 'I')
1865 print_error("Command and option do not match");
1866 if (c == 'i') {
1867 check_option(&replace.flags, OPT_IN);
1868 if (replace.selected_hook > 2 &&
1869 replace.selected_hook < NF_BR_BROUTING)
1870 print_error("Use in-interface only in "
1871 "INPUT, FORWARD, PREROUTING and"
1872 "BROUTING chains");
1873 if (check_inverse(optarg))
1874 new_entry->invflags |= EBT_IIN;
1875
1876 if (optind > argc)
1877 print_error("No in-interface "
1878 "specified");
1879 if (strlen(argv[optind - 1]) >= IFNAMSIZ)
Bart De Schuymerc5075142002-08-18 14:21:19 +00001880 print_if_l_error;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001881 strcpy(new_entry->in, argv[optind - 1]);
1882 break;
1883 }
1884 if (c == 2) {
1885 check_option(&replace.flags, OPT_LOGICALIN);
1886 if (replace.selected_hook > 2 &&
1887 replace.selected_hook < NF_BR_BROUTING)
1888 print_error("Use logical in-interface "
1889 "only in INPUT, FORWARD, "
1890 "PREROUTING and BROUTING chains");
1891 if (check_inverse(optarg))
1892 new_entry->invflags |= EBT_ILOGICALIN;
1893
1894 if (optind > argc)
1895 print_error("No logical in-interface "
1896 "specified");
1897 if (strlen(argv[optind - 1]) >= IFNAMSIZ)
Bart De Schuymerc5075142002-08-18 14:21:19 +00001898 print_if_l_error;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001899 strcpy(new_entry->logical_in, argv[optind - 1]);
1900 break;
1901 }
1902 if (c == 'o') {
1903 check_option(&replace.flags, OPT_OUT);
1904 if (replace.selected_hook < 2)
1905 print_error("Use out-interface only"
1906 " in OUTPUT, FORWARD and "
1907 "POSTROUTING chains");
1908 if (check_inverse(optarg))
1909 new_entry->invflags |= EBT_IOUT;
1910
1911 if (optind > argc)
1912 print_error("No out-interface "
1913 "specified");
1914
1915 if (strlen(argv[optind - 1]) >= IFNAMSIZ)
Bart De Schuymerc5075142002-08-18 14:21:19 +00001916 print_if_l_error;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001917 strcpy(new_entry->out, argv[optind - 1]);
1918 break;
1919 }
1920 if (c == 3) {
1921 check_option(&replace.flags, OPT_LOGICALOUT);
1922 if (replace.selected_hook < 2)
1923 print_error("Use logical out-interface "
1924 "only in OUTPUT, FORWARD and "
1925 "POSTROUTING chains");
1926 if (check_inverse(optarg))
1927 new_entry->invflags |= EBT_ILOGICALOUT;
1928
1929 if (optind > argc)
1930 print_error("No logical out-interface "
1931 "specified");
1932
1933 if (strlen(argv[optind - 1]) >= IFNAMSIZ)
Bart De Schuymerc5075142002-08-18 14:21:19 +00001934 print_if_l_error;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001935 strcpy(new_entry->logical_out,
1936 argv[optind - 1]);
1937 break;
1938 }
1939 if (c == 'j') {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001940 check_option(&replace.flags, OPT_JUMP);
1941 for (i = 0; i < NUM_STANDARD_TARGETS; i++)
1942 if (!strcmp(optarg,
1943 standard_targets[i])) {
1944 t = find_target(
1945 EBT_STANDARD_TARGET);
1946 ((struct ebt_standard_target *)
Bart De Schuymer60332e02002-06-23 08:01:47 +00001947 t->t)->verdict = -i - 1;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001948 break;
1949 }
Bart De Schuymer60332e02002-06-23 08:01:47 +00001950 if (-i - 1 == EBT_RETURN) {
1951 if (replace.selected_hook < NF_BR_NUMHOOKS)
1952 print_error("Return target"
1953 " only for user defined chains");
1954 }
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +00001955 if (i != NUM_STANDARD_TARGETS)
1956 break;
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001957 if ((i = get_hooknr(optarg)) != -1) {
1958 if (i < NF_BR_NUMHOOKS)
1959 print_error("don't jump"
1960 " to a standard chain");
1961 t = find_target(
1962 EBT_STANDARD_TARGET);
1963 ((struct ebt_standard_target *)
1964 t->t)->verdict = i - NF_BR_NUMHOOKS;
1965 break;
1966 }
1967 else {
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001968 /*
1969 * must be an extension then
1970 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001971 struct ebt_u_target *t;
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001972
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001973 t = find_target(optarg);
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001974 /*
1975 * -j standard not allowed either
1976 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001977 if (!t || t ==
1978 (struct ebt_u_target *)new_entry->t)
1979 print_error("Illegal target "
1980 "name");
1981 new_entry->t =
1982 (struct ebt_entry_target *)t;
1983 }
1984 break;
1985 }
1986 if (c == 's') {
1987 check_option(&replace.flags, OPT_SOURCE);
1988 if (check_inverse(optarg))
1989 new_entry->invflags |= EBT_ISOURCE;
1990
1991 if (optind > argc)
1992 print_error("No source mac "
1993 "specified");
1994 if (getmac_and_mask(argv[optind - 1],
1995 new_entry->sourcemac, new_entry->sourcemsk))
1996 print_error("Problem with specified "
1997 "source mac");
1998 new_entry->bitmask |= EBT_SOURCEMAC;
1999 break;
2000 }
2001 if (c == 'd') {
2002 check_option(&replace.flags, OPT_DEST);
2003 if (check_inverse(optarg))
2004 new_entry->invflags |= EBT_IDEST;
2005
2006 if (optind > argc)
2007 print_error("No destination mac "
2008 "specified");
2009 if (getmac_and_mask(argv[optind - 1],
2010 new_entry->destmac, new_entry->destmsk))
2011 print_error("Problem with specified "
2012 "destination mac");
2013 new_entry->bitmask |= EBT_DESTMAC;
2014 break;
2015 }
2016 check_option(&replace.flags, OPT_PROTOCOL);
2017 if (check_inverse(optarg))
2018 new_entry->invflags |= EBT_IPROTO;
2019
2020 if (optind > argc)
2021 print_error("No protocol specified");
2022 new_entry->bitmask &= ~((unsigned int)EBT_NOPROTO);
2023 i = strtol(argv[optind - 1], &buffer, 16);
2024 if (*buffer == '\0' && (i < 0 || i > 0xFFFF))
2025 print_error("Problem with the specified "
2026 "protocol");
2027 new_entry->ethproto = i;
Bart De Schuymer28bf6f62002-06-26 18:57:24 +00002028 if (*buffer != '\0') {
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002029 struct ethertypeent *ent;
2030
2031 if (!strcasecmp(argv[optind - 1], "LENGTH")) {
2032 new_entry->bitmask |= EBT_802_3;
2033 break;
2034 }
2035 ent = getethertypebyname(argv[optind - 1]);
2036 if (!ent)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002037 print_error("Problem with the specified"
2038 " protocol");
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002039 new_entry->ethproto = ent->e_ethertype;
Bart De Schuymer28bf6f62002-06-26 18:57:24 +00002040 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002041 if (new_entry->ethproto < 1536 &&
2042 !(new_entry->bitmask & EBT_802_3))
2043 print_error("Sorry, protocols have values above"
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00002044 " or equal to 0x0600");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002045 break;
2046
Bart De Schuymer9af14f92002-07-10 20:49:10 +00002047 case 4 : // Lc
2048 check_option(&replace.flags, LIST_C);
Bart De Schuymer9af14f92002-07-10 20:49:10 +00002049 if (replace.command != 'L')
2050 print_error("Use --Lc with -L");
2051 if (replace.flags & LIST_X)
2052 print_error("--Lx not compatible with --Lc");
2053 replace.flags |= LIST_C;
2054 break;
2055 case 5 : // Ln
2056 check_option(&replace.flags, LIST_N);
Bart De Schuymer9af14f92002-07-10 20:49:10 +00002057 if (replace.command != 'L')
2058 print_error("Use --Ln with -L");
2059 if (replace.flags & LIST_X)
2060 print_error("--Lx not compatible with --Ln");
2061 replace.flags |= LIST_N;
2062 break;
2063 case 6 : // Lx
2064 check_option(&replace.flags, LIST_X);
Bart De Schuymer9af14f92002-07-10 20:49:10 +00002065 if (replace.command != 'L')
2066 print_error("Use --Lx with -L");
2067 if (replace.flags & LIST_C)
2068 print_error("--Lx not compatible with --Lc");
2069 if (replace.flags & LIST_N)
2070 print_error("--Lx not compatible with --Ln");
2071 replace.flags |= LIST_X;
2072 break;
Bart De Schuymer62423742002-07-14 19:06:20 +00002073 case 8 : // atomic-commit
2074 replace.command = c;
2075 if (replace.flags & OPT_COMMAND)
2076 print_error("Multiple commands not allowed");
2077 replace.flags |= OPT_COMMAND;
Bart De Schuymer5885b362002-12-03 20:51:36 +00002078 if (!replace.filename)
2079 print_error("No atomic file specified");
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002080 /*
2081 * get the information from the file
2082 */
Bart De Schuymer62423742002-07-14 19:06:20 +00002083 get_table(&replace);
Bart De Schuymer868bf642002-07-16 18:14:20 +00002084 if (replace.nentries) {
Bart De Schuymered053432002-07-21 19:35:39 +00002085 replace.counterchanges = (unsigned short *)
Bart De Schuymer868bf642002-07-16 18:14:20 +00002086 malloc(sizeof(unsigned short) * (replace.nentries + 1));
2087 for (i = 0; i < replace.nentries; i++)
Bart De Schuymered053432002-07-21 19:35:39 +00002088 replace.counterchanges[i] = CNT_NORM;
2089 replace.counterchanges[i] = CNT_END;
Bart De Schuymer868bf642002-07-16 18:14:20 +00002090 }
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002091 /*
2092 * we don't want the kernel giving us its counters, they would
2093 * overwrite the counters extracted from the file
2094 */
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00002095 replace.num_counters = 0;
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002096 /*
2097 * make sure the table will be written to the kernel
Bart De Schuymer5885b362002-12-03 20:51:36 +00002098 * possible memory leak here
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002099 */
Bart De Schuymer62423742002-07-14 19:06:20 +00002100 replace.filename = NULL;
Bart De Schuymerc5c3c2d2002-08-16 19:48:03 +00002101 ebtables_insmod("ebtables", modprobe);
Bart De Schuymer62423742002-07-14 19:06:20 +00002102 break;
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002103 case 7 : /* atomic-init */
2104 case 10: /* atomic-save */
2105 case 11: /* init-table */
Bart De Schuymer62423742002-07-14 19:06:20 +00002106 replace.command = c;
2107 if (replace.flags & OPT_COMMAND)
2108 print_error("Multiple commands not allowed");
Bart De Schuymer5885b362002-12-03 20:51:36 +00002109 if (c != 11 && !replace.filename)
2110 print_error("No atomic file specified");
Bart De Schuymer62423742002-07-14 19:06:20 +00002111 replace.flags |= OPT_COMMAND;
Bart De Schuymer5885b362002-12-03 20:51:36 +00002112 {
2113 char *tmp = replace.filename;
2114
2115 tmp = replace.filename;
2116 /* get the kernel table */
2117 replace.filename = NULL;
2118 get_kernel_table(modprobe);
2119 replace.filename = tmp;
2120 }
Bart De Schuymera8d920b2002-07-16 18:30:44 +00002121 if (replace.nentries) {
Bart De Schuymered053432002-07-21 19:35:39 +00002122 replace.counterchanges = (unsigned short *)
Bart De Schuymer5f16dc72002-07-16 18:08:36 +00002123 malloc(sizeof(unsigned short) * (replace.nentries + 1));
2124 for (i = 0; i < replace.nentries; i++)
Bart De Schuymered053432002-07-21 19:35:39 +00002125 replace.counterchanges[i] = CNT_NORM;
2126 replace.counterchanges[i] = CNT_END;
Bart De Schuymer5f16dc72002-07-16 18:08:36 +00002127 }
Bart De Schuymer5885b362002-12-03 20:51:36 +00002128 break;
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002129 case 9 : /* atomic */
Bart De Schuymer5885b362002-12-03 20:51:36 +00002130 if (replace.flags & OPT_COMMAND)
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00002131 print_error("--atomic has to come before"
2132 " the command");
Bart De Schuymer5885b362002-12-03 20:51:36 +00002133 /* another possible memory leak here */
Bart De Schuymer62423742002-07-14 19:06:20 +00002134 replace.filename = (char *)malloc(strlen(optarg) + 1);
2135 strcpy(replace.filename, optarg);
2136 break;
Bart De Schuymera615b962002-11-03 14:54:09 +00002137 case 1 :
2138 if (!strcmp(optarg, "!"))
2139 check_inverse(optarg);
2140 else
2141 print_error("Bad argument : %s", optarg);
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002142 /*
2143 * check_inverse() did optind++
2144 */
Bart De Schuymera615b962002-11-03 14:54:09 +00002145 optind--;
2146 continue;
Bart De Schuymer9af14f92002-07-10 20:49:10 +00002147 default:
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002148 /*
2149 * is it a target option?
2150 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002151 t = (struct ebt_u_target *)new_entry->t;
2152 if ((t->parse(c - t->option_offset, argv, argc,
2153 new_entry, &t->flags, &t->t)))
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00002154 goto check_extension;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002155
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002156 /*
2157 * is it a match_option?
2158 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002159 for (m = matches; m; m = m->next)
2160 if (m->parse(c - m->option_offset, argv,
2161 argc, new_entry, &m->flags, &m->m))
2162 break;
2163
2164 if (m != NULL) {
2165 if (m->used == 0)
2166 add_match(m);
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00002167 goto check_extension;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002168 }
2169
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002170 /*
2171 * is it a watcher option?
2172 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002173 for (w = watchers; w; w = w->next)
2174 if (w->parse(c-w->option_offset, argv,
2175 argc, new_entry, &w->flags, &w->w))
2176 break;
2177
2178 if (w == NULL)
2179 print_error("Unknown argument");
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00002180 if (w->used == 0)
2181 add_watcher(w);
2182check_extension:
Bart De Schuymer60332e02002-06-23 08:01:47 +00002183 if (replace.command != 'A' && replace.command != 'I' &&
2184 replace.command != 'D')
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00002185 print_error("Extensions only for -A, -I and -D");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002186 }
Bart De Schuymera615b962002-11-03 14:54:09 +00002187 invert = 0;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002188 }
2189
Bart De Schuymer25c741d2002-06-23 18:54:34 +00002190 if ( !table && !(table = find_table(replace.name)) )
2191 print_error("Bad table name");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002192
2193 if ( (replace.flags & OPT_COMMAND) && replace.command != 'L' &&
2194 replace.flags & OPT_ZERO )
2195 print_error("Command -Z only allowed together with command -L");
2196
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002197 /*
2198 * do this after parsing everything, so we can print specific info
2199 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002200 if (replace.command == 'h' && !(replace.flags & OPT_ZERO))
2201 print_help();
2202
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002203 /*
2204 * do the final checks
2205 */
Bart De Schuymer60332e02002-06-23 08:01:47 +00002206 if (replace.command == 'A' || replace.command == 'I' ||
2207 replace.command == 'D') {
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002208 /*
2209 * this will put the hook_mask right for the chains
2210 */
Bart De Schuymer60332e02002-06-23 08:01:47 +00002211 check_for_loops();
2212 entries = to_chain();
2213 m_l = new_entry->m_list;
2214 w_l = new_entry->w_list;
2215 t = (struct ebt_u_target *)new_entry->t;
2216 while (m_l) {
2217 m = (struct ebt_u_match *)(m_l->m);
2218 m->final_check(new_entry, m->m, replace.name,
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +00002219 entries->hook_mask, 0);
Bart De Schuymer60332e02002-06-23 08:01:47 +00002220 m_l = m_l->next;
2221 }
2222 while (w_l) {
2223 w = (struct ebt_u_watcher *)(w_l->w);
2224 w->final_check(new_entry, w->w, replace.name,
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +00002225 entries->hook_mask, 0);
Bart De Schuymer60332e02002-06-23 08:01:47 +00002226 w_l = w_l->next;
2227 }
2228 t->final_check(new_entry, t->t, replace.name,
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +00002229 entries->hook_mask, 0);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002230 }
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002231 /*
2232 * so, the extensions can work with the host endian
2233 * the kernel does not have to do this ofcourse
2234 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002235 new_entry->ethproto = htons(new_entry->ethproto);
2236
Bart De Schuymerc34f4672002-08-18 18:03:52 +00002237 if (replace.command == 'P') {
2238 if (replace.selected_hook < NF_BR_NUMHOOKS &&
2239 policy == EBT_RETURN)
2240 print_error("Policy RETURN only allowed for user "
2241 "defined chains");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002242 change_policy(policy);
Bart De Schuymerc34f4672002-08-18 18:03:52 +00002243 } else if (replace.command == 'L') {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002244 list_rules();
2245 if (replace.flags & OPT_ZERO)
2246 zero_counters(zerochain);
2247 else
2248 exit(0);
2249 }
2250 if (replace.flags & OPT_ZERO)
2251 zero_counters(zerochain);
Bart De Schuymer1ab41562002-06-23 17:09:54 +00002252 else if (replace.command == 'F') {
2253 if (flush_chains() == -1)
2254 exit(0);
2255 } else if (replace.command == 'A' || replace.command == 'I') {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002256 add_rule(rule_nr);
Bart De Schuymer1ab41562002-06-23 17:09:54 +00002257 check_for_loops();
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002258 /*
2259 * do the final_check(), for all entries
2260 * needed when adding a rule that has a chain target
2261 */
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +00002262 i = -1;
2263 while (1) {
2264 struct ebt_u_entry *e;
2265
2266 i++;
2267 entries = nr_to_chain(i);
2268 if (!entries) {
2269 if (i < NF_BR_NUMHOOKS)
2270 continue;
2271 else
2272 break;
2273 }
2274 e = entries->entries;
2275 while (e) {
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002276 /*
2277 * userspace extensions use host endian
2278 */
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +00002279 e->ethproto = ntohs(e->ethproto);
2280 do_final_checks(e, entries);
2281 e->ethproto = htons(e->ethproto);
2282 e = e->next;
2283 }
2284 }
Bart De Schuymercc440052002-11-06 21:10:33 +00002285 } else if (replace.command == 'D') {
2286 if (rule_nr != -1 && rule_nr_end == -1)
2287 rule_nr_end = entries->nentries;
2288 delete_rule(rule_nr, rule_nr_end);
2289 }
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002290 /*
2291 * commands -N, -E, -X, --atomic-commit, --atomic-commit, --atomic-save,
2292 * --init-table fall through
2293 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002294
2295 if (table->check)
2296 table->check(&replace);
2297
2298 deliver_table(&replace);
2299
Bart De Schuymered053432002-07-21 19:35:39 +00002300 if (replace.counterchanges)
2301 deliver_counters(&replace);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002302 return 0;
2303}