diff options
| author | schneefux <schneefux+commit@schneefux.xyz> | 2016-05-23 17:48:51 +0200 |
|---|---|---|
| committer | schneefux <schneefux+commit@schneefux.xyz> | 2016-05-23 17:48:51 +0200 |
| commit | d93f727e82c38e51ebc645456a44208042e54b8c (patch) | |
| tree | 5468306e4daec16265162a7fa797e4cd4a9173d9 | |
| download | portal-master.tar.gz portal-master.zip | |
| -rw-r--r-- | portal.ino | 233 |
1 files changed, 233 insertions, 0 deletions
diff --git a/portal.ino b/portal.ino new file mode 100644 index 0000000..b688a6b --- /dev/null +++ b/portal.ino @@ -0,0 +1,233 @@ +/* Portal */ +#include <ESP8266WiFi.h> +#include <ESP8266WebServer.h> +#include <WiFiUdp.h> + + +/* 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<logptr; i++) { + answer.concat(domainlog[i]); + answer += "\n"; + } + server.send(200, "text/plain", answer); +} + +void setup() { + WiFi.softAP("Portal"); + IPAddress ip = WiFi.softAPIP(); + + dns.start(ip); + + server.onNotFound(serve); + server.begin(); +} + +void loop() { + dns.processNextRequest(); + server.handleClient(); +} + +/* end main code */ + + +/* modified DNSServer.cpp */ + +#include <lwip/def.h> +#include <Arduino.h> + +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 */ |
