Add sanity check for return of sotoinpcb() and intotcpcb()
[unix-history] / sys / netinet / ip_icmp.c
index 1e99abb..1085bb7 100644 (file)
@@ -31,7 +31,7 @@
  * SUCH DAMAGE.
  *
  *     from: @(#)ip_icmp.c     7.15 (Berkeley) 4/20/91
  * SUCH DAMAGE.
  *
  *     from: @(#)ip_icmp.c     7.15 (Berkeley) 4/20/91
- *     $Id$
+ *     $Id: ip_icmp.c,v 1.6 1993/12/19 00:52:42 wollman Exp $
  */
 
 #include "param.h"
  */
 
 #include "param.h"
  * routines to turnaround packets back to the originator, and
  * host table maintenance routines.
  */
  * routines to turnaround packets back to the originator, and
  * host table maintenance routines.
  */
-#ifdef ICMPPRINTFS
-int    icmpprintfs = 0;
-#endif
 
 
-extern struct protosw inetsw[];
+#define satosin(sa) ((struct sockaddr_in *)(sa))
+static void icmp_reflect(struct mbuf *);
+static void icmp_send(struct mbuf *, struct mbuf *);
+
 
 /*
  * Generate an error packet of type error
  * in response to bad packet ip.
  */
 
 /*
  * Generate an error packet of type error
  * in response to bad packet ip.
  */
-/*VARARGS3*/
-icmp_error(n, type, code, dest)
+void
+icmp_error(n, type, code, dest, mtu)
        struct mbuf *n;
        int type, code;
        struct in_addr dest;
        struct mbuf *n;
        int type, code;
        struct in_addr dest;
+       int mtu;                /* mtu for ICMP_UNREACH_SRCFRAG */
 {
        register struct ip *oip = mtod(n, struct ip *), *nip;
        register unsigned oiplen = oip->ip_hl << 2;
        register struct icmp *icp;
 {
        register struct ip *oip = mtod(n, struct ip *), *nip;
        register unsigned oiplen = oip->ip_hl << 2;
        register struct icmp *icp;
-       register struct mbuf *m;
+       register struct mbuf *m = 0;
        unsigned icmplen;
        unsigned icmplen;
+       u_long oaddr;
 
 #ifdef ICMPPRINTFS
        if (icmpprintfs)
 
 #ifdef ICMPPRINTFS
        if (icmpprintfs)
@@ -86,6 +88,61 @@ icmp_error(n, type, code, dest)
 #endif
        if (type != ICMP_REDIRECT)
                icmpstat.icps_error++;
 #endif
        if (type != ICMP_REDIRECT)
                icmpstat.icps_error++;
+
+       /*
+        * Quoth RFC 1122 (Requirements for Internet Hosts):
+        *
+        * An ICMP error message MUST NOT be sent as the result of
+        * receiving:
+        * - an ICMP error message, or
+        * - a datagram destined to an IP broadcast or IP multicast
+        *   address, or
+        * - a datagram sent as a link-layer broadcast, or
+        * - a non-initial fragment, or
+        * - a datagram whose source address does not define a single
+        *   host -- e.g., a zero address, a loopback address, a
+        *   broadcast address, a multicast address, or a Class E
+        *   address.
+        *
+        * NOTE: THESE RESTRICTIONS TAKE PRECEDENCE OVER ANY REQUIREMENT
+        * ELSEWHERE IN THIS DOCUMENT FOR SENDING ICMP ERROR MESSAGES.
+        */
+
+       oaddr = ntohl(oip->ip_src.s_addr);
+
+       /*
+        * Don't send error messages to multicast or broadcast addresses.
+        */
+       if (IN_MULTICAST(oaddr)
+           || oaddr == INADDR_BROADCAST
+           || n->m_flags & (M_BCAST | M_MCAST)) {
+         icmpstat.icps_oldmcast++;
+         goto freeit;
+       }
+
+       /*
+        * Don't send error messages to zero addresses or class E's.
+        */
+       if (IN_EXPERIMENTAL(oaddr)
+           || ! in_lnaof(oip->ip_src)
+           || ! in_netof(oip->ip_src)) {
+         icmpstat.icps_oldbadaddr++;
+         goto freeit;
+       }
+
+       /*
+        * Don't send error messages to loopback addresses.
+        * As a special (unauthorized) exception, we check to see
+        * if the packet came from the loopback interface.  If it
+        * did, then we should allow the errors through, because
+        * the upper layers rely on them.
+        */
+       if(in_netof(oip->ip_src) == IN_LOOPBACKNET
+          && !(m->m_pkthdr.rcvif->if_flags & IFF_LOOPBACK)) {
+         icmpstat.icps_oldbadaddr++;
+         goto freeit;
+       }
+
        /*
         * Don't send error if not the first fragment of message.
         * Don't error if the old packet protocol was ICMP
        /*
         * Don't send error if not the first fragment of message.
         * Don't error if the old packet protocol was ICMP
@@ -99,6 +156,11 @@ icmp_error(n, type, code, dest)
                icmpstat.icps_oldicmp++;
                goto freeit;
        }
                icmpstat.icps_oldicmp++;
                goto freeit;
        }
+#ifdef MULTICAST
+       /* Don't send error in response to a multicast or broadcast packet */
+       if(n->m_flags & (M_MCAST | M_BCAST))
+               goto freeit;
+#endif
 
        /*
         * First, formulate icmp message
 
        /*
         * First, formulate icmp message
@@ -116,8 +178,12 @@ icmp_error(n, type, code, dest)
        icp->icmp_type = type;
        if (type == ICMP_REDIRECT)
                icp->icmp_gwaddr = dest;
        icp->icmp_type = type;
        if (type == ICMP_REDIRECT)
                icp->icmp_gwaddr = dest;
-       else
+       else if (type == ICMP_UNREACH && code == ICMP_UNREACH_NEEDFRAG) {
+               icp->icmp_mtu = htons(mtu);
+               icp->icmp_mtuvoid = 0;
+       } else {
                icp->icmp_void = 0;
                icp->icmp_void = 0;
+       }
        if (type == ICMP_PARAMPROB) {
                icp->icmp_pptr = code;
                code = 0;
        if (type == ICMP_PARAMPROB) {
                icp->icmp_pptr = code;
                code = 0;
@@ -152,12 +218,11 @@ static struct sockproto icmproto = { AF_INET, IPPROTO_ICMP };
 static struct sockaddr_in icmpsrc = { sizeof (struct sockaddr_in), AF_INET };
 static struct sockaddr_in icmpdst = { sizeof (struct sockaddr_in), AF_INET };
 static struct sockaddr_in icmpgw = { sizeof (struct sockaddr_in), AF_INET };
 static struct sockaddr_in icmpsrc = { sizeof (struct sockaddr_in), AF_INET };
 static struct sockaddr_in icmpdst = { sizeof (struct sockaddr_in), AF_INET };
 static struct sockaddr_in icmpgw = { sizeof (struct sockaddr_in), AF_INET };
-struct sockaddr_in icmpmask = { 8, 0 };
-struct in_ifaddr *ifptoia();
 
 /*
  * Process a received ICMP message.
  */
 
 /*
  * Process a received ICMP message.
  */
+void
 icmp_input(m, hlen)
        register struct mbuf *m;
        int hlen;
 icmp_input(m, hlen)
        register struct mbuf *m;
        int hlen;
@@ -167,9 +232,8 @@ icmp_input(m, hlen)
        int icmplen = ip->ip_len;
        register int i;
        struct in_ifaddr *ia;
        int icmplen = ip->ip_len;
        register int i;
        struct in_ifaddr *ia;
-       int (*ctlfunc)(), code;
-       extern u_char ip_protox[];
-       extern struct in_addr in_makeaddr();
+       in_ctlinput_t *ctlfunc;
+       int code;
 
        /*
         * Locate icmp structure in mbuf, and check
 
        /*
         * Locate icmp structure in mbuf, and check
@@ -214,21 +278,35 @@ icmp_input(m, hlen)
        switch (icp->icmp_type) {
 
        case ICMP_UNREACH:
        switch (icp->icmp_type) {
 
        case ICMP_UNREACH:
-               if (code > 5)
+               if (code > ICMP_UNREACH_MAXCODE)
                        goto badcode;
                        goto badcode;
-               code += PRC_UNREACH_NET;
+               if (code == ICMP_UNREACH_NEEDFRAG) {
+#ifdef MTUDISC
+                       /*
+                        * Need to adjust the routing tables immediately;
+                        * when ULP's get the PRC_MSGSIZE, it is their
+                        * responsibility to notice it and update their
+                        * internal ideas of MTU-derived protocol parameters.
+                        */
+                       in_mtureduce(icp->icmp_ip.ip_dst, 
+                                    ntohs(icp->icmp_mtu));
+                       code = PRC_MSGSIZE;
+#endif /* MTUDISC */
+               } else {
+                       code += PRC_UNREACH_NET;
+               }
                goto deliver;
 
        case ICMP_TIMXCEED:
                goto deliver;
 
        case ICMP_TIMXCEED:
-               if (code > 1)
+               if (code > ICMP_TIMXCEED_MAXCODE)
                        goto badcode;
                code += PRC_TIMXCEED_INTRANS;
                goto deliver;
 
        case ICMP_PARAMPROB:
                        goto badcode;
                code += PRC_TIMXCEED_INTRANS;
                goto deliver;
 
        case ICMP_PARAMPROB:
-               if (code)
+               if (code > ICMP_PARAMPROB_MAXCODE)
                        goto badcode;
                        goto badcode;
-               code = PRC_PARAMPROB;
+               code += PRC_PARAMPROB;
                goto deliver;
 
        case ICMP_SOURCEQUENCH:
                goto deliver;
 
        case ICMP_SOURCEQUENCH:
@@ -252,14 +330,36 @@ icmp_input(m, hlen)
                icmpsrc.sin_addr = icp->icmp_ip.ip_dst;
                if (ctlfunc = inetsw[ip_protox[icp->icmp_ip.ip_p]].pr_ctlinput)
                        (*ctlfunc)(code, (struct sockaddr *)&icmpsrc,
                icmpsrc.sin_addr = icp->icmp_ip.ip_dst;
                if (ctlfunc = inetsw[ip_protox[icp->icmp_ip.ip_p]].pr_ctlinput)
                        (*ctlfunc)(code, (struct sockaddr *)&icmpsrc,
-                           (caddr_t) &icp->icmp_ip);
+                                  &icp->icmp_ip);
                break;
 
        badcode:
                icmpstat.icps_badcode++;
                break;
 
                break;
 
        badcode:
                icmpstat.icps_badcode++;
                break;
 
+               /*
+                * Always respond to pings from valid addresses.
+                * Don't respond to broadcast pings unless ipbroadcastecho
+                * is set.  Don't respond to multicast pings unless
+                * ipbraodcastecho is set AND we support multicasting
+                * to begin with.  (Per RFC 1122, we may choose either.)
+                */
        case ICMP_ECHO:
        case ICMP_ECHO:
+               {
+                 u_long srcaddr = ntohl(icp->icmp_ip.ip_src.s_addr);
+#ifdef MULTICAST
+                 if(IN_MULTICAST(srcaddr) && !ipbroadcastecho)
+                   break;
+#else /* not MULTICAST */
+                 if(IN_MULTICAST(srcaddr))
+                   break;
+#endif /* not MULTICAST */
+                 if((srcaddr == INADDR_BROADCAST
+                     || m->m_flags & M_BCAST)
+                    && !ipbroadcastecho)
+                   break;
+               }
+
                icp->icmp_type = ICMP_ECHOREPLY;
                goto reflect;
 
                icp->icmp_type = ICMP_ECHOREPLY;
                goto reflect;
 
@@ -273,16 +373,14 @@ icmp_input(m, hlen)
                icp->icmp_ttime = icp->icmp_rtime;      /* bogus, do later! */
                goto reflect;
                
                icp->icmp_ttime = icp->icmp_rtime;      /* bogus, do later! */
                goto reflect;
                
-       case ICMP_IREQ:
-#define        satosin(sa)     ((struct sockaddr_in *)(sa))
-               if (in_netof(ip->ip_src) == 0 &&
-                   (ia = ifptoia(m->m_pkthdr.rcvif)))
-                       ip->ip_src = in_makeaddr(in_netof(IA_SIN(ia)->sin_addr),
-                           in_lnaof(ip->ip_src));
-               icp->icmp_type = ICMP_IREQREPLY;
-               goto reflect;
-
+               /*
+                * Per RFC 1122, only respond to ICMP mask requests
+                * if the administrator has SPECIFICALLY CONFIGURED
+                * this host as an address mask agent.
+                */
        case ICMP_MASKREQ:
        case ICMP_MASKREQ:
+               if (!ipmaskagent)
+                 break;
                if (icmplen < ICMP_MASKLEN ||
                    (ia = ifptoia(m->m_pkthdr.rcvif)) == 0)
                        break;
                if (icmplen < ICMP_MASKLEN ||
                    (ia = ifptoia(m->m_pkthdr.rcvif)) == 0)
                        break;
@@ -320,8 +418,21 @@ reflect:
                        printf("redirect dst %x to %x\n", icp->icmp_ip.ip_dst,
                                icp->icmp_gwaddr);
 #endif
                        printf("redirect dst %x to %x\n", icp->icmp_ip.ip_dst,
                                icp->icmp_gwaddr);
 #endif
+               /*
+                * Per RFC 1122, throw away redirects that
+                * suggested places we can't get to, or
+                * an interface other than the one the packet
+                * arrived on.
+                *
+                * It also says that we SHOULD throw away
+                * redirects that come from someone other
+                * than the current first-hop gateway for the
+                * specified destination.
+                *
+                * These are both implemented as general policy
+                * by rtredirect().
+                */
                if (code == ICMP_REDIRECT_NET || code == ICMP_REDIRECT_TOSNET) {
                if (code == ICMP_REDIRECT_NET || code == ICMP_REDIRECT_TOSNET) {
-                       u_long in_netof();
                        icmpsrc.sin_addr =
                         in_makeaddr(in_netof(icp->icmp_ip.ip_dst), INADDR_ANY);
                        in_sockmaskof(icp->icmp_ip.ip_dst, &icmpmask);
                        icmpsrc.sin_addr =
                         in_makeaddr(in_netof(icp->icmp_ip.ip_dst), INADDR_ANY);
                        in_sockmaskof(icp->icmp_ip.ip_dst, &icmpmask);
@@ -369,6 +480,7 @@ freeit:
 /*
  * Reflect the ip packet back to the source
  */
 /*
  * Reflect the ip packet back to the source
  */
+static void
 icmp_reflect(m)
        struct mbuf *m;
 {
 icmp_reflect(m)
        struct mbuf *m;
 {
@@ -485,6 +597,7 @@ ifptoia(ifp)
  * 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.
  */
+static void
 icmp_send(m, opts)
        register struct mbuf *m;
        struct mbuf *opts;
 icmp_send(m, opts)
        register struct mbuf *m;
        struct mbuf *opts;