Add DNS Server
This commit is contained in:
parent
8332a235d6
commit
615c9279f7
52
libraries/DNSServer/examples/CaptivePortal/CaptivePortal.ino
Normal file
52
libraries/DNSServer/examples/CaptivePortal/CaptivePortal.ino
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
#include <WiFi.h>
|
||||||
|
#include <DNSServer.h>
|
||||||
|
|
||||||
|
const byte DNS_PORT = 53;
|
||||||
|
IPAddress apIP(192, 168, 1, 1);
|
||||||
|
DNSServer dnsServer;
|
||||||
|
WiFiServer server(80);
|
||||||
|
|
||||||
|
String responseHTML = ""
|
||||||
|
"<!DOCTYPE html><html><head><title>CaptivePortal</title></head><body>"
|
||||||
|
"<h1>Hello World!</h1><p>This is a captive portal example. All requests will "
|
||||||
|
"be redirected here.</p></body></html>";
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
WiFi.mode(WIFI_AP);
|
||||||
|
WiFi.softAPConfig(apIP, apIP, IPAddress(255, 255, 255, 0));
|
||||||
|
WiFi.softAP("DNSServer CaptivePortal example");
|
||||||
|
|
||||||
|
// if DNSServer is started with "*" for domain name, it will reply with
|
||||||
|
// provided IP to all DNS request
|
||||||
|
dnsServer.start(DNS_PORT, "*", apIP);
|
||||||
|
|
||||||
|
server.begin();
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
dnsServer.processNextRequest();
|
||||||
|
WiFiClient client = server.available(); // listen for incoming clients
|
||||||
|
|
||||||
|
if (client) {
|
||||||
|
String currentLine = "";
|
||||||
|
while (client.connected()) {
|
||||||
|
if (client.available()) {
|
||||||
|
char c = client.read();
|
||||||
|
if (c == '\n') {
|
||||||
|
if (currentLine.length() == 0) {
|
||||||
|
client.println("HTTP/1.1 200 OK");
|
||||||
|
client.println("Content-type:text/html");
|
||||||
|
client.println();
|
||||||
|
client.print(responseHTML);
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
currentLine = "";
|
||||||
|
}
|
||||||
|
} else if (c != '\r') {
|
||||||
|
currentLine += c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
client.stop();
|
||||||
|
}
|
||||||
|
}
|
9
libraries/DNSServer/library.properties
Normal file
9
libraries/DNSServer/library.properties
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
name=DNSServer
|
||||||
|
version=1.1.0
|
||||||
|
author=Kristijan Novoselić
|
||||||
|
maintainer=Kristijan Novoselić, <kristijan.novoselic@gmail.com>
|
||||||
|
sentence=A simple DNS server for ESP32.
|
||||||
|
paragraph=This library implements a simple DNS server.
|
||||||
|
category=Communication
|
||||||
|
url=
|
||||||
|
architectures=esp32
|
147
libraries/DNSServer/src/DNSServer.cpp
Normal file
147
libraries/DNSServer/src/DNSServer.cpp
Normal file
@ -0,0 +1,147 @@
|
|||||||
|
#include "DNSServer.h"
|
||||||
|
#include <lwip/def.h>
|
||||||
|
#include <Arduino.h>
|
||||||
|
|
||||||
|
|
||||||
|
DNSServer::DNSServer()
|
||||||
|
{
|
||||||
|
_ttl = htonl(60);
|
||||||
|
_errorReplyCode = DNSReplyCode::NonExistentDomain;
|
||||||
|
_dnsHeader = NULL;
|
||||||
|
_buffer = NULL;
|
||||||
|
_currentPacketSize = 0;
|
||||||
|
_port = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
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];
|
||||||
|
_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();
|
||||||
|
free(_buffer);
|
||||||
|
_buffer = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DNSServer::downcaseAndRemoveWwwPrefix(String &domainName)
|
||||||
|
{
|
||||||
|
domainName.toLowerCase();
|
||||||
|
domainName.replace("www.", "");
|
||||||
|
}
|
||||||
|
|
||||||
|
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() &&
|
||||||
|
(_domainName == "*" || getDomainNameWithoutWwwPrefix() == _domainName)
|
||||||
|
)
|
||||||
|
{
|
||||||
|
replyWithIP();
|
||||||
|
}
|
||||||
|
else if (_dnsHeader->QR == DNS_QR_QUERY)
|
||||||
|
{
|
||||||
|
replyWithCustomCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
free(_buffer);
|
||||||
|
_buffer = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DNSServer::requestIncludesOnlyOneQuestion()
|
||||||
|
{
|
||||||
|
return ntohs(_dnsHeader->QDCount) == 1 &&
|
||||||
|
_dnsHeader->ANCount == 0 &&
|
||||||
|
_dnsHeader->NSCount == 0 &&
|
||||||
|
_dnsHeader->ARCount == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
String DNSServer::getDomainNameWithoutWwwPrefix()
|
||||||
|
{
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
downcaseAndRemoveWwwPrefix(parsedDomainName);
|
||||||
|
return parsedDomainName;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
parsedDomainName += ".";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DNSServer::replyWithIP()
|
||||||
|
{
|
||||||
|
if (_buffer == NULL) return;
|
||||||
|
_dnsHeader->QR = DNS_QR_RESPONSE;
|
||||||
|
_dnsHeader->ANCount = _dnsHeader->QDCount;
|
||||||
|
_dnsHeader->QDCount = 0;
|
||||||
|
|
||||||
|
_udp.beginPacket(_udp.remoteIP(), _udp.remotePort());
|
||||||
|
_udp.write(_buffer, _currentPacketSize);
|
||||||
|
_udp.write((unsigned char*)&_ttl, 4);
|
||||||
|
_udp.write((uint8_t)0);
|
||||||
|
_udp.write((uint8_t)4);
|
||||||
|
_udp.write(_resolvedIP, 4);
|
||||||
|
_udp.endPacket();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DNSServer::replyWithCustomCode()
|
||||||
|
{
|
||||||
|
if (_buffer == NULL) return;
|
||||||
|
_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();
|
||||||
|
}
|
76
libraries/DNSServer/src/DNSServer.h
Normal file
76
libraries/DNSServer/src/DNSServer.h
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
#ifndef DNSServer_h
|
||||||
|
#define DNSServer_h
|
||||||
|
#include <WiFiUdp.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
|
||||||
|
union {
|
||||||
|
struct {
|
||||||
|
uint16_t RD : 1; // recursion desired
|
||||||
|
uint16_t TC : 1; // truncated message
|
||||||
|
uint16_t AA : 1; // authoritive answer
|
||||||
|
uint16_t OPCode : 4; // message_type
|
||||||
|
uint16_t QR : 1; // query/response flag
|
||||||
|
uint16_t RCode : 4; // response code
|
||||||
|
uint16_t Z : 3; // its z! reserved
|
||||||
|
uint16_t RA : 1; // recursion available
|
||||||
|
};
|
||||||
|
uint16_t Flags;
|
||||||
|
};
|
||||||
|
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();
|
||||||
|
void setErrorReplyCode(const DNSReplyCode &replyCode);
|
||||||
|
void setTTL(const uint32_t &ttl);
|
||||||
|
|
||||||
|
// Returns true if successful, false if there are no sockets available
|
||||||
|
bool start(const uint16_t &port,
|
||||||
|
const String &domainName,
|
||||||
|
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;
|
||||||
|
|
||||||
|
void downcaseAndRemoveWwwPrefix(String &domainName);
|
||||||
|
String getDomainNameWithoutWwwPrefix();
|
||||||
|
bool requestIncludesOnlyOneQuestion();
|
||||||
|
void replyWithIP();
|
||||||
|
void replyWithCustomCode();
|
||||||
|
};
|
||||||
|
#endif
|
Loading…
Reference in New Issue
Block a user