Skip to content

Commit

Permalink
WiFiServer IPv6 support and example, WiFiClient::remoteIP IPv6 support
Browse files Browse the repository at this point in the history
This is one of useful examples of IPv6, such device can be reached
from internet without any port forward on NAT and etc.

Most of changes for WiFiServer is to use ip6 structures, and for ip4
we use ipv6-to-ipv4 mapped addresses (RFC 4291).
For RemoteIP i added support ip4 to ip6 mapping as well.

Scenarios tested:
wifiMulti.IPv6(true); but set to listen on IPv4 only
IPv6 disabled, with or without bind to specific IP4
AsyncUDPServer without IPv6 support, to check if remoteIP works properly

Signed-off-by: Denys Fedoryshchenko <[email protected]>
  • Loading branch information
nuclearcat committed May 7, 2022
1 parent 4735f66 commit 4a05392
Show file tree
Hide file tree
Showing 5 changed files with 50 additions and 15 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ void setup() {
Serial.begin(115200);
Serial.println("\nConnecting");

wifiMulti.IPv6(true);
wifiMulti.addAP(ssid, password);
wifiMulti.addAP("ssid_from_AP_2", "your_password_for_AP_2");
wifiMulti.addAP("ssid_from_AP_3", "your_password_for_AP_3");
Expand Down
24 changes: 22 additions & 2 deletions libraries/WiFi/src/WiFiClient.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -561,8 +561,28 @@ IPAddress WiFiClient::remoteIP(int fd) const
struct sockaddr_storage addr;
socklen_t len = sizeof addr;
getpeername(fd, (struct sockaddr*)&addr, &len);
struct sockaddr_in *s = (struct sockaddr_in *)&addr;
return IPAddress((uint32_t)(s->sin_addr.s_addr));

// Old way, IPv4
if (((struct sockaddr*)&addr)->sa_family == AF_INET) {
struct sockaddr_in *s = (struct sockaddr_in *)&addr;
return IPAddress((uint32_t)(s->sin_addr.s_addr));
}
// IPv6, but it might be IPv4 mapped address
if (((struct sockaddr*)&addr)->sa_family == AF_INET6) {
struct sockaddr_in6 *saddr6 = (struct sockaddr_in6 *)&addr;
if (IN6_IS_ADDR_V4MAPPED(saddr6->sin6_addr.un.u32_addr)) {
struct sockaddr_in addr4;
memset(&addr4, 0, sizeof(addr4));
addr4.sin_family = AF_INET;
addr4.sin_port = saddr6->sin6_port;
memcpy(&addr4.sin_addr.s_addr, saddr6->sin6_addr.s6_addr+12, sizeof(addr4.sin_addr.s_addr));
return IPAddress((uint32_t)(addr4.sin_addr.s_addr));
}
log_e("WiFiClient::remoteIP IPv6 not supported yet");
return (IPAddress(0,0,0,0));
}
log_e("WiFiClient::remoteIP Not AF_INET or AF_INET6?");
return (IPAddress(0,0,0,0));
}

uint16_t WiFiClient::remotePort(int fd) const
Expand Down
5 changes: 5 additions & 0 deletions libraries/WiFi/src/WiFiClient.h
Original file line number Diff line number Diff line change
Expand Up @@ -106,4 +106,9 @@ class WiFiClient : public ESPLwIPClient
using Print::write;
};

#define IN6_IS_ADDR_V4MAPPED(a) \
((((__const uint32_t *) (a))[0] == 0) \
&& (((__const uint32_t *) (a))[1] == 0) \
&& (((__const uint32_t *) (a))[2] == htonl (0xffff)))

#endif /* _WIFICLIENT_H_ */
18 changes: 9 additions & 9 deletions libraries/WiFi/src/WiFiServer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,8 @@ WiFiClient WiFiServer::available(){
_accepted_sockfd = -1;
}
else {
struct sockaddr_in _client;
int cs = sizeof(struct sockaddr_in);
struct sockaddr_in6 _client;
int cs = sizeof(struct sockaddr_in6);
#ifdef ESP_IDF_VERSION_MAJOR
client_sock = lwip_accept(sockfd, (struct sockaddr *)&_client, (socklen_t*)&cs);
#else
Expand Down Expand Up @@ -76,14 +76,14 @@ void WiFiServer::begin(uint16_t port, int enable){
if(port){
_port = port;
}
struct sockaddr_in server;
sockfd = socket(AF_INET , SOCK_STREAM, 0);
struct sockaddr_in6 server;
sockfd = socket(AF_INET6 , SOCK_STREAM, 0);
if (sockfd < 0)
return;
setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(int));
server.sin_family = AF_INET;
server.sin_addr.s_addr = _addr;
server.sin_port = htons(_port);
server.sin6_family = AF_INET6;
server.sin6_addr = _addr;
server.sin6_port = htons(_port);
if(bind(sockfd, (struct sockaddr *)&server, sizeof(server)) < 0)
return;
if(listen(sockfd , _max_clients) < 0)
Expand All @@ -106,8 +106,8 @@ bool WiFiServer::hasClient() {
if (_accepted_sockfd >= 0) {
return true;
}
struct sockaddr_in _client;
int cs = sizeof(struct sockaddr_in);
struct sockaddr_in6 _client;
int cs = sizeof(struct sockaddr_in6);
#ifdef ESP_IDF_VERSION_MAJOR
_accepted_sockfd = lwip_accept(sockfd, (struct sockaddr *)&_client, (socklen_t*)&cs);
#else
Expand Down
17 changes: 13 additions & 4 deletions libraries/WiFi/src/WiFiServer.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,14 @@
#include "Server.h"
#include "WiFiClient.h"
#include "IPAddress.h"
#include "lwip/inet.h"
#include "lwip/netdb.h"

class WiFiServer : public Server {
private:
int sockfd;
int _accepted_sockfd = -1;
IPAddress _addr;
in6_addr _addr;
uint16_t _port;
uint8_t _max_clients;
bool _listening;
Expand All @@ -37,12 +39,19 @@ class WiFiServer : public Server {
public:
void listenOnLocalhost(){}

// _addr(INADDR_ANY) is the same as _addr() ==> 0.0.0.0
WiFiServer(uint16_t port=80, uint8_t max_clients=4):sockfd(-1),_accepted_sockfd(-1),_addr(),_port(port),_max_clients(max_clients),_listening(false),_noDelay(false) {
WiFiServer(uint16_t port=80, uint8_t max_clients=4):sockfd(-1),_accepted_sockfd(-1),_port(port),_max_clients(max_clients),_listening(false),_noDelay(false) {
log_v("WiFiServer::WiFiServer(port=%d, ...)", port);
_addr = IN6ADDR_ANY_INIT;
}
WiFiServer(const IPAddress& addr, uint16_t port=80, uint8_t max_clients=4):sockfd(-1),_accepted_sockfd(-1),_addr(addr),_port(port),_max_clients(max_clients),_listening(false),_noDelay(false) {
WiFiServer(const IPAddress& addr, uint16_t port=80, uint8_t max_clients=4):sockfd(-1),_accepted_sockfd(-1),_port(port),_max_clients(max_clients),_listening(false),_noDelay(false) {
log_v("WiFiServer::WiFiServer(addr=%s, port=%d, ...)", addr.toString().c_str(), port);
char buffer[64] = { 0 };
// Print IPv4 in IPv6 notation
sprintf(buffer, "::FFFF:%s", addr.toString().c_str());
int rc = inet_pton(AF_INET6, buffer, &_addr);
if (rc != 1) {
log_e("WiFiServer::WiFiServer unable to resolve address, rc=%d", rc);
}
}
~WiFiServer(){ end();}
WiFiClient available();
Expand Down

0 comments on commit 4a05392

Please sign in to comment.