git: 3fdb1b6f10b3 - main - netinet6: further refactor in6_pcbconnect()

From: Gleb Smirnoff <glebius_at_FreeBSD.org>
Date: Tue, 07 Jul 2026 16:28:26 UTC
The branch main has been updated by glebius:

URL: https://cgit.FreeBSD.org/src/commit/?id=3fdb1b6f10b33f9ac62a80d75898a89c153445fc

commit 3fdb1b6f10b33f9ac62a80d75898a89c153445fc
Author:     Gleb Smirnoff <glebius@FreeBSD.org>
AuthorDate: 2026-07-07 16:27:57 +0000
Commit:     Gleb Smirnoff <glebius@FreeBSD.org>
CommitDate: 2026-07-07 16:27:57 +0000

    netinet6: further refactor in6_pcbconnect()
    
    A mistake from 90ea8e89d9b7 is that in6_pcblookup_internal() was skipped
    for an inpcb that had unspecified local address.  This is incorrect, as
    such inpcb could have already have a port set, and in_pcb_lport_dest()
    shall not be called on such inpcb.  That could lead to creation of an
    alised connection in the database.
    
    This makes the function almost identical to in_pcbconnect().  While here,
    fix minor bug of missing INP_ANONPORT.  This flag has no use in kernel,
    but affects netstat(1) output in certain mode.
    
    Fixes:  90ea8e89d9b751e8b5ae90ef3397883b035788e5
    Reviewed by:            pouria
    Differential Revision:  https://reviews.freebsd.org/D57987
---
 sys/netinet6/in6_pcb.c | 34 +++++++++++++++++++---------------
 1 file changed, 19 insertions(+), 15 deletions(-)

diff --git a/sys/netinet6/in6_pcb.c b/sys/netinet6/in6_pcb.c
index 971f05838ce2..1b55a3425e59 100644
--- a/sys/netinet6/in6_pcb.c
+++ b/sys/netinet6/in6_pcb.c
@@ -450,8 +450,9 @@ in6_pcbconnect(struct inpcb *inp, struct sockaddr_in6 *sin6, struct ucred *cred,
     bool sas_required)
 {
 	struct inpcbinfo *pcbinfo = inp->inp_pcbinfo;
-	struct sockaddr_in6 laddr6;
+	struct sockaddr_in6 laddr6 = { .sin6_family = AF_INET6 };
 	int error;
+	bool anonport;
 
 	NET_EPOCH_ASSERT();
 	INP_WLOCK_ASSERT(inp);
@@ -462,8 +463,7 @@ in6_pcbconnect(struct inpcb *inp, struct sockaddr_in6 *sin6, struct ucred *cred,
 	KASSERT(IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_faddr),
 	    ("%s: inp is already connected", __func__));
 
-	bzero(&laddr6, sizeof(laddr6));
-	laddr6.sin6_family = AF_INET6;
+	anonport = (inp->inp_lport == 0);
 
 	INP_HASH_WLOCK(pcbinfo);
 	if (IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_laddr)) {
@@ -477,25 +477,27 @@ in6_pcbconnect(struct inpcb *inp, struct sockaddr_in6 *sin6, struct ucred *cred,
 			INP_HASH_WUNLOCK(pcbinfo);
 			return (error);
 		}
-		if (inp->inp_lport == 0) {
-			error = in_pcb_lport_dest(inp,
-			    (struct sockaddr *) &laddr6, &inp->inp_lport,
-			    (struct sockaddr *) sin6, sin6->sin6_port, cred,
-			    INPLOOKUP_WILDCARD);
-			if (__predict_false(error)) {
-				INP_HASH_WUNLOCK(pcbinfo);
-				return (error);
-			}
+	} else
+		laddr6.sin6_addr = inp->in6p_laddr;
+
+	if (anonport) {
+		error = in_pcb_lport_dest(inp, (struct sockaddr *) &laddr6,
+		    &inp->inp_lport, (struct sockaddr *) sin6, sin6->sin6_port,
+		    cred, INPLOOKUP_WILDCARD);
+		if (__predict_false(error)) {
+			INP_HASH_WUNLOCK(pcbinfo);
+			return (error);
 		}
-		inp->in6p_laddr = laddr6.sin6_addr;
 	} else if (in6_pcblookup_internal(pcbinfo, &sin6->sin6_addr,
-	    sin6->sin6_port, &inp->in6p_laddr, inp->inp_lport, 0,
+	    sin6->sin6_port, &laddr6.sin6_addr, inp->inp_lport, 0,
 	    M_NODOM, RT_ALL_FIBS) != NULL) {
 		INP_HASH_WUNLOCK(pcbinfo);
 		return (EADDRINUSE);
 	}
+
 	MPASS(inp->inp_lport != 0);
-	MPASS(!IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_laddr));
+	MPASS(!IN6_IS_ADDR_UNSPECIFIED(&laddr6.sin6_addr));
+	inp->in6p_laddr = laddr6.sin6_addr;
 	inp->in6p_faddr = sin6->sin6_addr;
 	inp->inp_fport = sin6->sin6_port;
 	/* update flowinfo - draft-itojun-ipv6-flowlabel-api-00 */
@@ -520,6 +522,8 @@ in6_pcbconnect(struct inpcb *inp, struct sockaddr_in6 *sin6, struct ucred *cred,
 		inp->inp_flowid = hash_val;
 		inp->inp_flowtype = hash_type;
 	}
+	if (anonport)
+		inp->inp_flags |= INP_ANONPORT;
 
 	return (0);
 }