The branch main has been updated by glebius: URL: https://cgit.FreeBSD.org/src/commit/?id=3fdb1b6f10b33f9ac62a80d75898a89c153445fc
commit 3fdb1b6f10b33f9ac62a80d75898a89c153445fc Author: Gleb Smirnoff <[email protected]> AuthorDate: 2026-07-07 16:27:57 +0000 Commit: Gleb Smirnoff <[email protected]> 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); }
