1
0
mirror of https://github.com/esp8266/Arduino.git synced 2025-04-19 23:22:16 +03:00

Added a DNSServer library

This commit is contained in:
Kristijan Novoselic 2015-06-06 22:12:18 +02:00 committed by Ivan Grokhotkov
parent 533b6c184b
commit c570d0f593
5 changed files with 263 additions and 18 deletions

View File

@ -102,9 +102,9 @@ This is mostly similar to WiFi shield library. Differences include:
- ```WiFi.RSSI()``` doesn't work - ```WiFi.RSSI()``` doesn't work
- ```WiFi.printDiag(Serial);``` will print out some diagnostic info - ```WiFi.printDiag(Serial);``` will print out some diagnostic info
- ```WiFiUDP``` class supports sending and receiving multicast packets on STA interface. - ```WiFiUDP``` class supports sending and receiving multicast packets on STA interface.
When sending a multicast packet, replace ```udp.beginPacket(addr, port)``` with When sending a multicast packet, replace ```udp.beginPacket(addr, port)``` with
```udp.beginPacketMulticast(addr, port, WiFi.localIP())```. ```udp.beginPacketMulticast(addr, port, WiFi.localIP())```.
When listening to multicast packets, replace ```udp.begin(port)``` with When listening to multicast packets, replace ```udp.begin(port)``` with
```udp.beginMulticast(WiFi.localIP(), multicast_ip_addr, port)```. ```udp.beginMulticast(WiFi.localIP(), multicast_ip_addr, port)```.
You can use ```udp.destinationIP()``` to tell whether the packet received was You can use ```udp.destinationIP()``` to tell whether the packet received was
sent to the multicast or unicast address. sent to the multicast or unicast address.
@ -118,7 +118,7 @@ You can see more commands here: [http://www.arduino.cc/en/Reference/WiFi](http:/
Library for calling functions repeatedly with a certain period. Two examples included. Library for calling functions repeatedly with a certain period. Two examples included.
It is currently not recommended to do blocking IO operations (network, serial, file) from Ticker It is currently not recommended to do blocking IO operations (network, serial, file) from Ticker
callback functions. Instead, set a flag inside the ticker callback and check for that flag inside the loop function. callback functions. Instead, set a flag inside the ticker callback and check for that flag inside the loop function.
#### EEPROM #### #### EEPROM ####
@ -184,6 +184,11 @@ Allows the sketch to respond to multicast DNS queries for domain names like "foo
Currently the library only works on STA interface, AP interface is not supported. Currently the library only works on STA interface, AP interface is not supported.
See attached example and library README file for details. See attached example and library README file for details.
#### DNS server (DNSServer library) ####
Implements a simple DNS server that can be used in both STA and AP modes. The DNS server currently supports only one domain (for all other domains it will reply with NXDOMAIN or custom status code). With it clients can open a web server running on ESP8266 using a domain name, not an IP address.
See attached example for details.
#### Servo #### #### Servo ####
This library exposes the ability to control RC (hobby) servo motors. It will support upto 24 servos on any available output pin. By defualt the first 12 servos will use Timer0 and currently this will not interfere with any other support. Servo counts above 12 will use Timer1 and features that use it will be effected. This library exposes the ability to control RC (hobby) servo motors. It will support upto 24 servos on any available output pin. By defualt the first 12 servos will use Timer0 and currently this will not interfere with any other support. Servo counts above 12 will use Timer1 and features that use it will be effected.
@ -212,10 +217,10 @@ You need to put ESP8266 into bootloader mode before uploading code.
For stable use of the ESP8266 a power supply with 3V3 and >= 250mA is required. For stable use of the ESP8266 a power supply with 3V3 and >= 250mA is required.
* Note * Note
- using Power from USB to Serial is may unstable, they not deliver enough current. - using Power from USB to Serial is may unstable, they not deliver enough current.
#### Serial Adapter #### #### Serial Adapter ####
There are many different USB to Serial adapters / boards. There are many different USB to Serial adapters / boards.
* Note * Note
@ -224,17 +229,17 @@ There are many different USB to Serial adapters / boards.
- not all board have all pins of the ICs as breakout (check before order) - not all board have all pins of the ICs as breakout (check before order)
- CTS and DSR are not useful for upload (they are Inputs) - CTS and DSR are not useful for upload (they are Inputs)
* Working ICs * Working ICs
- FT232RL - FT232RL
- CP2102 - CP2102
- may others (drop a comment) - may others (drop a comment)
#### Minimal hardware Setup for Bootloading and usage #### #### Minimal hardware Setup for Bootloading and usage ####
ESPxx Hardware ESPxx Hardware
| PIN | Resistor | Serial Adapter | | PIN | Resistor | Serial Adapter |
| ------------- | -------- | -------------- | | ------------- | -------- | -------------- |
| VCC | | VCC (3.3V) | | VCC | | VCC (3.3V) |
| GND | | GND | | GND | | GND |
| TX or GPIO2* | | RX | | TX or GPIO2* | | RX |
@ -244,11 +249,11 @@ ESPxx Hardware
| GPIO15* | PullDown | | | GPIO15* | PullDown | |
| CH_PD | PullUp | | | CH_PD | PullUp | |
* Note * Note
- GPIO15 is also named MTDO - GPIO15 is also named MTDO
- Reset is also named RSBT or REST (adding PullUp improves the stability of the Module) - Reset is also named RSBT or REST (adding PullUp improves the stability of the Module)
- GPIO2 is alternative TX for the boot loader mode - GPIO2 is alternative TX for the boot loader mode
###### esp to Serial ###### esp to Serial
![ESP to Serial](https://raw.githubusercontent.com/Links2004/Arduino/esp8266/docs/ESP_to_serial.png) ![ESP to Serial](https://raw.githubusercontent.com/Links2004/Arduino/esp8266/docs/ESP_to_serial.png)
@ -256,7 +261,7 @@ ESPxx Hardware
ESPxx Hardware ESPxx Hardware
| PIN | Resistor | Serial Adapter | | PIN | Resistor | Serial Adapter |
| ------------- | -------- | --------------- | | ------------- | -------- | --------------- |
| VCC | | VCC (3.3V) | | VCC | | VCC (3.3V) |
| GND | | GND | | GND | | GND |
| TX or GPIO2 | | RX | | TX or GPIO2 | | RX |
@ -266,15 +271,15 @@ ESPxx Hardware
| GPIO15 | PullDown | | | GPIO15 | PullDown | |
| CH_PD | PullUp | | | CH_PD | PullUp | |
* Note * Note
- if no RTS is used a manual power toggle is needed - if no RTS is used a manual power toggle is needed
#### Minimal hardware Setup for running only #### #### Minimal hardware Setup for running only ####
ESPxx Hardware ESPxx Hardware
| PIN | Resistor | Power supply | | PIN | Resistor | Power supply |
| ------------- | -------- | --------------- | | ------------- | -------- | --------------- |
| VCC | | VCC (3.3V) | | VCC | | VCC (3.3V) |
| GND | | GND | | GND | | GND |
| GPIO0 | PullUp | | | GPIO0 | PullUp | |
@ -285,7 +290,7 @@ ESPxx Hardware
![ESP min](https://raw.githubusercontent.com/Links2004/Arduino/esp8266/docs/ESP_min.png) ![ESP min](https://raw.githubusercontent.com/Links2004/Arduino/esp8266/docs/ESP_min.png)
###### improved stability ###### improved stability
![ESP improved stability](https://raw.githubusercontent.com/Links2004/Arduino/esp8266/docs/ESP_improved_stability.png) ![ESP improved stability](https://raw.githubusercontent.com/Links2004/Arduino/esp8266/docs/ESP_improved_stability.png)
### Issues and support ### ### Issues and support ###
@ -306,5 +311,3 @@ Esptool written by Christian Klippel is licensed under GPLv2, currently maintain
ESP8266 core support, ESP8266WiFi, Ticker, ESP8266WebServer libraries were written by Ivan Grokhotkov, ivan@esp8266.com. ESP8266 core support, ESP8266WiFi, Ticker, ESP8266WebServer libraries were written by Ivan Grokhotkov, ivan@esp8266.com.
[SPI Flash File System (SPIFFS)](https://github.com/pellepl/spiffs) written by Peter Andersson is used in this project. It is distributed under MIT license. [SPI Flash File System (SPIFFS)](https://github.com/pellepl/spiffs) written by Peter Andersson is used in this project. It is distributed under MIT license.

View File

@ -0,0 +1,28 @@
#include <ESP8266WiFi.h>
#include <DNSServer.h>
const byte DNS_PORT = 53;
IPAddress apIP(192, 168, 1, 1);
DNSServer dnsServer;
void setup() {
WiFi.mode(WIFI_AP);
WiFi.softAPConfig(apIP, apIP, IPAddress(255, 255, 255, 0));
WiFi.softAP("DNSServer example");
// modify TTL associated with the domain name (in seconds)
// default is 60 seconds
dnsServer.setTTL(300);
// set which return code will be used for all other domains (e.g. sending
// ServerFailure instead of NonExistentDomain will reduce number of queries
// sent by clients)
// default is DNSReplyCode::NonExistentDomain
dnsServer.setErrorReplyCode(DNSReplyCode::ServerFailure);
//start DNS server for a specific domain name
dnsServer.start(DNS_PORT, "www.example.com", apIP);
}
void loop() {
dnsServer.processNextRequest();
}

View File

@ -0,0 +1,9 @@
name=DNSServer
version=1.0.0
author=Kristijan Novoselić
maintainer=Kristijan Novoselić, <kristijan.novoselic@gmail.com>
sentence=A simple DNS server for ESP8266.
paragraph=This library implements a simple DNS server.
category=Communication
url=
architectures=esp8266

View File

@ -0,0 +1,133 @@
#include "DNSServer.h"
#include <lwip/def.h>
#include <Arduino.h>
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.", "");
}
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() &&
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 = 0;
_udp.beginPacket(_udp.remoteIP(), _udp.remotePort());
_udp.write(_buffer, _currentPacketSize);
_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();
}
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();
}

View File

@ -0,0 +1,72 @@
#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
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();
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