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