#include "./DNSServer.h" #include #include #define DEBUG #define DEBUG_OUTPUT Serial DNSServer::DNSServer() { _ttl = htonl(60); _errorReplyCode = DNSReplyCode::NonExistentDomain; } bool DNSServer::start(const uint16_t &port, const String &domainName, const IPAddress &resolvedIP) { _port = port; _domainName = domainName; _resolvedIP[0] = resolvedIP[0]; _resolvedIP[1] = resolvedIP[1]; _resolvedIP[2] = resolvedIP[2]; _resolvedIP[3] = resolvedIP[3]; downcaseAndRemoveWwwPrefix(_domainName); return _udp.begin(_port) == 1; } void DNSServer::setErrorReplyCode(const DNSReplyCode &replyCode) { _errorReplyCode = replyCode; } void DNSServer::setTTL(const uint32_t &ttl) { _ttl = htonl(ttl); } void DNSServer::stop() { _udp.stop(); } void DNSServer::downcaseAndRemoveWwwPrefix(String &domainName) { domainName.toLowerCase(); domainName.replace("www.", ""); domainName.replace("https://", ""); } void DNSServer::processNextRequest() { _currentPacketSize = _udp.parsePacket(); if (_currentPacketSize) { _buffer = (unsigned char*)malloc(_currentPacketSize * sizeof(char)); _udp.read(_buffer, _currentPacketSize); _dnsHeader = (DNSHeader*) _buffer; if (_dnsHeader->QR == DNS_QR_QUERY && _dnsHeader->OPCode == DNS_OPCODE_QUERY && requestIncludesOnlyOneQuestion() && (_domainName == "*" || getDomainNameWithoutWwwPrefix() == _domainName) ) { replyWithIP(); } else if (_dnsHeader->QR == DNS_QR_QUERY) { replyWithCustomCode(); } free(_buffer); } } bool DNSServer::requestIncludesOnlyOneQuestion() { return ntohs(_dnsHeader->QDCount) == 1 && _dnsHeader->ANCount == 0 && _dnsHeader->NSCount == 0 && _dnsHeader->ARCount == 0; } String DNSServer::getDomainNameWithoutWwwPrefix() { String parsedDomainName = ""; unsigned char *start = _buffer + 12; if (*start == 0) { return parsedDomainName; } int pos = 0; while(true) { unsigned char labelLength = *(start + pos); for(int i = 0; i < labelLength; i++) { pos++; parsedDomainName += (char)*(start + pos); } pos++; if (*(start + pos) == 0) { downcaseAndRemoveWwwPrefix(parsedDomainName); return parsedDomainName; } else { parsedDomainName += "."; } } } void DNSServer::replyWithIP() { _dnsHeader->QR = DNS_QR_RESPONSE; _dnsHeader->ANCount = _dnsHeader->QDCount; _dnsHeader->QDCount = _dnsHeader->QDCount; //_dnsHeader->RA = 1; _udp.beginPacket(_udp.remoteIP(), _udp.remotePort()); _udp.write(_buffer, _currentPacketSize); _udp.write((uint8_t)192); // answer name is a pointer _udp.write((uint8_t)12); // pointer to offset at 0x00c _udp.write((uint8_t)0); // 0x0001 answer is type A query (host address) _udp.write((uint8_t)1); _udp.write((uint8_t)0); //0x0001 answer is class IN (internet address) _udp.write((uint8_t)1); _udp.write((unsigned char*)&_ttl, 4); // Length of RData is 4 bytes (because, in this case, RData is IPv4) _udp.write((uint8_t)0); _udp.write((uint8_t)4); _udp.write(_resolvedIP, sizeof(_resolvedIP)); _udp.endPacket(); #ifdef DEBUG DEBUG_OUTPUT.print("DNS responds: "); DEBUG_OUTPUT.print(_resolvedIP[0]); DEBUG_OUTPUT.print("."); DEBUG_OUTPUT.print(_resolvedIP[1]); DEBUG_OUTPUT.print("."); DEBUG_OUTPUT.print(_resolvedIP[2]); DEBUG_OUTPUT.print("."); DEBUG_OUTPUT.print(_resolvedIP[3]); DEBUG_OUTPUT.print(" for "); DEBUG_OUTPUT.println(getDomainNameWithoutWwwPrefix()); #endif } void DNSServer::replyWithCustomCode() { _dnsHeader->QR = DNS_QR_RESPONSE; _dnsHeader->RCode = (unsigned char)_errorReplyCode; _dnsHeader->QDCount = 0; _udp.beginPacket(_udp.remoteIP(), _udp.remotePort()); _udp.write(_buffer, sizeof(DNSHeader)); _udp.endPacket(); }