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);