Main Page   Modules   Data Structures   File List   Data Fields   Globals   Related Pages   Examples  

/opentcp/dns/dns.c

Go to the documentation of this file.
00001 /*
00002  *Copyright (c) 2000-2002 Viola Systems Ltd.
00003  *All rights reserved.
00004  *
00005  *Redistribution and use in source and binary forms, with or without
00006  *modification, are permitted provided that the following conditions
00007  *are met:
00008  *
00009  *1. Redistributions of source code must retain the above copyright
00010  *notice, this list of conditions and the following disclaimer.
00011  *
00012  *2. Redistributions in binary form must reproduce the above copyright
00013  *notice, this list of conditions and the following disclaimer in the
00014  *documentation and/or other materials provided with the distribution.
00015  *
00016  *3. The end-user documentation included with the redistribution, if
00017  *any, must include the following acknowledgment:
00018  *      "This product includes software developed by Viola
00019  *      Systems (http://www.violasystems.com/)."
00020  *
00021  *Alternately, this acknowledgment may appear in the software itself,
00022  *if and wherever such third-party acknowledgments normally appear.
00023  *
00024  *4. The names "OpenTCP" and "Viola Systems" must not be used to
00025  *endorse or promote products derived from this software without prior
00026  *written permission. For written permission, please contact
00027  *opentcp@opentcp.org.
00028  *
00029  *5. Products derived from this software may not be called "OpenTCP",
00030  *nor may "OpenTCP" appear in their name, without prior written
00031  *permission of the Viola Systems Ltd.
00032  *
00033  *THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
00034  *WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
00035  *MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
00036  *IN NO EVENT SHALL VIOLA SYSTEMS LTD. OR ITS CONTRIBUTORS BE LIABLE
00037  *FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
00038  *CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
00039  *SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
00040  *BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
00041  *WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
00042  *OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
00043  *EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00044  *====================================================================
00045  *
00046  *OpenTCP is the unified open source TCP/IP stack available on a series
00047  *of 8/16-bit microcontrollers, please see <http://www.opentcp.org>.
00048  *
00049  *For more information on how to network-enable your devices, or how to
00050  *obtain commercial technical support for OpenTCP, please see
00051  *<http://www.violasystems.com/>.
00052  */
00053 
00054 
00075 #include <inet/debug.h>
00076 #include <inet/datatypes.h>
00077 #include <inet/globalvariables.h>
00078 #include <inet/system.h>
00079 #include <inet/timers.h>
00080 #include <inet/tcp_ip.h>
00081 #include <inet/dns/dns.h>
00082 
00083 
00084 #define DNS_STATE_READY         0
00085 #define DNS_STATE_BUSY          1
00086 #define DNS_STATE_RESEND        2       /* retransmit request */
00087 
00088 UINT8 dns_state; 
00089 UINT8 dns_socket; 
00090 UINT8 dns_timer; 
00091 UINT8 dns_retries; 
00093 UINT32 dns_tmp_ip; 
00095 UINT8 *dns_hostptr;     
00098 void (*dns_event_listener)(UINT8 event, UINT32 data);
00099 
00108 void dns_init(void){
00109 
00110         dns_state = DNS_STATE_READY;
00111 
00112         dns_socket=udp_getsocket(0 , dns_eventlistener , UDP_OPT_SEND_CS | UDP_OPT_CHECK_CS);
00113 
00114         if(dns_socket == -1){
00115                 DEBUGOUT("DNS: No free UDP sockets!! \r\n");
00116                 return;
00117         }
00118 
00119         /* open socket */
00120         udp_open(dns_socket,DNS_UDP_PORT);
00121 
00122         /* now the timer. This will be used for retransmitting the requests */
00123         dns_timer=get_timer();
00124 
00125         /* TODO: if GetTimer is modified so that it doesn't reset system if
00126                 no timers available, check return value! */
00127 
00128         DEBUGOUT("Initialized DNS client\r\n");
00129 
00130 }
00131 
00142 void dns_retransmit(void){
00143         if(dns_retries!=0){
00144                 dns_state=DNS_STATE_RESEND;
00145                 dns_retries--;
00146                 get_host_by_name(dns_hostptr,dns_event_listener);
00147                 init_timer(dns_timer,DNS_RESEND_PERIOD*TIMERTIC);
00148         }else{
00149 
00150                 /* timeout happened */
00151                 dns_state=DNS_STATE_READY;
00152 
00153                 dns_event_listener(DNS_EVENT_ERROR,DNS_ERROR_TIMEOUT);
00154 
00155         }
00156 
00157 }
00158 
00168 void dns_run(void){
00169         if((dns_state==DNS_STATE_BUSY)||(dns_state==DNS_STATE_RESEND)){
00170                 /* checking retransmission timer */
00171                 if(!check_timer(dns_timer)){
00172 
00173                         DEBUGOUT("DNS: retransmitting the request \r\n");
00174                         /* timeout, send another one */
00175                         dns_retransmit();
00176 
00177                 }
00178         }
00179 }
00180 
00205 INT32 dns_eventlistener(INT8 cbhandle, UINT8 event, UINT32 ipaddr, UINT16 port, UINT16 buffindex, UINT16 datalen){
00206         UINT8 tmp_byte;
00207         UINT16 tmp_int;
00208         UINT8 *tmp_ptr;
00209         UINT8 count;
00210         /* it will fit in 8bits most of the time but... */
00211         UINT16 dns_ancount;
00212         UINT16 dns_nscount;
00213 
00214         if(cbhandle!=dns_socket){
00215                 DEBUGOUT("DNS: not my handle!!!!");
00216                 return (-1);
00217         }
00218 
00219         if(ipaddr!=dns_tmp_ip){
00220                 DEBUGOUT("DNS: received DNS but IP addr not OK!\r\n");
00221         }
00222 
00223         switch(event){
00224                 case UDP_EVENT_DATA:
00225                         /* only process data while not in ready state */
00226                         if(dns_state==DNS_STATE_READY){
00227                                 DEBUGOUT("DNS: Received answer in wrong state\r\n");
00228                                 return (-1);
00229                         }
00230 
00231                         /* inital size checking. Every DNS reply will be bigger
00232                                 than 16 bytes */
00233                         if(datalen<16){
00234                                 DEBUGOUT("DNS: UDP packet way to short for DNS!\r\n");
00235                                 return (-1);
00236                         }
00237 
00238                         /* some data received, check if it's what we're waiting for */
00239                         tmp_int=RECEIVE_NETWORK_B();
00240                         tmp_int=(tmp_int<<8)+RECEIVE_NETWORK_B();
00241                         if(tmp_int!=0xaaaa){
00242                                 DEBUGOUT("DNS: ERROR: ID wrong!\r\n");
00243                                 return (-1);
00244                         }
00245 
00246                         tmp_byte=RECEIVE_NETWORK_B();
00247 
00248                         if(!(tmp_byte&0x80)){
00249                                 DEBUGOUT("DNS: THIS IS NOT AN ANSWER! WE'RE NOT A DNS SERVER!\r\n");
00250                                 return (-1);
00251                         }
00252 
00253                         /* opcode or truncated ? */
00254                         if(tmp_byte&0x7a){
00255                                 DEBUGOUT("DNS: Opcode not zero or message truncated. \r\n");
00256                                 dns_event_listener(DNS_EVENT_ERROR,DNS_ERROR_GENERAL);
00257                                 return (-1);
00258                         }
00259 
00260                         tmp_byte=RECEIVE_NETWORK_B();
00261 
00262                         /* check RCODE */
00263                         if((tmp_byte&0x7f)&&(tmp_byte&0x80)){
00264                                 /* RCODE not zero, and recursion is available   */
00265                                 /* There was an error. Inform listener                  */
00266                                 DEBUGOUT("DNS: RCODE not zero and recursion available! \r\n");
00267                                 dns_event_listener(DNS_EVENT_ERROR,tmp_byte&0x7f);
00268                                 return (-1);
00269                         }
00270 
00271                         /* question count == 1 ? */
00272                         tmp_int=(((UINT16)RECEIVE_NETWORK_B())<<8);
00273                         tmp_int+=RECEIVE_NETWORK_B();
00274                         if(tmp_int != 1){
00275                                 DEBUGOUT("DNS: we only sent one question and received a couple of answers!!\r\n");
00276                                 dns_event_listener(DNS_EVENT_ERROR,DNS_ERROR_GENERAL);
00277                                 return (-1);
00278                         }
00279 
00280                         dns_ancount=(((UINT16)RECEIVE_NETWORK_B())<<8);
00281                         dns_ancount+=RECEIVE_NETWORK_B();
00282 
00283                         dns_nscount=(((UINT16)RECEIVE_NETWORK_B())<<8);
00284                         dns_nscount+=RECEIVE_NETWORK_B();
00285 
00286                         /* skip ARCOUNT */
00287                         RECEIVE_NETWORK_B();
00288                         RECEIVE_NETWORK_B();
00289 
00290                         /* got to the data, let's process it */
00291                         /* check if question section is appropriate (QNAME the same
00292                                 and QTYPE=QCLASS=1
00293                         */
00294                         tmp_ptr=dns_hostptr;
00295                         while((tmp_byte=RECEIVE_NETWORK_B())!=0){
00296                                 while((tmp_byte--)!=0){
00297                                         if(*tmp_ptr++!=RECEIVE_NETWORK_B()){
00298                                                 DEBUGOUT("DNS: QNAME not the same!!!! \r\n");
00299                                                 /* we'll assume that this was from some previous
00300                                                         query and just exit here */
00301                                                 return (-1);
00302                                         }
00303                                 }
00304                                 /* reached the end of the label. Is it dot or end of string? */
00305 
00306                                 if(*tmp_ptr=='\0'){
00307                                         continue;
00308                                 }
00309 
00310                                 if(*tmp_ptr++!='.'){
00311                                         DEBUGOUT("DNS: DOT not where it's supposed to be!\r\n");
00312                                         return (-1);
00313                                 }
00314                         }
00315 
00316 
00317                         /* qtype and qclass */
00318                         tmp_int=(((UINT16)RECEIVE_NETWORK_B())<<8);
00319                         tmp_int+=RECEIVE_NETWORK_B();
00320 
00321                         tmp_int|=((UINT16)(RECEIVE_NETWORK_B())<<8);
00322                         tmp_int|=RECEIVE_NETWORK_B();
00323 
00324                         if(tmp_int!=0x0001){
00325                                 DEBUGOUT("DNS: Question section QTYPE and/or QCLASS not ok!\r\n");
00326                                 dns_event_listener(DNS_EVENT_ERROR,DNS_ERROR_GENERAL);
00327                                 return (-1);
00328                         }
00329 
00330                         /* process all answer RRs and try to find answer */
00331 
00332                         /* simply try to find INET class RR. It is
00333                                 _PROBABLY_ what we're after. More extensive checking
00334                                 would demand buffering the reply which may not be
00335                                 desireable.
00336                          */
00337                         while(dns_ancount||dns_nscount){
00338                                 do{
00339                                         tmp_byte=RECEIVE_NETWORK_B();
00340                                 }while((tmp_byte!=0)&&((tmp_byte&0xc0)!=0xc0));
00341 
00342                                 if(tmp_byte!=0) /*second offset byte used in compression*/
00343                                         RECEIVE_NETWORK_B();
00344 
00345                                 /* TYPE */
00346                                 tmp_int=((UINT16)RECEIVE_NETWORK_B())<<8;
00347                                 tmp_int|=RECEIVE_NETWORK_B();
00348 
00349                                 /* CLASS */
00350                                 tmp_int|=(((UINT16)RECEIVE_NETWORK_B())<<8);
00351                                 tmp_int|=RECEIVE_NETWORK_B();
00352 
00353                                 /* CLASS==INET and TYPE=A ? */
00354                                 if(tmp_int==0x0001){
00355 
00356                                         /* got it. Skip TTL and read RDLENGTH */
00357                                         for(tmp_byte=0;tmp_byte<6;tmp_byte++){
00358                                                 tmp_int=(tmp_int<<8)+RECEIVE_NETWORK_B();
00359                                         }
00360 
00361                                         if(tmp_int==0x0004){
00362                                                 /* great, read IP address*/
00363                                                 dns_tmp_ip=((UINT32)RECEIVE_NETWORK_B())<<24;
00364                                                 dns_tmp_ip+=((UINT32)RECEIVE_NETWORK_B())<<16;
00365                                                 dns_tmp_ip+=((UINT32)RECEIVE_NETWORK_B())<<8;
00366                                                 dns_tmp_ip+=RECEIVE_NETWORK_B();
00367 
00368                                                 /* we got some IP address. Is it what we asked for
00369                                                         or a NS IP addr*/
00370                                                 if(dns_ancount){
00371                                                         DEBUGOUT("DNS: Got IP address!\r\n");
00372                                                         dns_event_listener(DNS_EVENT_SUCCESS,dns_tmp_ip);
00373                                                         dns_state=DNS_STATE_READY;
00374                                                 }else{
00375                                                         DEBUGOUT("DNS: Got auth DNS IP addr!\r\n");
00376                                                         /* invoke another query to the authority */
00377                                                         dns_retransmit();
00378                                                 }
00379 
00380                                                 return 0;
00381                                         }else{
00382                                                 /* nope, skip other bytes */
00383                                                 while(tmp_int--)
00384                                                         RECEIVE_NETWORK_B();
00385                                         }
00386                                 }else{
00387 
00388                                         DEBUGOUT("DNS: RR.CLASS not INET. Skipping!\r\n");
00389 
00390                                         /* skip TTL and read RDLENGTH*/
00391                                         for(tmp_byte=0;tmp_byte<6;tmp_byte++){
00392                                                 tmp_int=(tmp_int<<8)+RECEIVE_NETWORK_B();
00393                                         }
00394 
00395                                         /* skip RDATA */
00396                                         while(tmp_int--)
00397                                                 RECEIVE_NETWORK_B();
00398                                 }
00399                                 /* decrement counters */
00400                                 if(dns_ancount)
00401                                         dns_ancount--;
00402                                 else
00403                                         if(dns_nscount)
00404                                                 dns_nscount--;
00405 
00406                         }
00407                         break;
00408 
00409                 default:
00410                         DEBUGOUT("DNS: unknown UDP event :-(");
00411                         break;
00412         }
00413         return 0;
00414 }
00415 
00445 UINT8 get_host_by_name(UINT8 *host_name_ptr, void (*listener)(UINT8 , UINT32 )){
00446 
00447         UINT8 *buf_ptr;
00448         INT8 i;
00449         UINT16 total;
00450 
00451         switch(dns_state){
00452 
00453                 case DNS_STATE_READY:
00454                         dns_state=DNS_STATE_BUSY;
00455                         dns_hostptr=host_name_ptr;
00456                         dns_event_listener=listener;
00457                         dns_tmp_ip=DNS_SERVER_IP;
00458                         dns_retries=DNS_NUM_RETRIES;
00459                         init_timer(dns_timer,DNS_RESEND_PERIOD*TIMERTIC);
00460                         break;
00461 
00462                 case DNS_STATE_BUSY:
00463                         DEBUGOUT("DNS: Error, trying to invoke two DNS requests at the same time!\r\n");
00464                         return  DNS_ERROR_BUSY;
00465 
00466 
00467                 case DNS_STATE_RESEND:
00468                         if(host_name_ptr!=dns_hostptr){
00469                                 DEBUGOUT("DNS: Ptrs different. Can't do that! \r\n");
00470                                 return DNS_ERROR_BUSY;
00471                         }
00472                         break;
00473 
00474                 default:
00475                         DEBUGOUT("DNS: What am I doing in this state?\r\n");
00476                         RESET_SYSTEM();
00477         }
00478 
00479 
00480         /* OK, create message in the Netbuf transmit buffer */
00481 
00482         buf_ptr=net_buf+UDP_APP_OFFSET;
00483 
00484         /* first the header */
00485         *((UINT16 *)buf_ptr)=0xAAAA; /* id, fixed for now*/
00486         buf_ptr+=2;
00487 
00488         *buf_ptr++=0x01;
00489         *buf_ptr++=0x00;
00490 
00491         /*question count*/
00492         *buf_ptr++=0x00;
00493         *buf_ptr++=0x01;
00494 
00495         /* others are zero */
00496         for(i=0;i<6;i++)
00497                 *buf_ptr++=0x00;
00498 
00499         /* ok, create the question section */
00500         total=0;
00501 
00502         while((*host_name_ptr)!='\0'){
00503 
00504                 /* we are still not at the end. Reserve space for count */
00505                 buf_ptr++;
00506                 i=0;
00507 
00508                 while(((*host_name_ptr)!='.')&&((*host_name_ptr)!='\0')){
00509                         i++;
00510                         *buf_ptr++=*host_name_ptr++;
00511                         if(buf_ptr==(net_buf+NETWORK_TX_BUFFER_SIZE)){
00512                                 DEBUGOUT("DNS: Buffer overflow!!!\r\n");
00513                                 return(DNS_ERROR_OVERFLOW);
00514                         }
00515                 }
00516 
00517                 /* label shorter than 63 bytes or less? */
00518                 if((i<=0)||(i>=64)){
00519                         DEBUGOUT("DNS: Label size wrong! Aborting....\r\n");
00520                         return(DNS_ERROR_LABEL);
00521                 }
00522 
00523                 /* it seems ok for now. Increase total name length*/
00524                 total+=i;
00525 
00526                 if(total>=264){
00527                         DEBUGOUT("DNS: Name size wrong! Aborting....\r\n");
00528                         return(DNS_ERROR_NAME);
00529                 }
00530 
00531                 *(buf_ptr-i-1)=i;       /* store label length */
00532 
00533                 /* ok, where are we ? */
00534                 if((*host_name_ptr)=='.'){
00535                         /* still not at the end, skip dot */
00536                         host_name_ptr++;
00537                 }else
00538                         if((*host_name_ptr)=='\0'){
00539                                 /* OHO, finished,
00540                                         add ZERO,QTYPE and QCLASS */
00541                                 *buf_ptr++=0x00;
00542                                 *buf_ptr++=0x00;
00543                                 *buf_ptr++=0x01;
00544                                 *buf_ptr++=0x00;
00545                                 *buf_ptr++=0x01;
00546                                 kick_WD();
00547                                 /* ok, now send the request */
00548                                 return udp_send(dns_socket,dns_tmp_ip,DNS_UDP_PORT,net_buf+UDP_APP_OFFSET,NETWORK_TX_BUFFER_SIZE-UDP_APP_OFFSET,buf_ptr-(net_buf+UDP_APP_OFFSET));
00549                         }
00550         }
00551 }
00552 

Generated on Sun Aug 3 20:32:59 2003 for OpenTCP by doxygen1.2.18