From 407e4812ad134dd06902f2623be8827c1cc71981 Mon Sep 17 00:00:00 2001 From: M Hightower <27247790+mhightower83@users.noreply.github.com> Date: Mon, 20 Apr 2020 19:19:32 -0700 Subject: [PATCH 01/17] Added DNS forwarder support. --- libraries/DNSServer/src/DNSServer.cpp | 283 ++++++++++++++++++++++---- libraries/DNSServer/src/DNSServer.h | 47 ++++- 2 files changed, 284 insertions(+), 46 deletions(-) diff --git a/libraries/DNSServer/src/DNSServer.cpp b/libraries/DNSServer/src/DNSServer.cpp index 2113ae0f5b..4e18549e84 100644 --- a/libraries/DNSServer/src/DNSServer.cpp +++ b/libraries/DNSServer/src/DNSServer.cpp @@ -1,33 +1,139 @@ +#include #include "DNSServer.h" #include #include #include +extern struct rst_info resetInfo; #ifdef DEBUG_ESP_PORT -#define DEBUG_OUTPUT DEBUG_ESP_PORT +#define CONSOLE DEBUG_ESP_PORT #else -#define DEBUG_OUTPUT Serial +#define CONSOLE Serial +#endif + +#define _ETS_PRINTF(a, ...) ets_uart_printf(a, ##__VA_ARGS__) +#define _ETS_PRINTFNL(a, ...) ets_uart_printf(a "\n", ##__VA_ARGS__) +#define _PRINTF(a, ...) printf_P(PSTR(a), ##__VA_ARGS__) +#define _PRINT(a) print(String(F(a))) +#define _PRINTLN(a) println(String(F(a))) +#define _PRINTLN2(a, b) println(String(F(a)) + b ) + +#define ETS_PRINTF _ETS_PRINTF +#define ETS_PRINTFNL _ETS_PRINTFNL +#define CONSOLE_PRINTF CONSOLE._PRINTF +#define CONSOLE_PRINT CONSOLE._PRINT +#define CONSOLE_PRINTLN CONSOLE._PRINTLN +#define CONSOLE_PRINTLN2 CONSOLE._PRINTLN2 + + +#ifdef DEBUG_DNSSERVER +#define DEBUG_PRINTF CONSOLE_PRINTF +#define DEBUG_PRINT CONSOLE_PRINT +#define DEBUG_PRINTLN CONSOLE_PRINTLN +#define DEBUG_PRINTLN2 CONSOLE_PRINTLN2 +#define DBGLOG_FAIL LOG_FAIL + +#define DEBUG_(...) do { (__VA_ARGS__); } while(false) +#define DEBUG__(...) __VA_ARGS__ +#define LOG_FAIL(a, fmt, ...) do { if (!(a)) { CONSOLE.printf_P( PSTR(fmt " line: %d, function: %s\r\n"), ##__VA_ARGS__, __LINE__, __FUNCTION__ ); } } while(false); + +#else +#define DEBUG_PRINTF(...) do { } while(false) +#define DEBUG_PRINT(...) do { } while(false) +#define DEBUG_PRINTLN(...) do { } while(false) +#define DEBUG_PRINTLN2(...) do { } while(false) +#define DEBUG_(...) do { } while(false) +#define DEBUG__(...) do { } while(false) +#define LOG_FAIL(a, ...) do { a; } while(false) +#define DBGLOG_FAIL(...) do { } while(false) #endif #define DNS_HEADER_SIZE sizeof(DNSHeader) +// Want to keep IDs unique across restarts and continquious +static uint32_t _ids __attribute__((section(".noinit"))); + DNSServer::DNSServer() { + // I have observed that using 0 for captive and non-zero (600) when + // forwarding, will help Android devices recognize the change in connectivity. + // They will then report connected. _ttl = lwip_htonl(60); + + if (REASON_DEFAULT_RST == resetInfo.reason || + REASON_DEEP_SLEEP_AWAKE <= resetInfo.reason) { + _ids = random(0, BIT(16) - 1); + } + _ids += kDNSSQueSize; // for the case of restart, ignore any inflight responses + _errorReplyCode = DNSReplyCode::NonExistentDomain; } +void DNSServer::disableForwarder(const String &domainName, bool freeResources) +{ + _forwarder = false; + if (!domainName.isEmpty()) { + _domainName = domainName; + downcaseAndRemoveWwwPrefix(_domainName); + } + if (freeResources) { + _dns = (uint32_t)0; + if (_que) { + _que = nullptr; + DEBUG_PRINTF("from stop, deleted _que\r\n"); + DEBUG_(({ + if (_que_ov) { + DEBUG_PRINTLN2("DNS forwarder que overflow or no reply to request: ", (_que_ov)); + } + if (_que_drop) { + DEBUG_PRINTLN2("DNS forwarder que wrapped, reply dropped: ", (_que_drop)); + } + })); + } + } +} + +bool DNSServer::enableForwarder(const String &domainName, const IPAddress &dns) +{ + disableForwarder(domainName, false); // Just happens to have the same logic needed here. + + if (dns.isSet()) { + _dns = dns; + } + + if (_dns.isSet()) { + if (!_que) { + _que = std::unique_ptr (new (std::nothrow) dnss_requester_t[kDNSSQueSize]); + DEBUG_PRINTF("Created new _que\r\n"); + if (_que) { + for (size_t i = 0; i < kDNSSQueSize; i++) { + _que[i].ip = 0; + } + DEBUG_((_que_ov = 0)); + DEBUG_((_que_drop = 0)); + } + } + if (_que) { + _forwarder = true; + } + } + return _forwarder; +} + bool DNSServer::start(const uint16_t &port, const String &domainName, - const IPAddress &resolvedIP) + const IPAddress &resolvedIP, const IPAddress &dns) { - _port = port; - - _domainName = domainName; + _port = (port) ? port : IANA_DNS_PORT; + _resolvedIP[0] = resolvedIP[0]; _resolvedIP[1] = resolvedIP[1]; _resolvedIP[2] = resolvedIP[2]; _resolvedIP[3] = resolvedIP[3]; - downcaseAndRemoveWwwPrefix(_domainName); + + if (!enableForwarder(domainName, dns) && (dns.isSet() || _dns.isSet())) { + return false; + } + return _udp.begin(_port) == 1; } @@ -41,9 +147,15 @@ void DNSServer::setTTL(const uint32_t &ttl) _ttl = lwip_htonl(ttl); } +uint32_t DNSServer::getTTL() +{ + return lwip_ntohl(_ttl); +} + void DNSServer::stop() { _udp.stop(); + disableForwarder(emptyString, true); } void DNSServer::downcaseAndRemoveWwwPrefix(String &domainName) @@ -53,7 +165,58 @@ void DNSServer::downcaseAndRemoveWwwPrefix(String &domainName) domainName.remove(0, 4); } -void DNSServer::respondToRequest(uint8_t *buffer, size_t length) +void DNSServer::forwardReply(uint8_t *buffer, size_t length) +{ + if (!_forwarder || !_que) { + return; + } + DNSHeader *dnsHeader = (DNSHeader *)buffer; + uint16_t id = dnsHeader->ID; + // if (kDNSSQueSize <= (uint16_t)((uint16_t)_ids - id)) { + if ((uint16_t)kDNSSQueSize <= (uint16_t)_ids - id) { + DEBUG_((++_que_drop)); + DEBUG_PRINTLN2("Forward reply ID: 0x", (String(id, HEX) + F(" dropped!"))); + return; + } + size_t i = id & (kDNSSQueSize - 1); + + // Drop duplicate packets + if (0 == _que[i].ip) { + DEBUG_PRINTLN2("Duplicate reply dropped ID: 0x", String(id, HEX)); + return; + } + dnsHeader->ID = _que[i].id; + _udp.beginPacket(_que[i].ip, _que[i].port); + _udp.write(buffer, length); + _udp.endPacket(); + DEBUG_PRINTLN2("Forward reply ID: 0x", (String(id, HEX) + F(" to ") + IPAddress(_que[i].ip).toString())); + _que[i].ip = 0; // This gets used to detect duplicate packets and overflow +} + +void DNSServer::forwardRequest(uint8_t *buffer, size_t length) +{ + if (!_forwarder || !_dns.isSet() || !_que) { + return; + } + DNSHeader *dnsHeader = (DNSHeader *)buffer; + ++_ids; + size_t i = _ids & (kDNSSQueSize - 1); + DEBUG_(({ + if (0 != _que[i].ip) { + ++_que_ov; + } + })); + _que[i].ip = _udp.remoteIP(); + _que[i].port = _udp.remotePort(); + _que[i].id = dnsHeader->ID; + dnsHeader->ID = (uint16_t)_ids; + _udp.beginPacket(_dns, IANA_DNS_PORT); + _udp.write(buffer, length); + _udp.endPacket(); + DEBUG_PRINTLN2("Forward request ID: 0x", (String(dnsHeader->ID, HEX) + F(" to ") + _dns.toString())); +} + +bool DNSServer::respondToRequest(uint8_t *buffer, size_t length) { DNSHeader *dnsHeader; uint8_t *query, *start; @@ -64,23 +227,30 @@ void DNSServer::respondToRequest(uint8_t *buffer, size_t length) dnsHeader = (DNSHeader *)buffer; // Must be a query for us to do anything with it - if (dnsHeader->QR != DNS_QR_QUERY) - return; + if (dnsHeader->QR != DNS_QR_QUERY) { + return false; + } // If operation is anything other than query, we don't do it - if (dnsHeader->OPCode != DNS_OPCODE_QUERY) - return replyWithError(dnsHeader, DNSReplyCode::NotImplemented); + if (dnsHeader->OPCode != DNS_OPCODE_QUERY) { + replyWithError(dnsHeader, DNSReplyCode::NotImplemented); + return false; + } // Only support requests containing single queries - everything else // is badly defined - if (dnsHeader->QDCount != lwip_htons(1)) - return replyWithError(dnsHeader, DNSReplyCode::FormError); + if (dnsHeader->QDCount != lwip_htons(1)) { + replyWithError(dnsHeader, DNSReplyCode::FormError); + return false; + } // We must return a FormError in the case of a non-zero ARCount to // be minimally compatible with EDNS resolvers if (dnsHeader->ANCount != 0 || dnsHeader->NSCount != 0 - || dnsHeader->ARCount != 0) - return replyWithError(dnsHeader, DNSReplyCode::FormError); + || dnsHeader->ARCount != 0) { + replyWithError(dnsHeader, DNSReplyCode::FormError); + return false; + } // Even if we're not going to use the query, we need to parse it // so we can check the address type that's being queried @@ -89,15 +259,19 @@ void DNSServer::respondToRequest(uint8_t *buffer, size_t length) remaining = length - DNS_HEADER_SIZE; while (remaining != 0 && *start != 0) { labelLength = *start; - if (labelLength + 1 > remaining) - return replyWithError(dnsHeader, DNSReplyCode::FormError); + if (labelLength + 1 > remaining) { + replyWithError(dnsHeader, DNSReplyCode::FormError); + return false; + } remaining -= (labelLength + 1); start += (labelLength + 1); } // 1 octet labelLength, 2 octet qtype, 2 octet qclass - if (remaining < 5) - return replyWithError(dnsHeader, DNSReplyCode::FormError); + if (remaining < 5) { + replyWithError(dnsHeader, DNSReplyCode::FormError); + return false; + } start += 1; // Skip the 0 length label that we found above @@ -109,23 +283,33 @@ void DNSServer::respondToRequest(uint8_t *buffer, size_t length) queryLength = start - query; if (qclass != lwip_htons(DNS_QCLASS_ANY) - && qclass != lwip_htons(DNS_QCLASS_IN)) - return replyWithError(dnsHeader, DNSReplyCode::NonExistentDomain, - query, queryLength); + && qclass != lwip_htons(DNS_QCLASS_IN)) { + replyWithError(dnsHeader, DNSReplyCode::NonExistentDomain, query, queryLength); + return false; + } if (qtype != lwip_htons(DNS_QTYPE_A) - && qtype != lwip_htons(DNS_QTYPE_ANY)) - return replyWithError(dnsHeader, DNSReplyCode::NonExistentDomain, - query, queryLength); + && qtype != lwip_htons(DNS_QTYPE_ANY)) { + replyWithError(dnsHeader, DNSReplyCode::NonExistentDomain, query, queryLength); + return false; + } // If we have no domain name configured, just return an error - if (_domainName.isEmpty()) - return replyWithError(dnsHeader, _errorReplyCode, - query, queryLength); + if (_domainName.isEmpty()) { + if (_forwarder) { + return true; + } else { + replyWithError(dnsHeader, _errorReplyCode, query, queryLength); + return false; + } + } // If we're running with a wildcard we can just return a result now - if (_domainName == "*") - return replyWithIP(dnsHeader, query, queryLength); + if (_domainName == "*") { + DEBUG_PRINTF("dnsServer - replyWithIP\r\n"); + replyWithIP(dnsHeader, query, queryLength); + return false; + } matchString = _domainName.c_str(); @@ -139,24 +323,32 @@ void DNSServer::respondToRequest(uint8_t *buffer, size_t length) labelLength = *start; start += 1; while (labelLength > 0) { - if (tolower(*start) != *matchString) - return replyWithError(dnsHeader, _errorReplyCode, - query, queryLength); + if (tolower(*start) != *matchString) { + if (_forwarder) { + return true; + } else { + replyWithError(dnsHeader, _errorReplyCode, query, queryLength); + return false; + } + } ++start; ++matchString; --labelLength; } - if (*start == 0 && *matchString == '\0') - return replyWithIP(dnsHeader, query, queryLength); + if (*start == 0 && *matchString == '\0') { + replyWithIP(dnsHeader, query, queryLength); + return false; + } - if (*matchString != '.') - return replyWithError(dnsHeader, _errorReplyCode, - query, queryLength); + if (*matchString != '.') { + replyWithError(dnsHeader, _errorReplyCode, query, queryLength); + return false; + } ++matchString; } - return replyWithError(dnsHeader, _errorReplyCode, - query, queryLength); + replyWithError(dnsHeader, _errorReplyCode, query, queryLength); + return false; } void DNSServer::processNextRequest() @@ -183,7 +375,14 @@ void DNSServer::processNextRequest() return; _udp.read(buffer.get(), currentPacketSize); - respondToRequest(buffer.get(), currentPacketSize); + if (_dns.isSet() && _udp.remoteIP() == _dns) { + // _forwarder may have been set to false; however, for now allow inflight + // replys to finish. //?? + forwardReply(buffer.get(), currentPacketSize); + } else + if (respondToRequest(buffer.get(), currentPacketSize)) { + forwardRequest(buffer.get(), currentPacketSize); + } } void DNSServer::writeNBOShort(uint16_t value) diff --git a/libraries/DNSServer/src/DNSServer.h b/libraries/DNSServer/src/DNSServer.h index 0f3ebd7a34..3ee163ee71 100644 --- a/libraries/DNSServer/src/DNSServer.h +++ b/libraries/DNSServer/src/DNSServer.h @@ -2,6 +2,14 @@ #define DNSServer_h #include +// #define DEBUG_DNSSERVER + +// https://www.iana.org/assignments/service-names-port-numbers/service-names-port-numbers.txt +#ifndef IANA_DNS_PORT +#define IANA_DNS_PORT 53 // AKA domain +constexpr uint16_t kIanaDnsPort = 53; +#endif + #define DNS_QR_QUERY 0 #define DNS_QR_RESPONSE 1 #define DNS_OPCODE_QUERY 0 @@ -45,6 +53,15 @@ struct DNSHeader uint16_t ARCount; // number of resource entries }; +constexpr size_t kDNSSQueSizeAddrBits = 3; // The number of bits used to address que entries +constexpr size_t kDNSSQueSize = BIT(kDNSSQueSizeAddrBits); + +typedef struct DNSS_REQUESTER { + uint32_t ip; + uint16_t port; + uint16_t id; +} dnss_requester_t; + class DNSServer { public: @@ -52,24 +69,44 @@ class DNSServer ~DNSServer() { stop(); }; + bool enableForwarder(const String &domainName = emptyString, const IPAddress &dns = (uint32_t)0); + void disableForwarder(const String &domainName = emptyString, bool freeResources = false); + bool isForwarding() { return _forwarder && _dns.isSet(); } + void setDNS(const IPAddress& dns) { _dns = dns; } + IPAddress getDNS() { return _dns; } + bool isDNSSet() { return _dns.isSet(); } + void processNextRequest(); void setErrorReplyCode(const DNSReplyCode &replyCode); void setTTL(const uint32_t &ttl); + uint32_t getTTL(); + String getDomainName() { return _domainName; } // Returns true if successful, false if there are no sockets available bool start(const uint16_t &port, const String &domainName, - const IPAddress &resolvedIP); + const IPAddress &resolvedIP, + const IPAddress &dns = (uint32_t)0); // stops the DNS server void stop(); private: WiFiUDP _udp; - uint16_t _port; String _domainName; - unsigned char _resolvedIP[4]; + IPAddress _dns; + std::unique_ptr _que; uint32_t _ttl; +#ifdef DEBUG_DNSSERVER + // There are 2 possiblities for OverFlow: + // 1) we have more than kDNSSQueSize request already outstanding. + // 2) we have request that never received a reply. + uint32_t _que_ov; + uint32_t _que_drop; +#endif DNSReplyCode _errorReplyCode; + bool _forwarder; + unsigned char _resolvedIP[4]; + uint16_t _port; void downcaseAndRemoveWwwPrefix(String &domainName); void replyWithIP(DNSHeader *dnsHeader, @@ -81,7 +118,9 @@ class DNSServer size_t queryLength); void replyWithError(DNSHeader *dnsHeader, DNSReplyCode rcode); - void respondToRequest(uint8_t *buffer, size_t length); + bool respondToRequest(uint8_t *buffer, size_t length); + void forwardRequest(uint8_t *buffer, size_t length); + void forwardReply(uint8_t *buffer, size_t length); void writeNBOShort(uint16_t value); }; #endif From 0e33d6e8a01f1d8b6f23053796a60577a3c7a4d8 Mon Sep 17 00:00:00 2001 From: M Hightower <27247790+mhightower83@users.noreply.github.com> Date: Tue, 21 Apr 2020 17:42:35 -0700 Subject: [PATCH 02/17] Added example to use DNS forwarder --- .../NAPTCaptivePortal/NAPTCaptivePortal.ino | 366 ++++++++++++++++++ .../NAPTCaptivePortal/PortalRedirectHttp.ino | 43 ++ .../examples/NAPTCaptivePortal/WifiHttp.h | 325 ++++++++++++++++ .../NAPTCaptivePortal/credentials.ino | 28 ++ .../examples/NAPTCaptivePortal/handleHttp.ino | 219 +++++++++++ .../examples/NAPTCaptivePortal/tools.ino | 81 ++++ 6 files changed, 1062 insertions(+) create mode 100644 libraries/DNSServer/examples/NAPTCaptivePortal/NAPTCaptivePortal.ino create mode 100644 libraries/DNSServer/examples/NAPTCaptivePortal/PortalRedirectHttp.ino create mode 100644 libraries/DNSServer/examples/NAPTCaptivePortal/WifiHttp.h create mode 100644 libraries/DNSServer/examples/NAPTCaptivePortal/credentials.ino create mode 100644 libraries/DNSServer/examples/NAPTCaptivePortal/handleHttp.ino create mode 100644 libraries/DNSServer/examples/NAPTCaptivePortal/tools.ino diff --git a/libraries/DNSServer/examples/NAPTCaptivePortal/NAPTCaptivePortal.ino b/libraries/DNSServer/examples/NAPTCaptivePortal/NAPTCaptivePortal.ino new file mode 100644 index 0000000000..f4b243bdbb --- /dev/null +++ b/libraries/DNSServer/examples/NAPTCaptivePortal/NAPTCaptivePortal.ino @@ -0,0 +1,366 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define NAPT 1000 +#define NAPT_PORT 10 + +/* + This example shows the use of the 'DNS forwarder' feature in the DNSServer. + It does so by combining two examples CaptivePortalAdvanced and + RangeExtender-NAPT. Additionally the CaptivePortalAdvanced part has a few + upgrades to the HTML presentation to improve readability and ease of use on + mobile devices. + + Also for an example of using HTML chunked response, see handleWifi() in + handleHttp.ino. + + This example starts up in Captive Portal mode by default. + It starts the SoftAP and NAPT w/o connecting the WLAN side. + + You connect your computer or mobile device to the WiFi Network 'MagicPortal' + password 'ShowTime'. Your device should shortly notify you of a Captive + Portal and the need to login. If it fails to do so in a timely maner, + navigate to http://172.217.28.1/wifi and configure it there. + + Note, until a successful WLAN connection is made all DNS lookups will point + back to the SoftAP at 172.217.28.1. This is the Captive Portal element of + this example. + + Once the WLAN is connected, your device should notify you that you are + connected. This, of course, assumes your WLAN connection has a path to the + Internet. + + At this stage we are no longer running as a Captive Portal, but a regular + NAPT. The DNSServer will be running with the DNS forwarder enabled. The + DNSServer will resolve lookups for 'margicportal' to point to 172.217.28.1 + and all other lookup request will be forwarded to the 1st DNS server that was + in the DHCP response for the WLAN interface. + + You should now be able to access things on the Internet. The ease of access + to devices on your home Network may vary. By IP address it should work. + Access by a hostname - maybe. Some home routers will use the hostname + supplied during DHCP to support a local DNS table; some do not. + + There is an additional possible complication for using the local DNS, the DNS + suffix list, this subject is seldom discussed. It is normally handled + automaticly by the host computers DNS lookup code. For the DHCP case, the + DHCP server will supply a suffix list, if there is one. Then when a name + lookup fails and the name does not have a trailing (.)dot the host computer + will append a suffix from the list and try again, until successful or the + list is exhaused. This I fear is becoming a TL;DR. On a Ubuntu system run + 'nmcli dev show eth0 | grep IP4\.DOMAIN` that may show you a suffix list. + (replace eth0 with your wlan interface name) Try adding them to the local + name you are failing to connect to. For example, assume 'myhost' fails. You + see that 'lan' is in the suffix list. Try connecting to 'myhost.lan'. + + mDNS names also will not work. We do not have a way to pass those request + back and forth through the NAPT. + + Note if hostnames are going to work for an ESP8266 device on your home + Network, you have to have the call to WiFi.hostname(...) before you call + WiFi.begin(). + + In this example the SoftAP in 'Captive Portal' uses the same public address + that was used in the CaptivePortalAdvanced example. Depending on your devices + you may or may not be successful in using a private address. A previous + PR-author discovered a fix that made the CaptivePortalAdvanced example work + better with Android devices. That fix was to use that public address. At this + time, this PR-author with a different Android device running the latest + version of Android has seen no problems in using either. At least not yet :) + FWIW: My device also works with the original CaptivePortalAdvanced example + when using a private address. I would suggest keeping the private address + for a while. At lest until you are confident everything is working well + before experimenting with a private address. +*/ + +/* + Some defines for debugging +*/ +#ifdef DEBUG_ESP_PORT +#define CONSOLE DEBUG_ESP_PORT +#else +#define CONSOLE Serial +#endif + +#define _PRINTF(a, ...) printf_P(PSTR(a), ##__VA_ARGS__) +#define _PRINT(a) print(String(F(a))) +#define _PRINTLN(a) println(String(F(a))) +#define _PRINTLN2(a, b) println(String(F(a)) + b ) + +#define CONSOLE_PRINTF CONSOLE._PRINTF +#define CONSOLE_PRINT CONSOLE._PRINT +#define CONSOLE_PRINTLN CONSOLE._PRINTLN +#define CONSOLE_PRINTLN2 CONSOLE._PRINTLN2 + +#ifdef DEBUG_SKETCH +#define DEBUG_PRINTF CONSOLE_PRINTF +#define DEBUG_PRINT CONSOLE_PRINT +#define DEBUG_PRINTLN CONSOLE_PRINTLN +#define DEBUG_PRINTLN2 CONSOLE_PRINTLN2 + +#else +#define DEBUG_PRINTF(...) do { } while(false) +#define DEBUG_PRINT(...) do { } while(false) +#define DEBUG_PRINTLN(...) do { } while(false) +#define DEBUG_PRINTLN2(...) do { } while(false) +#endif + + +#if !(LWIP_FEATURES && !LWIP_IPV6) +#error "Requirements: LWIP_FEATURES && ! LWIP_IPV6" +#endif + +/* Set these to your desired softAP credentials. They are not configurable at runtime */ +#ifndef APSSID +#define APSSID "MagicPortal" +#define APPSK "ShowTime" +#endif + +const char *softAP_ssid = APSSID; +const char *softAP_password = APPSK; + +/* hostname for mDNS. Should work at least on windows. Try http://esp8266.local */ +const char *myHostname = "magicportal"; + +/* Don't set this wifi credentials. They are configurated at runtime and stored on EEPROM */ +char ssid[33] = ""; +char password[65] = ""; +uint8_t bssid[6]; +WiFiEventHandler staModeConnectedHandler; +WiFiEventHandler staModeDisconnectedHandler; + +// DNS server +const byte DNS_PORT = 53; +DNSServer dnsServer; + +// Web server +ESP8266WebServer server(80); + +/* Soft AP network parameters */ +IPAddress apIP(172, 217, 28, 1); +IPAddress netMsk(255, 255, 255, 0); + + +/** Should I connect to WLAN asap? */ +bool connect = false; + +/** Set to true to start WiFi STA at setup time when credentials loaded successfuly from EEPROM */ +/** Set to false to defer WiFi STA until configured through web interface. */ +bool staReady = false; // Don't connect right away + +/** Last time I tried to connect to WLAN */ +unsigned long lastConnectTry = 0; + +/** Current WLAN status */ +unsigned int status = WL_IDLE_STATUS; + +void setup() { + WiFi.persistent(false); // w/o this a flash write occurs at every boot + WiFi.mode(WIFI_OFF); // Prevent use of SDK stored credentials + CONSOLE.begin(115200); + CONSOLE_PRINTLN("\r\n\r\nNAPT with Configuration Portal ..."); + + staModeConnectedHandler = WiFi.onStationModeConnected( + [](WiFiEventStationModeConnected data) { + // Keep a copy of the BSSID for the AP that WLAN connects to. + // This is used in the WLAN report on WiFi Details page. + memcpy(bssid, data.bssid, sizeof(bssid)); + }); + + staModeDisconnectedHandler = WiFi.onStationModeDisconnected( + [](WiFiEventStationModeDisconnected data) { + (void)data; + if (dnsServer.isForwarding()) { + dnsServer.disableForwarder("*"); + dnsServer.setTTL(0); + // Reminder, Serial.println() will not work from these callbacks. + // For debug printf use ets_uart_printf(). + } + }); + + /* You can remove the password parameter if you want the AP to be open. */ + WiFi.softAPConfig(apIP, apIP, netMsk); + WiFi.softAP(softAP_ssid, softAP_password); + // The following comment was committed Aug 19, 2015; is it still true?? + // Comment out for verification. + // delay(500); // Without delay I've seen the IP address blank + CONSOLE_PRINTF("SoftAP '%s' started\r\n", softAP_ssid); + CONSOLE_PRINTLN2(" IP address: ", WiFi.softAPIP().toString()); + + /* Captive portals will usually use a TTL of 0 to avoid DNS cache poisoning. */ + dnsServer.setTTL(0); + + /* Setup the DNS server redirecting all the domains to the apIP */ + dnsServer.start(IANA_DNS_PORT, "*", apIP); + CONSOLE_PRINTLN("DNSServer started:"); + CONSOLE_PRINTF(" DNS Forwarding is %s\r\n", dnsServer.isForwarding() ? "on" : "off"); + CONSOLE_PRINTF(" Resolve all domain lookups, '%s', to this AP's IP address, '%s' %s.\r\n", + dnsServer.getDomainName().c_str(), + softAP_ssid, + WiFi.softAPIP().toString().c_str()); + CONSOLE_PRINTF(" TTL set to %u\r\n", dnsServer.getTTL()); + + /* + Do some NAPT startup stuff + */ + CONSOLE_PRINTLN("Begin NAPT initialization:"); + CONSOLE_PRINTF(" Heap before NAPT init: %d\r\n", ESP.getFreeHeap()); + + err_t ret = ip_napt_init(NAPT, NAPT_PORT); + CONSOLE_PRINTF(" ip_napt_init(%d,%d): ret=%d (OK=%d)\r\n", NAPT, NAPT_PORT, (int)ret, (int)ERR_OK); + if (ret == ERR_OK) { + ret = ip_napt_enable_no(SOFTAP_IF, 1); + CONSOLE_PRINTF(" ip_napt_enable_no(SOFTAP_IF): ret=%d (OK=%d)\r\n", (int)ret, (int)ERR_OK); + if (ret == ERR_OK) { + CONSOLE_PRINTF(" NAPT AP '%s' started.\r\n", softAP_ssid); + if (WiFi.localIP().isSet()) { + CONSOLE_PRINTF(" It is an extension of '%s' made through WLAN interface.\r\n", ssid); + CONSOLE_PRINTF(" Remote WLAN IP Address: %s.\r\n", WiFi.localIP().toString().c_str()); + } + } + } + CONSOLE_PRINTF(" Heap after NAPT init: %d\r\n", ESP.getFreeHeap()); + if (ret != ERR_OK) { + CONSOLE_PRINTF(" NAPT initialization failed!!!\r\n"); + } + + /* Setup web pages: root, wifi config pages, SO captive portal detectors and not found. */ + server.on("/", handleRoot); + server.on("/wifi", handleWifi); + server.on("/wifisave", handleWifiSave); + server.on("/generate_204", handleRoot); //Android captive portal. Maybe not needed. Might be handled by notFound handler. + server.on("/fwlink", handleRoot); //Microsoft captive portal. Maybe not needed. Might be handled by notFound handler. + server.onNotFound(handleNotFound); + server.begin(); // Web server start + CONSOLE_PRINTLN("HTTP server started"); + loadCredentials(); // Load WLAN credentials from network + connect = (strlen(ssid) > 0 && staReady); // Request WLAN connect if there is a SSID and we want to connect at startup +} + +void connectWifi() { + CONSOLE_PRINTF("Connecting as wifi client, WLAN, to '%s' ...\r\n", ssid); + WiFi.disconnect(); + /* + A call to set hostname, must be set before the call to WiFi.begin, otherwise + the name may be missing from the routers DNS lookup results. Note, not all + routers will import registered DHCP host names from clients into the active + local DNS resolver. For those that do, it is best to set hostname before + calling WiFi.begin(). + */ + WiFi.hostname(myHostname); + WiFi.begin(ssid, password); + int connRes = WiFi.waitForConnectResult(); + if (-1 == connRes) { + CONSOLE_PRINTLN(" WiFi.waitForConnectResult() timed out."); + } else { + CONSOLE_PRINTF(" Connection status: %s, %d\r\n", getWiFiStatusString(connRes).c_str(), connRes); + } +} + +void loop() { + if (connect) { + // CONSOLE.println("Connect requested"); + connect = false; + connectWifi(); + lastConnectTry = millis(); + } + { + unsigned int s = WiFi.status(); + if (s == 0 && millis() > (lastConnectTry + 60000) && ssid[0] && staReady) { + /* When all of the following conditions are true, try to connect */ + /* 1) If WLAN disconnected */ + /* 2) Required idle time between connect attempts has passed. */ + /* 3) We have an ssid configured */ + /* 4) We are ready for the STA to come up */ + /* Don't set retry time too low as retry interfere the softAP operation */ + connect = true; + } + if (status != s) { // WLAN status change + CONSOLE_PRINTF("WLAN Status changed:\r\n"); + CONSOLE_PRINTF(" new status: %s, %d\r\n", getWiFiStatusString(s).c_str(), s); + CONSOLE_PRINTF(" previous status: %s, %d\r\n", getWiFiStatusString(status).c_str(), status); + status = s; + if (s == WL_CONNECTED) { + /* Just connected to WLAN */ + CONSOLE.println(); + if (WiFi.localIP().isSet() && WiFi.softAPIP().isSet()) { + CONSOLE_PRINTF("NAPT AP '%s' status:\r\n", softAP_ssid); + if (WiFi.localIP().isSet()) { + CONSOLE_PRINTF(" It is an extension of '%s' made through WLAN interface.\r\n", ssid); + CONSOLE_PRINTF(" WLAN connected with IP Address: %s.\r\n", WiFi.localIP().toString().c_str()); + } + } else { + CONSOLE_PRINT("WLAN connected to "); + CONSOLE.println(ssid); + CONSOLE_PRINT(" IP address: "); + CONSOLE.println(WiFi.localIP()); + } + // Setup MDNS responder + if (!MDNS.begin(myHostname, WiFi.localIP())) { + CONSOLE_PRINTLN(" Error setting up MDNS responder!"); + } else { + CONSOLE_PRINTLN(" mDNS responder started"); + // Add service to MDNS-SD + MDNS.addService("http", "tcp", 80); + } + /* + Setup the DNSServer to respond only to request for our hostname and + forward other name request to the DNS configured to the WLAN. + */ + dnsServer.setTTL(600); // 10 minutes + dnsServer.enableForwarder(myHostname, WiFi.dnsIP(0)); + CONSOLE_PRINTF("DNSServer changes/status:\r\n"); + CONSOLE_PRINTF(" DNS Forwarding is %s\r\n", dnsServer.isForwarding() ? "on" : "off"); + CONSOLE_PRINTF(" Resolve '%s' to this AP's IP address, '%s' %s.\r\n", + dnsServer.getDomainName().c_str(), + softAP_ssid, + WiFi.softAPIP().toString().c_str()); + if (dnsServer.isDNSSet()) { + CONSOLE_PRINTF(" Forward other lookups to DNS: %s\r\n", dnsServer.getDNS().toString().c_str()); + } + CONSOLE_PRINTF(" TTL set to %u\r\n", dnsServer.getTTL()); + + } else { + /* Captive portals will usually use a TTL of 0 to avoid DNS cache poisoning. */ + dnsServer.setTTL(0); + /* Setup the DNSServer to redirect all the domain lookups to the apIP */ + dnsServer.disableForwarder("*"); + CONSOLE_PRINTF("DNSServer changes/status:\r\n"); + CONSOLE_PRINTF(" DNS Forwarding is %s\r\n", dnsServer.isForwarding() ? "on" : "off"); + CONSOLE_PRINTF(" Resolve all domain lookups, '%s', to this AP's IP address, '%s' %s.\r\n", + dnsServer.getDomainName().c_str(), + softAP_ssid, + WiFi.softAPIP().toString().c_str()); + CONSOLE_PRINTF(" TTL set to %u\r\n", dnsServer.getTTL()); + + // Note, it is not necessary to clear the DNS forwarder address. This + // is being done here, to test that methods isDNSSet() and setDNS() work. + dnsServer.setDNS(0U); + if (dnsServer.isDNSSet()) { + CONSOLE_PRINTF(" DNS forwarder address: %s\r\n", dnsServer.getDNS().toString().c_str()); + } else { + CONSOLE_PRINTF(" DNS forwarder address not set.\r\n"); + } + + if (s == WL_NO_SSID_AVAIL) { + WiFi.disconnect(); + } + } + } + if (s == WL_CONNECTED) { + MDNS.update(); + } + } + // Do work: + //DNS + dnsServer.processNextRequest(); + //HTTP + server.handleClient(); +} diff --git a/libraries/DNSServer/examples/NAPTCaptivePortal/PortalRedirectHttp.ino b/libraries/DNSServer/examples/NAPTCaptivePortal/PortalRedirectHttp.ino new file mode 100644 index 0000000000..489b8ea09b --- /dev/null +++ b/libraries/DNSServer/examples/NAPTCaptivePortal/PortalRedirectHttp.ino @@ -0,0 +1,43 @@ +// Substitution list: +// {t} - target name +// {1} - The target to redirect to, in absolute URL form. +#ifdef DEBUG_VIEW +static const char portalRedirectHTML[] PROGMEM = R"EOF( + + + + + +Redirecting + + +

Captive Portal Redirect

+

Redirecting to {t}

+

If you do not see the menu in 5 seconds, please click on the above link!

+ + +)EOF"; + +#else +static const char portalRedirectHTML[] PROGMEM = R"EOF( +Redirecting

Captive Portal Redirect

Redirecting to {t}

If you do not see the menu in 5 seconds, please click on the above link!

+)EOF"; +#endif + +void sendPortalRedirect(String path, String targetName) { + CONSOLE_PRINTLN2("Request redirected to captive portal, original request was for ", server.hostHeader()); + /* There are 3 points of redirection here: + 1) "Location" element in the header + 2) HTML meta element to redirect + 3) Click on link to redirect + If the "Location" header element works the HTML stuff is never seen. + */ + // https://tools.ietf.org/html/rfc7231#section-6.4.3 + server.sendHeader("Location", path, true); + addNoCacheHeader(); + String reply = FPSTR(portalRedirectHTML); + reply.reserve(reply.length() + 2 * path.length() + 80); + reply.replace("{t}", targetName); + reply.replace("{1}", path); + server.send(302, "text/html", reply); +} diff --git a/libraries/DNSServer/examples/NAPTCaptivePortal/WifiHttp.h b/libraries/DNSServer/examples/NAPTCaptivePortal/WifiHttp.h new file mode 100644 index 0000000000..8b5a7fdaca --- /dev/null +++ b/libraries/DNSServer/examples/NAPTCaptivePortal/WifiHttp.h @@ -0,0 +1,325 @@ +#ifndef WIFIHTTP_H_ +#define WIFIHTTP_H_ + + +// #define DEBUG_VIEW +// The idea here is to debug HTML with DEBUG_VIEW defined then, when finished, +// use one of the minify web applications to strip the comments and nice +// formating spaces. Then update the minified version below. +// +// Also there are comment sections at the top and bottom of each block of HTML +// code. The purpose is to move the lines of C code near by into the blocked +// comment sections. Then you have a large block of continguious HTML that can +// be copy/pasted into one of the online web HTML checkers. You can adjust the +// code there till it is correct then copy/paste back here. Then, you can move +// comment boarders around until the C code is back in place. + +#ifdef DEBUG_VIEW +static const char configHead[] PROGMEM = R"EOF( + + + + + + +WiFi + +)EOF"; +#else +static const char configHead[] PROGMEM = R"EOF(WiFi)EOF"; +#endif + +#ifdef DEBUG_VIEW +static const char configHead2[] PROGMEM = R"EOF( + + + + + + +)EOF"; +#else +static const char configHead2[] PROGMEM = R"EOF( )EOF"; +#endif + +#ifdef DEBUG_VIEW +static const char configConnection[] PROGMEM = R"EOF( + +
+
+

WiFi Details and Config

+

You are connected through the {w}

+ +)EOF"; +#else +static const char configConnection[] PROGMEM = R"EOF(

WiFi Details and Config

You are connected through the {w}

)EOF"; +#endif + +#ifdef DEBUG_VIEW +static const char configInfo[] PROGMEM = R"EOF( + +
+

SoftAP Details

+ + + + + +
SSI{s}
BSSID {b}
IP{i}
STACount: {a}
+ +)EOF"; +#else +static const char configInfo[] PROGMEM = R"EOF(

SoftAP Details

SSI{s}
BSSID {b}
IP{i}
STACount: {a}
)EOF"; +#endif + +#ifdef DEBUG_VIEW +static const char configInfo2[] PROGMEM = R"EOF( + +
+

WLAN Details

+ + + + + + + + + + + +
SSID{s}
BSSID {b}
CH{c}
PHY{p}
RSSI{r}
IP{i}
GW{g}
Mask{m}
DNS1{1}
DNS2{2}
+ +)EOF"; +#else +static const char configInfo2[] PROGMEM = R"EOF(

WLAN Details

SSID{s}
BSSID {b}
CH{c}
PHY{p}
RSSI{r}
IP{i}
GW{g}
Mask{m}
DNS1{1}
DNS2{2}
)EOF"; +#endif + +#ifdef DEBUG_VIEW +static const char configList[] PROGMEM = R"EOF( + +
+

WLAN Network List

+

(refresh if any are missing)

+ + + + + + +)EOF"; +#else +static const char configList[] PROGMEM = R"EOF(

WLAN Network List

(refresh if any are missing)

Network Name/SSIDCHRSSI
)EOF"; +#endif + +#ifdef DEBUG_VIEW +static const char configItem[] PROGMEM = R"EOF( + + + + + + +)EOF"; +#else +static const char configItem[] PROGMEM = R"EOF()EOF"; +#endif + +#ifdef DEBUG_VIEW +static const char configNoAPs[] PROGMEM = R"EOF( + + + + + + +)EOF"; +#else +static const char configNoAPs[] PROGMEM = R"EOF()EOF"; +#endif + +#ifdef DEBUG_VIEW +static const char configEnd[] PROGMEM = R"EOF( + +
Network Name/SSIDCHRSSI
{s}{c}{l}{r}
{s}{c}{l}{r}
No WLAN found
No WLAN found
+

Connect to Network:

+ +

+ +  👁 +

+
+
+

You may want to return to the home page.

+

+
+
+ + + +)EOF"; +#else +static const char configEnd[] PROGMEM = R"EOF(

Connect to Network:



  👁


You may want to return to the home page.

)EOF"; +#endif + +#endif diff --git a/libraries/DNSServer/examples/NAPTCaptivePortal/credentials.ino b/libraries/DNSServer/examples/NAPTCaptivePortal/credentials.ino new file mode 100644 index 0000000000..33b60fac4c --- /dev/null +++ b/libraries/DNSServer/examples/NAPTCaptivePortal/credentials.ino @@ -0,0 +1,28 @@ +/** Load WLAN credentials from EEPROM */ +void loadCredentials() { + EEPROM.begin(512); + EEPROM.get(0, ssid); + EEPROM.get(0 + sizeof(ssid), password); + char ok[2 + 1]; + EEPROM.get(0 + sizeof(ssid) + sizeof(password), ok); + EEPROM.end(); + if (String(ok) != String("OK")) { + ssid[0] = 0; + password[0] = 0; + } + + CONSOLE_PRINTLN("Recovered credentials:"); + CONSOLE_PRINTF(" %s\r\n", ssid); + CONSOLE_PRINTF(" %s\r\n", strlen(password) > 0 ? "********" : ""); +} + +/** Store WLAN credentials to EEPROM */ +void saveCredentials() { + EEPROM.begin(512); + EEPROM.put(0, ssid); + EEPROM.put(0 + sizeof(ssid), password); + char ok[2 + 1] = "OK"; + EEPROM.put(0 + sizeof(ssid) + sizeof(password), ok); + EEPROM.commit(); + EEPROM.end(); +} diff --git a/libraries/DNSServer/examples/NAPTCaptivePortal/handleHttp.ino b/libraries/DNSServer/examples/NAPTCaptivePortal/handleHttp.ino new file mode 100644 index 0000000000..4f1f24c8b6 --- /dev/null +++ b/libraries/DNSServer/examples/NAPTCaptivePortal/handleHttp.ino @@ -0,0 +1,219 @@ +#include "WifiHttp.h" +String& sendIfOver(String & str, size_t threshold = 512); + +size_t maxPage = 0; + +void addNoCacheHeader() { + server.sendHeader("Cache-Control", "no-cache, no-store, must-revalidate"); + server.sendHeader("Pragma", "no-cache"); + server.sendHeader("Expires", "-1"); +} + + +String& sendIfOver(String & str, size_t threshold) { + size_t len = str.length(); + if (len > threshold) { + maxPage = std::max(maxPage, len); + server.sendContent(str); + str = ""; + } + return str; +} + + +/** Handle root or redirect to captive portal */ +void handleRoot() { + if (captivePortal()) { + // If caprive portal is needed, redirect instead of displaying the page. + return; + } + addNoCacheHeader(); + + String Page; + Page += F( + "" + "" + "ADV CAP Portal Example" + "" + "

HELLO WORLD!!

"); + if (server.client().localIP() == apIP) { + Page += String(F("

You are connected through the soft AP: ")) + softAP_ssid + F("

"); + } else { + Page += String(F("

You are connected through the wifi network: ")) + ssid + F("

"); + } + Page += F( + "

You may want to config the wifi connection.

" + ""); + + server.send(200, F("text/html"), Page); +} + +/* + Redirect to the captive portal if we got a request for another domain. + Return true in that case, so the page handler does not try to handle + the request again. +*/ +boolean captivePortal() { + IPAddress hAddr, cAddr; + + cAddr = server.client().localIP(); + if (!cAddr.isSet()) { + // The connection closed prematurely on us. + // Return true, so no further action is taken. + return true; + } + + if (hAddr.fromString(server.hostHeader()) && hAddr == cAddr) { + return false; + } + + if (hAddr.isSet() || + (server.hostHeader() != (String(myHostname) + ".local") && // arrived here by mDNS + server.hostHeader() != String(myHostname))) { // arrived here by local router DNS + String whereTo = String("http://") + server.client().localIP().toString(); + sendPortalRedirect(whereTo, F("Captive Portal Example")); + return true; + } + + return false; +} + + +/** Wifi Details and Config page handler */ +void handleWifi() { + addNoCacheHeader(); + + // use HTTP/1.1 Chunked response to avoid building a huge temporary string + if (!server.chunkedResponseModeStart(200, F("text/html"))) { + server.send(505, F("text/plain"), F("HTTP1.1 required")); + return; + } + + // Send a few chunks of the HTML that don't need to change. + server.sendContent_P(configHead); + + String page; + + page = FPSTR(configHead2); + /* + Set previously used/entered credentials as a default entries. + This allows an opportunity to correct them and try again. + */ + page.replace("{s}", String(ssid)); + page.replace("{p}", String(password)); + sendIfOver(page, 0); + + page = FPSTR(configConnection); + if (server.client().localIP() == apIP) { + page.replace("{w}", String(F("SoftAP: ")) + softAP_ssid); + } else { + page.replace("{w}", String(F("WiFi Network: ")) + ssid); + } + + /* + To avoid sending lots of small packets. We call this function frequently, + to check if the 'page' has gone over 512 bytes and if so send. + */ + sendIfOver(page); + + page += FPSTR(configInfo); + { + uint8_t sta_cnt = wifi_softap_get_station_num(); + page.replace("{s}", String(softAP_ssid)); + page.replace("{b}", String(WiFi.softAPmacAddress())); + // page.replace("{c}", String(WiFi.softAPchannel())); //WiFi.softAPIP().channel())); + page.replace("{i}", WiFi.softAPIP().toString()); + page.replace("{a}", String(sta_cnt)); + if (sta_cnt) { + page += String(F("\r\n
\r\n"));
+      struct station_info *info = wifi_softap_get_station_info();
+      IPAddress addr;
+      while (info != NULL) {
+        addr = info->ip;
+        page += macToString(info->bssid) + F("  ") + addr.toString() + F("\r\n");
+        info = STAILQ_NEXT(info, next);
+      }
+      page += F("
\r\n"); + } + } + + /* + Before we prepare a large block for sending, we call 'sendIfOver' with a + threshold of 0 to force the sending of the current 'page' content. + */ + sendIfOver(page, 0); + + if (WiFi.localIP().isSet()) { + page += FPSTR(configInfo2); + page.replace("{s}", String(ssid)); + page.replace("{b}", macToString(bssid)); + page.replace("{c}", String(WiFi.channel())); + page.replace("{p}", String(F("802.11")) + (getPhyModeChar(WiFi.getPhyMode()))); + page.replace("{r}", String(WiFi.RSSI())); + page.replace("{i}", WiFi.localIP().toString()); + page.replace("{g}", WiFi.gatewayIP().toString()); + page.replace("{m}", WiFi.subnetMask().toString()); + page.replace("{1}", WiFi.dnsIP(0).toString()); + page.replace("{2}", WiFi.dnsIP(1).toString()); + sendIfOver(page, 0); + } else { + page += F("

WLAN - offline

"); + } + + page += FPSTR(configList); + sendIfOver(page, 0); + + CONSOLE_PRINTLN("scan start"); + int n = WiFi.scanNetworks(); + CONSOLE_PRINTLN("scan done"); + + if (n > 0) { + for (size_t i = 0; i < (size_t)n; i++) { + page += FPSTR(configItem); + page.replace("{s}", WiFi.SSID(i)); + page.replace("{t}", WiFi.BSSIDstr(i)); + page.replace("{c}", String(WiFi.channel(i))); + page.replace("{l}", (WiFi.encryptionType(i) == ENC_TYPE_NONE) ? F("") : F("🔒")); + page.replace("{r}", String(WiFi.RSSI(i))); + sendIfOver(page); + } + } else { + page += FPSTR(configNoAPs); + sendIfOver(page); + } + + page += FPSTR(configEnd); + page.replace("

", String(F("

MAX String memory used: ")) + (maxPage) + F("

")); + server.sendContent(page); + server.chunkedResponseFinalize(); +} + +/** Handle the WLAN save form and redirect to WLAN config page again */ +void handleWifiSave() { + CONSOLE_PRINTLN("wifi save"); + server.arg("n").toCharArray(ssid, sizeof(ssid) - 1); + server.arg("p").toCharArray(password, sizeof(password) - 1); + sendPortalRedirect(F("wifi"), F("Wifi Config")); + saveCredentials(); + connect = strlen(ssid) > 0; // Request WLAN connect with new credentials if there is a SSID +} + +void handleNotFound() { + if (captivePortal()) { // If captive portal redirect instead of displaying the error page. + return; + } + String message = F("File Not Found\r\n\r\n"); + message += F("URI: "); + message += server.uri(); + message += F("\r\nMethod: "); + message += (server.method() == HTTP_GET) ? "GET" : "POST"; + message += F("\r\nArguments: "); + message += server.args(); + message += F("\r\n"); + + for (uint8_t i = 0; i < server.args(); i++) { + message += String(F(" ")) + server.argName(i) + F(": ") + server.arg(i) + F("\r\n"); + } + addNoCacheHeader(); + server.send(404, F("text/plain"), message); +} diff --git a/libraries/DNSServer/examples/NAPTCaptivePortal/tools.ino b/libraries/DNSServer/examples/NAPTCaptivePortal/tools.ino new file mode 100644 index 0000000000..9619efd6b4 --- /dev/null +++ b/libraries/DNSServer/examples/NAPTCaptivePortal/tools.ino @@ -0,0 +1,81 @@ +/* + These functions may exist in other projects +*/ + +/* + Returns a descriptive string for WiFi.status() value +*/ +String getWiFiStatusString(uint32_t status) { + const __FlashStringHelper *r; + switch (status) { + case WL_IDLE_STATUS: + r = F("WL_IDLE_STATUS"); + break; + + case WL_NO_SSID_AVAIL: + r = F("WL_NO_SSID_AVAIL"); + break; + + case WL_SCAN_COMPLETED: + r = F("WL_SCAN_COMPLETED"); + break; + + case WL_CONNECTED: + r = F("WL_CONNECTED"); + break; + + case WL_CONNECT_FAILED: + r = F("WL_CONNECT_FAILED"); + break; + + case WL_CONNECTION_LOST: + r = F("WL_CONNECTION_LOST"); + break; + + case WL_DISCONNECTED: + r = F("WL_DISCONNECTED"); + break; + + case WL_NO_SHIELD: + r = F("WL_NO_SHIELD"); + break; + + default: + return String(F("Unknown: 0x")) + String(status, HEX); + } + return String(r); +} + +/* + Returns a single charcter to append to a "802.11" string to describe the PHY + mode of a WiFi device. Can be used with the value returned by WiFi.getPhyMode(). +*/ +char getPhyModeChar(WiFiPhyMode_t i) { + char phy = '?'; + switch (i) { + case WIFI_PHY_MODE_11B: + phy = 'b'; // = 1 + case WIFI_PHY_MODE_11G: + phy = 'g'; // = 2, + case WIFI_PHY_MODE_11N: + phy = 'n'; // = 3, + default: + break; + } + return phy; +} + +/* + Return a String of 6 colon separated hex bytes. + This format is commonly used when printing 6 byte MAC addresses. +*/ +String macToString(const unsigned char* mac) { + char buf[20]; + int rc = snprintf(buf, sizeof(buf), PSTR("%02X:%02X:%02X:%02X:%02X:%02X"), + mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); + + if (rc < 0 || rc >= (int)sizeof(buf)) { + return emptyString; + } + return String(buf); +} From 63f895870d1159abb28a30a2c1a0632a66ec6262 Mon Sep 17 00:00:00 2001 From: M Hightower <27247790+mhightower83@users.noreply.github.com> Date: Tue, 21 Apr 2020 18:43:25 -0700 Subject: [PATCH 03/17] Cleanup for CI --- .../NAPTCaptivePortal/NAPTCaptivePortal.ino | 68 +++++++++++-------- .../NAPTCaptivePortal/PortalRedirectHttp.ino | 5 ++ .../NAPTCaptivePortal/credentials.ino | 5 ++ .../examples/NAPTCaptivePortal/handleHttp.ino | 18 +++-- .../examples/NAPTCaptivePortal/tools.ino | 6 +- 5 files changed, 66 insertions(+), 36 deletions(-) diff --git a/libraries/DNSServer/examples/NAPTCaptivePortal/NAPTCaptivePortal.ino b/libraries/DNSServer/examples/NAPTCaptivePortal/NAPTCaptivePortal.ino index f4b243bdbb..c01c4b00c5 100644 --- a/libraries/DNSServer/examples/NAPTCaptivePortal/NAPTCaptivePortal.ino +++ b/libraries/DNSServer/examples/NAPTCaptivePortal/NAPTCaptivePortal.ino @@ -1,16 +1,3 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define NAPT 1000 -#define NAPT_PORT 10 - /* This example shows the use of the 'DNS forwarder' feature in the DNSServer. It does so by combining two examples CaptivePortalAdvanced and @@ -80,6 +67,22 @@ before experimenting with a private address. */ + +#if LWIP_FEATURES && !LWIP_IPV6 + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define NAPT 1000 +#define NAPT_PORT 10 + /* Some defines for debugging */ @@ -113,9 +116,6 @@ #endif -#if !(LWIP_FEATURES && !LWIP_IPV6) -#error "Requirements: LWIP_FEATURES && ! LWIP_IPV6" -#endif /* Set these to your desired softAP credentials. They are not configurable at runtime */ #ifndef APSSID @@ -168,21 +168,21 @@ void setup() { CONSOLE_PRINTLN("\r\n\r\nNAPT with Configuration Portal ..."); staModeConnectedHandler = WiFi.onStationModeConnected( - [](WiFiEventStationModeConnected data) { - // Keep a copy of the BSSID for the AP that WLAN connects to. - // This is used in the WLAN report on WiFi Details page. - memcpy(bssid, data.bssid, sizeof(bssid)); + [](WiFiEventStationModeConnected data) { + // Keep a copy of the BSSID for the AP that WLAN connects to. + // This is used in the WLAN report on WiFi Details page. + memcpy(bssid, data.bssid, sizeof(bssid)); }); staModeDisconnectedHandler = WiFi.onStationModeDisconnected( - [](WiFiEventStationModeDisconnected data) { - (void)data; - if (dnsServer.isForwarding()) { - dnsServer.disableForwarder("*"); - dnsServer.setTTL(0); - // Reminder, Serial.println() will not work from these callbacks. - // For debug printf use ets_uart_printf(). - } + [](WiFiEventStationModeDisconnected data) { + (void)data; + if (dnsServer.isForwarding()) { + dnsServer.disableForwarder("*"); + dnsServer.setTTL(0); + // Reminder, Serial.println() will not work from these callbacks. + // For debug printf use ets_uart_printf(). + } }); /* You can remove the password parameter if you want the AP to be open. */ @@ -364,3 +364,15 @@ void loop() { //HTTP server.handleClient(); } + +#else + +void setup() { + Serial.begin(115200); + Serial.printf("\n\nNAPT not supported in this configuration\n"); +} + +#endif + +void loop() { +} diff --git a/libraries/DNSServer/examples/NAPTCaptivePortal/PortalRedirectHttp.ino b/libraries/DNSServer/examples/NAPTCaptivePortal/PortalRedirectHttp.ino index 489b8ea09b..266c7c3c8a 100644 --- a/libraries/DNSServer/examples/NAPTCaptivePortal/PortalRedirectHttp.ino +++ b/libraries/DNSServer/examples/NAPTCaptivePortal/PortalRedirectHttp.ino @@ -1,3 +1,6 @@ + +#if LWIP_FEATURES && !LWIP_IPV6 + // Substitution list: // {t} - target name // {1} - The target to redirect to, in absolute URL form. @@ -41,3 +44,5 @@ void sendPortalRedirect(String path, String targetName) { reply.replace("{1}", path); server.send(302, "text/html", reply); } + +#endif // LWIP_FEATURES && !LWIP_IPV6 diff --git a/libraries/DNSServer/examples/NAPTCaptivePortal/credentials.ino b/libraries/DNSServer/examples/NAPTCaptivePortal/credentials.ino index 33b60fac4c..04735a4d77 100644 --- a/libraries/DNSServer/examples/NAPTCaptivePortal/credentials.ino +++ b/libraries/DNSServer/examples/NAPTCaptivePortal/credentials.ino @@ -1,3 +1,6 @@ + +#if LWIP_FEATURES && !LWIP_IPV6 + /** Load WLAN credentials from EEPROM */ void loadCredentials() { EEPROM.begin(512); @@ -26,3 +29,5 @@ void saveCredentials() { EEPROM.commit(); EEPROM.end(); } + +#endif // LWIP_FEATURES && !LWIP_IPV6 diff --git a/libraries/DNSServer/examples/NAPTCaptivePortal/handleHttp.ino b/libraries/DNSServer/examples/NAPTCaptivePortal/handleHttp.ino index 4f1f24c8b6..9a8b796712 100644 --- a/libraries/DNSServer/examples/NAPTCaptivePortal/handleHttp.ino +++ b/libraries/DNSServer/examples/NAPTCaptivePortal/handleHttp.ino @@ -1,3 +1,5 @@ +#if LWIP_FEATURES && !LWIP_IPV6 + #include "WifiHttp.h" String& sendIfOver(String & str, size_t threshold = 512); @@ -13,9 +15,9 @@ void addNoCacheHeader() { String& sendIfOver(String & str, size_t threshold) { size_t len = str.length(); if (len > threshold) { - maxPage = std::max(maxPage, len); - server.sendContent(str); - str = ""; + maxPage = std::max(maxPage, len); + server.sendContent(str); + str = ""; } return str; } @@ -68,8 +70,8 @@ boolean captivePortal() { } if (hAddr.isSet() || - (server.hostHeader() != (String(myHostname) + ".local") && // arrived here by mDNS - server.hostHeader() != String(myHostname))) { // arrived here by local router DNS + (server.hostHeader() != (String(myHostname) + ".local") && // arrived here by mDNS + server.hostHeader() != String(myHostname))) { // arrived here by local router DNS String whereTo = String("http://") + server.client().localIP().toString(); sendPortalRedirect(whereTo, F("Captive Portal Example")); return true; @@ -178,8 +180,8 @@ void handleWifi() { sendIfOver(page); } } else { - page += FPSTR(configNoAPs); - sendIfOver(page); + page += FPSTR(configNoAPs); + sendIfOver(page); } page += FPSTR(configEnd); @@ -217,3 +219,5 @@ void handleNotFound() { addNoCacheHeader(); server.send(404, F("text/plain"), message); } + +#endif // LWIP_FEATURES && !LWIP_IPV6 diff --git a/libraries/DNSServer/examples/NAPTCaptivePortal/tools.ino b/libraries/DNSServer/examples/NAPTCaptivePortal/tools.ino index 9619efd6b4..7a4deec74b 100644 --- a/libraries/DNSServer/examples/NAPTCaptivePortal/tools.ino +++ b/libraries/DNSServer/examples/NAPTCaptivePortal/tools.ino @@ -2,6 +2,8 @@ These functions may exist in other projects */ +#if LWIP_FEATURES && !LWIP_IPV6 + /* Returns a descriptive string for WiFi.status() value */ @@ -72,10 +74,12 @@ char getPhyModeChar(WiFiPhyMode_t i) { String macToString(const unsigned char* mac) { char buf[20]; int rc = snprintf(buf, sizeof(buf), PSTR("%02X:%02X:%02X:%02X:%02X:%02X"), - mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); + mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); if (rc < 0 || rc >= (int)sizeof(buf)) { return emptyString; } return String(buf); } + +#endif // LWIP_FEATURES && !LWIP_IPV6 From aa430d0252a3aec60339fdd8203fca21f56bae7b Mon Sep 17 00:00:00 2001 From: M Hightower <27247790+mhightower83@users.noreply.github.com> Date: Tue, 21 Apr 2020 20:19:56 -0700 Subject: [PATCH 04/17] Fixed insert error --- .../examples/NAPTCaptivePortal/NAPTCaptivePortal.ino | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libraries/DNSServer/examples/NAPTCaptivePortal/NAPTCaptivePortal.ino b/libraries/DNSServer/examples/NAPTCaptivePortal/NAPTCaptivePortal.ino index c01c4b00c5..bce86b88d2 100644 --- a/libraries/DNSServer/examples/NAPTCaptivePortal/NAPTCaptivePortal.ino +++ b/libraries/DNSServer/examples/NAPTCaptivePortal/NAPTCaptivePortal.ino @@ -365,14 +365,14 @@ void loop() { server.handleClient(); } -#else +#else // LWIP_FEATURES && !LWIP_IPV6 void setup() { Serial.begin(115200); Serial.printf("\n\nNAPT not supported in this configuration\n"); } -#endif - void loop() { } + +#endif // LWIP_FEATURES && !LWIP_IPV6 From a101809090cbc06eb6f1575fcba4b0f3dc862f7e Mon Sep 17 00:00:00 2001 From: M Hightower <27247790+mhightower83@users.noreply.github.com> Date: Wed, 22 Apr 2020 13:30:55 -0700 Subject: [PATCH 05/17] Add/updated comments. Remove commented code. Reduced size of a chunk of HTML string. Added maxlength to HTML input fields for credentials. --- .../NAPTCaptivePortal/NAPTCaptivePortal.ino | 26 ++++++++++++------- .../examples/NAPTCaptivePortal/WifiHttp.h | 24 +++++++++++++---- .../examples/NAPTCaptivePortal/handleHttp.ino | 8 +++--- libraries/DNSServer/src/DNSServer.h | 16 ++++++++++++ 4 files changed, 55 insertions(+), 19 deletions(-) diff --git a/libraries/DNSServer/examples/NAPTCaptivePortal/NAPTCaptivePortal.ino b/libraries/DNSServer/examples/NAPTCaptivePortal/NAPTCaptivePortal.ino index bce86b88d2..1d0cafe975 100644 --- a/libraries/DNSServer/examples/NAPTCaptivePortal/NAPTCaptivePortal.ino +++ b/libraries/DNSServer/examples/NAPTCaptivePortal/NAPTCaptivePortal.ino @@ -41,11 +41,12 @@ DHCP server will supply a suffix list, if there is one. Then when a name lookup fails and the name does not have a trailing (.)dot the host computer will append a suffix from the list and try again, until successful or the - list is exhaused. This I fear is becoming a TL;DR. On a Ubuntu system run - 'nmcli dev show eth0 | grep IP4\.DOMAIN` that may show you a suffix list. - (replace eth0 with your wlan interface name) Try adding them to the local - name you are failing to connect to. For example, assume 'myhost' fails. You - see that 'lan' is in the suffix list. Try connecting to 'myhost.lan'. + list is exhaused. This topic I fear can become a TL;DR. A quick wrapup by way + of an example. On an Ubuntu system run `nmcli dev show eth0 | grep + IP4\.DOMAIN` that may show you a suffix list. (replace eth0 with your wlan + interface name) Try adding them to the local name you are failing to connect + to. For example, assume 'myhost' fails. You see that 'lan' is in the suffix + list. Try connecting to 'myhost.lan'. mDNS names also will not work. We do not have a way to pass those request back and forth through the NAPT. @@ -62,7 +63,7 @@ time, this PR-author with a different Android device running the latest version of Android has seen no problems in using either. At least not yet :) FWIW: My device also works with the original CaptivePortalAdvanced example - when using a private address. I would suggest keeping the private address + when using a private address. I would suggest keeping the public address for a while. At lest until you are confident everything is working well before experimenting with a private address. */ @@ -185,11 +186,15 @@ void setup() { } }); - /* You can remove the password parameter if you want the AP to be open. */ + /* + While you can remove the password parameter to make the AP open. + You will be operating with less security and allowing snoopers to see + the credentials you use for your WiFi. + */ WiFi.softAPConfig(apIP, apIP, netMsk); WiFi.softAP(softAP_ssid, softAP_password); - // The following comment was committed Aug 19, 2015; is it still true?? - // Comment out for verification. + // The following comment for delay(500) was committed Aug 19, 2015; is it + // still true? Commented out for verification. - APR 2020 // delay(500); // Without delay I've seen the IP address blank CONSOLE_PRINTF("SoftAP '%s' started\r\n", softAP_ssid); CONSOLE_PRINTLN2(" IP address: ", WiFi.softAPIP().toString()); @@ -266,7 +271,6 @@ void connectWifi() { void loop() { if (connect) { - // CONSOLE.println("Connect requested"); connect = false; connectWifi(); lastConnectTry = millis(); @@ -368,6 +372,8 @@ void loop() { #else // LWIP_FEATURES && !LWIP_IPV6 void setup() { + WiFi.persistent(false); + WiFi.mode(WIFI_OFF); Serial.begin(115200); Serial.printf("\n\nNAPT not supported in this configuration\n"); } diff --git a/libraries/DNSServer/examples/NAPTCaptivePortal/WifiHttp.h b/libraries/DNSServer/examples/NAPTCaptivePortal/WifiHttp.h index 8b5a7fdaca..6e7d21ee35 100644 --- a/libraries/DNSServer/examples/NAPTCaptivePortal/WifiHttp.h +++ b/libraries/DNSServer/examples/NAPTCaptivePortal/WifiHttp.h @@ -59,7 +59,6 @@ a { } .lg { - /*width: 90%;*/ font-size: 1em; height: 1.8em; } @@ -152,7 +151,22 @@ function cs(i){ j.value=''; af(j); } + + +)EOF"; +#else +static const char configHead2[] PROGMEM = R"EOF( )EOF"; +#endif +#ifdef DEBUG_VIEW +static const char configPresetInput[] PROGMEM = R"EOF( + + )EOF"; +static const char configPresetInput[] PROGMEM = R"EOF()EOF"; #endif #ifdef DEBUG_VIEW @@ -302,9 +316,9 @@ static const char configEnd[] PROGMEM = R"EOF( -->

Connect to Network:

- +

- +   👁

@@ -319,7 +333,7 @@ static const char configEnd[] PROGMEM = R"EOF( --> )EOF"; #else -static const char configEnd[] PROGMEM = R"EOF(

Connect to Network:



  👁


You may want to return to the home page.

)EOF"; +static const char configEnd[] PROGMEM = R"EOF(

Connect to Network:



  👁


You may want to return to the home page.

)EOF"; #endif #endif diff --git a/libraries/DNSServer/examples/NAPTCaptivePortal/handleHttp.ino b/libraries/DNSServer/examples/NAPTCaptivePortal/handleHttp.ino index 9a8b796712..8b7072caf4 100644 --- a/libraries/DNSServer/examples/NAPTCaptivePortal/handleHttp.ino +++ b/libraries/DNSServer/examples/NAPTCaptivePortal/handleHttp.ino @@ -93,19 +93,20 @@ void handleWifi() { // Send a few chunks of the HTML that don't need to change. server.sendContent_P(configHead); + server.sendContent_P(configHead2); String page; - page = FPSTR(configHead2); + page = FPSTR(configPresetInput); /* Set previously used/entered credentials as a default entries. This allows an opportunity to correct them and try again. */ page.replace("{s}", String(ssid)); page.replace("{p}", String(password)); - sendIfOver(page, 0); + sendIfOver(page); - page = FPSTR(configConnection); + page += FPSTR(configConnection); if (server.client().localIP() == apIP) { page.replace("{w}", String(F("SoftAP: ")) + softAP_ssid); } else { @@ -123,7 +124,6 @@ void handleWifi() { uint8_t sta_cnt = wifi_softap_get_station_num(); page.replace("{s}", String(softAP_ssid)); page.replace("{b}", String(WiFi.softAPmacAddress())); - // page.replace("{c}", String(WiFi.softAPchannel())); //WiFi.softAPIP().channel())); page.replace("{i}", WiFi.softAPIP().toString()); page.replace("{a}", String(sta_cnt)); if (sta_cnt) { diff --git a/libraries/DNSServer/src/DNSServer.h b/libraries/DNSServer/src/DNSServer.h index 3ee163ee71..db853a919d 100644 --- a/libraries/DNSServer/src/DNSServer.h +++ b/libraries/DNSServer/src/DNSServer.h @@ -69,7 +69,23 @@ class DNSServer ~DNSServer() { stop(); }; + /* + If specified, `enableForwarder` will update the `domainName` that is used + to match DNS request to this AP's IP Address. A non-matching request will + be forwarded to the DNS server specified by `dns`. + + Returns `true` on success. + + Returns `false`, + * when forwarding `dns` is not set, or + * unable to allocate resources for managing the DNS forward function. + */ bool enableForwarder(const String &domainName = emptyString, const IPAddress &dns = (uint32_t)0); + /* + `disableForwarder` will stop forwarding DNS requests. If specified, + updates the `domainName` that is matched for returning this AP's IP Address. + Optionally, resources used for the DNS forward function can be freed. + */ void disableForwarder(const String &domainName = emptyString, bool freeResources = false); bool isForwarding() { return _forwarder && _dns.isSet(); } void setDNS(const IPAddress& dns) { _dns = dns; } From ad62a7f3e4e78a2e1a34fe72ded8cbd5a91562c1 Mon Sep 17 00:00:00 2001 From: M Hightower <27247790+mhightower83@users.noreply.github.com> Date: Thu, 23 Apr 2020 12:24:37 -0700 Subject: [PATCH 06/17] Added missing include for unsupported build environment --- .../DNSServer/examples/NAPTCaptivePortal/NAPTCaptivePortal.ino | 1 + 1 file changed, 1 insertion(+) diff --git a/libraries/DNSServer/examples/NAPTCaptivePortal/NAPTCaptivePortal.ino b/libraries/DNSServer/examples/NAPTCaptivePortal/NAPTCaptivePortal.ino index 1d0cafe975..30897f2b86 100644 --- a/libraries/DNSServer/examples/NAPTCaptivePortal/NAPTCaptivePortal.ino +++ b/libraries/DNSServer/examples/NAPTCaptivePortal/NAPTCaptivePortal.ino @@ -371,6 +371,7 @@ void loop() { #else // LWIP_FEATURES && !LWIP_IPV6 +#include void setup() { WiFi.persistent(false); WiFi.mode(WIFI_OFF); From ee9777796590f06ba6046969c65bcf1c3dda7c6f Mon Sep 17 00:00:00 2001 From: M Hightower <27247790+mhightower83@users.noreply.github.com> Date: Sat, 25 Apr 2020 08:27:30 -0700 Subject: [PATCH 07/17] Updated HTML to limit/remove screen flash when using show password. --- .../examples/NAPTCaptivePortal/WifiHttp.h | 22 ++++++++----------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/libraries/DNSServer/examples/NAPTCaptivePortal/WifiHttp.h b/libraries/DNSServer/examples/NAPTCaptivePortal/WifiHttp.h index 6e7d21ee35..1120526795 100644 --- a/libraries/DNSServer/examples/NAPTCaptivePortal/WifiHttp.h +++ b/libraries/DNSServer/examples/NAPTCaptivePortal/WifiHttp.h @@ -126,13 +126,7 @@ function ge(i) { return document.getElementById(i); } -// apply focus - move to element and scroll into view -function af(e) { - e.focus(); - e.scrollIntoView(); -} - -// Password View +// Toggle password view function pv() { let e = ge('p'); if (e.type === 'password') { @@ -140,23 +134,25 @@ function pv() { } else { e.type = 'password'; } - af(e); + e.focus(); } // Copy SSID value to input element for SSID // Move focus to password input element and clear function cs(i){ - ge('s').value=i.innerText||i.textContent; - let j=ge('p'); - j.value=''; - af(j); + ge('s').value = i.innerText; + let e = ge('p'); + e.type = 'password'; + e.value = ''; + e.focus(); + e.scrollIntoView(); } )EOF"; #else -static const char configHead2[] PROGMEM = R"EOF( )EOF"; +static const char configHead2[] PROGMEM = R"EOF( )EOF"; #endif #ifdef DEBUG_VIEW From 6755a5b0f0fc596d4d2a0a012fb295fcdc7ca466 Mon Sep 17 00:00:00 2001 From: M Hightower <27247790+mhightower83@users.noreply.github.com> Date: Mon, 27 Apr 2020 12:50:07 -0700 Subject: [PATCH 08/17] Reserved space in String page. Re-adjusted size of chuncks. Added print statements for monitoring size of chunks etc. Novice improvents to HTML and variable names. --- .../examples/NAPTCaptivePortal/WifiHttp.h | 71 +++++++++++-------- .../examples/NAPTCaptivePortal/handleHttp.ino | 25 +++++-- 2 files changed, 59 insertions(+), 37 deletions(-) diff --git a/libraries/DNSServer/examples/NAPTCaptivePortal/WifiHttp.h b/libraries/DNSServer/examples/NAPTCaptivePortal/WifiHttp.h index 1120526795..8a298d4a1a 100644 --- a/libraries/DNSServer/examples/NAPTCaptivePortal/WifiHttp.h +++ b/libraries/DNSServer/examples/NAPTCaptivePortal/WifiHttp.h @@ -88,33 +88,16 @@ static const char configHead2[] PROGMEM = R"EOF( text-align: right; } -@media screen and (orientation: portrait) { - #inner { - display: block; - margin: 0 auto; - max-width: 400px; - min-width: 350px; - text-align: left; - } - - #outer { - width:100% - } +#outer { + width:100% + overflow-y: auto; } - -@media screen and (orientation: landscape) { - #inner { - display: block; - margin: 0 auto; - width: 400px; - text-align: left; - } - - #outer { - width:100% - } +#inner { + margin: .75em auto; + max-width: 500px; + min-width: 428px; + text-align: left; } - @@ -152,7 +135,7 @@ function cs(i){ --> )EOF"; #else -static const char configHead2[] PROGMEM = R"EOF( )EOF"; +static const char configHead2[] PROGMEM = R"EOF( )EOF"; #endif #ifdef DEBUG_VIEW @@ -195,7 +178,7 @@ static const char configConnection[] PROGMEM = R"EOF(


+ +)EOF"; +#else +static const char configEnd[] PROGMEM = R"EOF(

Connect to Network:



)EOF"; +#endif + +#ifdef DEBUG_VIEW +static const char configEnd2[] PROGMEM = R"EOF( +   👁

@@ -329,7 +338,7 @@ static const char configEnd[] PROGMEM = R"EOF( --> )EOF"; #else -static const char configEnd[] PROGMEM = R"EOF(

Connect to Network:



  👁


You may want to return to the home page.

)EOF"; +static const char configEnd2[] PROGMEM = R"EOF(  👁


You may want to return to the home page.

)EOF"; #endif #endif diff --git a/libraries/DNSServer/examples/NAPTCaptivePortal/handleHttp.ino b/libraries/DNSServer/examples/NAPTCaptivePortal/handleHttp.ino index 8b7072caf4..473a299b24 100644 --- a/libraries/DNSServer/examples/NAPTCaptivePortal/handleHttp.ino +++ b/libraries/DNSServer/examples/NAPTCaptivePortal/handleHttp.ino @@ -97,6 +97,16 @@ void handleWifi() { String page; + // Just do max on some of the visually larger HTML chunks that will be loaded + // into page and add a little for growth when substituting values in. + size_t thisMany = std::max(sizeof(configWLANInfo), std::max(sizeof(configList), sizeof(configEnd))) + 200; + CONSOLE_PRINTLN2("sizeof(configWLANInfo): ", (sizeof(configWLANInfo))); + CONSOLE_PRINTLN2("sizeof(configList): ", (sizeof(configList))); + CONSOLE_PRINTLN2("sizeof(configEnd): ", (sizeof(configEnd))); + CONSOLE_PRINTLN2("sizeof(configEnd2): ", (sizeof(configEnd2))); + CONSOLE_PRINTLN2("page reserve size: ", (thisMany)); + page.reserve(thisMany); + page = FPSTR(configPresetInput); /* Set previously used/entered credentials as a default entries. @@ -119,7 +129,7 @@ void handleWifi() { */ sendIfOver(page); - page += FPSTR(configInfo); + page += FPSTR(configAPInfo); { uint8_t sta_cnt = wifi_softap_get_station_num(); page.replace("{s}", String(softAP_ssid)); @@ -146,7 +156,7 @@ void handleWifi() { sendIfOver(page, 0); if (WiFi.localIP().isSet()) { - page += FPSTR(configInfo2); + page += FPSTR(configWLANInfo); page.replace("{s}", String(ssid)); page.replace("{b}", macToString(bssid)); page.replace("{c}", String(WiFi.channel())); @@ -159,7 +169,7 @@ void handleWifi() { page.replace("{2}", WiFi.dnsIP(1).toString()); sendIfOver(page, 0); } else { - page += F("

WLAN - offline

"); + page += FPSTR(configWLANOffline); //F("

WLAN - offline

"); } page += FPSTR(configList); @@ -183,10 +193,13 @@ void handleWifi() { page += FPSTR(configNoAPs); sendIfOver(page); } + sendIfOver(page, 0); // send what we have buffered before next direct send. + + // No changes to this chunk, no need to use Strings class. Send asis. + server.sendContent_P(configEnd); + server.sendContent_P(configEnd2); - page += FPSTR(configEnd); - page.replace("

", String(F("

MAX String memory used: ")) + (maxPage) + F("

")); - server.sendContent(page); + CONSOLE_PRINTLN2("MAX String memory used: ", (maxPage)); server.chunkedResponseFinalize(); } From 10f631198d6f2859802aff2563263e8943e8e4ef Mon Sep 17 00:00:00 2001 From: M Hightower <27247790+mhightower83@users.noreply.github.com> Date: Tue, 5 May 2020 08:44:00 -0700 Subject: [PATCH 09/17] Added logic to handle dividing large PROGMEM strings into smaller chunks to avoid large allocations to buffer the send. --- .../examples/NAPTCaptivePortal/WifiHttp.h | 18 +----- .../examples/NAPTCaptivePortal/handleHttp.ino | 57 ++++++++++++------- 2 files changed, 39 insertions(+), 36 deletions(-) diff --git a/libraries/DNSServer/examples/NAPTCaptivePortal/WifiHttp.h b/libraries/DNSServer/examples/NAPTCaptivePortal/WifiHttp.h index 8a298d4a1a..46979b96d4 100644 --- a/libraries/DNSServer/examples/NAPTCaptivePortal/WifiHttp.h +++ b/libraries/DNSServer/examples/NAPTCaptivePortal/WifiHttp.h @@ -62,20 +62,7 @@ a { font-size: 1em; height: 1.8em; } -/* -*/ - -)EOF"; -#else -static const char configHead[] PROGMEM = R"EOF(WiFi)EOF"; -#endif - -#ifdef DEBUG_VIEW -static const char configHead2[] PROGMEM = R"EOF( - )EOF"; +static const char configHead[] PROGMEM = R"EOF(WiFi )EOF"; #endif #ifdef DEBUG_VIEW @@ -317,7 +304,6 @@ static const char configEnd[] PROGMEM = R"EOF( --> )EOF"; #else -static const char configEnd[] PROGMEM = R"EOF(

Connect to Network:



)EOF"; #endif #ifdef DEBUG_VIEW @@ -338,7 +324,7 @@ static const char configEnd2[] PROGMEM = R"EOF( --> )EOF"; #else -static const char configEnd2[] PROGMEM = R"EOF(  👁


You may want to return to the home page.

)EOF"; +static const char configEnd[] PROGMEM = R"EOF(

Connect to Network:



  👁


You may want to return to the home page.

)EOF"; #endif #endif diff --git a/libraries/DNSServer/examples/NAPTCaptivePortal/handleHttp.ino b/libraries/DNSServer/examples/NAPTCaptivePortal/handleHttp.ino index 473a299b24..9e18a8fde2 100644 --- a/libraries/DNSServer/examples/NAPTCaptivePortal/handleHttp.ino +++ b/libraries/DNSServer/examples/NAPTCaptivePortal/handleHttp.ino @@ -1,7 +1,16 @@ #if LWIP_FEATURES && !LWIP_IPV6 -#include "WifiHttp.h" -String& sendIfOver(String & str, size_t threshold = 512); +#include "WifiHttpv2.h" + +#ifndef TCP_MSS +#define TCP_MSS 1460 +#endif +/* + Use kMaxChunkSize to limit size of chuncks +*/ +constexpr size_t kMaxChunkSize = TCP_MSS; +String& sendIfOver(String & str, size_t threshold = kMaxChunkSize/2); +size_t sendAsChunks_P(PGM_P content, size_t chunkSize = kMaxChunkSize); size_t maxPage = 0; @@ -15,6 +24,7 @@ void addNoCacheHeader() { String& sendIfOver(String & str, size_t threshold) { size_t len = str.length(); if (len > threshold) { + // Use later to determine if we reserved enough room in page to avoid realloc maxPage = std::max(maxPage, len); server.sendContent(str); str = ""; @@ -22,11 +32,22 @@ String& sendIfOver(String & str, size_t threshold) { return str; } +/* + The idea here is to avoid a large allocation by sendContent_P to copy a + big PROGMEM string. Slice PROGMEM string into chuncks and send. +*/ +size_t sendAsChunks_P(PGM_P content, size_t chunkSize) { + size_t len = strlen_P(content); + for (size_t pos = 0; pos < len; pos += chunkSize) { + server.sendContent_P(&content[pos], ((len - pos) >= chunkSize) ? chunkSize : len - pos); + } + return len; +} /** Handle root or redirect to captive portal */ void handleRoot() { if (captivePortal()) { - // If caprive portal is needed, redirect instead of displaying the page. + // If captive portal is needed, redirect instead of displaying the page. return; } addNoCacheHeader(); @@ -92,20 +113,19 @@ void handleWifi() { } // Send a few chunks of the HTML that don't need to change. - server.sendContent_P(configHead); - server.sendContent_P(configHead2); + sendAsChunks_P(configHead); String page; - // Just do max on some of the visually larger HTML chunks that will be loaded - // into page and add a little for growth when substituting values in. - size_t thisMany = std::max(sizeof(configWLANInfo), std::max(sizeof(configList), sizeof(configEnd))) + 200; + CONSOLE_PRINTLN2("sizeof(configHead): ", (sizeof(configHead))); CONSOLE_PRINTLN2("sizeof(configWLANInfo): ", (sizeof(configWLANInfo))); CONSOLE_PRINTLN2("sizeof(configList): ", (sizeof(configList))); CONSOLE_PRINTLN2("sizeof(configEnd): ", (sizeof(configEnd))); - CONSOLE_PRINTLN2("sizeof(configEnd2): ", (sizeof(configEnd2))); - CONSOLE_PRINTLN2("page reserve size: ", (thisMany)); - page.reserve(thisMany); + // Just do max on some of the visually larger HTML chunks that will be loaded + // into page and add a little for growth when substituting values in. + size_t thisMany = std::max(sizeof(configWLANInfo), sizeof(configList)) + 200; + CONSOLE_PRINTLN2("Estimate Minimum page reserve size: ", (thisMany)); + page.reserve(std::max(kMaxChunkSize, thisMany)); page = FPSTR(configPresetInput); /* @@ -136,6 +156,7 @@ void handleWifi() { page.replace("{b}", String(WiFi.softAPmacAddress())); page.replace("{i}", WiFi.softAPIP().toString()); page.replace("{a}", String(sta_cnt)); + sendIfOver(page); if (sta_cnt) { page += String(F("\r\n
\r\n"));
       struct station_info *info = wifi_softap_get_station_info();
@@ -144,6 +165,7 @@ void handleWifi() {
         addr = info->ip;
         page += macToString(info->bssid) + F("  ") + addr.toString() + F("\r\n");
         info = STAILQ_NEXT(info, next);
+        sendIfOver(page);
       }
       page += F("
\r\n"); } @@ -153,9 +175,9 @@ void handleWifi() { Before we prepare a large block for sending, we call 'sendIfOver' with a threshold of 0 to force the sending of the current 'page' content. */ - sendIfOver(page, 0); if (WiFi.localIP().isSet()) { + sendIfOver(page, 0); page += FPSTR(configWLANInfo); page.replace("{s}", String(ssid)); page.replace("{b}", macToString(bssid)); @@ -167,13 +189,12 @@ void handleWifi() { page.replace("{m}", WiFi.subnetMask().toString()); page.replace("{1}", WiFi.dnsIP(0).toString()); page.replace("{2}", WiFi.dnsIP(1).toString()); - sendIfOver(page, 0); } else { - page += FPSTR(configWLANOffline); //F("

WLAN - offline

"); + page += FPSTR(configWLANOffline); } - page += FPSTR(configList); sendIfOver(page, 0); + sendAsChunks_P(configList); CONSOLE_PRINTLN("scan start"); int n = WiFi.scanNetworks(); @@ -191,13 +212,9 @@ void handleWifi() { } } else { page += FPSTR(configNoAPs); - sendIfOver(page); } sendIfOver(page, 0); // send what we have buffered before next direct send. - - // No changes to this chunk, no need to use Strings class. Send asis. - server.sendContent_P(configEnd); - server.sendContent_P(configEnd2); + sendAsChunks_P(configEnd); CONSOLE_PRINTLN2("MAX String memory used: ", (maxPage)); server.chunkedResponseFinalize(); From f9371b350e989a88427c2f4abc160bd36a8c3fb6 Mon Sep 17 00:00:00 2001 From: M Hightower <27247790+mhightower83@users.noreply.github.com> Date: Fri, 10 Jul 2020 11:23:00 -0700 Subject: [PATCH 10/17] Corrected case statement in getPhyModeChar(). Plus 1 for new complier catch! --- libraries/DNSServer/examples/NAPTCaptivePortal/tools.ino | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/libraries/DNSServer/examples/NAPTCaptivePortal/tools.ino b/libraries/DNSServer/examples/NAPTCaptivePortal/tools.ino index 7a4deec74b..90b9e305a8 100644 --- a/libraries/DNSServer/examples/NAPTCaptivePortal/tools.ino +++ b/libraries/DNSServer/examples/NAPTCaptivePortal/tools.ino @@ -53,18 +53,17 @@ String getWiFiStatusString(uint32_t status) { mode of a WiFi device. Can be used with the value returned by WiFi.getPhyMode(). */ char getPhyModeChar(WiFiPhyMode_t i) { - char phy = '?'; switch (i) { case WIFI_PHY_MODE_11B: - phy = 'b'; // = 1 + return 'b'; // = 1 case WIFI_PHY_MODE_11G: - phy = 'g'; // = 2, + return 'g'; // = 2, case WIFI_PHY_MODE_11N: - phy = 'n'; // = 3, + return 'n'; // = 3, default: break; } - return phy; + return '?'; } /* From 0613216acbee33b34ad41d7475f48866db76bffa Mon Sep 17 00:00:00 2001 From: M Hightower <27247790+mhightower83@users.noreply.github.com> Date: Fri, 10 Jul 2020 12:29:21 -0700 Subject: [PATCH 11/17] Fixed errors. --- libraries/DNSServer/examples/NAPTCaptivePortal/handleHttp.ino | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/DNSServer/examples/NAPTCaptivePortal/handleHttp.ino b/libraries/DNSServer/examples/NAPTCaptivePortal/handleHttp.ino index 9e18a8fde2..a4efef8ca0 100644 --- a/libraries/DNSServer/examples/NAPTCaptivePortal/handleHttp.ino +++ b/libraries/DNSServer/examples/NAPTCaptivePortal/handleHttp.ino @@ -1,6 +1,6 @@ #if LWIP_FEATURES && !LWIP_IPV6 -#include "WifiHttpv2.h" +#include "WifiHttpv.h" #ifndef TCP_MSS #define TCP_MSS 1460 @@ -9,7 +9,7 @@ Use kMaxChunkSize to limit size of chuncks */ constexpr size_t kMaxChunkSize = TCP_MSS; -String& sendIfOver(String & str, size_t threshold = kMaxChunkSize/2); +String& sendIfOver(String & str, size_t threshold = kMaxChunkSize / 2); size_t sendAsChunks_P(PGM_P content, size_t chunkSize = kMaxChunkSize); size_t maxPage = 0; From 1ef128c99564999f976e897eab4a28e4d7cfb8ea Mon Sep 17 00:00:00 2001 From: M Hightower <27247790+mhightower83@users.noreply.github.com> Date: Fri, 10 Jul 2020 17:12:32 -0700 Subject: [PATCH 12/17] typo --- libraries/DNSServer/examples/NAPTCaptivePortal/handleHttp.ino | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/DNSServer/examples/NAPTCaptivePortal/handleHttp.ino b/libraries/DNSServer/examples/NAPTCaptivePortal/handleHttp.ino index a4efef8ca0..329be2cc0c 100644 --- a/libraries/DNSServer/examples/NAPTCaptivePortal/handleHttp.ino +++ b/libraries/DNSServer/examples/NAPTCaptivePortal/handleHttp.ino @@ -1,6 +1,6 @@ #if LWIP_FEATURES && !LWIP_IPV6 -#include "WifiHttpv.h" +#include "WifiHttp.h" #ifndef TCP_MSS #define TCP_MSS 1460 From 6d95e41e6978c3ce882798d54073518804a89561 Mon Sep 17 00:00:00 2001 From: M Hightower <27247790+mhightower83@users.noreply.github.com> Date: Wed, 27 Apr 2022 10:50:55 -0700 Subject: [PATCH 13/17] Added inline to constexpr removed typedef Changed run_CI_locally.sh to run ci/style_check.sh. Copied resulting style changes from /tmp to PR --- .../NAPTCaptivePortal/NAPTCaptivePortal.ino | 94 ++++++++++--------- .../NAPTCaptivePortal/PortalRedirectHttp.ino | 2 +- .../{WifiHttp.h => WifiHttp.ino} | 5 - .../NAPTCaptivePortal/credentials.ino | 2 +- .../examples/NAPTCaptivePortal/handleHttp.ino | 37 ++++---- .../examples/NAPTCaptivePortal/tools.ino | 10 +- libraries/DNSServer/src/DNSServer.cpp | 2 +- libraries/DNSServer/src/DNSServer.h | 12 +-- tests/run_CI_locally.sh | 2 +- 9 files changed, 83 insertions(+), 83 deletions(-) rename libraries/DNSServer/examples/NAPTCaptivePortal/{WifiHttp.h => WifiHttp.ino} (99%) diff --git a/libraries/DNSServer/examples/NAPTCaptivePortal/NAPTCaptivePortal.ino b/libraries/DNSServer/examples/NAPTCaptivePortal/NAPTCaptivePortal.ino index 30897f2b86..c344c6b7eb 100644 --- a/libraries/DNSServer/examples/NAPTCaptivePortal/NAPTCaptivePortal.ino +++ b/libraries/DNSServer/examples/NAPTCaptivePortal/NAPTCaptivePortal.ino @@ -94,26 +94,34 @@ #endif #define _PRINTF(a, ...) printf_P(PSTR(a), ##__VA_ARGS__) -#define _PRINT(a) print(String(F(a))) -#define _PRINTLN(a) println(String(F(a))) -#define _PRINTLN2(a, b) println(String(F(a)) + b ) +#define _PRINT(a) print(String(F(a))) +#define _PRINTLN(a) println(String(F(a))) +#define _PRINTLN2(a, b) println(String(F(a)) + b) -#define CONSOLE_PRINTF CONSOLE._PRINTF -#define CONSOLE_PRINT CONSOLE._PRINT -#define CONSOLE_PRINTLN CONSOLE._PRINTLN +#define CONSOLE_PRINTF CONSOLE._PRINTF +#define CONSOLE_PRINT CONSOLE._PRINT +#define CONSOLE_PRINTLN CONSOLE._PRINTLN #define CONSOLE_PRINTLN2 CONSOLE._PRINTLN2 #ifdef DEBUG_SKETCH -#define DEBUG_PRINTF CONSOLE_PRINTF -#define DEBUG_PRINT CONSOLE_PRINT -#define DEBUG_PRINTLN CONSOLE_PRINTLN -#define DEBUG_PRINTLN2 CONSOLE_PRINTLN2 +#define DEBUG_PRINTF CONSOLE_PRINTF +#define DEBUG_PRINT CONSOLE_PRINT +#define DEBUG_PRINTLN CONSOLE_PRINTLN +#define DEBUG_PRINTLN2 CONSOLE_PRINTLN2 #else -#define DEBUG_PRINTF(...) do { } while(false) -#define DEBUG_PRINT(...) do { } while(false) -#define DEBUG_PRINTLN(...) do { } while(false) -#define DEBUG_PRINTLN2(...) do { } while(false) +#define DEBUG_PRINTF(...) \ + do { \ + } while (false) +#define DEBUG_PRINT(...) \ + do { \ + } while (false) +#define DEBUG_PRINTLN(...) \ + do { \ + } while (false) +#define DEBUG_PRINTLN2(...) \ + do { \ + } while (false) #endif @@ -121,7 +129,7 @@ /* Set these to your desired softAP credentials. They are not configurable at runtime */ #ifndef APSSID #define APSSID "MagicPortal" -#define APPSK "ShowTime" +#define APPSK "ShowTime" #endif const char *softAP_ssid = APSSID; @@ -154,7 +162,7 @@ bool connect = false; /** Set to true to start WiFi STA at setup time when credentials loaded successfuly from EEPROM */ /** Set to false to defer WiFi STA until configured through web interface. */ -bool staReady = false; // Don't connect right away +bool staReady = false; // Don't connect right away /** Last time I tried to connect to WLAN */ unsigned long lastConnectTry = 0; @@ -163,28 +171,28 @@ unsigned long lastConnectTry = 0; unsigned int status = WL_IDLE_STATUS; void setup() { - WiFi.persistent(false); // w/o this a flash write occurs at every boot - WiFi.mode(WIFI_OFF); // Prevent use of SDK stored credentials + WiFi.persistent(false); // w/o this a flash write occurs at every boot + WiFi.mode(WIFI_OFF); // Prevent use of SDK stored credentials CONSOLE.begin(115200); CONSOLE_PRINTLN("\r\n\r\nNAPT with Configuration Portal ..."); staModeConnectedHandler = WiFi.onStationModeConnected( - [](WiFiEventStationModeConnected data) { - // Keep a copy of the BSSID for the AP that WLAN connects to. - // This is used in the WLAN report on WiFi Details page. - memcpy(bssid, data.bssid, sizeof(bssid)); - }); + [](WiFiEventStationModeConnected data) { + // Keep a copy of the BSSID for the AP that WLAN connects to. + // This is used in the WLAN report on WiFi Details page. + memcpy(bssid, data.bssid, sizeof(bssid)); + }); staModeDisconnectedHandler = WiFi.onStationModeDisconnected( - [](WiFiEventStationModeDisconnected data) { - (void)data; - if (dnsServer.isForwarding()) { - dnsServer.disableForwarder("*"); - dnsServer.setTTL(0); - // Reminder, Serial.println() will not work from these callbacks. - // For debug printf use ets_uart_printf(). - } - }); + [](WiFiEventStationModeDisconnected data) { + (void)data; + if (dnsServer.isForwarding()) { + dnsServer.disableForwarder("*"); + dnsServer.setTTL(0); + // Reminder, Serial.println() will not work from these callbacks. + // For debug printf use ets_uart_printf(). + } + }); /* While you can remove the password parameter to make the AP open. @@ -240,13 +248,13 @@ void setup() { server.on("/", handleRoot); server.on("/wifi", handleWifi); server.on("/wifisave", handleWifiSave); - server.on("/generate_204", handleRoot); //Android captive portal. Maybe not needed. Might be handled by notFound handler. - server.on("/fwlink", handleRoot); //Microsoft captive portal. Maybe not needed. Might be handled by notFound handler. + server.on("/generate_204", handleRoot); // Android captive portal. Maybe not needed. Might be handled by notFound handler. + server.on("/fwlink", handleRoot); // Microsoft captive portal. Maybe not needed. Might be handled by notFound handler. server.onNotFound(handleNotFound); - server.begin(); // Web server start + server.begin(); // Web server start CONSOLE_PRINTLN("HTTP server started"); - loadCredentials(); // Load WLAN credentials from network - connect = (strlen(ssid) > 0 && staReady); // Request WLAN connect if there is a SSID and we want to connect at startup + loadCredentials(); // Load WLAN credentials from network + connect = (strlen(ssid) > 0 && staReady); // Request WLAN connect if there is a SSID and we want to connect at startup } void connectWifi() { @@ -286,7 +294,7 @@ void loop() { /* Don't set retry time too low as retry interfere the softAP operation */ connect = true; } - if (status != s) { // WLAN status change + if (status != s) { // WLAN status change CONSOLE_PRINTF("WLAN Status changed:\r\n"); CONSOLE_PRINTF(" new status: %s, %d\r\n", getWiFiStatusString(s).c_str(), s); CONSOLE_PRINTF(" previous status: %s, %d\r\n", getWiFiStatusString(status).c_str(), status); @@ -318,7 +326,7 @@ void loop() { Setup the DNSServer to respond only to request for our hostname and forward other name request to the DNS configured to the WLAN. */ - dnsServer.setTTL(600); // 10 minutes + dnsServer.setTTL(600); // 10 minutes dnsServer.enableForwarder(myHostname, WiFi.dnsIP(0)); CONSOLE_PRINTF("DNSServer changes/status:\r\n"); CONSOLE_PRINTF(" DNS Forwarding is %s\r\n", dnsServer.isForwarding() ? "on" : "off"); @@ -331,7 +339,7 @@ void loop() { } CONSOLE_PRINTF(" TTL set to %u\r\n", dnsServer.getTTL()); - } else { + } else { /* Captive portals will usually use a TTL of 0 to avoid DNS cache poisoning. */ dnsServer.setTTL(0); /* Setup the DNSServer to redirect all the domain lookups to the apIP */ @@ -363,9 +371,9 @@ void loop() { } } // Do work: - //DNS + // DNS dnsServer.processNextRequest(); - //HTTP + // HTTP server.handleClient(); } @@ -382,4 +390,4 @@ void setup() { void loop() { } -#endif // LWIP_FEATURES && !LWIP_IPV6 +#endif // LWIP_FEATURES && !LWIP_IPV6 diff --git a/libraries/DNSServer/examples/NAPTCaptivePortal/PortalRedirectHttp.ino b/libraries/DNSServer/examples/NAPTCaptivePortal/PortalRedirectHttp.ino index 266c7c3c8a..286490772d 100644 --- a/libraries/DNSServer/examples/NAPTCaptivePortal/PortalRedirectHttp.ino +++ b/libraries/DNSServer/examples/NAPTCaptivePortal/PortalRedirectHttp.ino @@ -45,4 +45,4 @@ void sendPortalRedirect(String path, String targetName) { server.send(302, "text/html", reply); } -#endif // LWIP_FEATURES && !LWIP_IPV6 +#endif // LWIP_FEATURES && !LWIP_IPV6 diff --git a/libraries/DNSServer/examples/NAPTCaptivePortal/WifiHttp.h b/libraries/DNSServer/examples/NAPTCaptivePortal/WifiHttp.ino similarity index 99% rename from libraries/DNSServer/examples/NAPTCaptivePortal/WifiHttp.h rename to libraries/DNSServer/examples/NAPTCaptivePortal/WifiHttp.ino index 46979b96d4..f042327762 100644 --- a/libraries/DNSServer/examples/NAPTCaptivePortal/WifiHttp.h +++ b/libraries/DNSServer/examples/NAPTCaptivePortal/WifiHttp.ino @@ -1,6 +1,3 @@ -#ifndef WIFIHTTP_H_ -#define WIFIHTTP_H_ - // #define DEBUG_VIEW // The idea here is to debug HTML with DEBUG_VIEW defined then, when finished, @@ -326,5 +323,3 @@ static const char configEnd2[] PROGMEM = R"EOF( #else static const char configEnd[] PROGMEM = R"EOF(

Connect to Network:



  👁


You may want to return to the home page.

)EOF"; #endif - -#endif diff --git a/libraries/DNSServer/examples/NAPTCaptivePortal/credentials.ino b/libraries/DNSServer/examples/NAPTCaptivePortal/credentials.ino index 04735a4d77..2d0827d0c2 100644 --- a/libraries/DNSServer/examples/NAPTCaptivePortal/credentials.ino +++ b/libraries/DNSServer/examples/NAPTCaptivePortal/credentials.ino @@ -30,4 +30,4 @@ void saveCredentials() { EEPROM.end(); } -#endif // LWIP_FEATURES && !LWIP_IPV6 +#endif // LWIP_FEATURES && !LWIP_IPV6 diff --git a/libraries/DNSServer/examples/NAPTCaptivePortal/handleHttp.ino b/libraries/DNSServer/examples/NAPTCaptivePortal/handleHttp.ino index 329be2cc0c..d8c2a48433 100644 --- a/libraries/DNSServer/examples/NAPTCaptivePortal/handleHttp.ino +++ b/libraries/DNSServer/examples/NAPTCaptivePortal/handleHttp.ino @@ -1,15 +1,13 @@ #if LWIP_FEATURES && !LWIP_IPV6 -#include "WifiHttp.h" - #ifndef TCP_MSS #define TCP_MSS 1460 #endif /* Use kMaxChunkSize to limit size of chuncks */ -constexpr size_t kMaxChunkSize = TCP_MSS; -String& sendIfOver(String & str, size_t threshold = kMaxChunkSize / 2); +constexpr inline size_t kMaxChunkSize = TCP_MSS; +String& sendIfOver(String& str, size_t threshold = kMaxChunkSize / 2); size_t sendAsChunks_P(PGM_P content, size_t chunkSize = kMaxChunkSize); size_t maxPage = 0; @@ -21,7 +19,7 @@ void addNoCacheHeader() { } -String& sendIfOver(String & str, size_t threshold) { +String& sendIfOver(String& str, size_t threshold) { size_t len = str.length(); if (len > threshold) { // Use later to determine if we reserved enough room in page to avoid realloc @@ -54,19 +52,19 @@ void handleRoot() { String Page; Page += F( - "" - "" - "ADV CAP Portal Example" - "" - "

HELLO WORLD!!

"); + "" + "" + "ADV CAP Portal Example" + "" + "

HELLO WORLD!!

"); if (server.client().localIP() == apIP) { Page += String(F("

You are connected through the soft AP: ")) + softAP_ssid + F("

"); } else { Page += String(F("

You are connected through the wifi network: ")) + ssid + F("

"); } Page += F( - "

You may want to config the wifi connection.

" - ""); + "

You may want to config the wifi connection.

" + ""); server.send(200, F("text/html"), Page); } @@ -90,9 +88,8 @@ boolean captivePortal() { return false; } - if (hAddr.isSet() || - (server.hostHeader() != (String(myHostname) + ".local") && // arrived here by mDNS - server.hostHeader() != String(myHostname))) { // arrived here by local router DNS + if (hAddr.isSet() || (server.hostHeader() != (String(myHostname) + ".local") && // arrived here by mDNS + server.hostHeader() != String(myHostname))) { // arrived here by local router DNS String whereTo = String("http://") + server.client().localIP().toString(); sendPortalRedirect(whereTo, F("Captive Portal Example")); return true; @@ -159,7 +156,7 @@ void handleWifi() { sendIfOver(page); if (sta_cnt) { page += String(F("\r\n
\r\n"));
-      struct station_info *info = wifi_softap_get_station_info();
+      struct station_info* info = wifi_softap_get_station_info();
       IPAddress addr;
       while (info != NULL) {
         addr = info->ip;
@@ -213,7 +210,7 @@ void handleWifi() {
   } else {
     page += FPSTR(configNoAPs);
   }
-  sendIfOver(page, 0); // send what we have buffered before next direct send.
+  sendIfOver(page, 0);  // send what we have buffered before next direct send.
   sendAsChunks_P(configEnd);
 
   CONSOLE_PRINTLN2("MAX String memory used: ", (maxPage));
@@ -227,11 +224,11 @@ void handleWifiSave() {
   server.arg("p").toCharArray(password, sizeof(password) - 1);
   sendPortalRedirect(F("wifi"), F("Wifi Config"));
   saveCredentials();
-  connect = strlen(ssid) > 0; // Request WLAN connect with new credentials if there is a SSID
+  connect = strlen(ssid) > 0;  // Request WLAN connect with new credentials if there is a SSID
 }
 
 void handleNotFound() {
-  if (captivePortal()) { // If captive portal redirect instead of displaying the error page.
+  if (captivePortal()) {  // If captive portal redirect instead of displaying the error page.
     return;
   }
   String message = F("File Not Found\r\n\r\n");
@@ -250,4 +247,4 @@ void handleNotFound() {
   server.send(404, F("text/plain"), message);
 }
 
-#endif // LWIP_FEATURES && !LWIP_IPV6
+#endif  // LWIP_FEATURES && !LWIP_IPV6
diff --git a/libraries/DNSServer/examples/NAPTCaptivePortal/tools.ino b/libraries/DNSServer/examples/NAPTCaptivePortal/tools.ino
index 90b9e305a8..976ecc9fb4 100644
--- a/libraries/DNSServer/examples/NAPTCaptivePortal/tools.ino
+++ b/libraries/DNSServer/examples/NAPTCaptivePortal/tools.ino
@@ -8,7 +8,7 @@
   Returns a descriptive string for WiFi.status() value
 */
 String getWiFiStatusString(uint32_t status) {
-  const __FlashStringHelper *r;
+  const __FlashStringHelper* r;
   switch (status) {
     case WL_IDLE_STATUS:
       r = F("WL_IDLE_STATUS");
@@ -55,11 +55,11 @@ String getWiFiStatusString(uint32_t status) {
 char getPhyModeChar(WiFiPhyMode_t i) {
   switch (i) {
     case WIFI_PHY_MODE_11B:
-      return 'b'; // = 1
+      return 'b';  // = 1
     case WIFI_PHY_MODE_11G:
-      return 'g'; // = 2,
+      return 'g';  // = 2,
     case WIFI_PHY_MODE_11N:
-      return 'n'; // = 3,
+      return 'n';  // = 3,
     default:
       break;
   }
@@ -81,4 +81,4 @@ String macToString(const unsigned char* mac) {
   return String(buf);
 }
 
-#endif // LWIP_FEATURES && !LWIP_IPV6
+#endif  // LWIP_FEATURES && !LWIP_IPV6
diff --git a/libraries/DNSServer/src/DNSServer.cpp b/libraries/DNSServer/src/DNSServer.cpp
index 57e533b1a0..b450807045 100644
--- a/libraries/DNSServer/src/DNSServer.cpp
+++ b/libraries/DNSServer/src/DNSServer.cpp
@@ -103,7 +103,7 @@ bool DNSServer::enableForwarder(const String &domainName, const IPAddress &dns)
 
   if (_dns.isSet()) {
     if (!_que) {
-      _que = std::unique_ptr (new (std::nothrow) dnss_requester_t[kDNSSQueSize]);
+      _que = std::unique_ptr (new (std::nothrow) struct DNSS_REQUESTER[kDNSSQueSize]);
       DEBUG_PRINTF("Created new _que\r\n");
       if (_que) {
         for (size_t i = 0; i < kDNSSQueSize; i++) {
diff --git a/libraries/DNSServer/src/DNSServer.h b/libraries/DNSServer/src/DNSServer.h
index e747e05a18..f8a70dd52e 100644
--- a/libraries/DNSServer/src/DNSServer.h
+++ b/libraries/DNSServer/src/DNSServer.h
@@ -7,7 +7,7 @@
 // https://www.iana.org/assignments/service-names-port-numbers/service-names-port-numbers.txt
 #ifndef IANA_DNS_PORT
 #define IANA_DNS_PORT 53        // AKA domain
-constexpr uint16_t kIanaDnsPort = 53;
+constexpr inline uint16_t kIanaDnsPort = 53;
 #endif
 
 #define DNS_QR_QUERY 0
@@ -53,14 +53,14 @@ struct DNSHeader
   uint16_t ARCount;          // number of resource entries
 };
 
-constexpr size_t kDNSSQueSizeAddrBits = 3; // The number of bits used to address que entries
-constexpr size_t kDNSSQueSize = BIT(kDNSSQueSizeAddrBits);
+constexpr inline size_t kDNSSQueSizeAddrBits = 3; // The number of bits used to address que entries
+constexpr inline size_t kDNSSQueSize = BIT(kDNSSQueSizeAddrBits);
 
-typedef struct DNSS_REQUESTER {
+struct DNSS_REQUESTER {
   uint32_t ip;
   uint16_t port;
   uint16_t id;
-} dnss_requester_t;
+};
 
 class DNSServer
 {
@@ -110,7 +110,7 @@ class DNSServer
     WiFiUDP _udp;
     String _domainName;
     IPAddress _dns;
-    std::unique_ptr _que;
+    std::unique_ptr _que;
     uint32_t _ttl;
 #ifdef DEBUG_DNSSERVER
     // There are 2 possiblities for OverFlow:
diff --git a/tests/run_CI_locally.sh b/tests/run_CI_locally.sh
index ee9dc39cb0..0c67eb202f 100755
--- a/tests/run_CI_locally.sh
+++ b/tests/run_CI_locally.sh
@@ -115,7 +115,7 @@ elif [ "$BUILD_TYPE" = host ]; then
     tests/ci/host_test.sh
 
 elif [ "$BUILD_TYPE" = style ]; then
-    tests/ci/check_restyle.sh
+    tests/ci/style_check.sh
     tests/restyle.sh
 
 else

From 32fe7e1250092be7e61c76fc16969dbbda906ca6 Mon Sep 17 00:00:00 2001
From: M Hightower <27247790+mhightower83@users.noreply.github.com>
Date: Sun, 1 May 2022 10:26:08 -0700
Subject: [PATCH 14/17] Updates

removed stale #define
add const
remove struct prefix
---
 .../examples/NAPTCaptivePortal/NAPTCaptivePortal.ino        | 6 ++----
 libraries/DNSServer/src/DNSServer.cpp                       | 2 +-
 libraries/DNSServer/src/DNSServer.h                         | 4 ++--
 3 files changed, 5 insertions(+), 7 deletions(-)

diff --git a/libraries/DNSServer/examples/NAPTCaptivePortal/NAPTCaptivePortal.ino b/libraries/DNSServer/examples/NAPTCaptivePortal/NAPTCaptivePortal.ino
index c344c6b7eb..325cd3c246 100644
--- a/libraries/DNSServer/examples/NAPTCaptivePortal/NAPTCaptivePortal.ino
+++ b/libraries/DNSServer/examples/NAPTCaptivePortal/NAPTCaptivePortal.ino
@@ -146,7 +146,6 @@ WiFiEventHandler staModeConnectedHandler;
 WiFiEventHandler staModeDisconnectedHandler;
 
 // DNS server
-const byte DNS_PORT = 53;
 DNSServer dnsServer;
 
 // Web server
@@ -177,15 +176,14 @@ void setup() {
   CONSOLE_PRINTLN("\r\n\r\nNAPT with Configuration Portal ...");
 
   staModeConnectedHandler = WiFi.onStationModeConnected(
-    [](WiFiEventStationModeConnected data) {
+    [](const WiFiEventStationModeConnected data) {
       // Keep a copy of the BSSID for the AP that WLAN connects to.
       // This is used in the WLAN report on WiFi Details page.
       memcpy(bssid, data.bssid, sizeof(bssid));
     });
 
   staModeDisconnectedHandler = WiFi.onStationModeDisconnected(
-    [](WiFiEventStationModeDisconnected data) {
-      (void)data;
+    [](const WiFiEventStationModeDisconnected) {
       if (dnsServer.isForwarding()) {
         dnsServer.disableForwarder("*");
         dnsServer.setTTL(0);
diff --git a/libraries/DNSServer/src/DNSServer.cpp b/libraries/DNSServer/src/DNSServer.cpp
index b450807045..d2c41f79d7 100644
--- a/libraries/DNSServer/src/DNSServer.cpp
+++ b/libraries/DNSServer/src/DNSServer.cpp
@@ -103,7 +103,7 @@ bool DNSServer::enableForwarder(const String &domainName, const IPAddress &dns)
 
   if (_dns.isSet()) {
     if (!_que) {
-      _que = std::unique_ptr (new (std::nothrow) struct DNSS_REQUESTER[kDNSSQueSize]);
+      _que = std::unique_ptr (new (std::nothrow) DNSS_REQUESTER[kDNSSQueSize]);
       DEBUG_PRINTF("Created new _que\r\n");
       if (_que) {
         for (size_t i = 0; i < kDNSSQueSize; i++) {
diff --git a/libraries/DNSServer/src/DNSServer.h b/libraries/DNSServer/src/DNSServer.h
index f8a70dd52e..1ca16697f9 100644
--- a/libraries/DNSServer/src/DNSServer.h
+++ b/libraries/DNSServer/src/DNSServer.h
@@ -7,7 +7,7 @@
 // https://www.iana.org/assignments/service-names-port-numbers/service-names-port-numbers.txt
 #ifndef IANA_DNS_PORT
 #define IANA_DNS_PORT 53        // AKA domain
-constexpr inline uint16_t kIanaDnsPort = 53;
+constexpr inline uint16_t kIanaDnsPort = IANA_DNS_PORT;
 #endif
 
 #define DNS_QR_QUERY 0
@@ -110,7 +110,7 @@ class DNSServer
     WiFiUDP _udp;
     String _domainName;
     IPAddress _dns;
-    std::unique_ptr _que;
+    std::unique_ptr _que;
     uint32_t _ttl;
 #ifdef DEBUG_DNSSERVER
     // There are 2 possiblities for OverFlow:

From dda4e04fef0295c401e3c3bbb948d442988b18dd Mon Sep 17 00:00:00 2001
From: M Hightower <27247790+mhightower83@users.noreply.github.com>
Date: Mon, 2 May 2022 08:35:01 -0700
Subject: [PATCH 15/17] Update
 libraries/DNSServer/examples/NAPTCaptivePortal/NAPTCaptivePortal.ino

Co-authored-by: Max Prokhorov 
---
 .../DNSServer/examples/NAPTCaptivePortal/NAPTCaptivePortal.ino  | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/libraries/DNSServer/examples/NAPTCaptivePortal/NAPTCaptivePortal.ino b/libraries/DNSServer/examples/NAPTCaptivePortal/NAPTCaptivePortal.ino
index 325cd3c246..58c2fcb879 100644
--- a/libraries/DNSServer/examples/NAPTCaptivePortal/NAPTCaptivePortal.ino
+++ b/libraries/DNSServer/examples/NAPTCaptivePortal/NAPTCaptivePortal.ino
@@ -176,7 +176,7 @@ void setup() {
   CONSOLE_PRINTLN("\r\n\r\nNAPT with Configuration Portal ...");
 
   staModeConnectedHandler = WiFi.onStationModeConnected(
-    [](const WiFiEventStationModeConnected data) {
+    [](const WiFiEventStationModeConnected& data) {
       // Keep a copy of the BSSID for the AP that WLAN connects to.
       // This is used in the WLAN report on WiFi Details page.
       memcpy(bssid, data.bssid, sizeof(bssid));

From 8afa9cab8dad40335b952c640d1e7fe8cacd1893 Mon Sep 17 00:00:00 2001
From: M Hightower <27247790+mhightower83@users.noreply.github.com>
Date: Mon, 2 May 2022 08:35:08 -0700
Subject: [PATCH 16/17] Update
 libraries/DNSServer/examples/NAPTCaptivePortal/NAPTCaptivePortal.ino

Co-authored-by: Max Prokhorov 
---
 .../DNSServer/examples/NAPTCaptivePortal/NAPTCaptivePortal.ino  | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/libraries/DNSServer/examples/NAPTCaptivePortal/NAPTCaptivePortal.ino b/libraries/DNSServer/examples/NAPTCaptivePortal/NAPTCaptivePortal.ino
index 58c2fcb879..87927798cd 100644
--- a/libraries/DNSServer/examples/NAPTCaptivePortal/NAPTCaptivePortal.ino
+++ b/libraries/DNSServer/examples/NAPTCaptivePortal/NAPTCaptivePortal.ino
@@ -183,7 +183,7 @@ void setup() {
     });
 
   staModeDisconnectedHandler = WiFi.onStationModeDisconnected(
-    [](const WiFiEventStationModeDisconnected) {
+    [](const WiFiEventStationModeDisconnected&) {
       if (dnsServer.isForwarding()) {
         dnsServer.disableForwarder("*");
         dnsServer.setTTL(0);

From ea3e97191e3e6672eff8e2f69e41026dddbf236e Mon Sep 17 00:00:00 2001
From: M Hightower <27247790+mhightower83@users.noreply.github.com>
Date: Thu, 5 May 2022 17:57:34 -0700
Subject: [PATCH 17/17] style

---
 .../examples/NAPTCaptivePortal/NAPTCaptivePortal.ino          | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/libraries/DNSServer/examples/NAPTCaptivePortal/NAPTCaptivePortal.ino b/libraries/DNSServer/examples/NAPTCaptivePortal/NAPTCaptivePortal.ino
index 87927798cd..cb65f518ef 100644
--- a/libraries/DNSServer/examples/NAPTCaptivePortal/NAPTCaptivePortal.ino
+++ b/libraries/DNSServer/examples/NAPTCaptivePortal/NAPTCaptivePortal.ino
@@ -176,14 +176,14 @@ void setup() {
   CONSOLE_PRINTLN("\r\n\r\nNAPT with Configuration Portal ...");
 
   staModeConnectedHandler = WiFi.onStationModeConnected(
-    [](const WiFiEventStationModeConnected& data) {
+    [](const WiFiEventStationModeConnected &data) {
       // Keep a copy of the BSSID for the AP that WLAN connects to.
       // This is used in the WLAN report on WiFi Details page.
       memcpy(bssid, data.bssid, sizeof(bssid));
     });
 
   staModeDisconnectedHandler = WiFi.onStationModeDisconnected(
-    [](const WiFiEventStationModeDisconnected&) {
+    [](const WiFiEventStationModeDisconnected &) {
       if (dnsServer.isForwarding()) {
         dnsServer.disableForwarder("*");
         dnsServer.setTTL(0);