This document contains two DNS client-side code snippets in C/C++. The first code snippet handles DNS queries from the user, formats the query properly, and sends it to the DNS server. It then receives and analyzes the response. The second code snippet focuses on analyzing the DNS response packet by examining specific bits and fields to determine status and errors.
1. //2 codes, as presented to Dr. Amjad<br />//client side<br />#include quot;
stdafx.hquot;
<br />#ifndef unix<br />#define WIN32<br />#include <windows.h><br />#include <winsock.h><br />#include <io.h><br />#else<br />#define closesocket close<br />#include <sys/types.h><br />#include <sys/socket.h><br />#include <netinet/in.h><br />#include <arpa/inet.h><br />#include <netdb.h><br />#endif<br />#include <stdio.h><br />#include <string.h><br />#define PROTOPORT 53 /* default protocol port number */<br /> <br />char ServerIP[] = quot;
127.0.0.3quot;
;<br />void analyse_response(char* response);<br />void main() //here we will get what the user wants, then we will reformat what he typed in a useful DNS query<br />{<br /> struct hostent *IPAddrServer;/* pointer to a host table entry */<br /> struct protoent *UDP_Protocol; /* pointer to a protocol table entry */<br /> struct sockaddr_in SockAddrInToServer, SockAddrInFromServer; /*IP, port, family*/<br /> int ClientSocket; /* socket descriptor */<br /> int port; /* protocol port number */<br /> char *host; /* pointer to host name */<br /> int n,i; /* number of characters read */<br />char response[512]={''}; <br />char buf[512]={''},b1[255]; /* b1 buffer for data from the user. buf is the good reformatting for DNS usage *//*size of 'buf' and 'response' should be bigger than 512, as a max UDP message should*/<br />#ifdef WIN32<br /> WSADATA wsaData;<br /> WSAStartup(0x0101, &wsaData);<br />#endif<br /> memset((char *)&SockAddrInToServer,0,sizeof(SockAddrInToServer));/* clear client sockaddr structure */<br /> SockAddrInToServer.sin_family = AF_INET;/* set family to Internet */<br /> port = PROTOPORT; <br /> SockAddrInToServer.sin_port = htons((u_short)port);/* set port number */<br /> /* Convert host name to equivalent IP address and copy to SockAddrInToServer. */<br />host = ServerIP;<br /> IPAddrServer = gethostbyname(host);//now here comes a new worker thread...<br /> if ( ((char *)IPAddrServer) == NULL ) <br />{<br /> fprintf(stderr,quot;
invalid host: %squot;
, host);<br /> getchar();<br /> exit(1);<br /> }<br /> memcpy(&SockAddrInToServer.sin_addr, IPAddrServer->h_addr, IPAddrServer->h_length);<br /> /* Map UDP transport protocol name to protocol number. */<br /> if ( ((int)(UDP_Protocol = getprotobyname(quot;
udpquot;
))) == 0) <br />{<br /> fprintf(stderr, quot;
cannot map "
udp"
to protocol numberquot;
);<br /> getchar();<br /> exit(1);<br /> }<br /> /* Create a socket. */<br /> ClientSocket = socket(PF_INET, SOCK_DGRAM, UDP_Protocol->p_proto);<br /> if (ClientSocket < 0) <br />{<br /> fprintf(stderr, quot;
socket creation failedquot;
);<br /> getchar();<br /> exit(1);<br /> }<br />printf(quot;
You can start by requesting the DNS server.quot;
);<br />char b2[255]; /* b2 is to get the hotmail, com, yahoo, mail, msn, ... from user input */<br />int j, k, t, l, firstpart;<br />char question[255]={''}; //so strlen(question)==0<br />int h = sizeof(struct sockaddr);<br />char header[255]={0,0,1,0,0,1,0,0,0,0,0,0}; //this is our desired header, but the last 0's won't be distinguished from the remaining of the of header, because all the remaining is also 0 or ''<br />unsigned short id_short = 0;<br />char *id;<br />id=(char*) &id_short;<br />int how_many_times = 0;<br />while(1)<br />{<br />how_many_times++;<br />printf(quot;
your number %d request, please:quot;
,how_many_times);<br />for (i=0;i<255;i++) //this is for cleaning, we clean many arrays.<br />b1[i]=0;<br /> <br />scanf(quot;
%squot;
,&b1); //assuming something like www.hotmail.com<br />//gets(b1); //also we can use gets<br />//The following is the reformatting of b1 in order to make a useful DNS query<br />//making the header<br />header[0] = *(id+1);<br />header[1] = *id;<br />//your header is made of 12 elements<br />//there you go your wonderful header<br />//now, making the Question<br />for (i=0; i<255; i++)<br />question[i] = 0;<br />for (i=0; i<255; i++)<br />b2[i] = 0;<br />i=0; j=0; k=0; t=0; l=0; firstpart=0;<br />while(i<strlen(b1)+1)<br />{if (0==strlen(b1) || b1[0]=='.') <br />break; <br />if (b1[i-1]=='.' && b1[i]!='.')<br />j=i;<br />if (b1[i]=='.' || b1[i]=='')<br />{<br />for(t=0; t<255; t++)<br />b2[t]=0; //not '0' <br />t=0;<br />for (k=j; k<i; k++)<br />{<br />b2[t]=b1[k];<br />t++;<br />}<br />question[strlen(question)]=t; //feeling safe that no truncated part like www or hotmail would be longer than 63! because the upper 2 bits of this specific byte must be 0's <br />strcat(question,b2);<br />}<br />i++;<br />}<br />if (strlen(question)>255) //the idea of this condition could be found in page 9 in RFC 1035<br />{<br />printf(quot;
The name you entered must be smaller. You can retry. Thanksquot;
);<br />break;<br />}<br />//of course there is the 'root' left, which is a null byte. simply the strlen(question) would be itself + 1 <br />//now let's add QType and QClass<br />question[strlen(question)+2]=1;<br />question[strlen(question)+4]=1;<br />//there you go your wonderful Question made of strlen(question) + 5 elements.<br />//now putting everything together in buf<br />for (i=0; i<12; i++)//10 is the lengh of the header<br />buf[i]=header[i];<br />for (i=12; i < (strlen(question)+17); i++)<br />buf[i]=question[i-12];<br />if (strlen(buf)>512) //the idea of this condition is from page 31 of RFC 1035<br />{<br />//in fact it's the whole UDP message and not only the entered name<br />printf(quot;
The name you entered must be smaller. You can retry. Thanksquot;
);<br />break;<br />}<br />n = sendto(ClientSocket, buf, sizeof(buf), 0,(sockaddr *)&SockAddrInToServer,h);<br />for (i=0; i<512; i++)<br />buf[i]=0;<br />for (i=0;i<512;i++)<br />response[i]=0;<br />n = recvfrom(ClientSocket, response, sizeof(response), 0, (sockaddr *)&SockAddrInFromServer,&h);<br />analyse_response(response);<br />id_short++;<br />//if (id_short==2^16-1)<br />}<br /> /* Close the socket. */<br /> closesocket(ClientSocket);<br /> /* Terminate the client program gracefully. */<br />getchar();<br /> exit(0);<br />}<br />void analyse_response(char* response)<br />{<br />char aa1 = response[0]; //we want to interchange the values of header id bytes. The final aim of this is to have a correct value of id_short<br />response[0] = response[1];<br />response[1]= aa1;<br />unsigned short *id_short;<br />id_short=(unsigned short*) response;<br />//we can get them back as before, but why bother.<br />printf(quot;
The gathered info for your number %d request are the following:quot;
,*id_short + 1);//one limitation of using id_short is that user here tries more than (2^16 - 1) times, so the 2^16 th time would be 0 not 2^16. <br />if ((response[2]&2)==2) printf(quot;
Message is truncated, so we're expecting a malicious resultquot;
); //we mean here: header->third byte->second bit<br />if ((response[3]&128)==0) printf(quot;
Expecting a malicious result, since resursion was not availablequot;
);<br />if ((response[3]&16)==16) printf(quot;
Expecting a malicious result, since there was a format errorquot;
);<br />if ((response[3]&32)==32) printf(quot;
Server Failurequot;
);//because of this case, you may create in the DNS server another socket for clients complains...<br />if ((response[3]&48)==48) printf(quot;
Name errorquot;
);<br />if ((response[3]&64)==64) printf(quot;
Not Implementedquot;
);<br />if ((response[3]&80)==80) printf(quot;
Server refused to perform operationquot;
);<br />unsigned short ANCOUNT = *(response + 7);<br />//now, determining the end of the question section <br />char a = 1;//here I want whatever value <br />int End_Of_Question = 12;<br />while (a!=0)<br />{<br />a = response[End_Of_Question];<br />End_Of_Question++;<br />}//now End_Of_Question is the first byte of QTYPE<br />End_Of_Question = End_Of_Question + 4;<br />//now End Of question section is reached, and End_Of_Question is the first byte in the Answer section<br />//now beginnig with the Answer section<br />int nameLengh = 0;<br />char *name = response + End_Of_Question; //quot;
namequot;
belongs to NAME, not to the question section <br />while(*(name + nameLengh)!=0)//no need to this loop, but no harm<br />nameLengh++;<br />// the 0 value of *(name + nameLengh) could have 2 meanings, it may belong to NAME (e.g in case no compression) or to TYPE (e.g in case of compression so we don't need a 0 in NAME because it would be mentionned in the QNAME, and from another hand the higher order byte of TYPE is 0 because values of TYPE goes from 1 to 16)<br />char *b = name; //b will pass over all the response <br />short count=0;<br />while (count < ANCOUNT)<br />{<br />count++;<br />char NAME_field[512]={''};<br />int ii=0;<br />for (ii=0;ii<512;ii++)//cleaning NAME_field<br />NAME_field[ii]=0;<br />int NAME_field_lengh = 0;<br />int name1Lengh;<br />while ( ((*b & 192) != 192) && (*b != 0) ) //in this loop: no compression. The condition (*b != 0) is not meant for the first time we enter the loop; it's meant if there was no pointer and the 0 exits explicitly in NAME. I don't know if the 0 _in case it appeared here_ could not belong to NAME.<br />{//192 in binary is 11000000<br />name1Lengh = 0;<br />while(name1Lengh<*b)<br />{<br />NAME_field[NAME_field_lengh + name1Lengh] = *(b + name1Lengh + 1);<br />name1Lengh++;<br />}<br />NAME_field_lengh = NAME_field_lengh + name1Lengh;<br />NAME_field[NAME_field_lengh]='.';<br />NAME_field_lengh++;<br />b = b + *b + 1;<br />}<br />//now in case we have a pointer<br />char *name1 = b;//this assigement in case there is a pointer inside a pointer (or more generally pointer inside a pointer inside a pointer inside ..., and for this general case we made name2)<br />while (((*name1 & 192) == 192) )<br />{<br />char ab[3];<br />ab[0] = *(name1 + 1);<br />ab[1] = *name1 & 63; //63 in binary is 00111111<br />unsigned short *pointer_value = (unsigned short*) ab;<br />//char * name2 = name1;<br />name1 = response + *pointer_value;<br />while((*name1)!=0 && (*name1 & 192)!=192) //the condition is for the case if inside one pointer there is another pointer to somewhere else<br />{<br />name1Lengh = 0;<br />while (name1Lengh < (*name1) )<br />{<br />NAME_field[NAME_field_lengh + name1Lengh] = *(name1 + name1Lengh + 1);<br />name1Lengh++;<br />}<br />name1 = name1 + *name1 + 1;<br />NAME_field_lengh = NAME_field_lengh + name1Lengh;<br />NAME_field[NAME_field_lengh]='.';<br />NAME_field_lengh++;<br />}<br />//name2 = name2 + 2;//this is not needed since we assume that after a pointer there is no useful info to add to NAME_field, and surely some more code should be added and we may use recursivity<br />}<br />if (name1 != b)//this means we entered the pointer loop<br />b = b + 2;<br />//now beginning with TYPE<br />//now *b = 0<br />if (*(b+1)==0)//means b is part of NAME and represents root<br />b=b+1;<br />//now b is part of TYPE<br />char TYPE[10]={''};<br />switch ( *(b+1) )<br />{<br /> case 1:<br /> TYPE[0]='A';<br /> break;<br /> case 2:<br /> TYPE[0]='N';TYPE[1]='S';<br /> break;<br /> case 3:<br /> TYPE[0]='M';TYPE[1]='D';<br /> break;<br /> case 4:<br /> TYPE[0]='M';TYPE[1]='F';<br /> break;<br /> case 5:<br /> TYPE[0]='C';TYPE[1]='N';TYPE[2]='A';TYPE[3]='M';TYPE[4]='E';<br /> break;<br /> case 6:<br /> TYPE[0]='S';TYPE[1]='O';TYPE[2]='A';<br /> break;<br /> case 7:<br /> TYPE[0]='M';TYPE[1]='B';<br /> break;<br /> case 8:<br /> TYPE[0]='M';TYPE[1]='G';<br /> break;<br /> case 9:<br /> TYPE[0]='M';TYPE[1]='R';<br /> break;<br /> case 10:<br /> TYPE[0]='N';TYPE[1]='U';TYPE[2]='L';TYPE[3]='L';<br /> break;<br /> case 11:<br /> TYPE[0]='W';TYPE[1]='K';TYPE[2]='S';<br /> break;<br /> case 12:<br /> TYPE[0]='P';TYPE[1]='T';TYPE[2]='R';<br /> break;<br /> case 13:<br /> TYPE[0]='H';TYPE[1]='I';TYPE[2]='N';TYPE[3]='F';TYPE[4]='O';<br /> break;<br /> case 14:<br /> TYPE[0]='M';TYPE[1]='I';TYPE[2]='N';TYPE[3]='F';TYPE[4]='O';<br /> break;<br /> case 15:<br /> TYPE[0]='M';TYPE[1]='X';<br /> break;<br /> case 16:<br /> TYPE[0]='T';TYPE[1]='X';TYPE[2]='T';<br /> break;<br />}<br />//now beginning with CLASS<br />b=b+3; //now b is the lower byte of CLASS<br />char CLASS[3]={''};<br />switch (*b)<br />{<br /> case 1:<br /> CLASS[0]='I';CLASS[1]='N';<br /> break;<br /> case 2:<br /> CLASS[0]='C';CLASS[1]='S';<br /> break;<br /> case 3:<br /> CLASS[0]='C';CLASS[1]='H';<br /> break;<br /> case 4:<br /> CLASS[0]='H';CLASS[1]='S';<br /> break;<br />}<br />//now TTL<br />b = b + 4;//now b is at the lower byte of TTL section<br />char aa2[6];<br />aa2[0] = *b & 255; aa2[1] = *(b-1) & 255; aa2[2] = *(b-2) & 255; aa2[3] = *(b-3) & 255;<br />unsigned int *TTL = (unsigned int*) aa2;<br />//now *TTL is the time<br />//now the RDLENGTH<br />int aa3[3];<br />b = b + 2;//now b is at the lower byte of RDLENGTH section<br />aa3[0] = *b; aa3[1] = *(b-1);<br />unsigned short *RDLENGTH = (unsigned short*) aa3;<br />//now *RDLENGTH is the length of the RDATA<br />//now the RDATA, it's so similar to Name, but it's good to use RDLENGTH as well, since we don't know if RDATA _in case it's explicit_ ends with 0 (root) or no!<br />b = b + 1;<br />char RDATA_field[512]={''};<br />for (ii=0;ii<512;ii++) //cleaning RDATA_field<br />RDATA_field[ii]=0;<br />short RDLENGTH_count = 0;<br />if ( TYPE[0]=='C' && TYPE[1]=='N' && TYPE[2]=='A' && TYPE[3]=='M' && TYPE[4]=='E')<br />{<br />int RDATA_field_lengh = 0;<br />int RDATA1Lengh;<br />while ( ((*b & 192) != 192) && (*b != 0) && (RDLENGTH_count < *RDLENGTH)) //in this loop: no compression. The condition (*b != 0) is not meant for the first time we enter the loop; it's meant if there was no pointer and the 0 exits explicitly in RDATA. I don't know if the 0 _in case it appeared here_ could not belong to RDATA.<br />{//192 in binary is 11000000<br />RDATA1Lengh = 0;<br />while(RDATA1Lengh<*b)<br />{<br />RDATA_field[RDATA_field_lengh + RDATA1Lengh] = *(b + RDATA1Lengh + 1);<br />RDATA1Lengh++;<br />}<br />RDLENGTH_count = RDLENGTH_count + *b + 1;<br />RDATA_field_lengh = RDATA_field_lengh + RDATA1Lengh;<br />RDATA_field[RDATA_field_lengh]='.';<br />RDATA_field_lengh++;<br />b = b + *b + 1;<br />}<br />//in case of a pointer<br />char *RDATA1 = b;<br />while ((*RDATA1 & 192) == 192 && (RDLENGTH_count < *RDLENGTH))//the second condition is very important, e.g. in case of a first attempt to enter and the pointer belonged to another RR<br />{<br />char ab[3];<br />ab[0] = *(RDATA1+1);<br />ab[1] = *RDATA1 & 63; //63 in binary is 00111111<br />unsigned short *pointer_value = (unsigned short*) ab;<br />RDATA1 = response + *pointer_value;<br />while(*RDATA1!=0 && (*RDATA1 & 192)!=192)//consider this non-handeled case: the pointer pointed to a another RDATA-section-explicit-text where it ends (but not with 0, nor with a pointer) with the logic of RDLENGTH<br />{<br />RDATA1Lengh = 0;<br />while ( RDATA1Lengh < (*RDATA1) )<br />{<br />RDATA_field[RDATA_field_lengh + RDATA1Lengh] = *(RDATA1 + RDATA1Lengh + 1);<br />RDATA1Lengh++;<br />}<br />RDATA1 = RDATA1 + *RDATA1 + 1;<br />RDATA_field_lengh = RDATA_field_lengh + RDATA1Lengh;<br />RDATA_field[RDATA_field_lengh]='.';<br />RDATA_field_lengh++;<br />}<br />RDLENGTH_count = RDLENGTH_count + 2;<br />} <br />if (RDATA1 != b)//this means we entered the pointer loop<br />b = b + 2;<br />if ( *b == 0 && (RDLENGTH_count == *RDLENGTH-1) )//for both previous cases<br />{<br />b = b + 1;<br />RDLENGTH_count = *RDLENGTH;<br />}<br />//the last '.' in RDATA_field in our program should be put, and there is no restriction for it except being entered only in the first loop and not the second, and (also) if RDLENGTH_count = *RDLENGTH<br />if ( (RDATA1 == b) && (RDLENGTH_count == *RDLENGTH) )<br />RDATA_field[RDATA_field_lengh-1]=0;<br />//now appearing this RR to the client<br />printf(quot;
%s%s%s%d%squot;
, NAME_field, TYPE, CLASS, *TTL, RDATA_field);<br />}<br />if (TYPE[0]=='A')<br />{<br />//it is supposed now that *b is 4, referring to the IP address<br />unsigned short ab1,ab2,ab3,ab4;<br />ab1=*b; ab2=*(b+1); ab3=*(b+2); ab4=*(b+3); //the format of the IP address is like ab1.ab2.ab3.ab4<br />b = b + 4;<br />//now appearing this RR to the client<br />printf(quot;
%s%s%s%d%d.%d.%d.%dquot;
, NAME_field, TYPE, CLASS, *TTL, ab1 & 255 , ab2 & 255 , ab3 & 255 , ab4 & 255 );<br />}<br />}<br />}<br />//server side<br />#include quot;
stdafx.hquot;
<br />#include <iostream><br />#include <process.h><br />/* server.c - code for example DNS program that uses udp */<br />#ifndef unix<br />#include <windows.h><br />#include <winsock.h><br />#include <io.h><br />#else<br />#define closesocket close<br />#include <sys/types.h><br />#include <sys/socket.h><br />#include <netinet/in.h><br />#include <arpa/inet.h><br />#include <netdb.h><br />#endif<br />#include <stdio.h><br />#include <string.h><br />#include <stdlib.h><br />#include <malloc.h><br />#define PROTOPORT 53 /* 53 is the default protocol port number which corresponds to 13568*/<br />char MyIP_4ClientSide[] = quot;
127.0.0.3quot;
;//127.0.0.1 corresponds to 16777343and 127.0.0.2 corresponds to 33554559<br />char OuterServerIP[] = quot;
8.8.4.4quot;
;//208.67.222.222 corresponds to 3739108304//208.67.220.220 corresponds to 3705422800<br />//8.8.8.8 corresponds to 134744072//8.8.4.4 correposnds to 67373064<br />char response[512]={''};//512 is the exact value that must be for max size of a UDP message<br />struct sockaddr_in SockAddrIn_ToOuterDNSServerSide, SockAddrIn_Used4ClientSide, SockAddrInFromOuterDNS; /*IP, port, family*/<br />int ClientSideSocket, OuterDNSServerSideSocket; /* 2 socket descriptors, both of them correspond to this DNS server, i.e it's very true that both of them are for the same 1 system, but for technical reasons we'll only bind the client side */<br />//please note that SockAddrIn_GottenFromClient is a pointer in serverThread and a struct variable in main, Why one pointer and another variable? this is due to restriction in the function serverThread. Why SockAddrIn_GottenFromClient is not public? because ...<br />void serverThread(void* psd)<br />{<br />char *buf1= (char*)psd;<br />char *buf2= (char*)psd + 512;<br />struct sockaddr_in *SockAddrIn_GottenFromClient =(struct sockaddr_in*) buf2;<br />char buf[512];<br />int i;<br />for (i=0;i<512;i++)<br />buf[i]=*(buf1+i);<br />int n;<br />int h = sizeof(struct sockaddr);<br />printf(quot;
Towards Sending to DNS with id: %d %dquot;
,buf[0],buf[1]);<br />n = sendto(OuterDNSServerSideSocket, buf, sizeof(buf), 0, (sockaddr *)&SockAddrIn_ToOuterDNSServerSide,h);<br />printf(quot;
Towards Receiving from DNS with id: %d %dquot;
,buf[0],buf[1]);<br />n = recvfrom(OuterDNSServerSideSocket, response, sizeof(response), 0, (sockaddr *)&SockAddrInFromOuterDNS,&h);//here the port is 13568=53*2^8<br />printf(quot;
Towards Replying back to app with id: %d %dquot;
,response[0],response[1]);<br />n = sendto(ClientSideSocket, response, sizeof(response), 0,(sockaddr *)SockAddrIn_GottenFromClient,h);//here the port could be 45780=178*2^8+212 and it changes always<br />printf(quot;
End of thread with id: %d %dquot;
,response[0],response[1]);<br />}<br />void main()<br />{<br />struct sockaddr_in SockAddrIn_GottenFromClient;<br /> struct hostent *IPAddr_4ClientSide, *IPAddr_of_OuterDNSServer;/* pointer to a host table entry */<br /> struct protoent *UDP_Protocol; /* pointer to a protocol table entry */<br /> int port; /* protocol port number */<br /> char *host, buf[512]; /* pointer to host name, not important */<br /> int n,i,j; /* number of characters read */<br />#ifdef WIN32<br /> WSADATA wsaData;<br /> WSAStartup(0x0101, &wsaData);<br />#endif<br />//************************************We'll start now by working on the Outer DNS Server Side<br />//one other possible good name of SockAddrIn_ToOuterDNSServerSide is quot;
SockAddrIn_OfOuterDNSServerSidequot;
<br />memset((char *)&SockAddrIn_ToOuterDNSServerSide,0,sizeof(SockAddrIn_ToOuterDNSServerSide));/* clear client sockaddr structure */<br /> SockAddrIn_ToOuterDNSServerSide.sin_family = AF_INET;/* set family to Internet */<br /> port = PROTOPORT; <br /> SockAddrIn_ToOuterDNSServerSide.sin_port = htons((u_short)port);/* set port number */<br /> host = OuterServerIP;<br /> <br /> /* Convert host name to equivalent IP address and copy to SockAddrIn_ToOuterDNSServerSide. */<br /> IPAddr_of_OuterDNSServer = gethostbyname(host); //actually here there should be an error handling in case of failure in the function gethostbyname....................<br /> memcpy(&SockAddrIn_ToOuterDNSServerSide.sin_addr, IPAddr_of_OuterDNSServer->h_addr, IPAddr_of_OuterDNSServer->h_length);<br /> /* Map UDP transport protocol name to protocol number. */<br /> if ( ((int)(UDP_Protocol = getprotobyname(quot;
udpquot;
))) == 0) <br />{<br /> fprintf(stderr, quot;
cannot map "
udp"
to protocol numberquot;
);<br /> getchar();<br /> exit(1);<br /> }<br /> /* Create a socket. */<br /> OuterDNSServerSideSocket = socket(PF_INET, SOCK_DGRAM, UDP_Protocol->p_proto);<br /> if (OuterDNSServerSideSocket < 0) <br />{<br /> fprintf(stderr, quot;
socket creation failedquot;
);<br /> getchar();<br /> exit(1);<br /> }<br />//no binding is done for the Outer DNS Server side, it's automatic<br />//*********************************So, now we're done of the Outer DNS Server side<br />//################################# Now working on the Client side<br />/* Create a socket. */<br /> ClientSideSocket = socket(PF_INET, SOCK_DGRAM, UDP_Protocol->p_proto);<br /> if (ClientSideSocket < 0) <br />{<br /> fprintf(stderr, quot;
socket creation failedquot;
);<br /> getchar();<br /> exit(1);<br /> }<br />//now defining SockAddrIn_Used4ClientSide to use it in Binding only, and to let the Server realise for the Client the IP that I want as a client part<br />memset((char *)&SockAddrIn_Used4ClientSide,0,sizeof(SockAddrIn_Used4ClientSide));/* clear Client sockaddr structure */<br /> SockAddrIn_Used4ClientSide.sin_family = AF_INET;/* set family to Internet */<br />//port=port+1;<br />SockAddrIn_Used4ClientSide.sin_port = htons((u_short)port);/* set port number */<br />//SockAddrIn_Used4ClientSide.sin_addr.s_addr = INADDR_ANY; //INADDR_ANY<br />IPAddr_4ClientSide = gethostbyname(MyIP_4ClientSide);<br /> if ( ((char *)IPAddr_4ClientSide) == NULL ) <br />{ <br />fprintf(stderr,quot;
invalid host: %squot;
, host);<br /> getchar();<br /> exit(1);<br /> }<br /> memcpy(&SockAddrIn_Used4ClientSide.sin_addr, IPAddr_4ClientSide->h_addr, IPAddr_4ClientSide->h_length);<br /> /* Bind a local address to the socket */<br />int hh=0;<br />hh=bind(ClientSideSocket, (struct sockaddr *)&SockAddrIn_Used4ClientSide, sizeof(SockAddrIn_Used4ClientSide));<br />//int __stdcall bind(SOCKET s, const sockaddr *addr, int namelen)<br /> if (hh < 0) <br />{<br /> fprintf(stderr,quot;
bind failedquot;
);<br /> exit(1);<br /> }<br />//################################### Done with the client side<br /> /* Repeatedly read data from socket and write to user's screen. */<br />int h = sizeof(struct sockaddr);<br />//receiving from client<br />int how_many_times=0;<br />while(1)<br />{ <br />for (i=0;i<512;i++)<br />buf[i]=0;<br />how_many_times++; char first_time[3]=quot;
stquot;
,other_times[3]=quot;
thquot;
;<br />printf(quot;
Towards receiving from app, with %d%s timequot;
,how_many_times,(how_many_times==1)?first_time:other_times);<br />n = recvfrom(ClientSideSocket, buf, sizeof(buf), 0, (sockaddr *)&SockAddrIn_GottenFromClient,&h);<br />//for the administrator of this DNS, we can let him see the IP address of the client<br />printf (quot;
A request has came with the following characteristics:Port number:%dquot;
,ntohs(SockAddrIn_GottenFromClient.sin_port));<br />printf (quot;
IP address: %squot;
,inet_ntoa(SockAddrIn_GottenFromClient.sin_addr));<br />char *buf1=(char*)malloc(512+sizeof(SockAddrIn_GottenFromClient)); //what is the free keyword???<br />for (j=0;j<512;j++)<br />*(buf1+j)=buf[j];<br />char *a= (char*)&SockAddrIn_GottenFromClient;<br />for (j=512;j<512+sizeof(SockAddrIn_GottenFromClient);j++)<br />*(buf1+j)= *(a +j-512);<br />long kk=(long)buf1;<br />printf(quot;
Now I received sth from app with the header id: %d %dquot;
,buf[0],buf[1]);<br />_beginthread(serverThread, 0, (void*)kk);<br />}<br /> /* Close the socket. */<br /> closesocket(OuterDNSServerSideSocket);<br />closesocket(ClientSideSocket);<br /> /* Terminate the client program gracefully. */<br />getchar();<br /> exit(0);<br />}<br />