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