TCP/IP over an Ethernet Network
|
Ethernet is one of the most popular types of networking
protocol around. It's got a larger market share than IBM's token ring and more
importantly, we've got it installed in our institute, so we can work on it! We
don't know anyone with a Token Ring system and so it's impossible to test our
stuff out on it.
Before you try any of this out, make sure your machine
has been properly set up. You need at least two machines with Ethernet cards,
some cable and the gentle guidance of the local networking geek. If you've
already got a network up somewhere, then that's great. An HTTP server has to be
up and running on one machine so that you can try and connect to it. Use the
IIS Web server; thats what we used. Set up your Windows 2000 network on the
server. Be sure to include the card drivers, and the TCP/IP protocol. Give the
server an IP address (double-click on TCP/IP in the network tab within the
Control Panel). We've set our server's IP address to 70.0.0.8 and our own to
70.0.0.1. Startup the server and you're ready to go!
The Address Resolution Protocol
Before we start however, here's a bit on ARP or the Address
resolution Protocol...
Under Ethernet programming, there is a very interesting protocol
called ARP or the Address Resolution Protocol, which deals with the conversion
of IP addresses into Ethernet addresses.
If we were setting up a connection between two PPP peers,
we'd negotiate with the PPP peer at the ISP's end and get ourselves an IP
address for the duration of the session. But if we were using Ethernet instead
of PPP to get on-line, the procedure would be very different.
On an Ethernet network, every machine, including the
router, has a unique Ethernet address. The router, which is connected to the
ISP through a leased line, will also have a permanent IP address, given to it
by the ISP. The IP address of the router is given to Windows 2000 when a
machine is set up to work on the Internet over an Ethernet LAN. However, the
Ethernet address of the router is not coded in. Without the Ethernet address of
the router, the poor machine can't contact the gateway over the Ethernet cable
because to do so requires a valid Ethernet address, a commodity it lacks. This
is where ARP comes in.
In ARP, we simply create a packet with the destination
Ethernet address set to 0xff 0xff 0xff 0xff 0xff 0xff, called a
broadcast message. The source address is our own and the type is set to 0806
which is the code for ARP. After the type, we have a byte for the hardware
type, which in our case is set to 0001. After this we have the
protocol field which will be 0800 to represent IP. The next byte
holds the value 6, which is the size of the Ethernet address and
after that we have a 4, for our IP address. The next two bytes
hold the Op Code. When the Op Code is 01, it means that this
packet is an ARP request and when it's 02, it's an ARP reply. After this we
give our Ethernet address and our IP address. Finally, we put the Ethernet
address of the router, which is all zeros since we don't know what it is and
then the router's IP address, which we do know. Since this packet is a
broadcast message it will be picked up by all the Network Interface Cards
(NICs) on the wire.
A couple of seconds after sending this packet we get an
identical packet back from the router, except that the op code is now 02
and the routers Ethernet address field is filled up correctly. That just about
covers ARP.
We would have loved to do RARP with you, which is the
Reverse Address Resolution Protocol and which gives us a IP address if we don't
have one, but unfortunately, the place where we test out our programs doesn't
support this protocol and so we were unable to experiment with.
Maybe later perhaps...
prog1.c
#include <dos.h>
#include <stdio.h>
struct packet
{
unsigned char data[1000];
unsigned int packetsize;
};
union REGS a,b;
struct SREGS s;
unsigned char ad[6],c[2],d[60];
unsigned char e[1000];
int handle , i, y, ii;
void abc(unsigned char p)
{
FILE *fp;
fp = fopen("D:\\z.txt","a+");
fprintf(fp,"..%x..%d\n",p,p);
fclose(fp);
}
void sendarpreq()
{
struct packet sendpkt;
sendpkt.data[0]=0xff;
sendpkt.data[1]=0xff;
sendpkt.data[2]=0xff;
sendpkt.data[3]=0xff;
sendpkt.data[4]=0xff;
sendpkt.data[5]=0xff;
sendpkt.data[6]=0x04;
sendpkt.data[7]=0x01;
sendpkt.data[8]=0x20;
sendpkt.data[9]=0x45;
sendpkt.data[10]=0x00;
sendpkt.data[11]=0x00;
sendpkt.data[12]=0x08;
sendpkt.data[13]=0x06;
sendpkt.data[14]=0x00;
sendpkt.data[15]=0x01;
sendpkt.data[16]=0x08;
sendpkt.data[17]=0x00;
sendpkt.data[18]=0x06;
sendpkt.data[19]=0x04;
sendpkt.data[20]=0x00;
sendpkt.data[21]=0x01;
sendpkt.data[22]=0x04;
sendpkt.data[23]=0x01;
sendpkt.data[24]=0x20;
sendpkt.data[25]=0x45;
sendpkt.data[26]=0x00;
sendpkt.data[27]=0x00;
sendpkt.data[28]=70;
sendpkt.data[29]=0;
sendpkt.data[30]=0;
sendpkt.data[31]=1;
sendpkt.data[32]=0;
sendpkt.data[33]=0;
sendpkt.data[34]=0;
sendpkt.data[35]=0;
sendpkt.data[36]=0;
sendpkt.data[37]=0;
sendpkt.data[38]=70;
sendpkt.data[39]=0;
sendpkt.data[40]=0;
sendpkt.data[41]=8;
sendpkt.packetsize=42;
for(i=0;i<sendpkt.packetsize;i++)
{
printf("%x..",sendpkt.data[i]);
abc(sendpkt.data[i]);
}
a.h.ah = 4;
a.h.al=0;
a.x.si=FP_OFF(&sendpkt.data);
s.ds=FP_SEG(&sendpkt.data);
a.x.cx=sendpkt.packetsize;
int86x(0x60,&a,&b,&s);
}
void interrupt zzz(bp,di,si,ds,es,dx,cx,bx,ax,ip,cs,flags)
unsigned short bp,di,si,ds,es,dx,cx,bx,ax,ip,cs,flags;
{
printf("Receiver ax = %d Packet size = %d\n",ax,cx);
if (ax == 0)
{
es = FP_SEG(e);
di = FP_OFF(e);
ii = cx;
}
if (ax == 1)
{
for(i=0;i<ii;i++)
{
abc(e[i]);
printf("%x..",e[i]);
}
}
abc('-'); abc('-'); abc('-');
}
main()
{
segread(&s);
a.h.ah = 1;
a.h.al = 255;
int86x(0x60, &a, &b, &s);
printf("Carry Flag Driver Info - %d\n",b.x.cflag);
printf("Class - %d, Type - %d \n",b.h.ch, b.x.dx);
a.h.ah = 6;
a.x.cx = 6;
s.es = FP_SEG(ad);
a.x.di = FP_OFF(ad);
int86x(0x60, &a, &b, &s);
printf("Carry Flag Ethernet Address - %d\n",b.x.cflag);
printf("Address - %x: %x: %x: %x: %x: %x\n",ad[0],ad[1],ad[2],ad[3],ad[4],ad[5]);
a.h.al = 1;
a.x.bx = -1;
a.h.dl = 0;
a.x.cx = 0;
a.h.ah = 2;
s.es = FP_SEG(zzz);
a.x.di = FP_OFF(zzz);
c[0] = 0xff;
c[1] = 0xff;
s.ds = FP_SEG(c);
a.x.si = FP_OFF(c);
int86x(0x60, &a, &b, &s);
printf("Carry Flag Access Type - %d\n",b.x.cflag);
printf("Handle - %d\n",b.x.ax);
handle = b.x.ax;
a.h.ah = 21;
a.x.bx = handle;
int86x(0x60, &a, &b, &s);
printf("Get Recv Mode - %d\n",b.x.cflag);
printf("Receive Mode - %d\n",b.x.ax);
a.h.ah = 20;
a.x.bx = handle;
a.x.cx = 3;
int86x(0x60, &a, &b, &s);
printf("Carry Flag Set Recv Mode - %d\n",b.x.cflag);
sendarpreq();
getch(); getch(); getch();
a.h.ah = 3;
a.x.bx = handle;
int86x(0x60, &a, &b, &s);
printf("Carry Flag Release Type - %d\n",b.x.cflag);
printf("OVER");
}
This is the
first program we have to master before we can begin to send TCP/IP packets over
the wire. This program focuses entirely on ARP and demonstrates how we can use
it to retrieve the HTTP server's Ethernet address. We need the server's
Ethernet address because to send data on an Ethernet network, you need an
Ethernet address.
The program
itself is rather simple and if you've already read our general Ethernet tutorial
then you'll follow the code perfectly. Remember to load the packet driver,
ne1000.com, before you run this stuff!
As usual, we
first check the presence of the Packet Driver by loading a bunch of numbers in
the specified registers and calling the interrupt. We're rewarded with a load
of information about the driver. We then load the registers with fresh values
and call the interrupt. This time we're rewarded with the address of our own
Ethernet card.
We place new
values in the registers once more and set the filter and the callback zzz().
Now we place more stuff in the registers along with the handle can we get the
default Receive mode after calling the interrupt. All of this has been
discussed in detail in the Ethernet tutorial.
We now place
another bunch of values in the registers and place 3 in the CX register instead
of a 6. We've done this because we only want to read bytes destined for our
card, rather than all the bytes on the wire. Broadcast packets are always
received by every card no matter what the number in CX is.
Once we've set
the Receive Mode we call the function sendarpreq(). This function has a ready
made Ethernet packet just waiting to be shot across the lines. The first line
declares sendpkt to be a structure that looks just like packet.
The packet structure tag is made up of two members, a 1000 byte array
called data and a two byte field called packetsize. We first fill
up the array with some values. These values are the actual bytes that make up the
Ethernet frame.
The first six
bytes, from sendpkt.data[0] to sendpkt.data[5] form the destination Ethernet
address. Since this is a general broadcast, the value is 0xff 0xff 0xff 0xff
0xff 0xff.
sendpkt.data[0]=0xff;
sendpkt.data[1]=0xff;
sendpkt.data[2]=0xff;
sendpkt.data[3]=0xff;
sendpkt.data[4]=0xff;
sendpkt.data[5]=0xff;
The next six
bytes, from sendpkt.data[6] to sendpkt.data[11] hold the source Ethernet
address.
sendpkt.data[6]=0x04;
sendpkt.data[7]=0x01;
sendpkt.data[8]=0x20;
sendpkt.data[9]=0x45;
sendpkt.data[10]=0x00;
sendpkt.data[11]=0x00;
Now comes the
packet type. Since this is an ARP packet, the type is set to 0x08 0x06.
sendpkt.data[12]=0x08;
sendpkt.data[13]=0x06;
The next two
bytes specify the hardware type. This is almost always set to 0x00 0x01 becaue
those are the numbers that stand for the Ethernet network.
sendpkt.data[14]=0x00;
sendpkt.data[15]=0x01;
Now come two
bytes for the type pf address we require. 0x08 0x00 stands for 'IP address'.
sendpkt.data[16]=0x08;
sendpkt.data[17]=0x00;
Sendpkt.data[18]
is the length of the Ethernet address (the Hardware address) i.e. 6 bytes...
sendpkt.data[18]=0x06;
... and
sendpkt.data[19] is the length of an IP address (the Protocol address) i.e. 4
bytes.
sendpkt.data[19]=0x04;
These two
bytes specify which type of ARP packet this is. If it's 0x00 0x01, then it's an
ARP request (which it is). If it's 0x00 0x02 it's a reply.
sendpkt.data[20]=0x00;
sendpkt.data[21]=0x01;
The array data
from sendpkt.data[22] to sendpkt.data[27] holds our Ethernet address.
sendpkt.data[22]=0x04;
sendpkt.data[23]=0x01;
sendpkt.data[24]=0x20;
sendpkt.data[25]=0x45;
sendpkt.data[26]=0x00;
sendpkt.data[27]=0x00;
The next four bytes
in the array comprise our IP address.
sendpkt.data[28]=70;
sendpkt.data[29]=0;
sendpkt.data[30]=0;
sendpkt.data[31]=1;
The rest of
the bytes hold the destination Ethernet and IP address. The Ethernet address is
zero because we don't know what it is!
sendpkt.data[32]=0;
sendpkt.data[33]=0;
sendpkt.data[34]=0;
sendpkt.data[35]=0;
sendpkt.data[36]=0;
sendpkt.data[37]=0;
sendpkt.data[38]=70;
sendpkt.data[39]=0;
sendpkt.data[40]=0;
sendpkt.data[41]=8;
Now the variable
packetsize is initialized to the size of the packet and the entire packet is
printed out. We then call the interrupt and by passing it the correct values,
we send our packet on it's way. The function zzz() is called when ever we
receive any packets and all bytes received are printed out in a file called
z.txt.
1 |
2 |
3 |
4 |
5 |
6 |
1 |
2 |
3 |
4 |
5 |
6 |
1 |
2 |
Data |
Destn. Ethernet
Address |
Source Ethernet
Address |
Protocol |
Prot Data |
Format of an
Ethernet Packet
ARP PACKET
6 bytes - Destination Ethernet Address (0xff if it is ARP Request)
6 bytes - Source Ethernet Address
2 bytes - 0x8 0x6 - ARP type
2 bytes - Type of Hardware (0x00 0x01 - Ethernet)
2 bytes - Type of the Address ( 0x08 0x00 -IP Protocol)
1 byte - Length of the Hardware Address ( 0x06 - Ethernet Address)
1 byte - Length of the Protocol Address ( 0x04 - IP Address )
2 bytes - Op code (0x00 0x01 Request/ 0x00 0x02 Reply)
6 bytes - Senders Ethernet Address
4 bytes - Senders IP address
6 bytes - Destination Ethernet Address ( all 0s if it is ARP request)
4 bytes - Destination IP address (Computer we want to connect to)
z.txt
..2d..45
..2d..45
..2d..45
..4..4
..1..1
..20..32
..45..69
..0..0
..0..0 - Destination Ethernet Address
..4..4
..1..1
..30..48
..16..22
..0..0
..0..0 - Source Ethernet Address
..8..8
..6..6 - ARP Packet
..0..0
..1..1 - Hardware Type
..8..8
..0..0 - IP
..6..6 - Length of the Ethernet Address
..4..4 - Length of the IP address
..0..0
..2..2 - ARP reply
..4..4
..1..1
..30..48
..16..22
..0..0
..0..0 - Source Ethernet Address
..46..70
..0..0
..0..0
..8..8 - Source IP address
..4..4
..1..1
..20..32
..45..69
..0..0
..0..0 Destination Ethernet Address
..46..70
..0..0
..0..0
..1..1 - Destination IP address
..20..32
..20..32
..20..32
..20..32
..20..32
..20..32
..20..32
..20..32
..20..32
..20..32
..20..32
..20..32
..20..32
..20..32
..20..32
..20..32
..20..32
..20..32
..0..0
..2d..45
..2d..45
..2d..45
The file z.txt
contains each and every byte or faithful callback has recieved. We'll examine
them individually. The first three bytes are just junk and should be ignored.
..2d..45
..2d..45
..2d..45
The next 6
bytes comprise the destination Ethernet address. That means it's our Ethernet
address since this packet has been sent by someone else (The server).
..4..4
..1..1
..20..32
..45..69
..0..0
..0..0
The next 6
bytes are the most important bit, they're the Ethernet address of the machine
that's responded to our ARP request, the HTTP server!
..4..4
..1..1
..30..48
..16..22
..0..0
..0..0
These two
bytes declare this packet to be ARP.
..8..8
..6..6
Now comes the
hardware type, which is Ethernet...
..0..0
..1..1
...and the
Protocol type, which is IP.
..8..8
..0..0
Now comes the
length of the Hardware and Protocol address field. Ethernet and IP respectivly.
..6..6
..4..4
As mentioned
before, 0x00 0x02 is the op code for an ARP reply, which is what this packet
is.
..0..0
..2..2
The Source
Ethernet address is repeated, so you've got two places to pick it up from.
..4..4
..1..1
..30..48
..16..22
..0..0
..0..0
Here's the
source IP address i.e. the HTTP server's IP address.
..46..70
..0..0
..0..0
..8..8
Here's our
Ethernet and IP address.
..4..4
..1..1
..20..32
..45..69
..0..0
..0..0
..46..70
..0..0
..0..0
..1..1
The rest of
thepacket is composed of a lot of padding to make it 60 bytes large.
..20..32
..20..32
..20..32
..20..32
..20..32
..20..32
..20..32
..20..32
..20..32
..20..32
..20..32
..20..32
..20..32
..20..32
..20..32
..20..32
..20..32
..20..32
..0..0
..2d..45
..2d..45
..2d..45
That's it!!
chk.c
unsigned int checksum(unsigned short *ip1,unsigned int len);
main()
{
unsigned char ip[20];
unsigned int i;
ip[0]=0x45;
ip[1]=0x0;
ip[2]=0x0;
ip[3]=0x2c;
ip[4]=0x2e;
ip[5]=0x0;
ip[6]=0x40;
ip[7]=0x0;
ip[8]=0x20;
ip[9]=0x6;
ip[10]=0x0;
ip[11]=0x0;
ip[12]=0x46;
ip[13]=0x0 ;
ip[14]=0x0 ;
ip[15]=0x1 ;
ip[16]=0x46;
ip[17]=0x0 ;
ip[18]=0x0 ;
ip[19]=0x8 ;
i = checksum(ip,20);
printf("%x......%x\n",((i>>8)&0x00ff),(i&0x00ff));
getch();
}
unsigned int checksum(unsigned short *ip1,unsigned int len)
{
long sum = 0;
while ( len > 1)
{
sum += *ip1++;
if ( sum & 0x80000000 )
sum = ( sum & 0xffff) + ( sum >> 16);
len -= 2;
}
while ( sum >> 16)
sum = ( sum & 0xffff) + ( sum >> 16);
return ~sum;
}
Output
a0....c3
This is a cute
little program to demonstrate the actual mechanism behind the IP checksum. All
you have to do is pass the function checksum() the IP header and it's length
and it'll do all the calculations. As we've already explained earlier in our IP
tutorial, the checksum is calculated by taking bytes two at a time and adding
them together. If there's an overflow, it's dumped back into the pool and
added. If the size of the packet turns out to be an odd number, an extra byte
with zero is added. Remember that the checksum field in the header must be zero
while calculating the checksum. That's about all there is to it.
prog2.c
#include <dos.h>
#include <stdio.h>
struct packet {
unsigned char data[1000];
unsigned int packetsize;
};
struct iphdr {
unsigned char verlen;
unsigned char tos;
unsigned short totlen;
unsigned char id[2];
unsigned char frag[2];
unsigned char ttl;
unsigned char prot;
unsigned short chksum;
unsigned char sourceip[4];
unsigned char destip[4];
};
struct tcphdr {
unsigned short srcport;
unsigned short destport;
unsigned long seqno;
unsigned long ackno;
unsigned char hdrlen;
unsigned char flags;
unsigned short win;
unsigned short chksum;
unsigned short urgptr;
};
struct dummytcp {
unsigned char src[4];
unsigned char dest[4];
char u;
char prot;
unsigned short len;
};
union REGS a,b;
struct SREGS s;
unsigned char ad[6],c[2],d[60];
unsigned char e[1000];
int handle , i, y, ii;
void abc(unsigned char p)
{
FILE *fp;
fp = fopen("D:\\z.txt","a+");
fprintf(fp,"..%x..%d\n",p,p);
fclose(fp);
}
void sendsyn();
unsigned int ohtons(unsigned int h)
{
unsigned char h1,h2;
unsigned short h5;
h1 = (unsigned char ) h & 0xff;
h2 = (h >> 8)&0xff;
h5 = 256*h1 + h2 ;
return h5;
}
unsigned short checksum(unsigned short * ip1,unsigned int len) {
long sum = 0;
while ( len > 1) {
sum += *ip1++;
if ( sum & 0x80000000 )
sum = ( sum & 0xffff) + ( sum >> 16);
len -= 2;
}
while ( sum >> 16)
sum = ( sum & 0xffff) + ( sum >> 16);
return ~sum;
}
unsigned short tcpchecksum( unsigned char * tcp, unsigned char * o, unsigned int l, unsigned int lens ) {
unsigned char u[1000];
unsigned char *t;
struct dummytcp d;
unsigned short chksum;
unsigned int i,j;
unsigned short tcplen;
tcplen=l;
for(i=0;i<tcplen;i++) {
u[i]=tcp[i];
}
if(o != 0) {
tcplen=tcplen+lens;
for(j=0;j<lens;j++,i++)
u[i]=o[j];
}
l = tcplen;
d.src[0]=70;
d.src[1]=0;
d.src[2]=0;
d.src[3]=1;
d.dest[0]=70;
d.dest[1]=0;
d.dest[2]=0;
d.dest[3]=8;
d.u=0;
d.prot=6;
d.len=ohtons(l);
t=&d;
for (i = 0;i<=11;i++,l++) {
u[l] = t[i];
}
tcplen=l;
chksum=checksum( u,tcplen );
return chksum;
}
unsigned long ohtonl( unsigned long h ) {
unsigned char h1,h2,h3,h4;
unsigned long h5;
h1 = (unsigned char ) h & 0x000000ff;
h2 = (h >> 8)&0x000000ff;
h3 = (h >> 16) & 0x000000ff;
h4 = (h >> 24 ) & 0x000000ff;
h5 = ((long)1<<24)*h1 + h4 + h3*256 + h2*65536;
return h5;
}
void sendit(struct packet * spacket)
{
union REGS regs;
struct SREGS sregs;
struct packet sendpkt;
unsigned int i,j;
sendpkt.data[0]=0x04;
sendpkt.data[1]=0x01;
sendpkt.data[2]=0x30;
sendpkt.data[3]=0x16;
sendpkt.data[4]=0;
sendpkt.data[5]=0;
sendpkt.data[6]=0x04;
sendpkt.data[7]=0x01;
sendpkt.data[8]=0x20;
sendpkt.data[9]=0x45;
sendpkt.data[10]=0x00;
sendpkt.data[11]=0x00;
for(j=12,i=0;i< spacket->packetsize;j++,i++) {
sendpkt.data[j]=spacket->data[i];
}
sendpkt.packetsize=j;
for(i=0;i<sendpkt.packetsize;i++)
{
abc(sendpkt.data[i]);
printf("%x..",sendpkt.data[i]);
}
regs.h.ah = 4;
regs.h.al=0;
regs.x.si=FP_OFF(&sendpkt.data);
sregs.ds=FP_SEG(&sendpkt.data);
regs.x.cx=sendpkt.packetsize;
int86x(0x60,®s,®s,&sregs);
strset(e,0);
}
void interrupt zzz(bp,di,si,ds,es,dx,cx,bx,ax,ip,cs,flags)
unsigned short bp,di,si,ds,es,dx,cx,bx,ax,ip,cs,flags;
{
printf("Receiver ax = %d Packet size = %d\n",ax,cx);
if (ax == 0)
{
es = FP_SEG(e);
di = FP_OFF(e);
ii = cx;
}
if (ax == 1)
{
for(i=0;i<=ii;i++)
{
abc(e[i]);
printf("%x..",e[i]);
}
}
abc('-'); abc('-'); abc('-');
}
void writeabc(unsigned char *ip, unsigned char *tcp, unsigned char *opt, unsigned char *tdata ) {
struct packet tcpip;
unsigned int i,j;
unsigned char uu[1000];
j=0;
uu[j]=0x08;
j++;
uu[j]=0x00;
j++;
for(i=0;i<20;i++,j++) {
uu[j]=ip[i];
}
for(i=0;i<20;i++,j++) {
uu[j]=tcp[i];
}
if (opt != 0) {
for(i=0;i<4;i++,j++) {
uu[j]=opt[i];
}
}
if (tdata != 0) {
for(i=0;i<16;j++,i++) {
uu[j]=tdata[i];
}
}
for(i=0;i<j;i++) {
tcpip.data[i]=uu[i];
}
tcpip.packetsize=j;
sendit(&tcpip);
}
void sendsyn()
{
struct tcphdr tcp;
struct iphdr ip;
unsigned char opt[4]={2,4,2,0};
tcp.srcport=ohtons(1024);
tcp.destport=ohtons(80);
tcp.seqno=ohtonl(5);
tcp.ackno=ohtonl(0);
tcp.hdrlen=0x60;
tcp.flags=0x2;
tcp.win=ohtons(1024);
tcp.chksum=0;
tcp.urgptr=0;
tcp.chksum=tcpchecksum(&tcp,opt,20,4);
ip.verlen =0x45;
ip.tos =0x0;
ip.totlen =ohtons(44);
ip.id[0] =0x2e;
ip.id[1]=0;
ip.frag[0] =0x40;
ip.frag[1]=0;
ip.ttl =32;
ip.prot =0x6;
ip.chksum =0;
ip.sourceip[0] =70;
ip.sourceip[1] =0;
ip.sourceip[2] =0;
ip.sourceip[3] =1;
ip.destip[0] =70;
ip.destip[1] =0;
ip.destip[2] =0;
ip.destip[3] =8;
ip.chksum =checksum(&ip,20);
writeabc(&ip,&tcp,&opt,0);
}
main()
{
segread(&s);
a.h.ah = 1;
a.h.al = 255;
int86x(0x60, &a, &b, &s);
printf("Carry Flag Driver Info - %d\n",b.x.cflag);
printf("Class - %d, Type - %d \n",b.h.ch, b.x.dx);
a.h.ah = 6;
a.x.cx = 6;
s.es = FP_SEG(ad);
a.x.di = FP_OFF(ad);
int86x(0x60, &a, &b, &s);
printf("Carry Flag Ethernet Address - %d\n",b.x.cflag);
printf("Address - %x: %x: %x: %x: %x: %x\n",ad[0],ad[1],ad[2],ad[3],ad[4],ad[5]);
a.h.al = 1;
a.x.bx = -1;
a.h.dl = 0;
a.x.cx = 0;
a.h.ah = 2;
s.es = FP_SEG(zzz);
a.x.di = FP_OFF(zzz);
c[0] = 0xff;
c[1] = 0xff;
s.ds = FP_SEG(c);
a.x.si = FP_OFF(c);
int86x(0x60, &a, &b, &s);
printf("Carry Flag Access Type - %d\n",b.x.cflag);
printf("Handle - %d\n",b.x.ax);
handle = b.x.ax;
a.h.ah = 21;
a.x.bx = handle;
int86x(0x60, &a, &b, &s);
printf("Get Recv Mode - %d\n",b.x.cflag);
printf("Receive Mode - %d\n",b.x.ax);
a.h.ah = 20;
a.x.bx = handle;
a.x.cx = 3;
int86x(0x60, &a, &b, &s);
printf("Carry Flag Set Recv Mode - %d\n",b.x.cflag);
sendsyn();
getch(); getch(); getch();
a.h.ah = 3;
a.x.bx = handle;
int86x(0x60, &a, &b, &s);
printf("Carry Flag Release Type - %d\n",b.x.cflag);
printf("OVER");
}
This is the first
in a series of programs which use raw TCP/IP bytes to connect to an HTTP
server. The program looks a little large, but it's largely made up of array
declarations so it's not that complicated. Here we're going to send the server
a SYN packet, the first packet which has to be sent in the Three Way Handshake.
The function
main() is where we jump to first. It has all the usual stuff we've already done
earlier. The function which really kicks off the action is sendsyn(). Skip over
to that function.
Sendsyn()
initializes the entire TCP/IP header and sets the SYN flag on. It places
appropriate values like the port numbers, the sequence and acknowledgment
number, etc. in their appropriate places. It also handles the tcp options.
The ohtons()
and ohtonl() functions handle the conversion of short and long numbers
respectively into their big endian avatars.
The two
checksums are also here. The IP checksum has been explained (the mechanism, if
not the mathematics) but the tcp checksum is beyond us. This is where that
dummy tcp header is used. We really don't know how this works, so don't ask us
why it's required; it just is.
Sendsyn() now
calls the function writeabc() and passes it the IP and TCP headers, along with
the TCP options and data.
Tdata[] is
supposed to hold the TCP data but it's not used in this program.
Writeabc()
basically copies the bytes from these separate sources into one structure
called tcpip. The protocol bytes (0x08 0x00) are also added and the variable
packetsize is initialized. the function sendit() is then called and it's passed
the structure tcpip.
Sendit() now
takes everything and adds the ethernet header (the destination and source
Ethernet addresses). The full structure is now stored in sendpkt which looks
like the structure packet. We then stuff some values in the registers and pass
the register pair DS:SI the address of sendpkt.data. CX is given the value
stored in sendpkt.packetsize. The interrupt is then called and the stuff send
across.
We then call
the standard function strset() and initialize e to zeros. e is where the
servers response will be stored.
As and when
the server's response arrives, it is stored on disk.
So that's the
first program we're going to run. When the server receives our SYN, it should
respond with an SYN/ACK, but before he can do that, he has to discover our
Ethernet address and he needs ARP for that.
z.txt
Packet Sent
..4..4 Destination Ethernet Address
..1..1
..30..48
..16..22
..0..0
..0..0
..4..4 Source Ethernet Address
..1..1
..20..32
..45..69
..0..0
..0..0
..8..8 IP Protocol
..0..0
..45..69 IP Packet
..0..0
..0..0
..2c..44
..2e..46
..0..0
..40..64
..0..0
..20..32
..6..6 Protocol field is 6 - TCP
..a0..160
..c3..195
..46..70 70.0.0.1 - Source IP Address
..0..0
..0..0
..1..1
..46..70 70.0.0.8 - Destination IP Address
..0..0
..0..0
..8..8
..4..4 TCP PAcket
..0..0
..0..0
..50..80
..0..0
..0..0
..0..0
..5..5 Seq No.- 0005
..0..0
..0..0
..0..0
..0..0 Ack no - 0000
..60..96
..2..2 Flag is 2 - SYN
..4..4
..0..0
..7..7
..7d..125
..0..0
..0..0
..2..2
..4..4
..2..2
..0..0
..2d..45
..2d..45
..2d..45
Packet Received
..ff..255 Broadcast
..ff..255
..ff..255
..ff..255
..ff..255
..ff..255
..4..4 Source Ethernet Address
..1..1
..30..48
..16..22
..0..0
..0..0
..8..8 ARP TYPE
..6..6
..0..0 Hardware Type
..1..1
..8..8 IP
..0..0
..6..6 Len of Ethernet Address
..4..4 Len of IP Address
..0..0 ARP Request
..1..1
..4..4 Source Ethernet Address
..1..1
..30..48
..16..22
..0..0
..0..0
..46..70 Source IP Address
..0..0
..0..0
..8..8
..0..0 Destination Ethernet Address
..0..0
..0..0
..0..0
..0..0
..0..0
..46..70 Destination IP Address
..0..0
..0..0
..1..1
..20..32
..20..32
..20..32
..20..32
..20..32
..20..32
..20..32
..20..32
..20..32
..20..32
..20..32
..20..32
..20..32
..20..32
..20..32
..20..32
..20..32
..20..32
..0..0
..2d..45
..2d..45
..2d..45
Here are the
bytes we get; ARP Request, just as we predicted. Jump over to the next program
to see what it does.
prog3.c
#include <dos.h>
#include <stdio.h>
struct packet {
unsigned char data[1000];
unsigned int packetsize;
};
struct iphdr {
unsigned char verlen;
unsigned char tos;
unsigned short totlen;
unsigned char id[2];
unsigned char frag[2];
unsigned char ttl;
unsigned char prot;
unsigned short chksum;
unsigned char sourceip[4];
unsigned char destip[4];
};
struct tcphdr {
unsigned short srcport;
unsigned short destport;
unsigned long seqno;
unsigned long ackno;
unsigned char hdrlen;
unsigned char flags;
unsigned short win;
unsigned short chksum;
unsigned short urgptr;
};
struct dummytcp {
unsigned char src[4];
unsigned char dest[4];
char u;
char prot;
unsigned short len;
};
union REGS a,b;
struct SREGS s;
unsigned char ad[6],c[2],d[60];
unsigned char e[1000];
int handle , i, y, ii;
void abc(unsigned char p)
{
FILE *fp;
fp = fopen("D:\\z.txt","a+");
fprintf(fp,"..%x..%d\n",p,p);
fclose(fp);
}
void sendsyn();
unsigned int ohtons(unsigned int h)
{
unsigned char h1,h2;
unsigned short h5;
h1 = (unsigned char ) h & 0xff;
h2 = (h >> 8)&0xff;
h5 = 256*h1 + h2 ;
return h5;
}
unsigned short checksum(unsigned short * ip1,unsigned int len) {
long sum = 0;
while ( len > 1) {
sum += *ip1++;
if ( sum & 0x80000000 )
sum = ( sum & 0xffff) + ( sum >> 16);
len -= 2;
}
while ( sum >> 16)
sum = ( sum & 0xffff) + ( sum >> 16);
return ~sum;
}
unsigned short tcpchecksum( unsigned char * tcp, unsigned char * o, unsigned int l, unsigned int lens ) {
unsigned char u[1000];
unsigned char *t;
struct dummytcp d;
unsigned short chksum;
unsigned int i,j;
unsigned short tcplen;
tcplen=l;
for(i=0;i<tcplen;i++) {
u[i]=tcp[i];
}
if(o != 0) {
tcplen=tcplen+lens;
for(j=0;j<lens;j++,i++)
u[i]=o[j];
}
l = tcplen;
d.src[0]=70;
d.src[1]=0;
d.src[2]=0;
d.src[3]=1;
d.dest[0]=70;
d.dest[1]=0;
d.dest[2]=0;
d.dest[3]=8;
d.u=0;
d.prot=6;
d.len=ohtons(l);
t=&d;
for (i = 0;i<=11;i++,l++) {
u[l] = t[i];
}
tcplen=l;
chksum=checksum( u,tcplen );
return chksum;
}
unsigned long ohtonl( unsigned long h ) {
unsigned char h1,h2,h3,h4;
unsigned long h5;
h1 = (unsigned char ) h & 0x000000ff;
h2 = (h >> 8)&0x000000ff;
h3 = (h >> 16) & 0x000000ff;
h4 = (h >> 24 ) & 0x000000ff;
h5 = ((long)1<<24)*h1 + h4 + h3*256 + h2*65536;
return h5;
}
void sendit(struct packet * spacket)
{
union REGS regs;
struct SREGS sregs;
struct packet sendpkt;
unsigned int i,j;
sendpkt.data[0]=0x04;
sendpkt.data[1]=0x01;
sendpkt.data[2]=0x30;
sendpkt.data[3]=0x16;
sendpkt.data[4]=0;
sendpkt.data[5]=0;
sendpkt.data[6]=0x04;
sendpkt.data[7]=0x01;
sendpkt.data[8]=0x20;
sendpkt.data[9]=0x45;
sendpkt.data[10]=0x00;
sendpkt.data[11]=0x00;
for(j=12,i=0;i< spacket->packetsize;j++,i++) {
sendpkt.data[j]=spacket->data[i];
}
sendpkt.packetsize=j;
for(i=0;i<sendpkt.packetsize;i++)
{
abc(sendpkt.data[i]);
printf("%x..",sendpkt.data[i]);
}
regs.h.ah = 4;
regs.h.al=0;
regs.x.si=FP_OFF(&sendpkt.data);
sregs.ds=FP_SEG(&sendpkt.data);
regs.x.cx=sendpkt.packetsize;
int86x(0x60,®s,®s,&sregs);
strset(e,0);
}
int sendarpreply()
{
struct packet sendpkt1;
sendpkt1.data[0]=0x04;
sendpkt1.data[1]=0x01;
sendpkt1.data[2]=0x30;
sendpkt1.data[3]=0x16;
sendpkt1.data[4]=0x00;
sendpkt1.data[5]=0x00;
sendpkt1.data[6]=0x04;
sendpkt1.data[7]=0x01;
sendpkt1.data[8]=0x20;
sendpkt1.data[9]=0x45;
sendpkt1.data[10]=0x00;
sendpkt1.data[11]=0x00;
sendpkt1.data[12]=0x08;
sendpkt1.data[13]=0x06;
sendpkt1.data[14]=0x00;
sendpkt1.data[15]=0x01;
sendpkt1.data[16]=0x08;
sendpkt1.data[17]=0x00;
sendpkt1.data[18]=0x06;
sendpkt1.data[19]=0x04;
sendpkt1.data[20]=0x00;
sendpkt1.data[21]=0x02;
sendpkt1.data[22]=0x04;
sendpkt1.data[23]=0x01;
sendpkt1.data[24]=0x20;
sendpkt1.data[25]=0x45;
sendpkt1.data[26]=0x00;
sendpkt1.data[27]=0x00;
sendpkt1.data[28]=70;
sendpkt1.data[29]=0;
sendpkt1.data[30]=0;
sendpkt1.data[31]=1;
sendpkt1.data[32]=0x04;
sendpkt1.data[33]=0x01;
sendpkt1.data[34]=0x30;
sendpkt1.data[35]=0x16;
sendpkt1.data[36]=0x00;
sendpkt1.data[37]=0x00;
sendpkt1.data[38]=70;
sendpkt1.data[39]=0;
sendpkt1.data[40]=0;
sendpkt1.data[41]=8;
sendpkt1.packetsize=42;
a.h.ah = 4;
a.h.al=0;
a.x.si=FP_OFF(&sendpkt1.data);
s.ds=FP_SEG(&sendpkt1.data);
a.x.cx=sendpkt1.packetsize;
int86x(0x60,&a,&b,&s);
for(i=0;i<sendpkt1.packetsize;i++)
abc(sendpkt1.data[i]);
}
void interrupt zzz(bp,di,si,ds,es,dx,cx,bx,ax,ip,cs,flags)
unsigned short bp,di,si,ds,es,dx,cx,bx,ax,ip,cs,flags;
{
printf("Receiver ax = %d Packet size = %d\n",ax,cx);
if (ax == 0)
{
es = FP_SEG(e);
di = FP_OFF(e);
ii = cx;
}
if (ax == 1)
{
for(i=0;i<=ii;i++)
{
abc(e[i]);
printf("%x..",e[i]);
}
if ( e[12] == 0x08 && e[13] == 0x06 && e[20] == 0x00 && e[21] == 0x01)
{
sendarpreply();
}
}
abc('-'); abc('-'); abc('-');
}
void writeabc(unsigned char *ip, unsigned char *tcp, unsigned char *opt, unsigned char *tdata ) {
struct packet tcpip;
unsigned int i,j;
unsigned char uu[1000];
j=0;
uu[j]=0x08;
j++;
uu[j]=0x00;
j++;
for(i=0;i<20;i++,j++) {
uu[j]=ip[i];
}
for(i=0;i<20;i++,j++) {
uu[j]=tcp[i];
}
if (opt != 0) {
for(i=0;i<4;i++,j++) {
uu[j]=opt[i];
}
}
if (tdata != 0) {
for(i=0;i<16;j++) {
uu[j]=tdata[i];
}
}
for(i=0;i<j;i++) {
tcpip.data[i]=uu[i];
}
tcpip.packetsize=j;
sendit(&tcpip);
}
void sendsyn()
{
struct tcphdr tcp;
struct iphdr ip;
unsigned char opt[4]={2,4,2,0};
tcp.srcport=ohtons(1024);
tcp.destport=ohtons(80);
tcp.seqno=ohtonl(5);
tcp.ackno=ohtonl(0);
tcp.hdrlen=0x60;
tcp.flags=0x2;
tcp.win=ohtons(1024);
tcp.chksum=0;
tcp.urgptr=0;
tcp.chksum=tcpchecksum(&tcp,opt,20,4);
ip.verlen =0x45;
ip.tos =0x0;
ip.totlen =ohtons(44);
ip.id[0] =0x2e;
ip.id[1]=0;
ip.frag[0] =0x40;
ip.frag[1]=0;
ip.ttl =32;
ip.prot =0x6;
ip.chksum =0;
ip.sourceip[0] =70;
ip.sourceip[1] =0;
ip.sourceip[2] =0;
ip.sourceip[3] =1;
ip.destip[0] =70;
ip.destip[1] =0;
ip.destip[2] =0;
ip.destip[3] =8;
ip.chksum =checksum(&ip,20);
writeabc(&ip,&tcp,&opt,0);
}
main()
{
segread(&s);
a.h.ah = 1;
a.h.al = 255;
int86x(0x60, &a, &b, &s);
printf("Carry Flag Driver Info - %d\n",b.x.cflag);
printf("Class - %d, Type - %d \n",b.h.ch, b.x.dx);
a.h.ah = 6;
a.x.cx = 6;
s.es = FP_SEG(ad);
a.x.di = FP_OFF(ad);
int86x(0x60, &a, &b, &s);
printf("Carry Flag Ethernet Address - %d\n",b.x.cflag);
printf("Address - %x: %x: %x: %x: %x: %x\n",ad[0],ad[1],ad[2],ad[3],ad[4],ad[5]);
a.h.al = 1;
a.x.bx = -1;
a.h.dl = 0;
a.x.cx = 0;
a.h.ah = 2;
s.es = FP_SEG(zzz);
a.x.di = FP_OFF(zzz);
c[0] = 0xff;
c[1] = 0xff;
s.ds = FP_SEG(c);
a.x.si = FP_OFF(c);
int86x(0x60, &a, &b, &s);
printf("Carry Flag Access Type - %d\n",b.x.cflag);
printf("Handle - %d\n",b.x.ax);
handle = b.x.ax;
a.h.ah = 21;
a.x.bx = handle;
int86x(0x60, &a, &b, &s);
printf("Get Recv Mode - %d\n",b.x.cflag);
printf("Receive Mode - %d\n",b.x.ax);
a.h.ah = 20;
a.x.bx = handle;
a.x.cx = 6;
int86x(0x60, &a, &b, &s);
printf("Carry Flag Set Recv Mode - %d\n",b.x.cflag);
sendsyn();
getch(); getch(); getch();
a.h.ah = 3;
a.x.bx = handle;
int86x(0x60, &a, &b, &s);
printf("Carry Flag Release Type - %d\n",b.x.cflag);
printf("OVER");
}
As usual, our
interrupt zzz() captured the ARP bytes broadcast across the network. Siince
it's an ARP request, in function zzz() we call sendarpreply() which does just
that. The ARP packet has been hardwired in, see if you can't make it better.
Once the
server has our address, it sends us a SYN/ACK.
prog4.c
#include <dos.h>
#include <stdio.h>
struct packet {
unsigned char data[1000];
unsigned int packetsize;
};
struct iphdr {
unsigned char verlen;
unsigned char tos;
unsigned short totlen;
unsigned short id; // The id field and the fragmentation is two unsigned short frag;// bytes, so it can either be taken as two unsigned char ttl; //chars or one int
unsigned char prot;
unsigned short chksum;
unsigned char sourceip[4];
unsigned char destip[4];
};
struct tcphdr {
unsigned short srcport;
unsigned short destport;
unsigned long seqno;
unsigned long ackno;
unsigned char hdrlen;
unsigned char flags;
unsigned short win;
unsigned short chksum;
unsigned short urgptr;
};
struct dummytcp {
unsigned char src[4];
unsigned char dest[4];
char u;
char prot;
unsigned short len;
};
union REGS a,b;
struct SREGS s;
unsigned char ad[6],c[2],d[60];
unsigned char e[1000];
int handle , i, y, ii;
void abc(unsigned char p)
{
FILE *fp;
fp = fopen("D:\\z.txt","a+");
fprintf(fp,"..%x..%d\n",p,p);
fclose(fp);
}
void sendit(struct packet * spacket)
{
union REGS regs;
struct SREGS sregs;
struct packet sendpkt;
unsigned int i,j;
sendpkt.data[0]=0x04;
sendpkt.data[1]=0x01;
sendpkt.data[2]=0x30;
sendpkt.data[3]=0x16;
sendpkt.data[4]=0;
sendpkt.data[5]=0;
sendpkt.data[6]=0x04;
sendpkt.data[7]=0x01;
sendpkt.data[8]=0x20;
sendpkt.data[9]=0x45;
sendpkt.data[10]=0x00;
sendpkt.data[11]=0x00;
for(j=12,i=0;i< spacket->packetsize;j++,i++) {
sendpkt.data[j]=spacket->data[i];
}
sendpkt.packetsize=j;
for(i=0;i<sendpkt.packetsize;i++)
{
abc(sendpkt.data[i]);
printf("%x..",sendpkt.data[i]);
}
regs.h.ah = 4;
regs.h.al=0;
regs.x.si=FP_OFF(&sendpkt.data);
sregs.ds=FP_SEG(&sendpkt.data);
regs.x.cx=sendpkt.packetsize;
int86x(0x60,®s,®s,&sregs);
strset(e,0);
}
unsigned long oinetaddr( unsigned char data[] ) {
unsigned long h5;
h5=((((long)1<<24)*data[0])+(data[1]*65536)+(data[2]*256)+data[3]);
return h5;
}
void sendsyn();
void writeabc(unsigned char *ip, unsigned char *tcp, unsigned char *opt, unsigned char *tdata ) {
struct packet tcpip;
unsigned int i,j;
unsigned char uu[1000];
j=0;
uu[j]=0x08;
j++;
uu[j]=0x00;
j++;
for(i=0;i<20;i++,j++) {
uu[j]=ip[i];
}
for(i=0;i<20;i++,j++) {
uu[j]=tcp[i];
}
if (opt != 0) {
for(i=0;i<4;i++,j++) {
uu[j]=opt[i];
}
}
if (tdata != 0) {
for(i=0;i<16;j++) {
uu[j]=tdata[i];
}
}
for(i=0;i<j;i++) {
tcpip.data[i]=uu[i];
}
tcpip.packetsize=j;
sendit(&tcpip);
}
unsigned int ohtons(unsigned int h)
{
unsigned char h1,h2;
unsigned short h5;
h1 = (unsigned char ) h & 0xff;
h2 = (h >> 8)&0xff;
h5 = 256*h1 + h2 ;
return h5;
}
unsigned short checksum(unsigned short * ip1,unsigned int len) {
long sum = 0;
while ( len > 1) {
sum += *ip1++;
if ( sum & 0x80000000 )
sum = ( sum & 0xffff) + ( sum >> 16);
len -= 2;
}
while ( sum >> 16)
sum = ( sum & 0xffff) + ( sum >> 16);
return ~sum;
}
unsigned short tcpchecksum( unsigned char * tcp, unsigned char * o, unsigned int l, unsigned int lens ) {
unsigned char u[1000];
unsigned char *t;
struct dummytcp d;
unsigned short chksum;
unsigned int i,j;
unsigned short tcplen;
tcplen=l;
for(i=0;i<tcplen;i++) {
u[i]=tcp[i];
}
if(o != 0) {
tcplen=tcplen+lens;
for(j=0;j<lens;j++,i++)
u[i]=o[j];
}
l = tcplen;
d.src[0]=70;
d.src[1]=0;
d.src[2]=0;
d.src[3]=1;
d.dest[0]=70;
d.dest[1]=0;
d.dest[2]=0;
d.dest[3]=8;
d.u=0;
d.prot=6;
d.len=ohtons(l);
t=&d;
for (i = 0;i<=11;i++,l++) {
u[l] = t[i];
}
tcplen=l;
chksum=checksum( u,tcplen );
return chksum;
}
unsigned long ohtonl( unsigned long h ) {
unsigned char h1,h2,h3,h4;
unsigned long h5;
h1 = (unsigned char ) h & 0x000000ff;
h2 = (h >> 8)&0x000000ff;
h3 = (h >> 16) & 0x000000ff;
h4 = (h >> 24 ) & 0x000000ff;
h5 = ((long)1<<24)*h1 + h4 + h3*256 + h2*65536;
return h5;
}
int sendarpreply()
{
struct packet sendpkt1;
sendpkt1.data[0]=0x04;
sendpkt1.data[1]=0x01;
sendpkt1.data[2]=0x30;
sendpkt1.data[3]=0x16;
sendpkt1.data[4]=0x00;
sendpkt1.data[5]=0x00;
sendpkt1.data[6]=0x04;
sendpkt1.data[7]=0x01;
sendpkt1.data[8]=0x20;
sendpkt1.data[9]=0x45;
sendpkt1.data[10]=0x00;
sendpkt1.data[11]=0x00;
sendpkt1.data[12]=0x08;
sendpkt1.data[13]=0x06;
sendpkt1.data[14]=0x00;
sendpkt1.data[15]=0x01;
sendpkt1.data[16]=0x08;
sendpkt1.data[17]=0x00;
sendpkt1.data[18]=0x06;
sendpkt1.data[19]=0x04;
sendpkt1.data[20]=0x00;
sendpkt1.data[21]=0x02;
sendpkt1.data[22]=0x04;
sendpkt1.data[23]=0x01;
sendpkt1.data[24]=0x20;
sendpkt1.data[25]=0x45;
sendpkt1.data[26]=0x00;
sendpkt1.data[27]=0x00;
sendpkt1.data[28]=70;
sendpkt1.data[29]=0;
sendpkt1.data[30]=0;
sendpkt1.data[31]=1;
sendpkt1.data[32]=0x04;
sendpkt1.data[33]=0x01;
sendpkt1.data[34]=0x30;
sendpkt1.data[35]=0x16;
sendpkt1.data[36]=0x00;
sendpkt1.data[37]=0x00;
sendpkt1.data[38]=70;
sendpkt1.data[39]=0;
sendpkt1.data[40]=0;
sendpkt1.data[41]=8;
sendpkt1.packetsize=42;
for(i=0;i<sendpkt1.packetsize;i++)
{
abc(sendpkt1.data[i]);
printf("%x..",sendpkt1.data[i]);
}
a.h.ah = 4;
a.h.al=0;
a.x.si=FP_OFF(&sendpkt1.data);
s.ds=FP_SEG(&sendpkt1.data);
a.x.cx=sendpkt1.packetsize;
int86x(0x60,&a,&b,&s);
}
int sendlastack()
{
struct iphdr ip;
struct tcphdr tcp;
unsigned char sseq[4];
unsigned char aack[4];
unsigned long sno,ano;
ip.verlen =0x45;
ip.tos =0x0;
ip.totlen =ohtons(40);
ip.id =ohtons(3);
ip.frag =0;
ip.ttl =32;
ip.prot =0x6;
ip.chksum =0;
ip.sourceip[0] =70;
ip.sourceip[1] =0;
ip.sourceip[2] =0;
ip.sourceip[3] =1;
ip.destip[0] =70;
ip.destip[1] =0;
ip.destip[2] =0;
ip.destip[3] =8;
ip.chksum = checksum(&ip,20);
tcp.srcport=ohtons(1024);
tcp.destport=ohtons(80);
sseq[0]=e[42];
sseq[1]=e[43] ;
sseq[2]=e[44];
sseq[3]=e[45];
aack[0]=e[38];
aack[1]=e[39];
aack[2]=e[40];
aack[3]=e[41];
sno=oinetaddr(sseq);
ano=oinetaddr(aack);
tcp.seqno=ohtonl(sno);
tcp.ackno=ohtonl(ano+1);
tcp.hdrlen=0x50;
tcp.flags=0x10;
tcp.win=ohtons(1024);
tcp.chksum=0;
tcp.urgptr=0;
tcp.chksum=tcpchecksum(&tcp,0,20,0);
writeabc(&ip,&tcp,0,0);
}
void interrupt zzz(bp,di,si,ds,es,dx,cx,bx,ax,ip,cs,flags)
unsigned short bp,di,si,ds,es,dx,cx,bx,ax,ip,cs,flags;
{
printf("Receiver ax = %d Packet size = %d\n",ax,cx);
if (ax == 0)
{
es = FP_SEG(e);
di = FP_OFF(e);
ii = cx;
}
if (ax == 1)
{
for(i=0;i<=ii;i++)
{
abc(e[i]);
printf("%x..",e[i]);
}
if ( e[12] == 0x08 && e[13] == 0x06 && e[20] == 0x00 && e[21] == 0x01)
{
sendarpreply();
}
if (e[12]==0x08 && e[13]==0x00 && e[47]==18)
{
sendlastack();
}
}
abc('-'); abc('-'); abc('-');
}
void sendsyn()
{
struct tcphdr tcp;
struct iphdr ip;
unsigned char opt[4]={2,4,2,0};
tcp.srcport=ohtons(1024);
tcp.destport=ohtons(80);
tcp.seqno=ohtonl(5);
tcp.ackno=ohtonl(0);
tcp.hdrlen=0x60;
tcp.flags=0x2;
tcp.win=ohtons(1024);
tcp.chksum=0;
tcp.urgptr=0;
tcp.chksum=tcpchecksum(&tcp,opt,20,4);
ip.verlen =0x45;
ip.tos =0x0;
ip.totlen =ohtons(44);
ip.id =0;
ip.frag=0;
ip.ttl =32;
ip.prot =0x6;
ip.chksum =0;
ip.sourceip[0] =70;
ip.sourceip[1] =0;
ip.sourceip[2] =0;
ip.sourceip[3] =1;
ip.destip[0] =70;
ip.destip[1] =0;
ip.destip[2] =0;
ip.destip[3] =8;
ip.chksum =checksum(&ip,20);
writeabc(&ip,&tcp,&opt,0);
}
main()
{
segread(&s);
a.h.ah = 1;
a.h.al = 255;
int86x(0x60, &a, &b, &s);
printf("Carry Flag Driver Info - %d\n",b.x.cflag);
printf("Class - %d, Type - %d \n",b.h.ch, b.x.dx);
a.h.ah = 6;
a.x.cx = 6;
s.es = FP_SEG(ad);
a.x.di = FP_OFF(ad);
int86x(0x60, &a, &b, &s);
printf("Carry Flag Ethernet Address - %d\n",b.x.cflag);
printf("Address - %x: %x: %x: %x: %x: %x\n",ad[0],ad[1],ad[2],ad[3],ad[4],ad[5]);
a.h.al = 1;
a.x.bx = -1;
a.h.dl = 0;
a.x.cx = 0;
a.h.ah = 2;
s.es = FP_SEG(zzz);
a.x.di = FP_OFF(zzz);
c[0] = 0xff;
c[1] = 0xff;
s.ds = FP_SEG(c);
a.x.si = FP_OFF(c);
int86x(0x60, &a, &b, &s);
printf("Carry Flag Access Type - %d\n",b.x.cflag);
printf("Handle - %d\n",b.x.ax);
handle = b.x.ax;
a.h.ah = 21;
a.x.bx = handle;
int86x(0x60, &a, &b, &s);
printf("Get Recv Mode - %d\n",b.x.cflag);
printf("Receive Mode - %d\n",b.x.ax);
a.h.ah = 20;
a.x.bx = handle;
a.x.cx = 3;
int86x(0x60, &a, &b, &s);
printf("Carry Flag Set Recv Mode - %d\n",b.x.cflag);
sendsyn();
getch(); getch(); getch();
a.h.ah = 3;
a.x.bx = handle;
int86x(0x60, &a, &b, &s);
printf("Carry Flag Release Type - %d\n",b.x.cflag);
printf("OVER");
}
In this
program, we've received the server's SYN/ACK and now we have to send it an ACK.
Before we can do this we must synchronies our sequence and acknowledgment
numbers (brush up on 'em). To do that, in the function sendlastack() we copy
it's sequence number into the array aack and it's acknowledgment number into
the array sseq. That's because the servers sequence number is our
acknowledgment number and it's acknowledgment number is our sequence number.
The only flag
we've turned on is the ACK flag and notice that the TCP header is only 40 bytes
large. That's because the TCP options, (i.e. Maximum Segment Size) has to be
sent only once.
There are two
new functions in this program. oinetaddr() is a function which takes the
address of an array four bytes large and converts in into the Network Byte
Order. The second function, sendlastack() has already been discussed. It
constructs and sends the ACK the server's been waiting for.
prog5.c
#include <dos.h>
#include <stdio.h>
struct packet {
unsigned char data[1000];
unsigned int packetsize;
};
struct iphdr {
unsigned char verlen;
unsigned char tos;
unsigned short totlen;
unsigned short id;
unsigned short frag;
unsigned char ttl;
unsigned char prot;
unsigned short chksum;
unsigned char sourceip[4];
unsigned char destip[4];
};
struct tcphdr {
unsigned short srcport;
unsigned short destport;
unsigned long seqno;
unsigned long ackno;
unsigned char hdrlen;
unsigned char flags;
unsigned short win;
unsigned short chksum;
unsigned short urgptr;
};
struct dummytcp {
unsigned char src[4];
unsigned char dest[4];
char u;
char prot;
unsigned short len;
};
union REGS a,b;
struct SREGS s;
unsigned char ad[6],c[2],d[60];
unsigned char e[1000];
int handle , i, y, ii;
unsigned char mysyn[4];
void abc(unsigned char p)
{
FILE *fp;
fp = fopen("D:\\z.txt","a+");
fprintf(fp,"..%x..%d..%c\n",p,p,p);
fclose(fp);
}
void sendit(struct packet * spacket)
{
union REGS regs;
struct SREGS sregs;
struct packet sendpkt;
unsigned int i,j;
sendpkt.data[0]=0x04;
sendpkt.data[1]=0x01;
sendpkt.data[2]=0x30;
sendpkt.data[3]=0x16;
sendpkt.data[4]=0;
sendpkt.data[5]=0;
sendpkt.data[6]=0x04;
sendpkt.data[7]=0x01;
sendpkt.data[8]=0x20;
sendpkt.data[9]=0x45;
sendpkt.data[10]=0x00;
sendpkt.data[11]=0x00;
for(j=12,i=0;i< spacket->packetsize;j++,i++) {
sendpkt.data[j]=spacket->data[i];
}
sendpkt.packetsize=j;
for(i=0;i<sendpkt.packetsize;i++)
{
abc(sendpkt.data[i]);
printf("%x..",sendpkt.data[i]);
}
regs.h.ah = 4;
regs.h.al=0;
regs.x.si=FP_OFF(&sendpkt.data);
sregs.ds=FP_SEG(&sendpkt.data);
regs.x.cx=sendpkt.packetsize;
int86x(0x60,®s,®s,&sregs);
strset(e,0);
}
unsigned long oinetaddr( unsigned char data[] ) {
unsigned long h5;
h5=((((long)1<<24)*data[0])+(((long)1<<16)*data[1])+(((long)1<<8)*data[2])+(long)1*data[3]);
return h5;
}
void sendsyn();
void writeabc(unsigned char *ip, unsigned char *tcp, unsigned char *opt, unsigned char *tdata ) {
struct packet tcpip;
unsigned int i,j;
unsigned char uu[1000];
j=0;
uu[j]=0x08;
j++;
uu[j]=0x00;
j++;
for(i=0;i<20;i++,j++) {
uu[j]=ip[i];
}
for(i=0;i<20;i++,j++) {
uu[j]=tcp[i];
}
if (opt != 0) {
for(i=0;i<4;i++,j++) {
uu[j]=opt[i];
}
}
if (tdata != 0) {
for(i=0;i<strlen(tdata);j++,i++) {
uu[j]=tdata[i];
}
}
for(i=0;i<j;i++) {
tcpip.data[i]=uu[i];
}
tcpip.packetsize=j;
sendit(&tcpip);
}
unsigned int ohtons(unsigned int h)
{
unsigned char h1,h2;
unsigned short h5;
h1 = (unsigned char ) h & 0xff;
h2 = (h >> 8)&0xff;
h5 = 256*h1 + h2 ;
return h5;
}
unsigned short checksum(unsigned short * ip1,unsigned int len) {
long sum = 0;
while ( len > 1) {
sum += *ip1++;
if ( sum & 0x80000000 )
sum = ( sum & 0xffff) + ( sum >> 16);
len -= 2;
}
while ( sum >> 16)
sum = ( sum & 0xffff) + ( sum >> 16);
return ~sum;
}
unsigned short tcpchecksum( unsigned char * tcp, unsigned char * o, unsigned int l, unsigned int lens ) {
unsigned char u[1000];
unsigned char *t;
struct dummytcp d;
unsigned short chksum;
unsigned int i,j;
unsigned short tcplen;
tcplen=l;
for(i=0;i<tcplen;i++) {
u[i]=tcp[i];
}
if(o != 0) {
tcplen=tcplen+lens;
for(j=0;j<lens;j++,i++)
u[i]=o[j];
}
l = tcplen;
d.src[0]=70;
d.src[1]=0;
d.src[2]=0;
d.src[3]=1;
d.dest[0]=70;
d.dest[1]=0;
d.dest[2]=0;
d.dest[3]=8;
d.u=0;
d.prot=6;
d.len=ohtons(l);
t=&d;
for (i = 0;i<=11;i++,l++) {
u[l] = t[i];
}
tcplen=l;
chksum=checksum( u,tcplen );
return chksum;
}
unsigned long ohtonl( unsigned long h ) {
unsigned char h1,h2,h3,h4;
unsigned long h5;
h1 = (unsigned char ) h & 0x000000ff;
h2 = (h >> 8)&0x000000ff;
h3 = (h >> 16) & 0x000000ff;
h4 = (h >> 24 ) & 0x000000ff;
h5 = ((long)1<<24)*h1 + h4 + h3*256 + h2*65536;
return h5;
}
int sendarpreply()
{
struct packet sendpkt1;
sendpkt1.data[0]=0x04;
sendpkt1.data[1]=0x01;
sendpkt1.data[2]=0x30;
sendpkt1.data[3]=0x16;
sendpkt1.data[4]=0x00;
sendpkt1.data[5]=0x00;
sendpkt1.data[6]=0x04;
sendpkt1.data[7]=0x01;
sendpkt1.data[8]=0x20;
sendpkt1.data[9]=0x45;
sendpkt1.data[10]=0x00;
sendpkt1.data[11]=0x00;
sendpkt1.data[12]=0x08;
sendpkt1.data[13]=0x06;
sendpkt1.data[14]=0x00;
sendpkt1.data[15]=0x01;
sendpkt1.data[16]=0x08;
sendpkt1.data[17]=0x00;
sendpkt1.data[18]=0x06;
sendpkt1.data[19]=0x04;
sendpkt1.data[20]=0x00;
sendpkt1.data[21]=0x02;
sendpkt1.data[22]=0x04;
sendpkt1.data[23]=0x01;
sendpkt1.data[24]=0x20;
sendpkt1.data[25]=0x45;
sendpkt1.data[26]=0x00;
sendpkt1.data[27]=0x00;
sendpkt1.data[28]=70;
sendpkt1.data[29]=0;
sendpkt1.data[30]=0;
sendpkt1.data[31]=1;
sendpkt1.data[32]=0x04;
sendpkt1.data[33]=0x01;
sendpkt1.data[34]=0x30;
sendpkt1.data[35]=0x16;
sendpkt1.data[36]=0x00;
sendpkt1.data[37]=0x00;
sendpkt1.data[38]=70;
sendpkt1.data[39]=0;
sendpkt1.data[40]=0;
sendpkt1.data[41]=8;
sendpkt1.packetsize=42;
a.h.ah = 4;
a.h.al=0;
a.x.si=FP_OFF(&sendpkt1.data);
s.ds=FP_SEG(&sendpkt1.data);
a.x.cx=sendpkt1.packetsize;
int86x(0x60,&a,&b,&s);
for(i=0;i<sendpkt1.packetsize;i++)
abc(sendpkt1.data[i]);
}
int sendlastack()
{
struct iphdr ip;
struct tcphdr tcp;
unsigned char sseq[4];
unsigned char aack[4];
unsigned long sno,ano;
ip.verlen =0x45;
ip.tos =0x0;
ip.totlen =ohtons(40);
ip.id =ohtons(3);
ip.frag =0;
ip.ttl =32;
ip.prot =0x6;
ip.chksum =0;
ip.sourceip[0] =70;
ip.sourceip[1] =0;
ip.sourceip[2] =0;
ip.sourceip[3] =1;
ip.destip[0] =70;
ip.destip[1] =0;
ip.destip[2] =0;
ip.destip[3] =8;
ip.chksum = checksum(&ip,20);
tcp.srcport=ohtons(1024);
tcp.destport=ohtons(80);
sseq[0]=e[42];
sseq[1]=e[43] ;
sseq[2]=e[44];
sseq[3]=e[45];
mysyn[0]=e[42];
mysyn[1]=e[43];
mysyn[2]=e[44];
mysyn[3]=e[45];
aack[0]=e[38];
aack[1]=e[39];
aack[2]=e[40];
aack[3]=e[41];
sno=oinetaddr(sseq);
ano=oinetaddr(aack);
ano++;
tcp.seqno=ohtonl(sno);
tcp.ackno=ohtonl(ano);
tcp.hdrlen=0x50;
tcp.flags=0x10;
tcp.win=ohtons(1024);
tcp.chksum=0;
tcp.urgptr=0;
tcp.chksum=tcpchecksum(&tcp,0,20,0);
writeabc(&ip,&tcp,0,0);
}
int sendget()
{
struct tcphdr tcp;
struct iphdr ip;
unsigned long seqno;
unsigned long ackno;
unsigned char sseq[4];
unsigned char aack[4];
unsigned char tcpdata[]="GET / HTTP 1.0\r\n\r\n";
sseq[0]=e[42];
sseq[1]=e[43] ;
sseq[2]=e[44];
sseq[3]=e[45];
aack[0]=e[38];
aack[1]=e[39];
aack[2]=e[40];
aack[3]=e[41];
seqno=oinetaddr(sseq);
ackno=oinetaddr(aack);
tcp.srcport=ohtons(1024);
tcp.destport=ohtons(80);
tcp.seqno=ohtonl(seqno);
tcp.ackno=ohtonl(ackno +1);
tcp.hdrlen=0x50;
tcp.flags=0x10;
tcp.win=ohtons(1024);
tcp.chksum=0;
tcp.urgptr=0;
tcp.chksum=tcpchecksum( &tcp,tcpdata,20,strlen(tcpdata ));
ip.verlen =0x45;
ip.tos =0x0;
ip.totlen =ohtons( 20 + 20 + strlen(tcpdata ));
ip.id =ohtons( 1 );
ip.frag =0x00;
ip.ttl =0x1f;
ip.prot =0x6;
ip.chksum =0;
ip.sourceip[0] =70;
ip.sourceip[1] =0;
ip.sourceip[2] =0;
ip.sourceip[3] =1;
ip.destip[0] =70;
ip.destip[1] =0;
ip.destip[2] =0;
ip.destip[3] =8;
ip.chksum =checksum( &ip,20 );
writeabc( &ip,&tcp,0,&tcpdata );
}
void interrupt zzz(bp,di,si,ds,es,dx,cx,bx,ax,ip,cs,flags)
unsigned short bp,di,si,ds,es,dx,cx,bx,ax,ip,cs,flags;
{
printf("Receiver ax = %d Packet size = %d\n",ax,cx);
if (ax == 0)
{
es = FP_SEG(e);
di = FP_OFF(e);
ii = cx;
}
if (ax == 1)
{
for(i=0;i<=ii;i++)
{
abc(e[i]);
printf("%x..",e[i]);
}
if ( e[12] == 0x08 && e[13] == 0x06 && e[20] == 0x00 && e[21] == 0x01)
{
sendarpreply();
}
if (e[12]==0x08 && e[13]==0x00 && e[47]==18)
{
sendlastack();
}
if (e[42]==mysyn[0] && e[43] == mysyn[1] && e[44] == mysyn[2] && e[45] == mysyn[3])
{
sendget();
}
}
abc('-'); abc('-'); abc('-');
}
void sendsyn()
{
struct tcphdr tcp;
struct iphdr ip;
unsigned char opt[4]={2,4,2,0};
tcp.srcport=ohtons(1024);
tcp.destport=ohtons(80);
tcp.seqno=ohtonl(5);
mysyn[0]=0;
mysyn[1]=0;
mysyn[2]=0;
mysyn[3]=5;
tcp.ackno=ohtonl(0);
tcp.hdrlen=0x60;
tcp.flags=0x2;
tcp.win=ohtons(1024);
tcp.chksum=0;
tcp.urgptr=0;
tcp.chksum=tcpchecksum(&tcp,opt,20,4);
ip.verlen =0x45;
ip.tos =0x0;
ip.totlen =ohtons(44);
ip.id =0;
ip.frag=0;
ip.ttl =32;
ip.prot =0x6;
ip.chksum =0;
ip.sourceip[0] =70;
ip.sourceip[1] =0;
ip.sourceip[2] =0;
ip.sourceip[3] =1;
ip.destip[0] =70;
ip.destip[1] =0;
ip.destip[2] =0;
ip.destip[3] =8;
ip.chksum =checksum(&ip,20);
writeabc(&ip,&tcp,&opt,0);
}
main()
{
segread(&s);
a.h.ah = 1;
a.h.al = 255;
int86x(0x60, &a, &b, &s);
printf("Carry Flag Driver Info - %d\n",b.x.cflag);
printf("Class - %d, Type - %d \n",b.h.ch, b.x.dx);
a.h.ah = 6;
a.x.cx = 6;
s.es = FP_SEG(ad);
a.x.di = FP_OFF(ad);
int86x(0x60, &a, &b, &s);
printf("Carry Flag Ethernet Address - %d\n",b.x.cflag);
printf("Address - %x: %x: %x: %x: %x: %x\n",ad[0],ad[1],ad[2],ad[3],ad[4],ad[5]);
a.h.al = 1;
a.x.bx = -1;
a.h.dl = 0;
a.x.cx = 0;
a.h.ah = 2;
s.es = FP_SEG(zzz);
a.x.di = FP_OFF(zzz);
c[0] = 0xff;
c[1] = 0xff;
s.ds = FP_SEG(c);
a.x.si = FP_OFF(c);
int86x(0x60, &a, &b, &s);
printf("Carry Flag Access Type - %d\n",b.x.cflag);
printf("Handle - %d\n",b.x.ax);
handle = b.x.ax;
a.h.ah = 21;
a.x.bx = handle;
int86x(0x60, &a, &b, &s);
printf("Get Recv Mode - %d\n",b.x.cflag);
printf("Receive Mode - %d\n",b.x.ax);
a.h.ah = 20;
a.x.bx = handle;
a.x.cx = 3;
int86x(0x60, &a, &b, &s);
printf("Carry Flag Set Recv Mode - %d\n",b.x.cflag);
sendsyn();
getch(); getch(); getch();
a.h.ah = 3;
a.x.bx = handle;
int86x(0x60, &a, &b, &s);
printf("Carry Flag Release Type - %d\n",b.x.cflag);
printf("OVER");
}
Once we send
the last ACK, we've completed the Three Way Handshake and we're connected to the
HTTP server. This is exactly what the connect() function does. Since we're
connected to the server, we've got to ask if for something and so we send a GET
/ . The Get command asks for a file and when we say GET / we mean send over the
default page. We could also say GET default.html, but some servers have other
names for their default pages, like index.htm, index.html, default.htm etc.
It's best to use the /.
Not only do we
have to send the command, but we've also got to give the server some headers
for it to chew on. The line GET / HTTP/1.0 is essential. If you don't have it,
the server will refuse to respond. The function sendget() creates and sends the
GET / to the server.
We've also got
to take care of some potential problems. What if the ACK hasn't reached the
server?, we've got have a timer and when the timer expires, we have to send
another ACK. Additionally, the GET / should reach only after the ACK, not
before it. For such error checks, we've stored the server's acknowledgment
numbers in an array called mysyn in sendlastack().
Check out the
callback zzz() to figure out the sequence of function calls.
If you'll
scroll carefully through the z.txt, you'll see the server's response to our GET
/ displayed vertically.
It works!!
z.txt
we have shown only the get packet
Packet Sent
..4..4..
..1..1..
..30..48..0
..16..22..
..0..0..
..0..0..
..4..4..
..1..1..
..20..32..
..45..69..E
..0..0..
..0..0..
..8..8..
..0..0..
..45..69..E
..0..0..
..0..0..
..3a..58..: Len of the IP header
..0..0..
..1..1..
..0..0..
..0..0..
..1f..31..
..6..6..
..f..15..
..b5..181..µ
..46..70..F
..0..0..
..0..0..
..1..1..
..46..70..F
..0..0..
..0..0..
..8..8..
..4..4..
..0..0..
..0..0..
..50..80..P
..0..0.. Seq No. 0 0 0 6
..0..0..
..0..0..
..6..6..
..0..0.. Ack No. 0 1 51 49
..1..1..
..51..81..Q
..49..73..I
..50..80..P
..10..16..
..4..4..
..0..0..
..fa..250..ú
..79..121..y
..0..0..
..0..0..
..47..71..G
..45..69..E
..54..84..T
..20..32..
..2f..47../
..20..32..
..48..72..H
..54..84..T
..54..84..T
..50..80..P
..20..32..
..31..49..1
..2e..46...
..30..48..0
..d..13..
..a..10..
..d..13..
..a..10..
..2d..45..-
..2d..45..-
..2d..45..-
..2d..45..-
..2d..45..-
..2d..45..-
Packet Received
..4..4..
..1..1..
..20..32..
..45..69..E
..0..0..
..0..0..
..4..4..
..1..1..
..30..48..0
..16..22..
..0..0..
..0..0..
..8..8..
..0..0..
..45..69..E
..0..0..
..0..0..
..28..40..( Len of the IP datagram
..2..2..[1]
..0..0..
..40..64..@
..0..0..
..20..32..
..6..6..
..cc..204..Ì
..c7..199..Ç
..46..70..F
..0..0..
..0..0..
..8..8..
..46..70..F
..0..0..
..0..0..
..1..1..
..0..0..
..50..80..P
..4..4..
..0..0..
..0..0.. Seq No. 0 1 51 49
..1..1..
..51..81..Q
..49..73..I
..0..0.. Ack No. 0 0 0 18
..0..0..
..0..0..
..18..24..
..50..80..P
..10..16..
..1f..31..
..ee..238..î
..ae..174..®
..2b..43..+
..0..0..
..0..0..
..20..32..
..20..32..
..20..32..
..20..32..
..20..32..
..20..32..
..0..0..
..2d..45..-
..2d..45..-
..2d..45..-
..2d..45..-
..2d..45..-
..2d..45..-
Packet Received
..4..4..
..1..1..
..20..32..
..45..69..E
..0..0..
..0..0..
..4..4..
..1..1..
..30..48..0
..16..22..
..0..0..
..0..0..
..8..8..
..0..0..
..45..69..E IP Packet
..0..0..
..1..1..
..f..15.. Len of the IP datagram
..3..3..
..0..0..
..40..64..@
..0..0..
..20..32..
..6..6..
..ca..202..Ê
..e0..224..à
..46..70..F
..0..0..
..0..0..
..8..8..
..46..70..F
..0..0..
..0..0..
..1..1..
..0..0.. TCP Packet
..50..80..P
..4..4..
..0..0..
..0..0.. SeqNo. 0 1 51 49
..1..1..
..51..81..Q
..49..73..I
..0..0.. Ack No. 0 0 0 18
..0..0..
..0..0..
..18..24..
..50..80..P
..18..24.. ACK/PSH
..1f..31..
..ee..238..î
..c8..200..È
..47..71..G
..0..0..
..0..0..
..48..72..H TCP DATA
..54..84..T
..54..84..T
..50..80..P
..2f..47../
..31..49..1
..2e..46...
..30..48..0
..20..32..
..32..50..2
..30..48..0
..30..48..0
..20..32..
..4f..79..O
..4b..75..K
..d..13..
..a..10..
..44..68..D
..61..97..a
..74..116..t
..65..101..e
..3a..58..:
..20..32..
..54..84..T
..68..104..h
..75..117..u
..72..114..r
..73..115..s
..64..100..d
..61..97..a
..79..121..y
..2c..44..,
..20..32..
..32..50..2
..39..57..9
..2d..45..-
..4d..77..M
..61..97..a
..79..121..y
..2d..45..-
..39..57..9
..37..55..7
..20..32..
..31..49..1
..38..56..8
..3a..58..:
..34..52..4
..39..57..9
..3a..58..:
..32..50..2
..32..50..2
..20..32..
..47..71..G
..4d..77..M
..54..84..T
..d..13..
..a..10..
..53..83..S
..65..101..e
..72..114..r
..76..118..v
..65..101..e
..72..114..r
..3a..58..:
..20..32..
..57..87..W
..65..101..e
..62..98..b
..53..83..S
..69..105..i
..74..116..t
..65..101..e
..2f..47../
..31..49..1
..2e..46...
..31..49..1
..65..101..e
..d..13..
..a..10..
..41..65..A
..6c..108..l
..6c..108..l
..6f..111..o
..77..119..w
..2d..45..-
..72..114..r
..61..97..a
..6e..110..n
..67..103..g
..65..101..e
..73..115..s
..3a..58..:
..20..32..
..62..98..b
..79..121..y
..74..116..t
..65..101..e
..73..115..s
..d..13..
..a..10..
..43..67..C
..6f..111..o
..6e..110..n
..74..116..t
..65..101..e
..6e..110..n
..74..116..t
..2d..45..-
..74..116..t
..79..121..y
..70..112..p
..65..101..e
..3a..58..:
..20..32..
..74..116..t
..65..101..e
..78..120..x
..74..116..t
..2f..47../
..68..104..h
..74..116..t
..6d..109..m
..6c..108..l
..d..13..
..a..10..
..4c..76..L
..61..97..a
..73..115..s
..74..116..t
..2d..45..-
..6d..109..m
..6f..111..o
..64..100..d
..69..105..i
..66..102..f
..69..105..i
..65..101..e
..64..100..d
..3a..58..:
..20..32..
..54..84..T
..68..104..h
..75..117..u
..72..114..r
..73..115..s
..64..100..d
..61..97..a
..79..121..y
..2c..44..,
..20..32..
..32..50..2
..39..57..9
..2d..45..-
..4d..77..M
..61..97..a
..79..121..y
..2d..45..-
..39..57..9
..37..55..7
..20..32..
..31..49..1
..38..56..8
..3a..58..:
..32..50..2
..30..48..0
..3a..58..:
..30..48..0
..36..54..6
..20..32..
..47..71..G
..4d..77..M
..54..84..T
..d..13..
..a..10..
..43..67..C
..6f..111..o
..6e..110..n
..74..116..t
..65..101..e
..6e..110..n
..74..116..t
..2d..45..-
..6c..108..l
..65..101..e
..6e..110..n
..67..103..g
..74..116..t
..68..104..h
..3a..58..:
..20..32..
..33..51..3
..35..53..5
..d..13..
..a..10..
..d..13..
..a..10..
..3c..60..<
..68..104..h
..74..116..t
..6d..109..m
..6c..108..l
..3e..62..>
..d..13..
..a..10..
..3c..60..<
..62..98..b
..3e..62..>
..48..72..H
..65..101..e
..6c..108..l
..6c..108..l
..6f..111..o
..20..32..
..3c..60..<
..2f..47../
..62..98..b
..3e..62..>
..3c..60..<
..70..112..p
..3e..62..>
..d..13..
..a..10..
..3c..60..<
..2f..47../
..68..104..h
..74..116..t
..6d..109..m
..6c..108..l
..3e..62..>
..d..13..
..a..10..
..0..0..
..2d..45..-
..2d..45..-
..2d..45..-
..2d..45..-
..2d..45..-
..2d..45..-
prog6.c
#include
<dos.h>
#include
<stdio.h>
struct packet {
unsigned char data[1000];
unsigned int packetsize;
};
struct iphdr {
unsigned char verlen;
unsigned char tos;
unsigned short totlen;
unsigned short id;
unsigned short frag;
unsigned char ttl;
unsigned char prot;
unsigned short chksum;
unsigned char sourceip[4];
unsigned char destip[4];
};
struct tcphdr {
unsigned short srcport;
unsigned short destport;
unsigned long seqno;
unsigned long ackno;
unsigned char hdrlen;
unsigned char flags;
unsigned short win;
unsigned short chksum;
unsigned short urgptr;
};
struct dummytcp {
unsigned char src[4];
unsigned char dest[4];
char u;
char prot;
unsigned short len;
};
union REGS a,b;
struct SREGS s;
unsigned char ad[6],c[2],d[60];
unsigned char e[1000];
int handle , i, y, ii;
unsigned char mysyn[4];
int flag;
void abc(unsigned char p)
{
FILE *fp;
fp = fopen("D:\\z.txt","a+");
fprintf(fp,"..%x..%d..%c\n",p,p,p);
fclose(fp);
}
void sendit(struct packet * spacket)
{
union REGS regs;
struct SREGS sregs;
struct packet sendpkt;
unsigned int i,j;
sendpkt.data[0]=0x04;
sendpkt.data[1]=0x01;
sendpkt.data[2]=0x30;
sendpkt.data[3]=0x16;
sendpkt.data[4]=0;
sendpkt.data[5]=0;
sendpkt.data[6]=0x04;
sendpkt.data[7]=0x01;
sendpkt.data[8]=0x20;
sendpkt.data[9]=0x45;
sendpkt.data[10]=0x00;
sendpkt.data[11]=0x00;
for(j=12,i=0;i< spacket->packetsize;j++,i++) {
sendpkt.data[j]=spacket->data[i];
}
sendpkt.packetsize=j;
for(i=0;i<sendpkt.packetsize;i++)
{
abc(sendpkt.data[i]);
printf("%x..",sendpkt.data[i]);
}
regs.h.ah = 4;
regs.h.al=0;
regs.x.si=FP_OFF(&sendpkt.data);
sregs.ds=FP_SEG(&sendpkt.data);
regs.x.cx=sendpkt.packetsize;
int86x(0x60,®s,®s,&sregs);
strset(e,0);
}
unsigned long oinetaddr( unsigned char data[] ) {
unsigned long h5;
h5=((((long)1<<24)*data[0])+(((long)1<<16)*data[1])+(((long)1<<8)*data[2])+(long)1*data[3]);
return h5;
}
void sendsyn();
void writeabc(unsigned char *ip, unsigned char *tcp, unsigned char *opt, unsigned char *tdata ) {
struct packet tcpip;
unsigned int i,j;
unsigned char uu[1000];
j=0;
uu[j]=0x08;
j++;
uu[j]=0x00;
j++;
for(i=0;i<20;i++,j++) {
uu[j]=ip[i];
}
for(i=0;i<20;i++,j++) {
uu[j]=tcp[i];
}
if (opt != 0) {
for(i=0;i<4;i++,j++) {
uu[j]=opt[i];
}
}
if (tdata != 0) {
for(i=0;i<strlen(tdata);j++,i++) {
uu[j]=tdata[i];
}
}
for(i=0;i<j;i++) {
tcpip.data[i]=uu[i];
}
tcpip.packetsize=j;
sendit(&tcpip);
}
unsigned int ohtons(unsigned int h)
{
unsigned char h1,h2;
unsigned short h5;
h1 = (unsigned char ) h & 0xff;
h2 = (h >> 8)&0xff;
h5 = 256*h1 + h2 ;
return h5;
}
unsigned short checksum(unsigned short * ip1,unsigned int len) {
long sum = 0;
while ( len > 1) {
sum += *ip1++;
if ( sum & 0x80000000 )
sum = ( sum & 0xffff) + ( sum >> 16);
len -= 2;
}
while ( sum >> 16)
sum = ( sum & 0xffff) + ( sum >> 16);
return ~sum;
}
unsigned short tcpchecksum( unsigned char * tcp, unsigned char * o, unsigned int l, unsigned int lens ) {
unsigned char u[1000];
unsigned char *t;
struct dummytcp d;
unsigned short chksum;
unsigned int i,j;
unsigned short tcplen;
tcplen=l;
for(i=0;i<tcplen;i++) {
u[i]=tcp[i];
}
if(o != 0) {
tcplen=tcplen+lens;
for(j=0;j<lens;j++,i++)
u[i]=o[j];
}
l = tcplen;
d.src[0]=70;
d.src[1]=0;
d.src[2]=0;
d.src[3]=1;
d.dest[0]=70;
d.dest[1]=0;
d.dest[2]=0;
d.dest[3]=8;
d.u=0;
d.prot=6;
d.len=ohtons(l);
t=&d;
for (i = 0;i<=11;i++,l++) {
u[l] = t[i];
}
tcplen=l;
chksum=checksum( u,tcplen );
return chksum;
}
unsigned long ohtonl( unsigned long h ) {
unsigned char h1,h2,h3,h4;
unsigned long h5;
h1 = (unsigned char ) h & 0x000000ff;
h2 = (h >> 8)&0x000000ff;
h3 = (h >> 16) & 0x000000ff;
h4 = (h >> 24 ) & 0x000000ff;
h5 = ((long)1<<24)*h1 + h4 + h3*256 + h2*65536;
return h5;
}
int sendarpreply()
{
struct packet sendpkt1;
sendpkt1.data[0]=0x04;
sendpkt1.data[1]=0x01;
sendpkt1.data[2]=0x30;
sendpkt1.data[3]=0x16;
sendpkt1.data[4]=0x00;
sendpkt1.data[5]=0x00;
sendpkt1.data[6]=0x04;
sendpkt1.data[7]=0x01;
sendpkt1.data[8]=0x20;
sendpkt1.data[9]=0x45;
sendpkt1.data[10]=0x00;
sendpkt1.data[11]=0x00;
sendpkt1.data[12]=0x08;
sendpkt1.data[13]=0x06;
sendpkt1.data[14]=0x00;
sendpkt1.data[15]=0x01;
sendpkt1.data[16]=0x08;
sendpkt1.data[17]=0x00;
sendpkt1.data[18]=0x06;
sendpkt1.data[19]=0x04;
sendpkt1.data[20]=0x00;
sendpkt1.data[21]=0x02;
sendpkt1.data[22]=0x04;
sendpkt1.data[23]=0x01;
sendpkt1.data[24]=0x20;
sendpkt1.data[25]=0x45;
sendpkt1.data[26]=0x00;
sendpkt1.data[27]=0x00;
sendpkt1.data[28]=70;
sendpkt1.data[29]=0;
sendpkt1.data[30]=0;
sendpkt1.data[31]=1;
sendpkt1.data[32]=0x04;
sendpkt1.data[33]=0x01;
sendpkt1.data[34]=0x30;
sendpkt1.data[35]=0x16;
sendpkt1.data[36]=0x00;
sendpkt1.data[37]=0x00;
sendpkt1.data[38]=70;
sendpkt1.data[39]=0;
sendpkt1.data[40]=0;
sendpkt1.data[41]=8;
sendpkt1.packetsize=42;
for(i=0;i<sendpkt1.packetsize;i++)
{
abc(sendpkt1.data[i]);
printf("%x..",sendpkt1.data[i]);
}
a.h.ah = 4;
a.h.al=0;
a.x.si=FP_OFF(&sendpkt1.data);
s.ds=FP_SEG(&sendpkt1.data);
a.x.cx=sendpkt1.packetsize;
int86x(0x60,&a,&b,&s);
}
int sendlastack()
{
struct iphdr ip;
struct tcphdr tcp;
unsigned char sseq[4];
unsigned char aack[4];
unsigned long sno,ano;
ip.verlen =0x45;
ip.tos =0x0;
ip.totlen =ohtons(40);
ip.id =ohtons(3);
ip.frag =0;
ip.ttl =32;
ip.prot =0x6;
ip.chksum =0;
ip.sourceip[0] =70;
ip.sourceip[1] =0;
ip.sourceip[2] =0;
ip.sourceip[3] =1;
ip.destip[0] =70;
ip.destip[1] =0;
ip.destip[2] =0;
ip.destip[3] =8;
ip.chksum = checksum(&ip,20);
tcp.srcport=ohtons(1024);
tcp.destport=ohtons(80);
sseq[0]=e[42];
sseq[1]=e[43] ;
sseq[2]=e[44];
sseq[3]=e[45];
mysyn[0]=e[42];
mysyn[1]=e[43];
mysyn[2]=e[44];
mysyn[3]=e[45];
aack[0]=e[38];
aack[1]=e[39];
aack[2]=e[40];
aack[3]=e[41];
sno=oinetaddr(sseq);
ano=oinetaddr(aack);
ano++;
tcp.seqno=ohtonl(sno);
tcp.ackno=ohtonl(ano);
tcp.hdrlen=0x50;
tcp.flags=0x10;
tcp.win=ohtons(1024);
tcp.chksum=0;
tcp.urgptr=0;
tcp.chksum=tcpchecksum(&tcp,0,20,0);
writeabc(&ip,&tcp,0,0);
}
int sendget()
{
struct tcphdr tcp;
struct iphdr ip;
unsigned long seqno;
unsigned long ackno;
unsigned char sseq[4];
unsigned char aack[4];
unsigned char tcpdata[]="GET / HTTP 1.0\r\n\r\n";
sseq[0]=e[42];
sseq[1]=e[43] ;
sseq[2]=e[44];
sseq[3]=e[45];
aack[0]=e[38];
aack[1]=e[39];
aack[2]=e[40];
aack[3]=e[41];
seqno=oinetaddr(sseq);
ackno=oinetaddr(aack);
tcp.srcport=ohtons(1024);
tcp.destport=ohtons(80);
tcp.seqno=ohtonl(seqno);
tcp.ackno=ohtonl(ackno +1);
tcp.hdrlen=0x50;
tcp.flags=0x10;
tcp.win=ohtons(1024);
tcp.chksum=0;
tcp.urgptr=0;
tcp.chksum=tcpchecksum( &tcp,tcpdata,20,strlen(tcpdata ));
ip.verlen =0x45;
ip.tos =0x0;
ip.totlen =ohtons( 20 + 20 + strlen(tcpdata ));
ip.id =ohtons( 1 );
ip.frag =0x00;
ip.ttl =0x1f;
ip.prot =0x6;
ip.chksum =0;
ip.sourceip[0] =70;
ip.sourceip[1] =0;
ip.sourceip[2] =0;
ip.sourceip[3] =1;
ip.destip[0] =70;
ip.destip[1] =0;
ip.destip[2] =0;
ip.destip[3] =8;
ip.chksum =checksum( &ip,20 );
flag = 1;
writeabc( &ip,&tcp,0,&tcpdata );
}
int sendack()
{
struct iphdr ip;
struct tcphdr tcp;
unsigned char sseq[4];
unsigned char aack[4];
unsigned long sno,ano;
ip.verlen =0x45;
ip.tos =0x0;
ip.totlen =ohtons(40);
ip.id =ohtons(3);
ip.frag =0;
ip.ttl =32;
ip.prot =0x6;
ip.chksum =0;
ip.sourceip[0] =70;
ip.sourceip[1] =0;
ip.sourceip[2] =0;
ip.sourceip[3] =1;
ip.destip[0] =70;
ip.destip[1] =0;
ip.destip[2] =0;
ip.destip[3] =8;
ip.chksum = checksum(&ip,20);
tcp.srcport=ohtons(1024);
tcp.destport=ohtons(80);
sseq[0]=e[42];
sseq[1]=e[43] ;
sseq[2]=e[44];
sseq[3]=e[45];
aack[0]=e[38];
aack[1]=e[39];
aack[2]=e[40];
aack[3]=e[41];
sno=oinetaddr(sseq);
ano=oinetaddr(aack);
ano = ano +(((e[16]*256)+e[17])-40);
ano++;
tcp.seqno=ohtonl(sno);
tcp.ackno=ohtonl(ano);
tcp.hdrlen=0x50;
tcp.flags=0x10;
tcp.win=ohtons(1024) ;
tcp.chksum=0;
tcp.urgptr=0;
tcp.chksum=tcpchecksum(&tcp,0,20,0);
writeabc(&ip,&tcp,0,0);
}
void interrupt zzz(bp,di,si,ds,es,dx,cx,bx,ax,ip,cs,flags)
unsigned short bp,di,si,ds,es,dx,cx,bx,ax,ip,cs,flags;
{
printf("Receiver ax = %d Packet size = %d\n",ax,cx);
if (ax == 0)
{
es = FP_SEG(e);
di = FP_OFF(e);
ii = cx;
}
if (ax == 1)
{
for(i=0;i<=ii;i++)
{
abc(e[i]);
printf("%x..",e[i]);
}
if ( e[12] == 0x08 && e[13] == 0x06 && e[20] == 0x00 && e[21] == 0x01)
{
sendarpreply();
}
if (e[12]==0x08 && e[13]==0x00 && e[47]==18)
{
sendlastack();
}
if (e[42]==mysyn[0] && e[43] == mysyn[1] && e[44] == mysyn[2] && e[45] == mysyn[3])
{
sendget();
}
if(flag == 1 && (e[12]==0x08 && e[13]==0x00 && e[47]==0x18))
{
sendack();
}
if(flag == 1 && (e[12]==0x08 && e[13]==0x00 && e[47]==0x11))
{
printf("Fin Received");
}
}
abc('-'); abc('-'); abc('-');
}
void sendsyn()
{
struct tcphdr tcp;
struct iphdr ip;
unsigned char opt[4]={2,4,2,0};
tcp.srcport=ohtons(1024);
tcp.destport=ohtons(80);
tcp.seqno=ohtonl(5);
mysyn[0]=0;
mysyn[1]=0;
mysyn[2]=0;
mysyn[3]=5;
tcp.ackno=ohtonl(0);
tcp.hdrlen=0x60;
tcp.flags=0x2;
tcp.win=ohtons(1024);
tcp.chksum=0;
tcp.urgptr=0;
tcp.chksum=tcpchecksum(&tcp,opt,20,4);
ip.verlen =0x45;
ip.tos =0x0;
ip.totlen =ohtons(44);
ip.id =0;
ip.frag=0;
ip.ttl =32;
ip.prot =0x6;
ip.chksum =0;
ip.sourceip[0] =70;
ip.sourceip[1] =0;
ip.sourceip[2] =0;
ip.sourceip[3] =1;
ip.destip[0] =70;
ip.destip[1] =0;
ip.destip[2] =0;
ip.destip[3] =8;
ip.chksum =checksum(&ip,20);
writeabc(&ip,&tcp,&opt,0);
}
main()
{
segread(&s);
a.h.ah = 1;
a.h.al = 255;
int86x(0x60, &a, &b, &s);
printf("Carry Flag Driver Info - %d\n",b.x.cflag);
printf("Class - %d, Type - %d \n",b.h.ch, b.x.dx);
a.h.ah = 6;
a.x.cx = 6;
s.es = FP_SEG(ad);
a.x.di = FP_OFF(ad);
int86x(0x60, &a, &b, &s);
printf("Carry Flag Ethernet Address - %d\n",b.x.cflag);
printf("Address - %x: %x: %x: %x: %x: %x\n",ad[0],ad[1],ad[2],ad[3],ad[4],ad[5]);
a.h.al = 1;
a.x.bx = -1;
a.h.dl = 0;
a.x.cx = 0;
a.h.ah = 2;
s.es = FP_SEG(zzz);
a.x.di = FP_OFF(zzz);
c[0] = 0xff;
c[1] = 0xff;
s.ds = FP_SEG(c);
a.x.si = FP_OFF(c);
int86x(0x60, &a, &b, &s);
printf("Carry Flag Access Type - %d\n",b.x.cflag);
printf("Handle - %d\n",b.x.ax);
handle = b.x.ax;
a.h.ah = 21;
a.x.bx = handle;
int86x(0x60, &a, &b, &s);
printf("Get Recv Mode - %d\n",b.x.cflag);
printf("Receive Mode - %d\n",b.x.ax);
a.h.ah = 20;
a.x.bx = handle;
a.x.cx = 3;
int86x(0x60, &a, &b, &s);
printf("Carry Flag Set Recv Mode - %d\n",b.x.cflag);
sendsyn();
getch(); getch(); getch();
a.h.ah = 3;
a.x.bx = handle;
int86x(0x60, &a, &b, &s);
printf("Carry Flag Release Type - %d\n",b.x.cflag);
printf("OVER");
}
In TCP/IP, as
we've already explained in the TCP/IP tutorial, we have to keep ACKing packet
to assure the guy at the other end that we've received them intact and in good
time. The HTTP server too is anxious to please and if we don't ACK his data
often enough, he's going to keep resending it till he drops!
In the
function sendget(),we initialize the variable flag to 1. We do this cause we
later check this value in the if statement in zzz(). If the flag is on and we
receive an ACK packet or an ACK/PSH (PSH is a TCP flag called PUSH which
implies that the packet should be acted upon immediately. It is not necessary)
packet, we immediately count the number of bytes received and acknowledge them.
The acknowledgment field in the header will hold the number of bytes we have
received plus 1. The number of bytes we've received can be discovered by looking
at the length field in the IP header. The number must be converted from big
endian to little endian before use.
prog7.c
#include
<dos.h>
#include <stdio.h>
struct packet {
unsigned char data[1000];
unsigned int packetsize;
};
struct iphdr {
unsigned char verlen;
unsigned char tos;
unsigned short totlen;
unsigned short id;
unsigned short frag;
unsigned char ttl;
unsigned char prot;
unsigned short chksum;
unsigned char sourceip[4];
unsigned char destip[4];
};
struct tcphdr {
unsigned short srcport;
unsigned short destport;
unsigned long seqno;
unsigned long ackno;
unsigned char hdrlen;
unsigned char flags;
unsigned short win;
unsigned short chksum;
unsigned short urgptr;
};
struct dummytcp {
unsigned char src[4];
unsigned char dest[4];
char u;
char prot;
unsigned short len;
};
int ctr;
union REGS a,b;
struct SREGS s;
unsigned char ad[6],c[2],d[60];
unsigned char e[1000];
int handle , i, y, ii;
unsigned char mysyn[4];
int flag;
void abc(unsigned char p)
{
FILE *fp;
fp = fopen("D:\\z.txt","a+");
fprintf(fp,"..%x..%d..%c\n",p,p,p);
fclose(fp);
}
void sendit(struct packet * spacket)
{
union REGS regs;
struct SREGS sregs;
struct packet sendpkt;
unsigned int i,j;
sendpkt.data[0]=0x04;
sendpkt.data[1]=0x01;
sendpkt.data[2]=0x30;
sendpkt.data[3]=0x16;
sendpkt.data[4]=0;
sendpkt.data[5]=0;
sendpkt.data[6]=0x04;
sendpkt.data[7]=0x01;
sendpkt.data[8]=0x20;
sendpkt.data[9]=0x45;
sendpkt.data[10]=0x00;
sendpkt.data[11]=0x00;
for(j=12,i=0;i< spacket->packetsize;j++,i++) {
sendpkt.data[j]=spacket->data[i];
}
sendpkt.packetsize=j;
printf("\n");
for(i=0;i<sendpkt.packetsize;i++)
{
abc(sendpkt.data[i]);
printf("%x..",sendpkt.data[i]);
}
regs.h.ah = 4;
regs.h.al=0;
regs.x.si=FP_OFF(&sendpkt.data);
sregs.ds=FP_SEG(&sendpkt.data);
regs.x.cx=sendpkt.packetsize;
int86x(0x60,®s,®s,&sregs);
strset(e,0);
}
unsigned long oinetaddr( unsigned char data[] ) {
unsigned long h5;
h5=((((long)1<<24)*data[0])+(((long)1<<16)*data[1])+(((long)1<<8)*data[2])+(long)1*data[3]);
return h5;
}
void sendsyn();
void writeabc(unsigned char *ip, unsigned char *tcp, unsigned char *opt, unsigned char *tdata ) {
struct packet tcpip;
unsigned int i,j;
unsigned char uu[1000];
j=0;
uu[j]=0x08;
j++;
uu[j]=0x00;
j++;
for(i=0;i<20;i++,j++) {
uu[j]=ip[i];
}
for(i=0;i<20;i++,j++) {
uu[j]=tcp[i];
}
if (opt != 0) {
for(i=0;i<4;i++,j++) {
uu[j]=opt[i];
}
}
if (tdata != 0) {
for(i=0;i<strlen(tdata);j++,i++) {
uu[j]=tdata[i];
}
}
for(i=0;i<j;i++) {
tcpip.data[i]=uu[i];
}
tcpip.packetsize=j;
sendit(&tcpip);
}
unsigned int ohtons(unsigned int h)
{
unsigned char h1,h2;
unsigned short h5;
h1 = (unsigned char ) h & 0xff;
h2 = (h >> 8)&0xff;
h5 = 256*h1 + h2 ;
return h5;
}
unsigned short checksum(unsigned short * ip1,unsigned int len) {
long sum = 0;
while ( len > 1) {
sum += *ip1++;
if ( sum & 0x80000000 )
sum = ( sum & 0xffff) + ( sum >> 16);
len -= 2;
}
while ( sum >> 16)
sum = ( sum & 0xffff) + ( sum >> 16);
return ~sum;
}
unsigned short tcpchecksum( unsigned char * tcp, unsigned char * o, unsigned int l, unsigned int lens ) {
unsigned char u[1000];
unsigned char *t;
struct dummytcp d;
unsigned short chksum;
unsigned int i,j;
unsigned short tcplen;
tcplen=l;
for(i=0;i<tcplen;i++) {
u[i]=tcp[i];
}
if(o != 0) {
tcplen=tcplen+lens;
for(j=0;j<lens;j++,i++)
u[i]=o[j];
}
l = tcplen;
d.src[0]=70;
d.src[1]=0;
d.src[2]=0;
d.src[3]=1;
d.dest[0]=70;
d.dest[1]=0;
d.dest[2]=0;
d.dest[3]=8;
d.u=0;
d.prot=6;
d.len=ohtons(l);
t=&d;
for (i = 0;i<=11;i++,l++) {
u[l] = t[i];
}
tcplen=l;
chksum=checksum( u,tcplen );
return chksum;
}
unsigned long ohtonl( unsigned long h ) {
unsigned char h1,h2,h3,h4;
unsigned long h5;
h1 = (unsigned char ) h & 0x000000ff;
h2 = (h >> 8)&0x000000ff;
h3 = (h >> 16) & 0x000000ff;
h4 = (h >> 24 ) & 0x000000ff;
h5 = ((long)1<<24)*h1 + h4 + h3*256 + h2*65536;
return h5;
}
int sendarpreply()
{
struct packet sendpkt1;
sendpkt1.data[0]=0x04;
sendpkt1.data[1]=0x01;
sendpkt1.data[2]=0x30;
sendpkt1.data[3]=0x16;
sendpkt1.data[4]=0x00;
sendpkt1.data[5]=0x00;
sendpkt1.data[6]=0x04;
sendpkt1.data[7]=0x01;
sendpkt1.data[8]=0x20;
sendpkt1.data[9]=0x45;
sendpkt1.data[10]=0x00;
sendpkt1.data[11]=0x00;
sendpkt1.data[12]=0x08;
sendpkt1.data[13]=0x06;
sendpkt1.data[14]=0x00;
sendpkt1.data[15]=0x01;
sendpkt1.data[16]=0x08;
sendpkt1.data[17]=0x00;
sendpkt1.data[18]=0x06;
sendpkt1.data[19]=0x04;
sendpkt1.data[20]=0x00;
sendpkt1.data[21]=0x02;
sendpkt1.data[22]=0x04;
sendpkt1.data[23]=0x01;
sendpkt1.data[24]=0x20;
sendpkt1.data[25]=0x45;
sendpkt1.data[26]=0x00;
sendpkt1.data[27]=0x00;
sendpkt1.data[28]=70;
sendpkt1.data[29]=0;
sendpkt1.data[30]=0;
sendpkt1.data[31]=1;
sendpkt1.data[32]=0x04;
sendpkt1.data[33]=0x01;
sendpkt1.data[34]=0x30;
sendpkt1.data[35]=0x16;
sendpkt1.data[36]=0x00;
sendpkt1.data[37]=0x00;
sendpkt1.data[38]=70;
sendpkt1.data[39]=0;
sendpkt1.data[40]=0;
sendpkt1.data[41]=8;
sendpkt1.packetsize=42;
printf("\n");
for(i=0;i<sendpkt1.packetsize;i++)
{
abc(sendpkt1.data[i]);
printf("%x..",sendpkt1.data[i]);
}
a.h.ah = 4;
a.h.al=0;
a.x.si=FP_OFF(&sendpkt1.data);
s.ds=FP_SEG(&sendpkt1.data);
a.x.cx=sendpkt1.packetsize;
int86x(0x60,&a,&b,&s);
}
int sendlastack()
{
struct iphdr ip;
struct tcphdr tcp;
unsigned char sseq[4];
unsigned char aack[4];
unsigned long sno,ano;
ip.verlen =0x45;
ip.tos =0x0;
ip.totlen =ohtons(40);
ip.id =ohtons(3);
ip.frag =0;
ip.ttl =32;
ip.prot =0x6;
ip.chksum =0;
ip.sourceip[0] =70;
ip.sourceip[1] =0;
ip.sourceip[2] =0;
ip.sourceip[3] =1;
ip.destip[0] =70;
ip.destip[1] =0;
ip.destip[2] =0;
ip.destip[3] =8;
ip.chksum = checksum(&ip,20);
tcp.srcport=ohtons(1024);
tcp.destport=ohtons(80);
sseq[0]=e[42];
sseq[1]=e[43] ;
sseq[2]=e[44];
sseq[3]=e[45];
mysyn[0]=e[42];
mysyn[1]=e[43];
mysyn[2]=e[44];
mysyn[3]=e[45];
aack[0]=e[38];
aack[1]=e[39];
aack[2]=e[40];
aack[3]=e[41];
sno=oinetaddr(sseq);
ano=oinetaddr(aack);
ano++;
tcp.seqno=ohtonl(sno);
tcp.ackno=ohtonl(ano);
tcp.hdrlen=0x50;
tcp.flags=0x10;
tcp.win=ohtons(1024);
tcp.chksum=0;
tcp.urgptr=0;
tcp.chksum=tcpchecksum(&tcp,0,20,0);
writeabc(&ip,&tcp,0,0);
}
int sendget()
{
struct tcphdr tcp;
struct iphdr ip;
unsigned long seqno;
unsigned long ackno;
unsigned char sseq[4];
unsigned char aack[4];
unsigned char tcpdata[]="GET / HTTP 1.0\r\n\r\n";
sseq[0]=e[42];
sseq[1]=e[43] ;
sseq[2]=e[44];
sseq[3]=e[45];
aack[0]=e[38];
aack[1]=e[39];
aack[2]=e[40];
aack[3]=e[41];
seqno=oinetaddr(sseq);
ackno=oinetaddr(aack);
tcp.srcport=ohtons(1024);
tcp.destport=ohtons(80);
tcp.seqno=ohtonl(seqno);
tcp.ackno=ohtonl(ackno +1);
tcp.hdrlen=0x50;
tcp.flags=0x10;
tcp.win=ohtons(1024);
tcp.chksum=0;
tcp.urgptr=0;
tcp.chksum=tcpchecksum( &tcp,tcpdata,20,strlen(tcpdata ));
ip.verlen =0x45;
ip.tos =0x0;
ip.totlen =ohtons( 20 + 20 + strlen(tcpdata ));
ip.id =ohtons( 1 );
ip.frag =0x00;
ip.ttl =0x1f;
ip.prot =0x6;
ip.chksum =0;
ip.sourceip[0] =70;
ip.sourceip[1] =0;
ip.sourceip[2] =0;
ip.sourceip[3] =1;
ip.destip[0] =70;
ip.destip[1] =0;
ip.destip[2] =0;
ip.destip[3] =8;
ip.chksum =checksum( &ip,20 );
flag = 1;
writeabc( &ip,&tcp,0,&tcpdata );
}
int sendack()
{
struct iphdr ip;
struct tcphdr tcp;
unsigned char sseq[4];
unsigned char aack[4];
unsigned long sno,ano;
ip.verlen =0x45;
ip.tos =0x0;
ip.totlen =ohtons(40);
ip.id =ohtons(3);
ip.frag =0;
ip.ttl =32;
ip.prot =0x6;
ip.chksum =0;
ip.sourceip[0] =70;
ip.sourceip[1] =0;
ip.sourceip[2] =0;
ip.sourceip[3] =1;
ip.destip[0] =70;
ip.destip[1] =0;
ip.destip[2] =0;
ip.destip[3] =8;
ip.chksum = checksum(&ip,20);
tcp.srcport=ohtons(1024);
tcp.destport=ohtons(80);
sseq[0]=e[42];
sseq[1]=e[43] ;
sseq[2]=e[44];
sseq[3]=e[45];
aack[0]=e[38];
aack[1]=e[39];
aack[2]=e[40];
aack[3]=e[41];
sno=oinetaddr(sseq);
ano=oinetaddr(aack);
ano = ano +(((e[16]*256)+e[17])-40);
tcp.seqno=ohtonl(sno);
tcp.ackno=ohtonl(ano);
tcp.hdrlen=0x50;
tcp.flags=0x10;
tcp.win=ohtons(1024) ;
tcp.chksum=0;
tcp.urgptr=0;
tcp.chksum=tcpchecksum(&tcp,0,20,0);
writeabc(&ip,&tcp,0,0);
}
int sendfin()
{
struct iphdr ip;
struct tcphdr tcp;
unsigned char sseq[4];
unsigned char aack[4];
unsigned long sno,ano;
ip.verlen =0x45;
ip.tos =0x0;
ip.totlen =ohtons(40);
ip.id =ohtons(3);
ip.frag =0;
ip.ttl =32;
ip.prot =0x6;
ip.chksum =0;
ip.sourceip[0] =70;
ip.sourceip[1] =0;
ip.sourceip[2] =0;
ip.sourceip[3] =1;
ip.destip[0] =70;
ip.destip[1] =0;
ip.destip[2] =0;
ip.destip[3] =8;
ip.chksum = checksum(&ip,20);
tcp.srcport=ohtons(1024);
tcp.destport=ohtons(80);
sseq[0]=e[42];
sseq[1]=e[43] ;
sseq[2]=e[44];
sseq[3]=e[45];
aack[0]=e[38];
aack[1]=e[39];
aack[2]=e[40];
aack[3]=e[41];
sno=oinetaddr(sseq);
ano=oinetaddr(aack);
ano++;
tcp.seqno=ohtonl(sno);
tcp.ackno=ohtonl(ano);
tcp.hdrlen=0x50;
tcp.flags=0x01;
tcp.win=ohtons(1024) ;
tcp.chksum=0;
tcp.urgptr=0;
tcp.chksum=tcpchecksum(&tcp,0,20,0);
writeabc(&ip,&tcp,0,0);
}
void interrupt zzz(bp,di,si,ds,es,dx,cx,bx,ax,ip,cs,flags)
unsigned short bp,di,si,ds,es,dx,cx,bx,ax,ip,cs,flags;
{
printf("\nReceiver ax = %d Packet size = %d\n",ax,cx);
if (ax == 0)
{
es = FP_SEG(e);
di = FP_OFF(e);
ii = cx;
}
if (ax == 1)
{
for(i=0;i<=ii;i++)
{
abc(e[i]);
printf("%x..",e[i]);
}
if ( e[12] == 0x08 && e[13] == 0x06 && e[20] == 0x00 && e[21] == 0x01)
{
sendarpreply();
}
if (e[12]==0x08 && e[13]==0x00 && e[47]==18)
{
sendlastack();
}
if (e[42]==mysyn[0] && e[43] == mysyn[1] && e[44] == mysyn[2] && e[45] == mysyn[3])
{
sendget();
}
if(flag == 1 && (e[12]==0x08 && e[13]==0x00 && e[47]==0x18))
{
sendack();
}
if(flag == 1 && (e[12]==0x08 && e[13]==0x00 && e[47]==0x11))
{
sendfin();
}
}
abc('-'); abc('-'); abc('-');
}
void sendsyn()
{
struct tcphdr tcp;
struct iphdr ip;
unsigned char opt[4]={2,4,2,0};
tcp.srcport=ohtons(1024);
tcp.destport=ohtons(80);
tcp.seqno=ohtonl(5);
mysyn[0]=0;
mysyn[1]=0;
mysyn[2]=0;
mysyn[3]=5;
tcp.ackno=ohtonl(0);
tcp.hdrlen=0x60;
tcp.flags=0x2;
tcp.win=ohtons(1024);
tcp.chksum=0;
tcp.urgptr=0;
tcp.chksum=tcpchecksum(&tcp,opt,20,4);
ip.verlen =0x45;
ip.tos =0x0;
ip.totlen =ohtons(44);
ip.id =0;
ip.frag=0;
ip.ttl =32;
ip.prot =0x6;
ip.chksum =0;
ip.sourceip[0] =70;
ip.sourceip[1] =0;
ip.sourceip[2] =0;
ip.sourceip[3] =1;
ip.destip[0] =70;
ip.destip[1] =0;
ip.destip[2] =0;
ip.destip[3] =8;
ip.chksum =checksum(&ip,20);
writeabc(&ip,&tcp,&opt,0);
}
main()
{
segread(&s);
a.h.ah = 1;
a.h.al = 255;
int86x(0x60, &a, &b, &s);
printf("Carry Flag Driver Info - %d\n",b.x.cflag);
printf("Class - %d, Type - %d \n",b.h.ch, b.x.dx);
a.h.ah = 6;
a.x.cx = 6;
s.es = FP_SEG(ad);
a.x.di = FP_OFF(ad);
int86x(0x60, &a, &b, &s);
printf("Carry Flag Ethernet Address - %d\n",b.x.cflag);
printf("Address - %x: %x: %x: %x: %x: %x\n",ad[0],ad[1],ad[2],ad[3],ad[4],ad[5]);
a.h.al = 1;
a.x.bx = -1;
a.h.dl = 0;
a.x.cx = 0;
a.h.ah = 2;
s.es = FP_SEG(zzz);
a.x.di = FP_OFF(zzz);
c[0] = 0xff;
c[1] = 0xff;
s.ds = FP_SEG(c);
a.x.si = FP_OFF(c);
int86x(0x60, &a, &b, &s);
printf("Carry Flag Access Type - %d\n",b.x.cflag);
printf("Handle - %d\n",b.x.ax);
handle = b.x.ax;
a.h.ah = 21;
a.x.bx = handle;
int86x(0x60, &a, &b, &s);
printf("Get Recv Mode - %d\n",b.x.cflag);
printf("Receive Mode - %d\n",b.x.ax);
a.h.ah = 20;
a.x.bx = handle;
a.x.cx = 3;
int86x(0x60, &a, &b, &s);
printf("Carry Flag Set Recv Mode - %d\n",b.x.cflag);
sendsyn();
getch(); getch(); getch();
a.h.ah = 3;
a.x.bx = handle;
int86x(0x60, &a, &b, &s);
printf("Carry Flag Release Type - %d\n",b.x.cflag);
printf("OVER");
}
When all the
bytes have been sent across, the server send a FIN. This means it turns on the
FIN flag in the TCP flag field and sends us the packet. When we receive the
Fin, we increment the acknowledgment field by one, set the FIN flag on and then
ACK the packet. That just about covers TCP/IP over an Ethernet network.