blob: e6f798bf7ae8aae564aaaa81ab3cd79f0990e819 [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>
29#include <sys/socket.h>
30#include <sys/types.h>
31#include <linux/netfilter_bridge/ebtables.h>
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000032#include <netinet/in.h>
Bart De Schuymer41830412002-06-05 19:41:28 +000033#include <netinet/ether.h>
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000034#include "include/ebtables_u.h"
Bart De Schuymerc8531032002-06-14 21:55:29 +000035#include <unistd.h>
36#include <fcntl.h>
37#include <sys/wait.h>
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000038
Bart De Schuymerc56a31a2002-07-25 08:16:08 +000039// here are the number-name correspondences kept for the Ethernet
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000040// frame type field
41#define PROTOCOLFILE "/etc/ethertypes"
42
Bart De Schuymerc8531032002-06-14 21:55:29 +000043#ifndef PROC_SYS_MODPROBE
44#define PROC_SYS_MODPROBE "/proc/sys/kernel/modprobe"
45#endif
46
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000047static char *prog_name = PROGNAME;
48static char *prog_version = PROGVERSION;
Bart De Schuymer60332e02002-06-23 08:01:47 +000049char *hooknames[NF_BR_NUMHOOKS] =
50{
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000051 [NF_BR_PRE_ROUTING]"PREROUTING",
52 [NF_BR_LOCAL_IN]"INPUT",
53 [NF_BR_FORWARD]"FORWARD",
54 [NF_BR_LOCAL_OUT]"OUTPUT",
55 [NF_BR_POST_ROUTING]"POSTROUTING",
56 [NF_BR_BROUTING]"BROUTING"
57};
58
59// default command line options
Bart De Schuymer8d1d8942002-07-15 20:09:09 +000060// do not mess around with the already assigned numbers unless
61// you know what you are doing
Bart De Schuymer62423742002-07-14 19:06:20 +000062static struct option ebt_original_options[] =
63{
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000064 { "append" , required_argument, 0, 'A' },
65 { "insert" , required_argument, 0, 'I' },
66 { "delete" , required_argument, 0, 'D' },
67 { "list" , optional_argument, 0, 'L' },
Bart De Schuymer9af14f92002-07-10 20:49:10 +000068 { "Lc" , no_argument , 0, 4 },
69 { "Ln" , no_argument , 0, 5 },
70 { "Lx" , no_argument , 0, 6 },
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000071 { "zero" , optional_argument, 0, 'Z' },
72 { "flush" , optional_argument, 0, 'F' },
73 { "policy" , required_argument, 0, 'P' },
74 { "in-interface" , required_argument, 0, 'i' },
75 { "in-if" , required_argument, 0, 'i' },
76 { "logical-in" , required_argument, 0, 2 },
77 { "logical-out" , required_argument, 0, 3 },
78 { "out-interface" , required_argument, 0, 'o' },
79 { "out-if" , required_argument, 0, 'o' },
80 { "version" , no_argument , 0, 'V' },
81 { "help" , no_argument , 0, 'h' },
82 { "jump" , required_argument, 0, 'j' },
83 { "proto" , required_argument, 0, 'p' },
84 { "protocol" , required_argument, 0, 'p' },
85 { "db" , required_argument, 0, 'b' },
86 { "source" , required_argument, 0, 's' },
87 { "src" , required_argument, 0, 's' },
88 { "destination" , required_argument, 0, 'd' },
89 { "dst" , required_argument, 0, 'd' },
90 { "table" , required_argument, 0, 't' },
Bart De Schuymerc8531032002-06-14 21:55:29 +000091 { "modprobe" , required_argument, 0, 'M' },
Bart De Schuymer1ab41562002-06-23 17:09:54 +000092 { "new-chain" , required_argument, 0, 'N' },
93 { "rename-chain" , required_argument, 0, 'E' },
94 { "delete-chain" , required_argument, 0, 'X' },
Bart De Schuymer62423742002-07-14 19:06:20 +000095 { "atomic-init" , required_argument, 0, 7 },
Bart De Schuymer62423742002-07-14 19:06:20 +000096 { "atomic-commit" , required_argument, 0, 8 },
97 { "atomic" , required_argument, 0, 9 },
98 { "atomic-save" , required_argument, 0, 10 },
Bart De Schuymer8d1d8942002-07-15 20:09:09 +000099 { "init-table" , no_argument , 0, 11 },
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000100 { 0 }
101};
102
103static struct option *ebt_options = ebt_original_options;
104
105// yup, all the possible target names
Bart De Schuymer62423742002-07-14 19:06:20 +0000106char* standard_targets[NUM_STANDARD_TARGETS] =
107{
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000108 "ACCEPT",
109 "DROP",
110 "CONTINUE",
Bart De Schuymer60332e02002-06-23 08:01:47 +0000111 "RETURN",
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000112};
113
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000114unsigned char mac_type_unicast[ETH_ALEN] = {0,0,0,0,0,0};
115unsigned char msk_type_unicast[ETH_ALEN] = {1,0,0,0,0,0};
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000116unsigned char mac_type_multicast[ETH_ALEN] = {1,0,0,0,0,0};
117unsigned char msk_type_multicast[ETH_ALEN] = {1,0,0,0,0,0};
118unsigned char mac_type_broadcast[ETH_ALEN] = {255,255,255,255,255,255};
119unsigned char msk_type_broadcast[ETH_ALEN] = {255,255,255,255,255,255};
120
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000121// holds all the data
122static struct ebt_u_replace replace;
123
124// the chosen table
125static struct ebt_u_table *table = NULL;
126// the lists of supported tables, matches, watchers and targets
127static struct ebt_u_table *tables = NULL;
128static struct ebt_u_match *matches = NULL;
129static struct ebt_u_watcher *watchers = NULL;
130static struct ebt_u_target *targets = NULL;
131
132struct ebt_u_target *find_target(const char *name)
133{
134 struct ebt_u_target *t = targets;
135
136 while(t && strcmp(t->name, name))
137 t = t->next;
138 return t;
139}
140
141struct ebt_u_match *find_match(const char *name)
142{
143 struct ebt_u_match *m = matches;
144
145 while(m && strcmp(m->name, name))
146 m = m->next;
147 return m;
148}
149
150struct ebt_u_watcher *find_watcher(const char *name)
151{
152 struct ebt_u_watcher *w = watchers;
153
154 while(w && strcmp(w->name, name))
155 w = w->next;
156 return w;
157}
158
159struct ebt_u_table *find_table(char *name)
160{
161 struct ebt_u_table *t = tables;
162
163 while (t && strcmp(t->name, name))
164 t = t->next;
165 return t;
166}
167
168// The pointers in here are special:
169// The struct ebt_target * pointer is actually a struct ebt_u_target * pointer.
170// instead of making yet a few other structs, we just do a cast.
171// We need a struct ebt_u_target pointer because we know the address of the data
172// they point to won't change. We want to allow that the struct ebt_u_target.t
173// member can change.
174// Same holds for the struct ebt_match and struct ebt_watcher pointers
175struct ebt_u_entry *new_entry;
176
Bart De Schuymer62423742002-07-14 19:06:20 +0000177static void initialize_entry(struct ebt_u_entry *e)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000178{
179 e->bitmask = EBT_NOPROTO;
180 e->invflags = 0;
181 e->ethproto = 0;
182 strcpy(e->in, "");
183 strcpy(e->out, "");
184 strcpy(e->logical_in, "");
185 strcpy(e->logical_out, "");
186 e->m_list = NULL;
187 e->w_list = NULL;
188 // the init function of the standard target should have put the verdict
189 // on CONTINUE
190 e->t = (struct ebt_entry_target *)find_target(EBT_STANDARD_TARGET);
191 if (!e->t)
192 print_bug("Couldn't load standard target\n");
193}
194
195// this doesn't free e, becoz the calling function might need e->next
Bart De Schuymer62423742002-07-14 19:06:20 +0000196static void free_u_entry(struct ebt_u_entry *e)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000197{
198 struct ebt_u_match_list *m_l, *m_l2;
199 struct ebt_u_watcher_list *w_l, *w_l2;
200
201 m_l = e->m_list;
202 while (m_l) {
203 m_l2 = m_l->next;
204 free(m_l->m);
205 free(m_l);
206 m_l = m_l2;
207 }
208 w_l = e->w_list;
209 while (w_l) {
210 w_l2 = w_l->next;
211 free(w_l->w);
212 free(w_l);
213 w_l = w_l2;
214 }
215 free(e->t);
216}
217
218// the user will use the match, so put it in new_entry
219static void add_match(struct ebt_u_match *m)
220{
221 struct ebt_u_match_list **m_list, *new;
222
223 m->used = 1;
Bart De Schuymerc56a31a2002-07-25 08:16:08 +0000224 for (m_list = &new_entry->m_list; *m_list; m_list = &(*m_list)->next);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000225 new = (struct ebt_u_match_list *)
226 malloc(sizeof(struct ebt_u_match_list));
227 if (!new)
228 print_memory();
229 *m_list = new;
230 new->next = NULL;
231 new->m = (struct ebt_entry_match *)m;
232}
233
234static void add_watcher(struct ebt_u_watcher *w)
235{
236 struct ebt_u_watcher_list **w_list;
237 struct ebt_u_watcher_list *new;
238
239 w->used = 1;
Bart De Schuymerc56a31a2002-07-25 08:16:08 +0000240 for (w_list = &new_entry->w_list; *w_list; w_list = &(*w_list)->next);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000241 new = (struct ebt_u_watcher_list *)
242 malloc(sizeof(struct ebt_u_watcher_list));
243 if (!new)
244 print_memory();
245 *w_list = new;
246 new->next = NULL;
247 new->w = (struct ebt_entry_watcher *)w;
248}
249
250static int global_option_offset = 0;
251#define OPTION_OFFSET 256
252static struct option *
253merge_options(struct option *oldopts, const struct option *newopts,
254 unsigned int *options_offset)
255{
256 unsigned int num_old, num_new, i;
257 struct option *merge;
258
259 if (!newopts || !oldopts || !options_offset)
260 print_bug("merge wrong");
261 for (num_old = 0; oldopts[num_old].name; num_old++);
262 for (num_new = 0; newopts[num_new].name; num_new++);
263
264 global_option_offset += OPTION_OFFSET;
265 *options_offset = global_option_offset;
266
267 merge = malloc(sizeof(struct option) * (num_new + num_old + 1));
268 if (!merge)
269 print_memory();
270 memcpy(merge, oldopts, num_old * sizeof(struct option));
271 for (i = 0; i < num_new; i++) {
272 merge[num_old + i] = newopts[i];
273 merge[num_old + i].val += *options_offset;
274 }
275 memset(merge + num_old + num_new, 0, sizeof(struct option));
276 // only free dynamically allocated stuff
277 if (oldopts != ebt_original_options)
278 free(oldopts);
279
280 return merge;
281}
282
283void register_match(struct ebt_u_match *m)
284{
285 int size = m->size + sizeof(struct ebt_entry_match);
286 struct ebt_u_match **i;
287
288 m->m = (struct ebt_entry_match *)malloc(size);
289 if (!m->m)
290 print_memory();
291 strcpy(m->m->u.name, m->name);
292 m->m->match_size = m->size;
293 ebt_options = merge_options
294 (ebt_options, m->extra_ops, &(m->option_offset));
295 m->init(m->m);
296
297 for (i = &matches; *i; i = &((*i)->next));
298 m->next = NULL;
299 *i = m;
300}
301
302void register_watcher(struct ebt_u_watcher *w)
303{
304 int size = w->size + sizeof(struct ebt_entry_watcher);
305 struct ebt_u_watcher **i;
306
307 w->w = (struct ebt_entry_watcher *)malloc(size);
308 if (!w->w)
309 print_memory();
310 strcpy(w->w->u.name, w->name);
311 w->w->watcher_size = w->size;
312 ebt_options = merge_options
313 (ebt_options, w->extra_ops, &(w->option_offset));
314 w->init(w->w);
315
316 for (i = &watchers; *i; i = &((*i)->next));
317 w->next = NULL;
318 *i = w;
319}
320
321void register_target(struct ebt_u_target *t)
322{
323 int size = t->size + sizeof(struct ebt_entry_target);
324 struct ebt_u_target **i;
325
326 t->t = (struct ebt_entry_target *)malloc(size);
327 if (!t->t)
328 print_memory();
329 strcpy(t->t->u.name, t->name);
330 t->t->target_size = t->size;
331 ebt_options = merge_options
332 (ebt_options, t->extra_ops, &(t->option_offset));
333 t->init(t->t);
Bart De Schuymerc56a31a2002-07-25 08:16:08 +0000334
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000335 for (i = &targets; *i; i = &((*i)->next));
336 t->next = NULL;
337 *i = t;
338}
339
340void register_table(struct ebt_u_table *t)
341{
342 t->next = tables;
343 tables = t;
344}
345
Bart De Schuymerc8531032002-06-14 21:55:29 +0000346// blatently stolen (again) from iptables.c userspace program
347// find out where the modprobe utility is located
348static char *get_modprobe(void)
349{
350 int procfile;
351 char *ret;
352
353 procfile = open(PROC_SYS_MODPROBE, O_RDONLY);
354 if (procfile < 0)
355 return NULL;
356
357 ret = malloc(1024);
358 if (ret) {
359 switch (read(procfile, ret, 1024)) {
360 case -1: goto fail;
361 case 1024: goto fail; /* Partial read. Wierd */
362 }
363 if (ret[strlen(ret)-1]=='\n')
364 ret[strlen(ret)-1]=0;
365 close(procfile);
366 return ret;
367 }
368 fail:
369 free(ret);
370 close(procfile);
371 return NULL;
372}
373
Bart De Schuymerc8531032002-06-14 21:55:29 +0000374int ebtables_insmod(const char *modname, const char *modprobe)
375{
376 char *buf = NULL;
377 char *argv[3];
378
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000379 // If they don't explicitly set it, read out of kernel
Bart De Schuymerc8531032002-06-14 21:55:29 +0000380 if (!modprobe) {
381 buf = get_modprobe();
382 if (!buf)
383 return -1;
384 modprobe = buf;
385 }
386
387 switch (fork()) {
388 case 0:
389 argv[0] = (char *)modprobe;
390 argv[1] = (char *)modname;
391 argv[2] = NULL;
392 execv(argv[0], argv);
393
394 /* not usually reached */
395 exit(0);
396 case -1:
397 return -1;
398
399 default: /* parent */
400 wait(NULL);
401 }
402
403 free(buf);
404 return 0;
405}
406
Bart De Schuymerbbca3202002-06-05 18:55:44 +0000407// helper function: processes a line of data from the file /etc/ethertypes
Bart De Schuymer62423742002-07-14 19:06:20 +0000408static int get_a_line(char *buffer, char *value, FILE *ifp)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000409{
Bart De Schuymerf662ce52002-07-19 18:40:55 +0000410 char line[80], *p;
411 const char delim[] = " \t\n";
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000412
Bart De Schuymerf662ce52002-07-19 18:40:55 +0000413 while (fgets(line, sizeof(line), ifp)) {
414 p = strtok(line, delim);
415 if (!p || p[0] == '#')
416 continue;
417 if (strlen(p) > 20)
418 continue;
419 strcpy(buffer, p);
420 p = strtok(NULL, delim);
421 if (!p || strlen(p) > 10)
422 continue;
423 strcpy(value, p);
424 return 0;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000425 }
Bart De Schuymerf662ce52002-07-19 18:40:55 +0000426 return -1;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000427}
428
Bart De Schuymerb909f9b2002-06-26 18:35:31 +0000429// translate a hexadecimal number to a protocol name, parsing /etc/ethertypes
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000430// returns 0 on success
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000431int number_to_name(unsigned short proto, char *name)
432{
433 FILE *ifp;
Bart De Schuymerf662ce52002-07-19 18:40:55 +0000434 char buffer[21], value[11], *bfr;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000435 unsigned short i;
436
437 if ( !(ifp = fopen(PROTOCOLFILE, "r")) )
438 return -1;
439 while (1) {
440 if (get_a_line(buffer, value, ifp)) {
441 fclose(ifp);
442 return -1;
443 }
444 i = (unsigned short) strtol(value, &bfr, 16);
445 if (*bfr != '\0' || i != proto)
446 continue;
447 strcpy(name, buffer);
448 fclose(ifp);
449 return 0;
450 }
451}
452
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000453// we use replace.flags, so we can't use the following values:
454// 0x01 == OPT_COMMAND, 0x02 == OPT_TABLE, 0x100 == OPT_ZERO
455#define LIST_N 0x04
456#define LIST_C 0x08
457#define LIST_X 0x10
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000458// helper function for list_rules()
Bart De Schuymer60332e02002-06-23 08:01:47 +0000459static void list_em(struct ebt_u_entries *entries)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000460{
461 int i, j, space = 0, digits;
462 struct ebt_u_entry *hlp;
463 struct ebt_u_match_list *m_l;
464 struct ebt_u_watcher_list *w_l;
465 struct ebt_u_match *m;
466 struct ebt_u_watcher *w;
467 struct ebt_u_target *t;
468 char name[21];
469
Bart De Schuymer60332e02002-06-23 08:01:47 +0000470 hlp = entries->entries;
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000471 if (replace.flags & LIST_X && entries->policy != EBT_ACCEPT) {
472 printf("ebtables -t %s -P %s %s\n", replace.name,
473 entries->name, standard_targets[-entries->policy - 1]);
474 } else if (!(replace.flags & LIST_X)) {
Bart De Schuymerc87c9642002-08-01 15:34:16 +0000475 printf("\nBridge chain: %s, entries: %d, policy: %s\n",
476 entries->name, entries->nentries,
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000477 standard_targets[-entries->policy - 1]);
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000478 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000479
Bart De Schuymer60332e02002-06-23 08:01:47 +0000480 i = entries->nentries;
Bart De Schuymerf8f8f292002-06-25 15:43:57 +0000481 while (i > 9) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000482 space++;
483 i /= 10;
484 }
485
Bart De Schuymer60332e02002-06-23 08:01:47 +0000486 for (i = 0; i < entries->nentries; i++) {
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000487 if (replace.flags & LIST_N) {
488 digits = 0;
489 // A little work to get nice rule numbers.
490 j = i + 1;
491 while (j > 9) {
492 digits++;
493 j /= 10;
494 }
495 for (j = 0; j < space - digits; j++)
496 printf(" ");
497 printf("%d. ", i + 1);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000498 }
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000499 if (replace.flags & LIST_X)
500 printf("ebtables -t %s -A %s ",
501 replace.name, entries->name);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000502
503 // Don't print anything about the protocol if no protocol was
504 // specified, obviously this means any protocol will do.
505 if (!(hlp->bitmask & EBT_NOPROTO)) {
Bart De Schuymer60332e02002-06-23 08:01:47 +0000506 printf("-p ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000507 if (hlp->invflags & EBT_IPROTO)
508 printf("! ");
509 if (hlp->bitmask & EBT_802_3)
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000510 printf("Length ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000511 else {
512 if (number_to_name(ntohs(hlp->ethproto), name))
Bart De Schuymer60332e02002-06-23 08:01:47 +0000513 printf("0x%x ", ntohs(hlp->ethproto));
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000514 else
Bart De Schuymer60332e02002-06-23 08:01:47 +0000515 printf("%s ", name);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000516 }
517 }
518 if (hlp->bitmask & EBT_SOURCEMAC) {
519 char hlpmsk[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
520
Bart De Schuymer60332e02002-06-23 08:01:47 +0000521 printf("-s ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000522 if (hlp->invflags & EBT_ISOURCE)
523 printf("! ");
524 if (!memcmp(hlp->sourcemac, mac_type_unicast, 6) &&
525 !memcmp(hlp->sourcemsk, msk_type_unicast, 6)) {
526 printf("Unicast");
527 goto endsrc;
528 }
529 if (!memcmp(hlp->sourcemac, mac_type_multicast, 6) &&
530 !memcmp(hlp->sourcemsk, msk_type_multicast, 6)) {
531 printf("Multicast");
532 goto endsrc;
533 }
534 if (!memcmp(hlp->sourcemac, mac_type_broadcast, 6) &&
535 !memcmp(hlp->sourcemsk, msk_type_broadcast, 6)) {
536 printf("Broadcast");
537 goto endsrc;
538 }
Bart De Schuymer41830412002-06-05 19:41:28 +0000539 printf("%s", ether_ntoa((struct ether_addr *)
540 hlp->sourcemac));
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000541 if (memcmp(hlp->sourcemsk, hlpmsk, 6)) {
542 printf("/");
Bart De Schuymer41830412002-06-05 19:41:28 +0000543 printf("%s", ether_ntoa((struct ether_addr *)
544 hlp->sourcemsk));
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000545 }
546endsrc:
Bart De Schuymer60332e02002-06-23 08:01:47 +0000547 printf(" ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000548 }
549 if (hlp->bitmask & EBT_DESTMAC) {
550 char hlpmsk[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
551
Bart De Schuymer60332e02002-06-23 08:01:47 +0000552 printf("-d ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000553 if (hlp->invflags & EBT_IDEST)
554 printf("! ");
555 if (!memcmp(hlp->destmac, mac_type_unicast, 6) &&
556 !memcmp(hlp->destmsk, msk_type_unicast, 6)) {
557 printf("Unicast");
558 goto enddst;
559 }
560 if (!memcmp(hlp->destmac, mac_type_multicast, 6) &&
561 !memcmp(hlp->destmsk, msk_type_multicast, 6)) {
562 printf("Multicast");
563 goto enddst;
564 }
565 if (!memcmp(hlp->destmac, mac_type_broadcast, 6) &&
566 !memcmp(hlp->destmsk, msk_type_broadcast, 6)) {
567 printf("Broadcast");
568 goto enddst;
569 }
Bart De Schuymer41830412002-06-05 19:41:28 +0000570 printf("%s", ether_ntoa((struct ether_addr *)
571 hlp->destmac));
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000572 if (memcmp(hlp->destmsk, hlpmsk, 6)) {
573 printf("/");
Bart De Schuymer41830412002-06-05 19:41:28 +0000574 printf("%s", ether_ntoa((struct ether_addr *)
575 hlp->destmsk));
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000576 }
577enddst:
Bart De Schuymer60332e02002-06-23 08:01:47 +0000578 printf(" ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000579 }
580 if (hlp->in[0] != '\0') {
Bart De Schuymer60332e02002-06-23 08:01:47 +0000581 printf("-i ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000582 if (hlp->invflags & EBT_IIN)
583 printf("! ");
Bart De Schuymer60332e02002-06-23 08:01:47 +0000584 printf("%s ", hlp->in);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000585 }
586 if (hlp->logical_in[0] != '\0') {
Bart De Schuymer60332e02002-06-23 08:01:47 +0000587 printf("--logical-in ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000588 if (hlp->invflags & EBT_ILOGICALIN)
589 printf("! ");
Bart De Schuymer60332e02002-06-23 08:01:47 +0000590 printf("%s ", hlp->logical_in);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000591 }
592 if (hlp->logical_out[0] != '\0') {
Bart De Schuymer60332e02002-06-23 08:01:47 +0000593 printf("--logical-out ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000594 if (hlp->invflags & EBT_ILOGICALOUT)
595 printf("! ");
Bart De Schuymerb3d8f262002-07-07 14:26:15 +0000596 printf("%s ", hlp->logical_out);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000597 }
598 if (hlp->out[0] != '\0') {
Bart De Schuymer60332e02002-06-23 08:01:47 +0000599 printf("-o ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000600 if (hlp->invflags & EBT_IOUT)
601 printf("! ");
Bart De Schuymerb3d8f262002-07-07 14:26:15 +0000602 printf("%s ", hlp->out);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000603 }
604
605 m_l = hlp->m_list;
606 while (m_l) {
607 m = find_match(m_l->m->u.name);
608 if (!m)
609 print_bug("Match not found");
610 m->print(hlp, m_l->m);
611 m_l = m_l->next;
612 }
613 w_l = hlp->w_list;
614 while (w_l) {
615 w = find_watcher(w_l->w->u.name);
616 if (!w)
617 print_bug("Watcher not found");
618 w->print(hlp, w_l->w);
619 w_l = w_l->next;
620 }
621
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000622 printf("-j ");
623 if (strcmp(hlp->t->u.name, EBT_STANDARD_TARGET))
624 printf("%s ", hlp->t->u.name);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000625 t = find_target(hlp->t->u.name);
626 if (!t)
627 print_bug("Target not found");
628 t->print(hlp, hlp->t);
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000629 if (replace.flags & LIST_C)
630 printf(", count = %llu",
631 replace.counters[entries->counter_offset + i].pcnt);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000632 printf("\n");
633 hlp = hlp->next;
634 }
635}
636
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000637struct ebt_u_entries *nr_to_chain(int nr)
Bart De Schuymer60332e02002-06-23 08:01:47 +0000638{
639 if (nr == -1)
640 return NULL;
641 if (nr < NF_BR_NUMHOOKS)
642 return replace.hook_entry[nr];
643 else {
644 int i;
645 struct ebt_u_chain_list *cl = replace.udc;
646
647 i = nr - NF_BR_NUMHOOKS;
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000648 while (i > 0 && cl) {
Bart De Schuymer60332e02002-06-23 08:01:47 +0000649 cl = cl->next;
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000650 i--;
651 }
Bart De Schuymer60332e02002-06-23 08:01:47 +0000652 if (cl)
653 return cl->udc;
654 else
655 return NULL;
656 }
657}
658
659static struct ebt_u_entries *to_chain()
660{
661 return nr_to_chain(replace.selected_hook);
662}
663
664struct ebt_u_stack
665{
666 int chain_nr;
667 int n;
668 struct ebt_u_entry *e;
669 struct ebt_u_entries *entries;
670};
671
Bart De Schuymer62423742002-07-14 19:06:20 +0000672static void check_for_loops()
Bart De Schuymer60332e02002-06-23 08:01:47 +0000673{
674 int chain_nr , i, j , k, sp = 0, verdict;
675 struct ebt_u_entries *entries, *entries2;
676 struct ebt_u_stack *stack = NULL;
677 struct ebt_u_entry *e;
678
679 i = -1;
680 // initialize hook_mask to 0
681 while (1) {
682 i++;
683 if (i < NF_BR_NUMHOOKS && !(replace.valid_hooks & (1 << i)))
684 continue;
685 entries = nr_to_chain(i);
686 if (!entries)
687 break;
688 entries->hook_mask = 0;
689 }
690 if (i > NF_BR_NUMHOOKS) {
691 stack = (struct ebt_u_stack *)malloc((i - NF_BR_NUMHOOKS) *
692 sizeof(struct ebt_u_stack));
693 if (!stack)
694 print_memory();
695 }
696
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000697 // check for loops, starting from every base chain
Bart De Schuymer60332e02002-06-23 08:01:47 +0000698 for (i = 0; i < NF_BR_NUMHOOKS; i++) {
699 if (!(replace.valid_hooks & (1 << i)))
700 continue;
701 entries = nr_to_chain(i);
Bart De Schuymerb26649e2002-07-25 14:51:54 +0000702 // (1 << NF_BR_NUMHOOKS) implies it's a standard chain
703 // (usefull in the final_check() funtions)
704 entries->hook_mask = (1 << i) | (1 << NF_BR_NUMHOOKS);
Bart De Schuymer60332e02002-06-23 08:01:47 +0000705 chain_nr = i;
706
707 e = entries->entries;
708 for (j = 0; j < entries->nentries; j++) {
709 if (strcmp(e->t->u.name, EBT_STANDARD_TARGET))
710 goto letscontinue;
711 verdict = ((struct ebt_standard_target *)(e->t))->verdict;
712 if (verdict < 0)
713 goto letscontinue;
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000714 entries2 = nr_to_chain(verdict + NF_BR_NUMHOOKS);
Bart De Schuymer60332e02002-06-23 08:01:47 +0000715 entries2->hook_mask |= entries->hook_mask;
716 // now see if we've been here before
717 for (k = 0; k < sp; k++)
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000718 if (stack[k].chain_nr == verdict + NF_BR_NUMHOOKS)
Bart De Schuymer1a0a9c32002-06-24 21:10:16 +0000719 print_error("Loop from chain %s to chain %s",
Bart De Schuymerc56a31a2002-07-25 08:16:08 +0000720 nr_to_chain(chain_nr)->name,
721 nr_to_chain(stack[k].chain_nr)->name);
Bart De Schuymer60332e02002-06-23 08:01:47 +0000722 // jump to the chain, make sure we know how to get back
723 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 Schuymerdd5594b2002-06-26 18:05:20 +0000736 // we are at the end of a standard chain
Bart De Schuymer60332e02002-06-23 08:01:47 +0000737 if (sp == 0)
738 continue;
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000739 // go back to the chain one level higher
Bart De Schuymer60332e02002-06-23 08:01:47 +0000740 sp--;
741 j = stack[sp].n;
742 chain_nr = stack[sp].chain_nr;
743 e = stack[sp].e;
744 entries = stack[sp].entries;
745 goto letscontinue;
746 }
747 free(stack);
748 return;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000749}
750
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000751// parse the chain name and return the corresponding nr
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000752// returns -1 on failure
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000753int get_hooknr(char* arg)
754{
755 int i;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000756 struct ebt_u_chain_list *cl = replace.udc;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000757
Bart De Schuymer60332e02002-06-23 08:01:47 +0000758 for (i = 0; i < NF_BR_NUMHOOKS; i++) {
759 if (!(replace.valid_hooks & (1 << i)))
760 continue;
761 if (!strcmp(arg, replace.hook_entry[i]->name))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000762 return i;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000763 }
764 while(cl) {
765 if (!strcmp(arg, cl->udc->name))
766 return i;
767 i++;
768 cl = cl->next;
769 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000770 return -1;
771}
772
773// yup, print out help
Bart De Schuymer62423742002-07-14 19:06:20 +0000774static void print_help()
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000775{
776 struct ebt_u_match_list *m_l;
777 struct ebt_u_watcher_list *w_l;
778
779 printf(
780"%s v%s\n"
781"Usage:\n"
782"ebtables -[ADI] chain rule-specification [options]\n"
783"ebtables -P chain target\n"
784"ebtables -[LFZ] [chain]\n"
785"ebtables -[b] [y,n]\n"
786"Commands:\n"
787"--append -A chain : Append to chain\n"
788"--delete -D chain : Delete matching rule from chain\n"
789"--delete -D chain rulenum : Delete rule at position rulenum from chain\n"
790"--insert -I chain rulenum : insert rule at position rulenum in chain\n"
791"--list -L [chain] : List the rules in a chain or in all chains\n"
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000792"--flush -F [chain] : Delete all rules in chain or in all chains\n"
Bart De Schuymer8d1d8942002-07-15 20:09:09 +0000793"--init-table : Replace the kernel table with the initial table\n"
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000794"--zero -Z [chain] : Put counters on zero in chain or in all chains\n"
795"--policy -P chain target : Change policy on chain to target\n"
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000796"--new-chain -N chain : Create a user defined chain\n"
797"--rename-chain -E old new : Rename a chain\n"
798"--delete-chain -X chain : Delete a user defined chain\n"
Bart De Schuymer62423742002-07-14 19:06:20 +0000799"--atomic-commit file : update the kernel w/ the table contained in file\n"
800"--atomic-init file : put the initial kernel table into file\n"
801"--atomic-save file : put the current kernel table into file\n"
802"--atomic file : write changes to file instead of kernel\n"
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000803"Options:\n"
804"--proto -p [!] proto : protocol hexadecimal, by name or LENGTH\n"
805"--src -s [!] address[/mask]: source mac address\n"
806"--dst -d [!] address[/mask]: destination mac address\n"
807"--in-if -i [!] name : network input interface name\n"
808"--out-if -o [!] name : network output interface name\n"
809"--logical-in [!] name : logical bridge input interface name\n"
810"--logical-out [!] name : logical bridge output interface name\n"
Bart De Schuymer5cbc8e02002-07-14 21:15:28 +0000811"--modprobe -M program : try to insert modules using this program\n"
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000812"--version -V : print package version\n"
813"\n" ,
814 prog_name,
815 prog_version);
816
817 m_l = new_entry->m_list;
818 while (m_l) {
819 ((struct ebt_u_match *)m_l->m)->help();
820 printf("\n");
821 m_l = m_l->next;
822 }
823 w_l = new_entry->w_list;
824 while (w_l) {
825 ((struct ebt_u_watcher *)w_l->w)->help();
826 printf("\n");
827 w_l = w_l->next;
828 }
829 ((struct ebt_u_target *)new_entry->t)->help();
830 printf("\n");
831 if (table->help)
832 table->help(hooknames);
833 exit(0);
834}
835
836// execute command L
837static void list_rules()
838{
839 int i;
840
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000841 if (!(replace.flags & LIST_X))
842 printf("Bridge table: %s\n", table->name);
Bart De Schuymer60332e02002-06-23 08:01:47 +0000843 if (replace.selected_hook != -1) {
844 list_em(to_chain());
845 } else {
846 struct ebt_u_chain_list *cl = replace.udc;
847
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000848 // create new chains and rename standard chains when necessary
849 if (replace.flags & LIST_X) {
850 while (cl) {
851 printf("ebtables -t %s -N %s\n", replace.name,
852 cl->udc->name);
853 cl = cl->next;
854 }
855 cl = replace.udc;
856 for (i = 0; i < NF_BR_NUMHOOKS; i++)
857 if (replace.valid_hooks & (1 << i) &&
858 strcmp(replace.hook_entry[i]->name, hooknames[i]))
859 printf("ebtables -t %s -E %s %s\n",
860 replace.name, hooknames[i],
861 replace.hook_entry[i]->name);
862 }
Bart De Schuymer60332e02002-06-23 08:01:47 +0000863 i = 0;
864 while (1) {
865 if (i < NF_BR_NUMHOOKS) {
866 if (replace.valid_hooks & (1 << i))
867 list_em(replace.hook_entry[i]);
868 i++;
869 continue;
870 } else {
871 if (!cl)
872 break;
873 list_em(cl->udc);
874 cl = cl->next;
875 }
876 }
877 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000878}
879
880// execute command P
881static void change_policy(int policy)
882{
883 int i;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000884 struct ebt_u_entries *entries = to_chain();
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000885
886 // don't do anything if the policy is the same
Bart De Schuymer60332e02002-06-23 08:01:47 +0000887 if (entries->policy != policy) {
888 entries->policy = policy;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000889 replace.num_counters = replace.nentries;
890 if (replace.nentries) {
891 // '+ 1' for the CNT_END
Bart De Schuymered053432002-07-21 19:35:39 +0000892 if (!(replace.counterchanges = (unsigned short *) malloc(
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000893 (replace.nentries + 1) * sizeof(unsigned short))))
894 print_memory();
895 // done nothing special to the rules
896 for (i = 0; i < replace.nentries; i++)
Bart De Schuymered053432002-07-21 19:35:39 +0000897 replace.counterchanges[i] = CNT_NORM;
898 replace.counterchanges[replace.nentries] = CNT_END;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000899 }
900 else
Bart De Schuymered053432002-07-21 19:35:39 +0000901 replace.counterchanges = NULL;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000902 }
903 else
904 exit(0);
905}
906
907// flush one chain or the complete table
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000908// -1 == nothing to do
909// 0 == give back to kernel
910static int flush_chains()
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000911{
Bart De Schuymer60332e02002-06-23 08:01:47 +0000912 int i, j, oldnentries, numdel;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000913 unsigned short *cnt;
914 struct ebt_u_entry *u_e, *tmp;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000915 struct ebt_u_entries *entries = to_chain();
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000916
917 // flush whole table
Bart De Schuymer60332e02002-06-23 08:01:47 +0000918 if (!entries) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000919 if (replace.nentries == 0)
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000920 return -1;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000921 replace.nentries = 0;
922 // no need for the kernel to give us counters back
923 replace.num_counters = 0;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000924
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000925 // free everything and zero (n)entries
Bart De Schuymer60332e02002-06-23 08:01:47 +0000926 i = -1;
927 while (1) {
928 i++;
929 entries = nr_to_chain(i);
930 if (!entries) {
931 if (i < NF_BR_NUMHOOKS)
932 continue;
933 else
934 break;
935 }
936 entries->nentries = 0;
937 entries->counter_offset = 0;
938 u_e = entries->entries;
939 entries->entries = NULL;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000940 while (u_e) {
941 free_u_entry(u_e);
942 tmp = u_e->next;
943 free(u_e);
944 u_e = tmp;
945 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000946 }
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000947 return 0;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000948 }
949
Bart De Schuymer60332e02002-06-23 08:01:47 +0000950 if (entries->nentries == 0)
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000951 return -1;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000952 oldnentries = replace.nentries;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000953 replace.nentries -= entries->nentries;
954 numdel = entries->nentries;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000955
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000956 if (replace.nentries) {
957 // +1 for CNT_END
Bart De Schuymered053432002-07-21 19:35:39 +0000958 if ( !(replace.counterchanges = (unsigned short *)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000959 malloc((oldnentries + 1) * sizeof(unsigned short))) )
960 print_memory();
Bart De Schuymer60332e02002-06-23 08:01:47 +0000961 }
962 // delete the counters belonging to the specified chain,
963 // update counter_offset
964 i = -1;
Bart De Schuymered053432002-07-21 19:35:39 +0000965 cnt = replace.counterchanges;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000966 while (1) {
967 i++;
968 entries = nr_to_chain(i);
969 if (!entries) {
970 if (i < NF_BR_NUMHOOKS)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000971 continue;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000972 else
973 break;
974 }
975 if (i > replace.selected_hook)
976 entries->counter_offset -= numdel;
977 if (replace.nentries) {
978 for (j = 0; j < entries->nentries; j++) {
979 if (i == replace.selected_hook)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000980 *cnt = CNT_DEL;
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000981 else
982 *cnt = CNT_NORM;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000983 cnt++;
984 }
985 }
Bart De Schuymer60332e02002-06-23 08:01:47 +0000986 }
987
988 if (replace.nentries) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000989 *cnt = CNT_END;
990 replace.num_counters = oldnentries;
991 }
992 else
993 replace.num_counters = 0;
994
Bart De Schuymer60332e02002-06-23 08:01:47 +0000995 entries = to_chain();
996 entries->nentries = 0;
997 u_e = entries->entries;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000998 while (u_e) {
999 free_u_entry(u_e);
1000 tmp = u_e->next;
1001 free(u_e);
1002 u_e = tmp;
1003 }
Bart De Schuymer60332e02002-06-23 08:01:47 +00001004 entries->entries = NULL;
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001005 return 0;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001006}
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001007
1008// -1 == no match
1009static int check_rule_exists(int rule_nr)
1010{
1011 struct ebt_u_entry *u_e;
1012 struct ebt_u_match_list *m_l, *m_l2;
1013 struct ebt_u_match *m;
1014 struct ebt_u_watcher_list *w_l, *w_l2;
1015 struct ebt_u_watcher *w;
1016 struct ebt_u_target *t = (struct ebt_u_target *)new_entry->t;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001017 struct ebt_u_entries *entries = to_chain();
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001018 int i, j, k;
1019
1020 // handle '-D chain rulenr' command
1021 if (rule_nr != -1) {
Bart De Schuymer60332e02002-06-23 08:01:47 +00001022 if (rule_nr > entries->nentries)
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001023 return -1;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001024 // user starts counting from 1
1025 return rule_nr - 1;
1026 }
Bart De Schuymer60332e02002-06-23 08:01:47 +00001027 u_e = entries->entries;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001028 // check for an existing rule (if there are duplicate rules,
1029 // take the first occurance)
Bart De Schuymer60332e02002-06-23 08:01:47 +00001030 for (i = 0; i < entries->nentries; i++, u_e = u_e->next) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001031 if (!u_e)
1032 print_bug("Hmm, trouble");
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001033 if (u_e->ethproto != new_entry->ethproto)
1034 continue;
1035 if (strcmp(u_e->in, new_entry->in))
1036 continue;
1037 if (strcmp(u_e->out, new_entry->out))
1038 continue;
1039 if (strcmp(u_e->logical_in, new_entry->logical_in))
1040 continue;
1041 if (strcmp(u_e->logical_out, new_entry->logical_out))
1042 continue;
1043 if (new_entry->bitmask & EBT_SOURCEMAC &&
1044 memcmp(u_e->sourcemac, new_entry->sourcemac, ETH_ALEN))
1045 continue;
1046 if (new_entry->bitmask & EBT_DESTMAC &&
1047 memcmp(u_e->destmac, new_entry->destmac, ETH_ALEN))
1048 continue;
1049 if (new_entry->bitmask != u_e->bitmask ||
1050 new_entry->invflags != u_e->invflags)
1051 continue;
1052 // compare all matches
1053 m_l = new_entry->m_list;
1054 j = 0;
1055 while (m_l) {
1056 m = (struct ebt_u_match *)(m_l->m);
1057 m_l2 = u_e->m_list;
1058 while (m_l2 && strcmp(m_l2->m->u.name, m->m->u.name))
1059 m_l2 = m_l2->next;
1060 if (!m_l2 || !m->compare(m->m, m_l2->m))
1061 goto letscontinue;
1062 j++;
1063 m_l = m_l->next;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001064 }
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001065 // now be sure they have the same nr of matches
1066 k = 0;
1067 m_l = u_e->m_list;
1068 while (m_l) {
1069 k++;
1070 m_l = m_l->next;
1071 }
1072 if (j != k)
1073 continue;
1074
1075 // compare all watchers
1076 w_l = new_entry->w_list;
1077 j = 0;
1078 while (w_l) {
1079 w = (struct ebt_u_watcher *)(w_l->w);
1080 w_l2 = u_e->w_list;
1081 while (w_l2 && strcmp(w_l2->w->u.name, w->w->u.name))
1082 w_l2 = w_l2->next;
1083 if (!w_l2 || !w->compare(w->w, w_l2->w))
1084 goto letscontinue;
1085 j++;
1086 w_l = w_l->next;
1087 }
1088 k = 0;
1089 w_l = u_e->w_list;
1090 while (w_l) {
1091 k++;
1092 w_l = w_l->next;
1093 }
1094 if (j != k)
1095 continue;
1096 if (strcmp(t->t->u.name, u_e->t->u.name))
1097 continue;
1098 if (!t->compare(t->t, u_e->t))
1099 continue;
1100 return i;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001101letscontinue:
1102 }
1103 return -1;
1104}
1105
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001106// execute command A or I
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001107static void add_rule(int rule_nr)
1108{
1109 int i, j;
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001110 struct ebt_u_entry **u_e;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001111 unsigned short *cnt;
1112 struct ebt_u_match_list *m_l;
1113 struct ebt_u_watcher_list *w_l;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001114 struct ebt_u_entries *entries = to_chain(), *entries2;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001115
1116 if (rule_nr != -1) { // command -I
Bart De Schuymer60332e02002-06-23 08:01:47 +00001117 if (--rule_nr > entries->nentries)
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001118 print_error("rule nr too high: %d > %d", rule_nr + 1,
1119 entries->nentries + 1);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001120 } else
Bart De Schuymer60332e02002-06-23 08:01:47 +00001121 rule_nr = entries->nentries;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001122 // we're adding one rule
1123 replace.num_counters = replace.nentries;
1124 replace.nentries++;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001125 entries->nentries++;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001126
1127 // handle counter stuff
1128 // +1 for CNT_END
Bart De Schuymered053432002-07-21 19:35:39 +00001129 if ( !(replace.counterchanges = (unsigned short *)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001130 malloc((replace.nentries + 1) * sizeof(unsigned short))) )
1131 print_memory();
Bart De Schuymered053432002-07-21 19:35:39 +00001132 cnt = replace.counterchanges;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001133 for (i = 0; i < replace.selected_hook; i++) {
Bart De Schuymer60332e02002-06-23 08:01:47 +00001134 if (i < NF_BR_NUMHOOKS && !(replace.valid_hooks & (1 << i)))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001135 continue;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001136 entries2 = nr_to_chain(i);
1137 for (j = 0; j < entries2->nentries; j++) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001138 *cnt = CNT_NORM;
1139 cnt++;
1140 }
1141 }
1142 for (i = 0; i < rule_nr; i++) {
1143 *cnt = CNT_NORM;
1144 cnt++;
1145 }
1146 *cnt = CNT_ADD;
1147 cnt++;
Bart De Schuymered053432002-07-21 19:35:39 +00001148 while (cnt != replace.counterchanges + replace.nentries) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001149 *cnt = CNT_NORM;
1150 cnt++;
1151 }
1152 *cnt = CNT_END;
1153
1154 // go to the right position in the chain
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001155 u_e = &entries->entries;
1156 for (i = 0; i < rule_nr; i++)
1157 u_e = &(*u_e)->next;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001158 // insert the rule
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001159 new_entry->next = *u_e;
1160 *u_e = new_entry;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001161
1162 // put the ebt_[match, watcher, target] pointers in place
1163 m_l = new_entry->m_list;
1164 while (m_l) {
1165 m_l->m = ((struct ebt_u_match *)m_l->m)->m;
1166 m_l = m_l->next;
1167 }
1168 w_l = new_entry->w_list;
1169 while (w_l) {
1170 w_l->w = ((struct ebt_u_watcher *)w_l->w)->w;
1171 w_l = w_l->next;
1172 }
1173 new_entry->t = ((struct ebt_u_target *)new_entry->t)->t;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001174
1175 // update the counter_offset of chains behind this one
1176 i = replace.selected_hook;
1177 while (1) {
1178 i++;
1179 entries = nr_to_chain(i);
1180 if (!entries) {
1181 if (i < NF_BR_NUMHOOKS)
1182 continue;
1183 else
1184 break;
1185 } else
1186 entries->counter_offset++;
1187 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001188}
1189
1190// execute command D
1191static void delete_rule(int rule_nr)
1192{
1193 int i, j, lentmp = 0;
1194 unsigned short *cnt;
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001195 struct ebt_u_entry **u_e, *u_e2;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001196 struct ebt_u_entries *entries = to_chain(), *entries2;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001197
1198 if ( (i = check_rule_exists(rule_nr)) == -1 )
Bart De Schuymer60332e02002-06-23 08:01:47 +00001199 print_error("Sorry, rule does not exist");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001200
1201 // we're deleting a rule
1202 replace.num_counters = replace.nentries;
1203 replace.nentries--;
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001204 entries->nentries--;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001205
1206 if (replace.nentries) {
1207 for (j = 0; j < replace.selected_hook; j++) {
Bart De Schuymer60332e02002-06-23 08:01:47 +00001208 if (j < NF_BR_NUMHOOKS &&
1209 !(replace.valid_hooks & (1 << j)))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001210 continue;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001211 entries2 = nr_to_chain(j);
1212 lentmp += entries2->nentries;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001213 }
1214 lentmp += i;
1215 // +1 for CNT_END
Bart De Schuymered053432002-07-21 19:35:39 +00001216 if ( !(replace.counterchanges = (unsigned short *)malloc(
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001217 (replace.num_counters + 1) * sizeof(unsigned short))) )
1218 print_memory();
Bart De Schuymered053432002-07-21 19:35:39 +00001219 cnt = replace.counterchanges;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001220 for (j = 0; j < lentmp; j++) {
1221 *cnt = CNT_NORM;
1222 cnt++;
1223 }
1224 *cnt = CNT_DEL;
1225 cnt++;
1226 for (j = 0; j < replace.num_counters - lentmp; j++) {
1227 *cnt = CNT_NORM;
1228 cnt++;
1229 }
1230 *cnt = CNT_END;
1231 }
1232 else
1233 replace.num_counters = 0;
1234
1235 // go to the right position in the chain
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001236 u_e = &entries->entries;
1237 for (j = 0; j < i; j++)
1238 u_e = &(*u_e)->next;
1239 // remove the rule
1240 u_e2 = *u_e;
1241 *u_e = (*u_e)->next;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001242 // free everything
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001243 free_u_entry(u_e2);
1244 free(u_e2);
1245
Bart De Schuymer60332e02002-06-23 08:01:47 +00001246 // update the counter_offset of chains behind this one
1247 i = replace.selected_hook;
1248 while (1) {
1249 i++;
1250 entries = nr_to_chain(i);
1251 if (!entries) {
1252 if (i < NF_BR_NUMHOOKS)
1253 continue;
1254 else
1255 break;
1256 } else
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001257 entries->counter_offset--;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001258 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001259}
1260
1261// execute command Z
Bart De Schuymer62423742002-07-14 19:06:20 +00001262static void zero_counters(int zerochain)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001263{
1264
1265 if (zerochain == -1) {
1266 // tell main() we don't update the counters
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001267 // this results in tricking the kernel to zero its counters,
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001268 // naively expecting userspace to update its counters. Muahahaha
Bart De Schuymered053432002-07-21 19:35:39 +00001269 replace.counterchanges = NULL;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001270 replace.num_counters = 0;
1271 } else {
1272 int i, j;
1273 unsigned short *cnt;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001274 struct ebt_u_entries *entries = nr_to_chain(zerochain), *e2;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001275
Bart De Schuymer60332e02002-06-23 08:01:47 +00001276 if (entries->nentries == 0)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001277 exit(0);
Bart De Schuymered053432002-07-21 19:35:39 +00001278 replace.counterchanges = (unsigned short *)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001279 malloc((replace.nentries + 1) * sizeof(unsigned short));
Bart De Schuymered053432002-07-21 19:35:39 +00001280 if (!replace.counterchanges)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001281 print_memory();
Bart De Schuymered053432002-07-21 19:35:39 +00001282 cnt = replace.counterchanges;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001283 for (i = 0; i < zerochain; i++) {
Bart De Schuymer60332e02002-06-23 08:01:47 +00001284 if (i < NF_BR_NUMHOOKS &&
1285 !(replace.valid_hooks & (1 << i)))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001286 continue;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001287 e2 = nr_to_chain(i);
1288 for (j = 0; j < e2->nentries; j++) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001289 *cnt = CNT_NORM;
1290 cnt++;
1291 }
1292 }
Bart De Schuymer60332e02002-06-23 08:01:47 +00001293 for (i = 0; i < entries->nentries; i++) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001294 *cnt = CNT_ZERO;
1295 cnt++;
1296 }
Bart De Schuymered053432002-07-21 19:35:39 +00001297 while (cnt != replace.counterchanges + replace.nentries) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001298 *cnt = CNT_NORM;
1299 cnt++;
1300 }
1301 *cnt = CNT_END;
1302 }
1303}
1304
Bart De Schuymer28bf6f62002-06-26 18:57:24 +00001305// 0 == success
1306// 1 == success, but for the special 'protocol' LENGTH
1307// -1 == failure
1308int name_to_number(char *name, __u16 *proto)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001309{
1310 FILE *ifp;
Bart De Schuymerf662ce52002-07-19 18:40:55 +00001311 char buffer[21], value[11], *bfr;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001312 unsigned short i;
1313
1314 if (!strcasecmp("LENGTH", name)) {
Bart De Schuymer28bf6f62002-06-26 18:57:24 +00001315 *proto = 0;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001316 new_entry->bitmask |= EBT_802_3;
1317 return 1;
1318 }
1319 if ( !(ifp = fopen(PROTOCOLFILE, "r")) )
1320 return -1;
1321 while (1) {
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001322 if (get_a_line(buffer, value, ifp))
1323 return -1;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001324 if (strcasecmp(buffer, name))
1325 continue;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001326 fclose(ifp);
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001327 i = (unsigned short) strtol(value, &bfr, 16);
1328 if (*bfr != '\0')
1329 return -1;
1330 *proto = i;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001331 return 0;
1332 }
1333 return -1;
1334}
1335
1336// put the mac address into 6 (ETH_ALEN) bytes
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001337int getmac_and_mask(char *from, char *to, char *mask)
1338{
1339 char *p;
1340 int i;
Bart De Schuymer41830412002-06-05 19:41:28 +00001341 struct ether_addr *addr;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001342
1343 if (strcasecmp(from, "Unicast") == 0) {
1344 memcpy(to, mac_type_unicast, ETH_ALEN);
1345 memcpy(mask, msk_type_unicast, ETH_ALEN);
1346 return 0;
1347 }
1348 if (strcasecmp(from, "Multicast") == 0) {
1349 memcpy(to, mac_type_multicast, ETH_ALEN);
1350 memcpy(mask, msk_type_multicast, ETH_ALEN);
1351 return 0;
1352 }
1353 if (strcasecmp(from, "Broadcast") == 0) {
1354 memcpy(to, mac_type_broadcast, ETH_ALEN);
1355 memcpy(mask, msk_type_broadcast, ETH_ALEN);
1356 return 0;
1357 }
1358 if ( (p = strrchr(from, '/')) != NULL) {
1359 *p = '\0';
Bart De Schuymer41830412002-06-05 19:41:28 +00001360 if (!(addr = ether_aton(p + 1)))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001361 return -1;
Bart De Schuymer41830412002-06-05 19:41:28 +00001362 memcpy(mask, addr, ETH_ALEN);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001363 } else
1364 memset(mask, 0xff, ETH_ALEN);
Bart De Schuymer41830412002-06-05 19:41:28 +00001365 if (!(addr = ether_aton(from)))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001366 return -1;
Bart De Schuymer41830412002-06-05 19:41:28 +00001367 memcpy(to, addr, ETH_ALEN);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001368 for (i = 0; i < ETH_ALEN; i++)
1369 to[i] &= mask[i];
1370 return 0;
1371}
1372
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001373// executes the final_check() function for all extensions used by the rule
Bart De Schuymer62423742002-07-14 19:06:20 +00001374static void do_final_checks(struct ebt_u_entry *e, struct ebt_u_entries *entries)
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +00001375{
1376 struct ebt_u_match_list *m_l;
1377 struct ebt_u_watcher_list *w_l;
1378 struct ebt_u_target *t;
1379 struct ebt_u_match *m;
1380 struct ebt_u_watcher *w;
1381
1382 m_l = e->m_list;
1383 w_l = e->w_list;
1384 while (m_l) {
1385 m = find_match(m_l->m->u.name);
1386 m->final_check(e, m_l->m, replace.name,
1387 entries->hook_mask, 1);
1388 m_l = m_l->next;
1389 }
1390 while (w_l) {
1391 w = find_watcher(w_l->w->u.name);
1392 w->final_check(e, w_l->w, replace.name,
1393 entries->hook_mask, 1);
1394 w_l = w_l->next;
1395 }
1396 t = find_target(e->t->u.name);
1397 t->final_check(e, e->t, replace.name,
1398 entries->hook_mask, 1);
1399}
1400
Bart De Schuymerb909f9b2002-06-26 18:35:31 +00001401// used for the -X command
Bart De Schuymer62423742002-07-14 19:06:20 +00001402static void check_for_references(int chain_nr)
Bart De Schuymerb909f9b2002-06-26 18:35:31 +00001403{
1404 int i = -1, j;
1405 struct ebt_u_entries *entries;
1406 struct ebt_u_entry *e;
1407
1408 while (1) {
1409 i++;
1410 entries = nr_to_chain(i);
1411 if (!entries) {
1412 if (i < NF_BR_NUMHOOKS)
1413 continue;
1414 else
1415 break;
1416 }
1417 e = entries->entries;
1418 j = 0;
1419 while (e) {
1420 j++;
1421 if (strcmp(e->t->u.name, EBT_STANDARD_TARGET)) {
1422 e = e->next;
1423 continue;
1424 }
1425 if (((struct ebt_standard_target *)e->t)->verdict == chain_nr)
1426 print_error("Can't delete the chain, it's referenced "
1427 "in chain %s, rule %d", entries->name, j);
1428 e = e->next;
1429 }
1430 }
1431}
1432
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001433int check_inverse(const char option[])
1434{
1435 if (strcmp(option, "!") == 0) {
1436 optind++;
1437 return 1;
1438 }
1439 return 0;
1440}
1441
1442void check_option(unsigned int *flags, unsigned int mask)
1443{
1444 if (*flags & mask)
1445 print_error("Multiple use of same option not allowed");
1446 *flags |= mask;
1447}
1448
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001449static void get_kernel_table(const char *modprobe)
1450{
1451 if ( !(table = find_table(replace.name)) )
1452 print_error("Bad table name");
1453 // get the kernel's information
1454 if (get_table(&replace)) {
1455 ebtables_insmod("ebtables", modprobe);
1456 if (get_table(&replace))
1457 print_error("The kernel doesn't support the ebtables "
1458 "%s table", replace.name);
1459 }
1460}
1461
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001462#define OPT_COMMAND 0x01
1463#define OPT_TABLE 0x02
1464#define OPT_IN 0x04
1465#define OPT_OUT 0x08
1466#define OPT_JUMP 0x10
1467#define OPT_PROTOCOL 0x20
1468#define OPT_SOURCE 0x40
1469#define OPT_DEST 0x80
1470#define OPT_ZERO 0x100
1471#define OPT_LOGICALIN 0x200
1472#define OPT_LOGICALOUT 0x400
1473// the main thing
1474int main(int argc, char *argv[])
1475{
Bart De Schuymer923a5732002-08-11 12:01:33 +00001476 char *buffer;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001477 int c, i;
1478 // this special one for the -Z option (we can have -Z <this> -L <that>)
1479 int zerochain = -1;
Bart De Schuymerf8f8f292002-06-25 15:43:57 +00001480 int policy = 0;
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001481 int rule_nr = -1;// used for -[D,I] chain number
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001482 struct ebt_u_target *t;
1483 struct ebt_u_match *m;
1484 struct ebt_u_watcher *w;
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001485 struct ebt_u_match_list *m_l;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001486 struct ebt_u_watcher_list *w_l;
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001487 struct ebt_u_entries *entries;
Bart De Schuymerc8531032002-06-14 21:55:29 +00001488 const char *modprobe = NULL;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001489
1490 // initialize the table name, OPT_ flags, selected hook and command
1491 strcpy(replace.name, "filter");
1492 replace.flags = 0;
1493 replace.selected_hook = -1;
1494 replace.command = 'h';
Bart De Schuymer62423742002-07-14 19:06:20 +00001495 replace.filename = NULL;
Bart De Schuymered053432002-07-21 19:35:39 +00001496 replace.counterchanges = NULL;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001497
1498 new_entry = (struct ebt_u_entry *)malloc(sizeof(struct ebt_u_entry));
1499 if (!new_entry)
1500 print_memory();
1501 // put some sane values in our new entry
1502 initialize_entry(new_entry);
1503
Bart De Schuymer60332e02002-06-23 08:01:47 +00001504 // The scenario induced by this loop makes that:
Bart De Schuymer62423742002-07-14 19:06:20 +00001505 // '-t' ,'-M' and --atomic (if specified) have to come
1506 // before '-A' and the like
Bart De Schuymer60332e02002-06-23 08:01:47 +00001507
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001508 // getopt saves the day
1509 while ((c = getopt_long(argc, argv,
Bart De Schuymeraac31142002-08-11 11:57:52 +00001510 "-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 +00001511 switch (c) {
1512
1513 case 'A': // add a rule
1514 case 'D': // delete a rule
1515 case 'P': // define policy
1516 case 'I': // insert a rule
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001517 case 'N': // make a user defined chain
1518 case 'E': // rename chain
1519 case 'X': // delete chain
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001520 replace.command = c;
1521 if (replace.flags & OPT_COMMAND)
1522 print_error("Multiple commands not allowed");
1523 replace.flags |= OPT_COMMAND;
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001524 get_kernel_table(modprobe);
1525 if (optarg[0] == '-' || !strcmp(optarg, "!"))
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001526 print_error("No chain name specified");
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001527 if (c == 'N') {
1528 struct ebt_u_chain_list *cl, **cl2;
1529
1530 if (get_hooknr(optarg) != -1)
1531 print_error("Chain %s already exists",
1532 optarg);
1533 if (find_target(optarg))
1534 print_error("Target with name %s exists"
1535 , optarg);
1536 if (strlen(optarg) >= EBT_CHAIN_MAXNAMELEN)
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001537 print_error("Chain name length can't exceed %d",
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001538 EBT_CHAIN_MAXNAMELEN - 1);
1539 cl = (struct ebt_u_chain_list *)
1540 malloc(sizeof(struct ebt_u_chain_list));
1541 if (!cl)
1542 print_memory();
1543 cl->next = NULL;
1544 cl->udc = (struct ebt_u_entries *)
1545 malloc(sizeof(struct ebt_u_entries));
1546 if (!cl->udc)
1547 print_memory();
1548 cl->udc->nentries = 0;
1549 cl->udc->policy = EBT_ACCEPT;
1550 cl->udc->counter_offset = replace.nentries;
1551 cl->udc->hook_mask = 0;
1552 strcpy(cl->udc->name, optarg);
1553 cl->udc->entries = NULL;
1554 cl->kernel_start = NULL;
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001555 // put the new chain at the end
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001556 cl2 = &replace.udc;
1557 while (*cl2)
1558 cl2 = &((*cl2)->next);
1559 *cl2 = cl;
1560 break;
1561 }
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001562 if ((replace.selected_hook = get_hooknr(optarg)) == -1)
1563 print_error("Chain %s doesn't exist", optarg);
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001564 if (c == 'E') {
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001565 if (optind >= argc || argv[optind][0] == '-' ||
1566 !strcmp(argv[optind], "!"))
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001567 print_error("No new chain name specified");
1568 if (strlen(argv[optind]) >= EBT_CHAIN_MAXNAMELEN)
1569 print_error("Chain name len can't exceed %d",
1570 EBT_CHAIN_MAXNAMELEN - 1);
1571 if (get_hooknr(argv[optind]) != -1)
1572 print_error("Chain %s already exists",
1573 argv[optind]);
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001574 if (find_target(argv[optind]))
1575 print_error("Target with name %s exists"
1576 , argv[optind]);
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001577 entries = to_chain();
1578 strcpy(entries->name, argv[optind]);
1579 optind++;
1580 break;
1581 }
1582 if (c == 'X') {
1583 struct ebt_u_chain_list *cl, **cl2;
1584
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001585 if (replace.selected_hook < NF_BR_NUMHOOKS)
1586 print_error("You can't remove a standard chain");
Bart De Schuymerb909f9b2002-06-26 18:35:31 +00001587 // if the chain is referenced, don't delete it
1588 check_for_references(replace.selected_hook - NF_BR_NUMHOOKS);
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001589 flush_chains();
1590 entries = to_chain();
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001591 cl2 = &(replace.udc);
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001592 while ((*cl2)->udc != entries)
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001593 cl2 = &((*cl2)->next);
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001594 cl = (*cl2);
1595 (*cl2) = (*cl2)->next;
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001596 free(cl->udc);
1597 free(cl);
1598 break;
1599 }
1600
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001601 if ( (c == 'D' && optind < argc &&
1602 argv[optind][0] != '-') || c == 'I') {
1603 if (optind >= argc || argv[optind][0] == '-')
1604 print_error("No rulenr for -I"
1605 " specified");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001606 rule_nr = strtol(argv[optind], &buffer, 10);
1607 if (*buffer != '\0' || rule_nr < 0)
1608 print_error("Problem with the "
1609 "specified rule number");
1610 optind++;
1611 }
1612 if (c == 'P') {
1613 if (optind >= argc)
1614 print_error("No policy specified");
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001615 policy = 0;
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001616 for (i = 0; i < NUM_STANDARD_TARGETS; i++)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001617 if (!strcmp(argv[optind],
1618 standard_targets[i])) {
Bart De Schuymer60332e02002-06-23 08:01:47 +00001619 policy = -i -1;
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001620 if (policy == EBT_CONTINUE)
1621 policy = 0;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001622 break;
1623 }
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001624 if (policy == 0)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001625 print_error("Wrong policy");
1626 optind++;
1627 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001628 break;
1629
1630 case 'L': // list
1631 case 'F': // flush
1632 case 'Z': // zero counters
1633 if (c == 'Z') {
1634 if (replace.flags & OPT_ZERO)
1635 print_error("Multiple commands"
1636 " not allowed");
1637 if ( (replace.flags & OPT_COMMAND &&
1638 replace.command != 'L'))
1639 print_error("command -Z only allowed "
1640 "together with command -L");
1641 replace.flags |= OPT_ZERO;
1642 } else {
1643 replace.command = c;
1644 if (replace.flags & OPT_COMMAND)
1645 print_error("Multiple commands"
1646 " not allowed");
1647 replace.flags |= OPT_COMMAND;
1648 }
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001649 get_kernel_table(modprobe);
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001650 i = -1;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001651 if (optarg) {
1652 if ( (i = get_hooknr(optarg)) == -1 )
1653 print_error("Bad chain");
1654 } else
1655 if (optind < argc && argv[optind][0] != '-') {
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001656 if ((i = get_hooknr(argv[optind])) == -1)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001657 print_error("Bad chain");
1658 optind++;
1659 }
1660 if (i != -1) {
1661 if (c == 'Z')
1662 zerochain = i;
1663 else
1664 replace.selected_hook = i;
1665 }
1666 break;
1667
1668 case 'V': // version
1669 replace.command = 'V';
1670 if (replace.flags & OPT_COMMAND)
1671 print_error("Multiple commands not allowed");
1672 printf("%s, %s\n", prog_name, prog_version);
1673 exit(0);
1674
Bart De Schuymerc8531032002-06-14 21:55:29 +00001675 case 'M': // modprobe
Bart De Schuymer60332e02002-06-23 08:01:47 +00001676 if (replace.command != 'h')
1677 print_error("Please put the -M option earlier");
Bart De Schuymerc8531032002-06-14 21:55:29 +00001678 modprobe = optarg;
1679 break;
1680
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001681 case 'h': // help
1682 if (replace.flags & OPT_COMMAND)
1683 print_error("Multiple commands not allowed");
1684 replace.command = 'h';
1685 // All other arguments should be extension names
1686 while (optind < argc) {
1687 struct ebt_u_match *m;
1688 struct ebt_u_watcher *w;
1689
1690 if ((m = find_match(argv[optind])))
1691 add_match(m);
1692 else if ((w = find_watcher(argv[optind])))
1693 add_watcher(w);
1694 else {
1695 if (!(t = find_target(argv[optind])))
1696 print_error("Extension %s "
1697 "not found", argv[optind]);
1698 if (replace.flags & OPT_JUMP)
1699 print_error("Sorry, you can "
1700 "only see help for one "
1701 "target extension each time");
1702 replace.flags |= OPT_JUMP;
1703 new_entry->t =
1704 (struct ebt_entry_target *)t;
1705 }
1706 optind++;
1707 }
1708 break;
1709
1710 case 't': // table
Bart De Schuymer60332e02002-06-23 08:01:47 +00001711 if (replace.command != 'h')
1712 print_error("Please put the -t option first");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001713 check_option(&replace.flags, OPT_TABLE);
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001714 if (strlen(optarg) > EBT_TABLE_MAXNAMELEN - 1)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001715 print_error("Table name too long");
1716 strcpy(replace.name, optarg);
1717 break;
1718
1719 case 'i': // input interface
1720 case 2 : // logical input interface
1721 case 'o': // output interface
1722 case 3 : // logical output interface
1723 case 'j': // target
1724 case 'p': // net family protocol
1725 case 's': // source mac
1726 case 'd': // destination mac
1727 if ((replace.flags & OPT_COMMAND) == 0)
1728 print_error("No command specified");
1729 if ( replace.command != 'A' &&
1730 replace.command != 'D' && replace.command != 'I')
1731 print_error("Command and option do not match");
1732 if (c == 'i') {
1733 check_option(&replace.flags, OPT_IN);
1734 if (replace.selected_hook > 2 &&
1735 replace.selected_hook < NF_BR_BROUTING)
1736 print_error("Use in-interface only in "
1737 "INPUT, FORWARD, PREROUTING and"
1738 "BROUTING chains");
1739 if (check_inverse(optarg))
1740 new_entry->invflags |= EBT_IIN;
1741
1742 if (optind > argc)
1743 print_error("No in-interface "
1744 "specified");
1745 if (strlen(argv[optind - 1]) >= IFNAMSIZ)
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001746 print_error("Illegal interface length");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001747 strcpy(new_entry->in, argv[optind - 1]);
1748 break;
1749 }
1750 if (c == 2) {
1751 check_option(&replace.flags, OPT_LOGICALIN);
1752 if (replace.selected_hook > 2 &&
1753 replace.selected_hook < NF_BR_BROUTING)
1754 print_error("Use logical in-interface "
1755 "only in INPUT, FORWARD, "
1756 "PREROUTING and BROUTING chains");
1757 if (check_inverse(optarg))
1758 new_entry->invflags |= EBT_ILOGICALIN;
1759
1760 if (optind > argc)
1761 print_error("No logical in-interface "
1762 "specified");
1763 if (strlen(argv[optind - 1]) >= IFNAMSIZ)
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001764 print_error("Illegal interface length");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001765 strcpy(new_entry->logical_in, argv[optind - 1]);
1766 break;
1767 }
1768 if (c == 'o') {
1769 check_option(&replace.flags, OPT_OUT);
1770 if (replace.selected_hook < 2)
1771 print_error("Use out-interface only"
1772 " in OUTPUT, FORWARD and "
1773 "POSTROUTING chains");
1774 if (check_inverse(optarg))
1775 new_entry->invflags |= EBT_IOUT;
1776
1777 if (optind > argc)
1778 print_error("No out-interface "
1779 "specified");
1780
1781 if (strlen(argv[optind - 1]) >= IFNAMSIZ)
1782 print_error("Illegal interface "
1783 "length");
1784 strcpy(new_entry->out, argv[optind - 1]);
1785 break;
1786 }
1787 if (c == 3) {
1788 check_option(&replace.flags, OPT_LOGICALOUT);
1789 if (replace.selected_hook < 2)
1790 print_error("Use logical out-interface "
1791 "only in OUTPUT, FORWARD and "
1792 "POSTROUTING chains");
1793 if (check_inverse(optarg))
1794 new_entry->invflags |= EBT_ILOGICALOUT;
1795
1796 if (optind > argc)
1797 print_error("No logical out-interface "
1798 "specified");
1799
1800 if (strlen(argv[optind - 1]) >= IFNAMSIZ)
1801 print_error("Illegal interface "
1802 "length");
1803 strcpy(new_entry->logical_out,
1804 argv[optind - 1]);
1805 break;
1806 }
1807 if (c == 'j') {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001808 check_option(&replace.flags, OPT_JUMP);
1809 for (i = 0; i < NUM_STANDARD_TARGETS; i++)
1810 if (!strcmp(optarg,
1811 standard_targets[i])) {
1812 t = find_target(
1813 EBT_STANDARD_TARGET);
1814 ((struct ebt_standard_target *)
Bart De Schuymer60332e02002-06-23 08:01:47 +00001815 t->t)->verdict = -i - 1;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001816 break;
1817 }
Bart De Schuymer60332e02002-06-23 08:01:47 +00001818 if (-i - 1 == EBT_RETURN) {
1819 if (replace.selected_hook < NF_BR_NUMHOOKS)
1820 print_error("Return target"
1821 " only for user defined chains");
1822 }
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +00001823 if (i != NUM_STANDARD_TARGETS)
1824 break;
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001825 if ((i = get_hooknr(optarg)) != -1) {
1826 if (i < NF_BR_NUMHOOKS)
1827 print_error("don't jump"
1828 " to a standard chain");
1829 t = find_target(
1830 EBT_STANDARD_TARGET);
1831 ((struct ebt_standard_target *)
1832 t->t)->verdict = i - NF_BR_NUMHOOKS;
1833 break;
1834 }
1835 else {
1836 // must be an extension then
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001837 struct ebt_u_target *t;
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001838
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001839 t = find_target(optarg);
1840 // -j standard not allowed either
1841 if (!t || t ==
1842 (struct ebt_u_target *)new_entry->t)
1843 print_error("Illegal target "
1844 "name");
1845 new_entry->t =
1846 (struct ebt_entry_target *)t;
1847 }
1848 break;
1849 }
1850 if (c == 's') {
1851 check_option(&replace.flags, OPT_SOURCE);
1852 if (check_inverse(optarg))
1853 new_entry->invflags |= EBT_ISOURCE;
1854
1855 if (optind > argc)
1856 print_error("No source mac "
1857 "specified");
1858 if (getmac_and_mask(argv[optind - 1],
1859 new_entry->sourcemac, new_entry->sourcemsk))
1860 print_error("Problem with specified "
1861 "source mac");
1862 new_entry->bitmask |= EBT_SOURCEMAC;
1863 break;
1864 }
1865 if (c == 'd') {
1866 check_option(&replace.flags, OPT_DEST);
1867 if (check_inverse(optarg))
1868 new_entry->invflags |= EBT_IDEST;
1869
1870 if (optind > argc)
1871 print_error("No destination mac "
1872 "specified");
1873 if (getmac_and_mask(argv[optind - 1],
1874 new_entry->destmac, new_entry->destmsk))
1875 print_error("Problem with specified "
1876 "destination mac");
1877 new_entry->bitmask |= EBT_DESTMAC;
1878 break;
1879 }
1880 check_option(&replace.flags, OPT_PROTOCOL);
1881 if (check_inverse(optarg))
1882 new_entry->invflags |= EBT_IPROTO;
1883
1884 if (optind > argc)
1885 print_error("No protocol specified");
1886 new_entry->bitmask &= ~((unsigned int)EBT_NOPROTO);
1887 i = strtol(argv[optind - 1], &buffer, 16);
1888 if (*buffer == '\0' && (i < 0 || i > 0xFFFF))
1889 print_error("Problem with the specified "
1890 "protocol");
1891 new_entry->ethproto = i;
Bart De Schuymer28bf6f62002-06-26 18:57:24 +00001892 if (*buffer != '\0') {
1893 if ((i = name_to_number(argv[optind - 1],
1894 &new_entry->ethproto)) == -1)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001895 print_error("Problem with the specified"
1896 " protocol");
Bart De Schuymer28bf6f62002-06-26 18:57:24 +00001897 if (i == 1)
1898 new_entry->bitmask |= EBT_802_3;
1899 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001900 if (new_entry->ethproto < 1536 &&
1901 !(new_entry->bitmask & EBT_802_3))
1902 print_error("Sorry, protocols have values above"
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001903 " or equal to 0x0600");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001904 break;
1905
Bart De Schuymer9af14f92002-07-10 20:49:10 +00001906 case 4 : // Lc
1907 check_option(&replace.flags, LIST_C);
Bart De Schuymer9af14f92002-07-10 20:49:10 +00001908 if (replace.command != 'L')
1909 print_error("Use --Lc with -L");
1910 if (replace.flags & LIST_X)
1911 print_error("--Lx not compatible with --Lc");
1912 replace.flags |= LIST_C;
1913 break;
1914 case 5 : // Ln
1915 check_option(&replace.flags, LIST_N);
Bart De Schuymer9af14f92002-07-10 20:49:10 +00001916 if (replace.command != 'L')
1917 print_error("Use --Ln with -L");
1918 if (replace.flags & LIST_X)
1919 print_error("--Lx not compatible with --Ln");
1920 replace.flags |= LIST_N;
1921 break;
1922 case 6 : // Lx
1923 check_option(&replace.flags, LIST_X);
Bart De Schuymer9af14f92002-07-10 20:49:10 +00001924 if (replace.command != 'L')
1925 print_error("Use --Lx with -L");
1926 if (replace.flags & LIST_C)
1927 print_error("--Lx not compatible with --Lc");
1928 if (replace.flags & LIST_N)
1929 print_error("--Lx not compatible with --Ln");
1930 replace.flags |= LIST_X;
1931 break;
Bart De Schuymer62423742002-07-14 19:06:20 +00001932 case 8 : // atomic-commit
1933 replace.command = c;
1934 if (replace.flags & OPT_COMMAND)
1935 print_error("Multiple commands not allowed");
1936 replace.flags |= OPT_COMMAND;
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001937 if (replace.filename)
1938 print_error("--atomic incompatible with "
1939 "command");
Bart De Schuymer62423742002-07-14 19:06:20 +00001940 replace.filename = (char *)malloc(strlen(optarg) + 1);
1941 strcpy(replace.filename, optarg);
1942 // get the information from the file
1943 get_table(&replace);
Bart De Schuymer868bf642002-07-16 18:14:20 +00001944 if (replace.nentries) {
Bart De Schuymered053432002-07-21 19:35:39 +00001945 replace.counterchanges = (unsigned short *)
Bart De Schuymer868bf642002-07-16 18:14:20 +00001946 malloc(sizeof(unsigned short) * (replace.nentries + 1));
1947 for (i = 0; i < replace.nentries; i++)
Bart De Schuymered053432002-07-21 19:35:39 +00001948 replace.counterchanges[i] = CNT_NORM;
1949 replace.counterchanges[i] = CNT_END;
Bart De Schuymer868bf642002-07-16 18:14:20 +00001950 }
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001951 // we don't want the kernel giving us its counters, they would
1952 // overwrite the counters extracted from the file
1953 replace.num_counters = 0;
1954 // make sure the table will be written to the kernel
Bart De Schuymer62423742002-07-14 19:06:20 +00001955 free(replace.filename);
1956 replace.filename = NULL;
1957 break;
1958 case 7 : // atomic-init
1959 case 10: // atomic-save
Bart De Schuymer8d1d8942002-07-15 20:09:09 +00001960 case 11: // init-table
Bart De Schuymer62423742002-07-14 19:06:20 +00001961 replace.command = c;
1962 if (replace.flags & OPT_COMMAND)
1963 print_error("Multiple commands not allowed");
1964 replace.flags |= OPT_COMMAND;
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001965 if (replace.filename)
1966 print_error("--atomic incompatible with "
1967 "command");
1968 get_kernel_table(modprobe);
Bart De Schuymera8d920b2002-07-16 18:30:44 +00001969 if (replace.nentries) {
Bart De Schuymered053432002-07-21 19:35:39 +00001970 replace.counterchanges = (unsigned short *)
Bart De Schuymer5f16dc72002-07-16 18:08:36 +00001971 malloc(sizeof(unsigned short) * (replace.nentries + 1));
1972 for (i = 0; i < replace.nentries; i++)
Bart De Schuymered053432002-07-21 19:35:39 +00001973 replace.counterchanges[i] = CNT_NORM;
1974 replace.counterchanges[i] = CNT_END;
Bart De Schuymer5f16dc72002-07-16 18:08:36 +00001975 }
Bart De Schuymer8d1d8942002-07-15 20:09:09 +00001976 if (c == 11)
1977 break;
Bart De Schuymer62423742002-07-14 19:06:20 +00001978 case 9 : // atomic
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001979 if (c == 9 && (replace.flags & OPT_COMMAND))
1980 print_error("--atomic has to come before"
1981 " the command");
Bart De Schuymer62423742002-07-14 19:06:20 +00001982 replace.filename = (char *)malloc(strlen(optarg) + 1);
1983 strcpy(replace.filename, optarg);
1984 break;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001985
Bart De Schuymer9af14f92002-07-10 20:49:10 +00001986 default:
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001987 // is it a target option?
1988 t = (struct ebt_u_target *)new_entry->t;
1989 if ((t->parse(c - t->option_offset, argv, argc,
1990 new_entry, &t->flags, &t->t)))
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001991 goto check_extension;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001992
1993 // is it a match_option?
1994 for (m = matches; m; m = m->next)
1995 if (m->parse(c - m->option_offset, argv,
1996 argc, new_entry, &m->flags, &m->m))
1997 break;
1998
1999 if (m != NULL) {
2000 if (m->used == 0)
2001 add_match(m);
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00002002 goto check_extension;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002003 }
2004
2005 // is it a watcher option?
2006 for (w = watchers; w; w = w->next)
2007 if (w->parse(c-w->option_offset, argv,
2008 argc, new_entry, &w->flags, &w->w))
2009 break;
2010
2011 if (w == NULL)
2012 print_error("Unknown argument");
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00002013 if (w->used == 0)
2014 add_watcher(w);
2015check_extension:
Bart De Schuymer60332e02002-06-23 08:01:47 +00002016 if (replace.command != 'A' && replace.command != 'I' &&
2017 replace.command != 'D')
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00002018 print_error("Extensions only for -A, -I and -D");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002019 }
2020 }
2021
Bart De Schuymer25c741d2002-06-23 18:54:34 +00002022 if ( !table && !(table = find_table(replace.name)) )
2023 print_error("Bad table name");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002024
2025 if ( (replace.flags & OPT_COMMAND) && replace.command != 'L' &&
2026 replace.flags & OPT_ZERO )
2027 print_error("Command -Z only allowed together with command -L");
2028
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002029 // do this after parsing everything, so we can print specific info
2030 if (replace.command == 'h' && !(replace.flags & OPT_ZERO))
2031 print_help();
2032
2033 // do the final checks
Bart De Schuymer60332e02002-06-23 08:01:47 +00002034 if (replace.command == 'A' || replace.command == 'I' ||
2035 replace.command == 'D') {
2036 // this will put the hook_mask right for the chains
2037 check_for_loops();
2038 entries = to_chain();
2039 m_l = new_entry->m_list;
2040 w_l = new_entry->w_list;
2041 t = (struct ebt_u_target *)new_entry->t;
2042 while (m_l) {
2043 m = (struct ebt_u_match *)(m_l->m);
2044 m->final_check(new_entry, m->m, replace.name,
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +00002045 entries->hook_mask, 0);
Bart De Schuymer60332e02002-06-23 08:01:47 +00002046 m_l = m_l->next;
2047 }
2048 while (w_l) {
2049 w = (struct ebt_u_watcher *)(w_l->w);
2050 w->final_check(new_entry, w->w, replace.name,
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +00002051 entries->hook_mask, 0);
Bart De Schuymer60332e02002-06-23 08:01:47 +00002052 w_l = w_l->next;
2053 }
2054 t->final_check(new_entry, t->t, replace.name,
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +00002055 entries->hook_mask, 0);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002056 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002057 // so, the extensions can work with the host endian
2058 // the kernel does not have to do this ofcourse
2059 new_entry->ethproto = htons(new_entry->ethproto);
2060
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002061 if (replace.command == 'P')
2062 change_policy(policy);
2063 else if (replace.command == 'L') {
2064 list_rules();
2065 if (replace.flags & OPT_ZERO)
2066 zero_counters(zerochain);
2067 else
2068 exit(0);
2069 }
2070 if (replace.flags & OPT_ZERO)
2071 zero_counters(zerochain);
Bart De Schuymer1ab41562002-06-23 17:09:54 +00002072 else if (replace.command == 'F') {
2073 if (flush_chains() == -1)
2074 exit(0);
2075 } else if (replace.command == 'A' || replace.command == 'I') {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002076 add_rule(rule_nr);
Bart De Schuymer1ab41562002-06-23 17:09:54 +00002077 check_for_loops();
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +00002078 // do the final_check(), for all entries
2079 // needed when adding a rule that has a chain target
2080 i = -1;
2081 while (1) {
2082 struct ebt_u_entry *e;
2083
2084 i++;
2085 entries = nr_to_chain(i);
2086 if (!entries) {
2087 if (i < NF_BR_NUMHOOKS)
2088 continue;
2089 else
2090 break;
2091 }
2092 e = entries->entries;
2093 while (e) {
2094 // userspace extensions use host endian
2095 e->ethproto = ntohs(e->ethproto);
2096 do_final_checks(e, entries);
2097 e->ethproto = htons(e->ethproto);
2098 e = e->next;
2099 }
2100 }
Bart De Schuymer1ab41562002-06-23 17:09:54 +00002101 } else if (replace.command == 'D')
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002102 delete_rule(rule_nr);
Bart De Schuymer8d1d8942002-07-15 20:09:09 +00002103 // commands -N, -E, -X, --atomic-commit, --atomic-commit, --atomic-save,
2104 // --init-table fall through
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002105
2106 if (table->check)
2107 table->check(&replace);
2108
2109 deliver_table(&replace);
2110
Bart De Schuymered053432002-07-21 19:35:39 +00002111 if (replace.counterchanges)
2112 deliver_counters(&replace);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002113 return 0;
2114}