home *** CD-ROM | disk | FTP | other *** search
/ Columbia Kermit / kermit.zip / archives / msk316src.zip / MSNICM.C < prev    next >
C/C++ Source or Header  |  2000-10-31  |  9KB  |  359 lines

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