Commit 876665ea authored by Pablo Neira Ayuso's avatar Pablo Neira Ayuso

netfilter: nft_chain_nat_ipv6: use generic IPv6 NAT code from core

Use the exported IPv6 NAT functions that are provided by the core. This
removes duplicated code so iptables and nft use the same NAT codebase.
Signed-off-by: default avatarPablo Neira Ayuso <pablo@netfilter.org>
parent 2a5538e9
...@@ -24,144 +24,53 @@ ...@@ -24,144 +24,53 @@
#include <net/netfilter/nf_nat_l3proto.h> #include <net/netfilter/nf_nat_l3proto.h>
#include <net/ipv6.h> #include <net/ipv6.h>
/* static unsigned int nft_nat_do_chain(const struct nf_hook_ops *ops,
* IPv6 NAT chains struct sk_buff *skb,
*/ const struct net_device *in,
const struct net_device *out,
static unsigned int nft_nat_ipv6_fn(const struct nf_hook_ops *ops, struct nf_conn *ct)
struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
int (*okfn)(struct sk_buff *))
{ {
enum ip_conntrack_info ctinfo;
struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
struct nf_conn_nat *nat;
enum nf_nat_manip_type maniptype = HOOK2MANIP(ops->hooknum);
__be16 frag_off;
int hdrlen;
u8 nexthdr;
struct nft_pktinfo pkt; struct nft_pktinfo pkt;
unsigned int ret;
if (ct == NULL || nf_ct_is_untracked(ct))
return NF_ACCEPT;
nat = nf_ct_nat_ext_add(ct);
if (nat == NULL)
return NF_ACCEPT;
switch (ctinfo) {
case IP_CT_RELATED:
case IP_CT_RELATED + IP_CT_IS_REPLY:
nexthdr = ipv6_hdr(skb)->nexthdr;
hdrlen = ipv6_skip_exthdr(skb, sizeof(struct ipv6hdr),
&nexthdr, &frag_off);
if (hdrlen >= 0 && nexthdr == IPPROTO_ICMPV6) {
if (!nf_nat_icmpv6_reply_translation(skb, ct, ctinfo,
ops->hooknum,
hdrlen))
return NF_DROP;
else
return NF_ACCEPT;
}
/* Fall through */
case IP_CT_NEW:
if (nf_nat_initialized(ct, maniptype))
break;
nft_set_pktinfo_ipv6(&pkt, ops, skb, in, out);
ret = nft_do_chain(&pkt, ops); nft_set_pktinfo_ipv6(&pkt, ops, skb, in, out);
if (ret != NF_ACCEPT)
return ret;
if (!nf_nat_initialized(ct, maniptype)) {
ret = nf_nat_alloc_null_binding(ct, ops->hooknum);
if (ret != NF_ACCEPT)
return ret;
}
default:
break;
}
return nf_nat_packet(ct, ctinfo, ops->hooknum, skb); return nft_do_chain(&pkt, ops);
} }
static unsigned int nf_nat_ipv6_prerouting(const struct nf_hook_ops *ops, static unsigned int nft_nat_ipv6_fn(const struct nf_hook_ops *ops,
struct sk_buff *skb, struct sk_buff *skb,
const struct net_device *in, const struct net_device *in,
const struct net_device *out, const struct net_device *out,
int (*okfn)(struct sk_buff *)) int (*okfn)(struct sk_buff *))
{ {
struct in6_addr daddr = ipv6_hdr(skb)->daddr; return nf_nat_ipv6_fn(ops, skb, in, out, nft_nat_do_chain);
unsigned int ret;
ret = nft_nat_ipv6_fn(ops, skb, in, out, okfn);
if (ret != NF_DROP && ret != NF_STOLEN &&
ipv6_addr_cmp(&daddr, &ipv6_hdr(skb)->daddr))
skb_dst_drop(skb);
return ret;
} }
static unsigned int nf_nat_ipv6_postrouting(const struct nf_hook_ops *ops, static unsigned int nft_nat_ipv6_in(const struct nf_hook_ops *ops,
struct sk_buff *skb, struct sk_buff *skb,
const struct net_device *in, const struct net_device *in,
const struct net_device *out, const struct net_device *out,
int (*okfn)(struct sk_buff *)) int (*okfn)(struct sk_buff *))
{ {
enum ip_conntrack_info ctinfo __maybe_unused; return nf_nat_ipv6_in(ops, skb, in, out, nft_nat_do_chain);
const struct nf_conn *ct __maybe_unused;
unsigned int ret;
ret = nft_nat_ipv6_fn(ops, skb, in, out, okfn);
#ifdef CONFIG_XFRM
if (ret != NF_DROP && ret != NF_STOLEN &&
!(IP6CB(skb)->flags & IP6SKB_XFRM_TRANSFORMED) &&
(ct = nf_ct_get(skb, &ctinfo)) != NULL) {
enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
if (!nf_inet_addr_cmp(&ct->tuplehash[dir].tuple.src.u3,
&ct->tuplehash[!dir].tuple.dst.u3) ||
(ct->tuplehash[dir].tuple.src.u.all !=
ct->tuplehash[!dir].tuple.dst.u.all))
if (nf_xfrm_me_harder(skb, AF_INET6) < 0)
ret = NF_DROP;
}
#endif
return ret;
} }
static unsigned int nf_nat_ipv6_output(const struct nf_hook_ops *ops, static unsigned int nft_nat_ipv6_out(const struct nf_hook_ops *ops,
struct sk_buff *skb, struct sk_buff *skb,
const struct net_device *in, const struct net_device *in,
const struct net_device *out, const struct net_device *out,
int (*okfn)(struct sk_buff *)) int (*okfn)(struct sk_buff *))
{ {
enum ip_conntrack_info ctinfo; return nf_nat_ipv6_out(ops, skb, in, out, nft_nat_do_chain);
const struct nf_conn *ct; }
unsigned int ret;
ret = nft_nat_ipv6_fn(ops, skb, in, out, okfn);
if (ret != NF_DROP && ret != NF_STOLEN &&
(ct = nf_ct_get(skb, &ctinfo)) != NULL) {
enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
if (!nf_inet_addr_cmp(&ct->tuplehash[dir].tuple.dst.u3, static unsigned int nft_nat_ipv6_local_fn(const struct nf_hook_ops *ops,
&ct->tuplehash[!dir].tuple.src.u3)) { struct sk_buff *skb,
if (ip6_route_me_harder(skb)) const struct net_device *in,
ret = NF_DROP; const struct net_device *out,
} int (*okfn)(struct sk_buff *))
#ifdef CONFIG_XFRM {
else if (!(IP6CB(skb)->flags & IP6SKB_XFRM_TRANSFORMED) && return nf_nat_ipv6_local_fn(ops, skb, in, out, nft_nat_do_chain);
ct->tuplehash[dir].tuple.dst.u.all !=
ct->tuplehash[!dir].tuple.src.u.all)
if (nf_xfrm_me_harder(skb, AF_INET6))
ret = NF_DROP;
#endif
}
return ret;
} }
static const struct nf_chain_type nft_chain_nat_ipv6 = { static const struct nf_chain_type nft_chain_nat_ipv6 = {
...@@ -174,9 +83,9 @@ static const struct nf_chain_type nft_chain_nat_ipv6 = { ...@@ -174,9 +83,9 @@ static const struct nf_chain_type nft_chain_nat_ipv6 = {
(1 << NF_INET_LOCAL_OUT) | (1 << NF_INET_LOCAL_OUT) |
(1 << NF_INET_LOCAL_IN), (1 << NF_INET_LOCAL_IN),
.hooks = { .hooks = {
[NF_INET_PRE_ROUTING] = nf_nat_ipv6_prerouting, [NF_INET_PRE_ROUTING] = nft_nat_ipv6_in,
[NF_INET_POST_ROUTING] = nf_nat_ipv6_postrouting, [NF_INET_POST_ROUTING] = nft_nat_ipv6_out,
[NF_INET_LOCAL_OUT] = nf_nat_ipv6_output, [NF_INET_LOCAL_OUT] = nft_nat_ipv6_local_fn,
[NF_INET_LOCAL_IN] = nft_nat_ipv6_fn, [NF_INET_LOCAL_IN] = nft_nat_ipv6_fn,
}, },
}; };
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment