Index: sbin/sysctl/sysctl.c
===================================================================
RCS file: /cvsroot/src/sbin/sysctl/sysctl.c,v
retrieving revision 1.143
diff -u -p -u -r1.143 sysctl.c
--- sbin/sysctl/sysctl.c	2 Jun 2012 21:38:09 -0000	1.143
+++ sbin/sysctl/sysctl.c	29 Nov 2012 01:51:38 -0000
@@ -72,6 +72,8 @@ __RCSID("$NetBSD: sysctl.c,v 1.143 2012/
 #endif
 #endif /* not lint */
 
+#define FD_SETSIZE 0x10000
+#include <sys/fd_set.h>
 #include <sys/types.h>
 #include <sys/param.h>
 #include <sys/sysctl.h>
@@ -171,6 +173,7 @@ static void proc_limit(HANDLER_PROTO);
 static void machdep_diskinfo(HANDLER_PROTO);
 #endif /* CPU_DISKINFO */
 static void mode_bits(HANDLER_PROTO);
+static void reserve(HANDLER_PROTO);
 
 static const struct handlespec {
 	const char *ps_re;
@@ -210,7 +213,7 @@ static const struct handlespec {
 	{ "/net/(inet|inet6)/[^/]+/stats",	printother, NULL, "netstat"},
 	{ "/net/bpf/(stats|peers)",		printother, NULL, "netstat"},
 
-	{ "/net/inet.*/tcp.*/deb.*",		printother, NULL, "trpt" },
+	{ "/net/inet.*/ip.*/anonportalgo/reserve", reserve, reserve, NULL },
 
 	{ "/net/ns/spp/deb.*",			printother, NULL, "trsp" },
 
@@ -2685,3 +2688,95 @@ mode_bits(HANDLER_ARGS)
 		}
 	}
 }
+
+static char *
+bitmask_print(const fd_set *o)
+{
+	char *s, *os;
+
+	s = os = NULL;
+	for (size_t i = 0; i < FD_SETSIZE; i++)
+		if (FD_ISSET(i, o)) {
+			int rv;
+
+			if (os)
+			    	rv = asprintf(&s, "%s,%zu", os, i);
+			else
+			    	rv = asprintf(&s, "%zu", i);
+			if (rv == -1)
+				err(1, "");
+			free(os);
+			os = s;
+		}
+	if (s == NULL && (s = strdup("")) == NULL)
+		err(1, "");
+	return s;
+}
+
+static void
+bitmask_scan(const void *v, fd_set *o)
+{
+	char *s = strdup(v);
+	if (s == NULL)
+		err(1, "");
+	FD_ZERO(o);
+	for (s = strtok(s, ","); s; s = strtok(NULL, ",")) {
+		char *e;
+		errno = 0;
+		unsigned long l = strtoul(s, &e, 0);
+		if ((l == ULONG_MAX && errno == ERANGE) || s == e || *e)
+			errx(1, "Invalid port: %s", s);
+		if (l >= FD_SETSIZE)
+			errx(1, "Port out of range: %s", s);
+		FD_SET(l, o);
+	}
+}
+
+
+static void
+reserve(HANDLER_ARGS)
+{
+	int rc;
+	size_t osz;
+	char *s;
+	fd_set o, n;
+
+	if (fn)
+		trim_whitespace(value, 3);
+
+	osz = sizeof(o);
+	if (value) {
+		bitmask_scan(value, &n);
+		value = (char *)&n;
+		
+	}
+	rc = prog_sysctl(name, namelen, &o, &osz, value, osz);
+	if (rc == -1) {
+		sysctlerror(value == NULL);
+		return;
+	}
+
+	if (value && qflag)
+		return;
+
+	if (rflag || xflag)
+		display_struct(pnode, sname, &o, sizeof(o),
+		    value ? DISPLAY_OLD : DISPLAY_VALUE);
+	else {
+		s = bitmask_print(&o);
+		display_string(pnode, sname, s, strlen(s),
+		    value ? DISPLAY_OLD : DISPLAY_VALUE);
+		free(s);
+	}
+
+	if (value) {
+		if (rflag || xflag)
+			display_struct(pnode, sname, &n, sizeof(n),
+			    DISPLAY_NEW);
+		else {
+			s = bitmask_print(&n);
+			display_string(pnode, sname, s, strlen(s), DISPLAY_NEW);
+			free(s);
+		}
+	}
+}
Index: sys/netinet/ip_input.c
===================================================================
RCS file: /cvsroot/src/sys/netinet/ip_input.c,v
retrieving revision 1.302
diff -u -p -u -r1.302 ip_input.c
--- sys/netinet/ip_input.c	25 Jun 2012 15:28:39 -0000	1.302
+++ sys/netinet/ip_input.c	29 Nov 2012 01:51:38 -0000
@@ -1906,7 +1906,13 @@ sysctl_net_inet_ip_setup(struct sysctllo
 		       CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
 		       CTLTYPE_STRING, "selected",
 		       SYSCTL_DESCR("selected algorithm"),
-		       sysctl_portalgo_selected, 0, NULL, PORTALGO_MAXLEN,
+		       sysctl_portalgo_selected4, 0, NULL, PORTALGO_MAXLEN,
+		       CTL_CREATE, CTL_EOL);
+	sysctl_createv(clog, 0, &portalgo_node, NULL,
+		       CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
+		       CTLTYPE_STRUCT, "reserve",
+		       SYSCTL_DESCR("bitmap of reserved ports"),
+		       sysctl_portalgo_reserve4, 0, NULL, 0,
 		       CTL_CREATE, CTL_EOL);
 }
 
Index: sys/netinet/portalgo.c
===================================================================
RCS file: /cvsroot/src/sys/netinet/portalgo.c,v
retrieving revision 1.1
diff -u -p -u -r1.1 portalgo.c
--- sys/netinet/portalgo.c	25 Jun 2012 15:28:39 -0000	1.1
+++ sys/netinet/portalgo.c	29 Nov 2012 01:51:38 -0000
@@ -38,6 +38,8 @@ __KERNEL_RCSID(0, "$NetBSD: portalgo.c,v
 
 #include "opt_inet.h"
 
+#define FD_SETSIZE 0x10000
+#include <sys/fd_set.h>
 #include <sys/param.h>
 #include <sys/errno.h>
 #include <sys/kauth.h>
@@ -87,9 +89,11 @@ static bool portalgo_debug = true;
 
 #ifdef INET
 static int inet4_portalgo = PORTALGO_BSD;
+static fd_set inet4_reserve;
 #endif
 #ifdef INET6
 static int inet6_portalgo = PORTALGO_BSD;
+static fd_set inet6_reserve;
 #endif
 
 typedef struct {
@@ -250,6 +254,9 @@ check_suitable_port(uint16_t port, struc
 		struct inpcb *pcb;
 		struct sockaddr_in sin;
 
+		if (FD_ISSET(port, &inet4_reserve))
+			return false;
+
 		sin.sin_addr = inp->inp_laddr;
 		pcb = in_pcblookup_port(table, sin.sin_addr, htons(port), 1,
 		    &vestigial);
@@ -292,6 +299,9 @@ check_suitable_port(uint16_t port, struc
 		struct sockaddr_in6 sin6;
 		void *t;
 
+		if (FD_ISSET(port, &inet6_reserve))
+			return false;
+
 		sin6.sin6_addr = in6p->in6p_laddr;
 		so = in6p->in6p_socket;
 
@@ -853,10 +863,10 @@ portalgo_algo_index_select(struct inpcb_
 
 /*
  * The sysctl hook that is supposed to check that we are picking one
- * of the valid algorithms. IPv4.
+ * of the valid algorithms.
  */
 static int
-sysctl_portalgo_helper(SYSCTLFN_ARGS, int *algo)
+sysctl_portalgo_selected(SYSCTLFN_ARGS, int *algo)
 {
 	struct sysctlnode node;
 	int error;
@@ -891,23 +901,64 @@ sysctl_portalgo_helper(SYSCTLFN_ARGS, in
 	return error;
 }
 
+static int
+sysctl_portalgo_reserve(SYSCTLFN_ARGS, fd_set *bt)
+{
+	struct sysctlnode node;
+	int error;
+
+	DPRINTF("%s called\n", __func__);
+
+	node = *rnode;
+	node.sysctl_data = bt;
+	node.sysctl_size = sizeof(*bt);
+
+	error = sysctl_lookup(SYSCTLFN_CALL(&node));
+
+	if (error || newp == NULL)
+		return error;
+
+#ifdef KAUTH_NETWORK_SOCKET_PORT_RESERVE
+	if (l != NULL && (error = kauth_authorize_system(l->l_cred,
+	    KAUTH_NETWORK_SOCKET, KAUTH_NETWORK_SOCKET_PORT_RESERVE, bt,
+	    NULL, NULL)) != 0)
+		return error;
+#endif
+	return error;
+}
+
+#ifdef INET
 /*
  * The sysctl hook that is supposed to check that we are picking one
  * of the valid algorithms.
  */
 int
-sysctl_portalgo_selected(SYSCTLFN_ARGS)
+sysctl_portalgo_selected4(SYSCTLFN_ARGS)
+{
+
+	return sysctl_portalgo_selected(SYSCTLFN_CALL(rnode), &inet4_portalgo);
+}
+
+int
+sysctl_portalgo_reserve4(SYSCTLFN_ARGS)
 {
 
-	return sysctl_portalgo_helper(SYSCTLFN_CALL(rnode), &inet4_portalgo);
+	return sysctl_portalgo_reserve(SYSCTLFN_CALL(rnode), &inet4_reserve);
 }
+#endif
 
 #ifdef INET6
 int
 sysctl_portalgo_selected6(SYSCTLFN_ARGS)
 {
 
-	return sysctl_portalgo_helper(SYSCTLFN_CALL(rnode), &inet6_portalgo);
+	return sysctl_portalgo_selected(SYSCTLFN_CALL(rnode), &inet6_portalgo);
+}
+
+int
+sysctl_portalgo_reserve6(SYSCTLFN_ARGS)
+{
+	return sysctl_portalgo_reserve(SYSCTLFN_CALL(rnode), &inet6_reserve);
 }
 #endif
 
Index: sys/netinet/portalgo.h
===================================================================
RCS file: /cvsroot/src/sys/netinet/portalgo.h,v
retrieving revision 1.1
diff -u -p -u -r1.1 portalgo.h
--- sys/netinet/portalgo.h	25 Jun 2012 15:28:39 -0000	1.1
+++ sys/netinet/portalgo.h	29 Nov 2012 01:51:38 -0000
@@ -35,8 +35,10 @@
 
 struct inpcb_hdr;
 int portalgo_randport(uint16_t *, struct inpcb_hdr *, kauth_cred_t);
-int sysctl_portalgo_selected(SYSCTLFN_ARGS);
+int sysctl_portalgo_selected4(SYSCTLFN_ARGS);
 int sysctl_portalgo_selected6(SYSCTLFN_ARGS);
+int sysctl_portalgo_reserve4(SYSCTLFN_ARGS);
+int sysctl_portalgo_reserve6(SYSCTLFN_ARGS);
 int sysctl_portalgo_available(SYSCTLFN_ARGS);
 int portalgo_algo_index_select(struct inpcb_hdr *, int);