Library to resolve text URLs to IP addresses (IPv4)

Dependents:   NetworkSocketAPI NetworkSocketAPI Nucleo-AWS-IoT-mbed

Committer:
sarahmarshy
Date:
Tue Jul 14 20:48:12 2015 +0000
Revision:
0:fff4b9055396
Child:
1:5d978992a518
Initial commit of DNS query library. Changes made to @leihen's code.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
sarahmarshy 0:fff4b9055396 1 /* Copyright (c) 2013 Henry Leinen (henry[dot]leinen [at] online [dot] de)
sarahmarshy 0:fff4b9055396 2 *
sarahmarshy 0:fff4b9055396 3 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
sarahmarshy 0:fff4b9055396 4 * and associated documentation files (the "Software"), to deal in the Software without restriction,
sarahmarshy 0:fff4b9055396 5 * including without limitation the rights to use, copy, modify, merge, publish, distribute,
sarahmarshy 0:fff4b9055396 6 * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
sarahmarshy 0:fff4b9055396 7 * furnished to do so, subject to the following conditions:
sarahmarshy 0:fff4b9055396 8 *
sarahmarshy 0:fff4b9055396 9 * The above copyright notice and this permission notice shall be included in all copies or
sarahmarshy 0:fff4b9055396 10 * substantial portions of the Software.
sarahmarshy 0:fff4b9055396 11 *
sarahmarshy 0:fff4b9055396 12 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
sarahmarshy 0:fff4b9055396 13 * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
sarahmarshy 0:fff4b9055396 14 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
sarahmarshy 0:fff4b9055396 15 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
sarahmarshy 0:fff4b9055396 16 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
sarahmarshy 0:fff4b9055396 17 */
sarahmarshy 0:fff4b9055396 18 #include "mbed.h"
sarahmarshy 0:fff4b9055396 19 #include "DnsQuery.h"
sarahmarshy 0:fff4b9055396 20 #include "UDPSocket.h"
sarahmarshy 0:fff4b9055396 21
sarahmarshy 0:fff4b9055396 22 //Debug is disabled by default
sarahmarshy 0:fff4b9055396 23 #if 0
sarahmarshy 0:fff4b9055396 24 #define DBG(x, ...) printf("[DNS : DBG]"x" \t[%s,%d]\r\n", ##__VA_ARGS__,__FILE__,__LINE__);
sarahmarshy 0:fff4b9055396 25 #define WARN(x, ...) printf("[DNS : WARN]"x" \t[%s,%d]\r\n", ##__VA_ARGS__,__FILE__,__LINE__);
sarahmarshy 0:fff4b9055396 26 #define ERR(x, ...) printf("[DNS : ERR]"x" \t[%s,%d]\r\n", ##__VA_ARGS__,__FILE__,__LINE__);
sarahmarshy 0:fff4b9055396 27 #else
sarahmarshy 0:fff4b9055396 28 #define DBG(x, ...) //wait_us(10);
sarahmarshy 0:fff4b9055396 29 #define WARN(x, ...) //wait_us(10);
sarahmarshy 0:fff4b9055396 30 #define ERR(x, ...)
sarahmarshy 0:fff4b9055396 31 #endif
sarahmarshy 0:fff4b9055396 32
sarahmarshy 0:fff4b9055396 33 #if 0
sarahmarshy 0:fff4b9055396 34 #define INFO(x, ...) printf("[DNS : INFO]"x" \t[%s,%d]\r\n", ##__VA_ARGS__,__FILE__,__LINE__);
sarahmarshy 0:fff4b9055396 35 #else
sarahmarshy 0:fff4b9055396 36 #define INFO(x, ...)
sarahmarshy 0:fff4b9055396 37 #endif
sarahmarshy 0:fff4b9055396 38
sarahmarshy 0:fff4b9055396 39
sarahmarshy 0:fff4b9055396 40
sarahmarshy 0:fff4b9055396 41 DnsQuery::DnsQuery(IPADDRESS_t *dnsip)
sarahmarshy 0:fff4b9055396 42 {
sarahmarshy 0:fff4b9055396 43 _dnsip.sin_addr.o1 = dnsip->sin_addr.o1;
sarahmarshy 0:fff4b9055396 44 _dnsip.sin_addr.o2 = dnsip->sin_addr.o2;
sarahmarshy 0:fff4b9055396 45 _dnsip.sin_addr.o3 = dnsip->sin_addr.o3;
sarahmarshy 0:fff4b9055396 46 _dnsip.sin_addr.o4 = dnsip->sin_addr.o4;
sarahmarshy 0:fff4b9055396 47
sarahmarshy 0:fff4b9055396 48 INFO("Setting DNS = %d.%d.%d.%d !", dnsip->sin_addr.o1, dnsip->sin_addr.o2, dnsip->sin_addr.o3, dnsip->sin_addr.o4);
sarahmarshy 0:fff4b9055396 49 INFO("Accepting DNS = %s !",_dnsip.string_format());
sarahmarshy 0:fff4b9055396 50 }
sarahmarshy 0:fff4b9055396 51
sarahmarshy 0:fff4b9055396 52 bool DnsQuery::gethostbyname(char* hostname, IPADDRESS_t &ipaddress)
sarahmarshy 0:fff4b9055396 53 {
sarahmarshy 0:fff4b9055396 54 IPADDRESS_t dnsIp_1 = {209,244,0,3};
sarahmarshy 0:fff4b9055396 55 IPADDRESS_t dnsIp_2 = {8,8,8,8};
sarahmarshy 0:fff4b9055396 56 IPADDRESS_t dnsIp_3 = {84,200,69,80};
sarahmarshy 0:fff4b9055396 57 IPADDRESS_t dnsIp_4 = {8,26,56,26};
sarahmarshy 0:fff4b9055396 58 IPADDRESS_t dnsIp_5 = {208,67,222,222};
sarahmarshy 0:fff4b9055396 59 IPADDRESS_t dnsIp;
sarahmarshy 0:fff4b9055396 60 for(int i = 0; i<5; i++){
sarahmarshy 0:fff4b9055396 61 switch(i) {
sarahmarshy 0:fff4b9055396 62 case 0 : dnsIp= dnsIp_1; break ;
sarahmarshy 0:fff4b9055396 63 case 1 : dnsIp= dnsIp_2; break ;
sarahmarshy 0:fff4b9055396 64 case 2 : dnsIp= dnsIp_3; break ;
sarahmarshy 0:fff4b9055396 65 case 3 : dnsIp= dnsIp_4; break ;
sarahmarshy 0:fff4b9055396 66 case 4 : dnsIp= dnsIp_5; break ;
sarahmarshy 0:fff4b9055396 67 }
sarahmarshy 0:fff4b9055396 68 DnsQuery dns = DnsQuery(&dnsIp);
sarahmarshy 0:fff4b9055396 69 if(dns.getIP(hostname, ipaddress)){
sarahmarshy 0:fff4b9055396 70 return true;
sarahmarshy 0:fff4b9055396 71 }
sarahmarshy 0:fff4b9055396 72
sarahmarshy 0:fff4b9055396 73 }
sarahmarshy 0:fff4b9055396 74 return false;
sarahmarshy 0:fff4b9055396 75
sarahmarshy 0:fff4b9055396 76 }
sarahmarshy 0:fff4b9055396 77
sarahmarshy 0:fff4b9055396 78 bool DnsQuery::getIP(char* hostname, IPADDRESS_t &ipaddress)
sarahmarshy 0:fff4b9055396 79 {
sarahmarshy 0:fff4b9055396 80 INFO("%s", hostname);
sarahmarshy 0:fff4b9055396 81 int len = 0;
sarahmarshy 0:fff4b9055396 82 if (hostname == NULL)
sarahmarshy 0:fff4b9055396 83 return false;
sarahmarshy 0:fff4b9055396 84 len = strlen(hostname);
sarahmarshy 0:fff4b9055396 85 if ((len >128) || (len == 0))
sarahmarshy 0:fff4b9055396 86 return false;
sarahmarshy 0:fff4b9055396 87 memset (&ipaddress, 0, sizeof(ipaddress));
sarahmarshy 0:fff4b9055396 88
sarahmarshy 0:fff4b9055396 89 int packetlen = /* size of HEADER structure */ 12 + /* size of QUESTION Structure */5 + len + 1;
sarahmarshy 0:fff4b9055396 90 char *packet = new char[packetlen]; /* this is the UDP packet to send to the DNS */
sarahmarshy 0:fff4b9055396 91 if (packet == NULL)
sarahmarshy 0:fff4b9055396 92 return false;
sarahmarshy 0:fff4b9055396 93
sarahmarshy 0:fff4b9055396 94 // Fill the header
sarahmarshy 0:fff4b9055396 95 memset(packet, 0, packetlen);
sarahmarshy 0:fff4b9055396 96 packet[1] = 1; // ID = 1
sarahmarshy 0:fff4b9055396 97 packet[5] = 1; // QDCOUNT = 1 (contains one question)
sarahmarshy 0:fff4b9055396 98 packet[2] = 1; // recursion requested
sarahmarshy 0:fff4b9055396 99
sarahmarshy 0:fff4b9055396 100 int c = 13; // point to NAME element in question section or request
sarahmarshy 0:fff4b9055396 101 int cnt = 12; // points to the counter of
sarahmarshy 0:fff4b9055396 102 packet[cnt] = 0;
sarahmarshy 0:fff4b9055396 103 for (int i = 0 ; i < len ; i++) {
sarahmarshy 0:fff4b9055396 104 if (hostname[i] != '.') {
sarahmarshy 0:fff4b9055396 105 // Copy the character and increment the character counter
sarahmarshy 0:fff4b9055396 106 packet[cnt]++;
sarahmarshy 0:fff4b9055396 107 packet[c++] = hostname[i];
sarahmarshy 0:fff4b9055396 108 } else {
sarahmarshy 0:fff4b9055396 109 // Finished with this part, so go to the next
sarahmarshy 0:fff4b9055396 110 cnt = c++;
sarahmarshy 0:fff4b9055396 111 packet[cnt] = 0;
sarahmarshy 0:fff4b9055396 112 }
sarahmarshy 0:fff4b9055396 113 }
sarahmarshy 0:fff4b9055396 114
sarahmarshy 0:fff4b9055396 115 // Terminate this domain name with a zero entry
sarahmarshy 0:fff4b9055396 116 packet[c++] = 0;
sarahmarshy 0:fff4b9055396 117
sarahmarshy 0:fff4b9055396 118 // Set QTYPE
sarahmarshy 0:fff4b9055396 119 packet[c++] = 0;
sarahmarshy 0:fff4b9055396 120 packet[c++] = 1;
sarahmarshy 0:fff4b9055396 121 // Set QCLASS
sarahmarshy 0:fff4b9055396 122 packet[c++] = 0;
sarahmarshy 0:fff4b9055396 123 packet[c++] = 1;
sarahmarshy 0:fff4b9055396 124
sarahmarshy 0:fff4b9055396 125
sarahmarshy 0:fff4b9055396 126 // Ready to send to DNS
sarahmarshy 0:fff4b9055396 127 UDPSocket sock = UDPSocket();
sarahmarshy 0:fff4b9055396 128 Endpoint e = Endpoint();
sarahmarshy 0:fff4b9055396 129 //INFO("Using IP: %s",_dnsip.string_format());
sarahmarshy 0:fff4b9055396 130 char ip[7];
sarahmarshy 0:fff4b9055396 131 sprintf(ip,"%s",_dnsip.string_format());
sarahmarshy 0:fff4b9055396 132 e.set_address(ip, 53);
sarahmarshy 0:fff4b9055396 133 delete ip;
sarahmarshy 0:fff4b9055396 134
sarahmarshy 0:fff4b9055396 135 INFO("Sending packet");
sarahmarshy 0:fff4b9055396 136 if (sock.sendTo(e, packet, packetlen) < 0) {
sarahmarshy 0:fff4b9055396 137 delete packet;
sarahmarshy 0:fff4b9055396 138 return false;
sarahmarshy 0:fff4b9055396 139 }
sarahmarshy 0:fff4b9055396 140
sarahmarshy 0:fff4b9055396 141 delete packet;
sarahmarshy 0:fff4b9055396 142
sarahmarshy 0:fff4b9055396 143 packet = new char [1024];
sarahmarshy 0:fff4b9055396 144 if (packet == NULL) {
sarahmarshy 0:fff4b9055396 145 return false;
sarahmarshy 0:fff4b9055396 146 }
sarahmarshy 0:fff4b9055396 147
sarahmarshy 0:fff4b9055396 148 // Receive the answer from DNS
sarahmarshy 0:fff4b9055396 149 Timer t;
sarahmarshy 0:fff4b9055396 150 t.start();
sarahmarshy 0:fff4b9055396 151 int response_length = 0;
sarahmarshy 0:fff4b9055396 152 while (t.read_ms() < 10000) {
sarahmarshy 0:fff4b9055396 153 INFO("Recieving");
sarahmarshy 0:fff4b9055396 154 response_length = sock.receiveFrom(e, packet, 1024);
sarahmarshy 0:fff4b9055396 155 if (response_length > 0 ) {
sarahmarshy 0:fff4b9055396 156 int offset = packetlen;
sarahmarshy 0:fff4b9055396 157 for(int i = offset; i < 1024; i++) {
sarahmarshy 0:fff4b9055396 158 if(0x3A==packet[i]){
sarahmarshy 0:fff4b9055396 159 offset = i+1;
sarahmarshy 0:fff4b9055396 160 break;
sarahmarshy 0:fff4b9055396 161 }
sarahmarshy 0:fff4b9055396 162 }
sarahmarshy 0:fff4b9055396 163 char *offset_packet = packet + offset;
sarahmarshy 0:fff4b9055396 164 if (!resolve(offset_packet, ipaddress)) {
sarahmarshy 0:fff4b9055396 165 break;
sarahmarshy 0:fff4b9055396 166 }
sarahmarshy 0:fff4b9055396 167
sarahmarshy 0:fff4b9055396 168 // cleanup and return
sarahmarshy 0:fff4b9055396 169 delete packet;
sarahmarshy 0:fff4b9055396 170 sock.close();
sarahmarshy 0:fff4b9055396 171 //INFO("Found this IP:%s",ipaddress.string_format());
sarahmarshy 0:fff4b9055396 172 return true;
sarahmarshy 0:fff4b9055396 173 } else {
sarahmarshy 0:fff4b9055396 174 ERR("SocketRecvFrom returned %d !", response_length);
sarahmarshy 0:fff4b9055396 175 }
sarahmarshy 0:fff4b9055396 176 }
sarahmarshy 0:fff4b9055396 177 sock.close();
sarahmarshy 0:fff4b9055396 178 delete packet;
sarahmarshy 0:fff4b9055396 179 ERR("NO IP FOUND\n");
sarahmarshy 0:fff4b9055396 180 return false;
sarahmarshy 0:fff4b9055396 181 }
sarahmarshy 0:fff4b9055396 182
sarahmarshy 0:fff4b9055396 183
sarahmarshy 0:fff4b9055396 184 bool DnsQuery::resolve(char* resp, IPADDRESS_t &ipaddress)
sarahmarshy 0:fff4b9055396 185 {
sarahmarshy 0:fff4b9055396 186
sarahmarshy 0:fff4b9055396 187 int ID = (((int)resp[0]) <<8) + resp[1];
sarahmarshy 0:fff4b9055396 188 int QR = resp[2] >>7;
sarahmarshy 0:fff4b9055396 189 int Opcode = (resp[2]>>3) & 0x0F;
sarahmarshy 0:fff4b9055396 190 int RCODE = (resp[3] & 0x0F);
sarahmarshy 0:fff4b9055396 191 int ANCOUNT = (((int)resp[6])<<8)+ resp[7];
sarahmarshy 0:fff4b9055396 192
sarahmarshy 0:fff4b9055396 193 INFO("Resolving response : ID = %d, QR = %d, Opcode = %d, RCODE = %d", ID, QR, Opcode, RCODE);
sarahmarshy 0:fff4b9055396 194 if ((ID != 1) || (QR != 1) || (Opcode != 0) || (RCODE != 0)) {
sarahmarshy 0:fff4b9055396 195 ERR("Received non matching response from DNS !");
sarahmarshy 0:fff4b9055396 196 return false;
sarahmarshy 0:fff4b9055396 197 }
sarahmarshy 0:fff4b9055396 198
sarahmarshy 0:fff4b9055396 199 int c = 12;
sarahmarshy 0:fff4b9055396 200 int d;
sarahmarshy 0:fff4b9055396 201 // Skip domain question
sarahmarshy 0:fff4b9055396 202 while( (d=resp[c++]) != 0) {
sarahmarshy 0:fff4b9055396 203 c+=d;
sarahmarshy 0:fff4b9055396 204 }
sarahmarshy 0:fff4b9055396 205 c+= 4; // skip QTYPE and QCLASS
sarahmarshy 0:fff4b9055396 206
sarahmarshy 0:fff4b9055396 207 // Here comes the resource record
sarahmarshy 0:fff4b9055396 208 for (int ans = 0 ; ans < ANCOUNT; ans++) {
sarahmarshy 0:fff4b9055396 209 if (parseRR(resp, c, ipaddress)) {
sarahmarshy 0:fff4b9055396 210 return true;
sarahmarshy 0:fff4b9055396 211 }
sarahmarshy 0:fff4b9055396 212 }
sarahmarshy 0:fff4b9055396 213
sarahmarshy 0:fff4b9055396 214 return false;
sarahmarshy 0:fff4b9055396 215 }
sarahmarshy 0:fff4b9055396 216
sarahmarshy 0:fff4b9055396 217 bool DnsQuery::parseRR(char *resp, int& c, IPADDRESS_t& adr )
sarahmarshy 0:fff4b9055396 218 {
sarahmarshy 0:fff4b9055396 219 int n = 0;
sarahmarshy 0:fff4b9055396 220
sarahmarshy 0:fff4b9055396 221 while( (n=resp[c++]) != 0) {
sarahmarshy 0:fff4b9055396 222 if ((n & 0xc0) != 0) {
sarahmarshy 0:fff4b9055396 223 // This is a link
sarahmarshy 0:fff4b9055396 224 c++;
sarahmarshy 0:fff4b9055396 225 break;
sarahmarshy 0:fff4b9055396 226 } else {
sarahmarshy 0:fff4b9055396 227 c+= n; // skip this segment, not interested in string domain names
sarahmarshy 0:fff4b9055396 228 }
sarahmarshy 0:fff4b9055396 229 }
sarahmarshy 0:fff4b9055396 230
sarahmarshy 0:fff4b9055396 231 int TYPE = (((int)resp[c])<<8) + resp[c+1];
sarahmarshy 0:fff4b9055396 232 int CLASS = (((int)resp[c+2])<<8) + resp[c+3];
sarahmarshy 0:fff4b9055396 233 int RDLENGTH = (((int)resp[c+8])<<8) + resp[c+9];
sarahmarshy 0:fff4b9055396 234
sarahmarshy 0:fff4b9055396 235 INFO("Record of TYPE=%d and CLASS=%d detected !", TYPE, CLASS);
sarahmarshy 0:fff4b9055396 236 c+= 10;
sarahmarshy 0:fff4b9055396 237 if ((CLASS == 1) && (TYPE == 1)) {
sarahmarshy 0:fff4b9055396 238 adr.sin_addr.o1 = resp[c];
sarahmarshy 0:fff4b9055396 239 adr.sin_addr.o2 = resp[c+1];
sarahmarshy 0:fff4b9055396 240 adr.sin_addr.o3 = resp[c+2];
sarahmarshy 0:fff4b9055396 241 adr.sin_addr.o4 = resp[c+3];
sarahmarshy 0:fff4b9055396 242 c+= RDLENGTH;
sarahmarshy 0:fff4b9055396 243 return true;
sarahmarshy 0:fff4b9055396 244 } else {
sarahmarshy 0:fff4b9055396 245 }
sarahmarshy 0:fff4b9055396 246 c+= RDLENGTH;
sarahmarshy 0:fff4b9055396 247
sarahmarshy 0:fff4b9055396 248 return false;
sarahmarshy 0:fff4b9055396 249 }