home *** CD-ROM | disk | FTP | other *** search
/ Columbia Kermit / kermit.zip / mskermit / msnicm.c < prev    next >
C/C++ Source or Header  |  2020-01-01  |  9KB  |  343 lines

  1. /* File MSNICM.C
  2.  * ICMP packet processor
  3.  *
  4.  * Copyright (C) 1991, University of Waterloo.
  5.  *    Copyright (C) 1982, 1997, 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.  * 12 Jan 1995 v3.14
  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.     outs("\n\r ICMP: ");
  135.     outs(msg);
  136. }
  137.  
  138. struct pkt *
  139. icmp_Format(longword destip)
  140. {
  141.     eth_address dest;
  142.  
  143.         /* we use arp rather than supplied hardware address */
  144.  
  145.     if (arp_resolve(destip, dest) == 0)
  146.         return (NULL);            /* unable to find address */
  147.     return ((struct pkt*)eth_formatpacket(dest, TYPE_IP));
  148. }
  149. /*
  150.  * icmp_Reply - format a reply packet
  151.  *            - note that src and dest are NETWORK order
  152.  */
  153. int
  154. icmp_Reply(struct pkt *p, longword src, longword dest, int icmp_length)
  155. {
  156.  
  157.     if (p == NULL) return (0);        /* failure */
  158.     if ((dest == 0xffffffffL) || (dest == 0L)) /* broadcasts, ignore */
  159.         return(0);
  160.     if ((src == 0xffffffffL) || (dest == 0L)) /* broadcasts, ignore */
  161.         return(0);
  162.  
  163.     /* finish the icmp checksum portion */
  164.     p->icmp.unused.checksum = 0;
  165.     p->icmp.unused.checksum = ~checksum(&p->icmp, icmp_length);
  166.  
  167.     /* encapsulate into a nice IP packet */
  168.     p->in.hdrlen_ver = 0x45;
  169.     p->in.length = htons(sizeof(in_Header) + icmp_length);
  170.     p->in.tos = 0;
  171.     p->in.identification = htons(icmp_id++);    /* not using IP id */
  172.     p->in.frag = 0;
  173.     p->in.ttl = 250;
  174.     p->in.proto = ICMP_PROTO;
  175.     p->in.checksum = 0;
  176.     p->in.source = src;
  177.     p->in.destination = dest;
  178.     p->in.checksum = ~checksum(&p->in, sizeof(in_Header));
  179.  
  180.     return (eth_send(htons(p->in.length)));        /* send the reply */
  181. }
  182.  
  183. int
  184. do_ping(byte * hostid, longword hostip)
  185. {
  186.     register struct pkt *pkt;
  187.     byte mybuf[17];
  188.  
  189.     if (hostip == 0L)         /* if no host IP number yet */
  190.         if ((hostip = resolve(hostid)) == 0L)
  191.         return (-1);        /* failed to resolve host */
  192.  
  193.     pkt = icmp_Format(hostip);
  194.     pkt->icmp.echo.type = 8;            /* Echo Request */
  195.     pkt->icmp.echo.code = 0;
  196.     pkt->icmp.echo.identifier = (word)(htonl(my_ip_addr) & 0xffff);
  197.     pkt->icmp.echo.sequence = ping_number++;
  198.     pkt->icmp.timestamp.original = htonl(0x12345678);
  199.     icmp_Reply(pkt, htonl(my_ip_addr), htonl(hostip),
  200.                     4 + sizeof(struct icmp_echo));
  201.     outs("\r\n Sending Ping to ");
  202.     ntoa(mybuf, hostip); outs(mybuf);
  203.     return (0);
  204. }
  205.  
  206. int
  207. icmp_handler(in_Header *ip)
  208. {
  209.     register icmp_pkt *icmp, *newicmp;
  210.     struct pkt *pkt;
  211.     int len, code;
  212.     in_Header *ret;
  213.     byte nametemp[17];
  214.     extern void do_redirect(long, void *);
  215.     extern void do_quench(void *);
  216.  
  217.     len = (ip->hdrlen_ver & 0xf) << 2;    /* quad bytes to bytes */
  218.     icmp = (icmp_pkt *)((byte *)ip + len);
  219.     len = ntohs(ip->length) - len;
  220.     if (checksum(icmp, len) != 0xffff)
  221.         return (0);                /* 0 = failure */
  222.  
  223.     code = icmp->unused.code;
  224.     switch (icmp->unused.type)
  225.     {
  226.     case 0:             /* icmp echo reply received */
  227. /*        icmp_print("received icmp echo receipt");  */
  228.  
  229.         /* check if we were waiting for it */
  230.         if (icmp->echo.identifier == (word)(ntohl(my_ip_addr)&0xffff))
  231.             {            /* answer to our request */
  232.             outs("\r\n host is alive\r\n");
  233.             break;
  234.             }
  235.         break;
  236.  
  237.     case 3 :         /* destination or port unreachable message */
  238.         if (code < 6)
  239.             {
  240.             icmp_print(unreach[code]);    /* display msg */
  241.             icmp_unreach = 1 + code; /* say unreachable condx */
  242.                         /* handle udp or tcp socket */
  243.             ret = &icmp->ip.ip;    /* ret'd IP header + 8 bytes*/
  244.             if (ret->proto == TCP_PROTO)
  245.                 tcp_cancel(ret);
  246.             if (ret->proto == UDP_PROTO)
  247.                 udp_cancel(ret);
  248.             }
  249.         break;
  250.  
  251.     case 4:                /* source quench */
  252. /*        icmp_print("Source Quench"); */
  253.         do_quench(&icmp->ip.ip);    /* returned IP header */
  254.         break;
  255.  
  256.     case 5:                 /* redirect */
  257.         if (code < 4)
  258.             {
  259.                     /* new gateway IP address to use */ 
  260.             arp_register(ntohl(icmp->ip.ipaddr), 
  261.                 ntohl(icmp->ip.ip.destination));
  262.                     /* for this host IP address */
  263.                     /* and add to list of gateways */
  264.             icmp_print(redirect[code]);
  265.             ntoa(nametemp, ntohl(icmp->ip.ipaddr));
  266.             outs(" to gateway "); outs(nametemp);
  267.             ntoa(nametemp, ntohl(ip->source));
  268.             outs(" from gateway ");    outs(nametemp);
  269.             do_redirect(ntohl(icmp->ip.ipaddr), &icmp->ip.ip);
  270.                     /* new gateway  returned IP header */
  271.             }
  272.         break;
  273.  
  274.     case 8:             /* icmp echo request */
  275. /*         icmp_print("PING requested of us"); */
  276.             /* format the packet with the request's hardware address */
  277.         pkt = (struct pkt*)(eth_formatpacket(
  278.                 (eth_address *)eth_hardware(ip), TYPE_IP));
  279.         newicmp = &pkt->icmp;
  280.         bcopy(icmp, newicmp, len);
  281.         newicmp->echo.type = 0;
  282.         newicmp->echo.code = (byte)(code & 0xff);
  283.  
  284.         /* use supplied ip values in case we ever multi-home */
  285.         /* note that ip values are still in network order */
  286.  
  287.         icmp_Reply(pkt, ip->destination, ip->source, len);
  288. /*         icmp_print("PING reply sent"); */
  289.         break;
  290.  
  291.     case 11:             /* time exceeded message */
  292.         if (code < 2)
  293.             icmp_print(exceed[code]);
  294.         break;
  295.  
  296.     case 12:             /* parameter problem message */
  297.         icmp_print("IP Parameter problem");
  298.         break;
  299.  
  300.     case 13:             /* timestamp message */
  301. /*        icmp_print("Timestamp message"); */
  302.         /* send reply */
  303.         break;
  304.  
  305.     case 14:             /* timestamp reply */
  306. /*        icmp_print("Timestamp reply"); */
  307.         /* should store */
  308.         break;
  309.  
  310.     case 15:             /* info request */
  311. /*        icmp_print("Info requested"); */
  312.         /* send reply */
  313.         break;
  314.  
  315.     case 16:             /* info reply */
  316. /*        icmp_print("Info reply"); */
  317.         break;
  318.     }                /* end of switch */
  319.     return (1);            /* status of success */
  320. }
  321.  
  322. /* Return ICMP Destination and Port Unreachable message */
  323. void
  324. icmp_noport(in_Header *ip)
  325. {
  326.     register icmp_pkt *icmp, *newicmp;
  327.     struct pkt *pkt;
  328.     int len;
  329.  
  330.     len = (ip->hdrlen_ver & 0xf) << 2;    /* quad bytes to bytes */
  331.     icmp = (icmp_pkt *)((byte *)ip + len);
  332.     pkt = (struct pkt*)(eth_formatpacket(
  333.             (eth_address *)eth_hardware(ip), TYPE_IP));
  334.     newicmp = &pkt->icmp;
  335.     newicmp->unused.type = 3;    /* destination unreachable */
  336.     newicmp->unused.code = 3;    /* port unreachable */
  337.     newicmp->unused.unused = 0L;    /* must be zero for unreachables */
  338.         /* send back Internet header + first 64 bits of datagram */
  339.     bcopy(ip, &newicmp->unused.ip, 8 + sizeof(in_Header));
  340.     icmp_Reply(pkt, ip->destination, ip->source, 
  341.         sizeof(struct icmp_unused));    /* compose and send reply */
  342. }
  343.