diff options
Diffstat (limited to 'iptables/nft-ipv6.c')
-rw-r--r-- | iptables/nft-ipv6.c | 67 |
1 files changed, 66 insertions, 1 deletions
diff --git a/iptables/nft-ipv6.c b/iptables/nft-ipv6.c index 7b27d872..107a84e2 100644 --- a/iptables/nft-ipv6.c +++ b/iptables/nft-ipv6.c @@ -1,5 +1,5 @@ /* - * (C) 2012-2013 by Pablo Neira Ayuso <pablo@netfilter.org> + * (C) 2012-2014 by Pablo Neira Ayuso <pablo@netfilter.org> * (C) 2013 by Tomasz Bursztyka <tomasz.bursztyka@linux.intel.com> * * This program is free software; you can redistribute it and/or modify @@ -17,6 +17,7 @@ #include <sys/socket.h> #include <arpa/inet.h> #include <netinet/ip6.h> +#include <netdb.h> #include <xtables.h> @@ -376,6 +377,69 @@ static void nft_ipv6_save_counters(const void *data) save_counters(cs->counters.pcnt, cs->counters.bcnt); } +static void xlate_ipv6_addr(const char *selector, const struct in6_addr *addr, + int invert, struct xt_buf *buf) +{ + char addr_str[INET6_ADDRSTRLEN]; + + if (!invert && IN6_IS_ADDR_UNSPECIFIED(addr)) + return; + + inet_ntop(AF_INET6, addr, addr_str, INET6_ADDRSTRLEN); + xt_buf_add(buf, "%s %s%s ", selector, invert ? "!= " : "", addr_str); +} + +static int nft_ipv6_xlate(const void *data, struct xt_buf *buf) +{ + const struct iptables_command_state *cs = data; + int ret; + + if (cs->fw6.ipv6.iniface[0] != '\0') { + xt_buf_add(buf, "iifname %s%s ", + cs->fw6.ipv6.invflags & IP6T_INV_VIA_IN ? + "!= " : "", + cs->fw6.ipv6.iniface); + } + if (cs->fw6.ipv6.outiface[0] != '\0') { + xt_buf_add(buf, "oifname %s%s ", + cs->fw6.ipv6.invflags & IP6T_INV_VIA_OUT ? + "!= " : "", + cs->fw6.ipv6.outiface); + } + + if (cs->fw6.ipv6.proto != 0) { + const struct protoent *pent = + getprotobynumber(cs->fw6.ipv6.proto); + char protonum[strlen("255") + 1]; + + if (!xlate_find_match(cs, pent->p_name)) { + snprintf(protonum, sizeof(protonum), "%u", + cs->fw6.ipv6.proto); + protonum[sizeof(protonum) - 1] = '\0'; + xt_buf_add(buf, "ip protocol %s%s ", + cs->fw6.ipv6.invflags & IP6T_INV_PROTO ? + "!= " : "", + pent ? pent->p_name : protonum); + } + } + + xlate_ipv6_addr("ip saddr", &cs->fw6.ipv6.src, + cs->fw6.ipv6.invflags & IP6T_INV_SRCIP, buf); + xlate_ipv6_addr("ip daddr", &cs->fw6.ipv6.dst, + cs->fw6.ipv6.invflags & IP6T_INV_DSTIP, buf); + + ret = xlate_matches(cs, buf); + if (!ret) + return ret; + + /* Always add counters per rule, as in iptables */ + xt_buf_add(buf, "counter "); + + ret = xlate_action(cs, !!(cs->fw6.ipv6.flags & IP6T_F_GOTO), buf); + + return ret; +} + struct nft_family_ops nft_family_ops_ipv6 = { .add = nft_ipv6_add, .is_same = nft_ipv6_is_same, @@ -390,4 +454,5 @@ struct nft_family_ops nft_family_ops_ipv6 = { .post_parse = nft_ipv6_post_parse, .parse_target = nft_ipv6_parse_target, .rule_find = nft_ipv6_rule_find, + .xlate = nft_ipv6_xlate, }; |