aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGleb Smirnoff <glebius@FreeBSD.org>2026-07-07 16:27:57 +0000
committerGleb Smirnoff <glebius@FreeBSD.org>2026-07-07 16:27:57 +0000
commit3fdb1b6f10b33f9ac62a80d75898a89c153445fc (patch)
tree25efcc10cee52c2580c914fea75f21337d28ecb4
parent0083a4d6224f1290af31528b55ba27c51e27ba46 (diff)
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
-rw-r--r--sys/netinet6/in6_pcb.c34
1 files 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);
}