diff --git a/intl/msg_hash_us.h b/intl/msg_hash_us.h index 7a23fc815c..e2525ec37e 100644 --- a/intl/msg_hash_us.h +++ b/intl/msg_hash_us.h @@ -11659,6 +11659,10 @@ MSG_HASH( MSG_PUBLIC_ADDRESS, "Netplay Port Mapping Successful" ) +MSG_HASH( + MSG_PRIVATE_OR_SHARED_ADDRESS, + "External network has a private or shared address. Consider using a relay server." + ) MSG_HASH( MSG_UPNP_FAILED, "Netplay UPnP Port Mapping Failed" diff --git a/libretro-common/include/net/net_compat.h b/libretro-common/include/net/net_compat.h index aabf68d295..f00612e7ae 100644 --- a/libretro-common/include/net/net_compat.h +++ b/libretro-common/include/net/net_compat.h @@ -395,6 +395,9 @@ int getnameinfo_retro(const struct sockaddr *addr, socklen_t addrlen, bool addr_6to4(struct sockaddr_storage *addr); +bool ipv4_is_lan_address(struct sockaddr_in *addr); +bool ipv4_is_cgnat_address(struct sockaddr_in *addr); + /** * network_init: * diff --git a/libretro-common/net/net_compat.c b/libretro-common/net/net_compat.c index a954857a42..0977d77a81 100644 --- a/libretro-common/net/net_compat.c +++ b/libretro-common/net/net_compat.c @@ -24,6 +24,7 @@ #include #include +#include #include #include @@ -422,6 +423,35 @@ bool addr_6to4(struct sockaddr_storage *addr) return true; } +bool ipv4_is_lan_address(struct sockaddr_in *addr) +{ + static const uint32_t subnets[] = {0x0A000000, 0xAC100000, 0xC0A80000}; + static const uint32_t masks[] = {0xFF000000, 0xFFF00000, 0xFFFF0000}; + size_t i; + uint32_t uaddr; + + memcpy(&uaddr, &addr->sin_addr, sizeof(uaddr)); + uaddr = ntohl(uaddr); + + for (i = 0; i < ARRAY_SIZE(subnets); i++) + if ((uaddr & masks[i]) == subnets[i]) + return true; + + return false; +} + +bool ipv4_is_cgnat_address(struct sockaddr_in *addr) +{ + static const uint32_t subnet = 0x64400000; + static const uint32_t mask = 0xFFC00000; + uint32_t uaddr; + + memcpy(&uaddr, &addr->sin_addr, sizeof(uaddr)); + uaddr = ntohl(uaddr); + + return (uaddr & mask) == subnet; +} + /** * network_init: * diff --git a/msg_hash.h b/msg_hash.h index 2ecd39c611..873769f310 100644 --- a/msg_hash.h +++ b/msg_hash.h @@ -277,6 +277,7 @@ enum msg_hash_enums MSG_GOT_CONNECTION_FROM_NAME, MSG_CONNECTION_SLOT, MSG_PUBLIC_ADDRESS, + MSG_PRIVATE_OR_SHARED_ADDRESS, MSG_UPNP_FAILED, MSG_NO_SAVE_STATE_HAS_BEEN_OVERWRITTEN_YET, MSG_CANNOT_INFER_NEW_CONFIG_PATH, diff --git a/network/netplay/netplay.h b/network/netplay/netplay.h index e29eac9ec6..6631678a37 100644 --- a/network/netplay/netplay.h +++ b/network/netplay/netplay.h @@ -285,7 +285,6 @@ net_driver_state_t *networking_state_get_ptr(void); bool netplay_compatible_version(const char *version); 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); int netplay_rooms_parse(const char *buf, size_t len); int netplay_rooms_get_count(void); diff --git a/network/netplay/netplay_frontend.c b/network/netplay/netplay_frontend.c index 607323e8a8..6c22e0c86b 100644 --- a/network/netplay/netplay_frontend.c +++ b/network/netplay/netplay_frontend.c @@ -331,7 +331,7 @@ static bool netplay_lan_ad_client_response(void) if (!addr_6to4(&their_addr)) continue; - if (!netplay_is_lan_address((struct sockaddr_in*)&their_addr)) + if (!ipv4_is_lan_address((struct sockaddr_in*)&their_addr)) continue; if (getnameinfo_retro((struct sockaddr*)&their_addr, sizeof(their_addr), @@ -530,7 +530,7 @@ static bool netplay_lan_ad_server(netplay_t *netplay) if (!addr_6to4(&their_addr)) return true; - if (!netplay_is_lan_address((struct sockaddr_in*)&their_addr)) + if (!ipv4_is_lan_address((struct sockaddr_in*)&their_addr)) return true; RARCH_LOG("[Discovery] Query received on LAN interface.\n"); @@ -6420,24 +6420,35 @@ static void netplay_announce_nat_traversal(netplay_t *netplay, if (net_st->nat_traversal_request.status == NAT_TRAVERSAL_STATUS_OPENED) { - char msg[512]; - char host[256], port[6]; + struct sockaddr_in *addr = &net_st->nat_traversal_request.request.addr; netplay->ext_tcp_port = ext_port; - if (!getnameinfo_retro( - (struct sockaddr*)&net_st->nat_traversal_request.request.addr, - sizeof(net_st->nat_traversal_request.request.addr), - host, sizeof(host), port, sizeof(port), - NI_NUMERICHOST | NI_NUMERICSERV)) - snprintf(msg, sizeof(msg), "%s: %s:%s", - msg_hash_to_str(MSG_PUBLIC_ADDRESS), host, port); - else - strlcpy(msg, msg_hash_to_str(MSG_PUBLIC_ADDRESS), sizeof(msg)); + if (!ipv4_is_cgnat_address(addr) && !ipv4_is_lan_address(addr)) + { + char msg[512]; + char host[256], port[6]; - RARCH_LOG("[Netplay] %s\n", msg); - runloop_msg_queue_push(msg, 1, 180, false, NULL, - MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); + if (!getnameinfo_retro((struct sockaddr*)addr, sizeof(*addr), + host, sizeof(host), port, sizeof(port), + NI_NUMERICHOST | NI_NUMERICSERV)) + snprintf(msg, sizeof(msg), "%s: %s:%s", + msg_hash_to_str(MSG_PUBLIC_ADDRESS), host, port); + else + strlcpy(msg, msg_hash_to_str(MSG_PUBLIC_ADDRESS), sizeof(msg)); + + RARCH_LOG("[Netplay] %s\n", msg); + runloop_msg_queue_push(msg, 1, 180, false, NULL, + MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); + } + else + { + const char *msg = msg_hash_to_str(MSG_PRIVATE_OR_SHARED_ADDRESS); + + RARCH_WARN("[Netplay] %s\n", msg); + runloop_msg_queue_push(msg, 1, 600, false, NULL, + MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); + } } else { @@ -9124,23 +9135,6 @@ bool netplay_decode_hostname(const char *hostname, return true; } -bool netplay_is_lan_address(struct sockaddr_in *addr) -{ - static const uint32_t subnets[] = {0x0A000000, 0xAC100000, 0xC0A80000}; - static const uint32_t masks[] = {0xFF000000, 0xFFF00000, 0xFFFF0000}; - size_t i; - uint32_t uaddr; - - memcpy(&uaddr, &addr->sin_addr, sizeof(uaddr)); - uaddr = ntohl(uaddr); - - for (i = 0; i < ARRAY_SIZE(subnets); i++) - if ((uaddr & masks[i]) == subnets[i]) - return true; - - return false; -} - /* Netplay Widgets */ #ifdef HAVE_GFX_WIDGETS