blob: 4b513d51c5f50ad1891a79333bcc0b5c951a8607 [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 Schuymerc7bfa272002-11-20 19:40:13 +000051/*
52 * here are the number-name correspondences kept for the Ethernet
53 * frame type field
54 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000055#define PROTOCOLFILE "/etc/ethertypes"
56
Bart De Schuymerc8531032002-06-14 21:55:29 +000057#ifndef PROC_SYS_MODPROBE
58#define PROC_SYS_MODPROBE "/proc/sys/kernel/modprobe"
59#endif
60
Bart De Schuymer60332e02002-06-23 08:01:47 +000061char *hooknames[NF_BR_NUMHOOKS] =
62{
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000063 [NF_BR_PRE_ROUTING]"PREROUTING",
64 [NF_BR_LOCAL_IN]"INPUT",
65 [NF_BR_FORWARD]"FORWARD",
66 [NF_BR_LOCAL_OUT]"OUTPUT",
67 [NF_BR_POST_ROUTING]"POSTROUTING",
68 [NF_BR_BROUTING]"BROUTING"
69};
70
Bart De Schuymerc7bfa272002-11-20 19:40:13 +000071/*
72 * default command line options
73 * do not mess around with the already assigned numbers unless
74 * you know what you are doing
75 */
Bart De Schuymer62423742002-07-14 19:06:20 +000076static struct option ebt_original_options[] =
77{
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000078 { "append" , required_argument, 0, 'A' },
79 { "insert" , required_argument, 0, 'I' },
80 { "delete" , required_argument, 0, 'D' },
81 { "list" , optional_argument, 0, 'L' },
Bart De Schuymer9af14f92002-07-10 20:49:10 +000082 { "Lc" , no_argument , 0, 4 },
83 { "Ln" , no_argument , 0, 5 },
84 { "Lx" , no_argument , 0, 6 },
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000085 { "zero" , optional_argument, 0, 'Z' },
86 { "flush" , optional_argument, 0, 'F' },
87 { "policy" , required_argument, 0, 'P' },
88 { "in-interface" , required_argument, 0, 'i' },
89 { "in-if" , required_argument, 0, 'i' },
90 { "logical-in" , required_argument, 0, 2 },
91 { "logical-out" , required_argument, 0, 3 },
92 { "out-interface" , required_argument, 0, 'o' },
93 { "out-if" , required_argument, 0, 'o' },
94 { "version" , no_argument , 0, 'V' },
95 { "help" , no_argument , 0, 'h' },
96 { "jump" , required_argument, 0, 'j' },
97 { "proto" , required_argument, 0, 'p' },
98 { "protocol" , required_argument, 0, 'p' },
99 { "db" , required_argument, 0, 'b' },
100 { "source" , required_argument, 0, 's' },
101 { "src" , required_argument, 0, 's' },
102 { "destination" , required_argument, 0, 'd' },
103 { "dst" , required_argument, 0, 'd' },
104 { "table" , required_argument, 0, 't' },
Bart De Schuymerc8531032002-06-14 21:55:29 +0000105 { "modprobe" , required_argument, 0, 'M' },
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000106 { "new-chain" , required_argument, 0, 'N' },
107 { "rename-chain" , required_argument, 0, 'E' },
108 { "delete-chain" , required_argument, 0, 'X' },
Bart De Schuymer62423742002-07-14 19:06:20 +0000109 { "atomic-init" , required_argument, 0, 7 },
Bart De Schuymer62423742002-07-14 19:06:20 +0000110 { "atomic-commit" , required_argument, 0, 8 },
111 { "atomic" , required_argument, 0, 9 },
112 { "atomic-save" , required_argument, 0, 10 },
Bart De Schuymer8d1d8942002-07-15 20:09:09 +0000113 { "init-table" , no_argument , 0, 11 },
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000114 { 0 }
115};
116
117static struct option *ebt_options = ebt_original_options;
118
Bart De Schuymer62423742002-07-14 19:06:20 +0000119char* standard_targets[NUM_STANDARD_TARGETS] =
120{
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000121 "ACCEPT",
122 "DROP",
123 "CONTINUE",
Bart De Schuymer60332e02002-06-23 08:01:47 +0000124 "RETURN",
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000125};
126
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000127unsigned char mac_type_unicast[ETH_ALEN] = {0,0,0,0,0,0};
128unsigned char msk_type_unicast[ETH_ALEN] = {1,0,0,0,0,0};
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000129unsigned char mac_type_multicast[ETH_ALEN] = {1,0,0,0,0,0};
130unsigned char msk_type_multicast[ETH_ALEN] = {1,0,0,0,0,0};
131unsigned char mac_type_broadcast[ETH_ALEN] = {255,255,255,255,255,255};
132unsigned char msk_type_broadcast[ETH_ALEN] = {255,255,255,255,255,255};
133
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000134/*
135 * holds all the data
136 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000137static struct ebt_u_replace replace;
138
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000139/*
140 * the chosen table
141 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000142static struct ebt_u_table *table = NULL;
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000143/*
144 * the lists of supported tables, matches, watchers and targets
145 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000146static struct ebt_u_table *tables = NULL;
147static struct ebt_u_match *matches = NULL;
148static struct ebt_u_watcher *watchers = NULL;
149static struct ebt_u_target *targets = NULL;
150
151struct ebt_u_target *find_target(const char *name)
152{
153 struct ebt_u_target *t = targets;
154
155 while(t && strcmp(t->name, name))
156 t = t->next;
157 return t;
158}
159
160struct ebt_u_match *find_match(const char *name)
161{
162 struct ebt_u_match *m = matches;
163
164 while(m && strcmp(m->name, name))
165 m = m->next;
166 return m;
167}
168
169struct ebt_u_watcher *find_watcher(const char *name)
170{
171 struct ebt_u_watcher *w = watchers;
172
173 while(w && strcmp(w->name, name))
174 w = w->next;
175 return w;
176}
177
178struct ebt_u_table *find_table(char *name)
179{
180 struct ebt_u_table *t = tables;
181
182 while (t && strcmp(t->name, name))
183 t = t->next;
184 return t;
185}
186
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000187/*
188 * The pointers in here are special:
189 * The struct ebt_target * pointer is actually a struct ebt_u_target * pointer.
190 * instead of making yet a few other structs, we just do a cast.
191 * We need a struct ebt_u_target pointer because we know the address of the data
192 * they point to won't change. We want to allow that the struct ebt_u_target.t
193 * member can change.
194 * Same holds for the struct ebt_match and struct ebt_watcher pointers
195 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000196struct ebt_u_entry *new_entry;
197
Bart De Schuymer62423742002-07-14 19:06:20 +0000198static void initialize_entry(struct ebt_u_entry *e)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000199{
200 e->bitmask = EBT_NOPROTO;
201 e->invflags = 0;
202 e->ethproto = 0;
203 strcpy(e->in, "");
204 strcpy(e->out, "");
205 strcpy(e->logical_in, "");
206 strcpy(e->logical_out, "");
207 e->m_list = NULL;
208 e->w_list = NULL;
209 // the init function of the standard target should have put the verdict
210 // on CONTINUE
211 e->t = (struct ebt_entry_target *)find_target(EBT_STANDARD_TARGET);
212 if (!e->t)
Bart De Schuymerd4586482002-08-11 16:15:55 +0000213 print_bug("Couldn't load standard target");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000214}
215
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000216/*
217 * this doesn't free e, becoz the calling function might need e->next
218 */
Bart De Schuymer62423742002-07-14 19:06:20 +0000219static void free_u_entry(struct ebt_u_entry *e)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000220{
221 struct ebt_u_match_list *m_l, *m_l2;
222 struct ebt_u_watcher_list *w_l, *w_l2;
223
224 m_l = e->m_list;
225 while (m_l) {
226 m_l2 = m_l->next;
227 free(m_l->m);
228 free(m_l);
229 m_l = m_l2;
230 }
231 w_l = e->w_list;
232 while (w_l) {
233 w_l2 = w_l->next;
234 free(w_l->w);
235 free(w_l);
236 w_l = w_l2;
237 }
238 free(e->t);
239}
240
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000241/*
242 * the user will use the match, so put it in new_entry
243 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000244static void add_match(struct ebt_u_match *m)
245{
246 struct ebt_u_match_list **m_list, *new;
247
248 m->used = 1;
Bart De Schuymerc56a31a2002-07-25 08:16:08 +0000249 for (m_list = &new_entry->m_list; *m_list; m_list = &(*m_list)->next);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000250 new = (struct ebt_u_match_list *)
251 malloc(sizeof(struct ebt_u_match_list));
252 if (!new)
253 print_memory();
254 *m_list = new;
255 new->next = NULL;
256 new->m = (struct ebt_entry_match *)m;
257}
258
259static void add_watcher(struct ebt_u_watcher *w)
260{
261 struct ebt_u_watcher_list **w_list;
262 struct ebt_u_watcher_list *new;
263
264 w->used = 1;
Bart De Schuymerc56a31a2002-07-25 08:16:08 +0000265 for (w_list = &new_entry->w_list; *w_list; w_list = &(*w_list)->next);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000266 new = (struct ebt_u_watcher_list *)
267 malloc(sizeof(struct ebt_u_watcher_list));
268 if (!new)
269 print_memory();
270 *w_list = new;
271 new->next = NULL;
272 new->w = (struct ebt_entry_watcher *)w;
273}
274
275static int global_option_offset = 0;
276#define OPTION_OFFSET 256
277static struct option *
278merge_options(struct option *oldopts, const struct option *newopts,
279 unsigned int *options_offset)
280{
281 unsigned int num_old, num_new, i;
282 struct option *merge;
283
284 if (!newopts || !oldopts || !options_offset)
285 print_bug("merge wrong");
286 for (num_old = 0; oldopts[num_old].name; num_old++);
287 for (num_new = 0; newopts[num_new].name; num_new++);
288
289 global_option_offset += OPTION_OFFSET;
290 *options_offset = global_option_offset;
291
292 merge = malloc(sizeof(struct option) * (num_new + num_old + 1));
293 if (!merge)
294 print_memory();
295 memcpy(merge, oldopts, num_old * sizeof(struct option));
296 for (i = 0; i < num_new; i++) {
297 merge[num_old + i] = newopts[i];
298 merge[num_old + i].val += *options_offset;
299 }
300 memset(merge + num_old + num_new, 0, sizeof(struct option));
301 // only free dynamically allocated stuff
302 if (oldopts != ebt_original_options)
303 free(oldopts);
304
305 return merge;
306}
307
308void register_match(struct ebt_u_match *m)
309{
310 int size = m->size + sizeof(struct ebt_entry_match);
311 struct ebt_u_match **i;
312
313 m->m = (struct ebt_entry_match *)malloc(size);
314 if (!m->m)
315 print_memory();
316 strcpy(m->m->u.name, m->name);
317 m->m->match_size = m->size;
318 ebt_options = merge_options
319 (ebt_options, m->extra_ops, &(m->option_offset));
320 m->init(m->m);
321
322 for (i = &matches; *i; i = &((*i)->next));
323 m->next = NULL;
324 *i = m;
325}
326
327void register_watcher(struct ebt_u_watcher *w)
328{
329 int size = w->size + sizeof(struct ebt_entry_watcher);
330 struct ebt_u_watcher **i;
331
332 w->w = (struct ebt_entry_watcher *)malloc(size);
333 if (!w->w)
334 print_memory();
335 strcpy(w->w->u.name, w->name);
336 w->w->watcher_size = w->size;
337 ebt_options = merge_options
338 (ebt_options, w->extra_ops, &(w->option_offset));
339 w->init(w->w);
340
341 for (i = &watchers; *i; i = &((*i)->next));
342 w->next = NULL;
343 *i = w;
344}
345
346void register_target(struct ebt_u_target *t)
347{
348 int size = t->size + sizeof(struct ebt_entry_target);
349 struct ebt_u_target **i;
350
351 t->t = (struct ebt_entry_target *)malloc(size);
352 if (!t->t)
353 print_memory();
354 strcpy(t->t->u.name, t->name);
355 t->t->target_size = t->size;
356 ebt_options = merge_options
357 (ebt_options, t->extra_ops, &(t->option_offset));
358 t->init(t->t);
Bart De Schuymerc56a31a2002-07-25 08:16:08 +0000359
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000360 for (i = &targets; *i; i = &((*i)->next));
361 t->next = NULL;
362 *i = t;
363}
364
365void register_table(struct ebt_u_table *t)
366{
367 t->next = tables;
368 tables = t;
369}
370
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000371/*
372 * blatently stolen (again) from iptables.c userspace program
373 * find out where the modprobe utility is located
374 */
Bart De Schuymerc8531032002-06-14 21:55:29 +0000375static char *get_modprobe(void)
376{
377 int procfile;
378 char *ret;
379
380 procfile = open(PROC_SYS_MODPROBE, O_RDONLY);
381 if (procfile < 0)
382 return NULL;
383
384 ret = malloc(1024);
385 if (ret) {
386 switch (read(procfile, ret, 1024)) {
387 case -1: goto fail;
388 case 1024: goto fail; /* Partial read. Wierd */
389 }
390 if (ret[strlen(ret)-1]=='\n')
391 ret[strlen(ret)-1]=0;
392 close(procfile);
393 return ret;
394 }
395 fail:
396 free(ret);
397 close(procfile);
398 return NULL;
399}
400
Bart De Schuymerc8531032002-06-14 21:55:29 +0000401int ebtables_insmod(const char *modname, const char *modprobe)
402{
403 char *buf = NULL;
404 char *argv[3];
405
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000406 // If they don't explicitly set it, read out of kernel
Bart De Schuymerc8531032002-06-14 21:55:29 +0000407 if (!modprobe) {
408 buf = get_modprobe();
409 if (!buf)
410 return -1;
411 modprobe = buf;
412 }
413
414 switch (fork()) {
415 case 0:
416 argv[0] = (char *)modprobe;
417 argv[1] = (char *)modname;
418 argv[2] = NULL;
419 execv(argv[0], argv);
420
421 /* not usually reached */
422 exit(0);
423 case -1:
424 return -1;
425
426 default: /* parent */
427 wait(NULL);
428 }
429
430 free(buf);
431 return 0;
432}
433
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000434/*
435 * we use replace.flags, so we can't use the following values:
436 * 0x01 == OPT_COMMAND, 0x02 == OPT_TABLE, 0x100 == OPT_ZERO
437 */
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000438#define LIST_N 0x04
439#define LIST_C 0x08
440#define LIST_X 0x10
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000441/*
442 * helper function for list_rules()
443 */
Bart De Schuymer60332e02002-06-23 08:01:47 +0000444static void list_em(struct ebt_u_entries *entries)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000445{
446 int i, j, space = 0, digits;
447 struct ebt_u_entry *hlp;
448 struct ebt_u_match_list *m_l;
449 struct ebt_u_watcher_list *w_l;
450 struct ebt_u_match *m;
451 struct ebt_u_watcher *w;
452 struct ebt_u_target *t;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000453
Bart De Schuymer60332e02002-06-23 08:01:47 +0000454 hlp = entries->entries;
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000455 if (replace.flags & LIST_X && entries->policy != EBT_ACCEPT) {
456 printf("ebtables -t %s -P %s %s\n", replace.name,
457 entries->name, standard_targets[-entries->policy - 1]);
458 } else if (!(replace.flags & LIST_X)) {
Bart De Schuymerc87c9642002-08-01 15:34:16 +0000459 printf("\nBridge chain: %s, entries: %d, policy: %s\n",
460 entries->name, entries->nentries,
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000461 standard_targets[-entries->policy - 1]);
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000462 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000463
Bart De Schuymer60332e02002-06-23 08:01:47 +0000464 i = entries->nentries;
Bart De Schuymerf8f8f292002-06-25 15:43:57 +0000465 while (i > 9) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000466 space++;
467 i /= 10;
468 }
469
Bart De Schuymer60332e02002-06-23 08:01:47 +0000470 for (i = 0; i < entries->nentries; i++) {
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000471 if (replace.flags & LIST_N) {
472 digits = 0;
473 // A little work to get nice rule numbers.
474 j = i + 1;
475 while (j > 9) {
476 digits++;
477 j /= 10;
478 }
479 for (j = 0; j < space - digits; j++)
480 printf(" ");
481 printf("%d. ", i + 1);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000482 }
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000483 if (replace.flags & LIST_X)
484 printf("ebtables -t %s -A %s ",
485 replace.name, entries->name);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000486
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000487 /*
488 * Don't print anything about the protocol if no protocol was
489 * specified, obviously this means any protocol will do.
490 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000491 if (!(hlp->bitmask & EBT_NOPROTO)) {
Bart De Schuymer60332e02002-06-23 08:01:47 +0000492 printf("-p ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000493 if (hlp->invflags & EBT_IPROTO)
494 printf("! ");
495 if (hlp->bitmask & EBT_802_3)
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000496 printf("Length ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000497 else {
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000498 struct ethertypeent *ent;
499
500 ent = getethertypebynumber(ntohs(hlp->ethproto));
501 if (!ent)
Bart De Schuymer60332e02002-06-23 08:01:47 +0000502 printf("0x%x ", ntohs(hlp->ethproto));
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000503 else
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000504 printf("%s ", ent->e_name);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000505 }
506 }
507 if (hlp->bitmask & EBT_SOURCEMAC) {
508 char hlpmsk[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
509
Bart De Schuymer60332e02002-06-23 08:01:47 +0000510 printf("-s ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000511 if (hlp->invflags & EBT_ISOURCE)
512 printf("! ");
513 if (!memcmp(hlp->sourcemac, mac_type_unicast, 6) &&
514 !memcmp(hlp->sourcemsk, msk_type_unicast, 6)) {
515 printf("Unicast");
516 goto endsrc;
517 }
518 if (!memcmp(hlp->sourcemac, mac_type_multicast, 6) &&
519 !memcmp(hlp->sourcemsk, msk_type_multicast, 6)) {
520 printf("Multicast");
521 goto endsrc;
522 }
523 if (!memcmp(hlp->sourcemac, mac_type_broadcast, 6) &&
524 !memcmp(hlp->sourcemsk, msk_type_broadcast, 6)) {
525 printf("Broadcast");
526 goto endsrc;
527 }
Bart De Schuymer41830412002-06-05 19:41:28 +0000528 printf("%s", ether_ntoa((struct ether_addr *)
529 hlp->sourcemac));
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000530 if (memcmp(hlp->sourcemsk, hlpmsk, 6)) {
531 printf("/");
Bart De Schuymer41830412002-06-05 19:41:28 +0000532 printf("%s", ether_ntoa((struct ether_addr *)
533 hlp->sourcemsk));
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000534 }
535endsrc:
Bart De Schuymer60332e02002-06-23 08:01:47 +0000536 printf(" ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000537 }
538 if (hlp->bitmask & EBT_DESTMAC) {
539 char hlpmsk[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
540
Bart De Schuymer60332e02002-06-23 08:01:47 +0000541 printf("-d ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000542 if (hlp->invflags & EBT_IDEST)
543 printf("! ");
544 if (!memcmp(hlp->destmac, mac_type_unicast, 6) &&
545 !memcmp(hlp->destmsk, msk_type_unicast, 6)) {
546 printf("Unicast");
547 goto enddst;
548 }
549 if (!memcmp(hlp->destmac, mac_type_multicast, 6) &&
550 !memcmp(hlp->destmsk, msk_type_multicast, 6)) {
551 printf("Multicast");
552 goto enddst;
553 }
554 if (!memcmp(hlp->destmac, mac_type_broadcast, 6) &&
555 !memcmp(hlp->destmsk, msk_type_broadcast, 6)) {
556 printf("Broadcast");
557 goto enddst;
558 }
Bart De Schuymer41830412002-06-05 19:41:28 +0000559 printf("%s", ether_ntoa((struct ether_addr *)
560 hlp->destmac));
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000561 if (memcmp(hlp->destmsk, hlpmsk, 6)) {
562 printf("/");
Bart De Schuymer41830412002-06-05 19:41:28 +0000563 printf("%s", ether_ntoa((struct ether_addr *)
564 hlp->destmsk));
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000565 }
566enddst:
Bart De Schuymer60332e02002-06-23 08:01:47 +0000567 printf(" ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000568 }
569 if (hlp->in[0] != '\0') {
Bart De Schuymer60332e02002-06-23 08:01:47 +0000570 printf("-i ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000571 if (hlp->invflags & EBT_IIN)
572 printf("! ");
Bart De Schuymer60332e02002-06-23 08:01:47 +0000573 printf("%s ", hlp->in);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000574 }
575 if (hlp->logical_in[0] != '\0') {
Bart De Schuymer60332e02002-06-23 08:01:47 +0000576 printf("--logical-in ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000577 if (hlp->invflags & EBT_ILOGICALIN)
578 printf("! ");
Bart De Schuymer60332e02002-06-23 08:01:47 +0000579 printf("%s ", hlp->logical_in);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000580 }
581 if (hlp->logical_out[0] != '\0') {
Bart De Schuymer60332e02002-06-23 08:01:47 +0000582 printf("--logical-out ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000583 if (hlp->invflags & EBT_ILOGICALOUT)
584 printf("! ");
Bart De Schuymerb3d8f262002-07-07 14:26:15 +0000585 printf("%s ", hlp->logical_out);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000586 }
587 if (hlp->out[0] != '\0') {
Bart De Schuymer60332e02002-06-23 08:01:47 +0000588 printf("-o ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000589 if (hlp->invflags & EBT_IOUT)
590 printf("! ");
Bart De Schuymerb3d8f262002-07-07 14:26:15 +0000591 printf("%s ", hlp->out);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000592 }
593
594 m_l = hlp->m_list;
595 while (m_l) {
596 m = find_match(m_l->m->u.name);
597 if (!m)
598 print_bug("Match not found");
599 m->print(hlp, m_l->m);
600 m_l = m_l->next;
601 }
602 w_l = hlp->w_list;
603 while (w_l) {
604 w = find_watcher(w_l->w->u.name);
605 if (!w)
606 print_bug("Watcher not found");
607 w->print(hlp, w_l->w);
608 w_l = w_l->next;
609 }
610
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000611 printf("-j ");
612 if (strcmp(hlp->t->u.name, EBT_STANDARD_TARGET))
613 printf("%s ", hlp->t->u.name);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000614 t = find_target(hlp->t->u.name);
615 if (!t)
616 print_bug("Target not found");
617 t->print(hlp, hlp->t);
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000618 if (replace.flags & LIST_C)
Bart De Schuymer73fccca2002-10-17 22:00:23 +0000619 printf(", pcnt = %llu -- bcnt = %llu",
620 replace.counters[entries->counter_offset + i].pcnt,
621 replace.counters[entries->counter_offset + i].bcnt);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000622 printf("\n");
623 hlp = hlp->next;
624 }
625}
626
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000627struct ebt_u_entries *nr_to_chain(int nr)
Bart De Schuymer60332e02002-06-23 08:01:47 +0000628{
629 if (nr == -1)
630 return NULL;
631 if (nr < NF_BR_NUMHOOKS)
632 return replace.hook_entry[nr];
633 else {
634 int i;
635 struct ebt_u_chain_list *cl = replace.udc;
636
637 i = nr - NF_BR_NUMHOOKS;
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000638 while (i > 0 && cl) {
Bart De Schuymer60332e02002-06-23 08:01:47 +0000639 cl = cl->next;
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000640 i--;
641 }
Bart De Schuymer60332e02002-06-23 08:01:47 +0000642 if (cl)
643 return cl->udc;
644 else
645 return NULL;
646 }
647}
648
Bart De Schuymercc440052002-11-06 21:10:33 +0000649static inline struct ebt_u_entries *to_chain()
Bart De Schuymer60332e02002-06-23 08:01:47 +0000650{
651 return nr_to_chain(replace.selected_hook);
652}
653
654struct ebt_u_stack
655{
656 int chain_nr;
657 int n;
658 struct ebt_u_entry *e;
659 struct ebt_u_entries *entries;
660};
661
Bart De Schuymer62423742002-07-14 19:06:20 +0000662static void check_for_loops()
Bart De Schuymer60332e02002-06-23 08:01:47 +0000663{
664 int chain_nr , i, j , k, sp = 0, verdict;
665 struct ebt_u_entries *entries, *entries2;
666 struct ebt_u_stack *stack = NULL;
667 struct ebt_u_entry *e;
668
669 i = -1;
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000670 /*
671 * initialize hook_mask to 0
672 */
Bart De Schuymer60332e02002-06-23 08:01:47 +0000673 while (1) {
674 i++;
675 if (i < NF_BR_NUMHOOKS && !(replace.valid_hooks & (1 << i)))
676 continue;
677 entries = nr_to_chain(i);
678 if (!entries)
679 break;
680 entries->hook_mask = 0;
681 }
682 if (i > NF_BR_NUMHOOKS) {
683 stack = (struct ebt_u_stack *)malloc((i - NF_BR_NUMHOOKS) *
684 sizeof(struct ebt_u_stack));
685 if (!stack)
686 print_memory();
687 }
688
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000689 /*
690 * check for loops, starting from every base chain
691 */
Bart De Schuymer60332e02002-06-23 08:01:47 +0000692 for (i = 0; i < NF_BR_NUMHOOKS; i++) {
693 if (!(replace.valid_hooks & (1 << i)))
694 continue;
695 entries = nr_to_chain(i);
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000696 /*
697 * (1 << NF_BR_NUMHOOKS) implies it's a standard chain
698 * (usefull in the final_check() funtions)
699 */
Bart De Schuymerb26649e2002-07-25 14:51:54 +0000700 entries->hook_mask = (1 << i) | (1 << NF_BR_NUMHOOKS);
Bart De Schuymer60332e02002-06-23 08:01:47 +0000701 chain_nr = i;
702
703 e = entries->entries;
704 for (j = 0; j < entries->nentries; j++) {
705 if (strcmp(e->t->u.name, EBT_STANDARD_TARGET))
706 goto letscontinue;
707 verdict = ((struct ebt_standard_target *)(e->t))->verdict;
708 if (verdict < 0)
709 goto letscontinue;
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000710 entries2 = nr_to_chain(verdict + NF_BR_NUMHOOKS);
Bart De Schuymer60332e02002-06-23 08:01:47 +0000711 entries2->hook_mask |= entries->hook_mask;
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000712 /*
713 * now see if we've been here before
714 */
Bart De Schuymer60332e02002-06-23 08:01:47 +0000715 for (k = 0; k < sp; k++)
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000716 if (stack[k].chain_nr == verdict + NF_BR_NUMHOOKS)
Bart De Schuymer1a0a9c32002-06-24 21:10:16 +0000717 print_error("Loop from chain %s to chain %s",
Bart De Schuymerc56a31a2002-07-25 08:16:08 +0000718 nr_to_chain(chain_nr)->name,
719 nr_to_chain(stack[k].chain_nr)->name);
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000720 /*
721 * jump to the chain, make sure we know how to get back
722 */
Bart De Schuymer60332e02002-06-23 08:01:47 +0000723 stack[sp].chain_nr = chain_nr;
724 stack[sp].n = j;
725 stack[sp].entries = entries;
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000726 stack[sp].e = e;
727 sp++;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000728 j = -1;
729 e = entries2->entries;
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000730 chain_nr = verdict + NF_BR_NUMHOOKS;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000731 entries = entries2;
732 continue;
733letscontinue:
734 e = e->next;
735 }
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000736 /*
737 * we are at the end of a standard chain
738 */
Bart De Schuymer60332e02002-06-23 08:01:47 +0000739 if (sp == 0)
740 continue;
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000741 /*
742 * go back to the chain one level higher
743 */
Bart De Schuymer60332e02002-06-23 08:01:47 +0000744 sp--;
745 j = stack[sp].n;
746 chain_nr = stack[sp].chain_nr;
747 e = stack[sp].e;
748 entries = stack[sp].entries;
749 goto letscontinue;
750 }
751 free(stack);
752 return;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000753}
754
Bart De Schuymerc7bfa272002-11-20 19:40:13 +0000755/*
756 * parse the chain name and return the corresponding nr
757 * returns -1 on failure
758 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000759int get_hooknr(char* arg)
760{
761 int i;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000762 struct ebt_u_chain_list *cl = replace.udc;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000763
Bart De Schuymer60332e02002-06-23 08:01:47 +0000764 for (i = 0; i < NF_BR_NUMHOOKS; i++) {
765 if (!(replace.valid_hooks & (1 << i)))
766 continue;
767 if (!strcmp(arg, replace.hook_entry[i]->name))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000768 return i;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000769 }
770 while(cl) {
771 if (!strcmp(arg, cl->udc->name))
772 return i;
773 i++;
774 cl = cl->next;
775 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000776 return -1;
777}
778
Bart De Schuymer62423742002-07-14 19:06:20 +0000779static void print_help()
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000780{
781 struct ebt_u_match_list *m_l;
782 struct ebt_u_watcher_list *w_l;
783
Bart De Schuymerd4586482002-08-11 16:15:55 +0000784 printf(PROGNAME" v"PROGVERSION" ("PROGDATE")\n"
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000785"Usage:\n"
786"ebtables -[ADI] chain rule-specification [options]\n"
787"ebtables -P chain target\n"
788"ebtables -[LFZ] [chain]\n"
789"ebtables -[b] [y,n]\n"
790"Commands:\n"
Bart De Schuymer23f6dcf2002-08-17 09:14:07 +0000791"--append -A chain : append to chain\n"
792"--delete -D chain : delete matching rule from chain\n"
793"--delete -D chain rulenum : delete rule at position rulenum from chain\n"
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000794"--insert -I chain rulenum : insert rule at position rulenum in chain\n"
Bart De Schuymer23f6dcf2002-08-17 09:14:07 +0000795"--list -L [chain] : list the rules in a chain or in all chains\n"
796"--flush -F [chain] : delete all rules in chain or in all chains\n"
797"--init-table : replace the kernel table with the initial table\n"
798"--zero -Z [chain] : put counters on zero in chain or in all chains\n"
799"--policy -P chain target : change policy on chain to target\n"
800"--new-chain -N chain : create a user defined chain\n"
801"--rename-chain -E old new : rename a chain\n"
802"--delete-chain -X chain : delete a user defined chain\n"
Bart De Schuymer62423742002-07-14 19:06:20 +0000803"--atomic-commit file : update the kernel w/ the table contained in file\n"
804"--atomic-init file : put the initial kernel table into file\n"
805"--atomic-save file : put the current kernel table into file\n"
806"--atomic file : write changes to file instead of kernel\n"
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000807"Options:\n"
808"--proto -p [!] proto : protocol hexadecimal, by name or LENGTH\n"
809"--src -s [!] address[/mask]: source mac address\n"
810"--dst -d [!] address[/mask]: destination mac address\n"
811"--in-if -i [!] name : network input interface name\n"
812"--out-if -o [!] name : network output interface name\n"
813"--logical-in [!] name : logical bridge input interface name\n"
814"--logical-out [!] name : logical bridge output interface name\n"
Bart De Schuymer5cbc8e02002-07-14 21:15:28 +0000815"--modprobe -M program : try to insert modules using this program\n"
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000816"--version -V : print package version\n"
Bart De Schuymerd4586482002-08-11 16:15:55 +0000817"\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) {
1478 j++;
1479 if (strcmp(e->t->u.name, EBT_STANDARD_TARGET)) {
1480 e = e->next;
1481 continue;
1482 }
1483 if (((struct ebt_standard_target *)e->t)->verdict == chain_nr)
1484 print_error("Can't delete the chain, it's referenced "
1485 "in chain %s, rule %d", entries->name, j);
1486 e = e->next;
1487 }
1488 }
1489}
1490
Bart De Schuymercc440052002-11-06 21:10:33 +00001491static int parse_delete_rule(const char *argv, int *rule_nr, int *rule_nr_end)
1492{
1493 char *colon = strchr(argv, ':'), *buffer;
1494
1495 if (colon) {
1496 *colon = '\0';
1497 if (*(colon + 1) == '\0')
1498 *rule_nr_end = -1;
1499 else {
1500 *rule_nr_end = strtol(colon + 1, &buffer, 10);
1501 if (*buffer != '\0' || *rule_nr_end < 0)
1502 return -1;
1503 }
1504 }
1505 if (colon == argv)
1506 *rule_nr = 1;
1507 else {
1508 *rule_nr = strtol(argv, &buffer, 10);
1509 if (*buffer != '\0' || *rule_nr < 0)
1510 return -1;
1511 }
1512 if (!colon)
1513 *rule_nr_end = *rule_nr;
1514 if (*rule_nr_end != -1 && *rule_nr > *rule_nr_end)
1515 return -1;
1516 return 0;
1517}
1518
Bart De Schuymera615b962002-11-03 14:54:09 +00001519static int invert = 0;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001520int check_inverse(const char option[])
1521{
1522 if (strcmp(option, "!") == 0) {
Bart De Schuymera615b962002-11-03 14:54:09 +00001523 if (invert == 1)
1524 print_error("double use of '!' not allowed");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001525 optind++;
Bart De Schuymera615b962002-11-03 14:54:09 +00001526 invert = 1;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001527 return 1;
1528 }
Bart De Schuymera615b962002-11-03 14:54:09 +00001529 return invert;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001530}
1531
1532void check_option(unsigned int *flags, unsigned int mask)
1533{
1534 if (*flags & mask)
1535 print_error("Multiple use of same option not allowed");
1536 *flags |= mask;
1537}
1538
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001539static void get_kernel_table(const char *modprobe)
1540{
1541 if ( !(table = find_table(replace.name)) )
1542 print_error("Bad table name");
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001543 /*
1544 * get the kernel's information
1545 */
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001546 if (get_table(&replace)) {
1547 ebtables_insmod("ebtables", modprobe);
1548 if (get_table(&replace))
1549 print_error("The kernel doesn't support the ebtables "
1550 "%s table", replace.name);
1551 }
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001552 /*
1553 * when listing a table contained in a file, we don't expect the user
1554 * to know what the table's name is
1555 */
Bart De Schuymer62a7fdb2002-08-24 21:01:21 +00001556 if ( !(table = find_table(replace.name)) )
1557 print_error("Bad table name");
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001558}
1559
Bart De Schuymerc5075142002-08-18 14:21:19 +00001560#define print_if_l_error print_error("Interface name length must be less " \
1561 "than %d", IFNAMSIZ)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001562#define OPT_COMMAND 0x01
1563#define OPT_TABLE 0x02
1564#define OPT_IN 0x04
1565#define OPT_OUT 0x08
1566#define OPT_JUMP 0x10
1567#define OPT_PROTOCOL 0x20
1568#define OPT_SOURCE 0x40
1569#define OPT_DEST 0x80
1570#define OPT_ZERO 0x100
1571#define OPT_LOGICALIN 0x200
1572#define OPT_LOGICALOUT 0x400
1573// the main thing
1574int main(int argc, char *argv[])
1575{
Bart De Schuymer923a5732002-08-11 12:01:33 +00001576 char *buffer;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001577 int c, i;
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001578 /*
1579 * this special one for the -Z option (we can have -Z <this> -L <that>)
1580 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001581 int zerochain = -1;
Bart De Schuymerf8f8f292002-06-25 15:43:57 +00001582 int policy = 0;
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001583 int rule_nr = -1; /* used for -[D,I] */
1584 int rule_nr_end = -1; /* used for -I */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001585 struct ebt_u_target *t;
1586 struct ebt_u_match *m;
1587 struct ebt_u_watcher *w;
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001588 struct ebt_u_match_list *m_l;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001589 struct ebt_u_watcher_list *w_l;
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001590 struct ebt_u_entries *entries;
Bart De Schuymerc8531032002-06-14 21:55:29 +00001591 const char *modprobe = NULL;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001592
Bart De Schuymera615b962002-11-03 14:54:09 +00001593 opterr = 0;
1594
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001595 /*
1596 * initialize the table name, OPT_ flags, selected hook and command
1597 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001598 strcpy(replace.name, "filter");
1599 replace.flags = 0;
1600 replace.selected_hook = -1;
1601 replace.command = 'h';
Bart De Schuymer62423742002-07-14 19:06:20 +00001602 replace.filename = NULL;
Bart De Schuymered053432002-07-21 19:35:39 +00001603 replace.counterchanges = NULL;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001604
1605 new_entry = (struct ebt_u_entry *)malloc(sizeof(struct ebt_u_entry));
1606 if (!new_entry)
1607 print_memory();
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001608 /*
1609 * put some sane values in our new entry
1610 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001611 initialize_entry(new_entry);
1612
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001613 /*
1614 * The scenario induced by this loop makes that:
1615 * '-t' ,'-M' and --atomic (if specified) have to come
1616 * before '-A' and the like
1617 */
Bart De Schuymer60332e02002-06-23 08:01:47 +00001618
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001619 /*
1620 * getopt saves the day
1621 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001622 while ((c = getopt_long(argc, argv,
Bart De Schuymeraac31142002-08-11 11:57:52 +00001623 "-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 +00001624 switch (c) {
1625
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001626 case 'A': /* add a rule */
1627 case 'D': /* delete a rule */
1628 case 'P': /* define policy */
1629 case 'I': /* insert a rule */
1630 case 'N': /* make a user defined chain */
1631 case 'E': /* rename chain */
1632 case 'X': /* delete chain */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001633 replace.command = c;
1634 if (replace.flags & OPT_COMMAND)
1635 print_error("Multiple commands not allowed");
1636 replace.flags |= OPT_COMMAND;
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001637 get_kernel_table(modprobe);
1638 if (optarg[0] == '-' || !strcmp(optarg, "!"))
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001639 print_error("No chain name specified");
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001640 if (c == 'N') {
1641 struct ebt_u_chain_list *cl, **cl2;
1642
1643 if (get_hooknr(optarg) != -1)
1644 print_error("Chain %s already exists",
1645 optarg);
1646 if (find_target(optarg))
1647 print_error("Target with name %s exists"
1648 , optarg);
1649 if (strlen(optarg) >= EBT_CHAIN_MAXNAMELEN)
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001650 print_error("Chain name length can't exceed %d",
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001651 EBT_CHAIN_MAXNAMELEN - 1);
1652 cl = (struct ebt_u_chain_list *)
1653 malloc(sizeof(struct ebt_u_chain_list));
1654 if (!cl)
1655 print_memory();
1656 cl->next = NULL;
1657 cl->udc = (struct ebt_u_entries *)
1658 malloc(sizeof(struct ebt_u_entries));
1659 if (!cl->udc)
1660 print_memory();
1661 cl->udc->nentries = 0;
1662 cl->udc->policy = EBT_ACCEPT;
1663 cl->udc->counter_offset = replace.nentries;
1664 cl->udc->hook_mask = 0;
1665 strcpy(cl->udc->name, optarg);
1666 cl->udc->entries = NULL;
1667 cl->kernel_start = NULL;
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001668 /*
1669 * put the new chain at the end
1670 */
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001671 cl2 = &replace.udc;
1672 while (*cl2)
1673 cl2 = &((*cl2)->next);
1674 *cl2 = cl;
1675 break;
1676 }
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001677 if ((replace.selected_hook = get_hooknr(optarg)) == -1)
1678 print_error("Chain %s doesn't exist", optarg);
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001679 if (c == 'E') {
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001680 if (optind >= argc || argv[optind][0] == '-' ||
1681 !strcmp(argv[optind], "!"))
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001682 print_error("No new chain name specified");
1683 if (strlen(argv[optind]) >= EBT_CHAIN_MAXNAMELEN)
1684 print_error("Chain name len can't exceed %d",
1685 EBT_CHAIN_MAXNAMELEN - 1);
1686 if (get_hooknr(argv[optind]) != -1)
1687 print_error("Chain %s already exists",
1688 argv[optind]);
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001689 if (find_target(argv[optind]))
1690 print_error("Target with name %s exists"
1691 , argv[optind]);
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001692 entries = to_chain();
1693 strcpy(entries->name, argv[optind]);
1694 optind++;
1695 break;
1696 }
1697 if (c == 'X') {
1698 struct ebt_u_chain_list *cl, **cl2;
1699
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001700 if (replace.selected_hook < NF_BR_NUMHOOKS)
1701 print_error("You can't remove a standard chain");
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001702 /*
1703 * if the chain is referenced, don't delete it
1704 */
Bart De Schuymerb909f9b2002-06-26 18:35:31 +00001705 check_for_references(replace.selected_hook - NF_BR_NUMHOOKS);
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001706 flush_chains();
1707 entries = to_chain();
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001708 cl2 = &(replace.udc);
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001709 while ((*cl2)->udc != entries)
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001710 cl2 = &((*cl2)->next);
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001711 cl = (*cl2);
1712 (*cl2) = (*cl2)->next;
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001713 free(cl->udc);
1714 free(cl);
1715 break;
1716 }
1717
Bart De Schuymercc440052002-11-06 21:10:33 +00001718 if (c == 'D' && optind < argc &&
1719 argv[optind][0] != '-') {
1720 if (parse_delete_rule(argv[optind],
1721 &rule_nr, &rule_nr_end))
1722 print_error("Problem with the "
1723 "specified rule number(s)");
1724 optind++;
1725 }
1726 if (c == 'I') {
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001727 if (optind >= argc || argv[optind][0] == '-')
1728 print_error("No rulenr for -I"
1729 " specified");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001730 rule_nr = strtol(argv[optind], &buffer, 10);
1731 if (*buffer != '\0' || rule_nr < 0)
1732 print_error("Problem with the "
1733 "specified rule number");
1734 optind++;
1735 }
1736 if (c == 'P') {
1737 if (optind >= argc)
1738 print_error("No policy specified");
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001739 policy = 0;
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001740 for (i = 0; i < NUM_STANDARD_TARGETS; i++)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001741 if (!strcmp(argv[optind],
1742 standard_targets[i])) {
Bart De Schuymer60332e02002-06-23 08:01:47 +00001743 policy = -i -1;
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001744 if (policy == EBT_CONTINUE)
1745 policy = 0;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001746 break;
1747 }
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001748 if (policy == 0)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001749 print_error("Wrong policy");
1750 optind++;
1751 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001752 break;
1753
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001754 case 'L': /* list */
1755 case 'F': /* flush */
1756 case 'Z': /* zero counters */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001757 if (c == 'Z') {
1758 if (replace.flags & OPT_ZERO)
1759 print_error("Multiple commands"
1760 " not allowed");
1761 if ( (replace.flags & OPT_COMMAND &&
1762 replace.command != 'L'))
1763 print_error("command -Z only allowed "
1764 "together with command -L");
1765 replace.flags |= OPT_ZERO;
1766 } else {
1767 replace.command = c;
1768 if (replace.flags & OPT_COMMAND)
1769 print_error("Multiple commands"
1770 " not allowed");
1771 replace.flags |= OPT_COMMAND;
1772 }
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001773 get_kernel_table(modprobe);
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001774 i = -1;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001775 if (optarg) {
1776 if ( (i = get_hooknr(optarg)) == -1 )
1777 print_error("Bad chain");
1778 } else
1779 if (optind < argc && argv[optind][0] != '-') {
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001780 if ((i = get_hooknr(argv[optind])) == -1)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001781 print_error("Bad chain");
1782 optind++;
1783 }
1784 if (i != -1) {
1785 if (c == 'Z')
1786 zerochain = i;
1787 else
1788 replace.selected_hook = i;
1789 }
1790 break;
1791
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001792 case 'V': /* version */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001793 replace.command = 'V';
1794 if (replace.flags & OPT_COMMAND)
1795 print_error("Multiple commands not allowed");
Bart De Schuymerd4586482002-08-11 16:15:55 +00001796 printf(PROGNAME" v"PROGVERSION" ("PROGDATE")\n");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001797 exit(0);
1798
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001799 case 'M': /* modprobe */
Bart De Schuymer60332e02002-06-23 08:01:47 +00001800 if (replace.command != 'h')
1801 print_error("Please put the -M option earlier");
Bart De Schuymerc8531032002-06-14 21:55:29 +00001802 modprobe = optarg;
1803 break;
1804
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001805 case 'h': /* help */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001806 if (replace.flags & OPT_COMMAND)
1807 print_error("Multiple commands not allowed");
1808 replace.command = 'h';
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001809 /*
1810 * All other arguments should be extension names
1811 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001812 while (optind < argc) {
1813 struct ebt_u_match *m;
1814 struct ebt_u_watcher *w;
1815
1816 if ((m = find_match(argv[optind])))
1817 add_match(m);
1818 else if ((w = find_watcher(argv[optind])))
1819 add_watcher(w);
1820 else {
1821 if (!(t = find_target(argv[optind])))
1822 print_error("Extension %s "
1823 "not found", argv[optind]);
1824 if (replace.flags & OPT_JUMP)
1825 print_error("Sorry, you can "
1826 "only see help for one "
1827 "target extension each time");
1828 replace.flags |= OPT_JUMP;
1829 new_entry->t =
1830 (struct ebt_entry_target *)t;
1831 }
1832 optind++;
1833 }
1834 break;
1835
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001836 case 't': /* table */
Bart De Schuymer60332e02002-06-23 08:01:47 +00001837 if (replace.command != 'h')
1838 print_error("Please put the -t option first");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001839 check_option(&replace.flags, OPT_TABLE);
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001840 if (strlen(optarg) > EBT_TABLE_MAXNAMELEN - 1)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001841 print_error("Table name too long");
1842 strcpy(replace.name, optarg);
1843 break;
1844
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001845 case 'i': /* input interface */
1846 case 2 : /* logical input interface */
1847 case 'o': /* output interface */
1848 case 3 : /* logical output interface */
1849 case 'j': /* target */
1850 case 'p': /* net family protocol */
1851 case 's': /* source mac */
1852 case 'd': /* destination mac */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001853 if ((replace.flags & OPT_COMMAND) == 0)
1854 print_error("No command specified");
1855 if ( replace.command != 'A' &&
1856 replace.command != 'D' && replace.command != 'I')
1857 print_error("Command and option do not match");
1858 if (c == 'i') {
1859 check_option(&replace.flags, OPT_IN);
1860 if (replace.selected_hook > 2 &&
1861 replace.selected_hook < NF_BR_BROUTING)
1862 print_error("Use in-interface only in "
1863 "INPUT, FORWARD, PREROUTING and"
1864 "BROUTING chains");
1865 if (check_inverse(optarg))
1866 new_entry->invflags |= EBT_IIN;
1867
1868 if (optind > argc)
1869 print_error("No in-interface "
1870 "specified");
1871 if (strlen(argv[optind - 1]) >= IFNAMSIZ)
Bart De Schuymerc5075142002-08-18 14:21:19 +00001872 print_if_l_error;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001873 strcpy(new_entry->in, argv[optind - 1]);
1874 break;
1875 }
1876 if (c == 2) {
1877 check_option(&replace.flags, OPT_LOGICALIN);
1878 if (replace.selected_hook > 2 &&
1879 replace.selected_hook < NF_BR_BROUTING)
1880 print_error("Use logical in-interface "
1881 "only in INPUT, FORWARD, "
1882 "PREROUTING and BROUTING chains");
1883 if (check_inverse(optarg))
1884 new_entry->invflags |= EBT_ILOGICALIN;
1885
1886 if (optind > argc)
1887 print_error("No logical in-interface "
1888 "specified");
1889 if (strlen(argv[optind - 1]) >= IFNAMSIZ)
Bart De Schuymerc5075142002-08-18 14:21:19 +00001890 print_if_l_error;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001891 strcpy(new_entry->logical_in, argv[optind - 1]);
1892 break;
1893 }
1894 if (c == 'o') {
1895 check_option(&replace.flags, OPT_OUT);
1896 if (replace.selected_hook < 2)
1897 print_error("Use out-interface only"
1898 " in OUTPUT, FORWARD and "
1899 "POSTROUTING chains");
1900 if (check_inverse(optarg))
1901 new_entry->invflags |= EBT_IOUT;
1902
1903 if (optind > argc)
1904 print_error("No out-interface "
1905 "specified");
1906
1907 if (strlen(argv[optind - 1]) >= IFNAMSIZ)
Bart De Schuymerc5075142002-08-18 14:21:19 +00001908 print_if_l_error;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001909 strcpy(new_entry->out, argv[optind - 1]);
1910 break;
1911 }
1912 if (c == 3) {
1913 check_option(&replace.flags, OPT_LOGICALOUT);
1914 if (replace.selected_hook < 2)
1915 print_error("Use logical out-interface "
1916 "only in OUTPUT, FORWARD and "
1917 "POSTROUTING chains");
1918 if (check_inverse(optarg))
1919 new_entry->invflags |= EBT_ILOGICALOUT;
1920
1921 if (optind > argc)
1922 print_error("No logical out-interface "
1923 "specified");
1924
1925 if (strlen(argv[optind - 1]) >= IFNAMSIZ)
Bart De Schuymerc5075142002-08-18 14:21:19 +00001926 print_if_l_error;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001927 strcpy(new_entry->logical_out,
1928 argv[optind - 1]);
1929 break;
1930 }
1931 if (c == 'j') {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001932 check_option(&replace.flags, OPT_JUMP);
1933 for (i = 0; i < NUM_STANDARD_TARGETS; i++)
1934 if (!strcmp(optarg,
1935 standard_targets[i])) {
1936 t = find_target(
1937 EBT_STANDARD_TARGET);
1938 ((struct ebt_standard_target *)
Bart De Schuymer60332e02002-06-23 08:01:47 +00001939 t->t)->verdict = -i - 1;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001940 break;
1941 }
Bart De Schuymer60332e02002-06-23 08:01:47 +00001942 if (-i - 1 == EBT_RETURN) {
1943 if (replace.selected_hook < NF_BR_NUMHOOKS)
1944 print_error("Return target"
1945 " only for user defined chains");
1946 }
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +00001947 if (i != NUM_STANDARD_TARGETS)
1948 break;
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001949 if ((i = get_hooknr(optarg)) != -1) {
1950 if (i < NF_BR_NUMHOOKS)
1951 print_error("don't jump"
1952 " to a standard chain");
1953 t = find_target(
1954 EBT_STANDARD_TARGET);
1955 ((struct ebt_standard_target *)
1956 t->t)->verdict = i - NF_BR_NUMHOOKS;
1957 break;
1958 }
1959 else {
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001960 /*
1961 * must be an extension then
1962 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001963 struct ebt_u_target *t;
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001964
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001965 t = find_target(optarg);
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00001966 /*
1967 * -j standard not allowed either
1968 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001969 if (!t || t ==
1970 (struct ebt_u_target *)new_entry->t)
1971 print_error("Illegal target "
1972 "name");
1973 new_entry->t =
1974 (struct ebt_entry_target *)t;
1975 }
1976 break;
1977 }
1978 if (c == 's') {
1979 check_option(&replace.flags, OPT_SOURCE);
1980 if (check_inverse(optarg))
1981 new_entry->invflags |= EBT_ISOURCE;
1982
1983 if (optind > argc)
1984 print_error("No source mac "
1985 "specified");
1986 if (getmac_and_mask(argv[optind - 1],
1987 new_entry->sourcemac, new_entry->sourcemsk))
1988 print_error("Problem with specified "
1989 "source mac");
1990 new_entry->bitmask |= EBT_SOURCEMAC;
1991 break;
1992 }
1993 if (c == 'd') {
1994 check_option(&replace.flags, OPT_DEST);
1995 if (check_inverse(optarg))
1996 new_entry->invflags |= EBT_IDEST;
1997
1998 if (optind > argc)
1999 print_error("No destination mac "
2000 "specified");
2001 if (getmac_and_mask(argv[optind - 1],
2002 new_entry->destmac, new_entry->destmsk))
2003 print_error("Problem with specified "
2004 "destination mac");
2005 new_entry->bitmask |= EBT_DESTMAC;
2006 break;
2007 }
2008 check_option(&replace.flags, OPT_PROTOCOL);
2009 if (check_inverse(optarg))
2010 new_entry->invflags |= EBT_IPROTO;
2011
2012 if (optind > argc)
2013 print_error("No protocol specified");
2014 new_entry->bitmask &= ~((unsigned int)EBT_NOPROTO);
2015 i = strtol(argv[optind - 1], &buffer, 16);
2016 if (*buffer == '\0' && (i < 0 || i > 0xFFFF))
2017 print_error("Problem with the specified "
2018 "protocol");
2019 new_entry->ethproto = i;
Bart De Schuymer28bf6f62002-06-26 18:57:24 +00002020 if (*buffer != '\0') {
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002021 struct ethertypeent *ent;
2022
2023 if (!strcasecmp(argv[optind - 1], "LENGTH")) {
2024 new_entry->bitmask |= EBT_802_3;
2025 break;
2026 }
2027 ent = getethertypebyname(argv[optind - 1]);
2028 if (!ent)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002029 print_error("Problem with the specified"
2030 " protocol");
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002031 new_entry->ethproto = ent->e_ethertype;
Bart De Schuymer28bf6f62002-06-26 18:57:24 +00002032 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002033 if (new_entry->ethproto < 1536 &&
2034 !(new_entry->bitmask & EBT_802_3))
2035 print_error("Sorry, protocols have values above"
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00002036 " or equal to 0x0600");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002037 break;
2038
Bart De Schuymer9af14f92002-07-10 20:49:10 +00002039 case 4 : // Lc
2040 check_option(&replace.flags, LIST_C);
Bart De Schuymer9af14f92002-07-10 20:49:10 +00002041 if (replace.command != 'L')
2042 print_error("Use --Lc with -L");
2043 if (replace.flags & LIST_X)
2044 print_error("--Lx not compatible with --Lc");
2045 replace.flags |= LIST_C;
2046 break;
2047 case 5 : // Ln
2048 check_option(&replace.flags, LIST_N);
Bart De Schuymer9af14f92002-07-10 20:49:10 +00002049 if (replace.command != 'L')
2050 print_error("Use --Ln with -L");
2051 if (replace.flags & LIST_X)
2052 print_error("--Lx not compatible with --Ln");
2053 replace.flags |= LIST_N;
2054 break;
2055 case 6 : // Lx
2056 check_option(&replace.flags, LIST_X);
Bart De Schuymer9af14f92002-07-10 20:49:10 +00002057 if (replace.command != 'L')
2058 print_error("Use --Lx with -L");
2059 if (replace.flags & LIST_C)
2060 print_error("--Lx not compatible with --Lc");
2061 if (replace.flags & LIST_N)
2062 print_error("--Lx not compatible with --Ln");
2063 replace.flags |= LIST_X;
2064 break;
Bart De Schuymer62423742002-07-14 19:06:20 +00002065 case 8 : // atomic-commit
2066 replace.command = c;
2067 if (replace.flags & OPT_COMMAND)
2068 print_error("Multiple commands not allowed");
2069 replace.flags |= OPT_COMMAND;
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00002070 if (replace.filename)
2071 print_error("--atomic incompatible with "
2072 "command");
Bart De Schuymer62423742002-07-14 19:06:20 +00002073 replace.filename = (char *)malloc(strlen(optarg) + 1);
2074 strcpy(replace.filename, optarg);
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002075 /*
2076 * get the information from the file
2077 */
Bart De Schuymer62423742002-07-14 19:06:20 +00002078 get_table(&replace);
Bart De Schuymer868bf642002-07-16 18:14:20 +00002079 if (replace.nentries) {
Bart De Schuymered053432002-07-21 19:35:39 +00002080 replace.counterchanges = (unsigned short *)
Bart De Schuymer868bf642002-07-16 18:14:20 +00002081 malloc(sizeof(unsigned short) * (replace.nentries + 1));
2082 for (i = 0; i < replace.nentries; i++)
Bart De Schuymered053432002-07-21 19:35:39 +00002083 replace.counterchanges[i] = CNT_NORM;
2084 replace.counterchanges[i] = CNT_END;
Bart De Schuymer868bf642002-07-16 18:14:20 +00002085 }
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002086 /*
2087 * we don't want the kernel giving us its counters, they would
2088 * overwrite the counters extracted from the file
2089 */
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00002090 replace.num_counters = 0;
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002091 /*
2092 * make sure the table will be written to the kernel
2093 */
Bart De Schuymer62423742002-07-14 19:06:20 +00002094 free(replace.filename);
2095 replace.filename = NULL;
Bart De Schuymerc5c3c2d2002-08-16 19:48:03 +00002096 ebtables_insmod("ebtables", modprobe);
Bart De Schuymer62423742002-07-14 19:06:20 +00002097 break;
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002098 case 7 : /* atomic-init */
2099 case 10: /* atomic-save */
2100 case 11: /* init-table */
Bart De Schuymer62423742002-07-14 19:06:20 +00002101 replace.command = c;
2102 if (replace.flags & OPT_COMMAND)
2103 print_error("Multiple commands not allowed");
2104 replace.flags |= OPT_COMMAND;
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00002105 if (replace.filename)
2106 print_error("--atomic incompatible with "
2107 "command");
2108 get_kernel_table(modprobe);
Bart De Schuymera8d920b2002-07-16 18:30:44 +00002109 if (replace.nentries) {
Bart De Schuymered053432002-07-21 19:35:39 +00002110 replace.counterchanges = (unsigned short *)
Bart De Schuymer5f16dc72002-07-16 18:08:36 +00002111 malloc(sizeof(unsigned short) * (replace.nentries + 1));
2112 for (i = 0; i < replace.nentries; i++)
Bart De Schuymered053432002-07-21 19:35:39 +00002113 replace.counterchanges[i] = CNT_NORM;
2114 replace.counterchanges[i] = CNT_END;
Bart De Schuymer5f16dc72002-07-16 18:08:36 +00002115 }
Bart De Schuymer8d1d8942002-07-15 20:09:09 +00002116 if (c == 11)
2117 break;
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002118 case 9 : /* atomic */
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00002119 if (c == 9 && (replace.flags & OPT_COMMAND))
2120 print_error("--atomic has to come before"
2121 " the command");
Bart De Schuymer62423742002-07-14 19:06:20 +00002122 replace.filename = (char *)malloc(strlen(optarg) + 1);
2123 strcpy(replace.filename, optarg);
2124 break;
Bart De Schuymera615b962002-11-03 14:54:09 +00002125 case 1 :
2126 if (!strcmp(optarg, "!"))
2127 check_inverse(optarg);
2128 else
2129 print_error("Bad argument : %s", optarg);
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002130 /*
2131 * check_inverse() did optind++
2132 */
Bart De Schuymera615b962002-11-03 14:54:09 +00002133 optind--;
2134 continue;
Bart De Schuymer9af14f92002-07-10 20:49:10 +00002135 default:
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002136 /*
2137 * is it a target option?
2138 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002139 t = (struct ebt_u_target *)new_entry->t;
2140 if ((t->parse(c - t->option_offset, argv, argc,
2141 new_entry, &t->flags, &t->t)))
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00002142 goto check_extension;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002143
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002144 /*
2145 * is it a match_option?
2146 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002147 for (m = matches; m; m = m->next)
2148 if (m->parse(c - m->option_offset, argv,
2149 argc, new_entry, &m->flags, &m->m))
2150 break;
2151
2152 if (m != NULL) {
2153 if (m->used == 0)
2154 add_match(m);
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00002155 goto check_extension;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002156 }
2157
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002158 /*
2159 * is it a watcher option?
2160 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002161 for (w = watchers; w; w = w->next)
2162 if (w->parse(c-w->option_offset, argv,
2163 argc, new_entry, &w->flags, &w->w))
2164 break;
2165
2166 if (w == NULL)
2167 print_error("Unknown argument");
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00002168 if (w->used == 0)
2169 add_watcher(w);
2170check_extension:
Bart De Schuymer60332e02002-06-23 08:01:47 +00002171 if (replace.command != 'A' && replace.command != 'I' &&
2172 replace.command != 'D')
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00002173 print_error("Extensions only for -A, -I and -D");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002174 }
Bart De Schuymera615b962002-11-03 14:54:09 +00002175 invert = 0;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002176 }
2177
Bart De Schuymer25c741d2002-06-23 18:54:34 +00002178 if ( !table && !(table = find_table(replace.name)) )
2179 print_error("Bad table name");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002180
2181 if ( (replace.flags & OPT_COMMAND) && replace.command != 'L' &&
2182 replace.flags & OPT_ZERO )
2183 print_error("Command -Z only allowed together with command -L");
2184
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002185 /*
2186 * do this after parsing everything, so we can print specific info
2187 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002188 if (replace.command == 'h' && !(replace.flags & OPT_ZERO))
2189 print_help();
2190
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002191 /*
2192 * do the final checks
2193 */
Bart De Schuymer60332e02002-06-23 08:01:47 +00002194 if (replace.command == 'A' || replace.command == 'I' ||
2195 replace.command == 'D') {
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002196 /*
2197 * this will put the hook_mask right for the chains
2198 */
Bart De Schuymer60332e02002-06-23 08:01:47 +00002199 check_for_loops();
2200 entries = to_chain();
2201 m_l = new_entry->m_list;
2202 w_l = new_entry->w_list;
2203 t = (struct ebt_u_target *)new_entry->t;
2204 while (m_l) {
2205 m = (struct ebt_u_match *)(m_l->m);
2206 m->final_check(new_entry, m->m, replace.name,
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +00002207 entries->hook_mask, 0);
Bart De Schuymer60332e02002-06-23 08:01:47 +00002208 m_l = m_l->next;
2209 }
2210 while (w_l) {
2211 w = (struct ebt_u_watcher *)(w_l->w);
2212 w->final_check(new_entry, w->w, replace.name,
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +00002213 entries->hook_mask, 0);
Bart De Schuymer60332e02002-06-23 08:01:47 +00002214 w_l = w_l->next;
2215 }
2216 t->final_check(new_entry, t->t, replace.name,
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +00002217 entries->hook_mask, 0);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002218 }
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002219 /*
2220 * so, the extensions can work with the host endian
2221 * the kernel does not have to do this ofcourse
2222 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002223 new_entry->ethproto = htons(new_entry->ethproto);
2224
Bart De Schuymerc34f4672002-08-18 18:03:52 +00002225 if (replace.command == 'P') {
2226 if (replace.selected_hook < NF_BR_NUMHOOKS &&
2227 policy == EBT_RETURN)
2228 print_error("Policy RETURN only allowed for user "
2229 "defined chains");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002230 change_policy(policy);
Bart De Schuymerc34f4672002-08-18 18:03:52 +00002231 } else if (replace.command == 'L') {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002232 list_rules();
2233 if (replace.flags & OPT_ZERO)
2234 zero_counters(zerochain);
2235 else
2236 exit(0);
2237 }
2238 if (replace.flags & OPT_ZERO)
2239 zero_counters(zerochain);
Bart De Schuymer1ab41562002-06-23 17:09:54 +00002240 else if (replace.command == 'F') {
2241 if (flush_chains() == -1)
2242 exit(0);
2243 } else if (replace.command == 'A' || replace.command == 'I') {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002244 add_rule(rule_nr);
Bart De Schuymer1ab41562002-06-23 17:09:54 +00002245 check_for_loops();
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002246 /*
2247 * do the final_check(), for all entries
2248 * needed when adding a rule that has a chain target
2249 */
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +00002250 i = -1;
2251 while (1) {
2252 struct ebt_u_entry *e;
2253
2254 i++;
2255 entries = nr_to_chain(i);
2256 if (!entries) {
2257 if (i < NF_BR_NUMHOOKS)
2258 continue;
2259 else
2260 break;
2261 }
2262 e = entries->entries;
2263 while (e) {
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002264 /*
2265 * userspace extensions use host endian
2266 */
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +00002267 e->ethproto = ntohs(e->ethproto);
2268 do_final_checks(e, entries);
2269 e->ethproto = htons(e->ethproto);
2270 e = e->next;
2271 }
2272 }
Bart De Schuymercc440052002-11-06 21:10:33 +00002273 } else if (replace.command == 'D') {
2274 if (rule_nr != -1 && rule_nr_end == -1)
2275 rule_nr_end = entries->nentries;
2276 delete_rule(rule_nr, rule_nr_end);
2277 }
Bart De Schuymerc7bfa272002-11-20 19:40:13 +00002278 /*
2279 * commands -N, -E, -X, --atomic-commit, --atomic-commit, --atomic-save,
2280 * --init-table fall through
2281 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002282
2283 if (table->check)
2284 table->check(&replace);
2285
2286 deliver_table(&replace);
2287
Bart De Schuymered053432002-07-21 19:35:39 +00002288 if (replace.counterchanges)
2289 deliver_counters(&replace);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002290 return 0;
2291}