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