blob: aac97624f37f5a9191aad2b870e916f9608ab3ca [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
107unsigned 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};
109unsigned 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
376 /* If they don't explicitly set it, read out of kernel */
377 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 Schuymer1abc55d2002-06-01 19:23:47 +0000405// used to parse /etc/etherproto
406int disregard_whitespace(char *buffer, FILE *ifp)
407{
408 int hlp;
409 buffer[0] = '\t';
410 while (buffer[0] == '\t' || buffer[0] == '\n' || buffer[0] == ' ') {
411 hlp = fscanf(ifp, "%c", buffer);
412 if (hlp == EOF || hlp == 0) return -1;
413 }
414 return 0;
415}
416
417// used to parse /etc/etherproto
418int disregard_tabspace(char *buffer, FILE *ifp)
419{
420 int hlp;
421 buffer[0] = '\t';
422 while (buffer[0] == '\t' || buffer[0] == ' ') {
423 hlp = fscanf(ifp, "%c", buffer);
424 if (hlp == EOF || hlp == 0) return -1;
425 }
426 return 0;
427}
428
Bart De Schuymerbbca3202002-06-05 18:55:44 +0000429// helper function: processes a line of data from the file /etc/ethertypes
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000430int get_a_line(char *buffer, char *value, FILE *ifp)
431{
432 int i, hlp;
433 char anotherhlp;
434
435 /* discard comment lines && whitespace*/
436 while (1) {
437 if (disregard_whitespace(buffer, ifp)) return -1;
438 if (buffer[0] == '#')
439 while (1) {
440 hlp = fscanf(ifp, "%c", &anotherhlp);
441 if (!hlp || hlp == EOF)
442 return -1;
443 if (anotherhlp == '\n')
444 break;
445 }
446 else break;
447 }
448
449 // buffer[0] already contains the first letter
450 for (i = 1; i < 21; i++) {
451 hlp = fscanf(ifp, "%c", buffer + i);
452 if (hlp == EOF || hlp == 0) return -1;
453 if (buffer[i] == '\t' || buffer[i] == ' ')
454 break;
455 }
456 if (i == 21) return -1;
457 buffer[i] = '\0';
458 if (disregard_tabspace(value, ifp))
459 return -1;
460 // maybe I should allow 0x0800 instead of 0800, but I'm feeling lazy
461 // buffer[0] already contains the first letter
462 for (i = 1; i < 5; i++) {
463 hlp = fscanf(ifp, "%c", value+i);
464 if (value[i] == '\n' || value[i] == '\t' ||
465 value[i] == ' ' || hlp == EOF)
466 break;
467 }
468 if (i == 5) return -1;
Bart De Schuymerbbca3202002-06-05 18:55:44 +0000469 // discard comments at the end of a line
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000470 if (value[i] == '\t' || value[i] == ' ')
471 while (1) {
472 hlp = fscanf(ifp, "%c", &anotherhlp);
473 if (!hlp || hlp == EOF || anotherhlp == '\n')
474 break;
475 }
476 value[i] = '\0';
477 return 0;
478}
479
480// helper function for list_em()
481int number_to_name(unsigned short proto, char *name)
482{
483 FILE *ifp;
484 char buffer[21], value[5], *bfr;
485 unsigned short i;
486
487 if ( !(ifp = fopen(PROTOCOLFILE, "r")) )
488 return -1;
489 while (1) {
490 if (get_a_line(buffer, value, ifp)) {
491 fclose(ifp);
492 return -1;
493 }
494 i = (unsigned short) strtol(value, &bfr, 16);
495 if (*bfr != '\0' || i != proto)
496 continue;
497 strcpy(name, buffer);
498 fclose(ifp);
499 return 0;
500 }
501}
502
503// helper function for list_rules()
Bart De Schuymer60332e02002-06-23 08:01:47 +0000504static void list_em(struct ebt_u_entries *entries)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000505{
506 int i, j, space = 0, digits;
507 struct ebt_u_entry *hlp;
508 struct ebt_u_match_list *m_l;
509 struct ebt_u_watcher_list *w_l;
510 struct ebt_u_match *m;
511 struct ebt_u_watcher *w;
512 struct ebt_u_target *t;
513 char name[21];
514
Bart De Schuymer60332e02002-06-23 08:01:47 +0000515 hlp = entries->entries;
516 printf("\nBridge chain: %s\nPolicy: %s\n", entries->name,
517 standard_targets[-entries->policy - 1]);
518 printf("nr. of entries: %d \n", entries->nentries);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000519
Bart De Schuymer60332e02002-06-23 08:01:47 +0000520 i = entries->nentries;
Bart De Schuymerf8f8f292002-06-25 15:43:57 +0000521 while (i > 9) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000522 space++;
523 i /= 10;
524 }
525
Bart De Schuymer60332e02002-06-23 08:01:47 +0000526 for (i = 0; i < entries->nentries; i++) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000527 digits = 0;
528 // A little work to get nice rule numbers.
Bart De Schuymerf8f8f292002-06-25 15:43:57 +0000529 j = i + 1;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000530 while (j > 9) {
531 digits++;
532 j /= 10;
533 }
534 for (j = 0; j < space - digits; j++)
535 printf(" ");
536 printf("%d. ", i + 1);
537
538 // Don't print anything about the protocol if no protocol was
539 // specified, obviously this means any protocol will do.
540 if (!(hlp->bitmask & EBT_NOPROTO)) {
Bart De Schuymer60332e02002-06-23 08:01:47 +0000541 printf("-p ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000542 if (hlp->invflags & EBT_IPROTO)
543 printf("! ");
544 if (hlp->bitmask & EBT_802_3)
545 printf("Length, ");
546 else {
547 if (number_to_name(ntohs(hlp->ethproto), name))
Bart De Schuymer60332e02002-06-23 08:01:47 +0000548 printf("0x%x ", ntohs(hlp->ethproto));
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000549 else
Bart De Schuymer60332e02002-06-23 08:01:47 +0000550 printf("%s ", name);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000551 }
552 }
553 if (hlp->bitmask & EBT_SOURCEMAC) {
554 char hlpmsk[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
555
Bart De Schuymer60332e02002-06-23 08:01:47 +0000556 printf("-s ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000557 if (hlp->invflags & EBT_ISOURCE)
558 printf("! ");
559 if (!memcmp(hlp->sourcemac, mac_type_unicast, 6) &&
560 !memcmp(hlp->sourcemsk, msk_type_unicast, 6)) {
561 printf("Unicast");
562 goto endsrc;
563 }
564 if (!memcmp(hlp->sourcemac, mac_type_multicast, 6) &&
565 !memcmp(hlp->sourcemsk, msk_type_multicast, 6)) {
566 printf("Multicast");
567 goto endsrc;
568 }
569 if (!memcmp(hlp->sourcemac, mac_type_broadcast, 6) &&
570 !memcmp(hlp->sourcemsk, msk_type_broadcast, 6)) {
571 printf("Broadcast");
572 goto endsrc;
573 }
Bart De Schuymer41830412002-06-05 19:41:28 +0000574 printf("%s", ether_ntoa((struct ether_addr *)
575 hlp->sourcemac));
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000576 if (memcmp(hlp->sourcemsk, hlpmsk, 6)) {
577 printf("/");
Bart De Schuymer41830412002-06-05 19:41:28 +0000578 printf("%s", ether_ntoa((struct ether_addr *)
579 hlp->sourcemsk));
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000580 }
581endsrc:
Bart De Schuymer60332e02002-06-23 08:01:47 +0000582 printf(" ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000583 }
584 if (hlp->bitmask & EBT_DESTMAC) {
585 char hlpmsk[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
586
Bart De Schuymer60332e02002-06-23 08:01:47 +0000587 printf("-d ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000588 if (hlp->invflags & EBT_IDEST)
589 printf("! ");
590 if (!memcmp(hlp->destmac, mac_type_unicast, 6) &&
591 !memcmp(hlp->destmsk, msk_type_unicast, 6)) {
592 printf("Unicast");
593 goto enddst;
594 }
595 if (!memcmp(hlp->destmac, mac_type_multicast, 6) &&
596 !memcmp(hlp->destmsk, msk_type_multicast, 6)) {
597 printf("Multicast");
598 goto enddst;
599 }
600 if (!memcmp(hlp->destmac, mac_type_broadcast, 6) &&
601 !memcmp(hlp->destmsk, msk_type_broadcast, 6)) {
602 printf("Broadcast");
603 goto enddst;
604 }
Bart De Schuymer41830412002-06-05 19:41:28 +0000605 printf("%s", ether_ntoa((struct ether_addr *)
606 hlp->destmac));
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000607 if (memcmp(hlp->destmsk, hlpmsk, 6)) {
608 printf("/");
Bart De Schuymer41830412002-06-05 19:41:28 +0000609 printf("%s", ether_ntoa((struct ether_addr *)
610 hlp->destmsk));
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000611 }
612enddst:
Bart De Schuymer60332e02002-06-23 08:01:47 +0000613 printf(" ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000614 }
615 if (hlp->in[0] != '\0') {
Bart De Schuymer60332e02002-06-23 08:01:47 +0000616 printf("-i ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000617 if (hlp->invflags & EBT_IIN)
618 printf("! ");
Bart De Schuymer60332e02002-06-23 08:01:47 +0000619 printf("%s ", hlp->in);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000620 }
621 if (hlp->logical_in[0] != '\0') {
Bart De Schuymer60332e02002-06-23 08:01:47 +0000622 printf("--logical-in ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000623 if (hlp->invflags & EBT_ILOGICALIN)
624 printf("! ");
Bart De Schuymer60332e02002-06-23 08:01:47 +0000625 printf("%s ", hlp->logical_in);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000626 }
627 if (hlp->logical_out[0] != '\0') {
Bart De Schuymer60332e02002-06-23 08:01:47 +0000628 printf("--logical-out ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000629 if (hlp->invflags & EBT_ILOGICALOUT)
630 printf("! ");
Bart De Schuymer60332e02002-06-23 08:01:47 +0000631 printf("%s, ", hlp->logical_out);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000632 }
633 if (hlp->out[0] != '\0') {
Bart De Schuymer60332e02002-06-23 08:01:47 +0000634 printf("-o ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000635 if (hlp->invflags & EBT_IOUT)
636 printf("! ");
Bart De Schuymer60332e02002-06-23 08:01:47 +0000637 printf("%s, ", hlp->out);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000638 }
639
640 m_l = hlp->m_list;
641 while (m_l) {
642 m = find_match(m_l->m->u.name);
643 if (!m)
644 print_bug("Match not found");
645 m->print(hlp, m_l->m);
646 m_l = m_l->next;
647 }
648 w_l = hlp->w_list;
649 while (w_l) {
650 w = find_watcher(w_l->w->u.name);
651 if (!w)
652 print_bug("Watcher not found");
653 w->print(hlp, w_l->w);
654 w_l = w_l->next;
655 }
656
Bart De Schuymer25c741d2002-06-23 18:54:34 +0000657 printf("-j %s ", hlp->t->u.name);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000658 t = find_target(hlp->t->u.name);
659 if (!t)
660 print_bug("Target not found");
661 t->print(hlp, hlp->t);
662 printf(", count = %llu",
Bart De Schuymer60332e02002-06-23 08:01:47 +0000663 replace.counters[entries->counter_offset + i].pcnt);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000664 printf("\n");
665 hlp = hlp->next;
666 }
667}
668
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000669struct ebt_u_entries *nr_to_chain(int nr)
Bart De Schuymer60332e02002-06-23 08:01:47 +0000670{
671 if (nr == -1)
672 return NULL;
673 if (nr < NF_BR_NUMHOOKS)
674 return replace.hook_entry[nr];
675 else {
676 int i;
677 struct ebt_u_chain_list *cl = replace.udc;
678
679 i = nr - NF_BR_NUMHOOKS;
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000680 while (i > 0 && cl) {
Bart De Schuymer60332e02002-06-23 08:01:47 +0000681 cl = cl->next;
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000682 i--;
683 }
Bart De Schuymer60332e02002-06-23 08:01:47 +0000684 if (cl)
685 return cl->udc;
686 else
687 return NULL;
688 }
689}
690
691static struct ebt_u_entries *to_chain()
692{
693 return nr_to_chain(replace.selected_hook);
694}
695
696struct ebt_u_stack
697{
698 int chain_nr;
699 int n;
700 struct ebt_u_entry *e;
701 struct ebt_u_entries *entries;
702};
703
704void check_for_loops()
705{
706 int chain_nr , i, j , k, sp = 0, verdict;
707 struct ebt_u_entries *entries, *entries2;
708 struct ebt_u_stack *stack = NULL;
709 struct ebt_u_entry *e;
710
711 i = -1;
712 // initialize hook_mask to 0
713 while (1) {
714 i++;
715 if (i < NF_BR_NUMHOOKS && !(replace.valid_hooks & (1 << i)))
716 continue;
717 entries = nr_to_chain(i);
718 if (!entries)
719 break;
720 entries->hook_mask = 0;
721 }
722 if (i > NF_BR_NUMHOOKS) {
723 stack = (struct ebt_u_stack *)malloc((i - NF_BR_NUMHOOKS) *
724 sizeof(struct ebt_u_stack));
725 if (!stack)
726 print_memory();
727 }
728
729 for (i = 0; i < NF_BR_NUMHOOKS; i++) {
730 if (!(replace.valid_hooks & (1 << i)))
731 continue;
732 entries = nr_to_chain(i);
733 entries->hook_mask = (1 << i);
734 chain_nr = i;
735
736 e = entries->entries;
737 for (j = 0; j < entries->nentries; j++) {
738 if (strcmp(e->t->u.name, EBT_STANDARD_TARGET))
739 goto letscontinue;
740 verdict = ((struct ebt_standard_target *)(e->t))->verdict;
741 if (verdict < 0)
742 goto letscontinue;
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000743 entries2 = nr_to_chain(verdict + NF_BR_NUMHOOKS);
Bart De Schuymer60332e02002-06-23 08:01:47 +0000744 entries2->hook_mask |= entries->hook_mask;
745 // now see if we've been here before
746 for (k = 0; k < sp; k++)
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000747 if (stack[k].chain_nr == verdict + NF_BR_NUMHOOKS)
Bart De Schuymer1a0a9c32002-06-24 21:10:16 +0000748 print_error("Loop from chain %s to chain %s",
749 nr_to_chain(chain_nr)->name, nr_to_chain(stack[k].chain_nr)->name);
Bart De Schuymer60332e02002-06-23 08:01:47 +0000750 // jump to the chain, make sure we know how to get back
751 stack[sp].chain_nr = chain_nr;
752 stack[sp].n = j;
753 stack[sp].entries = entries;
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000754 stack[sp].e = e;
755 sp++;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000756 j = -1;
757 e = entries2->entries;
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000758 chain_nr = verdict + NF_BR_NUMHOOKS;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000759 entries = entries2;
760 continue;
761letscontinue:
762 e = e->next;
763 }
764 // we are in a standard chain
765 if (sp == 0)
766 continue;
767 // go back to the chain one level lower
768 sp--;
769 j = stack[sp].n;
770 chain_nr = stack[sp].chain_nr;
771 e = stack[sp].e;
772 entries = stack[sp].entries;
773 goto letscontinue;
774 }
775 free(stack);
776 return;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000777}
778
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000779// parse the chain name and return the corresponding nr
780int get_hooknr(char* arg)
781{
782 int i;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000783 struct ebt_u_chain_list *cl = replace.udc;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000784
785 // database is special case (not really a chain)
786 if (!strcmp(arg, DATABASEHOOKNAME))
787 return DATABASEHOOKNR;
788
Bart De Schuymer60332e02002-06-23 08:01:47 +0000789 for (i = 0; i < NF_BR_NUMHOOKS; i++) {
790 if (!(replace.valid_hooks & (1 << i)))
791 continue;
792 if (!strcmp(arg, replace.hook_entry[i]->name))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000793 return i;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000794 }
795 while(cl) {
796 if (!strcmp(arg, cl->udc->name))
797 return i;
798 i++;
799 cl = cl->next;
800 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000801 return -1;
802}
803
804// yup, print out help
805void print_help()
806{
807 struct ebt_u_match_list *m_l;
808 struct ebt_u_watcher_list *w_l;
809
810 printf(
811"%s v%s\n"
812"Usage:\n"
813"ebtables -[ADI] chain rule-specification [options]\n"
814"ebtables -P chain target\n"
815"ebtables -[LFZ] [chain]\n"
816"ebtables -[b] [y,n]\n"
817"Commands:\n"
818"--append -A chain : Append to chain\n"
819"--delete -D chain : Delete matching rule from chain\n"
820"--delete -D chain rulenum : Delete rule at position rulenum from chain\n"
821"--insert -I chain rulenum : insert rule at position rulenum in chain\n"
822"--list -L [chain] : List the rules in a chain or in all chains\n"
823"--list -L "DATABASEHOOKNAME" : List the database (if present)\n"
824"--flush -F [chain] : Delete all rules in chain or in all chains\n"
825"--zero -Z [chain] : Put counters on zero in chain or in all chains\n"
826"--policy -P chain target : Change policy on chain to target\n"
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000827"--new-chain -N chain : Create a user defined chain\n"
828"--rename-chain -E old new : Rename a chain\n"
829"--delete-chain -X chain : Delete a user defined chain\n"
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000830"Options:\n"
831"--proto -p [!] proto : protocol hexadecimal, by name or LENGTH\n"
832"--src -s [!] address[/mask]: source mac address\n"
833"--dst -d [!] address[/mask]: destination mac address\n"
834"--in-if -i [!] name : network input interface name\n"
835"--out-if -o [!] name : network output interface name\n"
836"--logical-in [!] name : logical bridge input interface name\n"
837"--logical-out [!] name : logical bridge output interface name\n"
Bart De Schuymerc8531032002-06-14 21:55:29 +0000838"--modprobe -M : try to insert modules using this command\n"
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000839"--version -V : print package version\n"
840"\n" ,
841 prog_name,
842 prog_version);
843
844 m_l = new_entry->m_list;
845 while (m_l) {
846 ((struct ebt_u_match *)m_l->m)->help();
847 printf("\n");
848 m_l = m_l->next;
849 }
850 w_l = new_entry->w_list;
851 while (w_l) {
852 ((struct ebt_u_watcher *)w_l->w)->help();
853 printf("\n");
854 w_l = w_l->next;
855 }
856 ((struct ebt_u_target *)new_entry->t)->help();
857 printf("\n");
858 if (table->help)
859 table->help(hooknames);
860 exit(0);
861}
862
863// execute command L
864static void list_rules()
865{
866 int i;
867
868 printf("Bridge table: %s\n", table->name);
Bart De Schuymer60332e02002-06-23 08:01:47 +0000869 if (replace.selected_hook != -1) {
870 list_em(to_chain());
871 } else {
872 struct ebt_u_chain_list *cl = replace.udc;
873
874 i = 0;
875 while (1) {
876 if (i < NF_BR_NUMHOOKS) {
877 if (replace.valid_hooks & (1 << i))
878 list_em(replace.hook_entry[i]);
879 i++;
880 continue;
881 } else {
882 if (!cl)
883 break;
884 list_em(cl->udc);
885 cl = cl->next;
886 }
887 }
888 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000889 return;
890}
891
892// execute command P
893static void change_policy(int policy)
894{
895 int i;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000896 struct ebt_u_entries *entries = to_chain();
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000897
898 // don't do anything if the policy is the same
Bart De Schuymer60332e02002-06-23 08:01:47 +0000899 if (entries->policy != policy) {
900 entries->policy = policy;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000901 replace.num_counters = replace.nentries;
902 if (replace.nentries) {
903 // '+ 1' for the CNT_END
904 if (!(counterchanges = (unsigned short *) malloc(
905 (replace.nentries + 1) * sizeof(unsigned short))))
906 print_memory();
907 // done nothing special to the rules
908 for (i = 0; i < replace.nentries; i++)
909 counterchanges[i] = CNT_NORM;
910 counterchanges[replace.nentries] = CNT_END;
911 }
912 else
913 counterchanges = NULL;
914 }
915 else
916 exit(0);
917}
918
919// flush one chain or the complete table
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000920// -1 == nothing to do
921// 0 == give back to kernel
922static int flush_chains()
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000923{
Bart De Schuymer60332e02002-06-23 08:01:47 +0000924 int i, j, oldnentries, numdel;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000925 unsigned short *cnt;
926 struct ebt_u_entry *u_e, *tmp;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000927 struct ebt_u_entries *entries = to_chain();
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000928
929 // flush whole table
Bart De Schuymer60332e02002-06-23 08:01:47 +0000930 if (!entries) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000931 if (replace.nentries == 0)
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000932 return -1;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000933 replace.nentries = 0;
934 // no need for the kernel to give us counters back
935 replace.num_counters = 0;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000936
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000937 // free everything and zero (n)entries
Bart De Schuymer60332e02002-06-23 08:01:47 +0000938 i = -1;
939 while (1) {
940 i++;
941 entries = nr_to_chain(i);
942 if (!entries) {
943 if (i < NF_BR_NUMHOOKS)
944 continue;
945 else
946 break;
947 }
948 entries->nentries = 0;
949 entries->counter_offset = 0;
950 u_e = entries->entries;
951 entries->entries = NULL;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000952 while (u_e) {
953 free_u_entry(u_e);
954 tmp = u_e->next;
955 free(u_e);
956 u_e = tmp;
957 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000958 }
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000959 return 0;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000960 }
961
Bart De Schuymer60332e02002-06-23 08:01:47 +0000962 if (entries->nentries == 0)
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000963 return -1;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000964 oldnentries = replace.nentries;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000965 replace.nentries -= entries->nentries;
966 numdel = entries->nentries;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000967
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000968 if (replace.nentries) {
969 // +1 for CNT_END
970 if ( !(counterchanges = (unsigned short *)
971 malloc((oldnentries + 1) * sizeof(unsigned short))) )
972 print_memory();
Bart De Schuymer60332e02002-06-23 08:01:47 +0000973 }
974 // delete the counters belonging to the specified chain,
975 // update counter_offset
976 i = -1;
Bart De Schuymerf8f8f292002-06-25 15:43:57 +0000977 cnt = counterchanges;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000978 while (1) {
979 i++;
980 entries = nr_to_chain(i);
981 if (!entries) {
982 if (i < NF_BR_NUMHOOKS)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000983 continue;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000984 else
985 break;
986 }
987 if (i > replace.selected_hook)
988 entries->counter_offset -= numdel;
989 if (replace.nentries) {
990 for (j = 0; j < entries->nentries; j++) {
991 if (i == replace.selected_hook)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000992 *cnt = CNT_DEL;
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000993 else
994 *cnt = CNT_NORM;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000995 cnt++;
996 }
997 }
Bart De Schuymer60332e02002-06-23 08:01:47 +0000998 }
999
1000 if (replace.nentries) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001001 *cnt = CNT_END;
1002 replace.num_counters = oldnentries;
1003 }
1004 else
1005 replace.num_counters = 0;
1006
Bart De Schuymer60332e02002-06-23 08:01:47 +00001007 entries = to_chain();
1008 entries->nentries = 0;
1009 u_e = entries->entries;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001010 while (u_e) {
1011 free_u_entry(u_e);
1012 tmp = u_e->next;
1013 free(u_e);
1014 u_e = tmp;
1015 }
Bart De Schuymer60332e02002-06-23 08:01:47 +00001016 entries->entries = NULL;
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001017 return 0;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001018}
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001019
1020// -1 == no match
1021static int check_rule_exists(int rule_nr)
1022{
1023 struct ebt_u_entry *u_e;
1024 struct ebt_u_match_list *m_l, *m_l2;
1025 struct ebt_u_match *m;
1026 struct ebt_u_watcher_list *w_l, *w_l2;
1027 struct ebt_u_watcher *w;
1028 struct ebt_u_target *t = (struct ebt_u_target *)new_entry->t;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001029 struct ebt_u_entries *entries = to_chain();
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001030 int i, j, k;
1031
1032 // handle '-D chain rulenr' command
1033 if (rule_nr != -1) {
Bart De Schuymer60332e02002-06-23 08:01:47 +00001034 if (rule_nr > entries->nentries)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001035 return 0;
1036 // user starts counting from 1
1037 return rule_nr - 1;
1038 }
Bart De Schuymer60332e02002-06-23 08:01:47 +00001039 u_e = entries->entries;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001040 // check for an existing rule (if there are duplicate rules,
1041 // take the first occurance)
Bart De Schuymer60332e02002-06-23 08:01:47 +00001042 for (i = 0; i < entries->nentries; i++, u_e = u_e->next) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001043 if (!u_e)
1044 print_bug("Hmm, trouble");
1045 if ( u_e->ethproto == new_entry->ethproto
1046 && !strcmp(u_e->in, new_entry->in)
1047 && !strcmp(u_e->out, new_entry->out)
1048 && u_e->bitmask == new_entry->bitmask) {
Bart De Schuymer60332e02002-06-23 08:01:47 +00001049 if (strcmp(u_e->logical_in, new_entry->logical_in) ||
1050 strcmp(u_e->logical_out, new_entry->logical_out))
1051 continue;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001052 if (new_entry->bitmask & EBT_SOURCEMAC &&
Bart De Schuymer60332e02002-06-23 08:01:47 +00001053 memcmp(u_e->sourcemac, new_entry->sourcemac, ETH_ALEN))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001054 continue;
1055 if (new_entry->bitmask & EBT_DESTMAC &&
Bart De Schuymer60332e02002-06-23 08:01:47 +00001056 memcmp(u_e->destmac, new_entry->destmac, ETH_ALEN))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001057 continue;
1058 if (new_entry->bitmask != u_e->bitmask ||
1059 new_entry->invflags != u_e->invflags)
1060 continue;
1061 // compare all matches
1062 m_l = new_entry->m_list;
1063 j = 0;
1064 while (m_l) {
1065 m = (struct ebt_u_match *)(m_l->m);
1066 m_l2 = u_e->m_list;
1067 while (m_l2 &&
1068 strcmp(m_l2->m->u.name, m->m->u.name))
1069 m_l2 = m_l2->next;
1070 if (!m_l2 || !m->compare(m->m, m_l2->m))
1071 goto letscontinue;
1072 j++;
1073 m_l = m_l->next;
1074 }
1075 // now be sure they have the same nr of matches
1076 k = 0;
1077 m_l = u_e->m_list;
1078 while (m_l) {
1079 k++;
1080 m_l = m_l->next;
1081 }
1082 if (j != k)
1083 continue;
1084
1085 // compare all watchers
1086 w_l = new_entry->w_list;
1087 j = 0;
1088 while (w_l) {
1089 w = (struct ebt_u_watcher *)(w_l->w);
1090 w_l2 = u_e->w_list;
1091 while (w_l2 &&
1092 strcmp(w_l2->w->u.name, w->w->u.name))
1093 w_l2 = w_l2->next;
1094 if (!w_l2 || !w->compare(w->w, w_l2->w))
1095 goto letscontinue;
1096 j++;
1097 w_l = w_l->next;
1098 }
1099 k = 0;
1100 w_l = u_e->w_list;
1101 while (w_l) {
1102 k++;
1103 w_l = w_l->next;
1104 }
1105 if (j != k)
1106 continue;
1107 if (strcmp(t->t->u.name, u_e->t->u.name))
1108 continue;
1109 if (!t->compare(t->t, u_e->t))
1110 continue;
1111 return i;
1112 }
1113letscontinue:
1114 }
1115 return -1;
1116}
1117
1118// execute command A
1119static void add_rule(int rule_nr)
1120{
1121 int i, j;
1122 struct ebt_u_entry *u_e, *u_e2;
1123 unsigned short *cnt;
1124 struct ebt_u_match_list *m_l;
1125 struct ebt_u_watcher_list *w_l;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001126 struct ebt_u_entries *entries = to_chain(), *entries2;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001127
1128 if (rule_nr != -1) { // command -I
Bart De Schuymer60332e02002-06-23 08:01:47 +00001129 if (--rule_nr > entries->nentries)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001130 print_error("rule nr too high: %d > %d", rule_nr,
Bart De Schuymer60332e02002-06-23 08:01:47 +00001131 entries->nentries);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001132 } else
Bart De Schuymer60332e02002-06-23 08:01:47 +00001133 rule_nr = entries->nentries;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001134 // we're adding one rule
1135 replace.num_counters = replace.nentries;
1136 replace.nentries++;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001137 entries->nentries++;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001138
1139 // handle counter stuff
1140 // +1 for CNT_END
1141 if ( !(counterchanges = (unsigned short *)
1142 malloc((replace.nentries + 1) * sizeof(unsigned short))) )
1143 print_memory();
1144 cnt = counterchanges;
1145 for (i = 0; i < replace.selected_hook; i++) {
Bart De Schuymer60332e02002-06-23 08:01:47 +00001146 if (i < NF_BR_NUMHOOKS && !(replace.valid_hooks & (1 << i)))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001147 continue;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001148 entries2 = nr_to_chain(i);
1149 for (j = 0; j < entries2->nentries; j++) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001150 *cnt = CNT_NORM;
1151 cnt++;
1152 }
1153 }
1154 for (i = 0; i < rule_nr; i++) {
1155 *cnt = CNT_NORM;
1156 cnt++;
1157 }
1158 *cnt = CNT_ADD;
1159 cnt++;
1160 while (cnt != counterchanges + replace.nentries) {
1161 *cnt = CNT_NORM;
1162 cnt++;
1163 }
1164 *cnt = CNT_END;
1165
1166 // go to the right position in the chain
1167 u_e2 = NULL;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001168 u_e = entries->entries;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001169 for (i = 0; i < rule_nr; i++) {
1170 u_e2 = u_e;
1171 u_e = u_e->next;
1172 }
1173 // insert the rule
1174 if (u_e2)
1175 u_e2->next = new_entry;
1176 else
Bart De Schuymer60332e02002-06-23 08:01:47 +00001177 entries->entries = new_entry;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001178 new_entry->next = u_e;
1179
1180 // put the ebt_[match, watcher, target] pointers in place
1181 m_l = new_entry->m_list;
1182 while (m_l) {
1183 m_l->m = ((struct ebt_u_match *)m_l->m)->m;
1184 m_l = m_l->next;
1185 }
1186 w_l = new_entry->w_list;
1187 while (w_l) {
1188 w_l->w = ((struct ebt_u_watcher *)w_l->w)->w;
1189 w_l = w_l->next;
1190 }
1191 new_entry->t = ((struct ebt_u_target *)new_entry->t)->t;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001192
1193 // update the counter_offset of chains behind this one
1194 i = replace.selected_hook;
1195 while (1) {
1196 i++;
1197 entries = nr_to_chain(i);
1198 if (!entries) {
1199 if (i < NF_BR_NUMHOOKS)
1200 continue;
1201 else
1202 break;
1203 } else
1204 entries->counter_offset++;
1205 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001206}
1207
1208// execute command D
1209static void delete_rule(int rule_nr)
1210{
1211 int i, j, lentmp = 0;
1212 unsigned short *cnt;
1213 struct ebt_u_entry *u_e, *u_e2;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001214 struct ebt_u_entries *entries = to_chain(), *entries2;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001215
1216 if ( (i = check_rule_exists(rule_nr)) == -1 )
Bart De Schuymer60332e02002-06-23 08:01:47 +00001217 print_error("Sorry, rule does not exist");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001218
1219 // we're deleting a rule
1220 replace.num_counters = replace.nentries;
1221 replace.nentries--;
1222
1223 if (replace.nentries) {
1224 for (j = 0; j < replace.selected_hook; j++) {
Bart De Schuymer60332e02002-06-23 08:01:47 +00001225 if (j < NF_BR_NUMHOOKS &&
1226 !(replace.valid_hooks & (1 << j)))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001227 continue;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001228 entries2 = nr_to_chain(j);
1229 lentmp += entries2->nentries;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001230 }
1231 lentmp += i;
1232 // +1 for CNT_END
1233 if ( !(counterchanges = (unsigned short *)malloc(
1234 (replace.num_counters + 1) * sizeof(unsigned short))) )
1235 print_memory();
1236 cnt = counterchanges;
1237 for (j = 0; j < lentmp; j++) {
1238 *cnt = CNT_NORM;
1239 cnt++;
1240 }
1241 *cnt = CNT_DEL;
1242 cnt++;
1243 for (j = 0; j < replace.num_counters - lentmp; j++) {
1244 *cnt = CNT_NORM;
1245 cnt++;
1246 }
1247 *cnt = CNT_END;
1248 }
1249 else
1250 replace.num_counters = 0;
1251
1252 // go to the right position in the chain
1253 u_e2 = NULL;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001254 u_e = entries->entries;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001255 for (j = 0; j < i; j++) {
1256 u_e2 = u_e;
1257 u_e = u_e->next;
1258 }
1259
1260 // remove from the chain
1261 if (u_e2)
1262 u_e2->next = u_e->next;
1263 else
Bart De Schuymer60332e02002-06-23 08:01:47 +00001264 entries->entries = u_e->next;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001265
Bart De Schuymer60332e02002-06-23 08:01:47 +00001266 entries->nentries--;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001267 // free everything
1268 free_u_entry(u_e);
1269 free(u_e);
Bart De Schuymer60332e02002-06-23 08:01:47 +00001270 // update the counter_offset of chains behind this one
1271 i = replace.selected_hook;
1272 while (1) {
1273 i++;
1274 entries = nr_to_chain(i);
1275 if (!entries) {
1276 if (i < NF_BR_NUMHOOKS)
1277 continue;
1278 else
1279 break;
1280 } else
1281 entries->counter_offset--;
1282 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001283}
1284
1285// execute command Z
1286void zero_counters(int zerochain)
1287{
1288
1289 if (zerochain == -1) {
1290 // tell main() we don't update the counters
1291 // this results in tricking the kernel to zero his counters,
1292 // naively expecting userspace to update its counters. Muahahaha
1293 counterchanges = NULL;
1294 replace.num_counters = 0;
1295 } else {
1296 int i, j;
1297 unsigned short *cnt;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001298 struct ebt_u_entries *entries = nr_to_chain(zerochain), *e2;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001299
Bart De Schuymer60332e02002-06-23 08:01:47 +00001300 if (entries->nentries == 0)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001301 exit(0);
1302 counterchanges = (unsigned short *)
1303 malloc((replace.nentries + 1) * sizeof(unsigned short));
1304 if (!counterchanges)
1305 print_memory();
1306 cnt = counterchanges;
1307 for (i = 0; i < zerochain; i++) {
Bart De Schuymer60332e02002-06-23 08:01:47 +00001308 if (i < NF_BR_NUMHOOKS &&
1309 !(replace.valid_hooks & (1 << i)))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001310 continue;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001311 e2 = nr_to_chain(i);
1312 for (j = 0; j < e2->nentries; j++) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001313 *cnt = CNT_NORM;
1314 cnt++;
1315 }
1316 }
Bart De Schuymer60332e02002-06-23 08:01:47 +00001317 for (i = 0; i < entries->nentries; i++) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001318 *cnt = CNT_ZERO;
1319 cnt++;
1320 }
1321 while (cnt != counterchanges + replace.nentries) {
1322 *cnt = CNT_NORM;
1323 cnt++;
1324 }
1325 *cnt = CNT_END;
1326 }
1327}
1328
1329// list the database (optionally compiled into the kernel)
1330static void list_db()
1331{
1332 struct brdb_dbinfo nr;
1333 struct brdb_dbentry *db;
1334 char name[21];
1335 int i;
1336
1337 get_dbinfo(&nr);
1338
1339 // 0 : database disabled (-db n)
1340 if (!(nr.nentries))
1341 print_error("Database not present"
1342 " (disabled), try ebtables --db y");
1343 nr.nentries--;
1344 if (!nr.nentries) print_error("Database empty");
1345 if ( !(db = (struct brdb_dbentry *)
1346 malloc(nr.nentries * sizeof(struct brdb_dbentry))) )
1347 print_memory();
1348
1349 get_db(nr.nentries, db);
1350 printf("number of entries: %d\n", nr.nentries);
1351 for (i = 0; i < nr.nentries; i++) {
1352 printf(
1353 "%d:\n"
1354 "hook : %s\n"
1355 "in-if : %s\n"
1356 "out-if : %s\n"
1357 "protocol: ", i + 1, hooknames[db->hook], db->in, db->out);
1358 if (db->ethproto == IDENTIFY802_3)
1359 printf("802.2/802.3 STYLE LENGTH FIELD\n");
1360 else {
1361 if (number_to_name(ntohs(db->ethproto), name))
1362 printf("%x\n",ntohs(db->ethproto));
1363 else
1364 printf("%s\n", name);
1365 }
1366 db++;
1367 }
1368 exit(0);
1369}
1370
1371// handle db [dis,en]abling
1372static void allowdb(char yorn)
1373{
1374 __u16 decision;
1375
1376 if (yorn != 'y' && yorn != 'n')
1377 print_error("Option [y] or [n] needed");
1378
1379 if (yorn == 'y')
1380 decision = BRDB_DB;
1381 else
1382 decision = BRDB_NODB;
1383
1384 deliver_allowdb(&decision);
1385
1386 exit(0);
1387}
1388
1389// set ethproto
1390int name_to_protocol(char *name)
1391{
1392 FILE *ifp;
1393 char buffer[21], value[5], *bfr;
1394 unsigned short i;
1395
1396 if (!strcasecmp("LENGTH", name)) {
1397 new_entry->ethproto = 0;
1398 new_entry->bitmask |= EBT_802_3;
1399 return 1;
1400 }
1401 if ( !(ifp = fopen(PROTOCOLFILE, "r")) )
1402 return -1;
1403 while (1) {
1404 if (get_a_line(buffer, value, ifp)) return -1;
1405 if (strcasecmp(buffer, name))
1406 continue;
1407 i = (unsigned short) strtol(value, &bfr, 16);
1408 if (*bfr != '\0')
1409 return -1;
1410 new_entry->ethproto = i;
1411 fclose(ifp);
1412 return 0;
1413 }
1414 return -1;
1415}
1416
1417// put the mac address into 6 (ETH_ALEN) bytes
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001418int getmac_and_mask(char *from, char *to, char *mask)
1419{
1420 char *p;
1421 int i;
Bart De Schuymer41830412002-06-05 19:41:28 +00001422 struct ether_addr *addr;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001423
1424 if (strcasecmp(from, "Unicast") == 0) {
1425 memcpy(to, mac_type_unicast, ETH_ALEN);
1426 memcpy(mask, msk_type_unicast, ETH_ALEN);
1427 return 0;
1428 }
1429 if (strcasecmp(from, "Multicast") == 0) {
1430 memcpy(to, mac_type_multicast, ETH_ALEN);
1431 memcpy(mask, msk_type_multicast, ETH_ALEN);
1432 return 0;
1433 }
1434 if (strcasecmp(from, "Broadcast") == 0) {
1435 memcpy(to, mac_type_broadcast, ETH_ALEN);
1436 memcpy(mask, msk_type_broadcast, ETH_ALEN);
1437 return 0;
1438 }
1439 if ( (p = strrchr(from, '/')) != NULL) {
1440 *p = '\0';
Bart De Schuymer41830412002-06-05 19:41:28 +00001441 if (!(addr = ether_aton(p + 1)))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001442 return -1;
Bart De Schuymer41830412002-06-05 19:41:28 +00001443 memcpy(mask, addr, ETH_ALEN);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001444 } else
1445 memset(mask, 0xff, ETH_ALEN);
Bart De Schuymer41830412002-06-05 19:41:28 +00001446 if (!(addr = ether_aton(from)))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001447 return -1;
Bart De Schuymer41830412002-06-05 19:41:28 +00001448 memcpy(to, addr, ETH_ALEN);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001449 for (i = 0; i < ETH_ALEN; i++)
1450 to[i] &= mask[i];
1451 return 0;
1452}
1453
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +00001454void do_final_checks(struct ebt_u_entry *e, struct ebt_u_entries *entries)
1455{
1456 struct ebt_u_match_list *m_l;
1457 struct ebt_u_watcher_list *w_l;
1458 struct ebt_u_target *t;
1459 struct ebt_u_match *m;
1460 struct ebt_u_watcher *w;
1461
1462 m_l = e->m_list;
1463 w_l = e->w_list;
1464 while (m_l) {
1465 m = find_match(m_l->m->u.name);
1466 m->final_check(e, m_l->m, replace.name,
1467 entries->hook_mask, 1);
1468 m_l = m_l->next;
1469 }
1470 while (w_l) {
1471 w = find_watcher(w_l->w->u.name);
1472 w->final_check(e, w_l->w, replace.name,
1473 entries->hook_mask, 1);
1474 w_l = w_l->next;
1475 }
1476 t = find_target(e->t->u.name);
1477 t->final_check(e, e->t, replace.name,
1478 entries->hook_mask, 1);
1479}
1480
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001481int check_inverse(const char option[])
1482{
1483 if (strcmp(option, "!") == 0) {
1484 optind++;
1485 return 1;
1486 }
1487 return 0;
1488}
1489
1490void check_option(unsigned int *flags, unsigned int mask)
1491{
1492 if (*flags & mask)
1493 print_error("Multiple use of same option not allowed");
1494 *flags |= mask;
1495}
1496
1497#define OPT_COMMAND 0x01
1498#define OPT_TABLE 0x02
1499#define OPT_IN 0x04
1500#define OPT_OUT 0x08
1501#define OPT_JUMP 0x10
1502#define OPT_PROTOCOL 0x20
1503#define OPT_SOURCE 0x40
1504#define OPT_DEST 0x80
1505#define OPT_ZERO 0x100
1506#define OPT_LOGICALIN 0x200
1507#define OPT_LOGICALOUT 0x400
1508// the main thing
1509int main(int argc, char *argv[])
1510{
1511 char *buffer, allowbc = 'n';
1512 int c, i;
1513 // this special one for the -Z option (we can have -Z <this> -L <that>)
1514 int zerochain = -1;
Bart De Schuymerf8f8f292002-06-25 15:43:57 +00001515 int policy = 0;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001516 int rule_nr = -1;// used for -D chain number
1517 struct ebt_u_target *t;
1518 struct ebt_u_match *m;
1519 struct ebt_u_watcher *w;
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +00001520 struct ebt_u_match_list *m_l;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001521 struct ebt_u_watcher_list *w_l;
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +00001522 struct ebt_u_entries *entries;
Bart De Schuymerc8531032002-06-14 21:55:29 +00001523 const char *modprobe = NULL;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001524
1525 // initialize the table name, OPT_ flags, selected hook and command
1526 strcpy(replace.name, "filter");
1527 replace.flags = 0;
1528 replace.selected_hook = -1;
1529 replace.command = 'h';
1530
1531 new_entry = (struct ebt_u_entry *)malloc(sizeof(struct ebt_u_entry));
1532 if (!new_entry)
1533 print_memory();
1534 // put some sane values in our new entry
1535 initialize_entry(new_entry);
1536
Bart De Schuymer60332e02002-06-23 08:01:47 +00001537 // The scenario induced by this loop makes that:
1538 // '-t' and '-M' (if specified) have to come before '-A' and the like
1539
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001540 // getopt saves the day
1541 while ((c = getopt_long(argc, argv,
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001542 "-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 +00001543 switch (c) {
1544
1545 case 'A': // add a rule
1546 case 'D': // delete a rule
1547 case 'P': // define policy
1548 case 'I': // insert a rule
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001549 case 'N': // make a user defined chain
1550 case 'E': // rename chain
1551 case 'X': // delete chain
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001552 replace.command = c;
1553 if (replace.flags & OPT_COMMAND)
1554 print_error("Multiple commands not allowed");
1555 replace.flags |= OPT_COMMAND;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001556 if ( !(table = find_table(replace.name)) )
1557 print_error("Bad table name");
1558 // get the kernel's information
1559 if (get_table(&replace)) {
1560 ebtables_insmod("ebtables", modprobe);
1561 if (get_table(&replace))
1562 print_error("can't initialize ebtables "
1563 "table %s", replace.name);
1564 }
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001565 if (c == 'N') {
1566 struct ebt_u_chain_list *cl, **cl2;
1567
1568 if (get_hooknr(optarg) != -1)
1569 print_error("Chain %s already exists",
1570 optarg);
1571 if (find_target(optarg))
1572 print_error("Target with name %s exists"
1573 , optarg);
1574 if (strlen(optarg) >= EBT_CHAIN_MAXNAMELEN)
1575 print_error("Chain name len can't exceed %d",
1576 EBT_CHAIN_MAXNAMELEN - 1);
1577 cl = (struct ebt_u_chain_list *)
1578 malloc(sizeof(struct ebt_u_chain_list));
1579 if (!cl)
1580 print_memory();
1581 cl->next = NULL;
1582 cl->udc = (struct ebt_u_entries *)
1583 malloc(sizeof(struct ebt_u_entries));
1584 if (!cl->udc)
1585 print_memory();
1586 cl->udc->nentries = 0;
1587 cl->udc->policy = EBT_ACCEPT;
1588 cl->udc->counter_offset = replace.nentries;
1589 cl->udc->hook_mask = 0;
1590 strcpy(cl->udc->name, optarg);
1591 cl->udc->entries = NULL;
1592 cl->kernel_start = NULL;
1593 cl2 = &replace.udc;
1594 while (*cl2)
1595 cl2 = &((*cl2)->next);
1596 *cl2 = cl;
1597 break;
1598 }
1599 if (c == 'E') {
1600 if ((replace.selected_hook = get_hooknr(optarg)) == -1)
1601 print_error("Chain %s doesn't exist", optarg);
1602 if (optind >= argc || argv[optind][0] == '-')
1603 print_error("No new chain name specified");
1604 if (strlen(argv[optind]) >= EBT_CHAIN_MAXNAMELEN)
1605 print_error("Chain name len can't exceed %d",
1606 EBT_CHAIN_MAXNAMELEN - 1);
1607 if (get_hooknr(argv[optind]) != -1)
1608 print_error("Chain %s already exists",
1609 argv[optind]);
1610 entries = to_chain();
1611 strcpy(entries->name, argv[optind]);
1612 optind++;
1613 break;
1614 }
1615 if (c == 'X') {
1616 struct ebt_u_chain_list *cl, **cl2;
1617
1618 if ((replace.selected_hook = get_hooknr(optarg)) == -1)
1619 print_error("Chain %s doesn't exist", optarg);
1620 if (replace.selected_hook < NF_BR_NUMHOOKS)
1621 print_error("You can't remove a standard chain");
1622 flush_chains();
1623 entries = to_chain();
1624 if (replace.udc->udc == entries) {
1625 cl = replace.udc;
1626 replace.udc = replace.udc->next;
1627 free(cl->udc);
1628 free(cl);
1629 break;
1630 }
1631 cl2 = &(replace.udc);
1632 while ((*cl2)->next->udc != entries)
1633 cl2 = &((*cl2)->next);
1634 cl = (*cl2)->next;
1635 (*cl2)->next = (*cl2)->next->next;
1636 free(cl->udc);
1637 free(cl);
1638 break;
1639 }
1640
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001641 if ((replace.selected_hook = get_hooknr(optarg)) == -1)
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001642 print_error("Chain %s doesn't exist", optarg);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001643 if (c == 'D' && optind < argc &&
1644 argv[optind][0] != '-') {
1645 rule_nr = strtol(argv[optind], &buffer, 10);
1646 if (*buffer != '\0' || rule_nr < 0)
1647 print_error("Problem with the "
1648 "specified rule number");
1649 optind++;
1650 }
1651 if (c == 'P') {
1652 if (optind >= argc)
1653 print_error("No policy specified");
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001654 policy = 0;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001655 for (i = 0; i < 4; i++)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001656 if (!strcmp(argv[optind],
1657 standard_targets[i])) {
Bart De Schuymer60332e02002-06-23 08:01:47 +00001658 policy = -i -1;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001659 break;
1660 }
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001661 if (policy == 0)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001662 print_error("Wrong policy");
1663 optind++;
1664 }
1665 if (c == 'I') {
1666 if (optind >= argc)
1667 print_error("No rulenr for -I"
1668 " specified");
1669 rule_nr = strtol(argv[optind], &buffer, 10);
1670 if (*buffer != '\0' || rule_nr < 0)
1671 print_error("Problem with the specified"
1672 " rule number");
1673 optind++;
1674 }
1675 break;
1676
1677 case 'L': // list
1678 case 'F': // flush
1679 case 'Z': // zero counters
1680 if (c == 'Z') {
1681 if (replace.flags & OPT_ZERO)
1682 print_error("Multiple commands"
1683 " not allowed");
1684 if ( (replace.flags & OPT_COMMAND &&
1685 replace.command != 'L'))
1686 print_error("command -Z only allowed "
1687 "together with command -L");
1688 replace.flags |= OPT_ZERO;
1689 } else {
1690 replace.command = c;
1691 if (replace.flags & OPT_COMMAND)
1692 print_error("Multiple commands"
1693 " not allowed");
1694 replace.flags |= OPT_COMMAND;
1695 }
1696 i = -1;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001697 if ( !(table = find_table(replace.name)) )
1698 print_error("Bad table name");
1699 // get the kernel's information
1700 if (get_table(&replace)) {
1701 ebtables_insmod("ebtables", modprobe);
1702 if (get_table(&replace))
1703 print_error("can't initialize ebtables "
1704 "table %s", replace.name);
1705 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001706 if (optarg) {
1707 if ( (i = get_hooknr(optarg)) == -1 )
1708 print_error("Bad chain");
1709 } else
1710 if (optind < argc && argv[optind][0] != '-') {
1711 if ((i = get_hooknr(argv[optind]))
1712 == -1)
1713 print_error("Bad chain");
1714 optind++;
1715 }
1716 if (i != -1) {
1717 if (c == 'Z')
1718 zerochain = i;
1719 else
1720 replace.selected_hook = i;
1721 }
1722 break;
1723
1724 case 'V': // version
1725 replace.command = 'V';
1726 if (replace.flags & OPT_COMMAND)
1727 print_error("Multiple commands not allowed");
1728 printf("%s, %s\n", prog_name, prog_version);
1729 exit(0);
1730
Bart De Schuymerc8531032002-06-14 21:55:29 +00001731 case 'M': // modprobe
Bart De Schuymer60332e02002-06-23 08:01:47 +00001732 if (replace.command != 'h')
1733 print_error("Please put the -M option earlier");
Bart De Schuymerc8531032002-06-14 21:55:29 +00001734 modprobe = optarg;
1735 break;
1736
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001737 case 'h': // help
1738 if (replace.flags & OPT_COMMAND)
1739 print_error("Multiple commands not allowed");
1740 replace.command = 'h';
1741 // All other arguments should be extension names
1742 while (optind < argc) {
1743 struct ebt_u_match *m;
1744 struct ebt_u_watcher *w;
1745
1746 if ((m = find_match(argv[optind])))
1747 add_match(m);
1748 else if ((w = find_watcher(argv[optind])))
1749 add_watcher(w);
1750 else {
1751 if (!(t = find_target(argv[optind])))
1752 print_error("Extension %s "
1753 "not found", argv[optind]);
1754 if (replace.flags & OPT_JUMP)
1755 print_error("Sorry, you can "
1756 "only see help for one "
1757 "target extension each time");
1758 replace.flags |= OPT_JUMP;
1759 new_entry->t =
1760 (struct ebt_entry_target *)t;
1761 }
1762 optind++;
1763 }
1764 break;
1765
1766 case 't': // table
Bart De Schuymer60332e02002-06-23 08:01:47 +00001767 if (replace.command != 'h')
1768 print_error("Please put the -t option first");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001769 check_option(&replace.flags, OPT_TABLE);
1770 if (strlen(optarg) > EBT_TABLE_MAXNAMELEN)
1771 print_error("Table name too long");
1772 strcpy(replace.name, optarg);
1773 break;
1774
1775 case 'i': // input interface
1776 case 2 : // logical input interface
1777 case 'o': // output interface
1778 case 3 : // logical output interface
1779 case 'j': // target
1780 case 'p': // net family protocol
1781 case 's': // source mac
1782 case 'd': // destination mac
1783 if ((replace.flags & OPT_COMMAND) == 0)
1784 print_error("No command specified");
1785 if ( replace.command != 'A' &&
1786 replace.command != 'D' && replace.command != 'I')
1787 print_error("Command and option do not match");
1788 if (c == 'i') {
1789 check_option(&replace.flags, OPT_IN);
1790 if (replace.selected_hook > 2 &&
1791 replace.selected_hook < NF_BR_BROUTING)
1792 print_error("Use in-interface only in "
1793 "INPUT, FORWARD, PREROUTING and"
1794 "BROUTING chains");
1795 if (check_inverse(optarg))
1796 new_entry->invflags |= EBT_IIN;
1797
1798 if (optind > argc)
1799 print_error("No in-interface "
1800 "specified");
1801 if (strlen(argv[optind - 1]) >= IFNAMSIZ)
1802 print_error("Illegal interfacelength");
1803 strcpy(new_entry->in, argv[optind - 1]);
1804 break;
1805 }
1806 if (c == 2) {
1807 check_option(&replace.flags, OPT_LOGICALIN);
1808 if (replace.selected_hook > 2 &&
1809 replace.selected_hook < NF_BR_BROUTING)
1810 print_error("Use logical in-interface "
1811 "only in INPUT, FORWARD, "
1812 "PREROUTING and BROUTING chains");
1813 if (check_inverse(optarg))
1814 new_entry->invflags |= EBT_ILOGICALIN;
1815
1816 if (optind > argc)
1817 print_error("No logical in-interface "
1818 "specified");
1819 if (strlen(argv[optind - 1]) >= IFNAMSIZ)
1820 print_error("Illegal interfacelength");
1821 strcpy(new_entry->logical_in, argv[optind - 1]);
1822 break;
1823 }
1824 if (c == 'o') {
1825 check_option(&replace.flags, OPT_OUT);
1826 if (replace.selected_hook < 2)
1827 print_error("Use out-interface only"
1828 " in OUTPUT, FORWARD and "
1829 "POSTROUTING chains");
1830 if (check_inverse(optarg))
1831 new_entry->invflags |= EBT_IOUT;
1832
1833 if (optind > argc)
1834 print_error("No out-interface "
1835 "specified");
1836
1837 if (strlen(argv[optind - 1]) >= IFNAMSIZ)
1838 print_error("Illegal interface "
1839 "length");
1840 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)
1857 print_error("Illegal interface "
1858 "length");
1859 strcpy(new_entry->logical_out,
1860 argv[optind - 1]);
1861 break;
1862 }
1863 if (c == 'j') {
1864
1865 check_option(&replace.flags, OPT_JUMP);
1866 for (i = 0; i < NUM_STANDARD_TARGETS; i++)
1867 if (!strcmp(optarg,
1868 standard_targets[i])) {
1869 t = find_target(
1870 EBT_STANDARD_TARGET);
1871 ((struct ebt_standard_target *)
Bart De Schuymer60332e02002-06-23 08:01:47 +00001872 t->t)->verdict = -i - 1;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001873 break;
1874 }
Bart De Schuymer60332e02002-06-23 08:01:47 +00001875 if (-i - 1 == EBT_RETURN) {
1876 if (replace.selected_hook < NF_BR_NUMHOOKS)
1877 print_error("Return target"
1878 " only for user defined chains");
1879 }
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +00001880 if (i != NUM_STANDARD_TARGETS)
1881 break;
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001882 if ((i = get_hooknr(optarg)) != -1) {
1883 if (i < NF_BR_NUMHOOKS)
1884 print_error("don't jump"
1885 " to a standard chain");
1886 t = find_target(
1887 EBT_STANDARD_TARGET);
1888 ((struct ebt_standard_target *)
1889 t->t)->verdict = i - NF_BR_NUMHOOKS;
1890 break;
1891 }
1892 else {
1893 // must be an extension then
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001894 struct ebt_u_target *t;
1895 t = find_target(optarg);
1896 // -j standard not allowed either
1897 if (!t || t ==
1898 (struct ebt_u_target *)new_entry->t)
1899 print_error("Illegal target "
1900 "name");
1901 new_entry->t =
1902 (struct ebt_entry_target *)t;
1903 }
1904 break;
1905 }
1906 if (c == 's') {
1907 check_option(&replace.flags, OPT_SOURCE);
1908 if (check_inverse(optarg))
1909 new_entry->invflags |= EBT_ISOURCE;
1910
1911 if (optind > argc)
1912 print_error("No source mac "
1913 "specified");
1914 if (getmac_and_mask(argv[optind - 1],
1915 new_entry->sourcemac, new_entry->sourcemsk))
1916 print_error("Problem with specified "
1917 "source mac");
1918 new_entry->bitmask |= EBT_SOURCEMAC;
1919 break;
1920 }
1921 if (c == 'd') {
1922 check_option(&replace.flags, OPT_DEST);
1923 if (check_inverse(optarg))
1924 new_entry->invflags |= EBT_IDEST;
1925
1926 if (optind > argc)
1927 print_error("No destination mac "
1928 "specified");
1929 if (getmac_and_mask(argv[optind - 1],
1930 new_entry->destmac, new_entry->destmsk))
1931 print_error("Problem with specified "
1932 "destination mac");
1933 new_entry->bitmask |= EBT_DESTMAC;
1934 break;
1935 }
1936 check_option(&replace.flags, OPT_PROTOCOL);
1937 if (check_inverse(optarg))
1938 new_entry->invflags |= EBT_IPROTO;
1939
1940 if (optind > argc)
1941 print_error("No protocol specified");
1942 new_entry->bitmask &= ~((unsigned int)EBT_NOPROTO);
1943 i = strtol(argv[optind - 1], &buffer, 16);
1944 if (*buffer == '\0' && (i < 0 || i > 0xFFFF))
1945 print_error("Problem with the specified "
1946 "protocol");
1947 new_entry->ethproto = i;
1948 if (*buffer != '\0')
1949 if (name_to_protocol(argv[optind - 1]) == -1)
1950 print_error("Problem with the specified"
1951 " protocol");
1952 if (new_entry->ethproto < 1536 &&
1953 !(new_entry->bitmask & EBT_802_3))
1954 print_error("Sorry, protocols have values above"
1955 " or equal to 1536 (0x0600)");
1956 break;
1957
1958 case 'b': // allow database?
1959 if (replace.flags & OPT_COMMAND)
1960 print_error("Multiple commands not allowed");
1961 replace.command = c;
1962 allowbc = *optarg;
1963 break;
1964
1965 default:
1966
1967 // is it a target option?
1968 t = (struct ebt_u_target *)new_entry->t;
1969 if ((t->parse(c - t->option_offset, argv, argc,
1970 new_entry, &t->flags, &t->t)))
1971 continue;
1972
1973 // is it a match_option?
1974 for (m = matches; m; m = m->next)
1975 if (m->parse(c - m->option_offset, argv,
1976 argc, new_entry, &m->flags, &m->m))
1977 break;
1978
1979 if (m != NULL) {
1980 if (m->used == 0)
1981 add_match(m);
1982 continue;
1983 }
1984
1985 // is it a watcher option?
1986 for (w = watchers; w; w = w->next)
1987 if (w->parse(c-w->option_offset, argv,
1988 argc, new_entry, &w->flags, &w->w))
1989 break;
1990
1991 if (w == NULL)
1992 print_error("Unknown argument");
Bart De Schuymer60332e02002-06-23 08:01:47 +00001993 if (replace.command != 'A' && replace.command != 'I' &&
1994 replace.command != 'D')
1995 print_error("extensions only for -A, -I and -D");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001996 if (w->used == 0)
1997 add_watcher(w);
1998 }
1999 }
2000
Bart De Schuymer25c741d2002-06-23 18:54:34 +00002001 if ( !table && !(table = find_table(replace.name)) )
2002 print_error("Bad table name");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002003 // database stuff before ebtables stuff
2004 if (replace.command == 'b')
2005 allowdb(allowbc);
2006 if (replace.command == 'L' && replace.selected_hook == DATABASEHOOKNR)
2007 list_db();
2008
2009 if ( (replace.flags & OPT_COMMAND) && replace.command != 'L' &&
2010 replace.flags & OPT_ZERO )
2011 print_error("Command -Z only allowed together with command -L");
2012
2013 if (replace.command == 'A' || replace.command == 'I' ||
2014 replace.command == 'D') {
2015 if (replace.selected_hook == -1)
2016 print_error("Not enough information");
2017 }
2018
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002019 // do this after parsing everything, so we can print specific info
2020 if (replace.command == 'h' && !(replace.flags & OPT_ZERO))
2021 print_help();
2022
2023 // do the final checks
Bart De Schuymer60332e02002-06-23 08:01:47 +00002024 if (replace.command == 'A' || replace.command == 'I' ||
2025 replace.command == 'D') {
2026 // this will put the hook_mask right for the chains
2027 check_for_loops();
2028 entries = to_chain();
2029 m_l = new_entry->m_list;
2030 w_l = new_entry->w_list;
2031 t = (struct ebt_u_target *)new_entry->t;
2032 while (m_l) {
2033 m = (struct ebt_u_match *)(m_l->m);
2034 m->final_check(new_entry, m->m, replace.name,
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +00002035 entries->hook_mask, 0);
Bart De Schuymer60332e02002-06-23 08:01:47 +00002036 m_l = m_l->next;
2037 }
2038 while (w_l) {
2039 w = (struct ebt_u_watcher *)(w_l->w);
2040 w->final_check(new_entry, w->w, replace.name,
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +00002041 entries->hook_mask, 0);
Bart De Schuymer60332e02002-06-23 08:01:47 +00002042 w_l = w_l->next;
2043 }
2044 t->final_check(new_entry, t->t, replace.name,
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +00002045 entries->hook_mask, 0);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002046 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002047 // so, the extensions can work with the host endian
2048 // the kernel does not have to do this ofcourse
2049 new_entry->ethproto = htons(new_entry->ethproto);
2050
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002051 if (replace.command == 'P')
2052 change_policy(policy);
2053 else if (replace.command == 'L') {
2054 list_rules();
2055 if (replace.flags & OPT_ZERO)
2056 zero_counters(zerochain);
2057 else
2058 exit(0);
2059 }
2060 if (replace.flags & OPT_ZERO)
2061 zero_counters(zerochain);
Bart De Schuymer1ab41562002-06-23 17:09:54 +00002062 else if (replace.command == 'F') {
2063 if (flush_chains() == -1)
2064 exit(0);
2065 } else if (replace.command == 'A' || replace.command == 'I') {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002066 add_rule(rule_nr);
Bart De Schuymer1ab41562002-06-23 17:09:54 +00002067 check_for_loops();
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +00002068 // do the final_check(), for all entries
2069 // needed when adding a rule that has a chain target
2070 i = -1;
2071 while (1) {
2072 struct ebt_u_entry *e;
2073
2074 i++;
2075 entries = nr_to_chain(i);
2076 if (!entries) {
2077 if (i < NF_BR_NUMHOOKS)
2078 continue;
2079 else
2080 break;
2081 }
2082 e = entries->entries;
2083 while (e) {
2084 // userspace extensions use host endian
2085 e->ethproto = ntohs(e->ethproto);
2086 do_final_checks(e, entries);
2087 e->ethproto = htons(e->ethproto);
2088 e = e->next;
2089 }
2090 }
Bart De Schuymer1ab41562002-06-23 17:09:54 +00002091 } else if (replace.command == 'D')
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002092 delete_rule(rule_nr);
Bart De Schuymer1ab41562002-06-23 17:09:54 +00002093 // commands -N, -E, -X fall through
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002094
2095 if (table->check)
2096 table->check(&replace);
2097
2098 deliver_table(&replace);
2099
2100 if (counterchanges)
2101 deliver_counters(&replace, counterchanges);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002102 return 0;
2103}