blob: 81285253c74a9c2e72a609c24d4252146807242f [file] [log] [blame]
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001/*
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00002 * ebtables.c, v2.0 July 2002
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00003 *
4 * Author: Bart De Schuymer
5 *
6 * This code is stongly inspired on the iptables code which is
7 * Copyright (C) 1999 Paul `Rusty' Russell & Michael J. Neuling
8 *
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License as
11 * published by the Free Software Foundation; either version 2 of the
12 * License, or (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 */
23
24#include <getopt.h>
25#include <string.h>
26#include <errno.h>
27#include <stdio.h>
28#include <stdlib.h>
29#include <sys/socket.h>
30#include <sys/types.h>
31#include <linux/netfilter_bridge/ebtables.h>
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 "include/ebtables_u.h"
Bart De Schuymerc8531032002-06-14 21:55:29 +000036#include <unistd.h>
37#include <fcntl.h>
38#include <sys/wait.h>
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000039
Bart De Schuymerc56a31a2002-07-25 08:16:08 +000040// here are the number-name correspondences kept for the Ethernet
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000041// frame type field
42#define PROTOCOLFILE "/etc/ethertypes"
43
Bart De Schuymerc8531032002-06-14 21:55:29 +000044#ifndef PROC_SYS_MODPROBE
45#define PROC_SYS_MODPROBE "/proc/sys/kernel/modprobe"
46#endif
47
Bart De Schuymer60332e02002-06-23 08:01:47 +000048#define DATABASEHOOKNR -2
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000049#define DATABASEHOOKNAME "DB"
50
51static char *prog_name = PROGNAME;
52static char *prog_version = PROGVERSION;
Bart De Schuymer60332e02002-06-23 08:01:47 +000053char *hooknames[NF_BR_NUMHOOKS] =
54{
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000055 [NF_BR_PRE_ROUTING]"PREROUTING",
56 [NF_BR_LOCAL_IN]"INPUT",
57 [NF_BR_FORWARD]"FORWARD",
58 [NF_BR_LOCAL_OUT]"OUTPUT",
59 [NF_BR_POST_ROUTING]"POSTROUTING",
60 [NF_BR_BROUTING]"BROUTING"
61};
62
63// default command line options
Bart De Schuymer8d1d8942002-07-15 20:09:09 +000064// do not mess around with the already assigned numbers unless
65// you know what you are doing
Bart De Schuymer62423742002-07-14 19:06:20 +000066static struct option ebt_original_options[] =
67{
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000068 { "append" , required_argument, 0, 'A' },
69 { "insert" , required_argument, 0, 'I' },
70 { "delete" , required_argument, 0, 'D' },
71 { "list" , optional_argument, 0, 'L' },
Bart De Schuymer9af14f92002-07-10 20:49:10 +000072 { "Lc" , no_argument , 0, 4 },
73 { "Ln" , no_argument , 0, 5 },
74 { "Lx" , no_argument , 0, 6 },
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000075 { "zero" , optional_argument, 0, 'Z' },
76 { "flush" , optional_argument, 0, 'F' },
77 { "policy" , required_argument, 0, 'P' },
78 { "in-interface" , required_argument, 0, 'i' },
79 { "in-if" , required_argument, 0, 'i' },
80 { "logical-in" , required_argument, 0, 2 },
81 { "logical-out" , required_argument, 0, 3 },
82 { "out-interface" , required_argument, 0, 'o' },
83 { "out-if" , required_argument, 0, 'o' },
84 { "version" , no_argument , 0, 'V' },
85 { "help" , no_argument , 0, 'h' },
86 { "jump" , required_argument, 0, 'j' },
87 { "proto" , required_argument, 0, 'p' },
88 { "protocol" , required_argument, 0, 'p' },
89 { "db" , required_argument, 0, 'b' },
90 { "source" , required_argument, 0, 's' },
91 { "src" , required_argument, 0, 's' },
92 { "destination" , required_argument, 0, 'd' },
93 { "dst" , required_argument, 0, 'd' },
94 { "table" , required_argument, 0, 't' },
Bart De Schuymerc8531032002-06-14 21:55:29 +000095 { "modprobe" , required_argument, 0, 'M' },
Bart De Schuymer1ab41562002-06-23 17:09:54 +000096 { "new-chain" , required_argument, 0, 'N' },
97 { "rename-chain" , required_argument, 0, 'E' },
98 { "delete-chain" , required_argument, 0, 'X' },
Bart De Schuymer62423742002-07-14 19:06:20 +000099 { "atomic-init" , required_argument, 0, 7 },
Bart De Schuymer62423742002-07-14 19:06:20 +0000100 { "atomic-commit" , required_argument, 0, 8 },
101 { "atomic" , required_argument, 0, 9 },
102 { "atomic-save" , required_argument, 0, 10 },
Bart De Schuymer8d1d8942002-07-15 20:09:09 +0000103 { "init-table" , no_argument , 0, 11 },
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000104 { 0 }
105};
106
107static struct option *ebt_options = ebt_original_options;
108
109// yup, all the possible target names
Bart De Schuymer62423742002-07-14 19:06:20 +0000110char* standard_targets[NUM_STANDARD_TARGETS] =
111{
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000112 "ACCEPT",
113 "DROP",
114 "CONTINUE",
Bart De Schuymer60332e02002-06-23 08:01:47 +0000115 "RETURN",
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000116};
117
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000118unsigned char mac_type_unicast[ETH_ALEN] = {0,0,0,0,0,0};
119unsigned char msk_type_unicast[ETH_ALEN] = {1,0,0,0,0,0};
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000120unsigned char mac_type_multicast[ETH_ALEN] = {1,0,0,0,0,0};
121unsigned char msk_type_multicast[ETH_ALEN] = {1,0,0,0,0,0};
122unsigned char mac_type_broadcast[ETH_ALEN] = {255,255,255,255,255,255};
123unsigned char msk_type_broadcast[ETH_ALEN] = {255,255,255,255,255,255};
124
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000125// holds all the data
126static struct ebt_u_replace replace;
127
128// the chosen table
129static struct ebt_u_table *table = NULL;
130// the lists of supported tables, matches, watchers and targets
131static struct ebt_u_table *tables = NULL;
132static struct ebt_u_match *matches = NULL;
133static struct ebt_u_watcher *watchers = NULL;
134static struct ebt_u_target *targets = NULL;
135
136struct ebt_u_target *find_target(const char *name)
137{
138 struct ebt_u_target *t = targets;
139
140 while(t && strcmp(t->name, name))
141 t = t->next;
142 return t;
143}
144
145struct ebt_u_match *find_match(const char *name)
146{
147 struct ebt_u_match *m = matches;
148
149 while(m && strcmp(m->name, name))
150 m = m->next;
151 return m;
152}
153
154struct ebt_u_watcher *find_watcher(const char *name)
155{
156 struct ebt_u_watcher *w = watchers;
157
158 while(w && strcmp(w->name, name))
159 w = w->next;
160 return w;
161}
162
163struct ebt_u_table *find_table(char *name)
164{
165 struct ebt_u_table *t = tables;
166
167 while (t && strcmp(t->name, name))
168 t = t->next;
169 return t;
170}
171
172// The pointers in here are special:
173// The struct ebt_target * pointer is actually a struct ebt_u_target * pointer.
174// instead of making yet a few other structs, we just do a cast.
175// We need a struct ebt_u_target pointer because we know the address of the data
176// they point to won't change. We want to allow that the struct ebt_u_target.t
177// member can change.
178// Same holds for the struct ebt_match and struct ebt_watcher pointers
179struct ebt_u_entry *new_entry;
180
Bart De Schuymer62423742002-07-14 19:06:20 +0000181static void initialize_entry(struct ebt_u_entry *e)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000182{
183 e->bitmask = EBT_NOPROTO;
184 e->invflags = 0;
185 e->ethproto = 0;
186 strcpy(e->in, "");
187 strcpy(e->out, "");
188 strcpy(e->logical_in, "");
189 strcpy(e->logical_out, "");
190 e->m_list = NULL;
191 e->w_list = NULL;
192 // the init function of the standard target should have put the verdict
193 // on CONTINUE
194 e->t = (struct ebt_entry_target *)find_target(EBT_STANDARD_TARGET);
195 if (!e->t)
196 print_bug("Couldn't load standard target\n");
197}
198
199// this doesn't free e, becoz the calling function might need e->next
Bart De Schuymer62423742002-07-14 19:06:20 +0000200static void free_u_entry(struct ebt_u_entry *e)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000201{
202 struct ebt_u_match_list *m_l, *m_l2;
203 struct ebt_u_watcher_list *w_l, *w_l2;
204
205 m_l = e->m_list;
206 while (m_l) {
207 m_l2 = m_l->next;
208 free(m_l->m);
209 free(m_l);
210 m_l = m_l2;
211 }
212 w_l = e->w_list;
213 while (w_l) {
214 w_l2 = w_l->next;
215 free(w_l->w);
216 free(w_l);
217 w_l = w_l2;
218 }
219 free(e->t);
220}
221
222// the user will use the match, so put it in new_entry
223static void add_match(struct ebt_u_match *m)
224{
225 struct ebt_u_match_list **m_list, *new;
226
227 m->used = 1;
Bart De Schuymerc56a31a2002-07-25 08:16:08 +0000228 for (m_list = &new_entry->m_list; *m_list; m_list = &(*m_list)->next);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000229 new = (struct ebt_u_match_list *)
230 malloc(sizeof(struct ebt_u_match_list));
231 if (!new)
232 print_memory();
233 *m_list = new;
234 new->next = NULL;
235 new->m = (struct ebt_entry_match *)m;
236}
237
238static void add_watcher(struct ebt_u_watcher *w)
239{
240 struct ebt_u_watcher_list **w_list;
241 struct ebt_u_watcher_list *new;
242
243 w->used = 1;
Bart De Schuymerc56a31a2002-07-25 08:16:08 +0000244 for (w_list = &new_entry->w_list; *w_list; w_list = &(*w_list)->next);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000245 new = (struct ebt_u_watcher_list *)
246 malloc(sizeof(struct ebt_u_watcher_list));
247 if (!new)
248 print_memory();
249 *w_list = new;
250 new->next = NULL;
251 new->w = (struct ebt_entry_watcher *)w;
252}
253
254static int global_option_offset = 0;
255#define OPTION_OFFSET 256
256static struct option *
257merge_options(struct option *oldopts, const struct option *newopts,
258 unsigned int *options_offset)
259{
260 unsigned int num_old, num_new, i;
261 struct option *merge;
262
263 if (!newopts || !oldopts || !options_offset)
264 print_bug("merge wrong");
265 for (num_old = 0; oldopts[num_old].name; num_old++);
266 for (num_new = 0; newopts[num_new].name; num_new++);
267
268 global_option_offset += OPTION_OFFSET;
269 *options_offset = global_option_offset;
270
271 merge = malloc(sizeof(struct option) * (num_new + num_old + 1));
272 if (!merge)
273 print_memory();
274 memcpy(merge, oldopts, num_old * sizeof(struct option));
275 for (i = 0; i < num_new; i++) {
276 merge[num_old + i] = newopts[i];
277 merge[num_old + i].val += *options_offset;
278 }
279 memset(merge + num_old + num_new, 0, sizeof(struct option));
280 // only free dynamically allocated stuff
281 if (oldopts != ebt_original_options)
282 free(oldopts);
283
284 return merge;
285}
286
287void register_match(struct ebt_u_match *m)
288{
289 int size = m->size + sizeof(struct ebt_entry_match);
290 struct ebt_u_match **i;
291
292 m->m = (struct ebt_entry_match *)malloc(size);
293 if (!m->m)
294 print_memory();
295 strcpy(m->m->u.name, m->name);
296 m->m->match_size = m->size;
297 ebt_options = merge_options
298 (ebt_options, m->extra_ops, &(m->option_offset));
299 m->init(m->m);
300
301 for (i = &matches; *i; i = &((*i)->next));
302 m->next = NULL;
303 *i = m;
304}
305
306void register_watcher(struct ebt_u_watcher *w)
307{
308 int size = w->size + sizeof(struct ebt_entry_watcher);
309 struct ebt_u_watcher **i;
310
311 w->w = (struct ebt_entry_watcher *)malloc(size);
312 if (!w->w)
313 print_memory();
314 strcpy(w->w->u.name, w->name);
315 w->w->watcher_size = w->size;
316 ebt_options = merge_options
317 (ebt_options, w->extra_ops, &(w->option_offset));
318 w->init(w->w);
319
320 for (i = &watchers; *i; i = &((*i)->next));
321 w->next = NULL;
322 *i = w;
323}
324
325void register_target(struct ebt_u_target *t)
326{
327 int size = t->size + sizeof(struct ebt_entry_target);
328 struct ebt_u_target **i;
329
330 t->t = (struct ebt_entry_target *)malloc(size);
331 if (!t->t)
332 print_memory();
333 strcpy(t->t->u.name, t->name);
334 t->t->target_size = t->size;
335 ebt_options = merge_options
336 (ebt_options, t->extra_ops, &(t->option_offset));
337 t->init(t->t);
Bart De Schuymerc56a31a2002-07-25 08:16:08 +0000338
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000339 for (i = &targets; *i; i = &((*i)->next));
340 t->next = NULL;
341 *i = t;
342}
343
344void register_table(struct ebt_u_table *t)
345{
346 t->next = tables;
347 tables = t;
348}
349
Bart De Schuymerc8531032002-06-14 21:55:29 +0000350// blatently stolen (again) from iptables.c userspace program
351// find out where the modprobe utility is located
352static char *get_modprobe(void)
353{
354 int procfile;
355 char *ret;
356
357 procfile = open(PROC_SYS_MODPROBE, O_RDONLY);
358 if (procfile < 0)
359 return NULL;
360
361 ret = malloc(1024);
362 if (ret) {
363 switch (read(procfile, ret, 1024)) {
364 case -1: goto fail;
365 case 1024: goto fail; /* Partial read. Wierd */
366 }
367 if (ret[strlen(ret)-1]=='\n')
368 ret[strlen(ret)-1]=0;
369 close(procfile);
370 return ret;
371 }
372 fail:
373 free(ret);
374 close(procfile);
375 return NULL;
376}
377
Bart De Schuymerc8531032002-06-14 21:55:29 +0000378int ebtables_insmod(const char *modname, const char *modprobe)
379{
380 char *buf = NULL;
381 char *argv[3];
382
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000383 // If they don't explicitly set it, read out of kernel
Bart De Schuymerc8531032002-06-14 21:55:29 +0000384 if (!modprobe) {
385 buf = get_modprobe();
386 if (!buf)
387 return -1;
388 modprobe = buf;
389 }
390
391 switch (fork()) {
392 case 0:
393 argv[0] = (char *)modprobe;
394 argv[1] = (char *)modname;
395 argv[2] = NULL;
396 execv(argv[0], argv);
397
398 /* not usually reached */
399 exit(0);
400 case -1:
401 return -1;
402
403 default: /* parent */
404 wait(NULL);
405 }
406
407 free(buf);
408 return 0;
409}
410
Bart De Schuymerbbca3202002-06-05 18:55:44 +0000411// helper function: processes a line of data from the file /etc/ethertypes
Bart De Schuymer62423742002-07-14 19:06:20 +0000412static int get_a_line(char *buffer, char *value, FILE *ifp)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000413{
Bart De Schuymerf662ce52002-07-19 18:40:55 +0000414 char line[80], *p;
415 const char delim[] = " \t\n";
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000416
Bart De Schuymerf662ce52002-07-19 18:40:55 +0000417 while (fgets(line, sizeof(line), ifp)) {
418 p = strtok(line, delim);
419 if (!p || p[0] == '#')
420 continue;
421 if (strlen(p) > 20)
422 continue;
423 strcpy(buffer, p);
424 p = strtok(NULL, delim);
425 if (!p || strlen(p) > 10)
426 continue;
427 strcpy(value, p);
428 return 0;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000429 }
Bart De Schuymerf662ce52002-07-19 18:40:55 +0000430 return -1;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000431}
432
Bart De Schuymerb909f9b2002-06-26 18:35:31 +0000433// translate a hexadecimal number to a protocol name, parsing /etc/ethertypes
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000434// returns 0 on success
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000435int number_to_name(unsigned short proto, char *name)
436{
437 FILE *ifp;
Bart De Schuymerf662ce52002-07-19 18:40:55 +0000438 char buffer[21], value[11], *bfr;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000439 unsigned short i;
440
441 if ( !(ifp = fopen(PROTOCOLFILE, "r")) )
442 return -1;
443 while (1) {
444 if (get_a_line(buffer, value, ifp)) {
445 fclose(ifp);
446 return -1;
447 }
448 i = (unsigned short) strtol(value, &bfr, 16);
449 if (*bfr != '\0' || i != proto)
450 continue;
451 strcpy(name, buffer);
452 fclose(ifp);
453 return 0;
454 }
455}
456
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000457// we use replace.flags, so we can't use the following values:
458// 0x01 == OPT_COMMAND, 0x02 == OPT_TABLE, 0x100 == OPT_ZERO
459#define LIST_N 0x04
460#define LIST_C 0x08
461#define LIST_X 0x10
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000462// helper function for list_rules()
Bart De Schuymer60332e02002-06-23 08:01:47 +0000463static void list_em(struct ebt_u_entries *entries)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000464{
465 int i, j, space = 0, digits;
466 struct ebt_u_entry *hlp;
467 struct ebt_u_match_list *m_l;
468 struct ebt_u_watcher_list *w_l;
469 struct ebt_u_match *m;
470 struct ebt_u_watcher *w;
471 struct ebt_u_target *t;
472 char name[21];
473
Bart De Schuymer60332e02002-06-23 08:01:47 +0000474 hlp = entries->entries;
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000475 if (replace.flags & LIST_X && entries->policy != EBT_ACCEPT) {
476 printf("ebtables -t %s -P %s %s\n", replace.name,
477 entries->name, standard_targets[-entries->policy - 1]);
478 } else if (!(replace.flags & LIST_X)) {
479 printf("\nBridge chain: %s\nPolicy: %s\n", entries->name,
480 standard_targets[-entries->policy - 1]);
481 printf("nr. of entries: %d \n", entries->nentries);
482 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000483
Bart De Schuymer60332e02002-06-23 08:01:47 +0000484 i = entries->nentries;
Bart De Schuymerf8f8f292002-06-25 15:43:57 +0000485 while (i > 9) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000486 space++;
487 i /= 10;
488 }
489
Bart De Schuymer60332e02002-06-23 08:01:47 +0000490 for (i = 0; i < entries->nentries; i++) {
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000491 if (replace.flags & LIST_N) {
492 digits = 0;
493 // A little work to get nice rule numbers.
494 j = i + 1;
495 while (j > 9) {
496 digits++;
497 j /= 10;
498 }
499 for (j = 0; j < space - digits; j++)
500 printf(" ");
501 printf("%d. ", i + 1);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000502 }
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000503 if (replace.flags & LIST_X)
504 printf("ebtables -t %s -A %s ",
505 replace.name, entries->name);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000506
507 // Don't print anything about the protocol if no protocol was
508 // specified, obviously this means any protocol will do.
509 if (!(hlp->bitmask & EBT_NOPROTO)) {
Bart De Schuymer60332e02002-06-23 08:01:47 +0000510 printf("-p ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000511 if (hlp->invflags & EBT_IPROTO)
512 printf("! ");
513 if (hlp->bitmask & EBT_802_3)
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000514 printf("Length ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000515 else {
516 if (number_to_name(ntohs(hlp->ethproto), name))
Bart De Schuymer60332e02002-06-23 08:01:47 +0000517 printf("0x%x ", ntohs(hlp->ethproto));
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000518 else
Bart De Schuymer60332e02002-06-23 08:01:47 +0000519 printf("%s ", name);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000520 }
521 }
522 if (hlp->bitmask & EBT_SOURCEMAC) {
523 char hlpmsk[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
524
Bart De Schuymer60332e02002-06-23 08:01:47 +0000525 printf("-s ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000526 if (hlp->invflags & EBT_ISOURCE)
527 printf("! ");
528 if (!memcmp(hlp->sourcemac, mac_type_unicast, 6) &&
529 !memcmp(hlp->sourcemsk, msk_type_unicast, 6)) {
530 printf("Unicast");
531 goto endsrc;
532 }
533 if (!memcmp(hlp->sourcemac, mac_type_multicast, 6) &&
534 !memcmp(hlp->sourcemsk, msk_type_multicast, 6)) {
535 printf("Multicast");
536 goto endsrc;
537 }
538 if (!memcmp(hlp->sourcemac, mac_type_broadcast, 6) &&
539 !memcmp(hlp->sourcemsk, msk_type_broadcast, 6)) {
540 printf("Broadcast");
541 goto endsrc;
542 }
Bart De Schuymer41830412002-06-05 19:41:28 +0000543 printf("%s", ether_ntoa((struct ether_addr *)
544 hlp->sourcemac));
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000545 if (memcmp(hlp->sourcemsk, hlpmsk, 6)) {
546 printf("/");
Bart De Schuymer41830412002-06-05 19:41:28 +0000547 printf("%s", ether_ntoa((struct ether_addr *)
548 hlp->sourcemsk));
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000549 }
550endsrc:
Bart De Schuymer60332e02002-06-23 08:01:47 +0000551 printf(" ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000552 }
553 if (hlp->bitmask & EBT_DESTMAC) {
554 char hlpmsk[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
555
Bart De Schuymer60332e02002-06-23 08:01:47 +0000556 printf("-d ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000557 if (hlp->invflags & EBT_IDEST)
558 printf("! ");
559 if (!memcmp(hlp->destmac, mac_type_unicast, 6) &&
560 !memcmp(hlp->destmsk, msk_type_unicast, 6)) {
561 printf("Unicast");
562 goto enddst;
563 }
564 if (!memcmp(hlp->destmac, mac_type_multicast, 6) &&
565 !memcmp(hlp->destmsk, msk_type_multicast, 6)) {
566 printf("Multicast");
567 goto enddst;
568 }
569 if (!memcmp(hlp->destmac, mac_type_broadcast, 6) &&
570 !memcmp(hlp->destmsk, msk_type_broadcast, 6)) {
571 printf("Broadcast");
572 goto enddst;
573 }
Bart De Schuymer41830412002-06-05 19:41:28 +0000574 printf("%s", ether_ntoa((struct ether_addr *)
575 hlp->destmac));
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000576 if (memcmp(hlp->destmsk, hlpmsk, 6)) {
577 printf("/");
Bart De Schuymer41830412002-06-05 19:41:28 +0000578 printf("%s", ether_ntoa((struct ether_addr *)
579 hlp->destmsk));
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000580 }
581enddst:
Bart De Schuymer60332e02002-06-23 08:01:47 +0000582 printf(" ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000583 }
584 if (hlp->in[0] != '\0') {
Bart De Schuymer60332e02002-06-23 08:01:47 +0000585 printf("-i ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000586 if (hlp->invflags & EBT_IIN)
587 printf("! ");
Bart De Schuymer60332e02002-06-23 08:01:47 +0000588 printf("%s ", hlp->in);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000589 }
590 if (hlp->logical_in[0] != '\0') {
Bart De Schuymer60332e02002-06-23 08:01:47 +0000591 printf("--logical-in ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000592 if (hlp->invflags & EBT_ILOGICALIN)
593 printf("! ");
Bart De Schuymer60332e02002-06-23 08:01:47 +0000594 printf("%s ", hlp->logical_in);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000595 }
596 if (hlp->logical_out[0] != '\0') {
Bart De Schuymer60332e02002-06-23 08:01:47 +0000597 printf("--logical-out ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000598 if (hlp->invflags & EBT_ILOGICALOUT)
599 printf("! ");
Bart De Schuymerb3d8f262002-07-07 14:26:15 +0000600 printf("%s ", hlp->logical_out);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000601 }
602 if (hlp->out[0] != '\0') {
Bart De Schuymer60332e02002-06-23 08:01:47 +0000603 printf("-o ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000604 if (hlp->invflags & EBT_IOUT)
605 printf("! ");
Bart De Schuymerb3d8f262002-07-07 14:26:15 +0000606 printf("%s ", hlp->out);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000607 }
608
609 m_l = hlp->m_list;
610 while (m_l) {
611 m = find_match(m_l->m->u.name);
612 if (!m)
613 print_bug("Match not found");
614 m->print(hlp, m_l->m);
615 m_l = m_l->next;
616 }
617 w_l = hlp->w_list;
618 while (w_l) {
619 w = find_watcher(w_l->w->u.name);
620 if (!w)
621 print_bug("Watcher not found");
622 w->print(hlp, w_l->w);
623 w_l = w_l->next;
624 }
625
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000626 printf("-j ");
627 if (strcmp(hlp->t->u.name, EBT_STANDARD_TARGET))
628 printf("%s ", hlp->t->u.name);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000629 t = find_target(hlp->t->u.name);
630 if (!t)
631 print_bug("Target not found");
632 t->print(hlp, hlp->t);
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000633 if (replace.flags & LIST_C)
634 printf(", count = %llu",
635 replace.counters[entries->counter_offset + i].pcnt);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000636 printf("\n");
637 hlp = hlp->next;
638 }
639}
640
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000641struct ebt_u_entries *nr_to_chain(int nr)
Bart De Schuymer60332e02002-06-23 08:01:47 +0000642{
643 if (nr == -1)
644 return NULL;
645 if (nr < NF_BR_NUMHOOKS)
646 return replace.hook_entry[nr];
647 else {
648 int i;
649 struct ebt_u_chain_list *cl = replace.udc;
650
651 i = nr - NF_BR_NUMHOOKS;
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000652 while (i > 0 && cl) {
Bart De Schuymer60332e02002-06-23 08:01:47 +0000653 cl = cl->next;
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000654 i--;
655 }
Bart De Schuymer60332e02002-06-23 08:01:47 +0000656 if (cl)
657 return cl->udc;
658 else
659 return NULL;
660 }
661}
662
663static struct ebt_u_entries *to_chain()
664{
665 return nr_to_chain(replace.selected_hook);
666}
667
668struct ebt_u_stack
669{
670 int chain_nr;
671 int n;
672 struct ebt_u_entry *e;
673 struct ebt_u_entries *entries;
674};
675
Bart De Schuymer62423742002-07-14 19:06:20 +0000676static void check_for_loops()
Bart De Schuymer60332e02002-06-23 08:01:47 +0000677{
678 int chain_nr , i, j , k, sp = 0, verdict;
679 struct ebt_u_entries *entries, *entries2;
680 struct ebt_u_stack *stack = NULL;
681 struct ebt_u_entry *e;
682
683 i = -1;
684 // initialize hook_mask to 0
685 while (1) {
686 i++;
687 if (i < NF_BR_NUMHOOKS && !(replace.valid_hooks & (1 << i)))
688 continue;
689 entries = nr_to_chain(i);
690 if (!entries)
691 break;
692 entries->hook_mask = 0;
693 }
694 if (i > NF_BR_NUMHOOKS) {
695 stack = (struct ebt_u_stack *)malloc((i - NF_BR_NUMHOOKS) *
696 sizeof(struct ebt_u_stack));
697 if (!stack)
698 print_memory();
699 }
700
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000701 // check for loops, starting from every base chain
Bart De Schuymer60332e02002-06-23 08:01:47 +0000702 for (i = 0; i < NF_BR_NUMHOOKS; i++) {
703 if (!(replace.valid_hooks & (1 << i)))
704 continue;
705 entries = nr_to_chain(i);
Bart De Schuymerb26649e2002-07-25 14:51:54 +0000706 // (1 << NF_BR_NUMHOOKS) implies it's a standard chain
707 // (usefull in the final_check() funtions)
708 entries->hook_mask = (1 << i) | (1 << NF_BR_NUMHOOKS);
Bart De Schuymer60332e02002-06-23 08:01:47 +0000709 chain_nr = i;
710
711 e = entries->entries;
712 for (j = 0; j < entries->nentries; j++) {
713 if (strcmp(e->t->u.name, EBT_STANDARD_TARGET))
714 goto letscontinue;
715 verdict = ((struct ebt_standard_target *)(e->t))->verdict;
716 if (verdict < 0)
717 goto letscontinue;
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000718 entries2 = nr_to_chain(verdict + NF_BR_NUMHOOKS);
Bart De Schuymer60332e02002-06-23 08:01:47 +0000719 entries2->hook_mask |= entries->hook_mask;
720 // now see if we've been here before
721 for (k = 0; k < sp; k++)
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000722 if (stack[k].chain_nr == verdict + NF_BR_NUMHOOKS)
Bart De Schuymer1a0a9c32002-06-24 21:10:16 +0000723 print_error("Loop from chain %s to chain %s",
Bart De Schuymerc56a31a2002-07-25 08:16:08 +0000724 nr_to_chain(chain_nr)->name,
725 nr_to_chain(stack[k].chain_nr)->name);
Bart De Schuymer60332e02002-06-23 08:01:47 +0000726 // jump to the chain, make sure we know how to get back
727 stack[sp].chain_nr = chain_nr;
728 stack[sp].n = j;
729 stack[sp].entries = entries;
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000730 stack[sp].e = e;
731 sp++;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000732 j = -1;
733 e = entries2->entries;
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000734 chain_nr = verdict + NF_BR_NUMHOOKS;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000735 entries = entries2;
736 continue;
737letscontinue:
738 e = e->next;
739 }
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000740 // we are at the end of a standard chain
Bart De Schuymer60332e02002-06-23 08:01:47 +0000741 if (sp == 0)
742 continue;
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000743 // go back to the chain one level higher
Bart De Schuymer60332e02002-06-23 08:01:47 +0000744 sp--;
745 j = stack[sp].n;
746 chain_nr = stack[sp].chain_nr;
747 e = stack[sp].e;
748 entries = stack[sp].entries;
749 goto letscontinue;
750 }
751 free(stack);
752 return;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000753}
754
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000755// parse the chain name and return the corresponding nr
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000756// returns -1 on failure
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000757int get_hooknr(char* arg)
758{
759 int i;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000760 struct ebt_u_chain_list *cl = replace.udc;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000761
762 // database is special case (not really a chain)
763 if (!strcmp(arg, DATABASEHOOKNAME))
764 return DATABASEHOOKNR;
765
Bart De Schuymer60332e02002-06-23 08:01:47 +0000766 for (i = 0; i < NF_BR_NUMHOOKS; i++) {
767 if (!(replace.valid_hooks & (1 << i)))
768 continue;
769 if (!strcmp(arg, replace.hook_entry[i]->name))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000770 return i;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000771 }
772 while(cl) {
773 if (!strcmp(arg, cl->udc->name))
774 return i;
775 i++;
776 cl = cl->next;
777 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000778 return -1;
779}
780
781// yup, print out help
Bart De Schuymer62423742002-07-14 19:06:20 +0000782static void print_help()
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000783{
784 struct ebt_u_match_list *m_l;
785 struct ebt_u_watcher_list *w_l;
786
787 printf(
788"%s v%s\n"
789"Usage:\n"
790"ebtables -[ADI] chain rule-specification [options]\n"
791"ebtables -P chain target\n"
792"ebtables -[LFZ] [chain]\n"
793"ebtables -[b] [y,n]\n"
794"Commands:\n"
795"--append -A chain : Append to chain\n"
796"--delete -D chain : Delete matching rule from chain\n"
797"--delete -D chain rulenum : Delete rule at position rulenum from chain\n"
798"--insert -I chain rulenum : insert rule at position rulenum in chain\n"
799"--list -L [chain] : List the rules in a chain or in all chains\n"
800"--list -L "DATABASEHOOKNAME" : List the database (if present)\n"
801"--flush -F [chain] : Delete all rules in chain or in all chains\n"
Bart De Schuymer8d1d8942002-07-15 20:09:09 +0000802"--init-table : Replace the kernel table with the initial table\n"
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000803"--zero -Z [chain] : Put counters on zero in chain or in all chains\n"
804"--policy -P chain target : Change policy on chain to target\n"
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000805"--new-chain -N chain : Create a user defined chain\n"
806"--rename-chain -E old new : Rename a chain\n"
807"--delete-chain -X chain : Delete a user defined chain\n"
Bart De Schuymer62423742002-07-14 19:06:20 +0000808"--atomic-commit file : update the kernel w/ the table contained in file\n"
809"--atomic-init file : put the initial kernel table into file\n"
810"--atomic-save file : put the current kernel table into file\n"
811"--atomic file : write changes to file instead of kernel\n"
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000812"Options:\n"
813"--proto -p [!] proto : protocol hexadecimal, by name or LENGTH\n"
814"--src -s [!] address[/mask]: source mac address\n"
815"--dst -d [!] address[/mask]: destination mac address\n"
816"--in-if -i [!] name : network input interface name\n"
817"--out-if -o [!] name : network output interface name\n"
818"--logical-in [!] name : logical bridge input interface name\n"
819"--logical-out [!] name : logical bridge output interface name\n"
Bart De Schuymer5cbc8e02002-07-14 21:15:28 +0000820"--modprobe -M program : try to insert modules using this program\n"
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000821"--version -V : print package version\n"
822"\n" ,
823 prog_name,
824 prog_version);
825
826 m_l = new_entry->m_list;
827 while (m_l) {
828 ((struct ebt_u_match *)m_l->m)->help();
829 printf("\n");
830 m_l = m_l->next;
831 }
832 w_l = new_entry->w_list;
833 while (w_l) {
834 ((struct ebt_u_watcher *)w_l->w)->help();
835 printf("\n");
836 w_l = w_l->next;
837 }
838 ((struct ebt_u_target *)new_entry->t)->help();
839 printf("\n");
840 if (table->help)
841 table->help(hooknames);
842 exit(0);
843}
844
845// execute command L
846static void list_rules()
847{
848 int i;
849
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000850 if (!(replace.flags & LIST_X))
851 printf("Bridge table: %s\n", table->name);
Bart De Schuymer60332e02002-06-23 08:01:47 +0000852 if (replace.selected_hook != -1) {
853 list_em(to_chain());
854 } else {
855 struct ebt_u_chain_list *cl = replace.udc;
856
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000857 // create new chains and rename standard chains when necessary
858 if (replace.flags & LIST_X) {
859 while (cl) {
860 printf("ebtables -t %s -N %s\n", replace.name,
861 cl->udc->name);
862 cl = cl->next;
863 }
864 cl = replace.udc;
865 for (i = 0; i < NF_BR_NUMHOOKS; i++)
866 if (replace.valid_hooks & (1 << i) &&
867 strcmp(replace.hook_entry[i]->name, hooknames[i]))
868 printf("ebtables -t %s -E %s %s\n",
869 replace.name, hooknames[i],
870 replace.hook_entry[i]->name);
871 }
Bart De Schuymer60332e02002-06-23 08:01:47 +0000872 i = 0;
873 while (1) {
874 if (i < NF_BR_NUMHOOKS) {
875 if (replace.valid_hooks & (1 << i))
876 list_em(replace.hook_entry[i]);
877 i++;
878 continue;
879 } else {
880 if (!cl)
881 break;
882 list_em(cl->udc);
883 cl = cl->next;
884 }
885 }
886 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000887}
888
889// execute command P
890static void change_policy(int policy)
891{
892 int i;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000893 struct ebt_u_entries *entries = to_chain();
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000894
895 // don't do anything if the policy is the same
Bart De Schuymer60332e02002-06-23 08:01:47 +0000896 if (entries->policy != policy) {
897 entries->policy = policy;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000898 replace.num_counters = replace.nentries;
899 if (replace.nentries) {
900 // '+ 1' for the CNT_END
Bart De Schuymered053432002-07-21 19:35:39 +0000901 if (!(replace.counterchanges = (unsigned short *) malloc(
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000902 (replace.nentries + 1) * sizeof(unsigned short))))
903 print_memory();
904 // done nothing special to the rules
905 for (i = 0; i < replace.nentries; i++)
Bart De Schuymered053432002-07-21 19:35:39 +0000906 replace.counterchanges[i] = CNT_NORM;
907 replace.counterchanges[replace.nentries] = CNT_END;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000908 }
909 else
Bart De Schuymered053432002-07-21 19:35:39 +0000910 replace.counterchanges = NULL;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000911 }
912 else
913 exit(0);
914}
915
916// flush one chain or the complete table
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000917// -1 == nothing to do
918// 0 == give back to kernel
919static int flush_chains()
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000920{
Bart De Schuymer60332e02002-06-23 08:01:47 +0000921 int i, j, oldnentries, numdel;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000922 unsigned short *cnt;
923 struct ebt_u_entry *u_e, *tmp;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000924 struct ebt_u_entries *entries = to_chain();
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000925
926 // flush whole table
Bart De Schuymer60332e02002-06-23 08:01:47 +0000927 if (!entries) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000928 if (replace.nentries == 0)
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000929 return -1;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000930 replace.nentries = 0;
931 // no need for the kernel to give us counters back
932 replace.num_counters = 0;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000933
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000934 // free everything and zero (n)entries
Bart De Schuymer60332e02002-06-23 08:01:47 +0000935 i = -1;
936 while (1) {
937 i++;
938 entries = nr_to_chain(i);
939 if (!entries) {
940 if (i < NF_BR_NUMHOOKS)
941 continue;
942 else
943 break;
944 }
945 entries->nentries = 0;
946 entries->counter_offset = 0;
947 u_e = entries->entries;
948 entries->entries = NULL;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000949 while (u_e) {
950 free_u_entry(u_e);
951 tmp = u_e->next;
952 free(u_e);
953 u_e = tmp;
954 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000955 }
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000956 return 0;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000957 }
958
Bart De Schuymer60332e02002-06-23 08:01:47 +0000959 if (entries->nentries == 0)
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000960 return -1;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000961 oldnentries = replace.nentries;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000962 replace.nentries -= entries->nentries;
963 numdel = entries->nentries;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000964
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000965 if (replace.nentries) {
966 // +1 for CNT_END
Bart De Schuymered053432002-07-21 19:35:39 +0000967 if ( !(replace.counterchanges = (unsigned short *)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000968 malloc((oldnentries + 1) * sizeof(unsigned short))) )
969 print_memory();
Bart De Schuymer60332e02002-06-23 08:01:47 +0000970 }
971 // delete the counters belonging to the specified chain,
972 // update counter_offset
973 i = -1;
Bart De Schuymered053432002-07-21 19:35:39 +0000974 cnt = replace.counterchanges;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000975 while (1) {
976 i++;
977 entries = nr_to_chain(i);
978 if (!entries) {
979 if (i < NF_BR_NUMHOOKS)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000980 continue;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000981 else
982 break;
983 }
984 if (i > replace.selected_hook)
985 entries->counter_offset -= numdel;
986 if (replace.nentries) {
987 for (j = 0; j < entries->nentries; j++) {
988 if (i == replace.selected_hook)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000989 *cnt = CNT_DEL;
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000990 else
991 *cnt = CNT_NORM;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000992 cnt++;
993 }
994 }
Bart De Schuymer60332e02002-06-23 08:01:47 +0000995 }
996
997 if (replace.nentries) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000998 *cnt = CNT_END;
999 replace.num_counters = oldnentries;
1000 }
1001 else
1002 replace.num_counters = 0;
1003
Bart De Schuymer60332e02002-06-23 08:01:47 +00001004 entries = to_chain();
1005 entries->nentries = 0;
1006 u_e = entries->entries;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001007 while (u_e) {
1008 free_u_entry(u_e);
1009 tmp = u_e->next;
1010 free(u_e);
1011 u_e = tmp;
1012 }
Bart De Schuymer60332e02002-06-23 08:01:47 +00001013 entries->entries = NULL;
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001014 return 0;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001015}
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001016
1017// -1 == no match
1018static int check_rule_exists(int rule_nr)
1019{
1020 struct ebt_u_entry *u_e;
1021 struct ebt_u_match_list *m_l, *m_l2;
1022 struct ebt_u_match *m;
1023 struct ebt_u_watcher_list *w_l, *w_l2;
1024 struct ebt_u_watcher *w;
1025 struct ebt_u_target *t = (struct ebt_u_target *)new_entry->t;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001026 struct ebt_u_entries *entries = to_chain();
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001027 int i, j, k;
1028
1029 // handle '-D chain rulenr' command
1030 if (rule_nr != -1) {
Bart De Schuymer60332e02002-06-23 08:01:47 +00001031 if (rule_nr > entries->nentries)
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001032 return -1;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001033 // user starts counting from 1
1034 return rule_nr - 1;
1035 }
Bart De Schuymer60332e02002-06-23 08:01:47 +00001036 u_e = entries->entries;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001037 // check for an existing rule (if there are duplicate rules,
1038 // take the first occurance)
Bart De Schuymer60332e02002-06-23 08:01:47 +00001039 for (i = 0; i < entries->nentries; i++, u_e = u_e->next) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001040 if (!u_e)
1041 print_bug("Hmm, trouble");
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001042 if (u_e->ethproto != new_entry->ethproto)
1043 continue;
1044 if (strcmp(u_e->in, new_entry->in))
1045 continue;
1046 if (strcmp(u_e->out, new_entry->out))
1047 continue;
1048 if (strcmp(u_e->logical_in, new_entry->logical_in))
1049 continue;
1050 if (strcmp(u_e->logical_out, new_entry->logical_out))
1051 continue;
1052 if (new_entry->bitmask & EBT_SOURCEMAC &&
1053 memcmp(u_e->sourcemac, new_entry->sourcemac, ETH_ALEN))
1054 continue;
1055 if (new_entry->bitmask & EBT_DESTMAC &&
1056 memcmp(u_e->destmac, new_entry->destmac, ETH_ALEN))
1057 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 && 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;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001073 }
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001074 // 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 && strcmp(w_l2->w->u.name, w->w->u.name))
1091 w_l2 = w_l2->next;
1092 if (!w_l2 || !w->compare(w->w, w_l2->w))
1093 goto letscontinue;
1094 j++;
1095 w_l = w_l->next;
1096 }
1097 k = 0;
1098 w_l = u_e->w_list;
1099 while (w_l) {
1100 k++;
1101 w_l = w_l->next;
1102 }
1103 if (j != k)
1104 continue;
1105 if (strcmp(t->t->u.name, u_e->t->u.name))
1106 continue;
1107 if (!t->compare(t->t, u_e->t))
1108 continue;
1109 return i;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001110letscontinue:
1111 }
1112 return -1;
1113}
1114
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001115// execute command A or I
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001116static void add_rule(int rule_nr)
1117{
1118 int i, j;
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001119 struct ebt_u_entry **u_e;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001120 unsigned short *cnt;
1121 struct ebt_u_match_list *m_l;
1122 struct ebt_u_watcher_list *w_l;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001123 struct ebt_u_entries *entries = to_chain(), *entries2;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001124
1125 if (rule_nr != -1) { // command -I
Bart De Schuymer60332e02002-06-23 08:01:47 +00001126 if (--rule_nr > entries->nentries)
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001127 print_error("rule nr too high: %d > %d", rule_nr + 1,
1128 entries->nentries + 1);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001129 } else
Bart De Schuymer60332e02002-06-23 08:01:47 +00001130 rule_nr = entries->nentries;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001131 // we're adding one rule
1132 replace.num_counters = replace.nentries;
1133 replace.nentries++;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001134 entries->nentries++;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001135
1136 // handle counter stuff
1137 // +1 for CNT_END
Bart De Schuymered053432002-07-21 19:35:39 +00001138 if ( !(replace.counterchanges = (unsigned short *)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001139 malloc((replace.nentries + 1) * sizeof(unsigned short))) )
1140 print_memory();
Bart De Schuymered053432002-07-21 19:35:39 +00001141 cnt = replace.counterchanges;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001142 for (i = 0; i < replace.selected_hook; i++) {
Bart De Schuymer60332e02002-06-23 08:01:47 +00001143 if (i < NF_BR_NUMHOOKS && !(replace.valid_hooks & (1 << i)))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001144 continue;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001145 entries2 = nr_to_chain(i);
1146 for (j = 0; j < entries2->nentries; j++) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001147 *cnt = CNT_NORM;
1148 cnt++;
1149 }
1150 }
1151 for (i = 0; i < rule_nr; i++) {
1152 *cnt = CNT_NORM;
1153 cnt++;
1154 }
1155 *cnt = CNT_ADD;
1156 cnt++;
Bart De Schuymered053432002-07-21 19:35:39 +00001157 while (cnt != replace.counterchanges + replace.nentries) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001158 *cnt = CNT_NORM;
1159 cnt++;
1160 }
1161 *cnt = CNT_END;
1162
1163 // go to the right position in the chain
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001164 u_e = &entries->entries;
1165 for (i = 0; i < rule_nr; i++)
1166 u_e = &(*u_e)->next;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001167 // insert the rule
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001168 new_entry->next = *u_e;
1169 *u_e = new_entry;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001170
1171 // put the ebt_[match, watcher, target] pointers in place
1172 m_l = new_entry->m_list;
1173 while (m_l) {
1174 m_l->m = ((struct ebt_u_match *)m_l->m)->m;
1175 m_l = m_l->next;
1176 }
1177 w_l = new_entry->w_list;
1178 while (w_l) {
1179 w_l->w = ((struct ebt_u_watcher *)w_l->w)->w;
1180 w_l = w_l->next;
1181 }
1182 new_entry->t = ((struct ebt_u_target *)new_entry->t)->t;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001183
1184 // update the counter_offset of chains behind this one
1185 i = replace.selected_hook;
1186 while (1) {
1187 i++;
1188 entries = nr_to_chain(i);
1189 if (!entries) {
1190 if (i < NF_BR_NUMHOOKS)
1191 continue;
1192 else
1193 break;
1194 } else
1195 entries->counter_offset++;
1196 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001197}
1198
1199// execute command D
1200static void delete_rule(int rule_nr)
1201{
1202 int i, j, lentmp = 0;
1203 unsigned short *cnt;
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001204 struct ebt_u_entry **u_e, *u_e2;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001205 struct ebt_u_entries *entries = to_chain(), *entries2;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001206
1207 if ( (i = check_rule_exists(rule_nr)) == -1 )
Bart De Schuymer60332e02002-06-23 08:01:47 +00001208 print_error("Sorry, rule does not exist");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001209
1210 // we're deleting a rule
1211 replace.num_counters = replace.nentries;
1212 replace.nentries--;
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001213 entries->nentries--;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001214
1215 if (replace.nentries) {
1216 for (j = 0; j < replace.selected_hook; j++) {
Bart De Schuymer60332e02002-06-23 08:01:47 +00001217 if (j < NF_BR_NUMHOOKS &&
1218 !(replace.valid_hooks & (1 << j)))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001219 continue;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001220 entries2 = nr_to_chain(j);
1221 lentmp += entries2->nentries;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001222 }
1223 lentmp += i;
1224 // +1 for CNT_END
Bart De Schuymered053432002-07-21 19:35:39 +00001225 if ( !(replace.counterchanges = (unsigned short *)malloc(
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001226 (replace.num_counters + 1) * sizeof(unsigned short))) )
1227 print_memory();
Bart De Schuymered053432002-07-21 19:35:39 +00001228 cnt = replace.counterchanges;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001229 for (j = 0; j < lentmp; j++) {
1230 *cnt = CNT_NORM;
1231 cnt++;
1232 }
1233 *cnt = CNT_DEL;
1234 cnt++;
1235 for (j = 0; j < replace.num_counters - lentmp; j++) {
1236 *cnt = CNT_NORM;
1237 cnt++;
1238 }
1239 *cnt = CNT_END;
1240 }
1241 else
1242 replace.num_counters = 0;
1243
1244 // go to the right position in the chain
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001245 u_e = &entries->entries;
1246 for (j = 0; j < i; j++)
1247 u_e = &(*u_e)->next;
1248 // remove the rule
1249 u_e2 = *u_e;
1250 *u_e = (*u_e)->next;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001251 // free everything
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001252 free_u_entry(u_e2);
1253 free(u_e2);
1254
Bart De Schuymer60332e02002-06-23 08:01:47 +00001255 // update the counter_offset of chains behind this one
1256 i = replace.selected_hook;
1257 while (1) {
1258 i++;
1259 entries = nr_to_chain(i);
1260 if (!entries) {
1261 if (i < NF_BR_NUMHOOKS)
1262 continue;
1263 else
1264 break;
1265 } else
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001266 entries->counter_offset--;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001267 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001268}
1269
1270// execute command Z
Bart De Schuymer62423742002-07-14 19:06:20 +00001271static void zero_counters(int zerochain)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001272{
1273
1274 if (zerochain == -1) {
1275 // tell main() we don't update the counters
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001276 // this results in tricking the kernel to zero its counters,
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001277 // naively expecting userspace to update its counters. Muahahaha
Bart De Schuymered053432002-07-21 19:35:39 +00001278 replace.counterchanges = NULL;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001279 replace.num_counters = 0;
1280 } else {
1281 int i, j;
1282 unsigned short *cnt;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001283 struct ebt_u_entries *entries = nr_to_chain(zerochain), *e2;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001284
Bart De Schuymer60332e02002-06-23 08:01:47 +00001285 if (entries->nentries == 0)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001286 exit(0);
Bart De Schuymered053432002-07-21 19:35:39 +00001287 replace.counterchanges = (unsigned short *)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001288 malloc((replace.nentries + 1) * sizeof(unsigned short));
Bart De Schuymered053432002-07-21 19:35:39 +00001289 if (!replace.counterchanges)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001290 print_memory();
Bart De Schuymered053432002-07-21 19:35:39 +00001291 cnt = replace.counterchanges;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001292 for (i = 0; i < zerochain; i++) {
Bart De Schuymer60332e02002-06-23 08:01:47 +00001293 if (i < NF_BR_NUMHOOKS &&
1294 !(replace.valid_hooks & (1 << i)))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001295 continue;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001296 e2 = nr_to_chain(i);
1297 for (j = 0; j < e2->nentries; j++) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001298 *cnt = CNT_NORM;
1299 cnt++;
1300 }
1301 }
Bart De Schuymer60332e02002-06-23 08:01:47 +00001302 for (i = 0; i < entries->nentries; i++) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001303 *cnt = CNT_ZERO;
1304 cnt++;
1305 }
Bart De Schuymered053432002-07-21 19:35:39 +00001306 while (cnt != replace.counterchanges + replace.nentries) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001307 *cnt = CNT_NORM;
1308 cnt++;
1309 }
1310 *cnt = CNT_END;
1311 }
1312}
1313
1314// list the database (optionally compiled into the kernel)
1315static void list_db()
1316{
1317 struct brdb_dbinfo nr;
1318 struct brdb_dbentry *db;
1319 char name[21];
1320 int i;
1321
1322 get_dbinfo(&nr);
1323
1324 // 0 : database disabled (-db n)
1325 if (!(nr.nentries))
1326 print_error("Database not present"
1327 " (disabled), try ebtables --db y");
1328 nr.nentries--;
1329 if (!nr.nentries) print_error("Database empty");
1330 if ( !(db = (struct brdb_dbentry *)
1331 malloc(nr.nentries * sizeof(struct brdb_dbentry))) )
1332 print_memory();
1333
1334 get_db(nr.nentries, db);
1335 printf("number of entries: %d\n", nr.nentries);
1336 for (i = 0; i < nr.nentries; i++) {
1337 printf(
1338 "%d:\n"
1339 "hook : %s\n"
1340 "in-if : %s\n"
1341 "out-if : %s\n"
1342 "protocol: ", i + 1, hooknames[db->hook], db->in, db->out);
1343 if (db->ethproto == IDENTIFY802_3)
1344 printf("802.2/802.3 STYLE LENGTH FIELD\n");
1345 else {
1346 if (number_to_name(ntohs(db->ethproto), name))
1347 printf("%x\n",ntohs(db->ethproto));
1348 else
1349 printf("%s\n", name);
1350 }
1351 db++;
1352 }
1353 exit(0);
1354}
1355
1356// handle db [dis,en]abling
1357static void allowdb(char yorn)
1358{
1359 __u16 decision;
1360
1361 if (yorn != 'y' && yorn != 'n')
1362 print_error("Option [y] or [n] needed");
1363
1364 if (yorn == 'y')
1365 decision = BRDB_DB;
1366 else
1367 decision = BRDB_NODB;
1368
1369 deliver_allowdb(&decision);
1370
1371 exit(0);
1372}
1373
Bart De Schuymer28bf6f62002-06-26 18:57:24 +00001374// 0 == success
1375// 1 == success, but for the special 'protocol' LENGTH
1376// -1 == failure
1377int name_to_number(char *name, __u16 *proto)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001378{
1379 FILE *ifp;
Bart De Schuymerf662ce52002-07-19 18:40:55 +00001380 char buffer[21], value[11], *bfr;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001381 unsigned short i;
1382
1383 if (!strcasecmp("LENGTH", name)) {
Bart De Schuymer28bf6f62002-06-26 18:57:24 +00001384 *proto = 0;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001385 new_entry->bitmask |= EBT_802_3;
1386 return 1;
1387 }
1388 if ( !(ifp = fopen(PROTOCOLFILE, "r")) )
1389 return -1;
1390 while (1) {
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001391 if (get_a_line(buffer, value, ifp))
1392 return -1;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001393 if (strcasecmp(buffer, name))
1394 continue;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001395 fclose(ifp);
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001396 i = (unsigned short) strtol(value, &bfr, 16);
1397 if (*bfr != '\0')
1398 return -1;
1399 *proto = i;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001400 return 0;
1401 }
1402 return -1;
1403}
1404
1405// put the mac address into 6 (ETH_ALEN) bytes
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001406int getmac_and_mask(char *from, char *to, char *mask)
1407{
1408 char *p;
1409 int i;
Bart De Schuymer41830412002-06-05 19:41:28 +00001410 struct ether_addr *addr;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001411
1412 if (strcasecmp(from, "Unicast") == 0) {
1413 memcpy(to, mac_type_unicast, ETH_ALEN);
1414 memcpy(mask, msk_type_unicast, ETH_ALEN);
1415 return 0;
1416 }
1417 if (strcasecmp(from, "Multicast") == 0) {
1418 memcpy(to, mac_type_multicast, ETH_ALEN);
1419 memcpy(mask, msk_type_multicast, ETH_ALEN);
1420 return 0;
1421 }
1422 if (strcasecmp(from, "Broadcast") == 0) {
1423 memcpy(to, mac_type_broadcast, ETH_ALEN);
1424 memcpy(mask, msk_type_broadcast, ETH_ALEN);
1425 return 0;
1426 }
1427 if ( (p = strrchr(from, '/')) != NULL) {
1428 *p = '\0';
Bart De Schuymer41830412002-06-05 19:41:28 +00001429 if (!(addr = ether_aton(p + 1)))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001430 return -1;
Bart De Schuymer41830412002-06-05 19:41:28 +00001431 memcpy(mask, addr, ETH_ALEN);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001432 } else
1433 memset(mask, 0xff, ETH_ALEN);
Bart De Schuymer41830412002-06-05 19:41:28 +00001434 if (!(addr = ether_aton(from)))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001435 return -1;
Bart De Schuymer41830412002-06-05 19:41:28 +00001436 memcpy(to, addr, ETH_ALEN);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001437 for (i = 0; i < ETH_ALEN; i++)
1438 to[i] &= mask[i];
1439 return 0;
1440}
1441
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001442// executes the final_check() function for all extensions used by the rule
Bart De Schuymer62423742002-07-14 19:06:20 +00001443static void do_final_checks(struct ebt_u_entry *e, struct ebt_u_entries *entries)
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +00001444{
1445 struct ebt_u_match_list *m_l;
1446 struct ebt_u_watcher_list *w_l;
1447 struct ebt_u_target *t;
1448 struct ebt_u_match *m;
1449 struct ebt_u_watcher *w;
1450
1451 m_l = e->m_list;
1452 w_l = e->w_list;
1453 while (m_l) {
1454 m = find_match(m_l->m->u.name);
1455 m->final_check(e, m_l->m, replace.name,
1456 entries->hook_mask, 1);
1457 m_l = m_l->next;
1458 }
1459 while (w_l) {
1460 w = find_watcher(w_l->w->u.name);
1461 w->final_check(e, w_l->w, replace.name,
1462 entries->hook_mask, 1);
1463 w_l = w_l->next;
1464 }
1465 t = find_target(e->t->u.name);
1466 t->final_check(e, e->t, replace.name,
1467 entries->hook_mask, 1);
1468}
1469
Bart De Schuymerb909f9b2002-06-26 18:35:31 +00001470// used for the -X command
Bart De Schuymer62423742002-07-14 19:06:20 +00001471static void check_for_references(int chain_nr)
Bart De Schuymerb909f9b2002-06-26 18:35:31 +00001472{
1473 int i = -1, j;
1474 struct ebt_u_entries *entries;
1475 struct ebt_u_entry *e;
1476
1477 while (1) {
1478 i++;
1479 entries = nr_to_chain(i);
1480 if (!entries) {
1481 if (i < NF_BR_NUMHOOKS)
1482 continue;
1483 else
1484 break;
1485 }
1486 e = entries->entries;
1487 j = 0;
1488 while (e) {
1489 j++;
1490 if (strcmp(e->t->u.name, EBT_STANDARD_TARGET)) {
1491 e = e->next;
1492 continue;
1493 }
1494 if (((struct ebt_standard_target *)e->t)->verdict == chain_nr)
1495 print_error("Can't delete the chain, it's referenced "
1496 "in chain %s, rule %d", entries->name, j);
1497 e = e->next;
1498 }
1499 }
1500}
1501
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001502int check_inverse(const char option[])
1503{
1504 if (strcmp(option, "!") == 0) {
1505 optind++;
1506 return 1;
1507 }
1508 return 0;
1509}
1510
1511void check_option(unsigned int *flags, unsigned int mask)
1512{
1513 if (*flags & mask)
1514 print_error("Multiple use of same option not allowed");
1515 *flags |= mask;
1516}
1517
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001518static void get_kernel_table(const char *modprobe)
1519{
1520 if ( !(table = find_table(replace.name)) )
1521 print_error("Bad table name");
1522 // get the kernel's information
1523 if (get_table(&replace)) {
1524 ebtables_insmod("ebtables", modprobe);
1525 if (get_table(&replace))
1526 print_error("The kernel doesn't support the ebtables "
1527 "%s table", replace.name);
1528 }
1529}
1530
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001531#define OPT_COMMAND 0x01
1532#define OPT_TABLE 0x02
1533#define OPT_IN 0x04
1534#define OPT_OUT 0x08
1535#define OPT_JUMP 0x10
1536#define OPT_PROTOCOL 0x20
1537#define OPT_SOURCE 0x40
1538#define OPT_DEST 0x80
1539#define OPT_ZERO 0x100
1540#define OPT_LOGICALIN 0x200
1541#define OPT_LOGICALOUT 0x400
1542// the main thing
1543int main(int argc, char *argv[])
1544{
1545 char *buffer, allowbc = 'n';
1546 int c, i;
1547 // this special one for the -Z option (we can have -Z <this> -L <that>)
1548 int zerochain = -1;
Bart De Schuymerf8f8f292002-06-25 15:43:57 +00001549 int policy = 0;
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001550 int rule_nr = -1;// used for -[D,I] chain number
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001551 struct ebt_u_target *t;
1552 struct ebt_u_match *m;
1553 struct ebt_u_watcher *w;
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001554 struct ebt_u_match_list *m_l;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001555 struct ebt_u_watcher_list *w_l;
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001556 struct ebt_u_entries *entries;
Bart De Schuymerc8531032002-06-14 21:55:29 +00001557 const char *modprobe = NULL;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001558
1559 // initialize the table name, OPT_ flags, selected hook and command
1560 strcpy(replace.name, "filter");
1561 replace.flags = 0;
1562 replace.selected_hook = -1;
1563 replace.command = 'h';
Bart De Schuymer62423742002-07-14 19:06:20 +00001564 replace.filename = NULL;
Bart De Schuymered053432002-07-21 19:35:39 +00001565 replace.counterchanges = NULL;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001566
1567 new_entry = (struct ebt_u_entry *)malloc(sizeof(struct ebt_u_entry));
1568 if (!new_entry)
1569 print_memory();
1570 // put some sane values in our new entry
1571 initialize_entry(new_entry);
1572
Bart De Schuymer60332e02002-06-23 08:01:47 +00001573 // The scenario induced by this loop makes that:
Bart De Schuymer62423742002-07-14 19:06:20 +00001574 // '-t' ,'-M' and --atomic (if specified) have to come
1575 // before '-A' and the like
Bart De Schuymer60332e02002-06-23 08:01:47 +00001576
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001577 // getopt saves the day
1578 while ((c = getopt_long(argc, argv,
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001579 "-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 +00001580 switch (c) {
1581
1582 case 'A': // add a rule
1583 case 'D': // delete a rule
1584 case 'P': // define policy
1585 case 'I': // insert a rule
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001586 case 'N': // make a user defined chain
1587 case 'E': // rename chain
1588 case 'X': // delete chain
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001589 replace.command = c;
1590 if (replace.flags & OPT_COMMAND)
1591 print_error("Multiple commands not allowed");
1592 replace.flags |= OPT_COMMAND;
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001593 get_kernel_table(modprobe);
1594 if (optarg[0] == '-' || !strcmp(optarg, "!"))
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001595 print_error("No chain name specified");
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001596 if (c == 'N') {
1597 struct ebt_u_chain_list *cl, **cl2;
1598
1599 if (get_hooknr(optarg) != -1)
1600 print_error("Chain %s already exists",
1601 optarg);
1602 if (find_target(optarg))
1603 print_error("Target with name %s exists"
1604 , optarg);
1605 if (strlen(optarg) >= EBT_CHAIN_MAXNAMELEN)
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001606 print_error("Chain name length can't exceed %d",
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001607 EBT_CHAIN_MAXNAMELEN - 1);
1608 cl = (struct ebt_u_chain_list *)
1609 malloc(sizeof(struct ebt_u_chain_list));
1610 if (!cl)
1611 print_memory();
1612 cl->next = NULL;
1613 cl->udc = (struct ebt_u_entries *)
1614 malloc(sizeof(struct ebt_u_entries));
1615 if (!cl->udc)
1616 print_memory();
1617 cl->udc->nentries = 0;
1618 cl->udc->policy = EBT_ACCEPT;
1619 cl->udc->counter_offset = replace.nentries;
1620 cl->udc->hook_mask = 0;
1621 strcpy(cl->udc->name, optarg);
1622 cl->udc->entries = NULL;
1623 cl->kernel_start = NULL;
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001624 // put the new chain at the end
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001625 cl2 = &replace.udc;
1626 while (*cl2)
1627 cl2 = &((*cl2)->next);
1628 *cl2 = cl;
1629 break;
1630 }
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001631 if ((replace.selected_hook = get_hooknr(optarg)) == -1)
1632 print_error("Chain %s doesn't exist", optarg);
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001633 if (c == 'E') {
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001634 if (optind >= argc || argv[optind][0] == '-' ||
1635 !strcmp(argv[optind], "!"))
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001636 print_error("No new chain name specified");
1637 if (strlen(argv[optind]) >= EBT_CHAIN_MAXNAMELEN)
1638 print_error("Chain name len can't exceed %d",
1639 EBT_CHAIN_MAXNAMELEN - 1);
1640 if (get_hooknr(argv[optind]) != -1)
1641 print_error("Chain %s already exists",
1642 argv[optind]);
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001643 if (find_target(argv[optind]))
1644 print_error("Target with name %s exists"
1645 , argv[optind]);
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001646 entries = to_chain();
1647 strcpy(entries->name, argv[optind]);
1648 optind++;
1649 break;
1650 }
1651 if (c == 'X') {
1652 struct ebt_u_chain_list *cl, **cl2;
1653
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001654 if (replace.selected_hook < NF_BR_NUMHOOKS)
1655 print_error("You can't remove a standard chain");
Bart De Schuymerb909f9b2002-06-26 18:35:31 +00001656 // if the chain is referenced, don't delete it
1657 check_for_references(replace.selected_hook - NF_BR_NUMHOOKS);
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001658 flush_chains();
1659 entries = to_chain();
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001660 cl2 = &(replace.udc);
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001661 while ((*cl2)->udc != entries)
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001662 cl2 = &((*cl2)->next);
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001663 cl = (*cl2);
1664 (*cl2) = (*cl2)->next;
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001665 free(cl->udc);
1666 free(cl);
1667 break;
1668 }
1669
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001670 if ( (c == 'D' && optind < argc &&
1671 argv[optind][0] != '-') || c == 'I') {
1672 if (optind >= argc || argv[optind][0] == '-')
1673 print_error("No rulenr for -I"
1674 " specified");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001675 rule_nr = strtol(argv[optind], &buffer, 10);
1676 if (*buffer != '\0' || rule_nr < 0)
1677 print_error("Problem with the "
1678 "specified rule number");
1679 optind++;
1680 }
1681 if (c == 'P') {
1682 if (optind >= argc)
1683 print_error("No policy specified");
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001684 policy = 0;
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001685 for (i = 0; i < NUM_STANDARD_TARGETS; i++)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001686 if (!strcmp(argv[optind],
1687 standard_targets[i])) {
Bart De Schuymer60332e02002-06-23 08:01:47 +00001688 policy = -i -1;
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001689 if (policy == EBT_CONTINUE)
1690 policy = 0;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001691 break;
1692 }
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001693 if (policy == 0)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001694 print_error("Wrong policy");
1695 optind++;
1696 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001697 break;
1698
1699 case 'L': // list
1700 case 'F': // flush
1701 case 'Z': // zero counters
1702 if (c == 'Z') {
1703 if (replace.flags & OPT_ZERO)
1704 print_error("Multiple commands"
1705 " not allowed");
1706 if ( (replace.flags & OPT_COMMAND &&
1707 replace.command != 'L'))
1708 print_error("command -Z only allowed "
1709 "together with command -L");
1710 replace.flags |= OPT_ZERO;
1711 } else {
1712 replace.command = c;
1713 if (replace.flags & OPT_COMMAND)
1714 print_error("Multiple commands"
1715 " not allowed");
1716 replace.flags |= OPT_COMMAND;
1717 }
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001718 get_kernel_table(modprobe);
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001719 i = -1;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001720 if (optarg) {
1721 if ( (i = get_hooknr(optarg)) == -1 )
1722 print_error("Bad chain");
1723 } else
1724 if (optind < argc && argv[optind][0] != '-') {
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001725 if ((i = get_hooknr(argv[optind])) == -1)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001726 print_error("Bad chain");
1727 optind++;
1728 }
1729 if (i != -1) {
1730 if (c == 'Z')
1731 zerochain = i;
1732 else
1733 replace.selected_hook = i;
1734 }
1735 break;
1736
1737 case 'V': // version
1738 replace.command = 'V';
1739 if (replace.flags & OPT_COMMAND)
1740 print_error("Multiple commands not allowed");
1741 printf("%s, %s\n", prog_name, prog_version);
1742 exit(0);
1743
Bart De Schuymerc8531032002-06-14 21:55:29 +00001744 case 'M': // modprobe
Bart De Schuymer60332e02002-06-23 08:01:47 +00001745 if (replace.command != 'h')
1746 print_error("Please put the -M option earlier");
Bart De Schuymerc8531032002-06-14 21:55:29 +00001747 modprobe = optarg;
1748 break;
1749
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001750 case 'h': // help
1751 if (replace.flags & OPT_COMMAND)
1752 print_error("Multiple commands not allowed");
1753 replace.command = 'h';
1754 // All other arguments should be extension names
1755 while (optind < argc) {
1756 struct ebt_u_match *m;
1757 struct ebt_u_watcher *w;
1758
1759 if ((m = find_match(argv[optind])))
1760 add_match(m);
1761 else if ((w = find_watcher(argv[optind])))
1762 add_watcher(w);
1763 else {
1764 if (!(t = find_target(argv[optind])))
1765 print_error("Extension %s "
1766 "not found", argv[optind]);
1767 if (replace.flags & OPT_JUMP)
1768 print_error("Sorry, you can "
1769 "only see help for one "
1770 "target extension each time");
1771 replace.flags |= OPT_JUMP;
1772 new_entry->t =
1773 (struct ebt_entry_target *)t;
1774 }
1775 optind++;
1776 }
1777 break;
1778
1779 case 't': // table
Bart De Schuymer60332e02002-06-23 08:01:47 +00001780 if (replace.command != 'h')
1781 print_error("Please put the -t option first");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001782 check_option(&replace.flags, OPT_TABLE);
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001783 if (strlen(optarg) > EBT_TABLE_MAXNAMELEN - 1)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001784 print_error("Table name too long");
1785 strcpy(replace.name, optarg);
1786 break;
1787
1788 case 'i': // input interface
1789 case 2 : // logical input interface
1790 case 'o': // output interface
1791 case 3 : // logical output interface
1792 case 'j': // target
1793 case 'p': // net family protocol
1794 case 's': // source mac
1795 case 'd': // destination mac
1796 if ((replace.flags & OPT_COMMAND) == 0)
1797 print_error("No command specified");
1798 if ( replace.command != 'A' &&
1799 replace.command != 'D' && replace.command != 'I')
1800 print_error("Command and option do not match");
1801 if (c == 'i') {
1802 check_option(&replace.flags, OPT_IN);
1803 if (replace.selected_hook > 2 &&
1804 replace.selected_hook < NF_BR_BROUTING)
1805 print_error("Use in-interface only in "
1806 "INPUT, FORWARD, PREROUTING and"
1807 "BROUTING chains");
1808 if (check_inverse(optarg))
1809 new_entry->invflags |= EBT_IIN;
1810
1811 if (optind > argc)
1812 print_error("No in-interface "
1813 "specified");
1814 if (strlen(argv[optind - 1]) >= IFNAMSIZ)
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001815 print_error("Illegal interface length");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001816 strcpy(new_entry->in, argv[optind - 1]);
1817 break;
1818 }
1819 if (c == 2) {
1820 check_option(&replace.flags, OPT_LOGICALIN);
1821 if (replace.selected_hook > 2 &&
1822 replace.selected_hook < NF_BR_BROUTING)
1823 print_error("Use logical in-interface "
1824 "only in INPUT, FORWARD, "
1825 "PREROUTING and BROUTING chains");
1826 if (check_inverse(optarg))
1827 new_entry->invflags |= EBT_ILOGICALIN;
1828
1829 if (optind > argc)
1830 print_error("No logical in-interface "
1831 "specified");
1832 if (strlen(argv[optind - 1]) >= IFNAMSIZ)
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001833 print_error("Illegal interface length");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001834 strcpy(new_entry->logical_in, argv[optind - 1]);
1835 break;
1836 }
1837 if (c == 'o') {
1838 check_option(&replace.flags, OPT_OUT);
1839 if (replace.selected_hook < 2)
1840 print_error("Use out-interface only"
1841 " in OUTPUT, FORWARD and "
1842 "POSTROUTING chains");
1843 if (check_inverse(optarg))
1844 new_entry->invflags |= EBT_IOUT;
1845
1846 if (optind > argc)
1847 print_error("No out-interface "
1848 "specified");
1849
1850 if (strlen(argv[optind - 1]) >= IFNAMSIZ)
1851 print_error("Illegal interface "
1852 "length");
1853 strcpy(new_entry->out, argv[optind - 1]);
1854 break;
1855 }
1856 if (c == 3) {
1857 check_option(&replace.flags, OPT_LOGICALOUT);
1858 if (replace.selected_hook < 2)
1859 print_error("Use logical out-interface "
1860 "only in OUTPUT, FORWARD and "
1861 "POSTROUTING chains");
1862 if (check_inverse(optarg))
1863 new_entry->invflags |= EBT_ILOGICALOUT;
1864
1865 if (optind > argc)
1866 print_error("No logical out-interface "
1867 "specified");
1868
1869 if (strlen(argv[optind - 1]) >= IFNAMSIZ)
1870 print_error("Illegal interface "
1871 "length");
1872 strcpy(new_entry->logical_out,
1873 argv[optind - 1]);
1874 break;
1875 }
1876 if (c == 'j') {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001877 check_option(&replace.flags, OPT_JUMP);
1878 for (i = 0; i < NUM_STANDARD_TARGETS; i++)
1879 if (!strcmp(optarg,
1880 standard_targets[i])) {
1881 t = find_target(
1882 EBT_STANDARD_TARGET);
1883 ((struct ebt_standard_target *)
Bart De Schuymer60332e02002-06-23 08:01:47 +00001884 t->t)->verdict = -i - 1;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001885 break;
1886 }
Bart De Schuymer60332e02002-06-23 08:01:47 +00001887 if (-i - 1 == EBT_RETURN) {
1888 if (replace.selected_hook < NF_BR_NUMHOOKS)
1889 print_error("Return target"
1890 " only for user defined chains");
1891 }
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +00001892 if (i != NUM_STANDARD_TARGETS)
1893 break;
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001894 if ((i = get_hooknr(optarg)) != -1) {
1895 if (i < NF_BR_NUMHOOKS)
1896 print_error("don't jump"
1897 " to a standard chain");
1898 t = find_target(
1899 EBT_STANDARD_TARGET);
1900 ((struct ebt_standard_target *)
1901 t->t)->verdict = i - NF_BR_NUMHOOKS;
1902 break;
1903 }
1904 else {
1905 // must be an extension then
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001906 struct ebt_u_target *t;
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001907
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001908 t = find_target(optarg);
1909 // -j standard not allowed either
1910 if (!t || t ==
1911 (struct ebt_u_target *)new_entry->t)
1912 print_error("Illegal target "
1913 "name");
1914 new_entry->t =
1915 (struct ebt_entry_target *)t;
1916 }
1917 break;
1918 }
1919 if (c == 's') {
1920 check_option(&replace.flags, OPT_SOURCE);
1921 if (check_inverse(optarg))
1922 new_entry->invflags |= EBT_ISOURCE;
1923
1924 if (optind > argc)
1925 print_error("No source mac "
1926 "specified");
1927 if (getmac_and_mask(argv[optind - 1],
1928 new_entry->sourcemac, new_entry->sourcemsk))
1929 print_error("Problem with specified "
1930 "source mac");
1931 new_entry->bitmask |= EBT_SOURCEMAC;
1932 break;
1933 }
1934 if (c == 'd') {
1935 check_option(&replace.flags, OPT_DEST);
1936 if (check_inverse(optarg))
1937 new_entry->invflags |= EBT_IDEST;
1938
1939 if (optind > argc)
1940 print_error("No destination mac "
1941 "specified");
1942 if (getmac_and_mask(argv[optind - 1],
1943 new_entry->destmac, new_entry->destmsk))
1944 print_error("Problem with specified "
1945 "destination mac");
1946 new_entry->bitmask |= EBT_DESTMAC;
1947 break;
1948 }
1949 check_option(&replace.flags, OPT_PROTOCOL);
1950 if (check_inverse(optarg))
1951 new_entry->invflags |= EBT_IPROTO;
1952
1953 if (optind > argc)
1954 print_error("No protocol specified");
1955 new_entry->bitmask &= ~((unsigned int)EBT_NOPROTO);
1956 i = strtol(argv[optind - 1], &buffer, 16);
1957 if (*buffer == '\0' && (i < 0 || i > 0xFFFF))
1958 print_error("Problem with the specified "
1959 "protocol");
1960 new_entry->ethproto = i;
Bart De Schuymer28bf6f62002-06-26 18:57:24 +00001961 if (*buffer != '\0') {
1962 if ((i = name_to_number(argv[optind - 1],
1963 &new_entry->ethproto)) == -1)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001964 print_error("Problem with the specified"
1965 " protocol");
Bart De Schuymer28bf6f62002-06-26 18:57:24 +00001966 if (i == 1)
1967 new_entry->bitmask |= EBT_802_3;
1968 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001969 if (new_entry->ethproto < 1536 &&
1970 !(new_entry->bitmask & EBT_802_3))
1971 print_error("Sorry, protocols have values above"
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001972 " or equal to 0x0600");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001973 break;
1974
1975 case 'b': // allow database?
1976 if (replace.flags & OPT_COMMAND)
1977 print_error("Multiple commands not allowed");
1978 replace.command = c;
1979 allowbc = *optarg;
1980 break;
1981
Bart De Schuymer9af14f92002-07-10 20:49:10 +00001982 case 4 : // Lc
1983 check_option(&replace.flags, LIST_C);
1984 if (replace.selected_hook == DATABASEHOOKNR)
1985 print_error("--Lc not valid for listing"
1986 " the database");
1987 if (replace.command != 'L')
1988 print_error("Use --Lc with -L");
1989 if (replace.flags & LIST_X)
1990 print_error("--Lx not compatible with --Lc");
1991 replace.flags |= LIST_C;
1992 break;
1993 case 5 : // Ln
1994 check_option(&replace.flags, LIST_N);
1995 if (replace.selected_hook == DATABASEHOOKNR)
1996 print_error("--Ln not valid for listing"
1997 " the database");
1998 if (replace.command != 'L')
1999 print_error("Use --Ln with -L");
2000 if (replace.flags & LIST_X)
2001 print_error("--Lx not compatible with --Ln");
2002 replace.flags |= LIST_N;
2003 break;
2004 case 6 : // Lx
2005 check_option(&replace.flags, LIST_X);
2006 if (replace.selected_hook == DATABASEHOOKNR)
2007 print_error("--Lx not valid for listing"
2008 " the database");
2009 if (replace.command != 'L')
2010 print_error("Use --Lx with -L");
2011 if (replace.flags & LIST_C)
2012 print_error("--Lx not compatible with --Lc");
2013 if (replace.flags & LIST_N)
2014 print_error("--Lx not compatible with --Ln");
2015 replace.flags |= LIST_X;
2016 break;
Bart De Schuymer62423742002-07-14 19:06:20 +00002017 case 8 : // atomic-commit
2018 replace.command = c;
2019 if (replace.flags & OPT_COMMAND)
2020 print_error("Multiple commands not allowed");
2021 replace.flags |= OPT_COMMAND;
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00002022 if (replace.filename)
2023 print_error("--atomic incompatible with "
2024 "command");
Bart De Schuymer62423742002-07-14 19:06:20 +00002025 replace.filename = (char *)malloc(strlen(optarg) + 1);
2026 strcpy(replace.filename, optarg);
2027 // get the information from the file
2028 get_table(&replace);
Bart De Schuymer868bf642002-07-16 18:14:20 +00002029 if (replace.nentries) {
Bart De Schuymered053432002-07-21 19:35:39 +00002030 replace.counterchanges = (unsigned short *)
Bart De Schuymer868bf642002-07-16 18:14:20 +00002031 malloc(sizeof(unsigned short) * (replace.nentries + 1));
2032 for (i = 0; i < replace.nentries; i++)
Bart De Schuymered053432002-07-21 19:35:39 +00002033 replace.counterchanges[i] = CNT_NORM;
2034 replace.counterchanges[i] = CNT_END;
Bart De Schuymer868bf642002-07-16 18:14:20 +00002035 }
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00002036 // we don't want the kernel giving us its counters, they would
2037 // overwrite the counters extracted from the file
2038 replace.num_counters = 0;
2039 // make sure the table will be written to the kernel
Bart De Schuymer62423742002-07-14 19:06:20 +00002040 free(replace.filename);
2041 replace.filename = NULL;
2042 break;
2043 case 7 : // atomic-init
2044 case 10: // atomic-save
Bart De Schuymer8d1d8942002-07-15 20:09:09 +00002045 case 11: // init-table
Bart De Schuymer62423742002-07-14 19:06:20 +00002046 replace.command = c;
2047 if (replace.flags & OPT_COMMAND)
2048 print_error("Multiple commands not allowed");
2049 replace.flags |= OPT_COMMAND;
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00002050 if (replace.filename)
2051 print_error("--atomic incompatible with "
2052 "command");
2053 get_kernel_table(modprobe);
Bart De Schuymera8d920b2002-07-16 18:30:44 +00002054 if (replace.nentries) {
Bart De Schuymered053432002-07-21 19:35:39 +00002055 replace.counterchanges = (unsigned short *)
Bart De Schuymer5f16dc72002-07-16 18:08:36 +00002056 malloc(sizeof(unsigned short) * (replace.nentries + 1));
2057 for (i = 0; i < replace.nentries; i++)
Bart De Schuymered053432002-07-21 19:35:39 +00002058 replace.counterchanges[i] = CNT_NORM;
2059 replace.counterchanges[i] = CNT_END;
Bart De Schuymer5f16dc72002-07-16 18:08:36 +00002060 }
Bart De Schuymer8d1d8942002-07-15 20:09:09 +00002061 if (c == 11)
2062 break;
Bart De Schuymer62423742002-07-14 19:06:20 +00002063 case 9 : // atomic
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00002064 if (c == 9 && (replace.flags & OPT_COMMAND))
2065 print_error("--atomic has to come before"
2066 " the command");
Bart De Schuymer62423742002-07-14 19:06:20 +00002067 replace.filename = (char *)malloc(strlen(optarg) + 1);
2068 strcpy(replace.filename, optarg);
2069 break;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002070
Bart De Schuymer9af14f92002-07-10 20:49:10 +00002071 default:
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002072 // is it a target option?
2073 t = (struct ebt_u_target *)new_entry->t;
2074 if ((t->parse(c - t->option_offset, argv, argc,
2075 new_entry, &t->flags, &t->t)))
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00002076 goto check_extension;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002077
2078 // is it a match_option?
2079 for (m = matches; m; m = m->next)
2080 if (m->parse(c - m->option_offset, argv,
2081 argc, new_entry, &m->flags, &m->m))
2082 break;
2083
2084 if (m != NULL) {
2085 if (m->used == 0)
2086 add_match(m);
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00002087 goto check_extension;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002088 }
2089
2090 // is it a watcher option?
2091 for (w = watchers; w; w = w->next)
2092 if (w->parse(c-w->option_offset, argv,
2093 argc, new_entry, &w->flags, &w->w))
2094 break;
2095
2096 if (w == NULL)
2097 print_error("Unknown argument");
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00002098 if (w->used == 0)
2099 add_watcher(w);
2100check_extension:
Bart De Schuymer60332e02002-06-23 08:01:47 +00002101 if (replace.command != 'A' && replace.command != 'I' &&
2102 replace.command != 'D')
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00002103 print_error("Extensions only for -A, -I and -D");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002104 }
2105 }
2106
Bart De Schuymer25c741d2002-06-23 18:54:34 +00002107 if ( !table && !(table = find_table(replace.name)) )
2108 print_error("Bad table name");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002109 // database stuff before ebtables stuff
2110 if (replace.command == 'b')
2111 allowdb(allowbc);
2112 if (replace.command == 'L' && replace.selected_hook == DATABASEHOOKNR)
2113 list_db();
2114
2115 if ( (replace.flags & OPT_COMMAND) && replace.command != 'L' &&
2116 replace.flags & OPT_ZERO )
2117 print_error("Command -Z only allowed together with command -L");
2118
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002119 // do this after parsing everything, so we can print specific info
2120 if (replace.command == 'h' && !(replace.flags & OPT_ZERO))
2121 print_help();
2122
2123 // do the final checks
Bart De Schuymer60332e02002-06-23 08:01:47 +00002124 if (replace.command == 'A' || replace.command == 'I' ||
2125 replace.command == 'D') {
2126 // this will put the hook_mask right for the chains
2127 check_for_loops();
2128 entries = to_chain();
2129 m_l = new_entry->m_list;
2130 w_l = new_entry->w_list;
2131 t = (struct ebt_u_target *)new_entry->t;
2132 while (m_l) {
2133 m = (struct ebt_u_match *)(m_l->m);
2134 m->final_check(new_entry, m->m, replace.name,
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +00002135 entries->hook_mask, 0);
Bart De Schuymer60332e02002-06-23 08:01:47 +00002136 m_l = m_l->next;
2137 }
2138 while (w_l) {
2139 w = (struct ebt_u_watcher *)(w_l->w);
2140 w->final_check(new_entry, w->w, replace.name,
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +00002141 entries->hook_mask, 0);
Bart De Schuymer60332e02002-06-23 08:01:47 +00002142 w_l = w_l->next;
2143 }
2144 t->final_check(new_entry, t->t, replace.name,
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +00002145 entries->hook_mask, 0);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002146 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002147 // so, the extensions can work with the host endian
2148 // the kernel does not have to do this ofcourse
2149 new_entry->ethproto = htons(new_entry->ethproto);
2150
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002151 if (replace.command == 'P')
2152 change_policy(policy);
2153 else if (replace.command == 'L') {
2154 list_rules();
2155 if (replace.flags & OPT_ZERO)
2156 zero_counters(zerochain);
2157 else
2158 exit(0);
2159 }
2160 if (replace.flags & OPT_ZERO)
2161 zero_counters(zerochain);
Bart De Schuymer1ab41562002-06-23 17:09:54 +00002162 else if (replace.command == 'F') {
2163 if (flush_chains() == -1)
2164 exit(0);
2165 } else if (replace.command == 'A' || replace.command == 'I') {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002166 add_rule(rule_nr);
Bart De Schuymer1ab41562002-06-23 17:09:54 +00002167 check_for_loops();
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +00002168 // do the final_check(), for all entries
2169 // needed when adding a rule that has a chain target
2170 i = -1;
2171 while (1) {
2172 struct ebt_u_entry *e;
2173
2174 i++;
2175 entries = nr_to_chain(i);
2176 if (!entries) {
2177 if (i < NF_BR_NUMHOOKS)
2178 continue;
2179 else
2180 break;
2181 }
2182 e = entries->entries;
2183 while (e) {
2184 // userspace extensions use host endian
2185 e->ethproto = ntohs(e->ethproto);
2186 do_final_checks(e, entries);
2187 e->ethproto = htons(e->ethproto);
2188 e = e->next;
2189 }
2190 }
Bart De Schuymer1ab41562002-06-23 17:09:54 +00002191 } else if (replace.command == 'D')
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002192 delete_rule(rule_nr);
Bart De Schuymer8d1d8942002-07-15 20:09:09 +00002193 // commands -N, -E, -X, --atomic-commit, --atomic-commit, --atomic-save,
2194 // --init-table fall through
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002195
2196 if (table->check)
2197 table->check(&replace);
2198
2199 deliver_table(&replace);
2200
Bart De Schuymered053432002-07-21 19:35:39 +00002201 if (replace.counterchanges)
2202 deliver_counters(&replace);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002203 return 0;
2204}