diff --git a/network/netplay/netplay.h b/network/netplay/netplay.h index 0d25101df1..22438ccc90 100644 --- a/network/netplay/netplay.h +++ b/network/netplay/netplay.h @@ -437,5 +437,6 @@ bool netplay_discovery_driver_ctl( bool netplay_decode_hostname(const char *hostname, char *address, unsigned *port, char *session, size_t len); bool netplay_is_lan_address(struct sockaddr_in *addr); +bool netplay_6to4(struct sockaddr_storage *addr); #endif diff --git a/network/netplay/netplay_frontend.c b/network/netplay/netplay_frontend.c index a159917c57..7f6155dc28 100644 --- a/network/netplay/netplay_frontend.c +++ b/network/netplay/netplay_frontend.c @@ -333,23 +333,19 @@ static bool netplay_lan_ad_client_response(void) /* And that we know how to handle it */ #ifdef HAVE_INET6 -/* skip the early return on android*/ -#ifndef ANDROID - if (their_addr.ss_family != AF_INET) + if (their_addr.ss_family == AF_INET6) + { + /* Check for IPv4 tunneling */ + if (!netplay_6to4(&their_addr)) + continue; + } + else if (their_addr.ss_family != AF_INET) continue; #endif -#endif -/* NOTE - Even if the IP address family is IPv4 it will be seen as an IPV6 - mapped IPv4 address on Android, so until someone can fix netplay_is_lan_address - let's skip that check for that use case. The netplay_is_lan_address function - was just meant to filter out bogus entries caused by TAP adapters or VNET adapters -*/ -#ifndef ANDROID if (!netplay_is_lan_address( (struct sockaddr_in *) &their_addr)) - continue; -#endif + continue; #ifndef HAVE_SOCKET_LEGACY if (getnameinfo((struct sockaddr *) @@ -558,7 +554,13 @@ static bool netplay_lan_ad_server(netplay_t *netplay) } #ifdef HAVE_INET6 - if (their_addr.ss_family != AF_INET) + if (their_addr.ss_family == AF_INET6) + { + /* Check for IPv4 tunneling */ + if (!netplay_6to4(&their_addr)) + return true; + } + else if (their_addr.ss_family != AF_INET) return true; #endif @@ -8775,6 +8777,33 @@ bool netplay_is_lan_address(struct sockaddr_in *addr) return false; } +bool netplay_6to4(struct sockaddr_storage *addr) +{ +#ifdef HAVE_INET6 + /* ::ffff:a.b.c.d */ + static const uint16_t preffix[] = {0,0,0,0,0,0xffff}; + uint32_t address; + uint16_t port; + struct sockaddr_in6 *addr6 = (struct sockaddr_in6*)addr; + struct sockaddr_in *addr4 = (struct sockaddr_in*)addr; + + /* Is the address provided an IPv4? */ + if (memcmp(&addr6->sin6_addr, preffix, sizeof(preffix))) + return false; + + memcpy(&address, ((uint8_t*)&addr6->sin6_addr) + sizeof(preffix), + sizeof(address)); + port = addr6->sin6_port; + + memset(addr, 0, sizeof(*addr)); + addr4->sin_family = AF_INET; + addr4->sin_port = port; + memcpy(&addr4->sin_addr, &address, sizeof(addr4->sin_addr)); +#endif + + return true; +} + /* Netplay Widgets */ #ifdef HAVE_GFX_WIDGETS