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 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)46 delete_entry(struct nft_handle *h,
47 const char *chain,
48 const char *table,
49 struct iptables_command_state *cs,
50 int rule_nr,
51 int rule_nr_end,
52 bool verbose)
53 {
54 int ret = 1;
55
56 if (rule_nr == -1)
57 ret = nft_cmd_rule_delete(h, chain, table, cs, verbose);
58 else {
59 do {
60 ret = nft_cmd_rule_delete_num(h, chain, table,
61 rule_nr, verbose);
62 rule_nr++;
63 } while (rule_nr < rule_nr_end);
64 }
65
66 return ret;
67 }
68
69 static int
change_entry_counters(struct nft_handle * h,const char * chain,const char * table,struct iptables_command_state * cs,int rule_nr,int rule_nr_end,uint8_t counter_op,bool verbose)70 change_entry_counters(struct nft_handle *h,
71 const char *chain, const char *table,
72 struct iptables_command_state *cs,
73 int rule_nr, int rule_nr_end, uint8_t counter_op,
74 bool verbose)
75 {
76 int ret = 1;
77
78 if (rule_nr == -1)
79 return nft_cmd_rule_change_counters(h, chain, table, cs,
80 rule_nr, counter_op,
81 verbose);
82 do {
83 ret = nft_cmd_rule_change_counters(h, chain, table, cs,
84 rule_nr, counter_op,
85 verbose);
86 rule_nr++;
87 } while (rule_nr < rule_nr_end);
88
89 return ret;
90 }
91
92 /* Default command line options. Do not mess around with the already
93 * assigned numbers unless you know what you are doing */
94 struct option ebt_original_options[] =
95 {
96 { "append" , required_argument, 0, 'A' },
97 { "insert" , required_argument, 0, 'I' },
98 { "delete" , required_argument, 0, 'D' },
99 { "list" , optional_argument, 0, 'L' },
100 { "Lc" , no_argument , 0, 17 },
101 { "Ln" , no_argument , 0, 18 },
102 { "Lx" , no_argument , 0, 19 },
103 { "Lmac2" , no_argument , 0, 12 },
104 { "zero" , optional_argument, 0, 'Z' },
105 { "flush" , optional_argument, 0, 'F' },
106 { "policy" , required_argument, 0, 'P' },
107 { "in-interface" , required_argument, 0, 'i' },
108 { "in-if" , required_argument, 0, 'i' },
109 { "logical-in" , required_argument, 0, 15 },
110 { "logical-out" , required_argument, 0, 16 },
111 { "out-interface" , required_argument, 0, 'o' },
112 { "out-if" , required_argument, 0, 'o' },
113 { "version" , no_argument , 0, 'V' },
114 { "verbose" , no_argument , 0, 'v' },
115 { "help" , no_argument , 0, 'h' },
116 { "jump" , required_argument, 0, 'j' },
117 { "set-counters" , required_argument, 0, 'c' },
118 { "change-counters", required_argument, 0, 'C' },
119 { "proto" , required_argument, 0, 'p' },
120 { "protocol" , required_argument, 0, 'p' },
121 { "db" , required_argument, 0, 'b' },
122 { "source" , required_argument, 0, 's' },
123 { "src" , required_argument, 0, 's' },
124 { "destination" , required_argument, 0, 'd' },
125 { "dst" , required_argument, 0, 'd' },
126 { "table" , required_argument, 0, 't' },
127 { "modprobe" , required_argument, 0, 'M' },
128 { "new-chain" , required_argument, 0, 'N' },
129 { "rename-chain" , required_argument, 0, 'E' },
130 { "delete-chain" , optional_argument, 0, 'X' },
131 { "init-table" , no_argument , 0, 11 },
132 { "concurrent" , no_argument , 0, 13 },
133 { "check" , required_argument, 0, 14 },
134 { 0 }
135 };
136
137 struct xtables_globals ebtables_globals = {
138 .option_offset = 0,
139 .program_version = PACKAGE_VERSION " (nf_tables)",
140 .orig_opts = ebt_original_options,
141 .compat_rev = nft_compatible_revision,
142 };
143
144 #define prog_name ebtables_globals.program_name
145 #define prog_vers ebtables_globals.program_version
146
147 /* Prints all registered extensions */
ebt_list_extensions(const struct xtables_target * t,const struct xtables_rule_match * m)148 static void ebt_list_extensions(const struct xtables_target *t,
149 const struct xtables_rule_match *m)
150 {
151 printf("%s v%s\n", prog_name, prog_vers);
152 printf("Loaded userspace extensions:\n");
153 /*printf("\nLoaded tables:\n");
154 while (tbl) {
155 printf("%s\n", tbl->name);
156 tbl = tbl->next;
157 }*/
158 printf("\nLoaded targets:\n");
159 for (t = xtables_targets; t; t = t->next) {
160 printf("%s\n", t->name);
161 }
162 printf("\nLoaded matches:\n");
163 for (; m != NULL; m = m->next)
164 printf("%s\n", m->match->name);
165 /*printf("\nLoaded watchers:\n");
166 while (w) {
167 printf("%s\n", w->name);
168 w = w->next;
169 }*/
170 }
171
nft_bridge_print_help(struct iptables_command_state * cs)172 void nft_bridge_print_help(struct iptables_command_state *cs)
173 {
174 const struct xtables_rule_match *m = cs->matches;
175 struct xtables_target *t = cs->target;
176
177 while (optind < cs->argc) {
178 /*struct ebt_u_match *m;
179 struct ebt_u_watcher *w;*/
180
181 if (!strcasecmp("list_extensions", cs->argv[optind])) {
182 ebt_list_extensions(xtables_targets, cs->matches);
183 exit(0);
184 }
185 /*if ((m = ebt_find_match(cs->argv[optind])))
186 ebt_add_match(new_entry, m);
187 else if ((w = ebt_find_watcher(cs->argv[optind])))
188 ebt_add_watcher(new_entry, w);
189 else {*/
190 if (!(t = xtables_find_target(cs->argv[optind],
191 XTF_TRY_LOAD)))
192 xtables_error(PARAMETER_PROBLEM,
193 "Extension '%s' not found",
194 cs->argv[optind]);
195 if (cs->options & OPT_JUMP)
196 xtables_error(PARAMETER_PROBLEM,
197 "Sorry, you can only see help for one target extension at a time");
198 cs->options |= OPT_JUMP;
199 cs->target = t;
200 //}
201 optind++;
202 }
203
204 printf("%s %s\n", prog_name, prog_vers);
205 printf(
206 "Usage:\n"
207 "ebtables -[ADI] chain rule-specification [options]\n"
208 "ebtables -P chain target\n"
209 "ebtables -[LFZ] [chain]\n"
210 "ebtables -[NX] [chain]\n"
211 "ebtables -E old-chain-name new-chain-name\n\n"
212 "Commands:\n"
213 "--append -A chain : append to chain\n"
214 "--delete -D chain : delete matching rule from chain\n"
215 "--delete -D chain rulenum : delete rule at position rulenum from chain\n"
216 "--change-counters -C chain\n"
217 " [rulenum] pcnt bcnt : change counters of existing rule\n"
218 "--insert -I chain rulenum : insert rule at position rulenum in chain\n"
219 "--list -L [chain] : list the rules in a chain or in all chains\n"
220 "--flush -F [chain] : delete all rules in chain or in all chains\n"
221 "--init-table : replace the kernel table with the initial table\n"
222 "--zero -Z [chain] : put counters on zero in chain or in all chains\n"
223 "--policy -P chain target : change policy on chain to target\n"
224 "--new-chain -N chain : create a user defined chain\n"
225 "--rename-chain -E old new : rename a chain\n"
226 "--delete-chain -X [chain] : delete a user defined chain\n"
227 "Options:\n"
228 "[!] --proto -p proto : protocol hexadecimal, by name or LENGTH\n"
229 "[!] --src -s address[/mask]: source mac address\n"
230 "[!] --dst -d address[/mask]: destination mac address\n"
231 "[!] --in-if -i name[+] : network input interface name\n"
232 "[!] --out-if -o name[+] : network output interface name\n"
233 "[!] --logical-in name[+] : logical bridge input interface name\n"
234 "[!] --logical-out name[+] : logical bridge output interface name\n"
235 "--set-counters -c chain\n"
236 " pcnt bcnt : set the counters of the to be added rule\n"
237 "--modprobe -M program : try to insert modules using this program\n"
238 "--concurrent : use a file lock to support concurrent scripts\n"
239 "--verbose -v : verbose mode\n"
240 "--version -V : print package version\n\n"
241 "Environment variable:\n"
242 /*ATOMIC_ENV_VARIABLE " : if set <FILE> (see above) will equal its value"*/
243 "\n\n");
244 for (; m != NULL; m = m->next) {
245 printf("\n");
246 m->match->help();
247 }
248 if (t != NULL) {
249 printf("\n");
250 t->help();
251 }
252 }
253
254 /* 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)255 static int list_rules(struct nft_handle *h, const char *chain, const char *table,
256 int rule_nr, int verbose, int numeric, int expanded,
257 int linenumbers, int counters)
258 {
259 unsigned int format;
260
261 format = FMT_OPTIONS | FMT_C_COUNTS;
262 if (verbose)
263 format |= FMT_VIA;
264
265 if (numeric)
266 format |= FMT_NUMERIC;
267
268 if (!expanded)
269 format |= FMT_KILOMEGAGIGA;
270
271 if (linenumbers)
272 format |= FMT_LINENUMBERS;
273
274 if (!counters)
275 format |= FMT_NOCOUNTS;
276
277 return nft_cmd_rule_list(h, chain, table, rule_nr, format);
278 }
279
280 /* This code is very similar to iptables/xtables.c:command_match() */
ebt_load_match(const char * name)281 static void ebt_load_match(const char *name)
282 {
283 struct option *opts = xt_params->opts;
284 struct xtables_match *m;
285 size_t size;
286
287 m = xtables_find_match(name, XTF_TRY_LOAD, NULL);
288 if (m == NULL) {
289 fprintf(stderr, "Unable to load %s match\n", name);
290 return;
291 }
292
293 size = XT_ALIGN(sizeof(struct xt_entry_match)) + m->size;
294 m->m = xtables_calloc(1, size);
295 m->m->u.match_size = size;
296 strcpy(m->m->u.user.name, m->name);
297 m->m->u.user.revision = m->revision;
298 xs_init_match(m);
299
300 if (m->x6_options != NULL)
301 opts = xtables_options_xfrm(xt_params->orig_opts, opts,
302 m->x6_options, &m->option_offset);
303 else if (m->extra_opts != NULL)
304 opts = xtables_merge_options(xt_params->orig_opts, opts,
305 m->extra_opts, &m->option_offset);
306 else
307 return;
308
309 if (opts == NULL)
310 xtables_error(OTHER_PROBLEM, "Can't alloc memory");
311 xt_params->opts = opts;
312 }
313
ebt_load_watcher(const char * name)314 static void ebt_load_watcher(const char *name)
315 {
316 struct option *opts = xt_params->opts;
317 struct xtables_target *watcher;
318 size_t size;
319
320 watcher = xtables_find_target(name, XTF_TRY_LOAD);
321 if (!watcher) {
322 fprintf(stderr, "Unable to load %s watcher\n", name);
323 return;
324 }
325
326 size = XT_ALIGN(sizeof(struct xt_entry_target)) + watcher->size;
327
328 watcher->t = xtables_calloc(1, size);
329 watcher->t->u.target_size = size;
330 snprintf(watcher->t->u.user.name,
331 sizeof(watcher->t->u.user.name), "%s", name);
332 watcher->t->u.user.name[sizeof(watcher->t->u.user.name)-1] = '\0';
333 watcher->t->u.user.revision = watcher->revision;
334
335 xs_init_target(watcher);
336
337 if (watcher->x6_options != NULL)
338 opts = xtables_options_xfrm(xt_params->orig_opts, opts,
339 watcher->x6_options,
340 &watcher->option_offset);
341 else if (watcher->extra_opts != NULL)
342 opts = xtables_merge_options(xt_params->orig_opts, opts,
343 watcher->extra_opts,
344 &watcher->option_offset);
345 else
346 return;
347
348 if (opts == NULL)
349 xtables_error(OTHER_PROBLEM, "Can't alloc memory");
350 xt_params->opts = opts;
351 }
352
ebt_load_match_extensions(void)353 static void ebt_load_match_extensions(void)
354 {
355 ebt_load_match("802_3");
356 ebt_load_match("arp");
357 ebt_load_match("ip");
358 ebt_load_match("ip6");
359 ebt_load_match("mark_m");
360 ebt_load_match("limit");
361 ebt_load_match("pkttype");
362 ebt_load_match("vlan");
363 ebt_load_match("stp");
364 ebt_load_match("among");
365
366 ebt_load_watcher("log");
367 ebt_load_watcher("nflog");
368 }
369
ebt_add_match(struct xtables_match * m,struct iptables_command_state * cs)370 struct xtables_match *ebt_add_match(struct xtables_match *m,
371 struct iptables_command_state *cs)
372 {
373 struct xtables_rule_match **rule_matches = &cs->matches;
374 struct ebt_match *newnode, **matchp;
375 struct xtables_match *newm;
376
377 newm = xtables_find_match(m->name, XTF_LOAD_MUST_SUCCEED, rule_matches);
378 if (newm == NULL)
379 xtables_error(OTHER_PROBLEM,
380 "Unable to add match %s", m->name);
381
382 newm->m = xtables_calloc(1, m->m->u.match_size);
383 memcpy(newm->m, m->m, m->m->u.match_size);
384 xs_init_match(newm);
385
386 /* glue code for watchers */
387 newnode = xtables_calloc(1, sizeof(struct ebt_match));
388 newnode->ismatch = true;
389 newnode->u.match = newm;
390
391 for (matchp = &cs->match_list; *matchp; matchp = &(*matchp)->next)
392 ;
393 *matchp = newnode;
394
395 return newm;
396 }
397
ebt_add_watcher(struct xtables_target * watcher,struct iptables_command_state * cs)398 struct xtables_target *ebt_add_watcher(struct xtables_target *watcher,
399 struct iptables_command_state *cs)
400 {
401 struct ebt_match *newnode, **matchp;
402 struct xtables_target *clone;
403
404 clone = xtables_malloc(sizeof(struct xtables_target));
405 memcpy(clone, watcher, sizeof(struct xtables_target));
406 clone->next = clone;
407 clone->udata = NULL;
408 xs_init_target(clone);
409
410 clone->t = xtables_calloc(1, watcher->t->u.target_size);
411 memcpy(clone->t, watcher->t, watcher->t->u.target_size);
412
413
414 newnode = xtables_calloc(1, sizeof(struct ebt_match));
415 newnode->u.watcher = clone;
416
417 for (matchp = &cs->match_list; *matchp; matchp = &(*matchp)->next)
418 ;
419 *matchp = newnode;
420
421 return clone;
422 }
423
ebt_command_default(struct iptables_command_state * cs,struct xtables_globals * unused,bool ebt_invert)424 int ebt_command_default(struct iptables_command_state *cs,
425 struct xtables_globals *unused, bool ebt_invert)
426 {
427 struct xtables_target *t = cs->target;
428 struct xtables_match *m;
429 struct ebt_match *matchp;
430
431 /* Is it a target option? */
432 if (cs->target != NULL &&
433 (cs->target->parse != NULL || cs->target->x6_parse != NULL) &&
434 cs->c >= cs->target->option_offset &&
435 cs->c < cs->target->option_offset + XT_OPTION_OFFSET_SCALE) {
436 xtables_option_tpcall(cs->c, cs->argv, ebt_invert,
437 cs->target, &cs->eb);
438 return 0;
439 }
440
441 /* check previously added matches/watchers to this rule first */
442 for (matchp = cs->match_list; matchp; matchp = matchp->next) {
443 if (matchp->ismatch) {
444 m = matchp->u.match;
445 if (!m->parse && !m->x6_parse)
446 continue;
447 if (cs->c < m->option_offset ||
448 cs->c >= m->option_offset + XT_OPTION_OFFSET_SCALE)
449 continue;
450 xtables_option_mpcall(cs->c, cs->argv, ebt_invert,
451 m, &cs->eb);
452 return 0;
453 } else {
454 t = matchp->u.watcher;
455 if (!t->parse && !t->x6_parse)
456 continue;
457 if (cs->c < t->option_offset ||
458 cs->c >= t->option_offset + XT_OPTION_OFFSET_SCALE)
459 continue;
460 xtables_option_tpcall(cs->c, cs->argv, ebt_invert,
461 t, &cs->eb);
462 return 0;
463 }
464 }
465
466 /* Is it a match_option? */
467 for (m = xtables_matches; m; m = m->next) {
468 if (!m->parse && !m->x6_parse)
469 continue;
470 if (cs->c < m->option_offset ||
471 cs->c >= m->option_offset + XT_OPTION_OFFSET_SCALE)
472 continue;
473 m = ebt_add_match(m, cs);
474 xtables_option_mpcall(cs->c, cs->argv, ebt_invert, m, &cs->eb);
475 return 0;
476 }
477
478 /* Is it a watcher option? */
479 for (t = xtables_targets; t; t = t->next) {
480 if (!(t->ext_flags & XTABLES_EXT_WATCHER))
481 continue;
482
483 if (!t->parse && !t->x6_parse)
484 continue;
485 if (cs->c < t->option_offset ||
486 cs->c >= t->option_offset + XT_OPTION_OFFSET_SCALE)
487 continue;
488 t = ebt_add_watcher(t, cs);
489 xtables_option_tpcall(cs->c, cs->argv, ebt_invert, t, &cs->eb);
490 return 0;
491 }
492 if (cs->c == ':')
493 xtables_error(PARAMETER_PROBLEM, "option \"%s\" "
494 "requires an argument", cs->argv[optind - 1]);
495 if (cs->c == '?') {
496 char optoptstr[3] = {'-', optopt, '\0'};
497
498 xtables_error(PARAMETER_PROBLEM, "unknown option \"%s\"",
499 optopt ? optoptstr : cs->argv[optind - 1]);
500 }
501 xtables_error(PARAMETER_PROBLEM, "Unknown arg \"%s\"", optarg);
502 }
503
nft_init_eb(struct nft_handle * h,const char * pname)504 int nft_init_eb(struct nft_handle *h, const char *pname)
505 {
506 ebtables_globals.program_name = pname;
507 if (xtables_init_all(&ebtables_globals, NFPROTO_BRIDGE) < 0) {
508 fprintf(stderr, "%s/%s Failed to initialize ebtables-compat\n",
509 ebtables_globals.program_name,
510 ebtables_globals.program_version);
511 exit(1);
512 }
513 init_extensions();
514 init_extensionsb();
515
516 if (nft_init(h, NFPROTO_BRIDGE) < 0)
517 xtables_error(OTHER_PROBLEM,
518 "Could not initialize nftables layer.");
519
520 /* manually registering ebt matches, given the original ebtables parser
521 * don't use '-m matchname' and the match can't be loaded dynamically when
522 * the user calls it.
523 */
524 ebt_load_match_extensions();
525
526 return 0;
527 }
528
nft_fini_eb(struct nft_handle * h)529 void nft_fini_eb(struct nft_handle *h)
530 {
531 struct xtables_match *match;
532 struct xtables_target *target;
533
534 for (match = xtables_matches; match; match = match->next) {
535 free(match->m);
536 }
537 for (target = xtables_targets; target; target = target->next) {
538 free(target->t);
539 }
540
541 free(xt_params->opts);
542
543 nft_fini(h);
544 xtables_fini();
545 }
546
do_commandeb(struct nft_handle * h,int argc,char * argv[],char ** table,bool restore)547 int do_commandeb(struct nft_handle *h, int argc, char *argv[], char **table,
548 bool restore)
549 {
550 struct iptables_command_state cs = {
551 .argc = argc,
552 .argv = argv,
553 .jumpto = "",
554 };
555 const struct builtin_table *t;
556 struct xtables_args args = {
557 .family = h->family,
558 };
559 struct xt_cmd_parse p = {
560 .table = *table,
561 .restore = restore,
562 .line = line,
563 .rule_ranges = true,
564 .ops = &h->ops->cmd_parse,
565 };
566 int ret = 0;
567
568 if (h->ops->init_cs)
569 h->ops->init_cs(&cs);
570
571 do_parse(argc, argv, &p, &cs, &args);
572
573 h->verbose = p.verbose;
574
575 t = nft_table_builtin_find(h, p.table);
576 if (!t)
577 xtables_error(VERSION_PROBLEM,
578 "table '%s' does not exist", p.table);
579
580 switch (p.command) {
581 case CMD_NEW_CHAIN:
582 case CMD_NEW_CHAIN | CMD_SET_POLICY:
583 ret = nft_cmd_chain_user_add(h, p.chain, p.table);
584 if (!ret || !(p.command & CMD_SET_POLICY))
585 break;
586 /* fall through */
587 case CMD_SET_POLICY:
588 if (!nft_chain_builtin_find(t, p.chain)) {
589 ret = ebt_cmd_user_chain_policy(h, p.table, p.chain,
590 p.policy);
591 break;
592 }
593 if (strcmp(p.policy, "RETURN") == 0) {
594 xtables_error(PARAMETER_PROBLEM,
595 "Policy RETURN only allowed for user defined chains");
596 }
597 ret = nft_cmd_chain_set(h, p.table, p.chain, p.policy, NULL);
598 if (ret < 0)
599 xtables_error(PARAMETER_PROBLEM, "Wrong policy");
600 break;
601 case CMD_LIST:
602 case CMD_LIST | CMD_ZERO:
603 case CMD_LIST | CMD_ZERO_NUM:
604 case CMD_LIST_RULES:
605 case CMD_LIST_RULES | CMD_ZERO:
606 case CMD_LIST_RULES | CMD_ZERO_NUM:
607 if (p.command & CMD_LIST)
608 ret = list_rules(h, p.chain, p.table, p.rulenum,
609 cs.options & OPT_VERBOSE,
610 0,
611 /*cs.options&OPT_EXPANDED*/0,
612 cs.options&OPT_LINENUMBERS,
613 cs.options&OPT_LIST_C);
614 else if (p.command & CMD_LIST_RULES)
615 ret = nft_cmd_rule_list_save(h, p.chain, p.table,
616 p.rulenum,
617 cs.options & OPT_VERBOSE);
618 if (ret && (p.command & CMD_ZERO))
619 ret = nft_cmd_chain_zero_counters(h, p.chain, p.table,
620 cs.options & OPT_VERBOSE);
621 if (ret && (p.command & CMD_ZERO_NUM))
622 ret = nft_cmd_rule_zero_counters(h, p.chain, p.table,
623 p.rulenum - 1);
624 break;
625 case CMD_ZERO:
626 ret = nft_cmd_chain_zero_counters(h, p.chain, p.table,
627 cs.options & OPT_VERBOSE);
628 break;
629 case CMD_ZERO_NUM:
630 ret = nft_cmd_rule_zero_counters(h, p.chain, p.table,
631 p.rulenum - 1);
632 break;
633 case CMD_FLUSH:
634 ret = nft_cmd_rule_flush(h, p.chain, p.table,
635 cs.options & OPT_VERBOSE);
636 break;
637 case CMD_APPEND:
638 ret = nft_cmd_rule_append(h, p.chain, p.table, &cs,
639 cs.options & OPT_VERBOSE);
640 break;
641 case CMD_INSERT:
642 ret = nft_cmd_rule_insert(h, p.chain, p.table, &cs,
643 p.rulenum - 1,
644 cs.options & OPT_VERBOSE);
645 break;
646 case CMD_DELETE:
647 case CMD_DELETE_NUM:
648 ret = delete_entry(h, p.chain, p.table, &cs, p.rulenum - 1,
649 p.rulenum_end, cs.options & OPT_VERBOSE);
650 break;
651 case CMD_DELETE_CHAIN:
652 ret = nft_cmd_chain_del(h, p.chain, p.table, 0);
653 break;
654 case CMD_RENAME_CHAIN:
655 ret = nft_cmd_chain_user_rename(h, p.chain, p.table, p.newname);
656 break;
657 case CMD_INIT_TABLE:
658 ret = nft_cmd_table_flush(h, p.table, false);
659 break;
660 case CMD_CHECK:
661 ret = nft_cmd_rule_check(h, p.chain, p.table,
662 &cs, cs.options & OPT_VERBOSE);
663 break;
664 case CMD_CHANGE_COUNTERS:
665 ret = change_entry_counters(h, p.chain, p.table, &cs,
666 p.rulenum - 1, p.rulenum_end,
667 args.counter_op,
668 cs.options & OPT_VERBOSE);
669 break;
670 case CMD_REPLACE:
671 ret = nft_cmd_rule_replace(h, p.chain, p.table, &cs,
672 p.rulenum - 1,
673 cs.options & OPT_VERBOSE);
674 break;
675 default:
676 /* We should never reach this... */
677 exit_tryhelp(2, line);
678 }
679
680 ebt_cs_clean(&cs);
681 return ret;
682 }
683