Library to resolve text URLs to IP addresses (IPv4)

Dependents:   NetworkSocketAPI NetworkSocketAPI Nucleo-AWS-IoT-mbed

Committer:
Christopher Haster
Date:
Sun Feb 28 11:23:59 2016 -0600
Revision:
9:16e5208cc4ef
Parent:
7:cbe1ef566314
Child:
10:0fe2c42a0261
Added proper types for systems where char != unsigned char

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