Implementation of the WifiPlusClick hardware module.

Dependents:   WifiPlusKlickExample

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers DnsQuery.cpp Source File

DnsQuery.cpp

00001 /* Copyright (c) 2013 Henry Leinen (henry[dot]leinen [at] online [dot] de)
00002  *
00003  * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
00004  * and associated documentation files (the "Software"), to deal in the Software without restriction,
00005  * including without limitation the rights to use, copy, modify, merge, publish, distribute,
00006  * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
00007  * furnished to do so, subject to the following conditions:
00008  *
00009  * The above copyright notice and this permission notice shall be included in all copies or
00010  * substantial portions of the Software.
00011  *
00012  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
00013  * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
00014  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
00015  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
00016  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
00017  */
00018 #include "mbed.h"
00019 #include "DnsQuery.h"
00020 
00021 #define DEBUG
00022 #include "debug.h"
00023 
00024 
00025 
00026 DnsQuery::DnsQuery(Wifi* wifi, IPADDRESS_t *dnsip)
00027     : _wifi(wifi)
00028 {
00029     _dnsip.sin_addr.o1 = dnsip->sin_addr.o1;
00030     _dnsip.sin_addr.o2 = dnsip->sin_addr.o2;
00031     _dnsip.sin_addr.o3 = dnsip->sin_addr.o3;
00032     _dnsip.sin_addr.o4 = dnsip->sin_addr.o4;
00033     INFO("Setting   DNS = %d.%d.%d.%d !", dnsip->sin_addr.o1, dnsip->sin_addr.o2, dnsip->sin_addr.o3, dnsip->sin_addr.o4);
00034     INFO("Accepting DNS = %d.%d.%d.%d !", _dnsip.sin_addr.o1, _dnsip.sin_addr.o2, _dnsip.sin_addr.o3, _dnsip.sin_addr.o4);
00035 }
00036 
00037 bool DnsQuery::gethostbyname(const char* hostname, IPADDRESS_t &ipaddress)
00038 {
00039     int len = 0;
00040     if (hostname == NULL)
00041         return false;
00042     len = strlen(hostname);
00043     if ((len >128) || (len == 0))
00044         return false;
00045     memset (&ipaddress, 0, sizeof(ipaddress));
00046     
00047     int packetlen = /* size of HEADER structure */ 12 + /* size of QUESTION Structure */5 + len + 1;
00048     char *packet = new char[packetlen]; /* this is the UDP packet to send to the DNS */
00049     if (packet == NULL)
00050         return false;
00051     
00052     //  Fill the header
00053     memset(packet, 0, packetlen);
00054     packet[1] = 1;      //  ID = 1
00055     packet[5] = 1;      // QDCOUNT = 1 (contains one question)
00056 
00057     int c = 13;         //  point to NAME element in question section or request
00058     int cnt = 12;       //  points to the counter of
00059     packet[cnt] = 0;
00060     for (int i = 0 ; i < len ; i++) {
00061         if (hostname[i] != '.') {
00062             //  Copy the character and increment the character counter
00063             packet[cnt]++;
00064             packet[c++] = hostname[i];
00065         } else {
00066             //  Finished with this part, so go to the next
00067             cnt = c++;
00068             packet[cnt] = 0;
00069         }
00070     }
00071     
00072     //  Terminate this domain name with a zero entry
00073     packet[c++] = 0;
00074     
00075     //  Set QTYPE
00076     packet[c++] = 0;
00077     packet[c++] = 1;
00078     //  Set QCLASS
00079     packet[c++] = 0;
00080     packet[c++] = 1;
00081     
00082     //  REMOVE ME !!!!
00083     std::printf("--> DUMPING UDP PACKET : ");
00084     int port;
00085     for( int i = 0 ; i < c ; i++) {
00086         std::printf("%02x ", packet[i]);
00087     }
00088     std::printf("\n\n\n");
00089     //  Ready to send to DNS
00090     SOCKET_HANDLE_t sock = _wifi->SocketCreate(UDP);
00091     if (sock == InvalidSocketHandle) {
00092         delete packet;
00093         return false;
00094     }
00095  
00096     INFO("Using %d.%d.%d.%d as DNS !", _dnsip.sin_addr.o1, _dnsip.sin_addr.o2, _dnsip.sin_addr.o3, _dnsip.sin_addr.o4);
00097     if (!_wifi->SocketSendTo(sock, &_dnsip, 53, packet, packetlen)) {
00098         delete packet;
00099         _wifi->SocketClose(sock);
00100         return false;
00101     }
00102     
00103     delete packet;
00104     
00105     packet = new char [1024];
00106     if (packet == NULL) {
00107         _wifi->SocketClose(sock);
00108         return false;
00109     }
00110     
00111     //  Receive the answer from DNS
00112     Timer t;
00113     int recvd = 0;
00114     t.start();
00115     
00116     while (t.read_ms() < 10000) {
00117         if ((recvd = _wifi->SocketRecvFrom (sock, NULL, &port, packet, 1024)) > 0 ) {
00118             //  process input
00119             std::printf("Received %d bytes from DNS !\n", recvd);
00120             if (!resolve(packet, ipaddress)) {
00121                 break;
00122             }
00123                         
00124             //  cleanup and return
00125             delete packet;
00126             _wifi->SocketClose(sock);
00127             return true;
00128         } else {
00129             ERR("SocketRecvFrom returned %d !", recvd);
00130         }
00131     }    
00132 
00133     delete packet;
00134     
00135     _wifi->SocketClose(sock);
00136         
00137     return false;
00138 }
00139 
00140 
00141 bool DnsQuery::resolve(char* resp, IPADDRESS_t &ipaddress)
00142 {
00143     int ID = (((int)resp[0]) <<8) + resp[1];
00144     int QR = resp[2] >>7;
00145     int Opcode = (resp[2]>>3) & 0x0F;
00146     int RCODE = (resp[3] & 0x0F);
00147     int ANCOUNT = (((int)resp[6])<<8)+ resp[7];
00148     
00149     INFO("Resolving response : ID = %d, QR = %d, Opcode = %d, RCODE = %d", ID, QR, Opcode, RCODE);
00150     if ((ID != 1) || (QR != 1) || (Opcode != 0) || (RCODE != 0)) {
00151         ERR("Received non matching response from DNS !");
00152         return false;
00153     }
00154     
00155     int c = 12;
00156     int d;
00157     //  Skip domain question
00158     while(  (d=resp[c++]) != 0) {
00159         c+=d;
00160     }
00161     c+= 4; //   skip QTYPE and QCLASS
00162     
00163     //  Here comes the resource record
00164     for (int ans = 0 ; ans < ANCOUNT; ans++) {
00165         if (parseRR(resp, c, ipaddress)) {
00166             return true;
00167         }
00168     }
00169     
00170     return false;
00171 }
00172 
00173 bool DnsQuery::parseRR(char *resp, int& c, IPADDRESS_t& adr )
00174 {
00175     int n = 0;
00176     
00177     while( (n=resp[c++]) != 0) {
00178         if ((n & 0xc0) != 0) {
00179             //  This is a link
00180             c++;
00181             break;
00182         } else {
00183             c+= n;  //  skip this segment, not interested in string domain names
00184         }
00185     }
00186     
00187     int TYPE = (((int)resp[c])<<8) + resp[c+1];
00188     int CLASS = (((int)resp[c+2])<<8) + resp[c+3];
00189     int RDLENGTH = (((int)resp[c+8])<<8) + resp[c+9];
00190 
00191     INFO("Record of TYPE=%d and CLASS=%d detected !", TYPE, CLASS);
00192     c+= 10;
00193     if ((CLASS == 1) && (TYPE == 1)) {
00194         adr.sin_addr.o1 = resp[c];
00195         adr.sin_addr.o2 = resp[c+1];
00196         adr.sin_addr.o3 = resp[c+2];
00197         adr.sin_addr.o4 = resp[c+3];
00198         c+= RDLENGTH;
00199         return true;
00200     } else {
00201     }
00202     c+= RDLENGTH;
00203     
00204     return false;
00205 }