diff options
-rw-r--r-- | gio/gsocket.c | 31 |
1 files changed, 31 insertions, 0 deletions
diff --git a/gio/gsocket.c b/gio/gsocket.c index 01792a7fe..2d32396c0 100644 --- a/gio/gsocket.c +++ b/gio/gsocket.c @@ -1216,6 +1216,33 @@ g_socket_get_fd (GSocket *socket) return socket->priv->fd; } +/* If the family is AF_INET6 then this could be a v6-in-v4 which, when + * get_local_address or get_remote_address is called, should never be + * returned as is. No-one wants to have their IPv4 addresses + * represented by IPv6 addresses like ::ffff:172.22.64.188. Therefore, + * let's convert it to a real IPv4 address. */ +static void +g_socket_normalize_address (struct sockaddr_storage *addr) +{ +#if defined (IN6_IS_ADDR_V4MAPPED) + struct sockaddr_in *s4 = (struct sockaddr_in *) addr; + struct sockaddr_in6 *s6 = (struct sockaddr_in6 *) addr; + + if (s6->sin6_family == AF_INET6 && IN6_IS_ADDR_V4MAPPED (&(s6->sin6_addr))) + { + u_int32_t addr_big_endian; + u_int16_t port; + + memcpy (&addr_big_endian, s6->sin6_addr.s6_addr + 12, 4); + port = s6->sin6_port; + + s4->sin_family = AF_INET; + s4->sin_addr.s_addr = addr_big_endian; + s4->sin_port = port; + } +#endif +} + /** * g_socket_get_local_address: * @socket: a #GSocket. @@ -1247,6 +1274,8 @@ g_socket_get_local_address (GSocket *socket, return NULL; } + g_socket_normalize_address (&buffer); + return g_socket_address_new_from_native (&buffer, len); } @@ -1290,6 +1319,8 @@ g_socket_get_remote_address (GSocket *socket, return NULL; } + g_socket_normalize_address (&buffer); + socket->priv->remote_address = g_socket_address_new_from_native (&buffer, len); } |