blob: 6bfbb8fa2c5aedbeeb00a5b71df0cccce8aebe20 [file] [log] [blame]
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001/*
2 * ebtables.c, v2.0 April 2002
3 *
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>
32#include <linux/br_db.h> // the database
33#include <netinet/in.h>
Bart De Schuymer41830412002-06-05 19:41:28 +000034#include <netinet/ether.h>
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000035#include <asm/types.h>
36#include "include/ebtables_u.h"
Bart De Schuymerc8531032002-06-14 21:55:29 +000037#include <unistd.h>
38#include <fcntl.h>
39#include <sys/wait.h>
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000040
41// here are the number-name correspondences kept for the ethernet
42// frame type field
43#define PROTOCOLFILE "/etc/ethertypes"
44
Bart De Schuymerc8531032002-06-14 21:55:29 +000045#ifndef PROC_SYS_MODPROBE
46#define PROC_SYS_MODPROBE "/proc/sys/kernel/modprobe"
47#endif
48
Bart De Schuymer60332e02002-06-23 08:01:47 +000049#define DATABASEHOOKNR -2
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000050#define DATABASEHOOKNAME "DB"
51
52static char *prog_name = PROGNAME;
53static char *prog_version = PROGVERSION;
Bart De Schuymer60332e02002-06-23 08:01:47 +000054char *hooknames[NF_BR_NUMHOOKS] =
55{
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000056 [NF_BR_PRE_ROUTING]"PREROUTING",
57 [NF_BR_LOCAL_IN]"INPUT",
58 [NF_BR_FORWARD]"FORWARD",
59 [NF_BR_LOCAL_OUT]"OUTPUT",
60 [NF_BR_POST_ROUTING]"POSTROUTING",
61 [NF_BR_BROUTING]"BROUTING"
62};
63
64// default command line options
65static struct option ebt_original_options[] = {
66 { "append" , required_argument, 0, 'A' },
67 { "insert" , required_argument, 0, 'I' },
68 { "delete" , required_argument, 0, 'D' },
69 { "list" , optional_argument, 0, 'L' },
70 { "zero" , optional_argument, 0, 'Z' },
71 { "flush" , optional_argument, 0, 'F' },
72 { "policy" , required_argument, 0, 'P' },
73 { "in-interface" , required_argument, 0, 'i' },
74 { "in-if" , required_argument, 0, 'i' },
75 { "logical-in" , required_argument, 0, 2 },
76 { "logical-out" , required_argument, 0, 3 },
77 { "out-interface" , required_argument, 0, 'o' },
78 { "out-if" , required_argument, 0, 'o' },
79 { "version" , no_argument , 0, 'V' },
80 { "help" , no_argument , 0, 'h' },
81 { "jump" , required_argument, 0, 'j' },
82 { "proto" , required_argument, 0, 'p' },
83 { "protocol" , required_argument, 0, 'p' },
84 { "db" , required_argument, 0, 'b' },
85 { "source" , required_argument, 0, 's' },
86 { "src" , required_argument, 0, 's' },
87 { "destination" , required_argument, 0, 'd' },
88 { "dst" , required_argument, 0, 'd' },
89 { "table" , required_argument, 0, 't' },
Bart De Schuymerc8531032002-06-14 21:55:29 +000090 { "modprobe" , required_argument, 0, 'M' },
Bart De Schuymer1ab41562002-06-23 17:09:54 +000091 { "new-chain" , required_argument, 0, 'N' },
92 { "rename-chain" , required_argument, 0, 'E' },
93 { "delete-chain" , required_argument, 0, 'X' },
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000094 { 0 }
95};
96
97static struct option *ebt_options = ebt_original_options;
98
99// yup, all the possible target names
100char* standard_targets[NUM_STANDARD_TARGETS] = {
101 "ACCEPT",
102 "DROP",
103 "CONTINUE",
Bart De Schuymer60332e02002-06-23 08:01:47 +0000104 "RETURN",
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000105};
106
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000107unsigned char mac_type_unicast[ETH_ALEN] = {0,0,0,0,0,0};
108unsigned char msk_type_unicast[ETH_ALEN] = {1,0,0,0,0,0};
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000109unsigned char mac_type_multicast[ETH_ALEN] = {1,0,0,0,0,0};
110unsigned char msk_type_multicast[ETH_ALEN] = {1,0,0,0,0,0};
111unsigned char mac_type_broadcast[ETH_ALEN] = {255,255,255,255,255,255};
112unsigned char msk_type_broadcast[ETH_ALEN] = {255,255,255,255,255,255};
113
114// tells what happened to the old rules
115static unsigned short *counterchanges;
116// holds all the data
117static struct ebt_u_replace replace;
118
119// the chosen table
120static struct ebt_u_table *table = NULL;
121// the lists of supported tables, matches, watchers and targets
122static struct ebt_u_table *tables = NULL;
123static struct ebt_u_match *matches = NULL;
124static struct ebt_u_watcher *watchers = NULL;
125static struct ebt_u_target *targets = NULL;
126
127struct ebt_u_target *find_target(const char *name)
128{
129 struct ebt_u_target *t = targets;
130
131 while(t && strcmp(t->name, name))
132 t = t->next;
133 return t;
134}
135
136struct ebt_u_match *find_match(const char *name)
137{
138 struct ebt_u_match *m = matches;
139
140 while(m && strcmp(m->name, name))
141 m = m->next;
142 return m;
143}
144
145struct ebt_u_watcher *find_watcher(const char *name)
146{
147 struct ebt_u_watcher *w = watchers;
148
149 while(w && strcmp(w->name, name))
150 w = w->next;
151 return w;
152}
153
154struct ebt_u_table *find_table(char *name)
155{
156 struct ebt_u_table *t = tables;
157
158 while (t && strcmp(t->name, name))
159 t = t->next;
160 return t;
161}
162
163// The pointers in here are special:
164// The struct ebt_target * pointer is actually a struct ebt_u_target * pointer.
165// instead of making yet a few other structs, we just do a cast.
166// We need a struct ebt_u_target pointer because we know the address of the data
167// they point to won't change. We want to allow that the struct ebt_u_target.t
168// member can change.
169// Same holds for the struct ebt_match and struct ebt_watcher pointers
170struct ebt_u_entry *new_entry;
171
172void initialize_entry(struct ebt_u_entry *e)
173{
174 e->bitmask = EBT_NOPROTO;
175 e->invflags = 0;
176 e->ethproto = 0;
177 strcpy(e->in, "");
178 strcpy(e->out, "");
179 strcpy(e->logical_in, "");
180 strcpy(e->logical_out, "");
181 e->m_list = NULL;
182 e->w_list = NULL;
183 // the init function of the standard target should have put the verdict
184 // on CONTINUE
185 e->t = (struct ebt_entry_target *)find_target(EBT_STANDARD_TARGET);
186 if (!e->t)
187 print_bug("Couldn't load standard target\n");
188}
189
190// this doesn't free e, becoz the calling function might need e->next
191void free_u_entry(struct ebt_u_entry *e)
192{
193 struct ebt_u_match_list *m_l, *m_l2;
194 struct ebt_u_watcher_list *w_l, *w_l2;
195
196 m_l = e->m_list;
197 while (m_l) {
198 m_l2 = m_l->next;
199 free(m_l->m);
200 free(m_l);
201 m_l = m_l2;
202 }
203 w_l = e->w_list;
204 while (w_l) {
205 w_l2 = w_l->next;
206 free(w_l->w);
207 free(w_l);
208 w_l = w_l2;
209 }
210 free(e->t);
211}
212
213// the user will use the match, so put it in new_entry
214static void add_match(struct ebt_u_match *m)
215{
216 struct ebt_u_match_list **m_list, *new;
217
218 m->used = 1;
219 for (m_list = &new_entry->m_list;
220 *m_list; m_list = &(*m_list)->next);
221 new = (struct ebt_u_match_list *)
222 malloc(sizeof(struct ebt_u_match_list));
223 if (!new)
224 print_memory();
225 *m_list = new;
226 new->next = NULL;
227 new->m = (struct ebt_entry_match *)m;
228}
229
230static void add_watcher(struct ebt_u_watcher *w)
231{
232 struct ebt_u_watcher_list **w_list;
233 struct ebt_u_watcher_list *new;
234
235 w->used = 1;
236 for (w_list = &new_entry->w_list;
237 *w_list; w_list = &(*w_list)->next);
238 new = (struct ebt_u_watcher_list *)
239 malloc(sizeof(struct ebt_u_watcher_list));
240 if (!new)
241 print_memory();
242 *w_list = new;
243 new->next = NULL;
244 new->w = (struct ebt_entry_watcher *)w;
245}
246
247static int global_option_offset = 0;
248#define OPTION_OFFSET 256
249static struct option *
250merge_options(struct option *oldopts, const struct option *newopts,
251 unsigned int *options_offset)
252{
253 unsigned int num_old, num_new, i;
254 struct option *merge;
255
256 if (!newopts || !oldopts || !options_offset)
257 print_bug("merge wrong");
258 for (num_old = 0; oldopts[num_old].name; num_old++);
259 for (num_new = 0; newopts[num_new].name; num_new++);
260
261 global_option_offset += OPTION_OFFSET;
262 *options_offset = global_option_offset;
263
264 merge = malloc(sizeof(struct option) * (num_new + num_old + 1));
265 if (!merge)
266 print_memory();
267 memcpy(merge, oldopts, num_old * sizeof(struct option));
268 for (i = 0; i < num_new; i++) {
269 merge[num_old + i] = newopts[i];
270 merge[num_old + i].val += *options_offset;
271 }
272 memset(merge + num_old + num_new, 0, sizeof(struct option));
273 // only free dynamically allocated stuff
274 if (oldopts != ebt_original_options)
275 free(oldopts);
276
277 return merge;
278}
279
280void register_match(struct ebt_u_match *m)
281{
282 int size = m->size + sizeof(struct ebt_entry_match);
283 struct ebt_u_match **i;
284
285 m->m = (struct ebt_entry_match *)malloc(size);
286 if (!m->m)
287 print_memory();
288 strcpy(m->m->u.name, m->name);
289 m->m->match_size = m->size;
290 ebt_options = merge_options
291 (ebt_options, m->extra_ops, &(m->option_offset));
292 m->init(m->m);
293
294 for (i = &matches; *i; i = &((*i)->next));
295 m->next = NULL;
296 *i = m;
297}
298
299void register_watcher(struct ebt_u_watcher *w)
300{
301 int size = w->size + sizeof(struct ebt_entry_watcher);
302 struct ebt_u_watcher **i;
303
304 w->w = (struct ebt_entry_watcher *)malloc(size);
305 if (!w->w)
306 print_memory();
307 strcpy(w->w->u.name, w->name);
308 w->w->watcher_size = w->size;
309 ebt_options = merge_options
310 (ebt_options, w->extra_ops, &(w->option_offset));
311 w->init(w->w);
312
313 for (i = &watchers; *i; i = &((*i)->next));
314 w->next = NULL;
315 *i = w;
316}
317
318void register_target(struct ebt_u_target *t)
319{
320 int size = t->size + sizeof(struct ebt_entry_target);
321 struct ebt_u_target **i;
322
323 t->t = (struct ebt_entry_target *)malloc(size);
324 if (!t->t)
325 print_memory();
326 strcpy(t->t->u.name, t->name);
327 t->t->target_size = t->size;
328 ebt_options = merge_options
329 (ebt_options, t->extra_ops, &(t->option_offset));
330 t->init(t->t);
331 for (i = &targets; *i; i = &((*i)->next));
332 t->next = NULL;
333 *i = t;
334}
335
336void register_table(struct ebt_u_table *t)
337{
338 t->next = tables;
339 tables = t;
340}
341
Bart De Schuymerc8531032002-06-14 21:55:29 +0000342// blatently stolen (again) from iptables.c userspace program
343// find out where the modprobe utility is located
344static char *get_modprobe(void)
345{
346 int procfile;
347 char *ret;
348
349 procfile = open(PROC_SYS_MODPROBE, O_RDONLY);
350 if (procfile < 0)
351 return NULL;
352
353 ret = malloc(1024);
354 if (ret) {
355 switch (read(procfile, ret, 1024)) {
356 case -1: goto fail;
357 case 1024: goto fail; /* Partial read. Wierd */
358 }
359 if (ret[strlen(ret)-1]=='\n')
360 ret[strlen(ret)-1]=0;
361 close(procfile);
362 return ret;
363 }
364 fail:
365 free(ret);
366 close(procfile);
367 return NULL;
368}
369
370// I hate stealing, really... Lets call it a tribute.
371int ebtables_insmod(const char *modname, const char *modprobe)
372{
373 char *buf = NULL;
374 char *argv[3];
375
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000376 // If they don't explicitly set it, read out of kernel
Bart De Schuymerc8531032002-06-14 21:55:29 +0000377 if (!modprobe) {
378 buf = get_modprobe();
379 if (!buf)
380 return -1;
381 modprobe = buf;
382 }
383
384 switch (fork()) {
385 case 0:
386 argv[0] = (char *)modprobe;
387 argv[1] = (char *)modname;
388 argv[2] = NULL;
389 execv(argv[0], argv);
390
391 /* not usually reached */
392 exit(0);
393 case -1:
394 return -1;
395
396 default: /* parent */
397 wait(NULL);
398 }
399
400 free(buf);
401 return 0;
402}
403
404
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000405// used to parse /etc/ethertypes
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000406int disregard_whitespace(char *buffer, FILE *ifp)
407{
408 int hlp;
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000409
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000410 buffer[0] = '\t';
411 while (buffer[0] == '\t' || buffer[0] == '\n' || buffer[0] == ' ') {
412 hlp = fscanf(ifp, "%c", buffer);
413 if (hlp == EOF || hlp == 0) return -1;
414 }
415 return 0;
416}
417
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000418// used to parse /etc/ethertypes
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000419int disregard_tabspace(char *buffer, FILE *ifp)
420{
421 int hlp;
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000422
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000423 buffer[0] = '\t';
424 while (buffer[0] == '\t' || buffer[0] == ' ') {
425 hlp = fscanf(ifp, "%c", buffer);
426 if (hlp == EOF || hlp == 0) return -1;
427 }
428 return 0;
429}
430
Bart De Schuymerbbca3202002-06-05 18:55:44 +0000431// helper function: processes a line of data from the file /etc/ethertypes
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000432int get_a_line(char *buffer, char *value, FILE *ifp)
433{
434 int i, hlp;
435 char anotherhlp;
436
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000437 // discard comment lines and whitespace
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000438 while (1) {
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000439 if (disregard_whitespace(buffer, ifp))
440 return -1;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000441 if (buffer[0] == '#')
442 while (1) {
443 hlp = fscanf(ifp, "%c", &anotherhlp);
444 if (!hlp || hlp == EOF)
445 return -1;
446 if (anotherhlp == '\n')
447 break;
448 }
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000449 else
450 break;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000451 }
452
453 // buffer[0] already contains the first letter
454 for (i = 1; i < 21; i++) {
455 hlp = fscanf(ifp, "%c", buffer + i);
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000456 if (hlp == EOF || hlp == 0)
457 return -1;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000458 if (buffer[i] == '\t' || buffer[i] == ' ')
459 break;
460 }
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000461 if (i == 21)
462 return -1;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000463 buffer[i] = '\0';
464 if (disregard_tabspace(value, ifp))
465 return -1;
466 // maybe I should allow 0x0800 instead of 0800, but I'm feeling lazy
467 // buffer[0] already contains the first letter
468 for (i = 1; i < 5; i++) {
469 hlp = fscanf(ifp, "%c", value+i);
470 if (value[i] == '\n' || value[i] == '\t' ||
471 value[i] == ' ' || hlp == EOF)
472 break;
473 }
474 if (i == 5) return -1;
Bart De Schuymerbbca3202002-06-05 18:55:44 +0000475 // discard comments at the end of a line
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000476 if (value[i] == '\t' || value[i] == ' ')
477 while (1) {
478 hlp = fscanf(ifp, "%c", &anotherhlp);
479 if (!hlp || hlp == EOF || anotherhlp == '\n')
480 break;
481 }
482 value[i] = '\0';
483 return 0;
484}
485
Bart De Schuymerb909f9b2002-06-26 18:35:31 +0000486// translate a hexadecimal number to a protocol name, parsing /etc/ethertypes
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000487// returns 0 on success
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000488int number_to_name(unsigned short proto, char *name)
489{
490 FILE *ifp;
491 char buffer[21], value[5], *bfr;
492 unsigned short i;
493
494 if ( !(ifp = fopen(PROTOCOLFILE, "r")) )
495 return -1;
496 while (1) {
497 if (get_a_line(buffer, value, ifp)) {
498 fclose(ifp);
499 return -1;
500 }
501 i = (unsigned short) strtol(value, &bfr, 16);
502 if (*bfr != '\0' || i != proto)
503 continue;
504 strcpy(name, buffer);
505 fclose(ifp);
506 return 0;
507 }
508}
509
510// helper function for list_rules()
Bart De Schuymer60332e02002-06-23 08:01:47 +0000511static void list_em(struct ebt_u_entries *entries)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000512{
513 int i, j, space = 0, digits;
514 struct ebt_u_entry *hlp;
515 struct ebt_u_match_list *m_l;
516 struct ebt_u_watcher_list *w_l;
517 struct ebt_u_match *m;
518 struct ebt_u_watcher *w;
519 struct ebt_u_target *t;
520 char name[21];
521
Bart De Schuymer60332e02002-06-23 08:01:47 +0000522 hlp = entries->entries;
523 printf("\nBridge chain: %s\nPolicy: %s\n", entries->name,
524 standard_targets[-entries->policy - 1]);
525 printf("nr. of entries: %d \n", entries->nentries);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000526
Bart De Schuymer60332e02002-06-23 08:01:47 +0000527 i = entries->nentries;
Bart De Schuymerf8f8f292002-06-25 15:43:57 +0000528 while (i > 9) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000529 space++;
530 i /= 10;
531 }
532
Bart De Schuymer60332e02002-06-23 08:01:47 +0000533 for (i = 0; i < entries->nentries; i++) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000534 digits = 0;
535 // A little work to get nice rule numbers.
Bart De Schuymerf8f8f292002-06-25 15:43:57 +0000536 j = i + 1;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000537 while (j > 9) {
538 digits++;
539 j /= 10;
540 }
541 for (j = 0; j < space - digits; j++)
542 printf(" ");
543 printf("%d. ", i + 1);
544
545 // Don't print anything about the protocol if no protocol was
546 // specified, obviously this means any protocol will do.
547 if (!(hlp->bitmask & EBT_NOPROTO)) {
Bart De Schuymer60332e02002-06-23 08:01:47 +0000548 printf("-p ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000549 if (hlp->invflags & EBT_IPROTO)
550 printf("! ");
551 if (hlp->bitmask & EBT_802_3)
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000552 printf("Length ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000553 else {
554 if (number_to_name(ntohs(hlp->ethproto), name))
Bart De Schuymer60332e02002-06-23 08:01:47 +0000555 printf("0x%x ", ntohs(hlp->ethproto));
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000556 else
Bart De Schuymer60332e02002-06-23 08:01:47 +0000557 printf("%s ", name);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000558 }
559 }
560 if (hlp->bitmask & EBT_SOURCEMAC) {
561 char hlpmsk[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
562
Bart De Schuymer60332e02002-06-23 08:01:47 +0000563 printf("-s ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000564 if (hlp->invflags & EBT_ISOURCE)
565 printf("! ");
566 if (!memcmp(hlp->sourcemac, mac_type_unicast, 6) &&
567 !memcmp(hlp->sourcemsk, msk_type_unicast, 6)) {
568 printf("Unicast");
569 goto endsrc;
570 }
571 if (!memcmp(hlp->sourcemac, mac_type_multicast, 6) &&
572 !memcmp(hlp->sourcemsk, msk_type_multicast, 6)) {
573 printf("Multicast");
574 goto endsrc;
575 }
576 if (!memcmp(hlp->sourcemac, mac_type_broadcast, 6) &&
577 !memcmp(hlp->sourcemsk, msk_type_broadcast, 6)) {
578 printf("Broadcast");
579 goto endsrc;
580 }
Bart De Schuymer41830412002-06-05 19:41:28 +0000581 printf("%s", ether_ntoa((struct ether_addr *)
582 hlp->sourcemac));
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000583 if (memcmp(hlp->sourcemsk, hlpmsk, 6)) {
584 printf("/");
Bart De Schuymer41830412002-06-05 19:41:28 +0000585 printf("%s", ether_ntoa((struct ether_addr *)
586 hlp->sourcemsk));
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000587 }
588endsrc:
Bart De Schuymer60332e02002-06-23 08:01:47 +0000589 printf(" ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000590 }
591 if (hlp->bitmask & EBT_DESTMAC) {
592 char hlpmsk[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
593
Bart De Schuymer60332e02002-06-23 08:01:47 +0000594 printf("-d ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000595 if (hlp->invflags & EBT_IDEST)
596 printf("! ");
597 if (!memcmp(hlp->destmac, mac_type_unicast, 6) &&
598 !memcmp(hlp->destmsk, msk_type_unicast, 6)) {
599 printf("Unicast");
600 goto enddst;
601 }
602 if (!memcmp(hlp->destmac, mac_type_multicast, 6) &&
603 !memcmp(hlp->destmsk, msk_type_multicast, 6)) {
604 printf("Multicast");
605 goto enddst;
606 }
607 if (!memcmp(hlp->destmac, mac_type_broadcast, 6) &&
608 !memcmp(hlp->destmsk, msk_type_broadcast, 6)) {
609 printf("Broadcast");
610 goto enddst;
611 }
Bart De Schuymer41830412002-06-05 19:41:28 +0000612 printf("%s", ether_ntoa((struct ether_addr *)
613 hlp->destmac));
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000614 if (memcmp(hlp->destmsk, hlpmsk, 6)) {
615 printf("/");
Bart De Schuymer41830412002-06-05 19:41:28 +0000616 printf("%s", ether_ntoa((struct ether_addr *)
617 hlp->destmsk));
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000618 }
619enddst:
Bart De Schuymer60332e02002-06-23 08:01:47 +0000620 printf(" ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000621 }
622 if (hlp->in[0] != '\0') {
Bart De Schuymer60332e02002-06-23 08:01:47 +0000623 printf("-i ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000624 if (hlp->invflags & EBT_IIN)
625 printf("! ");
Bart De Schuymer60332e02002-06-23 08:01:47 +0000626 printf("%s ", hlp->in);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000627 }
628 if (hlp->logical_in[0] != '\0') {
Bart De Schuymer60332e02002-06-23 08:01:47 +0000629 printf("--logical-in ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000630 if (hlp->invflags & EBT_ILOGICALIN)
631 printf("! ");
Bart De Schuymer60332e02002-06-23 08:01:47 +0000632 printf("%s ", hlp->logical_in);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000633 }
634 if (hlp->logical_out[0] != '\0') {
Bart De Schuymer60332e02002-06-23 08:01:47 +0000635 printf("--logical-out ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000636 if (hlp->invflags & EBT_ILOGICALOUT)
637 printf("! ");
Bart De Schuymerb3d8f262002-07-07 14:26:15 +0000638 printf("%s ", hlp->logical_out);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000639 }
640 if (hlp->out[0] != '\0') {
Bart De Schuymer60332e02002-06-23 08:01:47 +0000641 printf("-o ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000642 if (hlp->invflags & EBT_IOUT)
643 printf("! ");
Bart De Schuymerb3d8f262002-07-07 14:26:15 +0000644 printf("%s ", hlp->out);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000645 }
646
647 m_l = hlp->m_list;
648 while (m_l) {
649 m = find_match(m_l->m->u.name);
650 if (!m)
651 print_bug("Match not found");
652 m->print(hlp, m_l->m);
653 m_l = m_l->next;
654 }
655 w_l = hlp->w_list;
656 while (w_l) {
657 w = find_watcher(w_l->w->u.name);
658 if (!w)
659 print_bug("Watcher not found");
660 w->print(hlp, w_l->w);
661 w_l = w_l->next;
662 }
663
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000664 printf("-j ");
665 if (strcmp(hlp->t->u.name, EBT_STANDARD_TARGET))
666 printf("%s ", hlp->t->u.name);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000667 t = find_target(hlp->t->u.name);
668 if (!t)
669 print_bug("Target not found");
670 t->print(hlp, hlp->t);
671 printf(", count = %llu",
Bart De Schuymer60332e02002-06-23 08:01:47 +0000672 replace.counters[entries->counter_offset + i].pcnt);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000673 printf("\n");
674 hlp = hlp->next;
675 }
676}
677
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000678struct ebt_u_entries *nr_to_chain(int nr)
Bart De Schuymer60332e02002-06-23 08:01:47 +0000679{
680 if (nr == -1)
681 return NULL;
682 if (nr < NF_BR_NUMHOOKS)
683 return replace.hook_entry[nr];
684 else {
685 int i;
686 struct ebt_u_chain_list *cl = replace.udc;
687
688 i = nr - NF_BR_NUMHOOKS;
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000689 while (i > 0 && cl) {
Bart De Schuymer60332e02002-06-23 08:01:47 +0000690 cl = cl->next;
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000691 i--;
692 }
Bart De Schuymer60332e02002-06-23 08:01:47 +0000693 if (cl)
694 return cl->udc;
695 else
696 return NULL;
697 }
698}
699
700static struct ebt_u_entries *to_chain()
701{
702 return nr_to_chain(replace.selected_hook);
703}
704
705struct ebt_u_stack
706{
707 int chain_nr;
708 int n;
709 struct ebt_u_entry *e;
710 struct ebt_u_entries *entries;
711};
712
713void check_for_loops()
714{
715 int chain_nr , i, j , k, sp = 0, verdict;
716 struct ebt_u_entries *entries, *entries2;
717 struct ebt_u_stack *stack = NULL;
718 struct ebt_u_entry *e;
719
720 i = -1;
721 // initialize hook_mask to 0
722 while (1) {
723 i++;
724 if (i < NF_BR_NUMHOOKS && !(replace.valid_hooks & (1 << i)))
725 continue;
726 entries = nr_to_chain(i);
727 if (!entries)
728 break;
729 entries->hook_mask = 0;
730 }
731 if (i > NF_BR_NUMHOOKS) {
732 stack = (struct ebt_u_stack *)malloc((i - NF_BR_NUMHOOKS) *
733 sizeof(struct ebt_u_stack));
734 if (!stack)
735 print_memory();
736 }
737
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000738 // check for loops, starting from every base chain
Bart De Schuymer60332e02002-06-23 08:01:47 +0000739 for (i = 0; i < NF_BR_NUMHOOKS; i++) {
740 if (!(replace.valid_hooks & (1 << i)))
741 continue;
742 entries = nr_to_chain(i);
743 entries->hook_mask = (1 << i);
744 chain_nr = i;
745
746 e = entries->entries;
747 for (j = 0; j < entries->nentries; j++) {
748 if (strcmp(e->t->u.name, EBT_STANDARD_TARGET))
749 goto letscontinue;
750 verdict = ((struct ebt_standard_target *)(e->t))->verdict;
751 if (verdict < 0)
752 goto letscontinue;
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000753 entries2 = nr_to_chain(verdict + NF_BR_NUMHOOKS);
Bart De Schuymer60332e02002-06-23 08:01:47 +0000754 entries2->hook_mask |= entries->hook_mask;
755 // now see if we've been here before
756 for (k = 0; k < sp; k++)
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000757 if (stack[k].chain_nr == verdict + NF_BR_NUMHOOKS)
Bart De Schuymer1a0a9c32002-06-24 21:10:16 +0000758 print_error("Loop from chain %s to chain %s",
759 nr_to_chain(chain_nr)->name, nr_to_chain(stack[k].chain_nr)->name);
Bart De Schuymer60332e02002-06-23 08:01:47 +0000760 // jump to the chain, make sure we know how to get back
761 stack[sp].chain_nr = chain_nr;
762 stack[sp].n = j;
763 stack[sp].entries = entries;
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000764 stack[sp].e = e;
765 sp++;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000766 j = -1;
767 e = entries2->entries;
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000768 chain_nr = verdict + NF_BR_NUMHOOKS;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000769 entries = entries2;
770 continue;
771letscontinue:
772 e = e->next;
773 }
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000774 // we are at the end of a standard chain
Bart De Schuymer60332e02002-06-23 08:01:47 +0000775 if (sp == 0)
776 continue;
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000777 // go back to the chain one level higher
Bart De Schuymer60332e02002-06-23 08:01:47 +0000778 sp--;
779 j = stack[sp].n;
780 chain_nr = stack[sp].chain_nr;
781 e = stack[sp].e;
782 entries = stack[sp].entries;
783 goto letscontinue;
784 }
785 free(stack);
786 return;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000787}
788
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000789// parse the chain name and return the corresponding nr
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000790// returns -1 on failure
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000791int get_hooknr(char* arg)
792{
793 int i;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000794 struct ebt_u_chain_list *cl = replace.udc;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000795
796 // database is special case (not really a chain)
797 if (!strcmp(arg, DATABASEHOOKNAME))
798 return DATABASEHOOKNR;
799
Bart De Schuymer60332e02002-06-23 08:01:47 +0000800 for (i = 0; i < NF_BR_NUMHOOKS; i++) {
801 if (!(replace.valid_hooks & (1 << i)))
802 continue;
803 if (!strcmp(arg, replace.hook_entry[i]->name))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000804 return i;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000805 }
806 while(cl) {
807 if (!strcmp(arg, cl->udc->name))
808 return i;
809 i++;
810 cl = cl->next;
811 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000812 return -1;
813}
814
815// yup, print out help
816void print_help()
817{
818 struct ebt_u_match_list *m_l;
819 struct ebt_u_watcher_list *w_l;
820
821 printf(
822"%s v%s\n"
823"Usage:\n"
824"ebtables -[ADI] chain rule-specification [options]\n"
825"ebtables -P chain target\n"
826"ebtables -[LFZ] [chain]\n"
827"ebtables -[b] [y,n]\n"
828"Commands:\n"
829"--append -A chain : Append to chain\n"
830"--delete -D chain : Delete matching rule from chain\n"
831"--delete -D chain rulenum : Delete rule at position rulenum from chain\n"
832"--insert -I chain rulenum : insert rule at position rulenum in chain\n"
833"--list -L [chain] : List the rules in a chain or in all chains\n"
834"--list -L "DATABASEHOOKNAME" : List the database (if present)\n"
835"--flush -F [chain] : Delete all rules in chain or in all chains\n"
836"--zero -Z [chain] : Put counters on zero in chain or in all chains\n"
837"--policy -P chain target : Change policy on chain to target\n"
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000838"--new-chain -N chain : Create a user defined chain\n"
839"--rename-chain -E old new : Rename a chain\n"
840"--delete-chain -X chain : Delete a user defined chain\n"
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000841"Options:\n"
842"--proto -p [!] proto : protocol hexadecimal, by name or LENGTH\n"
843"--src -s [!] address[/mask]: source mac address\n"
844"--dst -d [!] address[/mask]: destination mac address\n"
845"--in-if -i [!] name : network input interface name\n"
846"--out-if -o [!] name : network output interface name\n"
847"--logical-in [!] name : logical bridge input interface name\n"
848"--logical-out [!] name : logical bridge output interface name\n"
Bart De Schuymerc8531032002-06-14 21:55:29 +0000849"--modprobe -M : try to insert modules using this command\n"
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000850"--version -V : print package version\n"
851"\n" ,
852 prog_name,
853 prog_version);
854
855 m_l = new_entry->m_list;
856 while (m_l) {
857 ((struct ebt_u_match *)m_l->m)->help();
858 printf("\n");
859 m_l = m_l->next;
860 }
861 w_l = new_entry->w_list;
862 while (w_l) {
863 ((struct ebt_u_watcher *)w_l->w)->help();
864 printf("\n");
865 w_l = w_l->next;
866 }
867 ((struct ebt_u_target *)new_entry->t)->help();
868 printf("\n");
869 if (table->help)
870 table->help(hooknames);
871 exit(0);
872}
873
874// execute command L
875static void list_rules()
876{
877 int i;
878
879 printf("Bridge table: %s\n", table->name);
Bart De Schuymer60332e02002-06-23 08:01:47 +0000880 if (replace.selected_hook != -1) {
881 list_em(to_chain());
882 } else {
883 struct ebt_u_chain_list *cl = replace.udc;
884
885 i = 0;
886 while (1) {
887 if (i < NF_BR_NUMHOOKS) {
888 if (replace.valid_hooks & (1 << i))
889 list_em(replace.hook_entry[i]);
890 i++;
891 continue;
892 } else {
893 if (!cl)
894 break;
895 list_em(cl->udc);
896 cl = cl->next;
897 }
898 }
899 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000900}
901
902// execute command P
903static void change_policy(int policy)
904{
905 int i;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000906 struct ebt_u_entries *entries = to_chain();
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000907
908 // don't do anything if the policy is the same
Bart De Schuymer60332e02002-06-23 08:01:47 +0000909 if (entries->policy != policy) {
910 entries->policy = policy;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000911 replace.num_counters = replace.nentries;
912 if (replace.nentries) {
913 // '+ 1' for the CNT_END
914 if (!(counterchanges = (unsigned short *) malloc(
915 (replace.nentries + 1) * sizeof(unsigned short))))
916 print_memory();
917 // done nothing special to the rules
918 for (i = 0; i < replace.nentries; i++)
919 counterchanges[i] = CNT_NORM;
920 counterchanges[replace.nentries] = CNT_END;
921 }
922 else
923 counterchanges = NULL;
924 }
925 else
926 exit(0);
927}
928
929// flush one chain or the complete table
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000930// -1 == nothing to do
931// 0 == give back to kernel
932static int flush_chains()
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000933{
Bart De Schuymer60332e02002-06-23 08:01:47 +0000934 int i, j, oldnentries, numdel;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000935 unsigned short *cnt;
936 struct ebt_u_entry *u_e, *tmp;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000937 struct ebt_u_entries *entries = to_chain();
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000938
939 // flush whole table
Bart De Schuymer60332e02002-06-23 08:01:47 +0000940 if (!entries) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000941 if (replace.nentries == 0)
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000942 return -1;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000943 replace.nentries = 0;
944 // no need for the kernel to give us counters back
945 replace.num_counters = 0;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000946
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000947 // free everything and zero (n)entries
Bart De Schuymer60332e02002-06-23 08:01:47 +0000948 i = -1;
949 while (1) {
950 i++;
951 entries = nr_to_chain(i);
952 if (!entries) {
953 if (i < NF_BR_NUMHOOKS)
954 continue;
955 else
956 break;
957 }
958 entries->nentries = 0;
959 entries->counter_offset = 0;
960 u_e = entries->entries;
961 entries->entries = NULL;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000962 while (u_e) {
963 free_u_entry(u_e);
964 tmp = u_e->next;
965 free(u_e);
966 u_e = tmp;
967 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000968 }
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000969 return 0;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000970 }
971
Bart De Schuymer60332e02002-06-23 08:01:47 +0000972 if (entries->nentries == 0)
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000973 return -1;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000974 oldnentries = replace.nentries;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000975 replace.nentries -= entries->nentries;
976 numdel = entries->nentries;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000977
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000978 if (replace.nentries) {
979 // +1 for CNT_END
980 if ( !(counterchanges = (unsigned short *)
981 malloc((oldnentries + 1) * sizeof(unsigned short))) )
982 print_memory();
Bart De Schuymer60332e02002-06-23 08:01:47 +0000983 }
984 // delete the counters belonging to the specified chain,
985 // update counter_offset
986 i = -1;
Bart De Schuymerf8f8f292002-06-25 15:43:57 +0000987 cnt = counterchanges;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000988 while (1) {
989 i++;
990 entries = nr_to_chain(i);
991 if (!entries) {
992 if (i < NF_BR_NUMHOOKS)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000993 continue;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000994 else
995 break;
996 }
997 if (i > replace.selected_hook)
998 entries->counter_offset -= numdel;
999 if (replace.nentries) {
1000 for (j = 0; j < entries->nentries; j++) {
1001 if (i == replace.selected_hook)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001002 *cnt = CNT_DEL;
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001003 else
1004 *cnt = CNT_NORM;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001005 cnt++;
1006 }
1007 }
Bart De Schuymer60332e02002-06-23 08:01:47 +00001008 }
1009
1010 if (replace.nentries) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001011 *cnt = CNT_END;
1012 replace.num_counters = oldnentries;
1013 }
1014 else
1015 replace.num_counters = 0;
1016
Bart De Schuymer60332e02002-06-23 08:01:47 +00001017 entries = to_chain();
1018 entries->nentries = 0;
1019 u_e = entries->entries;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001020 while (u_e) {
1021 free_u_entry(u_e);
1022 tmp = u_e->next;
1023 free(u_e);
1024 u_e = tmp;
1025 }
Bart De Schuymer60332e02002-06-23 08:01:47 +00001026 entries->entries = NULL;
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001027 return 0;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001028}
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001029
1030// -1 == no match
1031static int check_rule_exists(int rule_nr)
1032{
1033 struct ebt_u_entry *u_e;
1034 struct ebt_u_match_list *m_l, *m_l2;
1035 struct ebt_u_match *m;
1036 struct ebt_u_watcher_list *w_l, *w_l2;
1037 struct ebt_u_watcher *w;
1038 struct ebt_u_target *t = (struct ebt_u_target *)new_entry->t;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001039 struct ebt_u_entries *entries = to_chain();
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001040 int i, j, k;
1041
1042 // handle '-D chain rulenr' command
1043 if (rule_nr != -1) {
Bart De Schuymer60332e02002-06-23 08:01:47 +00001044 if (rule_nr > entries->nentries)
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001045 return -1;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001046 // user starts counting from 1
1047 return rule_nr - 1;
1048 }
Bart De Schuymer60332e02002-06-23 08:01:47 +00001049 u_e = entries->entries;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001050 // check for an existing rule (if there are duplicate rules,
1051 // take the first occurance)
Bart De Schuymer60332e02002-06-23 08:01:47 +00001052 for (i = 0; i < entries->nentries; i++, u_e = u_e->next) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001053 if (!u_e)
1054 print_bug("Hmm, trouble");
1055 if ( u_e->ethproto == new_entry->ethproto
1056 && !strcmp(u_e->in, new_entry->in)
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001057 && !strcmp(u_e->out, new_entry->out)) {
Bart De Schuymer60332e02002-06-23 08:01:47 +00001058 if (strcmp(u_e->logical_in, new_entry->logical_in) ||
1059 strcmp(u_e->logical_out, new_entry->logical_out))
1060 continue;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001061 if (new_entry->bitmask & EBT_SOURCEMAC &&
Bart De Schuymer60332e02002-06-23 08:01:47 +00001062 memcmp(u_e->sourcemac, new_entry->sourcemac, ETH_ALEN))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001063 continue;
1064 if (new_entry->bitmask & EBT_DESTMAC &&
Bart De Schuymer60332e02002-06-23 08:01:47 +00001065 memcmp(u_e->destmac, new_entry->destmac, ETH_ALEN))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001066 continue;
1067 if (new_entry->bitmask != u_e->bitmask ||
1068 new_entry->invflags != u_e->invflags)
1069 continue;
1070 // compare all matches
1071 m_l = new_entry->m_list;
1072 j = 0;
1073 while (m_l) {
1074 m = (struct ebt_u_match *)(m_l->m);
1075 m_l2 = u_e->m_list;
1076 while (m_l2 &&
1077 strcmp(m_l2->m->u.name, m->m->u.name))
1078 m_l2 = m_l2->next;
1079 if (!m_l2 || !m->compare(m->m, m_l2->m))
1080 goto letscontinue;
1081 j++;
1082 m_l = m_l->next;
1083 }
1084 // now be sure they have the same nr of matches
1085 k = 0;
1086 m_l = u_e->m_list;
1087 while (m_l) {
1088 k++;
1089 m_l = m_l->next;
1090 }
1091 if (j != k)
1092 continue;
1093
1094 // compare all watchers
1095 w_l = new_entry->w_list;
1096 j = 0;
1097 while (w_l) {
1098 w = (struct ebt_u_watcher *)(w_l->w);
1099 w_l2 = u_e->w_list;
1100 while (w_l2 &&
1101 strcmp(w_l2->w->u.name, w->w->u.name))
1102 w_l2 = w_l2->next;
1103 if (!w_l2 || !w->compare(w->w, w_l2->w))
1104 goto letscontinue;
1105 j++;
1106 w_l = w_l->next;
1107 }
1108 k = 0;
1109 w_l = u_e->w_list;
1110 while (w_l) {
1111 k++;
1112 w_l = w_l->next;
1113 }
1114 if (j != k)
1115 continue;
1116 if (strcmp(t->t->u.name, u_e->t->u.name))
1117 continue;
1118 if (!t->compare(t->t, u_e->t))
1119 continue;
1120 return i;
1121 }
1122letscontinue:
1123 }
1124 return -1;
1125}
1126
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001127// execute command A or I
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001128static void add_rule(int rule_nr)
1129{
1130 int i, j;
1131 struct ebt_u_entry *u_e, *u_e2;
1132 unsigned short *cnt;
1133 struct ebt_u_match_list *m_l;
1134 struct ebt_u_watcher_list *w_l;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001135 struct ebt_u_entries *entries = to_chain(), *entries2;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001136
1137 if (rule_nr != -1) { // command -I
Bart De Schuymer60332e02002-06-23 08:01:47 +00001138 if (--rule_nr > entries->nentries)
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001139 print_error("rule nr too high: %d > %d", rule_nr + 1,
1140 entries->nentries + 1);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001141 } else
Bart De Schuymer60332e02002-06-23 08:01:47 +00001142 rule_nr = entries->nentries;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001143 // we're adding one rule
1144 replace.num_counters = replace.nentries;
1145 replace.nentries++;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001146 entries->nentries++;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001147
1148 // handle counter stuff
1149 // +1 for CNT_END
1150 if ( !(counterchanges = (unsigned short *)
1151 malloc((replace.nentries + 1) * sizeof(unsigned short))) )
1152 print_memory();
1153 cnt = counterchanges;
1154 for (i = 0; i < replace.selected_hook; i++) {
Bart De Schuymer60332e02002-06-23 08:01:47 +00001155 if (i < NF_BR_NUMHOOKS && !(replace.valid_hooks & (1 << i)))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001156 continue;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001157 entries2 = nr_to_chain(i);
1158 for (j = 0; j < entries2->nentries; j++) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001159 *cnt = CNT_NORM;
1160 cnt++;
1161 }
1162 }
1163 for (i = 0; i < rule_nr; i++) {
1164 *cnt = CNT_NORM;
1165 cnt++;
1166 }
1167 *cnt = CNT_ADD;
1168 cnt++;
1169 while (cnt != counterchanges + replace.nentries) {
1170 *cnt = CNT_NORM;
1171 cnt++;
1172 }
1173 *cnt = CNT_END;
1174
1175 // go to the right position in the chain
1176 u_e2 = NULL;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001177 u_e = entries->entries;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001178 for (i = 0; i < rule_nr; i++) {
1179 u_e2 = u_e;
1180 u_e = u_e->next;
1181 }
1182 // insert the rule
1183 if (u_e2)
1184 u_e2->next = new_entry;
1185 else
Bart De Schuymer60332e02002-06-23 08:01:47 +00001186 entries->entries = new_entry;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001187 new_entry->next = u_e;
1188
1189 // put the ebt_[match, watcher, target] pointers in place
1190 m_l = new_entry->m_list;
1191 while (m_l) {
1192 m_l->m = ((struct ebt_u_match *)m_l->m)->m;
1193 m_l = m_l->next;
1194 }
1195 w_l = new_entry->w_list;
1196 while (w_l) {
1197 w_l->w = ((struct ebt_u_watcher *)w_l->w)->w;
1198 w_l = w_l->next;
1199 }
1200 new_entry->t = ((struct ebt_u_target *)new_entry->t)->t;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001201
1202 // update the counter_offset of chains behind this one
1203 i = replace.selected_hook;
1204 while (1) {
1205 i++;
1206 entries = nr_to_chain(i);
1207 if (!entries) {
1208 if (i < NF_BR_NUMHOOKS)
1209 continue;
1210 else
1211 break;
1212 } else
1213 entries->counter_offset++;
1214 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001215}
1216
1217// execute command D
1218static void delete_rule(int rule_nr)
1219{
1220 int i, j, lentmp = 0;
1221 unsigned short *cnt;
1222 struct ebt_u_entry *u_e, *u_e2;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001223 struct ebt_u_entries *entries = to_chain(), *entries2;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001224
1225 if ( (i = check_rule_exists(rule_nr)) == -1 )
Bart De Schuymer60332e02002-06-23 08:01:47 +00001226 print_error("Sorry, rule does not exist");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001227
1228 // we're deleting a rule
1229 replace.num_counters = replace.nentries;
1230 replace.nentries--;
1231
1232 if (replace.nentries) {
1233 for (j = 0; j < replace.selected_hook; j++) {
Bart De Schuymer60332e02002-06-23 08:01:47 +00001234 if (j < NF_BR_NUMHOOKS &&
1235 !(replace.valid_hooks & (1 << j)))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001236 continue;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001237 entries2 = nr_to_chain(j);
1238 lentmp += entries2->nentries;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001239 }
1240 lentmp += i;
1241 // +1 for CNT_END
1242 if ( !(counterchanges = (unsigned short *)malloc(
1243 (replace.num_counters + 1) * sizeof(unsigned short))) )
1244 print_memory();
1245 cnt = counterchanges;
1246 for (j = 0; j < lentmp; j++) {
1247 *cnt = CNT_NORM;
1248 cnt++;
1249 }
1250 *cnt = CNT_DEL;
1251 cnt++;
1252 for (j = 0; j < replace.num_counters - lentmp; j++) {
1253 *cnt = CNT_NORM;
1254 cnt++;
1255 }
1256 *cnt = CNT_END;
1257 }
1258 else
1259 replace.num_counters = 0;
1260
1261 // go to the right position in the chain
1262 u_e2 = NULL;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001263 u_e = entries->entries;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001264 for (j = 0; j < i; j++) {
1265 u_e2 = u_e;
1266 u_e = u_e->next;
1267 }
1268
1269 // remove from the chain
1270 if (u_e2)
1271 u_e2->next = u_e->next;
1272 else
Bart De Schuymer60332e02002-06-23 08:01:47 +00001273 entries->entries = u_e->next;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001274
Bart De Schuymer60332e02002-06-23 08:01:47 +00001275 entries->nentries--;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001276 // free everything
1277 free_u_entry(u_e);
1278 free(u_e);
Bart De Schuymer60332e02002-06-23 08:01:47 +00001279 // update the counter_offset of chains behind this one
1280 i = replace.selected_hook;
1281 while (1) {
1282 i++;
1283 entries = nr_to_chain(i);
1284 if (!entries) {
1285 if (i < NF_BR_NUMHOOKS)
1286 continue;
1287 else
1288 break;
1289 } else
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001290 entries->counter_offset--;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001291 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001292}
1293
1294// execute command Z
1295void zero_counters(int zerochain)
1296{
1297
1298 if (zerochain == -1) {
1299 // tell main() we don't update the counters
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001300 // this results in tricking the kernel to zero its counters,
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001301 // naively expecting userspace to update its counters. Muahahaha
1302 counterchanges = NULL;
1303 replace.num_counters = 0;
1304 } else {
1305 int i, j;
1306 unsigned short *cnt;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001307 struct ebt_u_entries *entries = nr_to_chain(zerochain), *e2;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001308
Bart De Schuymer60332e02002-06-23 08:01:47 +00001309 if (entries->nentries == 0)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001310 exit(0);
1311 counterchanges = (unsigned short *)
1312 malloc((replace.nentries + 1) * sizeof(unsigned short));
1313 if (!counterchanges)
1314 print_memory();
1315 cnt = counterchanges;
1316 for (i = 0; i < zerochain; i++) {
Bart De Schuymer60332e02002-06-23 08:01:47 +00001317 if (i < NF_BR_NUMHOOKS &&
1318 !(replace.valid_hooks & (1 << i)))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001319 continue;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001320 e2 = nr_to_chain(i);
1321 for (j = 0; j < e2->nentries; j++) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001322 *cnt = CNT_NORM;
1323 cnt++;
1324 }
1325 }
Bart De Schuymer60332e02002-06-23 08:01:47 +00001326 for (i = 0; i < entries->nentries; i++) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001327 *cnt = CNT_ZERO;
1328 cnt++;
1329 }
1330 while (cnt != counterchanges + replace.nentries) {
1331 *cnt = CNT_NORM;
1332 cnt++;
1333 }
1334 *cnt = CNT_END;
1335 }
1336}
1337
1338// list the database (optionally compiled into the kernel)
1339static void list_db()
1340{
1341 struct brdb_dbinfo nr;
1342 struct brdb_dbentry *db;
1343 char name[21];
1344 int i;
1345
1346 get_dbinfo(&nr);
1347
1348 // 0 : database disabled (-db n)
1349 if (!(nr.nentries))
1350 print_error("Database not present"
1351 " (disabled), try ebtables --db y");
1352 nr.nentries--;
1353 if (!nr.nentries) print_error("Database empty");
1354 if ( !(db = (struct brdb_dbentry *)
1355 malloc(nr.nentries * sizeof(struct brdb_dbentry))) )
1356 print_memory();
1357
1358 get_db(nr.nentries, db);
1359 printf("number of entries: %d\n", nr.nentries);
1360 for (i = 0; i < nr.nentries; i++) {
1361 printf(
1362 "%d:\n"
1363 "hook : %s\n"
1364 "in-if : %s\n"
1365 "out-if : %s\n"
1366 "protocol: ", i + 1, hooknames[db->hook], db->in, db->out);
1367 if (db->ethproto == IDENTIFY802_3)
1368 printf("802.2/802.3 STYLE LENGTH FIELD\n");
1369 else {
1370 if (number_to_name(ntohs(db->ethproto), name))
1371 printf("%x\n",ntohs(db->ethproto));
1372 else
1373 printf("%s\n", name);
1374 }
1375 db++;
1376 }
1377 exit(0);
1378}
1379
1380// handle db [dis,en]abling
1381static void allowdb(char yorn)
1382{
1383 __u16 decision;
1384
1385 if (yorn != 'y' && yorn != 'n')
1386 print_error("Option [y] or [n] needed");
1387
1388 if (yorn == 'y')
1389 decision = BRDB_DB;
1390 else
1391 decision = BRDB_NODB;
1392
1393 deliver_allowdb(&decision);
1394
1395 exit(0);
1396}
1397
Bart De Schuymer28bf6f62002-06-26 18:57:24 +00001398// 0 == success
1399// 1 == success, but for the special 'protocol' LENGTH
1400// -1 == failure
1401int name_to_number(char *name, __u16 *proto)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001402{
1403 FILE *ifp;
1404 char buffer[21], value[5], *bfr;
1405 unsigned short i;
1406
1407 if (!strcasecmp("LENGTH", name)) {
Bart De Schuymer28bf6f62002-06-26 18:57:24 +00001408 *proto = 0;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001409 new_entry->bitmask |= EBT_802_3;
1410 return 1;
1411 }
1412 if ( !(ifp = fopen(PROTOCOLFILE, "r")) )
1413 return -1;
1414 while (1) {
1415 if (get_a_line(buffer, value, ifp)) return -1;
1416 if (strcasecmp(buffer, name))
1417 continue;
1418 i = (unsigned short) strtol(value, &bfr, 16);
1419 if (*bfr != '\0')
1420 return -1;
Bart De Schuymer28bf6f62002-06-26 18:57:24 +00001421 *proto = i;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001422 fclose(ifp);
1423 return 0;
1424 }
1425 return -1;
1426}
1427
1428// put the mac address into 6 (ETH_ALEN) bytes
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001429int getmac_and_mask(char *from, char *to, char *mask)
1430{
1431 char *p;
1432 int i;
Bart De Schuymer41830412002-06-05 19:41:28 +00001433 struct ether_addr *addr;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001434
1435 if (strcasecmp(from, "Unicast") == 0) {
1436 memcpy(to, mac_type_unicast, ETH_ALEN);
1437 memcpy(mask, msk_type_unicast, ETH_ALEN);
1438 return 0;
1439 }
1440 if (strcasecmp(from, "Multicast") == 0) {
1441 memcpy(to, mac_type_multicast, ETH_ALEN);
1442 memcpy(mask, msk_type_multicast, ETH_ALEN);
1443 return 0;
1444 }
1445 if (strcasecmp(from, "Broadcast") == 0) {
1446 memcpy(to, mac_type_broadcast, ETH_ALEN);
1447 memcpy(mask, msk_type_broadcast, ETH_ALEN);
1448 return 0;
1449 }
1450 if ( (p = strrchr(from, '/')) != NULL) {
1451 *p = '\0';
Bart De Schuymer41830412002-06-05 19:41:28 +00001452 if (!(addr = ether_aton(p + 1)))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001453 return -1;
Bart De Schuymer41830412002-06-05 19:41:28 +00001454 memcpy(mask, addr, ETH_ALEN);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001455 } else
1456 memset(mask, 0xff, ETH_ALEN);
Bart De Schuymer41830412002-06-05 19:41:28 +00001457 if (!(addr = ether_aton(from)))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001458 return -1;
Bart De Schuymer41830412002-06-05 19:41:28 +00001459 memcpy(to, addr, ETH_ALEN);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001460 for (i = 0; i < ETH_ALEN; i++)
1461 to[i] &= mask[i];
1462 return 0;
1463}
1464
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001465// executes the final_check() function for all extensions used by the rule
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +00001466void do_final_checks(struct ebt_u_entry *e, struct ebt_u_entries *entries)
1467{
1468 struct ebt_u_match_list *m_l;
1469 struct ebt_u_watcher_list *w_l;
1470 struct ebt_u_target *t;
1471 struct ebt_u_match *m;
1472 struct ebt_u_watcher *w;
1473
1474 m_l = e->m_list;
1475 w_l = e->w_list;
1476 while (m_l) {
1477 m = find_match(m_l->m->u.name);
1478 m->final_check(e, m_l->m, replace.name,
1479 entries->hook_mask, 1);
1480 m_l = m_l->next;
1481 }
1482 while (w_l) {
1483 w = find_watcher(w_l->w->u.name);
1484 w->final_check(e, w_l->w, replace.name,
1485 entries->hook_mask, 1);
1486 w_l = w_l->next;
1487 }
1488 t = find_target(e->t->u.name);
1489 t->final_check(e, e->t, replace.name,
1490 entries->hook_mask, 1);
1491}
1492
Bart De Schuymerb909f9b2002-06-26 18:35:31 +00001493// used for the -X command
1494void check_for_references(int chain_nr)
1495{
1496 int i = -1, j;
1497 struct ebt_u_entries *entries;
1498 struct ebt_u_entry *e;
1499
1500 while (1) {
1501 i++;
1502 entries = nr_to_chain(i);
1503 if (!entries) {
1504 if (i < NF_BR_NUMHOOKS)
1505 continue;
1506 else
1507 break;
1508 }
1509 e = entries->entries;
1510 j = 0;
1511 while (e) {
1512 j++;
1513 if (strcmp(e->t->u.name, EBT_STANDARD_TARGET)) {
1514 e = e->next;
1515 continue;
1516 }
1517 if (((struct ebt_standard_target *)e->t)->verdict == chain_nr)
1518 print_error("Can't delete the chain, it's referenced "
1519 "in chain %s, rule %d", entries->name, j);
1520 e = e->next;
1521 }
1522 }
1523}
1524
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001525int check_inverse(const char option[])
1526{
1527 if (strcmp(option, "!") == 0) {
1528 optind++;
1529 return 1;
1530 }
1531 return 0;
1532}
1533
1534void check_option(unsigned int *flags, unsigned int mask)
1535{
1536 if (*flags & mask)
1537 print_error("Multiple use of same option not allowed");
1538 *flags |= mask;
1539}
1540
1541#define OPT_COMMAND 0x01
1542#define OPT_TABLE 0x02
1543#define OPT_IN 0x04
1544#define OPT_OUT 0x08
1545#define OPT_JUMP 0x10
1546#define OPT_PROTOCOL 0x20
1547#define OPT_SOURCE 0x40
1548#define OPT_DEST 0x80
1549#define OPT_ZERO 0x100
1550#define OPT_LOGICALIN 0x200
1551#define OPT_LOGICALOUT 0x400
1552// the main thing
1553int main(int argc, char *argv[])
1554{
1555 char *buffer, allowbc = 'n';
1556 int c, i;
1557 // this special one for the -Z option (we can have -Z <this> -L <that>)
1558 int zerochain = -1;
Bart De Schuymerf8f8f292002-06-25 15:43:57 +00001559 int policy = 0;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001560 int rule_nr = -1;// used for -D chain number
1561 struct ebt_u_target *t;
1562 struct ebt_u_match *m;
1563 struct ebt_u_watcher *w;
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001564 struct ebt_u_match_list *m_l;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001565 struct ebt_u_watcher_list *w_l;
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001566 struct ebt_u_entries *entries;
Bart De Schuymerc8531032002-06-14 21:55:29 +00001567 const char *modprobe = NULL;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001568
1569 // initialize the table name, OPT_ flags, selected hook and command
1570 strcpy(replace.name, "filter");
1571 replace.flags = 0;
1572 replace.selected_hook = -1;
1573 replace.command = 'h';
1574
1575 new_entry = (struct ebt_u_entry *)malloc(sizeof(struct ebt_u_entry));
1576 if (!new_entry)
1577 print_memory();
1578 // put some sane values in our new entry
1579 initialize_entry(new_entry);
1580
Bart De Schuymer60332e02002-06-23 08:01:47 +00001581 // The scenario induced by this loop makes that:
1582 // '-t' and '-M' (if specified) have to come before '-A' and the like
1583
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001584 // getopt saves the day
1585 while ((c = getopt_long(argc, argv,
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001586 "-A:D:I:N:E:X:L::Z::F::P:Vhi:o:j:p:b:s:d:t:M:", ebt_options, NULL)) != -1) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001587 switch (c) {
1588
1589 case 'A': // add a rule
1590 case 'D': // delete a rule
1591 case 'P': // define policy
1592 case 'I': // insert a rule
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001593 case 'N': // make a user defined chain
1594 case 'E': // rename chain
1595 case 'X': // delete chain
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001596 replace.command = c;
1597 if (replace.flags & OPT_COMMAND)
1598 print_error("Multiple commands not allowed");
1599 replace.flags |= OPT_COMMAND;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001600 if ( !(table = find_table(replace.name)) )
1601 print_error("Bad table name");
1602 // get the kernel's information
1603 if (get_table(&replace)) {
1604 ebtables_insmod("ebtables", modprobe);
1605 if (get_table(&replace))
1606 print_error("can't initialize ebtables "
1607 "table %s", replace.name);
1608 }
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001609 if (optarg[0] == '-')
1610 print_error("No chain name specified");
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001611 if (c == 'N') {
1612 struct ebt_u_chain_list *cl, **cl2;
1613
1614 if (get_hooknr(optarg) != -1)
1615 print_error("Chain %s already exists",
1616 optarg);
1617 if (find_target(optarg))
1618 print_error("Target with name %s exists"
1619 , optarg);
1620 if (strlen(optarg) >= EBT_CHAIN_MAXNAMELEN)
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001621 print_error("Chain name length can't exceed %d",
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001622 EBT_CHAIN_MAXNAMELEN - 1);
1623 cl = (struct ebt_u_chain_list *)
1624 malloc(sizeof(struct ebt_u_chain_list));
1625 if (!cl)
1626 print_memory();
1627 cl->next = NULL;
1628 cl->udc = (struct ebt_u_entries *)
1629 malloc(sizeof(struct ebt_u_entries));
1630 if (!cl->udc)
1631 print_memory();
1632 cl->udc->nentries = 0;
1633 cl->udc->policy = EBT_ACCEPT;
1634 cl->udc->counter_offset = replace.nentries;
1635 cl->udc->hook_mask = 0;
1636 strcpy(cl->udc->name, optarg);
1637 cl->udc->entries = NULL;
1638 cl->kernel_start = NULL;
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001639 // put the new chain at the end
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001640 cl2 = &replace.udc;
1641 while (*cl2)
1642 cl2 = &((*cl2)->next);
1643 *cl2 = cl;
1644 break;
1645 }
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001646 if ((replace.selected_hook = get_hooknr(optarg)) == -1)
1647 print_error("Chain %s doesn't exist", optarg);
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001648 if (c == 'E') {
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001649 if (optind >= argc || argv[optind][0] == '-')
1650 print_error("No new chain name specified");
1651 if (strlen(argv[optind]) >= EBT_CHAIN_MAXNAMELEN)
1652 print_error("Chain name len can't exceed %d",
1653 EBT_CHAIN_MAXNAMELEN - 1);
1654 if (get_hooknr(argv[optind]) != -1)
1655 print_error("Chain %s already exists",
1656 argv[optind]);
1657 entries = to_chain();
1658 strcpy(entries->name, argv[optind]);
1659 optind++;
1660 break;
1661 }
1662 if (c == 'X') {
1663 struct ebt_u_chain_list *cl, **cl2;
1664
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001665 if (replace.selected_hook < NF_BR_NUMHOOKS)
1666 print_error("You can't remove a standard chain");
Bart De Schuymerb909f9b2002-06-26 18:35:31 +00001667 // if the chain is referenced, don't delete it
1668 check_for_references(replace.selected_hook - NF_BR_NUMHOOKS);
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001669 flush_chains();
1670 entries = to_chain();
1671 if (replace.udc->udc == entries) {
1672 cl = replace.udc;
1673 replace.udc = replace.udc->next;
1674 free(cl->udc);
1675 free(cl);
1676 break;
1677 }
1678 cl2 = &(replace.udc);
1679 while ((*cl2)->next->udc != entries)
1680 cl2 = &((*cl2)->next);
1681 cl = (*cl2)->next;
1682 (*cl2)->next = (*cl2)->next->next;
1683 free(cl->udc);
1684 free(cl);
1685 break;
1686 }
1687
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001688 if (c == 'D' && optind < argc &&
1689 argv[optind][0] != '-') {
1690 rule_nr = strtol(argv[optind], &buffer, 10);
1691 if (*buffer != '\0' || rule_nr < 0)
1692 print_error("Problem with the "
1693 "specified rule number");
1694 optind++;
1695 }
1696 if (c == 'P') {
1697 if (optind >= argc)
1698 print_error("No policy specified");
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001699 policy = 0;
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001700 for (i = 0; i < NUM_STANDARD_TARGETS; i++)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001701 if (!strcmp(argv[optind],
1702 standard_targets[i])) {
Bart De Schuymer60332e02002-06-23 08:01:47 +00001703 policy = -i -1;
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001704 if (policy == EBT_CONTINUE)
1705 policy = 0;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001706 break;
1707 }
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001708 if (policy == 0)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001709 print_error("Wrong policy");
1710 optind++;
1711 }
1712 if (c == 'I') {
1713 if (optind >= argc)
1714 print_error("No rulenr for -I"
1715 " specified");
1716 rule_nr = strtol(argv[optind], &buffer, 10);
1717 if (*buffer != '\0' || rule_nr < 0)
1718 print_error("Problem with the specified"
1719 " rule number");
1720 optind++;
1721 }
1722 break;
1723
1724 case 'L': // list
1725 case 'F': // flush
1726 case 'Z': // zero counters
1727 if (c == 'Z') {
1728 if (replace.flags & OPT_ZERO)
1729 print_error("Multiple commands"
1730 " not allowed");
1731 if ( (replace.flags & OPT_COMMAND &&
1732 replace.command != 'L'))
1733 print_error("command -Z only allowed "
1734 "together with command -L");
1735 replace.flags |= OPT_ZERO;
1736 } else {
1737 replace.command = c;
1738 if (replace.flags & OPT_COMMAND)
1739 print_error("Multiple commands"
1740 " not allowed");
1741 replace.flags |= OPT_COMMAND;
1742 }
Bart De Schuymer60332e02002-06-23 08:01:47 +00001743 if ( !(table = find_table(replace.name)) )
1744 print_error("Bad table name");
1745 // get the kernel's information
1746 if (get_table(&replace)) {
1747 ebtables_insmod("ebtables", modprobe);
1748 if (get_table(&replace))
1749 print_error("can't initialize ebtables "
1750 "table %s", replace.name);
1751 }
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001752 i = -1;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001753 if (optarg) {
1754 if ( (i = get_hooknr(optarg)) == -1 )
1755 print_error("Bad chain");
1756 } else
1757 if (optind < argc && argv[optind][0] != '-') {
1758 if ((i = get_hooknr(argv[optind]))
1759 == -1)
1760 print_error("Bad chain");
1761 optind++;
1762 }
1763 if (i != -1) {
1764 if (c == 'Z')
1765 zerochain = i;
1766 else
1767 replace.selected_hook = i;
1768 }
1769 break;
1770
1771 case 'V': // version
1772 replace.command = 'V';
1773 if (replace.flags & OPT_COMMAND)
1774 print_error("Multiple commands not allowed");
1775 printf("%s, %s\n", prog_name, prog_version);
1776 exit(0);
1777
Bart De Schuymerc8531032002-06-14 21:55:29 +00001778 case 'M': // modprobe
Bart De Schuymer60332e02002-06-23 08:01:47 +00001779 if (replace.command != 'h')
1780 print_error("Please put the -M option earlier");
Bart De Schuymerc8531032002-06-14 21:55:29 +00001781 modprobe = optarg;
1782 break;
1783
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001784 case 'h': // help
1785 if (replace.flags & OPT_COMMAND)
1786 print_error("Multiple commands not allowed");
1787 replace.command = 'h';
1788 // All other arguments should be extension names
1789 while (optind < argc) {
1790 struct ebt_u_match *m;
1791 struct ebt_u_watcher *w;
1792
1793 if ((m = find_match(argv[optind])))
1794 add_match(m);
1795 else if ((w = find_watcher(argv[optind])))
1796 add_watcher(w);
1797 else {
1798 if (!(t = find_target(argv[optind])))
1799 print_error("Extension %s "
1800 "not found", argv[optind]);
1801 if (replace.flags & OPT_JUMP)
1802 print_error("Sorry, you can "
1803 "only see help for one "
1804 "target extension each time");
1805 replace.flags |= OPT_JUMP;
1806 new_entry->t =
1807 (struct ebt_entry_target *)t;
1808 }
1809 optind++;
1810 }
1811 break;
1812
1813 case 't': // table
Bart De Schuymer60332e02002-06-23 08:01:47 +00001814 if (replace.command != 'h')
1815 print_error("Please put the -t option first");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001816 check_option(&replace.flags, OPT_TABLE);
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001817 if (strlen(optarg) > EBT_TABLE_MAXNAMELEN - 1)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001818 print_error("Table name too long");
1819 strcpy(replace.name, optarg);
1820 break;
1821
1822 case 'i': // input interface
1823 case 2 : // logical input interface
1824 case 'o': // output interface
1825 case 3 : // logical output interface
1826 case 'j': // target
1827 case 'p': // net family protocol
1828 case 's': // source mac
1829 case 'd': // destination mac
1830 if ((replace.flags & OPT_COMMAND) == 0)
1831 print_error("No command specified");
1832 if ( replace.command != 'A' &&
1833 replace.command != 'D' && replace.command != 'I')
1834 print_error("Command and option do not match");
1835 if (c == 'i') {
1836 check_option(&replace.flags, OPT_IN);
1837 if (replace.selected_hook > 2 &&
1838 replace.selected_hook < NF_BR_BROUTING)
1839 print_error("Use in-interface only in "
1840 "INPUT, FORWARD, PREROUTING and"
1841 "BROUTING chains");
1842 if (check_inverse(optarg))
1843 new_entry->invflags |= EBT_IIN;
1844
1845 if (optind > argc)
1846 print_error("No in-interface "
1847 "specified");
1848 if (strlen(argv[optind - 1]) >= IFNAMSIZ)
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001849 print_error("Illegal interface length");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001850 strcpy(new_entry->in, argv[optind - 1]);
1851 break;
1852 }
1853 if (c == 2) {
1854 check_option(&replace.flags, OPT_LOGICALIN);
1855 if (replace.selected_hook > 2 &&
1856 replace.selected_hook < NF_BR_BROUTING)
1857 print_error("Use logical in-interface "
1858 "only in INPUT, FORWARD, "
1859 "PREROUTING and BROUTING chains");
1860 if (check_inverse(optarg))
1861 new_entry->invflags |= EBT_ILOGICALIN;
1862
1863 if (optind > argc)
1864 print_error("No logical in-interface "
1865 "specified");
1866 if (strlen(argv[optind - 1]) >= IFNAMSIZ)
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001867 print_error("Illegal interface length");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001868 strcpy(new_entry->logical_in, argv[optind - 1]);
1869 break;
1870 }
1871 if (c == 'o') {
1872 check_option(&replace.flags, OPT_OUT);
1873 if (replace.selected_hook < 2)
1874 print_error("Use out-interface only"
1875 " in OUTPUT, FORWARD and "
1876 "POSTROUTING chains");
1877 if (check_inverse(optarg))
1878 new_entry->invflags |= EBT_IOUT;
1879
1880 if (optind > argc)
1881 print_error("No out-interface "
1882 "specified");
1883
1884 if (strlen(argv[optind - 1]) >= IFNAMSIZ)
1885 print_error("Illegal interface "
1886 "length");
1887 strcpy(new_entry->out, argv[optind - 1]);
1888 break;
1889 }
1890 if (c == 3) {
1891 check_option(&replace.flags, OPT_LOGICALOUT);
1892 if (replace.selected_hook < 2)
1893 print_error("Use logical out-interface "
1894 "only in OUTPUT, FORWARD and "
1895 "POSTROUTING chains");
1896 if (check_inverse(optarg))
1897 new_entry->invflags |= EBT_ILOGICALOUT;
1898
1899 if (optind > argc)
1900 print_error("No logical out-interface "
1901 "specified");
1902
1903 if (strlen(argv[optind - 1]) >= IFNAMSIZ)
1904 print_error("Illegal interface "
1905 "length");
1906 strcpy(new_entry->logical_out,
1907 argv[optind - 1]);
1908 break;
1909 }
1910 if (c == 'j') {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001911 check_option(&replace.flags, OPT_JUMP);
1912 for (i = 0; i < NUM_STANDARD_TARGETS; i++)
1913 if (!strcmp(optarg,
1914 standard_targets[i])) {
1915 t = find_target(
1916 EBT_STANDARD_TARGET);
1917 ((struct ebt_standard_target *)
Bart De Schuymer60332e02002-06-23 08:01:47 +00001918 t->t)->verdict = -i - 1;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001919 break;
1920 }
Bart De Schuymer60332e02002-06-23 08:01:47 +00001921 if (-i - 1 == EBT_RETURN) {
1922 if (replace.selected_hook < NF_BR_NUMHOOKS)
1923 print_error("Return target"
1924 " only for user defined chains");
1925 }
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +00001926 if (i != NUM_STANDARD_TARGETS)
1927 break;
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001928 if ((i = get_hooknr(optarg)) != -1) {
1929 if (i < NF_BR_NUMHOOKS)
1930 print_error("don't jump"
1931 " to a standard chain");
1932 t = find_target(
1933 EBT_STANDARD_TARGET);
1934 ((struct ebt_standard_target *)
1935 t->t)->verdict = i - NF_BR_NUMHOOKS;
1936 break;
1937 }
1938 else {
1939 // must be an extension then
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001940 struct ebt_u_target *t;
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001941
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001942 t = find_target(optarg);
1943 // -j standard not allowed either
1944 if (!t || t ==
1945 (struct ebt_u_target *)new_entry->t)
1946 print_error("Illegal target "
1947 "name");
1948 new_entry->t =
1949 (struct ebt_entry_target *)t;
1950 }
1951 break;
1952 }
1953 if (c == 's') {
1954 check_option(&replace.flags, OPT_SOURCE);
1955 if (check_inverse(optarg))
1956 new_entry->invflags |= EBT_ISOURCE;
1957
1958 if (optind > argc)
1959 print_error("No source mac "
1960 "specified");
1961 if (getmac_and_mask(argv[optind - 1],
1962 new_entry->sourcemac, new_entry->sourcemsk))
1963 print_error("Problem with specified "
1964 "source mac");
1965 new_entry->bitmask |= EBT_SOURCEMAC;
1966 break;
1967 }
1968 if (c == 'd') {
1969 check_option(&replace.flags, OPT_DEST);
1970 if (check_inverse(optarg))
1971 new_entry->invflags |= EBT_IDEST;
1972
1973 if (optind > argc)
1974 print_error("No destination mac "
1975 "specified");
1976 if (getmac_and_mask(argv[optind - 1],
1977 new_entry->destmac, new_entry->destmsk))
1978 print_error("Problem with specified "
1979 "destination mac");
1980 new_entry->bitmask |= EBT_DESTMAC;
1981 break;
1982 }
1983 check_option(&replace.flags, OPT_PROTOCOL);
1984 if (check_inverse(optarg))
1985 new_entry->invflags |= EBT_IPROTO;
1986
1987 if (optind > argc)
1988 print_error("No protocol specified");
1989 new_entry->bitmask &= ~((unsigned int)EBT_NOPROTO);
1990 i = strtol(argv[optind - 1], &buffer, 16);
1991 if (*buffer == '\0' && (i < 0 || i > 0xFFFF))
1992 print_error("Problem with the specified "
1993 "protocol");
1994 new_entry->ethproto = i;
Bart De Schuymer28bf6f62002-06-26 18:57:24 +00001995 if (*buffer != '\0') {
1996 if ((i = name_to_number(argv[optind - 1],
1997 &new_entry->ethproto)) == -1)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001998 print_error("Problem with the specified"
1999 " protocol");
Bart De Schuymer28bf6f62002-06-26 18:57:24 +00002000 if (i == 1)
2001 new_entry->bitmask |= EBT_802_3;
2002 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002003 if (new_entry->ethproto < 1536 &&
2004 !(new_entry->bitmask & EBT_802_3))
2005 print_error("Sorry, protocols have values above"
2006 " or equal to 1536 (0x0600)");
2007 break;
2008
2009 case 'b': // allow database?
2010 if (replace.flags & OPT_COMMAND)
2011 print_error("Multiple commands not allowed");
2012 replace.command = c;
2013 allowbc = *optarg;
2014 break;
2015
2016 default:
2017
2018 // is it a target option?
2019 t = (struct ebt_u_target *)new_entry->t;
2020 if ((t->parse(c - t->option_offset, argv, argc,
2021 new_entry, &t->flags, &t->t)))
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00002022 goto check_extension;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002023
2024 // is it a match_option?
2025 for (m = matches; m; m = m->next)
2026 if (m->parse(c - m->option_offset, argv,
2027 argc, new_entry, &m->flags, &m->m))
2028 break;
2029
2030 if (m != NULL) {
2031 if (m->used == 0)
2032 add_match(m);
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00002033 goto check_extension;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002034 }
2035
2036 // is it a watcher option?
2037 for (w = watchers; w; w = w->next)
2038 if (w->parse(c-w->option_offset, argv,
2039 argc, new_entry, &w->flags, &w->w))
2040 break;
2041
2042 if (w == NULL)
2043 print_error("Unknown argument");
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00002044 if (w->used == 0)
2045 add_watcher(w);
2046check_extension:
Bart De Schuymer60332e02002-06-23 08:01:47 +00002047 if (replace.command != 'A' && replace.command != 'I' &&
2048 replace.command != 'D')
2049 print_error("extensions only for -A, -I and -D");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002050 }
2051 }
2052
Bart De Schuymer25c741d2002-06-23 18:54:34 +00002053 if ( !table && !(table = find_table(replace.name)) )
2054 print_error("Bad table name");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002055 // database stuff before ebtables stuff
2056 if (replace.command == 'b')
2057 allowdb(allowbc);
2058 if (replace.command == 'L' && replace.selected_hook == DATABASEHOOKNR)
2059 list_db();
2060
2061 if ( (replace.flags & OPT_COMMAND) && replace.command != 'L' &&
2062 replace.flags & OPT_ZERO )
2063 print_error("Command -Z only allowed together with command -L");
2064
2065 if (replace.command == 'A' || replace.command == 'I' ||
2066 replace.command == 'D') {
2067 if (replace.selected_hook == -1)
2068 print_error("Not enough information");
2069 }
2070
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002071 // do this after parsing everything, so we can print specific info
2072 if (replace.command == 'h' && !(replace.flags & OPT_ZERO))
2073 print_help();
2074
2075 // do the final checks
Bart De Schuymer60332e02002-06-23 08:01:47 +00002076 if (replace.command == 'A' || replace.command == 'I' ||
2077 replace.command == 'D') {
2078 // this will put the hook_mask right for the chains
2079 check_for_loops();
2080 entries = to_chain();
2081 m_l = new_entry->m_list;
2082 w_l = new_entry->w_list;
2083 t = (struct ebt_u_target *)new_entry->t;
2084 while (m_l) {
2085 m = (struct ebt_u_match *)(m_l->m);
2086 m->final_check(new_entry, m->m, replace.name,
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +00002087 entries->hook_mask, 0);
Bart De Schuymer60332e02002-06-23 08:01:47 +00002088 m_l = m_l->next;
2089 }
2090 while (w_l) {
2091 w = (struct ebt_u_watcher *)(w_l->w);
2092 w->final_check(new_entry, w->w, replace.name,
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +00002093 entries->hook_mask, 0);
Bart De Schuymer60332e02002-06-23 08:01:47 +00002094 w_l = w_l->next;
2095 }
2096 t->final_check(new_entry, t->t, replace.name,
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +00002097 entries->hook_mask, 0);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002098 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002099 // so, the extensions can work with the host endian
2100 // the kernel does not have to do this ofcourse
2101 new_entry->ethproto = htons(new_entry->ethproto);
2102
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002103 if (replace.command == 'P')
2104 change_policy(policy);
2105 else if (replace.command == 'L') {
2106 list_rules();
2107 if (replace.flags & OPT_ZERO)
2108 zero_counters(zerochain);
2109 else
2110 exit(0);
2111 }
2112 if (replace.flags & OPT_ZERO)
2113 zero_counters(zerochain);
Bart De Schuymer1ab41562002-06-23 17:09:54 +00002114 else if (replace.command == 'F') {
2115 if (flush_chains() == -1)
2116 exit(0);
2117 } else if (replace.command == 'A' || replace.command == 'I') {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002118 add_rule(rule_nr);
Bart De Schuymer1ab41562002-06-23 17:09:54 +00002119 check_for_loops();
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +00002120 // do the final_check(), for all entries
2121 // needed when adding a rule that has a chain target
2122 i = -1;
2123 while (1) {
2124 struct ebt_u_entry *e;
2125
2126 i++;
2127 entries = nr_to_chain(i);
2128 if (!entries) {
2129 if (i < NF_BR_NUMHOOKS)
2130 continue;
2131 else
2132 break;
2133 }
2134 e = entries->entries;
2135 while (e) {
2136 // userspace extensions use host endian
2137 e->ethproto = ntohs(e->ethproto);
2138 do_final_checks(e, entries);
2139 e->ethproto = htons(e->ethproto);
2140 e = e->next;
2141 }
2142 }
Bart De Schuymer1ab41562002-06-23 17:09:54 +00002143 } else if (replace.command == 'D')
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002144 delete_rule(rule_nr);
Bart De Schuymer1ab41562002-06-23 17:09:54 +00002145 // commands -N, -E, -X fall through
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002146
2147 if (table->check)
2148 table->check(&replace);
2149
2150 deliver_table(&replace);
2151
2152 if (counterchanges)
2153 deliver_counters(&replace, counterchanges);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002154 return 0;
2155}