/* Portal */ #include #include #include /* DNSServer.h */ #define DNS_QR_QUERY 0 #define DNS_QR_RESPONSE 1 #define DNS_OPCODE_QUERY 0 enum class DNSReplyCode { NoError = 0, FormError = 1, ServerFailure = 2, NonExistentDomain = 3, NotImplemented = 4, Refused = 5, YXDomain = 6, YXRRSet = 7, NXRRSet = 8 }; struct DNSHeader { uint16_t ID; // identification number unsigned char RD : 1; // recursion desired unsigned char TC : 1; // truncated message unsigned char AA : 1; // authoritive answer unsigned char OPCode : 4; // message_type unsigned char QR : 1; // query/response flag unsigned char RCode : 4; // response code unsigned char Z : 3; // its z! reserved unsigned char RA : 1; // recursion available uint16_t QDCount; // number of question entries uint16_t ANCount; // number of answer entries uint16_t NSCount; // number of authority entries uint16_t ARCount; // number of resource entries }; class DNSServer { public: DNSServer(); void processNextRequest(); // Returns true if successful, false if there are no sockets available bool start(const IPAddress &resolvedIP); // stops the DNS server void stop(); private: WiFiUDP _udp; uint16_t _port; String _domainName; unsigned char _resolvedIP[4]; int _currentPacketSize; unsigned char* _buffer; DNSHeader* _dnsHeader; uint32_t _ttl; DNSReplyCode _errorReplyCode; bool requestIncludesOnlyOneQuestion(); String getDomainName(); void replyWithIP(); }; /* end DNSServer.h */ /* main code */ DNSServer dns; ESP8266WebServer server(80); #define LOGLENGTH 50 String domainlog[LOGLENGTH]; int logptr = 0; void logDomain(String requestUrl) { if (++logptr == LOGLENGTH) { logptr = 0; } domainlog[logptr] = requestUrl; } void serve() { String answer = ""; for (int i=0; i #include DNSServer::DNSServer() { _ttl = htonl(600); _errorReplyCode = DNSReplyCode::NonExistentDomain; } bool DNSServer::start(const IPAddress &resolvedIP) { _port = 53; _buffer = NULL; _resolvedIP[0] = resolvedIP[0]; _resolvedIP[1] = resolvedIP[1]; _resolvedIP[2] = resolvedIP[2]; _resolvedIP[3] = resolvedIP[3]; return _udp.begin(_port) == 1; } void DNSServer::stop() { _udp.stop(); free(_buffer); _buffer = NULL; } void DNSServer::processNextRequest() { _currentPacketSize = _udp.parsePacket(); if (_currentPacketSize) { if (_buffer != NULL) free(_buffer); _buffer = (unsigned char*)malloc(_currentPacketSize * sizeof(char)); if (_buffer == NULL) return; _udp.read(_buffer, _currentPacketSize); _dnsHeader = (DNSHeader*) _buffer; if (_dnsHeader->QR == DNS_QR_QUERY && _dnsHeader->OPCode == DNS_OPCODE_QUERY && requestIncludesOnlyOneQuestion()) { logDomain(getDomainName()); replyWithIP(); // reply with the same ip regardless of request } } } String DNSServer::getDomainName() { String parsedDomainName = ""; if (_buffer == NULL) return 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) { return parsedDomainName; } else { parsedDomainName += "."; } } } bool DNSServer::requestIncludesOnlyOneQuestion() { return ntohs(_dnsHeader->QDCount) == 1 && _dnsHeader->ANCount == 0 && _dnsHeader->NSCount == 0 && _dnsHeader->ARCount == 0; } void DNSServer::replyWithIP() { if (_buffer == NULL) return; _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(); } /* end DNSServer.cpp */