diff options
author | Patrick McHardy <kaber@trash.net> | 2011-02-09 08:13:23 +0100 |
---|---|---|
committer | Patrick McHardy <kaber@trash.net> | 2011-02-09 08:13:23 +0100 |
commit | 7ada0bb7aafd94ef7c9c076e8be50c80bc549a4f (patch) | |
tree | 7d6917139d26782a24cd733a557006c8048b9dff | |
parent | e76ec99b48745b0e3c8aecbc91ed5bba186cf25f (diff) | |
parent | 58b491f8cb5b4a0315037d0e1f61f8162a556e8a (diff) |
Merge branch 'master' of git://dev.medozas.de/iptables
-rw-r--r-- | ip6tables.c | 565 | ||||
-rw-r--r-- | iptables.c | 607 | ||||
-rw-r--r-- | xshared.c | 70 | ||||
-rw-r--r-- | xshared.h | 37 |
4 files changed, 608 insertions, 671 deletions
diff --git a/ip6tables.c b/ip6tables.c index 8c1b5049..5561a7d5 100644 --- a/ip6tables.c +++ b/ip6tables.c @@ -86,20 +86,8 @@ static const char cmdflags[] = { 'I', 'D', 'D', 'R', 'A', 'L', 'F', 'Z', 'Z', 'N', 'X', 'P', 'E', 'S' }; -#define OPT_NONE 0x00000U -#define OPT_NUMERIC 0x00001U -#define OPT_SOURCE 0x00002U -#define OPT_DESTINATION 0x00004U -#define OPT_PROTOCOL 0x00008U -#define OPT_JUMP 0x00010U -#define OPT_VERBOSE 0x00020U -#define OPT_EXPANDED 0x00040U -#define OPT_VIANAMEIN 0x00080U -#define OPT_VIANAMEOUT 0x00100U -#define OPT_LINENUMBERS 0x00200U -#define OPT_COUNTERS 0x00400U -#define NUMBER_OF_OPT 11 -static const char optflags[NUMBER_OF_OPT] +#define NUMBER_OF_OPT ARRAY_SIZE(optflags) +static const char optflags[] = { 'n', 's', 'd', 'p', 'j', 'v', 'x', 'i', 'o', '0', 'c'}; static struct option original_opts[] = { @@ -205,24 +193,6 @@ struct pprot { uint8_t num; }; -static const char * -proto_to_name(uint8_t proto, int nolookup) -{ - unsigned int i; - - if (proto && !nolookup) { - const struct protoent *pent = getprotobynumber(proto); - if (pent) - return pent->p_name; - } - - for (i = 0; xtables_chain_protos[i].name != NULL; ++i) - if (xtables_chain_protos[i].num == proto) - return xtables_chain_protos[i].name; - - return NULL; -} - static void __attribute__((noreturn)) exit_tryhelp(int status) { @@ -406,24 +376,6 @@ add_command(unsigned int *cmd, const int newcmd, const int othercmds, * return global static data. */ -/* Christophe Burki wants `-p 6' to imply `-m tcp'. */ -static struct xtables_match * -find_proto(const char *pname, enum xtables_tryload tryload, - int nolookup, struct xtables_rule_match **matches) -{ - unsigned int proto; - - if (xtables_strtoui(pname, NULL, &proto, 0, UINT8_MAX)) { - const char *protoname = proto_to_name(proto, nolookup); - - if (protoname) - return xtables_find_match(protoname, tryload, matches); - } else - return xtables_find_match(pname, tryload, matches); - - return NULL; -} - /* These are invalid numbers as upper layer protocol */ static int is_exthdr(uint16_t proto) { @@ -1288,32 +1240,138 @@ static void clear_rule_matches(struct xtables_rule_match **matches) *matches = NULL; } +static void command_default(struct iptables_command_state *cs) +{ + struct xtables_rule_match *matchp; + struct xtables_match *m; + + if (cs->target == NULL || cs->target->parse == NULL || + cs->c < cs->target->option_offset || + cs->c >= cs->target->option_offset + XT_OPTION_OFFSET_SCALE) { + cs->target->parse(cs->c - cs->target->option_offset, cs->argv, + cs->invert, &cs->target->tflags, &cs->fw6, + &cs->target->t); + return; + } + + for (matchp = cs->matches; matchp; matchp = matchp->next) { + m = matchp->match; + + if (matchp->completed || m->parse == NULL) + continue; + if (cs->c < matchp->match->option_offset || + cs->c >= matchp->match->option_offset + XT_OPTION_OFFSET_SCALE) + continue; + m->parse(cs->c - m->option_offset, cs->argv, cs->invert, + &m->mflags, &cs->fw6, &m->m); + return; + } + + /* Try loading protocol */ + m = load_proto(cs); + if (m != NULL) { + size_t size; + + cs->proto_used = 1; + + size = IP6T_ALIGN(sizeof(struct ip6t_entry_match)) + m->size; + + m->m = xtables_calloc(1, size); + m->m->u.match_size = size; + strcpy(m->m->u.user.name, m->name); + m->m->u.user.revision = m->revision; + if (m->init != NULL) + m->init(m->m); + + opts = xtables_merge_options(ip6tables_globals.orig_opts, opts, + m->extra_opts, &m->option_offset); + + optind--; + return; + } + + if (cs->c == ':') + xtables_error(PARAMETER_PROBLEM, "option \"%s\" " + "requires an argument", cs->argv[optind-1]); + if (cs->c == '?') + xtables_error(PARAMETER_PROBLEM, "unknown option " + "\"%s\"", cs->argv[optind-1]); + xtables_error(PARAMETER_PROBLEM, "Unknown arg \"%s\"", optarg); +} + +static void command_jump(struct iptables_command_state *cs) +{ + size_t size; + + set_option(&cs->options, OPT_JUMP, &cs->fw6.ipv6.invflags, cs->invert); + cs->jumpto = parse_target(optarg); + /* TRY_LOAD (may be chain name) */ + cs->target = xtables_find_target(cs->jumpto, XTF_TRY_LOAD); + + if (cs->target == NULL) + return; + + size = IP6T_ALIGN(sizeof(struct ip6t_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); + cs->target->t->u.user.revision = cs->target->revision; + if (cs->target->init != NULL) + cs->target->init(cs->target->t); + opts = xtables_merge_options(ip6tables_globals.orig_opts, opts, + cs->target->extra_opts, + &cs->target->option_offset); + if (opts == NULL) + xtables_error(OTHER_PROBLEM, "can't alloc memory!"); +} + +static void command_match(struct iptables_command_state *cs) +{ + struct xtables_match *m; + size_t size; + + if (cs->invert) + xtables_error(PARAMETER_PROBLEM, + "unexpected ! flag before --match"); + + m = xtables_find_match(optarg, XTF_LOAD_MUST_SUCCEED, &cs->matches); + size = IP6T_ALIGN(sizeof(struct ip6t_entry_match)) + m->size; + m->m = xtables_calloc(1, size); + m->m->u.match_size = size; + strcpy(m->m->u.user.name, m->name); + m->m->u.user.revision = m->revision; + if (m->init != NULL) + m->init(m->m); + if (m != m->next) + /* Merge options for non-cloned matches */ + opts = xtables_merge_options(ip6tables_globals.orig_opts, opts, + m->extra_opts, &m->option_offset); +} + int do_command6(int argc, char *argv[], char **table, struct ip6tc_handle **handle) { - struct ip6t_entry fw, *e = NULL; - int invert = 0; + struct iptables_command_state cs; + struct ip6t_entry *e = NULL; unsigned int nsaddrs = 0, ndaddrs = 0; struct in6_addr *saddrs = NULL, *daddrs = NULL; struct in6_addr *smasks = NULL, *dmasks = NULL; - int c, verbose = 0; + int 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; + unsigned int rulenum = 0, command = 0; const char *pcnt = NULL, *bcnt = NULL; int ret = 1; struct xtables_match *m; - struct xtables_rule_match *matches = NULL; struct xtables_rule_match *matchp; - struct xtables_target *target = NULL; struct xtables_target *t; - const char *jumpto = ""; - char *protocol = NULL; - int proto_used = 0; unsigned long long cnt; - memset(&fw, 0, sizeof(fw)); + memset(&cs, 0, sizeof(cs)); + cs.jumpto = ""; + cs.argv = argv; /* re-set optind to 0 in case do_command gets called * a second time */ @@ -1334,22 +1392,22 @@ int do_command6(int argc, char *argv[], char **table, struct ip6tc_handle **hand opterr = 0; opts = xt_params->orig_opts; - while ((c = getopt_long(argc, argv, - "-A:D:R:I:L::S::M:F::Z::N:X::E:P:Vh::o:p:s:d:j:i:bvnt:m:xc:g:", + while ((cs.c = getopt_long(argc, argv, + "-:A:D:R:I:L::S::M:F::Z::N:X::E:P:Vh::o:p:s:d:j:i:bvnt:m:xc:g:", opts, NULL)) != -1) { - switch (c) { + switch (cs.c) { /* * Command selection */ case 'A': add_command(&command, CMD_APPEND, CMD_NONE, - invert); + cs.invert); chain = optarg; break; case 'D': add_command(&command, CMD_DELETE, CMD_NONE, - invert); + cs.invert); chain = optarg; if (optind < argc && argv[optind][0] != '-' && argv[optind][0] != '!') { @@ -1360,7 +1418,7 @@ int do_command6(int argc, char *argv[], char **table, struct ip6tc_handle **hand case 'R': add_command(&command, CMD_REPLACE, CMD_NONE, - invert); + cs.invert); chain = optarg; if (optind < argc && argv[optind][0] != '-' && argv[optind][0] != '!') @@ -1373,7 +1431,7 @@ int do_command6(int argc, char *argv[], char **table, struct ip6tc_handle **hand case 'I': add_command(&command, CMD_INSERT, CMD_NONE, - invert); + cs.invert); chain = optarg; if (optind < argc && argv[optind][0] != '-' && argv[optind][0] != '!') @@ -1383,7 +1441,7 @@ int do_command6(int argc, char *argv[], char **table, struct ip6tc_handle **hand case 'L': add_command(&command, CMD_LIST, - CMD_ZERO | CMD_ZERO_NUM, invert); + CMD_ZERO | CMD_ZERO_NUM, cs.invert); if (optarg) chain = optarg; else if (optind < argc && argv[optind][0] != '-' && argv[optind][0] != '!') @@ -1395,7 +1453,7 @@ int do_command6(int argc, char *argv[], char **table, struct ip6tc_handle **hand case 'S': add_command(&command, CMD_LIST_RULES, - CMD_ZERO | CMD_ZERO_NUM, invert); + CMD_ZERO | CMD_ZERO_NUM, cs.invert); if (optarg) chain = optarg; else if (optind < argc && argv[optind][0] != '-' && argv[optind][0] != '!') @@ -1407,7 +1465,7 @@ int do_command6(int argc, char *argv[], char **table, struct ip6tc_handle **hand case 'F': add_command(&command, CMD_FLUSH, CMD_NONE, - invert); + cs.invert); if (optarg) chain = optarg; else if (optind < argc && argv[optind][0] != '-' && argv[optind][0] != '!') @@ -1416,7 +1474,7 @@ int do_command6(int argc, char *argv[], char **table, struct ip6tc_handle **hand case 'Z': add_command(&command, CMD_ZERO, CMD_LIST|CMD_LIST_RULES, - invert); + cs.invert); if (optarg) chain = optarg; else if (optind < argc && argv[optind][0] != '-' && argv[optind][0] != '!') @@ -1438,13 +1496,13 @@ int do_command6(int argc, char *argv[], char **table, struct ip6tc_handle **hand "chain name may not clash " "with target name\n"); add_command(&command, CMD_NEW_CHAIN, CMD_NONE, - invert); + cs.invert); chain = optarg; break; case 'X': add_command(&command, CMD_DELETE_CHAIN, CMD_NONE, - invert); + cs.invert); if (optarg) chain = optarg; else if (optind < argc && argv[optind][0] != '-' && argv[optind][0] != '!') @@ -1453,7 +1511,7 @@ int do_command6(int argc, char *argv[], char **table, struct ip6tc_handle **hand case 'E': add_command(&command, CMD_RENAME_CHAIN, CMD_NONE, - invert); + cs.invert); chain = optarg; if (optind < argc && argv[optind][0] != '-' && argv[optind][0] != '!') @@ -1467,7 +1525,7 @@ int do_command6(int argc, char *argv[], char **table, struct ip6tc_handle **hand case 'P': add_command(&command, CMD_SET_POLICY, CMD_NONE, - invert); + cs.invert); chain = optarg; if (optind < argc && argv[optind][0] != '-' && argv[optind][0] != '!') @@ -1483,90 +1541,66 @@ int do_command6(int argc, char *argv[], char **table, struct ip6tc_handle **hand optarg = argv[optind]; /* ip6tables -p icmp -h */ - if (!matches && protocol) - xtables_find_match(protocol, XTF_TRY_LOAD, - &matches); + if (!cs.matches && cs.protocol) + xtables_find_match(cs.protocol, XTF_TRY_LOAD, + &cs.matches); - exit_printhelp(matches); + exit_printhelp(cs.matches); /* * Option selection */ case 'p': - xtables_check_inverse(optarg, &invert, &optind, argc, argv); - set_option(&options, OPT_PROTOCOL, &fw.ipv6.invflags, - invert); + xtables_check_inverse(optarg, &cs.invert, &optind, argc, argv); + set_option(&cs.options, OPT_PROTOCOL, &cs.fw6.ipv6.invflags, + cs.invert); /* Canonicalize into lower case */ - for (protocol = optarg; *protocol; protocol++) - *protocol = tolower(*protocol); + for (cs.protocol = optarg; *cs.protocol; cs.protocol++) + *cs.protocol = tolower(*cs.protocol); - protocol = optarg; - fw.ipv6.proto = xtables_parse_protocol(protocol); - fw.ipv6.flags |= IP6T_F_PROTO; + cs.protocol = optarg; + cs.fw6.ipv6.proto = xtables_parse_protocol(cs.protocol); + cs.fw6.ipv6.flags |= IP6T_F_PROTO; - if (fw.ipv6.proto == 0 - && (fw.ipv6.invflags & IP6T_INV_PROTO)) + if (cs.fw6.ipv6.proto == 0 + && (cs.fw6.ipv6.invflags & IP6T_INV_PROTO)) xtables_error(PARAMETER_PROBLEM, "rule would never match protocol"); - if (is_exthdr(fw.ipv6.proto) - && (fw.ipv6.invflags & IP6T_INV_PROTO) == 0) + if (is_exthdr(cs.fw6.ipv6.proto) + && (cs.fw6.ipv6.invflags & IP6T_INV_PROTO) == 0) fprintf(stderr, "Warning: never matched protocol: %s. " "use extension match instead.\n", - protocol); + cs.protocol); break; case 's': - xtables_check_inverse(optarg, &invert, &optind, argc, argv); - set_option(&options, OPT_SOURCE, &fw.ipv6.invflags, - invert); + xtables_check_inverse(optarg, &cs.invert, &optind, argc, argv); + set_option(&cs.options, OPT_SOURCE, &cs.fw6.ipv6.invflags, + cs.invert); shostnetworkmask = optarg; break; case 'd': - xtables_check_inverse(optarg, &invert, &optind, argc, argv); - set_option(&options, OPT_DESTINATION, &fw.ipv6.invflags, - invert); + xtables_check_inverse(optarg, &cs.invert, &optind, argc, argv); + set_option(&cs.options, OPT_DESTINATION, &cs.fw6.ipv6.invflags, + cs.invert); dhostnetworkmask = optarg; break; #ifdef IP6T_F_GOTO case 'g': - set_option(&options, OPT_JUMP, &fw.ipv6.invflags, - invert); - fw.ipv6.flags |= IP6T_F_GOTO; - jumpto = parse_target(optarg); + set_option(&cs.options, OPT_JUMP, &cs.fw6.ipv6.invflags, + cs.invert); + cs.fw6.ipv6.flags |= IP6T_F_GOTO; + cs.jumpto = parse_target(optarg); break; #endif case 'j': - set_option(&options, OPT_JUMP, &fw.ipv6.invflags, - invert); - jumpto = parse_target(optarg); - /* TRY_LOAD (may be chain name) */ - target = xtables_find_target(jumpto, XTF_TRY_LOAD); - - if (target) { - size_t size; - - size = IP6T_ALIGN(sizeof(struct ip6t_entry_target)) - + target->size; - - target->t = xtables_calloc(1, size); - target->t->u.target_size = size; - strcpy(target->t->u.user.name, jumpto); - target->t->u.user.revision = target->revision; - if (target->init != NULL) - target->init(target->t); - opts = xtables_merge_options(ip6tables_globals.orig_opts, opts, - target->extra_opts, - &target->option_offset); - if (opts == NULL) - xtables_error(OTHER_PROBLEM, - "can't alloc memory!"); - } + command_jump(&cs); break; @@ -1575,12 +1609,12 @@ int do_command6(int argc, char *argv[], char **table, struct ip6tc_handle **hand xtables_error(PARAMETER_PROBLEM, "Empty interface is likely to be " "undesired"); - xtables_check_inverse(optarg, &invert, &optind, argc, argv); - set_option(&options, OPT_VIANAMEIN, &fw.ipv6.invflags, - invert); + xtables_check_inverse(optarg, &cs.invert, &optind, argc, argv); + set_option(&cs.options, OPT_VIANAMEIN, &cs.fw6.ipv6.invflags, + cs.invert); xtables_parse_interface(optarg, - fw.ipv6.iniface, - fw.ipv6.iniface_mask); + cs.fw6.ipv6.iniface, + cs.fw6.ipv6.iniface_mask); break; case 'o': @@ -1588,63 +1622,44 @@ int do_command6(int argc, char *argv[], char **table, struct ip6tc_handle **hand xtables_error(PARAMETER_PROBLEM, "Empty interface is likely to be " "undesired"); - xtables_check_inverse(optarg, &invert, &optind, argc, argv); - set_option(&options, OPT_VIANAMEOUT, &fw.ipv6.invflags, - invert); + xtables_check_inverse(optarg, &cs.invert, &optind, argc, argv); + set_option(&cs.options, OPT_VIANAMEOUT, &cs.fw6.ipv6.invflags, + cs.invert); xtables_parse_interface(optarg, - fw.ipv6.outiface, - fw.ipv6.outiface_mask); + cs.fw6.ipv6.outiface, + cs.fw6.ipv6.outiface_mask); break; case 'v': if (!verbose) - set_option(&options, OPT_VERBOSE, - &fw.ipv6.invflags, invert); + set_option(&cs.options, OPT_VERBOSE, + &cs.fw6.ipv6.invflags, cs.invert); verbose++; break; - case 'm': { - size_t size; - - if (invert) - xtables_error(PARAMETER_PROBLEM, - "unexpected ! flag before --match"); - - m = xtables_find_match(optarg, XTF_LOAD_MUST_SUCCEED, - &matches); - size = IP6T_ALIGN(sizeof(struct ip6t_entry_match)) - + m->size; - m->m = xtables_calloc(1, size); - m->m->u.match_size = size; - strcpy(m->m->u.user.name, m->name); - m->m->u.user.revision = m->revision; - if (m->init != NULL) - m->init(m->m); - if (m != m->next) - /* Merge options for non-cloned matches */ - opts = xtables_merge_options(ip6tables_globals.orig_opts, opts, m->extra_opts, &m->option_offset); - } - break; + case 'm': + command_match(&cs); + break; case 'n': - set_option(&options, OPT_NUMERIC, &fw.ipv6.invflags, - invert); + set_option(&cs.options, OPT_NUMERIC, &cs.fw6.ipv6.invflags, + cs.invert); break; case 't': - if (invert) + if (cs.invert) xtables_error(PARAMETER_PROBLEM, "unexpected ! flag before --table"); *table = optarg; break; case 'x': - set_option(&options, OPT_EXPANDED, &fw.ipv6.invflags, - invert); + set_option(&cs.options, OPT_EXPANDED, &cs.fw6.ipv6.invflags, + cs.invert); break; case 'V': - if (invert) + if (cs.invert) printf("Not %s ;-)\n", prog_vers); else printf("%s v%s\n", @@ -1652,8 +1667,8 @@ int do_command6(int argc, char *argv[], char **table, struct ip6tc_handle **hand exit(0); case '0': - set_option(&options, OPT_LINENUMBERS, &fw.ipv6.invflags, - invert); + set_option(&cs.options, OPT_LINENUMBERS, &cs.fw6.ipv6.invflags, + cs.invert); break; case 'M': @@ -1662,8 +1677,8 @@ int do_command6(int argc, char *argv[], char **table, struct ip6tc_handle **hand case 'c': - set_option(&options, OPT_COUNTERS, &fw.ipv6.invflags, - invert); + set_option(&cs.options, OPT_COUNTERS, &cs.fw6.ipv6.invflags, + cs.invert); pcnt = optarg; bcnt = strchr(pcnt + 1, ','); if (bcnt) @@ -1680,22 +1695,22 @@ int do_command6(int argc, char *argv[], char **table, struct ip6tc_handle **hand xtables_error(PARAMETER_PROBLEM, "-%c packet counter not numeric", opt2char(OPT_COUNTERS)); - fw.counters.pcnt = cnt; + cs.fw6.counters.pcnt = cnt; if (sscanf(bcnt, "%llu", &cnt) != 1) xtables_error(PARAMETER_PROBLEM, "-%c byte counter not numeric", opt2char(OPT_COUNTERS)); - fw.counters.bcnt = cnt; + cs.fw6.counters.bcnt = cnt; break; case 1: /* non option */ if (optarg[0] == '!' && optarg[1] == '\0') { - if (invert) + if (cs.invert) xtables_error(PARAMETER_PROBLEM, "multiple consecutive ! not" " allowed"); - invert = TRUE; + cs.invert = TRUE; optarg[0] = '\0'; continue; } @@ -1703,115 +1718,18 @@ int do_command6(int argc, char *argv[], char **table, struct ip6tc_handle **hand exit_tryhelp(2); default: - if (target == NULL || target->parse == NULL || - c < target->option_offset || - c >= target->option_offset + XT_OPTION_OFFSET_SCALE || - !target->parse(c - target->option_offset, - argv, invert, - &target->tflags, - &fw, &target->t)) { - for (matchp = matches; matchp; matchp = matchp->next) { - if (matchp->completed || - matchp->match->parse == NULL) - continue; - if (c < matchp->match->option_offset || - c >= matchp->match->option_offset + XT_OPTION_OFFSET_SCALE) - continue; - if (matchp->match->parse(c - matchp->match->option_offset, - argv, invert, - &matchp->match->mflags, - &fw, - &matchp->match->m)) - break; - } - m = matchp ? matchp->match : NULL; - - /* If you listen carefully, you can - actually hear this code suck. */ - - /* some explanations (after four different bugs - * in 3 different releases): If we encounter a - * parameter, that has not been parsed yet, - * it's not an option of an explicitly loaded - * match or a target. However, we support - * implicit loading of the protocol match - * extension. '-p tcp' means 'l4 proto 6' and - * at the same time 'load tcp protocol match on - * demand if we specify --dport'. - * - * To make this work, we need to make sure: - * - the parameter has not been parsed by - * a match (m above) - * - a protocol has been specified - * - the protocol extension has not been - * loaded yet, or is loaded and unused - * [think of ip6tables-restore!] - * - the protocol extension can be successively - * loaded - */ - if (m == NULL - && protocol - && (!find_proto(protocol, XTF_DONT_LOAD, - options&OPT_NUMERIC, NULL) - || (find_proto(protocol, XTF_DONT_LOAD, - options&OPT_NUMERIC, NULL) - && (proto_used == 0)) - ) - && (m = find_proto(protocol, XTF_TRY_LOAD, - options&OPT_NUMERIC, &matches))) { - /* Try loading protocol */ - size_t size; - - proto_used = 1; - - size = IP6T_ALIGN(sizeof(struct ip6t_entry_match)) - + m->size; - - m->m = xtables_calloc(1, size); - m->m->u.match_size = size; - strcpy(m->m->u.user.name, m->name); - m->m->u.user.revision = m->revision; - if (m->init != NULL) - m->init(m->m); - - opts = xtables_merge_options(ip6tables_globals.orig_opts, opts, - m->extra_opts, &m->option_offset); - - optind--; - continue; - } - - if (!m) { - if (c == '?') { - if (optopt) { - xtables_error( - PARAMETER_PROBLEM, - "option `%s' " - "requires an " - "argument", - argv[optind-1]); - } else { - xtables_error( - PARAMETER_PROBLEM, - "unknown option " - "`%s'", - argv[optind-1]); - } - } - xtables_error(PARAMETER_PROBLEM, - "Unknown arg `%s'", optarg); - } - } + command_default(&cs); + break; } - invert = FALSE; + cs.invert = FALSE; } - for (matchp = matches; matchp; matchp = matchp->next) + for (matchp = cs.matches; matchp; matchp = matchp->next) if (matchp->match->final_check != NULL) matchp->match->final_check(matchp->match->mflags); - if (target != NULL && target->final_check != NULL) - target->final_check(target->tflags); + if (cs.target != NULL && cs.target->final_check != NULL) + cs.target->final_check(cs.target->tflags); /* Fix me: must put inverse options checking here --MN */ @@ -1820,14 +1738,14 @@ int do_command6(int argc, char *argv[], char **table, struct ip6tc_handle **hand "unknown arguments found on commandline"); if (!command) xtables_error(PARAMETER_PROBLEM, "no command specified"); - if (invert) + if (cs.invert) xtables_error(PARAMETER_PROBLEM, "nothing appropriate following !"); if (command & (CMD_REPLACE | CMD_INSERT | CMD_DELETE | CMD_APPEND)) { - if (!(options & OPT_DESTINATION)) + if (!(cs.options & OPT_DESTINATION)) dhostnetworkmask = "::0/0"; - if (!(options & OPT_SOURCE)) + if (!(cs.options & OPT_SOURCE)) shostnetworkmask = "::0/0"; } @@ -1840,7 +1758,7 @@ int do_command6(int argc, char *argv[], char **table, struct ip6tc_handle **hand &dmasks, &ndaddrs); if ((nsaddrs > 1 || ndaddrs > 1) && - (fw.ipv6.invflags & (IP6T_INV_SRCIP | IP6T_INV_DSTIP))) + (cs.fw6.ipv6.invflags & (IP6T_INV_SRCIP | IP6T_INV_DSTIP))) xtables_error(PARAMETER_PROBLEM, "! not allowed with multiple" " source or destination IP addresses"); @@ -1848,7 +1766,7 @@ int do_command6(int argc, char *argv[], char **table, struct ip6tc_handle **hand xtables_error(PARAMETER_PROBLEM, "Replacement rule does not " "specify a unique address"); - generic_opt_check(command, options); + generic_opt_check(command, cs.options); if (chain != NULL && strlen(chain) >= XT_EXTENSION_MAXNAMELEN) xtables_error(PARAMETER_PROBLEM, @@ -1875,7 +1793,7 @@ int do_command6(int argc, char *argv[], char **table, struct ip6tc_handle **hand if (strcmp(chain, "PREROUTING") == 0 || strcmp(chain, "INPUT") == 0) { /* -o not valid with incoming packets. */ - if (options & OPT_VIANAMEOUT) + if (cs.options & OPT_VIANAMEOUT) xtables_error(PARAMETER_PROBLEM, "Can't use -%c with %s\n", opt2char(OPT_VIANAMEOUT), @@ -1885,57 +1803,58 @@ int do_command6(int argc, char *argv[], char **table, struct ip6tc_handle **hand if (strcmp(chain, "POSTROUTING") == 0 || strcmp(chain, "OUTPUT") == 0) { /* -i not valid with outgoing packets */ - if (options & OPT_VIANAMEIN) + if (cs.options & OPT_VIANAMEIN) xtables_error(PARAMETER_PROBLEM, "Can't use -%c with %s\n", opt2char(OPT_VIANAMEIN), chain); } - if (target && ip6tc_is_chain(jumpto, *handle)) { + if (cs.target && ip6tc_is_chain(cs.jumpto, *handle)) { fprintf(stderr, "Warning: using chain %s, not extension\n", - jumpto); + cs.jumpto); - if (target->t) - free(target->t); + if (cs.target->t) + free(cs.target->t); - target = NULL; + cs.target = NULL; } /* If they didn't specify a target, or it's a chain name, use standard. */ - if (!target - && (strlen(jumpto) == 0 - || ip6tc_is_chain(jumpto, *handle))) { + if (!cs.target + && (strlen(cs.jumpto) == 0 + || ip6tc_is_chain(cs.jumpto, *handle))) { size_t size; - target = xtables_find_target(IP6T_STANDARD_TARGET, + cs.target = xtables_find_target(IP6T_STANDARD_TARGET, XTF_LOAD_MUST_SUCCEED); size = sizeof(struct ip6t_entry_target) - + target->size; - target->t = xtables_calloc(1, size); - target->t->u.target_size = size; - strcpy(target->t->u.user.name, jumpto); - if (target->init != NULL) - target->init(target->t); + + 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); + if (cs.target->init != NULL) + cs.target->init(cs.target->t); } - if (!target) { + if (!cs.target) { /* it is no chain, and we can't load a plugin. * We cannot know if the plugin is corrupt, non * existant OR if the user just misspelled a * chain. */ #ifdef IP6T_F_GOTO - if (fw.ipv6.flags & IP6T_F_GOTO) + if (cs.fw6.ipv6.flags & IP6T_F_GOTO) xtables_error(PARAMETER_PROBLEM, - "goto '%s' is not a chain\n", jumpto); + "goto '%s' is not a chain\n", + cs.jumpto); #endif - xtables_find_target(jumpto, XTF_LOAD_MUST_SUCCEED); + xtables_find_target(cs.jumpto, XTF_LOAD_MUST_SUCCEED); } else { - e = generate_entry(&fw, matches, target->t); - free(target->t); + e = generate_entry(&cs.fw6, cs.matches, cs.target->t); + free(cs.target->t); } } @@ -1944,15 +1863,15 @@ int do_command6(int argc, char *argv[], char **table, struct ip6tc_handle **hand ret = append_entry(chain, e, nsaddrs, saddrs, smasks, ndaddrs, daddrs, dmasks, - options&OPT_VERBOSE, + cs.options&OPT_VERBOSE, *handle); break; case CMD_DELETE: ret = delete_entry(chain, e, nsaddrs, saddrs, smasks, ndaddrs, daddrs, dmasks, - options&OPT_VERBOSE, - *handle, matches, target); + cs.options&OPT_VERBOSE, + *handle, cs.matches, cs.target); break; case CMD_DELETE_NUM: ret = ip6tc_delete_num_entry(chain, rulenum - 1, *handle); @@ -1960,20 +1879,20 @@ int do_command6(int argc, char *argv[], char **table, struct ip6tc_handle **hand case CMD_REPLACE: ret = replace_entry(chain, e, rulenum - 1, saddrs, smasks, daddrs, dmasks, - options&OPT_VERBOSE, *handle); + cs.options&OPT_VERBOSE, *handle); break; case CMD_INSERT: ret = insert_entry(chain, e, rulenum - 1, nsaddrs, saddrs, smasks, ndaddrs, daddrs, dmasks, - options&OPT_VERBOSE, + cs.options&OPT_VERBOSE, *handle); break; case CMD_FLUSH: - ret = flush_entries(chain, options&OPT_VERBOSE, *handle); + ret = flush_entries(chain, cs.options&OPT_VERBOSE, *handle); break; case CMD_ZERO: - ret = zero_entries(chain, options&OPT_VERBOSE, *handle); + ret = zero_entries(chain, cs.options&OPT_VERBOSE, *handle); break; case CMD_ZERO_NUM: ret = ip6tc_zero_counter(chain, rulenum, *handle); @@ -1983,14 +1902,14 @@ int do_command6(int argc, char *argv[], char **table, struct ip6tc_handle **hand case CMD_LIST|CMD_ZERO_NUM: ret = list_entries(chain, rulenum, - options&OPT_VERBOSE, - options&OPT_NUMERIC, - options&OPT_EXPANDED, - options&OPT_LINENUMBERS, + cs.options&OPT_VERBOSE, + cs.options&OPT_NUMERIC, + cs.options&OPT_EXPANDED, + cs.options&OPT_LINENUMBERS, *handle); if (ret && (command & CMD_ZERO)) ret = zero_entries(chain, - options&OPT_VERBOSE, *handle); + cs.options&OPT_VERBOSE, *handle); if (ret && (command & CMD_ZERO_NUM)) ret = ip6tc_zero_counter(chain, rulenum, *handle); break; @@ -1999,11 +1918,11 @@ int do_command6(int argc, char *argv[], char **table, struct ip6tc_handle **hand case CMD_LIST_RULES|CMD_ZERO_NUM: ret = list_rules(chain, rulenum, - options&OPT_VERBOSE, + cs.options&OPT_VERBOSE, *handle); if (ret && (command & CMD_ZERO)) ret = zero_entries(chain, - options&OPT_VERBOSE, *handle); + cs.options&OPT_VERBOSE, *handle); if (ret && (command & CMD_ZERO_NUM)) ret = ip6tc_zero_counter(chain, rulenum, *handle); break; @@ -2011,13 +1930,13 @@ int do_command6(int argc, char *argv[], char **table, struct ip6tc_handle **hand ret = ip6tc_create_chain(chain, *handle); break; case CMD_DELETE_CHAIN: - ret = delete_chain(chain, options&OPT_VERBOSE, *handle); + ret = delete_chain(chain, cs.options&OPT_VERBOSE, *handle); break; case CMD_RENAME_CHAIN: ret = ip6tc_rename_chain(chain, newname, *handle); break; case CMD_SET_POLICY: - ret = ip6tc_set_policy(chain, policy, options&OPT_COUNTERS ? &fw.counters : NULL, *handle); + ret = ip6tc_set_policy(chain, policy, cs.options&OPT_COUNTERS ? &cs.fw6.counters : NULL, *handle); break; default: /* We should never reach this... */ @@ -2027,7 +1946,7 @@ int do_command6(int argc, char *argv[], char **table, struct ip6tc_handle **hand if (verbose > 1) dump_entries6(*handle); - clear_rule_matches(&matches); + clear_rule_matches(&cs.matches); if (e != NULL) { free(e); @@ -83,22 +83,10 @@ static const char cmdflags[] = { 'I', 'D', 'D', 'R', 'A', 'L', 'F', 'Z', 'Z', 'N', 'X', 'P', 'E', 'S' }; -#define OPT_NONE 0x00000U -#define OPT_NUMERIC 0x00001U -#define OPT_SOURCE 0x00002U -#define OPT_DESTINATION 0x00004U -#define OPT_PROTOCOL 0x00008U -#define OPT_JUMP 0x00010U -#define OPT_VERBOSE 0x00020U -#define OPT_EXPANDED 0x00040U -#define OPT_VIANAMEIN 0x00080U -#define OPT_VIANAMEOUT 0x00100U -#define OPT_FRAGMENT 0x00200U -#define OPT_LINENUMBERS 0x00400U -#define OPT_COUNTERS 0x00800U -#define NUMBER_OF_OPT 12 -static const char optflags[NUMBER_OF_OPT] -= { 'n', 's', 'd', 'p', 'j', 'v', 'x', 'i', 'o', 'f', '0', 'c'}; +#define OPT_FRAGMENT 0x00800U +#define NUMBER_OF_OPT ARRAY_SIZE(optflags) +static const char optflags[] += { 'n', 's', 'd', 'p', 'j', 'v', 'x', 'i', 'o', '0', 'c', 'f'}; static struct option original_opts[] = { {.name = "append", .has_arg = 1, .val = 'A'}, @@ -163,19 +151,19 @@ struct xtables_globals iptables_globals = { static const char commands_v_options[NUMBER_OF_CMD][NUMBER_OF_OPT] = /* Well, it's better than "Re: Linux vs FreeBSD" */ { - /* -n -s -d -p -j -v -x -i -o -f --line -c */ -/*INSERT*/ {'x',' ',' ',' ',' ',' ','x',' ',' ',' ','x',' '}, -/*DELETE*/ {'x',' ',' ',' ',' ',' ','x',' ',' ',' ','x','x'}, + /* -n -s -d -p -j -v -x -i -o --line -c -f */ +/*INSERT*/ {'x',' ',' ',' ',' ',' ','x',' ',' ','x',' ',' '}, +/*DELETE*/ {'x',' ',' ',' ',' ',' ','x',' ',' ','x','x',' '}, /*DELETE_NUM*/{'x','x','x','x','x',' ','x','x','x','x','x','x'}, -/*REPLACE*/ {'x',' ',' ',' ',' ',' ','x',' ',' ',' ','x',' '}, -/*APPEND*/ {'x',' ',' ',' ',' ',' ','x',' ',' ',' ','x',' '}, -/*LIST*/ {' ','x','x','x','x',' ',' ','x','x','x',' ','x'}, +/*REPLACE*/ {'x',' ',' ',' ',' ',' ','x',' ',' ','x',' ',' '}, +/*APPEND*/ {'x',' ',' ',' ',' ',' ','x',' ',' ','x',' ',' '}, +/*LIST*/ {' ','x','x','x','x',' ',' ','x','x',' ','x','x'}, /*FLUSH*/ {'x','x','x','x','x',' ','x','x','x','x','x','x'}, /*ZERO*/ {'x','x','x','x','x',' ','x','x','x','x','x','x'}, /*ZERO_NUM*/ {'x','x','x','x','x',' ','x','x','x','x','x','x'}, /*NEW_CHAIN*/ {'x','x','x','x','x',' ','x','x','x','x','x','x'}, /*DEL_CHAIN*/ {'x','x','x','x','x',' ','x','x','x','x','x','x'}, -/*SET_POLICY*/{'x','x','x','x','x',' ','x','x','x','x','x',' '}, +/*SET_POLICY*/{'x','x','x','x','x',' ','x','x','x','x',' ','x'}, /*RENAME*/ {'x','x','x','x','x',' ','x','x','x','x','x','x'}, /*LIST_RULES*/{'x','x','x','x','x',' ','x','x','x','x','x','x'} }; @@ -213,24 +201,6 @@ int kernel_version; #endif #endif -static const char * -proto_to_name(uint8_t proto, int nolookup) -{ - unsigned int i; - - if (proto && !nolookup) { - struct protoent *pent = getprotobynumber(proto); - if (pent) - return pent->p_name; - } - - for (i = 0; xtables_chain_protos[i].name != NULL; ++i) - if (xtables_chain_protos[i].num == proto) - return xtables_chain_protos[i].name; - - return NULL; -} - enum { IPT_DOTTED_ADDR = 0, IPT_DOTTED_MASK @@ -420,23 +390,6 @@ add_command(unsigned int *cmd, const int newcmd, const int othercmds, */ /* Christophe Burki wants `-p 6' to imply `-m tcp'. */ -static struct xtables_match * -find_proto(const char *pname, enum xtables_tryload tryload, - int nolookup, struct xtables_rule_match **matches) -{ - unsigned int proto; - - if (xtables_strtoui(pname, NULL, &proto, 0, UINT8_MAX)) { - const char *protoname = proto_to_name(proto, nolookup); - - if (protoname) - return xtables_find_match(protoname, tryload, matches); - } else - return xtables_find_match(pname, tryload, matches); - - return NULL; -} - /* Can't be zero. */ static int parse_rulenumber(const char *rule) @@ -1311,32 +1264,144 @@ get_kernel_version(void) { kernel_version = LINUX_VERSION(x, y, z); } +static void command_default(struct iptables_command_state *cs) +{ + struct xtables_rule_match *matchp; + struct xtables_match *m; + + if (cs->target == NULL || cs->target->parse == NULL || + cs->c < cs->target->option_offset || + cs->c >= cs->target->option_offset + XT_OPTION_OFFSET_SCALE) { + cs->target->parse(cs->c - cs->target->option_offset, cs->argv, + cs->invert, &cs->target->tflags, &cs->fw, + &cs->target->t); + return; + } + + for (matchp = cs->matches; matchp; matchp = matchp->next) { + m = matchp->match; + + if (matchp->completed || m->parse == NULL) + continue; + if (cs->c < m->option_offset || + cs->c >= m->option_offset + XT_OPTION_OFFSET_SCALE) + continue; + m->parse(cs->c - m->option_offset, cs->argv, cs->invert, + &m->mflags, &cs->fw, &m->m); + return; + } + + /* Try loading protocol */ + m = load_proto(cs); + if (m != NULL) { + size_t size; + + cs->proto_used = 1; + + size = IPT_ALIGN(sizeof(struct ipt_entry_match)) + m->size; + + m->m = xtables_calloc(1, size); + m->m->u.match_size = size; + strcpy(m->m->u.user.name, m->name); + m->m->u.user.revision = m->revision; + if (m->init != NULL) + m->init(m->m); + + opts = xtables_merge_options(iptables_globals.orig_opts, opts, + m->extra_opts, &m->option_offset); + if (opts == NULL) + xtables_error(OTHER_PROBLEM, "can't alloc memory!"); + + optind--; + return; + } + + if (cs->c == ':') + xtables_error(PARAMETER_PROBLEM, "option \"%s\" " + "requires an argument", cs->argv[optind-1]); + if (cs->c == '?') + xtables_error(PARAMETER_PROBLEM, "unknown option " + "\"%s\"", cs->argv[optind-1]); + xtables_error(PARAMETER_PROBLEM, "Unknown arg \"%s\"", optarg); +} + +static void command_jump(struct iptables_command_state *cs) +{ + size_t size; + + set_option(&cs->options, OPT_JUMP, &cs->fw.ip.invflags, cs->invert); + cs->jumpto = parse_target(optarg); + /* TRY_LOAD (may be chain name) */ + cs->target = xtables_find_target(cs->jumpto, XTF_TRY_LOAD); + + if (cs->target == NULL) + return; + + size = IPT_ALIGN(sizeof(struct ipt_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); + cs->target->t->u.user.revision = cs->target->revision; + if (cs->target->init != NULL) + cs->target->init(cs->target->t); + opts = xtables_merge_options(iptables_globals.orig_opts, opts, + cs->target->extra_opts, + &cs->target->option_offset); + if (opts == NULL) + xtables_error(OTHER_PROBLEM, "can't alloc memory!"); +} + +static void command_match(struct iptables_command_state *cs) +{ + struct xtables_match *m; + size_t size; + + if (cs->invert) + xtables_error(PARAMETER_PROBLEM, + "unexpected ! flag before --match"); + + m = xtables_find_match(optarg, XTF_LOAD_MUST_SUCCEED, &cs->matches); + size = IPT_ALIGN(sizeof(struct ipt_entry_match)) + m->size; + m->m = xtables_calloc(1, size); + m->m->u.match_size = size; + strcpy(m->m->u.user.name, m->name); + m->m->u.user.revision = m->revision; + if (m->init != NULL) + m->init(m->m); + if (m != m->next) { + /* Merge options for non-cloned matches */ + opts = xtables_merge_options(iptables_globals.orig_opts, opts, + m->extra_opts, &m->option_offset); + if (opts == NULL) + xtables_error(OTHER_PROBLEM, "can't alloc memory!"); + } +} + int do_command(int argc, char *argv[], char **table, struct iptc_handle **handle) { - struct ipt_entry fw, *e = NULL; - int invert = 0; + struct iptables_command_state cs; + struct ipt_entry *e = NULL; unsigned int nsaddrs = 0, ndaddrs = 0; struct in_addr *saddrs = NULL, *smasks = NULL; struct in_addr *daddrs = NULL, *dmasks = NULL; - int c, verbose = 0; + int 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; + unsigned int rulenum = 0, command = 0; const char *pcnt = NULL, *bcnt = NULL; int ret = 1; struct xtables_match *m; - struct xtables_rule_match *matches = NULL; struct xtables_rule_match *matchp; - struct xtables_target *target = NULL; struct xtables_target *t; - const char *jumpto = ""; - char *protocol = NULL; - int proto_used = 0; unsigned long long cnt; - memset(&fw, 0, sizeof(fw)); + memset(&cs, 0, sizeof(cs)); + cs.jumpto = ""; + cs.argv = argv; /* re-set optind to 0 in case do_command gets called * a second time */ @@ -1357,22 +1422,22 @@ int do_command(int argc, char *argv[], char **table, struct iptc_handle **handle opterr = 0; opts = xt_params->orig_opts; - while ((c = getopt_long(argc, argv, - "-A:D:R:I:L::S::M:F::Z::N:X::E:P:Vh::o:p:s:d:j:i:fbvnt:m:xc:g:", + while ((cs.c = getopt_long(argc, argv, + "-:A:D:R:I:L::S::M:F::Z::N:X::E:P:Vh::o:p:s:d:j:i:fbvnt:m:xc:g:", opts, NULL)) != -1) { - switch (c) { + switch (cs.c) { /* * Command selection */ case 'A': add_command(&command, CMD_APPEND, CMD_NONE, - invert); + cs.invert); chain = optarg; break; case 'D': add_command(&command, CMD_DELETE, CMD_NONE, - invert); + cs.invert); chain = optarg; if (optind < argc && argv[optind][0] != '-' && argv[optind][0] != '!') { @@ -1383,7 +1448,7 @@ int do_command(int argc, char *argv[], char **table, struct iptc_handle **handle case 'R': add_command(&command, CMD_REPLACE, CMD_NONE, - invert); + cs.invert); chain = optarg; if (optind < argc && argv[optind][0] != '-' && argv[optind][0] != '!') @@ -1396,7 +1461,7 @@ int do_command(int argc, char *argv[], char **table, struct iptc_handle **handle case 'I': add_command(&command, CMD_INSERT, CMD_NONE, - invert); + cs.invert); chain = optarg; if (optind < argc && argv[optind][0] != '-' && argv[optind][0] != '!') @@ -1406,7 +1471,7 @@ int do_command(int argc, char *argv[], char **table, struct iptc_handle **handle case 'L': add_command(&command, CMD_LIST, - CMD_ZERO | CMD_ZERO_NUM, invert); + CMD_ZERO | CMD_ZERO_NUM, cs.invert); if (optarg) chain = optarg; else if (optind < argc && argv[optind][0] != '-' && argv[optind][0] != '!') @@ -1418,7 +1483,7 @@ int do_command(int argc, char *argv[], char **table, struct iptc_handle **handle case 'S': add_command(&command, CMD_LIST_RULES, - CMD_ZERO|CMD_ZERO_NUM, invert); + CMD_ZERO|CMD_ZERO_NUM, cs.invert); if (optarg) chain = optarg; else if (optind < argc && argv[optind][0] != '-' && argv[optind][0] != '!') @@ -1430,7 +1495,7 @@ int do_command(int argc, char *argv[], char **table, struct iptc_handle **handle case 'F': add_command(&command, CMD_FLUSH, CMD_NONE, - invert); + cs.invert); if (optarg) chain = optarg; else if (optind < argc && argv[optind][0] != '-' && argv[optind][0] != '!') @@ -1439,7 +1504,7 @@ int do_command(int argc, char *argv[], char **table, struct iptc_handle **handle case 'Z': add_command(&command, CMD_ZERO, CMD_LIST|CMD_LIST_RULES, - invert); + cs.invert); if (optarg) chain = optarg; else if (optind < argc && argv[optind][0] != '-' && argv[optind][0] != '!') @@ -1461,13 +1526,13 @@ int do_command(int argc, char *argv[], char **table, struct iptc_handle **handle "chain name may not clash " "with target name\n"); add_command(&command, CMD_NEW_CHAIN, CMD_NONE, - invert); + cs.invert); chain = optarg; break; case 'X': add_command(&command, CMD_DELETE_CHAIN, CMD_NONE, - invert); + cs.invert); if (optarg) chain = optarg; else if (optind < argc && argv[optind][0] != '-' && argv[optind][0] != '!') @@ -1476,7 +1541,7 @@ int do_command(int argc, char *argv[], char **table, struct iptc_handle **handle case 'E': add_command(&command, CMD_RENAME_CHAIN, CMD_NONE, - invert); + cs.invert); chain = optarg; if (optind < argc && argv[optind][0] != '-' && argv[optind][0] != '!') @@ -1490,7 +1555,7 @@ int do_command(int argc, char *argv[], char **table, struct iptc_handle **handle case 'P': add_command(&command, CMD_SET_POLICY, CMD_NONE, - invert); + cs.invert); chain = optarg; if (optind < argc && argv[optind][0] != '-' && argv[optind][0] != '!') @@ -1506,84 +1571,58 @@ int do_command(int argc, char *argv[], char **table, struct iptc_handle **handle optarg = argv[optind]; /* iptables -p icmp -h */ - if (!matches && protocol) - xtables_find_match(protocol, - XTF_TRY_LOAD, &matches); + if (!cs.matches && cs.protocol) + xtables_find_match(cs.protocol, + XTF_TRY_LOAD, &cs.matches); - exit_printhelp(matches); + exit_printhelp(cs.matches); /* * Option selection */ case 'p': - xtables_check_inverse(optarg, &invert, &optind, argc, argv); - set_option(&options, OPT_PROTOCOL, &fw.ip.invflags, - invert); + xtables_check_inverse(optarg, &cs.invert, &optind, argc, argv); + set_option(&cs.options, OPT_PROTOCOL, &cs.fw.ip.invflags, + cs.invert); /* Canonicalize into lower case */ - for (protocol = optarg; *protocol; protocol++) - *protocol = tolower(*protocol); + for (cs.protocol = optarg; *cs.protocol; cs.protocol++) + *cs.protocol = tolower(*cs.protocol); - protocol = optarg; - fw.ip.proto = xtables_parse_protocol(protocol); + cs.protocol = optarg; + cs.fw.ip.proto = xtables_parse_protocol(cs.protocol); - if (fw.ip.proto == 0 - && (fw.ip.invflags & IPT_INV_PROTO)) + if (cs.fw.ip.proto == 0 + && (cs.fw.ip.invflags & IPT_INV_PROTO)) xtables_error(PARAMETER_PROBLEM, "rule would never match protocol"); break; case 's': - xtables_check_inverse(optarg, &invert, &optind, argc, argv); - set_option(&options, OPT_SOURCE, &fw.ip.invflags, - invert); + xtables_check_inverse(optarg, &cs.invert, &optind, argc, argv); + set_option(&cs.options, OPT_SOURCE, &cs.fw.ip.invflags, + cs.invert); shostnetworkmask = optarg; break; case 'd': - xtables_check_inverse(optarg, &invert, &optind, argc, argv); - set_option(&options, OPT_DESTINATION, &fw.ip.invflags, - invert); + xtables_check_inverse(optarg, &cs.invert, &optind, argc, argv); + set_option(&cs.options, OPT_DESTINATION, &cs.fw.ip.invflags, + cs.invert); dhostnetworkmask = optarg; break; #ifdef IPT_F_GOTO case 'g': - set_option(&options, OPT_JUMP, &fw.ip.invflags, - invert); - fw.ip.flags |= IPT_F_GOTO; - jumpto = parse_target(optarg); + set_option(&cs.options, OPT_JUMP, &cs.fw.ip.invflags, + cs.invert); + cs.fw.ip.flags |= IPT_F_GOTO; + cs.jumpto = parse_target(optarg); break; #endif case 'j': - set_option(&options, OPT_JUMP, &fw.ip.invflags, - invert); - jumpto = parse_target(optarg); - /* TRY_LOAD (may be chain name) */ - target = xtables_find_target(jumpto, XTF_TRY_LOAD); - - if (target) { - size_t size; - - size = IPT_ALIGN(sizeof(struct ipt_entry_target)) - + target->size; - - target->t = xtables_calloc(1, size); - target->t->u.target_size = size; - strcpy(target->t->u.user.name, jumpto); - target->t->u.user.revision = target->revision; - if (target->init != NULL) - target->init(target->t); - opts = xtables_merge_options( - iptables_globals.orig_opts, - opts, - target->extra_opts, - &target->option_offset); - if (opts == NULL) - xtables_error(OTHER_PROBLEM, - "can't alloc memory!"); - } + command_jump(&cs); break; @@ -1592,12 +1631,12 @@ int do_command(int argc, char *argv[], char **table, struct iptc_handle **handle xtables_error(PARAMETER_PROBLEM, "Empty interface is likely to be " "undesired"); - xtables_check_inverse(optarg, &invert, &optind, argc, argv); - set_option(&options, OPT_VIANAMEIN, &fw.ip.invflags, - invert); + xtables_check_inverse(optarg, &cs.invert, &optind, argc, argv); + set_option(&cs.options, OPT_VIANAMEIN, &cs.fw.ip.invflags, + cs.invert); xtables_parse_interface(optarg, - fw.ip.iniface, - fw.ip.iniface_mask); + cs.fw.ip.iniface, + cs.fw.ip.iniface_mask); break; case 'o': @@ -1605,77 +1644,50 @@ int do_command(int argc, char *argv[], char **table, struct iptc_handle **handle xtables_error(PARAMETER_PROBLEM, "Empty interface is likely to be " "undesired"); - xtables_check_inverse(optarg, &invert, &optind, argc, argv); - set_option(&options, OPT_VIANAMEOUT, &fw.ip.invflags, - invert); + xtables_check_inverse(optarg, &cs.invert, &optind, argc, argv); + set_option(&cs.options, OPT_VIANAMEOUT, &cs.fw.ip.invflags, + cs.invert); xtables_parse_interface(optarg, - fw.ip.outiface, - fw.ip.outiface_mask); + cs.fw.ip.outiface, + cs.fw.ip.outiface_mask); break; case 'f': - set_option(&options, OPT_FRAGMENT, &fw.ip.invflags, - invert); - fw.ip.flags |= IPT_F_FRAG; + set_option(&cs.options, OPT_FRAGMENT, &cs.fw.ip.invflags, + cs.invert); + cs.fw.ip.flags |= IPT_F_FRAG; break; case 'v': if (!verbose) - set_option(&options, OPT_VERBOSE, - &fw.ip.invflags, invert); + set_option(&cs.options, OPT_VERBOSE, + &cs.fw.ip.invflags, cs.invert); verbose++; break; - case 'm': { - size_t size; - - if (invert) - xtables_error(PARAMETER_PROBLEM, - "unexpected ! flag before --match"); - - m = xtables_find_match(optarg, XTF_LOAD_MUST_SUCCEED, - &matches); - size = IPT_ALIGN(sizeof(struct ipt_entry_match)) - + m->size; - m->m = xtables_calloc(1, size); - m->m->u.match_size = size; - strcpy(m->m->u.user.name, m->name); - m->m->u.user.revision = m->revision; - if (m->init != NULL) - m->init(m->m); - if (m != m->next) { - /* Merge options for non-cloned matches */ - opts = xtables_merge_options( - iptables_globals.orig_opts, - opts, - m->extra_opts, - &m->option_offset); - if (opts == NULL) - xtables_error(OTHER_PROBLEM, - "can't alloc memory!"); - } - } - break; + case 'm': + command_match(&cs); + break; case 'n': - set_option(&options, OPT_NUMERIC, &fw.ip.invflags, - invert); + set_option(&cs.options, OPT_NUMERIC, &cs.fw.ip.invflags, + cs.invert); break; case 't': - if (invert) + if (cs.invert) xtables_error(PARAMETER_PROBLEM, "unexpected ! flag before --table"); *table = optarg; break; case 'x': - set_option(&options, OPT_EXPANDED, &fw.ip.invflags, - invert); + set_option(&cs.options, OPT_EXPANDED, &cs.fw.ip.invflags, + cs.invert); break; case 'V': - if (invert) + if (cs.invert) printf("Not %s ;-)\n", prog_vers); else printf("%s v%s\n", @@ -1683,8 +1695,8 @@ int do_command(int argc, char *argv[], char **table, struct iptc_handle **handle exit(0); case '0': - set_option(&options, OPT_LINENUMBERS, &fw.ip.invflags, - invert); + set_option(&cs.options, OPT_LINENUMBERS, &cs.fw.ip.invflags, + cs.invert); break; case 'M': @@ -1693,8 +1705,8 @@ int do_command(int argc, char *argv[], char **table, struct iptc_handle **handle case 'c': - set_option(&options, OPT_COUNTERS, &fw.ip.invflags, - invert); + set_option(&cs.options, OPT_COUNTERS, &cs.fw.ip.invflags, + cs.invert); pcnt = optarg; bcnt = strchr(pcnt + 1, ','); if (bcnt) @@ -1711,23 +1723,23 @@ int do_command(int argc, char *argv[], char **table, struct iptc_handle **handle xtables_error(PARAMETER_PROBLEM, "-%c packet counter not numeric", opt2char(OPT_COUNTERS)); - fw.counters.pcnt = cnt; + cs.fw.counters.pcnt = cnt; if (sscanf(bcnt, "%llu", &cnt) != 1) xtables_error(PARAMETER_PROBLEM, "-%c byte counter not numeric", opt2char(OPT_COUNTERS)); - fw.counters.bcnt = cnt; + cs.fw.counters.bcnt = cnt; break; case 1: /* non option */ if (optarg[0] == '!' && optarg[1] == '\0') { - if (invert) + if (cs.invert) xtables_error(PARAMETER_PROBLEM, "multiple consecutive ! not" " allowed"); - invert = TRUE; + cs.invert = TRUE; optarg[0] = '\0'; continue; } @@ -1735,127 +1747,25 @@ int do_command(int argc, char *argv[], char **table, struct iptc_handle **handle exit_tryhelp(2); default: - if (target == NULL || target->parse == NULL || - c < target->option_offset || - c >= target->option_offset + XT_OPTION_OFFSET_SCALE || - !target->parse(c - target->option_offset, - argv, invert, - &target->tflags, - &fw, &target->t)) { - for (matchp = matches; matchp; matchp = matchp->next) { - if (matchp->completed || - matchp->match->parse == NULL) - continue; - if (c < matchp->match->option_offset || - c >= matchp->match->option_offset + XT_OPTION_OFFSET_SCALE) - continue; - if (matchp->match->parse(c - matchp->match->option_offset, - argv, invert, - &matchp->match->mflags, - &fw, - &matchp->match->m)) - break; - } - m = matchp ? matchp->match : NULL; - - /* If you listen carefully, you can - actually hear this code suck. */ - - /* some explanations (after four different bugs - * in 3 different releases): If we encounter a - * parameter, that has not been parsed yet, - * it's not an option of an explicitly loaded - * match or a target. However, we support - * implicit loading of the protocol match - * extension. '-p tcp' means 'l4 proto 6' and - * at the same time 'load tcp protocol match on - * demand if we specify --dport'. - * - * To make this work, we need to make sure: - * - the parameter has not been parsed by - * a match (m above) - * - a protocol has been specified - * - the protocol extension has not been - * loaded yet, or is loaded and unused - * [think of iptables-restore!] - * - the protocol extension can be successively - * loaded - */ - if (m == NULL - && protocol - && (!find_proto(protocol, XTF_DONT_LOAD, - options&OPT_NUMERIC, NULL) - || (find_proto(protocol, XTF_DONT_LOAD, - options&OPT_NUMERIC, NULL) - && (proto_used == 0)) - ) - && (m = find_proto(protocol, XTF_TRY_LOAD, - options&OPT_NUMERIC, &matches))) { - /* Try loading protocol */ - size_t size; - - proto_used = 1; - - size = IPT_ALIGN(sizeof(struct ipt_entry_match)) - + m->size; - - m->m = xtables_calloc(1, size); - m->m->u.match_size = size; - strcpy(m->m->u.user.name, m->name); - m->m->u.user.revision = m->revision; - if (m->init != NULL) - m->init(m->m); - - opts = xtables_merge_options( - iptables_globals.orig_opts, - opts, - m->extra_opts, - &m->option_offset); - if (opts == NULL) - xtables_error(OTHER_PROBLEM, - "can't alloc memory!"); - - optind--; - continue; - } - if (!m) { - if (c == '?') { - if (optopt) { - xtables_error( - PARAMETER_PROBLEM, - "option `%s' " - "requires an " - "argument", - argv[optind-1]); - } else { - xtables_error( - PARAMETER_PROBLEM, - "unknown option " - "`%s'", - argv[optind-1]); - } - } - xtables_error(PARAMETER_PROBLEM, - "Unknown arg `%s'", optarg); - } - } + command_default(&cs); + break; } - invert = FALSE; + cs.invert = FALSE; } if (strcmp(*table, "nat") == 0 && ((policy != NULL && strcmp(policy, "DROP") == 0) || - (jumpto != NULL && strcmp(jumpto, "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"); - for (matchp = matches; matchp; matchp = matchp->next) + for (matchp = cs.matches; matchp; matchp = matchp->next) if (matchp->match->final_check != NULL) matchp->match->final_check(matchp->match->mflags); - if (target != NULL && target->final_check != NULL) - target->final_check(target->tflags); + if (cs.target != NULL && cs.target->final_check != NULL) + cs.target->final_check(cs.target->tflags); /* Fix me: must put inverse options checking here --MN */ @@ -1864,14 +1774,14 @@ int do_command(int argc, char *argv[], char **table, struct iptc_handle **handle "unknown arguments found on commandline"); if (!command) xtables_error(PARAMETER_PROBLEM, "no command specified"); - if (invert) + if (cs.invert) xtables_error(PARAMETER_PROBLEM, "nothing appropriate following !"); if (command & (CMD_REPLACE | CMD_INSERT | CMD_DELETE | CMD_APPEND)) { - if (!(options & OPT_DESTINATION)) + if (!(cs.options & OPT_DESTINATION)) dhostnetworkmask = "0.0.0.0/0"; - if (!(options & OPT_SOURCE)) + if (!(cs.options & OPT_SOURCE)) shostnetworkmask = "0.0.0.0/0"; } @@ -1884,7 +1794,7 @@ int do_command(int argc, char *argv[], char **table, struct iptc_handle **handle &dmasks, &ndaddrs); if ((nsaddrs > 1 || ndaddrs > 1) && - (fw.ip.invflags & (IPT_INV_SRCIP | IPT_INV_DSTIP))) + (cs.fw.ip.invflags & (IPT_INV_SRCIP | IPT_INV_DSTIP))) xtables_error(PARAMETER_PROBLEM, "! not allowed with multiple" " source or destination IP addresses"); @@ -1892,7 +1802,7 @@ int do_command(int argc, char *argv[], char **table, struct iptc_handle **handle xtables_error(PARAMETER_PROBLEM, "Replacement rule does not " "specify a unique address"); - generic_opt_check(command, options); + generic_opt_check(command, cs.options); if (chain != NULL && strlen(chain) >= XT_EXTENSION_MAXNAMELEN) xtables_error(PARAMETER_PROBLEM, @@ -1919,7 +1829,7 @@ int do_command(int argc, char *argv[], char **table, struct iptc_handle **handle if (strcmp(chain, "PREROUTING") == 0 || strcmp(chain, "INPUT") == 0) { /* -o not valid with incoming packets. */ - if (options & OPT_VIANAMEOUT) + if (cs.options & OPT_VIANAMEOUT) xtables_error(PARAMETER_PROBLEM, "Can't use -%c with %s\n", opt2char(OPT_VIANAMEOUT), @@ -1929,59 +1839,60 @@ int do_command(int argc, char *argv[], char **table, struct iptc_handle **handle if (strcmp(chain, "POSTROUTING") == 0 || strcmp(chain, "OUTPUT") == 0) { /* -i not valid with outgoing packets */ - if (options & OPT_VIANAMEIN) + if (cs.options & OPT_VIANAMEIN) xtables_error(PARAMETER_PROBLEM, "Can't use -%c with %s\n", opt2char(OPT_VIANAMEIN), chain); } - if (target && iptc_is_chain(jumpto, *handle)) { + if (cs.target && iptc_is_chain(cs.jumpto, *handle)) { fprintf(stderr, "Warning: using chain %s, not extension\n", - jumpto); + cs.jumpto); - if (target->t) - free(target->t); + if (cs.target->t) + free(cs.target->t); - target = NULL; + cs.target = NULL; } /* If they didn't specify a target, or it's a chain name, use standard. */ - if (!target - && (strlen(jumpto) == 0 - || iptc_is_chain(jumpto, *handle))) { + if (!cs.target + && (strlen(cs.jumpto) == 0 + || iptc_is_chain(cs.jumpto, *handle))) { size_t size; - target = xtables_find_target(IPT_STANDARD_TARGET, + cs.target = xtables_find_target(IPT_STANDARD_TARGET, XTF_LOAD_MUST_SUCCEED); size = sizeof(struct ipt_entry_target) - + target->size; - target->t = xtables_calloc(1, size); - target->t->u.target_size = size; - strcpy(target->t->u.user.name, jumpto); - if (!iptc_is_chain(jumpto, *handle)) - target->t->u.user.revision = target->revision; - if (target->init != NULL) - target->init(target->t); + + 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); + if (!iptc_is_chain(cs.jumpto, *handle)) + cs.target->t->u.user.revision = cs.target->revision; + if (cs.target->init != NULL) + cs.target->init(cs.target->t); } - if (!target) { + if (!cs.target) { /* it is no chain, and we can't load a plugin. * We cannot know if the plugin is corrupt, non * existant OR if the user just misspelled a * chain. */ #ifdef IPT_F_GOTO - if (fw.ip.flags & IPT_F_GOTO) + if (cs.fw.ip.flags & IPT_F_GOTO) xtables_error(PARAMETER_PROBLEM, - "goto '%s' is not a chain\n", jumpto); + "goto '%s' is not a chain\n", + cs.jumpto); #endif - xtables_find_target(jumpto, XTF_LOAD_MUST_SUCCEED); + xtables_find_target(cs.jumpto, XTF_LOAD_MUST_SUCCEED); } else { - e = generate_entry(&fw, matches, target->t); - free(target->t); + e = generate_entry(&cs.fw, cs.matches, cs.target->t); + free(cs.target->t); } } @@ -1990,15 +1901,15 @@ int do_command(int argc, char *argv[], char **table, struct iptc_handle **handle ret = append_entry(chain, e, nsaddrs, saddrs, smasks, ndaddrs, daddrs, dmasks, - options&OPT_VERBOSE, + cs.options&OPT_VERBOSE, *handle); break; case CMD_DELETE: ret = delete_entry(chain, e, nsaddrs, saddrs, smasks, ndaddrs, daddrs, dmasks, - options&OPT_VERBOSE, - *handle, matches, target); + cs.options&OPT_VERBOSE, + *handle, cs.matches, cs.target); break; case CMD_DELETE_NUM: ret = iptc_delete_num_entry(chain, rulenum - 1, *handle); @@ -2006,20 +1917,20 @@ int do_command(int argc, char *argv[], char **table, struct iptc_handle **handle case CMD_REPLACE: ret = replace_entry(chain, e, rulenum - 1, saddrs, smasks, daddrs, dmasks, - options&OPT_VERBOSE, *handle); + cs.options&OPT_VERBOSE, *handle); break; case CMD_INSERT: ret = insert_entry(chain, e, rulenum - 1, nsaddrs, saddrs, smasks, ndaddrs, daddrs, dmasks, - options&OPT_VERBOSE, + cs.options&OPT_VERBOSE, *handle); break; case CMD_FLUSH: - ret = flush_entries(chain, options&OPT_VERBOSE, *handle); + ret = flush_entries(chain, cs.options&OPT_VERBOSE, *handle); break; case CMD_ZERO: - ret = zero_entries(chain, options&OPT_VERBOSE, *handle); + ret = zero_entries(chain, cs.options&OPT_VERBOSE, *handle); break; case CMD_ZERO_NUM: ret = iptc_zero_counter(chain, rulenum, *handle); @@ -2029,14 +1940,14 @@ int do_command(int argc, char *argv[], char **table, struct iptc_handle **handle case CMD_LIST|CMD_ZERO_NUM: ret = list_entries(chain, rulenum, - options&OPT_VERBOSE, - options&OPT_NUMERIC, - options&OPT_EXPANDED, - options&OPT_LINENUMBERS, + cs.options&OPT_VERBOSE, + cs.options&OPT_NUMERIC, + cs.options&OPT_EXPANDED, + cs.options&OPT_LINENUMBERS, *handle); if (ret && (command & CMD_ZERO)) ret = zero_entries(chain, - options&OPT_VERBOSE, *handle); + cs.options&OPT_VERBOSE, *handle); if (ret && (command & CMD_ZERO_NUM)) ret = iptc_zero_counter(chain, rulenum, *handle); break; @@ -2045,11 +1956,11 @@ int do_command(int argc, char *argv[], char **table, struct iptc_handle **handle case CMD_LIST_RULES|CMD_ZERO_NUM: ret = list_rules(chain, rulenum, - options&OPT_VERBOSE, + cs.options&OPT_VERBOSE, *handle); if (ret && (command & CMD_ZERO)) ret = zero_entries(chain, - options&OPT_VERBOSE, *handle); + cs.options&OPT_VERBOSE, *handle); if (ret && (command & CMD_ZERO_NUM)) ret = iptc_zero_counter(chain, rulenum, *handle); break; @@ -2057,13 +1968,13 @@ int do_command(int argc, char *argv[], char **table, struct iptc_handle **handle ret = iptc_create_chain(chain, *handle); break; case CMD_DELETE_CHAIN: - ret = delete_chain(chain, options&OPT_VERBOSE, *handle); + ret = delete_chain(chain, cs.options&OPT_VERBOSE, *handle); break; case CMD_RENAME_CHAIN: ret = iptc_rename_chain(chain, newname, *handle); break; case CMD_SET_POLICY: - ret = iptc_set_policy(chain, policy, options&OPT_COUNTERS ? &fw.counters : NULL, *handle); + ret = iptc_set_policy(chain, policy, cs.options&OPT_COUNTERS ? &cs.fw.counters : NULL, *handle); break; default: /* We should never reach this... */ @@ -2073,7 +1984,7 @@ int do_command(int argc, char *argv[], char **table, struct iptc_handle **handle if (verbose > 1) dump_entries(*handle); - clear_rule_matches(&matches); + clear_rule_matches(&cs.matches); if (e != NULL) { free(e); @@ -1,3 +1,6 @@ +#include <netdb.h> +#include <stdbool.h> +#include <stdint.h> #include <stdio.h> #include <xtables.h> #include "xshared.h" @@ -29,3 +32,70 @@ void print_extension_helps(const struct xtables_target *t, m->match->help(); } } + +const char * +proto_to_name(uint8_t proto, int nolookup) +{ + unsigned int i; + + if (proto && !nolookup) { + struct protoent *pent = getprotobynumber(proto); + if (pent) + return pent->p_name; + } + + for (i = 0; xtables_chain_protos[i].name != NULL; ++i) + if (xtables_chain_protos[i].num == proto) + return xtables_chain_protos[i].name; + + return NULL; +} + +static struct xtables_match * +find_proto(const char *pname, enum xtables_tryload tryload, + int nolookup, struct xtables_rule_match **matches) +{ + unsigned int proto; + + if (xtables_strtoui(pname, NULL, &proto, 0, UINT8_MAX)) { + const char *protoname = proto_to_name(proto, nolookup); + + if (protoname) + return xtables_find_match(protoname, tryload, matches); + } else + return xtables_find_match(pname, tryload, matches); + + return NULL; +} + +/* + * Some explanations (after four different bugs in 3 different releases): If + * we encounter a parameter, that has not been parsed yet, it's not an option + * of an explicitly loaded match or a target. However, we support implicit + * loading of the protocol match extension. '-p tcp' means 'l4 proto 6' and at + * the same time 'load tcp protocol match on demand if we specify --dport'. + * + * To make this work, we need to make sure: + * - the parameter has not been parsed by a match (m above) + * - a protocol has been specified + * - the protocol extension has not been loaded yet, or is loaded and unused + * [think of ip6tables-restore!] + * - the protocol extension can be successively loaded + */ +static bool should_load_proto(struct iptables_command_state *cs) +{ + if (cs->protocol == NULL) + return false; + if (find_proto(cs->protocol, XTF_DONT_LOAD, + cs->options & OPT_NUMERIC, NULL) != NULL) + return true; + return cs->proto_used; +} + +struct xtables_match *load_proto(struct iptables_command_state *cs) +{ + if (!should_load_proto(cs)) + return NULL; + return find_proto(cs->protocol, XTF_TRY_LOAD, + cs->options & OPT_NUMERIC, &cs->matches); +} @@ -1,14 +1,51 @@ #ifndef IPTABLES_XSHARED_H #define IPTABLES_XSHARED_H 1 +#include <stdint.h> +#include <linux/netfilter_ipv4/ip_tables.h> +#include <linux/netfilter_ipv6/ip6_tables.h> + +enum { + OPT_NONE = 0, + OPT_NUMERIC = 1 << 0, + OPT_SOURCE = 1 << 1, + OPT_DESTINATION = 1 << 2, + OPT_PROTOCOL = 1 << 3, + OPT_JUMP = 1 << 4, + OPT_VERBOSE = 1 << 5, + OPT_EXPANDED = 1 << 6, + OPT_VIANAMEIN = 1 << 7, + OPT_VIANAMEOUT = 1 << 8, + OPT_LINENUMBERS = 1 << 9, + OPT_COUNTERS = 1 << 10, +}; + struct xtables_rule_match; struct xtables_target; +struct iptables_command_state { + union { + struct ipt_entry fw; + struct ip6t_entry fw6; + }; + int invert; + int c; + unsigned int options; + struct xtables_rule_match *matches; + struct xtables_target *target; + char *protocol; + int proto_used; + const char *jumpto; + char **argv; +}; + enum { XT_OPTION_OFFSET_SCALE = 256, }; extern void print_extension_helps(const struct xtables_target *, const struct xtables_rule_match *); +extern const char *proto_to_name(uint8_t, int); +extern struct xtables_match *load_proto(struct iptables_command_state *); #endif /* IPTABLES_XSHARED_H */ |