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