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