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