tech-net archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
in_pcbbind() changes
Hey,
Attached is a diff implementing changes to in_pcbbind() similar to the
ones recently done in in6_pcbbind():
- Add in_pcbbind_{addr,port}() and split functionality
- Add in_pcbsetport() (almost an exact copy of in6_pcbsetport() that
was open-coded inside in_pcbbind())
- All three "static" for now, will be exposed if we decide to
- Fix a bug where "sin" was passed to kauth(9) without being set to
anything
Please review. :)
Thanks,
-e.
Index: in_pcb.c
===================================================================
RCS file: /cvsroot/src/sys/netinet/in_pcb.c,v
retrieving revision 1.131
diff -u -p -r1.131 in_pcb.c
--- in_pcb.c 14 Apr 2009 21:25:20 -0000 1.131
+++ in_pcb.c 21 Apr 2009 16:12:17 -0000
@@ -111,6 +111,7 @@ __KERNEL_RCSID(0, "$NetBSD: in_pcb.c,v 1
#include <sys/proc.h>
#include <sys/kauth.h>
#include <sys/uidinfo.h>
+#include <sys/domain.h>
#include <net/if.h>
#include <net/route.h>
@@ -222,35 +223,92 @@ in_pcballoc(struct socket *so, void *v)
return (0);
}
-int
-in_pcbbind(void *v, struct mbuf *nam, struct lwp *l)
+static int
+in_pcbsetport(struct in_addr *laddr, struct inpcb *inp,
+ struct sockaddr_in *sin, kauth_cred_t cred)
{
- struct in_ifaddr *ia = NULL;
- struct inpcb *inp = v;
- struct socket *so = inp->inp_socket;
struct inpcbtable *table = inp->inp_table;
- struct sockaddr_in *sin = NULL; /* XXXGCC */
+ struct socket *so = inp->inp_socket;
+ int cnt;
+ u_int16_t mymin, mymax;
+ u_int16_t *lastport;
u_int16_t lport = 0;
- int wild = 0, reuseport = (so->so_options & SO_REUSEPORT);
- kauth_cred_t cred = l->l_cred;
- if (inp->inp_af != AF_INET)
- return (EINVAL);
+ if (inp->inp_flags & INP_LOWPORT) {
+#ifndef IPNOPRIVPORTS
+ if (kauth_authorize_network(cred,
+ KAUTH_NETWORK_BIND,
+ KAUTH_REQ_NETWORK_BIND_PRIVPORT, so,
+ sin, NULL))
+ return (EACCES);
+#endif
+ mymin = lowportmin;
+ mymax = lowportmax;
+ lastport = &table->inpt_lastlow;
+ } else {
+ mymin = anonportmin;
+ mymax = anonportmax;
+ lastport = &table->inpt_lastport;
+ }
+ if (mymin > mymax) { /* sanity check */
+ u_int16_t swp;
+
+ swp = mymin;
+ mymin = mymax;
+ mymax = swp;
+ }
+
+ lport = *lastport - 1;
+ for (cnt = mymax - mymin + 1; cnt; cnt--, lport--) {
+ if (lport < mymin || lport > mymax)
+ lport = mymax;
+ if (!in_pcblookup_port(table, inp->inp_laddr,
+ htons(lport), 1))
+ goto found;
+ }
+
+ return (EAGAIN);
+
+ found:
+ inp->inp_flags |= INP_ANONPORT;
+ *lastport = lport;
+ lport = htons(lport);
+ inp->inp_lport = lport;
+ in_pcbstate(inp, INP_BOUND);
- if (TAILQ_FIRST(&in_ifaddrhead) == 0)
- return (EADDRNOTAVAIL);
- if (inp->inp_lport || !in_nullhost(inp->inp_laddr))
- return (EINVAL);
- if ((so->so_options & (SO_REUSEADDR|SO_REUSEPORT)) == 0)
- wild = 1;
- if (nam == 0)
- goto noname;
- sin = mtod(nam, struct sockaddr_in *);
- if (nam->m_len != sizeof (*sin))
- return (EINVAL);
+ return (0);
+}
+
+static int
+in_pcbbind_addr(struct inpcb *inp, struct sockaddr_in *sin, kauth_cred_t cred)
+{
if (sin->sin_family != AF_INET)
return (EAFNOSUPPORT);
- lport = sin->sin_port;
+
+ if (!in_nullhost(sin->sin_addr)) {
+ struct in_ifaddr *ia = NULL;
+
+ INADDR_TO_IA(sin->sin_addr, ia);
+ /* check for broadcast addresses */
+ if (ia == NULL)
+ ia = ifatoia(ifa_ifwithaddr(sintosa(sin)));
+ if (ia == NULL)
+ return (EADDRNOTAVAIL);
+ }
+
+ inp->inp_laddr = sin->sin_addr;
+
+ return (0);
+}
+
+static int
+in_pcbbind_port(struct inpcb *inp, struct sockaddr_in *sin, kauth_cred_t cred)
+{
+ struct inpcbtable *table = inp->inp_table;
+ struct socket *so = inp->inp_socket;
+ int reuseport = (so->so_options & SO_REUSEPORT);
+ int wild = 0;
+
if (IN_MULTICAST(sin->sin_addr.s_addr)) {
/*
* Treat SO_REUSEADDR as SO_REUSEPORT for multicast;
@@ -261,23 +319,27 @@ in_pcbbind(void *v, struct mbuf *nam, st
*/
if (so->so_options & SO_REUSEADDR)
reuseport = SO_REUSEADDR|SO_REUSEPORT;
- } else if (!in_nullhost(sin->sin_addr)) {
- INADDR_TO_IA(sin->sin_addr, ia);
- /* check for broadcast addresses */
- if (ia == NULL)
- ia = ifatoia(ifa_ifwithaddr(sintosa(sin)));
- if (ia == NULL)
- return (EADDRNOTAVAIL);
- }
- if (lport) {
+ }
+
+ if (sin->sin_port == 0) {
+ int error;
+
+ error = in_pcbsetport(&inp->inp_laddr, inp, sin, cred);
+ if (error)
+ return (error);
+ } else {
struct inpcb *t;
#ifdef INET6
struct in6pcb *t6;
struct in6_addr mapped;
#endif
+
+ if ((so->so_options & (SO_REUSEADDR|SO_REUSEPORT)) == 0)
+ wild = 1;
+
#ifndef IPNOPRIVPORTS
/* GROSS */
- if (ntohs(lport) < IPPORT_RESERVED &&
+ if (ntohs(sin->sin_port) < IPPORT_RESERVED &&
kauth_authorize_network(cred,
KAUTH_NETWORK_BIND,
KAUTH_REQ_NETWORK_BIND_PRIVPORT, so, sin,
@@ -289,12 +351,12 @@ in_pcbbind(void *v, struct mbuf *nam, st
mapped.s6_addr16[5] = 0xffff;
memcpy(&mapped.s6_addr32[3], &sin->sin_addr,
sizeof(mapped.s6_addr32[3]));
- t6 = in6_pcblookup_port(table, &mapped, lport, wild);
+ t6 = in6_pcblookup_port(table, &mapped, sin->sin_port, wild);
if (t6 && (reuseport & t6->in6p_socket->so_options) == 0)
return (EADDRINUSE);
#endif
if (so->so_uidinfo->ui_uid &&
!IN_MULTICAST(sin->sin_addr.s_addr)) {
- t = in_pcblookup_port(table, sin->sin_addr, lport, 1);
+ t = in_pcblookup_port(table, sin->sin_addr,
sin->sin_port, 1);
/*
* XXX: investigate ramifications of loosening this
* restriction so that as long as both ports have
@@ -308,63 +370,58 @@ in_pcbbind(void *v, struct mbuf *nam, st
return (EADDRINUSE);
}
}
- t = in_pcblookup_port(table, sin->sin_addr, lport, wild);
+ t = in_pcblookup_port(table, sin->sin_addr, sin->sin_port,
wild);
if (t && (reuseport & t->inp_socket->so_options) == 0)
return (EADDRINUSE);
- }
- inp->inp_laddr = sin->sin_addr;
-
-noname:
- if (lport == 0) {
- int cnt;
- u_int16_t mymin, mymax;
- u_int16_t *lastport;
- if (inp->inp_flags & INP_LOWPORT) {
-#ifndef IPNOPRIVPORTS
- if (kauth_authorize_network(cred,
- KAUTH_NETWORK_BIND,
- KAUTH_REQ_NETWORK_BIND_PRIVPORT, so,
- sin, NULL))
- return (EACCES);
-#endif
- mymin = lowportmin;
- mymax = lowportmax;
- lastport = &table->inpt_lastlow;
- } else {
- mymin = anonportmin;
- mymax = anonportmax;
- lastport = &table->inpt_lastport;
- }
- if (mymin > mymax) { /* sanity check */
- u_int16_t swp;
-
- swp = mymin;
- mymin = mymax;
- mymax = swp;
- }
-
- lport = *lastport - 1;
- for (cnt = mymax - mymin + 1; cnt; cnt--, lport--) {
- if (lport < mymin || lport > mymax)
- lport = mymax;
- if (!in_pcblookup_port(table, inp->inp_laddr,
- htons(lport), 1))
- goto found;
- }
- if (!in_nullhost(inp->inp_laddr))
- inp->inp_laddr.s_addr = INADDR_ANY;
- return (EAGAIN);
- found:
- inp->inp_flags |= INP_ANONPORT;
- *lastport = lport;
- lport = htons(lport);
+ inp->inp_lport = sin->sin_port;
+ in_pcbstate(inp, INP_BOUND);
}
- inp->inp_lport = lport;
+
LIST_REMOVE(&inp->inp_head, inph_lhash);
LIST_INSERT_HEAD(INPCBHASH_PORT(table, inp->inp_lport), &inp->inp_head,
inph_lhash);
- in_pcbstate(inp, INP_BOUND);
+
+ return (0);
+}
+
+int
+in_pcbbind(void *v, struct mbuf *nam, struct lwp *l)
+{
+ struct inpcb *inp = v;
+ struct sockaddr_in *sin = NULL; /* XXXGCC */
+ int error;
+
+ if (inp->inp_af != AF_INET)
+ return (EINVAL);
+
+ if (TAILQ_FIRST(&in_ifaddrhead) == 0)
+ return (EADDRNOTAVAIL);
+ if (inp->inp_lport || !in_nullhost(inp->inp_laddr))
+ return (EINVAL);
+
+ if (nam != NULL) {
+ sin = mtod(nam, struct sockaddr_in *);
+ if (nam->m_len != sizeof (*sin))
+ return (EINVAL);
+ } else {
+ sin = (struct sockaddr_in *)
+ __UNCONST(inp->inp_socket->so_proto->pr_domain->dom_sa_any);
+ }
+
+ /* Bind address. */
+ error = in_pcbbind_addr(inp, sin, l->l_cred);
+ if (error)
+ return (error);
+
+ /* Bind port. */
+ error = in_pcbbind_port(inp, sin, l->l_cred);
+ if (error) {
+ inp->inp_laddr.s_addr = INADDR_ANY;
+
+ return (error);
+ }
+
return (0);
}
Home |
Main Index |
Thread Index |
Old Index