From: Florian Westphal <fw@strlen.de>
To: <netfilter-devel@vger.kernel.org>
Cc: eric@garver.life, phil@nwl.cc, kadlec@netfilter.org,
Florian Westphal <fw@strlen.de>
Subject: [PATCH RFC 2/2] netfilter: nf_nat: don't allow source ports that shadow local port
Date: Thu, 23 Sep 2021 15:12:43 +0200 [thread overview]
Message-ID: <20210923131243.24071-3-fw@strlen.de> (raw)
In-Reply-To: <20210923131243.24071-1-fw@strlen.de>
PoC, incomplete -- ipv4 udp only.
Ipv6 support needs help from ipv6 indirection infra.
Also lacks direction support: the check should only be done
for nf_conn objects created by externally generated packets.
Don't apply.
---
net/netfilter/nf_nat_core.c | 41 ++++++++++++++++++++++++++++++++++---
1 file changed, 38 insertions(+), 3 deletions(-)
diff --git a/net/netfilter/nf_nat_core.c b/net/netfilter/nf_nat_core.c
index 273117683922..843b639200f8 100644
--- a/net/netfilter/nf_nat_core.c
+++ b/net/netfilter/nf_nat_core.c
@@ -24,6 +24,7 @@
#include <net/netfilter/nf_nat.h>
#include <net/netfilter/nf_nat_helper.h>
#include <uapi/linux/netfilter/nf_nat.h>
+#include <net/udp.h>
#include "nf_internals.h"
@@ -372,6 +373,30 @@ find_best_ips_proto(const struct nf_conntrack_zone *zone,
}
}
+static bool is_port_shadow(struct net *net, const struct nf_conntrack_tuple *tuple)
+{
+ const struct sock *sk;
+ __be32 saddr, daddr;
+ __be16 sport, dport;
+
+ if (tuple->src.l3num != NFPROTO_IPV4 ||
+ tuple->dst.protonum != IPPROTO_UDP)
+ return false;
+
+ saddr = tuple->dst.u3.ip;
+ daddr = tuple->src.u3.ip;
+ sport = tuple->dst.u.udp.port;
+ dport = tuple->src.u.udp.port;
+
+ sk = __udp4_lib_lookup(net, saddr, sport, daddr, dport, 0, 0, &udp_table, NULL);
+
+ /* if this returns a socket, then replies might be reverse-natted and
+ * forwarded instead of being delivered to the local socket.
+ */
+
+ return sk != NULL;
+}
+
/* Alter the per-proto part of the tuple (depending on maniptype), to
* give a unique tuple in the given range if possible.
*
@@ -483,6 +508,10 @@ static void nf_nat_l4proto_unique_tuple(struct nf_conntrack_tuple *tuple,
another_round:
for (i = 0; i < attempts; i++, off++) {
*keyptr = htons(min + off % range_size);
+
+ if (maniptype == NF_NAT_MANIP_SRC && is_port_shadow(nf_ct_net(ct), tuple))
+ continue;
+
if (!nf_nat_used_tuple(tuple, ct))
return;
}
@@ -507,6 +536,7 @@ get_unique_tuple(struct nf_conntrack_tuple *tuple,
struct nf_conn *ct,
enum nf_nat_manip_type maniptype)
{
+ bool force_random = range->flags & NF_NAT_RANGE_PROTO_RANDOM_ALL;
const struct nf_conntrack_zone *zone;
struct net *net = nf_ct_net(ct);
@@ -520,8 +550,12 @@ get_unique_tuple(struct nf_conntrack_tuple *tuple,
* So far, we don't do local source mappings, so multiple
* manips not an issue.
*/
- if (maniptype == NF_NAT_MANIP_SRC &&
- !(range->flags & NF_NAT_RANGE_PROTO_RANDOM_ALL)) {
+ if (maniptype == NF_NAT_MANIP_SRC && !force_random) {
+ if (is_port_shadow(nf_ct_net(ct), orig_tuple)) {
+ force_random = true;
+ goto find_best_ips;
+ }
+
/* try the original tuple first */
if (in_range(orig_tuple, range)) {
if (!nf_nat_used_tuple(orig_tuple, ct)) {
@@ -536,6 +570,7 @@ get_unique_tuple(struct nf_conntrack_tuple *tuple,
}
}
+find_best_ips:
/* 2) Select the least-used IP/proto combination in the given range */
*tuple = *orig_tuple;
find_best_ips_proto(zone, tuple, range, ct, maniptype);
@@ -545,7 +580,7 @@ get_unique_tuple(struct nf_conntrack_tuple *tuple,
*/
/* Only bother mapping if it's not already in range and unique */
- if (!(range->flags & NF_NAT_RANGE_PROTO_RANDOM_ALL)) {
+ if (!force_random) {
if (range->flags & NF_NAT_RANGE_PROTO_SPECIFIED) {
if (!(range->flags & NF_NAT_RANGE_PROTO_OFFSET) &&
l4proto_in_range(tuple, maniptype,
--
2.32.0
next prev parent reply other threads:[~2021-09-23 13:13 UTC|newest]
Thread overview: 7+ messages / expand[flat|nested] mbox.gz Atom feed top
2021-09-23 13:12 [PATCH nf 0/1.5 RFC] netfilter: nat: source port shadowing Florian Westphal
2021-09-23 13:12 ` [PATCH nf 1/2] selftests: nft_nat: add udp hole punch test case Florian Westphal
2021-10-11 23:42 ` Pablo Neira Ayuso
2021-09-23 13:12 ` Florian Westphal [this message]
2021-10-01 13:21 ` [PATCH RFC 2/2] netfilter: nf_nat: don't allow source ports that shadow local port Florian Westphal
2021-10-04 10:16 ` Pablo Neira Ayuso
2021-10-04 10:41 ` Florian Westphal
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20210923131243.24071-3-fw@strlen.de \
--to=fw@strlen.de \
--cc=eric@garver.life \
--cc=kadlec@netfilter.org \
--cc=netfilter-devel@vger.kernel.org \
--cc=phil@nwl.cc \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).