Main Page   Data Structures   File List   Data Fields   Globals   Related Pages  

inet/dns.cpp

Go to the documentation of this file.
00001 
00002 #include <mem.h>
00003 #include <string.h>
00004 #include <stdio.h>
00005 #include <ctype.h>
00006 
00007 #include "clib/tcpip.h"
00008 #include "inet/dns.h"
00009 
00010 //#define TRACE   // comment out if you do not want prints of results & progress
00011 //#define MONITOR // use this to show the cute little hex dump!
00012 
00013 #define DNS_PORT    53          // Well known DNS port
00014 
00015 
00016 static unsigned int ident;  // ident counter, count up at every request
00017 
00018 #define BUFSIZE 600
00019 
00020 #define RRBUF 200
00021 
00022 typedef struct dn_rr_struct {
00023    char rrname[RRBUF];
00024    unsigned int rrtype;
00025    unsigned int rrclass;
00026    unsigned long rrttl;
00027    char rrrdata[RRBUF];
00028 } dn_rr;
00029 
00030 /* Define values for RR-types as specified in RFC1035 */
00031 #define DN_TYPE_A     1
00032 #define DN_TYPE_NS    2
00033 #define DN_TYPE_CNAME 5
00034 #define DN_TYPE_MX    15
00035 
00036 /* Define values for RR-class as specified in RFC1035 */
00037 #define DN_CLASS_IN   1
00038 
00039 
00040 #ifdef MONITOR
00041 /* pointer to begin of packet and length - shows up a cute hex-screen */
00042 void packetmonitor(int len2, char *buffer)
00043 {
00044    int j,i,k;
00045 
00046       j=0;
00047       for(i=0;i<len2;i++)
00048       {
00049   if(j==0)
00050   {
00051      printf("\n\r%3X  ",i);
00052   }
00053   printf("%02X ",buffer[i]&0xff);
00054   j++;
00055   if(j==16)
00056   {
00057     for(k=0;k<j;k++)
00058     {
00059       if(isprint(buffer[i-j+k+1]&0xff))
00060         printf("%c",buffer[i-j+k+1]&0xff);
00061       else
00062         printf(".");
00063     }
00064     j=0;
00065   }
00066       }
00067       i--;
00068       for(k=0;k<j;k++)
00069       {
00070   if(isprint(buffer[i-j+k+1]&0xff))
00071     printf("%c",buffer[i-j+k+1]&0xff);
00072   else
00073     printf(".");
00074       }
00075       j=0;
00076 }
00077 #endif
00078 
00079 /*
00080    convert a compressed domain-name to its ascii representation
00081    packet: pointer to a dns-query-packet within a dns answer or reply
00082    name: pointer to the name-field
00083    dest: destination of the domain-name
00084    len: length of dest
00085    returns: length of the compressed name field, -1 if length of
00086             dest is too small for dest to hold the whole domain-name
00087 */
00088 int dn_uncompress(char *dest, int len, char *packet, char *name)
00089 {
00090    int nlen, nlenok;
00091    unsigned int u;
00092 //   char *ptr;
00093 
00094    *dest= 0;
00095    nlen=nlenok= 0;
00096    while(*name) {
00097       if((*name&0xc0) == 0xc0) {              /* we found a compressed sign change read pointer */
00098          u= ((*name&0x3f)<<8) + (*(name+1));  /* resolve pointer */
00099          if(packet+u > name)                  /* pointer not allowed abort */
00100             return -1;
00101          name=packet+u;  //u
00102          if(nlenok == 0) {                    /* after first compressed sign block setting the length field */
00103             nlen+= 2;                         /* set the length field for the return value */
00104             nlenok= 1;
00105          }
00106       }
00107       else {
00108          if(*name > (len-2))                  /* domain-name is too long for dest */
00109             return -1;
00110          len-= *name;
00111          strncat(dest,name+1,*name);          /* copy next domain-part to the end of dest */
00112          if(nlenok == 0) {
00113             nlen+=*name+1;
00114          }
00115          name+= *name+1;
00116          if(*name) {                          /* if name not finished append '.' to dest */
00117             len--;
00118             strcat(dest,".");
00119          }
00120       }
00121    }
00122    if(nlenok == 0)                            /* if there was no compress sign in the domain-name include 0 for the length */
00123       nlen++;
00124    return nlen;                               /* return length of name-field */
00125 }
00126 
00127 /*
00128    extract a dns-rr message pointed to by message and return
00129    the values in an dn_rr struct
00130    rr: pointer to the dn_rr struct
00131    packet: pointer to the begin of the packet
00132    message: pointer in a packet pointing to the message to extract
00133    returns: the total length of the rr, or -1 if error occured
00134 */
00135 int dn_unpackrr(dn_rr *rr, char *packet, char *message)
00136 {
00137    int i;
00138    unsigned int u;
00139 
00140    if((i=dn_uncompress(rr->rrname,RRBUF,packet,message)) == -1) /* get name */
00141       return -1;
00142    message+=i;
00143    rr->rrtype= ((*message)<<8) + (*(message+1));              /* get type */
00144    message+=2;
00145    rr->rrclass= ((*message)<<8) + (*(message+1));             /* get class */
00146    message+=2;
00147    rr->rrttl=((*message)<<24)&0xff000000L;                     /* get ttl */
00148    rr->rrttl+=((*(message+1))<<16)&0xff0000L;
00149    rr->rrttl+=((*(message+2))<<8)&0xff00;
00150    rr->rrttl+=((*(message+3)))&0xff;
00151    message+=4;
00152    u= ((*message)<<8) + (*(message+1));                       /* get rdlength */
00153    message+=2;
00154    switch(rr->rrtype) {
00155       case DN_TYPE_CNAME:
00156       case DN_TYPE_NS:
00157                           if(dn_uncompress(rr->rrrdata,RRBUF,packet,message) == -1)
00158                              return -1;
00159                           break;
00160 
00161       case DN_TYPE_MX:    *(rr->rrrdata)=*message;
00162                           *(rr->rrrdata+1)=*(message+1);
00163                           message+=2;
00164                           if(dn_uncompress(rr->rrrdata+2,RRBUF-2,packet,message) == -1)
00165                              return -1;
00166                           break;
00167 
00168       case DN_TYPE_A:     if(rr->rrclass == DN_CLASS_IN) {
00169                              *(rr->rrrdata)=*message;            /* copy ip adress to struct */
00170                              *(rr->rrrdata+1)=*(message+1);
00171                              *(rr->rrrdata+2)=*(message+2);
00172                              *(rr->rrrdata+3)=*(message+3);
00173                              *(rr->rrrdata+4)=0;
00174                           }
00175                           else
00176                              return -2;                         /* unknown CLASS */
00177                           break;
00178       default:            *(rr->rrrdata)=0;
00179    }
00180    return u+i+10;                                               /* return total length of rr */
00181 }
00182 
00183 /*
00184    convert a string like "www.hello.de" to a string with following
00185    byte values: 3 119 119 199 5 104 101 108 108 111 2 100 101 0
00186    The bytes mean: length, ascii chars, length, ascii chars, ...., length=0
00187    returns length (including terminator) of string.
00188 */
00189 static int packdomain(char * dest, const char *src)
00190 {
00191   int i,n,cnt;
00192 
00193   n=strlen(src);
00194   dest[n+1]=0;  // terminator
00195   // walk back trough the string
00196   cnt=0;
00197   for (i=n; i>0; i--)
00198   {
00199     if (src[i-1]=='.')
00200     {
00201       dest[i]=cnt;
00202       cnt=0;
00203     }
00204     else
00205     {
00206       dest[i]=src[i-1];
00207       cnt++;
00208     }
00209   }
00210   dest[0]=cnt;
00211   return n+2;
00212 }
00213 
00214 /*
00215     gethostbyname
00216     This is the function it is all about.
00217     It prepares the request
00218     Opens the socket
00219     Sends the request
00220     Receives the answer
00221     Interprets the answer
00222     Closes the socket
00223 
00224     return 1 on succes
00225 */
00226 int gethostbyname(  const char *dnsServerIP, // where to ask for the dns resolution
00227         const char *domainName,  // The domain name "www.beck-ipc.com"
00228         unsigned long *ttl,      // Time to live in seconds
00229         unsigned long *IP,       // The 32 bit IP
00230         char *dest)              // The IP as text (make sure it is long enough)
00231 {
00232   unsigned char buffer[BUFSIZE+1];
00233   int sd,error;
00234   struct sockaddr_in  addr;
00235   int i,j,k,len1,len2,nRR;
00236 //  int type,clss; // type and class of record
00237   dn_rr myrr;
00238 
00239   #ifdef TRACE
00240     char s[200];
00241     printf("\r\ndns server: %s  Host: %s\r\n",dnsServerIP,domainName);
00242   #endif
00243 
00244   setmem(buffer,BUFSIZE,0);
00245 
00246   // ident is a sequence number
00247   if (++ident>126) ident=1;
00248   buffer[0]=(ident>>8);
00249   buffer[1]=(ident&0xff);
00250   // flags
00251   buffer[2]=1;
00252   buffer[3]=0;
00253   // number of questions
00254   buffer[4]=0;
00255   buffer[5]=1;
00256   // 12 bytes in header
00257   len1=12;
00258   len1+=packdomain((char *)&buffer[12],domainName);
00259   buffer[len1++]=0; buffer[len1++]=1; // query type is IP address
00260   buffer[len1++]=0; buffer[len1++]=1; // query class is also IP address
00261 
00262   #ifdef TRACE
00263     printf("Request holds %d bytes\r\n",len1);
00264     for (i=0; i<len1; i++) printf(" %X",buffer[i]&0x00ff);
00265   #endif
00266 
00267   sd=opensocket(SOCK_DGRAM,&error);                             /* open the socket */
00268   if (sd==API_ERROR) {
00269     printf("\r\nError %d opening socket\r\n",error);
00270     return 0;
00271   }
00272 
00273   addr.sin_family      = AF_INET;                               /* set address family to IP */
00274   if(inet_addr((char *)dnsServerIP, &addr.sin_addr.s_addr)) {   /* convert the sting holding the ns-ip to binary */
00275     printf("\r\nError converting DNS Server address %s \r\n",dnsServerIP);
00276     printf("\r\nIP %lX",addr.sin_addr.s_addr);
00277     return 0;
00278   }
00279   addr.sin_port=htons(DNS_PORT);                                /* set target port number */
00280   // send data
00281   if (  API_ERROR==sendto(sd, (char *)buffer, len1, MSG_BLOCKING, (const struct sockaddr * )&addr, &error))
00282   {
00283     printf("\r\nError %d sending data in line %d\r\n",error,__LINE__);
00284     closesocket(sd,&error);
00285     return 0;
00286   }
00287 
00288   api_sleep(100);                                               /* wait a little */
00289   // receive answer, with timeout
00290   len2=recvfrom(sd, (char *)buffer, BUFSIZE, MSG_TIMEOUT, 10000,(struct sockaddr *)&addr,&error);
00291   closesocket(sd,&error);
00292   if (len2<=len1)
00293   {
00294     printf("\r\nError %d receiving data\r\n",error);
00295     return 0;
00296   }
00297 
00298   #ifdef MONITOR
00299      packetmonitor(len2, buffer);
00300   #endif
00301   #ifdef TRACE
00302      printf("\r\nReceived %d bytes\r\n",len2);
00303      printf("Header:");
00304      for (i=0; i<12; i++)
00305         printf(" %X",buffer[i]&0xff);
00306      printf("\r\n");
00307   #endif
00308 
00309   // At this point I just assume that it is a valid answer
00310   // really good would be to check..... (I leave this to you)
00311   // the number of answers
00312   nRR=buffer[6];
00313   nRR=(nRR<<8)+buffer[7];
00314   #ifdef TRACE
00315      printf("\r\nGot %d answers",nRR);
00316   #endif
00317   // we only use one answer
00318   // the first answer starts where the question stopped
00319   i=len1;
00320   // at this point &buffer[i] points to the first answer rr
00321   k=1;
00322   while(nRR--) {
00323 
00324      if((j=dn_unpackrr(&myrr, (char *)buffer,(char *)&buffer[i])) == -1) {           /* get answer-rr from buffer */
00325         printf("\r\nError in answer section from DNS-server");
00326         return 0;
00327      }
00328      #ifdef TRACE
00329         printf("\r\nA%i: name=%s type=%i class=%i ttl=%lu",k++,myrr.rrname,myrr.rrtype, myrr.rrclass, myrr.rrttl);
00330         if(myrr.rrtype == DN_TYPE_CNAME)
00331            printf(" cname=%s",myrr.rrrdata);
00332      #endif
00333      if(myrr.rrtype == DN_TYPE_A && myrr.rrclass == DN_CLASS_IN) {  /* if it is a A record, we found what we want */
00334         k= -1;
00335         break;
00336      }
00337      i+=j;                                                          /* move position to next answer record */
00338   }
00339   if (k != -1) {
00340      return 0;
00341   }
00342   memcpy((void *)IP,(void *)myrr.rrrdata,4);
00343   *ttl=myrr.rrttl;
00344   InetToAscii(IP,dest);
00345   return 1;
00346 }

Generated on Sun Aug 4 21:47:28 2002 for k/os mp3v2 by doxygen1.2.16