Library to resolve text URLs to IP addresses (IPv4)

Dependents:   NetworkSocketAPI NetworkSocketAPI Nucleo-AWS-IoT-mbed

Revision:
10:0fe2c42a0261
Parent:
9:16e5208cc4ef
Child:
12:e23ef3dab4b9
--- a/DnsQuery.cpp	Sun Feb 28 11:23:59 2016 -0600
+++ b/DnsQuery.cpp	Sun Feb 28 22:07:29 2016 -0600
@@ -37,57 +37,129 @@
 #endif
 
 
-
-DnsQuery::DnsQuery(UDPSocket *sock,const char* hostname, char* ipaddress)
-{
-    socket = sock;
-    this->getHostByName(hostname, ipaddress);
-}
-
-bool DnsQuery::getHostByName(const char* hostname, char* resolvedIp)
-{
-    if (isIP(hostname)) {
-        strcpy(resolvedIp, hostname);
-        return true;
-    }
+#define DNS_COUNT (sizeof DNS_IPS / sizeof DNS_IPS[0])
+const char *DNS_IPS[] = {
+    "8.8.8.8",
+    "209.244.0.3",
+    "84.200.69.80",
+    "8.26.56.26",
+    "208.67.222.222"
+};
 
-    const char * dnsIPs[] = {
-        "8.8.8.8",
-        "209.244.0.3",
-        "84.200.69.80",
-        "8.26.56.26",
-        "208.67.222.222"
-    };
-    for(int i = 0; i<5; i++){
-        _dnsip = dnsIPs[i];
-        if(this->getIP(hostname, resolvedIp)){
-            return true;   
-        }
-           
-    }
-    return false;
-    
-}
-
-bool DnsQuery::isIP(const char* hostname) const
+static bool isIP(const char *host)
 {
     int i;
 
-    for (i = 0; hostname[i]; i++) {
-        if (!(hostname[i] >= '0' && hostname[i] <= '9') && hostname[i] != '.') {
+    for (i = 0; host[i]; i++) {
+        if (!(host[i] >= '0' && host[i] <= '9') && host[i] != '.') {
             return false;
         }
     }
 
-    // Ending with '.' garuntees hostname
-    if (i > 0 && hostname[i-1] == '.') {
+    // Ending with '.' garuntees host
+    if (i > 0 && host[i-1] == '.') {
         return false;
     }
 
     return true;
 }
 
-bool DnsQuery::getIP(const char* hostname, char* ipaddress)
+
+static bool parseRR(uint8_t *resp, int& c, char* adr )
+{
+    int n = 0;
+    while( (n=resp[c++]) != 0) {
+        if ((n & 0xc0) != 0) {
+            //  This is a link
+            c++;
+            break;
+        } else {
+            c+= n;  //  skip this segment, not interested in string domain names
+        }
+    }
+    
+    int TYPE = (((int)resp[c])<<8) + resp[c+1];
+    int CLASS = (((int)resp[c+2])<<8) + resp[c+3];
+    int RDLENGTH = (((int)resp[c+8])<<8) + resp[c+9];
+
+    INFO("Record of TYPE=%d and CLASS=%d detected !", TYPE, CLASS);
+    c+= 10;
+    if ((CLASS == 1) && (TYPE == 1)) {
+        sprintf(adr,"%d.%d.%d.%d", resp[c], resp[c+1], resp[c+2], resp[c+3]);
+        c+= RDLENGTH;
+        return true;
+    } else {
+    }
+    c+= RDLENGTH;
+    
+    return false;
+}
+
+
+static bool resolve(unsigned char* resp, char* ipaddress)
+{
+    
+    int ID = (((int)resp[0]) <<8) + resp[1];
+    int QR = resp[2] >>7;
+    int Opcode = (resp[2]>>3) & 0x0F;
+    int RCODE = (resp[3] & 0x0F);
+    int ANCOUNT = (((int)resp[6])<<8)+ resp[7];
+    
+    INFO("Resolving response : ID = %d, QR = %d, Opcode = %d, RCODE = %d", ID, QR, Opcode, RCODE);
+    if ((ID != 1) || (QR != 1) || (Opcode != 0) || (RCODE != 0)) {
+        ERR("Received non matching response from DNS !");
+        return false;
+    }
+    
+    int c = 12;
+    int d;
+    //  Skip domain question
+    while(  (d=resp[c++]) != 0) {
+        c+=d;
+    }
+    c+= 4; //   skip QTYPE and QCLASS
+    
+    //  Here comes the resource record
+    for (int ans = 0 ; ans < ANCOUNT; ans++) {
+        if (parseRR(resp, c, ipaddress)) {
+            return true;
+        }
+    }
+    
+    return false;
+}
+
+
+int32_t dnsQuery(NetworkInterface *iface, const char *host, char *ip)
+{
+    if (isIP(host)) {
+        strcpy(ip, host);
+        return 0;
+    }
+
+    UDPSocket sock(iface);
+    int32_t err;
+
+    for (unsigned i = 0; i < DNS_COUNT; i++) {
+        err = sock.open(DNS_IPS[0], 53);
+        if (err < 0) {
+            return err;
+        }
+
+        err = dnsQuery(&sock, host, ip);
+        if (err >= 0) {
+            return sock.close();
+        } else if (err != NS_ERROR_DNS_FAILURE) {
+            sock.close();
+            return err;
+        }
+    }
+
+    sock.close();
+    return NS_ERROR_DNS_FAILURE;
+}
+
+int32_t dnsQuery(UDPSocket *socket, const char *hostname, char *ipaddress)
 {
     INFO("%s", hostname);
     int len = 0;
@@ -132,11 +204,8 @@
     //  Set QCLASS
     packet[c++] = 0;
     packet[c++] = 1;
-    
-    
-    //  Ready to send to DNS
-    socket->open(_dnsip, 53);
    
+ 
     INFO("Sending packet of length %d",packetlen);
     /*
     for( int i = 0 ; i < c ; i++) {
@@ -162,85 +231,20 @@
         */
     if (response_length > 0 ) {
         if (!resolve(packet, ipaddress)) {
-            socket->close();
             delete packet;
             ERR("NO IP FOUND\n");
-            return false;
+            return NS_ERROR_DNS_FAILURE;
         }
                         
         //  cleanup and return
         delete packet;
-        socket->close();
-        return true;
+        return 0;
     } else {
         ERR("SocketRecvFrom returned %d !", response_length);
     }
-    socket->close();
     delete packet;
     ERR("NO IP FOUND\n");
-    return false;
+    return NS_ERROR_DNS_FAILURE;
 }
 
 
-bool DnsQuery::resolve(unsigned char* resp, char* ipaddress)
-{
-    
-    int ID = (((int)resp[0]) <<8) + resp[1];
-    int QR = resp[2] >>7;
-    int Opcode = (resp[2]>>3) & 0x0F;
-    int RCODE = (resp[3] & 0x0F);
-    int ANCOUNT = (((int)resp[6])<<8)+ resp[7];
-    
-    INFO("Resolving response : ID = %d, QR = %d, Opcode = %d, RCODE = %d", ID, QR, Opcode, RCODE);
-    if ((ID != 1) || (QR != 1) || (Opcode != 0) || (RCODE != 0)) {
-        ERR("Received non matching response from DNS !");
-        return false;
-    }
-    
-    int c = 12;
-    int d;
-    //  Skip domain question
-    while(  (d=resp[c++]) != 0) {
-        c+=d;
-    }
-    c+= 4; //   skip QTYPE and QCLASS
-    
-    //  Here comes the resource record
-    for (int ans = 0 ; ans < ANCOUNT; ans++) {
-        if (parseRR(resp, c, ipaddress)) {
-            return true;
-        }
-    }
-    
-    return false;
-}
-
-bool DnsQuery::parseRR(uint8_t *resp, int& c, char* adr )
-{
-    int n = 0;
-    while( (n=resp[c++]) != 0) {
-        if ((n & 0xc0) != 0) {
-            //  This is a link
-            c++;
-            break;
-        } else {
-            c+= n;  //  skip this segment, not interested in string domain names
-        }
-    }
-    
-    int TYPE = (((int)resp[c])<<8) + resp[c+1];
-    int CLASS = (((int)resp[c+2])<<8) + resp[c+3];
-    int RDLENGTH = (((int)resp[c+8])<<8) + resp[c+9];
-
-    INFO("Record of TYPE=%d and CLASS=%d detected !", TYPE, CLASS);
-    c+= 10;
-    if ((CLASS == 1) && (TYPE == 1)) {
-        sprintf(adr,"%d.%d.%d.%d", resp[c], resp[c+1], resp[c+2], resp[c+3]);
-        c+= RDLENGTH;
-        return true;
-    } else {
-    }
-    c+= RDLENGTH;
-    
-    return false;
-}