connectivity: merge branch 'th/connectivity-resolve'

https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/1176
This commit is contained in:
Thomas Haller 2022-04-04 16:10:22 +02:00
commit 721f0e75de
No known key found for this signature in database
GPG key ID: 29C2366E4DFC5728

View file

@ -623,47 +623,73 @@ _timeout_cb(gpointer user_data)
return G_SOURCE_REMOVE;
}
static gboolean
easy_debug_enabled(void)
{
static int enabled = 0;
int e;
/* libcurl debug logging can be useful, but is very verbose.
* Only enable it when we have a certain environment variable set. */
again:
e = g_atomic_int_get(&enabled);
if (G_UNLIKELY(e == 0)) {
e = _nm_utils_ascii_str_to_bool(g_getenv("NM_LOG_CONCHECK"), FALSE) ? 1 : -1;
if (G_UNLIKELY(!g_atomic_int_compare_and_exchange(&enabled, 0, e)))
goto again;
}
return e >= 0;
}
static int
easy_debug_cb(CURL *handle, curl_infotype type, char *data, size_t size, void *userptr)
{
NMConnectivityCheckHandle *cb_data = userptr;
const char *escaped = NULL;
gs_free char *to_free = NULL;
NMConnectivityCheckHandle *cb_data = userptr;
gs_free char *data_escaped = NULL;
const char *msg;
gboolean print_data = FALSE;
switch (type) {
case CURLINFO_TEXT:
escaped = nm_utils_buf_utf8safe_escape((char *) data,
size,
NM_UTILS_STR_UTF8_SAFE_FLAG_ESCAPE_CTRL,
&to_free);
_LOG2T("libcurl: == Info: %s", escaped ?: "");
/* fall-through */
default: /* in case a new one is introduced to shock us */
return 0;
print_data = TRUE;
msg = "== Info: ";
break;
case CURLINFO_DATA_OUT:
_LOG2T("libcurl => Send data");
return 0;
msg = "=> Send data";
break;
case CURLINFO_SSL_DATA_OUT:
_LOG2T("libcurl => Send SSL data");
return 0;
msg = "=> Send SSL data";
break;
case CURLINFO_HEADER_IN:
_LOG2T("libcurl <= Recv header");
return 0;
msg = "<= Recv header";
break;
case CURLINFO_DATA_IN:
_LOG2T("libcurl <= Recv data");
return 0;
msg = "<= Recv data";
break;
case CURLINFO_SSL_DATA_IN:
_LOG2T("libcurl <= Recv SSL data");
return 0;
msg = "<= Recv SSL data";
break;
case CURLINFO_HEADER_OUT:
escaped = nm_utils_buf_utf8safe_escape((char *) data,
size,
NM_UTILS_STR_UTF8_SAFE_FLAG_ESCAPE_CTRL,
&to_free);
_LOG2T("libcurl => Send header: %s", escaped ?: "");
print_data = TRUE;
msg = "=> Send header: ";
return 0;
default:
return 0;
}
_LOG2T("libcurl %s%s%s%s",
msg,
NM_PRINT_FMT_QUOTED(print_data,
"[",
(data_escaped = nm_utils_buf_utf8safe_escape_cp(
data,
size,
NM_UTILS_STR_UTF8_SAFE_FLAG_ESCAPE_CTRL))
?: "",
"]",
""));
return 0;
}
#endif
@ -684,12 +710,14 @@ _idle_cb(gpointer user_data)
#if WITH_CONCHECK
static void
do_curl_request(NMConnectivityCheckHandle *cb_data)
do_curl_request(NMConnectivityCheckHandle *cb_data, const char *hosts)
{
CURLM *mhandle;
CURL *ehandle;
long resolve;
_LOG2T("set curl resolve list to '%s'", hosts);
mhandle = curl_multi_init();
if (!mhandle) {
cb_data_complete(cb_data, NM_CONNECTIVITY_ERROR, "curl error");
@ -703,6 +731,8 @@ do_curl_request(NMConnectivityCheckHandle *cb_data)
return;
}
cb_data->concheck.hosts = curl_slist_append(NULL, hosts);
cb_data->concheck.curl_mhandle = mhandle;
cb_data->concheck.curl_ehandle = ehandle;
cb_data->concheck.request_headers = curl_slist_append(NULL, "Connection: close");
@ -739,7 +769,7 @@ do_curl_request(NMConnectivityCheckHandle *cb_data)
curl_easy_setopt(ehandle, CURLOPT_RESOLVE, cb_data->concheck.hosts);
curl_easy_setopt(ehandle, CURLOPT_IPRESOLVE, resolve);
curl_easy_setopt(ehandle, CURLOPT_PROTOCOLS, CURLPROTO_HTTP | CURLPROTO_HTTPS);
if (_LOGT_ENABLED()) {
if (_LOGT_ENABLED() && easy_debug_enabled()) {
curl_easy_setopt(ehandle, CURLOPT_DEBUGFUNCTION, easy_debug_cb);
curl_easy_setopt(ehandle, CURLOPT_DEBUGDATA, cb_data);
curl_easy_setopt(ehandle, CURLOPT_VERBOSE, 1L);
@ -749,7 +779,93 @@ do_curl_request(NMConnectivityCheckHandle *cb_data)
}
static void
resolve_cb(GObject *object, GAsyncResult *res, gpointer user_data)
system_resolver_resolve_cb(GObject *source_object, GAsyncResult *res, gpointer user_data)
{
nm_auto_str_buf NMStrBuf strbuf_hosts = NM_STR_BUF_INIT(0, FALSE);
gs_free_error GError *resolv_error = NULL;
GList *list;
GList *iter;
NMConnectivityCheckHandle *cb_data;
list = g_resolver_lookup_by_name_finish(G_RESOLVER(source_object), res, &resolv_error);
if (nm_utils_error_is_cancelled(resolv_error))
return;
cb_data = user_data;
nm_assert(cb_data);
nm_assert(NM_IS_CONNECTIVITY(cb_data->self));
if (resolv_error) {
_LOG2D("failure to resolve name: %s", resolv_error->message);
cb_data_complete(cb_data, NM_CONNECTIVITY_LIMITED, "resolve-error");
return;
}
for (iter = list; iter; iter = iter->next) {
GInetAddress *a = iter->data;
char str_addr[NM_UTILS_INET_ADDRSTRLEN];
int addr_family;
switch (g_inet_address_get_family(a)) {
case G_SOCKET_FAMILY_IPV4:
addr_family = AF_INET;
break;
case G_SOCKET_FAMILY_IPV6:
addr_family = AF_INET6;
break;
default:
addr_family = AF_UNSPEC;
break;
}
if (cb_data->addr_family != AF_UNSPEC && cb_data->addr_family != addr_family)
continue;
if (strbuf_hosts.len == 0) {
nm_str_buf_append_printf(&strbuf_hosts,
"%s:%s:",
cb_data->concheck.con_config->host,
cb_data->concheck.con_config->port ?: "80");
} else
nm_str_buf_append_c(&strbuf_hosts, ',');
nm_str_buf_append(&strbuf_hosts,
nm_utils_inet_ntop(addr_family, g_inet_address_to_bytes(a), str_addr));
}
g_list_free_full(list, g_object_unref);
if (strbuf_hosts.len == 0) {
_LOG2D("system resolver returned no usable IPv%c addresses",
nm_utils_addr_family_to_char(cb_data->addr_family));
cb_data_complete(cb_data, NM_CONNECTIVITY_LIMITED, "resolve-error");
return;
}
do_curl_request(cb_data, nm_str_buf_get_str(&strbuf_hosts));
}
static void
system_resolver_resolve(NMConnectivityCheckHandle *cb_data)
{
gs_unref_object GResolver *resolver = NULL;
_LOG2D("start request to '%s' (try resolving '%s' using system resolver)",
cb_data->concheck.con_config->uri,
cb_data->concheck.con_config->host);
resolver = g_resolver_get_default();
g_resolver_lookup_by_name_async(resolver,
cb_data->concheck.con_config->host,
cb_data->concheck.resolve_cancellable,
system_resolver_resolve_cb,
cb_data);
}
static void
systemd_resolved_resolve_cb(GObject *object, GAsyncResult *res, gpointer user_data)
{
NMConnectivityCheckHandle *cb_data;
gs_unref_variant GVariant *result = NULL;
@ -763,7 +879,7 @@ resolve_cb(GObject *object, GAsyncResult *res, gpointer user_data)
nm_auto_str_buf NMStrBuf strbuf_hosts = NM_STR_BUF_INIT(0, FALSE);
result = g_dbus_connection_call_finish(G_DBUS_CONNECTION(object), res, &error);
if (g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
if (nm_utils_error_is_cancelled(error))
return;
cb_data = user_data;
@ -771,9 +887,9 @@ resolve_cb(GObject *object, GAsyncResult *res, gpointer user_data)
g_clear_object(&cb_data->concheck.resolve_cancellable);
if (!result) {
/* Never mind. Just let do curl do its own resolving. */
/* Never mind. Fallback to the system resolver. */
_LOG2D("can't resolve a name via systemd-resolved: %s", error->message);
do_curl_request(cb_data);
system_resolver_resolve(cb_data);
return;
}
@ -807,14 +923,14 @@ resolve_cb(GObject *object, GAsyncResult *res, gpointer user_data)
nm_str_buf_append(&strbuf_hosts, nm_utils_inet_ntop(addr_family, address_buf, str_addr));
}
if (strbuf_hosts.len > 0) {
const char *s = nm_str_buf_get_str(&strbuf_hosts);
cb_data->concheck.hosts = curl_slist_append(NULL, s);
_LOG2T("set curl resolve list to '%s'", s);
if (strbuf_hosts.len == 0) {
_LOG2D("systemd-resolve returned no usable IPv%c addresses",
nm_utils_addr_family_to_char(cb_data->addr_family));
cb_data_complete(cb_data, NM_CONNECTIVITY_LIMITED, "resolve-error");
return;
}
do_curl_request(cb_data);
do_curl_request(cb_data, nm_str_buf_get_str(&strbuf_hosts));
}
#endif
@ -940,6 +1056,8 @@ nm_connectivity_check_start(NMConnectivity *self,
}
}
cb_data->concheck.resolve_cancellable = g_cancellable_new();
/* note that we pick up support for systemd-resolved right away when we need it.
* We don't need to remember the setting, because we can (cheaply) check anew
* on each request.
@ -975,8 +1093,6 @@ nm_connectivity_check_start(NMConnectivity *self,
return cb_data;
}
cb_data->concheck.resolve_cancellable = g_cancellable_new();
g_dbus_connection_call(dbus_connection,
"org.freedesktop.resolve1",
"/org/freedesktop/resolve1",
@ -991,17 +1107,15 @@ nm_connectivity_check_start(NMConnectivity *self,
G_DBUS_CALL_FLAGS_NONE,
-1,
cb_data->concheck.resolve_cancellable,
resolve_cb,
systemd_resolved_resolve_cb,
cb_data);
_LOG2D("start request to '%s' (try resolving '%s' using systemd-resolved)",
cb_data->concheck.con_config->uri,
cb_data->concheck.con_config->host);
} else {
_LOG2D("start request to '%s' (systemd-resolved not available)",
cb_data->concheck.con_config->uri);
do_curl_request(cb_data);
return cb_data;
}
system_resolver_resolve(cb_data);
return cb_data;
}
#endif