You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
167 lines
3.8 KiB
167 lines
3.8 KiB
4 years ago
|
#include "./DNSServer.h"
|
||
|
#include <lwip/def.h>
|
||
|
#include <Arduino.h>
|
||
|
|
||
|
#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();
|
||
|
}
|