static int parse(int c, char **argv, int invert, unsigned int *flags, const struct ipt_entry *entry, unsigned int *nfcache, struct ipt_entry_match **match) { struct ipt_policy_info *info = (void *)(*match)->data; struct ipt_policy_elem *e = &info->pol[info->len]; struct in_addr *addr = NULL, mask; unsigned int naddr = 0; int mode; check_inverse(optarg, &invert, &optind, 0); switch (c) { case '1': if (info->flags & (IPT_POLICY_MATCH_IN|IPT_POLICY_MATCH_OUT)) exit_error(PARAMETER_PROBLEM, "policy match: double --dir option"); if (invert) exit_error(PARAMETER_PROBLEM, "policy match: can't invert --dir option"); info->flags |= parse_direction(argv[optind-1]); break; case '2': if (invert) exit_error(PARAMETER_PROBLEM, "policy match: can't invert --policy option"); info->flags |= parse_policy(argv[optind-1]); break; case '3': if (info->flags & IPT_POLICY_MATCH_STRICT) exit_error(PARAMETER_PROBLEM, "policy match: double --strict option"); if (invert) exit_error(PARAMETER_PROBLEM, "policy match: can't invert --strict option"); info->flags |= IPT_POLICY_MATCH_STRICT; break; case '4': if (e->match.reqid) exit_error(PARAMETER_PROBLEM, "policy match: double --reqid option"); e->match.reqid = 1; e->invert.reqid = invert; e->reqid = strtol(argv[optind-1], NULL, 10); break; case '5': if (e->match.spi) exit_error(PARAMETER_PROBLEM, "policy match: double --spi option"); e->match.spi = 1; e->invert.spi = invert; e->spi = strtol(argv[optind-1], NULL, 0x10); break; case '6': if (e->match.saddr) exit_error(PARAMETER_PROBLEM, "policy match: double --tunnel-src option"); parse_hostnetworkmask(argv[optind-1], &addr, &mask, &naddr); if (naddr > 1) exit_error(PARAMETER_PROBLEM, "policy match: name resolves to multiple IPs"); e->match.saddr = 1; e->invert.saddr = invert; e->saddr.a4 = addr[0]; e->smask.a4 = mask; break; case '7': if (e->match.daddr) exit_error(PARAMETER_PROBLEM, "policy match: double --tunnel-dst option"); parse_hostnetworkmask(argv[optind-1], &addr, &mask, &naddr); if (naddr > 1) exit_error(PARAMETER_PROBLEM, "policy match: name resolves to multiple IPs"); e->match.daddr = 1; e->invert.daddr = invert; e->daddr.a4 = addr[0]; e->dmask.a4 = mask; break; case '8': if (e->match.proto) exit_error(PARAMETER_PROBLEM, "policy match: double --proto option"); e->proto = parse_protocol(argv[optind-1]); if (e->proto != IPPROTO_AH && e->proto != IPPROTO_ESP && e->proto != IPPROTO_COMP) exit_error(PARAMETER_PROBLEM, "policy match: protocol must ah/esp/ipcomp"); e->match.proto = 1; e->invert.proto = invert; break; case '9': if (e->match.mode) exit_error(PARAMETER_PROBLEM, "policy match: double --mode option"); mode = parse_mode(argv[optind-1]); e->match.mode = 1; e->invert.mode = invert; e->mode = mode; break; case 'a': if (invert) exit_error(PARAMETER_PROBLEM, "policy match: can't invert --next option"); if (++info->len == IPT_POLICY_MAX_ELEM) exit_error(PARAMETER_PROBLEM, "policy match: maximum policy depth reached"); break; default: return 0; } policy_info = info; return 1; }
/* Function which parses command options; returns true if it ate an option */ static int parse(int c, char **argv, int invert, unsigned int *flags, const struct ipt_entry *entry, unsigned int *nfcache, struct ipt_entry_match **match) { struct ipt_conntrack_info *sinfo = (struct ipt_conntrack_info *)(*match)->data; char *protocol = NULL; unsigned int naddrs = 0; struct in_addr *addrs = NULL; switch (c) { case '1': check_inverse(optarg, &invert, &optind, 0); parse_states(argv[optind-1], sinfo); if (invert) { sinfo->invflags |= IPT_CONNTRACK_STATE; } sinfo->flags |= IPT_CONNTRACK_STATE; break; case '2': check_inverse(optarg, &invert, &optind, 0); if(invert) sinfo->invflags |= IPT_CONNTRACK_PROTO; /* Canonicalize into lower case */ for (protocol = argv[optind-1]; *protocol; protocol++) *protocol = tolower(*protocol); protocol = argv[optind-1]; sinfo->tuple[IP_CT_DIR_ORIGINAL].dst.protonum = parse_protocol(protocol); if (sinfo->tuple[IP_CT_DIR_ORIGINAL].dst.protonum == 0 && (sinfo->invflags & IPT_INV_PROTO)) exit_error(PARAMETER_PROBLEM, "rule would never match protocol"); sinfo->flags |= IPT_CONNTRACK_PROTO; break; case '3': check_inverse(optarg, &invert, &optind, 9); if (invert) sinfo->invflags |= IPT_CONNTRACK_ORIGSRC; parse_hostnetworkmask(argv[optind-1], &addrs, &sinfo->sipmsk[IP_CT_DIR_ORIGINAL], &naddrs); if(naddrs > 1) exit_error(PARAMETER_PROBLEM, "multiple IP addresses not allowed"); if(naddrs == 1) { sinfo->tuple[IP_CT_DIR_ORIGINAL].src.ip = addrs[0].s_addr; } sinfo->flags |= IPT_CONNTRACK_ORIGSRC; break; case '4': check_inverse(optarg, &invert, &optind, 0); if (invert) sinfo->invflags |= IPT_CONNTRACK_ORIGDST; parse_hostnetworkmask(argv[optind-1], &addrs, &sinfo->dipmsk[IP_CT_DIR_ORIGINAL], &naddrs); if(naddrs > 1) exit_error(PARAMETER_PROBLEM, "multiple IP addresses not allowed"); if(naddrs == 1) { sinfo->tuple[IP_CT_DIR_ORIGINAL].dst.ip = addrs[0].s_addr; } sinfo->flags |= IPT_CONNTRACK_ORIGDST; break; case '5': check_inverse(optarg, &invert, &optind, 0); if (invert) sinfo->invflags |= IPT_CONNTRACK_REPLSRC; parse_hostnetworkmask(argv[optind-1], &addrs, &sinfo->sipmsk[IP_CT_DIR_REPLY], &naddrs); if(naddrs > 1) exit_error(PARAMETER_PROBLEM, "multiple IP addresses not allowed"); if(naddrs == 1) { sinfo->tuple[IP_CT_DIR_REPLY].src.ip = addrs[0].s_addr; } sinfo->flags |= IPT_CONNTRACK_REPLSRC; break; case '6': check_inverse(optarg, &invert, &optind, 0); if (invert) sinfo->invflags |= IPT_CONNTRACK_REPLDST; parse_hostnetworkmask(argv[optind-1], &addrs, &sinfo->dipmsk[IP_CT_DIR_REPLY], &naddrs); if(naddrs > 1) exit_error(PARAMETER_PROBLEM, "multiple IP addresses not allowed"); if(naddrs == 1) { sinfo->tuple[IP_CT_DIR_REPLY].dst.ip = addrs[0].s_addr; } sinfo->flags |= IPT_CONNTRACK_REPLDST; break; case '7': check_inverse(optarg, &invert, &optind, 0); parse_statuses(argv[optind-1], sinfo); if (invert) { sinfo->invflags |= IPT_CONNTRACK_STATUS; } sinfo->flags |= IPT_CONNTRACK_STATUS; break; case '8': check_inverse(optarg, &invert, &optind, 0); parse_expires(argv[optind-1], sinfo); if (invert) { sinfo->invflags |= IPT_CONNTRACK_EXPIRES; } sinfo->flags |= IPT_CONNTRACK_EXPIRES; break; default: return 0; } *flags = sinfo->flags; return 1; }
int do_commandarp(struct nft_handle *h, int argc, char *argv[], char **table) { struct arptables_command_state cs; int invert = 0; unsigned int nsaddrs = 0, ndaddrs = 0; struct in_addr *saddrs = NULL, *daddrs = NULL; int c, verbose = 0; const char *chain = NULL; const char *shostnetworkmask = NULL, *dhostnetworkmask = NULL; const char *policy = NULL, *newname = NULL; unsigned int rulenum = 0, options = 0, command = 0; const char *pcnt = NULL, *bcnt = NULL; int ret = 1; struct xtables_target *t; memset(&cs, 0, sizeof(cs)); cs.jumpto = ""; opts = original_opts; global_option_offset = 0; xtables_globals.orig_opts = original_opts; /* re-set optind to 0 in case do_command gets called * a second time */ optind = 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; while ((c = getopt_long(argc, argv, "-A:D:R:I:L::M:F::Z::N:X::E:P:Vh::o:p:s:d:j:l:i:vnt:m:c:", opts, NULL)) != -1) { switch (c) { /* * Command selection */ case 'A': add_command(&command, CMD_APPEND, CMD_NONE, invert); chain = optarg; break; case 'D': add_command(&command, CMD_DELETE, CMD_NONE, invert); chain = optarg; if (optind < argc && argv[optind][0] != '-' && argv[optind][0] != '!') { rulenum = parse_rulenumber(argv[optind++]); command = CMD_DELETE_NUM; } break; case 'R': add_command(&command, CMD_REPLACE, CMD_NONE, invert); chain = optarg; if (optind < argc && argv[optind][0] != '-' && argv[optind][0] != '!') rulenum = parse_rulenumber(argv[optind++]); else xtables_error(PARAMETER_PROBLEM, "-%c requires a rule number", cmd2char(CMD_REPLACE)); break; case 'I': add_command(&command, CMD_INSERT, CMD_NONE, invert); chain = optarg; if (optind < argc && argv[optind][0] != '-' && argv[optind][0] != '!') rulenum = parse_rulenumber(argv[optind++]); else rulenum = 1; break; case 'L': add_command(&command, CMD_LIST, CMD_ZERO, invert); if (optarg) chain = optarg; else if (optind < argc && argv[optind][0] != '-' && argv[optind][0] != '!') chain = argv[optind++]; break; case 'F': add_command(&command, CMD_FLUSH, CMD_NONE, invert); if (optarg) chain = optarg; else if (optind < argc && argv[optind][0] != '-' && argv[optind][0] != '!') chain = argv[optind++]; break; case 'Z': add_command(&command, CMD_ZERO, CMD_LIST, invert); if (optarg) chain = optarg; else if (optind < argc && argv[optind][0] != '-' && argv[optind][0] != '!') chain = argv[optind++]; break; case 'N': if (optarg && *optarg == '-') xtables_error(PARAMETER_PROBLEM, "chain name not allowed to start " "with `-'\n"); if (xtables_find_target(optarg, XTF_TRY_LOAD)) xtables_error(PARAMETER_PROBLEM, "chain name may not clash " "with target name\n"); add_command(&command, CMD_NEW_CHAIN, CMD_NONE, invert); chain = optarg; break; case 'X': add_command(&command, CMD_DELETE_CHAIN, CMD_NONE, invert); if (optarg) chain = optarg; else if (optind < argc && argv[optind][0] != '-' && argv[optind][0] != '!') chain = argv[optind++]; break; case 'E': add_command(&command, CMD_RENAME_CHAIN, CMD_NONE, invert); chain = optarg; if (optind < argc && argv[optind][0] != '-' && argv[optind][0] != '!') 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(&command, CMD_SET_POLICY, CMD_NONE, invert); chain = optarg; if (optind < argc && argv[optind][0] != '-' && argv[optind][0] != '!') 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]; exit_printhelp(); break; case 's': check_inverse(optarg, &invert, &optind, argc); set_option(&options, OPT_S_IP, &cs.fw.arp.invflags, invert); shostnetworkmask = argv[optind-1]; break; case 'd': check_inverse(optarg, &invert, &optind, argc); set_option(&options, OPT_D_IP, &cs.fw.arp.invflags, invert); dhostnetworkmask = argv[optind-1]; break; case 2:/* src-mac */ check_inverse(optarg, &invert, &optind, argc); set_option(&options, OPT_S_MAC, &cs.fw.arp.invflags, invert); if (getmac_and_mask(argv[optind - 1], cs.fw.arp.src_devaddr.addr, cs.fw.arp.src_devaddr.mask)) xtables_error(PARAMETER_PROBLEM, "Problem with specified " "source mac"); break; case 3:/* dst-mac */ check_inverse(optarg, &invert, &optind, argc); set_option(&options, OPT_D_MAC, &cs.fw.arp.invflags, invert); if (getmac_and_mask(argv[optind - 1], cs.fw.arp.tgt_devaddr.addr, cs.fw.arp.tgt_devaddr.mask)) xtables_error(PARAMETER_PROBLEM, "Problem with specified " "destination mac"); break; case 'l':/* hardware length */ check_inverse(optarg, &invert, &optind, argc); set_option(&options, OPT_H_LENGTH, &cs.fw.arp.invflags, invert); getlength_and_mask(argv[optind - 1], &cs.fw.arp.arhln, &cs.fw.arp.arhln_mask); if (cs.fw.arp.arhln != 6) { xtables_error(PARAMETER_PROBLEM, "Only harware address length of" " 6 is supported currently."); } break; case 8:/* protocol length */ xtables_error(PARAMETER_PROBLEM, "not supported"); /* check_inverse(optarg, &invert, &optind, argc); set_option(&options, OPT_P_LENGTH, &cs.fw.arp.invflags, invert); getlength_and_mask(argv[optind - 1], &cs.fw.arp.arpln, &cs.fw.arp.arpln_mask); break; */ case 4:/* opcode */ check_inverse(optarg, &invert, &optind, argc); set_option(&options, OPT_OPCODE, &cs.fw.arp.invflags, invert); if (get16_and_mask(argv[optind - 1], &cs.fw.arp.arpop, &cs.fw.arp.arpop_mask, 10)) { int i; for (i = 0; i < NUMOPCODES; i++) if (!strcasecmp(opcodes[i], optarg)) break; if (i == NUMOPCODES) xtables_error(PARAMETER_PROBLEM, "Problem with specified opcode"); cs.fw.arp.arpop = htons(i+1); } break; case 5:/* h-type */ check_inverse(optarg, &invert, &optind, argc); set_option(&options, OPT_H_TYPE, &cs.fw.arp.invflags, invert); if (get16_and_mask(argv[optind - 1], &cs.fw.arp.arhrd, &cs.fw.arp.arhrd_mask, 16)) { if (strcasecmp(argv[optind-1], "Ethernet")) xtables_error(PARAMETER_PROBLEM, "Problem with specified hardware type"); cs.fw.arp.arhrd = htons(1); } break; case 6:/* proto-type */ check_inverse(optarg, &invert, &optind, argc); set_option(&options, OPT_P_TYPE, &cs.fw.arp.invflags, invert); if (get16_and_mask(argv[optind - 1], &cs.fw.arp.arpro, &cs.fw.arp.arpro_mask, 0)) { if (strcasecmp(argv[optind-1], "ipv4")) xtables_error(PARAMETER_PROBLEM, "Problem with specified protocol type"); cs.fw.arp.arpro = htons(0x800); } break; case 'j': set_option(&options, OPT_JUMP, &cs.fw.arp.invflags, invert); cs.jumpto = parse_target(optarg); cs.target = command_jump(&cs.fw, cs.jumpto); break; case 'i': check_inverse(optarg, &invert, &optind, argc); set_option(&options, OPT_VIANAMEIN, &cs.fw.arp.invflags, invert); parse_interface(argv[optind-1], cs.fw.arp.iniface, cs.fw.arp.iniface_mask); /* cs.fw.nfcache |= NFC_IP_IF_IN; */ break; case 'o': check_inverse(optarg, &invert, &optind, argc); set_option(&options, OPT_VIANAMEOUT, &cs.fw.arp.invflags, invert); parse_interface(argv[optind-1], cs.fw.arp.outiface, cs.fw.arp.outiface_mask); /* cs.fw.nfcache |= NFC_IP_IF_OUT; */ break; case 'v': if (!verbose) set_option(&options, OPT_VERBOSE, &cs.fw.arp.invflags, invert); verbose++; break; case 'm': /*{ size_t size; if (invert) exit_error(PARAMETER_PROBLEM, "unexpected ! flag before --match"); m = find_match(optarg, LOAD_MUST_SUCCEED); size = ARPT_ALIGN(sizeof(struct arpt_entry_match)) + m->size; m->m = fw_calloc(1, size); m->m->u.match_size = size; strcpy(m->m->u.user.name, m->name); m->init(m->m, &fw.nfcache); opts = merge_options(opts, m->extra_opts, &m->option_offset); }*/ break; case 'n': set_option(&options, OPT_NUMERIC, &cs.fw.arp.invflags, invert); break; case 't': if (invert) xtables_error(PARAMETER_PROBLEM, "unexpected ! flag before --table"); *table = argv[optind-1]; break; case 'V': if (invert) printf("Not %s ;-)\n", program_version); else printf("%s v%s\n", program_name, program_version); exit(0); case '0': set_option(&options, OPT_LINENUMBERS, &cs.fw.arp.invflags, invert); break; case 'M': //modprobe = optarg; break; case 'c': set_option(&options, OPT_COUNTERS, &cs.fw.arp.invflags, invert); pcnt = optarg; if (optind < argc && argv[optind][0] != '-' && argv[optind][0] != '!') bcnt = argv[optind++]; else xtables_error(PARAMETER_PROBLEM, "-%c requires packet and byte counter", opt2char(OPT_COUNTERS)); if (sscanf(pcnt, "%llu", &cs.fw.counters.pcnt) != 1) xtables_error(PARAMETER_PROBLEM, "-%c packet counter not numeric", opt2char(OPT_COUNTERS)); if (sscanf(bcnt, "%llu", &cs.fw.counters.bcnt) != 1) xtables_error(PARAMETER_PROBLEM, "-%c byte counter not numeric", opt2char(OPT_COUNTERS)); break; 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; } printf("Bad argument `%s'\n", optarg); exit_tryhelp(2); default: if (cs.target) { xtables_option_tpcall(c, argv, invert, cs.target, &cs.fw); } break; } invert = FALSE; } if (cs.target) xtables_option_tfcall(cs.target); if (optind < argc) xtables_error(PARAMETER_PROBLEM, "unknown arguments found on commandline"); if (!command) xtables_error(PARAMETER_PROBLEM, "no command specified"); if (invert) xtables_error(PARAMETER_PROBLEM, "nothing appropriate following !"); if (command & (CMD_REPLACE | CMD_INSERT | CMD_DELETE | CMD_APPEND)) { if (!(options & OPT_D_IP)) dhostnetworkmask = "0.0.0.0/0"; if (!(options & OPT_S_IP)) shostnetworkmask = "0.0.0.0/0"; } if (shostnetworkmask) parse_hostnetworkmask(shostnetworkmask, &saddrs, &(cs.fw.arp.smsk), &nsaddrs); if (dhostnetworkmask) parse_hostnetworkmask(dhostnetworkmask, &daddrs, &(cs.fw.arp.tmsk), &ndaddrs); if ((nsaddrs > 1 || ndaddrs > 1) && (cs.fw.arp.invflags & (ARPT_INV_SRCIP | ARPT_INV_TGTIP))) xtables_error(PARAMETER_PROBLEM, "! not allowed with multiple" " source or destination IP addresses"); if (command == CMD_REPLACE && (nsaddrs != 1 || ndaddrs != 1)) xtables_error(PARAMETER_PROBLEM, "Replacement rule does not " "specify a unique address"); generic_opt_check(command, options); if (chain && strlen(chain) > ARPT_FUNCTION_MAXNAMELEN) xtables_error(PARAMETER_PROBLEM, "chain name `%s' too long (must be under %i chars)", chain, ARPT_FUNCTION_MAXNAMELEN); if (nft_init(h, xtables_arp) < 0) xtables_error(OTHER_PROBLEM, "Could not initialize nftables layer."); h->ops = nft_family_ops_lookup(h->family); if (h->ops == NULL) xtables_error(PARAMETER_PROBLEM, "Unknown family"); if (command == CMD_APPEND || command == CMD_DELETE || command == CMD_INSERT || command == CMD_REPLACE) { if (strcmp(chain, "PREROUTING") == 0 || strcmp(chain, "INPUT") == 0) { /* -o not valid with incoming packets. */ if (options & OPT_VIANAMEOUT) xtables_error(PARAMETER_PROBLEM, "Can't use -%c with %s\n", opt2char(OPT_VIANAMEOUT), chain); } if (strcmp(chain, "POSTROUTING") == 0 || strcmp(chain, "OUTPUT") == 0) { /* -i not valid with outgoing packets */ if (options & OPT_VIANAMEIN) xtables_error(PARAMETER_PROBLEM, "Can't use -%c with %s\n", opt2char(OPT_VIANAMEIN), chain); } if (!cs.target && strlen(cs.jumpto) != 0) { size_t size; cs.target = xtables_find_target(XT_STANDARD_TARGET, XTF_LOAD_MUST_SUCCEED); size = sizeof(struct arpt_entry_target) + cs.target->size; cs.target->t = xtables_calloc(1, size); cs.target->t->u.target_size = size; strcpy(cs.target->t->u.user.name, cs.jumpto); } } switch (command) { case CMD_APPEND: ret = append_entry(h, chain, *table, &cs, 0, nsaddrs, saddrs, ndaddrs, daddrs, options&OPT_VERBOSE, true); break; case CMD_DELETE: ret = delete_entry(chain, *table, &cs, nsaddrs, saddrs, ndaddrs, daddrs, options&OPT_VERBOSE, h); break; case CMD_DELETE_NUM: ret = nft_rule_delete_num(h, chain, *table, rulenum - 1, verbose); break; case CMD_REPLACE: ret = replace_entry(chain, *table, &cs, rulenum - 1, saddrs, daddrs, options&OPT_VERBOSE, h); break; case CMD_INSERT: ret = append_entry(h, chain, *table, &cs, rulenum - 1, nsaddrs, saddrs, ndaddrs, daddrs, options&OPT_VERBOSE, false); break; case CMD_LIST: ret = list_entries(h, chain, *table, rulenum, options&OPT_VERBOSE, options&OPT_NUMERIC, /*options&OPT_EXPANDED*/0, options&OPT_LINENUMBERS); break; case CMD_FLUSH: ret = nft_rule_flush(h, chain, *table); break; case CMD_ZERO: ret = nft_chain_zero_counters(h, chain, *table); break; case CMD_LIST|CMD_ZERO: ret = list_entries(h, chain, *table, rulenum, options&OPT_VERBOSE, options&OPT_NUMERIC, /*options&OPT_EXPANDED*/0, options&OPT_LINENUMBERS); if (ret) ret = nft_chain_zero_counters(h, chain, *table); break; case CMD_NEW_CHAIN: ret = nft_chain_user_add(h, chain, *table); break; case CMD_DELETE_CHAIN: ret = nft_chain_user_del(h, chain, *table); break; case CMD_RENAME_CHAIN: ret = nft_chain_user_rename(h, chain, *table, newname); break; case CMD_SET_POLICY: ret = nft_chain_set(h, *table, chain, policy, NULL); if (ret < 0) xtables_error(PARAMETER_PROBLEM, "Wrong policy `%s'\n", policy); break; default: /* We should never reach this... */ exit_tryhelp(2); } /* if (verbose > 1) dump_entries(*handle);*/ return ret; }