Annotation of kernel/bsd/netinet/ip_icmp.c, revision 1.1.1.1

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

unix.superglobalmegacorp.com

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