Commit 096d0906 authored by Florian Westphal's avatar Florian Westphal Committed by Pablo Neira Ayuso

netfilter: nat: move nlattr parse and xfrm session decode to core

None of these functions calls any external functions, moving them allows
to avoid both the indirection and a need to export these symbols.
Signed-off-by: default avatarFlorian Westphal <fw@strlen.de>
Signed-off-by: default avatarPablo Neira Ayuso <pablo@netfilter.org>
parent d1aca8ab
...@@ -18,15 +18,6 @@ struct nf_nat_l3proto { ...@@ -18,15 +18,6 @@ struct nf_nat_l3proto {
void (*csum_recalc)(struct sk_buff *skb, u8 proto, void (*csum_recalc)(struct sk_buff *skb, u8 proto,
void *data, __sum16 *check, void *data, __sum16 *check,
int datalen, int oldlen); int datalen, int oldlen);
void (*decode_session)(struct sk_buff *skb,
const struct nf_conn *ct,
enum ip_conntrack_dir dir,
unsigned long statusbit,
struct flowi *fl);
int (*nlattr_to_range)(struct nlattr *tb[],
struct nf_nat_range2 *range);
}; };
int nf_nat_l3proto_register(const struct nf_nat_l3proto *); int nf_nat_l3proto_register(const struct nf_nat_l3proto *);
......
...@@ -28,40 +28,6 @@ ...@@ -28,40 +28,6 @@
static const struct nf_nat_l3proto nf_nat_l3proto_ipv4; static const struct nf_nat_l3proto nf_nat_l3proto_ipv4;
#ifdef CONFIG_XFRM
static void nf_nat_ipv4_decode_session(struct sk_buff *skb,
const struct nf_conn *ct,
enum ip_conntrack_dir dir,
unsigned long statusbit,
struct flowi *fl)
{
const struct nf_conntrack_tuple *t = &ct->tuplehash[dir].tuple;
struct flowi4 *fl4 = &fl->u.ip4;
if (ct->status & statusbit) {
fl4->daddr = t->dst.u3.ip;
if (t->dst.protonum == IPPROTO_TCP ||
t->dst.protonum == IPPROTO_UDP ||
t->dst.protonum == IPPROTO_UDPLITE ||
t->dst.protonum == IPPROTO_DCCP ||
t->dst.protonum == IPPROTO_SCTP)
fl4->fl4_dport = t->dst.u.all;
}
statusbit ^= IPS_NAT_MASK;
if (ct->status & statusbit) {
fl4->saddr = t->src.u3.ip;
if (t->dst.protonum == IPPROTO_TCP ||
t->dst.protonum == IPPROTO_UDP ||
t->dst.protonum == IPPROTO_UDPLITE ||
t->dst.protonum == IPPROTO_DCCP ||
t->dst.protonum == IPPROTO_SCTP)
fl4->fl4_sport = t->src.u.all;
}
}
#endif /* CONFIG_XFRM */
static bool nf_nat_ipv4_manip_pkt(struct sk_buff *skb, static bool nf_nat_ipv4_manip_pkt(struct sk_buff *skb,
unsigned int iphdroff, unsigned int iphdroff,
const struct nf_conntrack_tuple *target, const struct nf_conntrack_tuple *target,
...@@ -127,35 +93,11 @@ static void nf_nat_ipv4_csum_recalc(struct sk_buff *skb, ...@@ -127,35 +93,11 @@ static void nf_nat_ipv4_csum_recalc(struct sk_buff *skb,
htons(oldlen), htons(datalen), true); htons(oldlen), htons(datalen), true);
} }
#if IS_ENABLED(CONFIG_NF_CT_NETLINK)
static int nf_nat_ipv4_nlattr_to_range(struct nlattr *tb[],
struct nf_nat_range2 *range)
{
if (tb[CTA_NAT_V4_MINIP]) {
range->min_addr.ip = nla_get_be32(tb[CTA_NAT_V4_MINIP]);
range->flags |= NF_NAT_RANGE_MAP_IPS;
}
if (tb[CTA_NAT_V4_MAXIP])
range->max_addr.ip = nla_get_be32(tb[CTA_NAT_V4_MAXIP]);
else
range->max_addr.ip = range->min_addr.ip;
return 0;
}
#endif
static const struct nf_nat_l3proto nf_nat_l3proto_ipv4 = { static const struct nf_nat_l3proto nf_nat_l3proto_ipv4 = {
.l3proto = NFPROTO_IPV4, .l3proto = NFPROTO_IPV4,
.manip_pkt = nf_nat_ipv4_manip_pkt, .manip_pkt = nf_nat_ipv4_manip_pkt,
.csum_update = nf_nat_ipv4_csum_update, .csum_update = nf_nat_ipv4_csum_update,
.csum_recalc = nf_nat_ipv4_csum_recalc, .csum_recalc = nf_nat_ipv4_csum_recalc,
#if IS_ENABLED(CONFIG_NF_CT_NETLINK)
.nlattr_to_range = nf_nat_ipv4_nlattr_to_range,
#endif
#ifdef CONFIG_XFRM
.decode_session = nf_nat_ipv4_decode_session,
#endif
}; };
int nf_nat_icmp_reply_translation(struct sk_buff *skb, int nf_nat_icmp_reply_translation(struct sk_buff *skb,
......
...@@ -28,40 +28,6 @@ ...@@ -28,40 +28,6 @@
static const struct nf_nat_l3proto nf_nat_l3proto_ipv6; static const struct nf_nat_l3proto nf_nat_l3proto_ipv6;
#ifdef CONFIG_XFRM
static void nf_nat_ipv6_decode_session(struct sk_buff *skb,
const struct nf_conn *ct,
enum ip_conntrack_dir dir,
unsigned long statusbit,
struct flowi *fl)
{
const struct nf_conntrack_tuple *t = &ct->tuplehash[dir].tuple;
struct flowi6 *fl6 = &fl->u.ip6;
if (ct->status & statusbit) {
fl6->daddr = t->dst.u3.in6;
if (t->dst.protonum == IPPROTO_TCP ||
t->dst.protonum == IPPROTO_UDP ||
t->dst.protonum == IPPROTO_UDPLITE ||
t->dst.protonum == IPPROTO_DCCP ||
t->dst.protonum == IPPROTO_SCTP)
fl6->fl6_dport = t->dst.u.all;
}
statusbit ^= IPS_NAT_MASK;
if (ct->status & statusbit) {
fl6->saddr = t->src.u3.in6;
if (t->dst.protonum == IPPROTO_TCP ||
t->dst.protonum == IPPROTO_UDP ||
t->dst.protonum == IPPROTO_UDPLITE ||
t->dst.protonum == IPPROTO_DCCP ||
t->dst.protonum == IPPROTO_SCTP)
fl6->fl6_sport = t->src.u.all;
}
}
#endif
static bool nf_nat_ipv6_manip_pkt(struct sk_buff *skb, static bool nf_nat_ipv6_manip_pkt(struct sk_buff *skb,
unsigned int iphdroff, unsigned int iphdroff,
const struct nf_conntrack_tuple *target, const struct nf_conntrack_tuple *target,
...@@ -136,37 +102,11 @@ static void nf_nat_ipv6_csum_recalc(struct sk_buff *skb, ...@@ -136,37 +102,11 @@ static void nf_nat_ipv6_csum_recalc(struct sk_buff *skb,
htons(oldlen), htons(datalen), true); htons(oldlen), htons(datalen), true);
} }
#if IS_ENABLED(CONFIG_NF_CT_NETLINK)
static int nf_nat_ipv6_nlattr_to_range(struct nlattr *tb[],
struct nf_nat_range2 *range)
{
if (tb[CTA_NAT_V6_MINIP]) {
nla_memcpy(&range->min_addr.ip6, tb[CTA_NAT_V6_MINIP],
sizeof(struct in6_addr));
range->flags |= NF_NAT_RANGE_MAP_IPS;
}
if (tb[CTA_NAT_V6_MAXIP])
nla_memcpy(&range->max_addr.ip6, tb[CTA_NAT_V6_MAXIP],
sizeof(struct in6_addr));
else
range->max_addr = range->min_addr;
return 0;
}
#endif
static const struct nf_nat_l3proto nf_nat_l3proto_ipv6 = { static const struct nf_nat_l3proto nf_nat_l3proto_ipv6 = {
.l3proto = NFPROTO_IPV6, .l3proto = NFPROTO_IPV6,
.manip_pkt = nf_nat_ipv6_manip_pkt, .manip_pkt = nf_nat_ipv6_manip_pkt,
.csum_update = nf_nat_ipv6_csum_update, .csum_update = nf_nat_ipv6_csum_update,
.csum_recalc = nf_nat_ipv6_csum_recalc, .csum_recalc = nf_nat_ipv6_csum_recalc,
#if IS_ENABLED(CONFIG_NF_CT_NETLINK)
.nlattr_to_range = nf_nat_ipv6_nlattr_to_range,
#endif
#ifdef CONFIG_XFRM
.decode_session = nf_nat_ipv6_decode_session,
#endif
}; };
int nf_nat_icmpv6_reply_translation(struct sk_buff *skb, int nf_nat_icmpv6_reply_translation(struct sk_buff *skb,
......
...@@ -65,9 +65,74 @@ __nf_nat_l3proto_find(u8 family) ...@@ -65,9 +65,74 @@ __nf_nat_l3proto_find(u8 family)
} }
#ifdef CONFIG_XFRM #ifdef CONFIG_XFRM
static void nf_nat_ipv4_decode_session(struct sk_buff *skb,
const struct nf_conn *ct,
enum ip_conntrack_dir dir,
unsigned long statusbit,
struct flowi *fl)
{
const struct nf_conntrack_tuple *t = &ct->tuplehash[dir].tuple;
struct flowi4 *fl4 = &fl->u.ip4;
if (ct->status & statusbit) {
fl4->daddr = t->dst.u3.ip;
if (t->dst.protonum == IPPROTO_TCP ||
t->dst.protonum == IPPROTO_UDP ||
t->dst.protonum == IPPROTO_UDPLITE ||
t->dst.protonum == IPPROTO_DCCP ||
t->dst.protonum == IPPROTO_SCTP)
fl4->fl4_dport = t->dst.u.all;
}
statusbit ^= IPS_NAT_MASK;
if (ct->status & statusbit) {
fl4->saddr = t->src.u3.ip;
if (t->dst.protonum == IPPROTO_TCP ||
t->dst.protonum == IPPROTO_UDP ||
t->dst.protonum == IPPROTO_UDPLITE ||
t->dst.protonum == IPPROTO_DCCP ||
t->dst.protonum == IPPROTO_SCTP)
fl4->fl4_sport = t->src.u.all;
}
}
static void nf_nat_ipv6_decode_session(struct sk_buff *skb,
const struct nf_conn *ct,
enum ip_conntrack_dir dir,
unsigned long statusbit,
struct flowi *fl)
{
#if IS_ENABLED(CONFIG_IPV6)
const struct nf_conntrack_tuple *t = &ct->tuplehash[dir].tuple;
struct flowi6 *fl6 = &fl->u.ip6;
if (ct->status & statusbit) {
fl6->daddr = t->dst.u3.in6;
if (t->dst.protonum == IPPROTO_TCP ||
t->dst.protonum == IPPROTO_UDP ||
t->dst.protonum == IPPROTO_UDPLITE ||
t->dst.protonum == IPPROTO_DCCP ||
t->dst.protonum == IPPROTO_SCTP)
fl6->fl6_dport = t->dst.u.all;
}
statusbit ^= IPS_NAT_MASK;
if (ct->status & statusbit) {
fl6->saddr = t->src.u3.in6;
if (t->dst.protonum == IPPROTO_TCP ||
t->dst.protonum == IPPROTO_UDP ||
t->dst.protonum == IPPROTO_UDPLITE ||
t->dst.protonum == IPPROTO_DCCP ||
t->dst.protonum == IPPROTO_SCTP)
fl6->fl6_sport = t->src.u.all;
}
#endif
}
static void __nf_nat_decode_session(struct sk_buff *skb, struct flowi *fl) static void __nf_nat_decode_session(struct sk_buff *skb, struct flowi *fl)
{ {
const struct nf_nat_l3proto *l3proto;
const struct nf_conn *ct; const struct nf_conn *ct;
enum ip_conntrack_info ctinfo; enum ip_conntrack_info ctinfo;
enum ip_conntrack_dir dir; enum ip_conntrack_dir dir;
...@@ -79,17 +144,20 @@ static void __nf_nat_decode_session(struct sk_buff *skb, struct flowi *fl) ...@@ -79,17 +144,20 @@ static void __nf_nat_decode_session(struct sk_buff *skb, struct flowi *fl)
return; return;
family = nf_ct_l3num(ct); family = nf_ct_l3num(ct);
l3proto = __nf_nat_l3proto_find(family);
if (l3proto == NULL)
return;
dir = CTINFO2DIR(ctinfo); dir = CTINFO2DIR(ctinfo);
if (dir == IP_CT_DIR_ORIGINAL) if (dir == IP_CT_DIR_ORIGINAL)
statusbit = IPS_DST_NAT; statusbit = IPS_DST_NAT;
else else
statusbit = IPS_SRC_NAT; statusbit = IPS_SRC_NAT;
l3proto->decode_session(skb, ct, dir, statusbit, fl); switch (family) {
case NFPROTO_IPV4:
nf_nat_ipv4_decode_session(skb, ct, dir, statusbit, fl);
return;
case NFPROTO_IPV6:
nf_nat_ipv6_decode_session(skb, ct, dir, statusbit, fl);
return;
}
} }
int nf_xfrm_me_harder(struct net *net, struct sk_buff *skb, unsigned int family) int nf_xfrm_me_harder(struct net *net, struct sk_buff *skb, unsigned int family)
...@@ -887,10 +955,43 @@ static const struct nla_policy nat_nla_policy[CTA_NAT_MAX+1] = { ...@@ -887,10 +955,43 @@ static const struct nla_policy nat_nla_policy[CTA_NAT_MAX+1] = {
[CTA_NAT_PROTO] = { .type = NLA_NESTED }, [CTA_NAT_PROTO] = { .type = NLA_NESTED },
}; };
static int nf_nat_ipv4_nlattr_to_range(struct nlattr *tb[],
struct nf_nat_range2 *range)
{
if (tb[CTA_NAT_V4_MINIP]) {
range->min_addr.ip = nla_get_be32(tb[CTA_NAT_V4_MINIP]);
range->flags |= NF_NAT_RANGE_MAP_IPS;
}
if (tb[CTA_NAT_V4_MAXIP])
range->max_addr.ip = nla_get_be32(tb[CTA_NAT_V4_MAXIP]);
else
range->max_addr.ip = range->min_addr.ip;
return 0;
}
static int nf_nat_ipv6_nlattr_to_range(struct nlattr *tb[],
struct nf_nat_range2 *range)
{
if (tb[CTA_NAT_V6_MINIP]) {
nla_memcpy(&range->min_addr.ip6, tb[CTA_NAT_V6_MINIP],
sizeof(struct in6_addr));
range->flags |= NF_NAT_RANGE_MAP_IPS;
}
if (tb[CTA_NAT_V6_MAXIP])
nla_memcpy(&range->max_addr.ip6, tb[CTA_NAT_V6_MAXIP],
sizeof(struct in6_addr));
else
range->max_addr = range->min_addr;
return 0;
}
static int static int
nfnetlink_parse_nat(const struct nlattr *nat, nfnetlink_parse_nat(const struct nlattr *nat,
const struct nf_conn *ct, struct nf_nat_range2 *range, const struct nf_conn *ct, struct nf_nat_range2 *range)
const struct nf_nat_l3proto *l3proto)
{ {
struct nlattr *tb[CTA_NAT_MAX+1]; struct nlattr *tb[CTA_NAT_MAX+1];
int err; int err;
...@@ -901,8 +1002,19 @@ nfnetlink_parse_nat(const struct nlattr *nat, ...@@ -901,8 +1002,19 @@ nfnetlink_parse_nat(const struct nlattr *nat,
if (err < 0) if (err < 0)
return err; return err;
err = l3proto->nlattr_to_range(tb, range); switch (nf_ct_l3num(ct)) {
if (err < 0) case NFPROTO_IPV4:
err = nf_nat_ipv4_nlattr_to_range(tb, range);
break;
case NFPROTO_IPV6:
err = nf_nat_ipv6_nlattr_to_range(tb, range);
break;
default:
err = -EPROTONOSUPPORT;
break;
}
if (err)
return err; return err;
if (!tb[CTA_NAT_PROTO]) if (!tb[CTA_NAT_PROTO])
...@@ -918,7 +1030,6 @@ nfnetlink_parse_nat_setup(struct nf_conn *ct, ...@@ -918,7 +1030,6 @@ nfnetlink_parse_nat_setup(struct nf_conn *ct,
const struct nlattr *attr) const struct nlattr *attr)
{ {
struct nf_nat_range2 range; struct nf_nat_range2 range;
const struct nf_nat_l3proto *l3proto;
int err; int err;
/* Should not happen, restricted to creating new conntracks /* Should not happen, restricted to creating new conntracks
...@@ -927,18 +1038,11 @@ nfnetlink_parse_nat_setup(struct nf_conn *ct, ...@@ -927,18 +1038,11 @@ nfnetlink_parse_nat_setup(struct nf_conn *ct,
if (WARN_ON_ONCE(nf_nat_initialized(ct, manip))) if (WARN_ON_ONCE(nf_nat_initialized(ct, manip)))
return -EEXIST; return -EEXIST;
/* Make sure that L3 NAT is there by when we call nf_nat_setup_info to
* attach the null binding, otherwise this may oops.
*/
l3proto = __nf_nat_l3proto_find(nf_ct_l3num(ct));
if (l3proto == NULL)
return -EAGAIN;
/* No NAT information has been passed, allocate the null-binding */ /* No NAT information has been passed, allocate the null-binding */
if (attr == NULL) if (attr == NULL)
return __nf_nat_alloc_null_binding(ct, manip) == NF_DROP ? -ENOMEM : 0; return __nf_nat_alloc_null_binding(ct, manip) == NF_DROP ? -ENOMEM : 0;
err = nfnetlink_parse_nat(attr, ct, &range, l3proto); err = nfnetlink_parse_nat(attr, ct, &range);
if (err < 0) if (err < 0)
return err; return err;
......
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