Module Name:    src
Committed By:   elad
Date:           Thu Apr 23 16:42:56 UTC 2009

Modified Files:
        src/sys/netinet: in_pcb.c

Log Message:
Some changes to in_pcbbind():

  - Extract guts to in_pcbbind_{addr,port}()

  - Put the port auto-assignment logic in in_pcbsetport(), which looks very
    similar to in6_pcbsetport()

  - Fix a bug where "sin" was passed to kauth(9) without being set to
    anything

No objections on tech-...@.


To generate a diff of this commit:
cvs rdiff -u -r1.131 -r1.132 src/sys/netinet/in_pcb.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/netinet/in_pcb.c
diff -u src/sys/netinet/in_pcb.c:1.131 src/sys/netinet/in_pcb.c:1.132
--- src/sys/netinet/in_pcb.c:1.131	Tue Apr 14 21:25:20 2009
+++ src/sys/netinet/in_pcb.c	Thu Apr 23 16:42:56 2009
@@ -1,4 +1,4 @@
-/*	$NetBSD: in_pcb.c,v 1.131 2009/04/14 21:25:20 elad Exp $	*/
+/*	$NetBSD: in_pcb.c,v 1.132 2009/04/23 16:42:56 elad Exp $	*/
 
 /*
  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@@ -91,7 +91,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: in_pcb.c,v 1.131 2009/04/14 21:25:20 elad Exp $");
+__KERNEL_RCSID(0, "$NetBSD: in_pcb.c,v 1.132 2009/04/23 16:42:56 elad Exp $");
 
 #include "opt_inet.h"
 #include "opt_ipsec.h"
@@ -111,6 +111,7 @@
 #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 @@
 	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 @@
 		 */
 		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 @@
 		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 @@
 				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);
 }
 

Reply via email to