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 a shareware Web server like O'Rielly's WebSite; it's what we used. Set up your Windows 95 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 95 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 the 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've already written.
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.
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)...2d..45 ..2d..45 ..2d..45
..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.
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.
z.txt
Packet Sent ..4..4 ..1..1 ..30..48 ..16..22 ..0..0 ..0..0 ..4..4 ..1..1 ..20..32 ..45..69 ..0..0 ..0..0 ..8..8 ..0..0 ..45..69 ..0..0 ..0..0 ..2c..44 ..2e..46 ..0..0 ..40..64 ..0..0 ..20..32 ..6..6 ..a0..160 ..c3..195 ..46..70 ..0..0 ..0..0 ..1..1 ..46..70 ..0..0 ..0..0 ..8..8 ..4..4 ..0..0 ..0..0 ..50..80 ..0..0 ..0..0 ..0..0 ..5..5 ..0..0 ..0..0 ..0..0 ..0..0 ..60..96 ..2..2 ..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 ..ff..255 ..ff..255 ..ff..255 ..ff..255 ..ff..255 ..4..4 ..1..1 ..30..48 ..16..22 ..0..0 ..0..0 ..8..8 ..6..6 ..0..0 ..1..1 ..8..8 ..0..0 ..6..6 ..4..4 ..0..0 ..1..1 ..4..4 ..1..1 ..30..48 ..16..22 ..0..0 ..0..0 ..46..70 ..0..0 ..0..0 ..8..8 ..0..0 ..0..0 ..0..0 ..0..0 ..0..0 ..0..0 ..46..70 ..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 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 ARP Packet ..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 Reply ..2..2 ..4..4 Source Ethernet Address ..1..1 ..20..32 ..45..69 ..0..0 ..0..0 ..46..70 Source IP Address ..0..0 ..0..0 ..1..1 ..4..4 Destination Ethernet Address ..1..1 ..30..48 ..16..22 ..0..0 ..0..0 ..46..70 Destination IP Address ..0..0 ..0..0 ..8..8 ..2d..45 ..2d..45 ..2d..45 ..2d..45 ..2d..45 ..2d..45 Packet Received ..4..4 Destination Ethernet Address ..1..1 ..20..32 ..45..69 ..0..0 ..0..0 ..4..4 Source Ethernet Address ..1..1 ..30..48 ..16..22 ..0..0 ..0..0 ..8..8 IP TYPE ..0..0 ..45..69 IP Packet ..0..0 ..0..0 ..2c..44 ..15..21 ..0..0 ..40..64 ..0..0 ..20..32 ..6..6 ..b9..185 ..c3..195 ..46..70 ..0..0 ..0..0 ..8..8 ..46..70 ..0..0 ..0..0 ..1..1 ..0..0 TCP Packet ..50..80 ..4..4 ..0..0 ..0..0 Sequence No.. 0 12 23 6f ..12..18 ..23..35 ..6f..111 ..0..0 Ack No. 0 0 0 6 ..0..0 ..0..0 ..6..6 ..60..96 ..12..18 SYN/ACK ..20..32 ..0..0 ..c4..196 ..36..54 ..0..0 ..0..0 ..2..2 ..4..4 ..5..5 ..b4..180 ..20..32 ..20..32 ..0..0 ..2d..45 ..2d..45 ..2d..45
The ARP request, reply and SYN/ACK packet are presented here is one big confusing file. Read it at leisure.
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.
z.txt
Packet Sent ..4..4 ..1..1 ..30..48 ..16..22 ..0..0 ..0..0 ..4..4 ..1..1 ..20..32 ..45..69 ..0..0 ..0..0 ..8..8 ..0..0 ..45..69 ..0..0 ..0..0 ..2c..44 ..0..0 ..0..0 ..0..0 ..0..0 ..20..32 ..6..6 ..e..14 ..c4..196 ..46..70 ..0..0 ..0..0 ..1..1 ..46..70 ..0..0 ..0..0 ..8..8 ..4..4 ..0..0 ..0..0 ..50..80 ..0..0 ..0..0 ..0..0 ..5..5 ..0..0 ..0..0 ..0..0 ..0..0 ..60..96 ..2..2 ..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 ..ff..255 ..ff..255 ..ff..255 ..ff..255 ..ff..255 ..4..4 ..1..1 ..30..48 ..16..22 ..0..0 ..0..0 ..8..8 ..6..6 ..0..0 ..1..1 ..8..8 ..0..0 ..6..6 ..4..4 ..0..0 ..1..1 ..4..4 ..1..1 ..30..48 ..16..22 ..0..0 ..0..0 ..46..70 ..0..0 ..0..0 ..8..8 ..0..0 ..0..0 ..0..0 ..0..0 ..0..0 ..0..0 ..46..70 ..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 Packet Sent ..4..4 ..1..1 ..30..48 ..16..22 ..0..0 ..0..0 ..4..4 ..1..1 ..20..32 ..45..69 ..0..0 ..0..0 ..8..8 ..6..6 ..0..0 ..1..1 ..8..8 ..0..0 ..6..6 ..4..4 ..0..0 ..2..2 ..4..4 ..1..1 ..20..32 ..45..69 ..0..0 ..0..0 ..46..70 ..0..0 ..0..0 ..1..1 ..4..4 ..1..1 ..30..48 ..16..22 ..0..0 ..0..0 ..46..70 ..0..0 ..0..0 ..8..8 ..2d..45 ..2d..45 ..2d..45 ..2d..45 ..2d..45 ..2d..45 Packet Received ..4..4 ..1..1 ..20..32 ..45..69 ..0..0 ..0..0 ..4..4 ..1..1 ..30..48 ..16..22 ..0..0 ..0..0 ..8..8 ..0..0 ..45..69 ..0..0 ..0..0 ..2c..44 ..1..1 ..0..0 ..40..64 ..0..0 ..20..32 ..6..6 ..cd..205 ..c3..195 ..46..70 ..0..0 ..0..0 ..8..8 ..46..70 ..0..0 ..0..0 ..1..1 ..0..0 ..50..80 ..4..4 ..0..0 ..0..0 Seq No. 0 1 1b de ..1..1 ..1b..27 ..de..222 ..0..0 Ack No. 0 0 0 6 ..0..0 ..0..0 ..6..6 ..60..96 ..12..18 SYN/ACK ..20..32 ..0..0 ..cb..203 ..d8..216 ..0..0 ..0..0 ..2..2 ..4..4 ..5..5 ..b4..180 ..20..32 ..20..32 ..0..0 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 Type ..0..0 ..45..69 IP Packet ..0..0 ..0..0 ..28..40 ..0..0 ..3..3 ..0..0 ..0..0 ..20..32 ..6..6 ..e..14 ..c5..197 ..46..70 ..0..0 ..0..0 ..1..1 ..46..70 ..0..0 ..0..0 ..8..8 ..4..4 TCP Packet ..0..0 ..0..0 ..50..80 ..0..0 Seq No. 0 0 0 6 ..0..0 ..0..0 ..6..6 ..0..0 Ack No. 0 1 1b df ..1..1 ..1b..27 ..df..223 ..50..80 ..10..16 Ack ..4..4 ..0..0 ..ff..255 ..95..149 ..0..0 ..0..0 ..2d..45 ..2d..45 ..2d..45
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!!
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.. ..2c..44.., ..0..0.. ..0..0.. ..0..0.. ..0..0.. ..20..32.. ..6..6.. ..e..14.. ..c4..196..Ä ..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.. ..0..0.. ..0..0.. ..5..5.. ..0..0.. ..0..0.. ..0..0.. ..0..0.. ..60..96..` ..2..2.. ..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..ÿ ..ff..255..ÿ ..ff..255..ÿ ..ff..255..ÿ ..ff..255..ÿ ..ff..255..ÿ ..4..4.. ..1..1.. ..30..48..0 ..16..22.. ..0..0.. ..0..0.. ..8..8.. ..6..6.. ..0..0.. ..1..1.. ..8..8.. ..0..0.. ..6..6.. ..4..4.. ..0..0.. ..1..1.. ..4..4.. ..1..1.. ..30..48..0 ..16..22.. ..0..0.. ..0..0.. ..46..70..F ..0..0.. ..0..0.. ..8..8.. ..0..0.. ..0..0.. ..0..0.. ..0..0.. ..0..0.. ..0..0.. ..46..70..F ..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.. 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.. ..6..6.. ..0..0.. ..1..1.. ..8..8.. ..0..0.. ..6..6.. ..4..4.. ..0..0.. ..2..2.. ..4..4.. ..1..1.. ..20..32.. ..45..69..E ..0..0.. ..0..0.. ..46..70..F ..0..0.. ..0..0.. ..1..1.. ..4..4.. ..1..1.. ..30..48..0 ..16..22.. ..0..0.. ..0..0.. ..46..70..F ..0..0.. ..0..0.. ..8..8.. ..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.. ..2c..44.., ..1..1.. ..0..0.. ..40..64..@ ..0..0.. ..20..32.. ..6..6.. ..cd..205..Í ..c3..195..Ã ..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 48 ..1..1.. ..51..81..Q ..48..72..H ..0..0.. Ack No. 0 0 0 6 ..0..0.. ..0..0.. ..6..6.. ..60..96..` ..12..18.. SYN/ACK ..20..32.. ..0..0.. ..96..150..– ..6e..110..n ..0..0.. ..0..0.. ..2..2.. ..4..4.. ..5..5.. ..b4..180..´ ..20..32.. ..20..32.. ..0..0.. 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.. ..28..40..( ..0..0.. ..3..3.. ..0..0.. ..0..0.. ..20..32.. ..6..6.. ..e..14.. ..c5..197..Å ..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.. ACK ..4..4.. ..0..0.. ..ca..202..Ê ..2b..43..+ ..0..0.. ..0..0.. 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.. ..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.
z.txt
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 cover TCP/IP over an Ethernet network, click on this word to jump to the tutorial on TCP/IP using PPP or the Point to Point Protocol
Mr. Vijay Mukhi
Ms. Sonal Kotecha
Mr. Arsalan Zaidi
Mr. Rajkumar Ganesan
Vijay Mukhi's Computer
Institute
VMCI, B-13, Everest Building, Tardeo, Mumbai 400 034, India
Tel : 91-22-496 4335 /6/7/8/9
Fax : 91-22-307 28 59
e-mail : vmukhi@giasbm01.vsnl.net.in
http://www.vijaymukhi.com