1 /* $NetBSD: portalgo.c,v 1.7 2014/12/02 20:25:47 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.7 2014/12/02 20:25:47 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 #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 increments the port number 412 * by a random amount. 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] = cprng_fast32() & 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 char buf[INET_ADDRSTRLEN]; 800 struct inpcb *inp = (struct inpcb *)(void *)inp_hdr; 801 DPRINTF("local addr: %s\n", IN_PRINT(buf, &inp->inp_laddr)); 802 DPRINTF("local port: %d\n", inp->inp_lport); 803 DPRINTF("foreign addr: %s\n", IN_PRINT(buf, &inp->inp_faddr)); 804 DPRINTF("foreign port: %d\n", inp->inp_fport); 805 break; 806 } 807 #endif 808 #ifdef INET6 809 case AF_INET6: { 810 char buf[INET6_ADDRSTRLEN]; 811 struct in6pcb *in6p = (struct in6pcb *)(void *)inp_hdr; 812 813 DPRINTF("local addr: %s\n", IN6_PRINT(buf, &in6p->in6p_laddr)); 814 DPRINTF("local port: %d\n", in6p->in6p_lport); 815 DPRINTF("foreign addr: %s\n", IN6_PRINT(buf, 816 &in6p->in6p_laddr)); 817 DPRINTF("foreign port: %d\n", in6p->in6p_fport); 818 break; 819 } 820 #endif 821 default: 822 break; 823 } 824 825 DPRINTF("%s portalgo = %d\n", __func__, algo); 826 827 error = (*algos[algo].func)(algo, &lport, inp_hdr, cred); 828 if (error == 0) { 829 *port = lport; 830 } else if (error != EAGAIN) { 831 uint16_t lastport, mymin, mymax, *pnext_ephemeral; 832 833 error = pcb_getports(inp_hdr, &lastport, &mymin, 834 &mymax, &pnext_ephemeral, algo); 835 if (error) 836 return error; 837 *port = lastport - 1; 838 } 839 return error; 840 } 841 842 /* Sets the algorithm to be used globally */ 843 static int 844 portalgo_algo_name_select(const char *name, int *algo) 845 { 846 size_t ai; 847 848 DPRINTF("%s called\n", __func__); 849 850 for (ai = 0; ai < NALGOS; ai++) 851 if (strcmp(algos[ai].name, name) == 0) { 852 DPRINTF("%s: found idx %zu\n", __func__, ai); 853 *algo = ai; 854 return 0; 855 } 856 return EINVAL; 857 } 858 859 /* Sets the algorithm to be used by the pcb inp. */ 860 int 861 portalgo_algo_index_select(struct inpcb_hdr *inp, int algo) 862 { 863 864 DPRINTF("%s called with algo %d for pcb %p\n", __func__, algo, inp ); 865 866 if ((algo < 0 || algo >= NALGOS) && 867 (algo != PORTALGO_DEFAULT)) 868 return EINVAL; 869 870 inp->inph_portalgo = algo; 871 return 0; 872 } 873 874 /* 875 * The sysctl hook that is supposed to check that we are picking one 876 * of the valid algorithms. 877 */ 878 static int 879 sysctl_portalgo_selected(SYSCTLFN_ARGS, int *algo) 880 { 881 struct sysctlnode node; 882 int error; 883 char newalgo[PORTALGO_MAXLEN]; 884 885 DPRINTF("%s called\n", __func__); 886 887 strlcpy(newalgo, algos[*algo].name, sizeof(newalgo)); 888 889 node = *rnode; 890 node.sysctl_data = newalgo; 891 node.sysctl_size = sizeof(newalgo); 892 893 error = sysctl_lookup(SYSCTLFN_CALL(&node)); 894 895 DPRINTF("newalgo: %s\n", newalgo); 896 897 if (error || newp == NULL || 898 strncmp(newalgo, algos[*algo].name, sizeof(newalgo)) == 0) 899 return error; 900 901 #ifdef KAUTH_NETWORK_SOCKET_PORT_RANDOMIZE 902 if (l != NULL && (error = kauth_authorize_system(l->l_cred, 903 KAUTH_NETWORK_SOCKET, KAUTH_NETWORK_SOCKET_PORT_RANDOMIZE, newname, 904 NULL, NULL)) != 0) 905 return error; 906 #endif 907 908 mutex_enter(softnet_lock); 909 error = portalgo_algo_name_select(newalgo, algo); 910 mutex_exit(softnet_lock); 911 return error; 912 } 913 914 static int 915 sysctl_portalgo_reserve(SYSCTLFN_ARGS, bitmap *bt) 916 { 917 struct sysctlnode node; 918 int error; 919 920 DPRINTF("%s called\n", __func__); 921 922 node = *rnode; 923 node.sysctl_data = bt; 924 node.sysctl_size = sizeof(*bt); 925 926 error = sysctl_lookup(SYSCTLFN_CALL(&node)); 927 928 if (error || newp == NULL) 929 return error; 930 931 #ifdef KAUTH_NETWORK_SOCKET_PORT_RESERVE 932 if (l != NULL && (error = kauth_authorize_system(l->l_cred, 933 KAUTH_NETWORK_SOCKET, KAUTH_NETWORK_SOCKET_PORT_RESERVE, bt, 934 NULL, NULL)) != 0) 935 return error; 936 #endif 937 return error; 938 } 939 940 #ifdef INET 941 /* 942 * The sysctl hook that is supposed to check that we are picking one 943 * of the valid algorithms. 944 */ 945 int 946 sysctl_portalgo_selected4(SYSCTLFN_ARGS) 947 { 948 949 return sysctl_portalgo_selected(SYSCTLFN_CALL(rnode), &inet4_portalgo); 950 } 951 952 int 953 sysctl_portalgo_reserve4(SYSCTLFN_ARGS) 954 { 955 956 return sysctl_portalgo_reserve(SYSCTLFN_CALL(rnode), &inet4_reserve); 957 } 958 #endif 959 960 #ifdef INET6 961 int 962 sysctl_portalgo_selected6(SYSCTLFN_ARGS) 963 { 964 965 return sysctl_portalgo_selected(SYSCTLFN_CALL(rnode), &inet6_portalgo); 966 } 967 968 int 969 sysctl_portalgo_reserve6(SYSCTLFN_ARGS) 970 { 971 return sysctl_portalgo_reserve(SYSCTLFN_CALL(rnode), &inet6_reserve); 972 } 973 #endif 974 975 /* 976 * The sysctl hook that returns the available 977 * algorithms. 978 */ 979 int 980 sysctl_portalgo_available(SYSCTLFN_ARGS) 981 { 982 size_t ai, len = 0; 983 struct sysctlnode node; 984 char availalgo[NALGOS * PORTALGO_MAXLEN]; 985 986 DPRINTF("%s called\n", __func__); 987 988 availalgo[0] = '\0'; 989 990 for (ai = 0; ai < NALGOS; ai++) { 991 len = strlcat(availalgo, algos[ai].name, sizeof(availalgo)); 992 if (ai < NALGOS - 1) 993 strlcat(availalgo, " ", sizeof(availalgo)); 994 } 995 996 DPRINTF("available algos: %s\n", availalgo); 997 998 node = *rnode; 999 node.sysctl_data = availalgo; 1000 node.sysctl_size = len; 1001 1002 return sysctl_lookup(SYSCTLFN_CALL(&node)); 1003 } 1004