Annotation of 43BSD/sys/netinet/ip_icmp.c, revision 1.1

1.1     ! root        1: /*
        !             2:  * Copyright (c) 1982, 1986 Regents of the University of California.
        !             3:  * All rights reserved.  The Berkeley software License Agreement
        !             4:  * specifies the terms and conditions for redistribution.
        !             5:  *
        !             6:  *     @(#)ip_icmp.c   7.2 (Berkeley) 1/10/87
        !             7:  */
        !             8: 
        !             9: #include "param.h"
        !            10: #include "systm.h"
        !            11: #include "mbuf.h"
        !            12: #include "protosw.h"
        !            13: #include "socket.h"
        !            14: #include "time.h"
        !            15: #include "kernel.h"
        !            16: 
        !            17: #include "../net/route.h"
        !            18: #include "../net/if.h"
        !            19: 
        !            20: #include "in.h"
        !            21: #include "in_systm.h"
        !            22: #include "in_var.h"
        !            23: #include "ip.h"
        !            24: #include "ip_icmp.h"
        !            25: #include "icmp_var.h"
        !            26: 
        !            27: #ifdef ICMPPRINTFS
        !            28: /*
        !            29:  * ICMP routines: error generation, receive packet processing, and
        !            30:  * routines to turnaround packets back to the originator, and
        !            31:  * host table maintenance routines.
        !            32:  */
        !            33: int    icmpprintfs = 0;
        !            34: #endif
        !            35: 
        !            36: /*
        !            37:  * Generate an error packet of type error
        !            38:  * in response to bad packet ip.
        !            39:  */
        !            40: /*VARARGS4*/
        !            41: icmp_error(oip, type, code, ifp, dest)
        !            42:        struct ip *oip;
        !            43:        int type, code;
        !            44:        struct ifnet *ifp;
        !            45:        struct in_addr dest;
        !            46: {
        !            47:        register unsigned oiplen = oip->ip_hl << 2;
        !            48:        register struct icmp *icp;
        !            49:        struct mbuf *m;
        !            50:        struct ip *nip;
        !            51:        unsigned icmplen;
        !            52: 
        !            53: #ifdef ICMPPRINTFS
        !            54:        if (icmpprintfs)
        !            55:                printf("icmp_error(%x, %d, %d)\n", oip, type, code);
        !            56: #endif
        !            57:        if (type != ICMP_REDIRECT)
        !            58:                icmpstat.icps_error++;
        !            59:        /*
        !            60:         * Don't send error if not the first fragment of message.
        !            61:         * Don't EVER error if the old packet protocol was ICMP.
        !            62:         * (Could do ECHO, etc, but not error indications.)
        !            63:         */
        !            64:        if (oip->ip_off &~ (IP_MF|IP_DF))
        !            65:                goto free;
        !            66:        if (oip->ip_p == IPPROTO_ICMP && type != ICMP_REDIRECT) {
        !            67:                icmpstat.icps_oldicmp++;
        !            68:                goto free;
        !            69:        }
        !            70: 
        !            71:        /*
        !            72:         * First, formulate icmp message
        !            73:         */
        !            74:        m = m_get(M_DONTWAIT, MT_HEADER);
        !            75:        if (m == NULL)
        !            76:                goto free;
        !            77:        icmplen = oiplen + MIN(8, oip->ip_len);
        !            78:        m->m_len = icmplen + ICMP_MINLEN;
        !            79:        m->m_off = MMAXOFF - m->m_len;
        !            80:        icp = mtod(m, struct icmp *);
        !            81:        if ((u_int)type > ICMP_MAXTYPE)
        !            82:                panic("icmp_error");
        !            83:        icmpstat.icps_outhist[type]++;
        !            84:        icp->icmp_type = type;
        !            85:        if (type == ICMP_REDIRECT)
        !            86:                icp->icmp_gwaddr = dest;
        !            87:        else
        !            88:                icp->icmp_void = 0;
        !            89:        if (type == ICMP_PARAMPROB) {
        !            90:                icp->icmp_pptr = code;
        !            91:                code = 0;
        !            92:        }
        !            93:        icp->icmp_code = code;
        !            94:        bcopy((caddr_t)oip, (caddr_t)&icp->icmp_ip, icmplen);
        !            95:        nip = &icp->icmp_ip;
        !            96:        nip->ip_len += oiplen;
        !            97:        nip->ip_len = htons((u_short)nip->ip_len);
        !            98: 
        !            99:        /*
        !           100:         * Now, copy old ip header in front of icmp message.
        !           101:         */
        !           102:        if (m->m_len + oiplen > MLEN)
        !           103:                oiplen = sizeof(struct ip);
        !           104:        if (m->m_len + oiplen > MLEN)
        !           105:                panic("icmp len");
        !           106:        m->m_off -= oiplen;
        !           107:        m->m_len += oiplen;
        !           108:        nip = mtod(m, struct ip *);
        !           109:        bcopy((caddr_t)oip, (caddr_t)nip, oiplen);
        !           110:        nip->ip_len = m->m_len;
        !           111:        nip->ip_p = IPPROTO_ICMP;
        !           112:        icmp_reflect(nip, ifp);
        !           113: 
        !           114: free:
        !           115:        m_freem(dtom(oip));
        !           116: }
        !           117: 
        !           118: static struct sockproto icmproto = { AF_INET, IPPROTO_ICMP };
        !           119: static struct sockaddr_in icmpsrc = { AF_INET };
        !           120: static struct sockaddr_in icmpdst = { AF_INET };
        !           121: static struct sockaddr_in icmpgw = { AF_INET };
        !           122: struct in_ifaddr *ifptoia();
        !           123: 
        !           124: /*
        !           125:  * Process a received ICMP message.
        !           126:  */
        !           127: icmp_input(m, ifp)
        !           128:        register struct mbuf *m;
        !           129:        struct ifnet *ifp;
        !           130: {
        !           131:        register struct icmp *icp;
        !           132:        register struct ip *ip = mtod(m, struct ip *);
        !           133:        int icmplen = ip->ip_len, hlen = ip->ip_hl << 2;
        !           134:        register int i;
        !           135:        struct in_ifaddr *ia;
        !           136:        int (*ctlfunc)(), code;
        !           137:        extern u_char ip_protox[];
        !           138:        extern struct in_addr in_makeaddr();
        !           139: 
        !           140:        /*
        !           141:         * Locate icmp structure in mbuf, and check
        !           142:         * that not corrupted and of at least minimum length.
        !           143:         */
        !           144: #ifdef ICMPPRINTFS
        !           145:        if (icmpprintfs)
        !           146:                printf("icmp_input from %x, len %d\n", ip->ip_src, icmplen);
        !           147: #endif
        !           148:        if (icmplen < ICMP_MINLEN) {
        !           149:                icmpstat.icps_tooshort++;
        !           150:                goto free;
        !           151:        }
        !           152:        i = hlen + MIN(icmplen, ICMP_ADVLENMIN);
        !           153:        if ((m->m_off > MMAXOFF || m->m_len < i) &&
        !           154:                (m = m_pullup(m, i)) == 0)  {
        !           155:                icmpstat.icps_tooshort++;
        !           156:                return;
        !           157:        }
        !           158:        ip = mtod(m, struct ip *);
        !           159:        m->m_len -= hlen;
        !           160:        m->m_off += hlen;
        !           161:        icp = mtod(m, struct icmp *);
        !           162:        if (in_cksum(m, icmplen)) {
        !           163:                icmpstat.icps_checksum++;
        !           164:                goto free;
        !           165:        }
        !           166:        m->m_len += hlen;
        !           167:        m->m_off -= hlen;
        !           168: 
        !           169: #ifdef ICMPPRINTFS
        !           170:        /*
        !           171:         * Message type specific processing.
        !           172:         */
        !           173:        if (icmpprintfs)
        !           174:                printf("icmp_input, type %d code %d\n", icp->icmp_type,
        !           175:                    icp->icmp_code);
        !           176: #endif
        !           177:        if (icp->icmp_type > ICMP_MAXTYPE)
        !           178:                goto raw;
        !           179:        icmpstat.icps_inhist[icp->icmp_type]++;
        !           180:        code = icp->icmp_code;
        !           181:        switch (icp->icmp_type) {
        !           182: 
        !           183:        case ICMP_UNREACH:
        !           184:                if (code > 5)
        !           185:                        goto badcode;
        !           186:                code += PRC_UNREACH_NET;
        !           187:                goto deliver;
        !           188: 
        !           189:        case ICMP_TIMXCEED:
        !           190:                if (code > 1)
        !           191:                        goto badcode;
        !           192:                code += PRC_TIMXCEED_INTRANS;
        !           193:                goto deliver;
        !           194: 
        !           195:        case ICMP_PARAMPROB:
        !           196:                if (code)
        !           197:                        goto badcode;
        !           198:                code = PRC_PARAMPROB;
        !           199:                goto deliver;
        !           200: 
        !           201:        case ICMP_SOURCEQUENCH:
        !           202:                if (code)
        !           203:                        goto badcode;
        !           204:                code = PRC_QUENCH;
        !           205:        deliver:
        !           206:                /*
        !           207:                 * Problem with datagram; advise higher level routines.
        !           208:                 */
        !           209:                icp->icmp_ip.ip_len = ntohs((u_short)icp->icmp_ip.ip_len);
        !           210:                if (icmplen < ICMP_ADVLENMIN || icmplen < ICMP_ADVLEN(icp)) {
        !           211:                        icmpstat.icps_badlen++;
        !           212:                        goto free;
        !           213:                }
        !           214: #ifdef ICMPPRINTFS
        !           215:                if (icmpprintfs)
        !           216:                        printf("deliver to protocol %d\n", icp->icmp_ip.ip_p);
        !           217: #endif
        !           218:                icmpsrc.sin_addr = icp->icmp_ip.ip_dst;
        !           219:                if (ctlfunc = inetsw[ip_protox[icp->icmp_ip.ip_p]].pr_ctlinput)
        !           220:                        (*ctlfunc)(code, (struct sockaddr *)&icmpsrc);
        !           221:                break;
        !           222: 
        !           223:        badcode:
        !           224:                icmpstat.icps_badcode++;
        !           225:                break;
        !           226: 
        !           227:        case ICMP_ECHO:
        !           228:                icp->icmp_type = ICMP_ECHOREPLY;
        !           229:                goto reflect;
        !           230: 
        !           231:        case ICMP_TSTAMP:
        !           232:                if (icmplen < ICMP_TSLEN) {
        !           233:                        icmpstat.icps_badlen++;
        !           234:                        break;
        !           235:                }
        !           236:                icp->icmp_type = ICMP_TSTAMPREPLY;
        !           237:                icp->icmp_rtime = iptime();
        !           238:                icp->icmp_ttime = icp->icmp_rtime;      /* bogus, do later! */
        !           239:                goto reflect;
        !           240:                
        !           241:        case ICMP_IREQ:
        !           242: #define        satosin(sa)     ((struct sockaddr_in *)(sa))
        !           243:                if (in_netof(ip->ip_src) == 0 && (ia = ifptoia(ifp)))
        !           244:                        ip->ip_src = in_makeaddr(in_netof(IA_SIN(ia)->sin_addr),
        !           245:                            in_lnaof(ip->ip_src));
        !           246:                icp->icmp_type = ICMP_IREQREPLY;
        !           247:                goto reflect;
        !           248: 
        !           249:        case ICMP_MASKREQ:
        !           250:                if (icmplen < ICMP_MASKLEN || (ia = ifptoia(ifp)) == 0)
        !           251:                        break;
        !           252:                icp->icmp_type = ICMP_MASKREPLY;
        !           253:                icp->icmp_mask = ia->ia_netmask;
        !           254:                if (ip->ip_src.s_addr == 0) {
        !           255:                        if (ia->ia_ifp->if_flags & IFF_BROADCAST)
        !           256:                            ip->ip_src = satosin(&ia->ia_broadaddr)->sin_addr;
        !           257:                        else if (ia->ia_ifp->if_flags & IFF_POINTOPOINT)
        !           258:                            ip->ip_src = satosin(&ia->ia_dstaddr)->sin_addr;
        !           259:                }
        !           260: reflect:
        !           261:                ip->ip_len += hlen;     /* since ip_input deducts this */
        !           262:                icmpstat.icps_reflect++;
        !           263:                icmpstat.icps_outhist[icp->icmp_type]++;
        !           264:                icmp_reflect(ip, ifp);
        !           265:                return;
        !           266: 
        !           267:        case ICMP_REDIRECT:
        !           268:                if (icmplen < ICMP_ADVLENMIN || icmplen < ICMP_ADVLEN(icp)) {
        !           269:                        icmpstat.icps_badlen++;
        !           270:                        break;
        !           271:                }
        !           272:                /*
        !           273:                 * Short circuit routing redirects to force
        !           274:                 * immediate change in the kernel's routing
        !           275:                 * tables.  The message is also handed to anyone
        !           276:                 * listening on a raw socket (e.g. the routing
        !           277:                 * daemon for use in updating its tables).
        !           278:                 */
        !           279:                icmpgw.sin_addr = ip->ip_src;
        !           280:                icmpdst.sin_addr = icp->icmp_gwaddr;
        !           281: #ifdef ICMPPRINTFS
        !           282:                if (icmpprintfs)
        !           283:                        printf("redirect dst %x to %x\n", icp->icmp_ip.ip_dst,
        !           284:                                icp->icmp_gwaddr);
        !           285: #endif
        !           286:                if (code == ICMP_REDIRECT_NET || code == ICMP_REDIRECT_TOSNET) {
        !           287:                        icmpsrc.sin_addr =
        !           288:                         in_makeaddr(in_netof(icp->icmp_ip.ip_dst), INADDR_ANY);
        !           289:                        rtredirect((struct sockaddr *)&icmpsrc,
        !           290:                          (struct sockaddr *)&icmpdst, RTF_GATEWAY,
        !           291:                          (struct sockaddr *)&icmpgw);
        !           292:                        icmpsrc.sin_addr = icp->icmp_ip.ip_dst;
        !           293:                        pfctlinput(PRC_REDIRECT_NET,
        !           294:                          (struct sockaddr *)&icmpsrc);
        !           295:                } else {
        !           296:                        icmpsrc.sin_addr = icp->icmp_ip.ip_dst;
        !           297:                        rtredirect((struct sockaddr *)&icmpsrc,
        !           298:                          (struct sockaddr *)&icmpdst, RTF_GATEWAY | RTF_HOST,
        !           299:                          (struct sockaddr *)&icmpgw);
        !           300:                        pfctlinput(PRC_REDIRECT_HOST,
        !           301:                          (struct sockaddr *)&icmpsrc);
        !           302:                }
        !           303:                break;
        !           304: 
        !           305:        /*
        !           306:         * No kernel processing for the following;
        !           307:         * just fall through to send to raw listener.
        !           308:         */
        !           309:        case ICMP_ECHOREPLY:
        !           310:        case ICMP_TSTAMPREPLY:
        !           311:        case ICMP_IREQREPLY:
        !           312:        case ICMP_MASKREPLY:
        !           313:        default:
        !           314:                break;
        !           315:        }
        !           316: 
        !           317: raw:
        !           318:        icmpsrc.sin_addr = ip->ip_src;
        !           319:        icmpdst.sin_addr = ip->ip_dst;
        !           320:        raw_input(m, &icmproto, (struct sockaddr *)&icmpsrc,
        !           321:            (struct sockaddr *)&icmpdst);
        !           322:        return;
        !           323: 
        !           324: free:
        !           325:        m_freem(m);
        !           326: }
        !           327: 
        !           328: /*
        !           329:  * Reflect the ip packet back to the source
        !           330:  */
        !           331: icmp_reflect(ip, ifp)
        !           332:        register struct ip *ip;
        !           333:        struct ifnet *ifp;
        !           334: {
        !           335:        register struct in_ifaddr *ia;
        !           336:        struct in_addr t;
        !           337:        struct mbuf *opts = 0, *ip_srcroute();
        !           338:        int optlen = (ip->ip_hl << 2) - sizeof(struct ip);
        !           339: 
        !           340:        t = ip->ip_dst;
        !           341:        ip->ip_dst = ip->ip_src;
        !           342:        /*
        !           343:         * If the incoming packet was addressed directly to us,
        !           344:         * use dst as the src for the reply.  Otherwise (broadcast
        !           345:         * or anonymous), use the address which corresponds
        !           346:         * to the incoming interface.
        !           347:         */
        !           348:        for (ia = in_ifaddr; ia; ia = ia->ia_next) {
        !           349:                if (t.s_addr == IA_SIN(ia)->sin_addr.s_addr)
        !           350:                        break;
        !           351:                if ((ia->ia_ifp->if_flags & IFF_BROADCAST) &&
        !           352:                    t.s_addr == satosin(&ia->ia_broadaddr)->sin_addr.s_addr)
        !           353:                        break;
        !           354:        }
        !           355:        if (ia == (struct in_ifaddr *)0)
        !           356:                ia = ifptoia(ifp);
        !           357:        if (ia == (struct in_ifaddr *)0)
        !           358:                ia = in_ifaddr;
        !           359:        t = IA_SIN(ia)->sin_addr;
        !           360:        ip->ip_src = t;
        !           361: 
        !           362:        if (optlen > 0) {
        !           363:                /*
        !           364:                 * Retrieve any source routing from the incoming packet
        !           365:                 * and strip out other options.  Adjust the IP length.
        !           366:                 */
        !           367:                opts = ip_srcroute();
        !           368:                ip->ip_len -= optlen;
        !           369:                ip_stripoptions(ip, (struct mbuf *)0);
        !           370:        }
        !           371:        icmp_send(ip, opts);
        !           372:        if (opts)
        !           373:                (void)m_free(opts);
        !           374: }
        !           375: 
        !           376: struct in_ifaddr *
        !           377: ifptoia(ifp)
        !           378:        struct ifnet *ifp;
        !           379: {
        !           380:        register struct in_ifaddr *ia;
        !           381: 
        !           382:        for (ia = in_ifaddr; ia; ia = ia->ia_next)
        !           383:                if (ia->ia_ifp == ifp)
        !           384:                        return (ia);
        !           385:        return ((struct in_ifaddr *)0);
        !           386: }
        !           387: 
        !           388: /*
        !           389:  * Send an icmp packet back to the ip level,
        !           390:  * after supplying a checksum.
        !           391:  */
        !           392: icmp_send(ip, opts)
        !           393:        register struct ip *ip;
        !           394:        struct mbuf *opts;
        !           395: {
        !           396:        register int hlen;
        !           397:        register struct icmp *icp;
        !           398:        register struct mbuf *m;
        !           399: 
        !           400:        m = dtom(ip);
        !           401:        hlen = ip->ip_hl << 2;
        !           402:        m->m_off += hlen;
        !           403:        m->m_len -= hlen;
        !           404:        icp = mtod(m, struct icmp *);
        !           405:        icp->icmp_cksum = 0;
        !           406:        icp->icmp_cksum = in_cksum(m, ip->ip_len - hlen);
        !           407:        m->m_off -= hlen;
        !           408:        m->m_len += hlen;
        !           409: #ifdef ICMPPRINTFS
        !           410:        if (icmpprintfs)
        !           411:                printf("icmp_send dst %x src %x\n", ip->ip_dst, ip->ip_src);
        !           412: #endif
        !           413:        (void) ip_output(m, opts, (struct route *)0, 0);
        !           414: }
        !           415: 
        !           416: n_time
        !           417: iptime()
        !           418: {
        !           419:        struct timeval atv;
        !           420:        u_long t;
        !           421: 
        !           422:        microtime(&atv);
        !           423:        t = (atv.tv_sec % (24*60*60)) * 1000 + atv.tv_usec / 1000;
        !           424:        return (htonl(t));
        !           425: }

unix.superglobalmegacorp.com

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