Changeset View
Changeset View
Standalone View
Standalone View
sys/netinet/in_pcb.c
Show First 20 Lines • Show All 910 Lines • ▼ Show 20 Lines | if (sin == NULL) { | ||||
if (error) | if (error) | ||||
return (error); | return (error); | ||||
if (sin->sin_port != *lportp) { | if (sin->sin_port != *lportp) { | ||||
/* Don't allow the port to change. */ | /* Don't allow the port to change. */ | ||||
if (*lportp != 0) | if (*lportp != 0) | ||||
return (EINVAL); | return (EINVAL); | ||||
lport = sin->sin_port; | lport = sin->sin_port; | ||||
} | } | ||||
laddr = sin->sin_addr; | |||||
/* NB: lport is left as 0 if the port isn't being changed. */ | /* NB: lport is left as 0 if the port isn't being changed. */ | ||||
if (IN_MULTICAST(ntohl(sin->sin_addr.s_addr))) { | if (IN_MULTICAST(ntohl(laddr.s_addr))) { | ||||
/* | /* | ||||
* Treat SO_REUSEADDR as SO_REUSEPORT for multicast; | * Treat SO_REUSEADDR as SO_REUSEPORT for multicast; | ||||
* allow complete duplication of binding if | * allow complete duplication of binding if | ||||
* SO_REUSEPORT is set, or if SO_REUSEADDR is set | * SO_REUSEPORT is set, or if SO_REUSEADDR is set | ||||
* and a multicast address is bound on both | * and a multicast address is bound on both | ||||
* new and duplicated sockets. | * new and duplicated sockets. | ||||
*/ | */ | ||||
if ((so->so_options & (SO_REUSEADDR|SO_REUSEPORT)) != 0) | if ((so->so_options & (SO_REUSEADDR|SO_REUSEPORT)) != 0) | ||||
reuseport = SO_REUSEADDR|SO_REUSEPORT; | reuseport = SO_REUSEADDR|SO_REUSEPORT; | ||||
/* | /* | ||||
* XXX: How to deal with SO_REUSEPORT_LB here? | * XXX: How to deal with SO_REUSEPORT_LB here? | ||||
* Treat same as SO_REUSEPORT for now. | * Treat same as SO_REUSEPORT for now. | ||||
*/ | */ | ||||
if ((so->so_options & | if ((so->so_options & | ||||
(SO_REUSEADDR|SO_REUSEPORT_LB)) != 0) | (SO_REUSEADDR|SO_REUSEPORT_LB)) != 0) | ||||
reuseport_lb = SO_REUSEADDR|SO_REUSEPORT_LB; | reuseport_lb = SO_REUSEADDR|SO_REUSEPORT_LB; | ||||
} else if (sin->sin_addr.s_addr != INADDR_ANY) { | } else if (!in_nullhost(laddr)) { | ||||
sin->sin_port = 0; /* yech... */ | sin->sin_port = 0; /* yech... */ | ||||
bzero(&sin->sin_zero, sizeof(sin->sin_zero)); | bzero(&sin->sin_zero, sizeof(sin->sin_zero)); | ||||
/* | /* | ||||
* Is the address a local IP address? | * Is the address a local IP address? | ||||
* If INP_BINDANY is set, then the socket may be bound | * If INP_BINDANY is set, then the socket may be bound | ||||
* to any endpoint address, local or not. | * to any endpoint address, local or not. | ||||
*/ | */ | ||||
if ((inp->inp_flags & INP_BINDANY) == 0 && | if ((inp->inp_flags & INP_BINDANY) == 0 && | ||||
ifa_ifwithaddr_check((struct sockaddr *)sin) == 0) | ifa_ifwithaddr_check( | ||||
(const struct sockaddr *)sin) == 0) | |||||
return (EADDRNOTAVAIL); | return (EADDRNOTAVAIL); | ||||
} | } | ||||
laddr = sin->sin_addr; | |||||
if (lport) { | if (lport) { | ||||
struct inpcb *t; | struct inpcb *t; | ||||
/* GROSS */ | |||||
if (ntohs(lport) <= V_ipport_reservedhigh && | if (ntohs(lport) <= V_ipport_reservedhigh && | ||||
ntohs(lport) >= V_ipport_reservedlow && | ntohs(lport) >= V_ipport_reservedlow && | ||||
priv_check_cred(cred, PRIV_NETINET_RESERVEDPORT)) | priv_check_cred(cred, PRIV_NETINET_RESERVEDPORT)) | ||||
return (EACCES); | return (EACCES); | ||||
if (!IN_MULTICAST(ntohl(sin->sin_addr.s_addr)) && | |||||
if (!IN_MULTICAST(ntohl(laddr.s_addr)) && | |||||
priv_check_cred(inp->inp_cred, PRIV_NETINET_REUSEPORT) != 0) { | priv_check_cred(inp->inp_cred, PRIV_NETINET_REUSEPORT) != 0) { | ||||
t = in_pcblookup_local(pcbinfo, sin->sin_addr, | t = in_pcblookup_local(pcbinfo, laddr, lport, | ||||
lport, INPLOOKUP_WILDCARD, cred); | INPLOOKUP_WILDCARD, cred); | ||||
/* | |||||
* XXX | |||||
* This entire block sorely needs a rewrite. | |||||
*/ | |||||
if (t != NULL && | if (t != NULL && | ||||
(so->so_type != SOCK_STREAM || | (so->so_type != SOCK_STREAM || | ||||
ntohl(t->inp_faddr.s_addr) == INADDR_ANY) && | in_nullhost(t->inp_faddr)) && | ||||
(ntohl(sin->sin_addr.s_addr) != INADDR_ANY || | (!in_nullhost(laddr) || | ||||
ntohl(t->inp_laddr.s_addr) != INADDR_ANY || | !in_nullhost(t->inp_laddr) || | ||||
(t->inp_socket->so_options & SO_REUSEPORT) || | (t->inp_socket->so_options & SO_REUSEPORT) || | ||||
(t->inp_socket->so_options & SO_REUSEPORT_LB) == 0) && | (t->inp_socket->so_options & SO_REUSEPORT_LB) == 0) && | ||||
(inp->inp_cred->cr_uid != | (inp->inp_cred->cr_uid != | ||||
t->inp_cred->cr_uid)) | t->inp_cred->cr_uid)) | ||||
return (EADDRINUSE); | return (EADDRINUSE); | ||||
} | } | ||||
t = in_pcblookup_local(pcbinfo, sin->sin_addr, | t = in_pcblookup_local(pcbinfo, laddr, lport, | ||||
lport, lookupflags, cred); | lookupflags, cred); | ||||
if (t != NULL && (reuseport & t->inp_socket->so_options) == 0 && | if (t != NULL && ((reuseport | reuseport_lb) & | ||||
(reuseport_lb & t->inp_socket->so_options) == 0) { | t->inp_socket->so_options) == 0) { | ||||
#ifdef INET6 | #ifdef INET6 | ||||
if (ntohl(sin->sin_addr.s_addr) != | if (!in_nullhost(laddr) || | ||||
INADDR_ANY || | !in_nullhost(t->inp_laddr) || | ||||
ntohl(t->inp_laddr.s_addr) != | |||||
INADDR_ANY || | |||||
(inp->inp_vflag & INP_IPV6PROTO) == 0 || | (inp->inp_vflag & INP_IPV6PROTO) == 0 || | ||||
(t->inp_vflag & INP_IPV6PROTO) == 0) | (t->inp_vflag & INP_IPV6PROTO) == 0) | ||||
#endif | #endif | ||||
return (EADDRINUSE); | return (EADDRINUSE); | ||||
} | } | ||||
} | } | ||||
} | } | ||||
if (*lportp != 0) | if (*lportp != 0) | ||||
lport = *lportp; | lport = *lportp; | ||||
if (lport == 0) { | if (lport == 0) { | ||||
error = in_pcb_lport(inp, &laddr, &lport, cred, lookupflags); | error = in_pcb_lport(inp, &laddr, &lport, cred, lookupflags); | ||||
if (error != 0) | if (error != 0) | ||||
▲ Show 20 Lines • Show All 2,514 Lines • Show Last 20 Lines |