Library to resolve text URLs to IP addresses (IPv4)

Dependents:   NetworkSocketAPI NetworkSocketAPI Nucleo-AWS-IoT-mbed

Committer:
Christopher Haster
Date:
Sun Feb 28 22:07:29 2016 -0600
Revision:
10:0fe2c42a0261
Parent:
9:16e5208cc4ef
Child:
12:e23ef3dab4b9
Rearranged DnsQuery to expose errors

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 "DnsQuery.h"
Christopher Haster 4:3749346dcd59 19 #include <stdio.h>
Christopher Haster 4:3749346dcd59 20 #include <string.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
Christopher Haster 10:0fe2c42a0261 40 #define DNS_COUNT (sizeof DNS_IPS / sizeof DNS_IPS[0])
Christopher Haster 10:0fe2c42a0261 41 const char *DNS_IPS[] = {
Christopher Haster 10:0fe2c42a0261 42 "8.8.8.8",
Christopher Haster 10:0fe2c42a0261 43 "209.244.0.3",
Christopher Haster 10:0fe2c42a0261 44 "84.200.69.80",
Christopher Haster 10:0fe2c42a0261 45 "8.26.56.26",
Christopher Haster 10:0fe2c42a0261 46 "208.67.222.222"
Christopher Haster 10:0fe2c42a0261 47 };
Christopher Haster 7:cbe1ef566314 48
Christopher Haster 10:0fe2c42a0261 49 static bool isIP(const char *host)
Christopher Haster 7:cbe1ef566314 50 {
Christopher Haster 7:cbe1ef566314 51 int i;
Christopher Haster 7:cbe1ef566314 52
Christopher Haster 10:0fe2c42a0261 53 for (i = 0; host[i]; i++) {
Christopher Haster 10:0fe2c42a0261 54 if (!(host[i] >= '0' && host[i] <= '9') && host[i] != '.') {
Christopher Haster 7:cbe1ef566314 55 return false;
Christopher Haster 7:cbe1ef566314 56 }
Christopher Haster 7:cbe1ef566314 57 }
Christopher Haster 7:cbe1ef566314 58
Christopher Haster 10:0fe2c42a0261 59 // Ending with '.' garuntees host
Christopher Haster 10:0fe2c42a0261 60 if (i > 0 && host[i-1] == '.') {
Christopher Haster 7:cbe1ef566314 61 return false;
Christopher Haster 7:cbe1ef566314 62 }
Christopher Haster 7:cbe1ef566314 63
Christopher Haster 7:cbe1ef566314 64 return true;
Christopher Haster 7:cbe1ef566314 65 }
Christopher Haster 7:cbe1ef566314 66
Christopher Haster 10:0fe2c42a0261 67
Christopher Haster 10:0fe2c42a0261 68 static bool parseRR(uint8_t *resp, int& c, char* adr )
Christopher Haster 10:0fe2c42a0261 69 {
Christopher Haster 10:0fe2c42a0261 70 int n = 0;
Christopher Haster 10:0fe2c42a0261 71 while( (n=resp[c++]) != 0) {
Christopher Haster 10:0fe2c42a0261 72 if ((n & 0xc0) != 0) {
Christopher Haster 10:0fe2c42a0261 73 // This is a link
Christopher Haster 10:0fe2c42a0261 74 c++;
Christopher Haster 10:0fe2c42a0261 75 break;
Christopher Haster 10:0fe2c42a0261 76 } else {
Christopher Haster 10:0fe2c42a0261 77 c+= n; // skip this segment, not interested in string domain names
Christopher Haster 10:0fe2c42a0261 78 }
Christopher Haster 10:0fe2c42a0261 79 }
Christopher Haster 10:0fe2c42a0261 80
Christopher Haster 10:0fe2c42a0261 81 int TYPE = (((int)resp[c])<<8) + resp[c+1];
Christopher Haster 10:0fe2c42a0261 82 int CLASS = (((int)resp[c+2])<<8) + resp[c+3];
Christopher Haster 10:0fe2c42a0261 83 int RDLENGTH = (((int)resp[c+8])<<8) + resp[c+9];
Christopher Haster 10:0fe2c42a0261 84
Christopher Haster 10:0fe2c42a0261 85 INFO("Record of TYPE=%d and CLASS=%d detected !", TYPE, CLASS);
Christopher Haster 10:0fe2c42a0261 86 c+= 10;
Christopher Haster 10:0fe2c42a0261 87 if ((CLASS == 1) && (TYPE == 1)) {
Christopher Haster 10:0fe2c42a0261 88 sprintf(adr,"%d.%d.%d.%d", resp[c], resp[c+1], resp[c+2], resp[c+3]);
Christopher Haster 10:0fe2c42a0261 89 c+= RDLENGTH;
Christopher Haster 10:0fe2c42a0261 90 return true;
Christopher Haster 10:0fe2c42a0261 91 } else {
Christopher Haster 10:0fe2c42a0261 92 }
Christopher Haster 10:0fe2c42a0261 93 c+= RDLENGTH;
Christopher Haster 10:0fe2c42a0261 94
Christopher Haster 10:0fe2c42a0261 95 return false;
Christopher Haster 10:0fe2c42a0261 96 }
Christopher Haster 10:0fe2c42a0261 97
Christopher Haster 10:0fe2c42a0261 98
Christopher Haster 10:0fe2c42a0261 99 static bool resolve(unsigned char* resp, char* ipaddress)
Christopher Haster 10:0fe2c42a0261 100 {
Christopher Haster 10:0fe2c42a0261 101
Christopher Haster 10:0fe2c42a0261 102 int ID = (((int)resp[0]) <<8) + resp[1];
Christopher Haster 10:0fe2c42a0261 103 int QR = resp[2] >>7;
Christopher Haster 10:0fe2c42a0261 104 int Opcode = (resp[2]>>3) & 0x0F;
Christopher Haster 10:0fe2c42a0261 105 int RCODE = (resp[3] & 0x0F);
Christopher Haster 10:0fe2c42a0261 106 int ANCOUNT = (((int)resp[6])<<8)+ resp[7];
Christopher Haster 10:0fe2c42a0261 107
Christopher Haster 10:0fe2c42a0261 108 INFO("Resolving response : ID = %d, QR = %d, Opcode = %d, RCODE = %d", ID, QR, Opcode, RCODE);
Christopher Haster 10:0fe2c42a0261 109 if ((ID != 1) || (QR != 1) || (Opcode != 0) || (RCODE != 0)) {
Christopher Haster 10:0fe2c42a0261 110 ERR("Received non matching response from DNS !");
Christopher Haster 10:0fe2c42a0261 111 return false;
Christopher Haster 10:0fe2c42a0261 112 }
Christopher Haster 10:0fe2c42a0261 113
Christopher Haster 10:0fe2c42a0261 114 int c = 12;
Christopher Haster 10:0fe2c42a0261 115 int d;
Christopher Haster 10:0fe2c42a0261 116 // Skip domain question
Christopher Haster 10:0fe2c42a0261 117 while( (d=resp[c++]) != 0) {
Christopher Haster 10:0fe2c42a0261 118 c+=d;
Christopher Haster 10:0fe2c42a0261 119 }
Christopher Haster 10:0fe2c42a0261 120 c+= 4; // skip QTYPE and QCLASS
Christopher Haster 10:0fe2c42a0261 121
Christopher Haster 10:0fe2c42a0261 122 // Here comes the resource record
Christopher Haster 10:0fe2c42a0261 123 for (int ans = 0 ; ans < ANCOUNT; ans++) {
Christopher Haster 10:0fe2c42a0261 124 if (parseRR(resp, c, ipaddress)) {
Christopher Haster 10:0fe2c42a0261 125 return true;
Christopher Haster 10:0fe2c42a0261 126 }
Christopher Haster 10:0fe2c42a0261 127 }
Christopher Haster 10:0fe2c42a0261 128
Christopher Haster 10:0fe2c42a0261 129 return false;
Christopher Haster 10:0fe2c42a0261 130 }
Christopher Haster 10:0fe2c42a0261 131
Christopher Haster 10:0fe2c42a0261 132
Christopher Haster 10:0fe2c42a0261 133 int32_t dnsQuery(NetworkInterface *iface, const char *host, char *ip)
Christopher Haster 10:0fe2c42a0261 134 {
Christopher Haster 10:0fe2c42a0261 135 if (isIP(host)) {
Christopher Haster 10:0fe2c42a0261 136 strcpy(ip, host);
Christopher Haster 10:0fe2c42a0261 137 return 0;
Christopher Haster 10:0fe2c42a0261 138 }
Christopher Haster 10:0fe2c42a0261 139
Christopher Haster 10:0fe2c42a0261 140 UDPSocket sock(iface);
Christopher Haster 10:0fe2c42a0261 141 int32_t err;
Christopher Haster 10:0fe2c42a0261 142
Christopher Haster 10:0fe2c42a0261 143 for (unsigned i = 0; i < DNS_COUNT; i++) {
Christopher Haster 10:0fe2c42a0261 144 err = sock.open(DNS_IPS[0], 53);
Christopher Haster 10:0fe2c42a0261 145 if (err < 0) {
Christopher Haster 10:0fe2c42a0261 146 return err;
Christopher Haster 10:0fe2c42a0261 147 }
Christopher Haster 10:0fe2c42a0261 148
Christopher Haster 10:0fe2c42a0261 149 err = dnsQuery(&sock, host, ip);
Christopher Haster 10:0fe2c42a0261 150 if (err >= 0) {
Christopher Haster 10:0fe2c42a0261 151 return sock.close();
Christopher Haster 10:0fe2c42a0261 152 } else if (err != NS_ERROR_DNS_FAILURE) {
Christopher Haster 10:0fe2c42a0261 153 sock.close();
Christopher Haster 10:0fe2c42a0261 154 return err;
Christopher Haster 10:0fe2c42a0261 155 }
Christopher Haster 10:0fe2c42a0261 156 }
Christopher Haster 10:0fe2c42a0261 157
Christopher Haster 10:0fe2c42a0261 158 sock.close();
Christopher Haster 10:0fe2c42a0261 159 return NS_ERROR_DNS_FAILURE;
Christopher Haster 10:0fe2c42a0261 160 }
Christopher Haster 10:0fe2c42a0261 161
Christopher Haster 10:0fe2c42a0261 162 int32_t dnsQuery(UDPSocket *socket, const char *hostname, char *ipaddress)
sarahmarshy 0:fff4b9055396 163 {
sarahmarshy 0:fff4b9055396 164 INFO("%s", hostname);
sarahmarshy 0:fff4b9055396 165 int len = 0;
sarahmarshy 0:fff4b9055396 166 if (hostname == NULL)
sarahmarshy 0:fff4b9055396 167 return false;
sarahmarshy 0:fff4b9055396 168 len = strlen(hostname);
sarahmarshy 0:fff4b9055396 169 if ((len >128) || (len == 0))
sarahmarshy 0:fff4b9055396 170 return false;
sarahmarshy 0:fff4b9055396 171
sarahmarshy 0:fff4b9055396 172 int packetlen = /* size of HEADER structure */ 12 + /* size of QUESTION Structure */5 + len + 1;
Christopher Haster 9:16e5208cc4ef 173 uint8_t *packet = new uint8_t[packetlen]; /* this is the UDP packet to send to the DNS */
sarahmarshy 0:fff4b9055396 174 if (packet == NULL)
sarahmarshy 0:fff4b9055396 175 return false;
sarahmarshy 0:fff4b9055396 176
sarahmarshy 0:fff4b9055396 177 // Fill the header
sarahmarshy 0:fff4b9055396 178 memset(packet, 0, packetlen);
sarahmarshy 0:fff4b9055396 179 packet[1] = 1; // ID = 1
sarahmarshy 0:fff4b9055396 180 packet[5] = 1; // QDCOUNT = 1 (contains one question)
sarahmarshy 0:fff4b9055396 181 packet[2] = 1; // recursion requested
sarahmarshy 0:fff4b9055396 182
sarahmarshy 0:fff4b9055396 183 int c = 13; // point to NAME element in question section or request
sarahmarshy 0:fff4b9055396 184 int cnt = 12; // points to the counter of
sarahmarshy 0:fff4b9055396 185 packet[cnt] = 0;
sarahmarshy 0:fff4b9055396 186 for (int i = 0 ; i < len ; i++) {
sarahmarshy 0:fff4b9055396 187 if (hostname[i] != '.') {
sarahmarshy 0:fff4b9055396 188 // Copy the character and increment the character counter
sarahmarshy 0:fff4b9055396 189 packet[cnt]++;
sarahmarshy 0:fff4b9055396 190 packet[c++] = hostname[i];
sarahmarshy 0:fff4b9055396 191 } else {
sarahmarshy 0:fff4b9055396 192 // Finished with this part, so go to the next
sarahmarshy 0:fff4b9055396 193 cnt = c++;
sarahmarshy 0:fff4b9055396 194 packet[cnt] = 0;
sarahmarshy 0:fff4b9055396 195 }
sarahmarshy 0:fff4b9055396 196 }
sarahmarshy 0:fff4b9055396 197
sarahmarshy 0:fff4b9055396 198 // Terminate this domain name with a zero entry
sarahmarshy 0:fff4b9055396 199 packet[c++] = 0;
sarahmarshy 0:fff4b9055396 200
sarahmarshy 0:fff4b9055396 201 // Set QTYPE
sarahmarshy 0:fff4b9055396 202 packet[c++] = 0;
sarahmarshy 0:fff4b9055396 203 packet[c++] = 1;
sarahmarshy 0:fff4b9055396 204 // Set QCLASS
sarahmarshy 0:fff4b9055396 205 packet[c++] = 0;
sarahmarshy 0:fff4b9055396 206 packet[c++] = 1;
sarahmarshy 0:fff4b9055396 207
Christopher Haster 10:0fe2c42a0261 208
sarahmarshy 1:5d978992a518 209 INFO("Sending packet of length %d",packetlen);
sarahmarshy 1:5d978992a518 210 /*
sarahmarshy 1:5d978992a518 211 for( int i = 0 ; i < c ; i++) {
sarahmarshy 1:5d978992a518 212 printf("%02x ", packet[i]);
sarahmarshy 1:5d978992a518 213 }
sarahmarshy 1:5d978992a518 214 */
sarahmarshy 1:5d978992a518 215 if (socket->send(packet, packetlen) < 0) {
sarahmarshy 0:fff4b9055396 216 delete packet;
sarahmarshy 0:fff4b9055396 217 return false;
sarahmarshy 0:fff4b9055396 218 }
sarahmarshy 0:fff4b9055396 219 delete packet;
sarahmarshy 0:fff4b9055396 220
Christopher Haster 9:16e5208cc4ef 221 packet = new uint8_t [1024];
sarahmarshy 0:fff4b9055396 222
sarahmarshy 0:fff4b9055396 223 // Receive the answer from DNS
sarahmarshy 0:fff4b9055396 224 int response_length = 0;
sarahmarshy 2:12d08f0f20cf 225 INFO("Recieving");
sarahmarshy 2:12d08f0f20cf 226 response_length = socket->recv(packet, 1024);
sarahmarshy 1:5d978992a518 227 /*
sarahmarshy 1:5d978992a518 228 for( int i = 0 ; i < 1024; i++) {
sarahmarshy 1:5d978992a518 229 printf("%02x ", packet[i]);
sarahmarshy 1:5d978992a518 230 }
sarahmarshy 1:5d978992a518 231 */
sarahmarshy 2:12d08f0f20cf 232 if (response_length > 0 ) {
sarahmarshy 2:12d08f0f20cf 233 if (!resolve(packet, ipaddress)) {
sarahmarshy 0:fff4b9055396 234 delete packet;
sarahmarshy 2:12d08f0f20cf 235 ERR("NO IP FOUND\n");
Christopher Haster 10:0fe2c42a0261 236 return NS_ERROR_DNS_FAILURE;
sarahmarshy 0:fff4b9055396 237 }
sarahmarshy 2:12d08f0f20cf 238
sarahmarshy 2:12d08f0f20cf 239 // cleanup and return
sarahmarshy 2:12d08f0f20cf 240 delete packet;
Christopher Haster 10:0fe2c42a0261 241 return 0;
sarahmarshy 2:12d08f0f20cf 242 } else {
sarahmarshy 2:12d08f0f20cf 243 ERR("SocketRecvFrom returned %d !", response_length);
sarahmarshy 2:12d08f0f20cf 244 }
sarahmarshy 0:fff4b9055396 245 delete packet;
sarahmarshy 0:fff4b9055396 246 ERR("NO IP FOUND\n");
Christopher Haster 10:0fe2c42a0261 247 return NS_ERROR_DNS_FAILURE;
sarahmarshy 0:fff4b9055396 248 }
sarahmarshy 0:fff4b9055396 249
sarahmarshy 0:fff4b9055396 250