1 /* Code to take an iptables-style command line and do it. */
2
3 /*
4 * Author: Paul.Russell@rustcorp.com.au and mneuling@radlogic.com.au
5 *
6 * (C) 2000-2002 by the netfilter coreteam <coreteam@netfilter.org>:
7 * Paul 'Rusty' Russell <rusty@rustcorp.com.au>
8 * Marc Boucher <marc+nf@mbsi.ca>
9 * James Morris <jmorris@intercode.com.au>
10 * Harald Welte <laforge@gnumonks.org>
11 * Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
12 *
13 * This program is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation; either version 2 of the License, or
16 * (at your option) any later version.
17 *
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
22 *
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, write to the Free Software
25 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26 */
27
28 #include <getopt.h>
29 #include <string.h>
30 #include <netdb.h>
31 #include <errno.h>
32 #include <stdbool.h>
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <ctype.h>
36 #include <stdarg.h>
37 #include <limits.h>
38 #include <unistd.h>
39 #include <iptables.h>
40 #include <xtables.h>
41 #include <fcntl.h>
42 #include "xshared.h"
43 #include "nft-shared.h"
44 #include "nft.h"
45
46 #ifndef TRUE
47 #define TRUE 1
48 #endif
49 #ifndef FALSE
50 #define FALSE 0
51 #endif
52
53 #define NUMBER_OF_CMD 16
54 static const char cmdflags[] = { 'I', 'D', 'D', 'R', 'A', 'L', 'F', 'Z',
55 'N', 'X', 'P', 'E', 'S', 'Z', 'C' };
56
57 #define OPT_FRAGMENT 0x00800U
58 #define NUMBER_OF_OPT ARRAY_SIZE(optflags)
59 static const char optflags[]
60 = { 'n', 's', 'd', 'p', 'j', 'v', 'x', 'i', 'o', '0', 'c', 'f'};
61
62 static struct option original_opts[] = {
63 {.name = "append", .has_arg = 1, .val = 'A'},
64 {.name = "delete", .has_arg = 1, .val = 'D'},
65 {.name = "check", .has_arg = 1, .val = 'C'},
66 {.name = "insert", .has_arg = 1, .val = 'I'},
67 {.name = "replace", .has_arg = 1, .val = 'R'},
68 {.name = "list", .has_arg = 2, .val = 'L'},
69 {.name = "list-rules", .has_arg = 2, .val = 'S'},
70 {.name = "flush", .has_arg = 2, .val = 'F'},
71 {.name = "zero", .has_arg = 2, .val = 'Z'},
72 {.name = "new-chain", .has_arg = 1, .val = 'N'},
73 {.name = "delete-chain", .has_arg = 2, .val = 'X'},
74 {.name = "rename-chain", .has_arg = 1, .val = 'E'},
75 {.name = "policy", .has_arg = 1, .val = 'P'},
76 {.name = "source", .has_arg = 1, .val = 's'},
77 {.name = "destination", .has_arg = 1, .val = 'd'},
78 {.name = "src", .has_arg = 1, .val = 's'}, /* synonym */
79 {.name = "dst", .has_arg = 1, .val = 'd'}, /* synonym */
80 {.name = "protocol", .has_arg = 1, .val = 'p'},
81 {.name = "in-interface", .has_arg = 1, .val = 'i'},
82 {.name = "jump", .has_arg = 1, .val = 'j'},
83 {.name = "table", .has_arg = 1, .val = 't'},
84 {.name = "match", .has_arg = 1, .val = 'm'},
85 {.name = "numeric", .has_arg = 0, .val = 'n'},
86 {.name = "out-interface", .has_arg = 1, .val = 'o'},
87 {.name = "verbose", .has_arg = 0, .val = 'v'},
88 {.name = "wait", .has_arg = 2, .val = 'w'},
89 {.name = "wait-interval", .has_arg = 2, .val = 'W'},
90 {.name = "exact", .has_arg = 0, .val = 'x'},
91 {.name = "fragments", .has_arg = 0, .val = 'f'},
92 {.name = "version", .has_arg = 0, .val = 'V'},
93 {.name = "help", .has_arg = 2, .val = 'h'},
94 {.name = "line-numbers", .has_arg = 0, .val = '0'},
95 {.name = "modprobe", .has_arg = 1, .val = 'M'},
96 {.name = "set-counters", .has_arg = 1, .val = 'c'},
97 {.name = "goto", .has_arg = 1, .val = 'g'},
98 {.name = "ipv4", .has_arg = 0, .val = '4'},
99 {.name = "ipv6", .has_arg = 0, .val = '6'},
100 {NULL},
101 };
102
103 void xtables_exit_error(enum xtables_exittype status, const char *msg, ...) __attribute__((noreturn, format(printf,2,3)));
104
105 struct xtables_globals xtables_globals = {
106 .option_offset = 0,
107 .program_version = IPTABLES_VERSION,
108 .orig_opts = original_opts,
109 .exit_err = xtables_exit_error,
110 .compat_rev = nft_compatible_revision,
111 };
112
113 /* Table of legal combinations of commands and options. If any of the
114 * given commands make an option legal, that option is legal (applies to
115 * CMD_LIST and CMD_ZERO only).
116 * Key:
117 * + compulsory
118 * x illegal
119 * optional
120 */
121
122 static const char commands_v_options[NUMBER_OF_CMD][NUMBER_OF_OPT] =
123 /* Well, it's better than "Re: Linux vs FreeBSD" */
124 {
125 /* -n -s -d -p -j -v -x -i -o --line -c -f */
126 /*INSERT*/ {'x',' ',' ',' ',' ',' ','x',' ',' ','x',' ',' '},
127 /*DELETE*/ {'x',' ',' ',' ',' ',' ','x',' ',' ','x','x',' '},
128 /*DELETE_NUM*/{'x','x','x','x','x',' ','x','x','x','x','x','x'},
129 /*REPLACE*/ {'x',' ',' ',' ',' ',' ','x',' ',' ','x',' ',' '},
130 /*APPEND*/ {'x',' ',' ',' ',' ',' ','x',' ',' ','x',' ',' '},
131 /*LIST*/ {' ','x','x','x','x',' ',' ','x','x',' ','x','x'},
132 /*FLUSH*/ {'x','x','x','x','x',' ','x','x','x','x','x','x'},
133 /*ZERO*/ {'x','x','x','x','x',' ','x','x','x','x','x','x'},
134 /*ZERO_NUM*/ {'x','x','x','x','x',' ','x','x','x','x','x','x'},
135 /*NEW_CHAIN*/ {'x','x','x','x','x',' ','x','x','x','x','x','x'},
136 /*DEL_CHAIN*/ {'x','x','x','x','x',' ','x','x','x','x','x','x'},
137 /*SET_POLICY*/{'x','x','x','x','x',' ','x','x','x','x',' ','x'},
138 /*RENAME*/ {'x','x','x','x','x',' ','x','x','x','x','x','x'},
139 /*LIST_RULES*/{'x','x','x','x','x',' ','x','x','x','x','x','x'},
140 /*CHECK*/ {'x',' ',' ',' ',' ',' ','x',' ',' ','x','x',' '},
141 };
142
143 static const int inverse_for_options[NUMBER_OF_OPT] =
144 {
145 /* -n */ 0,
146 /* -s */ IPT_INV_SRCIP,
147 /* -d */ IPT_INV_DSTIP,
148 /* -p */ XT_INV_PROTO,
149 /* -j */ 0,
150 /* -v */ 0,
151 /* -x */ 0,
152 /* -i */ IPT_INV_VIA_IN,
153 /* -o */ IPT_INV_VIA_OUT,
154 /*--line*/ 0,
155 /* -c */ 0,
156 /* -f */ IPT_INV_FRAG,
157 };
158
159 #define opts xtables_globals.opts
160 #define prog_name xtables_globals.program_name
161 #define prog_vers xtables_globals.program_version
162
163 static void __attribute__((noreturn))
exit_tryhelp(int status)164 exit_tryhelp(int status)
165 {
166 if (line != -1)
167 fprintf(stderr, "Error occurred at line: %d\n", line);
168 fprintf(stderr, "Try `%s -h' or '%s --help' for more information.\n",
169 prog_name, prog_name);
170 xtables_free_opts(1);
171 exit(status);
172 }
173
174 static void
exit_printhelp(const struct xtables_rule_match * matches)175 exit_printhelp(const struct xtables_rule_match *matches)
176 {
177 printf("%s v%s\n\n"
178 "Usage: %s -[ACD] chain rule-specification [options]\n"
179 " %s -I chain [rulenum] rule-specification [options]\n"
180 " %s -R chain rulenum rule-specification [options]\n"
181 " %s -D chain rulenum [options]\n"
182 " %s -[LS] [chain [rulenum]] [options]\n"
183 " %s -[FZ] [chain] [options]\n"
184 " %s -[NX] chain\n"
185 " %s -E old-chain-name new-chain-name\n"
186 " %s -P chain target [options]\n"
187 " %s -h (print this help information)\n\n",
188 prog_name, prog_vers, prog_name, prog_name,
189 prog_name, prog_name, prog_name, prog_name,
190 prog_name, prog_name, prog_name, prog_name);
191
192 printf(
193 "Commands:\n"
194 "Either long or short options are allowed.\n"
195 " --append -A chain Append to chain\n"
196 " --check -C chain Check for the existence of a rule\n"
197 " --delete -D chain Delete matching rule from chain\n"
198 " --delete -D chain rulenum\n"
199 " Delete rule rulenum (1 = first) from chain\n"
200 " --insert -I chain [rulenum]\n"
201 " Insert in chain as rulenum (default 1=first)\n"
202 " --replace -R chain rulenum\n"
203 " Replace rule rulenum (1 = first) in chain\n"
204 " --list -L [chain [rulenum]]\n"
205 " List the rules in a chain or all chains\n"
206 " --list-rules -S [chain [rulenum]]\n"
207 " Print the rules in a chain or all chains\n"
208 " --flush -F [chain] Delete all rules in chain or all chains\n"
209 " --zero -Z [chain [rulenum]]\n"
210 " Zero counters in chain or all chains\n"
211 " --new -N chain Create a new user-defined chain\n"
212 " --delete-chain\n"
213 " -X [chain] Delete a user-defined chain\n"
214 " --policy -P chain target\n"
215 " Change policy on chain to target\n"
216 " --rename-chain\n"
217 " -E old-chain new-chain\n"
218 " Change chain name, (moving any references)\n"
219
220 "Options:\n"
221 " --ipv4 -4 Nothing (line is ignored by ip6tables-restore)\n"
222 " --ipv6 -6 Error (line is ignored by iptables-restore)\n"
223 "[!] --proto -p proto protocol: by number or name, eg. `tcp'\n"
224 "[!] --source -s address[/mask][...]\n"
225 " source specification\n"
226 "[!] --destination -d address[/mask][...]\n"
227 " destination specification\n"
228 "[!] --in-interface -i input name[+]\n"
229 " network interface name ([+] for wildcard)\n"
230 " --jump -j target\n"
231 " target for rule (may load target extension)\n"
232 #ifdef IPT_F_GOTO
233 " --goto -g chain\n"
234 " jump to chain with no return\n"
235 #endif
236 " --match -m match\n"
237 " extended match (may load extension)\n"
238 " --numeric -n numeric output of addresses and ports\n"
239 "[!] --out-interface -o output name[+]\n"
240 " network interface name ([+] for wildcard)\n"
241 " --table -t table table to manipulate (default: `filter')\n"
242 " --verbose -v verbose mode\n"
243 " --wait -w [seconds] maximum wait to acquire xtables lock before give up\n"
244 " --wait-interval -W [usecs] wait time to try to acquire xtables lock\n"
245 " default is 1 second\n"
246 " --line-numbers print line numbers when listing\n"
247 " --exact -x expand numbers (display exact values)\n"
248 "[!] --fragment -f match second or further fragments only\n"
249 " --modprobe=<command> try to insert modules using this command\n"
250 " --set-counters PKTS BYTES set the counter during insert/append\n"
251 "[!] --version -V print package version.\n");
252
253 print_extension_helps(xtables_targets, matches);
254 exit(0);
255 }
256
257 void
xtables_exit_error(enum xtables_exittype status,const char * msg,...)258 xtables_exit_error(enum xtables_exittype status, const char *msg, ...)
259 {
260 va_list args;
261
262 va_start(args, msg);
263 fprintf(stderr, "%s v%s: ", prog_name, prog_vers);
264 vfprintf(stderr, msg, args);
265 va_end(args);
266 fprintf(stderr, "\n");
267 if (status == PARAMETER_PROBLEM)
268 exit_tryhelp(status);
269 if (status == VERSION_PROBLEM)
270 fprintf(stderr,
271 "Perhaps iptables or your kernel needs to be upgraded.\n");
272 /* On error paths, make sure that we don't leak memory */
273 xtables_free_opts(1);
274 exit(status);
275 }
276
277 static void
generic_opt_check(int command,int options)278 generic_opt_check(int command, int options)
279 {
280 int i, j, legal = 0;
281
282 /* Check that commands are valid with options. Complicated by the
283 * fact that if an option is legal with *any* command given, it is
284 * legal overall (ie. -z and -l).
285 */
286 for (i = 0; i < NUMBER_OF_OPT; i++) {
287 legal = 0; /* -1 => illegal, 1 => legal, 0 => undecided. */
288
289 for (j = 0; j < NUMBER_OF_CMD; j++) {
290 if (!(command & (1<<j)))
291 continue;
292
293 if (!(options & (1<<i))) {
294 if (commands_v_options[j][i] == '+')
295 xtables_error(PARAMETER_PROBLEM,
296 "You need to supply the `-%c' "
297 "option for this command\n",
298 optflags[i]);
299 } else {
300 if (commands_v_options[j][i] != 'x')
301 legal = 1;
302 else if (legal == 0)
303 legal = -1;
304 }
305 }
306 if (legal == -1)
307 xtables_error(PARAMETER_PROBLEM,
308 "Illegal option `-%c' with this command\n",
309 optflags[i]);
310 }
311 }
312
313 static char
opt2char(int option)314 opt2char(int option)
315 {
316 const char *ptr;
317 for (ptr = optflags; option > 1; option >>= 1, ptr++);
318
319 return *ptr;
320 }
321
322 static char
cmd2char(int option)323 cmd2char(int option)
324 {
325 const char *ptr;
326 for (ptr = cmdflags; option > 1; option >>= 1, ptr++);
327
328 return *ptr;
329 }
330
331 static void
add_command(unsigned int * cmd,const int newcmd,const int othercmds,int invert)332 add_command(unsigned int *cmd, const int newcmd, const int othercmds,
333 int invert)
334 {
335 if (invert)
336 xtables_error(PARAMETER_PROBLEM, "unexpected ! flag");
337 if (*cmd & (~othercmds))
338 xtables_error(PARAMETER_PROBLEM, "Cannot use -%c with -%c\n",
339 cmd2char(newcmd), cmd2char(*cmd & (~othercmds)));
340 *cmd |= newcmd;
341 }
342
343 /*
344 * All functions starting with "parse" should succeed, otherwise
345 * the program fails.
346 * Most routines return pointers to static data that may change
347 * between calls to the same or other routines with a few exceptions:
348 * "host_to_addr", "parse_hostnetwork", and "parse_hostnetworkmask"
349 * return global static data.
350 */
351
352 /* Christophe Burki wants `-p 6' to imply `-m tcp'. */
353 /* Can't be zero. */
354 static int
parse_rulenumber(const char * rule)355 parse_rulenumber(const char *rule)
356 {
357 unsigned int rulenum;
358
359 if (!xtables_strtoui(rule, NULL, &rulenum, 1, INT_MAX))
360 xtables_error(PARAMETER_PROBLEM,
361 "Invalid rule number `%s'", rule);
362
363 return rulenum;
364 }
365
366 static const char *
parse_target(const char * targetname)367 parse_target(const char *targetname)
368 {
369 const char *ptr;
370
371 if (strlen(targetname) < 1)
372 xtables_error(PARAMETER_PROBLEM,
373 "Invalid target name (too short)");
374
375 if (strlen(targetname) >= XT_EXTENSION_MAXNAMELEN)
376 xtables_error(PARAMETER_PROBLEM,
377 "Invalid target name `%s' (%u chars max)",
378 targetname, XT_EXTENSION_MAXNAMELEN - 1);
379
380 for (ptr = targetname; *ptr; ptr++)
381 if (isspace(*ptr))
382 xtables_error(PARAMETER_PROBLEM,
383 "Invalid target name `%s'", targetname);
384 return targetname;
385 }
386
387 static void
set_option(unsigned int * options,unsigned int option,uint8_t * invflg,int invert)388 set_option(unsigned int *options, unsigned int option, uint8_t *invflg,
389 int invert)
390 {
391 if (*options & option)
392 xtables_error(PARAMETER_PROBLEM, "multiple -%c flags not allowed",
393 opt2char(option));
394 *options |= option;
395
396 if (invert) {
397 unsigned int i;
398 for (i = 0; 1 << i != option; i++);
399
400 if (!inverse_for_options[i])
401 xtables_error(PARAMETER_PROBLEM,
402 "cannot have ! before -%c",
403 opt2char(option));
404 *invflg |= inverse_for_options[i];
405 }
406 }
407
408 static int
add_entry(const char * chain,const char * table,struct iptables_command_state * cs,int rulenum,int family,const struct addr_mask s,const struct addr_mask d,bool verbose,struct nft_handle * h,bool append)409 add_entry(const char *chain,
410 const char *table,
411 struct iptables_command_state *cs,
412 int rulenum, int family,
413 const struct addr_mask s,
414 const struct addr_mask d,
415 bool verbose, struct nft_handle *h, bool append)
416 {
417 unsigned int i, j;
418 int ret = 1;
419
420 for (i = 0; i < s.naddrs; i++) {
421 if (family == AF_INET) {
422 cs->fw.ip.src.s_addr = s.addr.v4[i].s_addr;
423 cs->fw.ip.smsk.s_addr = s.mask.v4[i].s_addr;
424 for (j = 0; j < d.naddrs; j++) {
425 cs->fw.ip.dst.s_addr = d.addr.v4[j].s_addr;
426 cs->fw.ip.dmsk.s_addr = d.mask.v4[j].s_addr;
427
428 if (append) {
429 ret = nft_rule_append(h, chain, table,
430 cs, 0,
431 verbose);
432 } else {
433 ret = nft_rule_insert(h, chain, table,
434 cs, rulenum,
435 verbose);
436 }
437 }
438 } else if (family == AF_INET6) {
439 memcpy(&cs->fw6.ipv6.src,
440 &s.addr.v6[i], sizeof(struct in6_addr));
441 memcpy(&cs->fw6.ipv6.smsk,
442 &s.mask.v6[i], sizeof(struct in6_addr));
443 for (j = 0; j < d.naddrs; j++) {
444 memcpy(&cs->fw6.ipv6.dst,
445 &d.addr.v6[j], sizeof(struct in6_addr));
446 memcpy(&cs->fw6.ipv6.dmsk,
447 &d.mask.v6[j], sizeof(struct in6_addr));
448 if (append) {
449 ret = nft_rule_append(h, chain, table,
450 cs, 0,
451 verbose);
452 } else {
453 ret = nft_rule_insert(h, chain, table,
454 cs, rulenum,
455 verbose);
456 }
457 }
458 }
459 }
460
461 return ret;
462 }
463
464 static int
replace_entry(const char * chain,const char * table,struct iptables_command_state * cs,unsigned int rulenum,int family,const struct addr_mask s,const struct addr_mask d,bool verbose,struct nft_handle * h)465 replace_entry(const char *chain, const char *table,
466 struct iptables_command_state *cs,
467 unsigned int rulenum,
468 int family,
469 const struct addr_mask s,
470 const struct addr_mask d,
471 bool verbose, struct nft_handle *h)
472 {
473 if (family == AF_INET) {
474 cs->fw.ip.src.s_addr = s.addr.v4->s_addr;
475 cs->fw.ip.dst.s_addr = d.addr.v4->s_addr;
476 cs->fw.ip.smsk.s_addr = s.mask.v4->s_addr;
477 cs->fw.ip.dmsk.s_addr = d.mask.v4->s_addr;
478 } else if (family == AF_INET6) {
479 memcpy(&cs->fw6.ipv6.src, s.addr.v6, sizeof(struct in6_addr));
480 memcpy(&cs->fw6.ipv6.dst, d.addr.v6, sizeof(struct in6_addr));
481 memcpy(&cs->fw6.ipv6.smsk, s.mask.v6, sizeof(struct in6_addr));
482 memcpy(&cs->fw6.ipv6.dmsk, d.mask.v6, sizeof(struct in6_addr));
483 } else
484 return 1;
485
486 return nft_rule_replace(h, chain, table, cs, rulenum, verbose);
487 }
488
489 static int
delete_entry(const char * chain,const char * table,struct iptables_command_state * cs,int family,const struct addr_mask s,const struct addr_mask d,bool verbose,struct nft_handle * h)490 delete_entry(const char *chain, const char *table,
491 struct iptables_command_state *cs,
492 int family,
493 const struct addr_mask s,
494 const struct addr_mask d,
495 bool verbose,
496 struct nft_handle *h)
497 {
498 unsigned int i, j;
499 int ret = 1;
500
501 for (i = 0; i < s.naddrs; i++) {
502 if (family == AF_INET) {
503 cs->fw.ip.src.s_addr = s.addr.v4[i].s_addr;
504 cs->fw.ip.smsk.s_addr = s.mask.v4[i].s_addr;
505 for (j = 0; j < d.naddrs; j++) {
506 cs->fw.ip.dst.s_addr = d.addr.v4[j].s_addr;
507 cs->fw.ip.dmsk.s_addr = d.mask.v4[j].s_addr;
508 ret = nft_rule_delete(h, chain,
509 table, cs, verbose);
510 }
511 } else if (family == AF_INET6) {
512 memcpy(&cs->fw6.ipv6.src,
513 &s.addr.v6[i], sizeof(struct in6_addr));
514 memcpy(&cs->fw6.ipv6.smsk,
515 &s.mask.v6[i], sizeof(struct in6_addr));
516 for (j = 0; j < d.naddrs; j++) {
517 memcpy(&cs->fw6.ipv6.dst,
518 &d.addr.v6[j], sizeof(struct in6_addr));
519 memcpy(&cs->fw6.ipv6.dmsk,
520 &d.mask.v6[j], sizeof(struct in6_addr));
521 ret = nft_rule_delete(h, chain,
522 table, cs, verbose);
523 }
524 }
525 }
526
527 return ret;
528 }
529
530 static int
check_entry(const char * chain,const char * table,struct iptables_command_state * cs,int family,const struct addr_mask s,const struct addr_mask d,bool verbose,struct nft_handle * h)531 check_entry(const char *chain, const char *table,
532 struct iptables_command_state *cs,
533 int family,
534 const struct addr_mask s,
535 const struct addr_mask d,
536 bool verbose, struct nft_handle *h)
537 {
538 unsigned int i, j;
539 int ret = 1;
540
541 for (i = 0; i < s.naddrs; i++) {
542 if (family == AF_INET) {
543 cs->fw.ip.src.s_addr = s.addr.v4[i].s_addr;
544 cs->fw.ip.smsk.s_addr = s.mask.v4[i].s_addr;
545 for (j = 0; j < d.naddrs; j++) {
546 cs->fw.ip.dst.s_addr = d.addr.v4[j].s_addr;
547 cs->fw.ip.dmsk.s_addr = d.mask.v4[j].s_addr;
548 ret = nft_rule_check(h, chain,
549 table, cs, verbose);
550 }
551 } else if (family == AF_INET6) {
552 memcpy(&cs->fw6.ipv6.src,
553 &s.addr.v6[i], sizeof(struct in6_addr));
554 memcpy(&cs->fw6.ipv6.smsk,
555 &s.mask.v6[i], sizeof(struct in6_addr));
556 for (j = 0; j < d.naddrs; j++) {
557 memcpy(&cs->fw6.ipv6.dst,
558 &d.addr.v6[j], sizeof(struct in6_addr));
559 memcpy(&cs->fw6.ipv6.dmsk,
560 &d.mask.v6[j], sizeof(struct in6_addr));
561 ret = nft_rule_check(h, chain,
562 table, cs, verbose);
563 }
564 }
565 }
566
567 return ret;
568 }
569
570 static int
list_entries(struct nft_handle * h,const char * chain,const char * table,int rulenum,int verbose,int numeric,int expanded,int linenumbers)571 list_entries(struct nft_handle *h, const char *chain, const char *table,
572 int rulenum, int verbose, int numeric, int expanded,
573 int linenumbers)
574 {
575 unsigned int format;
576
577 format = FMT_OPTIONS;
578 if (!verbose)
579 format |= FMT_NOCOUNTS;
580 else
581 format |= FMT_VIA;
582
583 if (numeric)
584 format |= FMT_NUMERIC;
585
586 if (!expanded)
587 format |= FMT_KILOMEGAGIGA;
588
589 if (linenumbers)
590 format |= FMT_LINENUMBERS;
591
592 return nft_rule_list(h, chain, table, rulenum, format);
593 }
594
595 static int
list_rules(struct nft_handle * h,const char * chain,const char * table,int rulenum,int counters)596 list_rules(struct nft_handle *h, const char *chain, const char *table,
597 int rulenum, int counters)
598 {
599 if (counters)
600 counters = -1; /* iptables -c format */
601
602 nft_rule_list_save(h, chain, table, rulenum, counters);
603
604 /* iptables does not return error if rule number not found */
605 return 1;
606 }
607
command_jump(struct iptables_command_state * cs)608 static void command_jump(struct iptables_command_state *cs)
609 {
610 size_t size;
611
612 set_option(&cs->options, OPT_JUMP, &cs->fw.ip.invflags, cs->invert);
613 cs->jumpto = parse_target(optarg);
614 /* TRY_LOAD (may be chain name) */
615 cs->target = xtables_find_target(cs->jumpto, XTF_TRY_LOAD);
616
617 if (cs->target == NULL)
618 return;
619
620 size = XT_ALIGN(sizeof(struct xt_entry_target))
621 + cs->target->size;
622
623 cs->target->t = xtables_calloc(1, size);
624 cs->target->t->u.target_size = size;
625 if (cs->target->real_name == NULL) {
626 strcpy(cs->target->t->u.user.name, cs->jumpto);
627 } else {
628 /* Alias support for userspace side */
629 strcpy(cs->target->t->u.user.name, cs->target->real_name);
630 if (!(cs->target->ext_flags & XTABLES_EXT_ALIAS))
631 fprintf(stderr, "Notice: The %s target is converted into %s target "
632 "in rule listing and saving.\n",
633 cs->jumpto, cs->target->real_name);
634 }
635 cs->target->t->u.user.revision = cs->target->revision;
636 xs_init_target(cs->target);
637
638 if (cs->target->x6_options != NULL)
639 opts = xtables_options_xfrm(xtables_globals.orig_opts, opts,
640 cs->target->x6_options,
641 &cs->target->option_offset);
642 else
643 opts = xtables_merge_options(xtables_globals.orig_opts, opts,
644 cs->target->extra_opts,
645 &cs->target->option_offset);
646 if (opts == NULL)
647 xtables_error(OTHER_PROBLEM, "can't alloc memory!");
648 }
649
command_match(struct iptables_command_state * cs)650 static void command_match(struct iptables_command_state *cs)
651 {
652 struct xtables_match *m;
653 size_t size;
654
655 if (cs->invert)
656 xtables_error(PARAMETER_PROBLEM,
657 "unexpected ! flag before --match");
658
659 m = xtables_find_match(optarg, XTF_LOAD_MUST_SUCCEED, &cs->matches);
660 size = XT_ALIGN(sizeof(struct xt_entry_match)) + m->size;
661 m->m = xtables_calloc(1, size);
662 m->m->u.match_size = size;
663 if (m->real_name == NULL) {
664 strcpy(m->m->u.user.name, m->name);
665 } else {
666 strcpy(m->m->u.user.name, m->real_name);
667 if (!(m->ext_flags & XTABLES_EXT_ALIAS))
668 fprintf(stderr, "Notice: the %s match is converted into %s match "
669 "in rule listing and saving.\n", m->name, m->real_name);
670 }
671 m->m->u.user.revision = m->revision;
672 xs_init_match(m);
673 if (m == m->next)
674 return;
675 /* Merge options for non-cloned matches */
676 if (m->x6_options != NULL)
677 opts = xtables_options_xfrm(xtables_globals.orig_opts, opts,
678 m->x6_options, &m->option_offset);
679 else if (m->extra_opts != NULL)
680 opts = xtables_merge_options(xtables_globals.orig_opts, opts,
681 m->extra_opts, &m->option_offset);
682 if (opts == NULL)
683 xtables_error(OTHER_PROBLEM, "can't alloc memory!");
684 }
685
do_parse(struct nft_handle * h,int argc,char * argv[],struct nft_xt_cmd_parse * p,struct iptables_command_state * cs,struct xtables_args * args)686 void do_parse(struct nft_handle *h, int argc, char *argv[],
687 struct nft_xt_cmd_parse *p, struct iptables_command_state *cs,
688 struct xtables_args *args)
689 {
690 struct xtables_match *m;
691 struct xtables_rule_match *matchp;
692 bool wait_interval_set = false;
693 struct timeval wait_interval;
694 struct xtables_target *t;
695 int wait = 0;
696
697 memset(cs, 0, sizeof(*cs));
698 cs->jumpto = "";
699 cs->argv = argv;
700
701 /* re-set optind to 0 in case do_command4 gets called
702 * a second time */
703 optind = 0;
704
705 /* clear mflags in case do_command4 gets called a second time
706 * (we clear the global list of all matches for security)*/
707 for (m = xtables_matches; m; m = m->next)
708 m->mflags = 0;
709
710 for (t = xtables_targets; t; t = t->next) {
711 t->tflags = 0;
712 t->used = 0;
713 }
714
715 /* Suppress error messages: we may add new options if we
716 demand-load a protocol. */
717 opterr = 0;
718
719 h->ops = nft_family_ops_lookup(h->family);
720 if (h->ops == NULL)
721 xtables_error(PARAMETER_PROBLEM, "Unknown family");
722
723 opts = xt_params->orig_opts;
724 while ((cs->c = getopt_long(argc, argv,
725 "-:A:C:D:R:I:L::S::M:F::Z::N:X::E:P:Vh::o:p:s:d:j:i:fbvw::W::nt:m:xc:g:46",
726 opts, NULL)) != -1) {
727 switch (cs->c) {
728 /*
729 * Command selection
730 */
731 case 'A':
732 add_command(&p->command, CMD_APPEND, CMD_NONE,
733 cs->invert);
734 p->chain = optarg;
735 break;
736
737 case 'C':
738 add_command(&p->command, CMD_CHECK, CMD_NONE,
739 cs->invert);
740 p->chain = optarg;
741 break;
742
743 case 'D':
744 add_command(&p->command, CMD_DELETE, CMD_NONE,
745 cs->invert);
746 p->chain = optarg;
747 if (xs_has_arg(argc, argv)) {
748 p->rulenum = parse_rulenumber(argv[optind++]);
749 p->command = CMD_DELETE_NUM;
750 }
751 break;
752
753 case 'R':
754 add_command(&p->command, CMD_REPLACE, CMD_NONE,
755 cs->invert);
756 p->chain = optarg;
757 if (xs_has_arg(argc, argv))
758 p->rulenum = parse_rulenumber(argv[optind++]);
759 else
760 xtables_error(PARAMETER_PROBLEM,
761 "-%c requires a rule number",
762 cmd2char(CMD_REPLACE));
763 break;
764
765 case 'I':
766 add_command(&p->command, CMD_INSERT, CMD_NONE,
767 cs->invert);
768 p->chain = optarg;
769 if (xs_has_arg(argc, argv))
770 p->rulenum = parse_rulenumber(argv[optind++]);
771 else
772 p->rulenum = 1;
773 break;
774
775 case 'L':
776 add_command(&p->command, CMD_LIST,
777 CMD_ZERO | CMD_ZERO_NUM, cs->invert);
778 if (optarg)
779 p->chain = optarg;
780 else if (xs_has_arg(argc, argv))
781 p->chain = argv[optind++];
782 if (xs_has_arg(argc, argv))
783 p->rulenum = parse_rulenumber(argv[optind++]);
784 break;
785
786 case 'S':
787 add_command(&p->command, CMD_LIST_RULES,
788 CMD_ZERO|CMD_ZERO_NUM, cs->invert);
789 if (optarg)
790 p->chain = optarg;
791 else if (xs_has_arg(argc, argv))
792 p->chain = argv[optind++];
793 if (xs_has_arg(argc, argv))
794 p->rulenum = parse_rulenumber(argv[optind++]);
795 break;
796
797 case 'F':
798 add_command(&p->command, CMD_FLUSH, CMD_NONE,
799 cs->invert);
800 if (optarg)
801 p->chain = optarg;
802 else if (xs_has_arg(argc, argv))
803 p->chain = argv[optind++];
804 break;
805
806 case 'Z':
807 add_command(&p->command, CMD_ZERO,
808 CMD_LIST|CMD_LIST_RULES, cs->invert);
809 if (optarg)
810 p->chain = optarg;
811 else if (xs_has_arg(argc, argv))
812 p->chain = argv[optind++];
813 if (xs_has_arg(argc, argv)) {
814 p->rulenum = parse_rulenumber(argv[optind++]);
815 p->command = CMD_ZERO_NUM;
816 }
817 break;
818
819 case 'N':
820 if (optarg && (*optarg == '-' || *optarg == '!'))
821 xtables_error(PARAMETER_PROBLEM,
822 "chain name not allowed to start "
823 "with `%c'\n", *optarg);
824 if (xtables_find_target(optarg, XTF_TRY_LOAD))
825 xtables_error(PARAMETER_PROBLEM,
826 "chain name may not clash "
827 "with target name\n");
828 add_command(&p->command, CMD_NEW_CHAIN, CMD_NONE,
829 cs->invert);
830 p->chain = optarg;
831 break;
832
833 case 'X':
834 add_command(&p->command, CMD_DELETE_CHAIN, CMD_NONE,
835 cs->invert);
836 if (optarg)
837 p->chain = optarg;
838 else if (xs_has_arg(argc, argv))
839 p->chain = argv[optind++];
840 break;
841
842 case 'E':
843 add_command(&p->command, CMD_RENAME_CHAIN, CMD_NONE,
844 cs->invert);
845 p->chain = optarg;
846 if (xs_has_arg(argc, argv))
847 p->newname = argv[optind++];
848 else
849 xtables_error(PARAMETER_PROBLEM,
850 "-%c requires old-chain-name and "
851 "new-chain-name",
852 cmd2char(CMD_RENAME_CHAIN));
853 break;
854
855 case 'P':
856 add_command(&p->command, CMD_SET_POLICY, CMD_NONE,
857 cs->invert);
858 p->chain = optarg;
859 if (xs_has_arg(argc, argv))
860 p->policy = argv[optind++];
861 else
862 xtables_error(PARAMETER_PROBLEM,
863 "-%c requires a chain and a policy",
864 cmd2char(CMD_SET_POLICY));
865 break;
866
867 case 'h':
868 if (!optarg)
869 optarg = argv[optind];
870
871 /* iptables -p icmp -h */
872 if (!cs->matches && cs->protocol)
873 xtables_find_match(cs->protocol,
874 XTF_TRY_LOAD, &cs->matches);
875
876 exit_printhelp(cs->matches);
877
878 /*
879 * Option selection
880 */
881 case 'p':
882 set_option(&cs->options, OPT_PROTOCOL,
883 &args->invflags, cs->invert);
884
885 /* Canonicalize into lower case */
886 for (cs->protocol = optarg; *cs->protocol; cs->protocol++)
887 *cs->protocol = tolower(*cs->protocol);
888
889 cs->protocol = optarg;
890 args->proto = xtables_parse_protocol(cs->protocol);
891
892 if (args->proto == 0 &&
893 (args->invflags & XT_INV_PROTO))
894 xtables_error(PARAMETER_PROBLEM,
895 "rule would never match protocol");
896
897 /* This needs to happen here to parse extensions */
898 h->ops->proto_parse(cs, args);
899 break;
900
901 case 's':
902 set_option(&cs->options, OPT_SOURCE,
903 &args->invflags, cs->invert);
904 args->shostnetworkmask = optarg;
905 break;
906
907 case 'd':
908 set_option(&cs->options, OPT_DESTINATION,
909 &args->invflags, cs->invert);
910 args->dhostnetworkmask = optarg;
911 break;
912
913 #ifdef IPT_F_GOTO
914 case 'g':
915 set_option(&cs->options, OPT_JUMP, &args->invflags,
916 cs->invert);
917 args->goto_set = true;
918 cs->jumpto = parse_target(optarg);
919 break;
920 #endif
921
922 case 'j':
923 command_jump(cs);
924 break;
925
926
927 case 'i':
928 if (*optarg == '\0')
929 xtables_error(PARAMETER_PROBLEM,
930 "Empty interface is likely to be "
931 "undesired");
932 set_option(&cs->options, OPT_VIANAMEIN,
933 &args->invflags, cs->invert);
934 xtables_parse_interface(optarg,
935 args->iniface,
936 args->iniface_mask);
937 break;
938
939 case 'o':
940 if (*optarg == '\0')
941 xtables_error(PARAMETER_PROBLEM,
942 "Empty interface is likely to be "
943 "undesired");
944 set_option(&cs->options, OPT_VIANAMEOUT,
945 &args->invflags, cs->invert);
946 xtables_parse_interface(optarg,
947 args->outiface,
948 args->outiface_mask);
949 break;
950
951 case 'f':
952 if (args->family == AF_INET6) {
953 xtables_error(PARAMETER_PROBLEM,
954 "`-f' is not supported in IPv6, "
955 "use -m frag instead");
956 }
957 set_option(&cs->options, OPT_FRAGMENT, &args->invflags,
958 cs->invert);
959 args->flags |= IPT_F_FRAG;
960 break;
961
962 case 'v':
963 if (!p->verbose)
964 set_option(&cs->options, OPT_VERBOSE,
965 &args->invflags, cs->invert);
966 p->verbose++;
967 break;
968
969 case 'm':
970 command_match(cs);
971 break;
972
973 case 'n':
974 set_option(&cs->options, OPT_NUMERIC, &args->invflags,
975 cs->invert);
976 break;
977
978 case 't':
979 if (cs->invert)
980 xtables_error(PARAMETER_PROBLEM,
981 "unexpected ! flag before --table");
982 p->table = optarg;
983 break;
984
985 case 'x':
986 set_option(&cs->options, OPT_EXPANDED, &args->invflags,
987 cs->invert);
988 break;
989
990 case 'V':
991 if (cs->invert)
992 printf("Not %s ;-)\n", prog_vers);
993 else
994 printf("%s v%s\n",
995 prog_name, prog_vers);
996 exit(0);
997
998 case 'w':
999 if (p->restore) {
1000 xtables_error(PARAMETER_PROBLEM,
1001 "You cannot use `-w' from "
1002 "iptables-restore");
1003 }
1004
1005 wait = parse_wait_time(argc, argv);
1006 break;
1007
1008 case 'W':
1009 if (p->restore) {
1010 xtables_error(PARAMETER_PROBLEM,
1011 "You cannot use `-W' from "
1012 "iptables-restore");
1013 }
1014
1015 parse_wait_interval(argc, argv, &wait_interval);
1016 wait_interval_set = true;
1017 break;
1018
1019 case '0':
1020 set_option(&cs->options, OPT_LINENUMBERS,
1021 &args->invflags, cs->invert);
1022 break;
1023
1024 case 'M':
1025 xtables_modprobe_program = optarg;
1026 break;
1027
1028 case 'c':
1029 set_option(&cs->options, OPT_COUNTERS, &args->invflags,
1030 cs->invert);
1031 args->pcnt = optarg;
1032 args->bcnt = strchr(args->pcnt + 1, ',');
1033 if (args->bcnt)
1034 args->bcnt++;
1035 if (!args->bcnt && xs_has_arg(argc, argv))
1036 args->bcnt = argv[optind++];
1037 if (!args->bcnt)
1038 xtables_error(PARAMETER_PROBLEM,
1039 "-%c requires packet and byte counter",
1040 opt2char(OPT_COUNTERS));
1041
1042 if (sscanf(args->pcnt, "%llu", &args->pcnt_cnt) != 1)
1043 xtables_error(PARAMETER_PROBLEM,
1044 "-%c packet counter not numeric",
1045 opt2char(OPT_COUNTERS));
1046
1047 if (sscanf(args->bcnt, "%llu", &args->bcnt_cnt) != 1)
1048 xtables_error(PARAMETER_PROBLEM,
1049 "-%c byte counter not numeric",
1050 opt2char(OPT_COUNTERS));
1051 break;
1052
1053 case '4':
1054 if (args->family != AF_INET)
1055 exit_tryhelp(2);
1056
1057 h->ops = nft_family_ops_lookup(args->family);
1058 break;
1059
1060 case '6':
1061 args->family = AF_INET6;
1062 xtables_set_nfproto(AF_INET6);
1063
1064 h->ops = nft_family_ops_lookup(args->family);
1065 if (h->ops == NULL)
1066 xtables_error(PARAMETER_PROBLEM,
1067 "Unknown family");
1068 break;
1069
1070 case 1: /* non option */
1071 if (optarg[0] == '!' && optarg[1] == '\0') {
1072 if (cs->invert)
1073 xtables_error(PARAMETER_PROBLEM,
1074 "multiple consecutive ! not"
1075 " allowed");
1076 cs->invert = TRUE;
1077 optarg[0] = '\0';
1078 continue;
1079 }
1080 fprintf(stderr, "Bad argument `%s'\n", optarg);
1081 exit_tryhelp(2);
1082
1083 default:
1084 if (command_default(cs, &xtables_globals) == 1)
1085 /* cf. ip6tables.c */
1086 continue;
1087 break;
1088 }
1089 cs->invert = FALSE;
1090 }
1091
1092 if (strcmp(p->table, "nat") == 0 &&
1093 ((p->policy != NULL && strcmp(p->policy, "DROP") == 0) ||
1094 (cs->jumpto != NULL && strcmp(cs->jumpto, "DROP") == 0)))
1095 xtables_error(PARAMETER_PROBLEM,
1096 "\nThe \"nat\" table is not intended for filtering, "
1097 "the use of DROP is therefore inhibited.\n\n");
1098
1099 if (!wait && wait_interval_set)
1100 xtables_error(PARAMETER_PROBLEM,
1101 "--wait-interval only makes sense with --wait\n");
1102
1103 for (matchp = cs->matches; matchp; matchp = matchp->next)
1104 xtables_option_mfcall(matchp->match);
1105 if (cs->target != NULL)
1106 xtables_option_tfcall(cs->target);
1107
1108 /* Fix me: must put inverse options checking here --MN */
1109
1110 if (optind < argc)
1111 xtables_error(PARAMETER_PROBLEM,
1112 "unknown arguments found on commandline");
1113 if (!p->command)
1114 xtables_error(PARAMETER_PROBLEM, "no command specified");
1115 if (cs->invert)
1116 xtables_error(PARAMETER_PROBLEM,
1117 "nothing appropriate following !");
1118
1119 /* Set only if required, needed by xtables-restore */
1120 if (h->family == AF_UNSPEC)
1121 h->family = args->family;
1122
1123 h->ops->post_parse(p->command, cs, args);
1124
1125 if (p->command == CMD_REPLACE &&
1126 (args->s.naddrs != 1 || args->d.naddrs != 1))
1127 xtables_error(PARAMETER_PROBLEM, "Replacement rule does not "
1128 "specify a unique address");
1129
1130 generic_opt_check(p->command, cs->options);
1131
1132 if (p->chain != NULL && strlen(p->chain) >= XT_EXTENSION_MAXNAMELEN)
1133 xtables_error(PARAMETER_PROBLEM,
1134 "chain name `%s' too long (must be under %u chars)",
1135 p->chain, XT_EXTENSION_MAXNAMELEN);
1136
1137 if (p->command == CMD_APPEND ||
1138 p->command == CMD_DELETE ||
1139 p->command == CMD_CHECK ||
1140 p->command == CMD_INSERT ||
1141 p->command == CMD_REPLACE) {
1142 if (strcmp(p->chain, "PREROUTING") == 0
1143 || strcmp(p->chain, "INPUT") == 0) {
1144 /* -o not valid with incoming packets. */
1145 if (cs->options & OPT_VIANAMEOUT)
1146 xtables_error(PARAMETER_PROBLEM,
1147 "Can't use -%c with %s\n",
1148 opt2char(OPT_VIANAMEOUT),
1149 p->chain);
1150 }
1151
1152 if (strcmp(p->chain, "POSTROUTING") == 0
1153 || strcmp(p->chain, "OUTPUT") == 0) {
1154 /* -i not valid with outgoing packets */
1155 if (cs->options & OPT_VIANAMEIN)
1156 xtables_error(PARAMETER_PROBLEM,
1157 "Can't use -%c with %s\n",
1158 opt2char(OPT_VIANAMEIN),
1159 p->chain);
1160 }
1161
1162 /*
1163 * Contrary to what iptables does, we assume that any jumpto
1164 * is a custom chain jumps (if no target is found). Later on,
1165 * nf_table will spot the error if the chain does not exists.
1166 */
1167 }
1168 }
1169
do_commandx(struct nft_handle * h,int argc,char * argv[],char ** table,bool restore)1170 int do_commandx(struct nft_handle *h, int argc, char *argv[], char **table,
1171 bool restore)
1172 {
1173 int ret = 1;
1174 struct nft_xt_cmd_parse p = {
1175 .table = *table,
1176 .restore = restore,
1177 };
1178 struct iptables_command_state cs;
1179 struct xtables_args args = {
1180 .family = h->family,
1181 };
1182
1183 do_parse(h, argc, argv, &p, &cs, &args);
1184
1185 switch (p.command) {
1186 case CMD_APPEND:
1187 ret = add_entry(p.chain, p.table, &cs, 0, h->family,
1188 args.s, args.d,
1189 cs.options & OPT_VERBOSE, h, true);
1190 break;
1191 case CMD_DELETE:
1192 ret = delete_entry(p.chain, p.table, &cs, h->family,
1193 args.s, args.d,
1194 cs.options & OPT_VERBOSE, h);
1195 break;
1196 case CMD_DELETE_NUM:
1197 ret = nft_rule_delete_num(h, p.chain, p.table,
1198 p.rulenum - 1, p.verbose);
1199 break;
1200 case CMD_CHECK:
1201 ret = check_entry(p.chain, p.table, &cs, h->family,
1202 args.s, args.d,
1203 cs.options & OPT_VERBOSE, h);
1204 break;
1205 case CMD_REPLACE:
1206 ret = replace_entry(p.chain, p.table, &cs, p.rulenum - 1,
1207 h->family, args.s, args.d,
1208 cs.options & OPT_VERBOSE, h);
1209 break;
1210 case CMD_INSERT:
1211 ret = add_entry(p.chain, p.table, &cs, p.rulenum - 1,
1212 h->family, args.s, args.d,
1213 cs.options&OPT_VERBOSE, h, false);
1214 break;
1215 case CMD_FLUSH:
1216 ret = nft_rule_flush(h, p.chain, p.table);
1217 break;
1218 case CMD_ZERO:
1219 ret = nft_chain_zero_counters(h, p.chain, p.table);
1220 break;
1221 case CMD_ZERO_NUM:
1222 ret = nft_rule_zero_counters(h, p.chain, p.table,
1223 p.rulenum - 1);
1224 break;
1225 case CMD_LIST:
1226 case CMD_LIST|CMD_ZERO:
1227 case CMD_LIST|CMD_ZERO_NUM:
1228 if (nft_is_ruleset_compatible(h) == 1) {
1229 printf("ERROR: You're using nft features that cannot be mapped to iptables, please keep using nft.\n");
1230 exit(EXIT_FAILURE);
1231 }
1232
1233 ret = list_entries(h, p.chain, p.table, p.rulenum,
1234 cs.options & OPT_VERBOSE,
1235 cs.options & OPT_NUMERIC,
1236 cs.options & OPT_EXPANDED,
1237 cs.options & OPT_LINENUMBERS);
1238 if (ret && (p.command & CMD_ZERO)) {
1239 ret = nft_chain_zero_counters(h, p.chain,
1240 p.table);
1241 }
1242 if (ret && (p.command & CMD_ZERO_NUM)) {
1243 ret = nft_rule_zero_counters(h, p.chain, p.table,
1244 p.rulenum - 1);
1245 }
1246 break;
1247 case CMD_LIST_RULES:
1248 case CMD_LIST_RULES|CMD_ZERO:
1249 case CMD_LIST_RULES|CMD_ZERO_NUM:
1250 ret = list_rules(h, p.chain, p.table, p.rulenum,
1251 cs.options & OPT_VERBOSE);
1252 if (ret && (p.command & CMD_ZERO)) {
1253 ret = nft_chain_zero_counters(h, p.chain,
1254 p.table);
1255 }
1256 if (ret && (p.command & CMD_ZERO_NUM)) {
1257 ret = nft_rule_zero_counters(h, p.chain, p.table,
1258 p.rulenum - 1);
1259 }
1260 break;
1261 case CMD_NEW_CHAIN:
1262 ret = nft_chain_user_add(h, p.chain, p.table);
1263 break;
1264 case CMD_DELETE_CHAIN:
1265 ret = nft_chain_user_del(h, p.chain, p.table);
1266 break;
1267 case CMD_RENAME_CHAIN:
1268 ret = nft_chain_user_rename(h, p.chain, p.table, p.newname);
1269 break;
1270 case CMD_SET_POLICY:
1271 ret = nft_chain_set(h, p.table, p.chain, p.policy, NULL);
1272 if (ret < 0)
1273 xtables_error(PARAMETER_PROBLEM, "Wrong policy `%s'\n",
1274 p.policy);
1275 break;
1276 default:
1277 /* We should never reach this... */
1278 exit_tryhelp(2);
1279 }
1280
1281 *table = p.table;
1282
1283 xtables_rule_matches_free(&cs.matches);
1284
1285 if (h->family == AF_INET) {
1286 free(args.s.addr.v4);
1287 free(args.s.mask.v4);
1288 free(args.d.addr.v4);
1289 free(args.d.mask.v4);
1290 } else if (h->family == AF_INET6) {
1291 free(args.s.addr.v6);
1292 free(args.s.mask.v6);
1293 free(args.d.addr.v6);
1294 free(args.d.mask.v6);
1295 }
1296 xtables_free_opts(1);
1297
1298 return ret;
1299 }
1300