1
0
mirror of https://github.com/systemd/systemd synced 2025-12-27 11:24:46 +01:00

Compare commits

...

4 Commits

Author SHA1 Message Date
Zbigniew Jędrzejewski-Szmek
092f5d2ed3
Merge pull request #17292 from poettering/idn-dlsym
turn libidn/libidn2 dep into dlopen() one
2020-10-10 16:25:49 +02:00
Lennart Poettering
c36d5b5be9 resolved: don't append RFC6975 data to stub replies
We previously checked the QR bit to decide whether the RFC6975 algorithm
data in our packets. But that doesn't work in many cases, since we
initialize the QR flags along with the other flags usually only after
appending OPT (since success to do so propagates into flags). Hence,
let's add an explicit parameter that controls whether to include RFC6975
data in DNS packets, and set it to false for stub reply, and on true for
upstream queries.

Fixes: #17217
2020-10-10 16:22:22 +02:00
Lennart Poettering
a60a05c715 update TODO 2020-10-09 15:47:09 +02:00
Lennart Poettering
4917e7c727 shared: make libidn/libdidn2 dependency a dlopen() one 2020-10-09 15:47:09 +02:00
11 changed files with 208 additions and 53 deletions

1
TODO
View File

@ -110,7 +110,6 @@ Features:
* make us use dynamically fewer deps for containers in general purpose distros: * make us use dynamically fewer deps for containers in general purpose distros:
o turn into dlopen() deps: o turn into dlopen() deps:
- libidn2 (always)
- elfutils (always) - elfutils (always)
- p11-kit-trust (always) - p11-kit-trust (always)
- kmod-libs (only when called from PID 1) - kmod-libs (only when called from PID 1)

View File

@ -142,7 +142,7 @@ libsystemd_resolve_core = static_library(
systemd_resolved_sources += [resolved_gperf_c, resolved_dnssd_gperf_c] systemd_resolved_sources += [resolved_gperf_c, resolved_dnssd_gperf_c]
systemd_resolved_dependencies = [threads, libgpg_error, libm, libidn] systemd_resolved_dependencies = [threads, libgpg_error, libm]
if conf.get('ENABLE_DNS_OVER_TLS') == 1 if conf.get('ENABLE_DNS_OVER_TLS') == 1
if conf.get('DNS_OVER_TLS_USE_GNUTLS') == 1 if conf.get('DNS_OVER_TLS_USE_GNUTLS') == 1
systemd_resolved_sources += files('resolved-dnstls-gnutls.c', systemd_resolved_sources += files('resolved-dnstls-gnutls.c',

View File

@ -689,7 +689,14 @@ fail:
} }
/* Append the OPT pseudo-RR described in RFC6891 */ /* Append the OPT pseudo-RR described in RFC6891 */
int dns_packet_append_opt(DnsPacket *p, uint16_t max_udp_size, bool edns0_do, int rcode, size_t *start) { int dns_packet_append_opt(
DnsPacket *p,
uint16_t max_udp_size,
bool edns0_do,
bool include_rfc6975,
int rcode,
size_t *start) {
size_t saved_size; size_t saved_size;
int r; int r;
@ -732,8 +739,10 @@ int dns_packet_append_opt(DnsPacket *p, uint16_t max_udp_size, bool edns0_do, in
goto fail; goto fail;
/* RDLENGTH */ /* RDLENGTH */
if (edns0_do && !DNS_PACKET_QR(p)) { if (edns0_do && include_rfc6975) {
/* If DO is on and this is not a reply, also append RFC6975 Algorithm data */ /* If DO is on and this is requested, also append RFC6975 Algorithm data. This is supposed to
* be done on queries, not on replies, hencer callers should turn this off when finishing off
* replies. */
static const uint8_t rfc6975[] = { static const uint8_t rfc6975[] = {

View File

@ -198,7 +198,7 @@ int dns_packet_append_label(DnsPacket *p, const char *s, size_t l, bool canonica
int dns_packet_append_name(DnsPacket *p, const char *name, bool allow_compression, bool canonical_candidate, size_t *start); int dns_packet_append_name(DnsPacket *p, const char *name, bool allow_compression, bool canonical_candidate, size_t *start);
int dns_packet_append_key(DnsPacket *p, const DnsResourceKey *key, const DnsAnswerFlags flags, size_t *start); int dns_packet_append_key(DnsPacket *p, const DnsResourceKey *key, const DnsAnswerFlags flags, size_t *start);
int dns_packet_append_rr(DnsPacket *p, const DnsResourceRecord *rr, const DnsAnswerFlags flags, size_t *start, size_t *rdata_start); int dns_packet_append_rr(DnsPacket *p, const DnsResourceRecord *rr, const DnsAnswerFlags flags, size_t *start, size_t *rdata_start);
int dns_packet_append_opt(DnsPacket *p, uint16_t max_udp_size, bool edns0_do, int rcode, size_t *start); int dns_packet_append_opt(DnsPacket *p, uint16_t max_udp_size, bool edns0_do, bool include_rfc6975, int rcode, size_t *start);
int dns_packet_append_question(DnsPacket *p, DnsQuestion *q); int dns_packet_append_question(DnsPacket *p, DnsQuestion *q);
int dns_packet_append_answer(DnsPacket *p, DnsAnswer *a); int dns_packet_append_answer(DnsPacket *p, DnsAnswer *a);

View File

@ -535,7 +535,7 @@ int dns_server_adjust_opt(DnsServer *server, DnsPacket *packet, DnsServerFeature
else else
packet_size = server->received_udp_packet_max; packet_size = server->received_udp_packet_max;
return dns_packet_append_opt(packet, packet_size, edns_do, 0, NULL); return dns_packet_append_opt(packet, packet_size, edns_do, /* include_rfc6975 = */ true, 0, NULL);
} }
int dns_server_ifindex(const DnsServer *s) { int dns_server_ifindex(const DnsServer *s) {

View File

@ -162,7 +162,7 @@ static int dns_stub_finish_reply_packet(
assert(p); assert(p);
if (add_opt) { if (add_opt) {
r = dns_packet_append_opt(p, ADVERTISE_DATAGRAM_SIZE_MAX, edns0_do, rcode, NULL); r = dns_packet_append_opt(p, ADVERTISE_DATAGRAM_SIZE_MAX, edns0_do, /* include_rfc6975 = */ false, rcode, NULL);
if (r == -EMSGSIZE) /* Hit the size limit? then indicate truncation */ if (r == -EMSGSIZE) /* Hit the size limit? then indicate truncation */
tc = true; tc = true;
else if (r < 0) else if (r < 0)

View File

@ -8,10 +8,6 @@
#include <sys/types.h> #include <sys/types.h>
#include <unistd.h> #include <unistd.h>
#if HAVE_LIBIDN2
#include <idn2.h>
#endif
#include "af-list.h" #include "af-list.h"
#include "alloc-util.h" #include "alloc-util.h"
#include "bus-polkit.h" #include "bus-polkit.h"
@ -20,6 +16,7 @@
#include "fd-util.h" #include "fd-util.h"
#include "fileio.h" #include "fileio.h"
#include "hostname-util.h" #include "hostname-util.h"
#include "idn-util.h"
#include "io-util.h" #include "io-util.h"
#include "missing_network.h" #include "missing_network.h"
#include "netlink-util.h" #include "netlink-util.h"
@ -346,11 +343,19 @@ static int determine_hostname(char **full_hostname, char **llmnr_hostname, char
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Couldn't find a single label in hostname."); "Couldn't find a single label in hostname.");
#if HAVE_LIBIDN || HAVE_LIBIDN2
r = dlopen_idn();
if (r < 0) {
log_debug_errno(r, "Failed to initialize IDN support, ignoring: %m");
decoded = label; /* no decoding */
} else
#endif
{
#if HAVE_LIBIDN2 #if HAVE_LIBIDN2
r = idn2_to_unicode_8z8z(label, &utf8, 0); r = sym_idn2_to_unicode_8z8z(label, &utf8, 0);
if (r != IDN2_OK) if (r != IDN2_OK)
return log_error_errno(SYNTHETIC_ERRNO(EUCLEAN), return log_error_errno(SYNTHETIC_ERRNO(EUCLEAN),
"Failed to undo IDNA: %s", idn2_strerror(r)); "Failed to undo IDNA: %s", sym_idn2_strerror(r));
assert(utf8_is_valid(utf8)); assert(utf8_is_valid(utf8));
r = strlen(utf8); r = strlen(utf8);
@ -369,6 +374,7 @@ static int determine_hostname(char **full_hostname, char **llmnr_hostname, char
#else #else
decoded = label; /* no decoding */ decoded = label; /* no decoding */
#endif #endif
}
r = dns_label_escape_new(decoded, r, &n); r = dns_label_escape_new(decoded, r, &n);
if (r < 0) if (r < 0)

View File

@ -1,12 +1,5 @@
/* SPDX-License-Identifier: LGPL-2.1+ */ /* SPDX-License-Identifier: LGPL-2.1+ */
#if HAVE_LIBIDN2
# include <idn2.h>
#elif HAVE_LIBIDN
# include <idna.h>
# include <stringprep.h>
#endif
#include <endian.h> #include <endian.h>
#include <netinet/in.h> #include <netinet/in.h>
#include <stdio.h> #include <stdio.h>
@ -17,6 +10,7 @@
#include "hashmap.h" #include "hashmap.h"
#include "hexdecoct.h" #include "hexdecoct.h"
#include "hostname-util.h" #include "hostname-util.h"
#include "idn-util.h"
#include "in-addr-util.h" #include "in-addr-util.h"
#include "macro.h" #include "macro.h"
#include "parse-util.h" #include "parse-util.h"
@ -312,12 +306,17 @@ int dns_label_apply_idna(const char *encoded, size_t encoded_size, char *decoded
const char *p; const char *p;
bool contains_8bit = false; bool contains_8bit = false;
char buffer[DNS_LABEL_MAX+1]; char buffer[DNS_LABEL_MAX+1];
int r;
assert(encoded); assert(encoded);
assert(decoded); assert(decoded);
/* Converts an U-label into an A-label */ /* Converts an U-label into an A-label */
r = dlopen_idn();
if (r < 0)
return r;
if (encoded_size <= 0) if (encoded_size <= 0)
return -EINVAL; return -EINVAL;
@ -332,11 +331,11 @@ int dns_label_apply_idna(const char *encoded, size_t encoded_size, char *decoded
return 0; return 0;
} }
input = stringprep_utf8_to_ucs4(encoded, encoded_size, &input_size); input = sym_stringprep_utf8_to_ucs4(encoded, encoded_size, &input_size);
if (!input) if (!input)
return -ENOMEM; return -ENOMEM;
if (idna_to_ascii_4i(input, input_size, buffer, 0) != 0) if (sym_idna_to_ascii_4i(input, input_size, buffer, 0) != 0)
return -EINVAL; return -EINVAL;
l = strlen(buffer); l = strlen(buffer);
@ -362,28 +361,33 @@ int dns_label_undo_idna(const char *encoded, size_t encoded_size, char *decoded,
_cleanup_free_ char *result = NULL; _cleanup_free_ char *result = NULL;
uint32_t *output = NULL; uint32_t *output = NULL;
size_t w; size_t w;
int r;
/* To be invoked after unescaping. Converts an A-label into an U-label. */ /* To be invoked after unescaping. Converts an A-label into an U-label. */
assert(encoded); assert(encoded);
assert(decoded); assert(decoded);
r = dlopen_idn();
if (r < 0)
return r;
if (encoded_size <= 0 || encoded_size > DNS_LABEL_MAX) if (encoded_size <= 0 || encoded_size > DNS_LABEL_MAX)
return -EINVAL; return -EINVAL;
if (!memory_startswith(encoded, encoded_size, IDNA_ACE_PREFIX)) if (!memory_startswith(encoded, encoded_size, IDNA_ACE_PREFIX))
return 0; return 0;
input = stringprep_utf8_to_ucs4(encoded, encoded_size, &input_size); input = sym_stringprep_utf8_to_ucs4(encoded, encoded_size, &input_size);
if (!input) if (!input)
return -ENOMEM; return -ENOMEM;
output_size = input_size; output_size = input_size;
output = newa(uint32_t, output_size); output = newa(uint32_t, output_size);
idna_to_unicode_44i(input, input_size, output, &output_size, 0); sym_idna_to_unicode_44i(input, input_size, output, &output_size, 0);
result = stringprep_ucs4_to_utf8(output, output_size, NULL, &w); result = sym_stringprep_ucs4_to_utf8(output, output_size, NULL, &w);
if (!result) if (!result)
return -ENOMEM; return -ENOMEM;
if (w <= 0) if (w <= 0)
@ -1266,26 +1270,38 @@ int dns_name_common_suffix(const char *a, const char *b, const char **ret) {
} }
int dns_name_apply_idna(const char *name, char **ret) { int dns_name_apply_idna(const char *name, char **ret) {
/* Return negative on error, 0 if not implemented, positive on success. */ /* Return negative on error, 0 if not implemented, positive on success. */
#if HAVE_LIBIDN2 #if HAVE_LIBIDN2 || HAVE_LIBIDN2
int r; int r;
r = dlopen_idn();
if (r == EOPNOTSUPP) {
*ret = NULL;
return 0;
}
if (r < 0)
return r;
#endif
#if HAVE_LIBIDN2
_cleanup_free_ char *t = NULL; _cleanup_free_ char *t = NULL;
assert(name); assert(name);
assert(ret); assert(ret);
r = idn2_lookup_u8((uint8_t*) name, (uint8_t**) &t, r = sym_idn2_lookup_u8((uint8_t*) name, (uint8_t**) &t,
IDN2_NFC_INPUT | IDN2_NONTRANSITIONAL); IDN2_NFC_INPUT | IDN2_NONTRANSITIONAL);
log_debug("idn2_lookup_u8: %s → %s", name, t); log_debug("idn2_lookup_u8: %s → %s", name, t);
if (r == IDN2_OK) { if (r == IDN2_OK) {
if (!startswith(name, "xn--")) { if (!startswith(name, "xn--")) {
_cleanup_free_ char *s = NULL; _cleanup_free_ char *s = NULL;
r = idn2_to_unicode_8z8z(t, &s, 0); r = sym_idn2_to_unicode_8z8z(t, &s, 0);
if (r != IDN2_OK) { if (r != IDN2_OK) {
log_debug("idn2_to_unicode_8z8z(\"%s\") failed: %d/%s", log_debug("idn2_to_unicode_8z8z(\"%s\") failed: %d/%s",
t, r, idn2_strerror(r)); t, r, sym_idn2_strerror(r));
return 0; return 0;
} }
@ -1301,7 +1317,7 @@ int dns_name_apply_idna(const char *name, char **ret) {
return 1; /* *ret has been written */ return 1; /* *ret has been written */
} }
log_debug("idn2_lookup_u8(\"%s\") failed: %d/%s", name, r, idn2_strerror(r)); log_debug("idn2_lookup_u8(\"%s\") failed: %d/%s", name, r, sym_idn2_strerror(r));
if (r == IDN2_2HYPHEN) if (r == IDN2_2HYPHEN)
/* The name has two hyphens — forbidden by IDNA2008 in some cases */ /* The name has two hyphens — forbidden by IDNA2008 in some cases */
return 0; return 0;
@ -1358,6 +1374,7 @@ int dns_name_apply_idna(const char *name, char **ret) {
return 1; return 1;
#else #else
*ret = NULL;
return 0; return 0;
#endif #endif
} }

91
src/shared/idn-util.c Normal file
View File

@ -0,0 +1,91 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
#if HAVE_LIBIDN2
# include <idn2.h>
#elif HAVE_LIBIDN
# include <idna.h>
# include <stringprep.h>
#endif
#include "alloc-util.h"
#include "dlfcn-util.h"
#include "idn-util.h"
#if HAVE_LIBIDN || HAVE_LIBIDN2
static void* idn_dl = NULL;
#endif
#if HAVE_LIBIDN2
int (*sym_idn2_lookup_u8)(const uint8_t* src, uint8_t** lookupname, int flags) = NULL;
const char *(*sym_idn2_strerror)(int rc) = NULL;
int (*sym_idn2_to_unicode_8z8z)(const char * input, char ** output, int flags) = NULL;
int dlopen_idn(void) {
_cleanup_(dlclosep) void *dl = NULL;
int r;
if (idn_dl)
return 0; /* Already loaded */
dl = dlopen("libidn2.so.0", RTLD_LAZY);
if (!dl)
return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
"libidn2 support is not installed: %s", dlerror());
r = dlsym_many_and_warn(
dl,
LOG_DEBUG,
&sym_idn2_lookup_u8, "idn2_lookup_u8",
&sym_idn2_strerror, "idn2_strerror",
&sym_idn2_to_unicode_8z8z, "idn2_to_unicode_8z8z",
NULL);
if (r < 0)
return r;
/* Note that we never release the reference here, because there's no real reason to, after all this
* was traditionally a regular shared library dependency which lives forever too. */
idn_dl = TAKE_PTR(dl);
return 1;
}
#endif
#if HAVE_LIBIDN
int (*sym_idna_to_ascii_4i)(const uint32_t * in, size_t inlen, char *out, int flags);
int (*sym_idna_to_unicode_44i)(const uint32_t * in, size_t inlen,uint32_t * out, size_t * outlen, int flags);
char* (*sym_stringprep_ucs4_to_utf8)(const uint32_t * str, ssize_t len, size_t * items_read, size_t * items_written);
uint32_t* (*sym_stringprep_utf8_to_ucs4)(const char *str, ssize_t len, size_t *items_written);
int dlopen_idn(void) {
_cleanup_(dlclosep) void *dl = NULL;
int r;
if (idn_dl)
return 0; /* Already loaded */
dl = dlopen("libidn.so.12", RTLD_LAZY);
if (!dl) {
/* libidn broke ABI in 1.34, but not in a way we care about (a new field got added to an
* open-coded struct we do not use), hence support both versions. */
dl = dlopen("libidn.so.11", RTLD_LAZY);
if (!dl)
return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
"libidn support is not installed: %s", dlerror());
}
r = dlsym_many_and_warn(
dl,
LOG_DEBUG,
&sym_idna_to_ascii_4i, "idna_to_ascii_4i",
&sym_idna_to_unicode_44i, "idna_to_unicode_44i",
&sym_stringprep_ucs4_to_utf8, "stringprep_ucs4_to_utf8",
&sym_stringprep_utf8_to_ucs4, "stringprep_utf8_to_ucs4",
NULL);
if (r < 0)
return r;
idn_dl = TAKE_PTR(dl);
return 1;
}
#endif

32
src/shared/idn-util.h Normal file
View File

@ -0,0 +1,32 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
#if HAVE_LIBIDN2
# include <idn2.h>
#elif HAVE_LIBIDN
# include <idna.h>
# include <stringprep.h>
#endif
#include <inttypes.h>
#if HAVE_LIBIDN2 || HAVE_LIBIDN
int dlopen_idn(void);
#else
static inline int dlopen_idn(void) {
return -EOPNOTSUPP;
}
#endif
#if HAVE_LIBIDN2
extern int (*sym_idn2_lookup_u8)(const uint8_t* src, uint8_t** lookupname, int flags);
extern const char *(*sym_idn2_strerror)(int rc);
extern int (*sym_idn2_to_unicode_8z8z)(const char * input, char ** output, int flags);
#endif
#if HAVE_LIBIDN
extern int (*sym_idna_to_ascii_4i)(const uint32_t * in, size_t inlen, char *out, int flags);
extern int (*sym_idna_to_unicode_44i)(const uint32_t * in, size_t inlen,uint32_t * out, size_t * outlen, int flags);
extern char* (*sym_stringprep_ucs4_to_utf8)(const uint32_t * str, ssize_t len, size_t * items_read, size_t * items_written);
extern uint32_t* (*sym_stringprep_utf8_to_ucs4)(const char *str, ssize_t len, size_t *items_written);
#endif

View File

@ -117,6 +117,8 @@ shared_sources = files('''
group-record.h group-record.h
id128-print.c id128-print.c
id128-print.h id128-print.h
idn-util.c
idn-util.h
ima-util.c ima-util.c
ima-util.h ima-util.h
import-util.c import-util.c
@ -355,7 +357,6 @@ libshared_deps = [threads,
libcap, libcap,
libcrypt, libcrypt,
libgcrypt, libgcrypt,
libidn,
libiptc, libiptc,
libkmod, libkmod,
liblz4, liblz4,