1 /*
2 * ebtables.c, v2.0 July 2002
3 *
4 * Author: Bart De Schuymer
5 *
6 * This code was 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 #include "config.h"
24 #include <ctype.h>
25 #include <errno.h>
26 #include <getopt.h>
27 #include <string.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <stdarg.h>
31 #include <inttypes.h>
32 #include <signal.h>
33 #include <net/if.h>
34 #include <netinet/ether.h>
35 #include <iptables.h>
36 #include <xtables.h>
37
38 #include <linux/netfilter_bridge.h>
39 #include <linux/netfilter/nf_tables.h>
40 #include <libiptc/libxtc.h>
41 #include "xshared.h"
42 #include "nft.h"
43 #include "nft-bridge.h"
44
45 /* from linux/netfilter_bridge/ebtables.h */
46 #define EBT_TABLE_MAXNAMELEN 32
47 #define EBT_CHAIN_MAXNAMELEN EBT_TABLE_MAXNAMELEN
48
49 /*
50 * From include/ebtables_u.h
51 */
52 #define ebt_check_option2(flags, mask) EBT_CHECK_OPTION(flags, mask)
53
54 /*
55 * From useful_functions.c
56 */
57
58 /* 0: default
59 * 1: the inverse '!' of the option has already been specified */
60 int ebt_invert = 0;
61
ebt_check_inverse2(const char option[],int argc,char ** argv)62 static int ebt_check_inverse2(const char option[], int argc, char **argv)
63 {
64 if (!option)
65 return ebt_invert;
66 if (strcmp(option, "!") == 0) {
67 if (ebt_invert == 1)
68 xtables_error(PARAMETER_PROBLEM,
69 "Double use of '!' not allowed");
70 if (optind >= argc)
71 optarg = NULL;
72 else
73 optarg = argv[optind];
74 optind++;
75 ebt_invert = 1;
76 return 1;
77 }
78 return ebt_invert;
79 }
80
81 /* XXX: merge with assert_valid_chain_name()? */
ebt_assert_valid_chain_name(const char * chainname)82 static void ebt_assert_valid_chain_name(const char *chainname)
83 {
84 if (strlen(chainname) >= EBT_CHAIN_MAXNAMELEN)
85 xtables_error(PARAMETER_PROBLEM,
86 "Chain name length can't exceed %d",
87 EBT_CHAIN_MAXNAMELEN - 1);
88
89 if (*chainname == '-' || *chainname == '!')
90 xtables_error(PARAMETER_PROBLEM, "No chain name specified");
91
92 if (xtables_find_target(chainname, XTF_TRY_LOAD))
93 xtables_error(PARAMETER_PROBLEM,
94 "Target with name %s exists", chainname);
95
96 if (strchr(chainname, ' ') != NULL)
97 xtables_error(PARAMETER_PROBLEM,
98 "Use of ' ' not allowed in chain names");
99 }
100
101 /*
102 * Glue code to use libxtables
103 */
parse_rule_number(const char * rule)104 static int parse_rule_number(const char *rule)
105 {
106 unsigned int rule_nr;
107
108 if (!xtables_strtoui(rule, NULL, &rule_nr, 1, INT_MAX))
109 xtables_error(PARAMETER_PROBLEM,
110 "Invalid rule number `%s'", rule);
111
112 return rule_nr;
113 }
114
115 static int
append_entry(struct nft_handle * h,const char * chain,const char * table,struct iptables_command_state * cs,int rule_nr,bool verbose,bool append)116 append_entry(struct nft_handle *h,
117 const char *chain,
118 const char *table,
119 struct iptables_command_state *cs,
120 int rule_nr,
121 bool verbose, bool append)
122 {
123 int ret = 1;
124
125 if (append)
126 ret = nft_cmd_rule_append(h, chain, table, cs, verbose);
127 else
128 ret = nft_cmd_rule_insert(h, chain, table, cs, rule_nr, verbose);
129
130 return ret;
131 }
132
133 static int
delete_entry(struct nft_handle * h,const char * chain,const char * table,struct iptables_command_state * cs,int rule_nr,int rule_nr_end,bool verbose)134 delete_entry(struct nft_handle *h,
135 const char *chain,
136 const char *table,
137 struct iptables_command_state *cs,
138 int rule_nr,
139 int rule_nr_end,
140 bool verbose)
141 {
142 int ret = 1;
143
144 if (rule_nr == -1)
145 ret = nft_cmd_rule_delete(h, chain, table, cs, verbose);
146 else {
147 do {
148 ret = nft_cmd_rule_delete_num(h, chain, table,
149 rule_nr, verbose);
150 rule_nr++;
151 } while (rule_nr < rule_nr_end);
152 }
153
154 return ret;
155 }
156
ebt_get_current_chain(const char * chain)157 int ebt_get_current_chain(const char *chain)
158 {
159 if (!chain)
160 return -1;
161
162 if (strcmp(chain, "PREROUTING") == 0)
163 return NF_BR_PRE_ROUTING;
164 else if (strcmp(chain, "INPUT") == 0)
165 return NF_BR_LOCAL_IN;
166 else if (strcmp(chain, "FORWARD") == 0)
167 return NF_BR_FORWARD;
168 else if (strcmp(chain, "OUTPUT") == 0)
169 return NF_BR_LOCAL_OUT;
170 else if (strcmp(chain, "POSTROUTING") == 0)
171 return NF_BR_POST_ROUTING;
172
173 /* placeholder for user defined chain */
174 return NF_BR_NUMHOOKS;
175 }
176
177 /*
178 * The original ebtables parser
179 */
180
181 /* Checks whether a command has already been specified */
182 #define OPT_COMMANDS (flags & OPT_COMMAND || flags & OPT_ZERO)
183
184 /* Default command line options. Do not mess around with the already
185 * assigned numbers unless you know what you are doing */
186 struct option ebt_original_options[] =
187 {
188 { "append" , required_argument, 0, 'A' },
189 { "insert" , required_argument, 0, 'I' },
190 { "delete" , required_argument, 0, 'D' },
191 { "list" , optional_argument, 0, 'L' },
192 { "Lc" , no_argument , 0, 4 },
193 { "Ln" , no_argument , 0, 5 },
194 { "Lx" , no_argument , 0, 6 },
195 { "Lmac2" , no_argument , 0, 12 },
196 { "zero" , optional_argument, 0, 'Z' },
197 { "flush" , optional_argument, 0, 'F' },
198 { "policy" , required_argument, 0, 'P' },
199 { "in-interface" , required_argument, 0, 'i' },
200 { "in-if" , required_argument, 0, 'i' },
201 { "logical-in" , required_argument, 0, 2 },
202 { "logical-out" , required_argument, 0, 3 },
203 { "out-interface" , required_argument, 0, 'o' },
204 { "out-if" , required_argument, 0, 'o' },
205 { "version" , no_argument , 0, 'V' },
206 { "verbose" , no_argument , 0, 'v' },
207 { "help" , no_argument , 0, 'h' },
208 { "jump" , required_argument, 0, 'j' },
209 { "set-counters" , required_argument, 0, 'c' },
210 { "change-counters", required_argument, 0, 'C' },
211 { "proto" , required_argument, 0, 'p' },
212 { "protocol" , required_argument, 0, 'p' },
213 { "db" , required_argument, 0, 'b' },
214 { "source" , required_argument, 0, 's' },
215 { "src" , required_argument, 0, 's' },
216 { "destination" , required_argument, 0, 'd' },
217 { "dst" , required_argument, 0, 'd' },
218 { "table" , required_argument, 0, 't' },
219 { "modprobe" , required_argument, 0, 'M' },
220 { "new-chain" , required_argument, 0, 'N' },
221 { "rename-chain" , required_argument, 0, 'E' },
222 { "delete-chain" , optional_argument, 0, 'X' },
223 { "init-table" , no_argument , 0, 11 },
224 { "concurrent" , no_argument , 0, 13 },
225 { "check" , required_argument, 0, 14 },
226 { 0 }
227 };
228
229 struct xtables_globals ebtables_globals = {
230 .option_offset = 0,
231 .program_version = PACKAGE_VERSION " (nf_tables)",
232 .orig_opts = ebt_original_options,
233 .compat_rev = nft_compatible_revision,
234 };
235
236 #define opts ebtables_globals.opts
237 #define prog_name ebtables_globals.program_name
238 #define prog_vers ebtables_globals.program_version
239
240 /*
241 * From libebtc.c
242 */
243
244 /* Prints all registered extensions */
ebt_list_extensions(const struct xtables_target * t,const struct xtables_rule_match * m)245 static void ebt_list_extensions(const struct xtables_target *t,
246 const struct xtables_rule_match *m)
247 {
248 printf("%s v%s\n", prog_name, prog_vers);
249 printf("Loaded userspace extensions:\n");
250 /*printf("\nLoaded tables:\n");
251 while (tbl) {
252 printf("%s\n", tbl->name);
253 tbl = tbl->next;
254 }*/
255 printf("\nLoaded targets:\n");
256 for (t = xtables_targets; t; t = t->next) {
257 printf("%s\n", t->name);
258 }
259 printf("\nLoaded matches:\n");
260 for (; m != NULL; m = m->next)
261 printf("%s\n", m->match->name);
262 /*printf("\nLoaded watchers:\n");
263 while (w) {
264 printf("%s\n", w->name);
265 w = w->next;
266 }*/
267 }
268
269 #define OPTION_OFFSET 256
merge_options(struct option * oldopts,const struct option * newopts,unsigned int * options_offset)270 static struct option *merge_options(struct option *oldopts,
271 const struct option *newopts,
272 unsigned int *options_offset)
273 {
274 unsigned int num_old, num_new, i;
275 struct option *merge;
276
277 if (!newopts || !oldopts || !options_offset)
278 return oldopts;
279 for (num_old = 0; oldopts[num_old].name; num_old++);
280 for (num_new = 0; newopts[num_new].name; num_new++);
281
282 ebtables_globals.option_offset += OPTION_OFFSET;
283 *options_offset = ebtables_globals.option_offset;
284
285 merge = xtables_malloc(sizeof(struct option) * (num_new + num_old + 1));
286 memcpy(merge, oldopts, num_old * sizeof(struct option));
287 for (i = 0; i < num_new; i++) {
288 merge[num_old + i] = newopts[i];
289 merge[num_old + i].val += *options_offset;
290 }
291 memset(merge + num_old + num_new, 0, sizeof(struct option));
292 /* Only free dynamically allocated stuff */
293 if (oldopts != ebt_original_options)
294 free(oldopts);
295
296 return merge;
297 }
298
print_help(const struct xtables_target * t,const struct xtables_rule_match * m,const char * table)299 static void print_help(const struct xtables_target *t,
300 const struct xtables_rule_match *m, const char *table)
301 {
302 printf("%s %s\n", prog_name, prog_vers);
303 printf(
304 "Usage:\n"
305 "ebtables -[ADI] chain rule-specification [options]\n"
306 "ebtables -P chain target\n"
307 "ebtables -[LFZ] [chain]\n"
308 "ebtables -[NX] [chain]\n"
309 "ebtables -E old-chain-name new-chain-name\n\n"
310 "Commands:\n"
311 "--append -A chain : append to chain\n"
312 "--delete -D chain : delete matching rule from chain\n"
313 "--delete -D chain rulenum : delete rule at position rulenum from chain\n"
314 "--change-counters -C chain\n"
315 " [rulenum] pcnt bcnt : change counters of existing rule\n"
316 "--insert -I chain rulenum : insert rule at position rulenum in chain\n"
317 "--list -L [chain] : list the rules in a chain or in all chains\n"
318 "--flush -F [chain] : delete all rules in chain or in all chains\n"
319 "--init-table : replace the kernel table with the initial table\n"
320 "--zero -Z [chain] : put counters on zero in chain or in all chains\n"
321 "--policy -P chain target : change policy on chain to target\n"
322 "--new-chain -N chain : create a user defined chain\n"
323 "--rename-chain -E old new : rename a chain\n"
324 "--delete-chain -X [chain] : delete a user defined chain\n"
325 "Options:\n"
326 "--proto -p [!] proto : protocol hexadecimal, by name or LENGTH\n"
327 "--src -s [!] address[/mask]: source mac address\n"
328 "--dst -d [!] address[/mask]: destination mac address\n"
329 "--in-if -i [!] name[+] : network input interface name\n"
330 "--out-if -o [!] name[+] : network output interface name\n"
331 "--logical-in [!] name[+] : logical bridge input interface name\n"
332 "--logical-out [!] name[+] : logical bridge output interface name\n"
333 "--set-counters -c chain\n"
334 " pcnt bcnt : set the counters of the to be added rule\n"
335 "--modprobe -M program : try to insert modules using this program\n"
336 "--concurrent : use a file lock to support concurrent scripts\n"
337 "--verbose -v : verbose mode\n"
338 "--version -V : print package version\n\n"
339 "Environment variable:\n"
340 /*ATOMIC_ENV_VARIABLE " : if set <FILE> (see above) will equal its value"*/
341 "\n\n");
342 for (; m != NULL; m = m->next) {
343 printf("\n");
344 m->match->help();
345 }
346 if (t != NULL) {
347 printf("\n");
348 t->help();
349 }
350
351 // if (table->help)
352 // table->help(ebt_hooknames);
353 }
354
355 /* Execute command L */
list_rules(struct nft_handle * h,const char * chain,const char * table,int rule_nr,int verbose,int numeric,int expanded,int linenumbers,int counters)356 static int list_rules(struct nft_handle *h, const char *chain, const char *table,
357 int rule_nr, int verbose, int numeric, int expanded,
358 int linenumbers, int counters)
359 {
360 unsigned int format;
361
362 format = FMT_OPTIONS | FMT_C_COUNTS;
363 if (verbose)
364 format |= FMT_VIA;
365
366 if (numeric)
367 format |= FMT_NUMERIC;
368
369 if (!expanded)
370 format |= FMT_KILOMEGAGIGA;
371
372 if (linenumbers)
373 format |= FMT_LINENUMBERS;
374
375 if (!counters)
376 format |= FMT_NOCOUNTS;
377
378 return nft_cmd_rule_list(h, chain, table, rule_nr, format);
379 }
380
parse_rule_range(const char * argv,int * rule_nr,int * rule_nr_end)381 static int parse_rule_range(const char *argv, int *rule_nr, int *rule_nr_end)
382 {
383 char *colon = strchr(argv, ':'), *buffer;
384
385 if (colon) {
386 *colon = '\0';
387 if (*(colon + 1) == '\0')
388 *rule_nr_end = -1; /* Until the last rule */
389 else {
390 *rule_nr_end = strtol(colon + 1, &buffer, 10);
391 if (*buffer != '\0' || *rule_nr_end == 0)
392 return -1;
393 }
394 }
395 if (colon == argv)
396 *rule_nr = 1; /* Beginning with the first rule */
397 else {
398 *rule_nr = strtol(argv, &buffer, 10);
399 if (*buffer != '\0' || *rule_nr == 0)
400 return -1;
401 }
402 if (!colon)
403 *rule_nr_end = *rule_nr;
404 return 0;
405 }
406
407 /* Incrementing or decrementing rules in daemon mode is not supported as the
408 * involved code overload is not worth it (too annoying to take the increased
409 * counters in the kernel into account). */
parse_change_counters_rule(int argc,char ** argv,int * rule_nr,int * rule_nr_end,struct iptables_command_state * cs)410 static int parse_change_counters_rule(int argc, char **argv, int *rule_nr, int *rule_nr_end, struct iptables_command_state *cs)
411 {
412 char *buffer;
413 int ret = 0;
414
415 if (optind + 1 >= argc || argv[optind][0] == '-' || argv[optind + 1][0] == '-')
416 xtables_error(PARAMETER_PROBLEM,
417 "The command -C needs at least 2 arguments");
418 if (optind + 2 < argc && (argv[optind + 2][0] != '-' || (argv[optind + 2][1] >= '0' && argv[optind + 2][1] <= '9'))) {
419 if (optind + 3 != argc)
420 xtables_error(PARAMETER_PROBLEM,
421 "No extra options allowed with -C start_nr[:end_nr] pcnt bcnt");
422 if (parse_rule_range(argv[optind], rule_nr, rule_nr_end))
423 xtables_error(PARAMETER_PROBLEM,
424 "Something is wrong with the rule number specification '%s'", argv[optind]);
425 optind++;
426 }
427
428 if (argv[optind][0] == '+') {
429 ret += 1;
430 cs->counters.pcnt = strtoull(argv[optind] + 1, &buffer, 10);
431 } else if (argv[optind][0] == '-') {
432 ret += 2;
433 cs->counters.pcnt = strtoull(argv[optind] + 1, &buffer, 10);
434 } else
435 cs->counters.pcnt = strtoull(argv[optind], &buffer, 10);
436
437 if (*buffer != '\0')
438 goto invalid;
439 optind++;
440 if (argv[optind][0] == '+') {
441 ret += 3;
442 cs->counters.bcnt = strtoull(argv[optind] + 1, &buffer, 10);
443 } else if (argv[optind][0] == '-') {
444 ret += 6;
445 cs->counters.bcnt = strtoull(argv[optind] + 1, &buffer, 10);
446 } else
447 cs->counters.bcnt = strtoull(argv[optind], &buffer, 10);
448
449 if (*buffer != '\0')
450 goto invalid;
451 optind++;
452 return ret;
453 invalid:
454 xtables_error(PARAMETER_PROBLEM,"Packet counter '%s' invalid", argv[optind]);
455 }
456
ebtables_parse_interface(const char * arg,char * vianame)457 static void ebtables_parse_interface(const char *arg, char *vianame)
458 {
459 unsigned char mask[IFNAMSIZ];
460 char *c;
461
462 xtables_parse_interface(arg, vianame, mask);
463
464 if ((c = strchr(vianame, '+'))) {
465 if (*(c + 1) != '\0')
466 xtables_error(PARAMETER_PROBLEM,
467 "Spurious characters after '+' wildcard");
468 }
469 }
470
471 /* This code is very similar to iptables/xtables.c:command_match() */
ebt_load_match(const char * name)472 static void ebt_load_match(const char *name)
473 {
474 struct xtables_match *m;
475 size_t size;
476
477 m = xtables_find_match(name, XTF_TRY_LOAD, NULL);
478 if (m == NULL) {
479 fprintf(stderr, "Unable to load %s match\n", name);
480 return;
481 }
482
483 size = XT_ALIGN(sizeof(struct xt_entry_match)) + m->size;
484 m->m = xtables_calloc(1, size);
485 m->m->u.match_size = size;
486 strcpy(m->m->u.user.name, m->name);
487 m->m->u.user.revision = m->revision;
488 xs_init_match(m);
489
490 opts = merge_options(opts, m->extra_opts, &m->option_offset);
491 if (opts == NULL)
492 xtables_error(OTHER_PROBLEM, "Can't alloc memory");
493 }
494
ebt_load_watcher(const char * name)495 static void ebt_load_watcher(const char *name)
496 {
497 struct xtables_target *watcher;
498 size_t size;
499
500 watcher = xtables_find_target(name, XTF_TRY_LOAD);
501 if (!watcher) {
502 fprintf(stderr, "Unable to load %s watcher\n", name);
503 return;
504 }
505
506 size = XT_ALIGN(sizeof(struct xt_entry_target)) + watcher->size;
507
508 watcher->t = xtables_calloc(1, size);
509 watcher->t->u.target_size = size;
510 snprintf(watcher->t->u.user.name,
511 sizeof(watcher->t->u.user.name), "%s", name);
512 watcher->t->u.user.name[sizeof(watcher->t->u.user.name)-1] = '\0';
513 watcher->t->u.user.revision = watcher->revision;
514
515 xs_init_target(watcher);
516
517 opts = merge_options(opts, watcher->extra_opts,
518 &watcher->option_offset);
519 if (opts == NULL)
520 xtables_error(OTHER_PROBLEM, "Can't alloc memory");
521 }
522
ebt_load_match_extensions(void)523 void ebt_load_match_extensions(void)
524 {
525 opts = ebt_original_options;
526 ebt_load_match("802_3");
527 ebt_load_match("arp");
528 ebt_load_match("ip");
529 ebt_load_match("ip6");
530 ebt_load_match("mark_m");
531 ebt_load_match("limit");
532 ebt_load_match("pkttype");
533 ebt_load_match("vlan");
534 ebt_load_match("stp");
535 ebt_load_match("among");
536
537 ebt_load_watcher("log");
538 ebt_load_watcher("nflog");
539 }
540
ebt_add_match(struct xtables_match * m,struct iptables_command_state * cs)541 void ebt_add_match(struct xtables_match *m,
542 struct iptables_command_state *cs)
543 {
544 struct xtables_rule_match **rule_matches = &cs->matches;
545 struct xtables_match *newm;
546 struct ebt_match *newnode, **matchp;
547 struct xt_entry_match *m2;
548
549 newm = xtables_find_match(m->name, XTF_LOAD_MUST_SUCCEED, rule_matches);
550 if (newm == NULL)
551 xtables_error(OTHER_PROBLEM,
552 "Unable to add match %s", m->name);
553
554 m2 = xtables_calloc(1, newm->m->u.match_size);
555 memcpy(m2, newm->m, newm->m->u.match_size);
556 memset(newm->m->data, 0, newm->size);
557 xs_init_match(newm);
558 newm->m = m2;
559
560 newm->mflags = m->mflags;
561 m->mflags = 0;
562
563 /* glue code for watchers */
564 newnode = xtables_calloc(1, sizeof(struct ebt_match));
565 newnode->ismatch = true;
566 newnode->u.match = newm;
567
568 for (matchp = &cs->match_list; *matchp; matchp = &(*matchp)->next)
569 ;
570 *matchp = newnode;
571 }
572
ebt_add_watcher(struct xtables_target * watcher,struct iptables_command_state * cs)573 void ebt_add_watcher(struct xtables_target *watcher,
574 struct iptables_command_state *cs)
575 {
576 struct ebt_match *newnode, **matchp;
577 struct xtables_target *clone;
578
579 clone = xtables_malloc(sizeof(struct xtables_target));
580 memcpy(clone, watcher, sizeof(struct xtables_target));
581 clone->udata = NULL;
582 clone->tflags = watcher->tflags;
583 clone->next = clone;
584
585 clone->t = xtables_calloc(1, watcher->t->u.target_size);
586 memcpy(clone->t, watcher->t, watcher->t->u.target_size);
587
588 memset(watcher->t->data, 0, watcher->size);
589 xs_init_target(watcher);
590 watcher->tflags = 0;
591
592
593 newnode = xtables_calloc(1, sizeof(struct ebt_match));
594 newnode->u.watcher = clone;
595
596 for (matchp = &cs->match_list; *matchp; matchp = &(*matchp)->next)
597 ;
598 *matchp = newnode;
599 }
600
ebt_command_default(struct iptables_command_state * cs)601 int ebt_command_default(struct iptables_command_state *cs)
602 {
603 struct xtables_target *t = cs->target;
604 struct xtables_match *m;
605 struct ebt_match *matchp;
606
607 /* Is it a target option? */
608 if (t && t->parse) {
609 if (t->parse(cs->c - t->option_offset, cs->argv,
610 ebt_invert, &t->tflags, NULL, &t->t))
611 return 0;
612 }
613
614 /* check previously added matches/watchers to this rule first */
615 for (matchp = cs->match_list; matchp; matchp = matchp->next) {
616 if (matchp->ismatch) {
617 m = matchp->u.match;
618 if (m->parse &&
619 m->parse(cs->c - m->option_offset, cs->argv,
620 ebt_invert, &m->mflags, NULL, &m->m))
621 return 0;
622 } else {
623 t = matchp->u.watcher;
624 if (t->parse &&
625 t->parse(cs->c - t->option_offset, cs->argv,
626 ebt_invert, &t->tflags, NULL, &t->t))
627 return 0;
628 }
629 }
630
631 /* Is it a match_option? */
632 for (m = xtables_matches; m; m = m->next) {
633 if (m->parse &&
634 m->parse(cs->c - m->option_offset, cs->argv,
635 ebt_invert, &m->mflags, NULL, &m->m)) {
636 ebt_add_match(m, cs);
637 return 0;
638 }
639 }
640
641 /* Is it a watcher option? */
642 for (t = xtables_targets; t; t = t->next) {
643 if (!(t->ext_flags & XTABLES_EXT_WATCHER))
644 continue;
645
646 if (t->parse &&
647 t->parse(cs->c - t->option_offset, cs->argv,
648 ebt_invert, &t->tflags, NULL, &t->t)) {
649 ebt_add_watcher(t, cs);
650 return 0;
651 }
652 }
653 if (cs->c == ':')
654 xtables_error(PARAMETER_PROBLEM, "option \"%s\" "
655 "requires an argument", cs->argv[optind - 1]);
656 if (cs->c == '?') {
657 char optoptstr[3] = {'-', optopt, '\0'};
658
659 xtables_error(PARAMETER_PROBLEM, "unknown option \"%s\"",
660 optopt ? optoptstr : cs->argv[optind - 1]);
661 }
662 xtables_error(PARAMETER_PROBLEM, "Unknown arg \"%s\"", optarg);
663 }
664
nft_init_eb(struct nft_handle * h,const char * pname)665 int nft_init_eb(struct nft_handle *h, const char *pname)
666 {
667 ebtables_globals.program_name = pname;
668 if (xtables_init_all(&ebtables_globals, NFPROTO_BRIDGE) < 0) {
669 fprintf(stderr, "%s/%s Failed to initialize ebtables-compat\n",
670 ebtables_globals.program_name,
671 ebtables_globals.program_version);
672 exit(1);
673 }
674 init_extensions();
675 init_extensionsb();
676
677 if (nft_init(h, NFPROTO_BRIDGE) < 0)
678 xtables_error(OTHER_PROBLEM,
679 "Could not initialize nftables layer.");
680
681 /* manually registering ebt matches, given the original ebtables parser
682 * don't use '-m matchname' and the match can't be loaded dynamically when
683 * the user calls it.
684 */
685 ebt_load_match_extensions();
686
687 return 0;
688 }
689
nft_fini_eb(struct nft_handle * h)690 void nft_fini_eb(struct nft_handle *h)
691 {
692 struct xtables_match *match;
693 struct xtables_target *target;
694
695 for (match = xtables_matches; match; match = match->next) {
696 free(match->m);
697 }
698 for (target = xtables_targets; target; target = target->next) {
699 free(target->t);
700 }
701
702 if (opts != ebt_original_options)
703 free(opts);
704
705 nft_fini(h);
706 xtables_fini();
707 }
708
do_commandeb(struct nft_handle * h,int argc,char * argv[],char ** table,bool restore)709 int do_commandeb(struct nft_handle *h, int argc, char *argv[], char **table,
710 bool restore)
711 {
712 char *buffer;
713 int c, i;
714 int chcounter = 0; /* Needed for -C */
715 int rule_nr = 0;
716 int rule_nr_end = 0;
717 int ret = 0;
718 unsigned int flags = 0;
719 struct xtables_target *t;
720 struct iptables_command_state cs = {
721 .argv = argv,
722 .jumpto = "",
723 .eb.bitmask = EBT_NOPROTO,
724 };
725 char command = 'h';
726 const char *chain = NULL;
727 const char *policy = NULL;
728 int selected_chain = -1;
729 struct xtables_rule_match *xtrm_i;
730 struct ebt_match *match;
731 bool table_set = false;
732
733 /* avoid cumulating verbosity with ebtables-restore */
734 h->verbose = 0;
735
736 /* prevent getopt to spoil our error reporting */
737 optind = 0;
738 opterr = false;
739
740 for (t = xtables_targets; t; t = t->next) {
741 t->tflags = 0;
742 t->used = 0;
743 }
744
745 /* Getopt saves the day */
746 while ((c = getopt_long(argc, argv, EBT_OPTSTRING,
747 opts, NULL)) != -1) {
748 cs.c = c;
749 switch (c) {
750
751 case 'A': /* Add a rule */
752 case 'D': /* Delete a rule */
753 case 'C': /* Change counters */
754 case 'P': /* Define policy */
755 case 'I': /* Insert a rule */
756 case 'N': /* Make a user defined chain */
757 case 'E': /* Rename chain */
758 case 'X': /* Delete chain */
759 case 14: /* check a rule */
760 /* We allow -N chainname -P policy */
761 if (command == 'N' && c == 'P') {
762 command = c;
763 optind--; /* No table specified */
764 goto handle_P;
765 }
766 if (OPT_COMMANDS)
767 xtables_error(PARAMETER_PROBLEM,
768 "Multiple commands are not allowed");
769
770 command = c;
771 if (optarg && (optarg[0] == '-' || !strcmp(optarg, "!")))
772 xtables_error(PARAMETER_PROBLEM, "No chain name specified");
773 chain = optarg;
774 selected_chain = ebt_get_current_chain(chain);
775 flags |= OPT_COMMAND;
776
777 if (c == 'N') {
778 ebt_assert_valid_chain_name(chain);
779 ret = nft_cmd_chain_user_add(h, chain, *table);
780 break;
781 } else if (c == 'X') {
782 /* X arg is optional, optarg is NULL */
783 if (!chain && optind < argc && argv[optind][0] != '-') {
784 chain = argv[optind];
785 optind++;
786 }
787 ret = nft_cmd_chain_del(h, chain, *table, 0);
788 break;
789 }
790
791 if (c == 'E') {
792 if (!xs_has_arg(argc, argv))
793 xtables_error(PARAMETER_PROBLEM, "No new chain name specified");
794 else if (optind < argc - 1)
795 xtables_error(PARAMETER_PROBLEM, "No extra options allowed with -E");
796
797 ebt_assert_valid_chain_name(argv[optind]);
798
799 errno = 0;
800 ret = nft_cmd_chain_user_rename(h, chain, *table,
801 argv[optind]);
802 if (ret != 0 && errno == ENOENT)
803 xtables_error(PARAMETER_PROBLEM, "Chain '%s' doesn't exists", chain);
804
805 optind++;
806 break;
807 } else if (c == 'D' && optind < argc && (argv[optind][0] != '-' || (argv[optind][1] >= '0' && argv[optind][1] <= '9'))) {
808 if (optind != argc - 1)
809 xtables_error(PARAMETER_PROBLEM,
810 "No extra options allowed with -D start_nr[:end_nr]");
811 if (parse_rule_range(argv[optind], &rule_nr, &rule_nr_end))
812 xtables_error(PARAMETER_PROBLEM,
813 "Problem with the specified rule number(s) '%s'", argv[optind]);
814 optind++;
815 } else if (c == 'C') {
816 if ((chcounter = parse_change_counters_rule(argc, argv, &rule_nr, &rule_nr_end, &cs)) == -1)
817 return -1;
818 } else if (c == 'I') {
819 if (optind >= argc || (argv[optind][0] == '-' && (argv[optind][1] < '0' || argv[optind][1] > '9')))
820 rule_nr = 1;
821 else {
822 rule_nr = parse_rule_number(argv[optind]);
823 optind++;
824 }
825 } else if (c == 'P') {
826 handle_P:
827 if (optind >= argc)
828 xtables_error(PARAMETER_PROBLEM,
829 "No policy specified");
830 for (i = 0; i < NUM_STANDARD_TARGETS; i++)
831 if (!strcmp(argv[optind], nft_ebt_standard_target(i))) {
832 policy = argv[optind];
833 if (-i-1 == EBT_CONTINUE)
834 xtables_error(PARAMETER_PROBLEM,
835 "Wrong policy '%s'",
836 argv[optind]);
837 break;
838 }
839 if (i == NUM_STANDARD_TARGETS)
840 xtables_error(PARAMETER_PROBLEM,
841 "Unknown policy '%s'", argv[optind]);
842 optind++;
843 }
844 break;
845 case 'L': /* List */
846 case 'F': /* Flush */
847 case 'Z': /* Zero counters */
848 if (c == 'Z') {
849 if ((flags & OPT_ZERO) || (flags & OPT_COMMAND && command != 'L'))
850 print_zero:
851 xtables_error(PARAMETER_PROBLEM,
852 "Command -Z only allowed together with command -L");
853 flags |= OPT_ZERO;
854 } else {
855 if (flags & OPT_COMMAND)
856 xtables_error(PARAMETER_PROBLEM,
857 "Multiple commands are not allowed");
858 command = c;
859 flags |= OPT_COMMAND;
860 if (flags & OPT_ZERO && c != 'L')
861 goto print_zero;
862 }
863
864 if (optind < argc && argv[optind][0] != '-') {
865 chain = argv[optind];
866 optind++;
867 }
868 break;
869 case 'v': /* verbose */
870 flags |= OPT_VERBOSE;
871 h->verbose++;
872 break;
873 case 'V': /* Version */
874 if (OPT_COMMANDS)
875 xtables_error(PARAMETER_PROBLEM,
876 "Multiple commands are not allowed");
877 printf("%s %s\n", prog_name, prog_vers);
878 exit(0);
879 case 'h': /* Help */
880 if (OPT_COMMANDS)
881 xtables_error(PARAMETER_PROBLEM,
882 "Multiple commands are not allowed");
883 command = 'h';
884
885 /* All other arguments should be extension names */
886 while (optind < argc) {
887 /*struct ebt_u_match *m;
888 struct ebt_u_watcher *w;*/
889
890 if (!strcasecmp("list_extensions", argv[optind])) {
891 ebt_list_extensions(xtables_targets, cs.matches);
892 exit(0);
893 }
894 /*if ((m = ebt_find_match(argv[optind])))
895 ebt_add_match(new_entry, m);
896 else if ((w = ebt_find_watcher(argv[optind])))
897 ebt_add_watcher(new_entry, w);
898 else {*/
899 if (!(t = xtables_find_target(argv[optind], XTF_TRY_LOAD)))
900 xtables_error(PARAMETER_PROBLEM,"Extension '%s' not found", argv[optind]);
901 if (flags & OPT_JUMP)
902 xtables_error(PARAMETER_PROBLEM,"Sorry, you can only see help for one target extension at a time");
903 flags |= OPT_JUMP;
904 cs.target = t;
905 //}
906 optind++;
907 }
908 break;
909 case 't': /* Table */
910 if (restore && table_set)
911 xtables_error(PARAMETER_PROBLEM,
912 "The -t option cannot be used in %s.",
913 xt_params->program_name);
914 else if (table_set)
915 xtables_error(PARAMETER_PROBLEM,
916 "Multiple use of same option not allowed");
917 if (!nft_table_builtin_find(h, optarg))
918 xtables_error(VERSION_PROBLEM,
919 "table '%s' does not exist",
920 optarg);
921 *table = optarg;
922 table_set = true;
923 break;
924 case 'i': /* Input interface */
925 case 2 : /* Logical input interface */
926 case 'o': /* Output interface */
927 case 3 : /* Logical output interface */
928 case 'j': /* Target */
929 case 'p': /* Net family protocol */
930 case 's': /* Source mac */
931 case 'd': /* Destination mac */
932 case 'c': /* Set counters */
933 if (!OPT_COMMANDS)
934 xtables_error(PARAMETER_PROBLEM,
935 "No command specified");
936 if (command != 'A' && command != 'D' &&
937 command != 'I' && command != 'C' && command != 14)
938 xtables_error(PARAMETER_PROBLEM,
939 "Command and option do not match");
940 if (c == 'i') {
941 ebt_check_option2(&flags, OPT_VIANAMEIN);
942 if (selected_chain > 2 && selected_chain < NF_BR_BROUTING)
943 xtables_error(PARAMETER_PROBLEM,
944 "Use -i only in INPUT, FORWARD, PREROUTING and BROUTING chains");
945 if (ebt_check_inverse2(optarg, argc, argv))
946 cs.eb.invflags |= EBT_IIN;
947
948 ebtables_parse_interface(optarg, cs.eb.in);
949 break;
950 } else if (c == 2) {
951 ebt_check_option2(&flags, OPT_LOGICALIN);
952 if (selected_chain > 2 && selected_chain < NF_BR_BROUTING)
953 xtables_error(PARAMETER_PROBLEM,
954 "Use --logical-in only in INPUT, FORWARD, PREROUTING and BROUTING chains");
955 if (ebt_check_inverse2(optarg, argc, argv))
956 cs.eb.invflags |= EBT_ILOGICALIN;
957
958 ebtables_parse_interface(optarg, cs.eb.logical_in);
959 break;
960 } else if (c == 'o') {
961 ebt_check_option2(&flags, OPT_VIANAMEOUT);
962 if (selected_chain < 2 || selected_chain == NF_BR_BROUTING)
963 xtables_error(PARAMETER_PROBLEM,
964 "Use -o only in OUTPUT, FORWARD and POSTROUTING chains");
965 if (ebt_check_inverse2(optarg, argc, argv))
966 cs.eb.invflags |= EBT_IOUT;
967
968 ebtables_parse_interface(optarg, cs.eb.out);
969 break;
970 } else if (c == 3) {
971 ebt_check_option2(&flags, OPT_LOGICALOUT);
972 if (selected_chain < 2 || selected_chain == NF_BR_BROUTING)
973 xtables_error(PARAMETER_PROBLEM,
974 "Use --logical-out only in OUTPUT, FORWARD and POSTROUTING chains");
975 if (ebt_check_inverse2(optarg, argc, argv))
976 cs.eb.invflags |= EBT_ILOGICALOUT;
977
978 ebtables_parse_interface(optarg, cs.eb.logical_out);
979 break;
980 } else if (c == 'j') {
981 ebt_check_option2(&flags, OPT_JUMP);
982 if (strcmp(optarg, "CONTINUE") != 0) {
983 command_jump(&cs, optarg);
984 }
985 break;
986 } else if (c == 's') {
987 ebt_check_option2(&flags, OPT_SOURCE);
988 if (ebt_check_inverse2(optarg, argc, argv))
989 cs.eb.invflags |= EBT_ISOURCE;
990
991 if (xtables_parse_mac_and_mask(optarg,
992 cs.eb.sourcemac,
993 cs.eb.sourcemsk))
994 xtables_error(PARAMETER_PROBLEM, "Problem with specified source mac '%s'", optarg);
995 cs.eb.bitmask |= EBT_SOURCEMAC;
996 break;
997 } else if (c == 'd') {
998 ebt_check_option2(&flags, OPT_DESTINATION);
999 if (ebt_check_inverse2(optarg, argc, argv))
1000 cs.eb.invflags |= EBT_IDEST;
1001
1002 if (xtables_parse_mac_and_mask(optarg,
1003 cs.eb.destmac,
1004 cs.eb.destmsk))
1005 xtables_error(PARAMETER_PROBLEM, "Problem with specified destination mac '%s'", optarg);
1006 cs.eb.bitmask |= EBT_DESTMAC;
1007 break;
1008 } else if (c == 'c') {
1009 ebt_check_option2(&flags, OPT_COUNTERS);
1010 if (ebt_check_inverse2(optarg, argc, argv))
1011 xtables_error(PARAMETER_PROBLEM,
1012 "Unexpected '!' after -c");
1013 if (optind >= argc || optarg[0] == '-' || argv[optind][0] == '-')
1014 xtables_error(PARAMETER_PROBLEM,
1015 "Option -c needs 2 arguments");
1016
1017 cs.counters.pcnt = strtoull(optarg, &buffer, 10);
1018 if (*buffer != '\0')
1019 xtables_error(PARAMETER_PROBLEM,
1020 "Packet counter '%s' invalid",
1021 optarg);
1022 cs.counters.bcnt = strtoull(argv[optind], &buffer, 10);
1023 if (*buffer != '\0')
1024 xtables_error(PARAMETER_PROBLEM,
1025 "Packet counter '%s' invalid",
1026 argv[optind]);
1027 optind++;
1028 break;
1029 }
1030 ebt_check_option2(&flags, OPT_PROTOCOL);
1031 if (ebt_check_inverse2(optarg, argc, argv))
1032 cs.eb.invflags |= EBT_IPROTO;
1033
1034 cs.eb.bitmask &= ~((unsigned int)EBT_NOPROTO);
1035 i = strtol(optarg, &buffer, 16);
1036 if (*buffer == '\0' && (i < 0 || i > 0xFFFF))
1037 xtables_error(PARAMETER_PROBLEM,
1038 "Problem with the specified protocol");
1039 if (*buffer != '\0') {
1040 struct xt_ethertypeent *ent;
1041
1042 if (!strcasecmp(optarg, "LENGTH")) {
1043 cs.eb.bitmask |= EBT_802_3;
1044 break;
1045 }
1046 ent = xtables_getethertypebyname(optarg);
1047 if (!ent)
1048 xtables_error(PARAMETER_PROBLEM,
1049 "Problem with the specified Ethernet protocol '%s', perhaps "XT_PATH_ETHERTYPES " is missing", optarg);
1050 cs.eb.ethproto = ent->e_ethertype;
1051 } else
1052 cs.eb.ethproto = i;
1053
1054 if (cs.eb.ethproto < 0x0600)
1055 xtables_error(PARAMETER_PROBLEM,
1056 "Sorry, protocols have values above or equal to 0x0600");
1057 break;
1058 case 4 : /* Lc */
1059 ebt_check_option2(&flags, LIST_C);
1060 if (command != 'L')
1061 xtables_error(PARAMETER_PROBLEM,
1062 "Use --Lc with -L");
1063 flags |= LIST_C;
1064 break;
1065 case 5 : /* Ln */
1066 ebt_check_option2(&flags, LIST_N);
1067 if (command != 'L')
1068 xtables_error(PARAMETER_PROBLEM,
1069 "Use --Ln with -L");
1070 if (flags & LIST_X)
1071 xtables_error(PARAMETER_PROBLEM,
1072 "--Lx is not compatible with --Ln");
1073 flags |= LIST_N;
1074 break;
1075 case 6 : /* Lx */
1076 ebt_check_option2(&flags, LIST_X);
1077 if (command != 'L')
1078 xtables_error(PARAMETER_PROBLEM,
1079 "Use --Lx with -L");
1080 if (flags & LIST_N)
1081 xtables_error(PARAMETER_PROBLEM,
1082 "--Lx is not compatible with --Ln");
1083 flags |= LIST_X;
1084 break;
1085 case 12 : /* Lmac2 */
1086 ebt_check_option2(&flags, LIST_MAC2);
1087 if (command != 'L')
1088 xtables_error(PARAMETER_PROBLEM,
1089 "Use --Lmac2 with -L");
1090 flags |= LIST_MAC2;
1091 break;
1092 case 11: /* init-table */
1093 if (restore)
1094 xtables_error(PARAMETER_PROBLEM,
1095 "--init-table is not supported in daemon mode");
1096 nft_cmd_table_flush(h, *table, false);
1097 return 1;
1098 case 13 :
1099 break;
1100 case 1 :
1101 if (!strcmp(optarg, "!"))
1102 ebt_check_inverse2(optarg, argc, argv);
1103 else
1104 xtables_error(PARAMETER_PROBLEM,
1105 "Bad argument : '%s'", optarg);
1106 /* ebt_ebt_check_inverse2() did optind++ */
1107 optind--;
1108 continue;
1109 default:
1110 ebt_check_inverse2(optarg, argc, argv);
1111 ebt_command_default(&cs);
1112
1113 if (command != 'A' && command != 'I' &&
1114 command != 'D' && command != 'C' && command != 14)
1115 xtables_error(PARAMETER_PROBLEM,
1116 "Extensions only for -A, -I, -D and -C");
1117 }
1118 ebt_invert = 0;
1119 }
1120
1121 /* Just in case we didn't catch an error */
1122 /*if (ebt_errormsg[0] != '\0')
1123 return -1;
1124
1125 if (!(table = ebt_find_table(replace->name)))
1126 ebt_print_error2("Bad table name");*/
1127
1128 if (command == 'h' && !(flags & OPT_ZERO)) {
1129 print_help(cs.target, cs.matches, *table);
1130 ret = 1;
1131 }
1132
1133 /* Do the final checks */
1134 if (command == 'A' || command == 'I' ||
1135 command == 'D' || command == 'C' || command == 14) {
1136 for (xtrm_i = cs.matches; xtrm_i; xtrm_i = xtrm_i->next)
1137 xtables_option_mfcall(xtrm_i->match);
1138
1139 for (match = cs.match_list; match; match = match->next) {
1140 if (match->ismatch)
1141 continue;
1142
1143 xtables_option_tfcall(match->u.watcher);
1144 }
1145
1146 if (cs.target != NULL)
1147 xtables_option_tfcall(cs.target);
1148 }
1149 /* So, the extensions can work with the host endian.
1150 * The kernel does not have to do this of course */
1151 cs.eb.ethproto = htons(cs.eb.ethproto);
1152
1153 if (command == 'P') {
1154 if (selected_chain >= NF_BR_NUMHOOKS) {
1155 ret = ebt_cmd_user_chain_policy(h, *table, chain, policy);
1156 } else {
1157 if (strcmp(policy, "RETURN") == 0) {
1158 xtables_error(PARAMETER_PROBLEM,
1159 "Policy RETURN only allowed for user defined chains");
1160 }
1161 ret = nft_cmd_chain_set(h, *table, chain, policy, NULL);
1162 if (ret < 0)
1163 xtables_error(PARAMETER_PROBLEM, "Wrong policy");
1164 }
1165 } else if (command == 'L') {
1166 ret = list_rules(h, chain, *table, rule_nr,
1167 flags & OPT_VERBOSE,
1168 0,
1169 /*flags&OPT_EXPANDED*/0,
1170 flags&LIST_N,
1171 flags&LIST_C);
1172 }
1173 if (flags & OPT_ZERO) {
1174 ret = nft_cmd_chain_zero_counters(h, chain, *table,
1175 flags & OPT_VERBOSE);
1176 } else if (command == 'F') {
1177 ret = nft_cmd_rule_flush(h, chain, *table, flags & OPT_VERBOSE);
1178 } else if (command == 'A') {
1179 ret = append_entry(h, chain, *table, &cs, 0,
1180 flags & OPT_VERBOSE, true);
1181 } else if (command == 'I') {
1182 ret = append_entry(h, chain, *table, &cs, rule_nr - 1,
1183 flags & OPT_VERBOSE, false);
1184 } else if (command == 'D') {
1185 ret = delete_entry(h, chain, *table, &cs, rule_nr - 1,
1186 rule_nr_end, flags & OPT_VERBOSE);
1187 } else if (command == 14) {
1188 ret = nft_cmd_rule_check(h, chain, *table,
1189 &cs, flags & OPT_VERBOSE);
1190 } /*else if (replace->command == 'C') {
1191 ebt_change_counters(replace, new_entry, rule_nr, rule_nr_end, &(new_entry->cnt_surplus), chcounter);
1192 if (ebt_errormsg[0] != '\0')
1193 return -1;
1194 }*/
1195
1196 ebt_cs_clean(&cs);
1197 return ret;
1198 }
1199