Implementation of the WifiPlusClick hardware module.
Dependents: WifiPlusKlickExample
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 }
Generated on Tue Jul 12 2022 23:18:35 by 1.7.2