aboutsummaryrefslogtreecommitdiff
path: root/sys/netinet/in_pcb.c
diff options
context:
space:
mode:
authorMike Karels <karels@FreeBSD.org>2022-07-29 14:23:23 +0000
committerMike Karels <karels@FreeBSD.org>2022-08-02 14:49:46 +0000
commit637f317c6d9c0c689677f499fc78ac545b192071 (patch)
tree9ec868be61f307c4c04086675a60081fa9d73508 /sys/netinet/in_pcb.c
parent190c4c2499e64e1c88f25f68c2929d110d635300 (diff)
downloadsrc-637f317c6d9c0c689677f499fc78ac545b192071.tar.gz
src-637f317c6d9c0c689677f499fc78ac545b192071.zip
IPv6: fix problem with duplicate port assignment with v4-mapped addrs
In in_pcb_lport_dest(), if an IPv6 socket does not match any other IPv6 socket using in6_pcblookup_local(), and if the socket can also connect to IPv4 (the INP_IPV4 vflag is set), check for IPv4 matches as well. Otherwise, we can allocate a port that is used by an IPv4 socket (possibly one created from IPv6 via the same procedure), and then connect() can fail with EADDRINUSE, when it could have succeeded if the bound port was not in use. PR: 265064 Submitted by: firk at cantconnect.ru (with modifications) Reviewed by: bz, melifaro Differential Revision: https://reviews.freebsd.org/D36012
Diffstat (limited to 'sys/netinet/in_pcb.c')
-rw-r--r--sys/netinet/in_pcb.c11
1 files changed, 9 insertions, 2 deletions
diff --git a/sys/netinet/in_pcb.c b/sys/netinet/in_pcb.c
index 63b5f39f7577..321af17a4767 100644
--- a/sys/netinet/in_pcb.c
+++ b/sys/netinet/in_pcb.c
@@ -784,7 +784,7 @@ in_pcb_lport_dest(struct inpcb *inp, struct sockaddr *lsa, u_short *lportp,
}
#ifdef INET
- laddr.s_addr = INADDR_ANY;
+ laddr.s_addr = INADDR_ANY; /* used by INET6+INET below too */
if ((inp->inp_vflag & (INP_IPV4|INP_IPV6)) == INP_IPV4) {
if (lsa != NULL)
laddr = ((struct sockaddr_in *)lsa)->sin_addr;
@@ -835,9 +835,16 @@ in_pcb_lport_dest(struct inpcb *inp, struct sockaddr *lsa, u_short *lportp,
#endif
} else {
#ifdef INET6
- if ((inp->inp_vflag & INP_IPV6) != 0)
+ if ((inp->inp_vflag & INP_IPV6) != 0) {
tmpinp = in6_pcblookup_local(pcbinfo,
&inp->in6p_laddr, lport, lookupflags, cred);
+#ifdef INET
+ if (tmpinp == NULL &&
+ (inp->inp_vflag & INP_IPV4))
+ tmpinp = in_pcblookup_local(pcbinfo,
+ laddr, lport, lookupflags, cred);
+#endif
+ }
#endif
#if defined(INET) && defined(INET6)
else