DatagramChannel::disconnect appears to rebind socket to the wildcard address
Kurt Miller
kurt at intricatesoftware.com
Wed Sep 25 20:03:11 UTC 2019
On Wed, 2019-09-25 at 20:37 +0100, Alan Bateman wrote:
> On 25/09/2019 19:50, Kurt Miller wrote:
> >
> > :
> > Yes, I have observed that bug on OpenBSD as well. It is indeed
> > a kernel bug on OpenBSD. I have kernel patches to correct it
> > but haven't pushed them forward through the review process there.
> >
> > I just did a quick test on FreeBSD 11 on amd64 and it also
> > doesn't retain the bound address.
> >
> Thanks for confirming the issue on OpenBSD and also checking FreeBSD
> too. I'm curious if the issue in the OpenBSD kernel is something simple
> or whether this is a significant change. My guess is that this is an
> issue that could have lurked for years as not many applications or
> usages would observe the local address changing like this.
>
Your welcome. It is something simple. Roughly speaking:
- set flag when bind on dgram socket sets IP addr
- when disconnecting (connect(2) called w/AF_UNSPEC) if flag
is set, don't reset it to INADDR_ANY
Here's a copy of the diff if you're curious. I guess I should
move this diff along through the review process.
Index: netinet/udp_usrreq.c
===================================================================
RCS file: /cvs/src/sys/netinet/udp_usrreq.c,v
retrieving revision 1.255
diff -u -p -u -r1.255 udp_usrreq.c
--- netinet/udp_usrreq.c 4 Feb 2019 21:40:52 -0000 1.255
+++ netinet/udp_usrreq.c 25 Sep 2019 19:59:17 -0000
@@ -1021,6 +1021,7 @@ udp_usrreq(struct socket *so, int req, s
{
struct inpcb *inp;
int error = 0;
+ udp_flags flags = 0;
if (req == PRU_CONTROL) {
#ifdef INET6
@@ -1048,7 +1049,30 @@ udp_usrreq(struct socket *so, int req, s
switch (req) {
case PRU_BIND:
+#ifdef INET6
+ if (inp->inp_flags & INP_IPV6) {
+ struct sockaddr_in6 *sin6;
+
+ if ((error = in6_nam2sin6(addr, &sin6)))
+ break;
+ if (!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr))
+ flags |= UF_ADDR_BOUND;
+ }
+ else
+#endif /* INET6 */
+ {
+ struct sockaddr_in *sin;
+
+ if ((error = in_nam2sin(addr, &sin)))
+ break;
+ if (sin->sin_addr.s_addr != INADDR_ANY)
+ flags |= UF_ADDR_BOUND;
+ }
+
error = in_pcbbind(inp, addr, p);
+ if (error == 0)
+ *intoudpflgp(inp) |= flags;
+
break;
case PRU_LISTEN:
@@ -1086,12 +1110,15 @@ udp_usrreq(struct socket *so, int req, s
break;
case PRU_DISCONNECT:
+ flags = *intoudpflgp(inp);
#ifdef INET6
if (inp->inp_flags & INP_IPV6) {
if (IN6_IS_ADDR_UNSPECIFIED(&inp->inp_faddr6)) {
error = ENOTCONN;
break;
}
+ if ((flags & UF_ADDR_BOUND) == 0)
+ inp->inp_laddr6 = in6addr_any;
} else
#endif /* INET6 */
{
@@ -1099,14 +1126,10 @@ udp_usrreq(struct socket *so, int req, s
error = ENOTCONN;
break;
}
+ if ((flags & UF_ADDR_BOUND) == 0)
+ inp->inp_laddr.s_addr = INADDR_ANY;
}
-#ifdef INET6
- if (inp->inp_flags & INP_IPV6)
- inp->inp_laddr6 = in6addr_any;
- else
-#endif /* INET6 */
- inp->inp_laddr.s_addr = INADDR_ANY;
in_pcbdisconnect(inp);
so->so_state &= ~SS_ISCONNECTED; /* XXX */
Index: netinet/udp_var.h
===================================================================
RCS file: /cvs/src/sys/netinet/udp_var.h,v
retrieving revision 1.34
diff -u -p -u -r1.34 udp_var.h
--- netinet/udp_var.h 2 Nov 2017 14:01:18 -0000 1.34
+++ netinet/udp_var.h 25 Sep 2019 19:59:17 -0000
@@ -101,6 +101,14 @@ struct udpstat {
NULL \
}
+/*
+ * Udp control block is just flags:
+ */
+typedef u_int udp_flags;
+#define UF_ADDR_BOUND 0x0001 /* IP Addr Bound */
+
+#define intoudpflgp(ip) ((udp_flags *)&(ip)->inp_ppcb)
+
#ifdef _KERNEL
#include <sys/percpu.h>
More information about the bsd-port-dev
mailing list