From 73ad642ba462d0992e1903012eee4ebfec89ed69 Mon Sep 17 00:00:00 2001 From: Arturo Borrero Date: Wed, 18 May 2016 10:56:36 +0200 Subject: src: add support for IPv6 NAT The conntrackd daemon lacks support for syncing IPv6 NATed connections. This patch adds support for managing the IPv6 part of struct __nfct_nat, also updating the corresponsing symbols. Signed-off-by: Arturo Borrero Gonzalez Signed-off-by: Pablo Neira Ayuso --- src/conntrack/build.c | 36 ++++++++++++++++++++++++++++++++++++ src/conntrack/build_mnl.c | 36 ++++++++++++++++++++++++++++++++++++ src/conntrack/copy.c | 16 ++++++++++++++++ src/conntrack/getter.c | 12 ++++++++++++ src/conntrack/objopt.c | 34 ++++++++++++++++++++++++++++++++-- src/conntrack/setter.c | 16 ++++++++++++++++ 6 files changed, 148 insertions(+), 2 deletions(-) (limited to 'src/conntrack') diff --git a/src/conntrack/build.c b/src/conntrack/build.c index 8ba6b16..cf282e6 100644 --- a/src/conntrack/build.c +++ b/src/conntrack/build.c @@ -283,6 +283,10 @@ static void __build_nat(struct nfnlhdr *req, nfnl_addattr_l(&req->nlh, size, CTA_NAT_MINIP, &nat->min_ip.v4, sizeof(uint32_t)); break; + case AF_INET6: + nfnl_addattr_l(&req->nlh, size, CTA_NAT_V6_MINIP, + &nat->min_ip.v6, sizeof(struct in6_addr)); + break; default: break; } @@ -312,6 +316,17 @@ static void __build_snat_ipv4(struct nfnlhdr *req, nfnl_nest_end(&req->nlh, nest); } +static void __build_snat_ipv6(struct nfnlhdr *req, + size_t size, + const struct nf_conntrack *ct) +{ + struct nfattr *nest; + + nest = nfnl_nest(&req->nlh, size, CTA_NAT_SRC); + __build_nat(req, size, &ct->snat, AF_INET6); + nfnl_nest_end(&req->nlh, nest); +} + static void __build_snat_port(struct nfnlhdr *req, size_t size, const struct nf_conntrack *ct) @@ -347,6 +362,17 @@ static void __build_dnat_ipv4(struct nfnlhdr *req, nfnl_nest_end(&req->nlh, nest); } +static void __build_dnat_ipv6(struct nfnlhdr *req, + size_t size, + const struct nf_conntrack *ct) +{ + struct nfattr *nest; + + nest = nfnl_nest(&req->nlh, size, CTA_NAT_DST); + __build_nat(req, size, &ct->dnat, AF_INET6); + nfnl_nest_end(&req->nlh, nest); +} + static void __build_dnat_port(struct nfnlhdr *req, size_t size, const struct nf_conntrack *ct) @@ -526,16 +552,26 @@ int __build_conntrack(struct nfnl_subsys_handle *ssh, if (test_bit(ATTR_SNAT_IPV4, ct->head.set) && test_bit(ATTR_SNAT_PORT, ct->head.set)) __build_snat(req, size, ct, AF_INET); + else if (test_bit(ATTR_SNAT_IPV6, ct->head.set) && + test_bit(ATTR_SNAT_PORT, ct->head.set)) + __build_snat(req, size, ct, AF_INET6); else if (test_bit(ATTR_SNAT_IPV4, ct->head.set)) __build_snat_ipv4(req, size, ct); + else if (test_bit(ATTR_SNAT_IPV6, ct->head.set)) + __build_snat_ipv6(req, size, ct); else if (test_bit(ATTR_SNAT_PORT, ct->head.set)) __build_snat_port(req, size, ct); if (test_bit(ATTR_DNAT_IPV4, ct->head.set) && test_bit(ATTR_DNAT_PORT, ct->head.set)) __build_dnat(req, size, ct, AF_INET); + else if (test_bit(ATTR_DNAT_IPV6, ct->head.set) && + test_bit(ATTR_DNAT_PORT, ct->head.set)) + __build_dnat(req, size, ct, AF_INET6); else if (test_bit(ATTR_DNAT_IPV4, ct->head.set)) __build_dnat_ipv4(req, size, ct); + else if (test_bit(ATTR_DNAT_IPV6, ct->head.set)) + __build_dnat_ipv6(req, size, ct); else if (test_bit(ATTR_DNAT_PORT, ct->head.set)) __build_dnat_port(req, size, ct); diff --git a/src/conntrack/build_mnl.c b/src/conntrack/build_mnl.c index f4bb287..2118bf3 100644 --- a/src/conntrack/build_mnl.c +++ b/src/conntrack/build_mnl.c @@ -271,6 +271,10 @@ nfct_build_nat(struct nlmsghdr *nlh, const struct __nfct_nat *nat, case AF_INET: mnl_attr_put_u32(nlh, CTA_NAT_MINIP, nat->min_ip.v4); break; + case AF_INET6: + mnl_attr_put(nlh, CTA_NAT_V6_MINIP, sizeof(struct in6_addr), + &nat->min_ip.v6); + break; default: break; } @@ -301,6 +305,17 @@ nfct_build_snat_ipv4(struct nlmsghdr *nlh, const struct nf_conntrack *ct) return 0; } +static int +nfct_build_snat_ipv6(struct nlmsghdr *nlh, const struct nf_conntrack *ct) +{ + struct nlattr *nest; + + nest = mnl_attr_nest_start(nlh, CTA_NAT_SRC); + nfct_build_nat(nlh, &ct->snat, AF_INET6); + mnl_attr_nest_end(nlh, nest); + return 0; +} + static int nfct_build_snat_port(struct nlmsghdr *nlh, const struct nf_conntrack *ct) { @@ -336,6 +351,17 @@ nfct_build_dnat_ipv4(struct nlmsghdr *nlh, const struct nf_conntrack *ct) return 0; } +static int +nfct_build_dnat_ipv6(struct nlmsghdr *nlh, const struct nf_conntrack *ct) +{ + struct nlattr *nest; + + nest = mnl_attr_nest_start(nlh, CTA_NAT_DST); + nfct_build_nat(nlh, &ct->dnat, AF_INET6); + mnl_attr_nest_end(nlh, nest); + return 0; +} + static int nfct_build_dnat_port(struct nlmsghdr *nlh, const struct nf_conntrack *ct) { @@ -508,8 +534,13 @@ nfct_nlmsg_build(struct nlmsghdr *nlh, const struct nf_conntrack *ct) if (test_bit(ATTR_SNAT_IPV4, ct->head.set) && test_bit(ATTR_SNAT_PORT, ct->head.set)) { nfct_build_snat(nlh, ct, AF_INET); + } else if (test_bit(ATTR_SNAT_IPV6, ct->head.set) && + test_bit(ATTR_SNAT_PORT, ct->head.set)) { + nfct_build_snat(nlh, ct, AF_INET6); } else if (test_bit(ATTR_SNAT_IPV4, ct->head.set)) { nfct_build_snat_ipv4(nlh, ct); + } else if (test_bit(ATTR_SNAT_IPV6, ct->head.set)) { + nfct_build_snat_ipv6(nlh, ct); } else if (test_bit(ATTR_SNAT_PORT, ct->head.set)) { nfct_build_snat_port(nlh, ct); } @@ -517,8 +548,13 @@ nfct_nlmsg_build(struct nlmsghdr *nlh, const struct nf_conntrack *ct) if (test_bit(ATTR_DNAT_IPV4, ct->head.set) && test_bit(ATTR_DNAT_PORT, ct->head.set)) { nfct_build_dnat(nlh, ct, AF_INET); + } else if (test_bit(ATTR_DNAT_IPV6, ct->head.set) && + test_bit(ATTR_DNAT_PORT, ct->head.set)) { + nfct_build_dnat(nlh, ct, AF_INET6); } else if (test_bit(ATTR_DNAT_IPV4, ct->head.set)) { nfct_build_dnat_ipv4(nlh, ct); + } else if (test_bit(ATTR_DNAT_IPV6, ct->head.set)) { + nfct_build_dnat_ipv6(nlh, ct); } else if (test_bit(ATTR_DNAT_PORT, ct->head.set)) { nfct_build_dnat_port(nlh, ct); } diff --git a/src/conntrack/copy.c b/src/conntrack/copy.c index eac977b..e6e4f7a 100644 --- a/src/conntrack/copy.c +++ b/src/conntrack/copy.c @@ -296,6 +296,20 @@ static void copy_attr_dnat_ipv4(struct nf_conntrack *dest, dest->dnat.min_ip.v4 = orig->dnat.min_ip.v4; } +static void copy_attr_snat_ipv6(struct nf_conntrack *dest, + const struct nf_conntrack *orig) +{ + memcpy(&dest->snat.min_ip.v6, &orig->snat.min_ip.v6, + sizeof(struct in6_addr)); +} + +static void copy_attr_dnat_ipv6(struct nf_conntrack *dest, + const struct nf_conntrack *orig) +{ + memcpy(&dest->dnat.min_ip.v6, &orig->dnat.min_ip.v6, + sizeof(struct in6_addr)); +} + static void copy_attr_snat_port(struct nf_conntrack *dest, const struct nf_conntrack *orig) { @@ -555,6 +569,8 @@ const copy_attr copy_attr_array[ATTR_MAX] = { [ATTR_HELPER_INFO] = copy_attr_help_info, [ATTR_CONNLABELS] = copy_attr_connlabels, [ATTR_CONNLABELS_MASK] = copy_attr_connlabels_mask, + [ATTR_SNAT_IPV6] = copy_attr_snat_ipv6, + [ATTR_DNAT_IPV6] = copy_attr_dnat_ipv6, }; /* this is used by nfct_copy() with the NFCT_CP_OVERRIDE flag set. */ diff --git a/src/conntrack/getter.c b/src/conntrack/getter.c index 20dd905..e818a05 100644 --- a/src/conntrack/getter.c +++ b/src/conntrack/getter.c @@ -214,6 +214,16 @@ static const void *get_attr_dnat_ipv4(const struct nf_conntrack *ct) return &ct->dnat.min_ip.v4; } +static const void *get_attr_snat_ipv6(const struct nf_conntrack *ct) +{ + return &ct->snat.min_ip.v6; +} + +static const void *get_attr_dnat_ipv6(const struct nf_conntrack *ct) +{ + return &ct->dnat.min_ip.v6; +} + static const void *get_attr_snat_port(const struct nf_conntrack *ct) { return &ct->snat.l4min.all; @@ -430,4 +440,6 @@ const get_attr get_attr_array[ATTR_MAX] = { [ATTR_HELPER_INFO] = get_attr_helper_info, [ATTR_CONNLABELS] = get_attr_connlabels, [ATTR_CONNLABELS_MASK] = get_attr_connlabels_mask, + [ATTR_SNAT_IPV6] = get_attr_snat_ipv6, + [ATTR_DNAT_IPV6] = get_attr_dnat_ipv6, }; diff --git a/src/conntrack/objopt.c b/src/conntrack/objopt.c index ab0b1a3..119a83a 100644 --- a/src/conntrack/objopt.c +++ b/src/conntrack/objopt.c @@ -59,6 +59,15 @@ static void setobjopt_undo_snat(struct nf_conntrack *ct) ct->repl.dst.v4 = ct->head.orig.src.v4; set_bit(ATTR_SNAT_IPV4, ct->head.set); break; + case AF_INET6: + memcpy(&ct->snat.min_ip.v6, &ct->repl.dst.v6, + sizeof(struct in6_addr)); + memcpy(&ct->snat.max_ip.v6, &ct->snat.min_ip.v6, + sizeof(struct in6_addr)); + memcpy(&ct->repl.dst.v6, &ct->head.orig.src.v6, + sizeof(struct in6_addr)); + set_bit(ATTR_SNAT_IPV6, ct->head.set); + break; default: break; } @@ -72,6 +81,15 @@ static void setobjopt_undo_dnat(struct nf_conntrack *ct) ct->dnat.max_ip.v4 = ct->dnat.min_ip.v4; ct->repl.src.v4 = ct->head.orig.dst.v4; set_bit(ATTR_DNAT_IPV4, ct->head.set); + case AF_INET6: + memcpy(&ct->dnat.min_ip.v6, &ct->repl.src.v6, + sizeof(struct in6_addr)); + memcpy(&ct->dnat.max_ip.v6, &ct->dnat.min_ip.v6, + sizeof(struct in6_addr)); + memcpy(&ct->repl.src.v6, &ct->head.orig.dst.v6, + sizeof(struct in6_addr)); + set_bit(ATTR_DNAT_IPV6, ct->head.set); + break; default: break; } @@ -125,7 +143,7 @@ int __setobjopt(struct nf_conntrack *ct, unsigned int option) static int getobjopt_is_snat(const struct nf_conntrack *ct) { - if (!(test_bit(ATTR_STATUS, ct->head.set)) + if (!(test_bit(ATTR_STATUS, ct->head.set))) return 0; if (!(ct->status & IPS_SRC_NAT_DONE)) @@ -134,6 +152,12 @@ static int getobjopt_is_snat(const struct nf_conntrack *ct) switch (ct->head.orig.l3protonum) { case AF_INET: return ct->repl.dst.v4 != ct->head.orig.src.v4; + case AF_INET6: + if (memcmp(&ct->repl.dst.v6, &ct->head.orig.src.v6, + sizeof(struct in6_addr)) != 0) + return 1; + else + return 0; default: return 0; } @@ -141,7 +165,7 @@ static int getobjopt_is_snat(const struct nf_conntrack *ct) static int getobjopt_is_dnat(const struct nf_conntrack *ct) { - if (!(test_bit(ATTR_STATUS, ct->head.set)) + if (!(test_bit(ATTR_STATUS, ct->head.set))) return 0; if (!(ct->status & IPS_DST_NAT_DONE)) @@ -150,6 +174,12 @@ static int getobjopt_is_dnat(const struct nf_conntrack *ct) switch (ct->head.orig.l3protonum) { case AF_INET: return ct->repl.src.v4 != ct->head.orig.dst.v4; + case AF_INET6: + if (memcmp(&ct->repl.src.v6, &ct->head.orig.dst.v6, + sizeof(struct in6_addr)) != 0) + return 1; + else + return 0; default: return 0; } diff --git a/src/conntrack/setter.c b/src/conntrack/setter.c index e103646..75ab09e 100644 --- a/src/conntrack/setter.c +++ b/src/conntrack/setter.c @@ -246,6 +246,20 @@ set_attr_dnat_ipv4(struct nf_conntrack *ct, const void *value, size_t len) ct->dnat.min_ip.v4 = ct->dnat.max_ip.v4 = *((uint32_t *) value); } +static void +set_attr_snat_ipv6(struct nf_conntrack *ct, const void *value, size_t len) +{ + memcpy(&ct->snat.min_ip.v6, value, sizeof(struct in6_addr)); + memcpy(&ct->snat.max_ip.v6, value, sizeof(struct in6_addr)); +} + +static void +set_attr_dnat_ipv6(struct nf_conntrack *ct, const void *value, size_t len) +{ + memcpy(&ct->dnat.min_ip.v6, value, sizeof(struct in6_addr)); + memcpy(&ct->dnat.max_ip.v6, value, sizeof(struct in6_addr)); +} + static void set_attr_snat_port(struct nf_conntrack *ct, const void *value, size_t len) { @@ -527,4 +541,6 @@ const set_attr set_attr_array[ATTR_MAX] = { [ATTR_HELPER_INFO] = set_attr_helper_info, [ATTR_CONNLABELS] = set_attr_connlabels, [ATTR_CONNLABELS_MASK] = set_attr_connlabels_mask, + [ATTR_SNAT_IPV6] = set_attr_snat_ipv6, + [ATTR_DNAT_IPV6] = set_attr_dnat_ipv6, }; -- cgit v1.2.3