blob: fc0c8c2f5988bada34899832678b480b218e6611 [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>
26#include <errno.h>
27#include <stdio.h>
28#include <stdlib.h>
Bart De Schuymerd4586482002-08-11 16:15:55 +000029#include <stdarg.h>
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000030#include <sys/socket.h>
31#include <sys/types.h>
32#include <linux/netfilter_bridge/ebtables.h>
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000033#include <netinet/in.h>
Bart De Schuymer41830412002-06-05 19:41:28 +000034#include <netinet/ether.h>
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000035#include "include/ebtables_u.h"
Bart De Schuymerc8531032002-06-14 21:55:29 +000036#include <unistd.h>
37#include <fcntl.h>
38#include <sys/wait.h>
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000039
Bart De Schuymerd4586482002-08-11 16:15:55 +000040// Don't use this function, use print_bug()
41void __print_bug(char *file, int line, char *format, ...)
42{
43 va_list l;
44
45 va_start(l, format);
46 printf(PROGNAME" v"PROGVERSION":%s:%d:--BUG--: \n", file, line);
47 vprintf(format, l);
48 printf("\n");
49 va_end(l);
50 exit (-1);
51}
52
Bart De Schuymerc56a31a2002-07-25 08:16:08 +000053// here are the number-name correspondences kept for the Ethernet
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000054// frame type field
55#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
71// default command line options
Bart De Schuymer8d1d8942002-07-15 20:09:09 +000072// do not mess around with the already assigned numbers unless
73// you know what you are doing
Bart De Schuymer62423742002-07-14 19:06:20 +000074static struct option ebt_original_options[] =
75{
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000076 { "append" , required_argument, 0, 'A' },
77 { "insert" , required_argument, 0, 'I' },
78 { "delete" , required_argument, 0, 'D' },
79 { "list" , optional_argument, 0, 'L' },
Bart De Schuymer9af14f92002-07-10 20:49:10 +000080 { "Lc" , no_argument , 0, 4 },
81 { "Ln" , no_argument , 0, 5 },
82 { "Lx" , no_argument , 0, 6 },
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000083 { "zero" , optional_argument, 0, 'Z' },
84 { "flush" , optional_argument, 0, 'F' },
85 { "policy" , required_argument, 0, 'P' },
86 { "in-interface" , required_argument, 0, 'i' },
87 { "in-if" , required_argument, 0, 'i' },
88 { "logical-in" , required_argument, 0, 2 },
89 { "logical-out" , required_argument, 0, 3 },
90 { "out-interface" , required_argument, 0, 'o' },
91 { "out-if" , required_argument, 0, 'o' },
92 { "version" , no_argument , 0, 'V' },
93 { "help" , no_argument , 0, 'h' },
94 { "jump" , required_argument, 0, 'j' },
95 { "proto" , required_argument, 0, 'p' },
96 { "protocol" , required_argument, 0, 'p' },
97 { "db" , required_argument, 0, 'b' },
98 { "source" , required_argument, 0, 's' },
99 { "src" , required_argument, 0, 's' },
100 { "destination" , required_argument, 0, 'd' },
101 { "dst" , required_argument, 0, 'd' },
102 { "table" , required_argument, 0, 't' },
Bart De Schuymerc8531032002-06-14 21:55:29 +0000103 { "modprobe" , required_argument, 0, 'M' },
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000104 { "new-chain" , required_argument, 0, 'N' },
105 { "rename-chain" , required_argument, 0, 'E' },
106 { "delete-chain" , required_argument, 0, 'X' },
Bart De Schuymer62423742002-07-14 19:06:20 +0000107 { "atomic-init" , required_argument, 0, 7 },
Bart De Schuymer62423742002-07-14 19:06:20 +0000108 { "atomic-commit" , required_argument, 0, 8 },
109 { "atomic" , required_argument, 0, 9 },
110 { "atomic-save" , required_argument, 0, 10 },
Bart De Schuymer8d1d8942002-07-15 20:09:09 +0000111 { "init-table" , no_argument , 0, 11 },
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000112 { 0 }
113};
114
115static struct option *ebt_options = ebt_original_options;
116
117// yup, all the possible target names
Bart De Schuymer62423742002-07-14 19:06:20 +0000118char* standard_targets[NUM_STANDARD_TARGETS] =
119{
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000120 "ACCEPT",
121 "DROP",
122 "CONTINUE",
Bart De Schuymer60332e02002-06-23 08:01:47 +0000123 "RETURN",
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000124};
125
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000126unsigned char mac_type_unicast[ETH_ALEN] = {0,0,0,0,0,0};
127unsigned char msk_type_unicast[ETH_ALEN] = {1,0,0,0,0,0};
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000128unsigned char mac_type_multicast[ETH_ALEN] = {1,0,0,0,0,0};
129unsigned char msk_type_multicast[ETH_ALEN] = {1,0,0,0,0,0};
130unsigned char mac_type_broadcast[ETH_ALEN] = {255,255,255,255,255,255};
131unsigned char msk_type_broadcast[ETH_ALEN] = {255,255,255,255,255,255};
132
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000133// holds all the data
134static struct ebt_u_replace replace;
135
136// the chosen table
137static struct ebt_u_table *table = NULL;
138// the lists of supported tables, matches, watchers and targets
139static struct ebt_u_table *tables = NULL;
140static struct ebt_u_match *matches = NULL;
141static struct ebt_u_watcher *watchers = NULL;
142static struct ebt_u_target *targets = NULL;
143
144struct ebt_u_target *find_target(const char *name)
145{
146 struct ebt_u_target *t = targets;
147
148 while(t && strcmp(t->name, name))
149 t = t->next;
150 return t;
151}
152
153struct ebt_u_match *find_match(const char *name)
154{
155 struct ebt_u_match *m = matches;
156
157 while(m && strcmp(m->name, name))
158 m = m->next;
159 return m;
160}
161
162struct ebt_u_watcher *find_watcher(const char *name)
163{
164 struct ebt_u_watcher *w = watchers;
165
166 while(w && strcmp(w->name, name))
167 w = w->next;
168 return w;
169}
170
171struct ebt_u_table *find_table(char *name)
172{
173 struct ebt_u_table *t = tables;
174
175 while (t && strcmp(t->name, name))
176 t = t->next;
177 return t;
178}
179
180// The pointers in here are special:
181// The struct ebt_target * pointer is actually a struct ebt_u_target * pointer.
182// instead of making yet a few other structs, we just do a cast.
183// We need a struct ebt_u_target pointer because we know the address of the data
184// they point to won't change. We want to allow that the struct ebt_u_target.t
185// member can change.
186// Same holds for the struct ebt_match and struct ebt_watcher pointers
187struct ebt_u_entry *new_entry;
188
Bart De Schuymer62423742002-07-14 19:06:20 +0000189static void initialize_entry(struct ebt_u_entry *e)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000190{
191 e->bitmask = EBT_NOPROTO;
192 e->invflags = 0;
193 e->ethproto = 0;
194 strcpy(e->in, "");
195 strcpy(e->out, "");
196 strcpy(e->logical_in, "");
197 strcpy(e->logical_out, "");
198 e->m_list = NULL;
199 e->w_list = NULL;
200 // the init function of the standard target should have put the verdict
201 // on CONTINUE
202 e->t = (struct ebt_entry_target *)find_target(EBT_STANDARD_TARGET);
203 if (!e->t)
Bart De Schuymerd4586482002-08-11 16:15:55 +0000204 print_bug("Couldn't load standard target");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000205}
206
207// this doesn't free e, becoz the calling function might need e->next
Bart De Schuymer62423742002-07-14 19:06:20 +0000208static void free_u_entry(struct ebt_u_entry *e)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000209{
210 struct ebt_u_match_list *m_l, *m_l2;
211 struct ebt_u_watcher_list *w_l, *w_l2;
212
213 m_l = e->m_list;
214 while (m_l) {
215 m_l2 = m_l->next;
216 free(m_l->m);
217 free(m_l);
218 m_l = m_l2;
219 }
220 w_l = e->w_list;
221 while (w_l) {
222 w_l2 = w_l->next;
223 free(w_l->w);
224 free(w_l);
225 w_l = w_l2;
226 }
227 free(e->t);
228}
229
230// the user will use the match, so put it in new_entry
231static void add_match(struct ebt_u_match *m)
232{
233 struct ebt_u_match_list **m_list, *new;
234
235 m->used = 1;
Bart De Schuymerc56a31a2002-07-25 08:16:08 +0000236 for (m_list = &new_entry->m_list; *m_list; m_list = &(*m_list)->next);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000237 new = (struct ebt_u_match_list *)
238 malloc(sizeof(struct ebt_u_match_list));
239 if (!new)
240 print_memory();
241 *m_list = new;
242 new->next = NULL;
243 new->m = (struct ebt_entry_match *)m;
244}
245
246static void add_watcher(struct ebt_u_watcher *w)
247{
248 struct ebt_u_watcher_list **w_list;
249 struct ebt_u_watcher_list *new;
250
251 w->used = 1;
Bart De Schuymerc56a31a2002-07-25 08:16:08 +0000252 for (w_list = &new_entry->w_list; *w_list; w_list = &(*w_list)->next);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000253 new = (struct ebt_u_watcher_list *)
254 malloc(sizeof(struct ebt_u_watcher_list));
255 if (!new)
256 print_memory();
257 *w_list = new;
258 new->next = NULL;
259 new->w = (struct ebt_entry_watcher *)w;
260}
261
262static int global_option_offset = 0;
263#define OPTION_OFFSET 256
264static struct option *
265merge_options(struct option *oldopts, const struct option *newopts,
266 unsigned int *options_offset)
267{
268 unsigned int num_old, num_new, i;
269 struct option *merge;
270
271 if (!newopts || !oldopts || !options_offset)
272 print_bug("merge wrong");
273 for (num_old = 0; oldopts[num_old].name; num_old++);
274 for (num_new = 0; newopts[num_new].name; num_new++);
275
276 global_option_offset += OPTION_OFFSET;
277 *options_offset = global_option_offset;
278
279 merge = malloc(sizeof(struct option) * (num_new + num_old + 1));
280 if (!merge)
281 print_memory();
282 memcpy(merge, oldopts, num_old * sizeof(struct option));
283 for (i = 0; i < num_new; i++) {
284 merge[num_old + i] = newopts[i];
285 merge[num_old + i].val += *options_offset;
286 }
287 memset(merge + num_old + num_new, 0, sizeof(struct option));
288 // only free dynamically allocated stuff
289 if (oldopts != ebt_original_options)
290 free(oldopts);
291
292 return merge;
293}
294
295void register_match(struct ebt_u_match *m)
296{
297 int size = m->size + sizeof(struct ebt_entry_match);
298 struct ebt_u_match **i;
299
300 m->m = (struct ebt_entry_match *)malloc(size);
301 if (!m->m)
302 print_memory();
303 strcpy(m->m->u.name, m->name);
304 m->m->match_size = m->size;
305 ebt_options = merge_options
306 (ebt_options, m->extra_ops, &(m->option_offset));
307 m->init(m->m);
308
309 for (i = &matches; *i; i = &((*i)->next));
310 m->next = NULL;
311 *i = m;
312}
313
314void register_watcher(struct ebt_u_watcher *w)
315{
316 int size = w->size + sizeof(struct ebt_entry_watcher);
317 struct ebt_u_watcher **i;
318
319 w->w = (struct ebt_entry_watcher *)malloc(size);
320 if (!w->w)
321 print_memory();
322 strcpy(w->w->u.name, w->name);
323 w->w->watcher_size = w->size;
324 ebt_options = merge_options
325 (ebt_options, w->extra_ops, &(w->option_offset));
326 w->init(w->w);
327
328 for (i = &watchers; *i; i = &((*i)->next));
329 w->next = NULL;
330 *i = w;
331}
332
333void register_target(struct ebt_u_target *t)
334{
335 int size = t->size + sizeof(struct ebt_entry_target);
336 struct ebt_u_target **i;
337
338 t->t = (struct ebt_entry_target *)malloc(size);
339 if (!t->t)
340 print_memory();
341 strcpy(t->t->u.name, t->name);
342 t->t->target_size = t->size;
343 ebt_options = merge_options
344 (ebt_options, t->extra_ops, &(t->option_offset));
345 t->init(t->t);
Bart De Schuymerc56a31a2002-07-25 08:16:08 +0000346
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000347 for (i = &targets; *i; i = &((*i)->next));
348 t->next = NULL;
349 *i = t;
350}
351
352void register_table(struct ebt_u_table *t)
353{
354 t->next = tables;
355 tables = t;
356}
357
Bart De Schuymerc8531032002-06-14 21:55:29 +0000358// blatently stolen (again) from iptables.c userspace program
359// find out where the modprobe utility is located
360static char *get_modprobe(void)
361{
362 int procfile;
363 char *ret;
364
365 procfile = open(PROC_SYS_MODPROBE, O_RDONLY);
366 if (procfile < 0)
367 return NULL;
368
369 ret = malloc(1024);
370 if (ret) {
371 switch (read(procfile, ret, 1024)) {
372 case -1: goto fail;
373 case 1024: goto fail; /* Partial read. Wierd */
374 }
375 if (ret[strlen(ret)-1]=='\n')
376 ret[strlen(ret)-1]=0;
377 close(procfile);
378 return ret;
379 }
380 fail:
381 free(ret);
382 close(procfile);
383 return NULL;
384}
385
Bart De Schuymerc8531032002-06-14 21:55:29 +0000386int ebtables_insmod(const char *modname, const char *modprobe)
387{
388 char *buf = NULL;
389 char *argv[3];
390
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000391 // If they don't explicitly set it, read out of kernel
Bart De Schuymerc8531032002-06-14 21:55:29 +0000392 if (!modprobe) {
393 buf = get_modprobe();
394 if (!buf)
395 return -1;
396 modprobe = buf;
397 }
398
399 switch (fork()) {
400 case 0:
401 argv[0] = (char *)modprobe;
402 argv[1] = (char *)modname;
403 argv[2] = NULL;
404 execv(argv[0], argv);
405
406 /* not usually reached */
407 exit(0);
408 case -1:
409 return -1;
410
411 default: /* parent */
412 wait(NULL);
413 }
414
415 free(buf);
416 return 0;
417}
418
Bart De Schuymerbbca3202002-06-05 18:55:44 +0000419// helper function: processes a line of data from the file /etc/ethertypes
Bart De Schuymer62423742002-07-14 19:06:20 +0000420static int get_a_line(char *buffer, char *value, FILE *ifp)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000421{
Bart De Schuymerf662ce52002-07-19 18:40:55 +0000422 char line[80], *p;
423 const char delim[] = " \t\n";
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000424
Bart De Schuymerf662ce52002-07-19 18:40:55 +0000425 while (fgets(line, sizeof(line), ifp)) {
426 p = strtok(line, delim);
427 if (!p || p[0] == '#')
428 continue;
429 if (strlen(p) > 20)
430 continue;
431 strcpy(buffer, p);
432 p = strtok(NULL, delim);
433 if (!p || strlen(p) > 10)
434 continue;
435 strcpy(value, p);
436 return 0;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000437 }
Bart De Schuymerf662ce52002-07-19 18:40:55 +0000438 return -1;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000439}
440
Bart De Schuymerb909f9b2002-06-26 18:35:31 +0000441// translate a hexadecimal number to a protocol name, parsing /etc/ethertypes
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000442// returns 0 on success
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000443int number_to_name(unsigned short proto, char *name)
444{
445 FILE *ifp;
Bart De Schuymerf662ce52002-07-19 18:40:55 +0000446 char buffer[21], value[11], *bfr;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000447 unsigned short i;
448
449 if ( !(ifp = fopen(PROTOCOLFILE, "r")) )
450 return -1;
451 while (1) {
452 if (get_a_line(buffer, value, ifp)) {
453 fclose(ifp);
454 return -1;
455 }
456 i = (unsigned short) strtol(value, &bfr, 16);
457 if (*bfr != '\0' || i != proto)
458 continue;
459 strcpy(name, buffer);
460 fclose(ifp);
461 return 0;
462 }
463}
464
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000465// we use replace.flags, so we can't use the following values:
466// 0x01 == OPT_COMMAND, 0x02 == OPT_TABLE, 0x100 == OPT_ZERO
467#define LIST_N 0x04
468#define LIST_C 0x08
469#define LIST_X 0x10
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000470// helper function for list_rules()
Bart De Schuymer60332e02002-06-23 08:01:47 +0000471static void list_em(struct ebt_u_entries *entries)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000472{
473 int i, j, space = 0, digits;
474 struct ebt_u_entry *hlp;
475 struct ebt_u_match_list *m_l;
476 struct ebt_u_watcher_list *w_l;
477 struct ebt_u_match *m;
478 struct ebt_u_watcher *w;
479 struct ebt_u_target *t;
480 char name[21];
481
Bart De Schuymer60332e02002-06-23 08:01:47 +0000482 hlp = entries->entries;
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000483 if (replace.flags & LIST_X && entries->policy != EBT_ACCEPT) {
484 printf("ebtables -t %s -P %s %s\n", replace.name,
485 entries->name, standard_targets[-entries->policy - 1]);
486 } else if (!(replace.flags & LIST_X)) {
Bart De Schuymerc87c9642002-08-01 15:34:16 +0000487 printf("\nBridge chain: %s, entries: %d, policy: %s\n",
488 entries->name, entries->nentries,
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000489 standard_targets[-entries->policy - 1]);
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000490 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000491
Bart De Schuymer60332e02002-06-23 08:01:47 +0000492 i = entries->nentries;
Bart De Schuymerf8f8f292002-06-25 15:43:57 +0000493 while (i > 9) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000494 space++;
495 i /= 10;
496 }
497
Bart De Schuymer60332e02002-06-23 08:01:47 +0000498 for (i = 0; i < entries->nentries; i++) {
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000499 if (replace.flags & LIST_N) {
500 digits = 0;
501 // A little work to get nice rule numbers.
502 j = i + 1;
503 while (j > 9) {
504 digits++;
505 j /= 10;
506 }
507 for (j = 0; j < space - digits; j++)
508 printf(" ");
509 printf("%d. ", i + 1);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000510 }
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000511 if (replace.flags & LIST_X)
512 printf("ebtables -t %s -A %s ",
513 replace.name, entries->name);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000514
515 // Don't print anything about the protocol if no protocol was
516 // specified, obviously this means any protocol will do.
517 if (!(hlp->bitmask & EBT_NOPROTO)) {
Bart De Schuymer60332e02002-06-23 08:01:47 +0000518 printf("-p ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000519 if (hlp->invflags & EBT_IPROTO)
520 printf("! ");
521 if (hlp->bitmask & EBT_802_3)
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000522 printf("Length ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000523 else {
524 if (number_to_name(ntohs(hlp->ethproto), name))
Bart De Schuymer60332e02002-06-23 08:01:47 +0000525 printf("0x%x ", ntohs(hlp->ethproto));
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000526 else
Bart De Schuymer60332e02002-06-23 08:01:47 +0000527 printf("%s ", name);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000528 }
529 }
530 if (hlp->bitmask & EBT_SOURCEMAC) {
531 char hlpmsk[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
532
Bart De Schuymer60332e02002-06-23 08:01:47 +0000533 printf("-s ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000534 if (hlp->invflags & EBT_ISOURCE)
535 printf("! ");
536 if (!memcmp(hlp->sourcemac, mac_type_unicast, 6) &&
537 !memcmp(hlp->sourcemsk, msk_type_unicast, 6)) {
538 printf("Unicast");
539 goto endsrc;
540 }
541 if (!memcmp(hlp->sourcemac, mac_type_multicast, 6) &&
542 !memcmp(hlp->sourcemsk, msk_type_multicast, 6)) {
543 printf("Multicast");
544 goto endsrc;
545 }
546 if (!memcmp(hlp->sourcemac, mac_type_broadcast, 6) &&
547 !memcmp(hlp->sourcemsk, msk_type_broadcast, 6)) {
548 printf("Broadcast");
549 goto endsrc;
550 }
Bart De Schuymer41830412002-06-05 19:41:28 +0000551 printf("%s", ether_ntoa((struct ether_addr *)
552 hlp->sourcemac));
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000553 if (memcmp(hlp->sourcemsk, hlpmsk, 6)) {
554 printf("/");
Bart De Schuymer41830412002-06-05 19:41:28 +0000555 printf("%s", ether_ntoa((struct ether_addr *)
556 hlp->sourcemsk));
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000557 }
558endsrc:
Bart De Schuymer60332e02002-06-23 08:01:47 +0000559 printf(" ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000560 }
561 if (hlp->bitmask & EBT_DESTMAC) {
562 char hlpmsk[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
563
Bart De Schuymer60332e02002-06-23 08:01:47 +0000564 printf("-d ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000565 if (hlp->invflags & EBT_IDEST)
566 printf("! ");
567 if (!memcmp(hlp->destmac, mac_type_unicast, 6) &&
568 !memcmp(hlp->destmsk, msk_type_unicast, 6)) {
569 printf("Unicast");
570 goto enddst;
571 }
572 if (!memcmp(hlp->destmac, mac_type_multicast, 6) &&
573 !memcmp(hlp->destmsk, msk_type_multicast, 6)) {
574 printf("Multicast");
575 goto enddst;
576 }
577 if (!memcmp(hlp->destmac, mac_type_broadcast, 6) &&
578 !memcmp(hlp->destmsk, msk_type_broadcast, 6)) {
579 printf("Broadcast");
580 goto enddst;
581 }
Bart De Schuymer41830412002-06-05 19:41:28 +0000582 printf("%s", ether_ntoa((struct ether_addr *)
583 hlp->destmac));
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000584 if (memcmp(hlp->destmsk, hlpmsk, 6)) {
585 printf("/");
Bart De Schuymer41830412002-06-05 19:41:28 +0000586 printf("%s", ether_ntoa((struct ether_addr *)
587 hlp->destmsk));
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000588 }
589enddst:
Bart De Schuymer60332e02002-06-23 08:01:47 +0000590 printf(" ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000591 }
592 if (hlp->in[0] != '\0') {
Bart De Schuymer60332e02002-06-23 08:01:47 +0000593 printf("-i ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000594 if (hlp->invflags & EBT_IIN)
595 printf("! ");
Bart De Schuymer60332e02002-06-23 08:01:47 +0000596 printf("%s ", hlp->in);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000597 }
598 if (hlp->logical_in[0] != '\0') {
Bart De Schuymer60332e02002-06-23 08:01:47 +0000599 printf("--logical-in ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000600 if (hlp->invflags & EBT_ILOGICALIN)
601 printf("! ");
Bart De Schuymer60332e02002-06-23 08:01:47 +0000602 printf("%s ", hlp->logical_in);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000603 }
604 if (hlp->logical_out[0] != '\0') {
Bart De Schuymer60332e02002-06-23 08:01:47 +0000605 printf("--logical-out ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000606 if (hlp->invflags & EBT_ILOGICALOUT)
607 printf("! ");
Bart De Schuymerb3d8f262002-07-07 14:26:15 +0000608 printf("%s ", hlp->logical_out);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000609 }
610 if (hlp->out[0] != '\0') {
Bart De Schuymer60332e02002-06-23 08:01:47 +0000611 printf("-o ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000612 if (hlp->invflags & EBT_IOUT)
613 printf("! ");
Bart De Schuymerb3d8f262002-07-07 14:26:15 +0000614 printf("%s ", hlp->out);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000615 }
616
617 m_l = hlp->m_list;
618 while (m_l) {
619 m = find_match(m_l->m->u.name);
620 if (!m)
621 print_bug("Match not found");
622 m->print(hlp, m_l->m);
623 m_l = m_l->next;
624 }
625 w_l = hlp->w_list;
626 while (w_l) {
627 w = find_watcher(w_l->w->u.name);
628 if (!w)
629 print_bug("Watcher not found");
630 w->print(hlp, w_l->w);
631 w_l = w_l->next;
632 }
633
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000634 printf("-j ");
635 if (strcmp(hlp->t->u.name, EBT_STANDARD_TARGET))
636 printf("%s ", hlp->t->u.name);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000637 t = find_target(hlp->t->u.name);
638 if (!t)
639 print_bug("Target not found");
640 t->print(hlp, hlp->t);
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000641 if (replace.flags & LIST_C)
642 printf(", count = %llu",
643 replace.counters[entries->counter_offset + i].pcnt);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000644 printf("\n");
645 hlp = hlp->next;
646 }
647}
648
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000649struct ebt_u_entries *nr_to_chain(int nr)
Bart De Schuymer60332e02002-06-23 08:01:47 +0000650{
651 if (nr == -1)
652 return NULL;
653 if (nr < NF_BR_NUMHOOKS)
654 return replace.hook_entry[nr];
655 else {
656 int i;
657 struct ebt_u_chain_list *cl = replace.udc;
658
659 i = nr - NF_BR_NUMHOOKS;
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000660 while (i > 0 && cl) {
Bart De Schuymer60332e02002-06-23 08:01:47 +0000661 cl = cl->next;
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000662 i--;
663 }
Bart De Schuymer60332e02002-06-23 08:01:47 +0000664 if (cl)
665 return cl->udc;
666 else
667 return NULL;
668 }
669}
670
671static struct ebt_u_entries *to_chain()
672{
673 return nr_to_chain(replace.selected_hook);
674}
675
676struct ebt_u_stack
677{
678 int chain_nr;
679 int n;
680 struct ebt_u_entry *e;
681 struct ebt_u_entries *entries;
682};
683
Bart De Schuymer62423742002-07-14 19:06:20 +0000684static void check_for_loops()
Bart De Schuymer60332e02002-06-23 08:01:47 +0000685{
686 int chain_nr , i, j , k, sp = 0, verdict;
687 struct ebt_u_entries *entries, *entries2;
688 struct ebt_u_stack *stack = NULL;
689 struct ebt_u_entry *e;
690
691 i = -1;
692 // initialize hook_mask to 0
693 while (1) {
694 i++;
695 if (i < NF_BR_NUMHOOKS && !(replace.valid_hooks & (1 << i)))
696 continue;
697 entries = nr_to_chain(i);
698 if (!entries)
699 break;
700 entries->hook_mask = 0;
701 }
702 if (i > NF_BR_NUMHOOKS) {
703 stack = (struct ebt_u_stack *)malloc((i - NF_BR_NUMHOOKS) *
704 sizeof(struct ebt_u_stack));
705 if (!stack)
706 print_memory();
707 }
708
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000709 // check for loops, starting from every base chain
Bart De Schuymer60332e02002-06-23 08:01:47 +0000710 for (i = 0; i < NF_BR_NUMHOOKS; i++) {
711 if (!(replace.valid_hooks & (1 << i)))
712 continue;
713 entries = nr_to_chain(i);
Bart De Schuymerb26649e2002-07-25 14:51:54 +0000714 // (1 << NF_BR_NUMHOOKS) implies it's a standard chain
715 // (usefull in the final_check() funtions)
716 entries->hook_mask = (1 << i) | (1 << NF_BR_NUMHOOKS);
Bart De Schuymer60332e02002-06-23 08:01:47 +0000717 chain_nr = i;
718
719 e = entries->entries;
720 for (j = 0; j < entries->nentries; j++) {
721 if (strcmp(e->t->u.name, EBT_STANDARD_TARGET))
722 goto letscontinue;
723 verdict = ((struct ebt_standard_target *)(e->t))->verdict;
724 if (verdict < 0)
725 goto letscontinue;
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000726 entries2 = nr_to_chain(verdict + NF_BR_NUMHOOKS);
Bart De Schuymer60332e02002-06-23 08:01:47 +0000727 entries2->hook_mask |= entries->hook_mask;
728 // now see if we've been here before
729 for (k = 0; k < sp; k++)
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000730 if (stack[k].chain_nr == verdict + NF_BR_NUMHOOKS)
Bart De Schuymer1a0a9c32002-06-24 21:10:16 +0000731 print_error("Loop from chain %s to chain %s",
Bart De Schuymerc56a31a2002-07-25 08:16:08 +0000732 nr_to_chain(chain_nr)->name,
733 nr_to_chain(stack[k].chain_nr)->name);
Bart De Schuymer60332e02002-06-23 08:01:47 +0000734 // jump to the chain, make sure we know how to get back
735 stack[sp].chain_nr = chain_nr;
736 stack[sp].n = j;
737 stack[sp].entries = entries;
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000738 stack[sp].e = e;
739 sp++;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000740 j = -1;
741 e = entries2->entries;
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000742 chain_nr = verdict + NF_BR_NUMHOOKS;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000743 entries = entries2;
744 continue;
745letscontinue:
746 e = e->next;
747 }
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000748 // we are at the end of a standard chain
Bart De Schuymer60332e02002-06-23 08:01:47 +0000749 if (sp == 0)
750 continue;
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000751 // go back to the chain one level higher
Bart De Schuymer60332e02002-06-23 08:01:47 +0000752 sp--;
753 j = stack[sp].n;
754 chain_nr = stack[sp].chain_nr;
755 e = stack[sp].e;
756 entries = stack[sp].entries;
757 goto letscontinue;
758 }
759 free(stack);
760 return;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000761}
762
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000763// parse the chain name and return the corresponding nr
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000764// returns -1 on failure
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000765int get_hooknr(char* arg)
766{
767 int i;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000768 struct ebt_u_chain_list *cl = replace.udc;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000769
Bart De Schuymer60332e02002-06-23 08:01:47 +0000770 for (i = 0; i < NF_BR_NUMHOOKS; i++) {
771 if (!(replace.valid_hooks & (1 << i)))
772 continue;
773 if (!strcmp(arg, replace.hook_entry[i]->name))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000774 return i;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000775 }
776 while(cl) {
777 if (!strcmp(arg, cl->udc->name))
778 return i;
779 i++;
780 cl = cl->next;
781 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000782 return -1;
783}
784
785// yup, print out help
Bart De Schuymer62423742002-07-14 19:06:20 +0000786static void print_help()
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000787{
788 struct ebt_u_match_list *m_l;
789 struct ebt_u_watcher_list *w_l;
790
Bart De Schuymerd4586482002-08-11 16:15:55 +0000791 printf(PROGNAME" v"PROGVERSION" ("PROGDATE")\n"
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000792"Usage:\n"
793"ebtables -[ADI] chain rule-specification [options]\n"
794"ebtables -P chain target\n"
795"ebtables -[LFZ] [chain]\n"
796"ebtables -[b] [y,n]\n"
797"Commands:\n"
798"--append -A chain : Append to chain\n"
799"--delete -D chain : Delete matching rule from chain\n"
800"--delete -D chain rulenum : Delete rule at position rulenum from chain\n"
801"--insert -I chain rulenum : insert rule at position rulenum in chain\n"
802"--list -L [chain] : List the rules in a chain or in all chains\n"
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000803"--flush -F [chain] : Delete all rules in chain or in all chains\n"
Bart De Schuymer8d1d8942002-07-15 20:09:09 +0000804"--init-table : Replace the kernel table with the initial table\n"
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000805"--zero -Z [chain] : Put counters on zero in chain or in all chains\n"
806"--policy -P chain target : Change policy on chain to target\n"
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000807"--new-chain -N chain : Create a user defined chain\n"
808"--rename-chain -E old new : Rename a chain\n"
809"--delete-chain -X chain : Delete a user defined chain\n"
Bart De Schuymer62423742002-07-14 19:06:20 +0000810"--atomic-commit file : update the kernel w/ the table contained in file\n"
811"--atomic-init file : put the initial kernel table into file\n"
812"--atomic-save file : put the current kernel table into file\n"
813"--atomic file : write changes to file instead of kernel\n"
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000814"Options:\n"
815"--proto -p [!] proto : protocol hexadecimal, by name or LENGTH\n"
816"--src -s [!] address[/mask]: source mac address\n"
817"--dst -d [!] address[/mask]: destination mac address\n"
818"--in-if -i [!] name : network input interface name\n"
819"--out-if -o [!] name : network output interface name\n"
820"--logical-in [!] name : logical bridge input interface name\n"
821"--logical-out [!] name : logical bridge output interface name\n"
Bart De Schuymer5cbc8e02002-07-14 21:15:28 +0000822"--modprobe -M program : try to insert modules using this program\n"
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000823"--version -V : print package version\n"
Bart De Schuymerd4586482002-08-11 16:15:55 +0000824"\n");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000825
826 m_l = new_entry->m_list;
827 while (m_l) {
828 ((struct ebt_u_match *)m_l->m)->help();
829 printf("\n");
830 m_l = m_l->next;
831 }
832 w_l = new_entry->w_list;
833 while (w_l) {
834 ((struct ebt_u_watcher *)w_l->w)->help();
835 printf("\n");
836 w_l = w_l->next;
837 }
838 ((struct ebt_u_target *)new_entry->t)->help();
839 printf("\n");
840 if (table->help)
841 table->help(hooknames);
842 exit(0);
843}
844
845// execute command L
846static void list_rules()
847{
848 int i;
849
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000850 if (!(replace.flags & LIST_X))
851 printf("Bridge table: %s\n", table->name);
Bart De Schuymer60332e02002-06-23 08:01:47 +0000852 if (replace.selected_hook != -1) {
853 list_em(to_chain());
854 } else {
855 struct ebt_u_chain_list *cl = replace.udc;
856
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000857 // create new chains and rename standard chains when necessary
858 if (replace.flags & LIST_X) {
859 while (cl) {
860 printf("ebtables -t %s -N %s\n", replace.name,
861 cl->udc->name);
862 cl = cl->next;
863 }
864 cl = replace.udc;
865 for (i = 0; i < NF_BR_NUMHOOKS; i++)
866 if (replace.valid_hooks & (1 << i) &&
867 strcmp(replace.hook_entry[i]->name, hooknames[i]))
868 printf("ebtables -t %s -E %s %s\n",
869 replace.name, hooknames[i],
870 replace.hook_entry[i]->name);
871 }
Bart De Schuymer60332e02002-06-23 08:01:47 +0000872 i = 0;
873 while (1) {
874 if (i < NF_BR_NUMHOOKS) {
875 if (replace.valid_hooks & (1 << i))
876 list_em(replace.hook_entry[i]);
877 i++;
878 continue;
879 } else {
880 if (!cl)
881 break;
882 list_em(cl->udc);
883 cl = cl->next;
884 }
885 }
886 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000887}
888
889// execute command P
890static void change_policy(int policy)
891{
892 int i;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000893 struct ebt_u_entries *entries = to_chain();
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000894
895 // don't do anything if the policy is the same
Bart De Schuymer60332e02002-06-23 08:01:47 +0000896 if (entries->policy != policy) {
897 entries->policy = policy;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000898 replace.num_counters = replace.nentries;
899 if (replace.nentries) {
900 // '+ 1' for the CNT_END
Bart De Schuymered053432002-07-21 19:35:39 +0000901 if (!(replace.counterchanges = (unsigned short *) malloc(
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000902 (replace.nentries + 1) * sizeof(unsigned short))))
903 print_memory();
904 // done nothing special to the rules
905 for (i = 0; i < replace.nentries; i++)
Bart De Schuymered053432002-07-21 19:35:39 +0000906 replace.counterchanges[i] = CNT_NORM;
907 replace.counterchanges[replace.nentries] = CNT_END;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000908 }
909 else
Bart De Schuymered053432002-07-21 19:35:39 +0000910 replace.counterchanges = NULL;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000911 }
912 else
913 exit(0);
914}
915
916// flush one chain or the complete table
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000917// -1 == nothing to do
918// 0 == give back to kernel
919static int flush_chains()
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000920{
Bart De Schuymer60332e02002-06-23 08:01:47 +0000921 int i, j, oldnentries, numdel;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000922 unsigned short *cnt;
923 struct ebt_u_entry *u_e, *tmp;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000924 struct ebt_u_entries *entries = to_chain();
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000925
926 // flush whole table
Bart De Schuymer60332e02002-06-23 08:01:47 +0000927 if (!entries) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000928 if (replace.nentries == 0)
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000929 return -1;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000930 replace.nentries = 0;
931 // no need for the kernel to give us counters back
932 replace.num_counters = 0;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000933
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000934 // free everything and zero (n)entries
Bart De Schuymer60332e02002-06-23 08:01:47 +0000935 i = -1;
936 while (1) {
937 i++;
938 entries = nr_to_chain(i);
939 if (!entries) {
940 if (i < NF_BR_NUMHOOKS)
941 continue;
942 else
943 break;
944 }
945 entries->nentries = 0;
946 entries->counter_offset = 0;
947 u_e = entries->entries;
948 entries->entries = NULL;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000949 while (u_e) {
950 free_u_entry(u_e);
951 tmp = u_e->next;
952 free(u_e);
953 u_e = tmp;
954 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000955 }
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000956 return 0;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000957 }
958
Bart De Schuymer60332e02002-06-23 08:01:47 +0000959 if (entries->nentries == 0)
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000960 return -1;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000961 oldnentries = replace.nentries;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000962 replace.nentries -= entries->nentries;
963 numdel = entries->nentries;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000964
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000965 if (replace.nentries) {
966 // +1 for CNT_END
Bart De Schuymered053432002-07-21 19:35:39 +0000967 if ( !(replace.counterchanges = (unsigned short *)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000968 malloc((oldnentries + 1) * sizeof(unsigned short))) )
969 print_memory();
Bart De Schuymer60332e02002-06-23 08:01:47 +0000970 }
971 // delete the counters belonging to the specified chain,
972 // update counter_offset
973 i = -1;
Bart De Schuymered053432002-07-21 19:35:39 +0000974 cnt = replace.counterchanges;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000975 while (1) {
976 i++;
977 entries = nr_to_chain(i);
978 if (!entries) {
979 if (i < NF_BR_NUMHOOKS)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000980 continue;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000981 else
982 break;
983 }
984 if (i > replace.selected_hook)
985 entries->counter_offset -= numdel;
986 if (replace.nentries) {
987 for (j = 0; j < entries->nentries; j++) {
988 if (i == replace.selected_hook)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000989 *cnt = CNT_DEL;
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000990 else
991 *cnt = CNT_NORM;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000992 cnt++;
993 }
994 }
Bart De Schuymer60332e02002-06-23 08:01:47 +0000995 }
996
997 if (replace.nentries) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000998 *cnt = CNT_END;
999 replace.num_counters = oldnentries;
1000 }
1001 else
1002 replace.num_counters = 0;
1003
Bart De Schuymer60332e02002-06-23 08:01:47 +00001004 entries = to_chain();
1005 entries->nentries = 0;
1006 u_e = entries->entries;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001007 while (u_e) {
1008 free_u_entry(u_e);
1009 tmp = u_e->next;
1010 free(u_e);
1011 u_e = tmp;
1012 }
Bart De Schuymer60332e02002-06-23 08:01:47 +00001013 entries->entries = NULL;
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001014 return 0;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001015}
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001016
1017// -1 == no match
1018static int check_rule_exists(int rule_nr)
1019{
1020 struct ebt_u_entry *u_e;
1021 struct ebt_u_match_list *m_l, *m_l2;
1022 struct ebt_u_match *m;
1023 struct ebt_u_watcher_list *w_l, *w_l2;
1024 struct ebt_u_watcher *w;
1025 struct ebt_u_target *t = (struct ebt_u_target *)new_entry->t;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001026 struct ebt_u_entries *entries = to_chain();
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001027 int i, j, k;
1028
1029 // handle '-D chain rulenr' command
1030 if (rule_nr != -1) {
Bart De Schuymer60332e02002-06-23 08:01:47 +00001031 if (rule_nr > entries->nentries)
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001032 return -1;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001033 // user starts counting from 1
1034 return rule_nr - 1;
1035 }
Bart De Schuymer60332e02002-06-23 08:01:47 +00001036 u_e = entries->entries;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001037 // check for an existing rule (if there are duplicate rules,
1038 // take the first occurance)
Bart De Schuymer60332e02002-06-23 08:01:47 +00001039 for (i = 0; i < entries->nentries; i++, u_e = u_e->next) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001040 if (!u_e)
1041 print_bug("Hmm, trouble");
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001042 if (u_e->ethproto != new_entry->ethproto)
1043 continue;
1044 if (strcmp(u_e->in, new_entry->in))
1045 continue;
1046 if (strcmp(u_e->out, new_entry->out))
1047 continue;
1048 if (strcmp(u_e->logical_in, new_entry->logical_in))
1049 continue;
1050 if (strcmp(u_e->logical_out, new_entry->logical_out))
1051 continue;
1052 if (new_entry->bitmask & EBT_SOURCEMAC &&
1053 memcmp(u_e->sourcemac, new_entry->sourcemac, ETH_ALEN))
1054 continue;
1055 if (new_entry->bitmask & EBT_DESTMAC &&
1056 memcmp(u_e->destmac, new_entry->destmac, ETH_ALEN))
1057 continue;
1058 if (new_entry->bitmask != u_e->bitmask ||
1059 new_entry->invflags != u_e->invflags)
1060 continue;
1061 // compare all matches
1062 m_l = new_entry->m_list;
1063 j = 0;
1064 while (m_l) {
1065 m = (struct ebt_u_match *)(m_l->m);
1066 m_l2 = u_e->m_list;
1067 while (m_l2 && strcmp(m_l2->m->u.name, m->m->u.name))
1068 m_l2 = m_l2->next;
1069 if (!m_l2 || !m->compare(m->m, m_l2->m))
1070 goto letscontinue;
1071 j++;
1072 m_l = m_l->next;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001073 }
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001074 // now be sure they have the same nr of matches
1075 k = 0;
1076 m_l = u_e->m_list;
1077 while (m_l) {
1078 k++;
1079 m_l = m_l->next;
1080 }
1081 if (j != k)
1082 continue;
1083
1084 // compare all watchers
1085 w_l = new_entry->w_list;
1086 j = 0;
1087 while (w_l) {
1088 w = (struct ebt_u_watcher *)(w_l->w);
1089 w_l2 = u_e->w_list;
1090 while (w_l2 && strcmp(w_l2->w->u.name, w->w->u.name))
1091 w_l2 = w_l2->next;
1092 if (!w_l2 || !w->compare(w->w, w_l2->w))
1093 goto letscontinue;
1094 j++;
1095 w_l = w_l->next;
1096 }
1097 k = 0;
1098 w_l = u_e->w_list;
1099 while (w_l) {
1100 k++;
1101 w_l = w_l->next;
1102 }
1103 if (j != k)
1104 continue;
1105 if (strcmp(t->t->u.name, u_e->t->u.name))
1106 continue;
1107 if (!t->compare(t->t, u_e->t))
1108 continue;
1109 return i;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001110letscontinue:
1111 }
1112 return -1;
1113}
1114
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001115// execute command A or I
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001116static void add_rule(int rule_nr)
1117{
1118 int i, j;
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001119 struct ebt_u_entry **u_e;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001120 unsigned short *cnt;
1121 struct ebt_u_match_list *m_l;
1122 struct ebt_u_watcher_list *w_l;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001123 struct ebt_u_entries *entries = to_chain(), *entries2;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001124
1125 if (rule_nr != -1) { // command -I
Bart De Schuymer60332e02002-06-23 08:01:47 +00001126 if (--rule_nr > entries->nentries)
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001127 print_error("rule nr too high: %d > %d", rule_nr + 1,
1128 entries->nentries + 1);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001129 } else
Bart De Schuymer60332e02002-06-23 08:01:47 +00001130 rule_nr = entries->nentries;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001131 // we're adding one rule
1132 replace.num_counters = replace.nentries;
1133 replace.nentries++;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001134 entries->nentries++;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001135
1136 // handle counter stuff
1137 // +1 for CNT_END
Bart De Schuymered053432002-07-21 19:35:39 +00001138 if ( !(replace.counterchanges = (unsigned short *)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001139 malloc((replace.nentries + 1) * sizeof(unsigned short))) )
1140 print_memory();
Bart De Schuymered053432002-07-21 19:35:39 +00001141 cnt = replace.counterchanges;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001142 for (i = 0; i < replace.selected_hook; i++) {
Bart De Schuymer60332e02002-06-23 08:01:47 +00001143 if (i < NF_BR_NUMHOOKS && !(replace.valid_hooks & (1 << i)))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001144 continue;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001145 entries2 = nr_to_chain(i);
1146 for (j = 0; j < entries2->nentries; j++) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001147 *cnt = CNT_NORM;
1148 cnt++;
1149 }
1150 }
1151 for (i = 0; i < rule_nr; i++) {
1152 *cnt = CNT_NORM;
1153 cnt++;
1154 }
1155 *cnt = CNT_ADD;
1156 cnt++;
Bart De Schuymered053432002-07-21 19:35:39 +00001157 while (cnt != replace.counterchanges + replace.nentries) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001158 *cnt = CNT_NORM;
1159 cnt++;
1160 }
1161 *cnt = CNT_END;
1162
1163 // go to the right position in the chain
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001164 u_e = &entries->entries;
1165 for (i = 0; i < rule_nr; i++)
1166 u_e = &(*u_e)->next;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001167 // insert the rule
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001168 new_entry->next = *u_e;
1169 *u_e = new_entry;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001170
1171 // put the ebt_[match, watcher, target] pointers in place
1172 m_l = new_entry->m_list;
1173 while (m_l) {
1174 m_l->m = ((struct ebt_u_match *)m_l->m)->m;
1175 m_l = m_l->next;
1176 }
1177 w_l = new_entry->w_list;
1178 while (w_l) {
1179 w_l->w = ((struct ebt_u_watcher *)w_l->w)->w;
1180 w_l = w_l->next;
1181 }
1182 new_entry->t = ((struct ebt_u_target *)new_entry->t)->t;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001183
1184 // update the counter_offset of chains behind this one
1185 i = replace.selected_hook;
1186 while (1) {
1187 i++;
1188 entries = nr_to_chain(i);
1189 if (!entries) {
1190 if (i < NF_BR_NUMHOOKS)
1191 continue;
1192 else
1193 break;
1194 } else
1195 entries->counter_offset++;
1196 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001197}
1198
1199// execute command D
1200static void delete_rule(int rule_nr)
1201{
1202 int i, j, lentmp = 0;
1203 unsigned short *cnt;
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001204 struct ebt_u_entry **u_e, *u_e2;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001205 struct ebt_u_entries *entries = to_chain(), *entries2;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001206
1207 if ( (i = check_rule_exists(rule_nr)) == -1 )
Bart De Schuymer60332e02002-06-23 08:01:47 +00001208 print_error("Sorry, rule does not exist");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001209
1210 // we're deleting a rule
1211 replace.num_counters = replace.nentries;
1212 replace.nentries--;
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001213 entries->nentries--;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001214
1215 if (replace.nentries) {
1216 for (j = 0; j < replace.selected_hook; j++) {
Bart De Schuymer60332e02002-06-23 08:01:47 +00001217 if (j < NF_BR_NUMHOOKS &&
1218 !(replace.valid_hooks & (1 << j)))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001219 continue;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001220 entries2 = nr_to_chain(j);
1221 lentmp += entries2->nentries;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001222 }
1223 lentmp += i;
1224 // +1 for CNT_END
Bart De Schuymered053432002-07-21 19:35:39 +00001225 if ( !(replace.counterchanges = (unsigned short *)malloc(
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001226 (replace.num_counters + 1) * sizeof(unsigned short))) )
1227 print_memory();
Bart De Schuymered053432002-07-21 19:35:39 +00001228 cnt = replace.counterchanges;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001229 for (j = 0; j < lentmp; j++) {
1230 *cnt = CNT_NORM;
1231 cnt++;
1232 }
1233 *cnt = CNT_DEL;
1234 cnt++;
1235 for (j = 0; j < replace.num_counters - lentmp; j++) {
1236 *cnt = CNT_NORM;
1237 cnt++;
1238 }
1239 *cnt = CNT_END;
1240 }
1241 else
1242 replace.num_counters = 0;
1243
1244 // go to the right position in the chain
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001245 u_e = &entries->entries;
1246 for (j = 0; j < i; j++)
1247 u_e = &(*u_e)->next;
1248 // remove the rule
1249 u_e2 = *u_e;
1250 *u_e = (*u_e)->next;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001251 // free everything
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001252 free_u_entry(u_e2);
1253 free(u_e2);
1254
Bart De Schuymer60332e02002-06-23 08:01:47 +00001255 // update the counter_offset of chains behind this one
1256 i = replace.selected_hook;
1257 while (1) {
1258 i++;
1259 entries = nr_to_chain(i);
1260 if (!entries) {
1261 if (i < NF_BR_NUMHOOKS)
1262 continue;
1263 else
1264 break;
1265 } else
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001266 entries->counter_offset--;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001267 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001268}
1269
1270// execute command Z
Bart De Schuymer62423742002-07-14 19:06:20 +00001271static void zero_counters(int zerochain)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001272{
1273
1274 if (zerochain == -1) {
1275 // tell main() we don't update the counters
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001276 // this results in tricking the kernel to zero its counters,
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001277 // naively expecting userspace to update its counters. Muahahaha
Bart De Schuymered053432002-07-21 19:35:39 +00001278 replace.counterchanges = NULL;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001279 replace.num_counters = 0;
1280 } else {
1281 int i, j;
1282 unsigned short *cnt;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001283 struct ebt_u_entries *entries = nr_to_chain(zerochain), *e2;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001284
Bart De Schuymer60332e02002-06-23 08:01:47 +00001285 if (entries->nentries == 0)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001286 exit(0);
Bart De Schuymered053432002-07-21 19:35:39 +00001287 replace.counterchanges = (unsigned short *)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001288 malloc((replace.nentries + 1) * sizeof(unsigned short));
Bart De Schuymered053432002-07-21 19:35:39 +00001289 if (!replace.counterchanges)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001290 print_memory();
Bart De Schuymered053432002-07-21 19:35:39 +00001291 cnt = replace.counterchanges;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001292 for (i = 0; i < zerochain; i++) {
Bart De Schuymer60332e02002-06-23 08:01:47 +00001293 if (i < NF_BR_NUMHOOKS &&
1294 !(replace.valid_hooks & (1 << i)))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001295 continue;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001296 e2 = nr_to_chain(i);
1297 for (j = 0; j < e2->nentries; j++) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001298 *cnt = CNT_NORM;
1299 cnt++;
1300 }
1301 }
Bart De Schuymer60332e02002-06-23 08:01:47 +00001302 for (i = 0; i < entries->nentries; i++) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001303 *cnt = CNT_ZERO;
1304 cnt++;
1305 }
Bart De Schuymered053432002-07-21 19:35:39 +00001306 while (cnt != replace.counterchanges + replace.nentries) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001307 *cnt = CNT_NORM;
1308 cnt++;
1309 }
1310 *cnt = CNT_END;
1311 }
1312}
1313
Bart De Schuymer28bf6f62002-06-26 18:57:24 +00001314// 0 == success
1315// 1 == success, but for the special 'protocol' LENGTH
1316// -1 == failure
1317int name_to_number(char *name, __u16 *proto)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001318{
1319 FILE *ifp;
Bart De Schuymerf662ce52002-07-19 18:40:55 +00001320 char buffer[21], value[11], *bfr;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001321 unsigned short i;
1322
1323 if (!strcasecmp("LENGTH", name)) {
Bart De Schuymer28bf6f62002-06-26 18:57:24 +00001324 *proto = 0;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001325 new_entry->bitmask |= EBT_802_3;
1326 return 1;
1327 }
1328 if ( !(ifp = fopen(PROTOCOLFILE, "r")) )
1329 return -1;
1330 while (1) {
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001331 if (get_a_line(buffer, value, ifp))
1332 return -1;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001333 if (strcasecmp(buffer, name))
1334 continue;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001335 fclose(ifp);
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001336 i = (unsigned short) strtol(value, &bfr, 16);
1337 if (*bfr != '\0')
1338 return -1;
1339 *proto = i;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001340 return 0;
1341 }
1342 return -1;
1343}
1344
1345// put the mac address into 6 (ETH_ALEN) bytes
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001346int getmac_and_mask(char *from, char *to, char *mask)
1347{
1348 char *p;
1349 int i;
Bart De Schuymer41830412002-06-05 19:41:28 +00001350 struct ether_addr *addr;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001351
1352 if (strcasecmp(from, "Unicast") == 0) {
1353 memcpy(to, mac_type_unicast, ETH_ALEN);
1354 memcpy(mask, msk_type_unicast, ETH_ALEN);
1355 return 0;
1356 }
1357 if (strcasecmp(from, "Multicast") == 0) {
1358 memcpy(to, mac_type_multicast, ETH_ALEN);
1359 memcpy(mask, msk_type_multicast, ETH_ALEN);
1360 return 0;
1361 }
1362 if (strcasecmp(from, "Broadcast") == 0) {
1363 memcpy(to, mac_type_broadcast, ETH_ALEN);
1364 memcpy(mask, msk_type_broadcast, ETH_ALEN);
1365 return 0;
1366 }
1367 if ( (p = strrchr(from, '/')) != NULL) {
1368 *p = '\0';
Bart De Schuymer41830412002-06-05 19:41:28 +00001369 if (!(addr = ether_aton(p + 1)))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001370 return -1;
Bart De Schuymer41830412002-06-05 19:41:28 +00001371 memcpy(mask, addr, ETH_ALEN);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001372 } else
1373 memset(mask, 0xff, ETH_ALEN);
Bart De Schuymer41830412002-06-05 19:41:28 +00001374 if (!(addr = ether_aton(from)))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001375 return -1;
Bart De Schuymer41830412002-06-05 19:41:28 +00001376 memcpy(to, addr, ETH_ALEN);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001377 for (i = 0; i < ETH_ALEN; i++)
1378 to[i] &= mask[i];
1379 return 0;
1380}
1381
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001382// executes the final_check() function for all extensions used by the rule
Bart De Schuymer62423742002-07-14 19:06:20 +00001383static void do_final_checks(struct ebt_u_entry *e, struct ebt_u_entries *entries)
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +00001384{
1385 struct ebt_u_match_list *m_l;
1386 struct ebt_u_watcher_list *w_l;
1387 struct ebt_u_target *t;
1388 struct ebt_u_match *m;
1389 struct ebt_u_watcher *w;
1390
1391 m_l = e->m_list;
1392 w_l = e->w_list;
1393 while (m_l) {
1394 m = find_match(m_l->m->u.name);
1395 m->final_check(e, m_l->m, replace.name,
1396 entries->hook_mask, 1);
1397 m_l = m_l->next;
1398 }
1399 while (w_l) {
1400 w = find_watcher(w_l->w->u.name);
1401 w->final_check(e, w_l->w, replace.name,
1402 entries->hook_mask, 1);
1403 w_l = w_l->next;
1404 }
1405 t = find_target(e->t->u.name);
1406 t->final_check(e, e->t, replace.name,
1407 entries->hook_mask, 1);
1408}
1409
Bart De Schuymerb909f9b2002-06-26 18:35:31 +00001410// used for the -X command
Bart De Schuymer62423742002-07-14 19:06:20 +00001411static void check_for_references(int chain_nr)
Bart De Schuymerb909f9b2002-06-26 18:35:31 +00001412{
1413 int i = -1, j;
1414 struct ebt_u_entries *entries;
1415 struct ebt_u_entry *e;
1416
1417 while (1) {
1418 i++;
1419 entries = nr_to_chain(i);
1420 if (!entries) {
1421 if (i < NF_BR_NUMHOOKS)
1422 continue;
1423 else
1424 break;
1425 }
1426 e = entries->entries;
1427 j = 0;
1428 while (e) {
1429 j++;
1430 if (strcmp(e->t->u.name, EBT_STANDARD_TARGET)) {
1431 e = e->next;
1432 continue;
1433 }
1434 if (((struct ebt_standard_target *)e->t)->verdict == chain_nr)
1435 print_error("Can't delete the chain, it's referenced "
1436 "in chain %s, rule %d", entries->name, j);
1437 e = e->next;
1438 }
1439 }
1440}
1441
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001442int check_inverse(const char option[])
1443{
1444 if (strcmp(option, "!") == 0) {
1445 optind++;
1446 return 1;
1447 }
1448 return 0;
1449}
1450
1451void check_option(unsigned int *flags, unsigned int mask)
1452{
1453 if (*flags & mask)
1454 print_error("Multiple use of same option not allowed");
1455 *flags |= mask;
1456}
1457
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001458static void get_kernel_table(const char *modprobe)
1459{
1460 if ( !(table = find_table(replace.name)) )
1461 print_error("Bad table name");
1462 // get the kernel's information
1463 if (get_table(&replace)) {
1464 ebtables_insmod("ebtables", modprobe);
1465 if (get_table(&replace))
1466 print_error("The kernel doesn't support the ebtables "
1467 "%s table", replace.name);
1468 }
1469}
1470
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001471#define OPT_COMMAND 0x01
1472#define OPT_TABLE 0x02
1473#define OPT_IN 0x04
1474#define OPT_OUT 0x08
1475#define OPT_JUMP 0x10
1476#define OPT_PROTOCOL 0x20
1477#define OPT_SOURCE 0x40
1478#define OPT_DEST 0x80
1479#define OPT_ZERO 0x100
1480#define OPT_LOGICALIN 0x200
1481#define OPT_LOGICALOUT 0x400
1482// the main thing
1483int main(int argc, char *argv[])
1484{
Bart De Schuymer923a5732002-08-11 12:01:33 +00001485 char *buffer;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001486 int c, i;
1487 // this special one for the -Z option (we can have -Z <this> -L <that>)
1488 int zerochain = -1;
Bart De Schuymerf8f8f292002-06-25 15:43:57 +00001489 int policy = 0;
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001490 int rule_nr = -1;// used for -[D,I] chain number
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001491 struct ebt_u_target *t;
1492 struct ebt_u_match *m;
1493 struct ebt_u_watcher *w;
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001494 struct ebt_u_match_list *m_l;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001495 struct ebt_u_watcher_list *w_l;
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001496 struct ebt_u_entries *entries;
Bart De Schuymerc8531032002-06-14 21:55:29 +00001497 const char *modprobe = NULL;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001498
1499 // initialize the table name, OPT_ flags, selected hook and command
1500 strcpy(replace.name, "filter");
1501 replace.flags = 0;
1502 replace.selected_hook = -1;
1503 replace.command = 'h';
Bart De Schuymer62423742002-07-14 19:06:20 +00001504 replace.filename = NULL;
Bart De Schuymered053432002-07-21 19:35:39 +00001505 replace.counterchanges = NULL;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001506
1507 new_entry = (struct ebt_u_entry *)malloc(sizeof(struct ebt_u_entry));
1508 if (!new_entry)
1509 print_memory();
1510 // put some sane values in our new entry
1511 initialize_entry(new_entry);
1512
Bart De Schuymer60332e02002-06-23 08:01:47 +00001513 // The scenario induced by this loop makes that:
Bart De Schuymer62423742002-07-14 19:06:20 +00001514 // '-t' ,'-M' and --atomic (if specified) have to come
1515 // before '-A' and the like
Bart De Schuymer60332e02002-06-23 08:01:47 +00001516
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001517 // getopt saves the day
1518 while ((c = getopt_long(argc, argv,
Bart De Schuymeraac31142002-08-11 11:57:52 +00001519 "-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 +00001520 switch (c) {
1521
1522 case 'A': // add a rule
1523 case 'D': // delete a rule
1524 case 'P': // define policy
1525 case 'I': // insert a rule
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001526 case 'N': // make a user defined chain
1527 case 'E': // rename chain
1528 case 'X': // delete chain
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001529 replace.command = c;
1530 if (replace.flags & OPT_COMMAND)
1531 print_error("Multiple commands not allowed");
1532 replace.flags |= OPT_COMMAND;
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001533 get_kernel_table(modprobe);
1534 if (optarg[0] == '-' || !strcmp(optarg, "!"))
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001535 print_error("No chain name specified");
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001536 if (c == 'N') {
1537 struct ebt_u_chain_list *cl, **cl2;
1538
1539 if (get_hooknr(optarg) != -1)
1540 print_error("Chain %s already exists",
1541 optarg);
1542 if (find_target(optarg))
1543 print_error("Target with name %s exists"
1544 , optarg);
1545 if (strlen(optarg) >= EBT_CHAIN_MAXNAMELEN)
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001546 print_error("Chain name length can't exceed %d",
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001547 EBT_CHAIN_MAXNAMELEN - 1);
1548 cl = (struct ebt_u_chain_list *)
1549 malloc(sizeof(struct ebt_u_chain_list));
1550 if (!cl)
1551 print_memory();
1552 cl->next = NULL;
1553 cl->udc = (struct ebt_u_entries *)
1554 malloc(sizeof(struct ebt_u_entries));
1555 if (!cl->udc)
1556 print_memory();
1557 cl->udc->nentries = 0;
1558 cl->udc->policy = EBT_ACCEPT;
1559 cl->udc->counter_offset = replace.nentries;
1560 cl->udc->hook_mask = 0;
1561 strcpy(cl->udc->name, optarg);
1562 cl->udc->entries = NULL;
1563 cl->kernel_start = NULL;
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001564 // put the new chain at the end
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001565 cl2 = &replace.udc;
1566 while (*cl2)
1567 cl2 = &((*cl2)->next);
1568 *cl2 = cl;
1569 break;
1570 }
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001571 if ((replace.selected_hook = get_hooknr(optarg)) == -1)
1572 print_error("Chain %s doesn't exist", optarg);
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001573 if (c == 'E') {
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001574 if (optind >= argc || argv[optind][0] == '-' ||
1575 !strcmp(argv[optind], "!"))
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001576 print_error("No new chain name specified");
1577 if (strlen(argv[optind]) >= EBT_CHAIN_MAXNAMELEN)
1578 print_error("Chain name len can't exceed %d",
1579 EBT_CHAIN_MAXNAMELEN - 1);
1580 if (get_hooknr(argv[optind]) != -1)
1581 print_error("Chain %s already exists",
1582 argv[optind]);
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001583 if (find_target(argv[optind]))
1584 print_error("Target with name %s exists"
1585 , argv[optind]);
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001586 entries = to_chain();
1587 strcpy(entries->name, argv[optind]);
1588 optind++;
1589 break;
1590 }
1591 if (c == 'X') {
1592 struct ebt_u_chain_list *cl, **cl2;
1593
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001594 if (replace.selected_hook < NF_BR_NUMHOOKS)
1595 print_error("You can't remove a standard chain");
Bart De Schuymerb909f9b2002-06-26 18:35:31 +00001596 // if the chain is referenced, don't delete it
1597 check_for_references(replace.selected_hook - NF_BR_NUMHOOKS);
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001598 flush_chains();
1599 entries = to_chain();
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001600 cl2 = &(replace.udc);
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001601 while ((*cl2)->udc != entries)
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001602 cl2 = &((*cl2)->next);
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001603 cl = (*cl2);
1604 (*cl2) = (*cl2)->next;
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001605 free(cl->udc);
1606 free(cl);
1607 break;
1608 }
1609
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001610 if ( (c == 'D' && optind < argc &&
1611 argv[optind][0] != '-') || c == 'I') {
1612 if (optind >= argc || argv[optind][0] == '-')
1613 print_error("No rulenr for -I"
1614 " specified");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001615 rule_nr = strtol(argv[optind], &buffer, 10);
1616 if (*buffer != '\0' || rule_nr < 0)
1617 print_error("Problem with the "
1618 "specified rule number");
1619 optind++;
1620 }
1621 if (c == 'P') {
1622 if (optind >= argc)
1623 print_error("No policy specified");
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001624 policy = 0;
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001625 for (i = 0; i < NUM_STANDARD_TARGETS; i++)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001626 if (!strcmp(argv[optind],
1627 standard_targets[i])) {
Bart De Schuymer60332e02002-06-23 08:01:47 +00001628 policy = -i -1;
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001629 if (policy == EBT_CONTINUE)
1630 policy = 0;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001631 break;
1632 }
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001633 if (policy == 0)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001634 print_error("Wrong policy");
1635 optind++;
1636 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001637 break;
1638
1639 case 'L': // list
1640 case 'F': // flush
1641 case 'Z': // zero counters
1642 if (c == 'Z') {
1643 if (replace.flags & OPT_ZERO)
1644 print_error("Multiple commands"
1645 " not allowed");
1646 if ( (replace.flags & OPT_COMMAND &&
1647 replace.command != 'L'))
1648 print_error("command -Z only allowed "
1649 "together with command -L");
1650 replace.flags |= OPT_ZERO;
1651 } else {
1652 replace.command = c;
1653 if (replace.flags & OPT_COMMAND)
1654 print_error("Multiple commands"
1655 " not allowed");
1656 replace.flags |= OPT_COMMAND;
1657 }
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001658 get_kernel_table(modprobe);
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001659 i = -1;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001660 if (optarg) {
1661 if ( (i = get_hooknr(optarg)) == -1 )
1662 print_error("Bad chain");
1663 } else
1664 if (optind < argc && argv[optind][0] != '-') {
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001665 if ((i = get_hooknr(argv[optind])) == -1)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001666 print_error("Bad chain");
1667 optind++;
1668 }
1669 if (i != -1) {
1670 if (c == 'Z')
1671 zerochain = i;
1672 else
1673 replace.selected_hook = i;
1674 }
1675 break;
1676
1677 case 'V': // version
1678 replace.command = 'V';
1679 if (replace.flags & OPT_COMMAND)
1680 print_error("Multiple commands not allowed");
Bart De Schuymerd4586482002-08-11 16:15:55 +00001681 printf(PROGNAME" v"PROGVERSION" ("PROGDATE")\n");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001682 exit(0);
1683
Bart De Schuymerc8531032002-06-14 21:55:29 +00001684 case 'M': // modprobe
Bart De Schuymer60332e02002-06-23 08:01:47 +00001685 if (replace.command != 'h')
1686 print_error("Please put the -M option earlier");
Bart De Schuymerc8531032002-06-14 21:55:29 +00001687 modprobe = optarg;
1688 break;
1689
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001690 case 'h': // help
1691 if (replace.flags & OPT_COMMAND)
1692 print_error("Multiple commands not allowed");
1693 replace.command = 'h';
1694 // All other arguments should be extension names
1695 while (optind < argc) {
1696 struct ebt_u_match *m;
1697 struct ebt_u_watcher *w;
1698
1699 if ((m = find_match(argv[optind])))
1700 add_match(m);
1701 else if ((w = find_watcher(argv[optind])))
1702 add_watcher(w);
1703 else {
1704 if (!(t = find_target(argv[optind])))
1705 print_error("Extension %s "
1706 "not found", argv[optind]);
1707 if (replace.flags & OPT_JUMP)
1708 print_error("Sorry, you can "
1709 "only see help for one "
1710 "target extension each time");
1711 replace.flags |= OPT_JUMP;
1712 new_entry->t =
1713 (struct ebt_entry_target *)t;
1714 }
1715 optind++;
1716 }
1717 break;
1718
1719 case 't': // table
Bart De Schuymer60332e02002-06-23 08:01:47 +00001720 if (replace.command != 'h')
1721 print_error("Please put the -t option first");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001722 check_option(&replace.flags, OPT_TABLE);
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001723 if (strlen(optarg) > EBT_TABLE_MAXNAMELEN - 1)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001724 print_error("Table name too long");
1725 strcpy(replace.name, optarg);
1726 break;
1727
1728 case 'i': // input interface
1729 case 2 : // logical input interface
1730 case 'o': // output interface
1731 case 3 : // logical output interface
1732 case 'j': // target
1733 case 'p': // net family protocol
1734 case 's': // source mac
1735 case 'd': // destination mac
1736 if ((replace.flags & OPT_COMMAND) == 0)
1737 print_error("No command specified");
1738 if ( replace.command != 'A' &&
1739 replace.command != 'D' && replace.command != 'I')
1740 print_error("Command and option do not match");
1741 if (c == 'i') {
1742 check_option(&replace.flags, OPT_IN);
1743 if (replace.selected_hook > 2 &&
1744 replace.selected_hook < NF_BR_BROUTING)
1745 print_error("Use in-interface only in "
1746 "INPUT, FORWARD, PREROUTING and"
1747 "BROUTING chains");
1748 if (check_inverse(optarg))
1749 new_entry->invflags |= EBT_IIN;
1750
1751 if (optind > argc)
1752 print_error("No in-interface "
1753 "specified");
1754 if (strlen(argv[optind - 1]) >= IFNAMSIZ)
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001755 print_error("Illegal interface length");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001756 strcpy(new_entry->in, argv[optind - 1]);
1757 break;
1758 }
1759 if (c == 2) {
1760 check_option(&replace.flags, OPT_LOGICALIN);
1761 if (replace.selected_hook > 2 &&
1762 replace.selected_hook < NF_BR_BROUTING)
1763 print_error("Use logical in-interface "
1764 "only in INPUT, FORWARD, "
1765 "PREROUTING and BROUTING chains");
1766 if (check_inverse(optarg))
1767 new_entry->invflags |= EBT_ILOGICALIN;
1768
1769 if (optind > argc)
1770 print_error("No logical in-interface "
1771 "specified");
1772 if (strlen(argv[optind - 1]) >= IFNAMSIZ)
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001773 print_error("Illegal interface length");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001774 strcpy(new_entry->logical_in, argv[optind - 1]);
1775 break;
1776 }
1777 if (c == 'o') {
1778 check_option(&replace.flags, OPT_OUT);
1779 if (replace.selected_hook < 2)
1780 print_error("Use out-interface only"
1781 " in OUTPUT, FORWARD and "
1782 "POSTROUTING chains");
1783 if (check_inverse(optarg))
1784 new_entry->invflags |= EBT_IOUT;
1785
1786 if (optind > argc)
1787 print_error("No out-interface "
1788 "specified");
1789
1790 if (strlen(argv[optind - 1]) >= IFNAMSIZ)
1791 print_error("Illegal interface "
1792 "length");
1793 strcpy(new_entry->out, argv[optind - 1]);
1794 break;
1795 }
1796 if (c == 3) {
1797 check_option(&replace.flags, OPT_LOGICALOUT);
1798 if (replace.selected_hook < 2)
1799 print_error("Use logical out-interface "
1800 "only in OUTPUT, FORWARD and "
1801 "POSTROUTING chains");
1802 if (check_inverse(optarg))
1803 new_entry->invflags |= EBT_ILOGICALOUT;
1804
1805 if (optind > argc)
1806 print_error("No logical out-interface "
1807 "specified");
1808
1809 if (strlen(argv[optind - 1]) >= IFNAMSIZ)
1810 print_error("Illegal interface "
1811 "length");
1812 strcpy(new_entry->logical_out,
1813 argv[optind - 1]);
1814 break;
1815 }
1816 if (c == 'j') {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001817 check_option(&replace.flags, OPT_JUMP);
1818 for (i = 0; i < NUM_STANDARD_TARGETS; i++)
1819 if (!strcmp(optarg,
1820 standard_targets[i])) {
1821 t = find_target(
1822 EBT_STANDARD_TARGET);
1823 ((struct ebt_standard_target *)
Bart De Schuymer60332e02002-06-23 08:01:47 +00001824 t->t)->verdict = -i - 1;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001825 break;
1826 }
Bart De Schuymer60332e02002-06-23 08:01:47 +00001827 if (-i - 1 == EBT_RETURN) {
1828 if (replace.selected_hook < NF_BR_NUMHOOKS)
1829 print_error("Return target"
1830 " only for user defined chains");
1831 }
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +00001832 if (i != NUM_STANDARD_TARGETS)
1833 break;
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001834 if ((i = get_hooknr(optarg)) != -1) {
1835 if (i < NF_BR_NUMHOOKS)
1836 print_error("don't jump"
1837 " to a standard chain");
1838 t = find_target(
1839 EBT_STANDARD_TARGET);
1840 ((struct ebt_standard_target *)
1841 t->t)->verdict = i - NF_BR_NUMHOOKS;
1842 break;
1843 }
1844 else {
1845 // must be an extension then
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001846 struct ebt_u_target *t;
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001847
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001848 t = find_target(optarg);
1849 // -j standard not allowed either
1850 if (!t || t ==
1851 (struct ebt_u_target *)new_entry->t)
1852 print_error("Illegal target "
1853 "name");
1854 new_entry->t =
1855 (struct ebt_entry_target *)t;
1856 }
1857 break;
1858 }
1859 if (c == 's') {
1860 check_option(&replace.flags, OPT_SOURCE);
1861 if (check_inverse(optarg))
1862 new_entry->invflags |= EBT_ISOURCE;
1863
1864 if (optind > argc)
1865 print_error("No source mac "
1866 "specified");
1867 if (getmac_and_mask(argv[optind - 1],
1868 new_entry->sourcemac, new_entry->sourcemsk))
1869 print_error("Problem with specified "
1870 "source mac");
1871 new_entry->bitmask |= EBT_SOURCEMAC;
1872 break;
1873 }
1874 if (c == 'd') {
1875 check_option(&replace.flags, OPT_DEST);
1876 if (check_inverse(optarg))
1877 new_entry->invflags |= EBT_IDEST;
1878
1879 if (optind > argc)
1880 print_error("No destination mac "
1881 "specified");
1882 if (getmac_and_mask(argv[optind - 1],
1883 new_entry->destmac, new_entry->destmsk))
1884 print_error("Problem with specified "
1885 "destination mac");
1886 new_entry->bitmask |= EBT_DESTMAC;
1887 break;
1888 }
1889 check_option(&replace.flags, OPT_PROTOCOL);
1890 if (check_inverse(optarg))
1891 new_entry->invflags |= EBT_IPROTO;
1892
1893 if (optind > argc)
1894 print_error("No protocol specified");
1895 new_entry->bitmask &= ~((unsigned int)EBT_NOPROTO);
1896 i = strtol(argv[optind - 1], &buffer, 16);
1897 if (*buffer == '\0' && (i < 0 || i > 0xFFFF))
1898 print_error("Problem with the specified "
1899 "protocol");
1900 new_entry->ethproto = i;
Bart De Schuymer28bf6f62002-06-26 18:57:24 +00001901 if (*buffer != '\0') {
1902 if ((i = name_to_number(argv[optind - 1],
1903 &new_entry->ethproto)) == -1)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001904 print_error("Problem with the specified"
1905 " protocol");
Bart De Schuymer28bf6f62002-06-26 18:57:24 +00001906 if (i == 1)
1907 new_entry->bitmask |= EBT_802_3;
1908 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001909 if (new_entry->ethproto < 1536 &&
1910 !(new_entry->bitmask & EBT_802_3))
1911 print_error("Sorry, protocols have values above"
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001912 " or equal to 0x0600");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001913 break;
1914
Bart De Schuymer9af14f92002-07-10 20:49:10 +00001915 case 4 : // Lc
1916 check_option(&replace.flags, LIST_C);
Bart De Schuymer9af14f92002-07-10 20:49:10 +00001917 if (replace.command != 'L')
1918 print_error("Use --Lc with -L");
1919 if (replace.flags & LIST_X)
1920 print_error("--Lx not compatible with --Lc");
1921 replace.flags |= LIST_C;
1922 break;
1923 case 5 : // Ln
1924 check_option(&replace.flags, LIST_N);
Bart De Schuymer9af14f92002-07-10 20:49:10 +00001925 if (replace.command != 'L')
1926 print_error("Use --Ln with -L");
1927 if (replace.flags & LIST_X)
1928 print_error("--Lx not compatible with --Ln");
1929 replace.flags |= LIST_N;
1930 break;
1931 case 6 : // Lx
1932 check_option(&replace.flags, LIST_X);
Bart De Schuymer9af14f92002-07-10 20:49:10 +00001933 if (replace.command != 'L')
1934 print_error("Use --Lx with -L");
1935 if (replace.flags & LIST_C)
1936 print_error("--Lx not compatible with --Lc");
1937 if (replace.flags & LIST_N)
1938 print_error("--Lx not compatible with --Ln");
1939 replace.flags |= LIST_X;
1940 break;
Bart De Schuymer62423742002-07-14 19:06:20 +00001941 case 8 : // atomic-commit
1942 replace.command = c;
1943 if (replace.flags & OPT_COMMAND)
1944 print_error("Multiple commands not allowed");
1945 replace.flags |= OPT_COMMAND;
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001946 if (replace.filename)
1947 print_error("--atomic incompatible with "
1948 "command");
Bart De Schuymer62423742002-07-14 19:06:20 +00001949 replace.filename = (char *)malloc(strlen(optarg) + 1);
1950 strcpy(replace.filename, optarg);
1951 // get the information from the file
1952 get_table(&replace);
Bart De Schuymer868bf642002-07-16 18:14:20 +00001953 if (replace.nentries) {
Bart De Schuymered053432002-07-21 19:35:39 +00001954 replace.counterchanges = (unsigned short *)
Bart De Schuymer868bf642002-07-16 18:14:20 +00001955 malloc(sizeof(unsigned short) * (replace.nentries + 1));
1956 for (i = 0; i < replace.nentries; i++)
Bart De Schuymered053432002-07-21 19:35:39 +00001957 replace.counterchanges[i] = CNT_NORM;
1958 replace.counterchanges[i] = CNT_END;
Bart De Schuymer868bf642002-07-16 18:14:20 +00001959 }
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001960 // we don't want the kernel giving us its counters, they would
1961 // overwrite the counters extracted from the file
1962 replace.num_counters = 0;
1963 // make sure the table will be written to the kernel
Bart De Schuymer62423742002-07-14 19:06:20 +00001964 free(replace.filename);
1965 replace.filename = NULL;
1966 break;
1967 case 7 : // atomic-init
1968 case 10: // atomic-save
Bart De Schuymer8d1d8942002-07-15 20:09:09 +00001969 case 11: // init-table
Bart De Schuymer62423742002-07-14 19:06:20 +00001970 replace.command = c;
1971 if (replace.flags & OPT_COMMAND)
1972 print_error("Multiple commands not allowed");
1973 replace.flags |= OPT_COMMAND;
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001974 if (replace.filename)
1975 print_error("--atomic incompatible with "
1976 "command");
1977 get_kernel_table(modprobe);
Bart De Schuymera8d920b2002-07-16 18:30:44 +00001978 if (replace.nentries) {
Bart De Schuymered053432002-07-21 19:35:39 +00001979 replace.counterchanges = (unsigned short *)
Bart De Schuymer5f16dc72002-07-16 18:08:36 +00001980 malloc(sizeof(unsigned short) * (replace.nentries + 1));
1981 for (i = 0; i < replace.nentries; i++)
Bart De Schuymered053432002-07-21 19:35:39 +00001982 replace.counterchanges[i] = CNT_NORM;
1983 replace.counterchanges[i] = CNT_END;
Bart De Schuymer5f16dc72002-07-16 18:08:36 +00001984 }
Bart De Schuymer8d1d8942002-07-15 20:09:09 +00001985 if (c == 11)
1986 break;
Bart De Schuymer62423742002-07-14 19:06:20 +00001987 case 9 : // atomic
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001988 if (c == 9 && (replace.flags & OPT_COMMAND))
1989 print_error("--atomic has to come before"
1990 " the command");
Bart De Schuymer62423742002-07-14 19:06:20 +00001991 replace.filename = (char *)malloc(strlen(optarg) + 1);
1992 strcpy(replace.filename, optarg);
1993 break;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001994
Bart De Schuymer9af14f92002-07-10 20:49:10 +00001995 default:
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001996 // is it a target option?
1997 t = (struct ebt_u_target *)new_entry->t;
1998 if ((t->parse(c - t->option_offset, argv, argc,
1999 new_entry, &t->flags, &t->t)))
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00002000 goto check_extension;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002001
2002 // is it a match_option?
2003 for (m = matches; m; m = m->next)
2004 if (m->parse(c - m->option_offset, argv,
2005 argc, new_entry, &m->flags, &m->m))
2006 break;
2007
2008 if (m != NULL) {
2009 if (m->used == 0)
2010 add_match(m);
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00002011 goto check_extension;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002012 }
2013
2014 // is it a watcher option?
2015 for (w = watchers; w; w = w->next)
2016 if (w->parse(c-w->option_offset, argv,
2017 argc, new_entry, &w->flags, &w->w))
2018 break;
2019
2020 if (w == NULL)
2021 print_error("Unknown argument");
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00002022 if (w->used == 0)
2023 add_watcher(w);
2024check_extension:
Bart De Schuymer60332e02002-06-23 08:01:47 +00002025 if (replace.command != 'A' && replace.command != 'I' &&
2026 replace.command != 'D')
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00002027 print_error("Extensions only for -A, -I and -D");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002028 }
2029 }
2030
Bart De Schuymer25c741d2002-06-23 18:54:34 +00002031 if ( !table && !(table = find_table(replace.name)) )
2032 print_error("Bad table name");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002033
2034 if ( (replace.flags & OPT_COMMAND) && replace.command != 'L' &&
2035 replace.flags & OPT_ZERO )
2036 print_error("Command -Z only allowed together with command -L");
2037
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002038 // do this after parsing everything, so we can print specific info
2039 if (replace.command == 'h' && !(replace.flags & OPT_ZERO))
2040 print_help();
2041
2042 // do the final checks
Bart De Schuymer60332e02002-06-23 08:01:47 +00002043 if (replace.command == 'A' || replace.command == 'I' ||
2044 replace.command == 'D') {
2045 // this will put the hook_mask right for the chains
2046 check_for_loops();
2047 entries = to_chain();
2048 m_l = new_entry->m_list;
2049 w_l = new_entry->w_list;
2050 t = (struct ebt_u_target *)new_entry->t;
2051 while (m_l) {
2052 m = (struct ebt_u_match *)(m_l->m);
2053 m->final_check(new_entry, m->m, replace.name,
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +00002054 entries->hook_mask, 0);
Bart De Schuymer60332e02002-06-23 08:01:47 +00002055 m_l = m_l->next;
2056 }
2057 while (w_l) {
2058 w = (struct ebt_u_watcher *)(w_l->w);
2059 w->final_check(new_entry, w->w, replace.name,
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +00002060 entries->hook_mask, 0);
Bart De Schuymer60332e02002-06-23 08:01:47 +00002061 w_l = w_l->next;
2062 }
2063 t->final_check(new_entry, t->t, replace.name,
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +00002064 entries->hook_mask, 0);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002065 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002066 // so, the extensions can work with the host endian
2067 // the kernel does not have to do this ofcourse
2068 new_entry->ethproto = htons(new_entry->ethproto);
2069
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002070 if (replace.command == 'P')
2071 change_policy(policy);
2072 else if (replace.command == 'L') {
2073 list_rules();
2074 if (replace.flags & OPT_ZERO)
2075 zero_counters(zerochain);
2076 else
2077 exit(0);
2078 }
2079 if (replace.flags & OPT_ZERO)
2080 zero_counters(zerochain);
Bart De Schuymer1ab41562002-06-23 17:09:54 +00002081 else if (replace.command == 'F') {
2082 if (flush_chains() == -1)
2083 exit(0);
2084 } else if (replace.command == 'A' || replace.command == 'I') {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002085 add_rule(rule_nr);
Bart De Schuymer1ab41562002-06-23 17:09:54 +00002086 check_for_loops();
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +00002087 // do the final_check(), for all entries
2088 // needed when adding a rule that has a chain target
2089 i = -1;
2090 while (1) {
2091 struct ebt_u_entry *e;
2092
2093 i++;
2094 entries = nr_to_chain(i);
2095 if (!entries) {
2096 if (i < NF_BR_NUMHOOKS)
2097 continue;
2098 else
2099 break;
2100 }
2101 e = entries->entries;
2102 while (e) {
2103 // userspace extensions use host endian
2104 e->ethproto = ntohs(e->ethproto);
2105 do_final_checks(e, entries);
2106 e->ethproto = htons(e->ethproto);
2107 e = e->next;
2108 }
2109 }
Bart De Schuymer1ab41562002-06-23 17:09:54 +00002110 } else if (replace.command == 'D')
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002111 delete_rule(rule_nr);
Bart De Schuymer8d1d8942002-07-15 20:09:09 +00002112 // commands -N, -E, -X, --atomic-commit, --atomic-commit, --atomic-save,
2113 // --init-table fall through
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002114
2115 if (table->check)
2116 table->check(&replace);
2117
2118 deliver_table(&replace);
2119
Bart De Schuymered053432002-07-21 19:35:39 +00002120 if (replace.counterchanges)
2121 deliver_counters(&replace);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002122 return 0;
2123}