aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorErmal Luçi <eri@FreeBSD.org>2017-02-10 05:51:39 +0000
committerErmal Luçi <eri@FreeBSD.org>2017-02-10 05:51:39 +0000
commitc0fadfdbbfb3525ac66902b7c9c661d3ab356664 (patch)
tree13a13fc094e68048836fc1713949c5d97753e749
parented55edceef6ae6afec1878287d3c5d9f20cbf1fa (diff)
downloadsrc-c0fadfdbbfb3525ac66902b7c9c661d3ab356664.tar.gz
src-c0fadfdbbfb3525ac66902b7c9c661d3ab356664.zip
Notes
-rw-r--r--sys/netinet/in_pcb.c33
-rw-r--r--sys/netinet/in_pcb.h4
-rw-r--r--sys/netinet/tcp_usrreq.c14
-rw-r--r--sys/netinet/udp_usrreq.c2
-rw-r--r--sys/netinet6/in6_pcb.c11
-rw-r--r--sys/netinet6/in6_pcb.h3
-rw-r--r--sys/netinet6/in6_src.c5
-rw-r--r--sys/netinet6/udp6_usrreq.c15
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)) {