diff -Nur iptables.org/extensions/.policy-test iptables/extensions/.policy-test --- iptables.org/extensions/.policy-test 1970-01-01 01:00:00.000000000 +0100 +++ iptables/extensions/.policy-test 2004-05-18 12:39:55.000000000 +0200 @@ -0,0 +1,3 @@ +#!/bin/sh +# +[ -f $KERNEL_DIR/include/linux/netfilter_ipv4/ipt_policy.h ] && echo policy diff -Nur iptables.org/extensions/.policy-test6 iptables/extensions/.policy-test6 --- iptables.org/extensions/.policy-test6 1970-01-01 01:00:00.000000000 +0100 +++ iptables/extensions/.policy-test6 2004-05-18 12:39:55.000000000 +0200 @@ -0,0 +1,3 @@ +#!/bin/sh +# +[ -f $KERNEL_DIR/include/linux/netfilter_ipv6/ip6t_policy.h ] && echo policy diff -Nur iptables.org/extensions/libip6t_policy.c iptables/extensions/libip6t_policy.c --- iptables.org/extensions/libip6t_policy.c 1970-01-01 01:00:00.000000000 +0100 +++ iptables/extensions/libip6t_policy.c 2004-05-18 12:39:55.000000000 +0200 @@ -0,0 +1,471 @@ +/* Shared library add-on to iptables to add policy support. */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +/* + * HACK: global pointer to current matchinfo for making + * final checks and adjustments in final_check. + */ +static struct ip6t_policy_info *policy_info; + +static void help(void) +{ + printf( +"policy v%s options:\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/masklen match tunnel source\n" +"[!] --tunnel-dst addr/masklen match tunnel destination\n" +" --next begin next element in policy\n", + IPTABLES_VERSION); +} + +static struct option opts[] = +{ + { + .name = "dir", + .has_arg = 1, + .val = '1', + }, + { + .name = "pol", + .has_arg = 1, + .val = '2', + }, + { + .name = "strict", + .val = '3' + }, + { + .name = "reqid", + .has_arg = 1, + .val = '4', + }, + { + .name = "spi", + .has_arg = 1, + .val = '5' + }, + { + .name = "tunnel-src", + .has_arg = 1, + .val = '6' + }, + { + .name = "tunnel-dst", + .has_arg = 1, + .val = '7' + }, + { + .name = "proto", + .has_arg = 1, + .val = '8' + }, + { + .name = "mode", + .has_arg = 1, + .val = '9' + }, + { + .name = "next", + .val = 'a' + }, + { } +}; + +/* FIXME - Duplicated code from ip6tables.c */ +/* Duplicated to stop too many changes in other files .... */ +static void +in6addrcpy(struct in6_addr *dst, struct in6_addr *src) +{ + memcpy(dst, src, sizeof(struct in6_addr)); + /* dst->s6_addr = src->s6_addr; */ +} + +static char * +addr_to_numeric(const struct in6_addr *addrp) +{ + /* 0000:0000:0000:0000:0000:000.000.000.000 + * 0000:0000:0000:0000:0000:0000:0000:0000 */ + static char buf[50+1]; + return (char *)inet_ntop(AF_INET6, addrp, buf, sizeof(buf)); +} + +static char * +mask_to_numeric(const struct in6_addr *addrp) +{ + static char buf[50+2]; + int l = ipv6_prefix_length(addrp); + if (l == -1) { + strcpy(buf, "/"); + strcat(buf, addr_to_numeric(addrp)); + return buf; + } + sprintf(buf, "/%d", l); + return buf; +} + +/* These should be in include/ip6tables.h... */ +extern u_int16_t parse_protocol(const char *s); +extern void parse_hostnetworkmask(const char *name, struct in6_addr **addrpp, + struct in6_addr *maskp, unsigned int *naddrs); + +/* End duplicated code from ip6tables.c */ + +static void init(struct ip6t_entry_match *m, unsigned int *nfcache) +{ + *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 POLICY_MODE_TRANSPORT; + if (strcmp(s, "tunnel") == 0) + 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 *flags, + const struct ip6t_entry *entry, + unsigned int *nfcache, + struct ip6t_entry_match **match) +{ + struct ip6t_policy_info *info = (void *)(*match)->data; + struct ip6t_policy_elem *e = &info->pol[info->len]; + struct in6_addr *addr = NULL, mask; + unsigned int naddr = 0; + 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, + "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; + in6addrcpy(&e->daddr, addr); + in6addrcpy(&e->dmask, &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; + in6addrcpy(&e->daddr, addr); + in6addrcpy(&e->dmask, &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 == POLICY_MAX_ELEM) + exit_error(PARAMETER_PROBLEM, + "policy match: maximum policy depth reached"); + break; + default: + return 0; + } + + policy_info = info; + return 1; +} + +static void final_check(unsigned int flags) +{ + struct ip6t_policy_info *info = policy_info; + struct ip6t_policy_elem *e; + int i; + + if (info == NULL) + exit_error(PARAMETER_PROBLEM, + "policy match: no parameters given"); + + 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) +{ + printf("%smode ", prefix); + + switch (mode) { + case POLICY_MODE_TRANSPORT: + printf("transport "); + break; + case POLICY_MODE_TUNNEL: + printf("tunnel "); + break; + default: + printf("??? "); + break; + } +} + +static void print_proto(char *prefix, u_int8_t proto, int numeric) +{ + struct protoent *p = NULL; + + printf("%sproto ", prefix); + if (!numeric) + p = getprotobynumber(proto); + if (p != NULL) + printf("%s ", p->p_name); + else + printf("%u ", proto); +} + +#define PRINT_INVERT(x) \ +do { \ + if (x) \ + printf("! "); \ +} while(0) + +static void print_entry(char *prefix, const struct ip6t_policy_elem *e, + int numeric) +{ + if (e->match.reqid) { + PRINT_INVERT(e->invert.reqid); + printf("%sreqid %u ", prefix, e->reqid); + } + if (e->match.spi) { + PRINT_INVERT(e->invert.spi); + printf("%sspi 0x%x ", prefix, e->spi); + } + if (e->match.proto) { + PRINT_INVERT(e->invert.proto); + print_proto(prefix, e->proto, numeric); + } + if (e->match.mode) { + PRINT_INVERT(e->invert.mode); + print_mode(prefix, e->mode, numeric); + } + if (e->match.daddr) { + PRINT_INVERT(e->invert.daddr); + printf("%stunnel-dst %s%s ", prefix, + addr_to_numeric((struct in6_addr *)&e->daddr), + mask_to_numeric((struct in6_addr *)&e->dmask)); + } + if (e->match.saddr) { + PRINT_INVERT(e->invert.saddr); + printf("%stunnel-src %s%s ", prefix, + addr_to_numeric((struct in6_addr *)&e->saddr), + mask_to_numeric((struct in6_addr *)&e->smask)); + } +} + +static void print_flags(char *prefix, const struct ip6t_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 ip6t_ip6 *ip, + const struct ip6t_entry_match *match, + int numeric) +{ + const struct ip6t_policy_info *info = (void *)match->data; + unsigned int i; + + printf("policy match "); + print_flags("", info); + for (i = 0; i < info->len; i++) { + if (info->len > 1) + printf("[%u] ", i); + print_entry("", &info->pol[i], numeric); + } + + printf("\n"); +} + +static void save(const struct ip6t_ip6 *ip, const struct ip6t_entry_match *match) +{ + const struct ip6t_policy_info *info = (void *)match->data; + unsigned int i; + + print_flags("--", info); + for (i = 0; i < info->len; i++) { + print_entry("--", &info->pol[i], 0); + if (i + 1 < info->len) + printf("--next "); + } +} + +struct ip6tables_match policy = { + .name = "policy", + .version = IPTABLES_VERSION, + .size = IP6T_ALIGN(sizeof(struct ip6t_policy_info)), + .userspacesize = IP6T_ALIGN(sizeof(struct ip6t_policy_info)), + .help = help, + .init = init, + .parse = parse, + .final_check = final_check, + .print = print, + .save = save, + .extra_opts = opts +}; + +void _init(void) +{ + register_match6(&policy); +} diff -Nur iptables.org/extensions/libipt_MARK.c iptables/extensions/libipt_MARK.c --- iptables.org/extensions/libipt_MARK.c 2002-08-06 20:46:18.000000000 +0200 +++ iptables/extensions/libipt_MARK.c 2004-05-18 12:38:18.000000000 +0200 @@ -20,12 +20,16 @@ printf( "MARK target v%s options:\n" " --set-mark value Set nfmark value\n" +" --and-mark value Binary AND the nfmark with value\n" +" --or-mark value Binary OR the nfmark with value\n" "\n", IPTABLES_VERSION); } static struct option opts[] = { { "set-mark", 1, 0, '1' }, + { "and-mark", 1, 0, '2' }, + { "or-mark", 1, 0, '3' }, { 0 } }; @@ -45,19 +49,31 @@ struct ipt_mark_target_info *markinfo = (struct ipt_mark_target_info *)(*target)->data; - switch (c) { - case '1': + if ((c == '1') || (c == '2') || (c == '3')) { + if (*flags) + exit_error(PARAMETER_PROBLEM, "MARK: can only specify " + "one action"); + if (invert) + exit_error(PARAMETER_PROBLEM, "MARK: unexpected `!'"); if (string_to_number(optarg, 0, 0xffffffff, (unsigned int *)&markinfo->mark)) - exit_error(PARAMETER_PROBLEM, "Bad MARK value `%s'", optarg); - if (*flags) - exit_error(PARAMETER_PROBLEM, - "MARK target: Can't specify --set-mark twice"); + exit_error(PARAMETER_PROBLEM, "Bad MARK value `%s'", + optarg); *flags = 1; - break; + } - default: - return 0; + switch (c) { + case '1': + markinfo->mode = IPT_MARK_SET; + break; + case '2': + markinfo->mode = IPT_MARK_AND; + break; + case '3': + markinfo->mode = IPT_MARK_OR; + break; + default: + return 0; } return 1; @@ -71,12 +87,6 @@ "MARK target: Parameter --set-mark is required"); } -static void -print_mark(unsigned long mark, int numeric) -{ - printf("0x%lx ", mark); -} - /* Prints out the targinfo. */ static void print(const struct ipt_ip *ip, @@ -85,8 +95,19 @@ { const struct ipt_mark_target_info *markinfo = (const struct ipt_mark_target_info *)target->data; - printf("MARK set "); - print_mark(markinfo->mark, numeric); + + switch (markinfo->mode) { + case IPT_MARK_SET: + printf("MARK set "); + break; + case IPT_MARK_AND: + printf("MARK and "); + break; + case IPT_MARK_OR: + printf("MARK or "); + break; + } + printf("0x%lx ", markinfo->mark); } /* Saves the union ipt_targinfo in parsable form to stdout. */ @@ -96,7 +117,18 @@ const struct ipt_mark_target_info *markinfo = (const struct ipt_mark_target_info *)target->data; - printf("--set-mark 0x%lx ", markinfo->mark); + switch (markinfo->mode) { + case IPT_MARK_SET: + printf("--set-mark "); + break; + case IPT_MARK_AND: + printf("--and-mark "); + break; + case IPT_MARK_OR: + printf("--or-mark "); + break; + } + printf("0x%lx ", markinfo->mark); } static diff -Nur iptables.org/extensions/libipt_helper.c iptables/extensions/libipt_helper.c --- iptables.org/extensions/libipt_helper.c 2004-01-31 16:33:55.000000000 +0100 +++ iptables/extensions/libipt_helper.c 2004-05-18 12:39:27.000000000 +0200 @@ -45,8 +45,9 @@ switch (c) { case '1': check_inverse(optarg, &invert, &invert, 0); - strncpy(info->name, optarg, 29); - info->name[29] = '\0'; + memset(info->name, 0, sizeof(info->name)); + if (strcmp(info->name, "any")) + strncpy(info->name, optarg, 29); if (invert) info->invert = 1; *flags = 1; @@ -74,8 +75,12 @@ int numeric) { struct ipt_helper_info *info = (struct ipt_helper_info *)match->data; + char *name = "any"; - printf("helper match %s\"%s\" ", info->invert ? "! " : "", info->name); + if (info->name[0] != '\0') + name = info->name; + + printf("helper match %s\"%s\" ", info->invert ? "! " : "", name); } /* Saves the union ipt_info in parsable form to stdout. */ diff -Nur iptables.org/extensions/libipt_policy.c iptables/extensions/libipt_policy.c --- iptables.org/extensions/libipt_policy.c 1970-01-01 01:00:00.000000000 +0100 +++ iptables/extensions/libipt_policy.c 2004-05-18 12:39:55.000000000 +0200 @@ -0,0 +1,431 @@ +/* Shared library add-on to iptables to add policy support. */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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" +" --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[] = +{ + { + .name = "dir", + .has_arg = 1, + .val = '1', + }, + { + .name = "pol", + .has_arg = 1, + .val = '2', + }, + { + .name = "strict", + .val = '3' + }, + { + .name = "reqid", + .has_arg = 1, + .val = '4', + }, + { + .name = "spi", + .has_arg = 1, + .val = '5' + }, + { + .name = "tunnel-src", + .has_arg = 1, + .val = '6' + }, + { + .name = "tunnel-dst", + .has_arg = 1, + .val = '7' + }, + { + .name = "proto", + .has_arg = 1, + .val = '8' + }, + { + .name = "mode", + .has_arg = 1, + .val = '9' + }, + { + .name = "next", + .val = 'a' + }, + { } +}; + +static void init(struct ipt_entry_match *m, unsigned int *nfcache) +{ + *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 POLICY_MODE_TRANSPORT; + if (strcmp(s, "tunnel") == 0) + 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 *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 & (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, + "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 = addr[0].s_addr; + e->smask = mask.s_addr; + 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 = addr[0].s_addr; + e->dmask = mask.s_addr; + 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 == POLICY_MAX_ELEM) + exit_error(PARAMETER_PROBLEM, + "policy match: maximum policy depth reached"); + break; + default: + return 0; + } + + policy_info = info; + return 1; +} + +static void final_check(unsigned int flags) +{ + struct ipt_policy_info *info = policy_info; + struct ipt_policy_elem *e; + int i; + + if (info == NULL) + exit_error(PARAMETER_PROBLEM, + "policy match: no parameters given"); + + 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) +{ + printf("%smode ", prefix); + + switch (mode) { + case POLICY_MODE_TRANSPORT: + printf("transport "); + break; + case POLICY_MODE_TUNNEL: + printf("tunnel "); + break; + default: + printf("??? "); + break; + } +} + +static void print_proto(char *prefix, u_int8_t proto, int numeric) +{ + struct protoent *p = NULL; + + printf("%sproto ", prefix); + if (!numeric) + p = getprotobynumber(proto); + if (p != NULL) + printf("%s ", p->p_name); + else + printf("%u ", proto); +} + +#define PRINT_INVERT(x) \ +do { \ + if (x) \ + printf("! "); \ +} while(0) + +static void print_entry(char *prefix, const struct ipt_policy_elem *e, + int numeric) +{ + if (e->match.reqid) { + PRINT_INVERT(e->invert.reqid); + printf("%sreqid %u ", prefix, e->reqid); + } + if (e->match.spi) { + PRINT_INVERT(e->invert.spi); + printf("%sspi 0x%x ", prefix, e->spi); + } + if (e->match.proto) { + PRINT_INVERT(e->invert.proto); + print_proto(prefix, e->proto, numeric); + } + if (e->match.mode) { + PRINT_INVERT(e->invert.mode); + print_mode(prefix, e->mode, numeric); + } + if (e->match.daddr) { + PRINT_INVERT(e->invert.daddr); + 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("%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) +{ + const struct ipt_policy_info *info = (void *)match->data; + unsigned int i; + + printf("policy match "); + print_flags("", info); + for (i = 0; i < info->len; i++) { + if (info->len > 1) + printf("[%u] ", i); + print_entry("", &info->pol[i], numeric); + } +} + +static void save(const struct ipt_ip *ip, const struct ipt_entry_match *match) +{ + const struct ipt_policy_info *info = (void *)match->data; + unsigned int i; + + print_flags("--", info); + for (i = 0; i < info->len; i++) { + print_entry("--", &info->pol[i], 0); + if (i + 1 < info->len) + printf("--next "); + } + + printf("\n"); +} + +struct iptables_match policy = { + .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) +{ + register_match(&policy); +} diff -Nur iptables.org/extensions/libipt_policy.man iptables/extensions/libipt_policy.man --- iptables.org/extensions/libipt_policy.man 1970-01-01 01:00:00.000000000 +0100 +++ iptables/extensions/libipt_policy.man 2004-05-18 12:39:55.000000000 +0200 @@ -0,0 +1,46 @@ +This modules matches the policy used by IPsec for handling a packet. +.TP +.BI "--dir " "in|out" +Used to select whether to match the policy used for decapsulation or the +policy that will be used for encapsulation. +.B in +is valid in the +.B PREROUTING, INPUT and FORWARD +chains, +.B out +is valid in the +.B POSTROUTING, OUTPUT and FORWARD +chains. +.TP +.BI "--pol " "none|ipsec" +Matches if the packet is subject to IPsec processing. +.TP +.BI "--strict" +Selects whether to match the exact policy or match if any rule of +the policy matches the given policy. +.TP +.BI "--reqid " "id" +Matches the reqid of the policy rule. The reqid can be specified with +.B setkey(8) +using +.B unique:id +as level. +.TP +.BI "--spi " "spi" +Matches the SPI of the SA. +.TP +.BI "--proto " "ah|esp|ipcomp" +Matches the encapsulation protocol. +.TP +.BI "--mode " "tunnel|transport" +Matches the encapsulation mode. +.TP +.BI "--tunnel-src " "addr[/mask]" +Matches the source address of a tunnel. Only valid with --mode tunnel. +.TP +.BI "--tunnel-dst " "addr[/mask]" +Matches the destination address of a tunnel. Only valid with --mode tunnel. +.TP +.BI "--next" +Start the next element in the policy specification. Can only be used with +--strict diff -Nur iptables.org/ip6tables.c iptables/ip6tables.c --- iptables.org/ip6tables.c 2004-05-18 20:09:43.000000000 +0200 +++ iptables/ip6tables.c 2004-04-07 11:36:29.000000000 +0200 @@ -1433,8 +1433,6 @@ ret &= ip6tc_delete_entry(chain, fw, mask, handle); } } - free(mask); - return ret; } @@ -1656,8 +1654,6 @@ for (matchp = *matches; matchp;) { tmp = matchp->next; - if (matchp->match->m) - free(matchp->match->m); free(matchp); matchp = tmp; } @@ -1692,6 +1688,9 @@ memset(&fw, 0, sizeof(fw)); + opts = original_opts; + global_option_offset = 0; + /* re-set optind to 0 in case do_command gets called * a second time */ optind = 0; @@ -2197,9 +2196,6 @@ printf("Warning: using chain %s, not extension\n", jumpto); - if (target->t) - free(target->t); - target = NULL; } @@ -2229,7 +2225,6 @@ find_target(jumpto, LOAD_MUST_SUCCEED); } else { e = generate_entry(&fw, matches, target->t); - free(target->t); } } @@ -2307,22 +2302,5 @@ clear_rule_matches(&matches); - if (e != NULL) { - free(e); - e = NULL; - } - - for (c = 0; c < nsaddrs; c++) - free(&saddrs[c]); - - for (c = 0; c < ndaddrs; c++) - free(&daddrs[c]); - - if (opts != original_opts) { - free(opts); - opts = original_opts; - global_option_offset = 0; - } - return ret; } diff -Nur iptables.org/iptables.8.in iptables/iptables.8.in --- iptables.org/iptables.8.in 2004-03-17 15:26:08.000000000 +0100 +++ iptables/iptables.8.in 2004-05-18 12:39:16.000000000 +0200 @@ -274,10 +274,18 @@ the fate of the packet immediately, or an extension (see .B EXTENSIONS below). If this -option is omitted in a rule, then matching the rule will have no +option is omitted in a rule (and +.B -g +is not used), then matching the rule will have no effect on the packet's fate, but the counters on the rule will be incremented. .TP +.BI "-g, --goto " "chain" +This specifies that the processing should continue in a user +specified chain. Unlike the --jump option return will not continue +processing in this chain but instead in the chain that called us via +--jump. +.TP .BR "-i, --in-interface " "[!] \fIname\fP" Name of an interface via which a packet was received (only for packets entering the diff -Nur iptables.org/iptables.c iptables/iptables.c --- iptables.org/iptables.c 2004-05-18 20:09:43.000000000 +0200 +++ iptables/iptables.c 2004-05-18 12:39:16.000000000 +0200 @@ -138,6 +138,7 @@ { "line-numbers", 0, 0, '0' }, { "modprobe", 1, 0, 'M' }, { "set-counters", 1, 0, 'c' }, + { "goto", 1, 0, 'g' }, { 0 } }; @@ -397,6 +398,10 @@ " network interface name ([+] for wildcard)\n" " --jump -j target\n" " target for rule (may load target extension)\n" +#ifdef IPT_F_GOTO +" --goto -g chain\n" +" jump to chain with no return\n" +#endif " --match -m match\n" " extended match (may load extension)\n" " --numeric -n numeric output of addresses and ports\n" @@ -1431,8 +1436,6 @@ ret &= iptc_delete_entry(chain, fw, mask, handle); } } - free(mask); - return ret; } @@ -1654,8 +1657,6 @@ for (matchp = *matches; matchp;) { tmp = matchp->next; - if (matchp->match->m) - free(matchp->match->m); free(matchp); matchp = tmp; } @@ -1689,6 +1690,9 @@ memset(&fw, 0, sizeof(fw)); + opts = original_opts; + global_option_offset = 0; + /* re-set optind to 0 in case do_command gets called * a second time */ optind = 0; @@ -1708,7 +1712,7 @@ 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:i:fbvnt:m:xc:", + "-A:D:R:I:L::M:F::Z::N:X::E:P:Vh::o:p:s:d:j:i:fbvnt:m:xc:g:", opts, NULL)) != -1) { switch (c) { /* @@ -1879,6 +1883,15 @@ fw.nfcache |= NFC_IP_DST; 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); + break; +#endif + case 'j': set_option(&options, OPT_JUMP, &fw.ip.invflags, invert); @@ -2197,9 +2210,6 @@ printf("Warning: using chain %s, not extension\n", jumpto); - if (target->t) - free(target->t); - target = NULL; } @@ -2226,10 +2236,14 @@ * 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) + exit_error(PARAMETER_PROBLEM, + "goto '%s' is not a chain\n", jumpto); +#endif find_target(jumpto, LOAD_MUST_SUCCEED); } else { e = generate_entry(&fw, matches, target->t); - free(target->t); } } @@ -2307,22 +2321,5 @@ clear_rule_matches(&matches); - if (e != NULL) { - free(e); - e = NULL; - } - - for (c = 0; c < nsaddrs; c++) - free(&saddrs[c]); - - for (c = 0; c < ndaddrs; c++) - free(&daddrs[c]); - - if (opts != original_opts) { - free(opts); - opts = original_opts; - global_option_offset = 0; - } - return ret; }