blob: acc2e0c4bab3a7d049c4b0fa8edd4c5fd32d11b5 [file] [log] [blame]
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001/*
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00002 * ebtables.c, v2.0 July 2002
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00003 *
4 * Author: Bart De Schuymer
5 *
6 * This code is stongly inspired on the iptables code which is
7 * Copyright (C) 1999 Paul `Rusty' Russell & Michael J. Neuling
8 *
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License as
11 * published by the Free Software Foundation; either version 2 of the
12 * License, or (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 */
23
24#include <getopt.h>
25#include <string.h>
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000026#include <stdio.h>
27#include <stdlib.h>
Bart De Schuymerd4586482002-08-11 16:15:55 +000028#include <stdarg.h>
Bart De Schuymer41830412002-06-05 19:41:28 +000029#include <netinet/ether.h>
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000030#include "include/ebtables_u.h"
Bart De Schuymerc8531032002-06-14 21:55:29 +000031#include <unistd.h>
32#include <fcntl.h>
33#include <sys/wait.h>
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000034
Bart De Schuymerd4586482002-08-11 16:15:55 +000035// Don't use this function, use print_bug()
36void __print_bug(char *file, int line, char *format, ...)
37{
38 va_list l;
39
40 va_start(l, format);
41 printf(PROGNAME" v"PROGVERSION":%s:%d:--BUG--: \n", file, line);
42 vprintf(format, l);
43 printf("\n");
44 va_end(l);
45 exit (-1);
46}
47
Bart De Schuymerc56a31a2002-07-25 08:16:08 +000048// here are the number-name correspondences kept for the Ethernet
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000049// frame type field
50#define PROTOCOLFILE "/etc/ethertypes"
51
Bart De Schuymerc8531032002-06-14 21:55:29 +000052#ifndef PROC_SYS_MODPROBE
53#define PROC_SYS_MODPROBE "/proc/sys/kernel/modprobe"
54#endif
55
Bart De Schuymer60332e02002-06-23 08:01:47 +000056char *hooknames[NF_BR_NUMHOOKS] =
57{
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000058 [NF_BR_PRE_ROUTING]"PREROUTING",
59 [NF_BR_LOCAL_IN]"INPUT",
60 [NF_BR_FORWARD]"FORWARD",
61 [NF_BR_LOCAL_OUT]"OUTPUT",
62 [NF_BR_POST_ROUTING]"POSTROUTING",
63 [NF_BR_BROUTING]"BROUTING"
64};
65
66// default command line options
Bart De Schuymer8d1d8942002-07-15 20:09:09 +000067// do not mess around with the already assigned numbers unless
68// you know what you are doing
Bart De Schuymer62423742002-07-14 19:06:20 +000069static struct option ebt_original_options[] =
70{
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000071 { "append" , required_argument, 0, 'A' },
72 { "insert" , required_argument, 0, 'I' },
73 { "delete" , required_argument, 0, 'D' },
74 { "list" , optional_argument, 0, 'L' },
Bart De Schuymer9af14f92002-07-10 20:49:10 +000075 { "Lc" , no_argument , 0, 4 },
76 { "Ln" , no_argument , 0, 5 },
77 { "Lx" , no_argument , 0, 6 },
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000078 { "zero" , optional_argument, 0, 'Z' },
79 { "flush" , optional_argument, 0, 'F' },
80 { "policy" , required_argument, 0, 'P' },
81 { "in-interface" , required_argument, 0, 'i' },
82 { "in-if" , required_argument, 0, 'i' },
83 { "logical-in" , required_argument, 0, 2 },
84 { "logical-out" , required_argument, 0, 3 },
85 { "out-interface" , required_argument, 0, 'o' },
86 { "out-if" , required_argument, 0, 'o' },
87 { "version" , no_argument , 0, 'V' },
88 { "help" , no_argument , 0, 'h' },
89 { "jump" , required_argument, 0, 'j' },
90 { "proto" , required_argument, 0, 'p' },
91 { "protocol" , required_argument, 0, 'p' },
92 { "db" , required_argument, 0, 'b' },
93 { "source" , required_argument, 0, 's' },
94 { "src" , required_argument, 0, 's' },
95 { "destination" , required_argument, 0, 'd' },
96 { "dst" , required_argument, 0, 'd' },
97 { "table" , required_argument, 0, 't' },
Bart De Schuymerc8531032002-06-14 21:55:29 +000098 { "modprobe" , required_argument, 0, 'M' },
Bart De Schuymer1ab41562002-06-23 17:09:54 +000099 { "new-chain" , required_argument, 0, 'N' },
100 { "rename-chain" , required_argument, 0, 'E' },
101 { "delete-chain" , required_argument, 0, 'X' },
Bart De Schuymer62423742002-07-14 19:06:20 +0000102 { "atomic-init" , required_argument, 0, 7 },
Bart De Schuymer62423742002-07-14 19:06:20 +0000103 { "atomic-commit" , required_argument, 0, 8 },
104 { "atomic" , required_argument, 0, 9 },
105 { "atomic-save" , required_argument, 0, 10 },
Bart De Schuymer8d1d8942002-07-15 20:09:09 +0000106 { "init-table" , no_argument , 0, 11 },
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000107 { 0 }
108};
109
110static struct option *ebt_options = ebt_original_options;
111
112// yup, all the possible target names
Bart De Schuymer62423742002-07-14 19:06:20 +0000113char* standard_targets[NUM_STANDARD_TARGETS] =
114{
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000115 "ACCEPT",
116 "DROP",
117 "CONTINUE",
Bart De Schuymer60332e02002-06-23 08:01:47 +0000118 "RETURN",
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000119};
120
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000121unsigned char mac_type_unicast[ETH_ALEN] = {0,0,0,0,0,0};
122unsigned char msk_type_unicast[ETH_ALEN] = {1,0,0,0,0,0};
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000123unsigned char mac_type_multicast[ETH_ALEN] = {1,0,0,0,0,0};
124unsigned char msk_type_multicast[ETH_ALEN] = {1,0,0,0,0,0};
125unsigned char mac_type_broadcast[ETH_ALEN] = {255,255,255,255,255,255};
126unsigned char msk_type_broadcast[ETH_ALEN] = {255,255,255,255,255,255};
127
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000128// holds all the data
129static struct ebt_u_replace replace;
130
131// the chosen table
132static struct ebt_u_table *table = NULL;
133// the lists of supported tables, matches, watchers and targets
134static struct ebt_u_table *tables = NULL;
135static struct ebt_u_match *matches = NULL;
136static struct ebt_u_watcher *watchers = NULL;
137static struct ebt_u_target *targets = NULL;
138
139struct ebt_u_target *find_target(const char *name)
140{
141 struct ebt_u_target *t = targets;
142
143 while(t && strcmp(t->name, name))
144 t = t->next;
145 return t;
146}
147
148struct ebt_u_match *find_match(const char *name)
149{
150 struct ebt_u_match *m = matches;
151
152 while(m && strcmp(m->name, name))
153 m = m->next;
154 return m;
155}
156
157struct ebt_u_watcher *find_watcher(const char *name)
158{
159 struct ebt_u_watcher *w = watchers;
160
161 while(w && strcmp(w->name, name))
162 w = w->next;
163 return w;
164}
165
166struct ebt_u_table *find_table(char *name)
167{
168 struct ebt_u_table *t = tables;
169
170 while (t && strcmp(t->name, name))
171 t = t->next;
172 return t;
173}
174
175// The pointers in here are special:
176// The struct ebt_target * pointer is actually a struct ebt_u_target * pointer.
177// instead of making yet a few other structs, we just do a cast.
178// We need a struct ebt_u_target pointer because we know the address of the data
179// they point to won't change. We want to allow that the struct ebt_u_target.t
180// member can change.
181// Same holds for the struct ebt_match and struct ebt_watcher pointers
182struct ebt_u_entry *new_entry;
183
Bart De Schuymer62423742002-07-14 19:06:20 +0000184static void initialize_entry(struct ebt_u_entry *e)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000185{
186 e->bitmask = EBT_NOPROTO;
187 e->invflags = 0;
188 e->ethproto = 0;
189 strcpy(e->in, "");
190 strcpy(e->out, "");
191 strcpy(e->logical_in, "");
192 strcpy(e->logical_out, "");
193 e->m_list = NULL;
194 e->w_list = NULL;
195 // the init function of the standard target should have put the verdict
196 // on CONTINUE
197 e->t = (struct ebt_entry_target *)find_target(EBT_STANDARD_TARGET);
198 if (!e->t)
Bart De Schuymerd4586482002-08-11 16:15:55 +0000199 print_bug("Couldn't load standard target");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000200}
201
202// this doesn't free e, becoz the calling function might need e->next
Bart De Schuymer62423742002-07-14 19:06:20 +0000203static void free_u_entry(struct ebt_u_entry *e)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000204{
205 struct ebt_u_match_list *m_l, *m_l2;
206 struct ebt_u_watcher_list *w_l, *w_l2;
207
208 m_l = e->m_list;
209 while (m_l) {
210 m_l2 = m_l->next;
211 free(m_l->m);
212 free(m_l);
213 m_l = m_l2;
214 }
215 w_l = e->w_list;
216 while (w_l) {
217 w_l2 = w_l->next;
218 free(w_l->w);
219 free(w_l);
220 w_l = w_l2;
221 }
222 free(e->t);
223}
224
225// the user will use the match, so put it in new_entry
226static void add_match(struct ebt_u_match *m)
227{
228 struct ebt_u_match_list **m_list, *new;
229
230 m->used = 1;
Bart De Schuymerc56a31a2002-07-25 08:16:08 +0000231 for (m_list = &new_entry->m_list; *m_list; m_list = &(*m_list)->next);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000232 new = (struct ebt_u_match_list *)
233 malloc(sizeof(struct ebt_u_match_list));
234 if (!new)
235 print_memory();
236 *m_list = new;
237 new->next = NULL;
238 new->m = (struct ebt_entry_match *)m;
239}
240
241static void add_watcher(struct ebt_u_watcher *w)
242{
243 struct ebt_u_watcher_list **w_list;
244 struct ebt_u_watcher_list *new;
245
246 w->used = 1;
Bart De Schuymerc56a31a2002-07-25 08:16:08 +0000247 for (w_list = &new_entry->w_list; *w_list; w_list = &(*w_list)->next);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000248 new = (struct ebt_u_watcher_list *)
249 malloc(sizeof(struct ebt_u_watcher_list));
250 if (!new)
251 print_memory();
252 *w_list = new;
253 new->next = NULL;
254 new->w = (struct ebt_entry_watcher *)w;
255}
256
257static int global_option_offset = 0;
258#define OPTION_OFFSET 256
259static struct option *
260merge_options(struct option *oldopts, const struct option *newopts,
261 unsigned int *options_offset)
262{
263 unsigned int num_old, num_new, i;
264 struct option *merge;
265
266 if (!newopts || !oldopts || !options_offset)
267 print_bug("merge wrong");
268 for (num_old = 0; oldopts[num_old].name; num_old++);
269 for (num_new = 0; newopts[num_new].name; num_new++);
270
271 global_option_offset += OPTION_OFFSET;
272 *options_offset = global_option_offset;
273
274 merge = malloc(sizeof(struct option) * (num_new + num_old + 1));
275 if (!merge)
276 print_memory();
277 memcpy(merge, oldopts, num_old * sizeof(struct option));
278 for (i = 0; i < num_new; i++) {
279 merge[num_old + i] = newopts[i];
280 merge[num_old + i].val += *options_offset;
281 }
282 memset(merge + num_old + num_new, 0, sizeof(struct option));
283 // only free dynamically allocated stuff
284 if (oldopts != ebt_original_options)
285 free(oldopts);
286
287 return merge;
288}
289
290void register_match(struct ebt_u_match *m)
291{
292 int size = m->size + sizeof(struct ebt_entry_match);
293 struct ebt_u_match **i;
294
295 m->m = (struct ebt_entry_match *)malloc(size);
296 if (!m->m)
297 print_memory();
298 strcpy(m->m->u.name, m->name);
299 m->m->match_size = m->size;
300 ebt_options = merge_options
301 (ebt_options, m->extra_ops, &(m->option_offset));
302 m->init(m->m);
303
304 for (i = &matches; *i; i = &((*i)->next));
305 m->next = NULL;
306 *i = m;
307}
308
309void register_watcher(struct ebt_u_watcher *w)
310{
311 int size = w->size + sizeof(struct ebt_entry_watcher);
312 struct ebt_u_watcher **i;
313
314 w->w = (struct ebt_entry_watcher *)malloc(size);
315 if (!w->w)
316 print_memory();
317 strcpy(w->w->u.name, w->name);
318 w->w->watcher_size = w->size;
319 ebt_options = merge_options
320 (ebt_options, w->extra_ops, &(w->option_offset));
321 w->init(w->w);
322
323 for (i = &watchers; *i; i = &((*i)->next));
324 w->next = NULL;
325 *i = w;
326}
327
328void register_target(struct ebt_u_target *t)
329{
330 int size = t->size + sizeof(struct ebt_entry_target);
331 struct ebt_u_target **i;
332
333 t->t = (struct ebt_entry_target *)malloc(size);
334 if (!t->t)
335 print_memory();
336 strcpy(t->t->u.name, t->name);
337 t->t->target_size = t->size;
338 ebt_options = merge_options
339 (ebt_options, t->extra_ops, &(t->option_offset));
340 t->init(t->t);
Bart De Schuymerc56a31a2002-07-25 08:16:08 +0000341
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000342 for (i = &targets; *i; i = &((*i)->next));
343 t->next = NULL;
344 *i = t;
345}
346
347void register_table(struct ebt_u_table *t)
348{
349 t->next = tables;
350 tables = t;
351}
352
Bart De Schuymerc8531032002-06-14 21:55:29 +0000353// blatently stolen (again) from iptables.c userspace program
354// find out where the modprobe utility is located
355static char *get_modprobe(void)
356{
357 int procfile;
358 char *ret;
359
360 procfile = open(PROC_SYS_MODPROBE, O_RDONLY);
361 if (procfile < 0)
362 return NULL;
363
364 ret = malloc(1024);
365 if (ret) {
366 switch (read(procfile, ret, 1024)) {
367 case -1: goto fail;
368 case 1024: goto fail; /* Partial read. Wierd */
369 }
370 if (ret[strlen(ret)-1]=='\n')
371 ret[strlen(ret)-1]=0;
372 close(procfile);
373 return ret;
374 }
375 fail:
376 free(ret);
377 close(procfile);
378 return NULL;
379}
380
Bart De Schuymerc8531032002-06-14 21:55:29 +0000381int ebtables_insmod(const char *modname, const char *modprobe)
382{
383 char *buf = NULL;
384 char *argv[3];
385
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000386 // If they don't explicitly set it, read out of kernel
Bart De Schuymerc8531032002-06-14 21:55:29 +0000387 if (!modprobe) {
388 buf = get_modprobe();
389 if (!buf)
390 return -1;
391 modprobe = buf;
392 }
393
394 switch (fork()) {
395 case 0:
396 argv[0] = (char *)modprobe;
397 argv[1] = (char *)modname;
398 argv[2] = NULL;
399 execv(argv[0], argv);
400
401 /* not usually reached */
402 exit(0);
403 case -1:
404 return -1;
405
406 default: /* parent */
407 wait(NULL);
408 }
409
410 free(buf);
411 return 0;
412}
413
Bart De Schuymerbbca3202002-06-05 18:55:44 +0000414// helper function: processes a line of data from the file /etc/ethertypes
Bart De Schuymer62423742002-07-14 19:06:20 +0000415static int get_a_line(char *buffer, char *value, FILE *ifp)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000416{
Bart De Schuymerf662ce52002-07-19 18:40:55 +0000417 char line[80], *p;
418 const char delim[] = " \t\n";
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000419
Bart De Schuymerf662ce52002-07-19 18:40:55 +0000420 while (fgets(line, sizeof(line), ifp)) {
421 p = strtok(line, delim);
422 if (!p || p[0] == '#')
423 continue;
424 if (strlen(p) > 20)
425 continue;
426 strcpy(buffer, p);
427 p = strtok(NULL, delim);
428 if (!p || strlen(p) > 10)
429 continue;
430 strcpy(value, p);
431 return 0;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000432 }
Bart De Schuymerf662ce52002-07-19 18:40:55 +0000433 return -1;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000434}
435
Bart De Schuymerb909f9b2002-06-26 18:35:31 +0000436// translate a hexadecimal number to a protocol name, parsing /etc/ethertypes
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000437// returns 0 on success
Bart De Schuymerc5c3c2d2002-08-16 19:48:03 +0000438// this demands the name buffer to be of size at least 21
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000439int number_to_name(unsigned short proto, char *name)
440{
441 FILE *ifp;
Bart De Schuymerf662ce52002-07-19 18:40:55 +0000442 char buffer[21], value[11], *bfr;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000443 unsigned short i;
444
445 if ( !(ifp = fopen(PROTOCOLFILE, "r")) )
446 return -1;
447 while (1) {
448 if (get_a_line(buffer, value, ifp)) {
449 fclose(ifp);
450 return -1;
451 }
452 i = (unsigned short) strtol(value, &bfr, 16);
453 if (*bfr != '\0' || i != proto)
454 continue;
455 strcpy(name, buffer);
456 fclose(ifp);
457 return 0;
458 }
459}
460
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000461// we use replace.flags, so we can't use the following values:
462// 0x01 == OPT_COMMAND, 0x02 == OPT_TABLE, 0x100 == OPT_ZERO
463#define LIST_N 0x04
464#define LIST_C 0x08
465#define LIST_X 0x10
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000466// helper function for list_rules()
Bart De Schuymer60332e02002-06-23 08:01:47 +0000467static void list_em(struct ebt_u_entries *entries)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000468{
469 int i, j, space = 0, digits;
470 struct ebt_u_entry *hlp;
471 struct ebt_u_match_list *m_l;
472 struct ebt_u_watcher_list *w_l;
473 struct ebt_u_match *m;
474 struct ebt_u_watcher *w;
475 struct ebt_u_target *t;
476 char name[21];
477
Bart De Schuymer60332e02002-06-23 08:01:47 +0000478 hlp = entries->entries;
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000479 if (replace.flags & LIST_X && entries->policy != EBT_ACCEPT) {
480 printf("ebtables -t %s -P %s %s\n", replace.name,
481 entries->name, standard_targets[-entries->policy - 1]);
482 } else if (!(replace.flags & LIST_X)) {
Bart De Schuymerc87c9642002-08-01 15:34:16 +0000483 printf("\nBridge chain: %s, entries: %d, policy: %s\n",
484 entries->name, entries->nentries,
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000485 standard_targets[-entries->policy - 1]);
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000486 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000487
Bart De Schuymer60332e02002-06-23 08:01:47 +0000488 i = entries->nentries;
Bart De Schuymerf8f8f292002-06-25 15:43:57 +0000489 while (i > 9) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000490 space++;
491 i /= 10;
492 }
493
Bart De Schuymer60332e02002-06-23 08:01:47 +0000494 for (i = 0; i < entries->nentries; i++) {
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000495 if (replace.flags & LIST_N) {
496 digits = 0;
497 // A little work to get nice rule numbers.
498 j = i + 1;
499 while (j > 9) {
500 digits++;
501 j /= 10;
502 }
503 for (j = 0; j < space - digits; j++)
504 printf(" ");
505 printf("%d. ", i + 1);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000506 }
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000507 if (replace.flags & LIST_X)
508 printf("ebtables -t %s -A %s ",
509 replace.name, entries->name);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000510
511 // Don't print anything about the protocol if no protocol was
512 // specified, obviously this means any protocol will do.
513 if (!(hlp->bitmask & EBT_NOPROTO)) {
Bart De Schuymer60332e02002-06-23 08:01:47 +0000514 printf("-p ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000515 if (hlp->invflags & EBT_IPROTO)
516 printf("! ");
517 if (hlp->bitmask & EBT_802_3)
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000518 printf("Length ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000519 else {
520 if (number_to_name(ntohs(hlp->ethproto), name))
Bart De Schuymer60332e02002-06-23 08:01:47 +0000521 printf("0x%x ", ntohs(hlp->ethproto));
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000522 else
Bart De Schuymer60332e02002-06-23 08:01:47 +0000523 printf("%s ", name);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000524 }
525 }
526 if (hlp->bitmask & EBT_SOURCEMAC) {
527 char hlpmsk[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
528
Bart De Schuymer60332e02002-06-23 08:01:47 +0000529 printf("-s ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000530 if (hlp->invflags & EBT_ISOURCE)
531 printf("! ");
532 if (!memcmp(hlp->sourcemac, mac_type_unicast, 6) &&
533 !memcmp(hlp->sourcemsk, msk_type_unicast, 6)) {
534 printf("Unicast");
535 goto endsrc;
536 }
537 if (!memcmp(hlp->sourcemac, mac_type_multicast, 6) &&
538 !memcmp(hlp->sourcemsk, msk_type_multicast, 6)) {
539 printf("Multicast");
540 goto endsrc;
541 }
542 if (!memcmp(hlp->sourcemac, mac_type_broadcast, 6) &&
543 !memcmp(hlp->sourcemsk, msk_type_broadcast, 6)) {
544 printf("Broadcast");
545 goto endsrc;
546 }
Bart De Schuymer41830412002-06-05 19:41:28 +0000547 printf("%s", ether_ntoa((struct ether_addr *)
548 hlp->sourcemac));
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000549 if (memcmp(hlp->sourcemsk, hlpmsk, 6)) {
550 printf("/");
Bart De Schuymer41830412002-06-05 19:41:28 +0000551 printf("%s", ether_ntoa((struct ether_addr *)
552 hlp->sourcemsk));
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000553 }
554endsrc:
Bart De Schuymer60332e02002-06-23 08:01:47 +0000555 printf(" ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000556 }
557 if (hlp->bitmask & EBT_DESTMAC) {
558 char hlpmsk[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
559
Bart De Schuymer60332e02002-06-23 08:01:47 +0000560 printf("-d ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000561 if (hlp->invflags & EBT_IDEST)
562 printf("! ");
563 if (!memcmp(hlp->destmac, mac_type_unicast, 6) &&
564 !memcmp(hlp->destmsk, msk_type_unicast, 6)) {
565 printf("Unicast");
566 goto enddst;
567 }
568 if (!memcmp(hlp->destmac, mac_type_multicast, 6) &&
569 !memcmp(hlp->destmsk, msk_type_multicast, 6)) {
570 printf("Multicast");
571 goto enddst;
572 }
573 if (!memcmp(hlp->destmac, mac_type_broadcast, 6) &&
574 !memcmp(hlp->destmsk, msk_type_broadcast, 6)) {
575 printf("Broadcast");
576 goto enddst;
577 }
Bart De Schuymer41830412002-06-05 19:41:28 +0000578 printf("%s", ether_ntoa((struct ether_addr *)
579 hlp->destmac));
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000580 if (memcmp(hlp->destmsk, hlpmsk, 6)) {
581 printf("/");
Bart De Schuymer41830412002-06-05 19:41:28 +0000582 printf("%s", ether_ntoa((struct ether_addr *)
583 hlp->destmsk));
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000584 }
585enddst:
Bart De Schuymer60332e02002-06-23 08:01:47 +0000586 printf(" ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000587 }
588 if (hlp->in[0] != '\0') {
Bart De Schuymer60332e02002-06-23 08:01:47 +0000589 printf("-i ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000590 if (hlp->invflags & EBT_IIN)
591 printf("! ");
Bart De Schuymer60332e02002-06-23 08:01:47 +0000592 printf("%s ", hlp->in);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000593 }
594 if (hlp->logical_in[0] != '\0') {
Bart De Schuymer60332e02002-06-23 08:01:47 +0000595 printf("--logical-in ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000596 if (hlp->invflags & EBT_ILOGICALIN)
597 printf("! ");
Bart De Schuymer60332e02002-06-23 08:01:47 +0000598 printf("%s ", hlp->logical_in);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000599 }
600 if (hlp->logical_out[0] != '\0') {
Bart De Schuymer60332e02002-06-23 08:01:47 +0000601 printf("--logical-out ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000602 if (hlp->invflags & EBT_ILOGICALOUT)
603 printf("! ");
Bart De Schuymerb3d8f262002-07-07 14:26:15 +0000604 printf("%s ", hlp->logical_out);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000605 }
606 if (hlp->out[0] != '\0') {
Bart De Schuymer60332e02002-06-23 08:01:47 +0000607 printf("-o ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000608 if (hlp->invflags & EBT_IOUT)
609 printf("! ");
Bart De Schuymerb3d8f262002-07-07 14:26:15 +0000610 printf("%s ", hlp->out);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000611 }
612
613 m_l = hlp->m_list;
614 while (m_l) {
615 m = find_match(m_l->m->u.name);
616 if (!m)
617 print_bug("Match not found");
618 m->print(hlp, m_l->m);
619 m_l = m_l->next;
620 }
621 w_l = hlp->w_list;
622 while (w_l) {
623 w = find_watcher(w_l->w->u.name);
624 if (!w)
625 print_bug("Watcher not found");
626 w->print(hlp, w_l->w);
627 w_l = w_l->next;
628 }
629
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000630 printf("-j ");
631 if (strcmp(hlp->t->u.name, EBT_STANDARD_TARGET))
632 printf("%s ", hlp->t->u.name);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000633 t = find_target(hlp->t->u.name);
634 if (!t)
635 print_bug("Target not found");
636 t->print(hlp, hlp->t);
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000637 if (replace.flags & LIST_C)
Bart De Schuymer73fccca2002-10-17 22:00:23 +0000638 printf(", pcnt = %llu -- bcnt = %llu",
639 replace.counters[entries->counter_offset + i].pcnt,
640 replace.counters[entries->counter_offset + i].bcnt);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000641 printf("\n");
642 hlp = hlp->next;
643 }
644}
645
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000646struct ebt_u_entries *nr_to_chain(int nr)
Bart De Schuymer60332e02002-06-23 08:01:47 +0000647{
648 if (nr == -1)
649 return NULL;
650 if (nr < NF_BR_NUMHOOKS)
651 return replace.hook_entry[nr];
652 else {
653 int i;
654 struct ebt_u_chain_list *cl = replace.udc;
655
656 i = nr - NF_BR_NUMHOOKS;
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000657 while (i > 0 && cl) {
Bart De Schuymer60332e02002-06-23 08:01:47 +0000658 cl = cl->next;
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000659 i--;
660 }
Bart De Schuymer60332e02002-06-23 08:01:47 +0000661 if (cl)
662 return cl->udc;
663 else
664 return NULL;
665 }
666}
667
Bart De Schuymercc440052002-11-06 21:10:33 +0000668static inline struct ebt_u_entries *to_chain()
Bart De Schuymer60332e02002-06-23 08:01:47 +0000669{
670 return nr_to_chain(replace.selected_hook);
671}
672
673struct ebt_u_stack
674{
675 int chain_nr;
676 int n;
677 struct ebt_u_entry *e;
678 struct ebt_u_entries *entries;
679};
680
Bart De Schuymer62423742002-07-14 19:06:20 +0000681static void check_for_loops()
Bart De Schuymer60332e02002-06-23 08:01:47 +0000682{
683 int chain_nr , i, j , k, sp = 0, verdict;
684 struct ebt_u_entries *entries, *entries2;
685 struct ebt_u_stack *stack = NULL;
686 struct ebt_u_entry *e;
687
688 i = -1;
689 // initialize hook_mask to 0
690 while (1) {
691 i++;
692 if (i < NF_BR_NUMHOOKS && !(replace.valid_hooks & (1 << i)))
693 continue;
694 entries = nr_to_chain(i);
695 if (!entries)
696 break;
697 entries->hook_mask = 0;
698 }
699 if (i > NF_BR_NUMHOOKS) {
700 stack = (struct ebt_u_stack *)malloc((i - NF_BR_NUMHOOKS) *
701 sizeof(struct ebt_u_stack));
702 if (!stack)
703 print_memory();
704 }
705
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000706 // check for loops, starting from every base chain
Bart De Schuymer60332e02002-06-23 08:01:47 +0000707 for (i = 0; i < NF_BR_NUMHOOKS; i++) {
708 if (!(replace.valid_hooks & (1 << i)))
709 continue;
710 entries = nr_to_chain(i);
Bart De Schuymerb26649e2002-07-25 14:51:54 +0000711 // (1 << NF_BR_NUMHOOKS) implies it's a standard chain
712 // (usefull in the final_check() funtions)
713 entries->hook_mask = (1 << i) | (1 << NF_BR_NUMHOOKS);
Bart De Schuymer60332e02002-06-23 08:01:47 +0000714 chain_nr = i;
715
716 e = entries->entries;
717 for (j = 0; j < entries->nentries; j++) {
718 if (strcmp(e->t->u.name, EBT_STANDARD_TARGET))
719 goto letscontinue;
720 verdict = ((struct ebt_standard_target *)(e->t))->verdict;
721 if (verdict < 0)
722 goto letscontinue;
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000723 entries2 = nr_to_chain(verdict + NF_BR_NUMHOOKS);
Bart De Schuymer60332e02002-06-23 08:01:47 +0000724 entries2->hook_mask |= entries->hook_mask;
725 // now see if we've been here before
726 for (k = 0; k < sp; k++)
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000727 if (stack[k].chain_nr == verdict + NF_BR_NUMHOOKS)
Bart De Schuymer1a0a9c32002-06-24 21:10:16 +0000728 print_error("Loop from chain %s to chain %s",
Bart De Schuymerc56a31a2002-07-25 08:16:08 +0000729 nr_to_chain(chain_nr)->name,
730 nr_to_chain(stack[k].chain_nr)->name);
Bart De Schuymer60332e02002-06-23 08:01:47 +0000731 // jump to the chain, make sure we know how to get back
732 stack[sp].chain_nr = chain_nr;
733 stack[sp].n = j;
734 stack[sp].entries = entries;
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000735 stack[sp].e = e;
736 sp++;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000737 j = -1;
738 e = entries2->entries;
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000739 chain_nr = verdict + NF_BR_NUMHOOKS;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000740 entries = entries2;
741 continue;
742letscontinue:
743 e = e->next;
744 }
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000745 // we are at the end of a standard chain
Bart De Schuymer60332e02002-06-23 08:01:47 +0000746 if (sp == 0)
747 continue;
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000748 // go back to the chain one level higher
Bart De Schuymer60332e02002-06-23 08:01:47 +0000749 sp--;
750 j = stack[sp].n;
751 chain_nr = stack[sp].chain_nr;
752 e = stack[sp].e;
753 entries = stack[sp].entries;
754 goto letscontinue;
755 }
756 free(stack);
757 return;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000758}
759
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000760// parse the chain name and return the corresponding nr
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000761// returns -1 on failure
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000762int get_hooknr(char* arg)
763{
764 int i;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000765 struct ebt_u_chain_list *cl = replace.udc;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000766
Bart De Schuymer60332e02002-06-23 08:01:47 +0000767 for (i = 0; i < NF_BR_NUMHOOKS; i++) {
768 if (!(replace.valid_hooks & (1 << i)))
769 continue;
770 if (!strcmp(arg, replace.hook_entry[i]->name))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000771 return i;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000772 }
773 while(cl) {
774 if (!strcmp(arg, cl->udc->name))
775 return i;
776 i++;
777 cl = cl->next;
778 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000779 return -1;
780}
781
782// yup, print out help
Bart De Schuymer62423742002-07-14 19:06:20 +0000783static void print_help()
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000784{
785 struct ebt_u_match_list *m_l;
786 struct ebt_u_watcher_list *w_l;
787
Bart De Schuymerd4586482002-08-11 16:15:55 +0000788 printf(PROGNAME" v"PROGVERSION" ("PROGDATE")\n"
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000789"Usage:\n"
790"ebtables -[ADI] chain rule-specification [options]\n"
791"ebtables -P chain target\n"
792"ebtables -[LFZ] [chain]\n"
793"ebtables -[b] [y,n]\n"
794"Commands:\n"
Bart De Schuymer23f6dcf2002-08-17 09:14:07 +0000795"--append -A chain : append to chain\n"
796"--delete -D chain : delete matching rule from chain\n"
797"--delete -D chain rulenum : delete rule at position rulenum from chain\n"
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000798"--insert -I chain rulenum : insert rule at position rulenum in chain\n"
Bart De Schuymer23f6dcf2002-08-17 09:14:07 +0000799"--list -L [chain] : list the rules in a chain or in all chains\n"
800"--flush -F [chain] : delete all rules in chain or in all chains\n"
801"--init-table : replace the kernel table with the initial table\n"
802"--zero -Z [chain] : put counters on zero in chain or in all chains\n"
803"--policy -P chain target : change policy on chain to target\n"
804"--new-chain -N chain : create a user defined chain\n"
805"--rename-chain -E old new : rename a chain\n"
806"--delete-chain -X chain : delete a user defined chain\n"
Bart De Schuymer62423742002-07-14 19:06:20 +0000807"--atomic-commit file : update the kernel w/ the table contained in file\n"
808"--atomic-init file : put the initial kernel table into file\n"
809"--atomic-save file : put the current kernel table into file\n"
810"--atomic file : write changes to file instead of kernel\n"
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000811"Options:\n"
812"--proto -p [!] proto : protocol hexadecimal, by name or LENGTH\n"
813"--src -s [!] address[/mask]: source mac address\n"
814"--dst -d [!] address[/mask]: destination mac address\n"
815"--in-if -i [!] name : network input interface name\n"
816"--out-if -o [!] name : network output interface name\n"
817"--logical-in [!] name : logical bridge input interface name\n"
818"--logical-out [!] name : logical bridge output interface name\n"
Bart De Schuymer5cbc8e02002-07-14 21:15:28 +0000819"--modprobe -M program : try to insert modules using this program\n"
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000820"--version -V : print package version\n"
Bart De Schuymerd4586482002-08-11 16:15:55 +0000821"\n");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000822
823 m_l = new_entry->m_list;
824 while (m_l) {
825 ((struct ebt_u_match *)m_l->m)->help();
826 printf("\n");
827 m_l = m_l->next;
828 }
829 w_l = new_entry->w_list;
830 while (w_l) {
831 ((struct ebt_u_watcher *)w_l->w)->help();
832 printf("\n");
833 w_l = w_l->next;
834 }
835 ((struct ebt_u_target *)new_entry->t)->help();
836 printf("\n");
837 if (table->help)
838 table->help(hooknames);
839 exit(0);
840}
841
842// execute command L
843static void list_rules()
844{
845 int i;
846
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000847 if (!(replace.flags & LIST_X))
848 printf("Bridge table: %s\n", table->name);
Bart De Schuymer60332e02002-06-23 08:01:47 +0000849 if (replace.selected_hook != -1) {
850 list_em(to_chain());
851 } else {
852 struct ebt_u_chain_list *cl = replace.udc;
853
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000854 // create new chains and rename standard chains when necessary
855 if (replace.flags & LIST_X) {
856 while (cl) {
857 printf("ebtables -t %s -N %s\n", replace.name,
858 cl->udc->name);
859 cl = cl->next;
860 }
861 cl = replace.udc;
862 for (i = 0; i < NF_BR_NUMHOOKS; i++)
863 if (replace.valid_hooks & (1 << i) &&
864 strcmp(replace.hook_entry[i]->name, hooknames[i]))
865 printf("ebtables -t %s -E %s %s\n",
866 replace.name, hooknames[i],
867 replace.hook_entry[i]->name);
868 }
Bart De Schuymer60332e02002-06-23 08:01:47 +0000869 i = 0;
870 while (1) {
871 if (i < NF_BR_NUMHOOKS) {
872 if (replace.valid_hooks & (1 << i))
873 list_em(replace.hook_entry[i]);
874 i++;
875 continue;
876 } else {
877 if (!cl)
878 break;
879 list_em(cl->udc);
880 cl = cl->next;
881 }
882 }
883 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000884}
885
886// execute command P
887static void change_policy(int policy)
888{
889 int i;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000890 struct ebt_u_entries *entries = to_chain();
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000891
892 // don't do anything if the policy is the same
Bart De Schuymer60332e02002-06-23 08:01:47 +0000893 if (entries->policy != policy) {
894 entries->policy = policy;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000895 replace.num_counters = replace.nentries;
896 if (replace.nentries) {
897 // '+ 1' for the CNT_END
Bart De Schuymered053432002-07-21 19:35:39 +0000898 if (!(replace.counterchanges = (unsigned short *) malloc(
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000899 (replace.nentries + 1) * sizeof(unsigned short))))
900 print_memory();
901 // done nothing special to the rules
902 for (i = 0; i < replace.nentries; i++)
Bart De Schuymered053432002-07-21 19:35:39 +0000903 replace.counterchanges[i] = CNT_NORM;
904 replace.counterchanges[replace.nentries] = CNT_END;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000905 }
906 else
Bart De Schuymered053432002-07-21 19:35:39 +0000907 replace.counterchanges = NULL;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000908 }
909 else
910 exit(0);
911}
912
913// flush one chain or the complete table
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000914// -1 == nothing to do
915// 0 == give back to kernel
916static int flush_chains()
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000917{
Bart De Schuymer60332e02002-06-23 08:01:47 +0000918 int i, j, oldnentries, numdel;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000919 unsigned short *cnt;
920 struct ebt_u_entry *u_e, *tmp;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000921 struct ebt_u_entries *entries = to_chain();
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000922
923 // flush whole table
Bart De Schuymer60332e02002-06-23 08:01:47 +0000924 if (!entries) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000925 if (replace.nentries == 0)
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000926 return -1;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000927 replace.nentries = 0;
928 // no need for the kernel to give us counters back
929 replace.num_counters = 0;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000930
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000931 // free everything and zero (n)entries
Bart De Schuymer60332e02002-06-23 08:01:47 +0000932 i = -1;
933 while (1) {
934 i++;
935 entries = nr_to_chain(i);
936 if (!entries) {
937 if (i < NF_BR_NUMHOOKS)
938 continue;
939 else
940 break;
941 }
942 entries->nentries = 0;
943 entries->counter_offset = 0;
944 u_e = entries->entries;
945 entries->entries = NULL;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000946 while (u_e) {
947 free_u_entry(u_e);
948 tmp = u_e->next;
949 free(u_e);
950 u_e = tmp;
951 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000952 }
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000953 return 0;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000954 }
955
Bart De Schuymer60332e02002-06-23 08:01:47 +0000956 if (entries->nentries == 0)
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000957 return -1;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000958 oldnentries = replace.nentries;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000959 replace.nentries -= entries->nentries;
960 numdel = entries->nentries;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000961
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000962 if (replace.nentries) {
963 // +1 for CNT_END
Bart De Schuymered053432002-07-21 19:35:39 +0000964 if ( !(replace.counterchanges = (unsigned short *)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000965 malloc((oldnentries + 1) * sizeof(unsigned short))) )
966 print_memory();
Bart De Schuymer60332e02002-06-23 08:01:47 +0000967 }
968 // delete the counters belonging to the specified chain,
969 // update counter_offset
970 i = -1;
Bart De Schuymered053432002-07-21 19:35:39 +0000971 cnt = replace.counterchanges;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000972 while (1) {
973 i++;
974 entries = nr_to_chain(i);
975 if (!entries) {
976 if (i < NF_BR_NUMHOOKS)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000977 continue;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000978 else
979 break;
980 }
981 if (i > replace.selected_hook)
982 entries->counter_offset -= numdel;
983 if (replace.nentries) {
984 for (j = 0; j < entries->nentries; j++) {
985 if (i == replace.selected_hook)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000986 *cnt = CNT_DEL;
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000987 else
988 *cnt = CNT_NORM;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000989 cnt++;
990 }
991 }
Bart De Schuymer60332e02002-06-23 08:01:47 +0000992 }
993
994 if (replace.nentries) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000995 *cnt = CNT_END;
996 replace.num_counters = oldnentries;
Bart De Schuymercc440052002-11-06 21:10:33 +0000997 } else
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000998 replace.num_counters = 0;
999
Bart De Schuymer60332e02002-06-23 08:01:47 +00001000 entries = to_chain();
1001 entries->nentries = 0;
1002 u_e = entries->entries;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001003 while (u_e) {
1004 free_u_entry(u_e);
1005 tmp = u_e->next;
1006 free(u_e);
1007 u_e = tmp;
1008 }
Bart De Schuymer60332e02002-06-23 08:01:47 +00001009 entries->entries = NULL;
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001010 return 0;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001011}
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001012
1013// -1 == no match
1014static int check_rule_exists(int rule_nr)
1015{
1016 struct ebt_u_entry *u_e;
1017 struct ebt_u_match_list *m_l, *m_l2;
1018 struct ebt_u_match *m;
1019 struct ebt_u_watcher_list *w_l, *w_l2;
1020 struct ebt_u_watcher *w;
1021 struct ebt_u_target *t = (struct ebt_u_target *)new_entry->t;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001022 struct ebt_u_entries *entries = to_chain();
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001023 int i, j, k;
1024
1025 // handle '-D chain rulenr' command
1026 if (rule_nr != -1) {
Bart De Schuymer60332e02002-06-23 08:01:47 +00001027 if (rule_nr > entries->nentries)
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001028 return -1;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001029 // user starts counting from 1
1030 return rule_nr - 1;
1031 }
Bart De Schuymer60332e02002-06-23 08:01:47 +00001032 u_e = entries->entries;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001033 // check for an existing rule (if there are duplicate rules,
1034 // take the first occurance)
Bart De Schuymer60332e02002-06-23 08:01:47 +00001035 for (i = 0; i < entries->nentries; i++, u_e = u_e->next) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001036 if (!u_e)
1037 print_bug("Hmm, trouble");
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001038 if (u_e->ethproto != new_entry->ethproto)
1039 continue;
1040 if (strcmp(u_e->in, new_entry->in))
1041 continue;
1042 if (strcmp(u_e->out, new_entry->out))
1043 continue;
1044 if (strcmp(u_e->logical_in, new_entry->logical_in))
1045 continue;
1046 if (strcmp(u_e->logical_out, new_entry->logical_out))
1047 continue;
1048 if (new_entry->bitmask & EBT_SOURCEMAC &&
1049 memcmp(u_e->sourcemac, new_entry->sourcemac, ETH_ALEN))
1050 continue;
1051 if (new_entry->bitmask & EBT_DESTMAC &&
1052 memcmp(u_e->destmac, new_entry->destmac, ETH_ALEN))
1053 continue;
1054 if (new_entry->bitmask != u_e->bitmask ||
1055 new_entry->invflags != u_e->invflags)
1056 continue;
1057 // compare all matches
1058 m_l = new_entry->m_list;
1059 j = 0;
1060 while (m_l) {
1061 m = (struct ebt_u_match *)(m_l->m);
1062 m_l2 = u_e->m_list;
1063 while (m_l2 && strcmp(m_l2->m->u.name, m->m->u.name))
1064 m_l2 = m_l2->next;
1065 if (!m_l2 || !m->compare(m->m, m_l2->m))
1066 goto letscontinue;
1067 j++;
1068 m_l = m_l->next;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001069 }
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001070 // now be sure they have the same nr of matches
1071 k = 0;
1072 m_l = u_e->m_list;
1073 while (m_l) {
1074 k++;
1075 m_l = m_l->next;
1076 }
1077 if (j != k)
1078 continue;
1079
1080 // compare all watchers
1081 w_l = new_entry->w_list;
1082 j = 0;
1083 while (w_l) {
1084 w = (struct ebt_u_watcher *)(w_l->w);
1085 w_l2 = u_e->w_list;
1086 while (w_l2 && strcmp(w_l2->w->u.name, w->w->u.name))
1087 w_l2 = w_l2->next;
1088 if (!w_l2 || !w->compare(w->w, w_l2->w))
1089 goto letscontinue;
1090 j++;
1091 w_l = w_l->next;
1092 }
1093 k = 0;
1094 w_l = u_e->w_list;
1095 while (w_l) {
1096 k++;
1097 w_l = w_l->next;
1098 }
1099 if (j != k)
1100 continue;
1101 if (strcmp(t->t->u.name, u_e->t->u.name))
1102 continue;
1103 if (!t->compare(t->t, u_e->t))
1104 continue;
1105 return i;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001106letscontinue:
1107 }
1108 return -1;
1109}
1110
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001111// execute command A or I
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001112static void add_rule(int rule_nr)
1113{
1114 int i, j;
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001115 struct ebt_u_entry **u_e;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001116 unsigned short *cnt;
1117 struct ebt_u_match_list *m_l;
1118 struct ebt_u_watcher_list *w_l;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001119 struct ebt_u_entries *entries = to_chain(), *entries2;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001120
1121 if (rule_nr != -1) { // command -I
Bart De Schuymer60332e02002-06-23 08:01:47 +00001122 if (--rule_nr > entries->nentries)
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001123 print_error("rule nr too high: %d > %d", rule_nr + 1,
1124 entries->nentries + 1);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001125 } else
Bart De Schuymer60332e02002-06-23 08:01:47 +00001126 rule_nr = entries->nentries;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001127 // we're adding one rule
1128 replace.num_counters = replace.nentries;
1129 replace.nentries++;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001130 entries->nentries++;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001131
1132 // handle counter stuff
1133 // +1 for CNT_END
Bart De Schuymered053432002-07-21 19:35:39 +00001134 if ( !(replace.counterchanges = (unsigned short *)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001135 malloc((replace.nentries + 1) * sizeof(unsigned short))) )
1136 print_memory();
Bart De Schuymered053432002-07-21 19:35:39 +00001137 cnt = replace.counterchanges;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001138 for (i = 0; i < replace.selected_hook; i++) {
Bart De Schuymer60332e02002-06-23 08:01:47 +00001139 if (i < NF_BR_NUMHOOKS && !(replace.valid_hooks & (1 << i)))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001140 continue;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001141 entries2 = nr_to_chain(i);
1142 for (j = 0; j < entries2->nentries; j++) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001143 *cnt = CNT_NORM;
1144 cnt++;
1145 }
1146 }
1147 for (i = 0; i < rule_nr; i++) {
1148 *cnt = CNT_NORM;
1149 cnt++;
1150 }
1151 *cnt = CNT_ADD;
1152 cnt++;
Bart De Schuymered053432002-07-21 19:35:39 +00001153 while (cnt != replace.counterchanges + replace.nentries) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001154 *cnt = CNT_NORM;
1155 cnt++;
1156 }
1157 *cnt = CNT_END;
1158
1159 // go to the right position in the chain
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001160 u_e = &entries->entries;
1161 for (i = 0; i < rule_nr; i++)
1162 u_e = &(*u_e)->next;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001163 // insert the rule
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001164 new_entry->next = *u_e;
1165 *u_e = new_entry;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001166
1167 // put the ebt_[match, watcher, target] pointers in place
1168 m_l = new_entry->m_list;
1169 while (m_l) {
1170 m_l->m = ((struct ebt_u_match *)m_l->m)->m;
1171 m_l = m_l->next;
1172 }
1173 w_l = new_entry->w_list;
1174 while (w_l) {
1175 w_l->w = ((struct ebt_u_watcher *)w_l->w)->w;
1176 w_l = w_l->next;
1177 }
1178 new_entry->t = ((struct ebt_u_target *)new_entry->t)->t;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001179
1180 // update the counter_offset of chains behind this one
1181 i = replace.selected_hook;
1182 while (1) {
1183 i++;
1184 entries = nr_to_chain(i);
1185 if (!entries) {
1186 if (i < NF_BR_NUMHOOKS)
1187 continue;
1188 else
1189 break;
1190 } else
1191 entries->counter_offset++;
1192 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001193}
1194
1195// execute command D
Bart De Schuymercc440052002-11-06 21:10:33 +00001196static void delete_rule(int begin, int end)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001197{
Bart De Schuymercc440052002-11-06 21:10:33 +00001198 int j, lentmp = 0, nr_deletes;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001199 unsigned short *cnt;
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001200 struct ebt_u_entry **u_e, *u_e2;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001201 struct ebt_u_entries *entries = to_chain(), *entries2;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001202
Bart De Schuymercc440052002-11-06 21:10:33 +00001203 if ((begin = check_rule_exists(begin)) == -1 ||
1204 (end = check_rule_exists(end)) == -1)
Bart De Schuymer60332e02002-06-23 08:01:47 +00001205 print_error("Sorry, rule does not exist");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001206
Bart De Schuymercc440052002-11-06 21:10:33 +00001207 // we're deleting rules
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001208 replace.num_counters = replace.nentries;
Bart De Schuymercc440052002-11-06 21:10:33 +00001209 nr_deletes = end - begin + 1;
1210 replace.nentries -= nr_deletes;
1211 entries->nentries -= nr_deletes;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001212
1213 if (replace.nentries) {
1214 for (j = 0; j < replace.selected_hook; j++) {
Bart De Schuymer60332e02002-06-23 08:01:47 +00001215 if (j < NF_BR_NUMHOOKS &&
1216 !(replace.valid_hooks & (1 << j)))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001217 continue;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001218 entries2 = nr_to_chain(j);
1219 lentmp += entries2->nentries;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001220 }
Bart De Schuymercc440052002-11-06 21:10:33 +00001221 lentmp += begin;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001222 // +1 for CNT_END
Bart De Schuymered053432002-07-21 19:35:39 +00001223 if ( !(replace.counterchanges = (unsigned short *)malloc(
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001224 (replace.num_counters + 1) * sizeof(unsigned short))) )
1225 print_memory();
Bart De Schuymered053432002-07-21 19:35:39 +00001226 cnt = replace.counterchanges;
Bart De Schuymercc440052002-11-06 21:10:33 +00001227 for (j = 0; j < lentmp; j++, cnt++)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001228 *cnt = CNT_NORM;
Bart De Schuymercc440052002-11-06 21:10:33 +00001229 for (j = 0; j < nr_deletes; j++, cnt++)
1230 *cnt = CNT_DEL;
1231
1232 for (j = 0; j < replace.num_counters - lentmp - nr_deletes;
1233 j++, cnt++)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001234 *cnt = CNT_NORM;
Bart De Schuymercc440052002-11-06 21:10:33 +00001235
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001236 *cnt = CNT_END;
1237 }
1238 else
1239 replace.num_counters = 0;
1240
1241 // go to the right position in the chain
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001242 u_e = &entries->entries;
Bart De Schuymercc440052002-11-06 21:10:33 +00001243 for (j = 0; j < begin; j++)
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001244 u_e = &(*u_e)->next;
Bart De Schuymercc440052002-11-06 21:10:33 +00001245 // remove the rules
1246 j = nr_deletes;
1247 while(j--) {
1248 u_e2 = *u_e;
1249 *u_e = (*u_e)->next;
1250 // free everything
1251 free_u_entry(u_e2);
1252 free(u_e2);
1253 }
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001254
Bart De Schuymer60332e02002-06-23 08:01:47 +00001255 // update the counter_offset of chains behind this one
Bart De Schuymercc440052002-11-06 21:10:33 +00001256 j = replace.selected_hook;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001257 while (1) {
Bart De Schuymercc440052002-11-06 21:10:33 +00001258 j++;
1259 entries = nr_to_chain(j);
Bart De Schuymer60332e02002-06-23 08:01:47 +00001260 if (!entries) {
Bart De Schuymercc440052002-11-06 21:10:33 +00001261 if (j < NF_BR_NUMHOOKS)
Bart De Schuymer60332e02002-06-23 08:01:47 +00001262 continue;
1263 else
1264 break;
Bart De Schuymercc440052002-11-06 21:10:33 +00001265 } else
1266 entries->counter_offset -= nr_deletes;
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 Schuymercc440052002-11-06 21:10:33 +00001442static int parse_delete_rule(const char *argv, int *rule_nr, int *rule_nr_end)
1443{
1444 char *colon = strchr(argv, ':'), *buffer;
1445
1446 if (colon) {
1447 *colon = '\0';
1448 if (*(colon + 1) == '\0')
1449 *rule_nr_end = -1;
1450 else {
1451 *rule_nr_end = strtol(colon + 1, &buffer, 10);
1452 if (*buffer != '\0' || *rule_nr_end < 0)
1453 return -1;
1454 }
1455 }
1456 if (colon == argv)
1457 *rule_nr = 1;
1458 else {
1459 *rule_nr = strtol(argv, &buffer, 10);
1460 if (*buffer != '\0' || *rule_nr < 0)
1461 return -1;
1462 }
1463 if (!colon)
1464 *rule_nr_end = *rule_nr;
1465 if (*rule_nr_end != -1 && *rule_nr > *rule_nr_end)
1466 return -1;
1467 return 0;
1468}
1469
Bart De Schuymera615b962002-11-03 14:54:09 +00001470static int invert = 0;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001471int check_inverse(const char option[])
1472{
1473 if (strcmp(option, "!") == 0) {
Bart De Schuymera615b962002-11-03 14:54:09 +00001474 if (invert == 1)
1475 print_error("double use of '!' not allowed");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001476 optind++;
Bart De Schuymera615b962002-11-03 14:54:09 +00001477 invert = 1;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001478 return 1;
1479 }
Bart De Schuymera615b962002-11-03 14:54:09 +00001480 return invert;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001481}
1482
1483void check_option(unsigned int *flags, unsigned int mask)
1484{
1485 if (*flags & mask)
1486 print_error("Multiple use of same option not allowed");
1487 *flags |= mask;
1488}
1489
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001490static void get_kernel_table(const char *modprobe)
1491{
1492 if ( !(table = find_table(replace.name)) )
1493 print_error("Bad table name");
1494 // get the kernel's information
1495 if (get_table(&replace)) {
1496 ebtables_insmod("ebtables", modprobe);
1497 if (get_table(&replace))
1498 print_error("The kernel doesn't support the ebtables "
1499 "%s table", replace.name);
1500 }
Bart De Schuymer62a7fdb2002-08-24 21:01:21 +00001501 // when listing a table contained in a file, we don't expect the user
1502 // to know what the table's name is
1503 if ( !(table = find_table(replace.name)) )
1504 print_error("Bad table name");
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001505}
1506
Bart De Schuymerc5075142002-08-18 14:21:19 +00001507#define print_if_l_error print_error("Interface name length must be less " \
1508 "than %d", IFNAMSIZ)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001509#define OPT_COMMAND 0x01
1510#define OPT_TABLE 0x02
1511#define OPT_IN 0x04
1512#define OPT_OUT 0x08
1513#define OPT_JUMP 0x10
1514#define OPT_PROTOCOL 0x20
1515#define OPT_SOURCE 0x40
1516#define OPT_DEST 0x80
1517#define OPT_ZERO 0x100
1518#define OPT_LOGICALIN 0x200
1519#define OPT_LOGICALOUT 0x400
1520// the main thing
1521int main(int argc, char *argv[])
1522{
Bart De Schuymer923a5732002-08-11 12:01:33 +00001523 char *buffer;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001524 int c, i;
1525 // this special one for the -Z option (we can have -Z <this> -L <that>)
1526 int zerochain = -1;
Bart De Schuymerf8f8f292002-06-25 15:43:57 +00001527 int policy = 0;
Bart De Schuymercc440052002-11-06 21:10:33 +00001528 int rule_nr = -1; // used for -[D,I]
1529 int rule_nr_end = -1; // used for -I
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001530 struct ebt_u_target *t;
1531 struct ebt_u_match *m;
1532 struct ebt_u_watcher *w;
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001533 struct ebt_u_match_list *m_l;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001534 struct ebt_u_watcher_list *w_l;
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001535 struct ebt_u_entries *entries;
Bart De Schuymerc8531032002-06-14 21:55:29 +00001536 const char *modprobe = NULL;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001537
Bart De Schuymera615b962002-11-03 14:54:09 +00001538 opterr = 0;
1539
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001540 // initialize the table name, OPT_ flags, selected hook and command
1541 strcpy(replace.name, "filter");
1542 replace.flags = 0;
1543 replace.selected_hook = -1;
1544 replace.command = 'h';
Bart De Schuymer62423742002-07-14 19:06:20 +00001545 replace.filename = NULL;
Bart De Schuymered053432002-07-21 19:35:39 +00001546 replace.counterchanges = NULL;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001547
1548 new_entry = (struct ebt_u_entry *)malloc(sizeof(struct ebt_u_entry));
1549 if (!new_entry)
1550 print_memory();
1551 // put some sane values in our new entry
1552 initialize_entry(new_entry);
1553
Bart De Schuymer60332e02002-06-23 08:01:47 +00001554 // The scenario induced by this loop makes that:
Bart De Schuymer62423742002-07-14 19:06:20 +00001555 // '-t' ,'-M' and --atomic (if specified) have to come
1556 // before '-A' and the like
Bart De Schuymer60332e02002-06-23 08:01:47 +00001557
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001558 // getopt saves the day
1559 while ((c = getopt_long(argc, argv,
Bart De Schuymeraac31142002-08-11 11:57:52 +00001560 "-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 +00001561 switch (c) {
1562
1563 case 'A': // add a rule
1564 case 'D': // delete a rule
1565 case 'P': // define policy
1566 case 'I': // insert a rule
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001567 case 'N': // make a user defined chain
1568 case 'E': // rename chain
1569 case 'X': // delete chain
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001570 replace.command = c;
1571 if (replace.flags & OPT_COMMAND)
1572 print_error("Multiple commands not allowed");
1573 replace.flags |= OPT_COMMAND;
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001574 get_kernel_table(modprobe);
1575 if (optarg[0] == '-' || !strcmp(optarg, "!"))
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001576 print_error("No chain name specified");
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001577 if (c == 'N') {
1578 struct ebt_u_chain_list *cl, **cl2;
1579
1580 if (get_hooknr(optarg) != -1)
1581 print_error("Chain %s already exists",
1582 optarg);
1583 if (find_target(optarg))
1584 print_error("Target with name %s exists"
1585 , optarg);
1586 if (strlen(optarg) >= EBT_CHAIN_MAXNAMELEN)
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001587 print_error("Chain name length can't exceed %d",
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001588 EBT_CHAIN_MAXNAMELEN - 1);
1589 cl = (struct ebt_u_chain_list *)
1590 malloc(sizeof(struct ebt_u_chain_list));
1591 if (!cl)
1592 print_memory();
1593 cl->next = NULL;
1594 cl->udc = (struct ebt_u_entries *)
1595 malloc(sizeof(struct ebt_u_entries));
1596 if (!cl->udc)
1597 print_memory();
1598 cl->udc->nentries = 0;
1599 cl->udc->policy = EBT_ACCEPT;
1600 cl->udc->counter_offset = replace.nentries;
1601 cl->udc->hook_mask = 0;
1602 strcpy(cl->udc->name, optarg);
1603 cl->udc->entries = NULL;
1604 cl->kernel_start = NULL;
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001605 // put the new chain at the end
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001606 cl2 = &replace.udc;
1607 while (*cl2)
1608 cl2 = &((*cl2)->next);
1609 *cl2 = cl;
1610 break;
1611 }
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001612 if ((replace.selected_hook = get_hooknr(optarg)) == -1)
1613 print_error("Chain %s doesn't exist", optarg);
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001614 if (c == 'E') {
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001615 if (optind >= argc || argv[optind][0] == '-' ||
1616 !strcmp(argv[optind], "!"))
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001617 print_error("No new chain name specified");
1618 if (strlen(argv[optind]) >= EBT_CHAIN_MAXNAMELEN)
1619 print_error("Chain name len can't exceed %d",
1620 EBT_CHAIN_MAXNAMELEN - 1);
1621 if (get_hooknr(argv[optind]) != -1)
1622 print_error("Chain %s already exists",
1623 argv[optind]);
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001624 if (find_target(argv[optind]))
1625 print_error("Target with name %s exists"
1626 , argv[optind]);
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001627 entries = to_chain();
1628 strcpy(entries->name, argv[optind]);
1629 optind++;
1630 break;
1631 }
1632 if (c == 'X') {
1633 struct ebt_u_chain_list *cl, **cl2;
1634
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001635 if (replace.selected_hook < NF_BR_NUMHOOKS)
1636 print_error("You can't remove a standard chain");
Bart De Schuymerb909f9b2002-06-26 18:35:31 +00001637 // if the chain is referenced, don't delete it
1638 check_for_references(replace.selected_hook - NF_BR_NUMHOOKS);
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001639 flush_chains();
1640 entries = to_chain();
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001641 cl2 = &(replace.udc);
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001642 while ((*cl2)->udc != entries)
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001643 cl2 = &((*cl2)->next);
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001644 cl = (*cl2);
1645 (*cl2) = (*cl2)->next;
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001646 free(cl->udc);
1647 free(cl);
1648 break;
1649 }
1650
Bart De Schuymercc440052002-11-06 21:10:33 +00001651 if (c == 'D' && optind < argc &&
1652 argv[optind][0] != '-') {
1653 if (parse_delete_rule(argv[optind],
1654 &rule_nr, &rule_nr_end))
1655 print_error("Problem with the "
1656 "specified rule number(s)");
1657 optind++;
1658 }
1659 if (c == 'I') {
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001660 if (optind >= argc || argv[optind][0] == '-')
1661 print_error("No rulenr for -I"
1662 " specified");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001663 rule_nr = strtol(argv[optind], &buffer, 10);
1664 if (*buffer != '\0' || rule_nr < 0)
1665 print_error("Problem with the "
1666 "specified rule number");
1667 optind++;
1668 }
1669 if (c == 'P') {
1670 if (optind >= argc)
1671 print_error("No policy specified");
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001672 policy = 0;
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001673 for (i = 0; i < NUM_STANDARD_TARGETS; i++)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001674 if (!strcmp(argv[optind],
1675 standard_targets[i])) {
Bart De Schuymer60332e02002-06-23 08:01:47 +00001676 policy = -i -1;
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001677 if (policy == EBT_CONTINUE)
1678 policy = 0;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001679 break;
1680 }
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001681 if (policy == 0)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001682 print_error("Wrong policy");
1683 optind++;
1684 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001685 break;
1686
1687 case 'L': // list
1688 case 'F': // flush
1689 case 'Z': // zero counters
1690 if (c == 'Z') {
1691 if (replace.flags & OPT_ZERO)
1692 print_error("Multiple commands"
1693 " not allowed");
1694 if ( (replace.flags & OPT_COMMAND &&
1695 replace.command != 'L'))
1696 print_error("command -Z only allowed "
1697 "together with command -L");
1698 replace.flags |= OPT_ZERO;
1699 } else {
1700 replace.command = c;
1701 if (replace.flags & OPT_COMMAND)
1702 print_error("Multiple commands"
1703 " not allowed");
1704 replace.flags |= OPT_COMMAND;
1705 }
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001706 get_kernel_table(modprobe);
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001707 i = -1;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001708 if (optarg) {
1709 if ( (i = get_hooknr(optarg)) == -1 )
1710 print_error("Bad chain");
1711 } else
1712 if (optind < argc && argv[optind][0] != '-') {
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001713 if ((i = get_hooknr(argv[optind])) == -1)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001714 print_error("Bad chain");
1715 optind++;
1716 }
1717 if (i != -1) {
1718 if (c == 'Z')
1719 zerochain = i;
1720 else
1721 replace.selected_hook = i;
1722 }
1723 break;
1724
1725 case 'V': // version
1726 replace.command = 'V';
1727 if (replace.flags & OPT_COMMAND)
1728 print_error("Multiple commands not allowed");
Bart De Schuymerd4586482002-08-11 16:15:55 +00001729 printf(PROGNAME" v"PROGVERSION" ("PROGDATE")\n");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001730 exit(0);
1731
Bart De Schuymerc8531032002-06-14 21:55:29 +00001732 case 'M': // modprobe
Bart De Schuymer60332e02002-06-23 08:01:47 +00001733 if (replace.command != 'h')
1734 print_error("Please put the -M option earlier");
Bart De Schuymerc8531032002-06-14 21:55:29 +00001735 modprobe = optarg;
1736 break;
1737
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001738 case 'h': // help
1739 if (replace.flags & OPT_COMMAND)
1740 print_error("Multiple commands not allowed");
1741 replace.command = 'h';
1742 // All other arguments should be extension names
1743 while (optind < argc) {
1744 struct ebt_u_match *m;
1745 struct ebt_u_watcher *w;
1746
1747 if ((m = find_match(argv[optind])))
1748 add_match(m);
1749 else if ((w = find_watcher(argv[optind])))
1750 add_watcher(w);
1751 else {
1752 if (!(t = find_target(argv[optind])))
1753 print_error("Extension %s "
1754 "not found", argv[optind]);
1755 if (replace.flags & OPT_JUMP)
1756 print_error("Sorry, you can "
1757 "only see help for one "
1758 "target extension each time");
1759 replace.flags |= OPT_JUMP;
1760 new_entry->t =
1761 (struct ebt_entry_target *)t;
1762 }
1763 optind++;
1764 }
1765 break;
1766
1767 case 't': // table
Bart De Schuymer60332e02002-06-23 08:01:47 +00001768 if (replace.command != 'h')
1769 print_error("Please put the -t option first");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001770 check_option(&replace.flags, OPT_TABLE);
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001771 if (strlen(optarg) > EBT_TABLE_MAXNAMELEN - 1)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001772 print_error("Table name too long");
1773 strcpy(replace.name, optarg);
1774 break;
1775
1776 case 'i': // input interface
1777 case 2 : // logical input interface
1778 case 'o': // output interface
1779 case 3 : // logical output interface
1780 case 'j': // target
1781 case 'p': // net family protocol
1782 case 's': // source mac
1783 case 'd': // destination mac
1784 if ((replace.flags & OPT_COMMAND) == 0)
1785 print_error("No command specified");
1786 if ( replace.command != 'A' &&
1787 replace.command != 'D' && replace.command != 'I')
1788 print_error("Command and option do not match");
1789 if (c == 'i') {
1790 check_option(&replace.flags, OPT_IN);
1791 if (replace.selected_hook > 2 &&
1792 replace.selected_hook < NF_BR_BROUTING)
1793 print_error("Use in-interface only in "
1794 "INPUT, FORWARD, PREROUTING and"
1795 "BROUTING chains");
1796 if (check_inverse(optarg))
1797 new_entry->invflags |= EBT_IIN;
1798
1799 if (optind > argc)
1800 print_error("No in-interface "
1801 "specified");
1802 if (strlen(argv[optind - 1]) >= IFNAMSIZ)
Bart De Schuymerc5075142002-08-18 14:21:19 +00001803 print_if_l_error;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001804 strcpy(new_entry->in, argv[optind - 1]);
1805 break;
1806 }
1807 if (c == 2) {
1808 check_option(&replace.flags, OPT_LOGICALIN);
1809 if (replace.selected_hook > 2 &&
1810 replace.selected_hook < NF_BR_BROUTING)
1811 print_error("Use logical in-interface "
1812 "only in INPUT, FORWARD, "
1813 "PREROUTING and BROUTING chains");
1814 if (check_inverse(optarg))
1815 new_entry->invflags |= EBT_ILOGICALIN;
1816
1817 if (optind > argc)
1818 print_error("No logical in-interface "
1819 "specified");
1820 if (strlen(argv[optind - 1]) >= IFNAMSIZ)
Bart De Schuymerc5075142002-08-18 14:21:19 +00001821 print_if_l_error;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001822 strcpy(new_entry->logical_in, argv[optind - 1]);
1823 break;
1824 }
1825 if (c == 'o') {
1826 check_option(&replace.flags, OPT_OUT);
1827 if (replace.selected_hook < 2)
1828 print_error("Use out-interface only"
1829 " in OUTPUT, FORWARD and "
1830 "POSTROUTING chains");
1831 if (check_inverse(optarg))
1832 new_entry->invflags |= EBT_IOUT;
1833
1834 if (optind > argc)
1835 print_error("No out-interface "
1836 "specified");
1837
1838 if (strlen(argv[optind - 1]) >= IFNAMSIZ)
Bart De Schuymerc5075142002-08-18 14:21:19 +00001839 print_if_l_error;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001840 strcpy(new_entry->out, argv[optind - 1]);
1841 break;
1842 }
1843 if (c == 3) {
1844 check_option(&replace.flags, OPT_LOGICALOUT);
1845 if (replace.selected_hook < 2)
1846 print_error("Use logical out-interface "
1847 "only in OUTPUT, FORWARD and "
1848 "POSTROUTING chains");
1849 if (check_inverse(optarg))
1850 new_entry->invflags |= EBT_ILOGICALOUT;
1851
1852 if (optind > argc)
1853 print_error("No logical out-interface "
1854 "specified");
1855
1856 if (strlen(argv[optind - 1]) >= IFNAMSIZ)
Bart De Schuymerc5075142002-08-18 14:21:19 +00001857 print_if_l_error;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001858 strcpy(new_entry->logical_out,
1859 argv[optind - 1]);
1860 break;
1861 }
1862 if (c == 'j') {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001863 check_option(&replace.flags, OPT_JUMP);
1864 for (i = 0; i < NUM_STANDARD_TARGETS; i++)
1865 if (!strcmp(optarg,
1866 standard_targets[i])) {
1867 t = find_target(
1868 EBT_STANDARD_TARGET);
1869 ((struct ebt_standard_target *)
Bart De Schuymer60332e02002-06-23 08:01:47 +00001870 t->t)->verdict = -i - 1;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001871 break;
1872 }
Bart De Schuymer60332e02002-06-23 08:01:47 +00001873 if (-i - 1 == EBT_RETURN) {
1874 if (replace.selected_hook < NF_BR_NUMHOOKS)
1875 print_error("Return target"
1876 " only for user defined chains");
1877 }
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +00001878 if (i != NUM_STANDARD_TARGETS)
1879 break;
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001880 if ((i = get_hooknr(optarg)) != -1) {
1881 if (i < NF_BR_NUMHOOKS)
1882 print_error("don't jump"
1883 " to a standard chain");
1884 t = find_target(
1885 EBT_STANDARD_TARGET);
1886 ((struct ebt_standard_target *)
1887 t->t)->verdict = i - NF_BR_NUMHOOKS;
1888 break;
1889 }
1890 else {
1891 // must be an extension then
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001892 struct ebt_u_target *t;
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001893
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001894 t = find_target(optarg);
1895 // -j standard not allowed either
1896 if (!t || t ==
1897 (struct ebt_u_target *)new_entry->t)
1898 print_error("Illegal target "
1899 "name");
1900 new_entry->t =
1901 (struct ebt_entry_target *)t;
1902 }
1903 break;
1904 }
1905 if (c == 's') {
1906 check_option(&replace.flags, OPT_SOURCE);
1907 if (check_inverse(optarg))
1908 new_entry->invflags |= EBT_ISOURCE;
1909
1910 if (optind > argc)
1911 print_error("No source mac "
1912 "specified");
1913 if (getmac_and_mask(argv[optind - 1],
1914 new_entry->sourcemac, new_entry->sourcemsk))
1915 print_error("Problem with specified "
1916 "source mac");
1917 new_entry->bitmask |= EBT_SOURCEMAC;
1918 break;
1919 }
1920 if (c == 'd') {
1921 check_option(&replace.flags, OPT_DEST);
1922 if (check_inverse(optarg))
1923 new_entry->invflags |= EBT_IDEST;
1924
1925 if (optind > argc)
1926 print_error("No destination mac "
1927 "specified");
1928 if (getmac_and_mask(argv[optind - 1],
1929 new_entry->destmac, new_entry->destmsk))
1930 print_error("Problem with specified "
1931 "destination mac");
1932 new_entry->bitmask |= EBT_DESTMAC;
1933 break;
1934 }
1935 check_option(&replace.flags, OPT_PROTOCOL);
1936 if (check_inverse(optarg))
1937 new_entry->invflags |= EBT_IPROTO;
1938
1939 if (optind > argc)
1940 print_error("No protocol specified");
1941 new_entry->bitmask &= ~((unsigned int)EBT_NOPROTO);
1942 i = strtol(argv[optind - 1], &buffer, 16);
1943 if (*buffer == '\0' && (i < 0 || i > 0xFFFF))
1944 print_error("Problem with the specified "
1945 "protocol");
1946 new_entry->ethproto = i;
Bart De Schuymer28bf6f62002-06-26 18:57:24 +00001947 if (*buffer != '\0') {
1948 if ((i = name_to_number(argv[optind - 1],
1949 &new_entry->ethproto)) == -1)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001950 print_error("Problem with the specified"
1951 " protocol");
Bart De Schuymer28bf6f62002-06-26 18:57:24 +00001952 if (i == 1)
1953 new_entry->bitmask |= EBT_802_3;
1954 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001955 if (new_entry->ethproto < 1536 &&
1956 !(new_entry->bitmask & EBT_802_3))
1957 print_error("Sorry, protocols have values above"
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001958 " or equal to 0x0600");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001959 break;
1960
Bart De Schuymer9af14f92002-07-10 20:49:10 +00001961 case 4 : // Lc
1962 check_option(&replace.flags, LIST_C);
Bart De Schuymer9af14f92002-07-10 20:49:10 +00001963 if (replace.command != 'L')
1964 print_error("Use --Lc with -L");
1965 if (replace.flags & LIST_X)
1966 print_error("--Lx not compatible with --Lc");
1967 replace.flags |= LIST_C;
1968 break;
1969 case 5 : // Ln
1970 check_option(&replace.flags, LIST_N);
Bart De Schuymer9af14f92002-07-10 20:49:10 +00001971 if (replace.command != 'L')
1972 print_error("Use --Ln with -L");
1973 if (replace.flags & LIST_X)
1974 print_error("--Lx not compatible with --Ln");
1975 replace.flags |= LIST_N;
1976 break;
1977 case 6 : // Lx
1978 check_option(&replace.flags, LIST_X);
Bart De Schuymer9af14f92002-07-10 20:49:10 +00001979 if (replace.command != 'L')
1980 print_error("Use --Lx with -L");
1981 if (replace.flags & LIST_C)
1982 print_error("--Lx not compatible with --Lc");
1983 if (replace.flags & LIST_N)
1984 print_error("--Lx not compatible with --Ln");
1985 replace.flags |= LIST_X;
1986 break;
Bart De Schuymer62423742002-07-14 19:06:20 +00001987 case 8 : // atomic-commit
1988 replace.command = c;
1989 if (replace.flags & OPT_COMMAND)
1990 print_error("Multiple commands not allowed");
1991 replace.flags |= OPT_COMMAND;
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001992 if (replace.filename)
1993 print_error("--atomic incompatible with "
1994 "command");
Bart De Schuymer62423742002-07-14 19:06:20 +00001995 replace.filename = (char *)malloc(strlen(optarg) + 1);
1996 strcpy(replace.filename, optarg);
1997 // get the information from the file
1998 get_table(&replace);
Bart De Schuymer868bf642002-07-16 18:14:20 +00001999 if (replace.nentries) {
Bart De Schuymered053432002-07-21 19:35:39 +00002000 replace.counterchanges = (unsigned short *)
Bart De Schuymer868bf642002-07-16 18:14:20 +00002001 malloc(sizeof(unsigned short) * (replace.nentries + 1));
2002 for (i = 0; i < replace.nentries; i++)
Bart De Schuymered053432002-07-21 19:35:39 +00002003 replace.counterchanges[i] = CNT_NORM;
2004 replace.counterchanges[i] = CNT_END;
Bart De Schuymer868bf642002-07-16 18:14:20 +00002005 }
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00002006 // we don't want the kernel giving us its counters, they would
2007 // overwrite the counters extracted from the file
2008 replace.num_counters = 0;
2009 // make sure the table will be written to the kernel
Bart De Schuymer62423742002-07-14 19:06:20 +00002010 free(replace.filename);
2011 replace.filename = NULL;
Bart De Schuymerc5c3c2d2002-08-16 19:48:03 +00002012 ebtables_insmod("ebtables", modprobe);
Bart De Schuymer62423742002-07-14 19:06:20 +00002013 break;
2014 case 7 : // atomic-init
2015 case 10: // atomic-save
Bart De Schuymer8d1d8942002-07-15 20:09:09 +00002016 case 11: // init-table
Bart De Schuymer62423742002-07-14 19:06:20 +00002017 replace.command = c;
2018 if (replace.flags & OPT_COMMAND)
2019 print_error("Multiple commands not allowed");
2020 replace.flags |= OPT_COMMAND;
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00002021 if (replace.filename)
2022 print_error("--atomic incompatible with "
2023 "command");
2024 get_kernel_table(modprobe);
Bart De Schuymera8d920b2002-07-16 18:30:44 +00002025 if (replace.nentries) {
Bart De Schuymered053432002-07-21 19:35:39 +00002026 replace.counterchanges = (unsigned short *)
Bart De Schuymer5f16dc72002-07-16 18:08:36 +00002027 malloc(sizeof(unsigned short) * (replace.nentries + 1));
2028 for (i = 0; i < replace.nentries; i++)
Bart De Schuymered053432002-07-21 19:35:39 +00002029 replace.counterchanges[i] = CNT_NORM;
2030 replace.counterchanges[i] = CNT_END;
Bart De Schuymer5f16dc72002-07-16 18:08:36 +00002031 }
Bart De Schuymer8d1d8942002-07-15 20:09:09 +00002032 if (c == 11)
2033 break;
Bart De Schuymer62423742002-07-14 19:06:20 +00002034 case 9 : // atomic
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00002035 if (c == 9 && (replace.flags & OPT_COMMAND))
2036 print_error("--atomic has to come before"
2037 " the command");
Bart De Schuymer62423742002-07-14 19:06:20 +00002038 replace.filename = (char *)malloc(strlen(optarg) + 1);
2039 strcpy(replace.filename, optarg);
2040 break;
Bart De Schuymera615b962002-11-03 14:54:09 +00002041 case 1 :
2042 if (!strcmp(optarg, "!"))
2043 check_inverse(optarg);
2044 else
2045 print_error("Bad argument : %s", optarg);
2046 // check_inverse() did optind++
2047 optind--;
2048 continue;
Bart De Schuymer9af14f92002-07-10 20:49:10 +00002049 default:
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002050 // is it a target option?
2051 t = (struct ebt_u_target *)new_entry->t;
2052 if ((t->parse(c - t->option_offset, argv, argc,
2053 new_entry, &t->flags, &t->t)))
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00002054 goto check_extension;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002055
2056 // is it a match_option?
2057 for (m = matches; m; m = m->next)
2058 if (m->parse(c - m->option_offset, argv,
2059 argc, new_entry, &m->flags, &m->m))
2060 break;
2061
2062 if (m != NULL) {
2063 if (m->used == 0)
2064 add_match(m);
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00002065 goto check_extension;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002066 }
2067
2068 // is it a watcher option?
2069 for (w = watchers; w; w = w->next)
2070 if (w->parse(c-w->option_offset, argv,
2071 argc, new_entry, &w->flags, &w->w))
2072 break;
2073
2074 if (w == NULL)
2075 print_error("Unknown argument");
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00002076 if (w->used == 0)
2077 add_watcher(w);
2078check_extension:
Bart De Schuymer60332e02002-06-23 08:01:47 +00002079 if (replace.command != 'A' && replace.command != 'I' &&
2080 replace.command != 'D')
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00002081 print_error("Extensions only for -A, -I and -D");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002082 }
Bart De Schuymera615b962002-11-03 14:54:09 +00002083 invert = 0;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002084 }
2085
Bart De Schuymer25c741d2002-06-23 18:54:34 +00002086 if ( !table && !(table = find_table(replace.name)) )
2087 print_error("Bad table name");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002088
2089 if ( (replace.flags & OPT_COMMAND) && replace.command != 'L' &&
2090 replace.flags & OPT_ZERO )
2091 print_error("Command -Z only allowed together with command -L");
2092
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002093 // do this after parsing everything, so we can print specific info
2094 if (replace.command == 'h' && !(replace.flags & OPT_ZERO))
2095 print_help();
2096
2097 // do the final checks
Bart De Schuymer60332e02002-06-23 08:01:47 +00002098 if (replace.command == 'A' || replace.command == 'I' ||
2099 replace.command == 'D') {
2100 // this will put the hook_mask right for the chains
2101 check_for_loops();
2102 entries = to_chain();
2103 m_l = new_entry->m_list;
2104 w_l = new_entry->w_list;
2105 t = (struct ebt_u_target *)new_entry->t;
2106 while (m_l) {
2107 m = (struct ebt_u_match *)(m_l->m);
2108 m->final_check(new_entry, m->m, replace.name,
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +00002109 entries->hook_mask, 0);
Bart De Schuymer60332e02002-06-23 08:01:47 +00002110 m_l = m_l->next;
2111 }
2112 while (w_l) {
2113 w = (struct ebt_u_watcher *)(w_l->w);
2114 w->final_check(new_entry, w->w, replace.name,
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +00002115 entries->hook_mask, 0);
Bart De Schuymer60332e02002-06-23 08:01:47 +00002116 w_l = w_l->next;
2117 }
2118 t->final_check(new_entry, t->t, replace.name,
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +00002119 entries->hook_mask, 0);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002120 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002121 // so, the extensions can work with the host endian
2122 // the kernel does not have to do this ofcourse
2123 new_entry->ethproto = htons(new_entry->ethproto);
2124
Bart De Schuymerc34f4672002-08-18 18:03:52 +00002125 if (replace.command == 'P') {
2126 if (replace.selected_hook < NF_BR_NUMHOOKS &&
2127 policy == EBT_RETURN)
2128 print_error("Policy RETURN only allowed for user "
2129 "defined chains");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002130 change_policy(policy);
Bart De Schuymerc34f4672002-08-18 18:03:52 +00002131 } else if (replace.command == 'L') {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002132 list_rules();
2133 if (replace.flags & OPT_ZERO)
2134 zero_counters(zerochain);
2135 else
2136 exit(0);
2137 }
2138 if (replace.flags & OPT_ZERO)
2139 zero_counters(zerochain);
Bart De Schuymer1ab41562002-06-23 17:09:54 +00002140 else if (replace.command == 'F') {
2141 if (flush_chains() == -1)
2142 exit(0);
2143 } else if (replace.command == 'A' || replace.command == 'I') {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002144 add_rule(rule_nr);
Bart De Schuymer1ab41562002-06-23 17:09:54 +00002145 check_for_loops();
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +00002146 // do the final_check(), for all entries
2147 // needed when adding a rule that has a chain target
2148 i = -1;
2149 while (1) {
2150 struct ebt_u_entry *e;
2151
2152 i++;
2153 entries = nr_to_chain(i);
2154 if (!entries) {
2155 if (i < NF_BR_NUMHOOKS)
2156 continue;
2157 else
2158 break;
2159 }
2160 e = entries->entries;
2161 while (e) {
2162 // userspace extensions use host endian
2163 e->ethproto = ntohs(e->ethproto);
2164 do_final_checks(e, entries);
2165 e->ethproto = htons(e->ethproto);
2166 e = e->next;
2167 }
2168 }
Bart De Schuymercc440052002-11-06 21:10:33 +00002169 } else if (replace.command == 'D') {
2170 if (rule_nr != -1 && rule_nr_end == -1)
2171 rule_nr_end = entries->nentries;
2172 delete_rule(rule_nr, rule_nr_end);
2173 }
Bart De Schuymer8d1d8942002-07-15 20:09:09 +00002174 // commands -N, -E, -X, --atomic-commit, --atomic-commit, --atomic-save,
2175 // --init-table fall through
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002176
2177 if (table->check)
2178 table->check(&replace);
2179
2180 deliver_table(&replace);
2181
Bart De Schuymered053432002-07-21 19:35:39 +00002182 if (replace.counterchanges)
2183 deliver_counters(&replace);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002184 return 0;
2185}