blob: 48861f3403c132b9c8e7063c70be07695d7086fe [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 Schuymer1abc55d2002-06-01 19:23:47 +0000521 while (i >9) {
522 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.
529 while (j > 9) {
530 digits++;
531 j /= 10;
532 }
533 for (j = 0; j < space - digits; j++)
534 printf(" ");
535 printf("%d. ", i + 1);
536
537 // Don't print anything about the protocol if no protocol was
538 // specified, obviously this means any protocol will do.
539 if (!(hlp->bitmask & EBT_NOPROTO)) {
Bart De Schuymer60332e02002-06-23 08:01:47 +0000540 printf("-p ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000541 if (hlp->invflags & EBT_IPROTO)
542 printf("! ");
543 if (hlp->bitmask & EBT_802_3)
544 printf("Length, ");
545 else {
546 if (number_to_name(ntohs(hlp->ethproto), name))
Bart De Schuymer60332e02002-06-23 08:01:47 +0000547 printf("0x%x ", ntohs(hlp->ethproto));
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000548 else
Bart De Schuymer60332e02002-06-23 08:01:47 +0000549 printf("%s ", name);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000550 }
551 }
552 if (hlp->bitmask & EBT_SOURCEMAC) {
553 char hlpmsk[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
554
Bart De Schuymer60332e02002-06-23 08:01:47 +0000555 printf("-s ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000556 if (hlp->invflags & EBT_ISOURCE)
557 printf("! ");
558 if (!memcmp(hlp->sourcemac, mac_type_unicast, 6) &&
559 !memcmp(hlp->sourcemsk, msk_type_unicast, 6)) {
560 printf("Unicast");
561 goto endsrc;
562 }
563 if (!memcmp(hlp->sourcemac, mac_type_multicast, 6) &&
564 !memcmp(hlp->sourcemsk, msk_type_multicast, 6)) {
565 printf("Multicast");
566 goto endsrc;
567 }
568 if (!memcmp(hlp->sourcemac, mac_type_broadcast, 6) &&
569 !memcmp(hlp->sourcemsk, msk_type_broadcast, 6)) {
570 printf("Broadcast");
571 goto endsrc;
572 }
Bart De Schuymer41830412002-06-05 19:41:28 +0000573 printf("%s", ether_ntoa((struct ether_addr *)
574 hlp->sourcemac));
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000575 if (memcmp(hlp->sourcemsk, hlpmsk, 6)) {
576 printf("/");
Bart De Schuymer41830412002-06-05 19:41:28 +0000577 printf("%s", ether_ntoa((struct ether_addr *)
578 hlp->sourcemsk));
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000579 }
580endsrc:
Bart De Schuymer60332e02002-06-23 08:01:47 +0000581 printf(" ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000582 }
583 if (hlp->bitmask & EBT_DESTMAC) {
584 char hlpmsk[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
585
Bart De Schuymer60332e02002-06-23 08:01:47 +0000586 printf("-d ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000587 if (hlp->invflags & EBT_IDEST)
588 printf("! ");
589 if (!memcmp(hlp->destmac, mac_type_unicast, 6) &&
590 !memcmp(hlp->destmsk, msk_type_unicast, 6)) {
591 printf("Unicast");
592 goto enddst;
593 }
594 if (!memcmp(hlp->destmac, mac_type_multicast, 6) &&
595 !memcmp(hlp->destmsk, msk_type_multicast, 6)) {
596 printf("Multicast");
597 goto enddst;
598 }
599 if (!memcmp(hlp->destmac, mac_type_broadcast, 6) &&
600 !memcmp(hlp->destmsk, msk_type_broadcast, 6)) {
601 printf("Broadcast");
602 goto enddst;
603 }
Bart De Schuymer41830412002-06-05 19:41:28 +0000604 printf("%s", ether_ntoa((struct ether_addr *)
605 hlp->destmac));
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000606 if (memcmp(hlp->destmsk, hlpmsk, 6)) {
607 printf("/");
Bart De Schuymer41830412002-06-05 19:41:28 +0000608 printf("%s", ether_ntoa((struct ether_addr *)
609 hlp->destmsk));
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000610 }
611enddst:
Bart De Schuymer60332e02002-06-23 08:01:47 +0000612 printf(" ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000613 }
614 if (hlp->in[0] != '\0') {
Bart De Schuymer60332e02002-06-23 08:01:47 +0000615 printf("-i ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000616 if (hlp->invflags & EBT_IIN)
617 printf("! ");
Bart De Schuymer60332e02002-06-23 08:01:47 +0000618 printf("%s ", hlp->in);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000619 }
620 if (hlp->logical_in[0] != '\0') {
Bart De Schuymer60332e02002-06-23 08:01:47 +0000621 printf("--logical-in ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000622 if (hlp->invflags & EBT_ILOGICALIN)
623 printf("! ");
Bart De Schuymer60332e02002-06-23 08:01:47 +0000624 printf("%s ", hlp->logical_in);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000625 }
626 if (hlp->logical_out[0] != '\0') {
Bart De Schuymer60332e02002-06-23 08:01:47 +0000627 printf("--logical-out ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000628 if (hlp->invflags & EBT_ILOGICALOUT)
629 printf("! ");
Bart De Schuymer60332e02002-06-23 08:01:47 +0000630 printf("%s, ", hlp->logical_out);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000631 }
632 if (hlp->out[0] != '\0') {
Bart De Schuymer60332e02002-06-23 08:01:47 +0000633 printf("-o ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000634 if (hlp->invflags & EBT_IOUT)
635 printf("! ");
Bart De Schuymer60332e02002-06-23 08:01:47 +0000636 printf("%s, ", hlp->out);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000637 }
638
639 m_l = hlp->m_list;
640 while (m_l) {
641 m = find_match(m_l->m->u.name);
642 if (!m)
643 print_bug("Match not found");
644 m->print(hlp, m_l->m);
645 m_l = m_l->next;
646 }
647 w_l = hlp->w_list;
648 while (w_l) {
649 w = find_watcher(w_l->w->u.name);
650 if (!w)
651 print_bug("Watcher not found");
652 w->print(hlp, w_l->w);
653 w_l = w_l->next;
654 }
655
Bart De Schuymer25c741d2002-06-23 18:54:34 +0000656 printf("-j %s ", hlp->t->u.name);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000657 t = find_target(hlp->t->u.name);
658 if (!t)
659 print_bug("Target not found");
660 t->print(hlp, hlp->t);
661 printf(", count = %llu",
Bart De Schuymer60332e02002-06-23 08:01:47 +0000662 replace.counters[entries->counter_offset + i].pcnt);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000663 printf("\n");
664 hlp = hlp->next;
665 }
666}
667
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000668struct ebt_u_entries *nr_to_chain(int nr)
Bart De Schuymer60332e02002-06-23 08:01:47 +0000669{
670 if (nr == -1)
671 return NULL;
672 if (nr < NF_BR_NUMHOOKS)
673 return replace.hook_entry[nr];
674 else {
675 int i;
676 struct ebt_u_chain_list *cl = replace.udc;
677
678 i = nr - NF_BR_NUMHOOKS;
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000679 while (i > 0 && cl) {
Bart De Schuymer60332e02002-06-23 08:01:47 +0000680 cl = cl->next;
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000681 i--;
682 }
Bart De Schuymer60332e02002-06-23 08:01:47 +0000683 if (cl)
684 return cl->udc;
685 else
686 return NULL;
687 }
688}
689
690static struct ebt_u_entries *to_chain()
691{
692 return nr_to_chain(replace.selected_hook);
693}
694
695struct ebt_u_stack
696{
697 int chain_nr;
698 int n;
699 struct ebt_u_entry *e;
700 struct ebt_u_entries *entries;
701};
702
703void check_for_loops()
704{
705 int chain_nr , i, j , k, sp = 0, verdict;
706 struct ebt_u_entries *entries, *entries2;
707 struct ebt_u_stack *stack = NULL;
708 struct ebt_u_entry *e;
709
710 i = -1;
711 // initialize hook_mask to 0
712 while (1) {
713 i++;
714 if (i < NF_BR_NUMHOOKS && !(replace.valid_hooks & (1 << i)))
715 continue;
716 entries = nr_to_chain(i);
717 if (!entries)
718 break;
719 entries->hook_mask = 0;
720 }
721 if (i > NF_BR_NUMHOOKS) {
722 stack = (struct ebt_u_stack *)malloc((i - NF_BR_NUMHOOKS) *
723 sizeof(struct ebt_u_stack));
724 if (!stack)
725 print_memory();
726 }
727
728 for (i = 0; i < NF_BR_NUMHOOKS; i++) {
729 if (!(replace.valid_hooks & (1 << i)))
730 continue;
731 entries = nr_to_chain(i);
732 entries->hook_mask = (1 << i);
733 chain_nr = i;
734
735 e = entries->entries;
736 for (j = 0; j < entries->nentries; j++) {
737 if (strcmp(e->t->u.name, EBT_STANDARD_TARGET))
738 goto letscontinue;
739 verdict = ((struct ebt_standard_target *)(e->t))->verdict;
740 if (verdict < 0)
741 goto letscontinue;
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000742 entries2 = nr_to_chain(verdict + NF_BR_NUMHOOKS);
Bart De Schuymer60332e02002-06-23 08:01:47 +0000743 entries2->hook_mask |= entries->hook_mask;
744 // now see if we've been here before
745 for (k = 0; k < sp; k++)
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000746 if (stack[k].chain_nr == verdict + NF_BR_NUMHOOKS)
Bart De Schuymer1a0a9c32002-06-24 21:10:16 +0000747 print_error("Loop from chain %s to chain %s",
748 nr_to_chain(chain_nr)->name, nr_to_chain(stack[k].chain_nr)->name);
Bart De Schuymer60332e02002-06-23 08:01:47 +0000749 // jump to the chain, make sure we know how to get back
750 stack[sp].chain_nr = chain_nr;
751 stack[sp].n = j;
752 stack[sp].entries = entries;
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000753 stack[sp].e = e;
754 sp++;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000755 j = -1;
756 e = entries2->entries;
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000757 chain_nr = verdict + NF_BR_NUMHOOKS;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000758 entries = entries2;
759 continue;
760letscontinue:
761 e = e->next;
762 }
763 // we are in a standard chain
764 if (sp == 0)
765 continue;
766 // go back to the chain one level lower
767 sp--;
768 j = stack[sp].n;
769 chain_nr = stack[sp].chain_nr;
770 e = stack[sp].e;
771 entries = stack[sp].entries;
772 goto letscontinue;
773 }
774 free(stack);
775 return;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000776}
777
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000778// parse the chain name and return the corresponding nr
779int get_hooknr(char* arg)
780{
781 int i;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000782 struct ebt_u_chain_list *cl = replace.udc;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000783
784 // database is special case (not really a chain)
785 if (!strcmp(arg, DATABASEHOOKNAME))
786 return DATABASEHOOKNR;
787
Bart De Schuymer60332e02002-06-23 08:01:47 +0000788 for (i = 0; i < NF_BR_NUMHOOKS; i++) {
789 if (!(replace.valid_hooks & (1 << i)))
790 continue;
791 if (!strcmp(arg, replace.hook_entry[i]->name))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000792 return i;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000793 }
794 while(cl) {
795 if (!strcmp(arg, cl->udc->name))
796 return i;
797 i++;
798 cl = cl->next;
799 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000800 return -1;
801}
802
803// yup, print out help
804void print_help()
805{
806 struct ebt_u_match_list *m_l;
807 struct ebt_u_watcher_list *w_l;
808
809 printf(
810"%s v%s\n"
811"Usage:\n"
812"ebtables -[ADI] chain rule-specification [options]\n"
813"ebtables -P chain target\n"
814"ebtables -[LFZ] [chain]\n"
815"ebtables -[b] [y,n]\n"
816"Commands:\n"
817"--append -A chain : Append to chain\n"
818"--delete -D chain : Delete matching rule from chain\n"
819"--delete -D chain rulenum : Delete rule at position rulenum from chain\n"
820"--insert -I chain rulenum : insert rule at position rulenum in chain\n"
821"--list -L [chain] : List the rules in a chain or in all chains\n"
822"--list -L "DATABASEHOOKNAME" : List the database (if present)\n"
823"--flush -F [chain] : Delete all rules in chain or in all chains\n"
824"--zero -Z [chain] : Put counters on zero in chain or in all chains\n"
825"--policy -P chain target : Change policy on chain to target\n"
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000826"--new-chain -N chain : Create a user defined chain\n"
827"--rename-chain -E old new : Rename a chain\n"
828"--delete-chain -X chain : Delete a user defined chain\n"
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000829"Options:\n"
830"--proto -p [!] proto : protocol hexadecimal, by name or LENGTH\n"
831"--src -s [!] address[/mask]: source mac address\n"
832"--dst -d [!] address[/mask]: destination mac address\n"
833"--in-if -i [!] name : network input interface name\n"
834"--out-if -o [!] name : network output interface name\n"
835"--logical-in [!] name : logical bridge input interface name\n"
836"--logical-out [!] name : logical bridge output interface name\n"
Bart De Schuymerc8531032002-06-14 21:55:29 +0000837"--modprobe -M : try to insert modules using this command\n"
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000838"--version -V : print package version\n"
839"\n" ,
840 prog_name,
841 prog_version);
842
843 m_l = new_entry->m_list;
844 while (m_l) {
845 ((struct ebt_u_match *)m_l->m)->help();
846 printf("\n");
847 m_l = m_l->next;
848 }
849 w_l = new_entry->w_list;
850 while (w_l) {
851 ((struct ebt_u_watcher *)w_l->w)->help();
852 printf("\n");
853 w_l = w_l->next;
854 }
855 ((struct ebt_u_target *)new_entry->t)->help();
856 printf("\n");
857 if (table->help)
858 table->help(hooknames);
859 exit(0);
860}
861
862// execute command L
863static void list_rules()
864{
865 int i;
866
867 printf("Bridge table: %s\n", table->name);
Bart De Schuymer60332e02002-06-23 08:01:47 +0000868 if (replace.selected_hook != -1) {
869 list_em(to_chain());
870 } else {
871 struct ebt_u_chain_list *cl = replace.udc;
872
873 i = 0;
874 while (1) {
875 if (i < NF_BR_NUMHOOKS) {
876 if (replace.valid_hooks & (1 << i))
877 list_em(replace.hook_entry[i]);
878 i++;
879 continue;
880 } else {
881 if (!cl)
882 break;
883 list_em(cl->udc);
884 cl = cl->next;
885 }
886 }
887 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000888 return;
889}
890
891// execute command P
892static void change_policy(int policy)
893{
894 int i;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000895 struct ebt_u_entries *entries = to_chain();
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000896
897 // don't do anything if the policy is the same
Bart De Schuymer60332e02002-06-23 08:01:47 +0000898 if (entries->policy != policy) {
899 entries->policy = policy;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000900 replace.num_counters = replace.nentries;
901 if (replace.nentries) {
902 // '+ 1' for the CNT_END
903 if (!(counterchanges = (unsigned short *) malloc(
904 (replace.nentries + 1) * sizeof(unsigned short))))
905 print_memory();
906 // done nothing special to the rules
907 for (i = 0; i < replace.nentries; i++)
908 counterchanges[i] = CNT_NORM;
909 counterchanges[replace.nentries] = CNT_END;
910 }
911 else
912 counterchanges = NULL;
913 }
914 else
915 exit(0);
916}
917
918// flush one chain or the complete table
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000919// -1 == nothing to do
920// 0 == give back to kernel
921static int flush_chains()
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000922{
Bart De Schuymer60332e02002-06-23 08:01:47 +0000923 int i, j, oldnentries, numdel;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000924 unsigned short *cnt;
925 struct ebt_u_entry *u_e, *tmp;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000926 struct ebt_u_entries *entries = to_chain();
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000927
928 // flush whole table
Bart De Schuymer60332e02002-06-23 08:01:47 +0000929 if (!entries) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000930 if (replace.nentries == 0)
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000931 return -1;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000932 replace.nentries = 0;
933 // no need for the kernel to give us counters back
934 replace.num_counters = 0;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000935
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000936 // free everything and zero (n)entries
Bart De Schuymer60332e02002-06-23 08:01:47 +0000937 i = -1;
938 while (1) {
939 i++;
940 entries = nr_to_chain(i);
941 if (!entries) {
942 if (i < NF_BR_NUMHOOKS)
943 continue;
944 else
945 break;
946 }
947 entries->nentries = 0;
948 entries->counter_offset = 0;
949 u_e = entries->entries;
950 entries->entries = NULL;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000951 while (u_e) {
952 free_u_entry(u_e);
953 tmp = u_e->next;
954 free(u_e);
955 u_e = tmp;
956 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000957 }
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000958 return 0;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000959 }
960
Bart De Schuymer60332e02002-06-23 08:01:47 +0000961 if (entries->nentries == 0)
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000962 return -1;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000963 oldnentries = replace.nentries;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000964 replace.nentries -= entries->nentries;
965 numdel = entries->nentries;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000966
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000967 if (replace.nentries) {
968 // +1 for CNT_END
969 if ( !(counterchanges = (unsigned short *)
970 malloc((oldnentries + 1) * sizeof(unsigned short))) )
971 print_memory();
972 cnt = counterchanges;
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;
977 while (1) {
978 i++;
979 entries = nr_to_chain(i);
980 if (!entries) {
981 if (i < NF_BR_NUMHOOKS)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000982 continue;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000983 else
984 break;
985 }
986 if (i > replace.selected_hook)
987 entries->counter_offset -= numdel;
988 if (replace.nentries) {
989 for (j = 0; j < entries->nentries; j++) {
990 if (i == replace.selected_hook)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000991 *cnt = CNT_DEL;
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000992 else
993 *cnt = CNT_NORM;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000994 cnt++;
995 }
996 }
Bart De Schuymer60332e02002-06-23 08:01:47 +0000997 }
998
999 if (replace.nentries) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001000 *cnt = CNT_END;
1001 replace.num_counters = oldnentries;
1002 }
1003 else
1004 replace.num_counters = 0;
1005
Bart De Schuymer60332e02002-06-23 08:01:47 +00001006 entries = to_chain();
1007 entries->nentries = 0;
1008 u_e = entries->entries;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001009 while (u_e) {
1010 free_u_entry(u_e);
1011 tmp = u_e->next;
1012 free(u_e);
1013 u_e = tmp;
1014 }
Bart De Schuymer60332e02002-06-23 08:01:47 +00001015 entries->entries = NULL;
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001016 return 0;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001017}
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001018
1019// -1 == no match
1020static int check_rule_exists(int rule_nr)
1021{
1022 struct ebt_u_entry *u_e;
1023 struct ebt_u_match_list *m_l, *m_l2;
1024 struct ebt_u_match *m;
1025 struct ebt_u_watcher_list *w_l, *w_l2;
1026 struct ebt_u_watcher *w;
1027 struct ebt_u_target *t = (struct ebt_u_target *)new_entry->t;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001028 struct ebt_u_entries *entries = to_chain();
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001029 int i, j, k;
1030
1031 // handle '-D chain rulenr' command
1032 if (rule_nr != -1) {
Bart De Schuymer60332e02002-06-23 08:01:47 +00001033 if (rule_nr > entries->nentries)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001034 return 0;
1035 // user starts counting from 1
1036 return rule_nr - 1;
1037 }
Bart De Schuymer60332e02002-06-23 08:01:47 +00001038 u_e = entries->entries;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001039 // check for an existing rule (if there are duplicate rules,
1040 // take the first occurance)
Bart De Schuymer60332e02002-06-23 08:01:47 +00001041 for (i = 0; i < entries->nentries; i++, u_e = u_e->next) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001042 if (!u_e)
1043 print_bug("Hmm, trouble");
1044 if ( u_e->ethproto == new_entry->ethproto
1045 && !strcmp(u_e->in, new_entry->in)
1046 && !strcmp(u_e->out, new_entry->out)
1047 && u_e->bitmask == new_entry->bitmask) {
Bart De Schuymer60332e02002-06-23 08:01:47 +00001048 if (strcmp(u_e->logical_in, new_entry->logical_in) ||
1049 strcmp(u_e->logical_out, new_entry->logical_out))
1050 continue;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001051 if (new_entry->bitmask & EBT_SOURCEMAC &&
Bart De Schuymer60332e02002-06-23 08:01:47 +00001052 memcmp(u_e->sourcemac, new_entry->sourcemac, ETH_ALEN))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001053 continue;
1054 if (new_entry->bitmask & EBT_DESTMAC &&
Bart De Schuymer60332e02002-06-23 08:01:47 +00001055 memcmp(u_e->destmac, new_entry->destmac, ETH_ALEN))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001056 continue;
1057 if (new_entry->bitmask != u_e->bitmask ||
1058 new_entry->invflags != u_e->invflags)
1059 continue;
1060 // compare all matches
1061 m_l = new_entry->m_list;
1062 j = 0;
1063 while (m_l) {
1064 m = (struct ebt_u_match *)(m_l->m);
1065 m_l2 = u_e->m_list;
1066 while (m_l2 &&
1067 strcmp(m_l2->m->u.name, m->m->u.name))
1068 m_l2 = m_l2->next;
1069 if (!m_l2 || !m->compare(m->m, m_l2->m))
1070 goto letscontinue;
1071 j++;
1072 m_l = m_l->next;
1073 }
1074 // now be sure they have the same nr of matches
1075 k = 0;
1076 m_l = u_e->m_list;
1077 while (m_l) {
1078 k++;
1079 m_l = m_l->next;
1080 }
1081 if (j != k)
1082 continue;
1083
1084 // compare all watchers
1085 w_l = new_entry->w_list;
1086 j = 0;
1087 while (w_l) {
1088 w = (struct ebt_u_watcher *)(w_l->w);
1089 w_l2 = u_e->w_list;
1090 while (w_l2 &&
1091 strcmp(w_l2->w->u.name, w->w->u.name))
1092 w_l2 = w_l2->next;
1093 if (!w_l2 || !w->compare(w->w, w_l2->w))
1094 goto letscontinue;
1095 j++;
1096 w_l = w_l->next;
1097 }
1098 k = 0;
1099 w_l = u_e->w_list;
1100 while (w_l) {
1101 k++;
1102 w_l = w_l->next;
1103 }
1104 if (j != k)
1105 continue;
1106 if (strcmp(t->t->u.name, u_e->t->u.name))
1107 continue;
1108 if (!t->compare(t->t, u_e->t))
1109 continue;
1110 return i;
1111 }
1112letscontinue:
1113 }
1114 return -1;
1115}
1116
1117// execute command A
1118static void add_rule(int rule_nr)
1119{
1120 int i, j;
1121 struct ebt_u_entry *u_e, *u_e2;
1122 unsigned short *cnt;
1123 struct ebt_u_match_list *m_l;
1124 struct ebt_u_watcher_list *w_l;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001125 struct ebt_u_entries *entries = to_chain(), *entries2;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001126
1127 if (rule_nr != -1) { // command -I
Bart De Schuymer60332e02002-06-23 08:01:47 +00001128 if (--rule_nr > entries->nentries)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001129 print_error("rule nr too high: %d > %d", rule_nr,
Bart De Schuymer60332e02002-06-23 08:01:47 +00001130 entries->nentries);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001131 } else
Bart De Schuymer60332e02002-06-23 08:01:47 +00001132 rule_nr = entries->nentries;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001133 // we're adding one rule
1134 replace.num_counters = replace.nentries;
1135 replace.nentries++;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001136 entries->nentries++;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001137
1138 // handle counter stuff
1139 // +1 for CNT_END
1140 if ( !(counterchanges = (unsigned short *)
1141 malloc((replace.nentries + 1) * sizeof(unsigned short))) )
1142 print_memory();
1143 cnt = counterchanges;
1144 for (i = 0; i < replace.selected_hook; i++) {
Bart De Schuymer60332e02002-06-23 08:01:47 +00001145 if (i < NF_BR_NUMHOOKS && !(replace.valid_hooks & (1 << i)))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001146 continue;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001147 entries2 = nr_to_chain(i);
1148 for (j = 0; j < entries2->nentries; j++) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001149 *cnt = CNT_NORM;
1150 cnt++;
1151 }
1152 }
1153 for (i = 0; i < rule_nr; i++) {
1154 *cnt = CNT_NORM;
1155 cnt++;
1156 }
1157 *cnt = CNT_ADD;
1158 cnt++;
1159 while (cnt != counterchanges + replace.nentries) {
1160 *cnt = CNT_NORM;
1161 cnt++;
1162 }
1163 *cnt = CNT_END;
1164
1165 // go to the right position in the chain
1166 u_e2 = NULL;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001167 u_e = entries->entries;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001168 for (i = 0; i < rule_nr; i++) {
1169 u_e2 = u_e;
1170 u_e = u_e->next;
1171 }
1172 // insert the rule
1173 if (u_e2)
1174 u_e2->next = new_entry;
1175 else
Bart De Schuymer60332e02002-06-23 08:01:47 +00001176 entries->entries = new_entry;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001177 new_entry->next = u_e;
1178
1179 // put the ebt_[match, watcher, target] pointers in place
1180 m_l = new_entry->m_list;
1181 while (m_l) {
1182 m_l->m = ((struct ebt_u_match *)m_l->m)->m;
1183 m_l = m_l->next;
1184 }
1185 w_l = new_entry->w_list;
1186 while (w_l) {
1187 w_l->w = ((struct ebt_u_watcher *)w_l->w)->w;
1188 w_l = w_l->next;
1189 }
1190 new_entry->t = ((struct ebt_u_target *)new_entry->t)->t;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001191
1192 // update the counter_offset of chains behind this one
1193 i = replace.selected_hook;
1194 while (1) {
1195 i++;
1196 entries = nr_to_chain(i);
1197 if (!entries) {
1198 if (i < NF_BR_NUMHOOKS)
1199 continue;
1200 else
1201 break;
1202 } else
1203 entries->counter_offset++;
1204 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001205}
1206
1207// execute command D
1208static void delete_rule(int rule_nr)
1209{
1210 int i, j, lentmp = 0;
1211 unsigned short *cnt;
1212 struct ebt_u_entry *u_e, *u_e2;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001213 struct ebt_u_entries *entries = to_chain(), *entries2;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001214
1215 if ( (i = check_rule_exists(rule_nr)) == -1 )
Bart De Schuymer60332e02002-06-23 08:01:47 +00001216 print_error("Sorry, rule does not exist");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001217
1218 // we're deleting a rule
1219 replace.num_counters = replace.nentries;
1220 replace.nentries--;
1221
1222 if (replace.nentries) {
1223 for (j = 0; j < replace.selected_hook; j++) {
Bart De Schuymer60332e02002-06-23 08:01:47 +00001224 if (j < NF_BR_NUMHOOKS &&
1225 !(replace.valid_hooks & (1 << j)))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001226 continue;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001227 entries2 = nr_to_chain(j);
1228 lentmp += entries2->nentries;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001229 }
1230 lentmp += i;
1231 // +1 for CNT_END
1232 if ( !(counterchanges = (unsigned short *)malloc(
1233 (replace.num_counters + 1) * sizeof(unsigned short))) )
1234 print_memory();
1235 cnt = counterchanges;
1236 for (j = 0; j < lentmp; j++) {
1237 *cnt = CNT_NORM;
1238 cnt++;
1239 }
1240 *cnt = CNT_DEL;
1241 cnt++;
1242 for (j = 0; j < replace.num_counters - lentmp; j++) {
1243 *cnt = CNT_NORM;
1244 cnt++;
1245 }
1246 *cnt = CNT_END;
1247 }
1248 else
1249 replace.num_counters = 0;
1250
1251 // go to the right position in the chain
1252 u_e2 = NULL;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001253 u_e = entries->entries;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001254 for (j = 0; j < i; j++) {
1255 u_e2 = u_e;
1256 u_e = u_e->next;
1257 }
1258
1259 // remove from the chain
1260 if (u_e2)
1261 u_e2->next = u_e->next;
1262 else
Bart De Schuymer60332e02002-06-23 08:01:47 +00001263 entries->entries = u_e->next;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001264
Bart De Schuymer60332e02002-06-23 08:01:47 +00001265 entries->nentries--;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001266 // free everything
1267 free_u_entry(u_e);
1268 free(u_e);
Bart De Schuymer60332e02002-06-23 08:01:47 +00001269 // update the counter_offset of chains behind this one
1270 i = replace.selected_hook;
1271 while (1) {
1272 i++;
1273 entries = nr_to_chain(i);
1274 if (!entries) {
1275 if (i < NF_BR_NUMHOOKS)
1276 continue;
1277 else
1278 break;
1279 } else
1280 entries->counter_offset--;
1281 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001282}
1283
1284// execute command Z
1285void zero_counters(int zerochain)
1286{
1287
1288 if (zerochain == -1) {
1289 // tell main() we don't update the counters
1290 // this results in tricking the kernel to zero his counters,
1291 // naively expecting userspace to update its counters. Muahahaha
1292 counterchanges = NULL;
1293 replace.num_counters = 0;
1294 } else {
1295 int i, j;
1296 unsigned short *cnt;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001297 struct ebt_u_entries *entries = nr_to_chain(zerochain), *e2;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001298
Bart De Schuymer60332e02002-06-23 08:01:47 +00001299 if (entries->nentries == 0)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001300 exit(0);
1301 counterchanges = (unsigned short *)
1302 malloc((replace.nentries + 1) * sizeof(unsigned short));
1303 if (!counterchanges)
1304 print_memory();
1305 cnt = counterchanges;
1306 for (i = 0; i < zerochain; i++) {
Bart De Schuymer60332e02002-06-23 08:01:47 +00001307 if (i < NF_BR_NUMHOOKS &&
1308 !(replace.valid_hooks & (1 << i)))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001309 continue;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001310 e2 = nr_to_chain(i);
1311 for (j = 0; j < e2->nentries; j++) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001312 *cnt = CNT_NORM;
1313 cnt++;
1314 }
1315 }
Bart De Schuymer60332e02002-06-23 08:01:47 +00001316 for (i = 0; i < entries->nentries; i++) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001317 *cnt = CNT_ZERO;
1318 cnt++;
1319 }
1320 while (cnt != counterchanges + replace.nentries) {
1321 *cnt = CNT_NORM;
1322 cnt++;
1323 }
1324 *cnt = CNT_END;
1325 }
1326}
1327
1328// list the database (optionally compiled into the kernel)
1329static void list_db()
1330{
1331 struct brdb_dbinfo nr;
1332 struct brdb_dbentry *db;
1333 char name[21];
1334 int i;
1335
1336 get_dbinfo(&nr);
1337
1338 // 0 : database disabled (-db n)
1339 if (!(nr.nentries))
1340 print_error("Database not present"
1341 " (disabled), try ebtables --db y");
1342 nr.nentries--;
1343 if (!nr.nentries) print_error("Database empty");
1344 if ( !(db = (struct brdb_dbentry *)
1345 malloc(nr.nentries * sizeof(struct brdb_dbentry))) )
1346 print_memory();
1347
1348 get_db(nr.nentries, db);
1349 printf("number of entries: %d\n", nr.nentries);
1350 for (i = 0; i < nr.nentries; i++) {
1351 printf(
1352 "%d:\n"
1353 "hook : %s\n"
1354 "in-if : %s\n"
1355 "out-if : %s\n"
1356 "protocol: ", i + 1, hooknames[db->hook], db->in, db->out);
1357 if (db->ethproto == IDENTIFY802_3)
1358 printf("802.2/802.3 STYLE LENGTH FIELD\n");
1359 else {
1360 if (number_to_name(ntohs(db->ethproto), name))
1361 printf("%x\n",ntohs(db->ethproto));
1362 else
1363 printf("%s\n", name);
1364 }
1365 db++;
1366 }
1367 exit(0);
1368}
1369
1370// handle db [dis,en]abling
1371static void allowdb(char yorn)
1372{
1373 __u16 decision;
1374
1375 if (yorn != 'y' && yorn != 'n')
1376 print_error("Option [y] or [n] needed");
1377
1378 if (yorn == 'y')
1379 decision = BRDB_DB;
1380 else
1381 decision = BRDB_NODB;
1382
1383 deliver_allowdb(&decision);
1384
1385 exit(0);
1386}
1387
1388// set ethproto
1389int name_to_protocol(char *name)
1390{
1391 FILE *ifp;
1392 char buffer[21], value[5], *bfr;
1393 unsigned short i;
1394
1395 if (!strcasecmp("LENGTH", name)) {
1396 new_entry->ethproto = 0;
1397 new_entry->bitmask |= EBT_802_3;
1398 return 1;
1399 }
1400 if ( !(ifp = fopen(PROTOCOLFILE, "r")) )
1401 return -1;
1402 while (1) {
1403 if (get_a_line(buffer, value, ifp)) return -1;
1404 if (strcasecmp(buffer, name))
1405 continue;
1406 i = (unsigned short) strtol(value, &bfr, 16);
1407 if (*bfr != '\0')
1408 return -1;
1409 new_entry->ethproto = i;
1410 fclose(ifp);
1411 return 0;
1412 }
1413 return -1;
1414}
1415
1416// put the mac address into 6 (ETH_ALEN) bytes
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001417int getmac_and_mask(char *from, char *to, char *mask)
1418{
1419 char *p;
1420 int i;
Bart De Schuymer41830412002-06-05 19:41:28 +00001421 struct ether_addr *addr;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001422
1423 if (strcasecmp(from, "Unicast") == 0) {
1424 memcpy(to, mac_type_unicast, ETH_ALEN);
1425 memcpy(mask, msk_type_unicast, ETH_ALEN);
1426 return 0;
1427 }
1428 if (strcasecmp(from, "Multicast") == 0) {
1429 memcpy(to, mac_type_multicast, ETH_ALEN);
1430 memcpy(mask, msk_type_multicast, ETH_ALEN);
1431 return 0;
1432 }
1433 if (strcasecmp(from, "Broadcast") == 0) {
1434 memcpy(to, mac_type_broadcast, ETH_ALEN);
1435 memcpy(mask, msk_type_broadcast, ETH_ALEN);
1436 return 0;
1437 }
1438 if ( (p = strrchr(from, '/')) != NULL) {
1439 *p = '\0';
Bart De Schuymer41830412002-06-05 19:41:28 +00001440 if (!(addr = ether_aton(p + 1)))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001441 return -1;
Bart De Schuymer41830412002-06-05 19:41:28 +00001442 memcpy(mask, addr, ETH_ALEN);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001443 } else
1444 memset(mask, 0xff, ETH_ALEN);
Bart De Schuymer41830412002-06-05 19:41:28 +00001445 if (!(addr = ether_aton(from)))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001446 return -1;
Bart De Schuymer41830412002-06-05 19:41:28 +00001447 memcpy(to, addr, ETH_ALEN);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001448 for (i = 0; i < ETH_ALEN; i++)
1449 to[i] &= mask[i];
1450 return 0;
1451}
1452
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +00001453void do_final_checks(struct ebt_u_entry *e, struct ebt_u_entries *entries)
1454{
1455 struct ebt_u_match_list *m_l;
1456 struct ebt_u_watcher_list *w_l;
1457 struct ebt_u_target *t;
1458 struct ebt_u_match *m;
1459 struct ebt_u_watcher *w;
1460
1461 m_l = e->m_list;
1462 w_l = e->w_list;
1463 while (m_l) {
1464 m = find_match(m_l->m->u.name);
1465 m->final_check(e, m_l->m, replace.name,
1466 entries->hook_mask, 1);
1467 m_l = m_l->next;
1468 }
1469 while (w_l) {
1470 w = find_watcher(w_l->w->u.name);
1471 w->final_check(e, w_l->w, replace.name,
1472 entries->hook_mask, 1);
1473 w_l = w_l->next;
1474 }
1475 t = find_target(e->t->u.name);
1476 t->final_check(e, e->t, replace.name,
1477 entries->hook_mask, 1);
1478}
1479
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001480int check_inverse(const char option[])
1481{
1482 if (strcmp(option, "!") == 0) {
1483 optind++;
1484 return 1;
1485 }
1486 return 0;
1487}
1488
1489void check_option(unsigned int *flags, unsigned int mask)
1490{
1491 if (*flags & mask)
1492 print_error("Multiple use of same option not allowed");
1493 *flags |= mask;
1494}
1495
1496#define OPT_COMMAND 0x01
1497#define OPT_TABLE 0x02
1498#define OPT_IN 0x04
1499#define OPT_OUT 0x08
1500#define OPT_JUMP 0x10
1501#define OPT_PROTOCOL 0x20
1502#define OPT_SOURCE 0x40
1503#define OPT_DEST 0x80
1504#define OPT_ZERO 0x100
1505#define OPT_LOGICALIN 0x200
1506#define OPT_LOGICALOUT 0x400
1507// the main thing
1508int main(int argc, char *argv[])
1509{
1510 char *buffer, allowbc = 'n';
1511 int c, i;
1512 // this special one for the -Z option (we can have -Z <this> -L <that>)
1513 int zerochain = -1;
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001514 int policy;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001515 int rule_nr = -1;// used for -D chain number
1516 struct ebt_u_target *t;
1517 struct ebt_u_match *m;
1518 struct ebt_u_watcher *w;
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +00001519 struct ebt_u_match_list *m_l;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001520 struct ebt_u_watcher_list *w_l;
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +00001521 struct ebt_u_entries *entries;
Bart De Schuymerc8531032002-06-14 21:55:29 +00001522 const char *modprobe = NULL;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001523
1524 // initialize the table name, OPT_ flags, selected hook and command
1525 strcpy(replace.name, "filter");
1526 replace.flags = 0;
1527 replace.selected_hook = -1;
1528 replace.command = 'h';
1529
1530 new_entry = (struct ebt_u_entry *)malloc(sizeof(struct ebt_u_entry));
1531 if (!new_entry)
1532 print_memory();
1533 // put some sane values in our new entry
1534 initialize_entry(new_entry);
1535
Bart De Schuymer60332e02002-06-23 08:01:47 +00001536 // The scenario induced by this loop makes that:
1537 // '-t' and '-M' (if specified) have to come before '-A' and the like
1538
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001539 // getopt saves the day
1540 while ((c = getopt_long(argc, argv,
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001541 "-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 +00001542 switch (c) {
1543
1544 case 'A': // add a rule
1545 case 'D': // delete a rule
1546 case 'P': // define policy
1547 case 'I': // insert a rule
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001548 case 'N': // make a user defined chain
1549 case 'E': // rename chain
1550 case 'X': // delete chain
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001551 replace.command = c;
1552 if (replace.flags & OPT_COMMAND)
1553 print_error("Multiple commands not allowed");
1554 replace.flags |= OPT_COMMAND;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001555 if ( !(table = find_table(replace.name)) )
1556 print_error("Bad table name");
1557 // get the kernel's information
1558 if (get_table(&replace)) {
1559 ebtables_insmod("ebtables", modprobe);
1560 if (get_table(&replace))
1561 print_error("can't initialize ebtables "
1562 "table %s", replace.name);
1563 }
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001564 if (c == 'N') {
1565 struct ebt_u_chain_list *cl, **cl2;
1566
1567 if (get_hooknr(optarg) != -1)
1568 print_error("Chain %s already exists",
1569 optarg);
1570 if (find_target(optarg))
1571 print_error("Target with name %s exists"
1572 , optarg);
1573 if (strlen(optarg) >= EBT_CHAIN_MAXNAMELEN)
1574 print_error("Chain name len can't exceed %d",
1575 EBT_CHAIN_MAXNAMELEN - 1);
1576 cl = (struct ebt_u_chain_list *)
1577 malloc(sizeof(struct ebt_u_chain_list));
1578 if (!cl)
1579 print_memory();
1580 cl->next = NULL;
1581 cl->udc = (struct ebt_u_entries *)
1582 malloc(sizeof(struct ebt_u_entries));
1583 if (!cl->udc)
1584 print_memory();
1585 cl->udc->nentries = 0;
1586 cl->udc->policy = EBT_ACCEPT;
1587 cl->udc->counter_offset = replace.nentries;
1588 cl->udc->hook_mask = 0;
1589 strcpy(cl->udc->name, optarg);
1590 cl->udc->entries = NULL;
1591 cl->kernel_start = NULL;
1592 cl2 = &replace.udc;
1593 while (*cl2)
1594 cl2 = &((*cl2)->next);
1595 *cl2 = cl;
1596 break;
1597 }
1598 if (c == 'E') {
1599 if ((replace.selected_hook = get_hooknr(optarg)) == -1)
1600 print_error("Chain %s doesn't exist", optarg);
1601 if (optind >= argc || argv[optind][0] == '-')
1602 print_error("No new chain name specified");
1603 if (strlen(argv[optind]) >= EBT_CHAIN_MAXNAMELEN)
1604 print_error("Chain name len can't exceed %d",
1605 EBT_CHAIN_MAXNAMELEN - 1);
1606 if (get_hooknr(argv[optind]) != -1)
1607 print_error("Chain %s already exists",
1608 argv[optind]);
1609 entries = to_chain();
1610 strcpy(entries->name, argv[optind]);
1611 optind++;
1612 break;
1613 }
1614 if (c == 'X') {
1615 struct ebt_u_chain_list *cl, **cl2;
1616
1617 if ((replace.selected_hook = get_hooknr(optarg)) == -1)
1618 print_error("Chain %s doesn't exist", optarg);
1619 if (replace.selected_hook < NF_BR_NUMHOOKS)
1620 print_error("You can't remove a standard chain");
1621 flush_chains();
1622 entries = to_chain();
1623 if (replace.udc->udc == entries) {
1624 cl = replace.udc;
1625 replace.udc = replace.udc->next;
1626 free(cl->udc);
1627 free(cl);
1628 break;
1629 }
1630 cl2 = &(replace.udc);
1631 while ((*cl2)->next->udc != entries)
1632 cl2 = &((*cl2)->next);
1633 cl = (*cl2)->next;
1634 (*cl2)->next = (*cl2)->next->next;
1635 free(cl->udc);
1636 free(cl);
1637 break;
1638 }
1639
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001640 if ((replace.selected_hook = get_hooknr(optarg)) == -1)
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001641 print_error("Chain %s doesn't exist", optarg);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001642 if (c == 'D' && optind < argc &&
1643 argv[optind][0] != '-') {
1644 rule_nr = strtol(argv[optind], &buffer, 10);
1645 if (*buffer != '\0' || rule_nr < 0)
1646 print_error("Problem with the "
1647 "specified rule number");
1648 optind++;
1649 }
1650 if (c == 'P') {
1651 if (optind >= argc)
1652 print_error("No policy specified");
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001653 policy = 0;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001654 for (i = 0; i < 4; i++)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001655 if (!strcmp(argv[optind],
1656 standard_targets[i])) {
Bart De Schuymer60332e02002-06-23 08:01:47 +00001657 policy = -i -1;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001658 break;
1659 }
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001660 if (policy == 0)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001661 print_error("Wrong policy");
1662 optind++;
1663 }
1664 if (c == 'I') {
1665 if (optind >= argc)
1666 print_error("No rulenr for -I"
1667 " specified");
1668 rule_nr = strtol(argv[optind], &buffer, 10);
1669 if (*buffer != '\0' || rule_nr < 0)
1670 print_error("Problem with the specified"
1671 " rule number");
1672 optind++;
1673 }
1674 break;
1675
1676 case 'L': // list
1677 case 'F': // flush
1678 case 'Z': // zero counters
1679 if (c == 'Z') {
1680 if (replace.flags & OPT_ZERO)
1681 print_error("Multiple commands"
1682 " not allowed");
1683 if ( (replace.flags & OPT_COMMAND &&
1684 replace.command != 'L'))
1685 print_error("command -Z only allowed "
1686 "together with command -L");
1687 replace.flags |= OPT_ZERO;
1688 } else {
1689 replace.command = c;
1690 if (replace.flags & OPT_COMMAND)
1691 print_error("Multiple commands"
1692 " not allowed");
1693 replace.flags |= OPT_COMMAND;
1694 }
1695 i = -1;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001696 if ( !(table = find_table(replace.name)) )
1697 print_error("Bad table name");
1698 // get the kernel's information
1699 if (get_table(&replace)) {
1700 ebtables_insmod("ebtables", modprobe);
1701 if (get_table(&replace))
1702 print_error("can't initialize ebtables "
1703 "table %s", replace.name);
1704 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001705 if (optarg) {
1706 if ( (i = get_hooknr(optarg)) == -1 )
1707 print_error("Bad chain");
1708 } else
1709 if (optind < argc && argv[optind][0] != '-') {
1710 if ((i = get_hooknr(argv[optind]))
1711 == -1)
1712 print_error("Bad chain");
1713 optind++;
1714 }
1715 if (i != -1) {
1716 if (c == 'Z')
1717 zerochain = i;
1718 else
1719 replace.selected_hook = i;
1720 }
1721 break;
1722
1723 case 'V': // version
1724 replace.command = 'V';
1725 if (replace.flags & OPT_COMMAND)
1726 print_error("Multiple commands not allowed");
1727 printf("%s, %s\n", prog_name, prog_version);
1728 exit(0);
1729
Bart De Schuymerc8531032002-06-14 21:55:29 +00001730 case 'M': // modprobe
Bart De Schuymer60332e02002-06-23 08:01:47 +00001731 if (replace.command != 'h')
1732 print_error("Please put the -M option earlier");
Bart De Schuymerc8531032002-06-14 21:55:29 +00001733 modprobe = optarg;
1734 break;
1735
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001736 case 'h': // help
1737 if (replace.flags & OPT_COMMAND)
1738 print_error("Multiple commands not allowed");
1739 replace.command = 'h';
1740 // All other arguments should be extension names
1741 while (optind < argc) {
1742 struct ebt_u_match *m;
1743 struct ebt_u_watcher *w;
1744
1745 if ((m = find_match(argv[optind])))
1746 add_match(m);
1747 else if ((w = find_watcher(argv[optind])))
1748 add_watcher(w);
1749 else {
1750 if (!(t = find_target(argv[optind])))
1751 print_error("Extension %s "
1752 "not found", argv[optind]);
1753 if (replace.flags & OPT_JUMP)
1754 print_error("Sorry, you can "
1755 "only see help for one "
1756 "target extension each time");
1757 replace.flags |= OPT_JUMP;
1758 new_entry->t =
1759 (struct ebt_entry_target *)t;
1760 }
1761 optind++;
1762 }
1763 break;
1764
1765 case 't': // table
Bart De Schuymer60332e02002-06-23 08:01:47 +00001766 if (replace.command != 'h')
1767 print_error("Please put the -t option first");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001768 check_option(&replace.flags, OPT_TABLE);
1769 if (strlen(optarg) > EBT_TABLE_MAXNAMELEN)
1770 print_error("Table name too long");
1771 strcpy(replace.name, optarg);
1772 break;
1773
1774 case 'i': // input interface
1775 case 2 : // logical input interface
1776 case 'o': // output interface
1777 case 3 : // logical output interface
1778 case 'j': // target
1779 case 'p': // net family protocol
1780 case 's': // source mac
1781 case 'd': // destination mac
1782 if ((replace.flags & OPT_COMMAND) == 0)
1783 print_error("No command specified");
1784 if ( replace.command != 'A' &&
1785 replace.command != 'D' && replace.command != 'I')
1786 print_error("Command and option do not match");
1787 if (c == 'i') {
1788 check_option(&replace.flags, OPT_IN);
1789 if (replace.selected_hook > 2 &&
1790 replace.selected_hook < NF_BR_BROUTING)
1791 print_error("Use in-interface only in "
1792 "INPUT, FORWARD, PREROUTING and"
1793 "BROUTING chains");
1794 if (check_inverse(optarg))
1795 new_entry->invflags |= EBT_IIN;
1796
1797 if (optind > argc)
1798 print_error("No in-interface "
1799 "specified");
1800 if (strlen(argv[optind - 1]) >= IFNAMSIZ)
1801 print_error("Illegal interfacelength");
1802 strcpy(new_entry->in, argv[optind - 1]);
1803 break;
1804 }
1805 if (c == 2) {
1806 check_option(&replace.flags, OPT_LOGICALIN);
1807 if (replace.selected_hook > 2 &&
1808 replace.selected_hook < NF_BR_BROUTING)
1809 print_error("Use logical in-interface "
1810 "only in INPUT, FORWARD, "
1811 "PREROUTING and BROUTING chains");
1812 if (check_inverse(optarg))
1813 new_entry->invflags |= EBT_ILOGICALIN;
1814
1815 if (optind > argc)
1816 print_error("No logical in-interface "
1817 "specified");
1818 if (strlen(argv[optind - 1]) >= IFNAMSIZ)
1819 print_error("Illegal interfacelength");
1820 strcpy(new_entry->logical_in, argv[optind - 1]);
1821 break;
1822 }
1823 if (c == 'o') {
1824 check_option(&replace.flags, OPT_OUT);
1825 if (replace.selected_hook < 2)
1826 print_error("Use out-interface only"
1827 " in OUTPUT, FORWARD and "
1828 "POSTROUTING chains");
1829 if (check_inverse(optarg))
1830 new_entry->invflags |= EBT_IOUT;
1831
1832 if (optind > argc)
1833 print_error("No out-interface "
1834 "specified");
1835
1836 if (strlen(argv[optind - 1]) >= IFNAMSIZ)
1837 print_error("Illegal interface "
1838 "length");
1839 strcpy(new_entry->out, argv[optind - 1]);
1840 break;
1841 }
1842 if (c == 3) {
1843 check_option(&replace.flags, OPT_LOGICALOUT);
1844 if (replace.selected_hook < 2)
1845 print_error("Use logical out-interface "
1846 "only in OUTPUT, FORWARD and "
1847 "POSTROUTING chains");
1848 if (check_inverse(optarg))
1849 new_entry->invflags |= EBT_ILOGICALOUT;
1850
1851 if (optind > argc)
1852 print_error("No logical out-interface "
1853 "specified");
1854
1855 if (strlen(argv[optind - 1]) >= IFNAMSIZ)
1856 print_error("Illegal interface "
1857 "length");
1858 strcpy(new_entry->logical_out,
1859 argv[optind - 1]);
1860 break;
1861 }
1862 if (c == 'j') {
1863
1864 check_option(&replace.flags, OPT_JUMP);
1865 for (i = 0; i < NUM_STANDARD_TARGETS; i++)
1866 if (!strcmp(optarg,
1867 standard_targets[i])) {
1868 t = find_target(
1869 EBT_STANDARD_TARGET);
1870 ((struct ebt_standard_target *)
Bart De Schuymer60332e02002-06-23 08:01:47 +00001871 t->t)->verdict = -i - 1;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001872 break;
1873 }
Bart De Schuymer60332e02002-06-23 08:01:47 +00001874 if (-i - 1 == EBT_RETURN) {
1875 if (replace.selected_hook < NF_BR_NUMHOOKS)
1876 print_error("Return target"
1877 " only for user defined chains");
1878 }
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +00001879 if (i != NUM_STANDARD_TARGETS)
1880 break;
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001881 if ((i = get_hooknr(optarg)) != -1) {
1882 if (i < NF_BR_NUMHOOKS)
1883 print_error("don't jump"
1884 " to a standard chain");
1885 t = find_target(
1886 EBT_STANDARD_TARGET);
1887 ((struct ebt_standard_target *)
1888 t->t)->verdict = i - NF_BR_NUMHOOKS;
1889 break;
1890 }
1891 else {
1892 // must be an extension then
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001893 struct ebt_u_target *t;
1894 t = find_target(optarg);
1895 // -j standard not allowed either
1896 if (!t || t ==
1897 (struct ebt_u_target *)new_entry->t)
1898 print_error("Illegal target "
1899 "name");
1900 new_entry->t =
1901 (struct ebt_entry_target *)t;
1902 }
1903 break;
1904 }
1905 if (c == 's') {
1906 check_option(&replace.flags, OPT_SOURCE);
1907 if (check_inverse(optarg))
1908 new_entry->invflags |= EBT_ISOURCE;
1909
1910 if (optind > argc)
1911 print_error("No source mac "
1912 "specified");
1913 if (getmac_and_mask(argv[optind - 1],
1914 new_entry->sourcemac, new_entry->sourcemsk))
1915 print_error("Problem with specified "
1916 "source mac");
1917 new_entry->bitmask |= EBT_SOURCEMAC;
1918 break;
1919 }
1920 if (c == 'd') {
1921 check_option(&replace.flags, OPT_DEST);
1922 if (check_inverse(optarg))
1923 new_entry->invflags |= EBT_IDEST;
1924
1925 if (optind > argc)
1926 print_error("No destination mac "
1927 "specified");
1928 if (getmac_and_mask(argv[optind - 1],
1929 new_entry->destmac, new_entry->destmsk))
1930 print_error("Problem with specified "
1931 "destination mac");
1932 new_entry->bitmask |= EBT_DESTMAC;
1933 break;
1934 }
1935 check_option(&replace.flags, OPT_PROTOCOL);
1936 if (check_inverse(optarg))
1937 new_entry->invflags |= EBT_IPROTO;
1938
1939 if (optind > argc)
1940 print_error("No protocol specified");
1941 new_entry->bitmask &= ~((unsigned int)EBT_NOPROTO);
1942 i = strtol(argv[optind - 1], &buffer, 16);
1943 if (*buffer == '\0' && (i < 0 || i > 0xFFFF))
1944 print_error("Problem with the specified "
1945 "protocol");
1946 new_entry->ethproto = i;
1947 if (*buffer != '\0')
1948 if (name_to_protocol(argv[optind - 1]) == -1)
1949 print_error("Problem with the specified"
1950 " protocol");
1951 if (new_entry->ethproto < 1536 &&
1952 !(new_entry->bitmask & EBT_802_3))
1953 print_error("Sorry, protocols have values above"
1954 " or equal to 1536 (0x0600)");
1955 break;
1956
1957 case 'b': // allow database?
1958 if (replace.flags & OPT_COMMAND)
1959 print_error("Multiple commands not allowed");
1960 replace.command = c;
1961 allowbc = *optarg;
1962 break;
1963
1964 default:
1965
1966 // is it a target option?
1967 t = (struct ebt_u_target *)new_entry->t;
1968 if ((t->parse(c - t->option_offset, argv, argc,
1969 new_entry, &t->flags, &t->t)))
1970 continue;
1971
1972 // is it a match_option?
1973 for (m = matches; m; m = m->next)
1974 if (m->parse(c - m->option_offset, argv,
1975 argc, new_entry, &m->flags, &m->m))
1976 break;
1977
1978 if (m != NULL) {
1979 if (m->used == 0)
1980 add_match(m);
1981 continue;
1982 }
1983
1984 // is it a watcher option?
1985 for (w = watchers; w; w = w->next)
1986 if (w->parse(c-w->option_offset, argv,
1987 argc, new_entry, &w->flags, &w->w))
1988 break;
1989
1990 if (w == NULL)
1991 print_error("Unknown argument");
Bart De Schuymer60332e02002-06-23 08:01:47 +00001992 if (replace.command != 'A' && replace.command != 'I' &&
1993 replace.command != 'D')
1994 print_error("extensions only for -A, -I and -D");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001995 if (w->used == 0)
1996 add_watcher(w);
1997 }
1998 }
1999
Bart De Schuymer25c741d2002-06-23 18:54:34 +00002000 if ( !table && !(table = find_table(replace.name)) )
2001 print_error("Bad table name");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002002 // database stuff before ebtables stuff
2003 if (replace.command == 'b')
2004 allowdb(allowbc);
2005 if (replace.command == 'L' && replace.selected_hook == DATABASEHOOKNR)
2006 list_db();
2007
2008 if ( (replace.flags & OPT_COMMAND) && replace.command != 'L' &&
2009 replace.flags & OPT_ZERO )
2010 print_error("Command -Z only allowed together with command -L");
2011
2012 if (replace.command == 'A' || replace.command == 'I' ||
2013 replace.command == 'D') {
2014 if (replace.selected_hook == -1)
2015 print_error("Not enough information");
2016 }
2017
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002018 // do this after parsing everything, so we can print specific info
2019 if (replace.command == 'h' && !(replace.flags & OPT_ZERO))
2020 print_help();
2021
2022 // do the final checks
Bart De Schuymer60332e02002-06-23 08:01:47 +00002023 if (replace.command == 'A' || replace.command == 'I' ||
2024 replace.command == 'D') {
2025 // this will put the hook_mask right for the chains
2026 check_for_loops();
2027 entries = to_chain();
2028 m_l = new_entry->m_list;
2029 w_l = new_entry->w_list;
2030 t = (struct ebt_u_target *)new_entry->t;
2031 while (m_l) {
2032 m = (struct ebt_u_match *)(m_l->m);
2033 m->final_check(new_entry, m->m, replace.name,
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +00002034 entries->hook_mask, 0);
Bart De Schuymer60332e02002-06-23 08:01:47 +00002035 m_l = m_l->next;
2036 }
2037 while (w_l) {
2038 w = (struct ebt_u_watcher *)(w_l->w);
2039 w->final_check(new_entry, w->w, replace.name,
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +00002040 entries->hook_mask, 0);
Bart De Schuymer60332e02002-06-23 08:01:47 +00002041 w_l = w_l->next;
2042 }
2043 t->final_check(new_entry, t->t, replace.name,
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +00002044 entries->hook_mask, 0);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002045 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002046 // so, the extensions can work with the host endian
2047 // the kernel does not have to do this ofcourse
2048 new_entry->ethproto = htons(new_entry->ethproto);
2049
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002050 if (replace.command == 'P')
2051 change_policy(policy);
2052 else if (replace.command == 'L') {
2053 list_rules();
2054 if (replace.flags & OPT_ZERO)
2055 zero_counters(zerochain);
2056 else
2057 exit(0);
2058 }
2059 if (replace.flags & OPT_ZERO)
2060 zero_counters(zerochain);
Bart De Schuymer1ab41562002-06-23 17:09:54 +00002061 else if (replace.command == 'F') {
2062 if (flush_chains() == -1)
2063 exit(0);
2064 } else if (replace.command == 'A' || replace.command == 'I') {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002065 add_rule(rule_nr);
Bart De Schuymer1ab41562002-06-23 17:09:54 +00002066 check_for_loops();
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +00002067 // do the final_check(), for all entries
2068 // needed when adding a rule that has a chain target
2069 i = -1;
2070 while (1) {
2071 struct ebt_u_entry *e;
2072
2073 i++;
2074 entries = nr_to_chain(i);
2075 if (!entries) {
2076 if (i < NF_BR_NUMHOOKS)
2077 continue;
2078 else
2079 break;
2080 }
2081 e = entries->entries;
2082 while (e) {
2083 // userspace extensions use host endian
2084 e->ethproto = ntohs(e->ethproto);
2085 do_final_checks(e, entries);
2086 e->ethproto = htons(e->ethproto);
2087 e = e->next;
2088 }
2089 }
Bart De Schuymer1ab41562002-06-23 17:09:54 +00002090 } else if (replace.command == 'D')
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002091 delete_rule(rule_nr);
Bart De Schuymer1ab41562002-06-23 17:09:54 +00002092 // commands -N, -E, -X fall through
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002093
2094 if (table->check)
2095 table->check(&replace);
2096
2097 deliver_table(&replace);
2098
2099 if (counterchanges)
2100 deliver_counters(&replace, counterchanges);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002101 return 0;
2102}