]> git.ipfire.org Git - thirdparty/iptables.git/commitdiff
policy: merge ipv6 and ipv4 variant
authorJan Engelhardt <jengelh@medozas.de>
Mon, 1 Jun 2009 09:46:12 +0000 (11:46 +0200)
committerJan Engelhardt <jengelh@medozas.de>
Mon, 1 Jun 2009 09:46:12 +0000 (11:46 +0200)
The files duplicate most of their code, and struct ipt_policy_info
being defined to xt_policy_info makes them actually have even more in
common.

Signed-off-by: Jan Engelhardt <jengelh@medozas.de>
extensions/libip6t_policy.c [deleted file]
extensions/libxt_policy.c [moved from extensions/libipt_policy.c with 70% similarity]

diff --git a/extensions/libip6t_policy.c b/extensions/libip6t_policy.c
deleted file mode 100644 (file)
index daeff89..0000000
+++ /dev/null
@@ -1,432 +0,0 @@
-/* Shared library add-on to ip6tables to add policy support. */
-#include <stdio.h>
-#include <netdb.h>
-#include <string.h>
-#include <stdlib.h>
-#include <syslog.h>
-#include <getopt.h>
-#include <netdb.h>
-#include <errno.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <xtables.h>
-#include <libiptc/libip6tc.h>
-#include <linux/netfilter/xt_policy.h>
-
-/*
- * HACK: global pointer to current matchinfo for making
- * final checks and adjustments in final_check.
- */
-static struct xt_policy_info *policy_info;
-
-static void policy_help(void)
-{
-       printf(
-"policy match 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");
-}
-
-static const struct option policy_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'
-       },
-       { .name = NULL }
-};
-
-static int parse_direction(char *s)
-{
-       if (strcmp(s, "in") == 0)
-               return XT_POLICY_MATCH_IN;
-       if (strcmp(s, "out") == 0)
-               return XT_POLICY_MATCH_OUT;
-       xtables_error(PARAMETER_PROBLEM, "policy_match: invalid dir \"%s\"", s);
-}
-
-static int parse_policy(char *s)
-{
-       if (strcmp(s, "none") == 0)
-               return XT_POLICY_MATCH_NONE;
-       if (strcmp(s, "ipsec") == 0)
-               return 0;
-       xtables_error(PARAMETER_PROBLEM, "policy match: invalid policy \"%s\"", s);
-}
-
-static int parse_mode(char *s)
-{
-       if (strcmp(s, "transport") == 0)
-               return XT_POLICY_MODE_TRANSPORT;
-       if (strcmp(s, "tunnel") == 0)
-               return XT_POLICY_MODE_TUNNEL;
-       xtables_error(PARAMETER_PROBLEM, "policy match: invalid mode \"%s\"", s);
-}
-
-static int policy_parse(int c, char **argv, int invert, unsigned int *flags,
-                        const void *entry, struct xt_entry_match **match)
-{
-       struct xt_policy_info *info = (void *)(*match)->data;
-       struct xt_policy_elem *e = &info->pol[info->len];
-       struct in6_addr *addr = NULL, mask;
-       unsigned int naddr = 0, num;
-       int mode;
-
-       xtables_check_inverse(optarg, &invert, &optind, 0);
-
-       switch (c) {
-       case '1':
-               if (info->flags & (XT_POLICY_MATCH_IN|XT_POLICY_MATCH_OUT))
-                       xtables_error(PARAMETER_PROBLEM,
-                                  "policy match: double --dir option");
-               if (invert)
-                       xtables_error(PARAMETER_PROBLEM,
-                                  "policy match: can't invert --dir option");
-
-               info->flags |= parse_direction(argv[optind-1]);
-               break;
-       case '2':
-               if (invert)
-                       xtables_error(PARAMETER_PROBLEM,
-                                  "policy match: can't invert --policy option");
-
-               info->flags |= parse_policy(argv[optind-1]);
-               break;
-       case '3':
-               if (info->flags & XT_POLICY_MATCH_STRICT)
-                       xtables_error(PARAMETER_PROBLEM,
-                                  "policy match: double --strict option");
-
-               if (invert)
-                       xtables_error(PARAMETER_PROBLEM,
-                                  "policy match: can't invert --strict option");
-
-               info->flags |= XT_POLICY_MATCH_STRICT;
-               break;
-       case '4':
-               if (e->match.reqid)
-                       xtables_error(PARAMETER_PROBLEM,
-                                  "policy match: double --reqid option");
-
-               e->match.reqid = 1;
-               e->invert.reqid = invert;
-               if (!xtables_strtoui(optarg, NULL, &num, 0, UINT32_MAX))
-                       xtables_param_act(XTF_BAD_VALUE, "policy", "--reqid", optarg);
-               e->reqid = num;
-               break;
-       case '5':
-               if (e->match.spi)
-                       xtables_error(PARAMETER_PROBLEM,
-                                  "policy match: double --spi option");
-
-               e->match.spi = 1;
-               e->invert.spi = invert;
-               if (!xtables_strtoui(optarg, NULL, &num, 0, UINT32_MAX))
-                       xtables_param_act(XTF_BAD_VALUE, "policy", "--spi", optarg);
-               e->spi = num;
-               break;
-       case '6':
-               if (e->match.saddr)
-                       xtables_error(PARAMETER_PROBLEM,
-                                  "policy match: double --tunnel-src option");
-
-               xtables_ip6parse_any(argv[optind-1], &addr, &mask, &naddr);
-               if (naddr > 1)
-                       xtables_error(PARAMETER_PROBLEM,
-                                  "policy match: name resolves to multiple IPs");
-
-               e->match.saddr = 1;
-               e->invert.saddr = invert;
-               memcpy(&e->saddr.a6, addr, sizeof(*addr));
-               memcpy(&e->smask.a6, &mask, sizeof(mask));
-                break;
-       case '7':
-               if (e->match.daddr)
-                       xtables_error(PARAMETER_PROBLEM,
-                                  "policy match: double --tunnel-dst option");
-
-               xtables_ip6parse_any(argv[optind-1], &addr, &mask, &naddr);
-               if (naddr > 1)
-                       xtables_error(PARAMETER_PROBLEM,
-                                  "policy match: name resolves to multiple IPs");
-
-               e->match.daddr = 1;
-               e->invert.daddr = invert;
-               memcpy(&e->daddr.a6, addr, sizeof(*addr));
-               memcpy(&e->dmask.a6, &mask, sizeof(mask));
-               break;
-       case '8':
-               if (e->match.proto)
-                       xtables_error(PARAMETER_PROBLEM,
-                                  "policy match: double --proto option");
-
-               e->proto = xtables_parse_protocol(argv[optind-1]);
-               if (e->proto != IPPROTO_AH && e->proto != IPPROTO_ESP &&
-                   e->proto != IPPROTO_COMP)
-                       xtables_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)
-                       xtables_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)
-                       xtables_error(PARAMETER_PROBLEM,
-                                  "policy match: can't invert --next option");
-
-               if (++info->len == XT_POLICY_MAX_ELEM)
-                       xtables_error(PARAMETER_PROBLEM,
-                                  "policy match: maximum policy depth reached");
-               break;
-       default:
-               return 0;
-       }
-
-       policy_info = info;
-       return 1;
-}
-
-static void policy_check(unsigned int flags)
-{
-       struct xt_policy_info *info = policy_info;
-       struct xt_policy_elem *e;
-       int i;
-
-       if (info == NULL)
-               xtables_error(PARAMETER_PROBLEM,
-                          "policy match: no parameters given");
-
-       if (!(info->flags & (XT_POLICY_MATCH_IN|XT_POLICY_MATCH_OUT)))
-               xtables_error(PARAMETER_PROBLEM,
-                          "policy match: neither --in nor --out specified");
-
-       if (info->flags & XT_POLICY_MATCH_NONE) {
-               if (info->flags & XT_POLICY_MATCH_STRICT)
-                       xtables_error(PARAMETER_PROBLEM,
-                                  "policy match: policy none but --strict given");
-
-               if (info->len != 0)
-                       xtables_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 & XT_POLICY_MATCH_STRICT) && info->len > 1)
-               xtables_error(PARAMETER_PROBLEM,
-                          "policy match: multiple elements but no --strict");
-
-       for (i = 0; i < info->len; i++) {
-               e = &info->pol[i];
-
-                if (info->flags & XT_POLICY_MATCH_STRICT &&
-                   !(e->match.reqid || e->match.spi || e->match.saddr ||
-                      e->match.daddr || e->match.proto || e->match.mode))
-                       xtables_error(PARAMETER_PROBLEM,
-                                   "policy match: empty policy element");
-
-               if ((e->match.saddr || e->match.daddr)
-                   && ((e->mode == XT_POLICY_MODE_TUNNEL && e->invert.mode) ||
-                       (e->mode == XT_POLICY_MODE_TRANSPORT && !e->invert.mode)))
-                       xtables_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 XT_POLICY_MODE_TRANSPORT:
-               printf("transport ");
-               break;
-       case XT_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 xt_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,
-                      xtables_ip6addr_to_numeric(&e->daddr.a6),
-                      xtables_ip6mask_to_numeric(&e->dmask.a6));
-       }
-       if (e->match.saddr) {
-               PRINT_INVERT(e->invert.saddr);
-               printf("%stunnel-src %s%s ", prefix,
-                      xtables_ip6addr_to_numeric(&e->saddr.a6),
-                      xtables_ip6mask_to_numeric(&e->smask.a6));
-       }
-}
-
-static void print_flags(char *prefix, const struct xt_policy_info *info)
-{
-       if (info->flags & XT_POLICY_MATCH_IN)
-               printf("%sdir in ", prefix);
-       else
-               printf("%sdir out ", prefix);
-
-       if (info->flags & XT_POLICY_MATCH_NONE)
-               printf("%spol none ", prefix);
-       else
-               printf("%spol ipsec ", prefix);
-
-       if (info->flags & XT_POLICY_MATCH_STRICT)
-               printf("%sstrict ", prefix);
-}
-
-static void policy_print(const void *ip, const struct xt_entry_match *match,
-                         int numeric)
-{
-       const struct xt_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 policy_save(const void *ip, const struct xt_entry_match *match)
-{
-       const struct xt_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 ");
-       }
-}
-
-static struct xtables_match policy_mt6_reg = {
-       .name           = "policy",
-       .version        = XTABLES_VERSION,
-       .family         = NFPROTO_IPV6,
-       .size           = XT_ALIGN(sizeof(struct xt_policy_info)),
-       .userspacesize  = XT_ALIGN(sizeof(struct xt_policy_info)),
-       .help           = policy_help,
-       .parse          = policy_parse,
-       .final_check    = policy_check,
-       .print          = policy_print,
-       .save           = policy_save,
-       .extra_opts     = policy_opts,
-};
-
-void _init(void)
-{
-       xtables_register_match(&policy_mt6_reg);
-}
similarity index 70%
rename from extensions/libipt_policy.c
rename to extensions/libxt_policy.c
index d6bad003da17f673c5456205bc292d39275bf781..d17b1bbc5fea15d06f3312d85c0e95b531af8138 100644 (file)
@@ -118,12 +118,12 @@ static int parse_mode(char *s)
        xtables_error(PARAMETER_PROBLEM, "policy match: invalid mode \"%s\"", s);
 }
 
-static int policy_parse(int c, char **argv, int invert, unsigned int *flags,
-                        const void *entry, struct xt_entry_match **match)
+static int policy_parse(int c, int invert, unsigned int *flags,
+                        struct xt_policy_info *info, uint8_t family)
 {
-       struct xt_policy_info *info = (void *)(*match)->data;
        struct xt_policy_elem *e = &info->pol[info->len];
        struct in_addr *addr = NULL, mask;
+       struct in6_addr *addr6 = NULL, mask6;
        unsigned int naddr = 0, num;
        int mode;
 
@@ -138,14 +138,14 @@ static int policy_parse(int c, char **argv, int invert, unsigned int *flags,
                        xtables_error(PARAMETER_PROBLEM,
                                   "policy match: can't invert --dir option");
 
-               info->flags |= parse_direction(argv[optind-1]);
+               info->flags |= parse_direction(optarg);
                break;
        case '2':
                if (invert)
                        xtables_error(PARAMETER_PROBLEM,
                                   "policy match: can't invert --policy option");
 
-               info->flags |= parse_policy(argv[optind-1]);
+               info->flags |= parse_policy(optarg);
                break;
        case '3':
                if (info->flags & XT_POLICY_MATCH_STRICT)
@@ -185,37 +185,53 @@ static int policy_parse(int c, char **argv, int invert, unsigned int *flags,
                        xtables_error(PARAMETER_PROBLEM,
                                   "policy match: double --tunnel-src option");
 
-               xtables_ipparse_any(argv[optind-1], &addr, &mask, &naddr);
+               if (family == NFPROTO_IPV6)
+                       xtables_ip6parse_any(optarg, &addr6, &mask6, &naddr);
+               else
+                       xtables_ipparse_any(optarg, &addr, &mask, &naddr);
                if (naddr > 1)
                        xtables_error(PARAMETER_PROBLEM,
                                   "policy match: name resolves to multiple IPs");
 
                e->match.saddr = 1;
                e->invert.saddr = invert;
-               e->saddr.a4 = addr[0];
-               e->smask.a4 = mask;
+               if (family == NFPROTO_IPV6) {
+                       memcpy(&e->saddr.a6, addr6, sizeof(*addr6));
+                       memcpy(&e->smask.a6, &mask6, sizeof(mask6));
+               } else {
+                       e->saddr.a4 = addr[0];
+                       e->smask.a4 = mask;
+               }
                 break;
        case '7':
                if (e->match.daddr)
                        xtables_error(PARAMETER_PROBLEM,
                                   "policy match: double --tunnel-dst option");
 
-               xtables_ipparse_any(argv[optind-1], &addr, &mask, &naddr);
+               if (family == NFPROTO_IPV6)
+                       xtables_ip6parse_any(optarg, &addr6, &mask6, &naddr);
+               else
+                       xtables_ipparse_any(optarg, &addr, &mask, &naddr);
                if (naddr > 1)
                        xtables_error(PARAMETER_PROBLEM,
                                   "policy match: name resolves to multiple IPs");
 
                e->match.daddr = 1;
                e->invert.daddr = invert;
-               e->daddr.a4 = addr[0];
-               e->dmask.a4 = mask;
+               if (family == NFPROTO_IPV6) {
+                       memcpy(&e->daddr.a6, addr6, sizeof(*addr6));
+                       memcpy(&e->dmask.a6, &mask6, sizeof(mask6));
+               } else {
+                       e->daddr.a4 = addr[0];
+                       e->dmask.a4 = mask;
+               }
                break;
        case '8':
                if (e->match.proto)
                        xtables_error(PARAMETER_PROBLEM,
                                   "policy match: double --proto option");
 
-               e->proto = xtables_parse_protocol(argv[optind-1]);
+               e->proto = xtables_parse_protocol(optarg);
                if (e->proto != IPPROTO_AH && e->proto != IPPROTO_ESP &&
                    e->proto != IPPROTO_COMP)
                        xtables_error(PARAMETER_PROBLEM,
@@ -228,7 +244,7 @@ static int policy_parse(int c, char **argv, int invert, unsigned int *flags,
                        xtables_error(PARAMETER_PROBLEM,
                                   "policy match: double --mode option");
 
-               mode = parse_mode(argv[optind-1]);
+               mode = parse_mode(optarg);
                e->match.mode = 1;
                e->invert.mode = invert;
                e->mode = mode;
@@ -250,6 +266,20 @@ static int policy_parse(int c, char **argv, int invert, unsigned int *flags,
        return 1;
 }
 
+static int policy4_parse(int c, char **argv, int invert, unsigned int *flags,
+                         const void *entry, struct xt_entry_match **match)
+{
+       return policy_parse(c, invert, flags, (void *)(*match)->data,
+              NFPROTO_IPV4);
+}
+
+static int policy6_parse(int c, char **argv, int invert, unsigned int *flags,
+                        const void *entry, struct xt_entry_match **match)
+{
+       return policy_parse(c, invert, flags, (void *)(*match)->data,
+              NFPROTO_IPV6);
+}
+
 static void policy_check(unsigned int flags)
 {
        struct xt_policy_info *info = policy_info;
@@ -297,7 +327,7 @@ static void policy_check(unsigned int flags)
        }
 }
 
-static void print_mode(char *prefix, u_int8_t mode, int numeric)
+static void print_mode(const char *prefix, u_int8_t mode, int numeric)
 {
        printf("%smode ", prefix);
 
@@ -314,7 +344,7 @@ static void print_mode(char *prefix, u_int8_t mode, int numeric)
        }
 }
 
-static void print_proto(char *prefix, u_int8_t proto, int numeric)
+static void print_proto(const char *prefix, u_int8_t proto, int numeric)
 {
        struct protoent *p = NULL;
 
@@ -333,8 +363,8 @@ do {                                \
                printf("! ");   \
 } while(0)
 
-static void print_entry(char *prefix, const struct xt_policy_elem *e,
-                        int numeric)
+static void print_entry(const char *prefix, const struct xt_policy_elem *e,
+                        bool numeric, uint8_t family)
 {
        if (e->match.reqid) {
                PRINT_INVERT(e->invert.reqid);
@@ -354,15 +384,25 @@ static void print_entry(char *prefix, const struct xt_policy_elem *e,
        }
        if (e->match.daddr) {
                PRINT_INVERT(e->invert.daddr);
-               printf("%stunnel-dst %s%s ", prefix,
-                      xtables_ipaddr_to_numeric((const void *)&e->daddr),
-                      xtables_ipmask_to_numeric((const void *)&e->dmask));
+               if (family == NFPROTO_IPV6)
+                       printf("%stunnel-dst %s%s ", prefix,
+                              xtables_ip6addr_to_numeric(&e->daddr.a6),
+                              xtables_ip6mask_to_numeric(&e->dmask.a6));
+               else
+                       printf("%stunnel-dst %s%s ", prefix,
+                              xtables_ipaddr_to_numeric(&e->daddr.a4),
+                              xtables_ipmask_to_numeric(&e->dmask.a4));
        }
        if (e->match.saddr) {
                PRINT_INVERT(e->invert.saddr);
-               printf("%stunnel-src %s%s ", prefix,
-                      xtables_ipaddr_to_numeric((const void *)&e->saddr),
-                      xtables_ipmask_to_numeric((const void *)&e->smask));
+               if (family == NFPROTO_IPV6)
+                       printf("%stunnel-src %s%s ", prefix,
+                              xtables_ip6addr_to_numeric(&e->saddr.a6),
+                              xtables_ip6mask_to_numeric(&e->smask.a6));
+               else
+                       printf("%stunnel-src %s%s ", prefix,
+                              xtables_ipaddr_to_numeric(&e->saddr.a4),
+                              xtables_ipmask_to_numeric(&e->smask.a4));
        }
 }
 
@@ -382,8 +422,23 @@ static void print_flags(char *prefix, const struct xt_policy_info *info)
                printf("%sstrict ", prefix);
 }
 
-static void policy_print(const void *ip, const struct xt_entry_match *match,
-                         int numeric)
+static void policy4_print(const void *ip, const struct xt_entry_match *match,
+                          int numeric)
+{
+       const struct xt_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, NFPROTO_IPV4);
+       }
+}
+
+static void policy6_print(const void *ip, const struct xt_entry_match *match,
+                          int numeric)
 {
        const struct xt_policy_info *info = (void *)match->data;
        unsigned int i;
@@ -393,18 +448,31 @@ static void policy_print(const void *ip, const struct xt_entry_match *match,
        for (i = 0; i < info->len; i++) {
                if (info->len > 1)
                        printf("[%u] ", i);
-               print_entry("", &info->pol[i], numeric);
+               print_entry("", &info->pol[i], numeric, NFPROTO_IPV6);
        }
 }
 
-static void policy_save(const void *ip, const struct xt_entry_match *match)
+static void policy4_save(const void *ip, const struct xt_entry_match *match)
 {
        const struct xt_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);
+               print_entry("--", &info->pol[i], false, NFPROTO_IPV4);
+               if (i + 1 < info->len)
+                       printf("--next ");
+       }
+}
+
+static void policy6_save(const void *ip, const struct xt_entry_match *match)
+{
+       const struct xt_policy_info *info = (void *)match->data;
+       unsigned int i;
+
+       print_flags("--", info);
+       for (i = 0; i < info->len; i++) {
+               print_entry("--", &info->pol[i], false, NFPROTO_IPV6);
                if (i + 1 < info->len)
                        printf("--next ");
        }
@@ -417,14 +485,29 @@ static struct xtables_match policy_mt_reg = {
        .size           = XT_ALIGN(sizeof(struct xt_policy_info)),
        .userspacesize  = XT_ALIGN(sizeof(struct xt_policy_info)),
        .help           = policy_help,
-       .parse          = policy_parse,
+       .parse          = policy4_parse,
+       .final_check    = policy_check,
+       .print          = policy4_print,
+       .save           = policy4_save,
+       .extra_opts     = policy_opts,
+};
+
+static struct xtables_match policy_mt6_reg = {
+       .name           = "policy",
+       .version        = XTABLES_VERSION,
+       .family         = NFPROTO_IPV6,
+       .size           = XT_ALIGN(sizeof(struct xt_policy_info)),
+       .userspacesize  = XT_ALIGN(sizeof(struct xt_policy_info)),
+       .help           = policy_help,
+       .parse          = policy6_parse,
        .final_check    = policy_check,
-       .print          = policy_print,
-       .save           = policy_save,
+       .print          = policy6_print,
+       .save           = policy6_save,
        .extra_opts     = policy_opts,
 };
 
 void _init(void)
 {
        xtables_register_match(&policy_mt_reg);
+       xtables_register_match(&policy_mt6_reg);
 }