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 >
Wrap
C/C++ Source or Header
|
1992-04-12
|
15KB
|
480 lines
/*
* IP.C
* IP level routines, including ICMP
* also includes a basic version of UDP, not generalized yet
*
****************************************************************************
* *
* part of: *
* TCP/IP kernel for NCSA Telnet *
* by Tim Krauskopf *
* *
* National Center for Supercomputing Applications *
* 152 Computing Applications Building *
* 605 E. Springfield Ave. *
* Champaign, IL 61820 *
* *
* This program is in the public domain. *
* *
****************************************************************************
*
* IP level routines ( including an ICMP handler )
*
****************************************************************************
* Revision history:
*
* 10/87 Initial source release, Tim Krauskopf
* 2/88 typedefs of integer lengths, TK
* 5/88 clean up for 2.3 release, JKM
* 9/91 Add input sanity checking, reorder tests, Nelson B. Bolyard
*
*/
/*
* Includes
*/
#include <stdio.h>
#include <fcntl.h>
#include <io.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "protocol.h"
#include "data.h"
#include "windat.h"
#include "externs.h"
#ifdef OLD_WAY
static int waiting_for_ping = FALSE;
int (*pingfunc)(ICMPKT *p, int icmplen) = NULL;
#endif
extern struct config Scon;
extern struct config def;
extern int SQwait;
extern int OKpackets;
static int neticmpturn(ICMPKT *,int );
static int icmpinterpret(ICMPKT *,int );
#define NBBDEBUG
#ifdef NBBDEBUG
int ipchecklen(char *s,int len,int line)
{
if(len<=0 || len>2048 ) {
#ifdef TELBIN
tprintf(console->vs,"ipchecklen: invalid len %d (%04x) at LINE %d\r\n",len,len,line);
#endif
return((int)0xDEAD); /* bad checksum, trust me! */
} /* end if */
return ipcheck(s,len);
} /* end ipchecklen() */
#define ipcheck(s,l) ipchecklen(s,l,__LINE__)
#endif
/*
* ipinterpret ( p )
*
* Called by the packet demuxer to interpret a new ip packet. Checks the
* validity of the packet (checksum, flags) and then passes it on to the
* appropriate protocol handler.
*
IPKT *p; ptr to packet from network
*/
static unsigned char junk[]={0,0,0,0};
int ipinterpret(IPKT *p)
{
int iplen;
int hlen;
/*
* Extract total length of packet
*/
iplen=intswap(p->i.tlen);
hlen=(p->i.versionandhdrlen&0x0f)<<2;
if(hlen<sizeof(p->i) /* Header too small */
|| iplen<hlen /* Header inconsistent */
|| iplen>2048 ) { /* WAY too big */
netposterr(300); /* bad IP checksum */
return(1); /* drop packet */
} /* end if */
/*
* We cannot handle fragmented IP packets yet, return an error
*/
if(p->i.frags&0x20) { /* check for a fragmented packet */
netposterr(304);
return(1);
}
/*
* checksum verification of IP header
*/
#ifdef QAK
if(p->i.check) { /* no IP checksumming if check=0 */
#endif
if(ipcheck(&p->i.versionandhdrlen,(p->i.versionandhdrlen&0x0f)<<1)) {
netposterr(300); /* bad IP checksum */
return(1); /* drop packet */
}
#ifdef QAK
}
#endif
if(iplen<=hlen) /* silently toss this legal-but-useless packet */
return(1);
/*
* See if there are any IP options to be handled.
* We don't understand IP options, post a warning to the user and drop
* the packet.
*/
if(hlen>sizeof(p->i)) { /* check for options in packet */
netposterr(302);
return(1);
} /* end if */
iplen-=hlen;
/*
* check to make sure that the packet is for me.
* Throws out all packets which are not directed to my IP address.
*
* This code is incomplete. It does not pass broadcast IP addresses up
* to higher layers. It used to report packets which were incorrectly
* addressed, but no longer does. Needs proper check for broadcast
* addresses.
*/
if(!comparen(nnipnum,p->i.ipdest,4)) { /* potential non-match */
if(comparen(nnipnum,junk,4) && p->i.protocol==PROTUDP)
return(udpinterpret((UDPKT *)p,iplen));
return(1); /* drop packet */
} /* end if */
switch (p->i.protocol) { /* which protocol to handle this packet? */
case PROTUDP:
return(udpinterpret((UDPKT *)p,iplen));
case PROTTCP:
return(tcpinterpret((TCPKT *)p,iplen)); /* pass tcplen on to TCP */
case PROTICMP:
return(icmpinterpret((ICMPKT *)p,iplen));
default:
netposterr(303);
return(1);
}
}
#ifdef NNDEBUG
/*
* ipdump ( p )
*
* Routine to dump an IP packet -- only compiled if the debug option is
* enabled.
*/
ipdump(IPKT *p)
{
uint16 iplen,iid;
iid=intswap(p->i.ident);
iplen=intswap(p->i.tlen);
puts("found IP packet:");
printf("Version+hdr: %x service %d tlen %u \n",
p->i.versionandhdrlen,p->i.service,iplen);
printf("Ident: %u frags: %4x ttl: %d prot: %d \n",
iid,p->i.frags,p->i.ttl,p->i.protocol);
printf("addresses: s: %d.%d.%d.%d t: %d.%d.%d.%d \n",
p->i.ipsource[0],p->i.ipsource[1],p->i.ipsource[2],p->i.ipsource[3],
p->i.ipdest[0],p->i.ipdest[1],p->i.ipdest[2],p->i.ipdest[3]);
puts("\n");
}
/***************************************************************************/
/* ipsend THIS ROUTINE HAS NOT BEEN TESTED, NEVER USED!
*
* generic send of an IP packet according to parameters. Use of this
* procedure is discouraged. Terribly inefficient, but may be useful for
* tricky or diagnostic situations. Unused for TCP.
*
* usage: ipsend(data,ident,prot,options,hdrlen)
* data is a pointer to the data to be sent
* ident is the 16 bit identifier
* prot is the protocol type, PROTUDP or PROTTCP or other
* hlen is in bytes, total header length, 20 is minimum
* dlen is the length of the data field, in bytes
* who is ip address of recipient
* options must be included in hlen and hidden in the data stream
*/
ipsend(uint8 *data,int dlen,int iid,uint8 iprot,uint8 *who,int hlen)
{
int iplen;
if(dlen>512)
dlen=512;
iplen=hlen+dlen; /* total length of packet */
blankip.i.tlen=intswap(iplen); /* byte swap */
blankip.i.versionandhdrlen=0x40|(hlen>>2);
blankip.i.ident=intswap(iid); /* byte swap */
blankip.i.protocol=iprot;
blankip.i.check=0; /* set to 0 before calculating */
movebytes(blankip.i.ipdest,who,4);
movebytes(blankip.d.me,myaddr,DADDLEN);
movenbytes(blankip.x.data,data,dlen); /* might be header options data */
blankip.i.check=ipcheck(&blankip.i.versionandhdrlen,hlen>>1);
/* checks based on words */
/* resolve knowledge of Ethernet hardware addresses */
/*
* This is commented out because I know that this procedure is broken!
* If you use it, debug it first.
dlayersend(&blankip,iplen+14);
*/
return(0);
}
#endif
/****************************************************************************/
/*
* icmpinterpret ( p, icmplen )
*
* Interpret the icmp message that just came off the wire
*
*/
static int icmpinterpret(ICMPKT *p,int icmplen)
{
uint i;
IPLAYER *iptr;
i=p->c.type;
netposterr(600+i); /* provide info for higher layer user */
if(p->c.check) { /* ignore if chksum=0 */
if(ipcheck((char *)&p->c,icmplen>>1)) {
netposterr(699);
return(-1);
} /* end if */
} /* end if */
switch(i) {
case 8: /* ping request sent to me */
p->c.type=0; /* echo reply type */
neticmpturn(p,icmplen); /* send back */
break;
case 5: /* ICMP redirect */
iptr=(IPLAYER *)p->data;
netputuev(ICMPCLASS,IREDIR,0); /* event to be picked up */
movebytes(nnicmpsave,iptr->ipdest,4); /* dest address */
movebytes(nnicmpnew,&p->c.part1,4); /* new gateway */
break;
case 4: /* ICMP source quench */
tprintf(console->vs,"ICMP: source quench received");
OKpackets=0;
SQwait+=100;
break;
#ifdef OLD_WAY
case 0: /* ping reply ? */
if(waiting_for_ping) {
if (!pingfunc)
waiting_for_ping = FALSE;
else {
if ((*pingfunc)(p, icmplen)) {
waiting_for_ping = FALSE;
pingfunc = NULL;
}
}
}
break;
#endif
default:
#ifdef ASK_JEFF
printf("ICMP\n");
#endif
break;
} /* end switch */
return(0);
} /* end icmpinterpret() */
#ifdef OLDPC
/****************************************************************************/
/* udpinterpret
* take incoming UDP packets and make them available to the user level
* routines. Currently keeps the last packet coming in to a port.
*
* Limitations:
* Can only listen to one UDP port at a time. Only saves the last packet
* received on that port.
* Port numbers should be assigned like TCP ports are (future).
*/
udpinterpret(UDPKT *p,int ulen)
{
uint hischeck,mycheck;
/*
* did we want this data ? If not, then let it go, no comment
* If we want it, copy the relevent information into our structure
*/
if(intswap(p->u.dest)!=ulist.listen)
return(1);
/*
* first compute the checksum to see if it is a valid packet
*/
hischeck=p->u.check;
p->u.check=0;
if (hischeck) {
movebytes(tcps.source,p->i.ipsource,8);
tcps.z=0;
tcps.proto=p->i.protocol;
tcps.tcplen=intswap(ulen);
mycheck=tcpcheck(&tcps,&p->u,ulen);
if (hischeck != mycheck) {
netposterr(700);
return(2);
}
p->u.check=hischeck; /* put it back */
}
ulen-=8; /* account for header */
if(ulen>UMAXLEN) /* most data that we can accept */
ulen=UMAXLEN;
movebytes(ulist.who,p->i.ipsource,4);
movebytes(ulist.data,p->data,ulen);
ulist.length=ulen;
ulist.stale=0;
netputuev(USERCLASS,UDPDATA,ulist.listen); /* post that it is here */
return(0);
}
/****************************************************************************/
/* neturead
* get the data from the UDP buffer
* Returns the number of bytes transferred into your buffer, -1 if none here
* This needs work.
*/
neturead(char *buffer)
{
if (ulist.stale)
return(-1);
movebytes(buffer,ulist.data,ulist.length);
ulist.stale=1;
return((int)ulist.length);
}
/***************************************************************************/
/* netulisten
* Specify which UDP port number to listen to.
* Can only listen to one at a time.
*/
void netulisten(int port)
{
ulist.listen=port;
}
/***************************************************************************/
/* netusend
* Send out an icmp packet -- probably in response to a ping operation.
* Assumes that the packet is already setup and just interchanges the source
* and destination address of the packet and inserts my address for the
* source and sends it.
*/
netusend(uint8 *machine,uint16 port,uint16 retport,uint8 *buffer,int n)
{
unsigned char *pc;
if (n>UMAXLEN)
n=UMAXLEN;
/*
* make sure that we have the right dlayer address
*/
if (!comparen(machine,ulist.udpout.i.ipdest,4)) {
pc=netdlayer(machine);
if(comparen(machine,broadip,4))
pc=broadaddr;
if (pc==NULL)
return(-2);
movebytes(ulist.udpout.d.dest,pc,DADDLEN);
movebytes(ulist.udpout.i.ipdest,machine,4);
movebytes(ulist.tcps.dest,machine,4);
}
ulist.udpout.u.dest=intswap(port);
ulist.udpout.u.source=intswap(retport);
ulist.tcps.tcplen=ulist.udpout.u.length=intswap(n+sizeof(UDPLAYER));
movenbytes(ulist.udpout.data,buffer,n);
/*
* put in checksum
*/
ulist.udpout.u.check=0;
ulist.udpout.u.check=tcpcheck(&ulist.tcps,&ulist.udpout.u,n+sizeof(UDPLAYER));
/*
* iplayer for send
*/
ulist.udpout.i.tlen=intswap(n+sizeof(IPLAYER)+sizeof(UDPLAYER));
ulist.udpout.i.ident=intswap(nnipident++);
ulist.udpout.i.check=0;
ulist.udpout.i.check=ipcheck(&ulist.udpout.i,10);
/*
* send it
*/
return(dlayersend(&ulist.udpout,
sizeof(DLAYER)+sizeof(IPLAYER)+sizeof(UDPLAYER)+n));
}
#endif
/***************************************************************************/
/* neticmpturn
*
* send out an icmp packet, probably in response to a ping operation
* interchanges the source and destination addresses of the packet,
* puts in my addresses for the source and sends it
*
* does not change any of the ICMP fields, just the IP and dlayers
* returns 0 on okay send, nonzero on error
*/
static int neticmpturn(ICMPKT *p,int ilen)
{
#ifdef OLD_WAY
unsigned char *pc;
#endif
/*
* reverse the addresses, dlayer and IP layer
*/
if(comparen(p->d.me,broadaddr,DADDLEN))
return(0);
movebytes(p->d.dest,p->d.me,DADDLEN);
#ifdef OLD_WAY
/*
* look up address in the arp cache if we are using AppleTalk
* encapsulation.
*/
if(!nnemac) {
pc=getdlayer(p->i.ipsource);
if(pc!=NULL)
movebytes(p->d.dest,pc,DADDLEN);
else
return(0); /* no hope this time */
}
#endif
movebytes(p->i.ipdest,p->i.ipsource,4);
movebytes(p->d.me,nnmyaddr,DADDLEN);
movebytes(p->i.ipsource,nnipnum,4);
/*
* prepare ICMP checksum
*/
p->c.check=0;
p->c.check=ipcheck((char *)&p->c,ilen>>1);
/*
* iplayer for send
*/
p->i.ident=intswap(nnipident++);
p->i.check=0;
p->i.check=ipcheck((char *)&p->i,10);
/*
* send it
*/
return((int)dlayersend((DLAYER *)p,sizeof(DLAYER)+sizeof(IPLAYER)+ilen));
}