home *** CD-ROM | disk | FTP | other *** search
/ The Pier Shareware 6 / The_Pier_Shareware_Number_6_(The_Pier_Exchange)_(1995).iso / 024 / psi110g.zip / ICMP.C < prev    next >
C/C++ Source or Header  |  1994-04-17  |  9KB  |  275 lines

  1. /* Internet Control Message Protocol (ICMP)
  2.  * Copyright 1991 Phil Karn, KA9Q
  3.  */
  4. #include "global.h"
  5. #include "mbuf.h"
  6. #include "iface.h"
  7. #include "ip.h"
  8. #include "icmp.h"
  9. #include "netuser.h"
  10.   
  11. struct mib_entry Icmp_mib[] = {
  12.     "",                     0,
  13.     "icmpInMsgs",           0,
  14.     "icmpInErrors",         0,
  15.     "icmpInDestUnreachs",   0,
  16.     "icmpInTimeExcds",      0,
  17.     "icmpInParmProbs",      0,
  18.     "icmpInSrcQuenchs",     0,
  19.     "icmpInRedirects",      0,
  20.     "icmpInEchos",          0,
  21.     "icmpInEchoReps",       0,
  22.     "icmpInTimestamps",     0,
  23.     "icmpInTimestampReps",  0,
  24.     "icmpInAddrMasks",      0,
  25.     "icmpInAddrMaskReps",   0,
  26.     "icmpOutMsgs",          0,
  27.     "icmpOutErrors",        0,
  28.     "icmpOutDestUnreachs",  0,
  29.     "icmpOutTimeExcds",     0,
  30.     "icmpOutParmProbs",     0,
  31.     "icmpOutSrcQuenchs",    0,
  32.     "icmpOutRedirects",     0,
  33.     "icmpOutEchos",         0,
  34.     "icmpOutEchoReps",      0,
  35.     "icmpOutTimestamps",    0,
  36.     "icmpOutTimestampReps", 0,
  37.     "icmpOutAddrMasks",     0,
  38.     "icmpOutAddrMaskReps",  0,
  39. };
  40.   
  41. /* Process an incoming ICMP packet */
  42. void
  43. icmp_input(iface,ip,bp,rxbroadcast)
  44. struct iface *iface;    /* Incoming interface (ignored) */
  45. struct ip *ip;          /* Pointer to decoded IP header structure */
  46. struct mbuf *bp;        /* Pointer to ICMP message */
  47. int rxbroadcast;
  48. {
  49.     struct icmplink *ipp;
  50.     struct mbuf *tbp;
  51.     struct icmp icmp;       /* ICMP header */
  52.     struct ip oip;          /* Offending datagram header */
  53.     int16 type;             /* Type of ICMP message */
  54.     int16 length;
  55.     int ok_trace;
  56.     char temp[40];
  57.   
  58.     icmpInMsgs++;
  59.     if(rxbroadcast){
  60.         /* Broadcast ICMP packets are to be IGNORED !! */
  61.         icmpInErrors++;
  62.         free_p(bp);
  63.         return;
  64.     }
  65.     length = ip->length - IPLEN - ip->optlen;
  66.     if(cksum(NULLHEADER,bp,length) != 0){
  67.         /* Bad ICMP checksum; discard */
  68.         icmpInErrors++;
  69.         free_p(bp);
  70.         return;
  71.     }
  72.     ntohicmp(&icmp,&bp);
  73.   
  74.     /* Process the message. Some messages are passed up to the protocol
  75.      * module for handling, others are handled here.
  76.      */
  77.     type = icmp.type;
  78.   
  79.     switch(uchar(type)){
  80.         case ICMP_TIME_EXCEED:  /* Time-to-live Exceeded */
  81.         case ICMP_DEST_UNREACH: /* Destination Unreachable */
  82.         case ICMP_QUENCH:       /* Source Quench */
  83.         switch(uchar(type)){
  84.             case ICMP_TIME_EXCEED:  /* Time-to-live Exceeded */
  85.                 icmpInTimeExcds++;
  86.                 break;
  87.             case ICMP_DEST_UNREACH: /* Destination Unreachable */
  88.                 icmpInDestUnreachs++;
  89.                 break;
  90.             case ICMP_QUENCH:       /* Source Quench */
  91.                 icmpInSrcQuenchs++;
  92.                 break;
  93.         }
  94.             ntohip(&oip,&bp);       /* Extract offending IP header */
  95.             if(Icmp_trace){
  96.                 switch(uchar(type)){
  97.                     case ICMP_TIME_EXCEED:
  98.                         ok_trace=1;
  99.                         sprintf(temp,"%s",
  100.                         smsg(Exceed,NEXCEED,uchar(icmp.code)));
  101.                         break;
  102.                     case ICMP_DEST_UNREACH:
  103.                         ok_trace=1;
  104.                         sprintf(temp,"%s",
  105.                         smsg(Unreach,NUNREACH,uchar(icmp.code)));
  106.                         break;
  107.                     default:
  108.                         ok_trace=0;
  109.                         sprintf(temp,"%u",uchar(icmp.code));
  110.                         break;
  111.                 }
  112.   
  113.                 if ((Icmp_trace==1) || (Icmp_trace==2 && ok_trace)){
  114.   
  115.                     printf("ICMP from %s:",inet_ntoa(ip->source));
  116.                     printf(" dest %s %s ",inet_ntoa(oip.dest),
  117.                     smsg(Icmptypes,ICMP_TYPES,uchar(type)));
  118.                     printf(" %s\n",temp);
  119.   
  120.                 }
  121.             }
  122.             for(ipp = Icmplink;ipp->funct != NULL;ipp++)
  123.                 if(ipp->proto == oip.protocol)
  124.                     break;
  125.             if(ipp->funct != NULL){
  126.                 (*ipp->funct)(ip->source,oip.source,oip.dest,icmp.type,
  127.                 icmp.code,&bp);
  128.             }
  129.             break;
  130.         case ICMP_ECHO:         /* Echo Request */
  131.         /* Change type to ECHO_REPLY, recompute checksum,
  132.          * and return datagram.
  133.          */
  134.             icmpInEchos++;
  135.             icmp.type = ICMP_ECHO_REPLY;
  136.             if((tbp = htonicmp(&icmp,bp)) == NULLBUF){
  137.                 free_p(bp);
  138.                 return;
  139.             }
  140.             icmpOutEchoReps++;
  141.             ip_send(ip->dest,ip->source,ICMP_PTCL,ip->tos,0,tbp,length,0,0);
  142.             return;
  143.         case ICMP_REDIRECT:     /* Redirect */
  144.             icmpInRedirects++;
  145.             break;
  146.         case ICMP_PARAM_PROB:   /* Parameter Problem */
  147.             icmpInParmProbs++;
  148.             break;
  149.         case ICMP_ECHO_REPLY:   /* Echo Reply */
  150.             icmpInEchoReps++;
  151.             echo_proc(ip->source,ip->dest,&icmp,bp);
  152.             bp = NULLBUF;   /* so it won't get freed */
  153.             break;
  154.         case ICMP_TIMESTAMP:    /* Timestamp */
  155.             icmpInTimestamps++;
  156.             break;
  157.         case ICMP_TIME_REPLY:   /* Timestamp Reply */
  158.             icmpInTimestampReps++;
  159.             break;
  160.         case ICMP_INFO_RQST:    /* Information Request */
  161.             break;
  162.         case ICMP_INFO_REPLY:   /* Information Reply */
  163.             break;
  164.     }
  165.     free_p(bp);
  166. }
  167. /* Return an ICMP response to the sender of a datagram.
  168.  * Unlike most routines, the callER frees the mbuf.
  169.  */
  170. int
  171. icmp_output(ip,data,type,code,args)
  172. struct ip *ip;          /* Header of offending datagram */
  173. struct mbuf *data;      /* Data portion of datagram */
  174. char type,code;         /* Codes to send */
  175. union icmp_args *args;
  176. {
  177.     struct mbuf *bp = NULLBUF;
  178.     struct icmp icmp;       /* ICMP protocol header */
  179.     int16 dlen;             /* Length of data portion of offending pkt */
  180.     int16 length;           /* Total length of reply */
  181.   
  182.     if(ip == NULLIP)
  183.         return -1;
  184.     if(uchar(ip->protocol) == ICMP_PTCL){
  185.         /* Peek at type field of ICMP header to see if it's safe to
  186.          * return an ICMP message
  187.          */
  188.         switch(uchar(data->data[0])){
  189.             case ICMP_ECHO_REPLY:
  190.             case ICMP_ECHO:
  191.             case ICMP_TIMESTAMP:
  192.             case ICMP_TIME_REPLY:
  193.             case ICMP_INFO_RQST:
  194.             case ICMP_INFO_REPLY:
  195.                 break;  /* These are all safe */
  196.             default:
  197.             /* Never send an ICMP error message about another
  198.              * ICMP error message!
  199.              */
  200.                 return -1;
  201.         }
  202.     }
  203.     /* Compute amount of original datagram to return.
  204.      * We return the original IP header, and up to 8 bytes past that.
  205.      */
  206.     dlen = min(8,len_p(data));
  207.     length = dlen + ICMPLEN + IPLEN + ip->optlen;
  208.     /* Take excerpt from data portion */
  209.     if(data != NULLBUF && dup_p(&bp,data,0,dlen) == 0)
  210.         return -1;      /* The caller will free data */
  211.   
  212.     /* Recreate and tack on offending IP header */
  213.     if((data = htonip(ip,bp,IP_CS_NEW)) == NULLBUF){
  214.         free_p(bp);
  215.         icmpOutErrors++;
  216.         return -1;
  217.     }
  218.     icmp.type = type;
  219.     icmp.code = code;
  220.     icmp.args.unused = 0;
  221.     switch(uchar(icmp.type)){
  222.         case ICMP_PARAM_PROB:
  223.             icmpOutParmProbs++;
  224.             icmp.args.pointer = args->pointer;
  225.             break;
  226.         case ICMP_REDIRECT:
  227.             icmpOutRedirects++;
  228.             icmp.args.address = args->address;
  229.             break;
  230.         case ICMP_ECHO:
  231.             icmpOutEchos++;
  232.             break;
  233.         case ICMP_ECHO_REPLY:
  234.             icmpOutEchoReps++;
  235.             break;
  236.         case ICMP_INFO_RQST:
  237.             break;
  238.         case ICMP_INFO_REPLY:
  239.             break;
  240.         case ICMP_TIMESTAMP:
  241.             icmpOutTimestamps++;
  242.             break;
  243.         case ICMP_TIME_REPLY:
  244.             icmpOutTimestampReps++;
  245.             icmp.args.echo.id = args->echo.id;
  246.             icmp.args.echo.seq = args->echo.seq;
  247.             break;
  248.         case ICMP_ADDR_MASK:
  249.             icmpOutAddrMasks++;
  250.             break;
  251.         case ICMP_ADDR_MASK_REPLY:
  252.             icmpOutAddrMaskReps++;
  253.             break;
  254.         case ICMP_DEST_UNREACH:
  255.             if(icmp.code == ICMP_FRAG_NEEDED)
  256.                 icmp.args.mtu = args->mtu;
  257.             icmpOutDestUnreachs++;
  258.             break;
  259.         case ICMP_TIME_EXCEED:
  260.             icmpOutTimeExcds++;
  261.             break;
  262.         case ICMP_QUENCH:
  263.             icmpOutSrcQuenchs++;
  264.             break;
  265.     }
  266.   
  267.     icmpOutMsgs++;
  268.     /* Now stick on the ICMP header */
  269.     if((bp = htonicmp(&icmp,data)) == NULLBUF){
  270.         free_p(data);
  271.         return -1;
  272.     }
  273.     return ip_send(INADDR_ANY,ip->source,ICMP_PTCL,ip->tos,0,bp,length,0,0);
  274. }
  275.