diff options
author | Ermal Luçi <eri@FreeBSD.org> | 2017-02-10 05:51:39 +0000 |
---|---|---|
committer | Ermal Luçi <eri@FreeBSD.org> | 2017-02-10 05:51:39 +0000 |
commit | c0fadfdbbfb3525ac66902b7c9c661d3ab356664 (patch) | |
tree | 13a13fc094e68048836fc1713949c5d97753e749 | |
parent | ed55edceef6ae6afec1878287d3c5d9f20cbf1fa (diff) | |
download | src-c0fadfdbbfb3525ac66902b7c9c661d3ab356664.tar.gz src-c0fadfdbbfb3525ac66902b7c9c661d3ab356664.zip |
Notes
-rw-r--r-- | sys/netinet/in_pcb.c | 33 | ||||
-rw-r--r-- | sys/netinet/in_pcb.h | 4 | ||||
-rw-r--r-- | sys/netinet/tcp_usrreq.c | 14 | ||||
-rw-r--r-- | sys/netinet/udp_usrreq.c | 2 | ||||
-rw-r--r-- | sys/netinet6/in6_pcb.c | 11 | ||||
-rw-r--r-- | sys/netinet6/in6_pcb.h | 3 | ||||
-rw-r--r-- | sys/netinet6/in6_src.c | 5 | ||||
-rw-r--r-- | sys/netinet6/udp6_usrreq.c | 15 |
8 files changed, 59 insertions, 28 deletions
diff --git a/sys/netinet/in_pcb.c b/sys/netinet/in_pcb.c index 9d66ca38f3c8..7e119c64356d 100644 --- a/sys/netinet/in_pcb.c +++ b/sys/netinet/in_pcb.c @@ -371,8 +371,8 @@ in_pcbbind(struct inpcb *inp, struct sockaddr *nam, struct ucred *cred) */ #if defined(INET) || defined(INET6) int -in_pcb_lport(struct inpcb *inp, struct in_addr *laddrp, u_short *lportp, - struct ucred *cred, int lookupflags) +in_pcb_lport(struct inpcb *inp, struct sockaddr *nam, struct in_addr *laddrp, + u_short *lportp, struct ucred *cred, int lookupflags) { struct inpcbinfo *pcbinfo; struct inpcb *tmpinp; @@ -381,6 +381,7 @@ in_pcb_lport(struct inpcb *inp, struct in_addr *laddrp, u_short *lportp, u_short aux, first, last, lport; #ifdef INET struct in_addr laddr; + struct sockaddr_in *sin = NULL; #endif pcbinfo = inp->inp_pcbinfo; @@ -447,6 +448,7 @@ in_pcb_lport(struct inpcb *inp, struct in_addr *laddrp, u_short *lportp, KASSERT(laddrp != NULL, ("%s: laddrp NULL for v4 inp %p", __func__, inp)); laddr = *laddrp; + sin = (struct sockaddr_in *)nam; } #endif tmpinp = NULL; /* Make compiler happy. */ @@ -466,16 +468,29 @@ in_pcb_lport(struct inpcb *inp, struct in_addr *laddrp, u_short *lportp, lport = htons(*lastport); #ifdef INET6 - if ((inp->inp_vflag & INP_IPV6) != 0) - tmpinp = in6_pcblookup_local(pcbinfo, - &inp->in6p_laddr, lport, lookupflags, cred); + if ((inp->inp_vflag & INP_IPV6) != 0) { + struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)nam; + if (sin6 != NULL && (inp->inp_flags & INP_ANONPORT)) { + tmpinp = in6_pcblookup_hash_locked(pcbinfo, + &sin6->sin6_addr, sin6->sin6_port, + &inp->in6p_laddr, lport, + lookupflags & (~INPLOOKUP_WILDCARD), + NULL); + } else + tmpinp = in6_pcblookup_local(pcbinfo, + &inp->in6p_laddr, lport, lookupflags, cred); + } #endif #if defined(INET) && defined(INET6) else #endif #ifdef INET - tmpinp = in_pcblookup_local(pcbinfo, laddr, - lport, lookupflags, cred); + if (sin != NULL && (inp->inp_flags & INP_ANONPORT)) + tmpinp = in_pcblookup_hash_locked(pcbinfo, sin->sin_addr, sin->sin_port, laddr, + lport, lookupflags & (~INPLOOKUP_WILDCARD), NULL); + else + tmpinp = in_pcblookup_local(pcbinfo, laddr, + lport, lookupflags, cred); #endif } while (tmpinp != NULL); @@ -571,7 +586,7 @@ in_pcbbind_setup(struct inpcb *inp, struct sockaddr *nam, in_addr_t *laddrp, return (EINVAL); if ((so->so_options & (SO_REUSEADDR|SO_REUSEPORT)) == 0) lookupflags = INPLOOKUP_WILDCARD; - if (nam == NULL) { + if (nam == NULL || ((*lportp) == 0 && (inp->inp_flags & INP_ANONPORT))) { if ((error = prison_local_ip4(cred, &laddr)) != 0) return (error); } else { @@ -692,7 +707,7 @@ in_pcbbind_setup(struct inpcb *inp, struct sockaddr *nam, in_addr_t *laddrp, if (*lportp != 0) lport = *lportp; if (lport == 0) { - error = in_pcb_lport(inp, &laddr, &lport, cred, lookupflags); + error = in_pcb_lport(inp, nam, &laddr, &lport, cred, lookupflags); if (error != 0) return (error); diff --git a/sys/netinet/in_pcb.h b/sys/netinet/in_pcb.h index e57138483c15..ac16d2660e27 100644 --- a/sys/netinet/in_pcb.h +++ b/sys/netinet/in_pcb.h @@ -697,8 +697,8 @@ void in_pcbgroup_update_mbuf(struct inpcb *, struct mbuf *); void in_pcbpurgeif0(struct inpcbinfo *, struct ifnet *); int in_pcballoc(struct socket *, struct inpcbinfo *); int in_pcbbind(struct inpcb *, struct sockaddr *, struct ucred *); -int in_pcb_lport(struct inpcb *, struct in_addr *, u_short *, - struct ucred *, int); +int in_pcb_lport(struct inpcb *, struct sockaddr *, struct in_addr *, + u_short *, struct ucred *, int); int in_pcbbind_setup(struct inpcb *, struct sockaddr *, in_addr_t *, u_short *, struct ucred *); int in_pcbconnect(struct inpcb *, struct sockaddr *, struct ucred *); diff --git a/sys/netinet/tcp_usrreq.c b/sys/netinet/tcp_usrreq.c index 7d225eec6b47..94193d9c23fc 100644 --- a/sys/netinet/tcp_usrreq.c +++ b/sys/netinet/tcp_usrreq.c @@ -1238,9 +1238,12 @@ tcp_connect(struct tcpcb *tp, struct sockaddr *nam, struct thread *td) INP_HASH_WLOCK(&V_tcbinfo); if (inp->inp_lport == 0) { - error = in_pcbbind(inp, (struct sockaddr *)0, td->td_ucred); - if (error) + inp->inp_flags |= INP_ANONPORT; + error = in_pcbbind(inp, nam, td->td_ucred); + if (error) { + inp->inp_flags &= ~INP_ANONPORT; goto out; + } } /* @@ -1296,9 +1299,12 @@ tcp6_connect(struct tcpcb *tp, struct sockaddr *nam, struct thread *td) INP_HASH_WLOCK(&V_tcbinfo); if (inp->inp_lport == 0) { - error = in6_pcbbind(inp, (struct sockaddr *)0, td->td_ucred); - if (error) + inp->inp_flags |= INP_ANONPORT; + error = in6_pcbbind(inp, nam, td->td_ucred); + if (error) { + inp->inp_flags &= ~INP_ANONPORT; goto out; + } } error = in6_pcbconnect(inp, nam, td->td_ucred); if (error != 0) diff --git a/sys/netinet/udp_usrreq.c b/sys/netinet/udp_usrreq.c index 56da929ef827..c45b6361f8e3 100644 --- a/sys/netinet/udp_usrreq.c +++ b/sys/netinet/udp_usrreq.c @@ -636,7 +636,7 @@ udp_input(struct mbuf **mp, int *offp, int proto) goto badunlocked; } UDP_PROBE(receive, NULL, last, ip, last, uh); - if (udp_append(last, ip, m, iphlen, udp_in) == 0) + if (udp_append(last, ip, m, iphlen, udpin) == 0) INP_RUNLOCK(last); inp_lost: INP_INFO_RUNLOCK(pcbinfo); diff --git a/sys/netinet6/in6_pcb.c b/sys/netinet6/in6_pcb.c index bab5259f7ffe..78dfec6b52ca 100644 --- a/sys/netinet6/in6_pcb.c +++ b/sys/netinet6/in6_pcb.c @@ -132,7 +132,7 @@ in6_pcbbind(register struct inpcb *inp, struct sockaddr *nam, return (EINVAL); if ((so->so_options & (SO_REUSEADDR|SO_REUSEPORT)) == 0) lookupflags = INPLOOKUP_WILDCARD; - if (nam == NULL) { + if (nam == NULL || (inp->inp_flags & INP_ANONPORT)) { if ((error = prison_local_ip6(cred, &inp->in6p_laddr, ((inp->inp_flags & IN6P_IPV6_V6ONLY) != 0))) != 0) return (error); @@ -296,7 +296,7 @@ in6_pcbbind(register struct inpcb *inp, struct sockaddr *nam, inp->in6p_laddr = sin6->sin6_addr; } if (lport == 0) { - if ((error = in6_pcbsetport(&inp->in6p_laddr, inp, cred)) != 0) { + if ((error = in6_pcbsetport(nam, &inp->in6p_laddr, inp, cred)) != 0) { /* Undo an address bind that may have occurred. */ inp->in6p_laddr = in6addr_any; return (error); @@ -416,9 +416,12 @@ in6_pcbconnect_mbuf(register struct inpcb *inp, struct sockaddr *nam, } if (IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_laddr)) { if (inp->inp_lport == 0) { - error = in6_pcbbind(inp, (struct sockaddr *)0, cred); - if (error) + inp->inp_flags |= INP_ANONPORT; + error = in6_pcbbind(inp, nam, cred); + if (error) { + inp->inp_flags &= ~INP_ANONPORT; return (error); + } } inp->in6p_laddr = addr6; } diff --git a/sys/netinet6/in6_pcb.h b/sys/netinet6/in6_pcb.h index 1ff09ea93ba6..d21bf78882da 100644 --- a/sys/netinet6/in6_pcb.h +++ b/sys/netinet6/in6_pcb.h @@ -112,7 +112,8 @@ int in6_getsockaddr(struct socket *so, struct sockaddr **nam); int in6_mapped_sockaddr(struct socket *so, struct sockaddr **nam); int in6_mapped_peeraddr(struct socket *so, struct sockaddr **nam); int in6_selecthlim(struct in6pcb *, struct ifnet *); -int in6_pcbsetport(struct in6_addr *, struct inpcb *, struct ucred *); +int in6_pcbsetport(struct sockaddr *, struct in6_addr *, struct inpcb *, + struct ucred *); void init_sin6(struct sockaddr_in6 *sin6, struct mbuf *m, int); #endif /* _KERNEL */ diff --git a/sys/netinet6/in6_src.c b/sys/netinet6/in6_src.c index 54c0a0a90a26..cb6e57318cc9 100644 --- a/sys/netinet6/in6_src.c +++ b/sys/netinet6/in6_src.c @@ -956,7 +956,8 @@ in6_selecthlim(struct inpcb *in6p, struct ifnet *ifp) * share this function by all *bsd*... */ int -in6_pcbsetport(struct in6_addr *laddr, struct inpcb *inp, struct ucred *cred) +in6_pcbsetport(struct sockaddr *nam6, struct in6_addr *laddr, struct inpcb *inp, + struct ucred *cred) { struct socket *so = inp->inp_socket; u_int16_t lport = 0; @@ -979,7 +980,7 @@ in6_pcbsetport(struct in6_addr *laddr, struct inpcb *inp, struct ucred *cred) inp->inp_flags |= INP_ANONPORT; - error = in_pcb_lport(inp, NULL, &lport, cred, lookupflags); + error = in_pcb_lport(inp, nam6, NULL, &lport, cred, lookupflags); if (error != 0) return (error); diff --git a/sys/netinet6/udp6_usrreq.c b/sys/netinet6/udp6_usrreq.c index bcf491f10808..2b0dab9f67fe 100644 --- a/sys/netinet6/udp6_usrreq.c +++ b/sys/netinet6/udp6_usrreq.c @@ -778,11 +778,16 @@ udp6_output(struct inpcb *inp, struct mbuf *m, struct sockaddr *addr6, error = EADDRNOTAVAIL; goto release; } - if (inp->inp_lport == 0 && - (error = in6_pcbsetport(laddr, inp, td->td_ucred)) != 0) { - /* Undo an address bind that may have occurred. */ - inp->in6p_laddr = in6addr_any; - goto release; + if (inp->inp_lport == 0) { + inp->inp_flags |= INP_ANONPORT; + error = in6_pcbsetport((struct sockaddr *)addr6, laddr, + inp, td->td_ucred); + if (error) { + inp->inp_flags &= ~INP_ANONPORT; + /* Undo an address bind that may have occurred. */ + inp->in6p_laddr = in6addr_any; + goto release; + } } } else { if (IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_faddr)) { |