Library to resolve text URLs to IP addresses (IPv4)

Dependents:   NetworkSocketAPI NetworkSocketAPI Nucleo-AWS-IoT-mbed

Committer:
Christopher Haster
Date:
Tue Apr 19 18:29:55 2016 -0500
Revision:
18:2cb1fffed50c
Parent:
17:18a6b52be896
Matched changes to NSAPI

Who changed what in which revision?

UserRevisionLine numberNew contents of line
Christopher Haster 18:2cb1fffed50c 1 /* Copyright (c) 2013 Henry Leinen (henry[dot]leinen [at] online [dot] de)
Christopher Haster 18:2cb1fffed50c 2 *
Christopher Haster 18:2cb1fffed50c 3 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
Christopher Haster 18:2cb1fffed50c 4 * and associated documentation files (the "Software"), to deal in the Software without restriction,
Christopher Haster 18:2cb1fffed50c 5 * including without limitation the rights to use, copy, modify, merge, publish, distribute,
Christopher Haster 18:2cb1fffed50c 6 * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
Christopher Haster 18:2cb1fffed50c 7 * furnished to do so, subject to the following conditions:
Christopher Haster 18:2cb1fffed50c 8 *
Christopher Haster 18:2cb1fffed50c 9 * The above copyright notice and this permission notice shall be included in all copies or
Christopher Haster 18:2cb1fffed50c 10 * substantial portions of the Software.
Christopher Haster 18:2cb1fffed50c 11 *
Christopher Haster 18:2cb1fffed50c 12 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
Christopher Haster 18:2cb1fffed50c 13 * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
Christopher Haster 18:2cb1fffed50c 14 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
Christopher Haster 18:2cb1fffed50c 15 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
Christopher Haster 18:2cb1fffed50c 16 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Christopher Haster 18:2cb1fffed50c 17 */
Christopher Haster 18:2cb1fffed50c 18 #include "DnsQuery.h"
Christopher Haster 18:2cb1fffed50c 19 #include <stdio.h>
Christopher Haster 18:2cb1fffed50c 20 #include <string.h>
Christopher Haster 18:2cb1fffed50c 21
Christopher Haster 18:2cb1fffed50c 22
Christopher Haster 18:2cb1fffed50c 23 #define DNS_COUNT (sizeof DNS_IPS / sizeof DNS_IPS[0])
Christopher Haster 18:2cb1fffed50c 24 const char *DNS_IPS[] = {
Christopher Haster 18:2cb1fffed50c 25 "8.8.8.8",
Christopher Haster 18:2cb1fffed50c 26 "209.244.0.3",
Christopher Haster 18:2cb1fffed50c 27 "84.200.69.80",
Christopher Haster 18:2cb1fffed50c 28 "8.26.56.26",
Christopher Haster 18:2cb1fffed50c 29 "208.67.222.222"
Christopher Haster 18:2cb1fffed50c 30 };
Christopher Haster 18:2cb1fffed50c 31
Christopher Haster 18:2cb1fffed50c 32 static bool isIP(const char *host)
Christopher Haster 18:2cb1fffed50c 33 {
Christopher Haster 18:2cb1fffed50c 34 int i;
Christopher Haster 18:2cb1fffed50c 35
Christopher Haster 18:2cb1fffed50c 36 for (i = 0; host[i]; i++) {
Christopher Haster 18:2cb1fffed50c 37 if (!(host[i] >= '0' && host[i] <= '9') && host[i] != '.') {
Christopher Haster 18:2cb1fffed50c 38 return false;
Christopher Haster 18:2cb1fffed50c 39 }
Christopher Haster 18:2cb1fffed50c 40 }
Christopher Haster 18:2cb1fffed50c 41
Christopher Haster 18:2cb1fffed50c 42 // Ending with '.' garuntees host
Christopher Haster 18:2cb1fffed50c 43 if (i > 0 && host[i-1] == '.') {
Christopher Haster 18:2cb1fffed50c 44 return false;
Christopher Haster 18:2cb1fffed50c 45 }
Christopher Haster 18:2cb1fffed50c 46
Christopher Haster 18:2cb1fffed50c 47 return true;
Christopher Haster 18:2cb1fffed50c 48 }
Christopher Haster 18:2cb1fffed50c 49
Christopher Haster 18:2cb1fffed50c 50
Christopher Haster 18:2cb1fffed50c 51 static bool parseRR(uint8_t *resp, int &c, char *adr)
Christopher Haster 18:2cb1fffed50c 52 {
Christopher Haster 18:2cb1fffed50c 53 int n = 0;
Christopher Haster 18:2cb1fffed50c 54 while((n=resp[c++]) != 0) {
Christopher Haster 18:2cb1fffed50c 55 if ((n & 0xc0) != 0) {
Christopher Haster 18:2cb1fffed50c 56 // This is a link
Christopher Haster 18:2cb1fffed50c 57 c++;
Christopher Haster 18:2cb1fffed50c 58 break;
Christopher Haster 18:2cb1fffed50c 59 } else {
Christopher Haster 18:2cb1fffed50c 60 // skip this segment, not interested in string domain names
Christopher Haster 18:2cb1fffed50c 61 c+= n;
Christopher Haster 18:2cb1fffed50c 62 }
Christopher Haster 18:2cb1fffed50c 63 }
Christopher Haster 18:2cb1fffed50c 64
Christopher Haster 18:2cb1fffed50c 65 int TYPE = (((int)resp[c])<<8) + resp[c+1];
Christopher Haster 18:2cb1fffed50c 66 int CLASS = (((int)resp[c+2])<<8) + resp[c+3];
Christopher Haster 18:2cb1fffed50c 67 int RDLENGTH = (((int)resp[c+8])<<8) + resp[c+9];
Christopher Haster 18:2cb1fffed50c 68
Christopher Haster 18:2cb1fffed50c 69 c+= 10;
Christopher Haster 18:2cb1fffed50c 70 if ((CLASS == 1) && (TYPE == 1)) {
Christopher Haster 18:2cb1fffed50c 71 sprintf(adr,"%d.%d.%d.%d", resp[c], resp[c+1], resp[c+2], resp[c+3]);
Christopher Haster 18:2cb1fffed50c 72 c+= RDLENGTH;
Christopher Haster 18:2cb1fffed50c 73 return true;
Christopher Haster 18:2cb1fffed50c 74 }
Christopher Haster 18:2cb1fffed50c 75 c+= RDLENGTH;
Christopher Haster 18:2cb1fffed50c 76
Christopher Haster 18:2cb1fffed50c 77 return false;
Christopher Haster 18:2cb1fffed50c 78 }
Christopher Haster 18:2cb1fffed50c 79
Christopher Haster 18:2cb1fffed50c 80
Christopher Haster 18:2cb1fffed50c 81 static bool resolve(unsigned char *resp, char *ipaddress)
Christopher Haster 18:2cb1fffed50c 82 {
Christopher Haster 18:2cb1fffed50c 83
Christopher Haster 18:2cb1fffed50c 84 int ID = (((int)resp[0]) <<8) + resp[1];
Christopher Haster 18:2cb1fffed50c 85 int QR = resp[2] >>7;
Christopher Haster 18:2cb1fffed50c 86 int Opcode = (resp[2]>>3) & 0x0F;
Christopher Haster 18:2cb1fffed50c 87 int RCODE = (resp[3] & 0x0F);
Christopher Haster 18:2cb1fffed50c 88 int ANCOUNT = (((int)resp[6])<<8)+ resp[7];
Christopher Haster 18:2cb1fffed50c 89
Christopher Haster 18:2cb1fffed50c 90 if ((ID != 1) || (QR != 1) || (Opcode != 0) || (RCODE != 0)) {
Christopher Haster 18:2cb1fffed50c 91 return false;
Christopher Haster 18:2cb1fffed50c 92 }
Christopher Haster 18:2cb1fffed50c 93
Christopher Haster 18:2cb1fffed50c 94 int c = 12;
Christopher Haster 18:2cb1fffed50c 95 int d;
Christopher Haster 18:2cb1fffed50c 96 // Skip domain question
Christopher Haster 18:2cb1fffed50c 97 while( (d=resp[c++]) != 0) {
Christopher Haster 18:2cb1fffed50c 98 c+=d;
Christopher Haster 18:2cb1fffed50c 99 }
Christopher Haster 18:2cb1fffed50c 100 c+= 4; // skip QTYPE and QCLASS
Christopher Haster 18:2cb1fffed50c 101
Christopher Haster 18:2cb1fffed50c 102 // Here comes the resource record
Christopher Haster 18:2cb1fffed50c 103 for (int ans = 0 ; ans < ANCOUNT; ans++) {
Christopher Haster 18:2cb1fffed50c 104 if (parseRR(resp, c, ipaddress)) {
Christopher Haster 18:2cb1fffed50c 105 return true;
Christopher Haster 18:2cb1fffed50c 106 }
Christopher Haster 18:2cb1fffed50c 107 }
Christopher Haster 18:2cb1fffed50c 108
Christopher Haster 18:2cb1fffed50c 109 return false;
Christopher Haster 18:2cb1fffed50c 110 }
Christopher Haster 18:2cb1fffed50c 111
Christopher Haster 18:2cb1fffed50c 112 static int32_t query(UDPSocket *socket, const SocketAddress &addr, const char *hostname, char *ipaddress)
Christopher Haster 18:2cb1fffed50c 113 {
Christopher Haster 18:2cb1fffed50c 114 int len = 0;
Christopher Haster 18:2cb1fffed50c 115 if (hostname == NULL) {
Christopher Haster 18:2cb1fffed50c 116 return false;
Christopher Haster 18:2cb1fffed50c 117 }
Christopher Haster 18:2cb1fffed50c 118 len = strlen(hostname);
Christopher Haster 18:2cb1fffed50c 119 if ((len > 128) || (len == 0)) {
Christopher Haster 18:2cb1fffed50c 120 return false;
Christopher Haster 18:2cb1fffed50c 121 }
Christopher Haster 18:2cb1fffed50c 122
Christopher Haster 18:2cb1fffed50c 123 int packetlen = /* size of HEADER structure */ 12 + /* size of QUESTION Structure */5 + len + 1;
Christopher Haster 18:2cb1fffed50c 124 uint8_t *packet = new uint8_t[packetlen]; /* this is the UDP packet to send to the DNS */
Christopher Haster 18:2cb1fffed50c 125 if (packet == NULL) {
Christopher Haster 18:2cb1fffed50c 126 return false;
Christopher Haster 18:2cb1fffed50c 127 }
Christopher Haster 18:2cb1fffed50c 128
Christopher Haster 18:2cb1fffed50c 129 // Fill the header
Christopher Haster 18:2cb1fffed50c 130 memset(packet, 0, packetlen);
Christopher Haster 18:2cb1fffed50c 131 packet[1] = 1; // ID = 1
Christopher Haster 18:2cb1fffed50c 132 packet[5] = 1; // QDCOUNT = 1 (contains one question)
Christopher Haster 18:2cb1fffed50c 133 packet[2] = 1; // recursion requested
Christopher Haster 18:2cb1fffed50c 134
Christopher Haster 18:2cb1fffed50c 135 int c = 13; // point to NAME element in question section or request
Christopher Haster 18:2cb1fffed50c 136 int cnt = 12; // points to the counter of
Christopher Haster 18:2cb1fffed50c 137 packet[cnt] = 0;
Christopher Haster 18:2cb1fffed50c 138 for (int i = 0 ; i < len ; i++) {
Christopher Haster 18:2cb1fffed50c 139 if (hostname[i] != '.') {
Christopher Haster 18:2cb1fffed50c 140 // Copy the character and increment the character counter
Christopher Haster 18:2cb1fffed50c 141 packet[cnt]++;
Christopher Haster 18:2cb1fffed50c 142 packet[c++] = hostname[i];
Christopher Haster 18:2cb1fffed50c 143 } else {
Christopher Haster 18:2cb1fffed50c 144 // Finished with this part, so go to the next
Christopher Haster 18:2cb1fffed50c 145 cnt = c++;
Christopher Haster 18:2cb1fffed50c 146 packet[cnt] = 0;
Christopher Haster 18:2cb1fffed50c 147 }
Christopher Haster 18:2cb1fffed50c 148 }
Christopher Haster 18:2cb1fffed50c 149
Christopher Haster 18:2cb1fffed50c 150 // Terminate this domain name with a zero entry
Christopher Haster 18:2cb1fffed50c 151 packet[c++] = 0;
Christopher Haster 18:2cb1fffed50c 152
Christopher Haster 18:2cb1fffed50c 153 // Set QTYPE
Christopher Haster 18:2cb1fffed50c 154 packet[c++] = 0;
Christopher Haster 18:2cb1fffed50c 155 packet[c++] = 1;
Christopher Haster 18:2cb1fffed50c 156 // Set QCLASS
Christopher Haster 18:2cb1fffed50c 157 packet[c++] = 0;
Christopher Haster 18:2cb1fffed50c 158 packet[c++] = 1;
Christopher Haster 18:2cb1fffed50c 159
Christopher Haster 18:2cb1fffed50c 160
Christopher Haster 18:2cb1fffed50c 161 if (socket->sendto(addr, packet, packetlen) < 0) {
Christopher Haster 18:2cb1fffed50c 162 delete packet;
Christopher Haster 18:2cb1fffed50c 163 return false;
Christopher Haster 18:2cb1fffed50c 164 }
Christopher Haster 18:2cb1fffed50c 165 delete packet;
Christopher Haster 18:2cb1fffed50c 166
Christopher Haster 18:2cb1fffed50c 167 packet = new uint8_t [1024];
Christopher Haster 18:2cb1fffed50c 168
Christopher Haster 18:2cb1fffed50c 169 // Receive the answer from DNS
Christopher Haster 18:2cb1fffed50c 170 int response_length = 0;
Christopher Haster 18:2cb1fffed50c 171 response_length = socket->recvfrom(NULL, packet, 1024);
Christopher Haster 18:2cb1fffed50c 172
Christopher Haster 18:2cb1fffed50c 173 if (response_length > 0 ) {
Christopher Haster 18:2cb1fffed50c 174 if (!resolve(packet, ipaddress)) {
Christopher Haster 18:2cb1fffed50c 175 delete packet;
Christopher Haster 18:2cb1fffed50c 176 return NSAPI_ERROR_DNS_FAILURE;
Christopher Haster 18:2cb1fffed50c 177 }
Christopher Haster 18:2cb1fffed50c 178
Christopher Haster 18:2cb1fffed50c 179 // cleanup and return
Christopher Haster 18:2cb1fffed50c 180 delete packet;
Christopher Haster 18:2cb1fffed50c 181 return 0;
Christopher Haster 18:2cb1fffed50c 182 }
Christopher Haster 18:2cb1fffed50c 183
Christopher Haster 18:2cb1fffed50c 184 delete packet;
Christopher Haster 18:2cb1fffed50c 185 return NSAPI_ERROR_DNS_FAILURE;
Christopher Haster 18:2cb1fffed50c 186 }
Christopher Haster 18:2cb1fffed50c 187
Christopher Haster 18:2cb1fffed50c 188 int32_t dnsQuery(NetworkStack *iface, const char *host, char *ip)
Christopher Haster 18:2cb1fffed50c 189 {
Christopher Haster 18:2cb1fffed50c 190 if (isIP(host)) {
Christopher Haster 18:2cb1fffed50c 191 strcpy(ip, host);
Christopher Haster 18:2cb1fffed50c 192 return 0;
Christopher Haster 18:2cb1fffed50c 193 }
Christopher Haster 18:2cb1fffed50c 194
Christopher Haster 18:2cb1fffed50c 195 UDPSocket sock(iface);
Christopher Haster 18:2cb1fffed50c 196
Christopher Haster 18:2cb1fffed50c 197 for (unsigned i = 0; i < DNS_COUNT; i++) {
Christopher Haster 18:2cb1fffed50c 198 return query(&sock, SocketAddress(DNS_IPS[0], 53), host, ip);
Christopher Haster 18:2cb1fffed50c 199 }
Christopher Haster 18:2cb1fffed50c 200
Christopher Haster 18:2cb1fffed50c 201 return NSAPI_ERROR_DNS_FAILURE;
Christopher Haster 18:2cb1fffed50c 202 }
Christopher Haster 18:2cb1fffed50c 203
Christopher Haster 18:2cb1fffed50c 204 int32_t dnsQuery(UDPSocket *socket, const char *host, char *ip)
Christopher Haster 18:2cb1fffed50c 205 {
Christopher Haster 18:2cb1fffed50c 206 if (isIP(host)) {
Christopher Haster 18:2cb1fffed50c 207 strcpy(ip, host);
Christopher Haster 18:2cb1fffed50c 208 return 0;
Christopher Haster 18:2cb1fffed50c 209 }
Christopher Haster 18:2cb1fffed50c 210
Christopher Haster 18:2cb1fffed50c 211 for (unsigned i = 0; i < DNS_COUNT; i++) {
Christopher Haster 18:2cb1fffed50c 212 return query(socket, SocketAddress(DNS_IPS[0], 53), host, ip);
Christopher Haster 18:2cb1fffed50c 213 }
Christopher Haster 18:2cb1fffed50c 214
Christopher Haster 18:2cb1fffed50c 215 return NSAPI_ERROR_DNS_FAILURE;
Christopher Haster 18:2cb1fffed50c 216 }