fix ip packet forwarding to not stomp on headers when fragmented;
[unix-history] / usr / src / sys / netinet / ip_icmp.c
index 2da7c96..5f46b42 100644 (file)
@@ -1,18 +1,20 @@
-/*     ip_icmp.c       4.22    82/10/20        */
+/*     ip_icmp.c       4.31    83/05/01        */
 
 #include "../h/param.h"
 #include "../h/systm.h"
 #include "../h/mbuf.h"
 #include "../h/protosw.h"
 #include "../h/socket.h"
 
 #include "../h/param.h"
 #include "../h/systm.h"
 #include "../h/mbuf.h"
 #include "../h/protosw.h"
 #include "../h/socket.h"
-#include <time.h>
+#include "../h/time.h"
 #include "../h/kernel.h"
 
 #include "../net/route.h"
 #include "../h/kernel.h"
 
 #include "../net/route.h"
+
 #include "../netinet/in.h"
 #include "../netinet/in_systm.h"
 #include "../netinet/ip.h"
 #include "../netinet/ip_icmp.h"
 #include "../netinet/in.h"
 #include "../netinet/in_systm.h"
 #include "../netinet/ip.h"
 #include "../netinet/ip_icmp.h"
+#include "../netinet/icmp_var.h"
 
 /*
  * ICMP routines: error generation, receive packet processing, and
 
 /*
  * ICMP routines: error generation, receive packet processing, and
@@ -27,7 +29,7 @@ int   icmpprintfs = 0;
  */
 icmp_error(oip, type, code)
        struct ip *oip;
  */
 icmp_error(oip, type, code)
        struct ip *oip;
-       int type, code;
+       u_int type, code;
 {
        register unsigned oiplen = oip->ip_hl << 2;
        register struct icmp *icp;
 {
        register unsigned oiplen = oip->ip_hl << 2;
        register struct icmp *icp;
@@ -36,23 +38,33 @@ icmp_error(oip, type, code)
 
        if (icmpprintfs)
                printf("icmp_error(%x, %d, %d)\n", oip, type, code);
 
        if (icmpprintfs)
                printf("icmp_error(%x, %d, %d)\n", oip, type, code);
+       icmpstat.icps_error++;
        /*
         * Make sure that the old IP packet had 8 bytes of data to return;
         * if not, don't bother.  Also don't EVER error if the old
         * packet protocol was ICMP.
         */
        /*
         * Make sure that the old IP packet had 8 bytes of data to return;
         * if not, don't bother.  Also don't EVER error if the old
         * packet protocol was ICMP.
         */
-       if (oip->ip_len < 8 || oip->ip_p == IPPROTO_ICMP)
+       if (oip->ip_len < 8) {
+               icmpstat.icps_oldshort++;
+               goto free;
+       }
+       if (oip->ip_p == IPPROTO_ICMP) {
+               icmpstat.icps_oldicmp++;
                goto free;
                goto free;
+       }
 
        /*
         * First, formulate icmp message
         */
 
        /*
         * First, formulate icmp message
         */
-       m = m_get(M_DONTWAIT);
-       if (m == 0)
+       m = m_get(M_DONTWAIT, MT_HEADER);
+       if (m == NULL)
                goto free;
        m->m_len = oiplen + 8 + ICMP_MINLEN;
        m->m_off = MMAXOFF - m->m_len;
        icp = mtod(m, struct icmp *);
                goto free;
        m->m_len = oiplen + 8 + ICMP_MINLEN;
        m->m_off = MMAXOFF - m->m_len;
        icp = mtod(m, struct icmp *);
+       if (type > ICMP_IREQREPLY)
+               panic("icmp_error");
+       icmpstat.icps_outhist[type]++;
        icp->icmp_type = type;
        icp->icmp_void = 0;
        if (type == ICMP_PARAMPROB) {
        icp->icmp_type = type;
        icp->icmp_void = 0;
        if (type == ICMP_PARAMPROB) {
@@ -63,9 +75,7 @@ icmp_error(oip, type, code)
        bcopy((caddr_t)oip, (caddr_t)&icp->icmp_ip, oiplen + 8);
        nip = &icp->icmp_ip;
        nip->ip_len += oiplen;
        bcopy((caddr_t)oip, (caddr_t)&icp->icmp_ip, oiplen + 8);
        nip = &icp->icmp_ip;
        nip->ip_len += oiplen;
-#if vax || pdp11 || ns16032
        nip->ip_len = htons((u_short)nip->ip_len);
        nip->ip_len = htons((u_short)nip->ip_len);
-#endif
 
        /*
         * Now, copy old ip header in front of icmp
 
        /*
         * Now, copy old ip header in front of icmp
@@ -106,7 +116,8 @@ icmp_input(m)
 {
        register struct icmp *icp;
        register struct ip *ip = mtod(m, struct ip *);
 {
        register struct icmp *icp;
        register struct ip *ip = mtod(m, struct ip *);
-       int icmplen = ip->ip_len, hlen = ip->ip_hl << 2, i, (*ctlfunc)();
+       int icmplen = ip->ip_len, hlen = ip->ip_hl << 2;
+       int (*ctlfunc)(), code, i;
        extern u_char ip_protox[];
 
        /*
        extern u_char ip_protox[];
 
        /*
@@ -115,8 +126,10 @@ icmp_input(m)
         */
        if (icmpprintfs)
                printf("icmp_input from %x, len %d\n", ip->ip_src, icmplen);
         */
        if (icmpprintfs)
                printf("icmp_input from %x, len %d\n", ip->ip_src, icmplen);
-       if (icmplen < ICMP_MINLEN)
+       if (icmplen < ICMP_MINLEN) {
+               icmpstat.icps_tooshort++;
                goto free;
                goto free;
+       }
        m->m_len -= hlen;
        m->m_off += hlen;
        /* need routine to make sure header is in this mbuf here */
        m->m_len -= hlen;
        m->m_off += hlen;
        /* need routine to make sure header is in this mbuf here */
@@ -124,7 +137,7 @@ icmp_input(m)
        i = icp->icmp_cksum;
        icp->icmp_cksum = 0;
        if (i != in_cksum(m, icmplen)) {
        i = icp->icmp_cksum;
        icp->icmp_cksum = 0;
        if (i != in_cksum(m, icmplen)) {
-               printf("icmp: cksum %x\n", i);
+               icmpstat.icps_checksum++;
                goto free;
        }
 
                goto free;
        }
 
@@ -134,26 +147,29 @@ icmp_input(m)
        if (icmpprintfs)
                printf("icmp_input, type %d code %d\n", icp->icmp_type,
                        icp->icmp_code);
        if (icmpprintfs)
                printf("icmp_input, type %d code %d\n", icp->icmp_type,
                        icp->icmp_code);
-       switch (i = icp->icmp_type) {
+       if (icp->icmp_type > ICMP_IREQREPLY)
+               goto free;
+       icmpstat.icps_inhist[icp->icmp_type]++;
+       switch (icp->icmp_type) {
 
        case ICMP_UNREACH:
        case ICMP_TIMXCEED:
        case ICMP_PARAMPROB:
 
        case ICMP_UNREACH:
        case ICMP_TIMXCEED:
        case ICMP_PARAMPROB:
-       case ICMP_REDIRECT:
        case ICMP_SOURCEQUENCH:
                /*
                 * Problem with previous datagram; advise
                 * higher level routines.
                 */
        case ICMP_SOURCEQUENCH:
                /*
                 * Problem with previous datagram; advise
                 * higher level routines.
                 */
-#if vax || pdp11 || ns16032
                icp->icmp_ip.ip_len = ntohs((u_short)icp->icmp_ip.ip_len);
                icp->icmp_ip.ip_len = ntohs((u_short)icp->icmp_ip.ip_len);
-#endif
-               if (icmplen < ICMP_ADVLENMIN || icmplen < ICMP_ADVLEN(icp))
+               if (icmplen < ICMP_ADVLENMIN || icmplen < ICMP_ADVLEN(icp)) {
+                       icmpstat.icps_badlen++;
                        goto free;
                        goto free;
+               }
                if (icmpprintfs)
                        printf("deliver to protocol %d\n", icp->icmp_ip.ip_p);
                if (icmpprintfs)
                        printf("deliver to protocol %d\n", icp->icmp_ip.ip_p);
-               if (ctlfunc = protosw[ip_protox[icp->icmp_ip.ip_p]].pr_ctlinput)
-                       (*ctlfunc)(icmpmap[i] + icp->icmp_code, (caddr_t)icp);
+               code = icp->icmp_type == ICMP_PARAMPROB ? 0 : icp->icmp_code;
+               if (ctlfunc = inetsw[ip_protox[icp->icmp_ip.ip_p]].pr_ctlinput)
+                       (*ctlfunc)(icmpmap[icp->icmp_type]+code, (caddr_t)icp);
                goto free;
 
        case ICMP_ECHO:
                goto free;
 
        case ICMP_ECHO:
@@ -161,8 +177,10 @@ icmp_input(m)
                goto reflect;
 
        case ICMP_TSTAMP:
                goto reflect;
 
        case ICMP_TSTAMP:
-               if (icmplen < ICMP_TSLEN)
+               if (icmplen < ICMP_TSLEN) {
+                       icmpstat.icps_badlen++;
                        goto free;
                        goto free;
+               }
                icp->icmp_type = ICMP_TSTAMPREPLY;
                icp->icmp_rtime = iptime();
                icp->icmp_ttime = icp->icmp_rtime;      /* bogus, do later! */
                icp->icmp_type = ICMP_TSTAMPREPLY;
                icp->icmp_rtime = iptime();
                icp->icmp_ttime = icp->icmp_rtime;      /* bogus, do later! */
@@ -172,22 +190,41 @@ icmp_input(m)
                /* fill in source address zero fields! */
                goto reflect;
 
                /* fill in source address zero fields! */
                goto reflect;
 
+       case ICMP_REDIRECT:
        case ICMP_ECHOREPLY:
        case ICMP_TSTAMPREPLY:
        case ICMP_IREQREPLY:
        case ICMP_ECHOREPLY:
        case ICMP_TSTAMPREPLY:
        case ICMP_IREQREPLY:
-               if (icmplen < ICMP_ADVLENMIN || icmplen < ICMP_ADVLEN(icp))
+               if (icmplen < ICMP_ADVLENMIN || icmplen < ICMP_ADVLEN(icp)) {
+                       icmpstat.icps_badlen++;
                        goto free;
                        goto free;
+               }
+               /*
+                * Short circuit routing redirects to force
+                * immediate change in the kernel's routing
+                * tables.  The message is also handed to anyone
+                * listening on a raw socket (e.g. the routing
+                * daemon for use in updating it's tables).
+                */
+               if (icp->icmp_type == ICMP_REDIRECT) {
+                       icmpsrc.sin_addr = icp->icmp_ip.ip_dst;
+                       icmpdst.sin_addr = icp->icmp_gwaddr;
+                       rtredirect((struct sockaddr *)&icmpsrc,
+                         (struct sockaddr *)&icmpdst);
+               }
                icmpsrc.sin_addr = ip->ip_src;
                icmpdst.sin_addr = ip->ip_dst;
                raw_input(dtom(icp), &icmproto, (struct sockaddr *)&icmpsrc,
                  (struct sockaddr *)&icmpdst);
                icmpsrc.sin_addr = ip->ip_src;
                icmpdst.sin_addr = ip->ip_dst;
                raw_input(dtom(icp), &icmproto, (struct sockaddr *)&icmpsrc,
                  (struct sockaddr *)&icmpdst);
-               goto free;
+               return;
 
        default:
                goto free;
        }
 reflect:
 
        default:
                goto free;
        }
 reflect:
+       ip->ip_len += hlen;             /* since ip_input deducts this */
+       icmpstat.icps_reflect++;
        icmp_reflect(ip);
        icmp_reflect(ip);
+       return;
 free:
        m_freem(dtom(ip));
 }
 free:
        m_freem(dtom(ip));
 }
@@ -207,8 +244,6 @@ icmp_reflect(ip)
        icmp_send(ip);
 }
 
        icmp_send(ip);
 }
 
-int    generateicmpmsgs = 1;
-
 /*
  * Send an icmp packet back to the ip level,
  * after supplying a checksum.
 /*
  * Send an icmp packet back to the ip level,
  * after supplying a checksum.
@@ -216,12 +251,12 @@ int       generateicmpmsgs = 1;
 icmp_send(ip)
        struct ip *ip;
 {
 icmp_send(ip)
        struct ip *ip;
 {
-       register int hlen = ip->ip_hl << 2;
+       register int hlen;
        register struct icmp *icp;
        register struct icmp *icp;
-       register struct mbuf *m = dtom(ip);
+       register struct mbuf *m;
 
 
-       if (!generateicmpmsgs)
-               return;
+       m = dtom(ip);
+       hlen = ip->ip_hl << 2;
        icp = mtod(m, struct icmp *);
        icp->icmp_cksum = 0;
        icp->icmp_cksum = in_cksum(m, ip->ip_len - hlen);
        icp = mtod(m, struct icmp *);
        icp->icmp_cksum = 0;
        icp->icmp_cksum = in_cksum(m, ip->ip_len - hlen);