LCOV - code coverage report
Current view: top level - netinet6 - in6_pcb.c (source / functions) Hit Total Coverage
Test: 6.4 Lines: 0 221 0.0 %
Date: 2018-10-19 03:25:38 Functions: 0 8 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*      $OpenBSD: in6_pcb.c,v 1.106 2018/09/11 21:04:03 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             : 
     104             : #include <sys/param.h>
     105             : #include <sys/systm.h>
     106             : #include <sys/mbuf.h>
     107             : #include <sys/protosw.h>
     108             : #include <sys/socket.h>
     109             : #include <sys/socketvar.h>
     110             : 
     111             : #include <net/if.h>
     112             : #include <net/if_var.h>
     113             : #include <net/pfvar.h>
     114             : 
     115             : #include <netinet/in.h>
     116             : #include <netinet/ip.h>
     117             : #include <netinet/ip_var.h>
     118             : #include <netinet/in_pcb.h>
     119             : 
     120             : #include <netinet6/in6_var.h>
     121             : 
     122             : const struct in6_addr zeroin6_addr;
     123             : 
     124             : struct inpcbhead *
     125           0 : in6_pcbhash(struct inpcbtable *table, int rdom,
     126             :     const struct in6_addr *faddr, u_short fport,
     127             :     const struct in6_addr *laddr, u_short lport)
     128             : {
     129           0 :         SIPHASH_CTX ctx;
     130           0 :         u_int32_t nrdom = htonl(rdom);
     131             : 
     132           0 :         SipHash24_Init(&ctx, &table->inpt_key);
     133           0 :         SipHash24_Update(&ctx, &nrdom, sizeof(nrdom));
     134           0 :         SipHash24_Update(&ctx, faddr, sizeof(*faddr));
     135           0 :         SipHash24_Update(&ctx, &fport, sizeof(fport));
     136           0 :         SipHash24_Update(&ctx, laddr, sizeof(*laddr));
     137           0 :         SipHash24_Update(&ctx, &lport, sizeof(lport));
     138             : 
     139           0 :         return (&table->inpt_hashtbl[SipHash24_End(&ctx) & table->inpt_mask]);
     140           0 : }
     141             : 
     142             : int
     143           0 : in6_pcbaddrisavail(struct inpcb *inp, struct sockaddr_in6 *sin6, int wild,
     144             :     struct proc *p)
     145             : {
     146           0 :         struct socket *so = inp->inp_socket;
     147           0 :         struct inpcbtable *table = inp->inp_table;
     148           0 :         u_short lport = sin6->sin6_port;
     149           0 :         int reuseport = (so->so_options & SO_REUSEPORT);
     150             : 
     151           0 :         wild |= INPLOOKUP_IPV6;
     152             :         /* KAME hack: embed scopeid */
     153           0 :         if (in6_embedscope(&sin6->sin6_addr, sin6, inp) != 0)
     154           0 :                 return (EINVAL);
     155             :         /* this must be cleared for ifa_ifwithaddr() */
     156           0 :         sin6->sin6_scope_id = 0;
     157             :         /* reject IPv4 mapped address, we have no support for it */
     158           0 :         if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr))
     159           0 :                 return (EADDRNOTAVAIL);
     160             : 
     161           0 :         if (IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) {
     162             :                 /*
     163             :                  * Treat SO_REUSEADDR as SO_REUSEPORT for multicast;
     164             :                  * allow complete duplication of binding if
     165             :                  * SO_REUSEPORT is set, or if SO_REUSEADDR is set
     166             :                  * and a multicast address is bound on both
     167             :                  * new and duplicated sockets.
     168             :                  */
     169           0 :                 if (so->so_options & (SO_REUSEADDR|SO_REUSEPORT))
     170           0 :                         reuseport = SO_REUSEADDR | SO_REUSEPORT;
     171           0 :         } else if (!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
     172             :                 struct ifaddr *ifa = NULL;
     173             : 
     174           0 :                 sin6->sin6_port = 0;  /*
     175             :                                        * Yechhhh, because of upcoming
     176             :                                        * call to ifa_ifwithaddr(), which
     177             :                                        * does bcmp's over the PORTS as
     178             :                                        * well.  (What about flow?)
     179             :                                        */
     180           0 :                 sin6->sin6_flowinfo = 0;
     181           0 :                 if (!(so->so_options & SO_BINDANY) &&
     182           0 :                     (ifa = ifa_ifwithaddr(sin6tosa(sin6),
     183           0 :                     inp->inp_rtableid)) == NULL)
     184           0 :                         return (EADDRNOTAVAIL);
     185           0 :                 sin6->sin6_port = lport;
     186             : 
     187             :                 /*
     188             :                  * bind to an anycast address might accidentally
     189             :                  * cause sending a packet with an anycast source
     190             :                  * address, so we forbid it.
     191             :                  *
     192             :                  * We should allow to bind to a deprecated address,
     193             :                  * since the application dare to use it.
     194             :                  * But, can we assume that they are careful enough
     195             :                  * to check if the address is deprecated or not?
     196             :                  * Maybe, as a safeguard, we should have a setsockopt
     197             :                  * flag to control the bind(2) behavior against
     198             :                  * deprecated addresses (default: forbid bind(2)).
     199             :                  */
     200           0 :                 if (ifa && ifatoia6(ifa)->ia6_flags & (IN6_IFF_ANYCAST|
     201             :                     IN6_IFF_TENTATIVE|IN6_IFF_DUPLICATED|IN6_IFF_DETACHED))
     202           0 :                         return (EADDRNOTAVAIL);
     203           0 :         }
     204           0 :         if (lport) {
     205             :                 struct inpcb *t;
     206             : 
     207           0 :                 if (so->so_euid) {
     208           0 :                         t = in_pcblookup_local(table,
     209           0 :                             (struct in_addr *)&sin6->sin6_addr, lport,
     210             :                             INPLOOKUP_WILDCARD | INPLOOKUP_IPV6,
     211           0 :                             inp->inp_rtableid);
     212           0 :                         if (t && (so->so_euid != t->inp_socket->so_euid))
     213           0 :                                 return (EADDRINUSE);
     214             :                 }
     215           0 :                 t = in_pcblookup_local(table,
     216           0 :                     (struct in_addr *)&sin6->sin6_addr, lport,
     217           0 :                     wild, inp->inp_rtableid);
     218           0 :                 if (t && (reuseport & t->inp_socket->so_options) == 0)
     219           0 :                         return (EADDRINUSE);
     220           0 :         }
     221           0 :         return (0);
     222           0 : }
     223             : 
     224             : /*
     225             :  * Connect from a socket to a specified address.
     226             :  * Both address and port must be specified in argument sin6.
     227             :  * Eventually, flow labels will have to be dealt with here, as well.
     228             :  *
     229             :  * If don't have a local address for this socket yet,
     230             :  * then pick one.
     231             :  */
     232             : int
     233           0 : in6_pcbconnect(struct inpcb *inp, struct mbuf *nam)
     234             : {
     235           0 :         struct in6_addr *in6a = NULL;
     236           0 :         struct sockaddr_in6 *sin6;
     237             :         int error;
     238           0 :         struct sockaddr_in6 tmp;
     239             : 
     240           0 :         KASSERT(inp->inp_flags & INP_IPV6);
     241             : 
     242           0 :         if ((error = in6_nam2sin6(nam, &sin6)))
     243           0 :                 return (error);
     244           0 :         if (sin6->sin6_port == 0)
     245           0 :                 return (EADDRNOTAVAIL);
     246             :         /* reject IPv4 mapped address, we have no support for it */
     247           0 :         if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr))
     248           0 :                 return (EADDRNOTAVAIL);
     249             : 
     250             :         /* protect *sin6 from overwrites */
     251           0 :         tmp = *sin6;
     252           0 :         sin6 = &tmp;
     253             : 
     254             :         /* KAME hack: embed scopeid */
     255           0 :         if (in6_embedscope(&sin6->sin6_addr, sin6, inp) != 0)
     256           0 :                 return EINVAL;
     257             :         /* this must be cleared for ifa_ifwithaddr() */
     258           0 :         sin6->sin6_scope_id = 0;
     259             : 
     260             :         /* Source address selection. */
     261             :         /*
     262             :          * XXX: in6_selectsrc might replace the bound local address
     263             :          * with the address specified by setsockopt(IPV6_PKTINFO).
     264             :          * Is it the intended behavior?
     265             :          */
     266           0 :         error = in6_pcbselsrc(&in6a, sin6, inp, inp->inp_outputopts6);
     267           0 :         if (error)
     268           0 :                 return (error);
     269             : 
     270           0 :         inp->inp_ipv6.ip6_hlim = (u_int8_t)in6_selecthlim(inp);
     271             : 
     272           0 :         if (in6_pcbhashlookup(inp->inp_table, &sin6->sin6_addr, sin6->sin6_port,
     273           0 :             IN6_IS_ADDR_UNSPECIFIED(&inp->inp_laddr6) ? in6a : &inp->inp_laddr6,
     274           0 :             inp->inp_lport, inp->inp_rtableid) != NULL) {
     275           0 :                 return (EADDRINUSE);
     276             :         }
     277             : 
     278           0 :         KASSERT(IN6_IS_ADDR_UNSPECIFIED(&inp->inp_laddr6) || inp->inp_lport);
     279             : 
     280           0 :         if (IN6_IS_ADDR_UNSPECIFIED(&inp->inp_laddr6)) {
     281           0 :                 if (inp->inp_lport == 0) {
     282           0 :                         error = in_pcbbind(inp, NULL, curproc);
     283           0 :                         if (error)
     284           0 :                                 return (error);
     285           0 :                         if (in6_pcbhashlookup(inp->inp_table, &sin6->sin6_addr,
     286           0 :                             sin6->sin6_port, in6a, inp->inp_lport,
     287           0 :                             inp->inp_rtableid) != NULL) {
     288           0 :                                 inp->inp_lport = 0;
     289           0 :                                 return (EADDRINUSE);
     290             :                         }
     291             :                 }
     292           0 :                 inp->inp_laddr6 = *in6a;
     293           0 :         }
     294           0 :         inp->inp_faddr6 = sin6->sin6_addr;
     295           0 :         inp->inp_fport = sin6->sin6_port;
     296           0 :         inp->inp_flowinfo &= ~IPV6_FLOWLABEL_MASK;
     297           0 :         if (ip6_auto_flowlabel)
     298           0 :                 inp->inp_flowinfo |=
     299           0 :                     (htonl(ip6_randomflowlabel()) & IPV6_FLOWLABEL_MASK);
     300           0 :         in_pcbrehash(inp);
     301           0 :         return (0);
     302           0 : }
     303             : 
     304             : /*
     305             :  * Get the local address/port, and put it in a sockaddr_in6.
     306             :  * This services the getsockname(2) call.
     307             :  */
     308             : int
     309           0 : in6_setsockaddr(struct inpcb *inp, struct mbuf *nam)
     310             : {
     311             :         struct sockaddr_in6 *sin6;
     312             : 
     313           0 :         nam->m_len = sizeof(struct sockaddr_in6);
     314           0 :         sin6 = mtod(nam,struct sockaddr_in6 *);
     315             : 
     316           0 :         bzero ((caddr_t)sin6,sizeof(struct sockaddr_in6));
     317           0 :         sin6->sin6_family = AF_INET6;
     318           0 :         sin6->sin6_len = sizeof(struct sockaddr_in6);
     319           0 :         sin6->sin6_port = inp->inp_lport;
     320           0 :         sin6->sin6_addr = inp->inp_laddr6;
     321             :         /* KAME hack: recover scopeid */
     322           0 :         in6_recoverscope(sin6, &inp->inp_laddr6);
     323             : 
     324           0 :         return 0;
     325             : }
     326             : 
     327             : /*
     328             :  * Get the foreign address/port, and put it in a sockaddr_in6.
     329             :  * This services the getpeername(2) call.
     330             :  */
     331             : int
     332           0 : in6_setpeeraddr(struct inpcb *inp, struct mbuf *nam)
     333             : {
     334             :         struct sockaddr_in6 *sin6;
     335             : 
     336           0 :         nam->m_len = sizeof(struct sockaddr_in6);
     337           0 :         sin6 = mtod(nam,struct sockaddr_in6 *);
     338             : 
     339           0 :         bzero ((caddr_t)sin6,sizeof(struct sockaddr_in6));
     340           0 :         sin6->sin6_family = AF_INET6;
     341           0 :         sin6->sin6_len = sizeof(struct sockaddr_in6);
     342           0 :         sin6->sin6_port = inp->inp_fport;
     343           0 :         sin6->sin6_addr = inp->inp_faddr6;
     344             :         /* KAME hack: recover scopeid */
     345           0 :         in6_recoverscope(sin6, &inp->inp_faddr6);
     346             : 
     347           0 :         return 0;
     348             : }
     349             : 
     350             : /*
     351             :  * Pass some notification to all connections of a protocol
     352             :  * associated with address dst.  The local address and/or port numbers
     353             :  * may be specified to limit the search.  The "usual action" will be
     354             :  * taken, depending on the ctlinput cmd.  The caller must filter any
     355             :  * cmds that are uninteresting (e.g., no error in the map).
     356             :  * Call the protocol specific routine (if any) to report
     357             :  * any errors for each matching socket.
     358             :  *
     359             :  * Also perform input-side security policy check
     360             :  *    once PCB to be notified has been located.
     361             :  */
     362             : int
     363           0 : in6_pcbnotify(struct inpcbtable *table, struct sockaddr_in6 *dst,
     364             :     uint fport_arg, const struct sockaddr_in6 *src, uint lport_arg,
     365             :     u_int rtable, int cmd, void *cmdarg, void (*notify)(struct inpcb *, int))
     366             : {
     367             :         struct inpcb *inp, *ninp;
     368           0 :         u_short fport = fport_arg, lport = lport_arg;
     369           0 :         struct sockaddr_in6 sa6_src;
     370             :         int errno, nmatch = 0;
     371             :         u_int32_t flowinfo;
     372             :         u_int rdomain;
     373             : 
     374           0 :         NET_ASSERT_LOCKED();
     375             : 
     376           0 :         if ((unsigned)cmd >= PRC_NCMDS)
     377           0 :                 return (0);
     378             : 
     379           0 :         if (IN6_IS_ADDR_UNSPECIFIED(&dst->sin6_addr))
     380           0 :                 return (0);
     381           0 :         if (IN6_IS_ADDR_V4MAPPED(&dst->sin6_addr)) {
     382             : #ifdef DIAGNOSTIC
     383           0 :                 printf("Huh?  Thought in6_pcbnotify() never got "
     384             :                        "called with mapped!\n");
     385             : #endif
     386           0 :                 return (0);
     387             :         }
     388             : 
     389             :         /*
     390             :          * note that src can be NULL when we get notify by local fragmentation.
     391             :          */
     392           0 :         sa6_src = (src == NULL) ? sa6_any : *src;
     393           0 :         flowinfo = sa6_src.sin6_flowinfo;
     394             : 
     395             :         /*
     396             :          * Redirects go to all references to the destination,
     397             :          * and use in_rtchange to invalidate the route cache.
     398             :          * Dead host indications: also use in_rtchange to invalidate
     399             :          * the cache, and deliver the error to all the sockets.
     400             :          * Otherwise, if we have knowledge of the local port and address,
     401             :          * deliver only to that socket.
     402             :          */
     403           0 :         if (PRC_IS_REDIRECT(cmd) || cmd == PRC_HOSTDEAD) {
     404             :                 fport = 0;
     405             :                 lport = 0;
     406           0 :                 sa6_src.sin6_addr = in6addr_any;
     407             : 
     408           0 :                 if (cmd != PRC_HOSTDEAD)
     409           0 :                         notify = in_rtchange;
     410             :         }
     411           0 :         errno = inet6ctlerrmap[cmd];
     412             : 
     413           0 :         rdomain = rtable_l2(rtable);
     414           0 :         TAILQ_FOREACH_SAFE(inp, &table->inpt_queue, inp_queue, ninp) {
     415           0 :                 if ((inp->inp_flags & INP_IPV6) == 0)
     416             :                         continue;
     417             : 
     418             :                 /*
     419             :                  * Under the following condition, notify of redirects
     420             :                  * to the pcb, without making address matches against inpcb.
     421             :                  * - redirect notification is arrived.
     422             :                  * - the inpcb is unconnected.
     423             :                  * - the inpcb is caching !RTF_HOST routing entry.
     424             :                  * - the ICMPv6 notification is from the gateway cached in the
     425             :                  *   inpcb.  i.e. ICMPv6 notification is from nexthop gateway
     426             :                  *   the inpcb used very recently.
     427             :                  *
     428             :                  * This is to improve interaction between netbsd/openbsd
     429             :                  * redirect handling code, and inpcb route cache code.
     430             :                  * without the clause, !RTF_HOST routing entry (which carries
     431             :                  * gateway used by inpcb right before the ICMPv6 redirect)
     432             :                  * will be cached forever in unconnected inpcb.
     433             :                  *
     434             :                  * There still is a question regarding to what is TRT:
     435             :                  * - On bsdi/freebsd, RTF_HOST (cloned) routing entry will be
     436             :                  *   generated on packet output.  inpcb will always cache
     437             :                  *   RTF_HOST routing entry so there's no need for the clause
     438             :                  *   (ICMPv6 redirect will update RTF_HOST routing entry,
     439             :                  *   and inpcb is caching it already).
     440             :                  *   However, bsdi/freebsd are vulnerable to local DoS attacks
     441             :                  *   due to the cloned routing entries.
     442             :                  * - Specwise, "destination cache" is mentioned in RFC2461.
     443             :                  *   Jinmei says that it implies bsdi/freebsd behavior, itojun
     444             :                  *   is not really convinced.
     445             :                  * - Having hiwat/lowat on # of cloned host route (redirect/
     446             :                  *   pmtud) may be a good idea.  netbsd/openbsd has it.  see
     447             :                  *   icmp6_mtudisc_update().
     448             :                  */
     449           0 :                 if ((PRC_IS_REDIRECT(cmd) || cmd == PRC_HOSTDEAD) &&
     450           0 :                     IN6_IS_ADDR_UNSPECIFIED(&inp->inp_laddr6) &&
     451           0 :                     inp->inp_route.ro_rt &&
     452           0 :                     !(inp->inp_route.ro_rt->rt_flags & RTF_HOST)) {
     453             :                         struct sockaddr_in6 *dst6;
     454             : 
     455           0 :                         dst6 = satosin6(&inp->inp_route.ro_dst);
     456           0 :                         if (IN6_ARE_ADDR_EQUAL(&dst6->sin6_addr,
     457             :                             &dst->sin6_addr))
     458           0 :                                 goto do_notify;
     459           0 :                 }
     460             : 
     461             :                 /*
     462             :                  * Detect if we should notify the error. If no source and
     463             :                  * destination ports are specified, but non-zero flowinfo and
     464             :                  * local address match, notify the error. This is the case
     465             :                  * when the error is delivered with an encrypted buffer
     466             :                  * by ESP. Otherwise, just compare addresses and ports
     467             :                  * as usual.
     468             :                  */
     469           0 :                 if (lport == 0 && fport == 0 && flowinfo &&
     470           0 :                     inp->inp_socket != NULL &&
     471           0 :                     flowinfo == (inp->inp_flowinfo & IPV6_FLOWLABEL_MASK) &&
     472           0 :                     IN6_ARE_ADDR_EQUAL(&inp->inp_laddr6, &sa6_src.sin6_addr))
     473             :                         goto do_notify;
     474           0 :                 else if (!IN6_ARE_ADDR_EQUAL(&inp->inp_faddr6,
     475           0 :                                              &dst->sin6_addr) ||
     476           0 :                          rtable_l2(inp->inp_rtableid) != rdomain ||
     477           0 :                          inp->inp_socket == 0 ||
     478           0 :                          (lport && inp->inp_lport != lport) ||
     479           0 :                          (!IN6_IS_ADDR_UNSPECIFIED(&sa6_src.sin6_addr) &&
     480           0 :                           !IN6_ARE_ADDR_EQUAL(&inp->inp_laddr6,
     481           0 :                                               &sa6_src.sin6_addr)) ||
     482           0 :                          (fport && inp->inp_fport != fport)) {
     483             :                         continue;
     484             :                 }
     485             :           do_notify:
     486           0 :                 nmatch++;
     487           0 :                 if (notify)
     488           0 :                         (*notify)(inp, errno);
     489             :         }
     490           0 :         return (nmatch);
     491           0 : }
     492             : 
     493             : struct inpcb *
     494           0 : in6_pcbhashlookup(struct inpcbtable *table, const struct in6_addr *faddr,
     495             :     u_int fport_arg, const struct in6_addr *laddr, u_int lport_arg,
     496             :     u_int rtable)
     497             : {
     498             :         struct inpcbhead *head;
     499             :         struct inpcb *inp;
     500           0 :         u_int16_t fport = fport_arg, lport = lport_arg;
     501             :         u_int rdomain;
     502             : 
     503           0 :         rdomain = rtable_l2(rtable);
     504           0 :         head = in6_pcbhash(table, rdomain, faddr, fport, laddr, lport);
     505           0 :         LIST_FOREACH(inp, head, inp_hash) {
     506           0 :                 if (!(inp->inp_flags & INP_IPV6))
     507             :                         continue;
     508           0 :                 if (IN6_ARE_ADDR_EQUAL(&inp->inp_faddr6, faddr) &&
     509           0 :                     inp->inp_fport == fport && inp->inp_lport == lport &&
     510           0 :                     IN6_ARE_ADDR_EQUAL(&inp->inp_laddr6, laddr) &&
     511           0 :                     rtable_l2(inp->inp_rtableid) == rdomain) {
     512             :                         /*
     513             :                          * Move this PCB to the head of hash chain so that
     514             :                          * repeated accesses are quicker.  This is analogous to
     515             :                          * the historic single-entry PCB cache.
     516             :                          */
     517           0 :                         if (inp != LIST_FIRST(head)) {
     518           0 :                                 LIST_REMOVE(inp, inp_hash);
     519           0 :                                 LIST_INSERT_HEAD(head, inp, inp_hash);
     520           0 :                         }
     521             :                         break;
     522             :                 }
     523             :         }
     524             : #ifdef DIAGNOSTIC
     525           0 :         if (inp == NULL && in_pcbnotifymiss) {
     526           0 :                 printf("%s: faddr= fport=%d laddr= lport=%d rdom=%u\n",
     527           0 :                     __func__, ntohs(fport), ntohs(lport), rdomain);
     528           0 :         }
     529             : #endif
     530           0 :         return (inp);
     531             : }
     532             : 
     533             : struct inpcb *
     534           0 : in6_pcblookup_listen(struct inpcbtable *table, struct in6_addr *laddr,
     535             :     u_int lport_arg, struct mbuf *m, u_int rtable)
     536             : {
     537             :         struct inpcbhead *head;
     538             :         const struct in6_addr *key1, *key2;
     539             :         struct inpcb *inp;
     540           0 :         u_int16_t lport = lport_arg;
     541             :         u_int rdomain;
     542             : 
     543             :         key1 = laddr;
     544             :         key2 = &zeroin6_addr;
     545             : #if NPF > 0
     546           0 :         if (m && m->m_pkthdr.pf.flags & PF_TAG_DIVERTED) {
     547             :                 struct pf_divert *divert;
     548             : 
     549           0 :                 divert = pf_find_divert(m);
     550           0 :                 KASSERT(divert != NULL);
     551           0 :                 switch (divert->type) {
     552             :                 case PF_DIVERT_TO:
     553           0 :                         key1 = key2 = &divert->addr.v6;
     554           0 :                         lport = divert->port;
     555             :                         break;
     556             :                 case PF_DIVERT_REPLY:
     557           0 :                         return (NULL);
     558             :                 default:
     559           0 :                         panic("%s: unknown divert type %d, mbuf %p, divert %p",
     560             :                             __func__, divert->type, m, divert);
     561             :                 }
     562           0 :         } else if (m && m->m_pkthdr.pf.flags & PF_TAG_TRANSLATE_LOCALHOST) {
     563             :                 /*
     564             :                  * Redirected connections should not be treated the same
     565             :                  * as connections directed to ::1 since localhost
     566             :                  * can only be accessed from the host itself.
     567             :                  */
     568             :                 key1 = &zeroin6_addr;
     569             :                 key2 = laddr;
     570           0 :         }
     571             : #endif
     572             : 
     573           0 :         rdomain = rtable_l2(rtable);
     574           0 :         head = in6_pcbhash(table, rdomain, &zeroin6_addr, 0, key1, lport);
     575           0 :         LIST_FOREACH(inp, head, inp_hash) {
     576           0 :                 if (!(inp->inp_flags & INP_IPV6))
     577             :                         continue;
     578           0 :                 if (inp->inp_lport == lport && inp->inp_fport == 0 &&
     579           0 :                     IN6_ARE_ADDR_EQUAL(&inp->inp_laddr6, key1) &&
     580           0 :                     IN6_IS_ADDR_UNSPECIFIED(&inp->inp_faddr6) &&
     581           0 :                     rtable_l2(inp->inp_rtableid) == rdomain)
     582             :                         break;
     583             :         }
     584           0 :         if (inp == NULL && ! IN6_ARE_ADDR_EQUAL(key1, key2)) {
     585           0 :                 head = in6_pcbhash(table, rdomain,
     586             :                     &zeroin6_addr, 0, key2, lport);
     587           0 :                 LIST_FOREACH(inp, head, inp_hash) {
     588           0 :                         if (!(inp->inp_flags & INP_IPV6))
     589             :                                 continue;
     590           0 :                         if (inp->inp_lport == lport && inp->inp_fport == 0 &&
     591           0 :                             IN6_ARE_ADDR_EQUAL(&inp->inp_laddr6, key2) &&
     592           0 :                             IN6_IS_ADDR_UNSPECIFIED(&inp->inp_faddr6) &&
     593           0 :                             rtable_l2(inp->inp_rtableid) == rdomain)
     594             :                                 break;
     595             :                 }
     596             :         }
     597             :         /*
     598             :          * Move this PCB to the head of hash chain so that
     599             :          * repeated accesses are quicker.  This is analogous to
     600             :          * the historic single-entry PCB cache.
     601             :          */
     602           0 :         if (inp != NULL && inp != LIST_FIRST(head)) {
     603           0 :                 LIST_REMOVE(inp, inp_hash);
     604           0 :                 LIST_INSERT_HEAD(head, inp, inp_hash);
     605           0 :         }
     606             : #ifdef DIAGNOSTIC
     607           0 :         if (inp == NULL && in_pcbnotifymiss) {
     608           0 :                 printf("%s: laddr= lport=%d rdom=%u\n",
     609           0 :                     __func__, ntohs(lport), rdomain);
     610           0 :         }
     611             : #endif
     612           0 :         return (inp);
     613           0 : }

Generated by: LCOV version 1.13