mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2024-12-26 15:36:14 +01:00
ea99872e45
This always resolves "localhost" to a loopback address which
has security benefits such as preventing a malicious dns server
redirecting local connections and allows software to assume
it is a secure hostname.
This is being adopted by web browsers:
- https://w3c.github.io/webappsec-secure-contexts/
- https://groups.google.com/a/chromium.org/forum/#!msg/blink-dev/RC9dSw-O3fE/E3_0XaT0BAAJ
- 8da2a80724
- https://bugs.webkit.org/show_bug.cgi?id=171934
- https://tools.ietf.org/html/draft-west-let-localhost-be-localhost-06
193 lines
5.8 KiB
C
193 lines
5.8 KiB
C
/* GIO - GLib Input, Output and Streaming Library
|
|
*
|
|
* Copyright (C) 2018 Igalia S.L.
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General
|
|
* Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include "mock-resolver.h"
|
|
|
|
struct _MockResolver
|
|
{
|
|
GResolver parent_instance;
|
|
guint ipv4_delay_ms;
|
|
guint ipv6_delay_ms;
|
|
GList *ipv4_results;
|
|
GList *ipv6_results;
|
|
GError *ipv4_error;
|
|
GError *ipv6_error;
|
|
};
|
|
|
|
G_DEFINE_TYPE (MockResolver, mock_resolver, G_TYPE_RESOLVER)
|
|
|
|
MockResolver *
|
|
mock_resolver_new (void)
|
|
{
|
|
return g_object_new (MOCK_TYPE_RESOLVER, NULL);
|
|
}
|
|
|
|
void
|
|
mock_resolver_set_ipv4_delay_ms (MockResolver *self, guint delay_ms)
|
|
{
|
|
self->ipv4_delay_ms = delay_ms;
|
|
}
|
|
|
|
static gpointer
|
|
copy_object (gconstpointer obj, gpointer user_data)
|
|
{
|
|
return g_object_ref (G_OBJECT (obj));
|
|
}
|
|
|
|
void
|
|
mock_resolver_set_ipv4_results (MockResolver *self, GList *results)
|
|
{
|
|
if (self->ipv4_results)
|
|
g_list_free_full (self->ipv4_results, g_object_unref);
|
|
self->ipv4_results = g_list_copy_deep (results, copy_object, NULL);
|
|
}
|
|
|
|
void
|
|
mock_resolver_set_ipv4_error (MockResolver *self, GError *error)
|
|
{
|
|
g_clear_error (&self->ipv4_error);
|
|
if (error)
|
|
self->ipv4_error = g_error_copy (error);
|
|
}
|
|
|
|
void
|
|
mock_resolver_set_ipv6_delay_ms (MockResolver *self, guint delay_ms)
|
|
{
|
|
self->ipv6_delay_ms = delay_ms;
|
|
}
|
|
|
|
void
|
|
mock_resolver_set_ipv6_results (MockResolver *self, GList *results)
|
|
{
|
|
if (self->ipv6_results)
|
|
g_list_free_full (self->ipv6_results, g_object_unref);
|
|
self->ipv6_results = g_list_copy_deep (results, copy_object, NULL);
|
|
}
|
|
|
|
void
|
|
mock_resolver_set_ipv6_error (MockResolver *self, GError *error)
|
|
{
|
|
g_clear_error (&self->ipv6_error);
|
|
if (error)
|
|
self->ipv6_error = g_error_copy (error);
|
|
}
|
|
|
|
static void
|
|
do_lookup_by_name (GTask *task,
|
|
gpointer source_object,
|
|
gpointer task_data,
|
|
GCancellable *cancellable)
|
|
{
|
|
MockResolver *self = source_object;
|
|
GResolverNameLookupFlags flags = GPOINTER_TO_UINT(task_data);
|
|
|
|
if (flags == G_RESOLVER_NAME_LOOKUP_FLAGS_IPV4_ONLY)
|
|
{
|
|
g_usleep (self->ipv4_delay_ms * 1000);
|
|
if (self->ipv4_error)
|
|
g_task_return_error (task, g_error_copy (self->ipv4_error));
|
|
else
|
|
g_task_return_pointer (task, g_list_copy_deep (self->ipv4_results, copy_object, NULL), NULL);
|
|
}
|
|
else if (flags == G_RESOLVER_NAME_LOOKUP_FLAGS_IPV6_ONLY)
|
|
{
|
|
g_usleep (self->ipv6_delay_ms * 1000);
|
|
if (self->ipv6_error)
|
|
g_task_return_error (task, g_error_copy (self->ipv6_error));
|
|
else
|
|
g_task_return_pointer (task, g_list_copy_deep (self->ipv6_results, copy_object, NULL), NULL);
|
|
}
|
|
else if (flags == G_RESOLVER_NAME_LOOKUP_FLAGS_DEFAULT)
|
|
{
|
|
/* This is only the minimal implementation needed for some tests */
|
|
g_assert (self->ipv4_error == NULL && self->ipv6_error == NULL && self->ipv6_results == NULL);
|
|
g_task_return_pointer (task, g_list_copy_deep (self->ipv4_results, copy_object, NULL), NULL);
|
|
}
|
|
else
|
|
g_assert_not_reached ();
|
|
}
|
|
|
|
static void
|
|
lookup_by_name_with_flags_async (GResolver *resolver,
|
|
const gchar *hostname,
|
|
GResolverNameLookupFlags flags,
|
|
GCancellable *cancellable,
|
|
GAsyncReadyCallback callback,
|
|
gpointer user_data)
|
|
{
|
|
GTask *task = g_task_new (resolver, cancellable, callback, user_data);
|
|
g_task_set_task_data (task, GUINT_TO_POINTER(flags), NULL);
|
|
g_task_run_in_thread (task, do_lookup_by_name);
|
|
g_object_unref (task);
|
|
}
|
|
|
|
static GList *
|
|
lookup_by_name (GResolver *resolver,
|
|
const gchar *hostname,
|
|
GCancellable *cancellable,
|
|
GError **error)
|
|
{
|
|
GList *result = NULL;
|
|
GTask *task = g_task_new (resolver, cancellable, NULL, NULL);
|
|
g_task_set_task_data (task, GUINT_TO_POINTER (G_RESOLVER_NAME_LOOKUP_FLAGS_DEFAULT), NULL);
|
|
g_task_run_in_thread_sync (task, do_lookup_by_name);
|
|
result = g_task_propagate_pointer (task, error);
|
|
g_object_unref (task);
|
|
return result;
|
|
}
|
|
|
|
|
|
static GList *
|
|
lookup_by_name_with_flags_finish (GResolver *resolver,
|
|
GAsyncResult *result,
|
|
GError **error)
|
|
{
|
|
return g_task_propagate_pointer (G_TASK (result), error);
|
|
}
|
|
|
|
static void
|
|
mock_resolver_finalize (GObject *object)
|
|
{
|
|
MockResolver *self = (MockResolver*)object;
|
|
|
|
g_clear_error (&self->ipv4_error);
|
|
g_clear_error (&self->ipv6_error);
|
|
if (self->ipv6_results)
|
|
g_list_free_full (self->ipv6_results, g_object_unref);
|
|
if (self->ipv4_results)
|
|
g_list_free_full (self->ipv4_results, g_object_unref);
|
|
|
|
G_OBJECT_CLASS (mock_resolver_parent_class)->finalize (object);
|
|
}
|
|
|
|
static void
|
|
mock_resolver_class_init (MockResolverClass *klass)
|
|
{
|
|
GResolverClass *resolver_class = G_RESOLVER_CLASS (klass);
|
|
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
|
resolver_class->lookup_by_name_with_flags_async = lookup_by_name_with_flags_async;
|
|
resolver_class->lookup_by_name_with_flags_finish = lookup_by_name_with_flags_finish;
|
|
resolver_class->lookup_by_name = lookup_by_name;
|
|
object_class->finalize = mock_resolver_finalize;
|
|
}
|
|
|
|
static void
|
|
mock_resolver_init (MockResolver *self)
|
|
{
|
|
}
|