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 */
60int ebt_invert = 0;
61
62unsigned char eb_mac_type_unicast[ETH_ALEN] =   {0,0,0,0,0,0};
63unsigned char eb_msk_type_unicast[ETH_ALEN] =   {1,0,0,0,0,0};
64unsigned char eb_mac_type_multicast[ETH_ALEN] = {1,0,0,0,0,0};
65unsigned char eb_msk_type_multicast[ETH_ALEN] = {1,0,0,0,0,0};
66unsigned char eb_mac_type_broadcast[ETH_ALEN] = {255,255,255,255,255,255};
67unsigned char eb_msk_type_broadcast[ETH_ALEN] = {255,255,255,255,255,255};
68unsigned char eb_mac_type_bridge_group[ETH_ALEN] = {0x01,0x80,0xc2,0,0,0};
69unsigned char eb_msk_type_bridge_group[ETH_ALEN] = {255,255,255,255,255,255};
70
71int 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
113static 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 */
135static 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
146static const char *
147parse_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
167static int
168append_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
185static int
186delete_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
209static 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 */
250static 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
295static void __attribute__((__noreturn__,format(printf,2,3)))
296ebt_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
307struct 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 */
324static 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
349static 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 */
383static 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
413static 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 */
473static 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
498static 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). */
527static 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)
548daemon_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)
555daemon_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;
583invalid:
584	xtables_error(PARAMETER_PROBLEM,"Packet counter '%s' invalid", argv[optind]);
585}
586
587static 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() */
603static 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
624static 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
651static 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
663static 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
699static 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. */
726int 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') {
855handle_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'))
879print_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)
994big_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			}*/
1279check_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