home *** CD-ROM | disk | FTP | other *** search
/ ProfitPress Mega CDROM2 …eeware (MSDOS)(1992)(Eng) / ProfitPress-MegaCDROM2.B6I / MISC / NETWORK / TEL23SRC.ZIP / ENGINE / IP.C < prev    next >
Encoding:
C/C++ Source or Header  |  1991-07-22  |  14.0 KB  |  451 lines

  1. /*
  2. *   IP.C
  3. *   IP level routines, including ICMP
  4. *   also includes a basic version of UDP, not generalized yet
  5. *
  6. ****************************************************************************
  7. *                                                                          *
  8. *      part of:                                                            *
  9. *      TCP/IP kernel for NCSA Telnet                                       *
  10. *      by Tim Krauskopf                                                    *
  11. *                                                                          *
  12. *      National Center for Supercomputing Applications                     *
  13. *      152 Computing Applications Building                                 *
  14. *      605 E. Springfield Ave.                                             *
  15. *      Champaign, IL  61820                                                *
  16. *                                                                          *
  17. *    Copyright (c) 1987, Board of Trustees of the University of Illinois   *
  18. *                                                                          *
  19. ****************************************************************************
  20. *
  21. *   IP level routines ( including an ICMP handler )
  22. *
  23. ****************************************************************************
  24. *  Revision history:
  25. *
  26. *   10/87  Initial source release, Tim Krauskopf
  27. *   2/88  typedefs of integer lengths, TK
  28. *   5/88    clean up for 2.3 release, JKM   
  29. *
  30. */
  31.  
  32. /*
  33. *   Includes
  34. */
  35. #include <stdio.h>
  36. #ifdef MEMORY_DEBUG
  37. #include "memdebug.h"
  38. #endif
  39. #include "protocol.h"
  40. #include "data.h"
  41. #include "externs.h"
  42.  
  43. #include <fcntl.h>
  44. #include <io.h>
  45. #include <sys/types.h>
  46. #include <sys/stat.h>
  47.  
  48. static int waiting_for_ping = FALSE;
  49. int (*pingfunc)(ICMPKT *p, int icmplen) = NULL;
  50. ICMPKT blankicmp;
  51. extern struct config Scon;
  52. extern struct config def;
  53.  
  54. extern int SQwait;
  55. extern int OKpackets;
  56.  
  57. /*
  58. *   ipinterpret ( p )
  59. *
  60. *   Called by the packet demuxer to interpret a new ip packet.  Checks the
  61. * validity of the packet (checksum, flags) and then passes it on to the
  62. * appropriate protocol handler.
  63. *
  64. */
  65. unsigned char junk[]={0,0,0,0};
  66.  
  67. int ipinterpret(p)
  68. IPKT *p;                        /* ptr to packet from network */
  69. {
  70.     int iplen,i;
  71. /*
  72. *  We cannot handle fragmented IP packets yet, return an error
  73. */
  74.     if(p->i.frags&0x20) {           /* check for a fragmented packet */
  75.         netposterr(304);
  76.         return(1);
  77.       }
  78. /*
  79. *  checksum verification of IP header
  80. */
  81.     if (p->i.check) {                       /* no IP checksumming if check=0 */
  82.         if(ipcheck(&p->i.versionandhdrlen,(p->i.versionandhdrlen&0x0f) << 1))  {
  83.             netposterr(300);        /* bad IP checksum */
  84.             return(1);          /* drop packet */
  85.           }
  86.       }  
  87. /*
  88. *  Extract total length of packet
  89. */
  90.     iplen=intswap(p->i.tlen);
  91. /*
  92. *  check to make sure that the packet is for me.
  93. *  Throws out all packets which are not directed to my IP address.
  94. *
  95. *  This code is incomplete.  It does not pass broadcast IP addresses up
  96. *  to higher layers.  It used to report packets which were incorrectly
  97. *  addressed, but no longer does.  Needs proper check for broadcast 
  98. *  addresses.
  99. */
  100.     if(!comparen(nnipnum,p->i.ipdest,4)) {     /* potential non-match */
  101.         if(comparen(nnipnum,junk,4) && p->i.protocol==PROTUDP) {
  102.             i=(p->i.versionandhdrlen & 0x0f)<<2;
  103.             return(udpinterpret((struct udp *)p,iplen-i));
  104.           } /* end if */
  105.         return(1);              /* drop packet */
  106.       }
  107. /*
  108. *  See if there are any IP options to be handled.
  109. *  We don't understand IP options, post a warning to the user and drop
  110. *  the packet.
  111. */
  112.     i=(p->i.versionandhdrlen&0x0f)<<2;
  113.     if(i>20) {      /* check for options in packet */
  114.         netposterr(302);
  115.         return(1);
  116.       }
  117.     switch (p->i.protocol) {        /* which protocol to handle this packet? */
  118.         case PROTUDP:
  119.             return(udpinterpret((UDPKT *)p,iplen-i));
  120.  
  121.         case PROTTCP:
  122.             return(tcpinterpret((TCPKT *)p,iplen-i));   /* pass tcplen on to TCP */
  123.  
  124.         case PROTICMP:
  125.             return(icmpinterpret((ICMPKT *)p,iplen-i));
  126.  
  127.         default:
  128.             netposterr(303);
  129.             return(1);
  130.       }
  131.     return(0);
  132. }   
  133.  
  134. #ifdef NNDEBUG
  135.  /*
  136.  *  ipdump ( p )
  137.  *
  138.  *  Routine to dump an IP packet -- only compiled if the debug option is 
  139.  * enabled.
  140.  */
  141. ipdump(p)
  142.     IPKT *p;
  143. {
  144.     uint16 iplen,iid;
  145.  
  146.     iid=intswap(p->i.ident);
  147.     iplen=intswap(p->i.tlen);
  148.  
  149.     puts("found IP packet:");
  150.     printf("Version+hdr: %x     service %d      tlen %u   \n",
  151.             p->i.versionandhdrlen,p->i.service,iplen);
  152.     printf("Ident: %u    frags: %4x    ttl: %d    prot: %d  \n",
  153.             iid,p->i.frags,p->i.ttl,p->i.protocol);
  154.     printf("addresses: s: %d.%d.%d.%d    t: %d.%d.%d.%d \n",
  155.         p->i.ipsource[0],p->i.ipsource[1],p->i.ipsource[2],p->i.ipsource[3],
  156.         p->i.ipdest[0],p->i.ipdest[1],p->i.ipdest[2],p->i.ipdest[3]);
  157.     puts("\n");
  158. }
  159.  
  160. /***************************************************************************/
  161. /*  ipsend   THIS ROUTINE HAS NOT BEEN TESTED, NEVER USED!
  162. *   generic send of an IP packet according to parameters.  Use of this
  163. *   procedure is discouraged.  Terribly inefficient, but may be useful for
  164. *   tricky or diagnostic situations.  Unused for TCP.
  165. *
  166. *   usage:  ipsend(data,ident,prot,options,hdrlen)
  167. *       data is a pointer to the data to be sent
  168. *       ident is the 16 bit identifier
  169. *       prot is the protocol type, PROTUDP or PROTTCP or other
  170. *       hlen is in bytes, total header length, 20 is minimum
  171. *       dlen is the length of the data field, in bytes
  172. *       who is ip address of recipient
  173. *       options must be included in hlen and hidden in the data stream
  174. */
  175. ipsend(data,dlen,iid,iprot,who,hlen)
  176.     unsigned char *data,iprot,*who;
  177.     int iid,dlen,hlen;
  178. {
  179.     int iplen;
  180.  
  181.     if(dlen>512)
  182.         dlen=512;
  183.     iplen=hlen+dlen;                        /* total length of packet */
  184.     blankip.i.tlen=intswap(iplen);            /* byte swap */
  185.     blankip.i.versionandhdrlen=0x40|(hlen>>2);
  186.     blankip.i.ident=intswap(iid);           /* byte swap */
  187.     blankip.i.protocol=iprot;
  188.     blankip.i.check=0;                    /* set to 0 before calculating */
  189.     movebytes(blankip.i.ipdest,who,4);
  190.     movebytes(blankip.d.me,myaddr,DADDLEN);
  191.     movenbytes(blankip.x.data,data,dlen);  /* might be header options data */
  192.     blankip.i.check=ipcheck(&blankip.i.versionandhdrlen,hlen>>1);
  193.                                     /* checks based on words */
  194.                                     /* resolve knowledge of Ethernet hardware addresses */
  195. /*
  196. *  This is commented out because I know that this procedure is broken!
  197. *  If you use it, debug it first.
  198.  
  199.     dlayersend(&blankip,iplen+14);
  200. */
  201.     return(0);
  202. }
  203. #endif
  204.  
  205. /****************************************************************************/
  206. /*
  207. *   icmpinterpret ( p, icmplen )
  208. *
  209. * Interpret the icmp message that just came off the wire
  210. *
  211. */
  212. int icmpinterpret(p,icmplen)
  213. ICMPKT *p;
  214. int icmplen;
  215. {
  216.     uint i;
  217.     IPLAYER *iptr;
  218.  
  219.     i=p->c.type;
  220.     netposterr(600+i);      /* provide info for higher layer user */
  221.     if(p->c.check) {        /* ignore if chksum=0 */
  222.         if(ipcheck((char *)&p->c,icmplen>>1)) {
  223.             netposterr(699);
  224.             return(-1);
  225.           }
  226.       }
  227.     switch (i) {
  228.         case 8:                         /* ping request sent to me */
  229.             p->c.type=0;                /* echo reply type */
  230.             neticmpturn(p,icmplen);     /* send back */
  231.             break;
  232.  
  233.         case 5:                         /* ICMP redirect */
  234.             iptr=(IPLAYER *)p->data;
  235.             netputuev(ICMPCLASS,IREDIR,0);      /* event to be picked up */
  236.             movebytes(nnicmpsave,iptr->ipdest,4);       /* dest address */
  237.             movebytes(nnicmpnew,&p->c.part1,4);         /* new gateway */
  238.             break;
  239.  
  240.         case 4:                         /* ICMP source quench */
  241.             vprint(console->vs,"ICMP: source quench received");
  242.             OKpackets=0;
  243.             SQwait += 100;
  244.             break;
  245.  
  246.         case 0:                         /* ping reply ? */
  247.             if (waiting_for_ping) {
  248.                 if (!pingfunc)
  249.                     waiting_for_ping = FALSE;
  250.                 else {
  251.                     if ((*pingfunc)(p, icmplen)) {
  252.                         waiting_for_ping = FALSE;
  253.                         pingfunc = NULL;
  254.                     }
  255.                 }
  256.             }
  257.             break;
  258.  
  259.         default:
  260. #ifdef ASK_JEFF
  261.             printf("ICMP\n");
  262. #endif
  263.             break;
  264.       }
  265.     return(0);
  266. }
  267.  
  268. #ifdef OLDPC
  269. /****************************************************************************/
  270. /*  udpinterpret
  271. *   take incoming UDP packets and make them available to the user level
  272. *   routines.  Currently keeps the last packet coming in to a port.
  273. *
  274. *   Limitations:
  275. *   Can only listen to one UDP port at a time.  Only saves the last packet
  276. *   received on that port.
  277. *   Port numbers should be assigned like TCP ports are (future).
  278. */
  279. udpinterpret(p,ulen)
  280.     UDPKT *p;
  281.     int ulen;
  282. {
  283.     uint hischeck,mycheck;
  284. /*
  285. *  did we want this data ?  If not, then let it go, no comment
  286. *  If we want it, copy the relevent information into our structure
  287. */
  288.     if(intswap(p->u.dest)!=ulist.listen) 
  289.         return(1);
  290. /*
  291. *  first compute the checksum to see if it is a valid packet
  292. */
  293.     hischeck=p->u.check;
  294.     p->u.check=0;
  295.     if (hischeck) {
  296.         movebytes(tcps.source,p->i.ipsource,8);
  297.         tcps.z=0;
  298.         tcps.proto=p->i.protocol;
  299.         tcps.tcplen=intswap(ulen);
  300.         mycheck=tcpcheck(&tcps,&p->u,ulen);
  301.         if (hischeck != mycheck) {
  302.             netposterr(700);
  303.             return(2);
  304.           }
  305.         p->u.check=hischeck;                    /* put it back */
  306.       }
  307.     ulen-=8;                        /* account for header */
  308.     if(ulen>UMAXLEN)                /* most data that we can accept */
  309.         ulen=UMAXLEN;
  310.     movebytes(ulist.who,p->i.ipsource,4);
  311.     movebytes(ulist.data,p->data,ulen);
  312.     ulist.length=ulen;
  313.     ulist.stale=0;
  314.     netputuev(USERCLASS,UDPDATA,ulist.listen);      /* post that it is here */
  315.     return(0);
  316. }
  317.  
  318. /****************************************************************************/
  319. /*  neturead
  320. *   get the data from the UDP buffer
  321. *   Returns the number of bytes transferred into your buffer, -1 if none here
  322. *   This needs work.
  323. */
  324. neturead(buffer)
  325.     char *buffer;
  326. {
  327.     if (ulist.stale)
  328.         return(-1);
  329.     movebytes(buffer,ulist.data,ulist.length);
  330.     ulist.stale=1;
  331.     return((int)ulist.length);
  332. }
  333.  
  334. /***************************************************************************/
  335. /*  netulisten
  336. *   Specify which UDP port number to listen to.
  337. *   Can only listen to one at a time.
  338. */
  339. void netulisten(port)
  340.     int port;
  341. {
  342.     ulist.listen=port;
  343. }
  344.  
  345. /***************************************************************************/
  346. /*  netusend
  347.  *  Send out an icmp packet -- probably in response to a ping operation.
  348.  * Assumes that the packet is already setup and just interchanges the source
  349.  * and destination address of the packet and inserts my address for the 
  350.  * source and sends it.
  351. */
  352. netusend(machine,port,retport,buffer,n)
  353.     unsigned char *machine,*buffer;
  354.     unsigned int port,retport;
  355.     int n;
  356. {
  357.     unsigned char *pc;
  358.  
  359.     if (n>UMAXLEN)
  360.         n=UMAXLEN;
  361. /*
  362. *  make sure that we have the right dlayer address
  363. */
  364.     if (!comparen(machine,ulist.udpout.i.ipdest,4)) {
  365.         pc=netdlayer(machine);
  366.         if(comparen(machine,broadip,4))
  367.             pc=broadaddr;
  368.         if (pc==NULL) 
  369.             return(-2);
  370.         movebytes(ulist.udpout.d.dest,pc,DADDLEN);
  371.         movebytes(ulist.udpout.i.ipdest,machine,4);
  372.         movebytes(ulist.tcps.dest,machine,4);
  373.       }
  374.     ulist.udpout.u.dest=intswap(port);
  375.     ulist.udpout.u.source=intswap(retport);
  376.     ulist.tcps.tcplen=ulist.udpout.u.length=intswap(n+sizeof(UDPLAYER));
  377.     movenbytes(ulist.udpout.data,buffer,n);
  378. /*
  379. *  put in checksum
  380. */
  381.     ulist.udpout.u.check=0;
  382.     ulist.udpout.u.check=tcpcheck(&ulist.tcps,&ulist.udpout.u,n+sizeof(UDPLAYER));
  383. /*
  384. *   iplayer for send
  385. */
  386.     ulist.udpout.i.tlen=intswap(n+sizeof(IPLAYER)+sizeof(UDPLAYER));
  387.     ulist.udpout.i.ident=intswap(nnipident++);
  388.     ulist.udpout.i.check=0;
  389.     ulist.udpout.i.check=ipcheck(&ulist.udpout.i,10);
  390. /*
  391. *  send it
  392. */
  393.     return(dlayersend(&ulist.udpout,
  394.         sizeof(DLAYER)+sizeof(IPLAYER)+sizeof(UDPLAYER)+n));
  395. }
  396. #endif
  397.  
  398. /***************************************************************************/
  399. /*  neticmpturn
  400. *
  401. *   send out an icmp packet, probably in response to a ping operation
  402. *   interchanges the source and destination addresses of the packet,
  403. *   puts in my addresses for the source and sends it
  404. *
  405. *   does not change any of the ICMP fields, just the IP and dlayers
  406. *   returns 0 on okay send, nonzero on error
  407. */
  408. int neticmpturn(p,ilen)
  409. ICMPKT *p;
  410. int ilen;
  411. {
  412.     unsigned char *pc;
  413.  
  414. /*
  415. *  reverse the addresses, dlayer and IP layer
  416. */
  417.     if (comparen(p->d.me,broadaddr,DADDLEN))
  418.         return(0);
  419.     movebytes(p->d.dest,p->d.me,DADDLEN);
  420. /*
  421. *   look up address in the arp cache if we are using AppleTalk
  422. *   encapsulation.
  423. */
  424.     if(!nnemac) {
  425.         pc=getdlayer(p->i.ipsource);
  426.         if(pc!=NULL)
  427.             movebytes(p->d.dest,pc,DADDLEN);
  428.         else
  429.             return(0);      /* no hope this time */
  430.       }
  431.     movebytes(p->i.ipdest,p->i.ipsource,4);
  432.     movebytes(p->d.me,nnmyaddr,DADDLEN);
  433.     movebytes(p->i.ipsource,nnipnum,4);
  434. /*
  435. *  prepare ICMP checksum
  436. */
  437.     p->c.check=0;
  438.     p->c.check=ipcheck((char *)&p->c,ilen>>1);
  439. /*
  440. *   iplayer for send
  441. */
  442.     p->i.ident=intswap(nnipident++);
  443.     p->i.check=0;
  444.     p->i.check=ipcheck((char *)&p->i,10);
  445. /*
  446. *  send it
  447. */
  448.     return((int)dlayersend((DLAYER *)p,sizeof(DLAYER)+sizeof(IPLAYER)+ilen));
  449. }
  450.