From 524bb803727baaad532915394ada06ec3eb8a11e Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Sat, 19 Nov 2005 09:00:03 +0000 Subject: Add policy match extensions from patch-o-matic --- extensions/.policy-test | 3 + extensions/.policy-test6 | 3 + extensions/libip6t_policy.c | 471 ++++++++++++++++++++++++++++++++++++++++++ extensions/libip6t_policy.man | 46 +++++ extensions/libipt_policy.c | 429 ++++++++++++++++++++++++++++++++++++++ extensions/libipt_policy.man | 46 +++++ 6 files changed, 998 insertions(+) create mode 100755 extensions/.policy-test create mode 100755 extensions/.policy-test6 create mode 100644 extensions/libip6t_policy.c create mode 100644 extensions/libip6t_policy.man create mode 100644 extensions/libipt_policy.c create mode 100644 extensions/libipt_policy.man (limited to 'extensions') diff --git a/extensions/.policy-test b/extensions/.policy-test new file mode 100755 index 00000000..c2bb7bd5 --- /dev/null +++ b/extensions/.policy-test @@ -0,0 +1,3 @@ +#!/bin/sh +# +[ -f $KERNEL_DIR/include/linux/netfilter_ipv4/ipt_policy.h ] && echo policy diff --git a/extensions/.policy-test6 b/extensions/.policy-test6 new file mode 100755 index 00000000..5e6f4843 --- /dev/null +++ b/extensions/.policy-test6 @@ -0,0 +1,3 @@ +#!/bin/sh +# +[ -f $KERNEL_DIR/include/linux/netfilter_ipv6/ip6t_policy.h ] && echo policy diff --git a/extensions/libip6t_policy.c b/extensions/libip6t_policy.c new file mode 100644 index 00000000..59f6204b --- /dev/null +++ b/extensions/libip6t_policy.c @@ -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 IP6T_POLICY_MATCH_IN; + if (strcmp(s, "out") == 0) + return IP6T_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 IP6T_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 IP6T_POLICY_MODE_TRANSPORT; + if (strcmp(s, "tunnel") == 0) + return IP6T_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 & (IP6T_POLICY_MATCH_IN|IP6T_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 & IP6T_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 |= IP6T_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 == IP6T_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 & (IP6T_POLICY_MATCH_IN|IP6T_POLICY_MATCH_OUT))) + exit_error(PARAMETER_PROBLEM, + "policy match: neither --in nor --out specified"); + + if (info->flags & IP6T_POLICY_MATCH_NONE) { + if (info->flags & IP6T_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 & IP6T_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 == IP6T_POLICY_MODE_TUNNEL && e->invert.mode) || + (e->mode == IP6T_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 IP6T_POLICY_MODE_TRANSPORT: + printf("transport "); + break; + case IP6T_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 & IP6T_POLICY_MATCH_IN) + printf("%sdir in ", prefix); + else + printf("%sdir out ", prefix); + + if (info->flags & IP6T_POLICY_MATCH_NONE) + printf("%spol none ", prefix); + else + printf("%spol ipsec ", prefix); + + if (info->flags & IP6T_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 --git a/extensions/libip6t_policy.man b/extensions/libip6t_policy.man new file mode 100644 index 00000000..395dc2c1 --- /dev/null +++ b/extensions/libip6t_policy.man @@ -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[/masklen]" +Matches the source address of a tunnel. Only valid with --mode tunnel. +.TP +.BI "--tunnel-dst " "addr[/masklen]" +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 --git a/extensions/libipt_policy.c b/extensions/libipt_policy.c new file mode 100644 index 00000000..403b1b73 --- /dev/null +++ b/extensions/libipt_policy.c @@ -0,0 +1,429 @@ +/* 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 IPT_POLICY_MATCH_IN; + if (strcmp(s, "out") == 0) + return IPT_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 IPT_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 IPT_POLICY_MODE_TRANSPORT; + if (strcmp(s, "tunnel") == 0) + return IPT_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 & (IPT_POLICY_MATCH_IN|IPT_POLICY_MATCH_OUT)) + exit_error(PARAMETER_PROBLEM, + "policy match: double --dir option"); + if (invert) + exit_error(PARAMETER_PROBLEM, + "policy match: can't invert --dir option"); + + info->flags |= parse_direction(argv[optind-1]); + break; + case '2': + if (invert) + exit_error(PARAMETER_PROBLEM, + "policy match: can't invert --policy option"); + + info->flags |= parse_policy(argv[optind-1]); + break; + case '3': + if (info->flags & IPT_POLICY_MATCH_STRICT) + exit_error(PARAMETER_PROBLEM, + "policy match: double --strict option"); + + if (invert) + exit_error(PARAMETER_PROBLEM, + "policy match: can't invert --strict option"); + + info->flags |= IPT_POLICY_MATCH_STRICT; + break; + case '4': + if (e->match.reqid) + exit_error(PARAMETER_PROBLEM, + "policy match: double --reqid option"); + + e->match.reqid = 1; + e->invert.reqid = invert; + e->reqid = strtol(argv[optind-1], NULL, 10); + break; + case '5': + if (e->match.spi) + exit_error(PARAMETER_PROBLEM, + "policy match: double --spi option"); + + e->match.spi = 1; + e->invert.spi = invert; + e->spi = strtol(argv[optind-1], NULL, 0x10); + break; + case '6': + if (e->match.saddr) + exit_error(PARAMETER_PROBLEM, + "policy match: double --tunnel-src option"); + + parse_hostnetworkmask(argv[optind-1], &addr, &mask, &naddr); + if (naddr > 1) + exit_error(PARAMETER_PROBLEM, + "policy match: name resolves to multiple IPs"); + + e->match.saddr = 1; + e->invert.saddr = invert; + e->saddr = 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 == IPT_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 & (IPT_POLICY_MATCH_IN|IPT_POLICY_MATCH_OUT))) + exit_error(PARAMETER_PROBLEM, + "policy match: neither --in nor --out specified"); + + if (info->flags & IPT_POLICY_MATCH_NONE) { + if (info->flags & IPT_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 & IPT_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 == IPT_POLICY_MODE_TUNNEL && e->invert.mode) || + (e->mode == IPT_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 IPT_POLICY_MODE_TRANSPORT: + printf("transport "); + break; + case IPT_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 & IPT_POLICY_MATCH_IN) + printf("%sdir in ", prefix); + else + printf("%sdir out ", prefix); + + if (info->flags & IPT_POLICY_MATCH_NONE) + printf("%spol none ", prefix); + else + printf("%spol ipsec ", prefix); + + if (info->flags & IPT_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 "); + } +} + +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 --git a/extensions/libipt_policy.man b/extensions/libipt_policy.man new file mode 100644 index 00000000..c2e81bed --- /dev/null +++ b/extensions/libipt_policy.man @@ -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 -- cgit v1.2.3