[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Message-id: <20181129015626.85441-1-cpaasch@apple.com>
Date: Wed, 28 Nov 2018 17:56:26 -0800
From: Christoph Paasch <cpaasch@...le.com>
To: netdev@...r.kernel.org
Cc: Ian Swett <ianswett@...gle.com>,
Leif Hedstrom <lhedstrom@...le.com>,
Jana Iyengar <jri.ietf@...il.com>,
Eric Dumazet <edumazet@...gle.com>
Subject: [PATCH] udp: Allow to defer reception until connect() happened
There are use-cases where a host wants to use a UDP socket with a
specific 4-tuple. The way to do this is to bind() and then connect() the
socket. However, after the bind(), the socket starts receiving data even
if it does not match the intended 4-tuple. That is because after the
bind() UDP-socket will match in the lookup for all incoming UDP-traffic
that has the specific IP/port.
This patch prevents any incoming traffic until the connect() system-call
is called whenever the app sets the UDP socket-option
UDP_WAIT_FOR_CONNECT.
Signed-off-by: Christoph Paasch <cpaasch@...le.com>
---
Notes:
Changes compared to the original RFC-submission:
* Make it a UDP-specific socket-option
* Rename it to 'wait-for-connect'
Wrt to the discussion on the original RFC submission
(cfr., https://marc.info/?l=linux-netdev&m=154102843910587&w=2):
We believe that this patch is still useful to enable applications to use
different models of implementing a UDP-server. For some frameworks it is much
easier to have a socket per-connection and thus let the de-multiplexing happen
in the kernel instead of the app.
include/linux/udp.h | 5 ++++-
include/net/udp.h | 1 +
include/uapi/linux/udp.h | 1 +
net/ipv4/udp.c | 26 +++++++++++++++++++++++++-
net/ipv4/udplite.c | 2 +-
net/ipv6/udp.c | 15 ++++++++++++++-
net/ipv6/udp_impl.h | 1 +
net/ipv6/udplite.c | 2 +-
8 files changed, 48 insertions(+), 5 deletions(-)
diff --git a/include/linux/udp.h b/include/linux/udp.h
index 2725c83395bf..9a715d25ce36 100644
--- a/include/linux/udp.h
+++ b/include/linux/udp.h
@@ -55,7 +55,10 @@ struct udp_sock {
* different encapsulation layer set
* this
*/
- gro_enabled:1; /* Can accept GRO packets */
+ gro_enabled:1, /* Can accept GRO packets */
+ wait_for_connect:1;/* Wait until app calls connect()
+ * before accepting incoming data
+ */
/*
* Following member retains the information to create a UDP header
* when the socket is uncorked.
diff --git a/include/net/udp.h b/include/net/udp.h
index fd6d948755c8..b7467a4129b3 100644
--- a/include/net/udp.h
+++ b/include/net/udp.h
@@ -285,6 +285,7 @@ int udp_get_port(struct sock *sk, unsigned short snum,
const struct sock *));
int udp_err(struct sk_buff *, u32);
int udp_abort(struct sock *sk, int err);
+int udp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len);
int udp_sendmsg(struct sock *sk, struct msghdr *msg, size_t len);
int udp_push_pending_frames(struct sock *sk);
void udp_flush_pending_frames(struct sock *sk);
diff --git a/include/uapi/linux/udp.h b/include/uapi/linux/udp.h
index 30baccb6c9c4..b61f8e8dd80b 100644
--- a/include/uapi/linux/udp.h
+++ b/include/uapi/linux/udp.h
@@ -34,6 +34,7 @@ struct udphdr {
#define UDP_NO_CHECK6_RX 102 /* Disable accpeting checksum for UDP6 */
#define UDP_SEGMENT 103 /* Set GSO segmentation size */
#define UDP_GRO 104 /* This socket can receive UDP GRO packets */
+#define UDP_WAIT_FOR_CONNECT 105 /* Don't accept incoming data until the app calls connect() */
/* UDP encapsulation types */
#define UDP_ENCAP_ESPINUDP_NON_IKE 1 /* draft-ietf-ipsec-nat-t-ike-00/01 */
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
index aff2a8e99e01..c5adafcfd52f 100644
--- a/net/ipv4/udp.c
+++ b/net/ipv4/udp.c
@@ -407,6 +407,9 @@ static int compute_score(struct sock *sk, struct net *net,
return -1;
score += 4;
+ if (udp_sk(sk)->wait_for_connect)
+ return -1;
+
if (sk->sk_incoming_cpu == raw_smp_processor_id())
score++;
return score;
@@ -2601,6 +2604,10 @@ int udp_lib_setsockopt(struct sock *sk, int level, int optname,
release_sock(sk);
break;
+ case UDP_WAIT_FOR_CONNECT:
+ up->wait_for_connect = valbool;
+ break;
+
/*
* UDP-Lite's partial checksum coverage (RFC 3828).
*/
@@ -2695,6 +2702,10 @@ int udp_lib_getsockopt(struct sock *sk, int level, int optname,
val = up->gso_size;
break;
+ case UDP_WAIT_FOR_CONNECT:
+ val = up->wait_for_connect;
+ break;
+
/* The following two cannot be changed on UDP sockets, the return is
* always 0 (which corresponds to the full checksum coverage of UDP). */
case UDPLITE_SEND_CSCOV:
@@ -2779,12 +2790,25 @@ int udp_abort(struct sock *sk, int err)
}
EXPORT_SYMBOL_GPL(udp_abort);
+int udp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
+{
+ int ret;
+
+ ret = ip4_datagram_connect(sk, uaddr, addr_len);
+
+ if (!ret)
+ udp_sk(sk)->wait_for_connect = 0;
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(udp_v4_connect);
+
struct proto udp_prot = {
.name = "UDP",
.owner = THIS_MODULE,
.close = udp_lib_close,
.pre_connect = udp_pre_connect,
- .connect = ip4_datagram_connect,
+ .connect = udp_v4_connect,
.disconnect = udp_disconnect,
.ioctl = udp_ioctl,
.init = udp_init_sock,
diff --git a/net/ipv4/udplite.c b/net/ipv4/udplite.c
index 39c7f17d916f..22c74822ff30 100644
--- a/net/ipv4/udplite.c
+++ b/net/ipv4/udplite.c
@@ -41,7 +41,7 @@ struct proto udplite_prot = {
.name = "UDP-Lite",
.owner = THIS_MODULE,
.close = udp_lib_close,
- .connect = ip4_datagram_connect,
+ .connect = udp_v4_connect,
.disconnect = udp_disconnect,
.ioctl = udp_ioctl,
.init = udplite_sk_init,
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c
index 09cba4cfe31f..c3a9101380de 100644
--- a/net/ipv6/udp.c
+++ b/net/ipv6/udp.c
@@ -1681,6 +1681,19 @@ void udp6_proc_exit(struct net *net)
}
#endif /* CONFIG_PROC_FS */
+int udp_v6_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
+{
+ int ret;
+
+ ret = ip6_datagram_connect(sk, uaddr, addr_len);
+
+ if (!ret)
+ udp_sk(sk)->wait_for_connect = 0;
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(udp_v6_connect);
+
/* ------------------------------------------------------------------------ */
struct proto udpv6_prot = {
@@ -1688,7 +1701,7 @@ struct proto udpv6_prot = {
.owner = THIS_MODULE,
.close = udp_lib_close,
.pre_connect = udpv6_pre_connect,
- .connect = ip6_datagram_connect,
+ .connect = udp_v6_connect,
.disconnect = udp_disconnect,
.ioctl = udp_ioctl,
.init = udp_init_sock,
diff --git a/net/ipv6/udp_impl.h b/net/ipv6/udp_impl.h
index 5730e6503cb4..14e847b63db9 100644
--- a/net/ipv6/udp_impl.h
+++ b/net/ipv6/udp_impl.h
@@ -14,6 +14,7 @@ int __udp6_lib_err(struct sk_buff *, struct inet6_skb_parm *, u8, u8, int,
int udp_v6_get_port(struct sock *sk, unsigned short snum);
+int udp_v6_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len);
int udpv6_getsockopt(struct sock *sk, int level, int optname,
char __user *optval, int __user *optlen);
int udpv6_setsockopt(struct sock *sk, int level, int optname,
diff --git a/net/ipv6/udplite.c b/net/ipv6/udplite.c
index a125aebc29e5..035e1b2f2529 100644
--- a/net/ipv6/udplite.c
+++ b/net/ipv6/udplite.c
@@ -38,7 +38,7 @@ struct proto udplitev6_prot = {
.name = "UDPLITEv6",
.owner = THIS_MODULE,
.close = udp_lib_close,
- .connect = ip6_datagram_connect,
+ .connect = udp_v6_connect,
.disconnect = udp_disconnect,
.ioctl = udp_ioctl,
.init = udplite_sk_init,
--
2.16.2
Powered by blists - more mailing lists