]> git.ipfire.org Git - thirdparty/iptables.git/commitdiff
xshared: Move do_parse to shared space
authorPhil Sutter <phil@nwl.cc>
Thu, 23 Dec 2021 18:03:37 +0000 (19:03 +0100)
committerPhil Sutter <phil@nwl.cc>
Wed, 12 Jan 2022 13:08:54 +0000 (14:08 +0100)
Small adjustments were needed:

- Pass line variable via xt_cmd_parse, xshared.c does not have it in
  namespace.
- Replace opts, prog_name and prog_vers defines by the respective
  xt_params field reference.

Signed-off-by: Phil Sutter <phil@nwl.cc>
iptables/nft-shared.h
iptables/xshared.c
iptables/xshared.h
iptables/xtables-translate.c
iptables/xtables.c

index 195e5fed43075552d894900fb90d4fbd3f183d44..c3241f4b8c7264302e83cf9960c5696b9e81952b 100644 (file)
@@ -174,10 +174,6 @@ void nft_ipv46_parse_target(struct xtables_target *t, void *data);
 bool compare_matches(struct xtables_rule_match *mt1, struct xtables_rule_match *mt2);
 bool compare_targets(struct xtables_target *tg1, struct xtables_target *tg2);
 
-void do_parse(int argc, char *argv[],
-             struct xt_cmd_parse *p, struct iptables_command_state *cs,
-             struct xtables_args *args);
-
 struct nftnl_chain_list;
 
 struct nft_xt_restore_cb {
index efee7a30b39fdf439cb68bcce475bfcf2bc8ec75..4c8ee3aa202789d6364c469ed4b45ec6640c78b8 100644 (file)
@@ -1262,3 +1262,556 @@ void exit_tryhelp(int status, int line)
        xtables_free_opts(1);
        exit(status);
 }
+
+static void check_empty_interface(struct xtables_args *args, const char *arg)
+{
+       const char *msg = "Empty interface is likely to be undesired";
+
+       if (*arg != '\0')
+               return;
+
+       if (args->family != NFPROTO_ARP)
+               xtables_error(PARAMETER_PROBLEM, msg);
+
+       fprintf(stderr, "%s", msg);
+}
+
+static void check_inverse(struct xtables_args *args, const char option[],
+                         bool *invert, int *optidx, int argc)
+{
+       switch (args->family) {
+       case NFPROTO_ARP:
+               break;
+       default:
+               return;
+       }
+
+       if (!option || strcmp(option, "!"))
+               return;
+
+       fprintf(stderr, "Using intrapositioned negation (`--option ! this`) "
+               "is deprecated in favor of extrapositioned (`! --option this`).\n");
+
+       if (*invert)
+               xtables_error(PARAMETER_PROBLEM,
+                             "Multiple `!' flags not allowed");
+       *invert = true;
+       if (optidx) {
+               *optidx = *optidx + 1;
+               if (argc && *optidx > argc)
+                       xtables_error(PARAMETER_PROBLEM,
+                                     "no argument following `!'");
+       }
+}
+
+void do_parse(int argc, char *argv[],
+             struct xt_cmd_parse *p, struct iptables_command_state *cs,
+             struct xtables_args *args)
+{
+       struct xtables_match *m;
+       struct xtables_rule_match *matchp;
+       bool wait_interval_set = false;
+       struct timeval wait_interval;
+       struct xtables_target *t;
+       bool table_set = false;
+       bool invert = false;
+       int wait = 0;
+
+       /* re-set optind to 0 in case do_command4 gets called
+        * a second time */
+       optind = 0;
+
+       /* clear mflags in case do_command4 gets called a second time
+        * (we clear the global list of all matches for security)*/
+       for (m = xtables_matches; m; m = m->next)
+               m->mflags = 0;
+
+       for (t = xtables_targets; t; t = t->next) {
+               t->tflags = 0;
+               t->used = 0;
+       }
+
+       /* Suppress error messages: we may add new options if we
+          demand-load a protocol. */
+       opterr = 0;
+
+       xt_params->opts = xt_params->orig_opts;
+       while ((cs->c = getopt_long(argc, argv, xt_params->optstring,
+                                   xt_params->opts, NULL)) != -1) {
+               switch (cs->c) {
+                       /*
+                        * Command selection
+                        */
+               case 'A':
+                       add_command(&p->command, CMD_APPEND, CMD_NONE, invert);
+                       p->chain = optarg;
+                       break;
+
+               case 'C':
+                       add_command(&p->command, CMD_CHECK, CMD_NONE, invert);
+                       p->chain = optarg;
+                       break;
+
+               case 'D':
+                       add_command(&p->command, CMD_DELETE, CMD_NONE, invert);
+                       p->chain = optarg;
+                       if (xs_has_arg(argc, argv)) {
+                               p->rulenum = parse_rulenumber(argv[optind++]);
+                               p->command = CMD_DELETE_NUM;
+                       }
+                       break;
+
+               case 'R':
+                       add_command(&p->command, CMD_REPLACE, CMD_NONE, invert);
+                       p->chain = optarg;
+                       if (xs_has_arg(argc, argv))
+                               p->rulenum = parse_rulenumber(argv[optind++]);
+                       else
+                               xtables_error(PARAMETER_PROBLEM,
+                                          "-%c requires a rule number",
+                                          cmd2char(CMD_REPLACE));
+                       break;
+
+               case 'I':
+                       add_command(&p->command, CMD_INSERT, CMD_NONE, invert);
+                       p->chain = optarg;
+                       if (xs_has_arg(argc, argv))
+                               p->rulenum = parse_rulenumber(argv[optind++]);
+                       else
+                               p->rulenum = 1;
+                       break;
+
+               case 'L':
+                       add_command(&p->command, CMD_LIST,
+                                   CMD_ZERO | CMD_ZERO_NUM, invert);
+                       if (optarg)
+                               p->chain = optarg;
+                       else if (xs_has_arg(argc, argv))
+                               p->chain = argv[optind++];
+                       if (xs_has_arg(argc, argv))
+                               p->rulenum = parse_rulenumber(argv[optind++]);
+                       break;
+
+               case 'S':
+                       add_command(&p->command, CMD_LIST_RULES,
+                                   CMD_ZERO|CMD_ZERO_NUM, invert);
+                       if (optarg)
+                               p->chain = optarg;
+                       else if (xs_has_arg(argc, argv))
+                               p->chain = argv[optind++];
+                       if (xs_has_arg(argc, argv))
+                               p->rulenum = parse_rulenumber(argv[optind++]);
+                       break;
+
+               case 'F':
+                       add_command(&p->command, CMD_FLUSH, CMD_NONE, invert);
+                       if (optarg)
+                               p->chain = optarg;
+                       else if (xs_has_arg(argc, argv))
+                               p->chain = argv[optind++];
+                       break;
+
+               case 'Z':
+                       add_command(&p->command, CMD_ZERO,
+                                   CMD_LIST|CMD_LIST_RULES, invert);
+                       if (optarg)
+                               p->chain = optarg;
+                       else if (xs_has_arg(argc, argv))
+                               p->chain = argv[optind++];
+                       if (xs_has_arg(argc, argv)) {
+                               p->rulenum = parse_rulenumber(argv[optind++]);
+                               p->command = CMD_ZERO_NUM;
+                       }
+                       break;
+
+               case 'N':
+                       parse_chain(optarg);
+                       add_command(&p->command, CMD_NEW_CHAIN, CMD_NONE,
+                                   invert);
+                       p->chain = optarg;
+                       break;
+
+               case 'X':
+                       add_command(&p->command, CMD_DELETE_CHAIN, CMD_NONE,
+                                   invert);
+                       if (optarg)
+                               p->chain = optarg;
+                       else if (xs_has_arg(argc, argv))
+                               p->chain = argv[optind++];
+                       break;
+
+               case 'E':
+                       add_command(&p->command, CMD_RENAME_CHAIN, CMD_NONE,
+                                   invert);
+                       p->chain = optarg;
+                       if (xs_has_arg(argc, argv))
+                               p->newname = argv[optind++];
+                       else
+                               xtables_error(PARAMETER_PROBLEM,
+                                          "-%c requires old-chain-name and "
+                                          "new-chain-name",
+                                           cmd2char(CMD_RENAME_CHAIN));
+                       break;
+
+               case 'P':
+                       add_command(&p->command, CMD_SET_POLICY, CMD_NONE,
+                                   invert);
+                       p->chain = optarg;
+                       if (xs_has_arg(argc, argv))
+                               p->policy = argv[optind++];
+                       else
+                               xtables_error(PARAMETER_PROBLEM,
+                                          "-%c requires a chain and a policy",
+                                          cmd2char(CMD_SET_POLICY));
+                       break;
+
+               case 'h':
+                       if (!optarg)
+                               optarg = argv[optind];
+
+                       /* iptables -p icmp -h */
+                       if (!cs->matches && cs->protocol)
+                               xtables_find_match(cs->protocol,
+                                       XTF_TRY_LOAD, &cs->matches);
+
+                       xt_params->print_help(cs->matches);
+                       p->command = CMD_NONE;
+                       return;
+
+                       /*
+                        * Option selection
+                        */
+               case 'p':
+                       check_inverse(args, optarg, &invert, &optind, argc);
+                       set_option(&cs->options, OPT_PROTOCOL,
+                                  &args->invflags, invert);
+
+                       /* Canonicalize into lower case */
+                       for (cs->protocol = argv[optind - 1];
+                            *cs->protocol; cs->protocol++)
+                               *cs->protocol = tolower(*cs->protocol);
+
+                       cs->protocol = argv[optind - 1];
+                       args->proto = xtables_parse_protocol(cs->protocol);
+
+                       if (args->proto == 0 &&
+                           (args->invflags & XT_INV_PROTO))
+                               xtables_error(PARAMETER_PROBLEM,
+                                          "rule would never match protocol");
+
+                       /* This needs to happen here to parse extensions */
+                       if (p->ops->proto_parse)
+                               p->ops->proto_parse(cs, args);
+                       break;
+
+               case 's':
+                       check_inverse(args, optarg, &invert, &optind, argc);
+                       set_option(&cs->options, OPT_SOURCE,
+                                  &args->invflags, invert);
+                       args->shostnetworkmask = argv[optind - 1];
+                       break;
+
+               case 'd':
+                       check_inverse(args, optarg, &invert, &optind, argc);
+                       set_option(&cs->options, OPT_DESTINATION,
+                                  &args->invflags, invert);
+                       args->dhostnetworkmask = argv[optind - 1];
+                       break;
+
+#ifdef IPT_F_GOTO
+               case 'g':
+                       set_option(&cs->options, OPT_JUMP, &args->invflags,
+                                  invert);
+                       args->goto_set = true;
+                       cs->jumpto = xt_parse_target(optarg);
+                       break;
+#endif
+
+               case 2:/* src-mac */
+                       check_inverse(args, optarg, &invert, &optind, argc);
+                       set_option(&cs->options, OPT_S_MAC, &args->invflags,
+                                  invert);
+                       args->src_mac = argv[optind - 1];
+                       break;
+
+               case 3:/* dst-mac */
+                       check_inverse(args, optarg, &invert, &optind, argc);
+                       set_option(&cs->options, OPT_D_MAC, &args->invflags,
+                                  invert);
+                       args->dst_mac = argv[optind - 1];
+                       break;
+
+               case 'l':/* hardware length */
+                       check_inverse(args, optarg, &invert, &optind, argc);
+                       set_option(&cs->options, OPT_H_LENGTH, &args->invflags,
+                                  invert);
+                       args->arp_hlen = argv[optind - 1];
+                       break;
+
+               case 8: /* was never supported, not even in arptables-legacy */
+                       xtables_error(PARAMETER_PROBLEM, "not supported");
+               case 4:/* opcode */
+                       check_inverse(args, optarg, &invert, &optind, argc);
+                       set_option(&cs->options, OPT_OPCODE, &args->invflags,
+                                  invert);
+                       args->arp_opcode = argv[optind - 1];
+                       break;
+
+               case 5:/* h-type */
+                       check_inverse(args, optarg, &invert, &optind, argc);
+                       set_option(&cs->options, OPT_H_TYPE, &args->invflags,
+                                  invert);
+                       args->arp_htype = argv[optind - 1];
+                       break;
+
+               case 6:/* proto-type */
+                       check_inverse(args, optarg, &invert, &optind, argc);
+                       set_option(&cs->options, OPT_P_TYPE, &args->invflags,
+                                  invert);
+                       args->arp_ptype = argv[optind - 1];
+                       break;
+
+               case 'j':
+                       set_option(&cs->options, OPT_JUMP, &args->invflags,
+                                  invert);
+                       command_jump(cs, argv[optind - 1]);
+                       break;
+
+               case 'i':
+                       check_empty_interface(args, optarg);
+                       check_inverse(args, optarg, &invert, &optind, argc);
+                       set_option(&cs->options, OPT_VIANAMEIN,
+                                  &args->invflags, invert);
+                       xtables_parse_interface(argv[optind - 1],
+                                               args->iniface,
+                                               args->iniface_mask);
+                       break;
+
+               case 'o':
+                       check_empty_interface(args, optarg);
+                       check_inverse(args, optarg, &invert, &optind, argc);
+                       set_option(&cs->options, OPT_VIANAMEOUT,
+                                  &args->invflags, invert);
+                       xtables_parse_interface(argv[optind - 1],
+                                               args->outiface,
+                                               args->outiface_mask);
+                       break;
+
+               case 'f':
+                       if (args->family == AF_INET6) {
+                               xtables_error(PARAMETER_PROBLEM,
+                                       "`-f' is not supported in IPv6, "
+                                       "use -m frag instead");
+                       }
+                       set_option(&cs->options, OPT_FRAGMENT, &args->invflags,
+                                  invert);
+                       args->flags |= IPT_F_FRAG;
+                       break;
+
+               case 'v':
+                       if (!p->verbose)
+                               set_option(&cs->options, OPT_VERBOSE,
+                                          &args->invflags, invert);
+                       p->verbose++;
+                       break;
+
+               case 'm':
+                       command_match(cs, invert);
+                       break;
+
+               case 'n':
+                       set_option(&cs->options, OPT_NUMERIC, &args->invflags,
+                                  invert);
+                       break;
+
+               case 't':
+                       if (invert)
+                               xtables_error(PARAMETER_PROBLEM,
+                                          "unexpected ! flag before --table");
+                       if (p->restore && table_set)
+                               xtables_error(PARAMETER_PROBLEM,
+                                             "The -t option cannot be used in %s.\n",
+                                             xt_params->program_name);
+                       p->table = optarg;
+                       table_set = true;
+                       break;
+
+               case 'x':
+                       set_option(&cs->options, OPT_EXPANDED, &args->invflags,
+                                  invert);
+                       break;
+
+               case 'V':
+                       if (invert)
+                               printf("Not %s ;-)\n",
+                                      xt_params->program_version);
+                       else
+                               printf("%s v%s\n",
+                                      xt_params->program_name,
+                                      xt_params->program_version);
+                       exit(0);
+
+               case 'w':
+                       if (p->restore) {
+                               xtables_error(PARAMETER_PROBLEM,
+                                             "You cannot use `-w' from "
+                                             "iptables-restore");
+                       }
+
+                       wait = parse_wait_time(argc, argv);
+                       break;
+
+               case 'W':
+                       if (p->restore) {
+                               xtables_error(PARAMETER_PROBLEM,
+                                             "You cannot use `-W' from "
+                                             "iptables-restore");
+                       }
+
+                       parse_wait_interval(argc, argv, &wait_interval);
+                       wait_interval_set = true;
+                       break;
+
+               case '0':
+                       set_option(&cs->options, OPT_LINENUMBERS,
+                                  &args->invflags, invert);
+                       break;
+
+               case 'M':
+                       xtables_modprobe_program = optarg;
+                       break;
+
+               case 'c':
+                       set_option(&cs->options, OPT_COUNTERS, &args->invflags,
+                                  invert);
+                       args->pcnt = optarg;
+                       args->bcnt = strchr(args->pcnt + 1, ',');
+                       if (args->bcnt)
+                           args->bcnt++;
+                       if (!args->bcnt && xs_has_arg(argc, argv))
+                               args->bcnt = argv[optind++];
+                       if (!args->bcnt)
+                               xtables_error(PARAMETER_PROBLEM,
+                                       "-%c requires packet and byte counter",
+                                       opt2char(OPT_COUNTERS));
+
+                       if (sscanf(args->pcnt, "%llu", &args->pcnt_cnt) != 1)
+                               xtables_error(PARAMETER_PROBLEM,
+                                       "-%c packet counter not numeric",
+                                       opt2char(OPT_COUNTERS));
+
+                       if (sscanf(args->bcnt, "%llu", &args->bcnt_cnt) != 1)
+                               xtables_error(PARAMETER_PROBLEM,
+                                       "-%c byte counter not numeric",
+                                       opt2char(OPT_COUNTERS));
+                       break;
+
+               case '4':
+                       if (args->family == AF_INET)
+                               break;
+
+                       if (p->restore && args->family == AF_INET6)
+                               return;
+
+                       exit_tryhelp(2, p->line);
+
+               case '6':
+                       if (args->family == AF_INET6)
+                               break;
+
+                       if (p->restore && args->family == AF_INET)
+                               return;
+
+                       exit_tryhelp(2, p->line);
+
+               case 1: /* non option */
+                       if (optarg[0] == '!' && optarg[1] == '\0') {
+                               if (invert)
+                                       xtables_error(PARAMETER_PROBLEM,
+                                                  "multiple consecutive ! not"
+                                                  " allowed");
+                               invert = true;
+                               optarg[0] = '\0';
+                               continue;
+                       }
+                       fprintf(stderr, "Bad argument `%s'\n", optarg);
+                       exit_tryhelp(2, p->line);
+
+               default:
+                       if (command_default(cs, xt_params, invert))
+                               /* cf. ip6tables.c */
+                               continue;
+                       break;
+               }
+               invert = false;
+       }
+
+       if (strcmp(p->table, "nat") == 0 &&
+           ((p->policy != NULL && strcmp(p->policy, "DROP") == 0) ||
+           (cs->jumpto != NULL && strcmp(cs->jumpto, "DROP") == 0)))
+               xtables_error(PARAMETER_PROBLEM,
+                       "\nThe \"nat\" table is not intended for filtering, "
+                       "the use of DROP is therefore inhibited.\n\n");
+
+       if (!wait && wait_interval_set)
+               xtables_error(PARAMETER_PROBLEM,
+                             "--wait-interval only makes sense with --wait\n");
+
+       for (matchp = cs->matches; matchp; matchp = matchp->next)
+               xtables_option_mfcall(matchp->match);
+       if (cs->target != NULL)
+               xtables_option_tfcall(cs->target);
+
+       /* Fix me: must put inverse options checking here --MN */
+
+       if (optind < argc)
+               xtables_error(PARAMETER_PROBLEM,
+                          "unknown arguments found on commandline");
+       if (!p->command)
+               xtables_error(PARAMETER_PROBLEM, "no command specified");
+       if (invert)
+               xtables_error(PARAMETER_PROBLEM,
+                          "nothing appropriate following !");
+
+       if (p->ops->post_parse)
+               p->ops->post_parse(p->command, cs, args);
+
+       if (p->command == CMD_REPLACE &&
+           (args->s.naddrs != 1 || args->d.naddrs != 1))
+               xtables_error(PARAMETER_PROBLEM, "Replacement rule does not "
+                          "specify a unique address");
+
+       generic_opt_check(p->command, cs->options);
+
+       if (p->chain != NULL && strlen(p->chain) >= XT_EXTENSION_MAXNAMELEN)
+               xtables_error(PARAMETER_PROBLEM,
+                          "chain name `%s' too long (must be under %u chars)",
+                          p->chain, XT_EXTENSION_MAXNAMELEN);
+
+       if (p->command == CMD_APPEND ||
+           p->command == CMD_DELETE ||
+           p->command == CMD_DELETE_NUM ||
+           p->command == CMD_CHECK ||
+           p->command == CMD_INSERT ||
+           p->command == CMD_REPLACE) {
+               if (strcmp(p->chain, "PREROUTING") == 0
+                   || strcmp(p->chain, "INPUT") == 0) {
+                       /* -o not valid with incoming packets. */
+                       if (cs->options & OPT_VIANAMEOUT)
+                               xtables_error(PARAMETER_PROBLEM,
+                                          "Can't use -%c with %s\n",
+                                          opt2char(OPT_VIANAMEOUT),
+                                          p->chain);
+               }
+
+               if (strcmp(p->chain, "POSTROUTING") == 0
+                   || strcmp(p->chain, "OUTPUT") == 0) {
+                       /* -i not valid with outgoing packets */
+                       if (cs->options & OPT_VIANAMEIN)
+                               xtables_error(PARAMETER_PROBLEM,
+                                          "Can't use -%c with %s\n",
+                                          opt2char(OPT_VIANAMEIN),
+                                          p->chain);
+               }
+       }
+}
index 34730be6ce004a79cf2832b73e79ba0ffeabb749..13ea05fef87e0863c739286b14808b958ab58050 100644 (file)
@@ -311,9 +311,14 @@ struct xt_cmd_parse {
        const char                      *newname;
        const char                      *policy;
        bool                            restore;
+       int                             line;
        int                             verbose;
        bool                            xlate;
        struct xt_cmd_parse_ops         *ops;
 };
 
+void do_parse(int argc, char *argv[],
+             struct xt_cmd_parse *p, struct iptables_command_state *cs,
+             struct xtables_args *args);
+
 #endif /* IPTABLES_XSHARED_H */
index c287d3bdc75e0999a4df29b2717acce00f2e9453..6a1cdac14a7da11f9044262bf4c6d99583c7be97 100644 (file)
@@ -251,6 +251,7 @@ static int do_command_xlate(struct nft_handle *h, int argc, char *argv[],
        struct xt_cmd_parse p = {
                .table          = *table,
                .restore        = restore,
+               .line           = line,
                .xlate          = true,
                .ops            = &h->ops->cmd_parse,
        };
index 59fc63d0fee865e1f32db3e64488b0528d7123ef..051d5c7b7f98be18d361861c13ef55d54525d182 100644 (file)
@@ -95,10 +95,6 @@ struct xtables_globals xtables_globals = {
        .print_help = xtables_printhelp,
 };
 
-#define opts xt_params->opts
-#define prog_name xt_params->program_name
-#define prog_vers xt_params->program_version
-
 /*
  *     All functions starting with "parse" should succeed, otherwise
  *     the program fails.
@@ -145,557 +141,6 @@ list_rules(struct nft_handle *h, const char *chain, const char *table,
        return nft_cmd_rule_list_save(h, chain, table, rulenum, counters);
 }
 
-static void check_empty_interface(struct xtables_args *args, const char *arg)
-{
-       const char *msg = "Empty interface is likely to be undesired";
-
-       if (*arg != '\0')
-               return;
-
-       if (args->family != NFPROTO_ARP)
-               xtables_error(PARAMETER_PROBLEM, msg);
-
-       fprintf(stderr, "%s", msg);
-}
-
-static void check_inverse(struct xtables_args *args, const char option[],
-                         bool *invert, int *optidx, int argc)
-{
-       switch (args->family) {
-       case NFPROTO_ARP:
-               break;
-       default:
-               return;
-       }
-
-       if (!option || strcmp(option, "!"))
-               return;
-
-       fprintf(stderr, "Using intrapositioned negation (`--option ! this`) "
-               "is deprecated in favor of extrapositioned (`! --option this`).\n");
-
-       if (*invert)
-               xtables_error(PARAMETER_PROBLEM,
-                             "Multiple `!' flags not allowed");
-       *invert = true;
-       if (optidx) {
-               *optidx = *optidx + 1;
-               if (argc && *optidx > argc)
-                       xtables_error(PARAMETER_PROBLEM,
-                                     "no argument following `!'");
-       }
-}
-
-void do_parse(int argc, char *argv[],
-             struct xt_cmd_parse *p, struct iptables_command_state *cs,
-             struct xtables_args *args)
-{
-       struct xtables_match *m;
-       struct xtables_rule_match *matchp;
-       bool wait_interval_set = false;
-       struct timeval wait_interval;
-       struct xtables_target *t;
-       bool table_set = false;
-       bool invert = false;
-       int wait = 0;
-
-       /* re-set optind to 0 in case do_command4 gets called
-        * a second time */
-       optind = 0;
-
-       /* clear mflags in case do_command4 gets called a second time
-        * (we clear the global list of all matches for security)*/
-       for (m = xtables_matches; m; m = m->next)
-               m->mflags = 0;
-
-       for (t = xtables_targets; t; t = t->next) {
-               t->tflags = 0;
-               t->used = 0;
-       }
-
-       /* Suppress error messages: we may add new options if we
-          demand-load a protocol. */
-       opterr = 0;
-
-       opts = xt_params->orig_opts;
-       while ((cs->c = getopt_long(argc, argv, xt_params->optstring,
-                                          opts, NULL)) != -1) {
-               switch (cs->c) {
-                       /*
-                        * Command selection
-                        */
-               case 'A':
-                       add_command(&p->command, CMD_APPEND, CMD_NONE, invert);
-                       p->chain = optarg;
-                       break;
-
-               case 'C':
-                       add_command(&p->command, CMD_CHECK, CMD_NONE, invert);
-                       p->chain = optarg;
-                       break;
-
-               case 'D':
-                       add_command(&p->command, CMD_DELETE, CMD_NONE, invert);
-                       p->chain = optarg;
-                       if (xs_has_arg(argc, argv)) {
-                               p->rulenum = parse_rulenumber(argv[optind++]);
-                               p->command = CMD_DELETE_NUM;
-                       }
-                       break;
-
-               case 'R':
-                       add_command(&p->command, CMD_REPLACE, CMD_NONE, invert);
-                       p->chain = optarg;
-                       if (xs_has_arg(argc, argv))
-                               p->rulenum = parse_rulenumber(argv[optind++]);
-                       else
-                               xtables_error(PARAMETER_PROBLEM,
-                                          "-%c requires a rule number",
-                                          cmd2char(CMD_REPLACE));
-                       break;
-
-               case 'I':
-                       add_command(&p->command, CMD_INSERT, CMD_NONE, invert);
-                       p->chain = optarg;
-                       if (xs_has_arg(argc, argv))
-                               p->rulenum = parse_rulenumber(argv[optind++]);
-                       else
-                               p->rulenum = 1;
-                       break;
-
-               case 'L':
-                       add_command(&p->command, CMD_LIST,
-                                   CMD_ZERO | CMD_ZERO_NUM, invert);
-                       if (optarg)
-                               p->chain = optarg;
-                       else if (xs_has_arg(argc, argv))
-                               p->chain = argv[optind++];
-                       if (xs_has_arg(argc, argv))
-                               p->rulenum = parse_rulenumber(argv[optind++]);
-                       break;
-
-               case 'S':
-                       add_command(&p->command, CMD_LIST_RULES,
-                                   CMD_ZERO|CMD_ZERO_NUM, invert);
-                       if (optarg)
-                               p->chain = optarg;
-                       else if (xs_has_arg(argc, argv))
-                               p->chain = argv[optind++];
-                       if (xs_has_arg(argc, argv))
-                               p->rulenum = parse_rulenumber(argv[optind++]);
-                       break;
-
-               case 'F':
-                       add_command(&p->command, CMD_FLUSH, CMD_NONE, invert);
-                       if (optarg)
-                               p->chain = optarg;
-                       else if (xs_has_arg(argc, argv))
-                               p->chain = argv[optind++];
-                       break;
-
-               case 'Z':
-                       add_command(&p->command, CMD_ZERO,
-                                   CMD_LIST|CMD_LIST_RULES, invert);
-                       if (optarg)
-                               p->chain = optarg;
-                       else if (xs_has_arg(argc, argv))
-                               p->chain = argv[optind++];
-                       if (xs_has_arg(argc, argv)) {
-                               p->rulenum = parse_rulenumber(argv[optind++]);
-                               p->command = CMD_ZERO_NUM;
-                       }
-                       break;
-
-               case 'N':
-                       parse_chain(optarg);
-                       add_command(&p->command, CMD_NEW_CHAIN, CMD_NONE,
-                                   invert);
-                       p->chain = optarg;
-                       break;
-
-               case 'X':
-                       add_command(&p->command, CMD_DELETE_CHAIN, CMD_NONE,
-                                   invert);
-                       if (optarg)
-                               p->chain = optarg;
-                       else if (xs_has_arg(argc, argv))
-                               p->chain = argv[optind++];
-                       break;
-
-               case 'E':
-                       add_command(&p->command, CMD_RENAME_CHAIN, CMD_NONE,
-                                   invert);
-                       p->chain = optarg;
-                       if (xs_has_arg(argc, argv))
-                               p->newname = argv[optind++];
-                       else
-                               xtables_error(PARAMETER_PROBLEM,
-                                          "-%c requires old-chain-name and "
-                                          "new-chain-name",
-                                           cmd2char(CMD_RENAME_CHAIN));
-                       break;
-
-               case 'P':
-                       add_command(&p->command, CMD_SET_POLICY, CMD_NONE,
-                                   invert);
-                       p->chain = optarg;
-                       if (xs_has_arg(argc, argv))
-                               p->policy = argv[optind++];
-                       else
-                               xtables_error(PARAMETER_PROBLEM,
-                                          "-%c requires a chain and a policy",
-                                          cmd2char(CMD_SET_POLICY));
-                       break;
-
-               case 'h':
-                       if (!optarg)
-                               optarg = argv[optind];
-
-                       /* iptables -p icmp -h */
-                       if (!cs->matches && cs->protocol)
-                               xtables_find_match(cs->protocol,
-                                       XTF_TRY_LOAD, &cs->matches);
-
-                       xt_params->print_help(cs->matches);
-                       p->command = CMD_NONE;
-                       return;
-
-                       /*
-                        * Option selection
-                        */
-               case 'p':
-                       check_inverse(args, optarg, &invert, &optind, argc);
-                       set_option(&cs->options, OPT_PROTOCOL,
-                                  &args->invflags, invert);
-
-                       /* Canonicalize into lower case */
-                       for (cs->protocol = argv[optind - 1];
-                            *cs->protocol; cs->protocol++)
-                               *cs->protocol = tolower(*cs->protocol);
-
-                       cs->protocol = argv[optind - 1];
-                       args->proto = xtables_parse_protocol(cs->protocol);
-
-                       if (args->proto == 0 &&
-                           (args->invflags & XT_INV_PROTO))
-                               xtables_error(PARAMETER_PROBLEM,
-                                          "rule would never match protocol");
-
-                       /* This needs to happen here to parse extensions */
-                       if (p->ops->proto_parse)
-                               p->ops->proto_parse(cs, args);
-                       break;
-
-               case 's':
-                       check_inverse(args, optarg, &invert, &optind, argc);
-                       set_option(&cs->options, OPT_SOURCE,
-                                  &args->invflags, invert);
-                       args->shostnetworkmask = argv[optind - 1];
-                       break;
-
-               case 'd':
-                       check_inverse(args, optarg, &invert, &optind, argc);
-                       set_option(&cs->options, OPT_DESTINATION,
-                                  &args->invflags, invert);
-                       args->dhostnetworkmask = argv[optind - 1];
-                       break;
-
-#ifdef IPT_F_GOTO
-               case 'g':
-                       set_option(&cs->options, OPT_JUMP, &args->invflags,
-                                  invert);
-                       args->goto_set = true;
-                       cs->jumpto = xt_parse_target(optarg);
-                       break;
-#endif
-
-               case 2:/* src-mac */
-                       check_inverse(args, optarg, &invert, &optind, argc);
-                       set_option(&cs->options, OPT_S_MAC, &args->invflags,
-                                  invert);
-                       args->src_mac = argv[optind - 1];
-                       break;
-
-               case 3:/* dst-mac */
-                       check_inverse(args, optarg, &invert, &optind, argc);
-                       set_option(&cs->options, OPT_D_MAC, &args->invflags,
-                                  invert);
-                       args->dst_mac = argv[optind - 1];
-                       break;
-
-               case 'l':/* hardware length */
-                       check_inverse(args, optarg, &invert, &optind, argc);
-                       set_option(&cs->options, OPT_H_LENGTH, &args->invflags,
-                                  invert);
-                       args->arp_hlen = argv[optind - 1];
-                       break;
-
-               case 8: /* was never supported, not even in arptables-legacy */
-                       xtables_error(PARAMETER_PROBLEM, "not supported");
-               case 4:/* opcode */
-                       check_inverse(args, optarg, &invert, &optind, argc);
-                       set_option(&cs->options, OPT_OPCODE, &args->invflags,
-                                  invert);
-                       args->arp_opcode = argv[optind - 1];
-                       break;
-
-               case 5:/* h-type */
-                       check_inverse(args, optarg, &invert, &optind, argc);
-                       set_option(&cs->options, OPT_H_TYPE, &args->invflags,
-                                  invert);
-                       args->arp_htype = argv[optind - 1];
-                       break;
-
-               case 6:/* proto-type */
-                       check_inverse(args, optarg, &invert, &optind, argc);
-                       set_option(&cs->options, OPT_P_TYPE, &args->invflags,
-                                  invert);
-                       args->arp_ptype = argv[optind - 1];
-                       break;
-
-               case 'j':
-                       set_option(&cs->options, OPT_JUMP, &args->invflags,
-                                  invert);
-                       command_jump(cs, argv[optind - 1]);
-                       break;
-
-               case 'i':
-                       check_empty_interface(args, optarg);
-                       check_inverse(args, optarg, &invert, &optind, argc);
-                       set_option(&cs->options, OPT_VIANAMEIN,
-                                  &args->invflags, invert);
-                       xtables_parse_interface(argv[optind - 1],
-                                               args->iniface,
-                                               args->iniface_mask);
-                       break;
-
-               case 'o':
-                       check_empty_interface(args, optarg);
-                       check_inverse(args, optarg, &invert, &optind, argc);
-                       set_option(&cs->options, OPT_VIANAMEOUT,
-                                  &args->invflags, invert);
-                       xtables_parse_interface(argv[optind - 1],
-                                               args->outiface,
-                                               args->outiface_mask);
-                       break;
-
-               case 'f':
-                       if (args->family == AF_INET6) {
-                               xtables_error(PARAMETER_PROBLEM,
-                                       "`-f' is not supported in IPv6, "
-                                       "use -m frag instead");
-                       }
-                       set_option(&cs->options, OPT_FRAGMENT, &args->invflags,
-                                  invert);
-                       args->flags |= IPT_F_FRAG;
-                       break;
-
-               case 'v':
-                       if (!p->verbose)
-                               set_option(&cs->options, OPT_VERBOSE,
-                                          &args->invflags, invert);
-                       p->verbose++;
-                       break;
-
-               case 'm':
-                       command_match(cs, invert);
-                       break;
-
-               case 'n':
-                       set_option(&cs->options, OPT_NUMERIC, &args->invflags,
-                                  invert);
-                       break;
-
-               case 't':
-                       if (invert)
-                               xtables_error(PARAMETER_PROBLEM,
-                                          "unexpected ! flag before --table");
-                       if (p->restore && table_set)
-                               xtables_error(PARAMETER_PROBLEM,
-                                             "The -t option cannot be used in %s.\n",
-                                             xt_params->program_name);
-                       p->table = optarg;
-                       table_set = true;
-                       break;
-
-               case 'x':
-                       set_option(&cs->options, OPT_EXPANDED, &args->invflags,
-                                  invert);
-                       break;
-
-               case 'V':
-                       if (invert)
-                               printf("Not %s ;-)\n", prog_vers);
-                       else
-                               printf("%s v%s\n",
-                                      prog_name, prog_vers);
-                       exit(0);
-
-               case 'w':
-                       if (p->restore) {
-                               xtables_error(PARAMETER_PROBLEM,
-                                             "You cannot use `-w' from "
-                                             "iptables-restore");
-                       }
-
-                       wait = parse_wait_time(argc, argv);
-                       break;
-
-               case 'W':
-                       if (p->restore) {
-                               xtables_error(PARAMETER_PROBLEM,
-                                             "You cannot use `-W' from "
-                                             "iptables-restore");
-                       }
-
-                       parse_wait_interval(argc, argv, &wait_interval);
-                       wait_interval_set = true;
-                       break;
-
-               case '0':
-                       set_option(&cs->options, OPT_LINENUMBERS,
-                                  &args->invflags, invert);
-                       break;
-
-               case 'M':
-                       xtables_modprobe_program = optarg;
-                       break;
-
-               case 'c':
-                       set_option(&cs->options, OPT_COUNTERS, &args->invflags,
-                                  invert);
-                       args->pcnt = optarg;
-                       args->bcnt = strchr(args->pcnt + 1, ',');
-                       if (args->bcnt)
-                           args->bcnt++;
-                       if (!args->bcnt && xs_has_arg(argc, argv))
-                               args->bcnt = argv[optind++];
-                       if (!args->bcnt)
-                               xtables_error(PARAMETER_PROBLEM,
-                                       "-%c requires packet and byte counter",
-                                       opt2char(OPT_COUNTERS));
-
-                       if (sscanf(args->pcnt, "%llu", &args->pcnt_cnt) != 1)
-                               xtables_error(PARAMETER_PROBLEM,
-                                       "-%c packet counter not numeric",
-                                       opt2char(OPT_COUNTERS));
-
-                       if (sscanf(args->bcnt, "%llu", &args->bcnt_cnt) != 1)
-                               xtables_error(PARAMETER_PROBLEM,
-                                       "-%c byte counter not numeric",
-                                       opt2char(OPT_COUNTERS));
-                       break;
-
-               case '4':
-                       if (args->family == AF_INET)
-                               break;
-
-                       if (p->restore && args->family == AF_INET6)
-                               return;
-
-                       exit_tryhelp(2, line);
-
-               case '6':
-                       if (args->family == AF_INET6)
-                               break;
-
-                       if (p->restore && args->family == AF_INET)
-                               return;
-
-                       exit_tryhelp(2, line);
-
-               case 1: /* non option */
-                       if (optarg[0] == '!' && optarg[1] == '\0') {
-                               if (invert)
-                                       xtables_error(PARAMETER_PROBLEM,
-                                                  "multiple consecutive ! not"
-                                                  " allowed");
-                               invert = true;
-                               optarg[0] = '\0';
-                               continue;
-                       }
-                       fprintf(stderr, "Bad argument `%s'\n", optarg);
-                       exit_tryhelp(2, line);
-
-               default:
-                       if (command_default(cs, xt_params, invert))
-                               /* cf. ip6tables.c */
-                               continue;
-                       break;
-               }
-               invert = false;
-       }
-
-       if (strcmp(p->table, "nat") == 0 &&
-           ((p->policy != NULL && strcmp(p->policy, "DROP") == 0) ||
-           (cs->jumpto != NULL && strcmp(cs->jumpto, "DROP") == 0)))
-               xtables_error(PARAMETER_PROBLEM,
-                       "\nThe \"nat\" table is not intended for filtering, "
-                       "the use of DROP is therefore inhibited.\n\n");
-
-       if (!wait && wait_interval_set)
-               xtables_error(PARAMETER_PROBLEM,
-                             "--wait-interval only makes sense with --wait\n");
-
-       for (matchp = cs->matches; matchp; matchp = matchp->next)
-               xtables_option_mfcall(matchp->match);
-       if (cs->target != NULL)
-               xtables_option_tfcall(cs->target);
-
-       /* Fix me: must put inverse options checking here --MN */
-
-       if (optind < argc)
-               xtables_error(PARAMETER_PROBLEM,
-                          "unknown arguments found on commandline");
-       if (!p->command)
-               xtables_error(PARAMETER_PROBLEM, "no command specified");
-       if (invert)
-               xtables_error(PARAMETER_PROBLEM,
-                          "nothing appropriate following !");
-
-       if (p->ops->post_parse)
-               p->ops->post_parse(p->command, cs, args);
-
-       if (p->command == CMD_REPLACE &&
-           (args->s.naddrs != 1 || args->d.naddrs != 1))
-               xtables_error(PARAMETER_PROBLEM, "Replacement rule does not "
-                          "specify a unique address");
-
-       generic_opt_check(p->command, cs->options);
-
-       if (p->chain != NULL && strlen(p->chain) >= XT_EXTENSION_MAXNAMELEN)
-               xtables_error(PARAMETER_PROBLEM,
-                          "chain name `%s' too long (must be under %u chars)",
-                          p->chain, XT_EXTENSION_MAXNAMELEN);
-
-       if (p->command == CMD_APPEND ||
-           p->command == CMD_DELETE ||
-           p->command == CMD_DELETE_NUM ||
-           p->command == CMD_CHECK ||
-           p->command == CMD_INSERT ||
-           p->command == CMD_REPLACE) {
-               if (strcmp(p->chain, "PREROUTING") == 0
-                   || strcmp(p->chain, "INPUT") == 0) {
-                       /* -o not valid with incoming packets. */
-                       if (cs->options & OPT_VIANAMEOUT)
-                               xtables_error(PARAMETER_PROBLEM,
-                                          "Can't use -%c with %s\n",
-                                          opt2char(OPT_VIANAMEOUT),
-                                          p->chain);
-               }
-
-               if (strcmp(p->chain, "POSTROUTING") == 0
-                   || strcmp(p->chain, "OUTPUT") == 0) {
-                       /* -i not valid with outgoing packets */
-                       if (cs->options & OPT_VIANAMEIN)
-                               xtables_error(PARAMETER_PROBLEM,
-                                          "Can't use -%c with %s\n",
-                                          opt2char(OPT_VIANAMEIN),
-                                          p->chain);
-               }
-       }
-}
-
 int do_commandx(struct nft_handle *h, int argc, char *argv[], char **table,
                bool restore)
 {
@@ -703,6 +148,7 @@ int do_commandx(struct nft_handle *h, int argc, char *argv[], char **table,
        struct xt_cmd_parse p = {
                .table          = *table,
                .restore        = restore,
+               .line           = line,
                .ops            = &h->ops->cmd_parse,
        };
        struct iptables_command_state cs = {