blob: c6d3100bcf22d939d818cfa29876e13cd1e6eb30 [file] [log] [blame]
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001/*
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00002 * ebtables.c, v2.0 July 2002
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00003 *
4 * Author: Bart De Schuymer
5 *
6 * This code is stongly inspired on the iptables code which is
7 * Copyright (C) 1999 Paul `Rusty' Russell & Michael J. Neuling
8 *
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License as
11 * published by the Free Software Foundation; either version 2 of the
12 * License, or (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 */
23
24#include <getopt.h>
25#include <string.h>
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000026#include <stdio.h>
27#include <stdlib.h>
Bart De Schuymerd4586482002-08-11 16:15:55 +000028#include <stdarg.h>
Bart De Schuymer41830412002-06-05 19:41:28 +000029#include <netinet/ether.h>
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000030#include "include/ebtables_u.h"
Bart De Schuymerc8531032002-06-14 21:55:29 +000031#include <unistd.h>
32#include <fcntl.h>
33#include <sys/wait.h>
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000034
Bart De Schuymerd4586482002-08-11 16:15:55 +000035// Don't use this function, use print_bug()
36void __print_bug(char *file, int line, char *format, ...)
37{
38 va_list l;
39
40 va_start(l, format);
41 printf(PROGNAME" v"PROGVERSION":%s:%d:--BUG--: \n", file, line);
42 vprintf(format, l);
43 printf("\n");
44 va_end(l);
45 exit (-1);
46}
47
Bart De Schuymerc56a31a2002-07-25 08:16:08 +000048// here are the number-name correspondences kept for the Ethernet
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000049// frame type field
50#define PROTOCOLFILE "/etc/ethertypes"
51
Bart De Schuymerc8531032002-06-14 21:55:29 +000052#ifndef PROC_SYS_MODPROBE
53#define PROC_SYS_MODPROBE "/proc/sys/kernel/modprobe"
54#endif
55
Bart De Schuymer60332e02002-06-23 08:01:47 +000056char *hooknames[NF_BR_NUMHOOKS] =
57{
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000058 [NF_BR_PRE_ROUTING]"PREROUTING",
59 [NF_BR_LOCAL_IN]"INPUT",
60 [NF_BR_FORWARD]"FORWARD",
61 [NF_BR_LOCAL_OUT]"OUTPUT",
62 [NF_BR_POST_ROUTING]"POSTROUTING",
63 [NF_BR_BROUTING]"BROUTING"
64};
65
66// default command line options
Bart De Schuymer8d1d8942002-07-15 20:09:09 +000067// do not mess around with the already assigned numbers unless
68// you know what you are doing
Bart De Schuymer62423742002-07-14 19:06:20 +000069static struct option ebt_original_options[] =
70{
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000071 { "append" , required_argument, 0, 'A' },
72 { "insert" , required_argument, 0, 'I' },
73 { "delete" , required_argument, 0, 'D' },
74 { "list" , optional_argument, 0, 'L' },
Bart De Schuymer9af14f92002-07-10 20:49:10 +000075 { "Lc" , no_argument , 0, 4 },
76 { "Ln" , no_argument , 0, 5 },
77 { "Lx" , no_argument , 0, 6 },
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000078 { "zero" , optional_argument, 0, 'Z' },
79 { "flush" , optional_argument, 0, 'F' },
80 { "policy" , required_argument, 0, 'P' },
81 { "in-interface" , required_argument, 0, 'i' },
82 { "in-if" , required_argument, 0, 'i' },
83 { "logical-in" , required_argument, 0, 2 },
84 { "logical-out" , required_argument, 0, 3 },
85 { "out-interface" , required_argument, 0, 'o' },
86 { "out-if" , required_argument, 0, 'o' },
87 { "version" , no_argument , 0, 'V' },
88 { "help" , no_argument , 0, 'h' },
89 { "jump" , required_argument, 0, 'j' },
90 { "proto" , required_argument, 0, 'p' },
91 { "protocol" , required_argument, 0, 'p' },
92 { "db" , required_argument, 0, 'b' },
93 { "source" , required_argument, 0, 's' },
94 { "src" , required_argument, 0, 's' },
95 { "destination" , required_argument, 0, 'd' },
96 { "dst" , required_argument, 0, 'd' },
97 { "table" , required_argument, 0, 't' },
Bart De Schuymerc8531032002-06-14 21:55:29 +000098 { "modprobe" , required_argument, 0, 'M' },
Bart De Schuymer1ab41562002-06-23 17:09:54 +000099 { "new-chain" , required_argument, 0, 'N' },
100 { "rename-chain" , required_argument, 0, 'E' },
101 { "delete-chain" , required_argument, 0, 'X' },
Bart De Schuymer62423742002-07-14 19:06:20 +0000102 { "atomic-init" , required_argument, 0, 7 },
Bart De Schuymer62423742002-07-14 19:06:20 +0000103 { "atomic-commit" , required_argument, 0, 8 },
104 { "atomic" , required_argument, 0, 9 },
105 { "atomic-save" , required_argument, 0, 10 },
Bart De Schuymer8d1d8942002-07-15 20:09:09 +0000106 { "init-table" , no_argument , 0, 11 },
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000107 { 0 }
108};
109
110static struct option *ebt_options = ebt_original_options;
111
112// yup, all the possible target names
Bart De Schuymer62423742002-07-14 19:06:20 +0000113char* standard_targets[NUM_STANDARD_TARGETS] =
114{
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000115 "ACCEPT",
116 "DROP",
117 "CONTINUE",
Bart De Schuymer60332e02002-06-23 08:01:47 +0000118 "RETURN",
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000119};
120
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000121unsigned char mac_type_unicast[ETH_ALEN] = {0,0,0,0,0,0};
122unsigned char msk_type_unicast[ETH_ALEN] = {1,0,0,0,0,0};
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000123unsigned char mac_type_multicast[ETH_ALEN] = {1,0,0,0,0,0};
124unsigned char msk_type_multicast[ETH_ALEN] = {1,0,0,0,0,0};
125unsigned char mac_type_broadcast[ETH_ALEN] = {255,255,255,255,255,255};
126unsigned char msk_type_broadcast[ETH_ALEN] = {255,255,255,255,255,255};
127
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000128// holds all the data
129static struct ebt_u_replace replace;
130
131// the chosen table
132static struct ebt_u_table *table = NULL;
133// the lists of supported tables, matches, watchers and targets
134static struct ebt_u_table *tables = NULL;
135static struct ebt_u_match *matches = NULL;
136static struct ebt_u_watcher *watchers = NULL;
137static struct ebt_u_target *targets = NULL;
138
139struct ebt_u_target *find_target(const char *name)
140{
141 struct ebt_u_target *t = targets;
142
143 while(t && strcmp(t->name, name))
144 t = t->next;
145 return t;
146}
147
148struct ebt_u_match *find_match(const char *name)
149{
150 struct ebt_u_match *m = matches;
151
152 while(m && strcmp(m->name, name))
153 m = m->next;
154 return m;
155}
156
157struct ebt_u_watcher *find_watcher(const char *name)
158{
159 struct ebt_u_watcher *w = watchers;
160
161 while(w && strcmp(w->name, name))
162 w = w->next;
163 return w;
164}
165
166struct ebt_u_table *find_table(char *name)
167{
168 struct ebt_u_table *t = tables;
169
170 while (t && strcmp(t->name, name))
171 t = t->next;
172 return t;
173}
174
175// The pointers in here are special:
176// The struct ebt_target * pointer is actually a struct ebt_u_target * pointer.
177// instead of making yet a few other structs, we just do a cast.
178// We need a struct ebt_u_target pointer because we know the address of the data
179// they point to won't change. We want to allow that the struct ebt_u_target.t
180// member can change.
181// Same holds for the struct ebt_match and struct ebt_watcher pointers
182struct ebt_u_entry *new_entry;
183
Bart De Schuymer62423742002-07-14 19:06:20 +0000184static void initialize_entry(struct ebt_u_entry *e)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000185{
186 e->bitmask = EBT_NOPROTO;
187 e->invflags = 0;
188 e->ethproto = 0;
189 strcpy(e->in, "");
190 strcpy(e->out, "");
191 strcpy(e->logical_in, "");
192 strcpy(e->logical_out, "");
193 e->m_list = NULL;
194 e->w_list = NULL;
195 // the init function of the standard target should have put the verdict
196 // on CONTINUE
197 e->t = (struct ebt_entry_target *)find_target(EBT_STANDARD_TARGET);
198 if (!e->t)
Bart De Schuymerd4586482002-08-11 16:15:55 +0000199 print_bug("Couldn't load standard target");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000200}
201
202// this doesn't free e, becoz the calling function might need e->next
Bart De Schuymer62423742002-07-14 19:06:20 +0000203static void free_u_entry(struct ebt_u_entry *e)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000204{
205 struct ebt_u_match_list *m_l, *m_l2;
206 struct ebt_u_watcher_list *w_l, *w_l2;
207
208 m_l = e->m_list;
209 while (m_l) {
210 m_l2 = m_l->next;
211 free(m_l->m);
212 free(m_l);
213 m_l = m_l2;
214 }
215 w_l = e->w_list;
216 while (w_l) {
217 w_l2 = w_l->next;
218 free(w_l->w);
219 free(w_l);
220 w_l = w_l2;
221 }
222 free(e->t);
223}
224
225// the user will use the match, so put it in new_entry
226static void add_match(struct ebt_u_match *m)
227{
228 struct ebt_u_match_list **m_list, *new;
229
230 m->used = 1;
Bart De Schuymerc56a31a2002-07-25 08:16:08 +0000231 for (m_list = &new_entry->m_list; *m_list; m_list = &(*m_list)->next);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000232 new = (struct ebt_u_match_list *)
233 malloc(sizeof(struct ebt_u_match_list));
234 if (!new)
235 print_memory();
236 *m_list = new;
237 new->next = NULL;
238 new->m = (struct ebt_entry_match *)m;
239}
240
241static void add_watcher(struct ebt_u_watcher *w)
242{
243 struct ebt_u_watcher_list **w_list;
244 struct ebt_u_watcher_list *new;
245
246 w->used = 1;
Bart De Schuymerc56a31a2002-07-25 08:16:08 +0000247 for (w_list = &new_entry->w_list; *w_list; w_list = &(*w_list)->next);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000248 new = (struct ebt_u_watcher_list *)
249 malloc(sizeof(struct ebt_u_watcher_list));
250 if (!new)
251 print_memory();
252 *w_list = new;
253 new->next = NULL;
254 new->w = (struct ebt_entry_watcher *)w;
255}
256
257static int global_option_offset = 0;
258#define OPTION_OFFSET 256
259static struct option *
260merge_options(struct option *oldopts, const struct option *newopts,
261 unsigned int *options_offset)
262{
263 unsigned int num_old, num_new, i;
264 struct option *merge;
265
266 if (!newopts || !oldopts || !options_offset)
267 print_bug("merge wrong");
268 for (num_old = 0; oldopts[num_old].name; num_old++);
269 for (num_new = 0; newopts[num_new].name; num_new++);
270
271 global_option_offset += OPTION_OFFSET;
272 *options_offset = global_option_offset;
273
274 merge = malloc(sizeof(struct option) * (num_new + num_old + 1));
275 if (!merge)
276 print_memory();
277 memcpy(merge, oldopts, num_old * sizeof(struct option));
278 for (i = 0; i < num_new; i++) {
279 merge[num_old + i] = newopts[i];
280 merge[num_old + i].val += *options_offset;
281 }
282 memset(merge + num_old + num_new, 0, sizeof(struct option));
283 // only free dynamically allocated stuff
284 if (oldopts != ebt_original_options)
285 free(oldopts);
286
287 return merge;
288}
289
290void register_match(struct ebt_u_match *m)
291{
292 int size = m->size + sizeof(struct ebt_entry_match);
293 struct ebt_u_match **i;
294
295 m->m = (struct ebt_entry_match *)malloc(size);
296 if (!m->m)
297 print_memory();
298 strcpy(m->m->u.name, m->name);
299 m->m->match_size = m->size;
300 ebt_options = merge_options
301 (ebt_options, m->extra_ops, &(m->option_offset));
302 m->init(m->m);
303
304 for (i = &matches; *i; i = &((*i)->next));
305 m->next = NULL;
306 *i = m;
307}
308
309void register_watcher(struct ebt_u_watcher *w)
310{
311 int size = w->size + sizeof(struct ebt_entry_watcher);
312 struct ebt_u_watcher **i;
313
314 w->w = (struct ebt_entry_watcher *)malloc(size);
315 if (!w->w)
316 print_memory();
317 strcpy(w->w->u.name, w->name);
318 w->w->watcher_size = w->size;
319 ebt_options = merge_options
320 (ebt_options, w->extra_ops, &(w->option_offset));
321 w->init(w->w);
322
323 for (i = &watchers; *i; i = &((*i)->next));
324 w->next = NULL;
325 *i = w;
326}
327
328void register_target(struct ebt_u_target *t)
329{
330 int size = t->size + sizeof(struct ebt_entry_target);
331 struct ebt_u_target **i;
332
333 t->t = (struct ebt_entry_target *)malloc(size);
334 if (!t->t)
335 print_memory();
336 strcpy(t->t->u.name, t->name);
337 t->t->target_size = t->size;
338 ebt_options = merge_options
339 (ebt_options, t->extra_ops, &(t->option_offset));
340 t->init(t->t);
Bart De Schuymerc56a31a2002-07-25 08:16:08 +0000341
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000342 for (i = &targets; *i; i = &((*i)->next));
343 t->next = NULL;
344 *i = t;
345}
346
347void register_table(struct ebt_u_table *t)
348{
349 t->next = tables;
350 tables = t;
351}
352
Bart De Schuymerc8531032002-06-14 21:55:29 +0000353// blatently stolen (again) from iptables.c userspace program
354// find out where the modprobe utility is located
355static char *get_modprobe(void)
356{
357 int procfile;
358 char *ret;
359
360 procfile = open(PROC_SYS_MODPROBE, O_RDONLY);
361 if (procfile < 0)
362 return NULL;
363
364 ret = malloc(1024);
365 if (ret) {
366 switch (read(procfile, ret, 1024)) {
367 case -1: goto fail;
368 case 1024: goto fail; /* Partial read. Wierd */
369 }
370 if (ret[strlen(ret)-1]=='\n')
371 ret[strlen(ret)-1]=0;
372 close(procfile);
373 return ret;
374 }
375 fail:
376 free(ret);
377 close(procfile);
378 return NULL;
379}
380
Bart De Schuymerc8531032002-06-14 21:55:29 +0000381int ebtables_insmod(const char *modname, const char *modprobe)
382{
383 char *buf = NULL;
384 char *argv[3];
385
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000386 // If they don't explicitly set it, read out of kernel
Bart De Schuymerc8531032002-06-14 21:55:29 +0000387 if (!modprobe) {
388 buf = get_modprobe();
389 if (!buf)
390 return -1;
391 modprobe = buf;
392 }
393
394 switch (fork()) {
395 case 0:
396 argv[0] = (char *)modprobe;
397 argv[1] = (char *)modname;
398 argv[2] = NULL;
399 execv(argv[0], argv);
400
401 /* not usually reached */
402 exit(0);
403 case -1:
404 return -1;
405
406 default: /* parent */
407 wait(NULL);
408 }
409
410 free(buf);
411 return 0;
412}
413
Bart De Schuymerbbca3202002-06-05 18:55:44 +0000414// helper function: processes a line of data from the file /etc/ethertypes
Bart De Schuymer62423742002-07-14 19:06:20 +0000415static int get_a_line(char *buffer, char *value, FILE *ifp)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000416{
Bart De Schuymerf662ce52002-07-19 18:40:55 +0000417 char line[80], *p;
418 const char delim[] = " \t\n";
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000419
Bart De Schuymerf662ce52002-07-19 18:40:55 +0000420 while (fgets(line, sizeof(line), ifp)) {
421 p = strtok(line, delim);
422 if (!p || p[0] == '#')
423 continue;
424 if (strlen(p) > 20)
425 continue;
426 strcpy(buffer, p);
427 p = strtok(NULL, delim);
428 if (!p || strlen(p) > 10)
429 continue;
430 strcpy(value, p);
431 return 0;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000432 }
Bart De Schuymerf662ce52002-07-19 18:40:55 +0000433 return -1;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000434}
435
Bart De Schuymerb909f9b2002-06-26 18:35:31 +0000436// translate a hexadecimal number to a protocol name, parsing /etc/ethertypes
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000437// returns 0 on success
Bart De Schuymerc5c3c2d2002-08-16 19:48:03 +0000438// this demands the name buffer to be of size at least 21
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000439int number_to_name(unsigned short proto, char *name)
440{
441 FILE *ifp;
Bart De Schuymerf662ce52002-07-19 18:40:55 +0000442 char buffer[21], value[11], *bfr;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000443 unsigned short i;
444
445 if ( !(ifp = fopen(PROTOCOLFILE, "r")) )
446 return -1;
447 while (1) {
448 if (get_a_line(buffer, value, ifp)) {
449 fclose(ifp);
450 return -1;
451 }
452 i = (unsigned short) strtol(value, &bfr, 16);
453 if (*bfr != '\0' || i != proto)
454 continue;
455 strcpy(name, buffer);
456 fclose(ifp);
457 return 0;
458 }
459}
460
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000461// we use replace.flags, so we can't use the following values:
462// 0x01 == OPT_COMMAND, 0x02 == OPT_TABLE, 0x100 == OPT_ZERO
463#define LIST_N 0x04
464#define LIST_C 0x08
465#define LIST_X 0x10
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000466// helper function for list_rules()
Bart De Schuymer60332e02002-06-23 08:01:47 +0000467static void list_em(struct ebt_u_entries *entries)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000468{
469 int i, j, space = 0, digits;
470 struct ebt_u_entry *hlp;
471 struct ebt_u_match_list *m_l;
472 struct ebt_u_watcher_list *w_l;
473 struct ebt_u_match *m;
474 struct ebt_u_watcher *w;
475 struct ebt_u_target *t;
476 char name[21];
477
Bart De Schuymer60332e02002-06-23 08:01:47 +0000478 hlp = entries->entries;
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000479 if (replace.flags & LIST_X && entries->policy != EBT_ACCEPT) {
480 printf("ebtables -t %s -P %s %s\n", replace.name,
481 entries->name, standard_targets[-entries->policy - 1]);
482 } else if (!(replace.flags & LIST_X)) {
Bart De Schuymerc87c9642002-08-01 15:34:16 +0000483 printf("\nBridge chain: %s, entries: %d, policy: %s\n",
484 entries->name, entries->nentries,
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000485 standard_targets[-entries->policy - 1]);
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000486 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000487
Bart De Schuymer60332e02002-06-23 08:01:47 +0000488 i = entries->nentries;
Bart De Schuymerf8f8f292002-06-25 15:43:57 +0000489 while (i > 9) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000490 space++;
491 i /= 10;
492 }
493
Bart De Schuymer60332e02002-06-23 08:01:47 +0000494 for (i = 0; i < entries->nentries; i++) {
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000495 if (replace.flags & LIST_N) {
496 digits = 0;
497 // A little work to get nice rule numbers.
498 j = i + 1;
499 while (j > 9) {
500 digits++;
501 j /= 10;
502 }
503 for (j = 0; j < space - digits; j++)
504 printf(" ");
505 printf("%d. ", i + 1);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000506 }
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000507 if (replace.flags & LIST_X)
508 printf("ebtables -t %s -A %s ",
509 replace.name, entries->name);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000510
511 // Don't print anything about the protocol if no protocol was
512 // specified, obviously this means any protocol will do.
513 if (!(hlp->bitmask & EBT_NOPROTO)) {
Bart De Schuymer60332e02002-06-23 08:01:47 +0000514 printf("-p ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000515 if (hlp->invflags & EBT_IPROTO)
516 printf("! ");
517 if (hlp->bitmask & EBT_802_3)
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000518 printf("Length ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000519 else {
520 if (number_to_name(ntohs(hlp->ethproto), name))
Bart De Schuymer60332e02002-06-23 08:01:47 +0000521 printf("0x%x ", ntohs(hlp->ethproto));
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000522 else
Bart De Schuymer60332e02002-06-23 08:01:47 +0000523 printf("%s ", name);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000524 }
525 }
526 if (hlp->bitmask & EBT_SOURCEMAC) {
527 char hlpmsk[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
528
Bart De Schuymer60332e02002-06-23 08:01:47 +0000529 printf("-s ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000530 if (hlp->invflags & EBT_ISOURCE)
531 printf("! ");
532 if (!memcmp(hlp->sourcemac, mac_type_unicast, 6) &&
533 !memcmp(hlp->sourcemsk, msk_type_unicast, 6)) {
534 printf("Unicast");
535 goto endsrc;
536 }
537 if (!memcmp(hlp->sourcemac, mac_type_multicast, 6) &&
538 !memcmp(hlp->sourcemsk, msk_type_multicast, 6)) {
539 printf("Multicast");
540 goto endsrc;
541 }
542 if (!memcmp(hlp->sourcemac, mac_type_broadcast, 6) &&
543 !memcmp(hlp->sourcemsk, msk_type_broadcast, 6)) {
544 printf("Broadcast");
545 goto endsrc;
546 }
Bart De Schuymer41830412002-06-05 19:41:28 +0000547 printf("%s", ether_ntoa((struct ether_addr *)
548 hlp->sourcemac));
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000549 if (memcmp(hlp->sourcemsk, hlpmsk, 6)) {
550 printf("/");
Bart De Schuymer41830412002-06-05 19:41:28 +0000551 printf("%s", ether_ntoa((struct ether_addr *)
552 hlp->sourcemsk));
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000553 }
554endsrc:
Bart De Schuymer60332e02002-06-23 08:01:47 +0000555 printf(" ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000556 }
557 if (hlp->bitmask & EBT_DESTMAC) {
558 char hlpmsk[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
559
Bart De Schuymer60332e02002-06-23 08:01:47 +0000560 printf("-d ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000561 if (hlp->invflags & EBT_IDEST)
562 printf("! ");
563 if (!memcmp(hlp->destmac, mac_type_unicast, 6) &&
564 !memcmp(hlp->destmsk, msk_type_unicast, 6)) {
565 printf("Unicast");
566 goto enddst;
567 }
568 if (!memcmp(hlp->destmac, mac_type_multicast, 6) &&
569 !memcmp(hlp->destmsk, msk_type_multicast, 6)) {
570 printf("Multicast");
571 goto enddst;
572 }
573 if (!memcmp(hlp->destmac, mac_type_broadcast, 6) &&
574 !memcmp(hlp->destmsk, msk_type_broadcast, 6)) {
575 printf("Broadcast");
576 goto enddst;
577 }
Bart De Schuymer41830412002-06-05 19:41:28 +0000578 printf("%s", ether_ntoa((struct ether_addr *)
579 hlp->destmac));
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000580 if (memcmp(hlp->destmsk, hlpmsk, 6)) {
581 printf("/");
Bart De Schuymer41830412002-06-05 19:41:28 +0000582 printf("%s", ether_ntoa((struct ether_addr *)
583 hlp->destmsk));
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000584 }
585enddst:
Bart De Schuymer60332e02002-06-23 08:01:47 +0000586 printf(" ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000587 }
588 if (hlp->in[0] != '\0') {
Bart De Schuymer60332e02002-06-23 08:01:47 +0000589 printf("-i ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000590 if (hlp->invflags & EBT_IIN)
591 printf("! ");
Bart De Schuymer60332e02002-06-23 08:01:47 +0000592 printf("%s ", hlp->in);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000593 }
594 if (hlp->logical_in[0] != '\0') {
Bart De Schuymer60332e02002-06-23 08:01:47 +0000595 printf("--logical-in ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000596 if (hlp->invflags & EBT_ILOGICALIN)
597 printf("! ");
Bart De Schuymer60332e02002-06-23 08:01:47 +0000598 printf("%s ", hlp->logical_in);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000599 }
600 if (hlp->logical_out[0] != '\0') {
Bart De Schuymer60332e02002-06-23 08:01:47 +0000601 printf("--logical-out ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000602 if (hlp->invflags & EBT_ILOGICALOUT)
603 printf("! ");
Bart De Schuymerb3d8f262002-07-07 14:26:15 +0000604 printf("%s ", hlp->logical_out);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000605 }
606 if (hlp->out[0] != '\0') {
Bart De Schuymer60332e02002-06-23 08:01:47 +0000607 printf("-o ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000608 if (hlp->invflags & EBT_IOUT)
609 printf("! ");
Bart De Schuymerb3d8f262002-07-07 14:26:15 +0000610 printf("%s ", hlp->out);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000611 }
612
613 m_l = hlp->m_list;
614 while (m_l) {
615 m = find_match(m_l->m->u.name);
616 if (!m)
617 print_bug("Match not found");
618 m->print(hlp, m_l->m);
619 m_l = m_l->next;
620 }
621 w_l = hlp->w_list;
622 while (w_l) {
623 w = find_watcher(w_l->w->u.name);
624 if (!w)
625 print_bug("Watcher not found");
626 w->print(hlp, w_l->w);
627 w_l = w_l->next;
628 }
629
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000630 printf("-j ");
631 if (strcmp(hlp->t->u.name, EBT_STANDARD_TARGET))
632 printf("%s ", hlp->t->u.name);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000633 t = find_target(hlp->t->u.name);
634 if (!t)
635 print_bug("Target not found");
636 t->print(hlp, hlp->t);
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000637 if (replace.flags & LIST_C)
Bart De Schuymer73fccca2002-10-17 22:00:23 +0000638 printf(", pcnt = %llu -- bcnt = %llu",
639 replace.counters[entries->counter_offset + i].pcnt,
640 replace.counters[entries->counter_offset + i].bcnt);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000641 printf("\n");
642 hlp = hlp->next;
643 }
644}
645
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000646struct ebt_u_entries *nr_to_chain(int nr)
Bart De Schuymer60332e02002-06-23 08:01:47 +0000647{
648 if (nr == -1)
649 return NULL;
650 if (nr < NF_BR_NUMHOOKS)
651 return replace.hook_entry[nr];
652 else {
653 int i;
654 struct ebt_u_chain_list *cl = replace.udc;
655
656 i = nr - NF_BR_NUMHOOKS;
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000657 while (i > 0 && cl) {
Bart De Schuymer60332e02002-06-23 08:01:47 +0000658 cl = cl->next;
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000659 i--;
660 }
Bart De Schuymer60332e02002-06-23 08:01:47 +0000661 if (cl)
662 return cl->udc;
663 else
664 return NULL;
665 }
666}
667
668static struct ebt_u_entries *to_chain()
669{
670 return nr_to_chain(replace.selected_hook);
671}
672
673struct ebt_u_stack
674{
675 int chain_nr;
676 int n;
677 struct ebt_u_entry *e;
678 struct ebt_u_entries *entries;
679};
680
Bart De Schuymer62423742002-07-14 19:06:20 +0000681static void check_for_loops()
Bart De Schuymer60332e02002-06-23 08:01:47 +0000682{
683 int chain_nr , i, j , k, sp = 0, verdict;
684 struct ebt_u_entries *entries, *entries2;
685 struct ebt_u_stack *stack = NULL;
686 struct ebt_u_entry *e;
687
688 i = -1;
689 // initialize hook_mask to 0
690 while (1) {
691 i++;
692 if (i < NF_BR_NUMHOOKS && !(replace.valid_hooks & (1 << i)))
693 continue;
694 entries = nr_to_chain(i);
695 if (!entries)
696 break;
697 entries->hook_mask = 0;
698 }
699 if (i > NF_BR_NUMHOOKS) {
700 stack = (struct ebt_u_stack *)malloc((i - NF_BR_NUMHOOKS) *
701 sizeof(struct ebt_u_stack));
702 if (!stack)
703 print_memory();
704 }
705
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000706 // check for loops, starting from every base chain
Bart De Schuymer60332e02002-06-23 08:01:47 +0000707 for (i = 0; i < NF_BR_NUMHOOKS; i++) {
708 if (!(replace.valid_hooks & (1 << i)))
709 continue;
710 entries = nr_to_chain(i);
Bart De Schuymerb26649e2002-07-25 14:51:54 +0000711 // (1 << NF_BR_NUMHOOKS) implies it's a standard chain
712 // (usefull in the final_check() funtions)
713 entries->hook_mask = (1 << i) | (1 << NF_BR_NUMHOOKS);
Bart De Schuymer60332e02002-06-23 08:01:47 +0000714 chain_nr = i;
715
716 e = entries->entries;
717 for (j = 0; j < entries->nentries; j++) {
718 if (strcmp(e->t->u.name, EBT_STANDARD_TARGET))
719 goto letscontinue;
720 verdict = ((struct ebt_standard_target *)(e->t))->verdict;
721 if (verdict < 0)
722 goto letscontinue;
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000723 entries2 = nr_to_chain(verdict + NF_BR_NUMHOOKS);
Bart De Schuymer60332e02002-06-23 08:01:47 +0000724 entries2->hook_mask |= entries->hook_mask;
725 // now see if we've been here before
726 for (k = 0; k < sp; k++)
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000727 if (stack[k].chain_nr == verdict + NF_BR_NUMHOOKS)
Bart De Schuymer1a0a9c32002-06-24 21:10:16 +0000728 print_error("Loop from chain %s to chain %s",
Bart De Schuymerc56a31a2002-07-25 08:16:08 +0000729 nr_to_chain(chain_nr)->name,
730 nr_to_chain(stack[k].chain_nr)->name);
Bart De Schuymer60332e02002-06-23 08:01:47 +0000731 // jump to the chain, make sure we know how to get back
732 stack[sp].chain_nr = chain_nr;
733 stack[sp].n = j;
734 stack[sp].entries = entries;
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000735 stack[sp].e = e;
736 sp++;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000737 j = -1;
738 e = entries2->entries;
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000739 chain_nr = verdict + NF_BR_NUMHOOKS;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000740 entries = entries2;
741 continue;
742letscontinue:
743 e = e->next;
744 }
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000745 // we are at the end of a standard chain
Bart De Schuymer60332e02002-06-23 08:01:47 +0000746 if (sp == 0)
747 continue;
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000748 // go back to the chain one level higher
Bart De Schuymer60332e02002-06-23 08:01:47 +0000749 sp--;
750 j = stack[sp].n;
751 chain_nr = stack[sp].chain_nr;
752 e = stack[sp].e;
753 entries = stack[sp].entries;
754 goto letscontinue;
755 }
756 free(stack);
757 return;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000758}
759
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000760// parse the chain name and return the corresponding nr
Bart De Schuymerdd5594b2002-06-26 18:05:20 +0000761// returns -1 on failure
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000762int get_hooknr(char* arg)
763{
764 int i;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000765 struct ebt_u_chain_list *cl = replace.udc;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000766
Bart De Schuymer60332e02002-06-23 08:01:47 +0000767 for (i = 0; i < NF_BR_NUMHOOKS; i++) {
768 if (!(replace.valid_hooks & (1 << i)))
769 continue;
770 if (!strcmp(arg, replace.hook_entry[i]->name))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000771 return i;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000772 }
773 while(cl) {
774 if (!strcmp(arg, cl->udc->name))
775 return i;
776 i++;
777 cl = cl->next;
778 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000779 return -1;
780}
781
782// yup, print out help
Bart De Schuymer62423742002-07-14 19:06:20 +0000783static void print_help()
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000784{
785 struct ebt_u_match_list *m_l;
786 struct ebt_u_watcher_list *w_l;
787
Bart De Schuymerd4586482002-08-11 16:15:55 +0000788 printf(PROGNAME" v"PROGVERSION" ("PROGDATE")\n"
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000789"Usage:\n"
790"ebtables -[ADI] chain rule-specification [options]\n"
791"ebtables -P chain target\n"
792"ebtables -[LFZ] [chain]\n"
793"ebtables -[b] [y,n]\n"
794"Commands:\n"
Bart De Schuymer23f6dcf2002-08-17 09:14:07 +0000795"--append -A chain : append to chain\n"
796"--delete -D chain : delete matching rule from chain\n"
797"--delete -D chain rulenum : delete rule at position rulenum from chain\n"
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000798"--insert -I chain rulenum : insert rule at position rulenum in chain\n"
Bart De Schuymer23f6dcf2002-08-17 09:14:07 +0000799"--list -L [chain] : list the rules in a chain or in all chains\n"
800"--flush -F [chain] : delete all rules in chain or in all chains\n"
801"--init-table : replace the kernel table with the initial table\n"
802"--zero -Z [chain] : put counters on zero in chain or in all chains\n"
803"--policy -P chain target : change policy on chain to target\n"
804"--new-chain -N chain : create a user defined chain\n"
805"--rename-chain -E old new : rename a chain\n"
806"--delete-chain -X chain : delete a user defined chain\n"
Bart De Schuymer62423742002-07-14 19:06:20 +0000807"--atomic-commit file : update the kernel w/ the table contained in file\n"
808"--atomic-init file : put the initial kernel table into file\n"
809"--atomic-save file : put the current kernel table into file\n"
810"--atomic file : write changes to file instead of kernel\n"
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000811"Options:\n"
812"--proto -p [!] proto : protocol hexadecimal, by name or LENGTH\n"
813"--src -s [!] address[/mask]: source mac address\n"
814"--dst -d [!] address[/mask]: destination mac address\n"
815"--in-if -i [!] name : network input interface name\n"
816"--out-if -o [!] name : network output interface name\n"
817"--logical-in [!] name : logical bridge input interface name\n"
818"--logical-out [!] name : logical bridge output interface name\n"
Bart De Schuymer5cbc8e02002-07-14 21:15:28 +0000819"--modprobe -M program : try to insert modules using this program\n"
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000820"--version -V : print package version\n"
Bart De Schuymerd4586482002-08-11 16:15:55 +0000821"\n");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000822
823 m_l = new_entry->m_list;
824 while (m_l) {
825 ((struct ebt_u_match *)m_l->m)->help();
826 printf("\n");
827 m_l = m_l->next;
828 }
829 w_l = new_entry->w_list;
830 while (w_l) {
831 ((struct ebt_u_watcher *)w_l->w)->help();
832 printf("\n");
833 w_l = w_l->next;
834 }
835 ((struct ebt_u_target *)new_entry->t)->help();
836 printf("\n");
837 if (table->help)
838 table->help(hooknames);
839 exit(0);
840}
841
842// execute command L
843static void list_rules()
844{
845 int i;
846
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000847 if (!(replace.flags & LIST_X))
848 printf("Bridge table: %s\n", table->name);
Bart De Schuymer60332e02002-06-23 08:01:47 +0000849 if (replace.selected_hook != -1) {
850 list_em(to_chain());
851 } else {
852 struct ebt_u_chain_list *cl = replace.udc;
853
Bart De Schuymer9af14f92002-07-10 20:49:10 +0000854 // create new chains and rename standard chains when necessary
855 if (replace.flags & LIST_X) {
856 while (cl) {
857 printf("ebtables -t %s -N %s\n", replace.name,
858 cl->udc->name);
859 cl = cl->next;
860 }
861 cl = replace.udc;
862 for (i = 0; i < NF_BR_NUMHOOKS; i++)
863 if (replace.valid_hooks & (1 << i) &&
864 strcmp(replace.hook_entry[i]->name, hooknames[i]))
865 printf("ebtables -t %s -E %s %s\n",
866 replace.name, hooknames[i],
867 replace.hook_entry[i]->name);
868 }
Bart De Schuymer60332e02002-06-23 08:01:47 +0000869 i = 0;
870 while (1) {
871 if (i < NF_BR_NUMHOOKS) {
872 if (replace.valid_hooks & (1 << i))
873 list_em(replace.hook_entry[i]);
874 i++;
875 continue;
876 } else {
877 if (!cl)
878 break;
879 list_em(cl->udc);
880 cl = cl->next;
881 }
882 }
883 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000884}
885
886// execute command P
887static void change_policy(int policy)
888{
889 int i;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000890 struct ebt_u_entries *entries = to_chain();
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000891
892 // don't do anything if the policy is the same
Bart De Schuymer60332e02002-06-23 08:01:47 +0000893 if (entries->policy != policy) {
894 entries->policy = policy;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000895 replace.num_counters = replace.nentries;
896 if (replace.nentries) {
897 // '+ 1' for the CNT_END
Bart De Schuymered053432002-07-21 19:35:39 +0000898 if (!(replace.counterchanges = (unsigned short *) malloc(
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000899 (replace.nentries + 1) * sizeof(unsigned short))))
900 print_memory();
901 // done nothing special to the rules
902 for (i = 0; i < replace.nentries; i++)
Bart De Schuymered053432002-07-21 19:35:39 +0000903 replace.counterchanges[i] = CNT_NORM;
904 replace.counterchanges[replace.nentries] = CNT_END;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000905 }
906 else
Bart De Schuymered053432002-07-21 19:35:39 +0000907 replace.counterchanges = NULL;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000908 }
909 else
910 exit(0);
911}
912
913// flush one chain or the complete table
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000914// -1 == nothing to do
915// 0 == give back to kernel
916static int flush_chains()
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000917{
Bart De Schuymer60332e02002-06-23 08:01:47 +0000918 int i, j, oldnentries, numdel;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000919 unsigned short *cnt;
920 struct ebt_u_entry *u_e, *tmp;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000921 struct ebt_u_entries *entries = to_chain();
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000922
923 // flush whole table
Bart De Schuymer60332e02002-06-23 08:01:47 +0000924 if (!entries) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000925 if (replace.nentries == 0)
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000926 return -1;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000927 replace.nentries = 0;
928 // no need for the kernel to give us counters back
929 replace.num_counters = 0;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000930
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000931 // free everything and zero (n)entries
Bart De Schuymer60332e02002-06-23 08:01:47 +0000932 i = -1;
933 while (1) {
934 i++;
935 entries = nr_to_chain(i);
936 if (!entries) {
937 if (i < NF_BR_NUMHOOKS)
938 continue;
939 else
940 break;
941 }
942 entries->nentries = 0;
943 entries->counter_offset = 0;
944 u_e = entries->entries;
945 entries->entries = NULL;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000946 while (u_e) {
947 free_u_entry(u_e);
948 tmp = u_e->next;
949 free(u_e);
950 u_e = tmp;
951 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000952 }
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000953 return 0;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000954 }
955
Bart De Schuymer60332e02002-06-23 08:01:47 +0000956 if (entries->nentries == 0)
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000957 return -1;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000958 oldnentries = replace.nentries;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000959 replace.nentries -= entries->nentries;
960 numdel = entries->nentries;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000961
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000962 if (replace.nentries) {
963 // +1 for CNT_END
Bart De Schuymered053432002-07-21 19:35:39 +0000964 if ( !(replace.counterchanges = (unsigned short *)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000965 malloc((oldnentries + 1) * sizeof(unsigned short))) )
966 print_memory();
Bart De Schuymer60332e02002-06-23 08:01:47 +0000967 }
968 // delete the counters belonging to the specified chain,
969 // update counter_offset
970 i = -1;
Bart De Schuymered053432002-07-21 19:35:39 +0000971 cnt = replace.counterchanges;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000972 while (1) {
973 i++;
974 entries = nr_to_chain(i);
975 if (!entries) {
976 if (i < NF_BR_NUMHOOKS)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000977 continue;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000978 else
979 break;
980 }
981 if (i > replace.selected_hook)
982 entries->counter_offset -= numdel;
983 if (replace.nentries) {
984 for (j = 0; j < entries->nentries; j++) {
985 if (i == replace.selected_hook)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000986 *cnt = CNT_DEL;
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000987 else
988 *cnt = CNT_NORM;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000989 cnt++;
990 }
991 }
Bart De Schuymer60332e02002-06-23 08:01:47 +0000992 }
993
994 if (replace.nentries) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000995 *cnt = CNT_END;
996 replace.num_counters = oldnentries;
997 }
998 else
999 replace.num_counters = 0;
1000
Bart De Schuymer60332e02002-06-23 08:01:47 +00001001 entries = to_chain();
1002 entries->nentries = 0;
1003 u_e = entries->entries;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001004 while (u_e) {
1005 free_u_entry(u_e);
1006 tmp = u_e->next;
1007 free(u_e);
1008 u_e = tmp;
1009 }
Bart De Schuymer60332e02002-06-23 08:01:47 +00001010 entries->entries = NULL;
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001011 return 0;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001012}
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001013
1014// -1 == no match
1015static int check_rule_exists(int rule_nr)
1016{
1017 struct ebt_u_entry *u_e;
1018 struct ebt_u_match_list *m_l, *m_l2;
1019 struct ebt_u_match *m;
1020 struct ebt_u_watcher_list *w_l, *w_l2;
1021 struct ebt_u_watcher *w;
1022 struct ebt_u_target *t = (struct ebt_u_target *)new_entry->t;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001023 struct ebt_u_entries *entries = to_chain();
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001024 int i, j, k;
1025
1026 // handle '-D chain rulenr' command
1027 if (rule_nr != -1) {
Bart De Schuymer60332e02002-06-23 08:01:47 +00001028 if (rule_nr > entries->nentries)
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001029 return -1;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001030 // user starts counting from 1
1031 return rule_nr - 1;
1032 }
Bart De Schuymer60332e02002-06-23 08:01:47 +00001033 u_e = entries->entries;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001034 // check for an existing rule (if there are duplicate rules,
1035 // take the first occurance)
Bart De Schuymer60332e02002-06-23 08:01:47 +00001036 for (i = 0; i < entries->nentries; i++, u_e = u_e->next) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001037 if (!u_e)
1038 print_bug("Hmm, trouble");
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001039 if (u_e->ethproto != new_entry->ethproto)
1040 continue;
1041 if (strcmp(u_e->in, new_entry->in))
1042 continue;
1043 if (strcmp(u_e->out, new_entry->out))
1044 continue;
1045 if (strcmp(u_e->logical_in, new_entry->logical_in))
1046 continue;
1047 if (strcmp(u_e->logical_out, new_entry->logical_out))
1048 continue;
1049 if (new_entry->bitmask & EBT_SOURCEMAC &&
1050 memcmp(u_e->sourcemac, new_entry->sourcemac, ETH_ALEN))
1051 continue;
1052 if (new_entry->bitmask & EBT_DESTMAC &&
1053 memcmp(u_e->destmac, new_entry->destmac, ETH_ALEN))
1054 continue;
1055 if (new_entry->bitmask != u_e->bitmask ||
1056 new_entry->invflags != u_e->invflags)
1057 continue;
1058 // compare all matches
1059 m_l = new_entry->m_list;
1060 j = 0;
1061 while (m_l) {
1062 m = (struct ebt_u_match *)(m_l->m);
1063 m_l2 = u_e->m_list;
1064 while (m_l2 && strcmp(m_l2->m->u.name, m->m->u.name))
1065 m_l2 = m_l2->next;
1066 if (!m_l2 || !m->compare(m->m, m_l2->m))
1067 goto letscontinue;
1068 j++;
1069 m_l = m_l->next;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001070 }
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001071 // now be sure they have the same nr of matches
1072 k = 0;
1073 m_l = u_e->m_list;
1074 while (m_l) {
1075 k++;
1076 m_l = m_l->next;
1077 }
1078 if (j != k)
1079 continue;
1080
1081 // compare all watchers
1082 w_l = new_entry->w_list;
1083 j = 0;
1084 while (w_l) {
1085 w = (struct ebt_u_watcher *)(w_l->w);
1086 w_l2 = u_e->w_list;
1087 while (w_l2 && strcmp(w_l2->w->u.name, w->w->u.name))
1088 w_l2 = w_l2->next;
1089 if (!w_l2 || !w->compare(w->w, w_l2->w))
1090 goto letscontinue;
1091 j++;
1092 w_l = w_l->next;
1093 }
1094 k = 0;
1095 w_l = u_e->w_list;
1096 while (w_l) {
1097 k++;
1098 w_l = w_l->next;
1099 }
1100 if (j != k)
1101 continue;
1102 if (strcmp(t->t->u.name, u_e->t->u.name))
1103 continue;
1104 if (!t->compare(t->t, u_e->t))
1105 continue;
1106 return i;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001107letscontinue:
1108 }
1109 return -1;
1110}
1111
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001112// execute command A or I
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001113static void add_rule(int rule_nr)
1114{
1115 int i, j;
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001116 struct ebt_u_entry **u_e;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001117 unsigned short *cnt;
1118 struct ebt_u_match_list *m_l;
1119 struct ebt_u_watcher_list *w_l;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001120 struct ebt_u_entries *entries = to_chain(), *entries2;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001121
1122 if (rule_nr != -1) { // command -I
Bart De Schuymer60332e02002-06-23 08:01:47 +00001123 if (--rule_nr > entries->nentries)
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001124 print_error("rule nr too high: %d > %d", rule_nr + 1,
1125 entries->nentries + 1);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001126 } else
Bart De Schuymer60332e02002-06-23 08:01:47 +00001127 rule_nr = entries->nentries;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001128 // we're adding one rule
1129 replace.num_counters = replace.nentries;
1130 replace.nentries++;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001131 entries->nentries++;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001132
1133 // handle counter stuff
1134 // +1 for CNT_END
Bart De Schuymered053432002-07-21 19:35:39 +00001135 if ( !(replace.counterchanges = (unsigned short *)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001136 malloc((replace.nentries + 1) * sizeof(unsigned short))) )
1137 print_memory();
Bart De Schuymered053432002-07-21 19:35:39 +00001138 cnt = replace.counterchanges;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001139 for (i = 0; i < replace.selected_hook; i++) {
Bart De Schuymer60332e02002-06-23 08:01:47 +00001140 if (i < NF_BR_NUMHOOKS && !(replace.valid_hooks & (1 << i)))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001141 continue;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001142 entries2 = nr_to_chain(i);
1143 for (j = 0; j < entries2->nentries; j++) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001144 *cnt = CNT_NORM;
1145 cnt++;
1146 }
1147 }
1148 for (i = 0; i < rule_nr; i++) {
1149 *cnt = CNT_NORM;
1150 cnt++;
1151 }
1152 *cnt = CNT_ADD;
1153 cnt++;
Bart De Schuymered053432002-07-21 19:35:39 +00001154 while (cnt != replace.counterchanges + replace.nentries) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001155 *cnt = CNT_NORM;
1156 cnt++;
1157 }
1158 *cnt = CNT_END;
1159
1160 // go to the right position in the chain
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001161 u_e = &entries->entries;
1162 for (i = 0; i < rule_nr; i++)
1163 u_e = &(*u_e)->next;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001164 // insert the rule
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001165 new_entry->next = *u_e;
1166 *u_e = new_entry;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001167
1168 // put the ebt_[match, watcher, target] pointers in place
1169 m_l = new_entry->m_list;
1170 while (m_l) {
1171 m_l->m = ((struct ebt_u_match *)m_l->m)->m;
1172 m_l = m_l->next;
1173 }
1174 w_l = new_entry->w_list;
1175 while (w_l) {
1176 w_l->w = ((struct ebt_u_watcher *)w_l->w)->w;
1177 w_l = w_l->next;
1178 }
1179 new_entry->t = ((struct ebt_u_target *)new_entry->t)->t;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001180
1181 // update the counter_offset of chains behind this one
1182 i = replace.selected_hook;
1183 while (1) {
1184 i++;
1185 entries = nr_to_chain(i);
1186 if (!entries) {
1187 if (i < NF_BR_NUMHOOKS)
1188 continue;
1189 else
1190 break;
1191 } else
1192 entries->counter_offset++;
1193 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001194}
1195
1196// execute command D
1197static void delete_rule(int rule_nr)
1198{
1199 int i, j, lentmp = 0;
1200 unsigned short *cnt;
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001201 struct ebt_u_entry **u_e, *u_e2;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001202 struct ebt_u_entries *entries = to_chain(), *entries2;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001203
1204 if ( (i = check_rule_exists(rule_nr)) == -1 )
Bart De Schuymer60332e02002-06-23 08:01:47 +00001205 print_error("Sorry, rule does not exist");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001206
1207 // we're deleting a rule
1208 replace.num_counters = replace.nentries;
1209 replace.nentries--;
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001210 entries->nentries--;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001211
1212 if (replace.nentries) {
1213 for (j = 0; j < replace.selected_hook; j++) {
Bart De Schuymer60332e02002-06-23 08:01:47 +00001214 if (j < NF_BR_NUMHOOKS &&
1215 !(replace.valid_hooks & (1 << j)))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001216 continue;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001217 entries2 = nr_to_chain(j);
1218 lentmp += entries2->nentries;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001219 }
1220 lentmp += i;
1221 // +1 for CNT_END
Bart De Schuymered053432002-07-21 19:35:39 +00001222 if ( !(replace.counterchanges = (unsigned short *)malloc(
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001223 (replace.num_counters + 1) * sizeof(unsigned short))) )
1224 print_memory();
Bart De Schuymered053432002-07-21 19:35:39 +00001225 cnt = replace.counterchanges;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001226 for (j = 0; j < lentmp; j++) {
1227 *cnt = CNT_NORM;
1228 cnt++;
1229 }
1230 *cnt = CNT_DEL;
1231 cnt++;
1232 for (j = 0; j < replace.num_counters - lentmp; j++) {
1233 *cnt = CNT_NORM;
1234 cnt++;
1235 }
1236 *cnt = CNT_END;
1237 }
1238 else
1239 replace.num_counters = 0;
1240
1241 // go to the right position in the chain
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001242 u_e = &entries->entries;
1243 for (j = 0; j < i; j++)
1244 u_e = &(*u_e)->next;
1245 // remove the rule
1246 u_e2 = *u_e;
1247 *u_e = (*u_e)->next;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001248 // free everything
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001249 free_u_entry(u_e2);
1250 free(u_e2);
1251
Bart De Schuymer60332e02002-06-23 08:01:47 +00001252 // update the counter_offset of chains behind this one
1253 i = replace.selected_hook;
1254 while (1) {
1255 i++;
1256 entries = nr_to_chain(i);
1257 if (!entries) {
1258 if (i < NF_BR_NUMHOOKS)
1259 continue;
1260 else
1261 break;
1262 } else
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001263 entries->counter_offset--;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001264 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001265}
1266
1267// execute command Z
Bart De Schuymer62423742002-07-14 19:06:20 +00001268static void zero_counters(int zerochain)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001269{
1270
1271 if (zerochain == -1) {
1272 // tell main() we don't update the counters
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001273 // this results in tricking the kernel to zero its counters,
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001274 // naively expecting userspace to update its counters. Muahahaha
Bart De Schuymered053432002-07-21 19:35:39 +00001275 replace.counterchanges = NULL;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001276 replace.num_counters = 0;
1277 } else {
1278 int i, j;
1279 unsigned short *cnt;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001280 struct ebt_u_entries *entries = nr_to_chain(zerochain), *e2;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001281
Bart De Schuymer60332e02002-06-23 08:01:47 +00001282 if (entries->nentries == 0)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001283 exit(0);
Bart De Schuymered053432002-07-21 19:35:39 +00001284 replace.counterchanges = (unsigned short *)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001285 malloc((replace.nentries + 1) * sizeof(unsigned short));
Bart De Schuymered053432002-07-21 19:35:39 +00001286 if (!replace.counterchanges)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001287 print_memory();
Bart De Schuymered053432002-07-21 19:35:39 +00001288 cnt = replace.counterchanges;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001289 for (i = 0; i < zerochain; i++) {
Bart De Schuymer60332e02002-06-23 08:01:47 +00001290 if (i < NF_BR_NUMHOOKS &&
1291 !(replace.valid_hooks & (1 << i)))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001292 continue;
Bart De Schuymer60332e02002-06-23 08:01:47 +00001293 e2 = nr_to_chain(i);
1294 for (j = 0; j < e2->nentries; j++) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001295 *cnt = CNT_NORM;
1296 cnt++;
1297 }
1298 }
Bart De Schuymer60332e02002-06-23 08:01:47 +00001299 for (i = 0; i < entries->nentries; i++) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001300 *cnt = CNT_ZERO;
1301 cnt++;
1302 }
Bart De Schuymered053432002-07-21 19:35:39 +00001303 while (cnt != replace.counterchanges + replace.nentries) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001304 *cnt = CNT_NORM;
1305 cnt++;
1306 }
1307 *cnt = CNT_END;
1308 }
1309}
1310
Bart De Schuymer28bf6f62002-06-26 18:57:24 +00001311// 0 == success
1312// 1 == success, but for the special 'protocol' LENGTH
1313// -1 == failure
1314int name_to_number(char *name, __u16 *proto)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001315{
1316 FILE *ifp;
Bart De Schuymerf662ce52002-07-19 18:40:55 +00001317 char buffer[21], value[11], *bfr;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001318 unsigned short i;
1319
1320 if (!strcasecmp("LENGTH", name)) {
Bart De Schuymer28bf6f62002-06-26 18:57:24 +00001321 *proto = 0;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001322 new_entry->bitmask |= EBT_802_3;
1323 return 1;
1324 }
1325 if ( !(ifp = fopen(PROTOCOLFILE, "r")) )
1326 return -1;
1327 while (1) {
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001328 if (get_a_line(buffer, value, ifp))
1329 return -1;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001330 if (strcasecmp(buffer, name))
1331 continue;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001332 fclose(ifp);
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001333 i = (unsigned short) strtol(value, &bfr, 16);
1334 if (*bfr != '\0')
1335 return -1;
1336 *proto = i;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001337 return 0;
1338 }
1339 return -1;
1340}
1341
1342// put the mac address into 6 (ETH_ALEN) bytes
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001343int getmac_and_mask(char *from, char *to, char *mask)
1344{
1345 char *p;
1346 int i;
Bart De Schuymer41830412002-06-05 19:41:28 +00001347 struct ether_addr *addr;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001348
1349 if (strcasecmp(from, "Unicast") == 0) {
1350 memcpy(to, mac_type_unicast, ETH_ALEN);
1351 memcpy(mask, msk_type_unicast, ETH_ALEN);
1352 return 0;
1353 }
1354 if (strcasecmp(from, "Multicast") == 0) {
1355 memcpy(to, mac_type_multicast, ETH_ALEN);
1356 memcpy(mask, msk_type_multicast, ETH_ALEN);
1357 return 0;
1358 }
1359 if (strcasecmp(from, "Broadcast") == 0) {
1360 memcpy(to, mac_type_broadcast, ETH_ALEN);
1361 memcpy(mask, msk_type_broadcast, ETH_ALEN);
1362 return 0;
1363 }
1364 if ( (p = strrchr(from, '/')) != NULL) {
1365 *p = '\0';
Bart De Schuymer41830412002-06-05 19:41:28 +00001366 if (!(addr = ether_aton(p + 1)))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001367 return -1;
Bart De Schuymer41830412002-06-05 19:41:28 +00001368 memcpy(mask, addr, ETH_ALEN);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001369 } else
1370 memset(mask, 0xff, ETH_ALEN);
Bart De Schuymer41830412002-06-05 19:41:28 +00001371 if (!(addr = ether_aton(from)))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001372 return -1;
Bart De Schuymer41830412002-06-05 19:41:28 +00001373 memcpy(to, addr, ETH_ALEN);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001374 for (i = 0; i < ETH_ALEN; i++)
1375 to[i] &= mask[i];
1376 return 0;
1377}
1378
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001379// executes the final_check() function for all extensions used by the rule
Bart De Schuymer62423742002-07-14 19:06:20 +00001380static void do_final_checks(struct ebt_u_entry *e, struct ebt_u_entries *entries)
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +00001381{
1382 struct ebt_u_match_list *m_l;
1383 struct ebt_u_watcher_list *w_l;
1384 struct ebt_u_target *t;
1385 struct ebt_u_match *m;
1386 struct ebt_u_watcher *w;
1387
1388 m_l = e->m_list;
1389 w_l = e->w_list;
1390 while (m_l) {
1391 m = find_match(m_l->m->u.name);
1392 m->final_check(e, m_l->m, replace.name,
1393 entries->hook_mask, 1);
1394 m_l = m_l->next;
1395 }
1396 while (w_l) {
1397 w = find_watcher(w_l->w->u.name);
1398 w->final_check(e, w_l->w, replace.name,
1399 entries->hook_mask, 1);
1400 w_l = w_l->next;
1401 }
1402 t = find_target(e->t->u.name);
1403 t->final_check(e, e->t, replace.name,
1404 entries->hook_mask, 1);
1405}
1406
Bart De Schuymerb909f9b2002-06-26 18:35:31 +00001407// used for the -X command
Bart De Schuymer62423742002-07-14 19:06:20 +00001408static void check_for_references(int chain_nr)
Bart De Schuymerb909f9b2002-06-26 18:35:31 +00001409{
1410 int i = -1, j;
1411 struct ebt_u_entries *entries;
1412 struct ebt_u_entry *e;
1413
1414 while (1) {
1415 i++;
1416 entries = nr_to_chain(i);
1417 if (!entries) {
1418 if (i < NF_BR_NUMHOOKS)
1419 continue;
1420 else
1421 break;
1422 }
1423 e = entries->entries;
1424 j = 0;
1425 while (e) {
1426 j++;
1427 if (strcmp(e->t->u.name, EBT_STANDARD_TARGET)) {
1428 e = e->next;
1429 continue;
1430 }
1431 if (((struct ebt_standard_target *)e->t)->verdict == chain_nr)
1432 print_error("Can't delete the chain, it's referenced "
1433 "in chain %s, rule %d", entries->name, j);
1434 e = e->next;
1435 }
1436 }
1437}
1438
Bart De Schuymera615b962002-11-03 14:54:09 +00001439static int invert = 0;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001440int check_inverse(const char option[])
1441{
1442 if (strcmp(option, "!") == 0) {
Bart De Schuymera615b962002-11-03 14:54:09 +00001443 if (invert == 1)
1444 print_error("double use of '!' not allowed");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001445 optind++;
Bart De Schuymera615b962002-11-03 14:54:09 +00001446 invert = 1;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001447 return 1;
1448 }
Bart De Schuymera615b962002-11-03 14:54:09 +00001449 return invert;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001450}
1451
1452void check_option(unsigned int *flags, unsigned int mask)
1453{
1454 if (*flags & mask)
1455 print_error("Multiple use of same option not allowed");
1456 *flags |= mask;
1457}
1458
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001459static void get_kernel_table(const char *modprobe)
1460{
1461 if ( !(table = find_table(replace.name)) )
1462 print_error("Bad table name");
1463 // get the kernel's information
1464 if (get_table(&replace)) {
1465 ebtables_insmod("ebtables", modprobe);
1466 if (get_table(&replace))
1467 print_error("The kernel doesn't support the ebtables "
1468 "%s table", replace.name);
1469 }
Bart De Schuymer62a7fdb2002-08-24 21:01:21 +00001470 // when listing a table contained in a file, we don't expect the user
1471 // to know what the table's name is
1472 if ( !(table = find_table(replace.name)) )
1473 print_error("Bad table name");
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001474}
1475
Bart De Schuymerc5075142002-08-18 14:21:19 +00001476#define print_if_l_error print_error("Interface name length must be less " \
1477 "than %d", IFNAMSIZ)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001478#define OPT_COMMAND 0x01
1479#define OPT_TABLE 0x02
1480#define OPT_IN 0x04
1481#define OPT_OUT 0x08
1482#define OPT_JUMP 0x10
1483#define OPT_PROTOCOL 0x20
1484#define OPT_SOURCE 0x40
1485#define OPT_DEST 0x80
1486#define OPT_ZERO 0x100
1487#define OPT_LOGICALIN 0x200
1488#define OPT_LOGICALOUT 0x400
1489// the main thing
1490int main(int argc, char *argv[])
1491{
Bart De Schuymer923a5732002-08-11 12:01:33 +00001492 char *buffer;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001493 int c, i;
1494 // this special one for the -Z option (we can have -Z <this> -L <that>)
1495 int zerochain = -1;
Bart De Schuymerf8f8f292002-06-25 15:43:57 +00001496 int policy = 0;
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001497 int rule_nr = -1;// used for -[D,I] chain number
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001498 struct ebt_u_target *t;
1499 struct ebt_u_match *m;
1500 struct ebt_u_watcher *w;
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001501 struct ebt_u_match_list *m_l;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001502 struct ebt_u_watcher_list *w_l;
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001503 struct ebt_u_entries *entries;
Bart De Schuymerc8531032002-06-14 21:55:29 +00001504 const char *modprobe = NULL;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001505
Bart De Schuymera615b962002-11-03 14:54:09 +00001506 opterr = 0;
1507
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001508 // initialize the table name, OPT_ flags, selected hook and command
1509 strcpy(replace.name, "filter");
1510 replace.flags = 0;
1511 replace.selected_hook = -1;
1512 replace.command = 'h';
Bart De Schuymer62423742002-07-14 19:06:20 +00001513 replace.filename = NULL;
Bart De Schuymered053432002-07-21 19:35:39 +00001514 replace.counterchanges = NULL;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001515
1516 new_entry = (struct ebt_u_entry *)malloc(sizeof(struct ebt_u_entry));
1517 if (!new_entry)
1518 print_memory();
1519 // put some sane values in our new entry
1520 initialize_entry(new_entry);
1521
Bart De Schuymer60332e02002-06-23 08:01:47 +00001522 // The scenario induced by this loop makes that:
Bart De Schuymer62423742002-07-14 19:06:20 +00001523 // '-t' ,'-M' and --atomic (if specified) have to come
1524 // before '-A' and the like
Bart De Schuymer60332e02002-06-23 08:01:47 +00001525
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001526 // getopt saves the day
1527 while ((c = getopt_long(argc, argv,
Bart De Schuymeraac31142002-08-11 11:57:52 +00001528 "-A:D:I:N:E:X:L::Z::F::P:Vhi:o:j:p:s:d:t:M:", ebt_options, NULL)) != -1) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001529 switch (c) {
1530
1531 case 'A': // add a rule
1532 case 'D': // delete a rule
1533 case 'P': // define policy
1534 case 'I': // insert a rule
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001535 case 'N': // make a user defined chain
1536 case 'E': // rename chain
1537 case 'X': // delete chain
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001538 replace.command = c;
1539 if (replace.flags & OPT_COMMAND)
1540 print_error("Multiple commands not allowed");
1541 replace.flags |= OPT_COMMAND;
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001542 get_kernel_table(modprobe);
1543 if (optarg[0] == '-' || !strcmp(optarg, "!"))
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001544 print_error("No chain name specified");
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001545 if (c == 'N') {
1546 struct ebt_u_chain_list *cl, **cl2;
1547
1548 if (get_hooknr(optarg) != -1)
1549 print_error("Chain %s already exists",
1550 optarg);
1551 if (find_target(optarg))
1552 print_error("Target with name %s exists"
1553 , optarg);
1554 if (strlen(optarg) >= EBT_CHAIN_MAXNAMELEN)
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001555 print_error("Chain name length can't exceed %d",
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001556 EBT_CHAIN_MAXNAMELEN - 1);
1557 cl = (struct ebt_u_chain_list *)
1558 malloc(sizeof(struct ebt_u_chain_list));
1559 if (!cl)
1560 print_memory();
1561 cl->next = NULL;
1562 cl->udc = (struct ebt_u_entries *)
1563 malloc(sizeof(struct ebt_u_entries));
1564 if (!cl->udc)
1565 print_memory();
1566 cl->udc->nentries = 0;
1567 cl->udc->policy = EBT_ACCEPT;
1568 cl->udc->counter_offset = replace.nentries;
1569 cl->udc->hook_mask = 0;
1570 strcpy(cl->udc->name, optarg);
1571 cl->udc->entries = NULL;
1572 cl->kernel_start = NULL;
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001573 // put the new chain at the end
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001574 cl2 = &replace.udc;
1575 while (*cl2)
1576 cl2 = &((*cl2)->next);
1577 *cl2 = cl;
1578 break;
1579 }
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001580 if ((replace.selected_hook = get_hooknr(optarg)) == -1)
1581 print_error("Chain %s doesn't exist", optarg);
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001582 if (c == 'E') {
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001583 if (optind >= argc || argv[optind][0] == '-' ||
1584 !strcmp(argv[optind], "!"))
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001585 print_error("No new chain name specified");
1586 if (strlen(argv[optind]) >= EBT_CHAIN_MAXNAMELEN)
1587 print_error("Chain name len can't exceed %d",
1588 EBT_CHAIN_MAXNAMELEN - 1);
1589 if (get_hooknr(argv[optind]) != -1)
1590 print_error("Chain %s already exists",
1591 argv[optind]);
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001592 if (find_target(argv[optind]))
1593 print_error("Target with name %s exists"
1594 , argv[optind]);
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001595 entries = to_chain();
1596 strcpy(entries->name, argv[optind]);
1597 optind++;
1598 break;
1599 }
1600 if (c == 'X') {
1601 struct ebt_u_chain_list *cl, **cl2;
1602
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001603 if (replace.selected_hook < NF_BR_NUMHOOKS)
1604 print_error("You can't remove a standard chain");
Bart De Schuymerb909f9b2002-06-26 18:35:31 +00001605 // if the chain is referenced, don't delete it
1606 check_for_references(replace.selected_hook - NF_BR_NUMHOOKS);
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001607 flush_chains();
1608 entries = to_chain();
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001609 cl2 = &(replace.udc);
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001610 while ((*cl2)->udc != entries)
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001611 cl2 = &((*cl2)->next);
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001612 cl = (*cl2);
1613 (*cl2) = (*cl2)->next;
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001614 free(cl->udc);
1615 free(cl);
1616 break;
1617 }
1618
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001619 if ( (c == 'D' && optind < argc &&
1620 argv[optind][0] != '-') || c == 'I') {
1621 if (optind >= argc || argv[optind][0] == '-')
1622 print_error("No rulenr for -I"
1623 " specified");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001624 rule_nr = strtol(argv[optind], &buffer, 10);
1625 if (*buffer != '\0' || rule_nr < 0)
1626 print_error("Problem with the "
1627 "specified rule number");
1628 optind++;
1629 }
1630 if (c == 'P') {
1631 if (optind >= argc)
1632 print_error("No policy specified");
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001633 policy = 0;
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001634 for (i = 0; i < NUM_STANDARD_TARGETS; i++)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001635 if (!strcmp(argv[optind],
1636 standard_targets[i])) {
Bart De Schuymer60332e02002-06-23 08:01:47 +00001637 policy = -i -1;
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001638 if (policy == EBT_CONTINUE)
1639 policy = 0;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001640 break;
1641 }
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001642 if (policy == 0)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001643 print_error("Wrong policy");
1644 optind++;
1645 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001646 break;
1647
1648 case 'L': // list
1649 case 'F': // flush
1650 case 'Z': // zero counters
1651 if (c == 'Z') {
1652 if (replace.flags & OPT_ZERO)
1653 print_error("Multiple commands"
1654 " not allowed");
1655 if ( (replace.flags & OPT_COMMAND &&
1656 replace.command != 'L'))
1657 print_error("command -Z only allowed "
1658 "together with command -L");
1659 replace.flags |= OPT_ZERO;
1660 } else {
1661 replace.command = c;
1662 if (replace.flags & OPT_COMMAND)
1663 print_error("Multiple commands"
1664 " not allowed");
1665 replace.flags |= OPT_COMMAND;
1666 }
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001667 get_kernel_table(modprobe);
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001668 i = -1;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001669 if (optarg) {
1670 if ( (i = get_hooknr(optarg)) == -1 )
1671 print_error("Bad chain");
1672 } else
1673 if (optind < argc && argv[optind][0] != '-') {
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001674 if ((i = get_hooknr(argv[optind])) == -1)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001675 print_error("Bad chain");
1676 optind++;
1677 }
1678 if (i != -1) {
1679 if (c == 'Z')
1680 zerochain = i;
1681 else
1682 replace.selected_hook = i;
1683 }
1684 break;
1685
1686 case 'V': // version
1687 replace.command = 'V';
1688 if (replace.flags & OPT_COMMAND)
1689 print_error("Multiple commands not allowed");
Bart De Schuymerd4586482002-08-11 16:15:55 +00001690 printf(PROGNAME" v"PROGVERSION" ("PROGDATE")\n");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001691 exit(0);
1692
Bart De Schuymerc8531032002-06-14 21:55:29 +00001693 case 'M': // modprobe
Bart De Schuymer60332e02002-06-23 08:01:47 +00001694 if (replace.command != 'h')
1695 print_error("Please put the -M option earlier");
Bart De Schuymerc8531032002-06-14 21:55:29 +00001696 modprobe = optarg;
1697 break;
1698
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001699 case 'h': // help
1700 if (replace.flags & OPT_COMMAND)
1701 print_error("Multiple commands not allowed");
1702 replace.command = 'h';
1703 // All other arguments should be extension names
1704 while (optind < argc) {
1705 struct ebt_u_match *m;
1706 struct ebt_u_watcher *w;
1707
1708 if ((m = find_match(argv[optind])))
1709 add_match(m);
1710 else if ((w = find_watcher(argv[optind])))
1711 add_watcher(w);
1712 else {
1713 if (!(t = find_target(argv[optind])))
1714 print_error("Extension %s "
1715 "not found", argv[optind]);
1716 if (replace.flags & OPT_JUMP)
1717 print_error("Sorry, you can "
1718 "only see help for one "
1719 "target extension each time");
1720 replace.flags |= OPT_JUMP;
1721 new_entry->t =
1722 (struct ebt_entry_target *)t;
1723 }
1724 optind++;
1725 }
1726 break;
1727
1728 case 't': // table
Bart De Schuymer60332e02002-06-23 08:01:47 +00001729 if (replace.command != 'h')
1730 print_error("Please put the -t option first");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001731 check_option(&replace.flags, OPT_TABLE);
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001732 if (strlen(optarg) > EBT_TABLE_MAXNAMELEN - 1)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001733 print_error("Table name too long");
1734 strcpy(replace.name, optarg);
1735 break;
1736
1737 case 'i': // input interface
1738 case 2 : // logical input interface
1739 case 'o': // output interface
1740 case 3 : // logical output interface
1741 case 'j': // target
1742 case 'p': // net family protocol
1743 case 's': // source mac
1744 case 'd': // destination mac
1745 if ((replace.flags & OPT_COMMAND) == 0)
1746 print_error("No command specified");
1747 if ( replace.command != 'A' &&
1748 replace.command != 'D' && replace.command != 'I')
1749 print_error("Command and option do not match");
1750 if (c == 'i') {
1751 check_option(&replace.flags, OPT_IN);
1752 if (replace.selected_hook > 2 &&
1753 replace.selected_hook < NF_BR_BROUTING)
1754 print_error("Use in-interface only in "
1755 "INPUT, FORWARD, PREROUTING and"
1756 "BROUTING chains");
1757 if (check_inverse(optarg))
1758 new_entry->invflags |= EBT_IIN;
1759
1760 if (optind > argc)
1761 print_error("No in-interface "
1762 "specified");
1763 if (strlen(argv[optind - 1]) >= IFNAMSIZ)
Bart De Schuymerc5075142002-08-18 14:21:19 +00001764 print_if_l_error;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001765 strcpy(new_entry->in, argv[optind - 1]);
1766 break;
1767 }
1768 if (c == 2) {
1769 check_option(&replace.flags, OPT_LOGICALIN);
1770 if (replace.selected_hook > 2 &&
1771 replace.selected_hook < NF_BR_BROUTING)
1772 print_error("Use logical in-interface "
1773 "only in INPUT, FORWARD, "
1774 "PREROUTING and BROUTING chains");
1775 if (check_inverse(optarg))
1776 new_entry->invflags |= EBT_ILOGICALIN;
1777
1778 if (optind > argc)
1779 print_error("No logical in-interface "
1780 "specified");
1781 if (strlen(argv[optind - 1]) >= IFNAMSIZ)
Bart De Schuymerc5075142002-08-18 14:21:19 +00001782 print_if_l_error;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001783 strcpy(new_entry->logical_in, argv[optind - 1]);
1784 break;
1785 }
1786 if (c == 'o') {
1787 check_option(&replace.flags, OPT_OUT);
1788 if (replace.selected_hook < 2)
1789 print_error("Use out-interface only"
1790 " in OUTPUT, FORWARD and "
1791 "POSTROUTING chains");
1792 if (check_inverse(optarg))
1793 new_entry->invflags |= EBT_IOUT;
1794
1795 if (optind > argc)
1796 print_error("No out-interface "
1797 "specified");
1798
1799 if (strlen(argv[optind - 1]) >= IFNAMSIZ)
Bart De Schuymerc5075142002-08-18 14:21:19 +00001800 print_if_l_error;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001801 strcpy(new_entry->out, argv[optind - 1]);
1802 break;
1803 }
1804 if (c == 3) {
1805 check_option(&replace.flags, OPT_LOGICALOUT);
1806 if (replace.selected_hook < 2)
1807 print_error("Use logical out-interface "
1808 "only in OUTPUT, FORWARD and "
1809 "POSTROUTING chains");
1810 if (check_inverse(optarg))
1811 new_entry->invflags |= EBT_ILOGICALOUT;
1812
1813 if (optind > argc)
1814 print_error("No logical out-interface "
1815 "specified");
1816
1817 if (strlen(argv[optind - 1]) >= IFNAMSIZ)
Bart De Schuymerc5075142002-08-18 14:21:19 +00001818 print_if_l_error;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001819 strcpy(new_entry->logical_out,
1820 argv[optind - 1]);
1821 break;
1822 }
1823 if (c == 'j') {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001824 check_option(&replace.flags, OPT_JUMP);
1825 for (i = 0; i < NUM_STANDARD_TARGETS; i++)
1826 if (!strcmp(optarg,
1827 standard_targets[i])) {
1828 t = find_target(
1829 EBT_STANDARD_TARGET);
1830 ((struct ebt_standard_target *)
Bart De Schuymer60332e02002-06-23 08:01:47 +00001831 t->t)->verdict = -i - 1;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001832 break;
1833 }
Bart De Schuymer60332e02002-06-23 08:01:47 +00001834 if (-i - 1 == EBT_RETURN) {
1835 if (replace.selected_hook < NF_BR_NUMHOOKS)
1836 print_error("Return target"
1837 " only for user defined chains");
1838 }
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +00001839 if (i != NUM_STANDARD_TARGETS)
1840 break;
Bart De Schuymer1ab41562002-06-23 17:09:54 +00001841 if ((i = get_hooknr(optarg)) != -1) {
1842 if (i < NF_BR_NUMHOOKS)
1843 print_error("don't jump"
1844 " to a standard chain");
1845 t = find_target(
1846 EBT_STANDARD_TARGET);
1847 ((struct ebt_standard_target *)
1848 t->t)->verdict = i - NF_BR_NUMHOOKS;
1849 break;
1850 }
1851 else {
1852 // must be an extension then
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001853 struct ebt_u_target *t;
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00001854
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001855 t = find_target(optarg);
1856 // -j standard not allowed either
1857 if (!t || t ==
1858 (struct ebt_u_target *)new_entry->t)
1859 print_error("Illegal target "
1860 "name");
1861 new_entry->t =
1862 (struct ebt_entry_target *)t;
1863 }
1864 break;
1865 }
1866 if (c == 's') {
1867 check_option(&replace.flags, OPT_SOURCE);
1868 if (check_inverse(optarg))
1869 new_entry->invflags |= EBT_ISOURCE;
1870
1871 if (optind > argc)
1872 print_error("No source mac "
1873 "specified");
1874 if (getmac_and_mask(argv[optind - 1],
1875 new_entry->sourcemac, new_entry->sourcemsk))
1876 print_error("Problem with specified "
1877 "source mac");
1878 new_entry->bitmask |= EBT_SOURCEMAC;
1879 break;
1880 }
1881 if (c == 'd') {
1882 check_option(&replace.flags, OPT_DEST);
1883 if (check_inverse(optarg))
1884 new_entry->invflags |= EBT_IDEST;
1885
1886 if (optind > argc)
1887 print_error("No destination mac "
1888 "specified");
1889 if (getmac_and_mask(argv[optind - 1],
1890 new_entry->destmac, new_entry->destmsk))
1891 print_error("Problem with specified "
1892 "destination mac");
1893 new_entry->bitmask |= EBT_DESTMAC;
1894 break;
1895 }
1896 check_option(&replace.flags, OPT_PROTOCOL);
1897 if (check_inverse(optarg))
1898 new_entry->invflags |= EBT_IPROTO;
1899
1900 if (optind > argc)
1901 print_error("No protocol specified");
1902 new_entry->bitmask &= ~((unsigned int)EBT_NOPROTO);
1903 i = strtol(argv[optind - 1], &buffer, 16);
1904 if (*buffer == '\0' && (i < 0 || i > 0xFFFF))
1905 print_error("Problem with the specified "
1906 "protocol");
1907 new_entry->ethproto = i;
Bart De Schuymer28bf6f62002-06-26 18:57:24 +00001908 if (*buffer != '\0') {
1909 if ((i = name_to_number(argv[optind - 1],
1910 &new_entry->ethproto)) == -1)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001911 print_error("Problem with the specified"
1912 " protocol");
Bart De Schuymer28bf6f62002-06-26 18:57:24 +00001913 if (i == 1)
1914 new_entry->bitmask |= EBT_802_3;
1915 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001916 if (new_entry->ethproto < 1536 &&
1917 !(new_entry->bitmask & EBT_802_3))
1918 print_error("Sorry, protocols have values above"
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001919 " or equal to 0x0600");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001920 break;
1921
Bart De Schuymer9af14f92002-07-10 20:49:10 +00001922 case 4 : // Lc
1923 check_option(&replace.flags, LIST_C);
Bart De Schuymer9af14f92002-07-10 20:49:10 +00001924 if (replace.command != 'L')
1925 print_error("Use --Lc with -L");
1926 if (replace.flags & LIST_X)
1927 print_error("--Lx not compatible with --Lc");
1928 replace.flags |= LIST_C;
1929 break;
1930 case 5 : // Ln
1931 check_option(&replace.flags, LIST_N);
Bart De Schuymer9af14f92002-07-10 20:49:10 +00001932 if (replace.command != 'L')
1933 print_error("Use --Ln with -L");
1934 if (replace.flags & LIST_X)
1935 print_error("--Lx not compatible with --Ln");
1936 replace.flags |= LIST_N;
1937 break;
1938 case 6 : // Lx
1939 check_option(&replace.flags, LIST_X);
Bart De Schuymer9af14f92002-07-10 20:49:10 +00001940 if (replace.command != 'L')
1941 print_error("Use --Lx with -L");
1942 if (replace.flags & LIST_C)
1943 print_error("--Lx not compatible with --Lc");
1944 if (replace.flags & LIST_N)
1945 print_error("--Lx not compatible with --Ln");
1946 replace.flags |= LIST_X;
1947 break;
Bart De Schuymer62423742002-07-14 19:06:20 +00001948 case 8 : // atomic-commit
1949 replace.command = c;
1950 if (replace.flags & OPT_COMMAND)
1951 print_error("Multiple commands not allowed");
1952 replace.flags |= OPT_COMMAND;
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001953 if (replace.filename)
1954 print_error("--atomic incompatible with "
1955 "command");
Bart De Schuymer62423742002-07-14 19:06:20 +00001956 replace.filename = (char *)malloc(strlen(optarg) + 1);
1957 strcpy(replace.filename, optarg);
1958 // get the information from the file
1959 get_table(&replace);
Bart De Schuymer868bf642002-07-16 18:14:20 +00001960 if (replace.nentries) {
Bart De Schuymered053432002-07-21 19:35:39 +00001961 replace.counterchanges = (unsigned short *)
Bart De Schuymer868bf642002-07-16 18:14:20 +00001962 malloc(sizeof(unsigned short) * (replace.nentries + 1));
1963 for (i = 0; i < replace.nentries; i++)
Bart De Schuymered053432002-07-21 19:35:39 +00001964 replace.counterchanges[i] = CNT_NORM;
1965 replace.counterchanges[i] = CNT_END;
Bart De Schuymer868bf642002-07-16 18:14:20 +00001966 }
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001967 // we don't want the kernel giving us its counters, they would
1968 // overwrite the counters extracted from the file
1969 replace.num_counters = 0;
1970 // make sure the table will be written to the kernel
Bart De Schuymer62423742002-07-14 19:06:20 +00001971 free(replace.filename);
1972 replace.filename = NULL;
Bart De Schuymerc5c3c2d2002-08-16 19:48:03 +00001973 ebtables_insmod("ebtables", modprobe);
Bart De Schuymer62423742002-07-14 19:06:20 +00001974 break;
1975 case 7 : // atomic-init
1976 case 10: // atomic-save
Bart De Schuymer8d1d8942002-07-15 20:09:09 +00001977 case 11: // init-table
Bart De Schuymer62423742002-07-14 19:06:20 +00001978 replace.command = c;
1979 if (replace.flags & OPT_COMMAND)
1980 print_error("Multiple commands not allowed");
1981 replace.flags |= OPT_COMMAND;
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001982 if (replace.filename)
1983 print_error("--atomic incompatible with "
1984 "command");
1985 get_kernel_table(modprobe);
Bart De Schuymera8d920b2002-07-16 18:30:44 +00001986 if (replace.nentries) {
Bart De Schuymered053432002-07-21 19:35:39 +00001987 replace.counterchanges = (unsigned short *)
Bart De Schuymer5f16dc72002-07-16 18:08:36 +00001988 malloc(sizeof(unsigned short) * (replace.nentries + 1));
1989 for (i = 0; i < replace.nentries; i++)
Bart De Schuymered053432002-07-21 19:35:39 +00001990 replace.counterchanges[i] = CNT_NORM;
1991 replace.counterchanges[i] = CNT_END;
Bart De Schuymer5f16dc72002-07-16 18:08:36 +00001992 }
Bart De Schuymer8d1d8942002-07-15 20:09:09 +00001993 if (c == 11)
1994 break;
Bart De Schuymer62423742002-07-14 19:06:20 +00001995 case 9 : // atomic
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00001996 if (c == 9 && (replace.flags & OPT_COMMAND))
1997 print_error("--atomic has to come before"
1998 " the command");
Bart De Schuymer62423742002-07-14 19:06:20 +00001999 replace.filename = (char *)malloc(strlen(optarg) + 1);
2000 strcpy(replace.filename, optarg);
2001 break;
Bart De Schuymera615b962002-11-03 14:54:09 +00002002 case 1 :
2003 if (!strcmp(optarg, "!"))
2004 check_inverse(optarg);
2005 else
2006 print_error("Bad argument : %s", optarg);
2007 // check_inverse() did optind++
2008 optind--;
2009 continue;
Bart De Schuymer9af14f92002-07-10 20:49:10 +00002010 default:
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002011 // is it a target option?
2012 t = (struct ebt_u_target *)new_entry->t;
2013 if ((t->parse(c - t->option_offset, argv, argc,
2014 new_entry, &t->flags, &t->t)))
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00002015 goto check_extension;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002016
2017 // is it a match_option?
2018 for (m = matches; m; m = m->next)
2019 if (m->parse(c - m->option_offset, argv,
2020 argc, new_entry, &m->flags, &m->m))
2021 break;
2022
2023 if (m != NULL) {
2024 if (m->used == 0)
2025 add_match(m);
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00002026 goto check_extension;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002027 }
2028
2029 // is it a watcher option?
2030 for (w = watchers; w; w = w->next)
2031 if (w->parse(c-w->option_offset, argv,
2032 argc, new_entry, &w->flags, &w->w))
2033 break;
2034
2035 if (w == NULL)
2036 print_error("Unknown argument");
Bart De Schuymerdd5594b2002-06-26 18:05:20 +00002037 if (w->used == 0)
2038 add_watcher(w);
2039check_extension:
Bart De Schuymer60332e02002-06-23 08:01:47 +00002040 if (replace.command != 'A' && replace.command != 'I' &&
2041 replace.command != 'D')
Bart De Schuymerc56a31a2002-07-25 08:16:08 +00002042 print_error("Extensions only for -A, -I and -D");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002043 }
Bart De Schuymera615b962002-11-03 14:54:09 +00002044 invert = 0;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002045 }
2046
Bart De Schuymer25c741d2002-06-23 18:54:34 +00002047 if ( !table && !(table = find_table(replace.name)) )
2048 print_error("Bad table name");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002049
2050 if ( (replace.flags & OPT_COMMAND) && replace.command != 'L' &&
2051 replace.flags & OPT_ZERO )
2052 print_error("Command -Z only allowed together with command -L");
2053
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002054 // do this after parsing everything, so we can print specific info
2055 if (replace.command == 'h' && !(replace.flags & OPT_ZERO))
2056 print_help();
2057
2058 // do the final checks
Bart De Schuymer60332e02002-06-23 08:01:47 +00002059 if (replace.command == 'A' || replace.command == 'I' ||
2060 replace.command == 'D') {
2061 // this will put the hook_mask right for the chains
2062 check_for_loops();
2063 entries = to_chain();
2064 m_l = new_entry->m_list;
2065 w_l = new_entry->w_list;
2066 t = (struct ebt_u_target *)new_entry->t;
2067 while (m_l) {
2068 m = (struct ebt_u_match *)(m_l->m);
2069 m->final_check(new_entry, m->m, replace.name,
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +00002070 entries->hook_mask, 0);
Bart De Schuymer60332e02002-06-23 08:01:47 +00002071 m_l = m_l->next;
2072 }
2073 while (w_l) {
2074 w = (struct ebt_u_watcher *)(w_l->w);
2075 w->final_check(new_entry, w->w, replace.name,
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +00002076 entries->hook_mask, 0);
Bart De Schuymer60332e02002-06-23 08:01:47 +00002077 w_l = w_l->next;
2078 }
2079 t->final_check(new_entry, t->t, replace.name,
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +00002080 entries->hook_mask, 0);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002081 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002082 // so, the extensions can work with the host endian
2083 // the kernel does not have to do this ofcourse
2084 new_entry->ethproto = htons(new_entry->ethproto);
2085
Bart De Schuymerc34f4672002-08-18 18:03:52 +00002086 if (replace.command == 'P') {
2087 if (replace.selected_hook < NF_BR_NUMHOOKS &&
2088 policy == EBT_RETURN)
2089 print_error("Policy RETURN only allowed for user "
2090 "defined chains");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002091 change_policy(policy);
Bart De Schuymerc34f4672002-08-18 18:03:52 +00002092 } else if (replace.command == 'L') {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002093 list_rules();
2094 if (replace.flags & OPT_ZERO)
2095 zero_counters(zerochain);
2096 else
2097 exit(0);
2098 }
2099 if (replace.flags & OPT_ZERO)
2100 zero_counters(zerochain);
Bart De Schuymer1ab41562002-06-23 17:09:54 +00002101 else if (replace.command == 'F') {
2102 if (flush_chains() == -1)
2103 exit(0);
2104 } else if (replace.command == 'A' || replace.command == 'I') {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002105 add_rule(rule_nr);
Bart De Schuymer1ab41562002-06-23 17:09:54 +00002106 check_for_loops();
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +00002107 // do the final_check(), for all entries
2108 // needed when adding a rule that has a chain target
2109 i = -1;
2110 while (1) {
2111 struct ebt_u_entry *e;
2112
2113 i++;
2114 entries = nr_to_chain(i);
2115 if (!entries) {
2116 if (i < NF_BR_NUMHOOKS)
2117 continue;
2118 else
2119 break;
2120 }
2121 e = entries->entries;
2122 while (e) {
2123 // userspace extensions use host endian
2124 e->ethproto = ntohs(e->ethproto);
2125 do_final_checks(e, entries);
2126 e->ethproto = htons(e->ethproto);
2127 e = e->next;
2128 }
2129 }
Bart De Schuymer1ab41562002-06-23 17:09:54 +00002130 } else if (replace.command == 'D')
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002131 delete_rule(rule_nr);
Bart De Schuymer8d1d8942002-07-15 20:09:09 +00002132 // commands -N, -E, -X, --atomic-commit, --atomic-commit, --atomic-save,
2133 // --init-table fall through
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002134
2135 if (table->check)
2136 table->check(&replace);
2137
2138 deliver_table(&replace);
2139
Bart De Schuymered053432002-07-21 19:35:39 +00002140 if (replace.counterchanges)
2141 deliver_counters(&replace);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002142 return 0;
2143}