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