Annotation of Net2/netinet/ip_icmp.c, revision 1.1.1.2

1.1       root        1: /*
                      2:  * Copyright (c) 1982, 1986, 1989 Regents of the University of California.
                      3:  * All rights reserved.
                      4:  *
                      5:  * Redistribution and use in source and binary forms, with or without
                      6:  * modification, are permitted provided that the following conditions
                      7:  * are met:
                      8:  * 1. Redistributions of source code must retain the above copyright
                      9:  *    notice, this list of conditions and the following disclaimer.
                     10:  * 2. Redistributions in binary form must reproduce the above copyright
                     11:  *    notice, this list of conditions and the following disclaimer in the
                     12:  *    documentation and/or other materials provided with the distribution.
                     13:  * 3. All advertising materials mentioning features or use of this software
                     14:  *    must display the following acknowledgement:
                     15:  *     This product includes software developed by the University of
                     16:  *     California, Berkeley and its contributors.
                     17:  * 4. Neither the name of the University nor the names of its contributors
                     18:  *    may be used to endorse or promote products derived from this software
                     19:  *    without specific prior written permission.
                     20:  *
                     21:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
                     22:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                     23:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
                     24:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
                     25:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                     26:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
                     27:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     28:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                     29:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     30:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     31:  * SUCH DAMAGE.
                     32:  *
1.1.1.2 ! root       33:  *     from: @(#)ip_icmp.c     7.15 (Berkeley) 4/20/91
        !            34:  *     ip_icmp.c,v 1.2 1993/05/20 03:50:20 cgd Exp
1.1       root       35:  */
                     36: 
                     37: #include "param.h"
                     38: #include "systm.h"
                     39: #include "malloc.h"
                     40: #include "mbuf.h"
                     41: #include "protosw.h"
                     42: #include "socket.h"
                     43: #include "time.h"
                     44: #include "kernel.h"
                     45: 
                     46: #include "../net/route.h"
                     47: #include "../net/if.h"
                     48: 
                     49: #include "in.h"
                     50: #include "in_systm.h"
                     51: #include "in_var.h"
                     52: #include "ip.h"
                     53: #include "ip_icmp.h"
                     54: #include "icmp_var.h"
                     55: 
                     56: /*
                     57:  * ICMP routines: error generation, receive packet processing, and
                     58:  * routines to turnaround packets back to the originator, and
                     59:  * host table maintenance routines.
                     60:  */
                     61: #ifdef ICMPPRINTFS
                     62: int    icmpprintfs = 0;
                     63: #endif
                     64: 
                     65: extern struct protosw inetsw[];
                     66: 
                     67: /*
                     68:  * Generate an error packet of type error
                     69:  * in response to bad packet ip.
                     70:  */
                     71: /*VARARGS3*/
                     72: icmp_error(n, type, code, dest)
                     73:        struct mbuf *n;
                     74:        int type, code;
                     75:        struct in_addr dest;
                     76: {
                     77:        register struct ip *oip = mtod(n, struct ip *), *nip;
                     78:        register unsigned oiplen = oip->ip_hl << 2;
                     79:        register struct icmp *icp;
                     80:        register struct mbuf *m;
                     81:        unsigned icmplen;
                     82: 
                     83: #ifdef ICMPPRINTFS
                     84:        if (icmpprintfs)
                     85:                printf("icmp_error(%x, %d, %d)\n", oip, type, code);
                     86: #endif
                     87:        if (type != ICMP_REDIRECT)
                     88:                icmpstat.icps_error++;
                     89:        /*
                     90:         * Don't send error if not the first fragment of message.
                     91:         * Don't error if the old packet protocol was ICMP
                     92:         * error message, only known informational types.
                     93:         */
                     94:        if (oip->ip_off &~ (IP_MF|IP_DF))
                     95:                goto freeit;
                     96:        if (oip->ip_p == IPPROTO_ICMP && type != ICMP_REDIRECT &&
                     97:          n->m_len >= oiplen + ICMP_MINLEN &&
                     98:          !ICMP_INFOTYPE(((struct icmp *)((caddr_t)oip + oiplen))->icmp_type)) {
                     99:                icmpstat.icps_oldicmp++;
                    100:                goto freeit;
                    101:        }
                    102: 
                    103:        /*
                    104:         * First, formulate icmp message
                    105:         */
                    106:        m = m_gethdr(M_DONTWAIT, MT_HEADER);
                    107:        if (m == NULL)
                    108:                goto freeit;
                    109:        icmplen = oiplen + min(8, oip->ip_len);
                    110:        m->m_len = icmplen + ICMP_MINLEN;
                    111:        MH_ALIGN(m, m->m_len);
                    112:        icp = mtod(m, struct icmp *);
                    113:        if ((u_int)type > ICMP_MAXTYPE)
                    114:                panic("icmp_error");
                    115:        icmpstat.icps_outhist[type]++;
                    116:        icp->icmp_type = type;
                    117:        if (type == ICMP_REDIRECT)
                    118:                icp->icmp_gwaddr = dest;
                    119:        else
                    120:                icp->icmp_void = 0;
                    121:        if (type == ICMP_PARAMPROB) {
                    122:                icp->icmp_pptr = code;
                    123:                code = 0;
                    124:        }
                    125:        icp->icmp_code = code;
                    126:        bcopy((caddr_t)oip, (caddr_t)&icp->icmp_ip, icmplen);
                    127:        nip = &icp->icmp_ip;
                    128:        nip->ip_len = htons((u_short)(nip->ip_len + oiplen));
                    129: 
                    130:        /*
                    131:         * Now, copy old ip header (without options)
                    132:         * in front of icmp message.
                    133:         */
                    134:        if (m->m_data - sizeof(struct ip) < m->m_pktdat)
                    135:                panic("icmp len");
                    136:        m->m_data -= sizeof(struct ip);
                    137:        m->m_len += sizeof(struct ip);
                    138:        m->m_pkthdr.len = m->m_len;
                    139:        m->m_pkthdr.rcvif = n->m_pkthdr.rcvif;
                    140:        nip = mtod(m, struct ip *);
                    141:        bcopy((caddr_t)oip, (caddr_t)nip, oiplen);
                    142:        nip->ip_len = m->m_len;
                    143:        nip->ip_hl = sizeof(struct ip) >> 2;
                    144:        nip->ip_p = IPPROTO_ICMP;
                    145:        icmp_reflect(m);
                    146: 
                    147: freeit:
                    148:        m_freem(n);
                    149: }
                    150: 
                    151: static struct sockproto icmproto = { AF_INET, IPPROTO_ICMP };
                    152: static struct sockaddr_in icmpsrc = { sizeof (struct sockaddr_in), AF_INET };
                    153: static struct sockaddr_in icmpdst = { sizeof (struct sockaddr_in), AF_INET };
                    154: static struct sockaddr_in icmpgw = { sizeof (struct sockaddr_in), AF_INET };
                    155: struct sockaddr_in icmpmask = { 8, 0 };
                    156: struct in_ifaddr *ifptoia();
                    157: 
                    158: /*
                    159:  * Process a received ICMP message.
                    160:  */
                    161: icmp_input(m, hlen)
                    162:        register struct mbuf *m;
                    163:        int hlen;
                    164: {
                    165:        register struct icmp *icp;
                    166:        register struct ip *ip = mtod(m, struct ip *);
                    167:        int icmplen = ip->ip_len;
                    168:        register int i;
                    169:        struct in_ifaddr *ia;
                    170:        int (*ctlfunc)(), code;
                    171:        extern u_char ip_protox[];
                    172:        extern struct in_addr in_makeaddr();
                    173: 
                    174:        /*
                    175:         * Locate icmp structure in mbuf, and check
                    176:         * that not corrupted and of at least minimum length.
                    177:         */
                    178: #ifdef ICMPPRINTFS
                    179:        if (icmpprintfs)
                    180:                printf("icmp_input from %x, len %d\n", ip->ip_src, icmplen);
                    181: #endif
                    182:        if (icmplen < ICMP_MINLEN) {
                    183:                icmpstat.icps_tooshort++;
                    184:                goto freeit;
                    185:        }
                    186:        i = hlen + MIN(icmplen, ICMP_ADVLENMIN);
                    187:        if (m->m_len < i && (m = m_pullup(m, i)) == 0)  {
                    188:                icmpstat.icps_tooshort++;
                    189:                return;
                    190:        }
                    191:        ip = mtod(m, struct ip *);
                    192:        m->m_len -= hlen;
                    193:        m->m_data += hlen;
                    194:        icp = mtod(m, struct icmp *);
                    195:        if (in_cksum(m, icmplen)) {
                    196:                icmpstat.icps_checksum++;
                    197:                goto freeit;
                    198:        }
                    199:        m->m_len += hlen;
                    200:        m->m_data -= hlen;
                    201: 
                    202: #ifdef ICMPPRINTFS
                    203:        /*
                    204:         * Message type specific processing.
                    205:         */
                    206:        if (icmpprintfs)
                    207:                printf("icmp_input, type %d code %d\n", icp->icmp_type,
                    208:                    icp->icmp_code);
                    209: #endif
                    210:        if (icp->icmp_type > ICMP_MAXTYPE)
                    211:                goto raw;
                    212:        icmpstat.icps_inhist[icp->icmp_type]++;
                    213:        code = icp->icmp_code;
                    214:        switch (icp->icmp_type) {
                    215: 
                    216:        case ICMP_UNREACH:
                    217:                if (code > 5)
                    218:                        goto badcode;
                    219:                code += PRC_UNREACH_NET;
                    220:                goto deliver;
                    221: 
                    222:        case ICMP_TIMXCEED:
                    223:                if (code > 1)
                    224:                        goto badcode;
                    225:                code += PRC_TIMXCEED_INTRANS;
                    226:                goto deliver;
                    227: 
                    228:        case ICMP_PARAMPROB:
                    229:                if (code)
                    230:                        goto badcode;
                    231:                code = PRC_PARAMPROB;
                    232:                goto deliver;
                    233: 
                    234:        case ICMP_SOURCEQUENCH:
                    235:                if (code)
                    236:                        goto badcode;
                    237:                code = PRC_QUENCH;
                    238:        deliver:
                    239:                /*
                    240:                 * Problem with datagram; advise higher level routines.
                    241:                 */
                    242:                if (icmplen < ICMP_ADVLENMIN || icmplen < ICMP_ADVLEN(icp) ||
                    243:                    icp->icmp_ip.ip_hl < (sizeof(struct ip) >> 2)) {
                    244:                        icmpstat.icps_badlen++;
                    245:                        goto freeit;
                    246:                }
                    247:                NTOHS(icp->icmp_ip.ip_len);
                    248: #ifdef ICMPPRINTFS
                    249:                if (icmpprintfs)
                    250:                        printf("deliver to protocol %d\n", icp->icmp_ip.ip_p);
                    251: #endif
                    252:                icmpsrc.sin_addr = icp->icmp_ip.ip_dst;
                    253:                if (ctlfunc = inetsw[ip_protox[icp->icmp_ip.ip_p]].pr_ctlinput)
                    254:                        (*ctlfunc)(code, (struct sockaddr *)&icmpsrc,
                    255:                            (caddr_t) &icp->icmp_ip);
                    256:                break;
                    257: 
                    258:        badcode:
                    259:                icmpstat.icps_badcode++;
                    260:                break;
                    261: 
                    262:        case ICMP_ECHO:
                    263:                icp->icmp_type = ICMP_ECHOREPLY;
                    264:                goto reflect;
                    265: 
                    266:        case ICMP_TSTAMP:
                    267:                if (icmplen < ICMP_TSLEN) {
                    268:                        icmpstat.icps_badlen++;
                    269:                        break;
                    270:                }
                    271:                icp->icmp_type = ICMP_TSTAMPREPLY;
                    272:                icp->icmp_rtime = iptime();
                    273:                icp->icmp_ttime = icp->icmp_rtime;      /* bogus, do later! */
                    274:                goto reflect;
                    275:                
                    276:        case ICMP_IREQ:
                    277: #define        satosin(sa)     ((struct sockaddr_in *)(sa))
                    278:                if (in_netof(ip->ip_src) == 0 &&
                    279:                    (ia = ifptoia(m->m_pkthdr.rcvif)))
                    280:                        ip->ip_src = in_makeaddr(in_netof(IA_SIN(ia)->sin_addr),
                    281:                            in_lnaof(ip->ip_src));
                    282:                icp->icmp_type = ICMP_IREQREPLY;
                    283:                goto reflect;
                    284: 
                    285:        case ICMP_MASKREQ:
                    286:                if (icmplen < ICMP_MASKLEN ||
                    287:                    (ia = ifptoia(m->m_pkthdr.rcvif)) == 0)
                    288:                        break;
                    289:                icp->icmp_type = ICMP_MASKREPLY;
                    290:                icp->icmp_mask = ia->ia_sockmask.sin_addr.s_addr;
                    291:                if (ip->ip_src.s_addr == 0) {
                    292:                        if (ia->ia_ifp->if_flags & IFF_BROADCAST)
                    293:                            ip->ip_src = satosin(&ia->ia_broadaddr)->sin_addr;
                    294:                        else if (ia->ia_ifp->if_flags & IFF_POINTOPOINT)
                    295:                            ip->ip_src = satosin(&ia->ia_dstaddr)->sin_addr;
                    296:                }
                    297: reflect:
                    298:                ip->ip_len += hlen;     /* since ip_input deducts this */
                    299:                icmpstat.icps_reflect++;
                    300:                icmpstat.icps_outhist[icp->icmp_type]++;
                    301:                icmp_reflect(m);
                    302:                return;
                    303: 
                    304:        case ICMP_REDIRECT:
                    305:                if (icmplen < ICMP_ADVLENMIN || icmplen < ICMP_ADVLEN(icp)) {
                    306:                        icmpstat.icps_badlen++;
                    307:                        break;
                    308:                }
                    309:                /*
                    310:                 * Short circuit routing redirects to force
                    311:                 * immediate change in the kernel's routing
                    312:                 * tables.  The message is also handed to anyone
                    313:                 * listening on a raw socket (e.g. the routing
                    314:                 * daemon for use in updating its tables).
                    315:                 */
                    316:                icmpgw.sin_addr = ip->ip_src;
                    317:                icmpdst.sin_addr = icp->icmp_gwaddr;
                    318: #ifdef ICMPPRINTFS
                    319:                if (icmpprintfs)
                    320:                        printf("redirect dst %x to %x\n", icp->icmp_ip.ip_dst,
                    321:                                icp->icmp_gwaddr);
                    322: #endif
                    323:                if (code == ICMP_REDIRECT_NET || code == ICMP_REDIRECT_TOSNET) {
                    324:                        u_long in_netof();
                    325:                        icmpsrc.sin_addr =
                    326:                         in_makeaddr(in_netof(icp->icmp_ip.ip_dst), INADDR_ANY);
                    327:                        in_sockmaskof(icp->icmp_ip.ip_dst, &icmpmask);
                    328:                        rtredirect((struct sockaddr *)&icmpsrc,
                    329:                          (struct sockaddr *)&icmpdst,
                    330:                          (struct sockaddr *)&icmpmask, RTF_GATEWAY,
                    331:                          (struct sockaddr *)&icmpgw, (struct rtentry **)0);
                    332:                        icmpsrc.sin_addr = icp->icmp_ip.ip_dst;
                    333:                        pfctlinput(PRC_REDIRECT_NET,
                    334:                          (struct sockaddr *)&icmpsrc);
                    335:                } else {
                    336:                        icmpsrc.sin_addr = icp->icmp_ip.ip_dst;
                    337:                        rtredirect((struct sockaddr *)&icmpsrc,
                    338:                          (struct sockaddr *)&icmpdst,
                    339:                          (struct sockaddr *)0, RTF_GATEWAY | RTF_HOST,
                    340:                          (struct sockaddr *)&icmpgw, (struct rtentry **)0);
                    341:                        pfctlinput(PRC_REDIRECT_HOST,
                    342:                          (struct sockaddr *)&icmpsrc);
                    343:                }
                    344:                break;
                    345: 
                    346:        /*
                    347:         * No kernel processing for the following;
                    348:         * just fall through to send to raw listener.
                    349:         */
                    350:        case ICMP_ECHOREPLY:
                    351:        case ICMP_TSTAMPREPLY:
                    352:        case ICMP_IREQREPLY:
                    353:        case ICMP_MASKREPLY:
                    354:        default:
                    355:                break;
                    356:        }
                    357: 
                    358: raw:
                    359:        icmpsrc.sin_addr = ip->ip_src;
                    360:        icmpdst.sin_addr = ip->ip_dst;
                    361:        (void) raw_input(m, &icmproto, (struct sockaddr *)&icmpsrc,
                    362:            (struct sockaddr *)&icmpdst);
                    363:        return;
                    364: 
                    365: freeit:
                    366:        m_freem(m);
                    367: }
                    368: 
                    369: /*
                    370:  * Reflect the ip packet back to the source
                    371:  */
                    372: icmp_reflect(m)
                    373:        struct mbuf *m;
                    374: {
                    375:        register struct ip *ip = mtod(m, struct ip *);
                    376:        register struct in_ifaddr *ia;
                    377:        struct in_addr t;
                    378:        struct mbuf *opts = 0, *ip_srcroute();
                    379:        int optlen = (ip->ip_hl << 2) - sizeof(struct ip);
                    380: 
                    381:        t = ip->ip_dst;
                    382:        ip->ip_dst = ip->ip_src;
                    383:        /*
                    384:         * If the incoming packet was addressed directly to us,
                    385:         * use dst as the src for the reply.  Otherwise (broadcast
                    386:         * or anonymous), use the address which corresponds
                    387:         * to the incoming interface.
                    388:         */
                    389:        for (ia = in_ifaddr; ia; ia = ia->ia_next) {
                    390:                if (t.s_addr == IA_SIN(ia)->sin_addr.s_addr)
                    391:                        break;
                    392:                if ((ia->ia_ifp->if_flags & IFF_BROADCAST) &&
                    393:                    t.s_addr == satosin(&ia->ia_broadaddr)->sin_addr.s_addr)
                    394:                        break;
                    395:        }
                    396:        if (ia == (struct in_ifaddr *)0)
                    397:                ia = ifptoia(m->m_pkthdr.rcvif);
                    398:        if (ia == (struct in_ifaddr *)0)
                    399:                ia = in_ifaddr;
                    400:        t = IA_SIN(ia)->sin_addr;
                    401:        ip->ip_src = t;
                    402:        ip->ip_ttl = MAXTTL;
                    403: 
                    404:        if (optlen > 0) {
                    405:                register u_char *cp;
                    406:                int opt, cnt;
                    407:                u_int len;
                    408: 
                    409:                /*
                    410:                 * Retrieve any source routing from the incoming packet;
                    411:                 * add on any record-route or timestamp options.
                    412:                 */
                    413:                cp = (u_char *) (ip + 1);
                    414:                if ((opts = ip_srcroute()) == 0 &&
                    415:                    (opts = m_gethdr(M_DONTWAIT, MT_HEADER))) {
                    416:                        opts->m_len = sizeof(struct in_addr);
                    417:                        mtod(opts, struct in_addr *)->s_addr = 0;
                    418:                }
                    419:                if (opts) {
                    420: #ifdef ICMPPRINTFS
                    421:                    if (icmpprintfs)
                    422:                            printf("icmp_reflect optlen %d rt %d => ",
                    423:                                optlen, opts->m_len);
                    424: #endif
                    425:                    for (cnt = optlen; cnt > 0; cnt -= len, cp += len) {
                    426:                            opt = cp[IPOPT_OPTVAL];
                    427:                            if (opt == IPOPT_EOL)
                    428:                                    break;
                    429:                            if (opt == IPOPT_NOP)
                    430:                                    len = 1;
                    431:                            else {
                    432:                                    len = cp[IPOPT_OLEN];
                    433:                                    if (len <= 0 || len > cnt)
                    434:                                            break;
                    435:                            }
                    436:                            /*
                    437:                             * should check for overflow, but it "can't happen"
                    438:                             */
                    439:                            if (opt == IPOPT_RR || opt == IPOPT_TS) {
                    440:                                    bcopy((caddr_t)cp,
                    441:                                        mtod(opts, caddr_t) + opts->m_len, len);
                    442:                                    opts->m_len += len;
                    443:                            }
                    444:                    }
                    445:                    if (opts->m_len % 4 != 0) {
                    446:                            *(mtod(opts, caddr_t) + opts->m_len) = IPOPT_EOL;
                    447:                            opts->m_len++;
                    448:                    }
                    449: #ifdef ICMPPRINTFS
                    450:                    if (icmpprintfs)
                    451:                            printf("%d\n", opts->m_len);
                    452: #endif
                    453:                }
                    454:                /*
                    455:                 * Now strip out original options by copying rest of first
                    456:                 * mbuf's data back, and adjust the IP length.
                    457:                 */
                    458:                ip->ip_len -= optlen;
                    459:                ip->ip_hl = sizeof(struct ip) >> 2;
                    460:                m->m_len -= optlen;
                    461:                if (m->m_flags & M_PKTHDR)
                    462:                        m->m_pkthdr.len -= optlen;
                    463:                optlen += sizeof(struct ip);
                    464:                bcopy((caddr_t)ip + optlen, (caddr_t)(ip + 1),
                    465:                         (unsigned)(m->m_len - sizeof(struct ip)));
                    466:        }
                    467:        icmp_send(m, opts);
                    468:        if (opts)
                    469:                (void)m_free(opts);
                    470: }
                    471: 
                    472: struct in_ifaddr *
                    473: ifptoia(ifp)
                    474:        struct ifnet *ifp;
                    475: {
                    476:        register struct in_ifaddr *ia;
                    477: 
                    478:        for (ia = in_ifaddr; ia; ia = ia->ia_next)
                    479:                if (ia->ia_ifp == ifp)
                    480:                        return (ia);
                    481:        return ((struct in_ifaddr *)0);
                    482: }
                    483: 
                    484: /*
                    485:  * Send an icmp packet back to the ip level,
                    486:  * after supplying a checksum.
                    487:  */
                    488: icmp_send(m, opts)
                    489:        register struct mbuf *m;
                    490:        struct mbuf *opts;
                    491: {
                    492:        register struct ip *ip = mtod(m, struct ip *);
                    493:        register int hlen;
                    494:        register struct icmp *icp;
                    495: 
                    496:        hlen = ip->ip_hl << 2;
                    497:        m->m_data += hlen;
                    498:        m->m_len -= hlen;
                    499:        icp = mtod(m, struct icmp *);
                    500:        icp->icmp_cksum = 0;
                    501:        icp->icmp_cksum = in_cksum(m, ip->ip_len - hlen);
                    502:        m->m_data -= hlen;
                    503:        m->m_len += hlen;
                    504: #ifdef ICMPPRINTFS
                    505:        if (icmpprintfs)
                    506:                printf("icmp_send dst %x src %x\n", ip->ip_dst, ip->ip_src);
                    507: #endif
                    508:        (void) ip_output(m, opts, (struct route *)0, 0);
                    509: }
                    510: 
                    511: n_time
                    512: iptime()
                    513: {
                    514:        struct timeval atv;
                    515:        u_long t;
                    516: 
                    517:        microtime(&atv);
                    518:        t = (atv.tv_sec % (24*60*60)) * 1000 + atv.tv_usec / 1000;
                    519:        return (htonl(t));
                    520: }

unix.superglobalmegacorp.com

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