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

          Line data    Source code
       1             : /*      $OpenBSD: ip_icmp.c,v 1.177 2018/09/06 03:42:21 miko Exp $      */
       2             : /*      $NetBSD: ip_icmp.c,v 1.19 1996/02/13 23:42:22 christos Exp $    */
       3             : 
       4             : /*
       5             :  * Copyright (c) 1982, 1986, 1988, 1993
       6             :  *      The Regents of the University of California.  All rights reserved.
       7             :  *
       8             :  * Redistribution and use in source and binary forms, with or without
       9             :  * modification, are permitted provided that the following conditions
      10             :  * are met:
      11             :  * 1. Redistributions of source code must retain the above copyright
      12             :  *    notice, this list of conditions and the following disclaimer.
      13             :  * 2. Redistributions in binary form must reproduce the above copyright
      14             :  *    notice, this list of conditions and the following disclaimer in the
      15             :  *    documentation and/or other materials provided with the distribution.
      16             :  * 3. Neither the name of the University nor the names of its contributors
      17             :  *    may be used to endorse or promote products derived from this software
      18             :  *    without specific prior written permission.
      19             :  *
      20             :  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
      21             :  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
      22             :  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
      23             :  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
      24             :  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
      25             :  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
      26             :  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
      27             :  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
      28             :  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
      29             :  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
      30             :  * SUCH DAMAGE.
      31             :  *
      32             :  *      @(#)COPYRIGHT   1.1 (NRL) 17 January 1995
      33             :  *
      34             :  * NRL grants permission for redistribution and use in source and binary
      35             :  * forms, with or without modification, of the software and documentation
      36             :  * created at NRL provided that the following conditions are met:
      37             :  *
      38             :  * 1. Redistributions of source code must retain the above copyright
      39             :  *    notice, this list of conditions and the following disclaimer.
      40             :  * 2. Redistributions in binary form must reproduce the above copyright
      41             :  *    notice, this list of conditions and the following disclaimer in the
      42             :  *    documentation and/or other materials provided with the distribution.
      43             :  * 3. All advertising materials mentioning features or use of this software
      44             :  *    must display the following acknowledgements:
      45             :  *      This product includes software developed by the University of
      46             :  *      California, Berkeley and its contributors.
      47             :  *      This product includes software developed at the Information
      48             :  *      Technology Division, US Naval Research Laboratory.
      49             :  * 4. Neither the name of the NRL nor the names of its contributors
      50             :  *    may be used to endorse or promote products derived from this software
      51             :  *    without specific prior written permission.
      52             :  *
      53             :  * THE SOFTWARE PROVIDED BY NRL IS PROVIDED BY NRL AND CONTRIBUTORS ``AS
      54             :  * IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
      55             :  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
      56             :  * PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL NRL OR
      57             :  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
      58             :  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
      59             :  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
      60             :  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
      61             :  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
      62             :  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
      63             :  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
      64             :  *
      65             :  * The views and conclusions contained in the software and documentation
      66             :  * are those of the authors and should not be interpreted as representing
      67             :  * official policies, either expressed or implied, of the US Naval
      68             :  * Research Laboratory (NRL).
      69             :  */
      70             : 
      71             : #include "carp.h"
      72             : #include "pf.h"
      73             : 
      74             : #include <sys/param.h>
      75             : #include <sys/systm.h>
      76             : #include <sys/mbuf.h>
      77             : #include <sys/protosw.h>
      78             : #include <sys/socket.h>
      79             : #include <sys/sysctl.h>
      80             : 
      81             : #include <net/if.h>
      82             : #include <net/if_var.h>
      83             : #include <net/route.h>
      84             : 
      85             : #include <netinet/in.h>
      86             : #include <netinet/in_systm.h>
      87             : #include <netinet/in_var.h>
      88             : #include <netinet/ip.h>
      89             : #include <netinet/ip_icmp.h>
      90             : #include <netinet/ip_var.h>
      91             : #include <netinet/icmp_var.h>
      92             : 
      93             : #if NCARP > 0
      94             : #include <net/if_types.h>
      95             : #include <netinet/ip_carp.h>
      96             : #endif
      97             : 
      98             : #if NPF > 0
      99             : #include <net/pfvar.h>
     100             : #endif
     101             : 
     102             : /*
     103             :  * ICMP routines: error generation, receive packet processing, and
     104             :  * routines to turnaround packets back to the originator, and
     105             :  * host table maintenance routines.
     106             :  */
     107             : 
     108             : #ifdef ICMPPRINTFS
     109             : int     icmpprintfs = 0;        /* Settable from ddb */
     110             : #endif
     111             : 
     112             : /* values controllable via sysctl */
     113             : int     icmpmaskrepl = 0;
     114             : int     icmpbmcastecho = 0;
     115             : int     icmptstamprepl = 1;
     116             : int     icmperrppslim = 100;
     117             : int     icmp_rediraccept = 0;
     118             : int     icmp_redirtimeout = 10 * 60;
     119             : 
     120             : static int icmperrpps_count = 0;
     121             : static struct timeval icmperrppslim_last;
     122             : 
     123             : static struct rttimer_queue *icmp_redirect_timeout_q = NULL;
     124             : struct cpumem *icmpcounters;
     125             : 
     126             : int *icmpctl_vars[ICMPCTL_MAXID] = ICMPCTL_VARS;
     127             : 
     128             : void icmp_mtudisc_timeout(struct rtentry *, struct rttimer *);
     129             : int icmp_ratelimit(const struct in_addr *, const int, const int);
     130             : void icmp_redirect_timeout(struct rtentry *, struct rttimer *);
     131             : int icmp_input_if(struct ifnet *, struct mbuf **, int *, int, int);
     132             : int icmp_sysctl_icmpstat(void *, size_t *, void *);
     133             : 
     134             : void
     135           0 : icmp_init(void)
     136             : {
     137           0 :         icmpcounters = counters_alloc(icps_ncounters);
     138             :         /*
     139             :          * This is only useful if the user initializes redirtimeout to
     140             :          * something other than zero.
     141             :          */
     142           0 :         if (icmp_redirtimeout != 0) {
     143           0 :                 icmp_redirect_timeout_q =
     144           0 :                     rt_timer_queue_create(icmp_redirtimeout);
     145           0 :         }
     146           0 : }
     147             : 
     148             : struct mbuf *
     149           0 : icmp_do_error(struct mbuf *n, int type, int code, u_int32_t dest, int destmtu)
     150             : {
     151           0 :         struct ip *oip = mtod(n, struct ip *), *nip;
     152           0 :         unsigned oiplen = oip->ip_hl << 2;
     153             :         struct icmp *icp;
     154             :         struct mbuf *m;
     155             :         unsigned icmplen, mblen;
     156             : 
     157             : #ifdef ICMPPRINTFS
     158             :         if (icmpprintfs)
     159             :                 printf("icmp_error(%x, %d, %d)\n", oip, type, code);
     160             : #endif
     161           0 :         if (type != ICMP_REDIRECT)
     162           0 :                 icmpstat_inc(icps_error);
     163             :         /*
     164             :          * Don't send error if not the first fragment of message.
     165             :          * Don't error if the old packet protocol was ICMP
     166             :          * error message, only known informational types.
     167             :          */
     168           0 :         if (oip->ip_off & htons(IP_OFFMASK))
     169             :                 goto freeit;
     170           0 :         if (oip->ip_p == IPPROTO_ICMP && type != ICMP_REDIRECT &&
     171           0 :             n->m_len >= oiplen + ICMP_MINLEN &&
     172           0 :             !ICMP_INFOTYPE(((struct icmp *)
     173             :             ((caddr_t)oip + oiplen))->icmp_type)) {
     174           0 :                 icmpstat_inc(icps_oldicmp);
     175           0 :                 goto freeit;
     176             :         }
     177             :         /* Don't send error in response to a multicast or broadcast packet */
     178           0 :         if (n->m_flags & (M_BCAST|M_MCAST))
     179             :                 goto freeit;
     180             : 
     181             :         /*
     182             :          * First, do a rate limitation check.
     183             :          */
     184           0 :         if (icmp_ratelimit(&oip->ip_src, type, code)) {
     185           0 :                 icmpstat_inc(icps_toofreq);
     186           0 :                 goto freeit;
     187             :         }
     188             : 
     189             :         /*
     190             :          * Now, formulate icmp message
     191             :          */
     192           0 :         icmplen = oiplen + min(8, ntohs(oip->ip_len));
     193             :         /*
     194             :          * Defend against mbuf chains shorter than oip->ip_len:
     195             :          */
     196             :         mblen = 0;
     197           0 :         for (m = n; m && (mblen < icmplen); m = m->m_next)
     198           0 :                 mblen += m->m_len;
     199           0 :         icmplen = min(mblen, icmplen);
     200             : 
     201             :         /*
     202             :          * As we are not required to return everything we have,
     203             :          * we return whatever we can return at ease.
     204             :          *
     205             :          * Note that ICMP datagrams longer than 576 octets are out of spec
     206             :          * according to RFC1812;
     207             :          */
     208             : 
     209             :         KASSERT(ICMP_MINLEN <= MCLBYTES);
     210             : 
     211           0 :         if (icmplen + ICMP_MINLEN > MCLBYTES)
     212             :                 icmplen = MCLBYTES - ICMP_MINLEN - sizeof (struct ip);
     213             : 
     214           0 :         m = m_gethdr(M_DONTWAIT, MT_HEADER);
     215           0 :         if (m && (sizeof (struct ip) + icmplen + ICMP_MINLEN > MHLEN)) {
     216           0 :                 MCLGET(m, M_DONTWAIT);
     217           0 :                 if ((m->m_flags & M_EXT) == 0) {
     218           0 :                         m_freem(m);
     219             :                         m = NULL;
     220           0 :                 }
     221             :         }
     222           0 :         if (m == NULL)
     223             :                 goto freeit;
     224             :         /* keep in same rtable */
     225           0 :         m->m_pkthdr.ph_rtableid = n->m_pkthdr.ph_rtableid;
     226           0 :         m->m_len = icmplen + ICMP_MINLEN;
     227           0 :         if ((m->m_flags & M_EXT) == 0)
     228           0 :                 MH_ALIGN(m, m->m_len);
     229           0 :         icp = mtod(m, struct icmp *);
     230           0 :         if ((u_int)type > ICMP_MAXTYPE)
     231           0 :                 panic("icmp_error");
     232           0 :         icmpstat_inc(icps_outhist + type);
     233           0 :         icp->icmp_type = type;
     234           0 :         if (type == ICMP_REDIRECT)
     235           0 :                 icp->icmp_gwaddr.s_addr = dest;
     236             :         else {
     237           0 :                 icp->icmp_void = 0;
     238             :                 /*
     239             :                  * The following assignments assume an overlay with the
     240             :                  * zeroed icmp_void field.
     241             :                  */
     242           0 :                 if (type == ICMP_PARAMPROB) {
     243           0 :                         icp->icmp_pptr = code;
     244             :                         code = 0;
     245           0 :                 } else if (type == ICMP_UNREACH &&
     246           0 :                     code == ICMP_UNREACH_NEEDFRAG && destmtu)
     247           0 :                         icp->icmp_nextmtu = htons(destmtu);
     248             :         }
     249             : 
     250           0 :         icp->icmp_code = code;
     251           0 :         m_copydata(n, 0, icmplen, (caddr_t)&icp->icmp_ip);
     252             : 
     253             :         /*
     254             :          * Now, copy old ip header (without options)
     255             :          * in front of icmp message.
     256             :          */
     257           0 :         if ((m->m_flags & M_EXT) == 0 &&
     258           0 :             m->m_data - sizeof(struct ip) < m->m_pktdat)
     259           0 :                 panic("icmp len");
     260           0 :         m->m_data -= sizeof(struct ip);
     261           0 :         m->m_len += sizeof(struct ip);
     262           0 :         m->m_pkthdr.len = m->m_len;
     263           0 :         m->m_pkthdr.ph_ifidx = n->m_pkthdr.ph_ifidx;
     264           0 :         nip = mtod(m, struct ip *);
     265             :         /* ip_v set in ip_output */
     266           0 :         nip->ip_hl = sizeof(struct ip) >> 2;
     267           0 :         nip->ip_tos = 0;
     268           0 :         nip->ip_len = htons(m->m_len);
     269             :         /* ip_id set in ip_output */
     270           0 :         nip->ip_off = 0;
     271             :         /* ip_ttl set in icmp_reflect */
     272           0 :         nip->ip_p = IPPROTO_ICMP;
     273           0 :         nip->ip_src = oip->ip_src;
     274           0 :         nip->ip_dst = oip->ip_dst;
     275             : 
     276             :         /* move PF_GENERATED to new packet, if existent XXX preserve more? */
     277           0 :         if (n->m_pkthdr.pf.flags & PF_TAG_GENERATED)
     278           0 :                 m->m_pkthdr.pf.flags |= PF_TAG_GENERATED;
     279             : 
     280           0 :         m_freem(n);
     281           0 :         return (m);
     282             : 
     283             : freeit:
     284           0 :         m_freem(n);
     285           0 :         return (NULL);
     286           0 : }
     287             : 
     288             : /*
     289             :  * Generate an error packet of type error
     290             :  * in response to bad packet ip.
     291             :  *
     292             :  * The ip packet inside has ip_off and ip_len in host byte order.
     293             :  */
     294             : void
     295           0 : icmp_error(struct mbuf *n, int type, int code, u_int32_t dest, int destmtu)
     296             : {
     297             :         struct mbuf *m;
     298             : 
     299           0 :         m = icmp_do_error(n, type, code, dest, destmtu);
     300           0 :         if (m != NULL)
     301           0 :                 if (!icmp_reflect(m, NULL, NULL))
     302           0 :                         icmp_send(m, NULL);
     303           0 : }
     304             : 
     305             : /*
     306             :  * Process a received ICMP message.
     307             :  */
     308             : int
     309           0 : icmp_input(struct mbuf **mp, int *offp, int proto, int af)
     310             : {
     311             :         struct ifnet *ifp;
     312             : 
     313           0 :         ifp = if_get((*mp)->m_pkthdr.ph_ifidx);
     314           0 :         if (ifp == NULL) {
     315           0 :                 m_freemp(mp);
     316           0 :                 return IPPROTO_DONE;
     317             :         }
     318             : 
     319           0 :         proto = icmp_input_if(ifp, mp, offp, proto, af);
     320           0 :         if_put(ifp);
     321           0 :         return proto;
     322           0 : }
     323             : 
     324             : int
     325           0 : icmp_input_if(struct ifnet *ifp, struct mbuf **mp, int *offp, int proto, int af)
     326             : {
     327           0 :         struct mbuf *m = *mp;
     328           0 :         int hlen = *offp;
     329             :         struct icmp *icp;
     330           0 :         struct ip *ip = mtod(m, struct ip *);
     331           0 :         struct sockaddr_in sin;
     332             :         int icmplen, i, code;
     333             :         struct in_ifaddr *ia;
     334             :         void (*ctlfunc)(int, struct sockaddr *, u_int, void *);
     335           0 :         struct mbuf *opts;
     336             : 
     337             :         /*
     338             :          * Locate icmp structure in mbuf, and check
     339             :          * that not corrupted and of at least minimum length.
     340             :          */
     341           0 :         icmplen = ntohs(ip->ip_len) - hlen;
     342             : #ifdef ICMPPRINTFS
     343             :         if (icmpprintfs) {
     344             :                 char dst[INET_ADDRSTRLEN], src[INET_ADDRSTRLEN];
     345             : 
     346             :                 inet_ntop(AF_INET, &ip->ip_dst, dst, sizeof(dst));
     347             :                 inet_ntop(AF_INET, &ip->ip_src, src, sizeof(src));
     348             : 
     349             :                 printf("icmp_input from %s to %s, len %d\n", src, dst, icmplen);
     350             :         }
     351             : #endif
     352           0 :         if (icmplen < ICMP_MINLEN) {
     353           0 :                 icmpstat_inc(icps_tooshort);
     354           0 :                 goto freeit;
     355             :         }
     356           0 :         i = hlen + min(icmplen, ICMP_ADVLENMIN);
     357           0 :         if (m->m_len < i && (m = *mp = m_pullup(m, i)) == NULL) {
     358           0 :                 icmpstat_inc(icps_tooshort);
     359           0 :                 return IPPROTO_DONE;
     360             :         }
     361           0 :         ip = mtod(m, struct ip *);
     362           0 :         if (in4_cksum(m, 0, hlen, icmplen)) {
     363           0 :                 icmpstat_inc(icps_checksum);
     364           0 :                 goto freeit;
     365             :         }
     366             : 
     367           0 :         icp = (struct icmp *)(mtod(m, caddr_t) + hlen);
     368             : #ifdef ICMPPRINTFS
     369             :         /*
     370             :          * Message type specific processing.
     371             :          */
     372             :         if (icmpprintfs)
     373             :                 printf("icmp_input, type %d code %d\n", icp->icmp_type,
     374             :                     icp->icmp_code);
     375             : #endif
     376           0 :         if (icp->icmp_type > ICMP_MAXTYPE)
     377             :                 goto raw;
     378             : #if NPF > 0
     379           0 :         if (m->m_pkthdr.pf.flags & PF_TAG_DIVERTED) {
     380           0 :                 switch (icp->icmp_type) {
     381             :                  /*
     382             :                   * As pf_icmp_mapping() considers redirects belonging to a
     383             :                   * diverted connection, we must include it here.
     384             :                   */
     385             :                 case ICMP_REDIRECT:
     386             :                         /* FALLTHROUGH */
     387             :                 /*
     388             :                  * These ICMP types map to other connections.  They must be
     389             :                  * delivered to pr_ctlinput() also for diverted connections.
     390             :                  */
     391             :                 case ICMP_UNREACH:
     392             :                 case ICMP_TIMXCEED:
     393             :                 case ICMP_PARAMPROB:
     394             :                 case ICMP_SOURCEQUENCH:
     395             :                         /*
     396             :                          * Do not use the divert-to property of the TCP or UDP
     397             :                          * rule when doing the PCB lookup for the raw socket.
     398             :                          */
     399           0 :                         m->m_pkthdr.pf.flags &=~ PF_TAG_DIVERTED;
     400             :                         break;
     401             :                 default:
     402             :                         goto raw;
     403             :                 }
     404           0 :         }
     405             : #endif /* NPF */
     406           0 :         icmpstat_inc(icps_inhist + icp->icmp_type);
     407           0 :         code = icp->icmp_code;
     408           0 :         switch (icp->icmp_type) {
     409             : 
     410             :         case ICMP_UNREACH:
     411           0 :                 switch (code) {
     412             :                 case ICMP_UNREACH_NET:
     413             :                 case ICMP_UNREACH_HOST:
     414             :                 case ICMP_UNREACH_PROTOCOL:
     415             :                 case ICMP_UNREACH_PORT:
     416             :                 case ICMP_UNREACH_SRCFAIL:
     417           0 :                         code += PRC_UNREACH_NET;
     418           0 :                         break;
     419             : 
     420             :                 case ICMP_UNREACH_NEEDFRAG:
     421             :                         code = PRC_MSGSIZE;
     422           0 :                         break;
     423             : 
     424             :                 case ICMP_UNREACH_NET_UNKNOWN:
     425             :                 case ICMP_UNREACH_NET_PROHIB:
     426             :                 case ICMP_UNREACH_TOSNET:
     427             :                         code = PRC_UNREACH_NET;
     428           0 :                         break;
     429             : 
     430             :                 case ICMP_UNREACH_HOST_UNKNOWN:
     431             :                 case ICMP_UNREACH_ISOLATED:
     432             :                 case ICMP_UNREACH_HOST_PROHIB:
     433             :                 case ICMP_UNREACH_TOSHOST:
     434             :                 case ICMP_UNREACH_FILTER_PROHIB:
     435             :                 case ICMP_UNREACH_HOST_PRECEDENCE:
     436             :                 case ICMP_UNREACH_PRECEDENCE_CUTOFF:
     437             :                         code = PRC_UNREACH_HOST;
     438           0 :                         break;
     439             : 
     440             :                 default:
     441             :                         goto badcode;
     442             :                 }
     443             :                 goto deliver;
     444             : 
     445             :         case ICMP_TIMXCEED:
     446           0 :                 if (code > 1)
     447             :                         goto badcode;
     448           0 :                 code += PRC_TIMXCEED_INTRANS;
     449           0 :                 goto deliver;
     450             : 
     451             :         case ICMP_PARAMPROB:
     452           0 :                 if (code > 1)
     453             :                         goto badcode;
     454             :                 code = PRC_PARAMPROB;
     455           0 :                 goto deliver;
     456             : 
     457             :         case ICMP_SOURCEQUENCH:
     458           0 :                 if (code)
     459             :                         goto badcode;
     460           0 :                 code = PRC_QUENCH;
     461             :         deliver:
     462             :                 /*
     463             :                  * Problem with datagram; advise higher level routines.
     464             :                  */
     465           0 :                 if (icmplen < ICMP_ADVLENMIN || icmplen < ICMP_ADVLEN(icp) ||
     466           0 :                     icp->icmp_ip.ip_hl < (sizeof(struct ip) >> 2)) {
     467           0 :                         icmpstat_inc(icps_badlen);
     468           0 :                         goto freeit;
     469             :                 }
     470           0 :                 if (IN_MULTICAST(icp->icmp_ip.ip_dst.s_addr))
     471             :                         goto badcode;
     472             : #ifdef INET6
     473             :                 /* Get more contiguous data for a v6 in v4 ICMP message. */
     474           0 :                 if (icp->icmp_ip.ip_p == IPPROTO_IPV6) {
     475           0 :                         if (icmplen < ICMP_V6ADVLENMIN ||
     476           0 :                             icmplen < ICMP_V6ADVLEN(icp)) {
     477           0 :                                 icmpstat_inc(icps_badlen);
     478           0 :                                 goto freeit;
     479             :                         } else {
     480           0 :                                 if ((m = *mp = m_pullup(m, (ip->ip_hl << 2) +
     481           0 :                                     ICMP_V6ADVLEN(icp))) == NULL) {
     482           0 :                                         icmpstat_inc(icps_tooshort);
     483           0 :                                         return IPPROTO_DONE;
     484             :                                 }
     485           0 :                                 ip = mtod(m, struct ip *);
     486           0 :                                 icp = (struct icmp *)
     487           0 :                                     (m->m_data + (ip->ip_hl << 2));
     488             :                         }
     489           0 :                 }
     490             : #endif /* INET6 */
     491             : #ifdef ICMPPRINTFS
     492             :                 if (icmpprintfs)
     493             :                         printf("deliver to protocol %d\n", icp->icmp_ip.ip_p);
     494             : #endif
     495           0 :                 memset(&sin, 0, sizeof(sin));
     496           0 :                 sin.sin_family = AF_INET;
     497           0 :                 sin.sin_len = sizeof(struct sockaddr_in);
     498           0 :                 sin.sin_addr = icp->icmp_ip.ip_dst;
     499             : #if NCARP > 0
     500           0 :                 if (carp_lsdrop(ifp, m, AF_INET, &sin.sin_addr.s_addr,
     501           0 :                     &ip->ip_dst.s_addr, 1))
     502             :                         goto freeit;
     503             : #endif
     504             :                 /*
     505             :                  * XXX if the packet contains [IPv4 AH TCP], we can't make a
     506             :                  * notification to TCP layer.
     507             :                  */
     508           0 :                 ctlfunc = inetsw[ip_protox[icp->icmp_ip.ip_p]].pr_ctlinput;
     509           0 :                 if (ctlfunc)
     510           0 :                         (*ctlfunc)(code, sintosa(&sin), m->m_pkthdr.ph_rtableid,
     511           0 :                             &icp->icmp_ip);
     512             :                 break;
     513             : 
     514             :         badcode:
     515           0 :                 icmpstat_inc(icps_badcode);
     516           0 :                 break;
     517             : 
     518             :         case ICMP_ECHO:
     519           0 :                 if (!icmpbmcastecho &&
     520           0 :                     (m->m_flags & (M_MCAST | M_BCAST)) != 0) {
     521           0 :                         icmpstat_inc(icps_bmcastecho);
     522           0 :                         break;
     523             :                 }
     524           0 :                 icp->icmp_type = ICMP_ECHOREPLY;
     525           0 :                 goto reflect;
     526             : 
     527             :         case ICMP_TSTAMP:
     528           0 :                 if (icmptstamprepl == 0)
     529             :                         break;
     530             : 
     531           0 :                 if (!icmpbmcastecho &&
     532           0 :                     (m->m_flags & (M_MCAST | M_BCAST)) != 0) {
     533           0 :                         icmpstat_inc(icps_bmcastecho);
     534           0 :                         break;
     535             :                 }
     536           0 :                 if (icmplen < ICMP_TSLEN) {
     537           0 :                         icmpstat_inc(icps_badlen);
     538           0 :                         break;
     539             :                 }
     540           0 :                 icp->icmp_type = ICMP_TSTAMPREPLY;
     541           0 :                 icp->icmp_rtime = iptime();
     542           0 :                 icp->icmp_ttime = icp->icmp_rtime;        /* bogus, do later! */
     543           0 :                 goto reflect;
     544             : 
     545             :         case ICMP_MASKREQ:
     546           0 :                 if (icmpmaskrepl == 0)
     547             :                         break;
     548           0 :                 if (icmplen < ICMP_MASKLEN) {
     549           0 :                         icmpstat_inc(icps_badlen);
     550           0 :                         break;
     551             :                 }
     552             :                 /*
     553             :                  * We are not able to respond with all ones broadcast
     554             :                  * unless we receive it over a point-to-point interface.
     555             :                  */
     556           0 :                 memset(&sin, 0, sizeof(sin));
     557           0 :                 sin.sin_family = AF_INET;
     558           0 :                 sin.sin_len = sizeof(struct sockaddr_in);
     559           0 :                 if (ip->ip_dst.s_addr == INADDR_BROADCAST ||
     560           0 :                     ip->ip_dst.s_addr == INADDR_ANY)
     561           0 :                         sin.sin_addr = ip->ip_src;
     562             :                 else
     563           0 :                         sin.sin_addr = ip->ip_dst;
     564           0 :                 if (ifp == NULL)
     565             :                         break;
     566           0 :                 ia = ifatoia(ifaof_ifpforaddr(sintosa(&sin), ifp));
     567           0 :                 if (ia == NULL)
     568             :                         break;
     569           0 :                 icp->icmp_type = ICMP_MASKREPLY;
     570           0 :                 icp->icmp_mask = ia->ia_sockmask.sin_addr.s_addr;
     571           0 :                 if (ip->ip_src.s_addr == 0) {
     572           0 :                         if (ifp->if_flags & IFF_BROADCAST) {
     573           0 :                                 if (ia->ia_broadaddr.sin_addr.s_addr)
     574           0 :                                         ip->ip_src = ia->ia_broadaddr.sin_addr;
     575             :                                 else
     576           0 :                                         ip->ip_src.s_addr = INADDR_BROADCAST;
     577             :                         }
     578           0 :                         else if (ifp->if_flags & IFF_POINTOPOINT)
     579           0 :                                 ip->ip_src = ia->ia_dstaddr.sin_addr;
     580             :                 }
     581             : reflect:
     582             : #if NCARP > 0
     583           0 :                 if (carp_lsdrop(ifp, m, AF_INET, &ip->ip_src.s_addr,
     584           0 :                     &ip->ip_dst.s_addr, 1))
     585             :                         goto freeit;
     586             : #endif
     587           0 :                 icmpstat_inc(icps_reflect);
     588           0 :                 icmpstat_inc(icps_outhist + icp->icmp_type);
     589           0 :                 if (!icmp_reflect(m, &opts, NULL)) {
     590           0 :                         icmp_send(m, opts);
     591           0 :                         m_free(opts);
     592           0 :                 }
     593           0 :                 return IPPROTO_DONE;
     594             : 
     595             :         case ICMP_REDIRECT:
     596             :         {
     597           0 :                 struct sockaddr_in sdst;
     598           0 :                 struct sockaddr_in sgw;
     599           0 :                 struct sockaddr_in ssrc;
     600           0 :                 struct rtentry *newrt = NULL;
     601             : 
     602           0 :                 if (icmp_rediraccept == 0 || ipforwarding == 1)
     603           0 :                         goto freeit;
     604           0 :                 if (code > 3)
     605           0 :                         goto badcode;
     606           0 :                 if (icmplen < ICMP_ADVLENMIN || icmplen < ICMP_ADVLEN(icp) ||
     607           0 :                     icp->icmp_ip.ip_hl < (sizeof(struct ip) >> 2)) {
     608           0 :                         icmpstat_inc(icps_badlen);
     609           0 :                         break;
     610             :                 }
     611             :                 /*
     612             :                  * Short circuit routing redirects to force
     613             :                  * immediate change in the kernel's routing
     614             :                  * tables.  The message is also handed to anyone
     615             :                  * listening on a raw socket (e.g. the routing
     616             :                  * daemon for use in updating its tables).
     617             :                  */
     618           0 :                 memset(&sdst, 0, sizeof(sdst));
     619           0 :                 memset(&sgw, 0, sizeof(sgw));
     620           0 :                 memset(&ssrc, 0, sizeof(ssrc));
     621           0 :                 sdst.sin_family = sgw.sin_family = ssrc.sin_family = AF_INET;
     622           0 :                 sdst.sin_len = sgw.sin_len = ssrc.sin_len = sizeof(sdst);
     623           0 :                 memcpy(&sdst.sin_addr, &icp->icmp_ip.ip_dst,
     624             :                     sizeof(sdst.sin_addr));
     625           0 :                 memcpy(&sgw.sin_addr, &icp->icmp_gwaddr,
     626             :                     sizeof(sgw.sin_addr));
     627           0 :                 memcpy(&ssrc.sin_addr, &ip->ip_src,
     628             :                     sizeof(ssrc.sin_addr));
     629             : 
     630             : #ifdef  ICMPPRINTFS
     631             :                 if (icmpprintfs) {
     632             :                         char gw[INET_ADDRSTRLEN], dst[INET_ADDRSTRLEN];
     633             : 
     634             :                         inet_ntop(AF_INET, &icp->icmp_gwaddr, gw, sizeof(gw));
     635             :                         inet_ntop(AF_INET, &icp->icmp_ip.ip_dst,
     636             :                             dst, sizeof(dst));
     637             : 
     638             :                         printf("redirect dst %s to %s\n", dst, gw);
     639             :                 }
     640             : #endif
     641             : 
     642             : #if NCARP > 0
     643           0 :                 if (carp_lsdrop(ifp, m, AF_INET, &sdst.sin_addr.s_addr,
     644           0 :                     &ip->ip_dst.s_addr, 1))
     645           0 :                         goto freeit;
     646             : #endif
     647           0 :                 rtredirect(sintosa(&sdst), sintosa(&sgw),
     648           0 :                     sintosa(&ssrc), &newrt, m->m_pkthdr.ph_rtableid);
     649           0 :                 if (newrt != NULL && icmp_redirtimeout != 0) {
     650           0 :                         (void)rt_timer_add(newrt, icmp_redirect_timeout,
     651           0 :                             icmp_redirect_timeout_q, m->m_pkthdr.ph_rtableid);
     652           0 :                 }
     653           0 :                 if (newrt != NULL)
     654           0 :                         rtfree(newrt);
     655           0 :                 pfctlinput(PRC_REDIRECT_HOST, sintosa(&sdst));
     656           0 :                 break;
     657           0 :         }
     658             :         /*
     659             :          * No kernel processing for the following;
     660             :          * just fall through to send to raw listener.
     661             :          */
     662             :         case ICMP_ECHOREPLY:
     663             :         case ICMP_ROUTERADVERT:
     664             :         case ICMP_ROUTERSOLICIT:
     665             :         case ICMP_TSTAMPREPLY:
     666             :         case ICMP_IREQREPLY:
     667             :         case ICMP_MASKREPLY:
     668             :         case ICMP_TRACEROUTE:
     669             :         case ICMP_DATACONVERR:
     670             :         case ICMP_MOBILE_REDIRECT:
     671             :         case ICMP_IPV6_WHEREAREYOU:
     672             :         case ICMP_IPV6_IAMHERE:
     673             :         case ICMP_MOBILE_REGREQUEST:
     674             :         case ICMP_MOBILE_REGREPLY:
     675             :         case ICMP_PHOTURIS:
     676             :         default:
     677             :                 break;
     678             :         }
     679             : 
     680             : raw:
     681           0 :         return rip_input(mp, offp, proto, af);
     682             : 
     683             : freeit:
     684           0 :         m_freem(m);
     685           0 :         return IPPROTO_DONE;
     686           0 : }
     687             : 
     688             : /*
     689             :  * Reflect the ip packet back to the source
     690             :  */
     691             : int
     692           0 : icmp_reflect(struct mbuf *m, struct mbuf **op, struct in_ifaddr *ia)
     693             : {
     694           0 :         struct ip *ip = mtod(m, struct ip *);
     695             :         struct mbuf *opts = NULL;
     696           0 :         struct sockaddr_in sin;
     697             :         struct rtentry *rt = NULL;
     698           0 :         int optlen = (ip->ip_hl << 2) - sizeof(struct ip);
     699             :         u_int rtableid;
     700             : 
     701           0 :         if (!in_canforward(ip->ip_src) &&
     702           0 :             ((ip->ip_src.s_addr & IN_CLASSA_NET) !=
     703             :             htonl(IN_LOOPBACKNET << IN_CLASSA_NSHIFT))) {
     704           0 :                 m_freem(m);             /* Bad return address */
     705           0 :                 return (EHOSTUNREACH);
     706             :         }
     707             : 
     708           0 :         if (m->m_pkthdr.ph_loopcnt++ >= M_MAXLOOP) {
     709           0 :                 m_freem(m);
     710           0 :                 return (ELOOP);
     711             :         }
     712           0 :         rtableid = m->m_pkthdr.ph_rtableid;
     713           0 :         m_resethdr(m);
     714           0 :         m->m_pkthdr.ph_rtableid = rtableid;
     715             : 
     716             :         /*
     717             :          * If the incoming packet was addressed directly to us,
     718             :          * use dst as the src for the reply.  For broadcast, use
     719             :          * the address which corresponds to the incoming interface.
     720             :          */
     721           0 :         if (ia == NULL) {
     722           0 :                 memset(&sin, 0, sizeof(sin));
     723           0 :                 sin.sin_len = sizeof(sin);
     724           0 :                 sin.sin_family = AF_INET;
     725           0 :                 sin.sin_addr = ip->ip_dst;
     726             : 
     727           0 :                 rt = rtalloc(sintosa(&sin), 0, rtableid);
     728           0 :                 if (rtisvalid(rt) &&
     729           0 :                     ISSET(rt->rt_flags, RTF_LOCAL|RTF_BROADCAST))
     730           0 :                         ia = ifatoia(rt->rt_ifa);
     731             :         }
     732             : 
     733             :         /*
     734             :          * The following happens if the packet was not addressed to us.
     735             :          * Use the new source address and do a route lookup. If it fails
     736             :          * drop the packet as there is no path to the host.
     737             :          */
     738           0 :         if (ia == NULL) {
     739           0 :                 rtfree(rt);
     740             : 
     741           0 :                 memset(&sin, 0, sizeof(sin));
     742           0 :                 sin.sin_len = sizeof(sin);
     743           0 :                 sin.sin_family = AF_INET;
     744           0 :                 sin.sin_addr = ip->ip_src;
     745             : 
     746             :                 /* keep packet in the original virtual instance */
     747           0 :                 rt = rtalloc(sintosa(&sin), RT_RESOLVE, rtableid);
     748           0 :                 if (rt == NULL) {
     749           0 :                         ipstat_inc(ips_noroute);
     750           0 :                         m_freem(m);
     751           0 :                         return (EHOSTUNREACH);
     752             :                 }
     753             : 
     754           0 :                 ia = ifatoia(rt->rt_ifa);
     755           0 :         }
     756             : 
     757           0 :         ip->ip_dst = ip->ip_src;
     758           0 :         ip->ip_ttl = MAXTTL;
     759             : 
     760             :         /* It is safe to dereference ``ia'' iff ``rt'' is valid. */
     761           0 :         ip->ip_src = ia->ia_addr.sin_addr;
     762           0 :         rtfree(rt);
     763             : 
     764           0 :         if (optlen > 0) {
     765             :                 u_char *cp;
     766             :                 int opt, cnt;
     767             :                 u_int len;
     768             : 
     769             :                 /*
     770             :                  * Retrieve any source routing from the incoming packet;
     771             :                  * add on any record-route or timestamp options.
     772             :                  */
     773           0 :                 cp = (u_char *) (ip + 1);
     774           0 :                 if (op && (opts = ip_srcroute(m)) == NULL &&
     775           0 :                     (opts = m_gethdr(M_DONTWAIT, MT_HEADER))) {
     776           0 :                         opts->m_len = sizeof(struct in_addr);
     777           0 :                         mtod(opts, struct in_addr *)->s_addr = 0;
     778           0 :                 }
     779           0 :                 if (op && opts) {
     780             : #ifdef ICMPPRINTFS
     781             :                         if (icmpprintfs)
     782             :                                 printf("icmp_reflect optlen %d rt %d => ",
     783             :                                     optlen, opts->m_len);
     784             : #endif
     785           0 :                         for (cnt = optlen; cnt > 0; cnt -= len, cp += len) {
     786           0 :                                 opt = cp[IPOPT_OPTVAL];
     787           0 :                                 if (opt == IPOPT_EOL)
     788             :                                         break;
     789           0 :                                 if (opt == IPOPT_NOP)
     790           0 :                                         len = 1;
     791             :                                 else {
     792           0 :                                         if (cnt < IPOPT_OLEN + sizeof(*cp))
     793             :                                                 break;
     794           0 :                                         len = cp[IPOPT_OLEN];
     795           0 :                                         if (len < IPOPT_OLEN + sizeof(*cp) ||
     796           0 :                                             len > cnt)
     797             :                                                 break;
     798             :                                 }
     799             :                                 /*
     800             :                                  * Should check for overflow, but it
     801             :                                  * "can't happen"
     802             :                                  */
     803           0 :                                 if (opt == IPOPT_RR || opt == IPOPT_TS ||
     804           0 :                                     opt == IPOPT_SECURITY) {
     805           0 :                                         memcpy(mtod(opts, caddr_t) +
     806             :                                             opts->m_len, cp, len);
     807           0 :                                         opts->m_len += len;
     808           0 :                                 }
     809             :                         }
     810             :                         /* Terminate & pad, if necessary */
     811           0 :                         if ((cnt = opts->m_len % 4) != 0)
     812           0 :                                 for (; cnt < 4; cnt++) {
     813           0 :                                         *(mtod(opts, caddr_t) + opts->m_len) =
     814             :                                             IPOPT_EOL;
     815           0 :                                         opts->m_len++;
     816             :                                 }
     817             : #ifdef ICMPPRINTFS
     818             :                         if (icmpprintfs)
     819             :                                 printf("%d\n", opts->m_len);
     820             : #endif
     821             :                 }
     822           0 :                 ip_stripoptions(m);
     823           0 :         }
     824           0 :         m->m_flags &= ~(M_BCAST|M_MCAST);
     825           0 :         if (op)
     826           0 :                 *op = opts;
     827             : 
     828           0 :         return (0);
     829           0 : }
     830             : 
     831             : /*
     832             :  * Send an icmp packet back to the ip level
     833             :  */
     834             : void
     835           0 : icmp_send(struct mbuf *m, struct mbuf *opts)
     836             : {
     837           0 :         struct ip *ip = mtod(m, struct ip *);
     838           0 :         int hlen;
     839             :         struct icmp *icp;
     840             : 
     841           0 :         hlen = ip->ip_hl << 2;
     842           0 :         icp = (struct icmp *)(mtod(m, caddr_t) + hlen);
     843           0 :         icp->icmp_cksum = 0;
     844           0 :         m->m_pkthdr.csum_flags = M_ICMP_CSUM_OUT;
     845             : #ifdef ICMPPRINTFS
     846             :         if (icmpprintfs) {
     847             :                 char dst[INET_ADDRSTRLEN], src[INET_ADDRSTRLEN];
     848             : 
     849             :                 inet_ntop(AF_INET, &ip->ip_dst, dst, sizeof(dst));
     850             :                 inet_ntop(AF_INET, &ip->ip_src, src, sizeof(src));
     851             : 
     852             :                 printf("icmp_send dst %s src %s\n", dst, src);
     853             :         }
     854             : #endif
     855           0 :         if (opts != NULL)
     856           0 :                 m = ip_insertoptions(m, opts, &hlen);
     857             : 
     858           0 :         ip_send(m);
     859           0 : }
     860             : 
     861             : u_int32_t
     862           0 : iptime(void)
     863             : {
     864           0 :         struct timeval atv;
     865             :         u_long t;
     866             : 
     867           0 :         microtime(&atv);
     868           0 :         t = (atv.tv_sec % (24*60*60)) * 1000 + atv.tv_usec / 1000;
     869           0 :         return (htonl(t));
     870           0 : }
     871             : 
     872             : int
     873           0 : icmp_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, void *newp,
     874             :     size_t newlen)
     875             : {
     876             :         int error;
     877             : 
     878             :         /* All sysctl names at this level are terminal. */
     879           0 :         if (namelen != 1)
     880           0 :                 return (ENOTDIR);
     881             : 
     882           0 :         switch (name[0]) {
     883             :         case ICMPCTL_REDIRTIMEOUT:
     884             : 
     885           0 :                 NET_LOCK();
     886           0 :                 error = sysctl_int(oldp, oldlenp, newp, newlen,
     887             :                     &icmp_redirtimeout);
     888           0 :                 if (icmp_redirect_timeout_q != NULL) {
     889           0 :                         if (icmp_redirtimeout == 0) {
     890           0 :                                 rt_timer_queue_destroy(icmp_redirect_timeout_q);
     891           0 :                                 icmp_redirect_timeout_q = NULL;
     892           0 :                         } else
     893           0 :                                 rt_timer_queue_change(icmp_redirect_timeout_q,
     894           0 :                                     icmp_redirtimeout);
     895           0 :                 } else if (icmp_redirtimeout > 0) {
     896           0 :                         icmp_redirect_timeout_q =
     897           0 :                             rt_timer_queue_create(icmp_redirtimeout);
     898           0 :                 }
     899           0 :                 NET_UNLOCK();
     900           0 :                 break;
     901             : 
     902             :         case ICMPCTL_STATS:
     903           0 :                 error = icmp_sysctl_icmpstat(oldp, oldlenp, newp);
     904           0 :                 break;
     905             : 
     906             :         default:
     907           0 :                 if (name[0] < ICMPCTL_MAXID) {
     908           0 :                         NET_LOCK();
     909           0 :                         error = sysctl_int_arr(icmpctl_vars, name, namelen,
     910             :                             oldp, oldlenp, newp, newlen);
     911           0 :                         NET_UNLOCK();
     912           0 :                         break;
     913             :                 }
     914             :                 error = ENOPROTOOPT;
     915           0 :                 break;
     916             :         }
     917             : 
     918           0 :         return (error);
     919           0 : }
     920             : 
     921             : int
     922           0 : icmp_sysctl_icmpstat(void *oldp, size_t *oldlenp, void *newp)
     923             : {
     924           0 :         uint64_t counters[icps_ncounters];
     925           0 :         struct icmpstat icmpstat;
     926           0 :         u_long *words = (u_long *)&icmpstat;
     927             :         int i;
     928             : 
     929             :         CTASSERT(sizeof(icmpstat) == (nitems(counters) * sizeof(u_long)));
     930           0 :         memset(&icmpstat, 0, sizeof icmpstat);
     931           0 :         counters_read(icmpcounters, counters, nitems(counters));
     932             : 
     933           0 :         for (i = 0; i < nitems(counters); i++)
     934           0 :                 words[i] = (u_long)counters[i];
     935             : 
     936           0 :         return (sysctl_rdstruct(oldp, oldlenp, newp,
     937             :             &icmpstat, sizeof(icmpstat)));
     938           0 : }
     939             : 
     940             : struct rtentry *
     941           0 : icmp_mtudisc_clone(struct in_addr dst, u_int rtableid)
     942             : {
     943           0 :         struct sockaddr_in sin;
     944             :         struct rtentry *rt;
     945             :         int error;
     946             : 
     947           0 :         memset(&sin, 0, sizeof(sin));
     948           0 :         sin.sin_family = AF_INET;
     949           0 :         sin.sin_len = sizeof(sin);
     950           0 :         sin.sin_addr = dst;
     951             : 
     952           0 :         rt = rtalloc(sintosa(&sin), RT_RESOLVE, rtableid);
     953             : 
     954             :         /* Check if the route is actually usable */
     955           0 :         if (!rtisvalid(rt) || (rt->rt_flags & (RTF_REJECT|RTF_BLACKHOLE)))
     956             :                 goto bad;
     957             : 
     958             :         /*
     959             :          * No PMTU for local routes and permanent neighbors,
     960             :          * ARP and NDP use the same expire timer as the route.
     961             :          */
     962           0 :         if (ISSET(rt->rt_flags, RTF_LOCAL) ||
     963           0 :             (ISSET(rt->rt_flags, RTF_LLINFO) && rt->rt_expire == 0))
     964             :                 goto bad;
     965             : 
     966             :         /* If we didn't get a host route, allocate one */
     967           0 :         if ((rt->rt_flags & RTF_HOST) == 0) {
     968           0 :                 struct rtentry *nrt;
     969           0 :                 struct rt_addrinfo info;
     970           0 :                 struct sockaddr_rtlabel sa_rl;
     971             : 
     972           0 :                 memset(&info, 0, sizeof(info));
     973           0 :                 info.rti_ifa = rt->rt_ifa;
     974           0 :                 info.rti_flags = RTF_GATEWAY | RTF_HOST | RTF_DYNAMIC;
     975           0 :                 info.rti_info[RTAX_DST] = sintosa(&sin);
     976           0 :                 info.rti_info[RTAX_GATEWAY] = rt->rt_gateway;
     977           0 :                 info.rti_info[RTAX_LABEL] =
     978           0 :                     rtlabel_id2sa(rt->rt_labelid, &sa_rl);
     979             : 
     980           0 :                 error = rtrequest(RTM_ADD, &info, rt->rt_priority, &nrt,
     981             :                     rtableid);
     982           0 :                 if (error)
     983           0 :                         goto bad;
     984           0 :                 nrt->rt_rmx = rt->rt_rmx;
     985           0 :                 rtfree(rt);
     986           0 :                 rt = nrt;
     987           0 :                 rtm_send(rt, RTM_ADD, 0, rtableid);
     988           0 :         }
     989           0 :         error = rt_timer_add(rt, icmp_mtudisc_timeout, ip_mtudisc_timeout_q,
     990             :             rtableid);
     991           0 :         if (error)
     992             :                 goto bad;
     993             : 
     994           0 :         return (rt);
     995             : bad:
     996           0 :         rtfree(rt);
     997           0 :         return (NULL);
     998           0 : }
     999             : 
    1000             : /* Table of common MTUs: */
    1001             : static const u_short mtu_table[] = {
    1002             :         65535, 65280, 32000, 17914, 9180, 8166,
    1003             :         4352, 2002, 1492, 1006, 508, 296, 68, 0
    1004             : };
    1005             : 
    1006             : void
    1007           0 : icmp_mtudisc(struct icmp *icp, u_int rtableid)
    1008             : {
    1009             :         struct rtentry *rt;
    1010             :         struct ifnet *ifp;
    1011           0 :         u_long mtu = ntohs(icp->icmp_nextmtu);  /* Why a long?  IPv6 */
    1012             : 
    1013           0 :         rt = icmp_mtudisc_clone(icp->icmp_ip.ip_dst, rtableid);
    1014           0 :         if (rt == NULL)
    1015           0 :                 return;
    1016             : 
    1017           0 :         ifp = if_get(rt->rt_ifidx);
    1018           0 :         if (ifp == NULL) {
    1019           0 :                 rtfree(rt);
    1020           0 :                 return;
    1021             :         }
    1022             : 
    1023           0 :         if (mtu == 0) {
    1024             :                 int i = 0;
    1025             : 
    1026           0 :                 mtu = ntohs(icp->icmp_ip.ip_len);
    1027             :                 /* Some 4.2BSD-based routers incorrectly adjust the ip_len */
    1028           0 :                 if (mtu > rt->rt_mtu && rt->rt_mtu != 0)
    1029           0 :                         mtu -= (icp->icmp_ip.ip_hl << 2);
    1030             : 
    1031             :                 /* If we still can't guess a value, try the route */
    1032           0 :                 if (mtu == 0) {
    1033           0 :                         mtu = rt->rt_mtu;
    1034             : 
    1035             :                         /* If no route mtu, default to the interface mtu */
    1036             : 
    1037           0 :                         if (mtu == 0)
    1038           0 :                                 mtu = ifp->if_mtu;
    1039             :                 }
    1040             : 
    1041           0 :                 for (i = 0; i < nitems(mtu_table); i++)
    1042           0 :                         if (mtu > mtu_table[i]) {
    1043             :                                 mtu = mtu_table[i];
    1044           0 :                                 break;
    1045             :                         }
    1046           0 :         }
    1047             : 
    1048             :         /*
    1049             :          * XXX:   RTV_MTU is overloaded, since the admin can set it
    1050             :          *        to turn off PMTU for a route, and the kernel can
    1051             :          *        set it to indicate a serious problem with PMTU
    1052             :          *        on a route.  We should be using a separate flag
    1053             :          *        for the kernel to indicate this.
    1054             :          */
    1055           0 :         if ((rt->rt_locks & RTV_MTU) == 0) {
    1056           0 :                 if (mtu < 296 || mtu > ifp->if_mtu)
    1057           0 :                         rt->rt_locks |= RTV_MTU;
    1058           0 :                 else if (rt->rt_mtu > mtu || rt->rt_mtu == 0)
    1059           0 :                         rt->rt_mtu = mtu;
    1060             :         }
    1061             : 
    1062           0 :         if_put(ifp);
    1063           0 :         rtfree(rt);
    1064           0 : }
    1065             : 
    1066             : void
    1067           0 : icmp_mtudisc_timeout(struct rtentry *rt, struct rttimer *r)
    1068             : {
    1069             :         struct ifnet *ifp;
    1070             : 
    1071           0 :         NET_ASSERT_LOCKED();
    1072             : 
    1073           0 :         ifp = if_get(rt->rt_ifidx);
    1074           0 :         if (ifp == NULL)
    1075           0 :                 return;
    1076             : 
    1077           0 :         if ((rt->rt_flags & (RTF_DYNAMIC|RTF_HOST)) == (RTF_DYNAMIC|RTF_HOST)) {
    1078             :                 void (*ctlfunc)(int, struct sockaddr *, u_int, void *);
    1079           0 :                 struct sockaddr_in sin;
    1080             : 
    1081           0 :                 sin = *satosin(rt_key(rt));
    1082             : 
    1083           0 :                 rtdeletemsg(rt, ifp, r->rtt_tableid);
    1084             : 
    1085             :                 /* Notify TCP layer of increased Path MTU estimate */
    1086           0 :                 ctlfunc = inetsw[ip_protox[IPPROTO_TCP]].pr_ctlinput;
    1087           0 :                 if (ctlfunc)
    1088           0 :                         (*ctlfunc)(PRC_MTUINC, sintosa(&sin),
    1089           0 :                             r->rtt_tableid, NULL);
    1090           0 :         } else {
    1091           0 :                 if ((rt->rt_locks & RTV_MTU) == 0)
    1092           0 :                         rt->rt_mtu = 0;
    1093             :         }
    1094             : 
    1095           0 :         if_put(ifp);
    1096           0 : }
    1097             : 
    1098             : /*
    1099             :  * Perform rate limit check.
    1100             :  * Returns 0 if it is okay to send the icmp packet.
    1101             :  * Returns 1 if the router SHOULD NOT send this icmp packet due to rate
    1102             :  * limitation.
    1103             :  *
    1104             :  * XXX per-destination/type check necessary?
    1105             :  */
    1106             : int
    1107           0 : icmp_ratelimit(const struct in_addr *dst, const int type, const int code)
    1108             : {
    1109             :         /* PPS limit */
    1110           0 :         if (!ppsratecheck(&icmperrppslim_last, &icmperrpps_count,
    1111           0 :             icmperrppslim))
    1112           0 :                 return 1;       /* The packet is subject to rate limit */
    1113           0 :         return 0;       /* okay to send */
    1114           0 : }
    1115             : 
    1116             : void
    1117           0 : icmp_redirect_timeout(struct rtentry *rt, struct rttimer *r)
    1118             : {
    1119             :         struct ifnet *ifp;
    1120             : 
    1121           0 :         NET_ASSERT_LOCKED();
    1122             : 
    1123           0 :         ifp = if_get(rt->rt_ifidx);
    1124           0 :         if (ifp == NULL)
    1125           0 :                 return;
    1126             : 
    1127           0 :         if ((rt->rt_flags & (RTF_DYNAMIC|RTF_HOST)) == (RTF_DYNAMIC|RTF_HOST)) {
    1128           0 :                 rtdeletemsg(rt, ifp, r->rtt_tableid);
    1129           0 :         }
    1130             : 
    1131           0 :         if_put(ifp);
    1132           0 : }
    1133             : 
    1134             : int
    1135           0 : icmp_do_exthdr(struct mbuf *m, u_int16_t class, u_int8_t ctype, void *buf,
    1136             :     size_t len)
    1137             : {
    1138           0 :         struct ip *ip = mtod(m, struct ip *);
    1139           0 :         int hlen, off;
    1140             :         struct mbuf *n;
    1141             :         struct icmp *icp;
    1142             :         struct icmp_ext_hdr *ieh;
    1143           0 :         struct {
    1144             :                 struct icmp_ext_hdr     ieh;
    1145             :                 struct icmp_ext_obj_hdr ieo;
    1146             :         } hdr;
    1147             : 
    1148           0 :         hlen = ip->ip_hl << 2;
    1149           0 :         icp = (struct icmp *)(mtod(m, caddr_t) + hlen);
    1150           0 :         if (icp->icmp_type != ICMP_TIMXCEED && icp->icmp_type != ICMP_UNREACH &&
    1151           0 :             icp->icmp_type != ICMP_PARAMPROB)
    1152             :                 /* exthdr not supported */
    1153           0 :                 return (0);
    1154             : 
    1155           0 :         if (icp->icmp_length != 0)
    1156             :                 /* exthdr already present, giving up */
    1157           0 :                 return (0);
    1158             : 
    1159             :         /* the actual offset starts after the common ICMP header */
    1160           0 :         hlen += ICMP_MINLEN;
    1161             :         /* exthdr must start on a word boundary */
    1162           0 :         off = roundup(ntohs(ip->ip_len) - hlen, sizeof(u_int32_t));
    1163             :         /* ... and at an offset of ICMP_EXT_OFFSET or bigger */
    1164           0 :         off = max(off, ICMP_EXT_OFFSET);
    1165           0 :         icp->icmp_length = off / sizeof(u_int32_t);
    1166             : 
    1167           0 :         memset(&hdr, 0, sizeof(hdr));
    1168           0 :         hdr.ieh.ieh_version = ICMP_EXT_HDR_VERSION;
    1169           0 :         hdr.ieo.ieo_length = htons(sizeof(struct icmp_ext_obj_hdr) + len);
    1170           0 :         hdr.ieo.ieo_cnum = class;
    1171           0 :         hdr.ieo.ieo_ctype = ctype;
    1172             : 
    1173           0 :         if (m_copyback(m, hlen + off, sizeof(hdr), &hdr, M_NOWAIT) ||
    1174           0 :             m_copyback(m, hlen + off + sizeof(hdr), len, buf, M_NOWAIT)) {
    1175           0 :                 m_freem(m);
    1176           0 :                 return (ENOBUFS);
    1177             :         }
    1178             : 
    1179             :         /* calculate checksum */
    1180           0 :         n = m_getptr(m, hlen + off, &off);
    1181           0 :         if (n == NULL)
    1182           0 :                 panic("icmp_do_exthdr: m_getptr failure");
    1183           0 :         ieh = (struct icmp_ext_hdr *)(mtod(n, caddr_t) + off);
    1184           0 :         ieh->ieh_cksum = in4_cksum(n, 0, off, sizeof(hdr) + len);
    1185             : 
    1186           0 :         ip->ip_len = htons(m->m_pkthdr.len);
    1187             : 
    1188           0 :         return (0);
    1189           0 : }

Generated by: LCOV version 1.13