Home | History | Annotate | Line # | Download | only in netinet
portalgo.c revision 1.6.2.3
      1 /*	$NetBSD: portalgo.c,v 1.6.2.3 2016/05/29 08:44:38 skrll Exp $	*/
      2 
      3 /*
      4  * Copyright 2011 Vlad Balan
      5  *
      6  * Written by Vlad Balan for the NetBSD Foundation.
      7  *
      8  * Redistribution and use in source and binary forms, with or without
      9  * modification, are permitted provided that the following conditions
     10  * are met:
     11  * 1. Redistributions of source code must retain the above copyright
     12  *    notice, this list of conditions and the following disclaimer.
     13  * 2. Redistributions in binary form must reproduce the above copyright
     14  *    notice, this list of conditions and the following disclaimer in the
     15  *    documentation and/or other materials provided with the distribution.
     16  *
     17  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     27  * SUCH DAMAGE.
     28  *
     29  */
     30 
     31 /*
     32  * see:
     33  *	RFC 6056 Recommendations for Transport-Protocol Port Randomization
     34  */
     35 
     36 #include <sys/cdefs.h>
     37 __KERNEL_RCSID(0, "$NetBSD: portalgo.c,v 1.6.2.3 2016/05/29 08:44:38 skrll Exp $");
     38 
     39 #ifdef _KERNEL_OPT
     40 #include "opt_inet.h"
     41 #endif
     42 
     43 #include <sys/param.h>
     44 #include <sys/errno.h>
     45 #include <sys/kauth.h>
     46 #include <sys/uidinfo.h>
     47 #include <sys/domain.h>
     48 #include <sys/md5.h>
     49 #include <sys/cprng.h>
     50 #include <sys/bitops.h>
     51 
     52 #include <net/if.h>
     53 
     54 #include <netinet/in.h>
     55 #include <netinet/in_systm.h>
     56 #include <netinet/ip.h>
     57 #include <netinet/in_pcb.h>
     58 #include <netinet/in_var.h>
     59 #include <netinet/ip_var.h>
     60 
     61 #ifdef INET6
     62 #include <netinet/ip6.h>
     63 #include <netinet6/ip6_var.h>
     64 #include <netinet6/in6_pcb.h>
     65 #endif
     66 
     67 #include <netinet/tcp_vtw.h>
     68 
     69 #include "portalgo.h"
     70 
     71 #define NPROTO 2
     72 #define PORTALGO_TCP 0
     73 #define PORTALGO_UDP 1
     74 
     75 #define NAF 2
     76 #define PORTALGO_IPV4 0
     77 #define PORTALGO_IPV6 1
     78 
     79 #define NRANGES 2
     80 #define PORTALGO_LOWPORT 0
     81 #define PORTALGO_HIGHPORT 1
     82 
     83 #if PORTALGO_DEBUG
     84 static bool portalgo_debug = true;
     85 #define DPRINTF if (portalgo_debug) printf
     86 #else
     87 #define DPRINTF while (/*CONSTCOND*/0) printf
     88 #endif
     89 
     90 #ifndef PORTALGO_INET4_DEFAULT
     91 #define PORTALGO_INET4_DEFAULT PORTALGO_BSD
     92 #endif
     93 #ifndef PORTALGO_INET6_DEFAULT
     94 #define PORTALGO_INET6_DEFAULT PORTALGO_BSD
     95 #endif
     96 
     97 typedef __BITMAP_TYPE(, uint32_t, 0x10000) bitmap;
     98 #ifdef INET
     99 static int inet4_portalgo = PORTALGO_INET4_DEFAULT;
    100 static bitmap inet4_reserve;
    101 #endif
    102 #ifdef INET6
    103 static int inet6_portalgo = PORTALGO_INET6_DEFAULT;
    104 static bitmap inet6_reserve;
    105 #endif
    106 
    107 typedef struct {
    108 	const char *name;
    109 	int (*func)(int, uint16_t *, struct inpcb_hdr *, kauth_cred_t);
    110 } portalgo_algorithm_t;
    111 
    112 static int algo_bsd(int, uint16_t *, struct inpcb_hdr *, kauth_cred_t);
    113 static int algo_random_start(int, uint16_t *, struct inpcb_hdr *, kauth_cred_t);
    114 static int algo_random_pick(int, uint16_t *, struct inpcb_hdr *, kauth_cred_t);
    115 static int algo_hash(int, uint16_t *, struct inpcb_hdr *, kauth_cred_t);
    116 static int algo_doublehash(int, uint16_t *, struct inpcb_hdr *, kauth_cred_t);
    117 static int algo_randinc(int, uint16_t *, struct inpcb_hdr *, kauth_cred_t);
    118 
    119 static const portalgo_algorithm_t algos[] = {
    120 	{
    121 		.name = "bsd",
    122 		.func = algo_bsd
    123 	},
    124 	{
    125 		.name = "random_start",
    126 		.func = algo_random_start
    127 	},
    128 	{
    129 		.name = "random_pick",
    130 		.func = algo_random_pick
    131 	},
    132 	{
    133 		.name = "hash",
    134 		.func = algo_hash
    135 	},
    136 	{
    137 		.name = "doublehash",
    138 		.func = algo_doublehash
    139 	},
    140 	{
    141 		.name = "randinc",
    142 		.func = algo_randinc
    143 	}
    144 };
    145 
    146 #define NALGOS __arraycount(algos)
    147 
    148 static uint16_t portalgo_next_ephemeral[NPROTO][NAF][NRANGES][NALGOS];
    149 
    150 /*
    151  * Access the pcb and copy the values of the last port and the ends of
    152  * the port range.
    153  */
    154 static int
    155 pcb_getports(struct inpcb_hdr *inp_hdr, uint16_t *lastport,
    156     uint16_t *mymin, uint16_t *mymax, uint16_t **pnext_ephemeral, int algo)
    157 {
    158 	struct inpcbtable * const table = inp_hdr->inph_table;
    159 	struct socket *so;
    160 	int portalgo_proto;
    161 	int portalgo_af;
    162 	int portalgo_range;
    163 
    164 	so = inp_hdr->inph_socket;
    165 	switch (so->so_type) {
    166 	case SOCK_DGRAM: /* UDP or DCCP */
    167 	case SOCK_CONN_DGRAM:
    168 		portalgo_proto = PORTALGO_UDP;
    169 		break;
    170 	case SOCK_STREAM: /* TCP or SCTP */
    171 		portalgo_proto = PORTALGO_TCP;
    172 		break;
    173 	default:
    174 		return EPFNOSUPPORT;
    175 	}
    176 
    177 	switch (inp_hdr->inph_af) {
    178 #ifdef INET
    179 	case AF_INET: {
    180 		struct inpcb *inp = (struct inpcb *)(void *)inp_hdr;
    181 
    182 		portalgo_af = PORTALGO_IPV4;
    183 		if (inp->inp_flags & INP_LOWPORT) {
    184 			*mymin = lowportmin;
    185 			*mymax = lowportmax;
    186 			*lastport = table->inpt_lastlow;
    187 			portalgo_range = PORTALGO_LOWPORT;
    188 		} else {
    189 			*mymin = anonportmin;
    190 			*mymax = anonportmax;
    191 			*lastport = table->inpt_lastport;
    192 			portalgo_range = PORTALGO_HIGHPORT;
    193 		}
    194 		break;
    195 	}
    196 #endif
    197 #ifdef INET6
    198 	case AF_INET6: {
    199 		struct in6pcb *in6p = (struct in6pcb *)(void *)inp_hdr;
    200 
    201 		portalgo_af = PORTALGO_IPV6;
    202 		if (in6p->in6p_flags & IN6P_LOWPORT) {
    203 			*mymin = ip6_lowportmin;
    204 			*mymax = ip6_lowportmax;
    205 			*lastport = table->inpt_lastlow;
    206 			portalgo_range = PORTALGO_LOWPORT;
    207 		} else {
    208 			*mymin = ip6_anonportmin;
    209 			*mymax = ip6_anonportmax;
    210 			*lastport = table->inpt_lastport;
    211 			portalgo_range = PORTALGO_HIGHPORT;
    212 		}
    213 		break;
    214 	}
    215 #endif
    216 	default:
    217 		return EAFNOSUPPORT;
    218 	}
    219 
    220 	if (*mymin > *mymax) {	/* sanity check */
    221 		u_int16_t swp;
    222 
    223 		swp = *mymin;
    224 		*mymin = *mymax;
    225 		*mymax = swp;
    226 	}
    227 
    228 	DPRINTF("%s mymin:%d mymax:%d lastport:%d\n", __func__,
    229 	    *mymin, *mymax, *lastport);
    230 
    231 	*pnext_ephemeral = &portalgo_next_ephemeral[portalgo_proto]
    232 	    [portalgo_af][portalgo_range][algo];
    233 
    234 	DPRINTF("%s portalgo_proto:%d portalgo_af:%d portalgo_range:%d\n",
    235 	    __func__, portalgo_proto, portalgo_af, portalgo_range);
    236 	return 0;
    237 }
    238 
    239 /*
    240  * Check whether the port picked by the port randomizer is available
    241  * and whether KAUTH approves of our choice. This part of the code
    242  * shamelessly copied from in_pcb.c.
    243  */
    244 static bool
    245 check_suitable_port(uint16_t port, struct inpcb_hdr *inp_hdr, kauth_cred_t cred)
    246 {
    247 	struct inpcbtable * const table = inp_hdr->inph_table;
    248 #ifdef INET
    249 	vestigial_inpcb_t vestigial;
    250 #endif
    251 	int error;
    252 #ifdef INET6
    253 	struct socket *so;
    254 	int wild = 0;
    255 #endif
    256 
    257 	DPRINTF("%s called for argument %d\n", __func__, port);
    258 
    259 	switch (inp_hdr->inph_af) {
    260 #ifdef INET
    261 	case AF_INET: { /* IPv4 */
    262 		struct inpcb *inp = (struct inpcb *)(void *)inp_hdr;
    263 		struct inpcb *pcb;
    264 		struct sockaddr_in sin;
    265 
    266 		if (__BITMAP_ISSET(port, &inet4_reserve))
    267 			return false;
    268 
    269 		sin.sin_addr = inp->inp_laddr;
    270 		pcb = in_pcblookup_port(table, sin.sin_addr, htons(port), 1,
    271 		    &vestigial);
    272 
    273 		DPRINTF("%s in_pcblookup_port returned %p and "
    274 		    "vestigial.valid %d\n",
    275 		    __func__, pcb, vestigial.valid);
    276 
    277 		if ((!pcb) && (!vestigial.valid)) {
    278 			enum kauth_network_req req;
    279 
    280 			/* We have a free port. Check with the secmodel. */
    281 			if (inp->inp_flags & INP_LOWPORT) {
    282 #ifndef IPNOPRIVPORTS
    283 				req = KAUTH_REQ_NETWORK_BIND_PRIVPORT;
    284 #else
    285 				req = KAUTH_REQ_NETWORK_BIND_PORT;
    286 #endif
    287 			} else
    288 				req = KAUTH_REQ_NETWORK_BIND_PORT;
    289 
    290 			sin.sin_port = port;
    291 			error = kauth_authorize_network(cred,
    292 			    KAUTH_NETWORK_BIND,
    293 			    req, inp->inp_socket, &sin, NULL);
    294 			DPRINTF("%s kauth_authorize_network returned %d\n",
    295 			    __func__, error);
    296 
    297 			if (error == 0) {
    298 				DPRINTF("%s port approved\n", __func__);
    299 				return true;	/* KAUTH agrees */
    300 			}
    301 		}
    302 		break;
    303 	}
    304 #endif
    305 #ifdef INET6
    306 	case AF_INET6: { /* IPv6 */
    307 		struct in6pcb *in6p = (struct in6pcb *)(void *)inp_hdr;
    308 		struct sockaddr_in6 sin6;
    309 		void *t;
    310 
    311 		if (__BITMAP_ISSET(port, &inet6_reserve))
    312 			return false;
    313 
    314 		sin6.sin6_addr = in6p->in6p_laddr;
    315 		so = in6p->in6p_socket;
    316 
    317 		/* XXX: this is redundant when called from in6_pcbbind */
    318 		if ((so->so_options & (SO_REUSEADDR|SO_REUSEPORT)) == 0 &&
    319 		    ((so->so_proto->pr_flags & PR_CONNREQUIRED) == 0 ||
    320 			(so->so_options & SO_ACCEPTCONN) == 0))
    321 			wild = 1;
    322 
    323 #ifdef INET
    324 		if (IN6_IS_ADDR_V4MAPPED(&sin6.sin6_addr)) {
    325 			t = in_pcblookup_port(table,
    326 			    *(struct in_addr *)&sin6.sin6_addr.s6_addr32[3],
    327 			    htons(port), wild, &vestigial);
    328 			if (!t && vestigial.valid) {
    329 				DPRINTF("%s in_pcblookup_port returned "
    330 				    "a result\n", __func__);
    331 				return false;
    332 			}
    333 		} else
    334 #endif
    335 		{
    336 			t = in6_pcblookup_port(table, &sin6.sin6_addr,
    337 			    htons(port), wild, &vestigial);
    338 			if (!t && vestigial.valid) {
    339 				DPRINTF("%s in6_pcblookup_port returned "
    340 				    "a result\n", __func__);
    341 				return false;
    342 			}
    343 		}
    344 		if (t == NULL) {
    345 			enum kauth_network_req req;
    346 
    347 			/* We have a free port. Check with the secmodel. */
    348 			if (in6p->in6p_flags & IN6P_LOWPORT) {
    349 #ifndef IPNOPRIVPORTS
    350 				req = KAUTH_REQ_NETWORK_BIND_PRIVPORT;
    351 #else
    352 				req = KAUTH_REQ_NETWORK_BIND_PORT;
    353 #endif
    354 			} else {
    355 				req = KAUTH_REQ_NETWORK_BIND_PORT;
    356 			}
    357 
    358 			sin6.sin6_port = port;
    359 			error = kauth_authorize_network(cred,
    360 			    KAUTH_NETWORK_BIND, req, so, &sin6, NULL);
    361 			if (error) {
    362 				/* Secmodel says no. Keep looking. */
    363 				DPRINTF("%s secmodel says no\n", __func__);
    364 				return false;
    365 			}
    366 			DPRINTF("%s port approved\n", __func__);
    367 			return true;
    368 		}
    369 		break;
    370 	}
    371 #endif
    372 	default:
    373 		DPRINTF("%s unknown address family\n", __func__);
    374 		return false;
    375 	}
    376 	return false;
    377 }
    378 
    379 /* This is the default BSD algorithm, as described in RFC 6056 */
    380 static int
    381 algo_bsd(int algo, uint16_t *port, struct inpcb_hdr *inp_hdr, kauth_cred_t cred)
    382 {
    383 	uint16_t count;
    384 	uint16_t mymin, mymax, lastport;
    385 	uint16_t *next_ephemeral;
    386 	int error;
    387 
    388 	DPRINTF("%s called\n", __func__);
    389 	error = pcb_getports(inp_hdr, &lastport, &mymin, &mymax,
    390 	    &next_ephemeral, algo);
    391 	if (error)
    392 		return error;
    393 	count = mymax - mymin + 1;
    394 	do {
    395 		uint16_t myport = *next_ephemeral;
    396 
    397 		if (myport < mymin || mymax < myport)
    398 			myport = mymax;
    399 		*next_ephemeral = myport - 1;
    400 		if (check_suitable_port(myport, inp_hdr, cred)) {
    401 			*port = myport;
    402 			DPRINTF("%s returning port %d\n", __func__, *port);
    403 			return 0;
    404 		}
    405 		count--;
    406 	} while (count > 0);
    407 
    408 	DPRINTF("%s returning EAGAIN\n", __func__);
    409 	return EAGAIN;
    410 }
    411 
    412 /*
    413  * The straightforward algorithm that increments the port number
    414  * by a random amount.
    415  */
    416 static int
    417 algo_random_start(int algo, uint16_t *port, struct inpcb_hdr *inp_hdr,
    418     kauth_cred_t cred)
    419 {
    420 	uint16_t count, num_ephemeral;
    421 	uint16_t mymin, mymax, lastport;
    422 	uint16_t *next_ephemeral;
    423 	int error;
    424 
    425 	DPRINTF("%s called\n", __func__);
    426 
    427 	error = pcb_getports(inp_hdr, &lastport, &mymin, &mymax,
    428 	    &next_ephemeral, algo);
    429 	if (error)
    430 		return error;
    431 
    432 	num_ephemeral = mymax - mymin + 1;
    433 
    434 	DPRINTF("num_ephemeral: %u\n", num_ephemeral);
    435 
    436 	*next_ephemeral = mymin + (cprng_fast32() % num_ephemeral);
    437 
    438 	DPRINTF("next_ephemeral initially: %u\n", *next_ephemeral);
    439 
    440 	count = num_ephemeral;
    441 
    442 	do {
    443 		if (check_suitable_port(*next_ephemeral, inp_hdr, cred)) {
    444 			*port = *next_ephemeral;
    445 			DPRINTF("%s returning port %d\n", __func__, *port);
    446 			return 0;
    447 		}
    448 		if (*next_ephemeral == mymax) {
    449 			*next_ephemeral = mymin;
    450 		} else
    451 			(*next_ephemeral)++;
    452 
    453 		count--;
    454 
    455 
    456 		DPRINTF("next_ephemeral: %u count: %u\n", *next_ephemeral,
    457 		    count);
    458 
    459 	} while (count > 0);
    460 
    461 	DPRINTF("%s returning EINVAL\n", __func__);
    462 
    463 	return EINVAL;
    464 }
    465 
    466 /*
    467  * Since there is no state kept on the ports tried, we might actually
    468  * give up before exhausting the free ports.
    469  */
    470 static int
    471 algo_random_pick(int algo, uint16_t *port, struct inpcb_hdr *inp_hdr,
    472     kauth_cred_t cred)
    473 {
    474 	uint16_t count, num_ephemeral;
    475 	uint16_t mymin, mymax, lastport;
    476 	uint16_t *next_ephemeral;
    477 	int error;
    478 
    479 	DPRINTF("%s called\n", __func__);
    480 
    481 	error = pcb_getports(inp_hdr, &lastport, &mymin, &mymax,
    482 	    &next_ephemeral, algo);
    483 	if (error)
    484 		return error;
    485 
    486 	num_ephemeral = mymax - mymin + 1;
    487 
    488 	DPRINTF("num_ephemeral: %u\n", num_ephemeral);
    489 	*next_ephemeral = mymin + (cprng_fast32() % num_ephemeral);
    490 
    491 	DPRINTF("next_ephemeral initially: %u\n", *next_ephemeral);
    492 
    493 	count = num_ephemeral;
    494 
    495 	do {
    496 		if (check_suitable_port(*next_ephemeral, inp_hdr, cred)) {
    497 			*port = *next_ephemeral;
    498 			DPRINTF("%s returning port %d\n", __func__, *port);
    499 			return 0;
    500 		}
    501 		*next_ephemeral = mymin +
    502 		    (cprng_fast32() % num_ephemeral);
    503 
    504 		count--;
    505 
    506 		DPRINTF("next_ephemeral: %u count: %u\n",
    507 		    *next_ephemeral, count);
    508 	} while (count > 0);
    509 
    510 	DPRINTF("%s returning EINVAL\n", __func__);
    511 
    512 	return EINVAL;
    513 }
    514 
    515 /* This is the implementation from FreeBSD, with tweaks */
    516 static uint16_t
    517 Fhash(const struct inpcb_hdr *inp_hdr)
    518 {
    519 	MD5_CTX f_ctx;
    520 	uint32_t Ff[4];
    521 	uint32_t secret_f[4];
    522 	uint32_t offset;
    523 	uint16_t soffset[2];
    524 
    525 	cprng_fast(secret_f, sizeof(secret_f));
    526 
    527 	MD5Init(&f_ctx);
    528 	switch (inp_hdr->inph_af) {
    529 #ifdef INET
    530 	case AF_INET: {
    531 		const struct inpcb *inp =
    532 		    (const struct inpcb *)(const void *)inp_hdr;
    533 		MD5Update(&f_ctx, (const u_char *)&inp->inp_laddr,
    534 		    sizeof(inp->inp_laddr));
    535 		MD5Update(&f_ctx, (const u_char *)&inp->inp_faddr,
    536 		    sizeof(inp->inp_faddr));
    537 		MD5Update(&f_ctx, (const u_char *)&inp->inp_fport,
    538 		    sizeof(inp->inp_fport));
    539 		break;
    540 	}
    541 #endif
    542 #ifdef INET6
    543 	case AF_INET6: {
    544 		const struct in6pcb *in6p =
    545 		    (const struct in6pcb *)(const void *)inp_hdr;
    546 		MD5Update(&f_ctx, (const u_char *)&in6p->in6p_laddr,
    547 		    sizeof(in6p->in6p_laddr));
    548 		MD5Update(&f_ctx, (const u_char *)&in6p->in6p_faddr,
    549 		    sizeof(in6p->in6p_faddr));
    550 		MD5Update(&f_ctx, (const u_char *)&in6p->in6p_fport,
    551 		    sizeof(in6p->in6p_fport));
    552 		break;
    553 	}
    554 #endif
    555 	default:
    556 		break;
    557 	}
    558 	MD5Update(&f_ctx, (const u_char *)secret_f, sizeof(secret_f));
    559 	MD5Final((u_char *)&Ff, &f_ctx);
    560 
    561 	offset = (Ff[0] ^ Ff[1]) ^ (Ff[2] ^ Ff[3]);
    562 
    563 	memcpy(&soffset, &offset, sizeof(soffset));
    564 
    565 	return soffset[0] ^ soffset[1];
    566 }
    567 
    568 /*
    569  * Checks whether the tuple is complete. If not, marks the pcb for
    570  * late binding.
    571  */
    572 static bool
    573 iscompletetuple(struct inpcb_hdr *inp_hdr)
    574 {
    575 #ifdef INET6
    576 	struct in6pcb *in6p;
    577 #endif
    578 
    579 	switch (inp_hdr->inph_af) {
    580 #ifdef INET
    581 	case AF_INET: {
    582 		struct inpcb *inp = (struct inpcb *)(void *)inp_hdr;
    583 		if (inp->inp_fport == 0 || in_nullhost(inp->inp_faddr)) {
    584 			DPRINTF("%s fport or faddr missing, delaying port "
    585 			    "to connect/send\n", __func__);
    586 			inp->inp_bindportonsend = true;
    587 			return false;
    588 		} else {
    589 			inp->inp_bindportonsend = false;
    590 		}
    591 		break;
    592 	}
    593 #endif
    594 #ifdef INET6
    595 	case AF_INET6: {
    596 		in6p = (struct in6pcb *)(void *)inp_hdr;
    597 		if (in6p->in6p_fport == 0 || memcmp(&in6p->in6p_faddr,
    598 		    &in6addr_any, sizeof(in6p->in6p_faddr)) == 0) {
    599 			DPRINTF("%s fport or faddr missing, delaying port "
    600 			    "to connect/send\n", __func__);
    601 			in6p->in6p_bindportonsend = true;
    602 			return false;
    603 		} else {
    604 			in6p->in6p_bindportonsend = false;
    605 		}
    606 		break;
    607 	}
    608 #endif
    609 	default:
    610 		DPRINTF("%s incorrect address family\n", __func__);
    611 		return false;
    612 	}
    613 
    614 	return true;
    615 }
    616 
    617 static int
    618 algo_hash(int algo, uint16_t *port, struct inpcb_hdr *inp_hdr,
    619     kauth_cred_t cred)
    620 {
    621 	uint16_t count, num_ephemeral;
    622 	uint16_t mymin, mymax, lastport;
    623 	uint16_t *next_ephemeral;
    624 	uint16_t offset, myport;
    625 	int error;
    626 
    627 	DPRINTF("%s called\n", __func__);
    628 
    629 	error = pcb_getports(inp_hdr, &lastport, &mymin, &mymax,
    630 	    &next_ephemeral, algo);
    631 	if (error)
    632 		return error;
    633 
    634 	if (!iscompletetuple(inp_hdr)) {
    635 		*port = 0;
    636 		return 0;
    637 	}
    638 
    639 	/* Ephemeral port selection function */
    640 	num_ephemeral = mymax - mymin + 1;
    641 
    642 	DPRINTF("num_ephemeral: %d\n", num_ephemeral);
    643 
    644 	offset = Fhash(inp_hdr);
    645 
    646 	count = num_ephemeral;
    647 	do {
    648 		myport = mymin + (*next_ephemeral + offset)
    649 		    % num_ephemeral;
    650 
    651 		(*next_ephemeral)++;
    652 
    653 		if (check_suitable_port(myport, inp_hdr, cred)) {
    654 			*port = myport;
    655 			DPRINTF("%s returning port %d\n", __func__, *port);
    656 			return 0;
    657 		}
    658 		count--;
    659 	} while (count > 0);
    660 
    661 	DPRINTF("%s returning EINVAL\n", __func__);
    662 
    663 	return EINVAL;
    664 }
    665 
    666 static int
    667 algo_doublehash(int algo, uint16_t *port, struct inpcb_hdr *inp_hdr,
    668     kauth_cred_t cred)
    669 {
    670 	uint16_t count, num_ephemeral;
    671 	uint16_t mymin, mymax, lastport;
    672 	uint16_t *next_ephemeral;
    673 	uint16_t offset, myport;
    674 	static uint16_t dhtable[8];
    675 	size_t idx;
    676 	int error;
    677 
    678 	DPRINTF("%s called\n", __func__);
    679 
    680 	error = pcb_getports(inp_hdr, &lastport, &mymin, &mymax,
    681 	    &next_ephemeral, algo);
    682 	if (error)
    683 		return error;
    684 
    685 	if (!iscompletetuple(inp_hdr)) {
    686 		*port = 0;
    687 		return 0;
    688 	}
    689 	/* first time initialization */
    690 	if (dhtable[0] == 0)
    691 		for (size_t i = 0; i < __arraycount(dhtable); i++)
    692 			dhtable[i] = cprng_fast32() & 0xffff;
    693 
    694 	/* Ephemeral port selection function */
    695 	num_ephemeral = mymax - mymin + 1;
    696 	offset = Fhash(inp_hdr);
    697 	idx = Fhash(inp_hdr) % __arraycount(dhtable);	/* G */
    698 	count = num_ephemeral;
    699 
    700 	do {
    701 		myport = mymin + (offset + dhtable[idx])
    702 		    % num_ephemeral;
    703 		dhtable[idx]++;
    704 
    705 		if (check_suitable_port(myport, inp_hdr, cred)) {
    706 			*port = myport;
    707 			DPRINTF("%s returning port %d\n", __func__, *port);
    708 			return 0;
    709 		}
    710 		count--;
    711 
    712 	} while (count > 0);
    713 
    714 	DPRINTF("%s returning EINVAL\n", __func__);
    715 
    716 	return EINVAL;
    717 }
    718 
    719 static int
    720 algo_randinc(int algo, uint16_t *port, struct inpcb_hdr *inp_hdr,
    721     kauth_cred_t cred)
    722 {
    723 	static const uint16_t N = 500;	/* Determines the trade-off */
    724 	uint16_t count, num_ephemeral;
    725 	uint16_t mymin, mymax, lastport;
    726 	uint16_t *next_ephemeral;
    727 	uint16_t myport;
    728 	int error;
    729 
    730 	DPRINTF("%s called\n", __func__);
    731 
    732 	error = pcb_getports(inp_hdr, &lastport, &mymin, &mymax,
    733 	    &next_ephemeral, algo);
    734 	if (error)
    735 		return error;
    736 
    737 	if (*next_ephemeral == 0)
    738 		*next_ephemeral = cprng_fast32() & 0xffff;
    739 
    740 	/* Ephemeral port selection function */
    741 	num_ephemeral = mymax - mymin + 1;
    742 
    743 	count = num_ephemeral;
    744 	do {
    745 		*next_ephemeral = *next_ephemeral +
    746 		    (cprng_fast32() % N) + 1;
    747 		myport = mymin +
    748 		    (*next_ephemeral % num_ephemeral);
    749 
    750 		if (check_suitable_port(myport, inp_hdr, cred)) {
    751 			*port = myport;
    752 			DPRINTF("%s returning port %d\n", __func__, *port);
    753 			return 0;
    754 		}
    755 		count--;
    756 	} while (count > 0);
    757 
    758 	return EINVAL;
    759 }
    760 
    761 /* The generic function called in order to pick a port. */
    762 int
    763 portalgo_randport(uint16_t *port, struct inpcb_hdr *inp_hdr, kauth_cred_t cred)
    764 {
    765 	int algo, error;
    766 	uint16_t lport;
    767 	int default_algo;
    768 
    769 	DPRINTF("%s called\n", __func__);
    770 
    771 	if (inp_hdr->inph_portalgo == PORTALGO_DEFAULT) {
    772 		switch (inp_hdr->inph_af) {
    773 #ifdef INET
    774 		case AF_INET:
    775 			default_algo = inet4_portalgo;
    776 			break;
    777 #endif
    778 #ifdef INET6
    779 		case AF_INET6:
    780 			default_algo = inet6_portalgo;
    781 			break;
    782 #endif
    783 		default:
    784 			return EINVAL;
    785 		}
    786 
    787 		if (default_algo == PORTALGO_DEFAULT)
    788 			algo = PORTALGO_BSD;
    789 		else
    790 			algo = default_algo;
    791 	}
    792 	else /* socket specifies the algorithm */
    793 		algo = inp_hdr->inph_portalgo;
    794 
    795 	KASSERT(algo >= 0);
    796 	KASSERT(algo < NALGOS);
    797 
    798 	switch (inp_hdr->inph_af) {
    799 #ifdef INET
    800 	case AF_INET: {
    801 		char buf[INET_ADDRSTRLEN];
    802 		struct inpcb *inp = (struct inpcb *)(void *)inp_hdr;
    803 		DPRINTF("local addr: %s\n", IN_PRINT(buf, &inp->inp_laddr));
    804 		DPRINTF("local port: %d\n", inp->inp_lport);
    805 		DPRINTF("foreign addr: %s\n", IN_PRINT(buf, &inp->inp_faddr));
    806 		DPRINTF("foreign port: %d\n", inp->inp_fport);
    807 		break;
    808 	}
    809 #endif
    810 #ifdef INET6
    811 	case AF_INET6: {
    812 		char buf[INET6_ADDRSTRLEN];
    813 		struct in6pcb *in6p = (struct in6pcb *)(void *)inp_hdr;
    814 
    815 		DPRINTF("local addr: %s\n", IN6_PRINT(buf, &in6p->in6p_laddr));
    816 		DPRINTF("local port: %d\n", in6p->in6p_lport);
    817 		DPRINTF("foreign addr: %s\n", IN6_PRINT(buf,
    818 		    &in6p->in6p_laddr));
    819 		DPRINTF("foreign port: %d\n", in6p->in6p_fport);
    820 		break;
    821 	}
    822 #endif
    823 	default:
    824 		break;
    825 	}
    826 
    827 	DPRINTF("%s portalgo = %d\n", __func__, algo);
    828 
    829 	error = (*algos[algo].func)(algo, &lport, inp_hdr, cred);
    830 	if (error == 0) {
    831 		*port = lport;
    832 	} else if (error != EAGAIN) {
    833 		uint16_t lastport, mymin, mymax, *pnext_ephemeral;
    834 
    835 		error = pcb_getports(inp_hdr, &lastport, &mymin,
    836 		    &mymax, &pnext_ephemeral, algo);
    837 		if (error)
    838 			return error;
    839 		*port = lastport - 1;
    840 	}
    841 	return error;
    842 }
    843 
    844 /* Sets the algorithm to be used globally */
    845 static int
    846 portalgo_algo_name_select(const char *name, int *algo)
    847 {
    848 	size_t ai;
    849 
    850 	DPRINTF("%s called\n", __func__);
    851 
    852 	for (ai = 0; ai < NALGOS; ai++)
    853 		if (strcmp(algos[ai].name, name) == 0) {
    854 			DPRINTF("%s: found idx %zu\n", __func__, ai);
    855 			*algo = ai;
    856 			return 0;
    857 		}
    858 	return EINVAL;
    859 }
    860 
    861 /* Sets the algorithm to be used by the pcb inp. */
    862 int
    863 portalgo_algo_index_select(struct inpcb_hdr *inp, int algo)
    864 {
    865 
    866 	DPRINTF("%s called with algo %d for pcb %p\n", __func__, algo, inp );
    867 
    868 	if ((algo < 0 || algo >= NALGOS) &&
    869 	    (algo != PORTALGO_DEFAULT))
    870 		return EINVAL;
    871 
    872 	inp->inph_portalgo = algo;
    873 	return 0;
    874 }
    875 
    876 /*
    877  * The sysctl hook that is supposed to check that we are picking one
    878  * of the valid algorithms.
    879  */
    880 static int
    881 sysctl_portalgo_selected(SYSCTLFN_ARGS, int *algo)
    882 {
    883 	struct sysctlnode node;
    884 	int error;
    885 	char newalgo[PORTALGO_MAXLEN];
    886 
    887 	DPRINTF("%s called\n", __func__);
    888 
    889 	strlcpy(newalgo, algos[*algo].name, sizeof(newalgo));
    890 
    891 	node = *rnode;
    892 	node.sysctl_data = newalgo;
    893 	node.sysctl_size = sizeof(newalgo);
    894 
    895 	error = sysctl_lookup(SYSCTLFN_CALL(&node));
    896 
    897 	DPRINTF("newalgo: %s\n", newalgo);
    898 
    899 	if (error || newp == NULL ||
    900 	    strncmp(newalgo, algos[*algo].name, sizeof(newalgo)) == 0)
    901 		return error;
    902 
    903 #ifdef KAUTH_NETWORK_SOCKET_PORT_RANDOMIZE
    904 	if (l != NULL && (error = kauth_authorize_system(l->l_cred,
    905 	    KAUTH_NETWORK_SOCKET, KAUTH_NETWORK_SOCKET_PORT_RANDOMIZE, newname,
    906 	    NULL, NULL)) != 0)
    907 		return error;
    908 #endif
    909 
    910 	mutex_enter(softnet_lock);
    911 	error = portalgo_algo_name_select(newalgo, algo);
    912 	mutex_exit(softnet_lock);
    913 	return error;
    914 }
    915 
    916 static int
    917 sysctl_portalgo_reserve(SYSCTLFN_ARGS, bitmap *bt)
    918 {
    919 	struct sysctlnode node;
    920 	int error;
    921 
    922 	DPRINTF("%s called\n", __func__);
    923 
    924 	node = *rnode;
    925 	node.sysctl_data = bt;
    926 	node.sysctl_size = sizeof(*bt);
    927 
    928 	error = sysctl_lookup(SYSCTLFN_CALL(&node));
    929 
    930 	if (error || newp == NULL)
    931 		return error;
    932 
    933 #ifdef KAUTH_NETWORK_SOCKET_PORT_RESERVE
    934 	if (l != NULL && (error = kauth_authorize_system(l->l_cred,
    935 	    KAUTH_NETWORK_SOCKET, KAUTH_NETWORK_SOCKET_PORT_RESERVE, bt,
    936 	    NULL, NULL)) != 0)
    937 		return error;
    938 #endif
    939 	return error;
    940 }
    941 
    942 #ifdef INET
    943 /*
    944  * The sysctl hook that is supposed to check that we are picking one
    945  * of the valid algorithms.
    946  */
    947 int
    948 sysctl_portalgo_selected4(SYSCTLFN_ARGS)
    949 {
    950 
    951 	return sysctl_portalgo_selected(SYSCTLFN_CALL(rnode), &inet4_portalgo);
    952 }
    953 
    954 int
    955 sysctl_portalgo_reserve4(SYSCTLFN_ARGS)
    956 {
    957 
    958 	return sysctl_portalgo_reserve(SYSCTLFN_CALL(rnode), &inet4_reserve);
    959 }
    960 #endif
    961 
    962 #ifdef INET6
    963 int
    964 sysctl_portalgo_selected6(SYSCTLFN_ARGS)
    965 {
    966 
    967 	return sysctl_portalgo_selected(SYSCTLFN_CALL(rnode), &inet6_portalgo);
    968 }
    969 
    970 int
    971 sysctl_portalgo_reserve6(SYSCTLFN_ARGS)
    972 {
    973 	return sysctl_portalgo_reserve(SYSCTLFN_CALL(rnode), &inet6_reserve);
    974 }
    975 #endif
    976 
    977 /*
    978  * The sysctl hook that returns the available
    979  * algorithms.
    980  */
    981 int
    982 sysctl_portalgo_available(SYSCTLFN_ARGS)
    983 {
    984 	size_t ai, len = 0;
    985 	struct sysctlnode node;
    986 	char availalgo[NALGOS * PORTALGO_MAXLEN];
    987 
    988 	DPRINTF("%s called\n", __func__);
    989 
    990 	availalgo[0] = '\0';
    991 
    992 	for (ai = 0; ai < NALGOS; ai++) {
    993 		len = strlcat(availalgo, algos[ai].name, sizeof(availalgo));
    994 		if (ai < NALGOS - 1)
    995 			strlcat(availalgo, " ", sizeof(availalgo));
    996 	}
    997 
    998 	DPRINTF("available algos: %s\n", availalgo);
    999 
   1000 	node = *rnode;
   1001 	node.sysctl_data = availalgo;
   1002 	node.sysctl_size = len;
   1003 
   1004 	return sysctl_lookup(SYSCTLFN_CALL(&node));
   1005 }
   1006