diff -urN a/extensions/.policy-test b/extensions/.policy-test --- a/extensions/.policy-test 2004-02-23 20:39:37.000000000 +0100 +++ b/extensions/.policy-test 2004-03-04 21:41:39.000000000 +0100 @@ -1,2 +1,3 @@ #!/bin/sh -[ -f $KERNEL_DIR/net/ipv4/netfilter/ipt_policy.c -a -f $KERNEL_DIR/include/linux/netfilter_ipv4/ipt_policy.h ] && echo policy +# +[ -f $KERNEL_DIR/include/linux/netfilter_ipv4/ipt_policy.h ] && echo policy diff -urN a/extensions/libipt_policy.c b/extensions/libipt_policy.c --- a/extensions/libipt_policy.c 2004-02-23 20:38:37.000000000 +0100 +++ b/extensions/libipt_policy.c 2004-03-04 21:41:32.000000000 +0100 @@ -1,3 +1,4 @@ +/* Shared library add-on to iptables to add policy support. */ #include #include #include @@ -14,72 +15,82 @@ #include #include +/* + * HACK: global pointer to current matchinfo for making + * final checks and adjustments in final_check. + */ +static struct ipt_policy_info *policy_info; + static void help(void) { printf( "policy v%s options:\n" -"[!] --reqid reqid Match reqid\n" -"[!] --spi spi Match SPI\n" -"[!] --proto proto Match protocol (ah/esp/ipcomp)\n" -"[!] --mode mode Match mode (transport/tunnel)\n" -"[!] --local addr/mask Match local tunnel endpoint\n" -"[!] --remote addr/mask Match remote tunnel endpoint\n" -" --path Match path instead of single element at\n" -" any position\n" -" --next Begin next element in path\n", +" --dir in|out match policy applied during decapsulation/\n" +" policy to be applied during encapsulation\n" +" --pol none|ipsec match policy\n" +" --strict match entire policy instead of single element\n" +" at any position\n" +"[!] --reqid reqid match reqid\n" +"[!] --spi spi match SPI\n" +"[!] --proto proto match protocol (ah/esp/ipcomp)\n" +"[!] --mode mode match mode (transport/tunnel)\n" +"[!] --tunnel-src addr/mask match tunnel source\n" +"[!] --tunnel-dst addr/mask match tunnel destination\n" +" --next begin next element in policy\n", IPTABLES_VERSION); } -static struct option opts[] = { +static struct option opts[] = +{ { - .name = "reqid", + .name = "dir", .has_arg = 1, - .flag = 0, .val = '1', }, { - .name = "spi", + .name = "pol", .has_arg = 1, - .flag = 0, - .val = '2' + .val = '2', }, { - .name = "local", - .has_arg = 1, - .flag = 0, + .name = "strict", .val = '3' }, { - .name = "remote", + .name = "reqid", .has_arg = 1, - .flag = 0, - .val = '4' + .val = '4', }, { - .name = "proto", + .name = "spi", .has_arg = 1, - .flag = 0, .val = '5' }, { - .name = "mode", + .name = "tunnel-src", .has_arg = 1, - .flag = 0, .val = '6' }, { - .name = "path", - .has_arg = 0, - .flag = 0, + .name = "tunnel-dst", + .has_arg = 1, .val = '7' }, { - .name = "next", - .has_arg = 0, - .flag = 0, + .name = "proto", + .has_arg = 1, .val = '8' }, - { 0 } + { + .name = "mode", + .has_arg = 1, + .val = '9' + }, + { + .name = "next", + .val = 'a' + }, + { } }; static void init(struct ipt_entry_match *m, unsigned int *nfcache) @@ -87,154 +98,201 @@ *nfcache |= NFC_UNKNOWN; } +static int parse_direction(char *s) +{ + if (strcmp(s, "in") == 0) + return POLICY_MATCH_IN; + if (strcmp(s, "out") == 0) + return POLICY_MATCH_OUT; + exit_error(PARAMETER_PROBLEM, "policy_match: invalid dir `%s'", s); +} + +static int parse_policy(char *s) +{ + if (strcmp(s, "none") == 0) + return POLICY_MATCH_NONE; + if (strcmp(s, "ipsec") == 0) + return 0; + exit_error(PARAMETER_PROBLEM, "policy match: invalid policy `%s'", s); +} + static int parse_mode(char *s) { if (strcmp(s, "transport") == 0) - return SECPATH_MODE_TRANSPORT; + return POLICY_MODE_TRANSPORT; if (strcmp(s, "tunnel") == 0) - return SECPATH_MODE_TUNNEL; - return -EINVAL; + return POLICY_MODE_TUNNEL; + exit_error(PARAMETER_PROBLEM, "policy match: invalid mode `%s'", s); } -static int parse(int c, char **argv, int invert, unsigned int *i, +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->path[*i]; + struct ipt_policy_elem *e = &info->pol[info->len]; struct in_addr *addr = NULL, mask; - struct protoent *p; unsigned int naddr = 0; - int mode, proto; + int mode; check_inverse(optarg, &invert, &optind, 0); switch (c) { case '1': + if (info->flags & (POLICY_MATCH_IN|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 & 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 |= POLICY_MATCH_STRICT; + break; + case '4': if (e->match.reqid) exit_error(PARAMETER_PROBLEM, - "Can't specify --reqid twice"); + "policy match: double --reqid option"); e->match.reqid = 1; e->invert.reqid = invert; e->reqid = strtol(argv[optind-1], NULL, 10); break; - case '2': + case '5': if (e->match.spi) exit_error(PARAMETER_PROBLEM, - "Can't specify --spi twice"); + "policy match: double --spi option"); e->match.spi = 1; e->invert.spi = invert; e->spi = strtol(argv[optind-1], NULL, 0x10); break; - case '3': - if (e->match.daddr) - exit_error(PARAMETER_PROBLEM, - "Can't specify --local twice"); - - parse_hostnetworkmask(argv[optind-1], &addr, &mask, &naddr); - if (naddr > 1) - exit_error(PARAMETER_PROBLEM, - "Multiple IP addresses are not allowed"); - - e->match.daddr = 1; - e->invert.daddr = invert; - e->daddr = addr[0].s_addr; - e->dmask = mask.s_addr; - break; - case '4': + case '6': if (e->match.saddr) exit_error(PARAMETER_PROBLEM, - "Can't specify --remote twice"); + "policy match: double --tunnel-src option"); parse_hostnetworkmask(argv[optind-1], &addr, &mask, &naddr); if (naddr > 1) exit_error(PARAMETER_PROBLEM, - "Multiple IP addresses are not allowed"); + "policy match: name resolves to multiple IPs"); e->match.saddr = 1; e->invert.saddr = invert; e->saddr = addr[0].s_addr; e->smask = mask.s_addr; break; - case '5': - if (e->match.proto) + 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, - "Can't specify --proto twice"); + "policy match: name resolves to multiple IPs"); - p = getprotobyname(argv[optind-1]); - if (p != NULL) - proto = p->p_proto; - else if (!(proto = atoi(argv[optind-1]))) + e->match.daddr = 1; + e->invert.daddr = invert; + e->daddr = addr[0].s_addr; + e->dmask = mask.s_addr; + break; + case '8': + if (e->match.proto) exit_error(PARAMETER_PROBLEM, - "Unknown protocol `%s'\n", - argv[optind-1]); + "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; - e->proto = proto; break; - case '6': + case '9': if (e->match.mode) exit_error(PARAMETER_PROBLEM, - "Can't specify --mode twice"); + "policy match: double --mode option"); mode = parse_mode(argv[optind-1]); - if (mode < 0) - exit_error(PARAMETER_PROBLEM, - "Unknown mode `%s'\n", - argv[optind-1]); - e->match.mode = 1; e->invert.mode = invert; e->mode = mode; break; - case '7': - if (info->flags & MATCH_PATH) - exit_error(PARAMETER_PROBLEM, - "Can't specify --path twice"); - + case 'a': if (invert) exit_error(PARAMETER_PROBLEM, - "Can't invert `--path' option"); + "policy match: can't invert --next option"); - info->flags |= MATCH_PATH; - break; - case '8': - if (invert) + if (++info->len == POLICY_MAX_ELEM) exit_error(PARAMETER_PROBLEM, - "Can't invert `--next' option"); - - if (++(*i) == SECPATH_MAX_DEPTH) - exit_error(PARAMETER_PROBLEM, - "Maximum path depth reached"); - + "policy match: maximum policy depth reached"); break; default: return 0; } - info->len = *i + 1; + policy_info = info; return 1; } static void final_check(unsigned int flags) { - return; -} + struct ipt_policy_info *info = policy_info; + struct ipt_policy_elem *e; + int i; -static void print_proto(char *prefix, u_int8_t proto, int numeric) -{ - struct protoent *p = NULL; + if (info == NULL) + exit_error(PARAMETER_PROBLEM, + "policy match: no parameters given"); - if (!numeric) - p = getprotobynumber(proto); - if (p == NULL) - printf("%sproto %u ", prefix, proto); - else - printf("%sproto %s ", prefix, p->p_name); + if (!(info->flags & (POLICY_MATCH_IN|POLICY_MATCH_OUT))) + exit_error(PARAMETER_PROBLEM, + "policy match: neither --in nor --out specified"); + + if (info->flags & POLICY_MATCH_NONE) { + if (info->flags & POLICY_MATCH_STRICT) + exit_error(PARAMETER_PROBLEM, + "policy match: policy none but --strict given"); + + if (info->len != 0) + exit_error(PARAMETER_PROBLEM, + "policy match: policy none but policy given"); + } else + info->len++; /* increase len by 1, no --next after last element */ + + if (!(info->flags & POLICY_MATCH_STRICT) && info->len > 1) + exit_error(PARAMETER_PROBLEM, + "policy match: multiple elements but no --strict"); + + for (i = 0; i < info->len; i++) { + e = &info->pol[i]; + if ((e->match.saddr || e->match.daddr) + && ((e->mode == POLICY_MODE_TUNNEL && e->invert.mode) || + (e->mode == POLICY_MODE_TRANSPORT && !e->invert.mode))) + exit_error(PARAMETER_PROBLEM, + "policy match: --tunnel-src/--tunnel-dst " + "is only valid in tunnel mode"); + } } static void print_mode(char *prefix, u_int8_t mode, int numeric) @@ -242,10 +300,10 @@ printf("%smode ", prefix); switch (mode) { - case SECPATH_MODE_TRANSPORT: + case POLICY_MODE_TRANSPORT: printf("transport "); break; - case SECPATH_MODE_TUNNEL: + case POLICY_MODE_TUNNEL: printf("tunnel "); break; default: @@ -273,7 +331,7 @@ } if (e->match.proto) { PRINT_INVERT(e->invert.proto); - print_proto(prefix, e->proto, numeric); + printf("%sproto %s ", prefix, proto_to_name(e->proto, numeric)); } if (e->match.mode) { PRINT_INVERT(e->invert.mode); @@ -281,18 +339,34 @@ } if (e->match.daddr) { PRINT_INVERT(e->invert.daddr); - printf("%slocal %s%s ", prefix, + printf("%stunnel-dst %s%s ", prefix, addr_to_dotted((struct in_addr *)&e->daddr), mask_to_dotted((struct in_addr *)&e->dmask)); } if (e->match.saddr) { PRINT_INVERT(e->invert.saddr); - printf("%sremote %s%s ", prefix, + printf("%stunnel-src %s%s ", prefix, addr_to_dotted((struct in_addr *)&e->saddr), mask_to_dotted((struct in_addr *)&e->smask)); } } +static void print_flags(char *prefix, const struct ipt_policy_info *info) +{ + if (info->flags & POLICY_MATCH_IN) + printf("%sdir in ", prefix); + else + printf("%sdir out ", prefix); + + if (info->flags & POLICY_MATCH_NONE) + printf("%spol none ", prefix); + else + printf("%spol ipsec ", prefix); + + if (info->flags & POLICY_MATCH_STRICT) + printf("%sstrict ", prefix); +} + static void print(const struct ipt_ip *ip, const struct ipt_entry_match *match, int numeric) @@ -300,14 +374,12 @@ const struct ipt_policy_info *info = (void *)match->data; unsigned int i; - printf ("policy match "); - if (info->flags & MATCH_PATH) - printf("path "); - + printf("policy match "); + print_flags("", info); for (i = 0; i < info->len; i++) { if (info->len > 1) printf("[%u] ", i); - print_entry("", &info->path[i], numeric); + print_entry("", &info->pol[i], numeric); } printf("\n"); @@ -318,11 +390,9 @@ const struct ipt_policy_info *info = (void *)match->data; unsigned int i; - if (info->flags & MATCH_PATH) - printf("--path "); - + print_flags("--", info); for (i = 0; i < info->len; i++) { - print_entry("--", &info->path[i], 0); + print_entry("--", &info->pol[i], 0); if (i + 1 < info->len) printf("--next "); } @@ -332,18 +402,17 @@ struct iptables_match policy = { - NULL, - "policy", - IPTABLES_VERSION, - IPT_ALIGN(sizeof(struct ipt_policy_info)), - IPT_ALIGN(sizeof(struct ipt_policy_info)), - &help, - &init, - &parse, - &final_check, - &print, - &save, - opts + .name = "policy", + .version = IPTABLES_VERSION, + .size = IPT_ALIGN(sizeof(struct ipt_policy_info)), + .userspacesize = IPT_ALIGN(sizeof(struct ipt_policy_info)), + .help = help, + .init = init, + .parse = parse, + .final_check = final_check, + .print = print, + .save = save, + .extra_opts = opts }; void _init(void) diff -urN a/include/iptables.h b/include/iptables.h --- a/include/iptables.h 2004-03-04 21:37:40.000000000 +0100 +++ b/include/iptables.h 2004-03-04 21:38:36.000000000 +0100 @@ -122,6 +122,7 @@ extern void register_match(struct iptables_match *me); extern void register_target(struct iptables_target *me); +extern char *proto_to_name(u_int8_t proto, int nolookup); extern struct in_addr *dotted_to_addr(const char *dotted); extern char *addr_to_dotted(const struct in_addr *addrp); extern char *addr_to_anyname(const struct in_addr *addr); diff -urN a/iptables.c b/iptables.c --- a/iptables.c 2004-02-24 18:28:50.000000000 +0100 +++ b/iptables.c 2004-03-04 21:39:18.000000000 +0100 @@ -235,11 +235,12 @@ { "icmp", IPPROTO_ICMP }, { "esp", IPPROTO_ESP }, { "ah", IPPROTO_AH }, + { "ipcomp", IPPROTO_COMP }, { "sctp", IPPROTO_SCTP }, { "all", 0 }, }; -static char * +char * proto_to_name(u_int8_t proto, int nolookup) { unsigned int i;