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);




pFad - Phonifier reborn



Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy