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: Florian Westphal <fw@strlen.de> Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
This commit is contained in:
committed by
Pablo Neira Ayuso
parent
d1aca8ab31
commit
096d09067a
@@ -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 @@
|
|||||||
|
|
||||||
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,
|
|||||||
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 @@
|
|||||||
|
|
||||||
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,
|
|||||||
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,
|
||||||
|
|||||||
+123
-19
@@ -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)
|
|||||||
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] = {
|
|||||||
[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,
|
|||||||
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,
|
|||||||
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,
|
|||||||
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;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user