in_pcblookup() is always called with *:0 for the remote side. Remove the useless bits, shuffle the tests around and it's much easier to audit.
Ok ? Index: netinet/in_pcb.c =================================================================== RCS file: /cvs/src/sys/netinet/in_pcb.c,v retrieving revision 1.201 diff -u -p -r1.201 in_pcb.c --- netinet/in_pcb.c 8 Apr 2016 14:34:21 -0000 1.201 +++ netinet/in_pcb.c 9 Apr 2016 09:42:07 -0000 @@ -415,14 +415,13 @@ in_pcbaddrisavail(struct inpcb *inp, str struct inpcb *t; if (so->so_euid) { - t = in_pcblookup(table, &zeroin_addr, 0, - &sin->sin_addr, lport, INPLOOKUP_WILDCARD, - inp->inp_rtableid); + t = in_pcblookup_local(table, &sin->sin_addr, lport, + INPLOOKUP_WILDCARD, inp->inp_rtableid); if (t && (so->so_euid != t->inp_socket->so_euid)) return (EADDRINUSE); } - t = in_pcblookup(table, &zeroin_addr, 0, - &sin->sin_addr, lport, wild, inp->inp_rtableid); + t = in_pcblookup_local(table, &sin->sin_addr, lport, + wild, inp->inp_rtableid); if (t && (reuseport & t->inp_socket->so_options) == 0) return (EADDRINUSE); } @@ -475,8 +474,8 @@ in_pcbpickport(u_int16_t *lport, void *l candidate = lower; localport = htons(candidate); } while (in_baddynamic(localport, so->so_proto->pr_protocol) || - in_pcblookup(table, &zeroin46_addr, 0, - laddr, localport, wild, inp->inp_rtableid)); + in_pcblookup_local(table, laddr, localport, wild, + inp->inp_rtableid)); *lport = localport; return (0); @@ -734,14 +733,14 @@ in_rtchange(struct inpcb *inp, int errno } struct inpcb * -in_pcblookup(struct inpcbtable *table, void *faddrp, u_int fport_arg, - void *laddrp, u_int lport_arg, int flags, u_int rdomain) +in_pcblookup_local(struct inpcbtable *table, void *laddrp, u_int lport_arg, + int flags, u_int rdomain) { struct inpcb *inp, *match = NULL; int matchwild = 3, wildcard; - u_int16_t fport = fport_arg, lport = lport_arg; - struct in_addr faddr = *(struct in_addr *)faddrp; + u_int16_t lport = lport_arg; struct in_addr laddr = *(struct in_addr *)laddrp; + struct in6_addr *laddr6 = (struct in6_addr *)laddrp; struct inpcbhead *head; rdomain = rtable_l2(rdomain); /* convert passed rtableid to rdomain */ @@ -753,60 +752,40 @@ in_pcblookup(struct inpcbtable *table, v continue; wildcard = 0; #ifdef INET6 - if (flags & INPLOOKUP_IPV6) { - struct in6_addr *laddr6 = (struct in6_addr *)laddrp; - struct in6_addr *faddr6 = (struct in6_addr *)faddrp; - - if (!(inp->inp_flags & INP_IPV6)) + if (ISSET(flags, INPLOOKUP_IPV6)) { + if (!ISSET(inp->inp_flags, INP_IPV6)) continue; - if (!IN6_IS_ADDR_UNSPECIFIED(&inp->inp_laddr6)) { - if (IN6_IS_ADDR_UNSPECIFIED(laddr6)) - wildcard++; - else if (!IN6_ARE_ADDR_EQUAL(&inp->inp_laddr6, laddr6)) - continue; - } else { - if (!IN6_IS_ADDR_UNSPECIFIED(laddr6)) - wildcard++; - } + if (!IN6_IS_ADDR_UNSPECIFIED(&inp->inp_faddr6)) + wildcard++; - if (!IN6_IS_ADDR_UNSPECIFIED(&inp->inp_faddr6)) { - if (IN6_IS_ADDR_UNSPECIFIED(faddr6)) + if (!IN6_ARE_ADDR_EQUAL(&inp->inp_laddr6, laddr6)) { + if (IN6_IS_ADDR_UNSPECIFIED(&inp->inp_laddr6) || + IN6_IS_ADDR_UNSPECIFIED(laddr6)) wildcard++; - else if (!IN6_ARE_ADDR_EQUAL(&inp->inp_faddr6, - faddr6) || inp->inp_fport != fport) + else continue; - } else { - if (!IN6_IS_ADDR_UNSPECIFIED(faddr6)) - wildcard++; } + } else #endif /* INET6 */ { #ifdef INET6 - if (inp->inp_flags & INP_IPV6) + if (ISSET(inp->inp_flags, INP_IPV6)) continue; #endif /* INET6 */ - if (inp->inp_faddr.s_addr != INADDR_ANY) { - if (faddr.s_addr == INADDR_ANY) - wildcard++; - else if (inp->inp_faddr.s_addr != faddr.s_addr || - inp->inp_fport != fport) - continue; - } else { - if (faddr.s_addr != INADDR_ANY) - wildcard++; - } - if (inp->inp_laddr.s_addr != INADDR_ANY) { - if (laddr.s_addr == INADDR_ANY) + if (inp->inp_faddr.s_addr != INADDR_ANY) + wildcard++; + + if (inp->inp_laddr.s_addr != laddr.s_addr) { + if (inp->inp_laddr.s_addr == INADDR_ANY || + laddr.s_addr == INADDR_ANY) wildcard++; - else if (inp->inp_laddr.s_addr != laddr.s_addr) + else continue; - } else { - if (laddr.s_addr != INADDR_ANY) - wildcard++; } + } if ((!wildcard || (flags & INPLOOKUP_WILDCARD)) && wildcard < matchwild) { Index: netinet/in_pcb.h =================================================================== RCS file: /cvs/src/sys/netinet/in_pcb.h,v retrieving revision 1.97 diff -u -p -r1.97 in_pcb.h --- netinet/in_pcb.h 5 Apr 2016 19:34:05 -0000 1.97 +++ netinet/in_pcb.h 9 Apr 2016 09:42:07 -0000 @@ -271,8 +271,7 @@ int in6_setpeeraddr(struct inpcb *, str #endif /* INET6 */ void in_pcbinit(struct inpcbtable *, int); struct inpcb * - in_pcblookup(struct inpcbtable *, void *, u_int, void *, - u_int, int, u_int); + in_pcblookup_local(struct inpcbtable *, void *, u_int, int, u_int); void in_pcbnotifyall(struct inpcbtable *, struct sockaddr *, u_int, int, void (*)(struct inpcb *, int)); void in_pcbrehash(struct inpcb *); Index: netinet6/in6_pcb.c =================================================================== RCS file: /cvs/src/sys/netinet6/in6_pcb.c,v retrieving revision 1.91 diff -u -p -r1.91 in6_pcb.c --- netinet6/in6_pcb.c 5 Apr 2016 21:21:41 -0000 1.91 +++ netinet6/in6_pcb.c 9 Apr 2016 09:42:08 -0000 @@ -217,16 +217,14 @@ in6_pcbaddrisavail(struct inpcb *inp, st struct inpcb *t; if (so->so_euid) { - t = in_pcblookup(table, - (struct in_addr *)&zeroin6_addr, 0, + t = in_pcblookup_local(table, (struct in_addr *)&sin6->sin6_addr, lport, INPLOOKUP_WILDCARD | INPLOOKUP_IPV6, inp->inp_rtableid); if (t && (so->so_euid != t->inp_socket->so_euid)) return (EADDRINUSE); } - t = in_pcblookup(table, - (struct in_addr *)&zeroin6_addr, 0, + t = in_pcblookup_local(table, (struct in_addr *)&sin6->sin6_addr, lport, wild, inp->inp_rtableid); if (t && (reuseport & t->inp_socket->so_options) == 0)