From c6c11665668c47841011258e5dbca07ad3d8aba0 Mon Sep 17 00:00:00 2001 From: Dan Winship Date: Tue, 19 Feb 2013 15:19:22 -0500 Subject: [PATCH] GNetworkAddress: drop cached addresses on resolver reload If the resolver reloads (ie, if /etc/resolv.conf changes), GNetworkAddress needs to re-resolve its addresses the next time it's enumerated. Otherwise hosts that have different IP addresses inside and outside a VPN won't work correctly if you hold on to a GNetworkAddress for them for a long time. https://bugzilla.gnome.org/show_bug.cgi?id=694181 --- gio/gnetworkaddress.c | 70 +++++++++++++++++++++++++++++++++++------------- gio/gnetworkingprivate.h | 2 ++ gio/gresolver.c | 14 ++++++++++ 3 files changed, 67 insertions(+), 19 deletions(-) diff --git a/gio/gnetworkaddress.c b/gio/gnetworkaddress.c index 1335d94..2e4042c 100644 --- a/gio/gnetworkaddress.c +++ b/gio/gnetworkaddress.c @@ -65,6 +65,8 @@ struct _GNetworkAddressPrivate { guint16 port; GList *sockaddrs; gchar *scheme; + + gint64 resolver_serial; }; enum { @@ -226,7 +228,8 @@ g_network_address_get_property (GObject *object, static void g_network_address_set_addresses (GNetworkAddress *addr, - GList *addresses) + GList *addresses, + guint64 resolver_serial) { GList *a; GSocketAddress *sockaddr; @@ -241,6 +244,8 @@ g_network_address_set_addresses (GNetworkAddress *addr, } g_list_free (addresses); addr->priv->sockaddrs = g_list_reverse (addr->priv->sockaddrs); + + addr->priv->resolver_serial = resolver_serial; } static gboolean @@ -846,26 +851,39 @@ g_network_address_address_enumerator_next (GSocketAddressEnumerator *enumerator if (addr_enum->addresses == NULL) { - if (!addr_enum->addr->priv->sockaddrs) - g_network_address_parse_sockaddr (addr_enum->addr); - if (!addr_enum->addr->priv->sockaddrs) + GNetworkAddress *addr = addr_enum->addr; + GResolver *resolver = g_resolver_get_default (); + gint64 serial = g_resolver_get_serial (resolver); + + if (addr->priv->resolver_serial != 0 && + addr->priv->resolver_serial != serial) + { + /* Resolver has reloaded, discard cached addresses */ + g_list_free_full (addr->priv->sockaddrs, g_object_unref); + addr->priv->sockaddrs = NULL; + } + + if (!addr->priv->sockaddrs) + g_network_address_parse_sockaddr (addr); + if (!addr->priv->sockaddrs) { - GResolver *resolver = g_resolver_get_default (); GList *addresses; addresses = g_resolver_lookup_by_name (resolver, - addr_enum->addr->priv->hostname, + addr->priv->hostname, cancellable, error); - g_object_unref (resolver); - if (!addresses) - return NULL; + { + g_object_unref (resolver); + return NULL; + } - g_network_address_set_addresses (addr_enum->addr, addresses); + g_network_address_set_addresses (addr, addresses, serial); } - addr_enum->addresses = addr_enum->addr->priv->sockaddrs; + addr_enum->addresses = addr->priv->sockaddrs; addr_enum->next = addr_enum->addresses; + g_object_unref (resolver); } if (addr_enum->next == NULL) @@ -916,7 +934,10 @@ got_addresses (GObject *source_object, addresses = g_resolver_lookup_by_name_finish (resolver, result, &error); if (!error) - g_network_address_set_addresses (addr_enum->addr, addresses); + { + g_network_address_set_addresses (addr_enum->addr, addresses, + g_resolver_get_serial (resolver)); + } } have_addresses (addr_enum, task, error); } @@ -936,25 +957,36 @@ g_network_address_address_enumerator_next_async (GSocketAddressEnumerator *enum if (addr_enum->addresses == NULL) { - if (!addr_enum->addr->priv->sockaddrs) + GNetworkAddress *addr = addr_enum->addr; + GResolver *resolver = g_resolver_get_default (); + gint64 serial = g_resolver_get_serial (resolver); + + if (addr->priv->resolver_serial != 0 && + addr->priv->resolver_serial != serial) + { + /* Resolver has reloaded, discard cached addresses */ + g_list_free_full (addr->priv->sockaddrs, g_object_unref); + addr->priv->sockaddrs = NULL; + } + + if (!addr->priv->sockaddrs) { - if (g_network_address_parse_sockaddr (addr_enum->addr)) + if (g_network_address_parse_sockaddr (addr)) have_addresses (addr_enum, task, NULL); else { - GResolver *resolver = g_resolver_get_default (); - g_resolver_lookup_by_name_async (resolver, - addr_enum->addr->priv->hostname, + addr->priv->hostname, cancellable, got_addresses, task); - g_object_unref (resolver); } + g_object_unref (resolver); return; } - addr_enum->addresses = addr_enum->addr->priv->sockaddrs; + addr_enum->addresses = addr->priv->sockaddrs; addr_enum->next = addr_enum->addresses; + g_object_unref (resolver); } if (addr_enum->next) diff --git a/gio/gnetworkingprivate.h b/gio/gnetworkingprivate.h index 1a299c9..4341dc7 100644 --- a/gio/gnetworkingprivate.h +++ b/gio/gnetworkingprivate.h @@ -34,6 +34,8 @@ gchar * _g_uri_from_authority (const gchar *protocol, guint port, const gchar *userinfo); +guint64 g_resolver_get_serial (GResolver *resolver); + gint g_socket (gint domain, gint type, gint protocol, diff --git a/gio/gresolver.c b/gio/gresolver.c index 589e324..5549e4f 100644 --- a/gio/gresolver.c +++ b/gio/gresolver.c @@ -846,6 +846,20 @@ g_resolver_lookup_records_finish (GResolver *resolver, lookup_records_finish (resolver, result, error); } +guint64 +g_resolver_get_serial (GResolver *resolver) +{ + g_return_val_if_fail (G_IS_RESOLVER (resolver), 0); + + g_resolver_maybe_reload (resolver); + +#ifdef G_OS_UNIX + return (guint64) resolver->priv->resolv_conf_timestamp; +#else + return 1; +#endif +} + /** * g_resolver_error_quark: * -- 2.7.4