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