Compare commits

...

12 Commits

Author SHA1 Message Date
Raul Cheleguini 5c48f426a3
Merge fb437dc7ab into d209e197f8 2024-11-22 22:36:03 +05:30
Lennart Poettering d209e197f8
userdbctl: two trivial fixlets (#35296)
Fixes: #35294
2024-11-22 16:06:01 +01:00
Antonio Alvarez Feijoo 9ed090230e tpm2-util: fix parameter name 2024-11-22 16:04:16 +01:00
Luca Boccassi 9bf6ffe166
man: split cryptenroll man page into sections (#35297) 2024-11-22 12:01:07 +00:00
Lennart Poettering 47c5ca237b userdbctl: respect selected disposition also when showing gid boundaries
Follow-up for: ad5de3222f
2024-11-22 11:28:30 +01:00
Lennart Poettering 7f8a4f12df userdbctl: fix counting
Fixes: #35294
2024-11-22 11:28:28 +01:00
Lennart Poettering e412fc5e04 userbdctl: show 'mapped' user range only inside of userns
Outside of userns the concept makes no sense, there cannot be users
mapped from further outside.
2024-11-22 11:28:17 +01:00
Lennart Poettering cc6baba720 cryptenroll: it's called PKCS#11, not PKCS11
In the --help text we really should use the official spelling, just like
in the man page.
2024-11-22 10:42:37 +01:00
Lennart Poettering 3ae48d071c man: add enrollment type sections to cryptenroll man page
We have the same sections in the --help text, hence we even more so
should have them in the man page.
2024-11-22 10:42:37 +01:00
Antonio Alvarez Feijoo 2ccacdd57c bash-completion: add --list-devices to systemd-cryptenroll
And also use it to list suitable block devices.
2024-11-22 10:38:19 +01:00
Yu Watanabe d99198819c core/service: service_add_fd_store() consumes passed fd
Without this change, the fd is closed twice on failure.

Fixes a bug introduced by dff9808a62.

Fixes #35288.
2024-11-22 04:15:51 +01:00
Raul Cheleguini fb437dc7ab resolved: Add basic support for DNS-over-HTTPS (RFC 8484)
Add support for DNS-over-HTTPS (DoH) to resolved. The feature can be enabled
through the option DNSOverHTTPS. The implementation takes advantage of the
curl-util used by import tool, for that we move the curl-util to src/basic and
adjust import tool build settings.
2024-11-18 00:17:20 -03:00
23 changed files with 469 additions and 52 deletions

View File

@ -265,32 +265,11 @@
</refsect1>
<refsect1>
<title>Options</title>
<title>Unlocking</title>
<para>The following options are understood:</para>
<para>The following options are understood that may be used to unlock the device in preparation of the enrollment operations:</para>
<variablelist>
<varlistentry>
<term><option>--password</option></term>
<listitem><para>Enroll a regular password/passphrase. This command is mostly equivalent to
<command>cryptsetup luksAddKey</command>, however may be combined with
<option>--wipe-slot=</option> in one call, see below.</para>
<xi:include href="version-info.xml" xpointer="v248"/></listitem>
</varlistentry>
<varlistentry>
<term><option>--recovery-key</option></term>
<listitem><para>Enroll a recovery key. Recovery keys are mostly identical to passphrases, but are
computer-generated instead of being chosen by a human, and thus have a guaranteed high entropy. The
key uses a character set that is easy to type in, and may be scanned off screen via a QR code.
</para>
<xi:include href="version-info.xml" xpointer="v248"/></listitem>
</varlistentry>
<varlistentry>
<term><option>--unlock-key-file=<replaceable>PATH</replaceable></option></term>
@ -328,7 +307,45 @@
<xi:include href="version-info.xml" xpointer="v256"/></listitem>
</varlistentry>
</variablelist>
</refsect1>
<refsect1>
<title>Simple Enrollment</title>
<para>The following options are understood that may be used to enroll simple user input based
unlocking:</para>
<variablelist>
<varlistentry>
<term><option>--password</option></term>
<listitem><para>Enroll a regular password/passphrase. This command is mostly equivalent to
<command>cryptsetup luksAddKey</command>, however may be combined with
<option>--wipe-slot=</option> in one call, see below.</para>
<xi:include href="version-info.xml" xpointer="v248"/></listitem>
</varlistentry>
<varlistentry>
<term><option>--recovery-key</option></term>
<listitem><para>Enroll a recovery key. Recovery keys are mostly identical to passphrases, but are
computer-generated instead of being chosen by a human, and thus have a guaranteed high entropy. The
key uses a character set that is easy to type in, and may be scanned off screen via a QR code.
</para>
<xi:include href="version-info.xml" xpointer="v248"/></listitem>
</varlistentry>
</variablelist>
</refsect1>
<refsect1>
<title>PKCS#11 Enrollment</title>
<para>The following option is understood that may be used to enroll PKCS#11 tokens:</para>
<variablelist>
<varlistentry>
<term><option>--pkcs11-token-uri=<replaceable>URI</replaceable></option></term>
@ -361,7 +378,15 @@
<xi:include href="version-info.xml" xpointer="v248"/></listitem>
</varlistentry>
</variablelist>
</refsect1>
<refsect1>
<title>FIDO2 Enrollment</title>
<para>The following options are understood that may be used to enroll PKCS#11 tokens:</para>
<variablelist>
<varlistentry>
<term><option>--fido2-credential-algorithm=<replaceable>STRING</replaceable></option></term>
<listitem><para>Specify COSE algorithm used in credential generation. The default value is
@ -461,7 +486,15 @@
<xi:include href="version-info.xml" xpointer="v249"/></listitem>
</varlistentry>
</variablelist>
</refsect1>
<refsect1>
<title>TPM2 Enrollment</title>
<para>The following options are understood that may be used to enroll TPM2 devices:</para>
<variablelist>
<varlistentry>
<term><option>--tpm2-device=<replaceable>PATH</replaceable></option></term>
@ -636,7 +669,15 @@
<xi:include href="version-info.xml" xpointer="v255"/></listitem>
</varlistentry>
</variablelist>
</refsect1>
<refsect1>
<title>Other Options</title>
<para>The following additional options are understood:</para>
<variablelist>
<varlistentry>
<term><option>--wipe-slot=<replaceable>SLOT<optional>,SLOT...</optional></replaceable></option></term>

View File

@ -1579,6 +1579,29 @@ conf.set('DEFAULT_DNS_OVER_TLS_MODE',
'DNS_OVER_TLS_' + default_dns_over_tls.underscorify().to_upper())
conf.set_quoted('DEFAULT_DNS_OVER_TLS_MODE_STR', default_dns_over_tls)
dns_over_https = get_option('dns-over-https')
if dns_over_https != 'false'
have = true
if conf.get('HAVE_LIBCURL') == 0
message('DNS-over-HTTPS support depends on libcurl, but dependencies are not available')
have = false
endif
if conf.get('HAVE_OPENSSL') == 0
message('openssl required, but not available')
have = false
endif
endif
conf.set10('ENABLE_DNS_OVER_HTTPS', have)
default_dns_over_https = get_option('default-dns-over-https')
if default_dns_over_https != 'no' and conf.get('ENABLE_DNS_OVER_HTTPS') == 0
message('default-dns-over-https cannot be enabled. Setting default-dns-over-https to no.')
default_dns_over_https = 'no'
endif
conf.set('DEFAULT_DNS_OVER_HTTPS_MODE',
'DNS_OVER_HTTPS_' + default_dns_over_https.underscorify().to_upper())
conf.set_quoted('DEFAULT_DNS_OVER_HTTPS_MODE_STR', default_dns_over_https)
default_mdns = get_option('default-mdns')
conf.set('DEFAULT_MDNS_MODE',
'RESOLVE_SUPPORT_' + default_mdns.to_upper())
@ -3002,6 +3025,7 @@ summary({
'default compression method' : compression,
'default DNSSEC mode' : default_dnssec,
'default DNS-over-TLS mode' : default_dns_over_tls,
'default DNS-over-HTTPS mode' : default_dns_over_https,
'default mDNS mode' : default_mdns,
'default LLMNR mode' : default_llmnr,
'default DNS servers' : dns_servers.split(' '),

View File

@ -353,6 +353,10 @@ option('default-dns-over-tls', type : 'combo',
description : 'default DNS-over-TLS mode',
choices : ['yes', 'opportunistic', 'no'],
value : 'no')
option('default-dns-over-https', type : 'combo',
description : 'default DNS-over-HTTPS mode',
choices : ['yes', 'no'],
value : 'no')
option('default-mdns', type : 'combo',
choices : ['yes', 'resolve', 'no'],
description : 'default MulticastDNS mode',
@ -363,6 +367,8 @@ option('default-llmnr', type : 'combo',
value : 'yes')
option('dns-over-tls', type : 'combo', choices : ['auto', 'gnutls', 'openssl', 'true', 'false'],
description : 'DNS-over-TLS support')
option('dns-over-https', type : 'combo', choices : ['true', 'false'],
description : 'DNS-over-HTTPS support')
option('dns-servers', type : 'string',
description : 'space-separated list of default DNS servers',
value : '1.1.1.1#cloudflare-dns.com 8.8.8.8#dns.google 1.0.0.1#cloudflare-dns.com 8.8.4.4#dns.google 2606:4700:4700::1111#cloudflare-dns.com 2001:4860:4860::8888#dns.google 2606:4700:4700::1001#cloudflare-dns.com 2001:4860:4860::8844#dns.google')

View File

@ -38,19 +38,12 @@ __get_tpm2_devices() {
done
}
__get_block_devices() {
local i
for i in /dev/*; do
[ -b "$i" ] && printf '%s\n' "$i"
done
}
_systemd_cryptenroll() {
local comps
local cur=${COMP_WORDS[COMP_CWORD]} prev=${COMP_WORDS[COMP_CWORD-1]} words cword
local -A OPTS=(
[STANDALONE]='-h --help --version
--password --recovery-key'
--password --recovery-key --list-devices'
[ARG]='--unlock-key-file
--unlock-fido2-device
--unlock-tpm2-device
@ -116,7 +109,7 @@ _systemd_cryptenroll() {
return 0
fi
comps=$(__get_block_devices)
comps=$(systemd-cryptenroll --list-devices)
COMPREPLY=( $(compgen -W '$comps' -- "$cur") )
return 0
}

View File

@ -3426,14 +3426,12 @@ static int service_deserialize_item(Unit *u, const char *key, const char *value,
return 0;
}
r = service_add_fd_store(s, fd, fdn, do_poll);
r = service_add_fd_store(s, TAKE_FD(fd), fdn, do_poll);
if (r < 0) {
log_unit_debug_errno(u, r,
"Failed to store deserialized fd '%s', ignoring: %m", fdn);
return 0;
}
TAKE_FD(fd);
} else if (streq(key, "extra-fd")) {
_cleanup_free_ char *fdv = NULL, *fdn = NULL;
_cleanup_close_ int fd = -EBADF;

View File

@ -193,7 +193,7 @@ static int help(void) {
"\n%3$sSimple Enrollment:%4$s\n"
" --password Enroll a user-supplied password\n"
" --recovery-key Enroll a recovery key\n"
"\n%3$sPKCS11 Enrollment:%4$s\n"
"\n%3$sPKCS#11 Enrollment:%4$s\n"
" --pkcs11-token-uri=URI\n"
" Specify PKCS#11 security token URI\n"
"\n%3$sFIDO2 Enrollment:%4$s\n"

View File

@ -14,7 +14,6 @@ systemd_pull_sources = files(
'pull-tar.c',
'pull-job.c',
'pull-common.c',
'curl-util.c',
)
systemd_import_sources = files(

View File

@ -117,6 +117,10 @@ if conf.get('ENABLE_DNS_OVER_TLS') == 1
endif
endif
if conf.get('ENABLE_DNS_OVER_HTTPS') == 1
systemd_resolved_dependencies += libcurl
endif
link_with = [
libshared,
libsystemd_resolve_core,

View File

@ -422,10 +422,17 @@ DnsServerFeatureLevel dns_server_possible_feature_level(DnsServer *s) {
/* Determine the best feature level we care about. If DNSSEC mode is off there's no point in using anything
* better than EDNS0, hence don't even try. */
if (dns_server_get_dnssec_mode(s) != DNSSEC_NO)
if (dns_server_get_dnssec_mode(s) != DNSSEC_NO) {
best = dns_server_get_dns_over_tls_mode(s) == DNS_OVER_TLS_NO ?
DNS_SERVER_FEATURE_LEVEL_DO :
DNS_SERVER_FEATURE_LEVEL_TLS_DO;
/* TODO: Add HTTPS_PLAIN_DO too? */
#if ENABLE_DNS_OVER_HTTPS
best = dns_server_get_dns_over_https_mode(s) == DNS_OVER_HTTPS_NO ?
DNS_SERVER_FEATURE_LEVEL_DO :
DNS_SERVER_FEATURE_LEVEL_HTTPS_PLAIN;
#endif
}
else
best = dns_server_get_dns_over_tls_mode(s) == DNS_OVER_TLS_NO ?
DNS_SERVER_FEATURE_LEVEL_EDNS0 :
@ -493,7 +500,8 @@ DnsServerFeatureLevel dns_server_possible_feature_level(DnsServer *s) {
} else if (s->packet_bad_opt &&
DNS_SERVER_FEATURE_LEVEL_IS_EDNS0(s->possible_feature_level) &&
dns_server_get_dnssec_mode(s) != DNSSEC_YES &&
dns_server_get_dns_over_tls_mode(s) != DNS_OVER_TLS_YES) {
dns_server_get_dns_over_tls_mode(s) != DNS_OVER_TLS_YES &&
dns_server_get_dns_over_https_mode(s) != DNS_OVER_HTTPS_YES) {
/* A reply to one of our EDNS0 queries didn't carry a valid OPT RR, then downgrade to
* below EDNS0 levels. After all, some servers generate different responses with and
@ -962,6 +970,12 @@ DnsOverTlsMode dns_server_get_dns_over_tls_mode(DnsServer *s) {
return manager_get_dns_over_tls_mode(s->manager);
}
DnsOverHttpsMode dns_server_get_dns_over_https_mode(DnsServer *s) {
assert(s);
return manager_get_dns_over_https_mode(s->manager);
}
void dns_server_flush_cache(DnsServer *s) {
DnsServer *current;
DnsScope *scope;
@ -1099,6 +1113,7 @@ static const char* const dns_server_feature_level_table[_DNS_SERVER_FEATURE_LEVE
[DNS_SERVER_FEATURE_LEVEL_UDP] = "UDP",
[DNS_SERVER_FEATURE_LEVEL_EDNS0] = "UDP+EDNS0",
[DNS_SERVER_FEATURE_LEVEL_TLS_PLAIN] = "TLS+EDNS0",
[DNS_SERVER_FEATURE_LEVEL_HTTPS_PLAIN] = "HTTPS+EDNS0",
[DNS_SERVER_FEATURE_LEVEL_DO] = "UDP+EDNS0+DO",
[DNS_SERVER_FEATURE_LEVEL_TLS_DO] = "TLS+EDNS0+DO",
};

View File

@ -35,6 +35,7 @@ typedef enum DnsServerFeatureLevel {
DNS_SERVER_FEATURE_LEVEL_UDP,
DNS_SERVER_FEATURE_LEVEL_EDNS0,
DNS_SERVER_FEATURE_LEVEL_TLS_PLAIN,
DNS_SERVER_FEATURE_LEVEL_HTTPS_PLAIN,
DNS_SERVER_FEATURE_LEVEL_DO,
DNS_SERVER_FEATURE_LEVEL_TLS_DO,
_DNS_SERVER_FEATURE_LEVEL_MAX,
@ -46,6 +47,7 @@ typedef enum DnsServerFeatureLevel {
#define DNS_SERVER_FEATURE_LEVEL_IS_EDNS0(x) ((x) >= DNS_SERVER_FEATURE_LEVEL_EDNS0)
#define DNS_SERVER_FEATURE_LEVEL_IS_TLS(x) IN_SET(x, DNS_SERVER_FEATURE_LEVEL_TLS_PLAIN, DNS_SERVER_FEATURE_LEVEL_TLS_DO)
#define DNS_SERVER_FEATURE_LEVEL_IS_DNSSEC(x) ((x) >= DNS_SERVER_FEATURE_LEVEL_DO)
#define DNS_SERVER_FEATURE_LEVEL_IS_HTTPS(x) ((x) == DNS_SERVER_FEATURE_LEVEL_HTTPS_PLAIN)
#define DNS_SERVER_FEATURE_LEVEL_IS_UDP(x) IN_SET(x, DNS_SERVER_FEATURE_LEVEL_UDP, DNS_SERVER_FEATURE_LEVEL_EDNS0, DNS_SERVER_FEATURE_LEVEL_DO)
const char* dns_server_feature_level_to_string(DnsServerFeatureLevel i) _const_;
@ -164,6 +166,7 @@ void manager_next_dns_server(Manager *m, DnsServer *if_current);
DnssecMode dns_server_get_dnssec_mode(DnsServer *s);
DnsOverTlsMode dns_server_get_dns_over_tls_mode(DnsServer *s);
DnsOverHttpsMode dns_server_get_dns_over_https_mode(DnsServer *s);
size_t dns_server_get_mtu(DnsServer *s);

View File

@ -4,11 +4,13 @@
#include "af-list.h"
#include "alloc-util.h"
#include "dns-domain.h"
#include "errno-list.h"
#include "errno-util.h"
#include "fd-util.h"
#include "glyph-util.h"
#include "hexdecoct.h"
#include "random-util.h"
#include "resolved-dns-cache.h"
#include "resolved-dns-transaction.h"
@ -16,6 +18,10 @@
#include "resolved-llmnr.h"
#include "string-table.h"
#if ENABLE_DNS_OVER_HTTPS
#include "curl-util.h"
#endif
#define TRANSACTIONS_MAX 4096
#define TRANSACTION_TCP_TIMEOUT_USEC (10U*USEC_PER_SEC)
@ -682,7 +688,13 @@ static uint16_t dns_transaction_port(DnsTransaction *t) {
if (t->server->port > 0)
return t->server->port;
return DNS_SERVER_FEATURE_LEVEL_IS_TLS(t->current_feature_level) ? 853 : 53;
if (DNS_SERVER_FEATURE_LEVEL_IS_TLS(t->current_feature_level))
return 853;
if (DNS_SERVER_FEATURE_LEVEL_IS_HTTPS(t->current_feature_level))
return 443;
return 53;
}
static int dns_transaction_emit_tcp(DnsTransaction *t) {
@ -1518,6 +1530,9 @@ static int dns_transaction_emit_udp(DnsTransaction *t) {
if (t->current_feature_level < DNS_SERVER_FEATURE_LEVEL_UDP || DNS_SERVER_FEATURE_LEVEL_IS_TLS(t->current_feature_level))
return -EAGAIN; /* Sorry, can't do UDP, try TCP! */
if (DNS_SERVER_FEATURE_LEVEL_IS_HTTPS(t->current_feature_level))
return -EAGAIN; /* Direct request logic to HTTPS */
if (!t->bypass && !dns_server_dnssec_supported(t->server) && dns_type_is_dnssec(dns_transaction_key(t)->type))
return -EOPNOTSUPP;
@ -1984,6 +1999,223 @@ static int mdns_make_dummy_packet(DnsTransaction *t, DnsPacket **ret_packet, Set
return add_known_answers;
}
#if ENABLE_DNS_OVER_HTTPS
static size_t dns_transaction_curl_header_callback(void *contents, size_t size, size_t nmemb, void *userdata) {
_cleanup_free_ char *content_header = NULL;
DnsTransaction *t = ASSERT_PTR(userdata);
size_t sz = size * nmemb;
CURLcode code;
long status;
int r;
assert(contents);
code = curl_easy_getinfo(t->curl, CURLINFO_RESPONSE_CODE, &status);
if (code != CURLE_OK)
return log_error_errno(SYNTHETIC_ERRNO(EIO), "Failed to retrieve response code: %s", curl_easy_strerror(code));
if (status >= 200 && status <= 299) {
r = curl_header_strdup(contents, sz, "Content-Type:", &content_header);
if (r < 0) {
log_oom();
return 0;
}
if (r > 0) {
r = strcmp("application/dns-message", content_header);
if (r == 0)
t->valid_dns_message = true;
return sz;
}
}
return sz;
}
static size_t dns_transaction_curl_write_callback(void *contents, size_t size, size_t nmemb, void *userdata) {
DnsTransaction *t = ASSERT_PTR(userdata);
size_t sz = size * nmemb;
int r;
t->payload = memdup(contents, sz);
if (!t->payload) {
log_debug("Failed to extract HTTP payload to further processing");
r = log_oom();
goto fail;
}
t->payload_size += sz;
return sz;
fail:
dns_transaction_complete(t, DNS_TRANSACTION_INVALID_REPLY);
return r;
}
static int dns_transaction_curl_recv(DnsTransaction *t, DnsPacket **p) {
size_t ms;
int r;
ms = t->payload_size;
if (t->payload_size < 1) {
log_debug("Received HTTP payload unexpected size %zu", t->payload_size);
return -1;
}
r = dns_packet_new(p, DNS_PROTOCOL_DNS, ms, DNS_PACKET_SIZE_MAX);
if (r < 0)
return r;
log_debug("Received HTTP payload of size %zu", t->payload_size);
return 0;
}
static int dns_transaction_curl_make_url(DnsTransaction *t, char **url) {
_cleanup_free_ char *base64_string = NULL;
uint8_t *packet_to_send = DNS_PACKET_DATA(t->sent);
int r;
/* Let's zero the query ID according to the RFC */
packet_to_send[0] = 0;
packet_to_send[1] = 0;
r = base64mem_full(packet_to_send, t->sent->size, MAX_URL_LENGTH, &base64_string);
if (r < 0) {
log_debug_errno(r, "Failed to encode DNS packet to base64");
return r;
}
/* Remove base64 trailing characters */
delete_trailing_chars(base64_string, "=");
/* Build the DoH's wire format request URL */
r = asprintf(url, "https://%s/dns-query?dns=%s", t->server->server_string, base64_string);
if (r < 0) {
log_debug("Failed to allocate and set the url for transaction %" PRIu16 ".", t->id);
return r;
}
return 0;
}
static void dns_transaction_curl_on_response(CurlGlue *g, CURL *curl, CURLcode result) {
_cleanup_(dns_packet_unrefp) DnsPacket *p = NULL;
DnsTransaction *t = NULL;
int status;
int r;
assert(g);
assert(curl);
curl_easy_getinfo(curl, CURLINFO_PRIVATE, &t);
if (result != CURLE_OK) {
log_error_errno(SYNTHETIC_ERRNO(EIO), "HTTP request failed: %s", curl_easy_strerror(result));
status = DNS_TRANSACTION_INVALID_REPLY;
goto finish;
}
if (!t->valid_dns_message) {
log_debug("Received invalid HTTP payload, expected content type of application/dns-message");
status = DNS_TRANSACTION_INVALID_REPLY;
goto finish;
}
r = dns_transaction_curl_recv(t, &p);
if (r < 0) {
log_debug_errno(r, "HTTP payload receive failure");
dns_transaction_complete_errno(t, r);
return;
}
/* Transfer the received payload to transaction/packet struct */
uint8_t *p_data = DNS_PACKET_DATA(p);
memcpy(p_data, t->payload, t->payload_size);
p->size = t->payload_size;
r = dns_packet_validate_reply(p);
if (r < 0)
log_debug_errno(r, "Received invalid DNS packet as response, ignoring: %m");
if (r == 0)
log_debug("Received inappropriate DNS packet as response, ignoring");
dns_transaction_process_reply(t, p, false);
return;
finish:
dns_transaction_complete(t, status);
}
static int dns_transaction_emit_curl(DnsTransaction *t) {
_cleanup_(sd_event_unrefp) sd_event *e = NULL;
_cleanup_free_ char *rule = NULL;
int r;
assert(t);
assert(t->sent);
dns_transaction_close_connection(t, true);
if (t->scope->protocol == DNS_PROTOCOL_DNS) {
r = dns_transaction_pick_server(t);
if (r < 0)
return r;
if (manager_server_is_stub(t->scope->manager, t->server))
return -ELOOP;
r = curl_glue_new(&t->glue, e);
if (r < 0)
return r;
t->glue->on_finished = dns_transaction_curl_on_response;
r = dns_transaction_curl_make_url(t, &t->url);
if (r < 0)
return r;
r = curl_glue_make(&t->curl, t->url, t);
if (r < 0)
return r;
if (curl_easy_setopt(t->curl, CURLOPT_HEADERFUNCTION, dns_transaction_curl_header_callback) != CURLE_OK)
return -EIO;
if (curl_easy_setopt(t->curl, CURLOPT_HEADERDATA, t) != CURLE_OK)
return -EIO;
if (curl_easy_setopt(t->curl, CURLOPT_WRITEFUNCTION, dns_transaction_curl_write_callback) != CURLE_OK)
return -EIO;
if (curl_easy_setopt(t->curl, CURLOPT_WRITEDATA, t) != CURLE_OK)
return -EIO;
// Prevents libcurl's native name lookups
r = asprintf(&rule, "%s:443:%s", t->server->server_string, t->server->server_string);
if (r < 0) {
log_debug("Failed to compound IP resolution to CURLOPT_RESOLVE parameter");
return r;
}
t->glue->resolve_rules = curl_slist_append(NULL, rule);
if (curl_easy_setopt(t->curl, CURLOPT_RESOLVE, t->glue->resolve_rules) != CURLE_OK)
return -EIO;
log_debug("Emitting HTTPS request via curl for transaction %" PRIu16, t->id);
r = curl_glue_add(t->glue, t->curl);
if (r < 0)
return r;
} else
/* TODO: Is this the right error code here? */
return -ELOOP;
return 0;
}
#endif
static int dns_transaction_make_packet_mdns(DnsTransaction *t) {
_cleanup_(dns_packet_unrefp) DnsPacket *p = NULL, *dummy = NULL;
_cleanup_set_free_ Set *keys = NULL;
@ -2172,10 +2404,20 @@ int dns_transaction_go(DnsTransaction *t) {
r = dns_transaction_emit_udp(t);
if (r == -EMSGSIZE)
log_debug("Sending query via TCP since it is too large.");
#if ENABLE_DNS_OVER_HTTPS
else if ((r == -EAGAIN &&
(DNS_SERVER_FEATURE_LEVEL_IS_HTTPS(t->current_feature_level))))
log_debug("Sending query via HTTPS.");
#endif
else if (r == -EAGAIN)
log_debug("Sending query via TCP since UDP isn't supported or DNS-over-TLS is selected.");
else if (r == -EPERM)
log_debug("Sending query via TCP since UDP is blocked.");
#if ENABLE_DNS_OVER_HTTPS
if ((r == -EAGAIN &&
(DNS_SERVER_FEATURE_LEVEL_IS_HTTPS(t->current_feature_level))))
r = dns_transaction_emit_curl(t);
#endif
if (IN_SET(r, -EMSGSIZE, -EAGAIN, -EPERM))
r = dns_transaction_emit_tcp(t);
}

View File

@ -1,9 +1,19 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
#if ENABLE_DNS_OVER_HTTPS
#include <curl/curl.h>
#endif
#include "sd-event.h"
#if ENABLE_DNS_OVER_HTTPS
#include "curl-util.h"
#endif
#include "in-addr-util.h"
typedef struct DnsTransaction DnsTransaction;
typedef struct DnsTransactionFinder DnsTransactionFinder;
typedef enum DnsTransactionState DnsTransactionState;
@ -92,7 +102,15 @@ struct DnsTransaction {
/* TCP connection logic, if we need it */
DnsStream *stream;
#if ENABLE_DNS_OVER_HTTPS
/* HTTPS connection logic, if we need it */
CurlGlue *glue;
CURL *curl;
char *url;
uint8_t *payload;
size_t payload_size;
bool valid_dns_message;
#endif
/* The active server */
DnsServer *server;
@ -219,6 +237,9 @@ DnsTransactionSource dns_transaction_source_from_string(const char *s) _pure_;
/* Maximum attempts to send MDNS requests, see RFC 6762 Section 8.1 */
#define MDNS_TRANSACTION_ATTEMPTS_MAX 3
/* Maximum URL length for HTTP GET request, see RFC ... */
#define MAX_URL_LENGTH 2048
#define TRANSACTION_ATTEMPTS_MAX(p) ((p) == DNS_PROTOCOL_LLMNR ? \
LLMNR_TRANSACTION_ATTEMPTS_MAX : \
(p) == DNS_PROTOCOL_MDNS ? \

View File

@ -26,6 +26,7 @@ Resolve.LLMNR, config_parse_resolve_support, 0,
Resolve.MulticastDNS, config_parse_resolve_support, 0, offsetof(Manager, mdns_support)
Resolve.DNSSEC, config_parse_dnssec_mode, 0, offsetof(Manager, dnssec_mode)
Resolve.DNSOverTLS, config_parse_dns_over_tls_mode, 0, offsetof(Manager, dns_over_tls_mode)
Resolve.DNSOverHTTPS, config_parse_dns_over_https_mode, 0, offsetof(Manager, dns_over_https_mode)
Resolve.Cache, config_parse_dns_cache_mode, DNS_CACHE_MODE_YES, offsetof(Manager, enable_cache)
Resolve.DNSStubListener, config_parse_dns_stub_listener_mode, 0, offsetof(Manager, dns_stub_listener_mode)
Resolve.ReadEtcHosts, config_parse_bool, 0, offsetof(Manager, read_etc_hosts)

View File

@ -1670,6 +1670,15 @@ DnsOverTlsMode manager_get_dns_over_tls_mode(Manager *m) {
return DNS_OVER_TLS_NO;
}
DnsOverHttpsMode manager_get_dns_over_https_mode(Manager *m) {
assert(m);
if (m->dns_over_https_mode != _DNS_OVER_HTTPS_MODE_INVALID)
return m->dns_over_https_mode;
return DNS_OVER_HTTPS_NO;
}
void manager_dnssec_verdict(Manager *m, DnssecVerdict verdict, const DnsResourceKey *key) {
assert(verdict >= 0);

View File

@ -40,6 +40,7 @@ struct Manager {
ResolveSupport mdns_support;
DnssecMode dnssec_mode;
DnsOverTlsMode dns_over_tls_mode;
DnsOverHttpsMode dns_over_https_mode;
DnsCacheMode enable_cache;
bool cache_from_localhost;
DnsStubListenerMode dns_stub_listener_mode;
@ -207,6 +208,8 @@ bool manager_dnssec_supported(Manager *m);
DnsOverTlsMode manager_get_dns_over_tls_mode(Manager *m);
DnsOverHttpsMode manager_get_dns_over_https_mode(Manager *m);
void manager_dnssec_verdict(Manager *m, DnssecVerdict verdict, const DnsResourceKey *key);
bool manager_routable(Manager *m);

View File

@ -26,6 +26,7 @@
#Domains=
#DNSSEC={{DEFAULT_DNSSEC_MODE_STR}}
#DNSOverTLS={{DEFAULT_DNS_OVER_TLS_MODE_STR}}
#DNSOverHTTPS={{DEFAULT_DNS_OVER_HTTPS_MODE_STR}}
#MulticastDNS={{DEFAULT_MDNS_MODE_STR}}
#LLMNR={{DEFAULT_LLMNR_MODE_STR}}
#Cache=yes

View File

@ -311,6 +311,9 @@ void curl_glue_remove_and_free(CurlGlue *g, CURL *c) {
if (g->curl)
curl_multi_remove_handle(g->curl, c);
if (g->resolve_rules)
curl_slist_free_all(g->resolve_rules);
curl_easy_cleanup(c);
}

View File

@ -20,6 +20,7 @@ struct CurlGlue {
void (*on_finished)(CurlGlue *g, CURL *curl, CURLcode code);
void *userdata;
struct curl_slist *resolve_rules;;
};
int curl_glue_new(CurlGlue **glue, sd_event *event);

View File

@ -256,6 +256,10 @@ if conf.get('HAVE_TPM2') == 1 and conf.get('HAVE_LIBCRYPTSETUP') == 1
shared_sources += files('cryptsetup-tpm2.c')
endif
if conf.get('HAVE_LIBCURL') == 1
shared_sources += files('curl-util.c')
endif
generate_ip_protocol_list = find_program('generate-ip-protocol-list.sh')
ip_protocol_list_txt = custom_target(
'ip-protocol-list.txt',
@ -337,6 +341,11 @@ libshared_deps = [threads,
libxz_cflags,
libzstd_cflags]
# Is this correct?
if conf.get('HAVE_LIBCURL') == 1
libshared_deps += [libcurl]
endif
libshared_sym_path = meson.current_source_dir() / 'libshared.sym'
libshared_build_dir = meson.current_build_dir()

View File

@ -7,6 +7,7 @@
DEFINE_CONFIG_PARSE_ENUM(config_parse_resolve_support, resolve_support, ResolveSupport);
DEFINE_CONFIG_PARSE_ENUM(config_parse_dnssec_mode, dnssec_mode, DnssecMode);
DEFINE_CONFIG_PARSE_ENUM(config_parse_dns_over_tls_mode, dns_over_tls_mode, DnsOverTlsMode);
DEFINE_CONFIG_PARSE_ENUM(config_parse_dns_over_https_mode, dns_over_https_mode, DnsOverHttpsMode);
static const char* const resolve_support_table[_RESOLVE_SUPPORT_MAX] = {
[RESOLVE_SUPPORT_NO] = "no",
@ -29,6 +30,12 @@ static const char* const dns_over_tls_mode_table[_DNS_OVER_TLS_MODE_MAX] = {
};
DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(dns_over_tls_mode, DnsOverTlsMode, DNS_OVER_TLS_YES);
static const char* const dns_over_https_mode_table[_DNS_OVER_HTTPS_MODE_MAX] = {
[DNS_OVER_HTTPS_NO] = "no",
[DNS_OVER_HTTPS_YES] = "yes",
};
DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(dns_over_https_mode, DnsOverHttpsMode, DNS_OVER_HTTPS_YES);
bool dns_server_address_valid(int family, const union in_addr_union *sa) {
/* Refuses the 0 IP addresses as well as 127.0.0.53/127.0.0.54 (which is our own DNS stub) */

View File

@ -27,6 +27,7 @@ enum DnsCacheMode {
typedef enum ResolveSupport ResolveSupport;
typedef enum DnssecMode DnssecMode;
typedef enum DnsOverTlsMode DnsOverTlsMode;
typedef enum DnsOverHttpsMode DnsOverHttpsMode;
/* Do not change the order, see link_get_llmnr_support() or link_get_mdns_support(). */
enum ResolveSupport {
@ -70,9 +71,21 @@ enum DnsOverTlsMode {
_DNS_OVER_TLS_MODE_INVALID = -EINVAL,
};
enum DnsOverHttpsMode {
/* No connection is made for DNS-over-HTTPS */
DNS_OVER_HTTPS_NO,
/* Enforce DNS-over-HTTPS */
DNS_OVER_HTTPS_YES,
_DNS_OVER_HTTPS_MODE_MAX,
_DNS_OVER_HTTPS_MODE_INVALID = -EINVAL,
};
CONFIG_PARSER_PROTOTYPE(config_parse_resolve_support);
CONFIG_PARSER_PROTOTYPE(config_parse_dnssec_mode);
CONFIG_PARSER_PROTOTYPE(config_parse_dns_over_tls_mode);
CONFIG_PARSER_PROTOTYPE(config_parse_dns_over_https_mode);
CONFIG_PARSER_PROTOTYPE(config_parse_dns_cache_mode);
const char* resolve_support_to_string(ResolveSupport p) _const_;
@ -84,6 +97,9 @@ DnssecMode dnssec_mode_from_string(const char *s) _pure_;
const char* dns_over_tls_mode_to_string(DnsOverTlsMode p) _const_;
DnsOverTlsMode dns_over_tls_mode_from_string(const char *s) _pure_;
const char* dns_over_https_mode_to_string(DnsOverHttpsMode p) _const_;
DnsOverHttpsMode dns_over_https_mode_from_string(const char *s) _pure_;
bool dns_server_address_valid(int family, const union in_addr_union *sa);
const char* dns_cache_mode_to_string(DnsCacheMode p) _const_;

View File

@ -392,7 +392,7 @@ int tpm2_make_pcr_json_array(uint32_t pcr_mask, sd_json_variant **ret);
int tpm2_parse_pcr_json_array(sd_json_variant *v, uint32_t *ret);
int tpm2_make_luks2_json(int keyslot, uint32_t hash_pcr_mask, uint16_t pcr_bank, const struct iovec *pubkey, uint32_t pubkey_pcr_mask, uint16_t primary_alg, const struct iovec blobs[], size_t n_blobs, const struct iovec policy_hash[], size_t n_policy_hash, const struct iovec *salt, const struct iovec *srk, const struct iovec *pcrlock_nv, TPM2Flags flags, sd_json_variant **ret);
int tpm2_parse_luks2_json(sd_json_variant *v, int *ret_keyslot, uint32_t *ret_hash_pcr_mask, uint16_t *ret_pcr_bank, struct iovec *ret_pubkey, uint32_t *ret_pubkey_pcr_mask, uint16_t *ret_primary_alg, struct iovec **ret_blobs, size_t *ret_n_blobs, struct iovec **ret_policy_hash, size_t *ret_n_policy_hash, struct iovec *ret_salt, struct iovec *ret_srk, struct iovec *pcrlock_nv, TPM2Flags *ret_flags);
int tpm2_parse_luks2_json(sd_json_variant *v, int *ret_keyslot, uint32_t *ret_hash_pcr_mask, uint16_t *ret_pcr_bank, struct iovec *ret_pubkey, uint32_t *ret_pubkey_pcr_mask, uint16_t *ret_primary_alg, struct iovec **ret_blobs, size_t *ret_n_blobs, struct iovec **ret_policy_hash, size_t *ret_n_policy_hash, struct iovec *ret_salt, struct iovec *ret_srk, struct iovec *ret_pcrlock_nv, TPM2Flags *ret_flags);
/* Default to PCR 7 only */
#define TPM2_PCR_INDEX_DEFAULT UINT32_C(7)

View File

@ -23,6 +23,7 @@
#include "user-util.h"
#include "userdb.h"
#include "verbs.h"
#include "virt.h"
static enum {
OUTPUT_CLASSIC,
@ -139,10 +140,16 @@ static int show_user(UserRecord *ur, Table *table) {
return 0;
}
static bool test_show_mapped(void) {
/* Show mapped user range only in environments where user mapping is a thing. */
return running_in_userns() > 0;
}
static const struct {
uid_t first, last;
const char *name;
UserDisposition disposition;
bool (*test)(void);
} uid_range_table[] = {
{
.first = 1,
@ -175,11 +182,12 @@ static const struct {
.last = MAP_UID_MAX,
.name = "mapped",
.disposition = USER_REGULAR,
.test = test_show_mapped,
},
};
static int table_add_uid_boundaries(Table *table, const UIDRange *p) {
int r;
int r, n_added = 0;
assert(table);
@ -192,6 +200,9 @@ static int table_add_uid_boundaries(Table *table, const UIDRange *p) {
if (!uid_range_covers(p, i->first, i->last - i->first + 1))
continue;
if (i->test && !i->test())
continue;
name = strjoin(special_glyph(SPECIAL_GLYPH_ARROW_DOWN),
" begin ", i->name, " users ",
special_glyph(SPECIAL_GLYPH_ARROW_DOWN));
@ -249,9 +260,11 @@ static int table_add_uid_boundaries(Table *table, const UIDRange *p) {
TABLE_INT, 1); /* sort after any other entry with the same UID */
if (r < 0)
return table_log_add_error(r);
n_added += 2;
}
return ELEMENTSOF(uid_range_table) * 2;
return n_added;
}
static int add_unavailable_uid(Table *table, uid_t start, uid_t end) {
@ -565,16 +578,22 @@ static int show_group(GroupRecord *gr, Table *table) {
}
static int table_add_gid_boundaries(Table *table, const UIDRange *p) {
int r;
int r, n_added = 0;
assert(table);
FOREACH_ELEMENT(i, uid_range_table) {
_cleanup_free_ char *name = NULL, *comment = NULL;
if (!FLAGS_SET(arg_disposition_mask, UINT64_C(1) << i->disposition))
continue;
if (!uid_range_covers(p, i->first, i->last - i->first + 1))
continue;
if (i->test && !i->test())
continue;
name = strjoin(special_glyph(SPECIAL_GLYPH_ARROW_DOWN),
" begin ", i->name, " groups ",
special_glyph(SPECIAL_GLYPH_ARROW_DOWN));
@ -626,9 +645,11 @@ static int table_add_gid_boundaries(Table *table, const UIDRange *p) {
TABLE_INT, 1); /* sort after any other entry with the same GID */
if (r < 0)
return table_log_add_error(r);
n_added += 2;
}
return ELEMENTSOF(uid_range_table) * 2;
return n_added;
}
static int add_unavailable_gid(Table *table, uid_t start, uid_t end) {