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
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 <ebtables/ethernetdb.h>
41 #include <libiptc/libxtc.h>
42 #include "xshared.h"
43 #include "nft.h"
44 #include "nft-bridge.h"
45
46 /*
47 * From include/ebtables_u.h
48 */
49 #define EXEC_STYLE_PRG 0
50 #define EXEC_STYLE_DAEMON 1
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
62 unsigned char eb_mac_type_unicast[ETH_ALEN] = {0,0,0,0,0,0};
63 unsigned char eb_msk_type_unicast[ETH_ALEN] = {1,0,0,0,0,0};
64 unsigned char eb_mac_type_multicast[ETH_ALEN] = {1,0,0,0,0,0};
65 unsigned char eb_msk_type_multicast[ETH_ALEN] = {1,0,0,0,0,0};
66 unsigned char eb_mac_type_broadcast[ETH_ALEN] = {255,255,255,255,255,255};
67 unsigned char eb_msk_type_broadcast[ETH_ALEN] = {255,255,255,255,255,255};
68 unsigned char eb_mac_type_bridge_group[ETH_ALEN] = {0x01,0x80,0xc2,0,0,0};
69 unsigned char eb_msk_type_bridge_group[ETH_ALEN] = {255,255,255,255,255,255};
70
ebt_get_mac_and_mask(const char * from,unsigned char * to,unsigned char * mask)71 int ebt_get_mac_and_mask(const char *from, unsigned char *to,
72 unsigned char *mask)
73 {
74 char *p;
75 int i;
76 struct ether_addr *addr = NULL;
77
78 if (strcasecmp(from, "Unicast") == 0) {
79 memcpy(to, eb_mac_type_unicast, ETH_ALEN);
80 memcpy(mask, eb_msk_type_unicast, ETH_ALEN);
81 return 0;
82 }
83 if (strcasecmp(from, "Multicast") == 0) {
84 memcpy(to, eb_mac_type_multicast, ETH_ALEN);
85 memcpy(mask, eb_msk_type_multicast, ETH_ALEN);
86 return 0;
87 }
88 if (strcasecmp(from, "Broadcast") == 0) {
89 memcpy(to, eb_mac_type_broadcast, ETH_ALEN);
90 memcpy(mask, eb_msk_type_broadcast, ETH_ALEN);
91 return 0;
92 }
93 if (strcasecmp(from, "BGA") == 0) {
94 memcpy(to, eb_mac_type_bridge_group, ETH_ALEN);
95 memcpy(mask, eb_msk_type_bridge_group, ETH_ALEN);
96 return 0;
97 }
98 if ( (p = strrchr(from, '/')) != NULL) {
99 *p = '\0';
100 if (!(addr = ether_aton(p + 1)))
101 return -1;
102 memcpy(mask, addr, ETH_ALEN);
103 } else
104 memset(mask, 0xff, ETH_ALEN);
105 if (!(addr = ether_aton(from)))
106 return -1;
107 memcpy(to, addr, ETH_ALEN);
108 for (i = 0; i < ETH_ALEN; i++)
109 to[i] &= mask[i];
110 return 0;
111 }
112
ebt_check_inverse2(const char option[],int argc,char ** argv)113 static int ebt_check_inverse2(const char option[], int argc, char **argv)
114 {
115 if (!option)
116 return ebt_invert;
117 if (strcmp(option, "!") == 0) {
118 if (ebt_invert == 1)
119 xtables_error(PARAMETER_PROBLEM,
120 "Double use of '!' not allowed");
121 if (optind >= argc)
122 optarg = NULL;
123 else
124 optarg = argv[optind];
125 optind++;
126 ebt_invert = 1;
127 return 1;
128 }
129 return ebt_invert;
130 }
131
132 /*
133 * Glue code to use libxtables
134 */
parse_rule_number(const char * rule)135 static int parse_rule_number(const char *rule)
136 {
137 unsigned int rule_nr;
138
139 if (!xtables_strtoui(rule, NULL, &rule_nr, 1, INT_MAX))
140 xtables_error(PARAMETER_PROBLEM,
141 "Invalid rule number `%s'", rule);
142
143 return rule_nr;
144 }
145
146 static const char *
parse_target(const char * targetname)147 parse_target(const char *targetname)
148 {
149 const char *ptr;
150
151 if (strlen(targetname) < 1)
152 xtables_error(PARAMETER_PROBLEM,
153 "Invalid target name (too short)");
154
155 if (strlen(targetname)+1 > EBT_CHAIN_MAXNAMELEN)
156 xtables_error(PARAMETER_PROBLEM,
157 "Invalid target '%s' (%d chars max)",
158 targetname, EBT_CHAIN_MAXNAMELEN);
159
160 for (ptr = targetname; *ptr; ptr++)
161 if (isspace(*ptr))
162 xtables_error(PARAMETER_PROBLEM,
163 "Invalid target name `%s'", targetname);
164 return targetname;
165 }
166
167 static int
append_entry(struct nft_handle * h,const char * chain,const char * table,struct ebtables_command_state * cs,int rule_nr,bool verbose,bool append)168 append_entry(struct nft_handle *h,
169 const char *chain,
170 const char *table,
171 struct ebtables_command_state *cs,
172 int rule_nr,
173 bool verbose, bool append)
174 {
175 int ret = 1;
176
177 if (append)
178 ret = nft_rule_append(h, chain, table, cs, 0, verbose);
179 else
180 ret = nft_rule_insert(h, chain, table, cs, rule_nr, verbose);
181
182 return ret;
183 }
184
185 static int
delete_entry(struct nft_handle * h,const char * chain,const char * table,struct ebtables_command_state * cs,int rule_nr,int rule_nr_end,bool verbose)186 delete_entry(struct nft_handle *h,
187 const char *chain,
188 const char *table,
189 struct ebtables_command_state *cs,
190 int rule_nr,
191 int rule_nr_end,
192 bool verbose)
193 {
194 int ret = 1;
195
196 if (rule_nr == -1)
197 ret = nft_rule_delete(h, chain, table, cs, verbose);
198 else {
199 do {
200 ret = nft_rule_delete_num(h, chain, table,
201 rule_nr, verbose);
202 rule_nr++;
203 } while (rule_nr < rule_nr_end);
204 }
205
206 return ret;
207 }
208
get_current_chain(const char * chain)209 static int get_current_chain(const char *chain)
210 {
211 if (strcmp(chain, "PREROUTING") == 0)
212 return NF_BR_PRE_ROUTING;
213 else if (strcmp(chain, "INPUT") == 0)
214 return NF_BR_LOCAL_IN;
215 else if (strcmp(chain, "FORWARD") == 0)
216 return NF_BR_FORWARD;
217 else if (strcmp(chain, "OUTPUT") == 0)
218 return NF_BR_LOCAL_OUT;
219 else if (strcmp(chain, "POSTROUTING") == 0)
220 return NF_BR_POST_ROUTING;
221
222 return -1;
223 }
224
225 /*
226 * The original ebtables parser
227 */
228
229 /* Checks whether a command has already been specified */
230 #define OPT_COMMANDS (flags & OPT_COMMAND || flags & OPT_ZERO)
231
232 #define OPT_COMMAND 0x01
233 #define OPT_TABLE 0x02
234 #define OPT_IN 0x04
235 #define OPT_OUT 0x08
236 #define OPT_JUMP 0x10
237 #define OPT_PROTOCOL 0x20
238 #define OPT_SOURCE 0x40
239 #define OPT_DEST 0x80
240 #define OPT_ZERO 0x100
241 #define OPT_LOGICALIN 0x200
242 #define OPT_LOGICALOUT 0x400
243 #define OPT_KERNELDATA 0x800 /* This value is also defined in ebtablesd.c */
244 #define OPT_COUNT 0x1000 /* This value is also defined in libebtc.c */
245 #define OPT_CNT_INCR 0x2000 /* This value is also defined in libebtc.c */
246 #define OPT_CNT_DECR 0x4000 /* This value is also defined in libebtc.c */
247
248 /* Default command line options. Do not mess around with the already
249 * assigned numbers unless you know what you are doing */
250 static struct option ebt_original_options[] =
251 {
252 { "append" , required_argument, 0, 'A' },
253 { "insert" , required_argument, 0, 'I' },
254 { "delete" , required_argument, 0, 'D' },
255 { "list" , optional_argument, 0, 'L' },
256 { "Lc" , no_argument , 0, 4 },
257 { "Ln" , no_argument , 0, 5 },
258 { "Lx" , no_argument , 0, 6 },
259 { "Lmac2" , no_argument , 0, 12 },
260 { "zero" , optional_argument, 0, 'Z' },
261 { "flush" , optional_argument, 0, 'F' },
262 { "policy" , required_argument, 0, 'P' },
263 { "in-interface" , required_argument, 0, 'i' },
264 { "in-if" , required_argument, 0, 'i' },
265 { "logical-in" , required_argument, 0, 2 },
266 { "logical-out" , required_argument, 0, 3 },
267 { "out-interface" , required_argument, 0, 'o' },
268 { "out-if" , required_argument, 0, 'o' },
269 { "version" , no_argument , 0, 'V' },
270 { "help" , no_argument , 0, 'h' },
271 { "jump" , required_argument, 0, 'j' },
272 { "set-counters" , required_argument, 0, 'c' },
273 { "change-counters", required_argument, 0, 'C' },
274 { "proto" , required_argument, 0, 'p' },
275 { "protocol" , required_argument, 0, 'p' },
276 { "db" , required_argument, 0, 'b' },
277 { "source" , required_argument, 0, 's' },
278 { "src" , required_argument, 0, 's' },
279 { "destination" , required_argument, 0, 'd' },
280 { "dst" , required_argument, 0, 'd' },
281 { "table" , required_argument, 0, 't' },
282 { "modprobe" , required_argument, 0, 'M' },
283 { "new-chain" , required_argument, 0, 'N' },
284 { "rename-chain" , required_argument, 0, 'E' },
285 { "delete-chain" , optional_argument, 0, 'X' },
286 { "atomic-init" , no_argument , 0, 7 },
287 { "atomic-commit" , no_argument , 0, 8 },
288 { "atomic-file" , required_argument, 0, 9 },
289 { "atomic-save" , no_argument , 0, 10 },
290 { "init-table" , no_argument , 0, 11 },
291 { "concurrent" , no_argument , 0, 13 },
292 { 0 }
293 };
294
295 static void __attribute__((__noreturn__,format(printf,2,3)))
ebt_print_error(enum xtables_exittype status,const char * format,...)296 ebt_print_error(enum xtables_exittype status, const char *format, ...)
297 {
298 va_list l;
299
300 va_start(l, format);
301 vfprintf(stderr, format, l);
302 fprintf(stderr, ".\n");
303 va_end(l);
304 exit(-1);
305 }
306
307 struct xtables_globals ebtables_globals = {
308 .option_offset = 0,
309 .program_version = IPTABLES_VERSION,
310 .orig_opts = ebt_original_options,
311 .exit_err = ebt_print_error,
312 .compat_rev = nft_compatible_revision,
313 };
314
315 #define opts ebtables_globals.opts
316 #define prog_name ebtables_globals.program_name
317 #define prog_vers ebtables_globals.program_version
318
319 /*
320 * From libebtc.c
321 */
322
323 /* Prints all registered extensions */
ebt_list_extensions(const struct xtables_target * t,const struct xtables_rule_match * m)324 static void ebt_list_extensions(const struct xtables_target *t,
325 const struct xtables_rule_match *m)
326 {
327 printf("%s v%s\n", prog_name, prog_vers);
328 printf("Loaded userspace extensions:\n");
329 /*printf("\nLoaded tables:\n");
330 while (tbl) {
331 printf("%s\n", tbl->name);
332 tbl = tbl->next;
333 }*/
334 printf("\nLoaded targets:\n");
335 for (t = xtables_targets; t; t = t->next) {
336 printf("%s\n", t->name);
337 }
338 printf("\nLoaded matches:\n");
339 for (; m != NULL; m = m->next)
340 printf("%s\n", m->match->name);
341 /*printf("\nLoaded watchers:\n");
342 while (w) {
343 printf("%s\n", w->name);
344 w = w->next;
345 }*/
346 }
347
348 #define OPTION_OFFSET 256
merge_options(struct option * oldopts,const struct option * newopts,unsigned int * options_offset)349 static struct option *merge_options(struct option *oldopts,
350 const struct option *newopts,
351 unsigned int *options_offset)
352 {
353 unsigned int num_old, num_new, i;
354 struct option *merge;
355
356 if (!newopts || !oldopts || !options_offset)
357 return oldopts;
358 for (num_old = 0; oldopts[num_old].name; num_old++);
359 for (num_new = 0; newopts[num_new].name; num_new++);
360
361 ebtables_globals.option_offset += OPTION_OFFSET;
362 *options_offset = ebtables_globals.option_offset;
363
364 merge = malloc(sizeof(struct option) * (num_new + num_old + 1));
365 if (!merge)
366 return NULL;
367 memcpy(merge, oldopts, num_old * sizeof(struct option));
368 for (i = 0; i < num_new; i++) {
369 merge[num_old + i] = newopts[i];
370 merge[num_old + i].val += *options_offset;
371 }
372 memset(merge + num_old + num_new, 0, sizeof(struct option));
373 /* Only free dynamically allocated stuff */
374 if (oldopts != ebt_original_options)
375 free(oldopts);
376
377 return merge;
378 }
379
380 /*
381 * More glue code.
382 */
command_jump(struct ebtables_command_state * cs,const char * jumpto)383 static struct xtables_target *command_jump(struct ebtables_command_state *cs,
384 const char *jumpto)
385 {
386 struct xtables_target *target;
387 size_t size;
388
389 /* XTF_TRY_LOAD (may be chain name) */
390 target = xtables_find_target(jumpto, XTF_TRY_LOAD);
391
392 if (!target)
393 return NULL;
394
395 size = XT_ALIGN(sizeof(struct xt_entry_target))
396 + target->size;
397
398 target->t = xtables_calloc(1, size);
399 target->t->u.target_size = size;
400 strncpy(target->t->u.user.name, jumpto, sizeof(target->t->u.user.name));
401 target->t->u.user.name[sizeof(target->t->u.user.name)-1] = '\0';
402 target->t->u.user.revision = target->revision;
403
404 xs_init_target(target);
405
406 opts = merge_options(opts, target->extra_opts, &target->option_offset);
407 if (opts == NULL)
408 xtables_error(OTHER_PROBLEM, "Can't alloc memory");
409
410 return target;
411 }
412
print_help(const struct xtables_target * t,const struct xtables_rule_match * m,const char * table)413 static void print_help(const struct xtables_target *t,
414 const struct xtables_rule_match *m, const char *table)
415 {
416 printf("%s %s\n", prog_name, prog_vers);
417 printf(
418 "Usage:\n"
419 "ebtables -[ADI] chain rule-specification [options]\n"
420 "ebtables -P chain target\n"
421 "ebtables -[LFZ] [chain]\n"
422 "ebtables -[NX] [chain]\n"
423 "ebtables -E old-chain-name new-chain-name\n\n"
424 "Commands:\n"
425 "--append -A chain : append to chain\n"
426 "--delete -D chain : delete matching rule from chain\n"
427 "--delete -D chain rulenum : delete rule at position rulenum from chain\n"
428 "--change-counters -C chain\n"
429 " [rulenum] pcnt bcnt : change counters of existing rule\n"
430 "--insert -I chain rulenum : insert rule at position rulenum in chain\n"
431 "--list -L [chain] : list the rules in a chain or in all chains\n"
432 "--flush -F [chain] : delete all rules in chain or in all chains\n"
433 "--init-table : replace the kernel table with the initial table\n"
434 "--zero -Z [chain] : put counters on zero in chain or in all chains\n"
435 "--policy -P chain target : change policy on chain to target\n"
436 "--new-chain -N chain : create a user defined chain\n"
437 "--rename-chain -E old new : rename a chain\n"
438 "--delete-chain -X [chain] : delete a user defined chain\n"
439 "--atomic-commit : update the kernel w/t table contained in <FILE>\n"
440 "--atomic-init : put the initial kernel table into <FILE>\n"
441 "--atomic-save : put the current kernel table into <FILE>\n"
442 "--atomic-file file : set <FILE> to file\n\n"
443 "Options:\n"
444 "--proto -p [!] proto : protocol hexadecimal, by name or LENGTH\n"
445 "--src -s [!] address[/mask]: source mac address\n"
446 "--dst -d [!] address[/mask]: destination mac address\n"
447 "--in-if -i [!] name[+] : network input interface name\n"
448 "--out-if -o [!] name[+] : network output interface name\n"
449 "--logical-in [!] name[+] : logical bridge input interface name\n"
450 "--logical-out [!] name[+] : logical bridge output interface name\n"
451 "--set-counters -c chain\n"
452 " pcnt bcnt : set the counters of the to be added rule\n"
453 "--modprobe -M program : try to insert modules using this program\n"
454 "--concurrent : use a file lock to support concurrent scripts\n"
455 "--version -V : print package version\n\n"
456 "Environment variable:\n"
457 /*ATOMIC_ENV_VARIABLE " : if set <FILE> (see above) will equal its value"*/
458 "\n\n");
459 for (; m != NULL; m = m->next) {
460 printf("\n");
461 m->match->help();
462 }
463 if (t != NULL) {
464 printf("\n");
465 t->help();
466 }
467
468 // if (table->help)
469 // table->help(ebt_hooknames);
470 }
471
472 /* 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)473 static int list_rules(struct nft_handle *h, const char *chain, const char *table,
474 int rule_nr, int verbose, int numeric, int expanded,
475 int linenumbers, int counters)
476 {
477 unsigned int format;
478
479 format = FMT_OPTIONS;
480 if (verbose)
481 format |= FMT_VIA;
482
483 if (numeric)
484 format |= FMT_NUMERIC;
485
486 if (!expanded)
487 format |= FMT_KILOMEGAGIGA;
488
489 if (linenumbers)
490 format |= FMT_LINENUMBERS;
491
492 if (!counters)
493 format |= FMT_NOCOUNTS;
494
495 return nft_rule_list(h, chain, table, rule_nr, format);
496 }
497
parse_rule_range(const char * argv,int * rule_nr,int * rule_nr_end)498 static int parse_rule_range(const char *argv, int *rule_nr, int *rule_nr_end)
499 {
500 char *colon = strchr(argv, ':'), *buffer;
501
502 if (colon) {
503 *colon = '\0';
504 if (*(colon + 1) == '\0')
505 *rule_nr_end = -1; /* Until the last rule */
506 else {
507 *rule_nr_end = strtol(colon + 1, &buffer, 10);
508 if (*buffer != '\0' || *rule_nr_end == 0)
509 return -1;
510 }
511 }
512 if (colon == argv)
513 *rule_nr = 1; /* Beginning with the first rule */
514 else {
515 *rule_nr = strtol(argv, &buffer, 10);
516 if (*buffer != '\0' || *rule_nr == 0)
517 return -1;
518 }
519 if (!colon)
520 *rule_nr_end = *rule_nr;
521 return 0;
522 }
523
524 /* Incrementing or decrementing rules in daemon mode is not supported as the
525 * involved code overload is not worth it (too annoying to take the increased
526 * counters in the kernel into account). */
parse_change_counters_rule(int argc,char ** argv,int * rule_nr,int * rule_nr_end,int exec_style,struct ebtables_command_state * cs)527 static int parse_change_counters_rule(int argc, char **argv, int *rule_nr, int *rule_nr_end, int exec_style, struct ebtables_command_state *cs)
528 {
529 char *buffer;
530 int ret = 0;
531
532 if (optind + 1 >= argc || (argv[optind][0] == '-' && (argv[optind][1] < '0' || argv[optind][1] > '9')) ||
533 (argv[optind + 1][0] == '-' && (argv[optind + 1][1] < '0' && argv[optind + 1][1] > '9')))
534 xtables_error(PARAMETER_PROBLEM,
535 "The command -C needs at least 2 arguments");
536 if (optind + 2 < argc && (argv[optind + 2][0] != '-' || (argv[optind + 2][1] >= '0' && argv[optind + 2][1] <= '9'))) {
537 if (optind + 3 != argc)
538 xtables_error(PARAMETER_PROBLEM,
539 "No extra options allowed with -C start_nr[:end_nr] pcnt bcnt");
540 if (parse_rule_range(argv[optind], rule_nr, rule_nr_end))
541 xtables_error(PARAMETER_PROBLEM,
542 "Something is wrong with the rule number specification '%s'", argv[optind]);
543 optind++;
544 }
545
546 if (argv[optind][0] == '+') {
547 if (exec_style == EXEC_STYLE_DAEMON)
548 daemon_incr:
549 xtables_error(PARAMETER_PROBLEM,
550 "Incrementing rule counters (%s) not allowed in daemon mode", argv[optind]);
551 ret += 1;
552 cs->counters.pcnt = strtoull(argv[optind] + 1, &buffer, 10);
553 } else if (argv[optind][0] == '-') {
554 if (exec_style == EXEC_STYLE_DAEMON)
555 daemon_decr:
556 xtables_error(PARAMETER_PROBLEM,
557 "Decrementing rule counters (%s) not allowed in daemon mode", argv[optind]);
558 ret += 2;
559 cs->counters.pcnt = strtoull(argv[optind] + 1, &buffer, 10);
560 } else
561 cs->counters.pcnt = strtoull(argv[optind], &buffer, 10);
562
563 if (*buffer != '\0')
564 goto invalid;
565 optind++;
566 if (argv[optind][0] == '+') {
567 if (exec_style == EXEC_STYLE_DAEMON)
568 goto daemon_incr;
569 ret += 3;
570 cs->counters.bcnt = strtoull(argv[optind] + 1, &buffer, 10);
571 } else if (argv[optind][0] == '-') {
572 if (exec_style == EXEC_STYLE_DAEMON)
573 goto daemon_decr;
574 ret += 6;
575 cs->counters.bcnt = strtoull(argv[optind] + 1, &buffer, 10);
576 } else
577 cs->counters.bcnt = strtoull(argv[optind], &buffer, 10);
578
579 if (*buffer != '\0')
580 goto invalid;
581 optind++;
582 return ret;
583 invalid:
584 xtables_error(PARAMETER_PROBLEM,"Packet counter '%s' invalid", argv[optind]);
585 }
586
parse_iface(char * iface,char * option)587 static int parse_iface(char *iface, char *option)
588 {
589 char *c;
590
591 if ((c = strchr(iface, '+'))) {
592 if (*(c + 1) != '\0') {
593 xtables_error(PARAMETER_PROBLEM,
594 "Spurious characters after '+' wildcard for '%s'", option);
595 return -1;
596 } else
597 *c = IF_WILDCARD;
598 }
599 return 0;
600 }
601
602 /* This code is very similar to iptables/xtables.c:command_match() */
ebt_load_match(const char * name)603 static void ebt_load_match(const char *name)
604 {
605 struct xtables_match *m;
606 size_t size;
607
608 m = xtables_find_match(name, XTF_LOAD_MUST_SUCCEED, NULL);
609 if (m == NULL)
610 xtables_error(OTHER_PROBLEM, "Unable to load %s match", name);
611
612 size = XT_ALIGN(sizeof(struct xt_entry_match)) + m->size;
613 m->m = xtables_calloc(1, size);
614 m->m->u.match_size = size;
615 strcpy(m->m->u.user.name, m->name);
616 m->m->u.user.revision = m->revision;
617 xs_init_match(m);
618
619 opts = merge_options(opts, m->extra_opts, &m->option_offset);
620 if (opts == NULL)
621 xtables_error(OTHER_PROBLEM, "Can't alloc memory");
622 }
623
ebt_load_watcher(const char * name)624 static void ebt_load_watcher(const char *name)
625 {
626 struct xtables_target *watcher;
627 size_t size;
628
629 watcher = xtables_find_target(name, XTF_LOAD_MUST_SUCCEED);
630 if (!watcher)
631 xtables_error(OTHER_PROBLEM,
632 "Unable to load %s watcher", name);
633
634 size = XT_ALIGN(sizeof(struct xt_entry_target)) + watcher->size;
635
636 watcher->t = xtables_calloc(1, size);
637 watcher->t->u.target_size = size;
638 strncpy(watcher->t->u.user.name, name,
639 sizeof(watcher->t->u.user.name));
640 watcher->t->u.user.name[sizeof(watcher->t->u.user.name)-1] = '\0';
641 watcher->t->u.user.revision = watcher->revision;
642
643 xs_init_target(watcher);
644
645 opts = merge_options(opts, watcher->extra_opts,
646 &watcher->option_offset);
647 if (opts == NULL)
648 xtables_error(OTHER_PROBLEM, "Can't alloc memory");
649 }
650
ebt_load_match_extensions(void)651 static void ebt_load_match_extensions(void)
652 {
653 opts = ebt_original_options;
654 ebt_load_match("802_3");
655 ebt_load_match("ip");
656 ebt_load_match("mark_m");
657 ebt_load_match("limit");
658
659 ebt_load_watcher("log");
660 ebt_load_watcher("nflog");
661 }
662
ebt_add_match(struct xtables_match * m,struct ebtables_command_state * cs)663 static void ebt_add_match(struct xtables_match *m,
664 struct ebtables_command_state *cs)
665 {
666 struct xtables_rule_match *i, **rule_matches = &cs->matches;
667 struct xtables_match *newm;
668 struct ebt_match *newnode;
669
670 /* match already in rule_matches, skip inclusion */
671 for (i = *rule_matches; i; i = i->next) {
672 if (strcmp(m->name, i->match->name) == 0) {
673 i->match->mflags |= m->mflags;
674 return;
675 }
676 }
677
678 newm = xtables_find_match(m->name, XTF_LOAD_MUST_SUCCEED, rule_matches);
679 if (newm == NULL)
680 xtables_error(OTHER_PROBLEM,
681 "Unable to add match %s", m->name);
682
683 newm->mflags = m->mflags;
684
685 /* glue code for watchers */
686 newnode = calloc(1, sizeof(struct ebt_match));
687 if (newnode == NULL)
688 xtables_error(OTHER_PROBLEM, "Unable to alloc memory");
689
690 newnode->ismatch = true;
691 newnode->u.match = newm;
692
693 if (cs->match_list == NULL)
694 cs->match_list = newnode;
695 else
696 cs->match_list->next = newnode;
697 }
698
ebt_add_watcher(struct xtables_target * watcher,struct ebtables_command_state * cs)699 static void ebt_add_watcher(struct xtables_target *watcher,
700 struct ebtables_command_state *cs)
701 {
702 struct ebt_match *i, *newnode;
703
704 for (i = cs->match_list; i; i = i->next) {
705 if (i->ismatch)
706 continue;
707 if (strcmp(i->u.watcher->name, watcher->name) == 0) {
708 i->u.watcher->tflags |= watcher->tflags;
709 return;
710 }
711 }
712
713 newnode = calloc(1, sizeof(struct ebt_match));
714 if (newnode == NULL)
715 xtables_error(OTHER_PROBLEM, "Unable to alloc memory");
716
717 newnode->u.watcher = watcher;
718
719 if (cs->match_list == NULL)
720 cs->match_list = newnode;
721 else
722 cs->match_list->next = newnode;
723 }
724
725 /* We use exec_style instead of #ifdef's because ebtables.so is a shared object. */
do_commandeb(struct nft_handle * h,int argc,char * argv[],char ** table)726 int do_commandeb(struct nft_handle *h, int argc, char *argv[], char **table)
727 {
728 char *buffer;
729 int c, i;
730 int zerochain = -1; /* Needed for the -Z option (we can have -Z <this> -L <that>) */
731 int chcounter = 0; /* Needed for -C */
732 int rule_nr = 0;
733 int rule_nr_end = 0;
734 int ret = 0;
735 unsigned int flags = 0;
736 struct xtables_target *t, *w;
737 struct xtables_match *m;
738 struct ebtables_command_state cs;
739 char command = 'h';
740 const char *chain = NULL;
741 const char *policy = NULL;
742 int exec_style = EXEC_STYLE_PRG;
743 int selected_chain = -1;
744 struct xtables_rule_match *xtrm_i;
745 struct ebt_match *match;
746
747 memset(&cs, 0, sizeof(cs));
748 cs.argv = argv;
749
750 if (nft_init(h, xtables_bridge) < 0)
751 xtables_error(OTHER_PROBLEM,
752 "Could not initialize nftables layer.");
753
754 h->ops = nft_family_ops_lookup(h->family);
755 if (h->ops == NULL)
756 xtables_error(PARAMETER_PROBLEM, "Unknown family");
757
758 /* manually registering ebt matches, given the original ebtables parser
759 * don't use '-m matchname' and the match can't loaded dinamically when
760 * the user calls it.
761 */
762 ebt_load_match_extensions();
763
764 /* clear mflags in case do_commandeb gets called a second time
765 * (we clear the global list of all matches for security)*/
766 for (m = xtables_matches; m; m = m->next)
767 m->mflags = 0;
768
769 for (t = xtables_targets; t; t = t->next) {
770 t->tflags = 0;
771 t->used = 0;
772 }
773
774 /* prevent getopt to spoil our error reporting */
775 opterr = false;
776
777 /* Getopt saves the day */
778 while ((c = getopt_long(argc, argv,
779 "-A:D:C:I:N:E:X::L::Z::F::P:Vhi:o:j:c:p:s:d:t:M:", opts, NULL)) != -1) {
780 cs.c = c;
781 cs.invert = ebt_invert;
782 switch (c) {
783
784 case 'A': /* Add a rule */
785 case 'D': /* Delete a rule */
786 case 'C': /* Change counters */
787 case 'P': /* Define policy */
788 case 'I': /* Insert a rule */
789 case 'N': /* Make a user defined chain */
790 case 'E': /* Rename chain */
791 case 'X': /* Delete chain */
792 /* We allow -N chainname -P policy */
793 /* XXX: Not in ebtables-compat */
794 if (command == 'N' && c == 'P') {
795 command = c;
796 optind--; /* No table specified */
797 goto handle_P;
798 }
799 if (OPT_COMMANDS)
800 xtables_error(PARAMETER_PROBLEM,
801 "Multiple commands are not allowed");
802
803 command = c;
804 chain = optarg;
805 selected_chain = get_current_chain(chain);
806 flags |= OPT_COMMAND;
807 /*if (!(replace->flags & OPT_KERNELDATA))
808 ebt_get_kernel_table(replace, 0);*/
809 /*if (optarg && (optarg[0] == '-' || !strcmp(optarg, "!")))
810 ebt_print_error2("No chain name specified");*/
811 if (c == 'N') {
812 ret = nft_chain_user_add(h, chain, *table);
813 break;
814 } else if (c == 'X') {
815 ret = nft_chain_user_del(h, chain, *table);
816 break;
817 }
818
819 if (c == 'E') {
820 if (optind >= argc)
821 xtables_error(PARAMETER_PROBLEM, "No new chain name specified");
822 else if (optind < argc - 1)
823 xtables_error(PARAMETER_PROBLEM, "No extra options allowed with -E");
824 else if (strlen(argv[optind]) >= NFT_CHAIN_MAXNAMELEN)
825 xtables_error(PARAMETER_PROBLEM, "Chain name length can't exceed %d"" characters", NFT_CHAIN_MAXNAMELEN - 1);
826 else if (strchr(argv[optind], ' ') != NULL)
827 xtables_error(PARAMETER_PROBLEM, "Use of ' ' not allowed in chain names");
828
829 ret = nft_chain_user_rename(h, chain, *table,
830 argv[optind]);
831 if (ret != 0 && errno == ENOENT)
832 xtables_error(PARAMETER_PROBLEM, "Chain '%s' doesn't exists", chain);
833
834 optind++;
835 break;
836 } else if (c == 'D' && optind < argc && (argv[optind][0] != '-' || (argv[optind][1] >= '0' && argv[optind][1] <= '9'))) {
837 if (optind != argc - 1)
838 xtables_error(PARAMETER_PROBLEM,
839 "No extra options allowed with -D start_nr[:end_nr]");
840 if (parse_rule_range(argv[optind], &rule_nr, &rule_nr_end))
841 xtables_error(PARAMETER_PROBLEM,
842 "Problem with the specified rule number(s) '%s'", argv[optind]);
843 optind++;
844 } else if (c == 'C') {
845 if ((chcounter = parse_change_counters_rule(argc, argv, &rule_nr, &rule_nr_end, exec_style, &cs)) == -1)
846 return -1;
847 } else if (c == 'I') {
848 if (optind >= argc || (argv[optind][0] == '-' && (argv[optind][1] < '0' || argv[optind][1] > '9')))
849 rule_nr = 1;
850 else {
851 rule_nr = parse_rule_number(argv[optind]);
852 optind++;
853 }
854 } else if (c == 'P') {
855 handle_P:
856 if (optind >= argc)
857 xtables_error(PARAMETER_PROBLEM,
858 "No policy specified");
859 for (i = 0; i < NUM_STANDARD_TARGETS; i++)
860 if (!strcmp(argv[optind], nft_ebt_standard_target(i))) {
861 policy = argv[optind];
862 if (-i-1 == EBT_CONTINUE)
863 xtables_error(PARAMETER_PROBLEM,
864 "Wrong policy '%s'",
865 argv[optind]);
866 break;
867 }
868 if (i == NUM_STANDARD_TARGETS)
869 xtables_error(PARAMETER_PROBLEM,
870 "Unknown policy '%s'", argv[optind]);
871 optind++;
872 }
873 break;
874 case 'L': /* List */
875 case 'F': /* Flush */
876 case 'Z': /* Zero counters */
877 if (c == 'Z') {
878 if ((flags & OPT_ZERO) || (flags & OPT_COMMAND && command != 'L'))
879 print_zero:
880 xtables_error(PARAMETER_PROBLEM,
881 "Command -Z only allowed together with command -L");
882 flags |= OPT_ZERO;
883 } else {
884 if (flags & OPT_COMMAND)
885 xtables_error(PARAMETER_PROBLEM,
886 "Multiple commands are not allowed");
887 command = c;
888 flags |= OPT_COMMAND;
889 if (flags & OPT_ZERO && c != 'L')
890 goto print_zero;
891 }
892
893 #ifdef SILENT_DAEMON
894 if (c== 'L' && exec_style == EXEC_STYLE_DAEMON)
895 xtables_error(PARAMETER_PROBLEM,
896 "-L not supported in daemon mode");
897 #endif
898
899 /*if (!(replace->flags & OPT_KERNELDATA))
900 ebt_get_kernel_table(replace, 0);
901 i = -1;
902 if (optind < argc && argv[optind][0] != '-') {
903 if ((i = ebt_get_chainnr(replace, argv[optind])) == -1)
904 ebt_print_error2("Chain '%s' doesn't exist", argv[optind]);
905 optind++;
906 }
907 if (i != -1) {
908 if (c == 'Z')
909 zerochain = i;
910 else
911 replace->selected_chain = i;
912 }*/
913 break;
914 case 'V': /* Version */
915 if (OPT_COMMANDS)
916 xtables_error(PARAMETER_PROBLEM,
917 "Multiple commands are not allowed");
918 command = 'V';
919 if (exec_style == EXEC_STYLE_DAEMON)
920 xtables_error(PARAMETER_PROBLEM,
921 "%s %s\n", prog_name, prog_vers);
922 printf("%s %s\n", prog_name, prog_vers);
923 exit(0);
924 case 'h': /* Help */
925 #ifdef SILENT_DAEMON
926 if (exec_style == EXEC_STYLE_DAEMON)
927 xtables_error(PARAMETER_PROBLEM,
928 "-h not supported in daemon mode");
929 #endif
930 if (OPT_COMMANDS)
931 xtables_error(PARAMETER_PROBLEM,
932 "Multiple commands are not allowed");
933 command = 'h';
934
935 /* All other arguments should be extension names */
936 while (optind < argc) {
937 /*struct ebt_u_match *m;
938 struct ebt_u_watcher *w;*/
939
940 if (!strcasecmp("list_extensions", argv[optind])) {
941 ebt_list_extensions(xtables_targets, cs.matches);
942 exit(0);
943 }
944 /*if ((m = ebt_find_match(argv[optind])))
945 ebt_add_match(new_entry, m);
946 else if ((w = ebt_find_watcher(argv[optind])))
947 ebt_add_watcher(new_entry, w);
948 else {*/
949 if (!(t = xtables_find_target(argv[optind], XTF_TRY_LOAD)))
950 xtables_error(PARAMETER_PROBLEM,"Extension '%s' not found", argv[optind]);
951 if (flags & OPT_JUMP)
952 xtables_error(PARAMETER_PROBLEM,"Sorry, you can only see help for one target extension at a time");
953 flags |= OPT_JUMP;
954 cs.target = t;
955 //}
956 optind++;
957 }
958 break;
959 case 't': /* Table */
960 if (OPT_COMMANDS)
961 xtables_error(PARAMETER_PROBLEM,
962 "Please put the -t option first");
963 ebt_check_option2(&flags, OPT_TABLE);
964 if (strlen(optarg) > EBT_TABLE_MAXNAMELEN - 1)
965 xtables_error(PARAMETER_PROBLEM,
966 "Table name length cannot exceed %d characters",
967 EBT_TABLE_MAXNAMELEN - 1);
968 *table = optarg;
969 break;
970 case 'i': /* Input interface */
971 case 2 : /* Logical input interface */
972 case 'o': /* Output interface */
973 case 3 : /* Logical output interface */
974 case 'j': /* Target */
975 case 'p': /* Net family protocol */
976 case 's': /* Source mac */
977 case 'd': /* Destination mac */
978 case 'c': /* Set counters */
979 if (!OPT_COMMANDS)
980 xtables_error(PARAMETER_PROBLEM,
981 "No command specified");
982 if (command != 'A' && command != 'D' && command != 'I' && command != 'C')
983 xtables_error(PARAMETER_PROBLEM,
984 "Command and option do not match");
985 if (c == 'i') {
986 ebt_check_option2(&flags, OPT_IN);
987 if (selected_chain > 2 && selected_chain < NF_BR_BROUTING)
988 xtables_error(PARAMETER_PROBLEM,
989 "Use -i only in INPUT, FORWARD, PREROUTING and BROUTING chains");
990 if (ebt_check_inverse2(optarg, argc, argv))
991 cs.fw.invflags |= EBT_IIN;
992
993 if (strlen(optarg) >= IFNAMSIZ)
994 big_iface_length:
995 xtables_error(PARAMETER_PROBLEM,
996 "Interface name length cannot exceed %d characters",
997 IFNAMSIZ - 1);
998 xtables_parse_interface(optarg, cs.fw.in, cs.fw.in_mask);
999 break;
1000 } else if (c == 2) {
1001 ebt_check_option2(&flags, OPT_LOGICALIN);
1002 if (selected_chain > 2 && selected_chain < NF_BR_BROUTING)
1003 xtables_error(PARAMETER_PROBLEM,
1004 "Use --logical-in only in INPUT, FORWARD, PREROUTING and BROUTING chains");
1005 if (ebt_check_inverse2(optarg, argc, argv))
1006 cs.fw.invflags |= EBT_ILOGICALIN;
1007
1008 if (strlen(optarg) >= IFNAMSIZ)
1009 goto big_iface_length;
1010 strcpy(cs.fw.logical_in, optarg);
1011 if (parse_iface(cs.fw.logical_in, "--logical-in"))
1012 return -1;
1013 break;
1014 } else if (c == 'o') {
1015 ebt_check_option2(&flags, OPT_OUT);
1016 if (selected_chain < 2 || selected_chain == NF_BR_BROUTING)
1017 xtables_error(PARAMETER_PROBLEM,
1018 "Use -o only in OUTPUT, FORWARD and POSTROUTING chains");
1019 if (ebt_check_inverse2(optarg, argc, argv))
1020 cs.fw.invflags |= EBT_IOUT;
1021
1022 if (strlen(optarg) >= IFNAMSIZ)
1023 goto big_iface_length;
1024
1025 xtables_parse_interface(optarg, cs.fw.out, cs.fw.out_mask);
1026 break;
1027 } else if (c == 3) {
1028 ebt_check_option2(&flags, OPT_LOGICALOUT);
1029 if (selected_chain < 2 || selected_chain == NF_BR_BROUTING)
1030 xtables_error(PARAMETER_PROBLEM,
1031 "Use --logical-out only in OUTPUT, FORWARD and POSTROUTING chains");
1032 if (ebt_check_inverse2(optarg, argc, argv))
1033 cs.fw.invflags |= EBT_ILOGICALOUT;
1034
1035 if (strlen(optarg) >= IFNAMSIZ)
1036 goto big_iface_length;
1037 strcpy(cs.fw.logical_out, optarg);
1038 if (parse_iface(cs.fw.logical_out, "--logical-out"))
1039 return -1;
1040 break;
1041 } else if (c == 'j') {
1042 ebt_check_option2(&flags, OPT_JUMP);
1043 cs.jumpto = parse_target(optarg);
1044 cs.target = command_jump(&cs, cs.jumpto);
1045 break;
1046 } else if (c == 's') {
1047 ebt_check_option2(&flags, OPT_SOURCE);
1048 if (ebt_check_inverse2(optarg, argc, argv))
1049 cs.fw.invflags |= EBT_ISOURCE;
1050
1051 if (ebt_get_mac_and_mask(optarg, cs.fw.sourcemac, cs.fw.sourcemsk))
1052 xtables_error(PARAMETER_PROBLEM, "Problem with specified source mac '%s'", optarg);
1053 cs.fw.bitmask |= EBT_SOURCEMAC;
1054 break;
1055 } else if (c == 'd') {
1056 ebt_check_option2(&flags, OPT_DEST);
1057 if (ebt_check_inverse2(optarg, argc, argv))
1058 cs.fw.invflags |= EBT_IDEST;
1059
1060 if (ebt_get_mac_and_mask(optarg, cs.fw.destmac, cs.fw.destmsk))
1061 xtables_error(PARAMETER_PROBLEM, "Problem with specified destination mac '%s'", optarg);
1062 cs.fw.bitmask |= EBT_DESTMAC;
1063 break;
1064 } else if (c == 'c') {
1065 ebt_check_option2(&flags, OPT_COUNT);
1066 if (ebt_check_inverse2(optarg, argc, argv))
1067 xtables_error(PARAMETER_PROBLEM,
1068 "Unexpected '!' after -c");
1069 if (optind >= argc || optarg[0] == '-' || argv[optind][0] == '-')
1070 xtables_error(PARAMETER_PROBLEM,
1071 "Option -c needs 2 arguments");
1072
1073 cs.counters.pcnt = strtoull(optarg, &buffer, 10);
1074 if (*buffer != '\0')
1075 xtables_error(PARAMETER_PROBLEM,
1076 "Packet counter '%s' invalid",
1077 optarg);
1078 cs.counters.bcnt = strtoull(argv[optind], &buffer, 10);
1079 if (*buffer != '\0')
1080 xtables_error(PARAMETER_PROBLEM,
1081 "Packet counter '%s' invalid",
1082 argv[optind]);
1083 optind++;
1084 break;
1085 }
1086 ebt_check_option2(&flags, OPT_PROTOCOL);
1087 if (ebt_check_inverse2(optarg, argc, argv))
1088 cs.fw.invflags |= EBT_IPROTO;
1089
1090 cs.fw.bitmask &= ~((unsigned int)EBT_NOPROTO);
1091 i = strtol(optarg, &buffer, 16);
1092 if (*buffer == '\0' && (i < 0 || i > 0xFFFF))
1093 xtables_error(PARAMETER_PROBLEM,
1094 "Problem with the specified protocol");
1095 if (*buffer != '\0') {
1096 struct ethertypeent *ent;
1097
1098 if (!strcasecmp(optarg, "LENGTH")) {
1099 cs.fw.bitmask |= EBT_802_3;
1100 break;
1101 }
1102 ent = getethertypebyname(optarg);
1103 if (!ent)
1104 xtables_error(PARAMETER_PROBLEM,
1105 "Problem with the specified Ethernet protocol '%s', perhaps "_PATH_ETHERTYPES " is missing", optarg);
1106 cs.fw.ethproto = ent->e_ethertype;
1107 } else
1108 cs.fw.ethproto = i;
1109
1110 if (cs.fw.ethproto < 0x0600)
1111 xtables_error(PARAMETER_PROBLEM,
1112 "Sorry, protocols have values above or equal to 0x0600");
1113 break;
1114 case 4 : /* Lc */
1115 #ifdef SILENT_DAEMON
1116 if (exec_style == EXEC_STYLE_DAEMON)
1117 xtables_error(PARAMETER_PROBLEM,
1118 "--Lc is not supported in daemon mode");
1119 #endif
1120 ebt_check_option2(&flags, LIST_C);
1121 if (command != 'L')
1122 xtables_error(PARAMETER_PROBLEM,
1123 "Use --Lc with -L");
1124 flags |= LIST_C;
1125 break;
1126 case 5 : /* Ln */
1127 #ifdef SILENT_DAEMON
1128 if (exec_style == EXEC_STYLE_DAEMON)
1129 xtables_error(PARAMETER_PROBLEM,
1130 "--Ln is not supported in daemon mode");
1131 #endif
1132 ebt_check_option2(&flags, LIST_N);
1133 if (command != 'L')
1134 xtables_error(PARAMETER_PROBLEM,
1135 "Use --Ln with -L");
1136 if (flags & LIST_X)
1137 xtables_error(PARAMETER_PROBLEM,
1138 "--Lx is not compatible with --Ln");
1139 flags |= LIST_N;
1140 break;
1141 case 6 : /* Lx */
1142 #ifdef SILENT_DAEMON
1143 if (exec_style == EXEC_STYLE_DAEMON)
1144 xtables_error(PARAMETER_PROBLEM,
1145 "--Lx is not supported in daemon mode");
1146 #endif
1147 ebt_check_option2(&flags, LIST_X);
1148 if (command != 'L')
1149 xtables_error(PARAMETER_PROBLEM,
1150 "Use --Lx with -L");
1151 if (flags & LIST_N)
1152 xtables_error(PARAMETER_PROBLEM,
1153 "--Lx is not compatible with --Ln");
1154 flags |= LIST_X;
1155 break;
1156 case 12 : /* Lmac2 */
1157 #ifdef SILENT_DAEMON
1158 if (exec_style == EXEC_STYLE_DAEMON)
1159 xtables_error(PARAMETER_PROBLEM,
1160 "--Lmac2 is not supported in daemon mode");
1161 #endif
1162 ebt_check_option2(&flags, LIST_MAC2);
1163 if (command != 'L')
1164 xtables_error(PARAMETER_PROBLEM,
1165 "Use --Lmac2 with -L");
1166 flags |= LIST_MAC2;
1167 break;
1168 case 8 : /* atomic-commit */
1169 /* if (exec_style == EXEC_STYLE_DAEMON)
1170 ebt_print_error2("--atomic-commit is not supported in daemon mode");
1171 replace->command = c;
1172 if (OPT_COMMANDS)
1173 ebt_print_error2("Multiple commands are not allowed");
1174 replace->flags |= OPT_COMMAND;
1175 if (!replace->filename)
1176 ebt_print_error2("No atomic file specified");*/
1177 /* Get the information from the file */
1178 /*ebt_get_table(replace, 0);*/
1179 /* We don't want the kernel giving us its counters,
1180 * they would overwrite the counters extracted from
1181 * the file */
1182 /*replace->num_counters = 0;*/
1183 /* Make sure the table will be written to the kernel */
1184 /*free(replace->filename);
1185 replace->filename = NULL;
1186 break;*/
1187 /*case 7 :*/ /* atomic-init */
1188 /*case 10:*/ /* atomic-save */
1189 /*case 11:*/ /* init-table */
1190 /* if (exec_style == EXEC_STYLE_DAEMON) {
1191 if (c == 7) {
1192 ebt_print_error2("--atomic-init is not supported in daemon mode");
1193 } else if (c == 10)
1194 ebt_print_error2("--atomic-save is not supported in daemon mode");
1195 ebt_print_error2("--init-table is not supported in daemon mode");
1196 }
1197 replace->command = c;
1198 if (OPT_COMMANDS)
1199 ebt_print_error2("Multiple commands are not allowed");
1200 if (c != 11 && !replace->filename)
1201 ebt_print_error2("No atomic file specified");
1202 replace->flags |= OPT_COMMAND;
1203 {
1204 char *tmp = replace->filename;*/
1205
1206 /* Get the kernel table */
1207 /*replace->filename = NULL;
1208 ebt_get_kernel_table(replace, c == 10 ? 0 : 1);
1209 replace->filename = tmp;
1210 }
1211 break;
1212 case 9 :*/ /* atomic */
1213 /*if (exec_style == EXEC_STYLE_DAEMON)
1214 ebt_print_error2("--atomic is not supported in daemon mode");
1215 if (OPT_COMMANDS)
1216 ebt_print_error2("--atomic has to come before the command");*/
1217 /* A possible memory leak here, but this is not
1218 * executed in daemon mode */
1219 /*replace->filename = (char *)malloc(strlen(optarg) + 1);
1220 strcpy(replace->filename, optarg);
1221 break;
1222 case 13 : *//* concurrent */
1223 /*signal(SIGINT, sighandler);
1224 signal(SIGTERM, sighandler);
1225 use_lockfd = 1;
1226 break;*/
1227 case 1 :
1228 if (!strcmp(optarg, "!"))
1229 ebt_check_inverse2(optarg, argc, argv);
1230 else
1231 xtables_error(PARAMETER_PROBLEM,
1232 "Bad argument : '%s'", optarg);
1233 /* ebt_ebt_check_inverse2() did optind++ */
1234 optind--;
1235 continue;
1236 default:
1237 /* Is it a target option? */
1238 if (cs.target != NULL && cs.target->parse != NULL) {
1239 int opt_offset = cs.target->option_offset;
1240 if (cs.target->parse(c - opt_offset,
1241 argv, ebt_invert,
1242 &cs.target->tflags,
1243 NULL, &cs.target->t))
1244 goto check_extension;
1245 }
1246
1247 /* Is it a match_option? */
1248 for (m = xtables_matches; m; m = m->next) {
1249 if (m->parse(c - m->option_offset, argv, ebt_invert, &m->mflags, NULL, &m->m)) {
1250 ebt_add_match(m, &cs);
1251 goto check_extension;
1252 }
1253 }
1254
1255 /* Is it a watcher option? */
1256 for (w = xtables_targets; w; w = w->next) {
1257 if (w->parse(c - w->option_offset, argv,
1258 ebt_invert, &w->tflags,
1259 NULL, &w->t)) {
1260 ebt_add_watcher(w, &cs);
1261 goto check_extension;
1262 }
1263 }
1264 /*
1265 if (w == NULL && c == '?')
1266 ebt_print_error2("Unknown argument: '%s'", argv[optind - 1], (char)optopt, (char)c);
1267 else if (w == NULL) {
1268 if (!strcmp(t->name, "standard"))
1269 ebt_print_error2("Unknown argument: don't forget the -t option");
1270 else
1271 ebt_print_error2("Target-specific option does not correspond with specified target");
1272 }
1273 if (ebt_errormsg[0] != '\0')
1274 return -1;
1275 if (w->used == 0) {
1276 ebt_add_watcher(new_entry, w);
1277 w->used = 1;
1278 }*/
1279 check_extension:
1280 if (command != 'A' && command != 'I' &&
1281 command != 'D' && command != 'C')
1282 xtables_error(PARAMETER_PROBLEM,
1283 "Extensions only for -A, -I, -D and -C");
1284 }
1285 ebt_invert = 0;
1286 }
1287
1288 /* Just in case we didn't catch an error */
1289 /*if (ebt_errormsg[0] != '\0')
1290 return -1;
1291
1292 if (!(table = ebt_find_table(replace->name)))
1293 ebt_print_error2("Bad table name");*/
1294
1295 if (command == 'h' && !(flags & OPT_ZERO)) {
1296 print_help(cs.target, cs.matches, *table);
1297 if (exec_style == EXEC_STYLE_PRG)
1298 exit(0);
1299 }
1300
1301 /* Do the final checks */
1302 if (command == 'A' || command == 'I' ||
1303 command == 'D' || command == 'C') {
1304 for (xtrm_i = cs.matches; xtrm_i; xtrm_i = xtrm_i->next)
1305 xtables_option_mfcall(xtrm_i->match);
1306
1307 for (match = cs.match_list; match; match = match->next) {
1308 if (match->ismatch)
1309 continue;
1310
1311 xtables_option_tfcall(match->u.watcher);
1312 }
1313
1314 if (cs.target != NULL)
1315 xtables_option_tfcall(cs.target);
1316 }
1317 /* So, the extensions can work with the host endian.
1318 * The kernel does not have to do this of course */
1319 cs.fw.ethproto = htons(cs.fw.ethproto);
1320
1321 if (command == 'P') {
1322 if (selected_chain < 0) {
1323 xtables_error(PARAMETER_PROBLEM,
1324 "Policy %s not allowed for user defined chains",
1325 policy);
1326 }
1327 if (strcmp(policy, "RETURN") == 0) {
1328 xtables_error(PARAMETER_PROBLEM,
1329 "Policy RETURN only allowed for user defined chains");
1330 }
1331 ret = nft_chain_set(h, *table, chain, policy, NULL);
1332 if (ret < 0)
1333 xtables_error(PARAMETER_PROBLEM, "Wrong policy");
1334 } else if (command == 'L') {
1335 ret = list_rules(h, chain, *table, rule_nr,
1336 flags&OPT_VERBOSE,
1337 flags&OPT_NUMERIC,
1338 /*flags&OPT_EXPANDED*/0,
1339 flags&LIST_N,
1340 flags&LIST_C);
1341 if (!(flags & OPT_ZERO) && exec_style == EXEC_STYLE_PRG)
1342 exit(0);
1343 }
1344 if (flags & OPT_ZERO) {
1345 selected_chain = zerochain;
1346 ret = nft_chain_zero_counters(h, chain, *table);
1347 } else if (command == 'F') {
1348 ret = nft_rule_flush(h, chain, *table);
1349 } else if (command == 'A') {
1350 ret = append_entry(h, chain, *table, &cs, 0,
1351 flags&OPT_VERBOSE, true);
1352 } else if (command == 'I') {
1353 ret = append_entry(h, chain, *table, &cs, rule_nr - 1,
1354 flags&OPT_VERBOSE, false);
1355 } else if (command == 'D') {
1356 ret = delete_entry(h, chain, *table, &cs, rule_nr - 1,
1357 rule_nr_end, flags&OPT_VERBOSE);
1358 } /*else if (replace->command == 'C') {
1359 ebt_change_counters(replace, new_entry, rule_nr, rule_nr_end, &(new_entry->cnt_surplus), chcounter);
1360 if (ebt_errormsg[0] != '\0')
1361 return -1;
1362 }*/
1363 /* Commands -N, -E, -X, --atomic-commit, --atomic-commit, --atomic-save,
1364 * --init-table fall through */
1365
1366 /*if (ebt_errormsg[0] != '\0')
1367 return -1;
1368 if (table->check)
1369 table->check(replace);
1370
1371 if (exec_style == EXEC_STYLE_PRG) {*//* Implies ebt_errormsg[0] == '\0' */
1372 /*ebt_deliver_table(replace);
1373
1374 if (replace->nentries)
1375 ebt_deliver_counters(replace);*/
1376
1377 ebt_cs_clean(&cs);
1378 return ret;
1379 }
1380