Skip to content

Commit 4a05392

Browse files
committed
WiFiServer IPv6 support and example, WiFiClient::remoteIP IPv6 support
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]>
1 parent 4735f66 commit 4a05392

File tree

5 files changed

+50
-15
lines changed

5 files changed

+50
-15
lines changed

Diff for: libraries/WiFi/examples/WiFiTelnetToSerial/WiFiTelnetToSerial.ino

+1
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ void setup() {
3535
Serial.begin(115200);
3636
Serial.println("\nConnecting");
3737

38+
wifiMulti.IPv6(true);
3839
wifiMulti.addAP(ssid, password);
3940
wifiMulti.addAP("ssid_from_AP_2", "your_password_for_AP_2");
4041
wifiMulti.addAP("ssid_from_AP_3", "your_password_for_AP_3");

Diff for: libraries/WiFi/src/WiFiClient.cpp

+22-2
Original file line numberDiff line numberDiff line change
@@ -561,8 +561,28 @@ IPAddress WiFiClient::remoteIP(int fd) const
561561
struct sockaddr_storage addr;
562562
socklen_t len = sizeof addr;
563563
getpeername(fd, (struct sockaddr*)&addr, &len);
564-
struct sockaddr_in *s = (struct sockaddr_in *)&addr;
565-
return IPAddress((uint32_t)(s->sin_addr.s_addr));
564+
565+
// Old way, IPv4
566+
if (((struct sockaddr*)&addr)->sa_family == AF_INET) {
567+
struct sockaddr_in *s = (struct sockaddr_in *)&addr;
568+
return IPAddress((uint32_t)(s->sin_addr.s_addr));
569+
}
570+
// IPv6, but it might be IPv4 mapped address
571+
if (((struct sockaddr*)&addr)->sa_family == AF_INET6) {
572+
struct sockaddr_in6 *saddr6 = (struct sockaddr_in6 *)&addr;
573+
if (IN6_IS_ADDR_V4MAPPED(saddr6->sin6_addr.un.u32_addr)) {
574+
struct sockaddr_in addr4;
575+
memset(&addr4, 0, sizeof(addr4));
576+
addr4.sin_family = AF_INET;
577+
addr4.sin_port = saddr6->sin6_port;
578+
memcpy(&addr4.sin_addr.s_addr, saddr6->sin6_addr.s6_addr+12, sizeof(addr4.sin_addr.s_addr));
579+
return IPAddress((uint32_t)(addr4.sin_addr.s_addr));
580+
}
581+
log_e("WiFiClient::remoteIP IPv6 not supported yet");
582+
return (IPAddress(0,0,0,0));
583+
}
584+
log_e("WiFiClient::remoteIP Not AF_INET or AF_INET6?");
585+
return (IPAddress(0,0,0,0));
566586
}
567587

568588
uint16_t WiFiClient::remotePort(int fd) const

Diff for: libraries/WiFi/src/WiFiClient.h

+5
Original file line numberDiff line numberDiff line change
@@ -106,4 +106,9 @@ class WiFiClient : public ESPLwIPClient
106106
using Print::write;
107107
};
108108

109+
#define IN6_IS_ADDR_V4MAPPED(a) \
110+
((((__const uint32_t *) (a))[0] == 0) \
111+
&& (((__const uint32_t *) (a))[1] == 0) \
112+
&& (((__const uint32_t *) (a))[2] == htonl (0xffff)))
113+
109114
#endif /* _WIFICLIENT_H_ */

Diff for: libraries/WiFi/src/WiFiServer.cpp

+9-9
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,8 @@ WiFiClient WiFiServer::available(){
4747
_accepted_sockfd = -1;
4848
}
4949
else {
50-
struct sockaddr_in _client;
51-
int cs = sizeof(struct sockaddr_in);
50+
struct sockaddr_in6 _client;
51+
int cs = sizeof(struct sockaddr_in6);
5252
#ifdef ESP_IDF_VERSION_MAJOR
5353
client_sock = lwip_accept(sockfd, (struct sockaddr *)&_client, (socklen_t*)&cs);
5454
#else
@@ -76,14 +76,14 @@ void WiFiServer::begin(uint16_t port, int enable){
7676
if(port){
7777
_port = port;
7878
}
79-
struct sockaddr_in server;
80-
sockfd = socket(AF_INET , SOCK_STREAM, 0);
79+
struct sockaddr_in6 server;
80+
sockfd = socket(AF_INET6 , SOCK_STREAM, 0);
8181
if (sockfd < 0)
8282
return;
8383
setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(int));
84-
server.sin_family = AF_INET;
85-
server.sin_addr.s_addr = _addr;
86-
server.sin_port = htons(_port);
84+
server.sin6_family = AF_INET6;
85+
server.sin6_addr = _addr;
86+
server.sin6_port = htons(_port);
8787
if(bind(sockfd, (struct sockaddr *)&server, sizeof(server)) < 0)
8888
return;
8989
if(listen(sockfd , _max_clients) < 0)
@@ -106,8 +106,8 @@ bool WiFiServer::hasClient() {
106106
if (_accepted_sockfd >= 0) {
107107
return true;
108108
}
109-
struct sockaddr_in _client;
110-
int cs = sizeof(struct sockaddr_in);
109+
struct sockaddr_in6 _client;
110+
int cs = sizeof(struct sockaddr_in6);
111111
#ifdef ESP_IDF_VERSION_MAJOR
112112
_accepted_sockfd = lwip_accept(sockfd, (struct sockaddr *)&_client, (socklen_t*)&cs);
113113
#else

Diff for: libraries/WiFi/src/WiFiServer.h

+13-4
Original file line numberDiff line numberDiff line change
@@ -23,12 +23,14 @@
2323
#include "Server.h"
2424
#include "WiFiClient.h"
2525
#include "IPAddress.h"
26+
#include "lwip/inet.h"
27+
#include "lwip/netdb.h"
2628

2729
class WiFiServer : public Server {
2830
private:
2931
int sockfd;
3032
int _accepted_sockfd = -1;
31-
IPAddress _addr;
33+
in6_addr _addr;
3234
uint16_t _port;
3335
uint8_t _max_clients;
3436
bool _listening;
@@ -37,12 +39,19 @@ class WiFiServer : public Server {
3739
public:
3840
void listenOnLocalhost(){}
3941

40-
// _addr(INADDR_ANY) is the same as _addr() ==> 0.0.0.0
41-
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) {
42+
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) {
4243
log_v("WiFiServer::WiFiServer(port=%d, ...)", port);
44+
_addr = IN6ADDR_ANY_INIT;
4345
}
44-
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) {
46+
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) {
4547
log_v("WiFiServer::WiFiServer(addr=%s, port=%d, ...)", addr.toString().c_str(), port);
48+
char buffer[64] = { 0 };
49+
// Print IPv4 in IPv6 notation
50+
sprintf(buffer, "::FFFF:%s", addr.toString().c_str());
51+
int rc = inet_pton(AF_INET6, buffer, &_addr);
52+
if (rc != 1) {
53+
log_e("WiFiServer::WiFiServer unable to resolve address, rc=%d", rc);
54+
}
4655
}
4756
~WiFiServer(){ end();}
4857
WiFiClient available();

0 commit comments

Comments
 (0)