home *** CD-ROM | disk | FTP | other *** search
/ Columbia Kermit / kermit.zip / archives / msr313src.zip / msnicm.c < prev    next >
C/C++ Source or Header  |  1993-07-12  |  9KB  |  363 lines

  1. /* File MSNICM.C
  2.  * ICMP packet processor
  3.  *
  4.  * Copyright (C) 1991, University of Waterloo.
  5.  * Copyright (C) 1985, 1993, Trustees of Columbia University in the 
  6.  * City of New York.  Permission is granted to any individual or institution
  7.  * to use this software as long as it is not sold for profit.  This copyright
  8.  * notice must be retained.  This software may not be included in commercial
  9.  * products without written permission of Columbia University.
  10.  *
  11.  * Original version created by Erick Engelke of the University of
  12.  *  Waterloo, Waterloo, Ontario, Canada.
  13.  * Adapted and modified for MS-DOS Kermit by Joe R. Doupnik, 
  14.  *  Utah State University, jrd@cc.usu.edu, jrd@usu.Bitnet.
  15.  *
  16.  * Last edit
  17.  * 27 August 1992 v3.13
  18.  */
  19. #include "msntcp.h"
  20. #include "msnlib.h"
  21.  
  22. /*
  23.  * ICMP - RFC 792
  24.  */
  25.  
  26. static byte *unreach[] = {
  27.     "Network Unreachable",
  28.     "Host Unreachable",
  29.     "Protocol Unreachable",
  30.     "Port Unreachable",
  31.     "Fragmentation needed and DF set",
  32.     "Source Route Failed" };
  33.  
  34. static byte *exceed[] = {
  35.     "TTL exceeded in transit",
  36.     "Frag ReAsm time exceeded" };
  37.  
  38. static byte *redirect[] = {
  39.     "Redirect for Network",
  40.     "Redirect for Host",
  41.     "Redirect for TOS and Network",
  42.     "Redirect for TOS and Host" };
  43.  
  44. /* constants */
  45.  
  46.  
  47. typedef struct icmp_unused {
  48.     byte     type;
  49.     byte    code;
  50.     word    checksum;
  51.     longword    unused;
  52.     in_Header    ip;
  53.     byte    spares[ 8 ];
  54. };
  55.  
  56. typedef struct icmp_pointer {
  57.     byte    type;
  58.     byte    code;
  59.     word    checksum;
  60.     byte    pointer;
  61.     byte    unused[ 3 ];
  62.     in_Header    ip;
  63. };
  64. typedef struct icmp_ip {
  65.     byte    type;
  66.     byte    code;
  67.     word    checksum;
  68.     longword    ipaddr;
  69.     in_Header    ip;
  70. };
  71. typedef struct icmp_echo {
  72.     byte    type;
  73.     byte    code;
  74.     word    checksum;
  75.     word    identifier;
  76.     word    sequence;
  77. };
  78.  
  79. typedef struct icmp_timestamp {
  80.     byte    type;
  81.     byte    code;
  82.     word    checksum;
  83.     word    identifier;
  84.     word    sequence;
  85.     longword    original;    /* original timestamp */
  86.     longword    receive;    /* receive timestamp */
  87.     longword    transmit;    /* transmit timestamp */
  88. };
  89.  
  90. typedef struct icmp_info {
  91.     byte    type;
  92.     byte    code;
  93.     word    checksum;
  94.     word    identifier;
  95.     word    sequence;
  96. };
  97.  
  98. typedef union  {
  99.     struct icmp_unused    unused;
  100.     struct icmp_pointer    pointer;
  101.     struct icmp_ip        ip;
  102.     struct icmp_echo    echo;
  103.     struct icmp_timestamp    timestamp;
  104.     struct icmp_info    info;
  105. } icmp_pkt;
  106.  
  107. typedef struct pkt {
  108.     in_Header     in;
  109.     icmp_pkt     icmp;
  110.     in_Header    data;
  111. };
  112.  
  113. static word icmp_id = 0;
  114. static longword ping_hcache = 0L;    /* host */
  115. static longword ping_tcache = 0L;    /* time */
  116. static longword ping_number = 0L;
  117. extern    word debug_on;
  118. extern    word sourcequench;        /* non-zero if rcv'd ICMP S. Q. */
  119. int    icmp_unreach = 0;        /* tell world about unreachables */
  120. int    icmp_redirect = 0;
  121.  
  122. void
  123. icmp_init()                /* reinit all local statics */
  124. {
  125.     ping_hcache = ping_tcache = ping_number = 0L;
  126.     icmp_id = 0;
  127.     return;
  128. }
  129.  
  130. #ifndef KERMIT
  131. longword 
  132. chk_ping(longword host, longword *ptr)
  133. {
  134.     if ((ping_hcache == host) && (ptr != NULL))
  135.         {
  136.         ping_hcache = 0xffffffffL;
  137.         *ptr = ping_number;
  138.         return (ping_tcache);
  139.         }
  140.     return (0xffffffffL);
  141. }
  142. #endif /* KERMIT */
  143.  
  144. void
  145. icmp_print(byte *msg)
  146. {
  147.     if (msg == NULL) return;
  148.     outs("\n\r ICMP: ");
  149.     outs(msg);
  150. }
  151.  
  152. struct pkt *
  153. icmp_Format(longword destip)
  154. {
  155.     eth_address dest;
  156.  
  157.         /* we use arp rather than supplied hardware address */
  158.         /* after first ping this will still be in cache */
  159.  
  160.     if (arp_resolve(destip, dest) == 0)
  161.         return (NULL);            /* unable to find address */
  162.     return ((struct pkt*)eth_formatpacket(dest, TYPE_IP));
  163. }
  164. /*
  165.  * icmp_Reply - format a reply packet
  166.  *            - note that src and dest are NETWORK order not host!!!!
  167.  */
  168. int
  169. icmp_Reply(struct pkt *p, longword src, longword dest, int icmp_length)
  170. {
  171.  
  172.     if (p == NULL) return (0);        /* failure */
  173.  
  174.     /* finish the icmp checksum portion */
  175.     p->icmp.unused.checksum = 0;
  176.     p->icmp.unused.checksum = ~checksum(&p->icmp, icmp_length);
  177.  
  178.     /* encapsulate into a nice IP packet */
  179.     p->in.hdrlen_ver = 0x45;
  180.     p->in.length = htons(sizeof(in_Header) + icmp_length);
  181.     p->in.tos = 0;
  182.     p->in.identification = htons(icmp_id++);    /* not using IP id */
  183.     p->in.frag = 0;
  184.     p->in.ttl = 250;
  185.     p->in.proto = ICMP_PROTO;
  186.     p->in.checksum = 0;
  187.     p->in.source = src;
  188.     p->in.destination = dest;
  189.     p->in.checksum = ~checksum(&p->in, sizeof(in_Header));
  190.  
  191.     return (eth_send(htons(p->in.length)));        /* send the reply */
  192. }
  193.  
  194. int
  195. do_ping(byte * hostid, longword hostip)
  196. {
  197.     register struct pkt *pkt;
  198.     byte mybuf[17];
  199.  
  200.     if (hostip == 0L)         /* if no host IP number yet */
  201.         if ((hostip = resolve(hostid)) == 0L)
  202.         return (-1);        /* failed to resolve host */
  203.  
  204.     pkt = icmp_Format(hostip);
  205.     pkt->icmp.echo.type = 8;            /* Echo Request */
  206.     pkt->icmp.echo.code = 0;
  207.     pkt->icmp.echo.identifier = (word)(htonl(my_ip_addr) & 0xffff);
  208.     pkt->icmp.echo.sequence = (word)((ping_number++) & 0xffff);
  209.     pkt->icmp.timestamp.original = htonl(0x12345678);
  210.     icmp_Reply(pkt, htonl(my_ip_addr), htonl(hostip),
  211.                     4 + sizeof(struct icmp_echo));
  212.     outs("\r\n Sending Ping to ");
  213.     ntoa(mybuf, hostip); outs(mybuf);
  214.     return (0);
  215. }
  216.  
  217. int
  218. icmp_handler(in_Header *ip)
  219. {
  220.     register icmp_pkt *icmp, *newicmp;
  221.     struct pkt *pkt;
  222.     int len, code;
  223.     in_Header *ret;
  224.     byte nametemp[17];
  225.     extern void do_redirect(long, void *);
  226.  
  227.     len = in_GetHdrlenBytes(ip);
  228.     icmp = (icmp_pkt *)((byte *)ip + len);
  229.     len = ntohs(ip->length) - len;
  230.     if (checksum(icmp, len) != 0xffff)
  231.         return (0);                /* 0 = failure */
  232.  
  233.     code = icmp->unused.code;
  234.     switch (icmp->unused.type)
  235.     {
  236.     case 0:             /* icmp echo reply received */
  237.     /*     icmp_print("received icmp echo receipt");  */
  238.  
  239.         /* check if we were waiting for it */
  240.         if (icmp->echo.identifier == (word)(ntohl(my_ip_addr)&0xffff))
  241.             {            /* answer to our request */
  242.             outs("\r\n host is alive\r\n");
  243.             break;
  244.             }
  245. #ifndef KERMIT
  246.         ping_hcache = ntohl(ip->source);
  247.         ping_tcache = set_timeout(1) -
  248.             *(longword *)(&icmp->echo.identifier);
  249.         if (ping_tcache > 0xffffffffL)
  250.             ping_tcache += 0x1800b0L;
  251.  
  252.         ping_number =
  253.             *(longword*)(((byte*)(&icmp->echo.identifier)) + 4);
  254.                         /* do more */
  255. #endif /* Kermit */
  256.         break;
  257.  
  258.     case 3 : /* destination or port unreachable message */
  259.         if (code < 6)
  260.             {
  261.             icmp_print(unreach[code]);    /* display msg */
  262.             icmp_unreach = 1 + code; /* say unreachable condx */
  263.                         /* handle udp or tcp socket */
  264.             ret = &icmp->ip.ip;    /* ret'd IP header + 8 bytes*/
  265.             if (ret->proto == TCP_PROTO)
  266.                 tcp_cancel(ret);
  267.             if (ret->proto == UDP_PROTO)
  268.                 udp_cancel(ret);
  269.             }
  270.         break;
  271.  
  272.     case 4:                /* source quench */
  273. /*        icmp_print("Source Quench"); */
  274.         sourcequench = 1;    /* set flag, used in TCP code */
  275.         break;
  276.  
  277.     case 5:                 /* redirect */
  278.         if (code < 4)
  279.             {
  280.                     /* new gateway IP address to use */ 
  281.             arp_register(ntohl(icmp->ip.ipaddr), 
  282.                 ntohl(icmp->ip.ip.destination));
  283.                     /* for this host IP address */
  284.                     /* and add to list of gateways */
  285.             ntoa(nametemp, ntohl(icmp->ip.ipaddr));
  286.             icmp_print(redirect[code]);
  287.             outs(" to gateway "); outs(nametemp);
  288.             do_redirect(ntohl(icmp->ip.ipaddr), &icmp->ip.ip);
  289.                 /* new gateway        returned IP header */
  290.             }
  291.         break;
  292.  
  293.     case 8: /* icmp echo request */
  294. /*         icmp_print("PING requested of us"); */
  295.  
  296.             /* format the packet with the request's hardware address */
  297.         pkt = (struct pkt*)(eth_formatpacket(
  298.                 (eth_address *)eth_hardware(ip), TYPE_IP));
  299.         newicmp = &pkt->icmp;
  300.         bcopy(icmp, newicmp, len);
  301.         newicmp->echo.type = 0;
  302.         newicmp->echo.code = (byte)(code & 0xff);
  303.  
  304.         /* use supplied ip values in case we ever multi-home */
  305.         /* note that ip values are still in network order */
  306.  
  307.         icmp_Reply(pkt, ip->destination, ip->source, len);
  308. /*         icmp_print("PING reply sent"); */
  309.         break;
  310.  
  311.     case 11:             /* time exceeded message */
  312.         if (code < 2)
  313.             icmp_print(exceed[code]);
  314.         break;
  315.  
  316.     case 12:             /* parameter problem message */
  317.         icmp_print("IP Parameter problem");
  318.         break;
  319.  
  320.     case 13:             /* timestamp message */
  321. /*        icmp_print("Timestamp message"); */
  322.         /* send reply */
  323.         break;
  324.  
  325.     case 14:             /* timestamp reply */
  326. /*        icmp_print("Timestamp reply"); */
  327.         /* should store */
  328.         break;
  329.  
  330.     case 15:             /* info request */
  331. /*        icmp_print("Info requested"); */
  332.         /* send reply */
  333.         break;
  334.  
  335.     case 16:             /* info reply */
  336. /*        icmp_print("Info reply"); */
  337.         break;
  338.     }                /* end of switch */
  339.     return (1);            /* status of success */
  340. }
  341.  
  342. /* Return ICMP Destination and Port Unreachable message */
  343. void
  344. icmp_noport(in_Header *ip)
  345. {
  346.     register icmp_pkt *icmp, *newicmp;
  347.     struct pkt *pkt;
  348.     int len;
  349.  
  350.     len = in_GetHdrlenBytes(ip);
  351.     icmp = (icmp_pkt *)((byte *)ip + len);
  352.     pkt = (struct pkt*)(eth_formatpacket(
  353.             (eth_address *)eth_hardware(ip), TYPE_IP));
  354.     newicmp = &pkt->icmp;
  355.     newicmp->unused.type = 3;    /* destination unreachable */
  356.     newicmp->unused.code = 3;    /* port unreachable */
  357.     newicmp->unused.unused = 0L;    /* must be zero for unreachables */
  358.         /* send back Internet header + first 64 bits of datagram */
  359.     bcopy(ip, &newicmp->unused.ip, 8 + sizeof(in_Header));
  360.     icmp_Reply(pkt, ip->destination, ip->source, 
  361.         sizeof(struct icmp_unused));    /* compose and send reply */
  362. }
  363.