From 0926f3489dbc93a2e91ec8607a0ceb5d4d8a53e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Fri, 21 Jul 2017 07:51:07 -0400 Subject: [PATCH 1/3] resolved: make sure idn2 conversions are roundtrippable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit While working on the gateway→_gateway conversion, I noticed that libidn2 strips the leading underscore in some names. https://gitlab.com/libidn/libidn2/issues/30 was resolved in https://gitlab.com/libidn/libidn2/commit/05d753ea69e2308cd02436d0511f4b844071dc79, which disabled "STD3 ASCII rules" by default, i.e. disabled stripping of underscores. So the situation is that with previously released libidn2 versions we would get incorrect behaviour, and once new libidn2 is released, we should be OK. Let's implement a simple test which checks that the name survives the roundtrip, and if it doesn't, skip IDN resolution. Under old libidn2 this will fail in more cases, and under new libidn2 in fewer, but should be the right thing to do also under new libidn2. --- src/shared/dns-domain.c | 29 ++++++++++++++++++++++++++--- src/test/test-dns-domain.c | 6 ++++++ 2 files changed, 32 insertions(+), 3 deletions(-) diff --git a/src/shared/dns-domain.c b/src/shared/dns-domain.c index 12c4d65dd3..139d286af8 100644 --- a/src/shared/dns-domain.c +++ b/src/shared/dns-domain.c @@ -1274,15 +1274,38 @@ int dns_name_apply_idna(const char *name, char **ret) { #if defined(HAVE_LIBIDN2) int r; + _cleanup_free_ char *t = NULL; assert(name); assert(ret); - r = idn2_lookup_u8((uint8_t*) name, (uint8_t**) ret, + r = idn2_lookup_u8((uint8_t*) name, (uint8_t**) &t, IDN2_NFC_INPUT | IDN2_NONTRANSITIONAL); - if (r == IDN2_OK) + log_debug("idn2_lookup_u8: %s → %s", name, t); + if (r == IDN2_OK) { + if (!startswith(name, "xn--")) { + _cleanup_free_ char *s = NULL; + + r = idn2_to_unicode_8z8z(t, &s, 0); + if (r != IDN2_OK) { + log_debug("idn2_to_unicode_8z8z(\"%s\") failed: %d/%s", + t, r, idn2_strerror(r)); + return 0; + } + + if (!streq_ptr(name, s)) { + log_debug("idn2 roundtrip failed: \"%s\" → \"%s\" → \"%s\", ignoring.", + name, t, s); + return 0; + } + } + + *ret = t; + t = NULL; return 1; /* *ret has been written */ - log_debug("idn2_lookup_u8(\"%s\") failed: %s", name, idn2_strerror(r)); + } + + log_debug("idn2_lookup_u8(\"%s\") failed: %d/%s", name, r, idn2_strerror(r)); if (r == IDN2_2HYPHEN) /* The name has two hypens — forbidden by IDNA2008 in some cases */ return 0; diff --git a/src/test/test-dns-domain.c b/src/test/test-dns-domain.c index 11cf0b1f0b..cbd2d1e656 100644 --- a/src/test/test-dns-domain.c +++ b/src/test/test-dns-domain.c @@ -652,6 +652,12 @@ static void test_dns_name_apply_idna(void) { test_dns_name_apply_idna_one("föö.bär.", ret, "xn--f-1gaa.xn--br-via"); test_dns_name_apply_idna_one("xn--f-1gaa.xn--br-via", ret, "xn--f-1gaa.xn--br-via"); + test_dns_name_apply_idna_one("_443._tcp.fedoraproject.org", ret2, + "_443._tcp.fedoraproject.org"); + test_dns_name_apply_idna_one("_443", ret2, "_443"); + test_dns_name_apply_idna_one("gateway", ret, "gateway"); + test_dns_name_apply_idna_one("_gateway", ret2, "_gateway"); + test_dns_name_apply_idna_one("r3---sn-ab5l6ne7.googlevideo.com", ret2, ret2 ? "r3---sn-ab5l6ne7.googlevideo.com" : ""); } From 5248e7e1f11aba6859de0b28f0dd3778b22842f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Tue, 11 Jul 2017 02:15:08 -0400 Subject: [PATCH 2/3] resolved,nss-myhostname: use _gateway for the gateway MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This changes the symbolic name for the default gateway from "gateway" to "_gateway". A new configuration option -Dcompat-gateway-hostname=true|false is added. If it is set, the old name is also supported, but the new name is used as the canonical name in either case. This is intended as a temporary measure to make the transition easier, and the option should be removed after a few releases, at which point only the new name will be used. The old "gateway" name mostly works OK, but hasn't gained widespread acceptance because of the following (potential) conflicts: - it is completely legal to have a host called "gateway" - there is no guarantee that "gateway" will not be registered as a TLD, even though this currently seems unlikely. (Even then, there would be no conflict except for the case when the top-level domain itself was being resolved. The "gateway" or "_gateway" labels have only special meaning when the whole name consists of a single label, so resolution of any subdomain of the hypothetical gateway. TLD would still work OK. ) Moving to "_gateway" avoids those issues because underscores are not allowed in host names (RFC 1123, §2.1) and avoids potential conflicts with local or global names. v2: - simplify the logic to hardcode "_gateway" and allow -Dcompat-gateway-hostname=true as a temporary measure. --- meson.build | 3 +++ meson_options.txt | 2 ++ src/basic/hostname-util.c | 7 +++++-- src/nss-myhostname/nss-myhostname.c | 6 +++--- src/resolve/resolved-dns-synthesize.c | 2 +- src/test/test-nss.c | 2 +- 6 files changed, 15 insertions(+), 7 deletions(-) diff --git a/meson.build b/meson.build index ba8bb81856..2be88c5ea1 100644 --- a/meson.build +++ b/meson.build @@ -537,6 +537,8 @@ endforeach ############################################################ conf.set_quoted('FALLBACK_HOSTNAME', get_option('fallback-hostname')) +conf.set10('ENABLE_COMPAT_GATEWAY_HOSTNAME', get_option('compat-gateway-hostname')) +gateway_hostnames = ['_gateway'] + (conf.get('ENABLE_COMPAT_GATEWAY_HOSTNAME') == 1 ? ['gateway'] : []) default_hierarchy = get_option('default-hierarchy') conf.set_quoted('DEFAULT_HIERARCHY_NAME', default_hierarchy, @@ -2399,6 +2401,7 @@ status = [ 'nobody user name: @0@'.format(get_option('nobody-user')), 'nobody group name: @0@'.format(get_option('nobody-group')), 'fallback hostname: @0@'.format(get_option('fallback-hostname')), + 'symbolic gateway hostnames: @0@'.format(', '.join(gateway_hostnames)), 'default DNSSEC mode: @0@'.format(default_dnssec), 'default cgroup hierarchy: @0@'.format(default_hierarchy), diff --git a/meson_options.txt b/meson_options.txt index 0cd8fb02e7..a2de6aba3a 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -120,6 +120,8 @@ option('pamconfdir', type : 'string', option('fallback-hostname', type : 'string', value : 'localhost', description : 'the hostname used if none configured') +option('compat-gateway-hostname', type : 'boolean', value : 'false', + description : 'allow "gateway" as the symbolic name for default gateway') option('default-hierarchy', type : 'combo', choices : ['legacy', 'hybrid', 'unified'], value : 'hybrid', description : 'default cgroup hierarchy') diff --git a/src/basic/hostname-util.c b/src/basic/hostname-util.c index a94037b303..b511a36301 100644 --- a/src/basic/hostname-util.c +++ b/src/basic/hostname-util.c @@ -196,8 +196,11 @@ bool is_gateway_hostname(const char *hostname) { * synthetic "gateway" host. */ return - strcaseeq(hostname, "gateway") || - strcaseeq(hostname, "gateway."); + strcaseeq(hostname, "_gateway") || strcaseeq(hostname, "_gateway.") +#if ENABLE_COMPAT_GATEWAY_HOSTNAME + || strcaseeq(hostname, "gateway") || strcaseeq(hostname, "gateway.") +#endif + ; } int sethostname_idempotent(const char *s) { diff --git a/src/nss-myhostname/nss-myhostname.c b/src/nss-myhostname/nss-myhostname.c index 0570fde592..9ebdbb7cf3 100644 --- a/src/nss-myhostname/nss-myhostname.c +++ b/src/nss-myhostname/nss-myhostname.c @@ -86,7 +86,7 @@ enum nss_status _nss_myhostname_gethostbyname4_r( return NSS_STATUS_NOTFOUND; } - canonical = "gateway"; + canonical = "_gateway"; } else { hn = gethostname_malloc(); @@ -356,7 +356,7 @@ enum nss_status _nss_myhostname_gethostbyname3_r( return NSS_STATUS_NOTFOUND; } - canonical = "gateway"; + canonical = "_gateway"; } else { hn = gethostname_malloc(); @@ -467,7 +467,7 @@ enum nss_status _nss_myhostname_gethostbyaddr2_r( continue; if (memcmp(addr, &a->address, FAMILY_ADDRESS_SIZE(af)) == 0) { - canonical = "gateway"; + canonical = "_gateway"; goto found; } } diff --git a/src/resolve/resolved-dns-synthesize.c b/src/resolve/resolved-dns-synthesize.c index e3003411f7..c454f64049 100644 --- a/src/resolve/resolved-dns-synthesize.c +++ b/src/resolve/resolved-dns-synthesize.c @@ -334,7 +334,7 @@ static int synthesize_gateway_ptr(Manager *m, int af, const union in_addr_union if (n < 0) return n; - return answer_add_addresses_ptr(answer, "gateway", addresses, n, af, address); + return answer_add_addresses_ptr(answer, "_gateway", addresses, n, af, address); } int dns_synthesize_answer( diff --git a/src/test/test-nss.c b/src/test/test-nss.c index 57eeb8e40c..44570caa6c 100644 --- a/src/test/test-nss.c +++ b/src/test/test-nss.c @@ -491,7 +491,7 @@ static int parse_argv(int argc, char **argv, if (!hostname) return -ENOMEM; - names = strv_new("localhost", "gateway", "foo_no_such_host", hostname, NULL); + names = strv_new("localhost", "_gateway", "foo_no_such_host", hostname, NULL); if (!names) return -ENOMEM; From d5da77077d9a9727d42e1d1a77d1db52c258c207 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Tue, 11 Jul 2017 08:50:56 -0400 Subject: [PATCH 3/3] resolved: add debug message about stub listener --- src/resolve/resolved-dns-stub.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/resolve/resolved-dns-stub.c b/src/resolve/resolved-dns-stub.c index 7afbfedfb0..6f7b5ab9e8 100644 --- a/src/resolve/resolved-dns-stub.c +++ b/src/resolve/resolved-dns-stub.c @@ -543,6 +543,14 @@ int manager_dns_stub_start(Manager *m) { assert(m); + if (m->dns_stub_listener_mode == DNS_STUB_LISTENER_NO) + log_debug("Not creating stub listener."); + else + log_debug("Creating stub listener using %s.", + m->dns_stub_listener_mode == DNS_STUB_LISTENER_UDP ? "UDP" : + m->dns_stub_listener_mode == DNS_STUB_LISTENER_TCP ? "TCP" : + "UDP/TCP"); + if (IN_SET(m->dns_stub_listener_mode, DNS_STUB_LISTENER_YES, DNS_STUB_LISTENER_UDP)) r = manager_dns_stub_udp_fd(m);