Library to resolve text URLs to IP addresses (IPv4)

Dependents:   NetworkSocketAPI NetworkSocketAPI Nucleo-AWS-IoT-mbed

Committer:
Christopher Haster
Date:
Tue Apr 05 13:22:27 2016 -0500
Revision:
15:e3a13efb2675
Parent:
14:248f32a9c48d
Child:
16:a1bd52472dff
Matched changes to NSAPI

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
Christopher Haster 10:0fe2c42a0261 23 #define DNS_COUNT (sizeof DNS_IPS / sizeof DNS_IPS[0])
Christopher Haster 10:0fe2c42a0261 24 const char *DNS_IPS[] = {
Christopher Haster 10:0fe2c42a0261 25 "8.8.8.8",
Christopher Haster 10:0fe2c42a0261 26 "209.244.0.3",
Christopher Haster 10:0fe2c42a0261 27 "84.200.69.80",
Christopher Haster 10:0fe2c42a0261 28 "8.26.56.26",
Christopher Haster 10:0fe2c42a0261 29 "208.67.222.222"
Christopher Haster 10:0fe2c42a0261 30 };
Christopher Haster 7:cbe1ef566314 31
Christopher Haster 10:0fe2c42a0261 32 static bool isIP(const char *host)
Christopher Haster 7:cbe1ef566314 33 {
Christopher Haster 7:cbe1ef566314 34 int i;
Christopher Haster 7:cbe1ef566314 35
Christopher Haster 10:0fe2c42a0261 36 for (i = 0; host[i]; i++) {
Christopher Haster 10:0fe2c42a0261 37 if (!(host[i] >= '0' && host[i] <= '9') && host[i] != '.') {
Christopher Haster 7:cbe1ef566314 38 return false;
Christopher Haster 7:cbe1ef566314 39 }
Christopher Haster 7:cbe1ef566314 40 }
Christopher Haster 7:cbe1ef566314 41
Christopher Haster 10:0fe2c42a0261 42 // Ending with '.' garuntees host
Christopher Haster 10:0fe2c42a0261 43 if (i > 0 && host[i-1] == '.') {
Christopher Haster 7:cbe1ef566314 44 return false;
Christopher Haster 7:cbe1ef566314 45 }
Christopher Haster 7:cbe1ef566314 46
Christopher Haster 7:cbe1ef566314 47 return true;
Christopher Haster 7:cbe1ef566314 48 }
Christopher Haster 7:cbe1ef566314 49
Christopher Haster 10:0fe2c42a0261 50
geky 13:9c6e83b0ae7c 51 static bool parseRR(uint8_t *resp, int &c, char *adr)
Christopher Haster 10:0fe2c42a0261 52 {
Christopher Haster 10:0fe2c42a0261 53 int n = 0;
geky 13:9c6e83b0ae7c 54 while((n=resp[c++]) != 0) {
Christopher Haster 10:0fe2c42a0261 55 if ((n & 0xc0) != 0) {
Christopher Haster 10:0fe2c42a0261 56 // This is a link
Christopher Haster 10:0fe2c42a0261 57 c++;
Christopher Haster 10:0fe2c42a0261 58 break;
Christopher Haster 10:0fe2c42a0261 59 } else {
geky 12:e23ef3dab4b9 60 // skip this segment, not interested in string domain names
geky 13:9c6e83b0ae7c 61 c+= n;
Christopher Haster 10:0fe2c42a0261 62 }
Christopher Haster 10:0fe2c42a0261 63 }
geky 13:9c6e83b0ae7c 64
Christopher Haster 10:0fe2c42a0261 65 int TYPE = (((int)resp[c])<<8) + resp[c+1];
Christopher Haster 10:0fe2c42a0261 66 int CLASS = (((int)resp[c+2])<<8) + resp[c+3];
Christopher Haster 10:0fe2c42a0261 67 int RDLENGTH = (((int)resp[c+8])<<8) + resp[c+9];
Christopher Haster 10:0fe2c42a0261 68
Christopher Haster 10:0fe2c42a0261 69 c+= 10;
Christopher Haster 10:0fe2c42a0261 70 if ((CLASS == 1) && (TYPE == 1)) {
Christopher Haster 10:0fe2c42a0261 71 sprintf(adr,"%d.%d.%d.%d", resp[c], resp[c+1], resp[c+2], resp[c+3]);
Christopher Haster 10:0fe2c42a0261 72 c+= RDLENGTH;
Christopher Haster 10:0fe2c42a0261 73 return true;
Christopher Haster 10:0fe2c42a0261 74 }
Christopher Haster 10:0fe2c42a0261 75 c+= RDLENGTH;
geky 13:9c6e83b0ae7c 76
Christopher Haster 10:0fe2c42a0261 77 return false;
Christopher Haster 10:0fe2c42a0261 78 }
Christopher Haster 10:0fe2c42a0261 79
Christopher Haster 10:0fe2c42a0261 80
geky 13:9c6e83b0ae7c 81 static bool resolve(unsigned char *resp, char *ipaddress)
Christopher Haster 10:0fe2c42a0261 82 {
geky 13:9c6e83b0ae7c 83
Christopher Haster 10:0fe2c42a0261 84 int ID = (((int)resp[0]) <<8) + resp[1];
Christopher Haster 10:0fe2c42a0261 85 int QR = resp[2] >>7;
Christopher Haster 10:0fe2c42a0261 86 int Opcode = (resp[2]>>3) & 0x0F;
Christopher Haster 10:0fe2c42a0261 87 int RCODE = (resp[3] & 0x0F);
Christopher Haster 10:0fe2c42a0261 88 int ANCOUNT = (((int)resp[6])<<8)+ resp[7];
geky 13:9c6e83b0ae7c 89
Christopher Haster 10:0fe2c42a0261 90 if ((ID != 1) || (QR != 1) || (Opcode != 0) || (RCODE != 0)) {
Christopher Haster 10:0fe2c42a0261 91 return false;
Christopher Haster 10:0fe2c42a0261 92 }
geky 13:9c6e83b0ae7c 93
Christopher Haster 10:0fe2c42a0261 94 int c = 12;
Christopher Haster 10:0fe2c42a0261 95 int d;
Christopher Haster 10:0fe2c42a0261 96 // Skip domain question
Christopher Haster 10:0fe2c42a0261 97 while( (d=resp[c++]) != 0) {
Christopher Haster 10:0fe2c42a0261 98 c+=d;
Christopher Haster 10:0fe2c42a0261 99 }
Christopher Haster 10:0fe2c42a0261 100 c+= 4; // skip QTYPE and QCLASS
geky 13:9c6e83b0ae7c 101
Christopher Haster 10:0fe2c42a0261 102 // Here comes the resource record
Christopher Haster 10:0fe2c42a0261 103 for (int ans = 0 ; ans < ANCOUNT; ans++) {
Christopher Haster 10:0fe2c42a0261 104 if (parseRR(resp, c, ipaddress)) {
Christopher Haster 10:0fe2c42a0261 105 return true;
Christopher Haster 10:0fe2c42a0261 106 }
Christopher Haster 10:0fe2c42a0261 107 }
geky 13:9c6e83b0ae7c 108
Christopher Haster 10:0fe2c42a0261 109 return false;
Christopher Haster 10:0fe2c42a0261 110 }
Christopher Haster 10:0fe2c42a0261 111
Christopher Haster 15:e3a13efb2675 112 static int32_t query(UDPSocket *socket, const SocketAddress &addr, const char *hostname, char *ipaddress)
sarahmarshy 0:fff4b9055396 113 {
sarahmarshy 0:fff4b9055396 114 int len = 0;
geky 13:9c6e83b0ae7c 115 if (hostname == NULL) {
sarahmarshy 0:fff4b9055396 116 return false;
geky 13:9c6e83b0ae7c 117 }
sarahmarshy 0:fff4b9055396 118 len = strlen(hostname);
geky 13:9c6e83b0ae7c 119 if ((len > 128) || (len == 0)) {
sarahmarshy 0:fff4b9055396 120 return false;
geky 13:9c6e83b0ae7c 121 }
geky 13:9c6e83b0ae7c 122
sarahmarshy 0:fff4b9055396 123 int packetlen = /* size of HEADER structure */ 12 + /* size of QUESTION Structure */5 + len + 1;
Christopher Haster 9:16e5208cc4ef 124 uint8_t *packet = new uint8_t[packetlen]; /* this is the UDP packet to send to the DNS */
geky 13:9c6e83b0ae7c 125 if (packet == NULL) {
sarahmarshy 0:fff4b9055396 126 return false;
geky 13:9c6e83b0ae7c 127 }
geky 13:9c6e83b0ae7c 128
sarahmarshy 0:fff4b9055396 129 // Fill the header
sarahmarshy 0:fff4b9055396 130 memset(packet, 0, packetlen);
sarahmarshy 0:fff4b9055396 131 packet[1] = 1; // ID = 1
sarahmarshy 0:fff4b9055396 132 packet[5] = 1; // QDCOUNT = 1 (contains one question)
sarahmarshy 0:fff4b9055396 133 packet[2] = 1; // recursion requested
sarahmarshy 0:fff4b9055396 134
sarahmarshy 0:fff4b9055396 135 int c = 13; // point to NAME element in question section or request
sarahmarshy 0:fff4b9055396 136 int cnt = 12; // points to the counter of
sarahmarshy 0:fff4b9055396 137 packet[cnt] = 0;
sarahmarshy 0:fff4b9055396 138 for (int i = 0 ; i < len ; i++) {
sarahmarshy 0:fff4b9055396 139 if (hostname[i] != '.') {
sarahmarshy 0:fff4b9055396 140 // Copy the character and increment the character counter
sarahmarshy 0:fff4b9055396 141 packet[cnt]++;
sarahmarshy 0:fff4b9055396 142 packet[c++] = hostname[i];
sarahmarshy 0:fff4b9055396 143 } else {
sarahmarshy 0:fff4b9055396 144 // Finished with this part, so go to the next
sarahmarshy 0:fff4b9055396 145 cnt = c++;
sarahmarshy 0:fff4b9055396 146 packet[cnt] = 0;
sarahmarshy 0:fff4b9055396 147 }
sarahmarshy 0:fff4b9055396 148 }
geky 13:9c6e83b0ae7c 149
sarahmarshy 0:fff4b9055396 150 // Terminate this domain name with a zero entry
sarahmarshy 0:fff4b9055396 151 packet[c++] = 0;
geky 13:9c6e83b0ae7c 152
sarahmarshy 0:fff4b9055396 153 // Set QTYPE
sarahmarshy 0:fff4b9055396 154 packet[c++] = 0;
sarahmarshy 0:fff4b9055396 155 packet[c++] = 1;
sarahmarshy 0:fff4b9055396 156 // Set QCLASS
sarahmarshy 0:fff4b9055396 157 packet[c++] = 0;
sarahmarshy 0:fff4b9055396 158 packet[c++] = 1;
geky 13:9c6e83b0ae7c 159
geky 12:e23ef3dab4b9 160
Christopher Haster 15:e3a13efb2675 161 if (socket->sendto(addr, packet, packetlen) < 0) {
sarahmarshy 0:fff4b9055396 162 delete packet;
sarahmarshy 0:fff4b9055396 163 return false;
sarahmarshy 0:fff4b9055396 164 }
sarahmarshy 0:fff4b9055396 165 delete packet;
geky 13:9c6e83b0ae7c 166
Christopher Haster 9:16e5208cc4ef 167 packet = new uint8_t [1024];
geky 13:9c6e83b0ae7c 168
sarahmarshy 0:fff4b9055396 169 // Receive the answer from DNS
sarahmarshy 0:fff4b9055396 170 int response_length = 0;
Christopher Haster 15:e3a13efb2675 171 response_length = socket->recvfrom(NULL, packet, 1024);
geky 13:9c6e83b0ae7c 172
sarahmarshy 2:12d08f0f20cf 173 if (response_length > 0 ) {
sarahmarshy 2:12d08f0f20cf 174 if (!resolve(packet, ipaddress)) {
sarahmarshy 0:fff4b9055396 175 delete packet;
Christopher Haster 15:e3a13efb2675 176 return NSAPI_ERROR_DNS_FAILURE;
sarahmarshy 0:fff4b9055396 177 }
geky 13:9c6e83b0ae7c 178
sarahmarshy 2:12d08f0f20cf 179 // cleanup and return
sarahmarshy 2:12d08f0f20cf 180 delete packet;
Christopher Haster 10:0fe2c42a0261 181 return 0;
sarahmarshy 2:12d08f0f20cf 182 }
geky 13:9c6e83b0ae7c 183
sarahmarshy 0:fff4b9055396 184 delete packet;
Christopher Haster 15:e3a13efb2675 185 return NSAPI_ERROR_DNS_FAILURE;
sarahmarshy 0:fff4b9055396 186 }
sarahmarshy 0:fff4b9055396 187
Christopher Haster 15:e3a13efb2675 188 int32_t dnsQuery(NetworkInterface *iface, const char *host, char *ip)
Christopher Haster 15:e3a13efb2675 189 {
Christopher Haster 15:e3a13efb2675 190 if (isIP(host)) {
Christopher Haster 15:e3a13efb2675 191 strcpy(ip, host);
Christopher Haster 15:e3a13efb2675 192 return 0;
Christopher Haster 15:e3a13efb2675 193 }
sarahmarshy 0:fff4b9055396 194
Christopher Haster 15:e3a13efb2675 195 UDPSocket sock(iface);
Christopher Haster 15:e3a13efb2675 196
Christopher Haster 15:e3a13efb2675 197 for (unsigned i = 0; i < DNS_COUNT; i++) {
Christopher Haster 15:e3a13efb2675 198 int32_t err = query(&sock, SocketAddress(DNS_IPS[0], 53), host, ip);
Christopher Haster 15:e3a13efb2675 199 sock.close();
Christopher Haster 15:e3a13efb2675 200 return err;
Christopher Haster 15:e3a13efb2675 201 }
Christopher Haster 15:e3a13efb2675 202
Christopher Haster 15:e3a13efb2675 203 sock.close();
Christopher Haster 15:e3a13efb2675 204 return NSAPI_ERROR_DNS_FAILURE;
Christopher Haster 15:e3a13efb2675 205 }
Christopher Haster 15:e3a13efb2675 206
Christopher Haster 15:e3a13efb2675 207 int32_t dnsQuery(UDPSocket *socket, const char *host, char *ip)
Christopher Haster 15:e3a13efb2675 208 {
Christopher Haster 15:e3a13efb2675 209 if (isIP(host)) {
Christopher Haster 15:e3a13efb2675 210 strcpy(ip, host);
Christopher Haster 15:e3a13efb2675 211 return 0;
Christopher Haster 15:e3a13efb2675 212 }
Christopher Haster 15:e3a13efb2675 213
Christopher Haster 15:e3a13efb2675 214 for (unsigned i = 0; i < DNS_COUNT; i++) {
Christopher Haster 15:e3a13efb2675 215 return query(socket, SocketAddress(DNS_IPS[0], 53), host, ip);
Christopher Haster 15:e3a13efb2675 216 }
Christopher Haster 15:e3a13efb2675 217
Christopher Haster 15:e3a13efb2675 218 return NSAPI_ERROR_DNS_FAILURE;
Christopher Haster 15:e3a13efb2675 219 }