Annotation of 43BSDTahoe/sys/netinet/ip_icmp.c, revision 1.1.1.1

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

unix.superglobalmegacorp.com

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