1*8ee0399bSmvs /* $OpenBSD: in6_pcb.c,v 1.146 2024/12/21 00:10:04 mvs Exp $ */ 2a7a563d1Sitojun 3a7a563d1Sitojun /* 4a7a563d1Sitojun * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 5a7a563d1Sitojun * All rights reserved. 6a7a563d1Sitojun * 7a7a563d1Sitojun * Redistribution and use in source and binary forms, with or without 8a7a563d1Sitojun * modification, are permitted provided that the following conditions 9a7a563d1Sitojun * are met: 10a7a563d1Sitojun * 1. Redistributions of source code must retain the above copyright 11a7a563d1Sitojun * notice, this list of conditions and the following disclaimer. 12a7a563d1Sitojun * 2. Redistributions in binary form must reproduce the above copyright 13a7a563d1Sitojun * notice, this list of conditions and the following disclaimer in the 14a7a563d1Sitojun * documentation and/or other materials provided with the distribution. 15a7a563d1Sitojun * 3. Neither the name of the project nor the names of its contributors 16a7a563d1Sitojun * may be used to endorse or promote products derived from this software 17a7a563d1Sitojun * without specific prior written permission. 18a7a563d1Sitojun * 19a7a563d1Sitojun * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 20a7a563d1Sitojun * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21a7a563d1Sitojun * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22a7a563d1Sitojun * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 23a7a563d1Sitojun * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24a7a563d1Sitojun * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25a7a563d1Sitojun * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26a7a563d1Sitojun * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27a7a563d1Sitojun * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28a7a563d1Sitojun * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29a7a563d1Sitojun * SUCH DAMAGE. 30a7a563d1Sitojun */ 313d09c762Sangelos 32d3b325d0Sderaadt /* 336cdd78adSderaadt * @(#)COPYRIGHT 1.1 (NRL) 17 January 1995 346cdd78adSderaadt * 356cdd78adSderaadt * NRL grants permission for redistribution and use in source and binary 366cdd78adSderaadt * forms, with or without modification, of the software and documentation 376cdd78adSderaadt * created at NRL provided that the following conditions are met: 386cdd78adSderaadt * 396cdd78adSderaadt * 1. Redistributions of source code must retain the above copyright 406cdd78adSderaadt * notice, this list of conditions and the following disclaimer. 416cdd78adSderaadt * 2. Redistributions in binary form must reproduce the above copyright 426cdd78adSderaadt * notice, this list of conditions and the following disclaimer in the 436cdd78adSderaadt * documentation and/or other materials provided with the distribution. 446cdd78adSderaadt * 3. All advertising materials mentioning features or use of this software 456cdd78adSderaadt * must display the following acknowledgements: 466cdd78adSderaadt * This product includes software developed by the University of 476cdd78adSderaadt * California, Berkeley and its contributors. 486cdd78adSderaadt * This product includes software developed at the Information 496cdd78adSderaadt * Technology Division, US Naval Research Laboratory. 506cdd78adSderaadt * 4. Neither the name of the NRL nor the names of its contributors 516cdd78adSderaadt * may be used to endorse or promote products derived from this software 526cdd78adSderaadt * without specific prior written permission. 536cdd78adSderaadt * 546cdd78adSderaadt * THE SOFTWARE PROVIDED BY NRL IS PROVIDED BY NRL AND CONTRIBUTORS ``AS 556cdd78adSderaadt * IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 566cdd78adSderaadt * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 576cdd78adSderaadt * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NRL OR 586cdd78adSderaadt * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 596cdd78adSderaadt * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 606cdd78adSderaadt * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 616cdd78adSderaadt * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 626cdd78adSderaadt * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 636cdd78adSderaadt * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 646cdd78adSderaadt * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 656cdd78adSderaadt * 666cdd78adSderaadt * The views and conclusions contained in the software and documentation 676cdd78adSderaadt * are those of the authors and should not be interpreted as representing 686cdd78adSderaadt * official policies, either expressed or implied, of the US Naval 696cdd78adSderaadt * Research Laboratory (NRL). 70d3b325d0Sderaadt */ 716cdd78adSderaadt 72d3b325d0Sderaadt /* 73d3b325d0Sderaadt * Copyright (c) 1982, 1986, 1990, 1993, 1995 74d3b325d0Sderaadt * Regents of the University of California. All rights reserved. 75d3b325d0Sderaadt * 76d3b325d0Sderaadt * Redistribution and use in source and binary forms, with or without 77d3b325d0Sderaadt * modification, are permitted provided that the following conditions 78d3b325d0Sderaadt * are met: 79d3b325d0Sderaadt * 1. Redistributions of source code must retain the above copyright 80d3b325d0Sderaadt * notice, this list of conditions and the following disclaimer. 81d3b325d0Sderaadt * 2. Redistributions in binary form must reproduce the above copyright 82d3b325d0Sderaadt * notice, this list of conditions and the following disclaimer in the 83d3b325d0Sderaadt * documentation and/or other materials provided with the distribution. 8429295d1cSmillert * 3. Neither the name of the University nor the names of its contributors 85d3b325d0Sderaadt * may be used to endorse or promote products derived from this software 86d3b325d0Sderaadt * without specific prior written permission. 87d3b325d0Sderaadt * 88d3b325d0Sderaadt * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 89d3b325d0Sderaadt * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 90d3b325d0Sderaadt * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 91d3b325d0Sderaadt * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 92d3b325d0Sderaadt * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 93d3b325d0Sderaadt * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 94d3b325d0Sderaadt * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 95d3b325d0Sderaadt * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 96d3b325d0Sderaadt * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 97d3b325d0Sderaadt * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 98d3b325d0Sderaadt * SUCH DAMAGE. 99d3b325d0Sderaadt * 100d3b325d0Sderaadt */ 101d3b325d0Sderaadt 102531c7ccdSbluhm #include "pf.h" 103aa794c2bSdlg #include "stoeplitz.h" 104531c7ccdSbluhm 105d3b325d0Sderaadt #include <sys/param.h> 106d3b325d0Sderaadt #include <sys/systm.h> 107d3b325d0Sderaadt #include <sys/mbuf.h> 108d3b325d0Sderaadt #include <sys/protosw.h> 109d3b325d0Sderaadt #include <sys/socket.h> 110d3b325d0Sderaadt #include <sys/socketvar.h> 111d3b325d0Sderaadt 112d3b325d0Sderaadt #include <net/if.h> 1130deb6685Smpi #include <net/if_var.h> 114531c7ccdSbluhm #include <net/pfvar.h> 115d3b325d0Sderaadt 116d3b325d0Sderaadt #include <netinet/in.h> 11794c0e2bdSbluhm #include <netinet6/in6_var.h> 118d3b325d0Sderaadt #include <netinet/ip.h> 11996c82063Smpi #include <netinet/ip_var.h> 120940d25acSbluhm #include <netinet6/ip6_var.h> 121531c7ccdSbluhm #include <netinet/in_pcb.h> 122d3b325d0Sderaadt 123aa794c2bSdlg #if NSTOEPLITZ > 0 124aa794c2bSdlg #include <net/toeplitz.h> 125aa794c2bSdlg #endif 126aa794c2bSdlg 1272709209dSbluhm const struct in6_addr zeroin6_addr; 128d3b325d0Sderaadt 1298bde4b77Sbluhm struct inpcb *in6_pcbhash_lookup(struct inpcbtable *, uint64_t, u_int, 130a6b8fd29Sbluhm const struct in6_addr *, u_short, const struct in6_addr *, u_short); 131a6b8fd29Sbluhm 1326426d56dSbluhm struct inpcb * in6_pcblookup_lock(struct inpcbtable *, const struct in6_addr *, 1336426d56dSbluhm u_int, const struct in6_addr *, u_int, u_int, int); 1346426d56dSbluhm 1358bde4b77Sbluhm uint64_t 136a6b8fd29Sbluhm in6_pcbhash(struct inpcbtable *table, u_int rdomain, 137531c7ccdSbluhm const struct in6_addr *faddr, u_short fport, 138531c7ccdSbluhm const struct in6_addr *laddr, u_short lport) 139531c7ccdSbluhm { 140531c7ccdSbluhm SIPHASH_CTX ctx; 141a6b8fd29Sbluhm u_int32_t nrdom = htonl(rdomain); 142531c7ccdSbluhm 143531c7ccdSbluhm SipHash24_Init(&ctx, &table->inpt_key); 144531c7ccdSbluhm SipHash24_Update(&ctx, &nrdom, sizeof(nrdom)); 145531c7ccdSbluhm SipHash24_Update(&ctx, faddr, sizeof(*faddr)); 146531c7ccdSbluhm SipHash24_Update(&ctx, &fport, sizeof(fport)); 147531c7ccdSbluhm SipHash24_Update(&ctx, laddr, sizeof(*laddr)); 148531c7ccdSbluhm SipHash24_Update(&ctx, &lport, sizeof(lport)); 1498bde4b77Sbluhm return SipHash24_End(&ctx); 150531c7ccdSbluhm } 151531c7ccdSbluhm 152b23e58bbSvgross int 153ad6c4bdcSbluhm in6_pcbaddrisavail_lock(const struct inpcb *inp, struct sockaddr_in6 *sin6, 154ad6c4bdcSbluhm int wild, struct proc *p, int lock) 155b23e58bbSvgross { 156b23e58bbSvgross struct socket *so = inp->inp_socket; 157b23e58bbSvgross struct inpcbtable *table = inp->inp_table; 158b23e58bbSvgross u_short lport = sin6->sin6_port; 159b23e58bbSvgross int reuseport = (so->so_options & SO_REUSEPORT); 160b23e58bbSvgross 161b23e58bbSvgross wild |= INPLOOKUP_IPV6; 162efbbc66dSitojun /* KAME hack: embed scopeid */ 163952c6363Sbluhm if (in6_embedscope(&sin6->sin6_addr, sin6, 164952c6363Sbluhm inp->inp_outputopts6, inp->inp_moptions6) != 0) 165b23e58bbSvgross return (EINVAL); 166efbbc66dSitojun /* this must be cleared for ifa_ifwithaddr() */ 167efbbc66dSitojun sin6->sin6_scope_id = 0; 16890687512Sitojun /* reject IPv4 mapped address, we have no support for it */ 16990687512Sitojun if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) 170b23e58bbSvgross return (EADDRNOTAVAIL); 17190687512Sitojun 17252527073Sitojun if (IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) { 173d3b325d0Sderaadt /* 174d3b325d0Sderaadt * Treat SO_REUSEADDR as SO_REUSEPORT for multicast; 175d3b325d0Sderaadt * allow complete duplication of binding if 176d3b325d0Sderaadt * SO_REUSEPORT is set, or if SO_REUSEADDR is set 177d3b325d0Sderaadt * and a multicast address is bound on both 178d3b325d0Sderaadt * new and duplicated sockets. 179d3b325d0Sderaadt */ 18079e2bfeeSvgross if (so->so_options & (SO_REUSEADDR|SO_REUSEPORT)) 181d3b325d0Sderaadt reuseport = SO_REUSEADDR | SO_REUSEPORT; 182a81bf0a7Sitojun } else if (!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { 1833e0567a8Sbluhm struct ifaddr *ifa = NULL; 184a81bf0a7Sitojun 185a81bf0a7Sitojun sin6->sin6_port = 0; /* 186a81bf0a7Sitojun * Yechhhh, because of upcoming 187a81bf0a7Sitojun * call to ifa_ifwithaddr(), which 188a81bf0a7Sitojun * does bcmp's over the PORTS as 189a81bf0a7Sitojun * well. (What about flow?) 190a81bf0a7Sitojun */ 191a81bf0a7Sitojun sin6->sin6_flowinfo = 0; 19261cc8529Smarkus if (!(so->so_options & SO_BINDANY) && 1933e0567a8Sbluhm (ifa = ifa_ifwithaddr(sin6tosa(sin6), 194ba79ddd5Ssperreault inp->inp_rtableid)) == NULL) 195b23e58bbSvgross return (EADDRNOTAVAIL); 196b23e58bbSvgross sin6->sin6_port = lport; 197a81bf0a7Sitojun 198a81bf0a7Sitojun /* 19947811ac7Sitojun * bind to an anycast address might accidentally 20047811ac7Sitojun * cause sending a packet with an anycast source 20147811ac7Sitojun * address, so we forbid it. 20247811ac7Sitojun * 20347811ac7Sitojun * We should allow to bind to a deprecated address, 20447811ac7Sitojun * since the application dare to use it. 20547811ac7Sitojun * But, can we assume that they are careful enough 20647811ac7Sitojun * to check if the address is deprecated or not? 20747811ac7Sitojun * Maybe, as a safeguard, we should have a setsockopt 20847811ac7Sitojun * flag to control the bind(2) behavior against 20947811ac7Sitojun * deprecated addresses (default: forbid bind(2)). 210a81bf0a7Sitojun */ 211b2ea68e0Smpi if (ifa && ifatoia6(ifa)->ia6_flags & (IN6_IFF_ANYCAST| 212b2ea68e0Smpi IN6_IFF_TENTATIVE|IN6_IFF_DUPLICATED|IN6_IFF_DETACHED)) 213a81bf0a7Sitojun return (EADDRNOTAVAIL); 21490687512Sitojun } 21552527073Sitojun if (lport) { 216d3b325d0Sderaadt struct inpcb *t; 2179e8a1cdfSbluhm int error = 0; 218d3b325d0Sderaadt 21975456467Sclaudio if (so->so_euid && !IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) { 2206426d56dSbluhm t = in_pcblookup_local_lock(table, &sin6->sin6_addr, 2216426d56dSbluhm lport, INPLOOKUP_WILDCARD | INPLOOKUP_IPV6, 2226426d56dSbluhm inp->inp_rtableid, lock); 223b23e58bbSvgross if (t && (so->so_euid != t->inp_socket->so_euid)) 2249e8a1cdfSbluhm error = EADDRINUSE; 2256426d56dSbluhm if (lock == IN_PCBLOCK_GRAB) 2269e8a1cdfSbluhm in_pcbunref(t); 2279e8a1cdfSbluhm if (error) 2289e8a1cdfSbluhm return (error); 2295b750a1dSvgross } 2306426d56dSbluhm t = in_pcblookup_local_lock(table, &sin6->sin6_addr, lport, 2316426d56dSbluhm wild, inp->inp_rtableid, lock); 232d3b325d0Sderaadt if (t && (reuseport & t->inp_socket->so_options) == 0) 2339e8a1cdfSbluhm error = EADDRINUSE; 2346426d56dSbluhm if (lock == IN_PCBLOCK_GRAB) 2359e8a1cdfSbluhm in_pcbunref(t); 2369e8a1cdfSbluhm if (error) 2379e8a1cdfSbluhm return (error); 238d3b325d0Sderaadt } 239b23e58bbSvgross return (0); 240d3b325d0Sderaadt } 241d3b325d0Sderaadt 2426426d56dSbluhm int 243ad6c4bdcSbluhm in6_pcbaddrisavail(const struct inpcb *inp, struct sockaddr_in6 *sin6, 244ad6c4bdcSbluhm int wild, struct proc *p) 2456426d56dSbluhm { 2466426d56dSbluhm return in6_pcbaddrisavail_lock(inp, sin6, wild, p, IN_PCBLOCK_GRAB); 2476426d56dSbluhm } 2486426d56dSbluhm 24952527073Sitojun /* 250d3b325d0Sderaadt * Connect from a socket to a specified address. 251d3b325d0Sderaadt * Both address and port must be specified in argument sin6. 252d3b325d0Sderaadt * Eventually, flow labels will have to be dealt with here, as well. 253d3b325d0Sderaadt * 254d3b325d0Sderaadt * If don't have a local address for this socket yet, 255d3b325d0Sderaadt * then pick one. 25652527073Sitojun */ 257d3b325d0Sderaadt int 258ee37ea65Smcbride in6_pcbconnect(struct inpcb *inp, struct mbuf *nam) 259287546eaSitojun { 260cd28665aSbluhm struct inpcbtable *table = inp->inp_table; 261cff23a6bSbluhm const struct in6_addr *in6a; 262b2a698eaSbluhm struct sockaddr_in6 *sin6; 2639e8a1cdfSbluhm struct inpcb *t; 264b2a698eaSbluhm int error; 265efbbc66dSitojun struct sockaddr_in6 tmp; 266287546eaSitojun 267ab485656Sbluhm KASSERT(ISSET(inp->inp_flags, INP_IPV6)); 2689cff7dccSbluhm 269b2a698eaSbluhm if ((error = in6_nam2sin6(nam, &sin6))) 270b2a698eaSbluhm return (error); 271287546eaSitojun if (sin6->sin6_port == 0) 272287546eaSitojun return (EADDRNOTAVAIL); 27390687512Sitojun /* reject IPv4 mapped address, we have no support for it */ 27490687512Sitojun if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) 2756b081901Sbluhm return (EADDRNOTAVAIL); 276287546eaSitojun 277efbbc66dSitojun /* protect *sin6 from overwrites */ 278efbbc66dSitojun tmp = *sin6; 279efbbc66dSitojun sin6 = &tmp; 280efbbc66dSitojun 281efbbc66dSitojun /* KAME hack: embed scopeid */ 282952c6363Sbluhm if (in6_embedscope(&sin6->sin6_addr, sin6, 283952c6363Sbluhm inp->inp_outputopts6, inp->inp_moptions6) != 0) 284952c6363Sbluhm return (EINVAL); 285efbbc66dSitojun /* this must be cleared for ifa_ifwithaddr() */ 286efbbc66dSitojun sin6->sin6_scope_id = 0; 287287546eaSitojun 288287546eaSitojun /* Source address selection. */ 289287546eaSitojun /* 290287546eaSitojun * XXX: in6_selectsrc might replace the bound local address 291287546eaSitojun * with the address specified by setsockopt(IPV6_PKTINFO). 292287546eaSitojun * Is it the intended behavior? 293287546eaSitojun */ 2943e4bd4b4Svgross error = in6_pcbselsrc(&in6a, sin6, inp, inp->inp_outputopts6); 2950039ae51Sjca if (error) 296287546eaSitojun return (error); 297c194eafeSitojun 29893e31651Smpi inp->inp_ipv6.ip6_hlim = (u_int8_t)in6_selecthlim(inp); 299287546eaSitojun 3006426d56dSbluhm /* keep lookup, modification, and rehash in sync */ 3016426d56dSbluhm mtx_enter(&table->inpt_mtx); 3026426d56dSbluhm 3036426d56dSbluhm t = in6_pcblookup_lock(inp->inp_table, &sin6->sin6_addr, 3046426d56dSbluhm sin6->sin6_port, 30552527073Sitojun IN6_IS_ADDR_UNSPECIFIED(&inp->inp_laddr6) ? in6a : &inp->inp_laddr6, 3066426d56dSbluhm inp->inp_lport, inp->inp_rtableid, IN_PCBLOCK_HOLD); 3079e8a1cdfSbluhm if (t != NULL) { 3086426d56dSbluhm mtx_leave(&table->inpt_mtx); 309287546eaSitojun return (EADDRINUSE); 31052527073Sitojun } 3115bf9318fSmpi 3125bf9318fSmpi KASSERT(IN6_IS_ADDR_UNSPECIFIED(&inp->inp_laddr6) || inp->inp_lport); 3135bf9318fSmpi 314c194eafeSitojun if (IN6_IS_ADDR_UNSPECIFIED(&inp->inp_laddr6)) { 31550eeb2baSbluhm if (inp->inp_lport == 0) { 31697ca6483Sbluhm error = in_pcbbind_locked(inp, NULL, in6a, curproc); 3176426d56dSbluhm if (error) { 3186426d56dSbluhm mtx_leave(&table->inpt_mtx); 31950eeb2baSbluhm return (error); 3206426d56dSbluhm } 3216426d56dSbluhm t = in6_pcblookup_lock(inp->inp_table, &sin6->sin6_addr, 32250eeb2baSbluhm sin6->sin6_port, in6a, inp->inp_lport, 3236426d56dSbluhm inp->inp_rtableid, IN_PCBLOCK_HOLD); 3249e8a1cdfSbluhm if (t != NULL) { 32550eeb2baSbluhm inp->inp_lport = 0; 3266426d56dSbluhm mtx_leave(&table->inpt_mtx); 32750eeb2baSbluhm return (EADDRINUSE); 32850eeb2baSbluhm } 32950eeb2baSbluhm } 330287546eaSitojun inp->inp_laddr6 = *in6a; 331287546eaSitojun } 332287546eaSitojun inp->inp_faddr6 = sin6->sin6_addr; 333287546eaSitojun inp->inp_fport = sin6->sin6_port; 334cd28665aSbluhm in_pcbrehash(inp); 3356426d56dSbluhm 336cd28665aSbluhm mtx_leave(&table->inpt_mtx); 337cd28665aSbluhm 338d8b2e91cSitojun inp->inp_flowinfo &= ~IPV6_FLOWLABEL_MASK; 339d8b2e91cSitojun if (ip6_auto_flowlabel) 340d8b2e91cSitojun inp->inp_flowinfo |= 341d8b2e91cSitojun (htonl(ip6_randomflowlabel()) & IPV6_FLOWLABEL_MASK); 342aa794c2bSdlg #if NSTOEPLITZ > 0 343f5bb2424Spatrick inp->inp_flowid = stoeplitz_ip6port(&inp->inp_faddr6, 344f5bb2424Spatrick &inp->inp_laddr6, inp->inp_fport, inp->inp_lport); 345aa794c2bSdlg #endif 346287546eaSitojun return (0); 347287546eaSitojun } 348d3b325d0Sderaadt 34952527073Sitojun /* 350531c7ccdSbluhm * Get the local address/port, and put it in a sockaddr_in6. 351531c7ccdSbluhm * This services the getsockname(2) call. 352531c7ccdSbluhm */ 353018bdca7Sdlg void 354531c7ccdSbluhm in6_setsockaddr(struct inpcb *inp, struct mbuf *nam) 355531c7ccdSbluhm { 356531c7ccdSbluhm struct sockaddr_in6 *sin6; 357531c7ccdSbluhm 358531c7ccdSbluhm nam->m_len = sizeof(struct sockaddr_in6); 359531c7ccdSbluhm sin6 = mtod(nam,struct sockaddr_in6 *); 360531c7ccdSbluhm 361531c7ccdSbluhm bzero ((caddr_t)sin6,sizeof(struct sockaddr_in6)); 362531c7ccdSbluhm sin6->sin6_family = AF_INET6; 363531c7ccdSbluhm sin6->sin6_len = sizeof(struct sockaddr_in6); 364531c7ccdSbluhm sin6->sin6_port = inp->inp_lport; 365531c7ccdSbluhm sin6->sin6_addr = inp->inp_laddr6; 366531c7ccdSbluhm /* KAME hack: recover scopeid */ 367531c7ccdSbluhm in6_recoverscope(sin6, &inp->inp_laddr6); 368531c7ccdSbluhm } 369531c7ccdSbluhm 370531c7ccdSbluhm /* 371531c7ccdSbluhm * Get the foreign address/port, and put it in a sockaddr_in6. 372531c7ccdSbluhm * This services the getpeername(2) call. 373531c7ccdSbluhm */ 374018bdca7Sdlg void 375531c7ccdSbluhm in6_setpeeraddr(struct inpcb *inp, struct mbuf *nam) 376531c7ccdSbluhm { 377531c7ccdSbluhm struct sockaddr_in6 *sin6; 378531c7ccdSbluhm 379531c7ccdSbluhm nam->m_len = sizeof(struct sockaddr_in6); 380531c7ccdSbluhm sin6 = mtod(nam,struct sockaddr_in6 *); 381531c7ccdSbluhm 382531c7ccdSbluhm bzero ((caddr_t)sin6,sizeof(struct sockaddr_in6)); 383531c7ccdSbluhm sin6->sin6_family = AF_INET6; 384531c7ccdSbluhm sin6->sin6_len = sizeof(struct sockaddr_in6); 385531c7ccdSbluhm sin6->sin6_port = inp->inp_fport; 386531c7ccdSbluhm sin6->sin6_addr = inp->inp_faddr6; 387531c7ccdSbluhm /* KAME hack: recover scopeid */ 388531c7ccdSbluhm in6_recoverscope(sin6, &inp->inp_faddr6); 389531c7ccdSbluhm } 390531c7ccdSbluhm 3910dc53d81Smvs int 3920dc53d81Smvs in6_sockaddr(struct socket *so, struct mbuf *nam) 3930dc53d81Smvs { 394921ffa12Sbluhm struct inpcb *inp; 3950dc53d81Smvs 396921ffa12Sbluhm inp = sotoinpcb(so); 397921ffa12Sbluhm in6_setsockaddr(inp, nam); 3980dc53d81Smvs 3990dc53d81Smvs return (0); 4000dc53d81Smvs } 4010dc53d81Smvs 402c3a3d609Smvs int 403c3a3d609Smvs in6_peeraddr(struct socket *so, struct mbuf *nam) 404c3a3d609Smvs { 405921ffa12Sbluhm struct inpcb *inp; 406c3a3d609Smvs 407921ffa12Sbluhm inp = sotoinpcb(so); 408921ffa12Sbluhm in6_setpeeraddr(inp, nam); 409c3a3d609Smvs 410c3a3d609Smvs return (0); 411c3a3d609Smvs } 412c3a3d609Smvs 413531c7ccdSbluhm /* 414d3b325d0Sderaadt * Pass some notification to all connections of a protocol 415d3b325d0Sderaadt * associated with address dst. The local address and/or port numbers 416d3b325d0Sderaadt * may be specified to limit the search. The "usual action" will be 417d3b325d0Sderaadt * taken, depending on the ctlinput cmd. The caller must filter any 418d3b325d0Sderaadt * cmds that are uninteresting (e.g., no error in the map). 419d3b325d0Sderaadt * Call the protocol specific routine (if any) to report 420d3b325d0Sderaadt * any errors for each matching socket. 421d3b325d0Sderaadt * 422d3b325d0Sderaadt * Also perform input-side security policy check 423d3b325d0Sderaadt * once PCB to be notified has been located. 42452527073Sitojun */ 4251941b8b5Sbluhm void 4267b1356d5Sbluhm in6_pcbnotify(struct inpcbtable *table, const struct sockaddr_in6 *dst, 427dc01e491Sphessler uint fport_arg, const struct sockaddr_in6 *src, uint lport_arg, 428d2d2913eSbluhm u_int rtable, int cmd, void *cmdarg, void (*notify)(struct inpcb *, int)) 429d3b325d0Sderaadt { 430*8ee0399bSmvs struct inpcb_iterator iter = { .inp_table = NULL }; 431*8ee0399bSmvs struct inpcb *inp = NULL; 432d3b325d0Sderaadt u_short fport = fport_arg, lport = lport_arg; 43355851b2eSbluhm struct sockaddr_in6 sa6_src; 4341941b8b5Sbluhm int errno; 4357ee01f6fSitojun u_int32_t flowinfo; 436d2d2913eSbluhm u_int rdomain; 437d3b325d0Sderaadt 43855851b2eSbluhm if ((unsigned)cmd >= PRC_NCMDS) 4391941b8b5Sbluhm return; 4407ee01f6fSitojun 44155851b2eSbluhm if (IN6_IS_ADDR_UNSPECIFIED(&dst->sin6_addr)) 4421941b8b5Sbluhm return; 44355851b2eSbluhm if (IN6_IS_ADDR_V4MAPPED(&dst->sin6_addr)) { 444c194eafeSitojun #ifdef DIAGNOSTIC 445ab0ea4a9Snayden printf("%s: Huh? Thought we never got " 446ab0ea4a9Snayden "called with mapped!\n", __func__); 447c194eafeSitojun #endif 4481941b8b5Sbluhm return; 449c194eafeSitojun } 4507ee01f6fSitojun 4517ee01f6fSitojun /* 4527ee01f6fSitojun * note that src can be NULL when we get notify by local fragmentation. 4537ee01f6fSitojun */ 45455851b2eSbluhm sa6_src = (src == NULL) ? sa6_any : *src; 4557ee01f6fSitojun flowinfo = sa6_src.sin6_flowinfo; 456d3b325d0Sderaadt 457d3b325d0Sderaadt /* 458d3b325d0Sderaadt * Redirects go to all references to the destination, 459a7a563d1Sitojun * and use in_rtchange to invalidate the route cache. 460a7a563d1Sitojun * Dead host indications: also use in_rtchange to invalidate 4613a20cb21Sitojun * the cache, and deliver the error to all the sockets. 462d3b325d0Sderaadt * Otherwise, if we have knowledge of the local port and address, 463d3b325d0Sderaadt * deliver only to that socket. 464d3b325d0Sderaadt */ 46552527073Sitojun if (PRC_IS_REDIRECT(cmd) || cmd == PRC_HOSTDEAD) { 466d3b325d0Sderaadt fport = 0; 467d3b325d0Sderaadt lport = 0; 4687ee01f6fSitojun sa6_src.sin6_addr = in6addr_any; 4693a20cb21Sitojun 4707ee01f6fSitojun if (cmd != PRC_HOSTDEAD) 471d3b325d0Sderaadt notify = in_rtchange; 472d3b325d0Sderaadt } 473d3b325d0Sderaadt errno = inet6ctlerrmap[cmd]; 474dc28d33fSbluhm if (notify == NULL) 475dc28d33fSbluhm return; 476d3b325d0Sderaadt 477d2d2913eSbluhm rdomain = rtable_l2(rtable); 478dc28d33fSbluhm mtx_enter(&table->inpt_mtx); 479*8ee0399bSmvs while ((inp = in_pcb_iterator(table, inp, &iter)) != NULL) { 48093536db2Sbluhm KASSERT(ISSET(inp->inp_flags, INP_IPV6)); 481a7a563d1Sitojun 4823a20cb21Sitojun /* 4837ee01f6fSitojun * Under the following condition, notify of redirects 4847ee01f6fSitojun * to the pcb, without making address matches against inpcb. 4857ee01f6fSitojun * - redirect notification is arrived. 4867ee01f6fSitojun * - the inpcb is unconnected. 4877ee01f6fSitojun * - the inpcb is caching !RTF_HOST routing entry. 4887ee01f6fSitojun * - the ICMPv6 notification is from the gateway cached in the 4897ee01f6fSitojun * inpcb. i.e. ICMPv6 notification is from nexthop gateway 4907ee01f6fSitojun * the inpcb used very recently. 4913a20cb21Sitojun * 4927ee01f6fSitojun * This is to improve interaction between netbsd/openbsd 4937ee01f6fSitojun * redirect handling code, and inpcb route cache code. 4947ee01f6fSitojun * without the clause, !RTF_HOST routing entry (which carries 4957ee01f6fSitojun * gateway used by inpcb right before the ICMPv6 redirect) 4967ee01f6fSitojun * will be cached forever in unconnected inpcb. 4977ee01f6fSitojun * 4987ee01f6fSitojun * There still is a question regarding to what is TRT: 4997ee01f6fSitojun * - On bsdi/freebsd, RTF_HOST (cloned) routing entry will be 5007ee01f6fSitojun * generated on packet output. inpcb will always cache 5017ee01f6fSitojun * RTF_HOST routing entry so there's no need for the clause 5027ee01f6fSitojun * (ICMPv6 redirect will update RTF_HOST routing entry, 5037ee01f6fSitojun * and inpcb is caching it already). 5047ee01f6fSitojun * However, bsdi/freebsd are vulnerable to local DoS attacks 5057ee01f6fSitojun * due to the cloned routing entries. 5067ee01f6fSitojun * - Specwise, "destination cache" is mentioned in RFC2461. 5077ee01f6fSitojun * Jinmei says that it implies bsdi/freebsd behavior, itojun 5087ee01f6fSitojun * is not really convinced. 5097ee01f6fSitojun * - Having hiwat/lowat on # of cloned host route (redirect/ 5107ee01f6fSitojun * pmtud) may be a good idea. netbsd/openbsd has it. see 5117ee01f6fSitojun * icmp6_mtudisc_update(). 5123a20cb21Sitojun */ 5137ee01f6fSitojun if ((PRC_IS_REDIRECT(cmd) || cmd == PRC_HOSTDEAD) && 5147ee01f6fSitojun IN6_IS_ADDR_UNSPECIFIED(&inp->inp_laddr6) && 5157ee01f6fSitojun inp->inp_route.ro_rt && 51694c0e2bdSbluhm !(inp->inp_route.ro_rt->rt_flags & RTF_HOST) && 51794c0e2bdSbluhm IN6_ARE_ADDR_EQUAL(&inp->inp_route.ro_dstsin6.sin6_addr, 51894c0e2bdSbluhm &dst->sin6_addr)) { 5197ee01f6fSitojun goto do_notify; 5203a20cb21Sitojun } 521a7a563d1Sitojun 5227ee01f6fSitojun /* 5237ee01f6fSitojun * Detect if we should notify the error. If no source and 524ab37e897Sderaadt * destination ports are specified, but non-zero flowinfo and 5257ee01f6fSitojun * local address match, notify the error. This is the case 5267ee01f6fSitojun * when the error is delivered with an encrypted buffer 5277ee01f6fSitojun * by ESP. Otherwise, just compare addresses and ports 5287ee01f6fSitojun * as usual. 5297ee01f6fSitojun */ 5307ee01f6fSitojun if (lport == 0 && fport == 0 && flowinfo && 5317ee01f6fSitojun flowinfo == (inp->inp_flowinfo & IPV6_FLOWLABEL_MASK) && 5327ee01f6fSitojun IN6_ARE_ADDR_EQUAL(&inp->inp_laddr6, &sa6_src.sin6_addr)) 5337ee01f6fSitojun goto do_notify; 5347ee01f6fSitojun else if (!IN6_ARE_ADDR_EQUAL(&inp->inp_faddr6, 53555851b2eSbluhm &dst->sin6_addr) || 536dc01e491Sphessler rtable_l2(inp->inp_rtableid) != rdomain || 537d3b325d0Sderaadt (lport && inp->inp_lport != lport) || 5387ee01f6fSitojun (!IN6_IS_ADDR_UNSPECIFIED(&sa6_src.sin6_addr) && 5397ee01f6fSitojun !IN6_ARE_ADDR_EQUAL(&inp->inp_laddr6, 5407ee01f6fSitojun &sa6_src.sin6_addr)) || 54152527073Sitojun (fport && inp->inp_fport != fport)) { 542d3b325d0Sderaadt continue; 543d3b325d0Sderaadt } 5447ee01f6fSitojun do_notify: 545*8ee0399bSmvs mtx_leave(&table->inpt_mtx); 546*8ee0399bSmvs (*notify)(inp, errno); 547*8ee0399bSmvs mtx_enter(&table->inpt_mtx); 548dc28d33fSbluhm } 549dc28d33fSbluhm mtx_leave(&table->inpt_mtx); 550d3b325d0Sderaadt } 551d3b325d0Sderaadt 5523dc61bc4Sbluhm struct rtentry * 5533dc61bc4Sbluhm in6_pcbrtentry(struct inpcb *inp) 5543dc61bc4Sbluhm { 5553dc61bc4Sbluhm if (IN6_IS_ADDR_UNSPECIFIED(&inp->inp_faddr6)) 5563dc61bc4Sbluhm return (NULL); 557eb7afff9Sbluhm return (route6_mpath(&inp->inp_route, &inp->inp_faddr6, 558eb7afff9Sbluhm &inp->inp_laddr6, inp->inp_rtableid)); 5593dc61bc4Sbluhm } 5603dc61bc4Sbluhm 561531c7ccdSbluhm struct inpcb * 5628bde4b77Sbluhm in6_pcbhash_lookup(struct inpcbtable *table, uint64_t hash, u_int rdomain, 563a6b8fd29Sbluhm const struct in6_addr *faddr, u_short fport, 564a6b8fd29Sbluhm const struct in6_addr *laddr, u_short lport) 565d3b325d0Sderaadt { 566531c7ccdSbluhm struct inpcbhead *head; 567531c7ccdSbluhm struct inpcb *inp; 568d3b325d0Sderaadt 569a6b8fd29Sbluhm NET_ASSERT_LOCKED(); 570a6b8fd29Sbluhm MUTEX_ASSERT_LOCKED(&table->inpt_mtx); 571a6b8fd29Sbluhm 5728bde4b77Sbluhm head = &table->inpt_hashtbl[hash & table->inpt_mask]; 573531c7ccdSbluhm LIST_FOREACH(inp, head, inp_hash) { 57493536db2Sbluhm KASSERT(ISSET(inp->inp_flags, INP_IPV6)); 57593536db2Sbluhm 576a6b8fd29Sbluhm if (inp->inp_fport == fport && inp->inp_lport == lport && 577a6b8fd29Sbluhm IN6_ARE_ADDR_EQUAL(&inp->inp_faddr6, faddr) && 578531c7ccdSbluhm IN6_ARE_ADDR_EQUAL(&inp->inp_laddr6, laddr) && 579531c7ccdSbluhm rtable_l2(inp->inp_rtableid) == rdomain) { 580a6b8fd29Sbluhm break; 581a6b8fd29Sbluhm } 582a6b8fd29Sbluhm } 583a6b8fd29Sbluhm if (inp != NULL) { 584531c7ccdSbluhm /* 585531c7ccdSbluhm * Move this PCB to the head of hash chain so that 586531c7ccdSbluhm * repeated accesses are quicker. This is analogous to 587531c7ccdSbluhm * the historic single-entry PCB cache. 588531c7ccdSbluhm */ 589531c7ccdSbluhm if (inp != LIST_FIRST(head)) { 590531c7ccdSbluhm LIST_REMOVE(inp, inp_hash); 591531c7ccdSbluhm LIST_INSERT_HEAD(head, inp, inp_hash); 592531c7ccdSbluhm } 593531c7ccdSbluhm } 594a6b8fd29Sbluhm return (inp); 595531c7ccdSbluhm } 596a6b8fd29Sbluhm 597a6b8fd29Sbluhm struct inpcb * 5986426d56dSbluhm in6_pcblookup_lock(struct inpcbtable *table, const struct in6_addr *faddr, 5996426d56dSbluhm u_int fport, const struct in6_addr *laddr, u_int lport, u_int rtable, 6006426d56dSbluhm int lock) 601a6b8fd29Sbluhm { 602a6b8fd29Sbluhm struct inpcb *inp; 6038bde4b77Sbluhm uint64_t hash; 604a6b8fd29Sbluhm u_int rdomain; 605a6b8fd29Sbluhm 606a6b8fd29Sbluhm rdomain = rtable_l2(rtable); 6078bde4b77Sbluhm hash = in6_pcbhash(table, rdomain, faddr, fport, laddr, lport); 6088bde4b77Sbluhm 6096426d56dSbluhm if (lock == IN_PCBLOCK_GRAB) { 610a6b8fd29Sbluhm mtx_enter(&table->inpt_mtx); 6116426d56dSbluhm } else { 6126426d56dSbluhm KASSERT(lock == IN_PCBLOCK_HOLD); 6136426d56dSbluhm MUTEX_ASSERT_LOCKED(&table->inpt_mtx); 6146426d56dSbluhm } 6158bde4b77Sbluhm inp = in6_pcbhash_lookup(table, hash, rdomain, 6168bde4b77Sbluhm faddr, fport, laddr, lport); 6176426d56dSbluhm if (lock == IN_PCBLOCK_GRAB) { 6189e8a1cdfSbluhm in_pcbref(inp); 619dc28d33fSbluhm mtx_leave(&table->inpt_mtx); 6206426d56dSbluhm } 6218bde4b77Sbluhm 622531c7ccdSbluhm #ifdef DIAGNOSTIC 623531c7ccdSbluhm if (inp == NULL && in_pcbnotifymiss) { 624531c7ccdSbluhm printf("%s: faddr= fport=%d laddr= lport=%d rdom=%u\n", 625531c7ccdSbluhm __func__, ntohs(fport), ntohs(lport), rdomain); 626531c7ccdSbluhm } 627531c7ccdSbluhm #endif 628531c7ccdSbluhm return (inp); 629d3b325d0Sderaadt } 630d3b325d0Sderaadt 631531c7ccdSbluhm struct inpcb * 6326426d56dSbluhm in6_pcblookup(struct inpcbtable *table, const struct in6_addr *faddr, 6336426d56dSbluhm u_int fport, const struct in6_addr *laddr, u_int lport, u_int rtable) 6346426d56dSbluhm { 6356426d56dSbluhm return in6_pcblookup_lock(table, faddr, fport, laddr, lport, rtable, 6366426d56dSbluhm IN_PCBLOCK_GRAB); 6376426d56dSbluhm } 6386426d56dSbluhm 6396426d56dSbluhm struct inpcb * 640531c7ccdSbluhm in6_pcblookup_listen(struct inpcbtable *table, struct in6_addr *laddr, 641a6b8fd29Sbluhm u_int lport, struct mbuf *m, u_int rtable) 642d3b325d0Sderaadt { 643531c7ccdSbluhm const struct in6_addr *key1, *key2; 644531c7ccdSbluhm struct inpcb *inp; 6458bde4b77Sbluhm uint64_t hash; 646531c7ccdSbluhm u_int rdomain; 647d3b325d0Sderaadt 648531c7ccdSbluhm key1 = laddr; 649531c7ccdSbluhm key2 = &zeroin6_addr; 650531c7ccdSbluhm #if NPF > 0 651531c7ccdSbluhm if (m && m->m_pkthdr.pf.flags & PF_TAG_DIVERTED) { 652531c7ccdSbluhm struct pf_divert *divert; 653d3b325d0Sderaadt 654531c7ccdSbluhm divert = pf_find_divert(m); 655531c7ccdSbluhm KASSERT(divert != NULL); 656531c7ccdSbluhm switch (divert->type) { 657531c7ccdSbluhm case PF_DIVERT_TO: 658531c7ccdSbluhm key1 = key2 = &divert->addr.v6; 659531c7ccdSbluhm lport = divert->port; 660531c7ccdSbluhm break; 661531c7ccdSbluhm case PF_DIVERT_REPLY: 662531c7ccdSbluhm return (NULL); 663531c7ccdSbluhm default: 664531c7ccdSbluhm panic("%s: unknown divert type %d, mbuf %p, divert %p", 665531c7ccdSbluhm __func__, divert->type, m, divert); 666531c7ccdSbluhm } 667531c7ccdSbluhm } else if (m && m->m_pkthdr.pf.flags & PF_TAG_TRANSLATE_LOCALHOST) { 668531c7ccdSbluhm /* 669531c7ccdSbluhm * Redirected connections should not be treated the same 670531c7ccdSbluhm * as connections directed to ::1 since localhost 671531c7ccdSbluhm * can only be accessed from the host itself. 672531c7ccdSbluhm */ 673531c7ccdSbluhm key1 = &zeroin6_addr; 674531c7ccdSbluhm key2 = laddr; 675531c7ccdSbluhm } 676531c7ccdSbluhm #endif 677a7a563d1Sitojun 678531c7ccdSbluhm rdomain = rtable_l2(rtable); 6798bde4b77Sbluhm hash = in6_pcbhash(table, rdomain, &zeroin6_addr, 0, key1, lport); 6808bde4b77Sbluhm 681dc28d33fSbluhm mtx_enter(&table->inpt_mtx); 6828bde4b77Sbluhm inp = in6_pcbhash_lookup(table, hash, rdomain, 6838bde4b77Sbluhm &zeroin6_addr, 0, key1, lport); 684531c7ccdSbluhm if (inp == NULL && ! IN6_ARE_ADDR_EQUAL(key1, key2)) { 6858bde4b77Sbluhm hash = in6_pcbhash(table, rdomain, 6868bde4b77Sbluhm &zeroin6_addr, 0, key2, lport); 6878bde4b77Sbluhm inp = in6_pcbhash_lookup(table, hash, rdomain, 688531c7ccdSbluhm &zeroin6_addr, 0, key2, lport); 689531c7ccdSbluhm } 6909e8a1cdfSbluhm in_pcbref(inp); 691dc28d33fSbluhm mtx_leave(&table->inpt_mtx); 6928bde4b77Sbluhm 693531c7ccdSbluhm #ifdef DIAGNOSTIC 694531c7ccdSbluhm if (inp == NULL && in_pcbnotifymiss) { 695531c7ccdSbluhm printf("%s: laddr= lport=%d rdom=%u\n", 696531c7ccdSbluhm __func__, ntohs(lport), rdomain); 697531c7ccdSbluhm } 698531c7ccdSbluhm #endif 699531c7ccdSbluhm return (inp); 700d3b325d0Sderaadt } 701