Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dns server cleanup #5194

Merged
merged 5 commits into from
Oct 4, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions libraries/DNSServer/keywords.txt
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ stop KEYWORD2
DNS_QR_QUERY LITERAL1 RESERVED_WORD_2
DNS_QR_RESPONSE LITERAL1 RESERVED_WORD_2
DNS_OPCODE_QUERY LITERAL1 RESERVED_WORD_2
MAX_DNSNAME_LENGTH LITERAL1 RESERVED_WORD_2
NoError LITERAL1 RESERVED_WORD_2
FormError LITERAL1 RESERVED_WORD_2
ServerFailure LITERAL1 RESERVED_WORD_2
Expand Down
2 changes: 1 addition & 1 deletion libraries/DNSServer/library.properties
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
name=DNSServer
version=1.1.0
version=1.1.1
author=Kristijan Novoselić
maintainer=Kristijan Novoselić, <kristijan.novoselic@gmail.com>
sentence=A simple DNS server for ESP8266.
Expand Down
144 changes: 85 additions & 59 deletions libraries/DNSServer/src/DNSServer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ bool DNSServer::start(const uint16_t &port, const String &domainName,
const IPAddress &resolvedIP)
{
_port = port;
_buffer = NULL;

_domainName = domainName;
_resolvedIP[0] = resolvedIP[0];
_resolvedIP[1] = resolvedIP[1];
Expand All @@ -36,8 +36,6 @@ void DNSServer::setTTL(const uint32_t &ttl)
void DNSServer::stop()
{
_udp.stop();
free(_buffer);
_buffer = NULL;
}

void DNSServer::downcaseAndRemoveWwwPrefix(String &domainName)
Expand All @@ -48,82 +46,106 @@ void DNSServer::downcaseAndRemoveWwwPrefix(String &domainName)

void DNSServer::processNextRequest()
{
_currentPacketSize = _udp.parsePacket();
if (_currentPacketSize)
size_t packetSize = _udp.parsePacket();

if (packetSize >= sizeof(DNSHeader))
{
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() &&
(_domainName == "*" || getDomainNameWithoutWwwPrefix() == _domainName)
uint8_t* buffer = reinterpret_cast<uint8_t*>(malloc(packetSize));
if (buffer == NULL) return;

_udp.read(buffer, packetSize);

DNSHeader* dnsHeader = reinterpret_cast<DNSHeader*>(buffer);

if (dnsHeader->QR == DNS_QR_QUERY &&
dnsHeader->OPCode == DNS_OPCODE_QUERY &&
requestIncludesOnlyOneQuestion(dnsHeader) &&
(_domainName == "*" || getDomainNameWithoutWwwPrefix(buffer, packetSize) == _domainName)
)
{
replyWithIP();
replyWithIP(buffer, packetSize);
}
else if (_dnsHeader->QR == DNS_QR_QUERY)
else if (dnsHeader->QR == DNS_QR_QUERY)
{
replyWithCustomCode();
replyWithCustomCode(buffer, packetSize);
}

free(_buffer);
_buffer = NULL;
free(buffer);
}
}

bool DNSServer::requestIncludesOnlyOneQuestion()
bool DNSServer::requestIncludesOnlyOneQuestion(const DNSHeader* dnsHeader)
{
return ntohs(_dnsHeader->QDCount) == 1 &&
_dnsHeader->ANCount == 0 &&
_dnsHeader->NSCount == 0 &&
_dnsHeader->ARCount == 0;
return ntohs(dnsHeader->QDCount) == 1 &&
dnsHeader->ANCount == 0 &&
dnsHeader->NSCount == 0 &&
dnsHeader->ARCount == 0;
}

String DNSServer::getDomainNameWithoutWwwPrefix()
String DNSServer::getDomainNameWithoutWwwPrefix(const uint8_t* buffer, size_t packetSize)
{
String parsedDomainName = "";
if (_buffer == NULL) return parsedDomainName;
unsigned char *start = _buffer + 12;
if (*start == 0)
{
return parsedDomainName;
}
int pos = 0;
while(true)
String parsedDomainName;

const uint8_t* pos = buffer + sizeof(DNSHeader);
const uint8_t* end = buffer + packetSize;

// to minimize reallocations due to concats below
// we reserve enough space that a median or average domain
// name size cold be easily contained without a reallocation
// - max size would be 253, in 2013, average is 11 and max was 42
//
parsedDomainName.reserve(32);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yay! String::reserve() examples are few and far between.


uint8_t labelLength = *pos;

while (true)
{
unsigned char labelLength = *(start + pos);
for(int i = 0; i < labelLength; i++)
if (labelLength == 0)
{
// no more labels
downcaseAndRemoveWwwPrefix(parsedDomainName);
return parsedDomainName;
}

// append next label
for (int i = 0; i < labelLength && pos < end; i++)
{
pos++;
parsedDomainName += (char)*(start + pos);
parsedDomainName += static_cast<char>(*pos);
}
pos++;
if (*(start + pos) == 0)

if (pos >= end)
{
downcaseAndRemoveWwwPrefix(parsedDomainName);
return parsedDomainName;
// malformed packet, return an empty domain name
parsedDomainName = "";
return parsedDomainName;
}
else
{
parsedDomainName += ".";
// next label
pos++;
labelLength = *pos;

// if there is another label, add delimiter
if (labelLength != 0)
{
parsedDomainName += ".";
}
}
}
}

void DNSServer::replyWithIP()
void DNSServer::replyWithIP(uint8_t* buffer, size_t packetSize)
{
if (_buffer == NULL) return;
_dnsHeader->QR = DNS_QR_RESPONSE;
_dnsHeader->ANCount = _dnsHeader->QDCount;
_dnsHeader->QDCount = _dnsHeader->QDCount;
//_dnsHeader->RA = 1;
DNSHeader* dnsHeader = reinterpret_cast<DNSHeader*>(buffer);

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(buffer, packetSize);

_udp.write((uint8_t)192); // answer name is a pointer
_udp.write((uint8_t)12); // pointer to offset at 0x00c
Expand All @@ -142,22 +164,26 @@ void DNSServer::replyWithIP()
_udp.write(_resolvedIP, sizeof(_resolvedIP));
_udp.endPacket();



#ifdef DEBUG_ESP_DNS
DEBUG_ESP_PORT.printf("DNS responds: %s for %s\n",
IPAddress(_resolvedIP).toString().c_str(), getDomainNameWithoutWwwPrefix().c_str() );
IPAddress(_resolvedIP).toString().c_str(), getDomainNameWithoutWwwPrefix(buffer, packetSize).c_str() );
#endif
}

void DNSServer::replyWithCustomCode()
void DNSServer::replyWithCustomCode(uint8_t* buffer, size_t packetSize)
{
if (_buffer == NULL) return;
_dnsHeader->QR = DNS_QR_RESPONSE;
_dnsHeader->RCode = (unsigned char)_errorReplyCode;
_dnsHeader->QDCount = 0;
if (packetSize < sizeof(DNSHeader))
{
return;
}

DNSHeader* dnsHeader = reinterpret_cast<DNSHeader*>(buffer);

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.write(buffer, sizeof(DNSHeader));
_udp.endPacket();
}
16 changes: 9 additions & 7 deletions libraries/DNSServer/src/DNSServer.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
#define DNS_QR_RESPONSE 1
#define DNS_OPCODE_QUERY 0

#define MAX_DNSNAME_LENGTH 253

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not used anywhere as far as I can see, but shouldn't do any harm.

enum class DNSReplyCode
{
NoError = 0,
Expand Down Expand Up @@ -40,6 +42,9 @@ class DNSServer
{
public:
DNSServer();
~DNSServer() {
stop();
};
void processNextRequest();
void setErrorReplyCode(const DNSReplyCode &replyCode);
void setTTL(const uint32_t &ttl);
Expand All @@ -56,16 +61,13 @@ class DNSServer
uint16_t _port;
String _domainName;
unsigned char _resolvedIP[4];
int _currentPacketSize;
unsigned char* _buffer;
DNSHeader* _dnsHeader;
uint32_t _ttl;
DNSReplyCode _errorReplyCode;

void downcaseAndRemoveWwwPrefix(String &domainName);
String getDomainNameWithoutWwwPrefix();
bool requestIncludesOnlyOneQuestion();
void replyWithIP();
void replyWithCustomCode();
String getDomainNameWithoutWwwPrefix(const uint8_t* buffer, size_t packetSize);
bool requestIncludesOnlyOneQuestion(const DNSHeader* dnsHeader);
void replyWithIP(uint8_t* buffer, size_t packetSize);
void replyWithCustomCode(uint8_t* buffer, size_t packetSize);
};
#endif