1 /* $OpenBSD: in6_pcb.c,v 1.124 2023/06/24 20:54:46 bluhm Exp $ */ 2 3 /* 4 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. Neither the name of the project nor the names of its contributors 16 * may be used to endorse or promote products derived from this software 17 * without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 */ 31 32 /* 33 * @(#)COPYRIGHT 1.1 (NRL) 17 January 1995 34 * 35 * NRL grants permission for redistribution and use in source and binary 36 * forms, with or without modification, of the software and documentation 37 * created at NRL provided that the following conditions are met: 38 * 39 * 1. Redistributions of source code must retain the above copyright 40 * notice, this list of conditions and the following disclaimer. 41 * 2. Redistributions in binary form must reproduce the above copyright 42 * notice, this list of conditions and the following disclaimer in the 43 * documentation and/or other materials provided with the distribution. 44 * 3. All advertising materials mentioning features or use of this software 45 * must display the following acknowledgements: 46 * This product includes software developed by the University of 47 * California, Berkeley and its contributors. 48 * This product includes software developed at the Information 49 * Technology Division, US Naval Research Laboratory. 50 * 4. Neither the name of the NRL nor the names of its contributors 51 * may be used to endorse or promote products derived from this software 52 * without specific prior written permission. 53 * 54 * THE SOFTWARE PROVIDED BY NRL IS PROVIDED BY NRL AND CONTRIBUTORS ``AS 55 * IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 56 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 57 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NRL OR 58 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 59 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 60 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 61 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 62 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 63 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 64 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 65 * 66 * The views and conclusions contained in the software and documentation 67 * are those of the authors and should not be interpreted as representing 68 * official policies, either expressed or implied, of the US Naval 69 * Research Laboratory (NRL). 70 */ 71 72 /* 73 * Copyright (c) 1982, 1986, 1990, 1993, 1995 74 * Regents of the University of California. All rights reserved. 75 * 76 * Redistribution and use in source and binary forms, with or without 77 * modification, are permitted provided that the following conditions 78 * are met: 79 * 1. Redistributions of source code must retain the above copyright 80 * notice, this list of conditions and the following disclaimer. 81 * 2. Redistributions in binary form must reproduce the above copyright 82 * notice, this list of conditions and the following disclaimer in the 83 * documentation and/or other materials provided with the distribution. 84 * 3. Neither the name of the University nor the names of its contributors 85 * may be used to endorse or promote products derived from this software 86 * without specific prior written permission. 87 * 88 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 89 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 90 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 91 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 92 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 93 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 94 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 95 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 96 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 97 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 98 * SUCH DAMAGE. 99 * 100 */ 101 102 #include "pf.h" 103 #include "stoeplitz.h" 104 105 #include <sys/param.h> 106 #include <sys/systm.h> 107 #include <sys/mbuf.h> 108 #include <sys/protosw.h> 109 #include <sys/socket.h> 110 #include <sys/socketvar.h> 111 112 #include <net/if.h> 113 #include <net/if_var.h> 114 #include <net/pfvar.h> 115 116 #include <netinet/in.h> 117 #include <netinet/ip.h> 118 #include <netinet/ip_var.h> 119 #include <netinet/in_pcb.h> 120 121 #include <netinet6/in6_var.h> 122 123 #if NSTOEPLITZ > 0 124 #include <net/toeplitz.h> 125 #endif 126 127 const struct in6_addr zeroin6_addr; 128 129 struct inpcb *in6_pcbhash_lookup(struct inpcbtable *, uint64_t, u_int, 130 const struct in6_addr *, u_short, const struct in6_addr *, u_short); 131 132 uint64_t 133 in6_pcbhash(struct inpcbtable *table, u_int rdomain, 134 const struct in6_addr *faddr, u_short fport, 135 const struct in6_addr *laddr, u_short lport) 136 { 137 SIPHASH_CTX ctx; 138 u_int32_t nrdom = htonl(rdomain); 139 140 SipHash24_Init(&ctx, &table->inpt_key); 141 SipHash24_Update(&ctx, &nrdom, sizeof(nrdom)); 142 SipHash24_Update(&ctx, faddr, sizeof(*faddr)); 143 SipHash24_Update(&ctx, &fport, sizeof(fport)); 144 SipHash24_Update(&ctx, laddr, sizeof(*laddr)); 145 SipHash24_Update(&ctx, &lport, sizeof(lport)); 146 return SipHash24_End(&ctx); 147 } 148 149 int 150 in6_pcbaddrisavail(struct inpcb *inp, struct sockaddr_in6 *sin6, int wild, 151 struct proc *p) 152 { 153 struct socket *so = inp->inp_socket; 154 struct inpcbtable *table = inp->inp_table; 155 u_short lport = sin6->sin6_port; 156 int reuseport = (so->so_options & SO_REUSEPORT); 157 158 wild |= INPLOOKUP_IPV6; 159 /* KAME hack: embed scopeid */ 160 if (in6_embedscope(&sin6->sin6_addr, sin6, inp) != 0) 161 return (EINVAL); 162 /* this must be cleared for ifa_ifwithaddr() */ 163 sin6->sin6_scope_id = 0; 164 /* reject IPv4 mapped address, we have no support for it */ 165 if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) 166 return (EADDRNOTAVAIL); 167 168 if (IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) { 169 /* 170 * Treat SO_REUSEADDR as SO_REUSEPORT for multicast; 171 * allow complete duplication of binding if 172 * SO_REUSEPORT is set, or if SO_REUSEADDR is set 173 * and a multicast address is bound on both 174 * new and duplicated sockets. 175 */ 176 if (so->so_options & (SO_REUSEADDR|SO_REUSEPORT)) 177 reuseport = SO_REUSEADDR | SO_REUSEPORT; 178 } else if (!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { 179 struct ifaddr *ifa = NULL; 180 181 sin6->sin6_port = 0; /* 182 * Yechhhh, because of upcoming 183 * call to ifa_ifwithaddr(), which 184 * does bcmp's over the PORTS as 185 * well. (What about flow?) 186 */ 187 sin6->sin6_flowinfo = 0; 188 if (!(so->so_options & SO_BINDANY) && 189 (ifa = ifa_ifwithaddr(sin6tosa(sin6), 190 inp->inp_rtableid)) == NULL) 191 return (EADDRNOTAVAIL); 192 sin6->sin6_port = lport; 193 194 /* 195 * bind to an anycast address might accidentally 196 * cause sending a packet with an anycast source 197 * address, so we forbid it. 198 * 199 * We should allow to bind to a deprecated address, 200 * since the application dare to use it. 201 * But, can we assume that they are careful enough 202 * to check if the address is deprecated or not? 203 * Maybe, as a safeguard, we should have a setsockopt 204 * flag to control the bind(2) behavior against 205 * deprecated addresses (default: forbid bind(2)). 206 */ 207 if (ifa && ifatoia6(ifa)->ia6_flags & (IN6_IFF_ANYCAST| 208 IN6_IFF_TENTATIVE|IN6_IFF_DUPLICATED|IN6_IFF_DETACHED)) 209 return (EADDRNOTAVAIL); 210 } 211 if (lport) { 212 struct inpcb *t; 213 int error = 0; 214 215 if (so->so_euid && !IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) { 216 t = in_pcblookup_local(table, &sin6->sin6_addr, lport, 217 INPLOOKUP_WILDCARD | INPLOOKUP_IPV6, 218 inp->inp_rtableid); 219 if (t && (so->so_euid != t->inp_socket->so_euid)) 220 error = EADDRINUSE; 221 in_pcbunref(t); 222 if (error) 223 return (error); 224 } 225 t = in_pcblookup_local(table, &sin6->sin6_addr, lport, 226 wild, inp->inp_rtableid); 227 if (t && (reuseport & t->inp_socket->so_options) == 0) 228 error = EADDRINUSE; 229 in_pcbunref(t); 230 if (error) 231 return (error); 232 } 233 return (0); 234 } 235 236 /* 237 * Connect from a socket to a specified address. 238 * Both address and port must be specified in argument sin6. 239 * Eventually, flow labels will have to be dealt with here, as well. 240 * 241 * If don't have a local address for this socket yet, 242 * then pick one. 243 */ 244 int 245 in6_pcbconnect(struct inpcb *inp, struct mbuf *nam) 246 { 247 struct in6_addr *in6a = NULL; 248 struct sockaddr_in6 *sin6; 249 struct inpcb *t; 250 int error; 251 struct sockaddr_in6 tmp; 252 253 KASSERT(inp->inp_flags & INP_IPV6); 254 255 if ((error = in6_nam2sin6(nam, &sin6))) 256 return (error); 257 if (sin6->sin6_port == 0) 258 return (EADDRNOTAVAIL); 259 /* reject IPv4 mapped address, we have no support for it */ 260 if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) 261 return (EADDRNOTAVAIL); 262 263 /* protect *sin6 from overwrites */ 264 tmp = *sin6; 265 sin6 = &tmp; 266 267 /* KAME hack: embed scopeid */ 268 if (in6_embedscope(&sin6->sin6_addr, sin6, inp) != 0) 269 return EINVAL; 270 /* this must be cleared for ifa_ifwithaddr() */ 271 sin6->sin6_scope_id = 0; 272 273 /* Source address selection. */ 274 /* 275 * XXX: in6_selectsrc might replace the bound local address 276 * with the address specified by setsockopt(IPV6_PKTINFO). 277 * Is it the intended behavior? 278 */ 279 error = in6_pcbselsrc(&in6a, sin6, inp, inp->inp_outputopts6); 280 if (error) 281 return (error); 282 283 inp->inp_ipv6.ip6_hlim = (u_int8_t)in6_selecthlim(inp); 284 285 t = in6_pcblookup(inp->inp_table, &sin6->sin6_addr, sin6->sin6_port, 286 IN6_IS_ADDR_UNSPECIFIED(&inp->inp_laddr6) ? in6a : &inp->inp_laddr6, 287 inp->inp_lport, inp->inp_rtableid); 288 if (t != NULL) { 289 in_pcbunref(t); 290 return (EADDRINUSE); 291 } 292 293 KASSERT(IN6_IS_ADDR_UNSPECIFIED(&inp->inp_laddr6) || inp->inp_lport); 294 295 if (IN6_IS_ADDR_UNSPECIFIED(&inp->inp_laddr6)) { 296 if (inp->inp_lport == 0) { 297 error = in_pcbbind(inp, NULL, curproc); 298 if (error) 299 return (error); 300 t = in6_pcblookup(inp->inp_table, &sin6->sin6_addr, 301 sin6->sin6_port, in6a, inp->inp_lport, 302 inp->inp_rtableid); 303 if (t != NULL) { 304 inp->inp_lport = 0; 305 in_pcbunref(t); 306 return (EADDRINUSE); 307 } 308 } 309 inp->inp_laddr6 = *in6a; 310 } 311 inp->inp_faddr6 = sin6->sin6_addr; 312 inp->inp_fport = sin6->sin6_port; 313 inp->inp_flowinfo &= ~IPV6_FLOWLABEL_MASK; 314 if (ip6_auto_flowlabel) 315 inp->inp_flowinfo |= 316 (htonl(ip6_randomflowlabel()) & IPV6_FLOWLABEL_MASK); 317 #if NSTOEPLITZ > 0 318 inp->inp_flowid = stoeplitz_ip6port(&inp->inp_faddr6, 319 &inp->inp_laddr6, inp->inp_fport, inp->inp_lport); 320 #endif 321 in_pcbrehash(inp); 322 return (0); 323 } 324 325 /* 326 * Get the local address/port, and put it in a sockaddr_in6. 327 * This services the getsockname(2) call. 328 */ 329 void 330 in6_setsockaddr(struct inpcb *inp, struct mbuf *nam) 331 { 332 struct sockaddr_in6 *sin6; 333 334 nam->m_len = sizeof(struct sockaddr_in6); 335 sin6 = mtod(nam,struct sockaddr_in6 *); 336 337 bzero ((caddr_t)sin6,sizeof(struct sockaddr_in6)); 338 sin6->sin6_family = AF_INET6; 339 sin6->sin6_len = sizeof(struct sockaddr_in6); 340 sin6->sin6_port = inp->inp_lport; 341 sin6->sin6_addr = inp->inp_laddr6; 342 /* KAME hack: recover scopeid */ 343 in6_recoverscope(sin6, &inp->inp_laddr6); 344 } 345 346 /* 347 * Get the foreign address/port, and put it in a sockaddr_in6. 348 * This services the getpeername(2) call. 349 */ 350 void 351 in6_setpeeraddr(struct inpcb *inp, struct mbuf *nam) 352 { 353 struct sockaddr_in6 *sin6; 354 355 nam->m_len = sizeof(struct sockaddr_in6); 356 sin6 = mtod(nam,struct sockaddr_in6 *); 357 358 bzero ((caddr_t)sin6,sizeof(struct sockaddr_in6)); 359 sin6->sin6_family = AF_INET6; 360 sin6->sin6_len = sizeof(struct sockaddr_in6); 361 sin6->sin6_port = inp->inp_fport; 362 sin6->sin6_addr = inp->inp_faddr6; 363 /* KAME hack: recover scopeid */ 364 in6_recoverscope(sin6, &inp->inp_faddr6); 365 } 366 367 int 368 in6_sockaddr(struct socket *so, struct mbuf *nam) 369 { 370 struct inpcb *in6p; 371 372 in6p = sotoinpcb(so); 373 in6_setsockaddr(in6p, nam); 374 375 return (0); 376 } 377 378 int 379 in6_peeraddr(struct socket *so, struct mbuf *nam) 380 { 381 struct inpcb *in6p; 382 383 in6p = sotoinpcb(so); 384 in6_setpeeraddr(in6p, nam); 385 386 return (0); 387 } 388 389 /* 390 * Pass some notification to all connections of a protocol 391 * associated with address dst. The local address and/or port numbers 392 * may be specified to limit the search. The "usual action" will be 393 * taken, depending on the ctlinput cmd. The caller must filter any 394 * cmds that are uninteresting (e.g., no error in the map). 395 * Call the protocol specific routine (if any) to report 396 * any errors for each matching socket. 397 * 398 * Also perform input-side security policy check 399 * once PCB to be notified has been located. 400 */ 401 void 402 in6_pcbnotify(struct inpcbtable *table, struct sockaddr_in6 *dst, 403 uint fport_arg, const struct sockaddr_in6 *src, uint lport_arg, 404 u_int rtable, int cmd, void *cmdarg, void (*notify)(struct inpcb *, int)) 405 { 406 SIMPLEQ_HEAD(, inpcb) inpcblist; 407 struct inpcb *inp; 408 u_short fport = fport_arg, lport = lport_arg; 409 struct sockaddr_in6 sa6_src; 410 int errno; 411 u_int32_t flowinfo; 412 u_int rdomain; 413 414 if ((unsigned)cmd >= PRC_NCMDS) 415 return; 416 417 if (IN6_IS_ADDR_UNSPECIFIED(&dst->sin6_addr)) 418 return; 419 if (IN6_IS_ADDR_V4MAPPED(&dst->sin6_addr)) { 420 #ifdef DIAGNOSTIC 421 printf("%s: Huh? Thought we never got " 422 "called with mapped!\n", __func__); 423 #endif 424 return; 425 } 426 427 /* 428 * note that src can be NULL when we get notify by local fragmentation. 429 */ 430 sa6_src = (src == NULL) ? sa6_any : *src; 431 flowinfo = sa6_src.sin6_flowinfo; 432 433 /* 434 * Redirects go to all references to the destination, 435 * and use in_rtchange to invalidate the route cache. 436 * Dead host indications: also use in_rtchange to invalidate 437 * the cache, and deliver the error to all the sockets. 438 * Otherwise, if we have knowledge of the local port and address, 439 * deliver only to that socket. 440 */ 441 if (PRC_IS_REDIRECT(cmd) || cmd == PRC_HOSTDEAD) { 442 fport = 0; 443 lport = 0; 444 sa6_src.sin6_addr = in6addr_any; 445 446 if (cmd != PRC_HOSTDEAD) 447 notify = in_rtchange; 448 } 449 errno = inet6ctlerrmap[cmd]; 450 if (notify == NULL) 451 return; 452 453 SIMPLEQ_INIT(&inpcblist); 454 rdomain = rtable_l2(rtable); 455 rw_enter_write(&table->inpt_notify); 456 mtx_enter(&table->inpt_mtx); 457 TAILQ_FOREACH(inp, &table->inpt_queue, inp_queue) { 458 if ((inp->inp_flags & INP_IPV6) == 0) 459 continue; 460 461 /* 462 * Under the following condition, notify of redirects 463 * to the pcb, without making address matches against inpcb. 464 * - redirect notification is arrived. 465 * - the inpcb is unconnected. 466 * - the inpcb is caching !RTF_HOST routing entry. 467 * - the ICMPv6 notification is from the gateway cached in the 468 * inpcb. i.e. ICMPv6 notification is from nexthop gateway 469 * the inpcb used very recently. 470 * 471 * This is to improve interaction between netbsd/openbsd 472 * redirect handling code, and inpcb route cache code. 473 * without the clause, !RTF_HOST routing entry (which carries 474 * gateway used by inpcb right before the ICMPv6 redirect) 475 * will be cached forever in unconnected inpcb. 476 * 477 * There still is a question regarding to what is TRT: 478 * - On bsdi/freebsd, RTF_HOST (cloned) routing entry will be 479 * generated on packet output. inpcb will always cache 480 * RTF_HOST routing entry so there's no need for the clause 481 * (ICMPv6 redirect will update RTF_HOST routing entry, 482 * and inpcb is caching it already). 483 * However, bsdi/freebsd are vulnerable to local DoS attacks 484 * due to the cloned routing entries. 485 * - Specwise, "destination cache" is mentioned in RFC2461. 486 * Jinmei says that it implies bsdi/freebsd behavior, itojun 487 * is not really convinced. 488 * - Having hiwat/lowat on # of cloned host route (redirect/ 489 * pmtud) may be a good idea. netbsd/openbsd has it. see 490 * icmp6_mtudisc_update(). 491 */ 492 if ((PRC_IS_REDIRECT(cmd) || cmd == PRC_HOSTDEAD) && 493 IN6_IS_ADDR_UNSPECIFIED(&inp->inp_laddr6) && 494 inp->inp_route.ro_rt && 495 !(inp->inp_route.ro_rt->rt_flags & RTF_HOST)) { 496 struct sockaddr_in6 *dst6; 497 498 dst6 = satosin6(&inp->inp_route.ro_dst); 499 if (IN6_ARE_ADDR_EQUAL(&dst6->sin6_addr, 500 &dst->sin6_addr)) 501 goto do_notify; 502 } 503 504 /* 505 * Detect if we should notify the error. If no source and 506 * destination ports are specified, but non-zero flowinfo and 507 * local address match, notify the error. This is the case 508 * when the error is delivered with an encrypted buffer 509 * by ESP. Otherwise, just compare addresses and ports 510 * as usual. 511 */ 512 if (lport == 0 && fport == 0 && flowinfo && 513 inp->inp_socket != NULL && 514 flowinfo == (inp->inp_flowinfo & IPV6_FLOWLABEL_MASK) && 515 IN6_ARE_ADDR_EQUAL(&inp->inp_laddr6, &sa6_src.sin6_addr)) 516 goto do_notify; 517 else if (!IN6_ARE_ADDR_EQUAL(&inp->inp_faddr6, 518 &dst->sin6_addr) || 519 rtable_l2(inp->inp_rtableid) != rdomain || 520 inp->inp_socket == NULL || 521 (lport && inp->inp_lport != lport) || 522 (!IN6_IS_ADDR_UNSPECIFIED(&sa6_src.sin6_addr) && 523 !IN6_ARE_ADDR_EQUAL(&inp->inp_laddr6, 524 &sa6_src.sin6_addr)) || 525 (fport && inp->inp_fport != fport)) { 526 continue; 527 } 528 do_notify: 529 in_pcbref(inp); 530 SIMPLEQ_INSERT_TAIL(&inpcblist, inp, inp_notify); 531 } 532 mtx_leave(&table->inpt_mtx); 533 534 while ((inp = SIMPLEQ_FIRST(&inpcblist)) != NULL) { 535 SIMPLEQ_REMOVE_HEAD(&inpcblist, inp_notify); 536 (*notify)(inp, errno); 537 in_pcbunref(inp); 538 } 539 rw_exit_write(&table->inpt_notify); 540 } 541 542 struct inpcb * 543 in6_pcbhash_lookup(struct inpcbtable *table, uint64_t hash, u_int rdomain, 544 const struct in6_addr *faddr, u_short fport, 545 const struct in6_addr *laddr, u_short lport) 546 { 547 struct inpcbhead *head; 548 struct inpcb *inp; 549 550 NET_ASSERT_LOCKED(); 551 MUTEX_ASSERT_LOCKED(&table->inpt_mtx); 552 553 head = &table->inpt_hashtbl[hash & table->inpt_mask]; 554 LIST_FOREACH(inp, head, inp_hash) { 555 if (!ISSET(inp->inp_flags, INP_IPV6)) 556 continue; 557 if (inp->inp_fport == fport && inp->inp_lport == lport && 558 IN6_ARE_ADDR_EQUAL(&inp->inp_faddr6, faddr) && 559 IN6_ARE_ADDR_EQUAL(&inp->inp_laddr6, laddr) && 560 rtable_l2(inp->inp_rtableid) == rdomain) { 561 break; 562 } 563 } 564 if (inp != NULL) { 565 /* 566 * Move this PCB to the head of hash chain so that 567 * repeated accesses are quicker. This is analogous to 568 * the historic single-entry PCB cache. 569 */ 570 if (inp != LIST_FIRST(head)) { 571 LIST_REMOVE(inp, inp_hash); 572 LIST_INSERT_HEAD(head, inp, inp_hash); 573 } 574 } 575 return (inp); 576 } 577 578 struct inpcb * 579 in6_pcblookup(struct inpcbtable *table, const struct in6_addr *faddr, 580 u_int fport, const struct in6_addr *laddr, u_int lport, u_int rtable) 581 { 582 struct inpcb *inp; 583 uint64_t hash; 584 u_int rdomain; 585 586 rdomain = rtable_l2(rtable); 587 hash = in6_pcbhash(table, rdomain, faddr, fport, laddr, lport); 588 589 mtx_enter(&table->inpt_mtx); 590 inp = in6_pcbhash_lookup(table, hash, rdomain, 591 faddr, fport, laddr, lport); 592 in_pcbref(inp); 593 mtx_leave(&table->inpt_mtx); 594 595 #ifdef DIAGNOSTIC 596 if (inp == NULL && in_pcbnotifymiss) { 597 printf("%s: faddr= fport=%d laddr= lport=%d rdom=%u\n", 598 __func__, ntohs(fport), ntohs(lport), rdomain); 599 } 600 #endif 601 return (inp); 602 } 603 604 struct inpcb * 605 in6_pcblookup_listen(struct inpcbtable *table, struct in6_addr *laddr, 606 u_int lport, struct mbuf *m, u_int rtable) 607 { 608 const struct in6_addr *key1, *key2; 609 struct inpcb *inp; 610 uint64_t hash; 611 u_int rdomain; 612 613 key1 = laddr; 614 key2 = &zeroin6_addr; 615 #if NPF > 0 616 if (m && m->m_pkthdr.pf.flags & PF_TAG_DIVERTED) { 617 struct pf_divert *divert; 618 619 divert = pf_find_divert(m); 620 KASSERT(divert != NULL); 621 switch (divert->type) { 622 case PF_DIVERT_TO: 623 key1 = key2 = &divert->addr.v6; 624 lport = divert->port; 625 break; 626 case PF_DIVERT_REPLY: 627 return (NULL); 628 default: 629 panic("%s: unknown divert type %d, mbuf %p, divert %p", 630 __func__, divert->type, m, divert); 631 } 632 } else if (m && m->m_pkthdr.pf.flags & PF_TAG_TRANSLATE_LOCALHOST) { 633 /* 634 * Redirected connections should not be treated the same 635 * as connections directed to ::1 since localhost 636 * can only be accessed from the host itself. 637 */ 638 key1 = &zeroin6_addr; 639 key2 = laddr; 640 } 641 #endif 642 643 rdomain = rtable_l2(rtable); 644 hash = in6_pcbhash(table, rdomain, &zeroin6_addr, 0, key1, lport); 645 646 mtx_enter(&table->inpt_mtx); 647 inp = in6_pcbhash_lookup(table, hash, rdomain, 648 &zeroin6_addr, 0, key1, lport); 649 if (inp == NULL && ! IN6_ARE_ADDR_EQUAL(key1, key2)) { 650 hash = in6_pcbhash(table, rdomain, 651 &zeroin6_addr, 0, key2, lport); 652 inp = in6_pcbhash_lookup(table, hash, rdomain, 653 &zeroin6_addr, 0, key2, lport); 654 } 655 in_pcbref(inp); 656 mtx_leave(&table->inpt_mtx); 657 658 #ifdef DIAGNOSTIC 659 if (inp == NULL && in_pcbnotifymiss) { 660 printf("%s: laddr= lport=%d rdom=%u\n", 661 __func__, ntohs(lport), rdomain); 662 } 663 #endif 664 return (inp); 665 } 666