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