home *** CD-ROM | disk | FTP | other *** search
/ ftp.muug.mb.ca / 2014.06.ftp.muug.mb.ca.tar / ftp.muug.mb.ca / pub / src / traceroute / ip_icmp.c next >
C/C++ Source or Header  |  1989-10-13  |  11KB  |  448 lines

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