Unify address parsing for GInetAddress and GInetSocketAddress

This allows scope-ids to work for GInetAddress
This commit is contained in:
Patrick Griffis
2025-07-03 16:51:55 -05:00
parent ed8bae5483
commit b40194865a
3 changed files with 54 additions and 58 deletions

View File

@@ -435,9 +435,6 @@ GInetAddress *
g_inet_address_new_from_string (const gchar *string)
{
struct in_addr in_addr;
#ifdef HAVE_IPV6
struct in6_addr in6_addr;
#endif
g_return_val_if_fail (string != NULL, NULL);
@@ -447,13 +444,54 @@ g_inet_address_new_from_string (const gchar *string)
*/
g_networking_init ();
if (inet_pton (AF_INET, string, &in_addr) > 0)
return g_inet_address_new_from_bytes ((guint8 *)&in_addr, AF_INET);
#ifdef HAVE_IPV6
else if (inet_pton (AF_INET6, string, &in6_addr) > 0)
return g_inet_address_new_from_bytes ((guint8 *)&in6_addr, AF_INET6);
/* IPv6 address (or it's invalid). We use getaddrinfo() because
* it will handle parsing a scope_id as well.
*/
if (strchr (string, ':'))
{
struct addrinfo *res;
struct addrinfo hints = {
.ai_family = AF_INET6,
.ai_socktype = SOCK_STREAM,
.ai_flags = AI_NUMERICHOST,
};
int status;
GInetAddress *address = NULL;
status = getaddrinfo (string, NULL, &hints, &res);
if (status == 0)
{
g_assert (res->ai_addrlen == sizeof (struct sockaddr_in6));
struct sockaddr_in6 *sockaddr6 = (struct sockaddr_in6 *)res->ai_addr;
address = g_inet_address_new_from_bytes_with_ipv6_info (((guint8 *)&sockaddr6->sin6_addr),
G_SOCKET_FAMILY_IPV6,
sockaddr6->sin6_flowinfo,
sockaddr6->sin6_scope_id);
freeaddrinfo (res);
}
else
{
struct in6_addr in6_addr;
g_debug ("getaddrinfo failed to resolve host string %s", string);
if (inet_pton (AF_INET6, string, &in6_addr) > 0)
address = g_inet_address_new_from_bytes ((guint8 *)&in6_addr, G_SOCKET_FAMILY_IPV6);
}
return address;
}
#endif
/* IPv4 (or invalid). We don't want to use getaddrinfo() here,
* because it accepts the stupid "IPv4 numbers-and-dots
* notation" addresses that are never used for anything except
* phishing. Since we don't have to worry about scope IDs for
* IPv4, we can just use inet_pton().
*/
if (inet_pton (AF_INET, string, &in_addr) > 0)
return g_inet_address_new_from_bytes ((guint8 *)&in_addr, G_SOCKET_FAMILY_IPV4);
return NULL;
}

View File

@@ -413,60 +413,16 @@ GSocketAddress *
g_inet_socket_address_new_from_string (const char *address,
guint port)
{
static struct addrinfo *hints, hints_struct;
GSocketAddress *saddr;
GInetAddress *iaddr;
struct addrinfo *res;
gint status;
if (strchr (address, ':'))
{
/* IPv6 address (or it's invalid). We use getaddrinfo() because
* it will handle parsing a scope_id as well.
*/
iaddr = g_inet_address_new_from_string (address);
if (!iaddr)
return NULL;
if (G_UNLIKELY (g_once_init_enter_pointer (&hints)))
{
hints_struct.ai_family = AF_UNSPEC;
hints_struct.ai_socktype = SOCK_STREAM;
hints_struct.ai_protocol = 0;
hints_struct.ai_flags = AI_NUMERICHOST;
g_once_init_leave_pointer (&hints, &hints_struct);
}
status = getaddrinfo (address, NULL, hints, &res);
if (status != 0)
return NULL;
if (res->ai_family == AF_INET6 &&
res->ai_addrlen == sizeof (struct sockaddr_in6))
{
((struct sockaddr_in6 *)res->ai_addr)->sin6_port = g_htons (port);
saddr = g_socket_address_new_from_native (res->ai_addr, res->ai_addrlen);
}
else
saddr = NULL;
freeaddrinfo (res);
}
else
{
/* IPv4 (or invalid). We don't want to use getaddrinfo() here,
* because it accepts the stupid "IPv4 numbers-and-dots
* notation" addresses that are never used for anything except
* phishing. Since we don't have to worry about scope IDs for
* IPv4, we can just use g_inet_address_new_from_string().
*/
iaddr = g_inet_address_new_from_string (address);
if (!iaddr)
return NULL;
g_warn_if_fail (g_inet_address_get_family (iaddr) == G_SOCKET_FAMILY_IPV4);
saddr = g_inet_socket_address_new (iaddr, port);
g_object_unref (iaddr);
}
saddr = g_inet_socket_address_new (iaddr, port);
g_object_unref (iaddr);
return saddr;
}

View File

@@ -53,6 +53,9 @@ test_parse (void)
addr = g_inet_address_new_from_string ("204.152.189.116");
g_assert (addr != NULL);
g_object_unref (addr);
addr = g_inet_address_new_from_string ("::1%0");
g_assert (addr != NULL);
g_object_unref (addr);
addr = g_inet_address_new_from_string ("::1::2");
g_assert (addr == NULL);
@@ -206,12 +209,11 @@ test_socket_address (void)
g_object_unref (saddr);
addr = g_inet_address_new_from_string ("::1");
addr = g_inet_address_new_from_string ("::1%25");
saddr = G_INET_SOCKET_ADDRESS (g_object_new (G_TYPE_INET_SOCKET_ADDRESS,
"address", addr,
"port", 308,
"flowinfo", 10,
"scope-id", 25,
NULL));
g_object_unref (addr);