Annotation of XNU/bsd/netinet/ip_icmp.c, revision 1.1

1.1     ! root        1: /*
        !             2:  * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
        !             3:  *
        !             4:  * @APPLE_LICENSE_HEADER_START@
        !             5:  * 
        !             6:  * The contents of this file constitute Original Code as defined in and
        !             7:  * are subject to the Apple Public Source License Version 1.1 (the
        !             8:  * "License").  You may not use this file except in compliance with the
        !             9:  * License.  Please obtain a copy of the License at
        !            10:  * http://www.apple.com/publicsource and read it before using this file.
        !            11:  * 
        !            12:  * This Original Code and all software distributed under the License are
        !            13:  * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
        !            14:  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
        !            15:  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
        !            16:  * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
        !            17:  * License for the specific language governing rights and limitations
        !            18:  * under the License.
        !            19:  * 
        !            20:  * @APPLE_LICENSE_HEADER_END@
        !            21:  */
        !            22: /*
        !            23:  * Copyright (c) 1982, 1986, 1988, 1993
        !            24:  *     The Regents of the University of California.  All rights reserved.
        !            25:  *
        !            26:  * Redistribution and use in source and binary forms, with or without
        !            27:  * modification, are permitted provided that the following conditions
        !            28:  * are met:
        !            29:  * 1. Redistributions of source code must retain the above copyright
        !            30:  *    notice, this list of conditions and the following disclaimer.
        !            31:  * 2. Redistributions in binary form must reproduce the above copyright
        !            32:  *    notice, this list of conditions and the following disclaimer in the
        !            33:  *    documentation and/or other materials provided with the distribution.
        !            34:  * 3. All advertising materials mentioning features or use of this software
        !            35:  *    must display the following acknowledgement:
        !            36:  *     This product includes software developed by the University of
        !            37:  *     California, Berkeley and its contributors.
        !            38:  * 4. Neither the name of the University nor the names of its contributors
        !            39:  *    may be used to endorse or promote products derived from this software
        !            40:  *    without specific prior written permission.
        !            41:  *
        !            42:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
        !            43:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
        !            44:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
        !            45:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
        !            46:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
        !            47:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
        !            48:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
        !            49:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
        !            50:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
        !            51:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
        !            52:  * SUCH DAMAGE.
        !            53:  *
        !            54:  *     @(#)ip_icmp.c   8.2 (Berkeley) 1/4/94
        !            55:  */
        !            56: 
        !            57: #include <sys/param.h>
        !            58: #include <sys/systm.h>
        !            59: #include <sys/mbuf.h>
        !            60: #include <sys/protosw.h>
        !            61: #include <sys/socket.h>
        !            62: #include <sys/time.h>
        !            63: #include <sys/kernel.h>
        !            64: #include <sys/sysctl.h>
        !            65: 
        !            66: #include <net/if.h>
        !            67: #include <net/route.h>
        !            68: 
        !            69: #define _IP_VHL
        !            70: #include <netinet/in.h>
        !            71: #include <netinet/in_systm.h>
        !            72: #include <netinet/in_var.h>
        !            73: #include <netinet/ip.h>
        !            74: #include <netinet/ip_icmp.h>
        !            75: #include <netinet/ip_var.h>
        !            76: #include <netinet/icmp_var.h>
        !            77: 
        !            78: /*
        !            79:  * ICMP routines: error generation, receive packet processing, and
        !            80:  * routines to turnaround packets back to the originator, and
        !            81:  * host table maintenance routines.
        !            82:  */
        !            83: 
        !            84: static struct  icmpstat icmpstat;
        !            85: SYSCTL_STRUCT(_net_inet_icmp, ICMPCTL_STATS, stats, CTLFLAG_RD,
        !            86:        &icmpstat, icmpstat, "");
        !            87: 
        !            88: static int     icmpmaskrepl = 0;
        !            89: SYSCTL_INT(_net_inet_icmp, ICMPCTL_MASKREPL, maskrepl, CTLFLAG_RW,
        !            90:        &icmpmaskrepl, 0, "");
        !            91: 
        !            92: #if ICMP_BANDLIM 
        !            93:  
        !            94: /*    
        !            95:  * ICMP error-response bandwidth limiting sysctl.  If not enabled, sysctl
        !            96:  *      variable content is -1 and read-only.
        !            97:  */     
        !            98:     
        !            99: static int      icmplim = 100;
        !           100: SYSCTL_INT(_net_inet_icmp, ICMPCTL_ICMPLIM, icmplim, CTLFLAG_RW,
        !           101:        &icmplim, 0, "");
        !           102: #else
        !           103: 
        !           104: static int      icmplim = -1;
        !           105: SYSCTL_INT(_net_inet_icmp, ICMPCTL_ICMPLIM, icmplim, CTLFLAG_RD,
        !           106:        &icmplim, 0, "");
        !           107:        
        !           108: #endif 
        !           109: 
        !           110: /*
        !           111:  * ICMP broadcast echo sysctl
        !           112:  */
        !           113: 
        !           114: static int     icmpbmcastecho = 0;
        !           115: SYSCTL_INT(_net_inet_icmp, OID_AUTO, bmcastecho, CTLFLAG_RW, &icmpbmcastecho,
        !           116:           0, "");
        !           117: 
        !           118: 
        !           119: #if ICMPPRINTFS
        !           120: int    icmpprintfs = 0;
        !           121: #endif
        !           122: 
        !           123: static void    icmp_reflect __P((struct mbuf *));
        !           124: static void    icmp_send __P((struct mbuf *, struct mbuf *));
        !           125: static int     ip_next_mtu __P((int, int));
        !           126: 
        !           127: extern struct protosw inetsw[];
        !           128: 
        !           129: /*
        !           130:  * Generate an error packet of type error
        !           131:  * in response to bad packet ip.
        !           132:  */
        !           133: void
        !           134: icmp_error(n, type, code, dest, destifp)
        !           135:        struct mbuf *n;
        !           136:        int type, code;
        !           137:        n_long dest;
        !           138:        struct ifnet *destifp;
        !           139: {
        !           140:        register struct ip *oip = mtod(n, struct ip *), *nip;
        !           141:        register unsigned oiplen = IP_VHL_HL(oip->ip_vhl) << 2;
        !           142:        register struct icmp *icp;
        !           143:        register struct mbuf *m;
        !           144:        unsigned icmplen;
        !           145: 
        !           146: #if ICMPPRINTFS
        !           147:        if (icmpprintfs)
        !           148:                printf("icmp_error(%p, %x, %d)\n", oip, type, code);
        !           149: #endif
        !           150:        if (type != ICMP_REDIRECT)
        !           151:                icmpstat.icps_error++;
        !           152:        /*
        !           153:         * Don't send error if not the first fragment of message.
        !           154:         * Don't error if the old packet protocol was ICMP
        !           155:         * error message, only known informational types.
        !           156:         */
        !           157:        if (oip->ip_off &~ (IP_MF|IP_DF))
        !           158:                goto freeit;
        !           159:        if (oip->ip_p == IPPROTO_ICMP && type != ICMP_REDIRECT &&
        !           160:          n->m_len >= oiplen + ICMP_MINLEN &&
        !           161:          !ICMP_INFOTYPE(((struct icmp *)((caddr_t)oip + oiplen))->icmp_type)) {
        !           162:                icmpstat.icps_oldicmp++;
        !           163:                goto freeit;
        !           164:        }
        !           165:        /* Don't send error in response to a multicast or broadcast packet */
        !           166:        if (n->m_flags & (M_BCAST|M_MCAST))
        !           167:                goto freeit;
        !           168:        /*
        !           169:         * First, formulate icmp message
        !           170:         */
        !           171:        m = m_gethdr(M_DONTWAIT, MT_HEADER);
        !           172:        if (m == NULL)
        !           173:                goto freeit;
        !           174:        icmplen = oiplen + min(8, oip->ip_len);
        !           175:        m->m_len = icmplen + ICMP_MINLEN;
        !           176:        MH_ALIGN(m, m->m_len);
        !           177:        icp = mtod(m, struct icmp *);
        !           178:        if ((u_int)type > ICMP_MAXTYPE)
        !           179:                panic("icmp_error");
        !           180:        icmpstat.icps_outhist[type]++;
        !           181:        icp->icmp_type = type;
        !           182:        if (type == ICMP_REDIRECT)
        !           183:                icp->icmp_gwaddr.s_addr = dest;
        !           184:        else {
        !           185:                icp->icmp_void = 0;
        !           186:                /*
        !           187:                 * The following assignments assume an overlay with the
        !           188:                 * zeroed icmp_void field.
        !           189:                 */
        !           190:                if (type == ICMP_PARAMPROB) {
        !           191:                        icp->icmp_pptr = code;
        !           192:                        code = 0;
        !           193:                } else if (type == ICMP_UNREACH &&
        !           194:                        code == ICMP_UNREACH_NEEDFRAG && destifp) {
        !           195:                        icp->icmp_nextmtu = htons(destifp->if_mtu);
        !           196:                }
        !           197:        }
        !           198: 
        !           199:        icp->icmp_code = code;
        !           200:        bcopy((caddr_t)oip, (caddr_t)&icp->icmp_ip, icmplen);
        !           201:        nip = &icp->icmp_ip;
        !           202:        nip->ip_len = htons((u_short)(nip->ip_len + oiplen));
        !           203: 
        !           204:        /*
        !           205:         * Now, copy old ip header (without options)
        !           206:         * in front of icmp message.
        !           207:         */
        !           208:        if (m->m_data - sizeof(struct ip) < m->m_pktdat)
        !           209:                panic("icmp len");
        !           210:        m->m_data -= sizeof(struct ip);
        !           211:        m->m_len += sizeof(struct ip);
        !           212:        m->m_pkthdr.len = m->m_len;
        !           213:        m->m_pkthdr.rcvif = n->m_pkthdr.rcvif;
        !           214:        nip = mtod(m, struct ip *);
        !           215:        bcopy((caddr_t)oip, (caddr_t)nip, sizeof(struct ip));
        !           216:        nip->ip_len = m->m_len;
        !           217:        nip->ip_vhl = IP_VHL_BORING;
        !           218:        nip->ip_p = IPPROTO_ICMP;
        !           219:        nip->ip_tos = 0;
        !           220:        icmp_reflect(m);
        !           221: 
        !           222: freeit:
        !           223:        m_freem(n);
        !           224: }
        !           225: 
        !           226: static struct sockaddr_in icmpsrc = { sizeof (struct sockaddr_in), AF_INET };
        !           227: static struct sockaddr_in icmpdst = { sizeof (struct sockaddr_in), AF_INET };
        !           228: static struct sockaddr_in icmpgw = { sizeof (struct sockaddr_in), AF_INET };
        !           229: 
        !           230: /*
        !           231:  * Process a received ICMP message.
        !           232:  */
        !           233: void
        !           234: icmp_input(m, hlen)
        !           235:        register struct mbuf *m;
        !           236:        int hlen;
        !           237: {
        !           238:        register struct icmp *icp;
        !           239:        register struct ip *ip = mtod(m, struct ip *);
        !           240:        int icmplen = ip->ip_len;
        !           241:        register int i;
        !           242:        struct in_ifaddr *ia;
        !           243:        void (*ctlfunc) __P((int, struct sockaddr *, void *));
        !           244:        int code;
        !           245: 
        !           246:        /*
        !           247:         * Locate icmp structure in mbuf, and check
        !           248:         * that not corrupted and of at least minimum length.
        !           249:         */
        !           250: #if ICMPPRINTFS
        !           251:        if (icmpprintfs) {
        !           252:                char buf[4 * sizeof "123"];
        !           253:                strcpy(buf, inet_ntoa(ip->ip_src));
        !           254:                printf("icmp_input from %s to %s, len %d\n",
        !           255:                       buf, inet_ntoa(ip->ip_dst), icmplen);
        !           256:        }
        !           257: #endif
        !           258:        if (icmplen < ICMP_MINLEN) {
        !           259:                icmpstat.icps_tooshort++;
        !           260:                goto freeit;
        !           261:        }
        !           262:        i = hlen + min(icmplen, ICMP_ADVLENMIN);
        !           263:        if (m->m_len < i && (m = m_pullup(m, i)) == 0)  {
        !           264:                icmpstat.icps_tooshort++;
        !           265:                return;
        !           266:        }
        !           267:        ip = mtod(m, struct ip *);
        !           268:        m->m_len -= hlen;
        !           269:        m->m_data += hlen;
        !           270:        icp = mtod(m, struct icmp *);
        !           271:        if (in_cksum(m, icmplen)) {
        !           272:                icmpstat.icps_checksum++;
        !           273:                goto freeit;
        !           274:        }
        !           275:        m->m_len += hlen;
        !           276:        m->m_data -= hlen;
        !           277: 
        !           278: #if ICMPPRINTFS
        !           279:        if (icmpprintfs)
        !           280:                printf("icmp_input, type %d code %d\n", icp->icmp_type,
        !           281:                    icp->icmp_code);
        !           282: #endif
        !           283: 
        !           284:        /*
        !           285:         * Message type specific processing.
        !           286:         */
        !           287:        if (icp->icmp_type > ICMP_MAXTYPE)
        !           288:                goto raw;
        !           289:        icmpstat.icps_inhist[icp->icmp_type]++;
        !           290:        code = icp->icmp_code;
        !           291:        switch (icp->icmp_type) {
        !           292: 
        !           293:        case ICMP_UNREACH:
        !           294:                switch (code) {
        !           295:                        case ICMP_UNREACH_NET:
        !           296:                        case ICMP_UNREACH_HOST:
        !           297:                        case ICMP_UNREACH_PROTOCOL:
        !           298:                        case ICMP_UNREACH_PORT:
        !           299:                        case ICMP_UNREACH_SRCFAIL:
        !           300:                                code += PRC_UNREACH_NET;
        !           301:                                break;
        !           302: 
        !           303:                        case ICMP_UNREACH_NEEDFRAG:
        !           304:                                code = PRC_MSGSIZE;
        !           305:                                break;
        !           306: 
        !           307:                        case ICMP_UNREACH_NET_UNKNOWN:
        !           308:                        case ICMP_UNREACH_NET_PROHIB:
        !           309:                        case ICMP_UNREACH_TOSNET:
        !           310:                                code = PRC_UNREACH_NET;
        !           311:                                break;
        !           312: 
        !           313:                        case ICMP_UNREACH_HOST_UNKNOWN:
        !           314:                        case ICMP_UNREACH_ISOLATED:
        !           315:                        case ICMP_UNREACH_HOST_PROHIB:
        !           316:                        case ICMP_UNREACH_TOSHOST:
        !           317:                                code = PRC_UNREACH_HOST;
        !           318:                                break;
        !           319: 
        !           320:                        case ICMP_UNREACH_FILTER_PROHIB:
        !           321:                        case ICMP_UNREACH_HOST_PRECEDENCE:
        !           322:                        case ICMP_UNREACH_PRECEDENCE_CUTOFF:
        !           323:                                code = PRC_UNREACH_PORT;
        !           324:                                break;
        !           325: 
        !           326:                        default:
        !           327:                                goto badcode;
        !           328:                }
        !           329:                goto deliver;
        !           330: 
        !           331:        case ICMP_TIMXCEED:
        !           332:                if (code > 1)
        !           333:                        goto badcode;
        !           334:                code += PRC_TIMXCEED_INTRANS;
        !           335:                goto deliver;
        !           336: 
        !           337:        case ICMP_PARAMPROB:
        !           338:                if (code > 1)
        !           339:                        goto badcode;
        !           340:                code = PRC_PARAMPROB;
        !           341:                goto deliver;
        !           342: 
        !           343:        case ICMP_SOURCEQUENCH:
        !           344:                if (code)
        !           345:                        goto badcode;
        !           346:                code = PRC_QUENCH;
        !           347:        deliver:
        !           348:                /*
        !           349:                 * Problem with datagram; advise higher level routines.
        !           350:                 */
        !           351:                if (icmplen < ICMP_ADVLENMIN || icmplen < ICMP_ADVLEN(icp) ||
        !           352:                    IP_VHL_HL(icp->icmp_ip.ip_vhl) < (sizeof(struct ip) >> 2)) {
        !           353:                        icmpstat.icps_badlen++;
        !           354:                        goto freeit;
        !           355:                }
        !           356:                NTOHS(icp->icmp_ip.ip_len);
        !           357:                /* Discard ICMP's in response to multicast packets */
        !           358:                if (IN_MULTICAST(ntohl(icp->icmp_ip.ip_dst.s_addr)))
        !           359:                        goto badcode;
        !           360: #if ICMPPRINTFS
        !           361:                if (icmpprintfs)
        !           362:                        printf("deliver to protocol %d\n", icp->icmp_ip.ip_p);
        !           363: #endif
        !           364:                icmpsrc.sin_addr = icp->icmp_ip.ip_dst;
        !           365: #if 1
        !           366:                /*
        !           367:                 * MTU discovery:
        !           368:                 * If we got a needfrag and there is a host route to the
        !           369:                 * original destination, and the MTU is not locked, then
        !           370:                 * set the MTU in the route to the suggested new value
        !           371:                 * (if given) and then notify as usual.  The ULPs will
        !           372:                 * notice that the MTU has changed and adapt accordingly.
        !           373:                 * If no new MTU was suggested, then we guess a new one
        !           374:                 * less than the current value.  If the new MTU is 
        !           375:                 * unreasonably small (arbitrarily set at 296), then
        !           376:                 * we reset the MTU to the interface value and enable the
        !           377:                 * lock bit, indicating that we are no longer doing MTU
        !           378:                 * discovery.
        !           379:                 */
        !           380:                if (code == PRC_MSGSIZE) {
        !           381:                        struct rtentry *rt;
        !           382:                        int mtu;
        !           383: 
        !           384:                        rt = rtalloc1((struct sockaddr *)&icmpsrc, 0,
        !           385:                                      RTF_CLONING | RTF_PRCLONING);
        !           386:                        if (rt && (rt->rt_flags & RTF_HOST)
        !           387:                            && !(rt->rt_rmx.rmx_locks & RTV_MTU)) {
        !           388:                                mtu = ntohs(icp->icmp_nextmtu);
        !           389:                                if (!mtu)
        !           390:                                        mtu = ip_next_mtu(rt->rt_rmx.rmx_mtu,
        !           391:                                                          1);
        !           392: #if DEBUG_MTUDISC
        !           393:                                printf("MTU for %s reduced to %d\n",
        !           394:                                        inet_ntoa(icmpsrc.sin_addr), mtu);
        !           395: #endif
        !           396:                                if (mtu < 296) {
        !           397:                                        /* rt->rt_rmx.rmx_mtu =
        !           398:                                                rt->rt_ifp->if_mtu; */
        !           399:                                        rt->rt_rmx.rmx_locks |= RTV_MTU;
        !           400:                                } else if (rt->rt_rmx.rmx_mtu > mtu) {
        !           401:                                        rt->rt_rmx.rmx_mtu = mtu;
        !           402:                                }
        !           403:                        }
        !           404:                        if (rt)
        !           405:                                RTFREE(rt);
        !           406:                }
        !           407: 
        !           408: #endif
        !           409:                ctlfunc = ip_protox[icp->icmp_ip.ip_p]->pr_ctlinput;
        !           410:                if (ctlfunc)
        !           411:                        (*ctlfunc)(code, (struct sockaddr *)&icmpsrc,
        !           412:                                   (void *)&icp->icmp_ip);
        !           413:                break;
        !           414: 
        !           415:        badcode:
        !           416:                icmpstat.icps_badcode++;
        !           417:                break;
        !           418: 
        !           419:        case ICMP_ECHO:
        !           420:                if (!icmpbmcastecho
        !           421:                    && (m->m_flags & (M_MCAST | M_BCAST)) != 0) {
        !           422:                        icmpstat.icps_bmcastecho++;
        !           423:                        break;
        !           424:                }
        !           425:                icp->icmp_type = ICMP_ECHOREPLY;
        !           426:                goto reflect;
        !           427: 
        !           428:        case ICMP_TSTAMP:
        !           429:                if (!icmpbmcastecho
        !           430:                    && (m->m_flags & (M_MCAST | M_BCAST)) != 0) {
        !           431:                        icmpstat.icps_bmcasttstamp++;
        !           432:                        break;
        !           433:                }
        !           434:                if (icmplen < ICMP_TSLEN) {
        !           435:                        icmpstat.icps_badlen++;
        !           436:                        break;
        !           437:                }
        !           438:                icp->icmp_type = ICMP_TSTAMPREPLY;
        !           439:                icp->icmp_rtime = iptime();
        !           440:                icp->icmp_ttime = icp->icmp_rtime;      /* bogus, do later! */
        !           441:                goto reflect;
        !           442: 
        !           443:        case ICMP_MASKREQ:
        !           444: #define        satosin(sa)     ((struct sockaddr_in *)(sa))
        !           445:                if (icmpmaskrepl == 0)
        !           446:                        break;
        !           447:                /*
        !           448:                 * We are not able to respond with all ones broadcast
        !           449:                 * unless we receive it over a point-to-point interface.
        !           450:                 */
        !           451:                if (icmplen < ICMP_MASKLEN)
        !           452:                        break;
        !           453:                switch (ip->ip_dst.s_addr) {
        !           454: 
        !           455:                case INADDR_BROADCAST:
        !           456:                case INADDR_ANY:
        !           457:                        icmpdst.sin_addr = ip->ip_src;
        !           458:                        break;
        !           459: 
        !           460:                default:
        !           461:                        icmpdst.sin_addr = ip->ip_dst;
        !           462:                }
        !           463:                ia = (struct in_ifaddr *)ifaof_ifpforaddr(
        !           464:                            (struct sockaddr *)&icmpdst, m->m_pkthdr.rcvif);
        !           465:                if (ia == 0)
        !           466:                        break;
        !           467:                if (ia->ia_ifp == 0)
        !           468:                        break;
        !           469:                icp->icmp_type = ICMP_MASKREPLY;
        !           470:                icp->icmp_mask = ia->ia_sockmask.sin_addr.s_addr;
        !           471:                if (ip->ip_src.s_addr == 0) {
        !           472:                        if (ia->ia_ifp->if_flags & IFF_BROADCAST)
        !           473:                            ip->ip_src = satosin(&ia->ia_broadaddr)->sin_addr;
        !           474:                        else if (ia->ia_ifp->if_flags & IFF_POINTOPOINT)
        !           475:                            ip->ip_src = satosin(&ia->ia_dstaddr)->sin_addr;
        !           476:                }
        !           477: reflect:
        !           478:                ip->ip_len += hlen;     /* since ip_input deducts this */
        !           479:                icmpstat.icps_reflect++;
        !           480:                icmpstat.icps_outhist[icp->icmp_type]++;
        !           481:                icmp_reflect(m);
        !           482:                return;
        !           483: 
        !           484:        case ICMP_REDIRECT:
        !           485:                if (code > 3)
        !           486:                        goto badcode;
        !           487:                if (icmplen < ICMP_ADVLENMIN || icmplen < ICMP_ADVLEN(icp) ||
        !           488:                    IP_VHL_HL(icp->icmp_ip.ip_vhl) < (sizeof(struct ip) >> 2)) {
        !           489:                        icmpstat.icps_badlen++;
        !           490:                        break;
        !           491:                }
        !           492:                /*
        !           493:                 * Short circuit routing redirects to force
        !           494:                 * immediate change in the kernel's routing
        !           495:                 * tables.  The message is also handed to anyone
        !           496:                 * listening on a raw socket (e.g. the routing
        !           497:                 * daemon for use in updating its tables).
        !           498:                 */
        !           499:                icmpgw.sin_addr = ip->ip_src;
        !           500:                icmpdst.sin_addr = icp->icmp_gwaddr;
        !           501: #if    ICMPPRINTFS
        !           502:                if (icmpprintfs) {
        !           503:                        char buf[4 * sizeof "123"];
        !           504:                        strcpy(buf, inet_ntoa(icp->icmp_ip.ip_dst));
        !           505: 
        !           506:                        printf("redirect dst %s to %s\n",
        !           507:                               buf, inet_ntoa(icp->icmp_gwaddr));
        !           508:                }
        !           509: #endif
        !           510:                icmpsrc.sin_addr = icp->icmp_ip.ip_dst;
        !           511:                rtredirect((struct sockaddr *)&icmpsrc,
        !           512:                  (struct sockaddr *)&icmpdst,
        !           513:                  (struct sockaddr *)0, RTF_GATEWAY | RTF_HOST,
        !           514:                  (struct sockaddr *)&icmpgw, (struct rtentry **)0);
        !           515:                pfctlinput(PRC_REDIRECT_HOST, (struct sockaddr *)&icmpsrc);
        !           516:                break;
        !           517: 
        !           518:        /*
        !           519:         * No kernel processing for the following;
        !           520:         * just fall through to send to raw listener.
        !           521:         */
        !           522:        case ICMP_ECHOREPLY:
        !           523:        case ICMP_ROUTERADVERT:
        !           524:        case ICMP_ROUTERSOLICIT:
        !           525:        case ICMP_TSTAMPREPLY:
        !           526:        case ICMP_IREQREPLY:
        !           527:        case ICMP_MASKREPLY:
        !           528:        default:
        !           529:                break;
        !           530:        }
        !           531: 
        !           532: raw:
        !           533:        rip_input(m, hlen);
        !           534:        return;
        !           535: 
        !           536: freeit:
        !           537:        m_freem(m);
        !           538: }
        !           539: 
        !           540: /*
        !           541:  * Reflect the ip packet back to the source
        !           542:  */
        !           543: static void
        !           544: icmp_reflect(m)
        !           545:        struct mbuf *m;
        !           546: {
        !           547:        register struct ip *ip = mtod(m, struct ip *);
        !           548:        register struct in_ifaddr *ia;
        !           549:        struct in_addr t;
        !           550:        struct mbuf *opts = 0;
        !           551:        int optlen = (IP_VHL_HL(ip->ip_vhl) << 2) - sizeof(struct ip);
        !           552: 
        !           553:        if (!in_canforward(ip->ip_src) &&
        !           554:            ((ntohl(ip->ip_src.s_addr) & IN_CLASSA_NET) !=
        !           555:             (IN_LOOPBACKNET << IN_CLASSA_NSHIFT))) {
        !           556:                m_freem(m);     /* Bad return address */
        !           557:                goto done;      /* Ip_output() will check for broadcast */
        !           558:        }
        !           559:        t = ip->ip_dst;
        !           560:        ip->ip_dst = ip->ip_src;
        !           561:        /*
        !           562:         * If the incoming packet was addressed directly to us,
        !           563:         * use dst as the src for the reply.  Otherwise (broadcast
        !           564:         * or anonymous), use the address which corresponds
        !           565:         * to the incoming interface.
        !           566:         */
        !           567:        for (ia = in_ifaddrhead.tqh_first; ia; ia = ia->ia_link.tqe_next) {
        !           568:                if (t.s_addr == IA_SIN(ia)->sin_addr.s_addr)
        !           569:                        break;
        !           570:                if (ia->ia_ifp && (ia->ia_ifp->if_flags & IFF_BROADCAST) &&
        !           571:                    t.s_addr == satosin(&ia->ia_broadaddr)->sin_addr.s_addr)
        !           572:                        break;
        !           573:        }
        !           574:        icmpdst.sin_addr = t;
        !           575:        if ((ia == (struct in_ifaddr *)0) && m->m_pkthdr.rcvif)
        !           576:                ia = (struct in_ifaddr *)ifaof_ifpforaddr(
        !           577:                        (struct sockaddr *)&icmpdst, m->m_pkthdr.rcvif);
        !           578:        /*
        !           579:         * The following happens if the packet was not addressed to us,
        !           580:         * and was received on an interface with no IP address.
        !           581:         */
        !           582:        if (ia == (struct in_ifaddr *)0)
        !           583:                ia = in_ifaddrhead.tqh_first;
        !           584:        t = IA_SIN(ia)->sin_addr;
        !           585:        ip->ip_src = t;
        !           586:        ip->ip_ttl = MAXTTL;
        !           587: 
        !           588:        if (optlen > 0) {
        !           589:                register u_char *cp;
        !           590:                int opt, cnt;
        !           591:                u_int len;
        !           592: 
        !           593:                /*
        !           594:                 * Retrieve any source routing from the incoming packet;
        !           595:                 * add on any record-route or timestamp options.
        !           596:                 */
        !           597:                cp = (u_char *) (ip + 1);
        !           598:                if ((opts = ip_srcroute()) == 0 &&
        !           599:                    (opts = m_gethdr(M_DONTWAIT, MT_HEADER))) {
        !           600:                        opts->m_len = sizeof(struct in_addr);
        !           601:                        mtod(opts, struct in_addr *)->s_addr = 0;
        !           602:                }
        !           603:                if (opts) {
        !           604: #if ICMPPRINTFS
        !           605:                    if (icmpprintfs)
        !           606:                            printf("icmp_reflect optlen %d rt %d => ",
        !           607:                                optlen, opts->m_len);
        !           608: #endif
        !           609:                    for (cnt = optlen; cnt > 0; cnt -= len, cp += len) {
        !           610:                            opt = cp[IPOPT_OPTVAL];
        !           611:                            if (opt == IPOPT_EOL)
        !           612:                                    break;
        !           613:                            if (opt == IPOPT_NOP)
        !           614:                                    len = 1;
        !           615:                            else {
        !           616:                                    len = cp[IPOPT_OLEN];
        !           617:                                    if (len <= 0 || len > cnt)
        !           618:                                            break;
        !           619:                            }
        !           620:                            /*
        !           621:                             * Should check for overflow, but it "can't happen"
        !           622:                             */
        !           623:                            if (opt == IPOPT_RR || opt == IPOPT_TS ||
        !           624:                                opt == IPOPT_SECURITY) {
        !           625:                                    bcopy((caddr_t)cp,
        !           626:                                        mtod(opts, caddr_t) + opts->m_len, len);
        !           627:                                    opts->m_len += len;
        !           628:                            }
        !           629:                    }
        !           630:                    /* Terminate & pad, if necessary */
        !           631:                    cnt = opts->m_len % 4;
        !           632:                    if (cnt) {
        !           633:                            for (; cnt < 4; cnt++) {
        !           634:                                    *(mtod(opts, caddr_t) + opts->m_len) =
        !           635:                                        IPOPT_EOL;
        !           636:                                    opts->m_len++;
        !           637:                            }
        !           638:                    }
        !           639: #if ICMPPRINTFS
        !           640:                    if (icmpprintfs)
        !           641:                            printf("%d\n", opts->m_len);
        !           642: #endif
        !           643:                }
        !           644:                /*
        !           645:                 * Now strip out original options by copying rest of first
        !           646:                 * mbuf's data back, and adjust the IP length.
        !           647:                 */
        !           648:                ip->ip_len -= optlen;
        !           649:                ip->ip_vhl = IP_VHL_BORING;
        !           650:                m->m_len -= optlen;
        !           651:                if (m->m_flags & M_PKTHDR)
        !           652:                        m->m_pkthdr.len -= optlen;
        !           653:                optlen += sizeof(struct ip);
        !           654:                bcopy((caddr_t)ip + optlen, (caddr_t)(ip + 1),
        !           655:                         (unsigned)(m->m_len - sizeof(struct ip)));
        !           656:        }
        !           657:        m->m_flags &= ~(M_BCAST|M_MCAST);
        !           658:        icmp_send(m, opts);
        !           659: done:
        !           660:        if (opts)
        !           661:                (void)m_free(opts);
        !           662: }
        !           663: 
        !           664: /*
        !           665:  * Send an icmp packet back to the ip level,
        !           666:  * after supplying a checksum.
        !           667:  */
        !           668: static void
        !           669: icmp_send(m, opts)
        !           670:        register struct mbuf *m;
        !           671:        struct mbuf *opts;
        !           672: {
        !           673:        register struct ip *ip = mtod(m, struct ip *);
        !           674:        register int hlen;
        !           675:        register struct icmp *icp;
        !           676:        struct route ro;
        !           677: 
        !           678:        hlen = IP_VHL_HL(ip->ip_vhl) << 2;
        !           679:        m->m_data += hlen;
        !           680:        m->m_len -= hlen;
        !           681:        icp = mtod(m, struct icmp *);
        !           682:        icp->icmp_cksum = 0;
        !           683:        icp->icmp_cksum = in_cksum(m, ip->ip_len - hlen);
        !           684:        m->m_data -= hlen;
        !           685:        m->m_len += hlen;
        !           686: #if ICMPPRINTFS
        !           687:        if (icmpprintfs) {
        !           688:                char buf[4 * sizeof "123"];
        !           689:                strcpy(buf, inet_ntoa(ip->ip_dst));
        !           690:                printf("icmp_send dst %s src %s\n",
        !           691:                       buf, inet_ntoa(ip->ip_src));
        !           692:        }
        !           693: #endif
        !           694:        bzero(&ro, sizeof ro);
        !           695:        (void) ip_output(m, opts, &ro, 0, NULL);
        !           696:        if (ro.ro_rt)
        !           697:                RTFREE(ro.ro_rt);
        !           698: }
        !           699: 
        !           700: n_time
        !           701: iptime()
        !           702: {
        !           703:        struct timeval atv;
        !           704:        u_long t;
        !           705: 
        !           706:        microtime(&atv);
        !           707:        t = (atv.tv_sec % (24*60*60)) * 1000 + atv.tv_usec / 1000;
        !           708:        return (htonl(t));
        !           709: }
        !           710: 
        !           711: #if 1
        !           712: /*
        !           713:  * Return the next larger or smaller MTU plateau (table from RFC 1191)
        !           714:  * given current value MTU.  If DIR is less than zero, a larger plateau
        !           715:  * is returned; otherwise, a smaller value is returned.
        !           716:  */
        !           717: static int
        !           718: ip_next_mtu(mtu, dir)
        !           719:        int mtu;
        !           720:        int dir;
        !           721: {
        !           722:        static int mtutab[] = {
        !           723:                65535, 32000, 17914, 8166, 4352, 2002, 1492, 1006, 508, 296,
        !           724:                68, 0
        !           725:        };
        !           726:        int i;
        !           727: 
        !           728:        for (i = 0; i < (sizeof mtutab) / (sizeof mtutab[0]); i++) {
        !           729:                if (mtu >= mtutab[i])
        !           730:                        break;
        !           731:        }
        !           732: 
        !           733:        if (dir < 0) {
        !           734:                if (i == 0) {
        !           735:                        return 0;
        !           736:                } else {
        !           737:                        return mtutab[i - 1];
        !           738:                }
        !           739:        } else {
        !           740:                if (mtutab[i] == 0) {
        !           741:                        return 0;
        !           742:                } else if(mtu > mtutab[i]) {
        !           743:                        return mtutab[i];
        !           744:                } else {
        !           745:                        return mtutab[i + 1];
        !           746:                }
        !           747:        }
        !           748: }
        !           749: #endif
        !           750: 
        !           751: #if ICMP_BANDLIM
        !           752: 
        !           753: /*
        !           754:  * badport_bandlim() - check for ICMP bandwidth limit
        !           755:  *
        !           756:  *     Return 0 if it is ok to send an ICMP error response, -1 if we have
        !           757:  *     hit our bandwidth limit and it is not ok.  
        !           758:  *
        !           759:  *     If icmplim is <= 0, the feature is disabled and 0 is returned.
        !           760:  *
        !           761:  *     For now we separate the TCP and UDP subsystems w/ different 'which'
        !           762:  *     values.  We may eventually remove this separation (and simplify the
        !           763:  *     code further).
        !           764:  *
        !           765:  *     Note that the printing of the error message is delayed so we can
        !           766:  *     properly print the icmp error rate that the system was trying to do
        !           767:  *     (i.e. 22000/100 pps, etc...).  This can cause long delays in printing
        !           768:  *     the 'final' error, but it doesn't make sense to solve the printing 
        !           769:  *     delay with more complex code.
        !           770:  */
        !           771: 
        !           772: int
        !           773: badport_bandlim(int which)
        !           774: {
        !           775:        static int lticks[2];
        !           776:        static int lpackets[2];
        !           777:        int dticks;
        !           778: 
        !           779:        /*
        !           780:         * Return ok status if feature disabled or argument out of
        !           781:         * ranage.
        !           782:         */
        !           783: 
        !           784:        if (icmplim <= 0 || which >= 2 || which < 0)
        !           785:                return(0);
        !           786:        dticks = ticks - lticks[which];
        !           787: 
        !           788:        /*
        !           789:         * reset stats when cumulative dt exceeds one second.
        !           790:         */
        !           791: 
        !           792:        if ((unsigned int)dticks > hz) {
        !           793:                if (lpackets[which] > icmplim) {
        !           794:                        printf("icmp-response bandwidth limit %d/%d pps\n",
        !           795:                                lpackets[which],
        !           796:                                icmplim
        !           797:                        );
        !           798:                }
        !           799:                lticks[which] = ticks;
        !           800:                lpackets[which] = 0;
        !           801:        }
        !           802: 
        !           803:        /*
        !           804:         * bump packet count
        !           805:         */
        !           806: 
        !           807:        if (++lpackets[which] > icmplim) {
        !           808:                return(-1);
        !           809:        }
        !           810:        return(0);
        !           811: }
        !           812: 
        !           813: #endif
        !           814: 
        !           815: 

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.