Network Services
Fork of W5500Interface_K22F by
DNSClient/DNSClient.cpp
- Committer:
- dgriffin65
- Date:
- 2017-06-15
- Revision:
- 15:14382459c8b7
File content as of revision 15:14382459c8b7:
// DNSClient.cpp 2013/8/27 #include "mbed.h" #include "mbed_debug.h" #include "DNSClient.h" #include "UDPSocket.h" #include "dnsname.h" #include "wiznet.h" #if DBG_DNS #define DBG2(...) do{debug("[DNS]%p %d %s ", this,__LINE__,__PRETTY_FUNCTION__); debug(__VA_ARGS__); } while(0); #else #define DBG2(...) while(0); #endif static SocketAddress theDnsServer; DNSClient::DNSClient() : m_state(MYNETDNS_START), m_udp(NULL) { m_ns = NULL; //default to google theDnsServer.set_ip_address("8.8.8.8"); // DNS theDnsServer.set_port(53); // DNS } DNSClient::DNSClient(NetworkStack *ns, const char* hostname) : m_state(MYNETDNS_START), m_udp(NULL) { m_hostname = hostname; m_ns = ns; //default to google theDnsServer.set_ip_address("8.8.8.8"); // DNS theDnsServer.set_port(53); // DNS } DNSClient::DNSClient(NetworkStack *ns, SocketAddress* pHost) : m_state(MYNETDNS_START), m_udp(NULL) { m_ns = ns; //default to google theDnsServer.set_ip_address("8.8.8.8"); // DNS theDnsServer.set_port(53); // DNS } DNSClient::~DNSClient() { if (m_udp) { delete m_udp; } } int DNSClient::setup(NetworkStack *ns) { m_ns = ns; return 0; } bool DNSClient::set_server(const char* serverip, int port) { theDnsServer.set_ip_address(serverip); theDnsServer.set_port(port); return true; } void DNSClient::callback() { uint8_t buf[512]; SocketAddress host; int len = m_udp->recvfrom(&host, (char*)buf, sizeof(buf)); if (len < 0) { return; } if (memcmp(buf+0, m_id, 2) != 0) { //verify return; } int rcode = response(buf, len); if (rcode == 0) { m_state = MYNETDNS_OK; } else { m_state = MYNETDNS_NOTFOUND; } } int DNSClient::response(uint8_t buf[], int size) { int rcode = buf[3] & 0x0f; if (rcode != 0) { return rcode; } int qdcount = buf[4]<<8|buf[5]; int ancount = buf[6]<<8|buf[7]; int pos = 12; while(qdcount-- > 0) { dnsname qname(buf); pos = qname.decode(pos); // qname pos += 4; // qtype qclass } while(ancount-- > 0) { dnsname name(buf); pos = name.decode(pos); // name int type = buf[pos]<<8|buf[pos+1]; pos += 8; // type class TTL int rdlength = buf[pos]<<8|buf[pos+1]; pos += 2; int rdata_pos = pos; pos += rdlength; if (type == 1) { // A record m_ip = (buf[rdata_pos]<<24) | (buf[rdata_pos+1]<<16) | (buf[rdata_pos+2]<<8) | buf[rdata_pos+3]; sprintf(m_ipaddr, "%d.%d.%d.%d", buf[rdata_pos],buf[rdata_pos+1],buf[rdata_pos+2],buf[rdata_pos+3]); } #if DBG_DNS printf("%s", name.str.c_str()); if (type == 1) { printf(" A %d.%d.%d.%d\n", buf[rdata_pos],buf[rdata_pos+1],buf[rdata_pos+2],buf[rdata_pos+3]); } else if (type == 5) { dnsname rdname(buf); rdname.decode(rdata_pos); printf(" CNAME %s\n", rdname.str.c_str()); } else { printf(" TYPE:%d", type); printfBytes(" RDATA:", &buf[rdata_pos], rdlength); } #endif } return rcode; } int DNSClient::query(uint8_t buf[], int size, const char* hostname) { const uint8_t header[] = { 0x00,0x00,0x01,0x00, // id=0x0000 QR=0 rd=1 opcode=0 rcode=0 0x00,0x01,0x00,0x00, // qdcount=1 ancount=0 0x00,0x00,0x00,0x00};// nscount=0 arcount=0 const uint8_t tail[] = {0x00,0x01,0x00,0x01}; // qtype=A qclass=IN memcpy(buf, header, sizeof(header)); int t = rand(); m_id[0] = t>>8; m_id[1] = t; memcpy(buf, m_id, 2); dnsname qname(buf); int pos = qname.encode(sizeof(header), (char*)hostname); memcpy(buf+pos, tail, sizeof(tail)); pos += sizeof(tail); return pos; } void DNSClient::resolve(const char* hostname) { if (m_udp == NULL) { m_udp = new UDPSocket; m_udp->open(m_ns); } m_udp->set_blocking(false); m_udp->bind(rand()&0x7fff); uint8_t buf[256]; int size = query(buf, sizeof(buf), hostname); #if DBG_DNS printf("hostname:[%s]\n", hostname); printHex(buf, size); #endif m_udp->sendto(theDnsServer, (char*)buf, size); m_interval.reset(); m_interval.start(); } void DNSClient::poll() { #if DBG_DNS printf("%p m_state: %d, m_udp: %p\n", this, m_state, m_udp); wait_ms(400); #endif switch(m_state) { case MYNETDNS_START: m_retry = 0; resolve(m_hostname); m_state = MYNETDNS_PROCESSING; break; case MYNETDNS_PROCESSING: break; case MYNETDNS_NOTFOUND: break; case MYNETDNS_ERROR: break; case MYNETDNS_OK: DBG2("m_retry=%d, m_interval=%d\n", m_retry, m_interval.read_ms()); break; } if (m_interval.read_ms() > 1000) { m_interval.stop(); DBG2("timeout m_retry=%d\n", m_retry); if (++m_retry >= 2) { m_state = MYNETDNS_ERROR; } else { resolve(m_hostname); m_state = MYNETDNS_PROCESSING; } } } //tests for a valid IP address, returns 0 if invalid IP address format, returns ip address if valid static uint32_t isValidIP(const char* ip) { int i1, i2, i3, i4; int len = strlen(ip); if (len < 7) return 0; //count the number of dots, there must be 3 int dotcount = 0; for (int i = 0; i < len; i++) { if (ip[i] == '.' ) dotcount++; } //there must be exactly 3 dots if (dotcount != 3) return 0; sscanf((char*)ip, "%d.%d.%d.%d", &i1, &i2, &i3, &i4); if (strlen(ip) <= 16 && (i1 >= 0 && i1 <= 255) && (i2 >= 0 && i2 <= 255) && (i3 >= 0 && i3 <= 255) && (i4 >= 0 && i4 <= 255)) { return ((i1<<24) | (i2<<16) | (i3<<8) | i4); } return 0; } bool DNSClient::lookup(const char* hostname) { m_hostname = hostname; uint32_t ip = isValidIP(hostname); //check if hostname is an IP address if (ip > 0) { //if it is already an IP address just return immediately m_ip = ip; strcpy(m_ipaddr, hostname); m_state = MYNETDNS_OK; return true; } m_state = MYNETDNS_START; while(1) { poll(); callback(); if (m_state != MYNETDNS_PROCESSING) { break; } } if (m_udp) { delete m_udp; m_udp = NULL; } return m_state == MYNETDNS_OK; }