mirror of
https://github.com/systemd/systemd.git
synced 2024-12-25 01:34:28 +03:00
Merge pull request #2648 from keszybz/dnssec-work
Better support for DANE, shell completion
This commit is contained in:
commit
e4d86881d5
@ -5205,6 +5205,12 @@ systemd_resolve_LDADD = \
|
||||
bin_PROGRAMS += \
|
||||
systemd-resolve
|
||||
|
||||
dist_bashcompletion_data += \
|
||||
shell-completion/bash/systemd-resolve
|
||||
|
||||
dist_zshcompletion_data += \
|
||||
shell-completion/zsh/_systemd-resolve
|
||||
|
||||
tests += \
|
||||
test-dns-packet \
|
||||
test-resolve-tables \
|
||||
|
@ -83,6 +83,13 @@
|
||||
<arg choice="plain"><replaceable>USER@DOMAIN</replaceable></arg>
|
||||
</cmdsynopsis>
|
||||
|
||||
<cmdsynopsis>
|
||||
<command>systemd-resolve</command>
|
||||
<arg choice="opt" rep="repeat">OPTIONS</arg>
|
||||
<command> --tlsa</command>
|
||||
<arg choice="plain"><replaceable>DOMAIN<optional>:PORT</optional></replaceable></arg>
|
||||
</cmdsynopsis>
|
||||
|
||||
<cmdsynopsis>
|
||||
<command>systemd-resolve</command>
|
||||
<arg choice="opt" rep="repeat">OPTIONS</arg>
|
||||
@ -121,10 +128,15 @@
|
||||
is assumed to be a domain name, that is already prefixed with an SRV type, and an SRV lookup is done (no
|
||||
TXT).</para>
|
||||
|
||||
<para>The <option>--openpgp</option> switch may be use to query PGP keys stored as the
|
||||
<para>The <option>--openpgp</option> switch may be used to query PGP keys stored as
|
||||
<ulink url="https://tools.ietf.org/html/draft-wouters-dane-openpgp-02">OPENPGPKEY</ulink> resource records.
|
||||
When this option is specified one or more e-mail address must be specified.</para>
|
||||
|
||||
<para>The <option>--tlsa</option> switch maybe be used to query TLS public
|
||||
keys stored as
|
||||
<ulink url="https://tools.ietf.org/html/rfc6698">TLSA</ulink> resource records.
|
||||
When this option is specified one or more domain names must be specified.</para>
|
||||
|
||||
<para>The <option>--statistics</option> switch may be used to show resolver statistics, including information about
|
||||
the number of successful and failed DNSSEC validations.</para>
|
||||
|
||||
@ -216,6 +228,20 @@
|
||||
printed.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>--tlsa</option></term>
|
||||
|
||||
<listitem><para>Enables TLSA resource record resolution (see above).
|
||||
A query will be performed for each of the specified names prefixed with
|
||||
the port and family
|
||||
(<literal>_<replaceable>port</replaceable>._<replaceable>family</replaceable>.<replaceable>domain</replaceable></literal>).
|
||||
The port number may be specified after a colon
|
||||
(<literal>:</literal>), otherwise <constant>443</constant> will be used
|
||||
by default. The family may be specified as an argument after
|
||||
<option>--tlsa</option>, otherwise <constant>tcp</constant> will be
|
||||
used.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>--cname=</option><replaceable>BOOL</replaceable></term>
|
||||
|
||||
@ -323,6 +349,18 @@ d08ee310438ca124a6149ea5cc21b6313b390dce485576eff96f8722._openpgpkey.fedoraproje
|
||||
mQINBFBHPMsBEACeInGYJCb+7TurKfb6wGyTottCDtiSJB310i37/6ZYoeIay/5soJjlMyf
|
||||
MFQ9T2XNT/0LM6gTa0MpC1st9LnzYTMsT6tzRly1D1UbVI6xw0g0vE5y2Cjk3xUwAynCsSs
|
||||
...
|
||||
</programlisting>
|
||||
</example>
|
||||
|
||||
<example>
|
||||
<title>Retrieve a TLS key (<literal>=tcp</literal> and
|
||||
<literal>:443</literal> could be skipped)</title>
|
||||
|
||||
<programlisting>$ systemd-resolve --tlsa=tcp fedoraproject.org:443
|
||||
_443._tcp.fedoraproject.org IN TLSA 0 0 1 19400be5b7a31fb733917700789d2f0a2471c0c9d506c0e504c06c16d7cb17c0
|
||||
-- Cert. usage: CA constraint
|
||||
-- Selector: Full Certificate
|
||||
-- Matching type: SHA-256
|
||||
</programlisting>
|
||||
</example>
|
||||
</refsect1>
|
||||
|
@ -45,7 +45,10 @@ __get_env() {
|
||||
}
|
||||
|
||||
__get_interfaces(){
|
||||
cut -f 1 -d ' ' /proc/net/dev | tail -n +3 | tr -s '\n' | tr -d ':' | xargs
|
||||
{ cd /sys/class/net && echo *; } | \
|
||||
while read -d' ' -r name; do
|
||||
[[ "$name" != "lo" ]] && echo "$name"
|
||||
done
|
||||
}
|
||||
|
||||
_systemd_nspawn() {
|
||||
|
64
shell-completion/bash/systemd-resolve
Normal file
64
shell-completion/bash/systemd-resolve
Normal file
@ -0,0 +1,64 @@
|
||||
# systemd-resolve(1) completion -*- shell-script -*-
|
||||
#
|
||||
# This file is part of systemd.
|
||||
#
|
||||
# Copyright 2016 Zbigniew Jędrzejewski-Szmek
|
||||
#
|
||||
# systemd 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.
|
||||
#
|
||||
# systemd 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
|
||||
# General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with systemd; If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
__contains_word () {
|
||||
local w word=$1; shift
|
||||
for w in "$@"; do
|
||||
[[ $w = "$word" ]] && return
|
||||
done
|
||||
}
|
||||
|
||||
__get_interfaces(){
|
||||
{ cd /sys/class/net && echo *; } | \
|
||||
while read -d' ' -r name; do
|
||||
[[ "$name" != "lo" ]] && echo "$name"
|
||||
done
|
||||
}
|
||||
|
||||
_systemd-resolve() {
|
||||
local i comps
|
||||
local cur=${COMP_WORDS[COMP_CWORD]} prev=${COMP_WORDS[COMP_CWORD-1]}
|
||||
local -A OPTS=(
|
||||
[STANDALONE]='-h --help --version -4 -6
|
||||
--service --openpgp --tlsa --statistics --reset-statistics
|
||||
--service-address=no --service-txt=no
|
||||
--cname=no --search=no --legend=no'
|
||||
[ARG]='-i --interface -p --protocol -t --type -c --class'
|
||||
)
|
||||
|
||||
if __contains_word "$prev" ${OPTS[ARG]}; then
|
||||
case $prev in
|
||||
--interface|-i)
|
||||
comps=$( __get_interfaces )
|
||||
;;
|
||||
--protocol|-p|--type|-t|--class|-c)
|
||||
comps=$( systemd-resolve --legend=no "$prev" help; echo help )
|
||||
;;
|
||||
esac
|
||||
COMPREPLY=( $(compgen -W '$comps' -- "$cur") )
|
||||
return 0
|
||||
fi
|
||||
|
||||
if [[ "$cur" = -* ]]; then
|
||||
COMPREPLY=( $(compgen -W '${OPTS[*]}' -- "$cur") )
|
||||
return 0
|
||||
fi
|
||||
}
|
||||
|
||||
complete -F _systemd-resolve systemd-resolve
|
64
shell-completion/zsh/_systemd-resolve
Normal file
64
shell-completion/zsh/_systemd-resolve
Normal file
@ -0,0 +1,64 @@
|
||||
#compdef systemd-resolve
|
||||
|
||||
#
|
||||
# This file is part of systemd.
|
||||
#
|
||||
# Copyright 2016 Zbigniew Jędrzejewski-Szmek
|
||||
#
|
||||
# systemd 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.
|
||||
#
|
||||
# systemd 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
|
||||
# General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with systemd; If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
_dns_protocol() {
|
||||
local -a _protocol
|
||||
_protocol=( $(_call_program protocol ${service} --legend=no --protocol help; echo help) )
|
||||
_values 'protocol' "$_protocol[@]"
|
||||
}
|
||||
|
||||
_dns_type() {
|
||||
local -a _type
|
||||
_type=( $(_call_program type ${service} --legend=no --type help; echo help) )
|
||||
_values 'type' "$_type[@]"
|
||||
}
|
||||
|
||||
_dns_class() {
|
||||
local -a _class
|
||||
_class=( $(_call_program class ${service} --legend=no --class help; echo help) )
|
||||
_values 'class' "$_class[@]"
|
||||
}
|
||||
|
||||
_systemd-resolve_none() {
|
||||
_alternative : \
|
||||
'domain:DNS address:' \
|
||||
'address:email address:'
|
||||
}
|
||||
|
||||
_arguments \
|
||||
{-h,--help}'[Print a short help text and exit]' \
|
||||
'--version[Print a short version string and exit]' \
|
||||
'--legend=no[Do not show headers and footers]' \
|
||||
'-4[Resolve IPv4 addresses]' \
|
||||
'-6[Resolve IPv6 addresses]' \
|
||||
{-i+,--interface=}'[Look on interface]:interface:_net_interfaces' \
|
||||
{-p+,--protocol=}'[Look via protocol]:protocol:_dns_protocol' \
|
||||
{-t+,--type=}'[Query RR with DNS type]:type:_dns_type' \
|
||||
{-c+,--class=}'[Query RR with DNS class]:class:_dns_class' \
|
||||
'--service[Resolve services]' \
|
||||
'--service-address=no[Do not resolve address for services]' \
|
||||
'--service-txt=no[Do not resolve TXT records for services]' \
|
||||
'--openpgp[Query OpenPGP public key]' \
|
||||
'--tlsa[Query TLS public key]' \
|
||||
'--cname=no[Do not follow CNAME redirects]' \
|
||||
'--search=no[Do not use search domains]' \
|
||||
'--statistics[Show resolver statistics]' \
|
||||
'--reset-statistics[Reset resolver statistics]' \
|
||||
'*::default: _systemd-resolve_none'
|
@ -44,12 +44,19 @@ static uint16_t arg_class = 0;
|
||||
static bool arg_legend = true;
|
||||
static uint64_t arg_flags = 0;
|
||||
|
||||
typedef enum ServiceFamily {
|
||||
SERVICE_FAMILY_TCP,
|
||||
SERVICE_FAMILY_UDP,
|
||||
SERVICE_FAMILY_SCTP,
|
||||
_SERVICE_FAMILY_INVALID = -1,
|
||||
} ServiceFamily;
|
||||
static ServiceFamily arg_service_family = SERVICE_FAMILY_TCP;
|
||||
|
||||
typedef enum RawType {
|
||||
RAW_NONE,
|
||||
RAW_PAYLOAD,
|
||||
RAW_PACKET,
|
||||
} RawType;
|
||||
|
||||
static RawType arg_raw = RAW_NONE;
|
||||
|
||||
static enum {
|
||||
@ -57,10 +64,34 @@ static enum {
|
||||
MODE_RESOLVE_RECORD,
|
||||
MODE_RESOLVE_SERVICE,
|
||||
MODE_RESOLVE_OPENPGP,
|
||||
MODE_RESOLVE_TLSA,
|
||||
MODE_STATISTICS,
|
||||
MODE_RESET_STATISTICS,
|
||||
} arg_mode = MODE_RESOLVE_HOST;
|
||||
|
||||
static ServiceFamily service_family_from_string(const char *s) {
|
||||
if (s == NULL || streq(s, "tcp"))
|
||||
return SERVICE_FAMILY_TCP;
|
||||
if (streq(s, "udp"))
|
||||
return SERVICE_FAMILY_UDP;
|
||||
if (streq(s, "sctp"))
|
||||
return SERVICE_FAMILY_SCTP;
|
||||
return _SERVICE_FAMILY_INVALID;
|
||||
}
|
||||
|
||||
static const char* service_family_to_string(ServiceFamily service) {
|
||||
switch(service) {
|
||||
case SERVICE_FAMILY_TCP:
|
||||
return "_tcp";
|
||||
case SERVICE_FAMILY_UDP:
|
||||
return "_udp";
|
||||
case SERVICE_FAMILY_SCTP:
|
||||
return "_sctp";
|
||||
default:
|
||||
assert_not_reached("invalid service");
|
||||
}
|
||||
}
|
||||
|
||||
static void print_source(uint64_t flags, usec_t rtt) {
|
||||
char rtt_str[FORMAT_TIMESTAMP_MAX];
|
||||
|
||||
@ -844,6 +875,38 @@ static int resolve_openpgp(sd_bus *bus, const char *address) {
|
||||
arg_type ?: DNS_TYPE_OPENPGPKEY);
|
||||
}
|
||||
|
||||
static int resolve_tlsa(sd_bus *bus, const char *address) {
|
||||
const char *port;
|
||||
uint16_t port_num = 443;
|
||||
_cleanup_free_ char *full = NULL;
|
||||
int r;
|
||||
|
||||
assert(bus);
|
||||
assert(address);
|
||||
|
||||
port = strrchr(address, ':');
|
||||
if (port) {
|
||||
r = safe_atou16(port + 1, &port_num);
|
||||
if (r < 0 || port_num == 0)
|
||||
return log_error_errno(r, "Invalid port \"%s\".", port + 1);
|
||||
|
||||
address = strndupa(address, port - address);
|
||||
}
|
||||
|
||||
r = asprintf(&full, "_%u.%s.%s",
|
||||
port_num,
|
||||
service_family_to_string(arg_service_family),
|
||||
address);
|
||||
if (r < 0)
|
||||
return log_oom();
|
||||
|
||||
log_debug("Looking up \"%s\".", full);
|
||||
|
||||
return resolve_record(bus, full,
|
||||
arg_class ?: DNS_CLASS_IN,
|
||||
arg_type ?: DNS_TYPE_TLSA);
|
||||
}
|
||||
|
||||
static int show_statistics(sd_bus *bus) {
|
||||
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
|
||||
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
|
||||
@ -1031,6 +1094,7 @@ static void help(void) {
|
||||
" --service-address=BOOL Resolve address for services (default: yes)\n"
|
||||
" --service-txt=BOOL Resolve TXT records for services (default: yes)\n"
|
||||
" --openpgp Query OpenPGP public key\n"
|
||||
" --tlsa Query TLS public key\n"
|
||||
" --cname=BOOL Follow CNAME redirects (default: yes)\n"
|
||||
" --search=BOOL Use search domains for single-label names\n"
|
||||
" (default: yes)\n"
|
||||
@ -1050,6 +1114,7 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
ARG_SERVICE_ADDRESS,
|
||||
ARG_SERVICE_TXT,
|
||||
ARG_OPENPGP,
|
||||
ARG_TLSA,
|
||||
ARG_RAW,
|
||||
ARG_SEARCH,
|
||||
ARG_STATISTICS,
|
||||
@ -1069,6 +1134,7 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
{ "service-address", required_argument, NULL, ARG_SERVICE_ADDRESS },
|
||||
{ "service-txt", required_argument, NULL, ARG_SERVICE_TXT },
|
||||
{ "openpgp", no_argument, NULL, ARG_OPENPGP },
|
||||
{ "tlsa", optional_argument, NULL, ARG_TLSA },
|
||||
{ "raw", optional_argument, NULL, ARG_RAW },
|
||||
{ "search", required_argument, NULL, ARG_SEARCH },
|
||||
{ "statistics", no_argument, NULL, ARG_STATISTICS, },
|
||||
@ -1183,6 +1249,15 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
arg_mode = MODE_RESOLVE_OPENPGP;
|
||||
break;
|
||||
|
||||
case ARG_TLSA:
|
||||
arg_mode = MODE_RESOLVE_TLSA;
|
||||
arg_service_family = service_family_from_string(optarg);
|
||||
if (arg_service_family < 0) {
|
||||
log_error("Unknown service family \"%s\".", optarg);
|
||||
return -EINVAL;
|
||||
}
|
||||
break;
|
||||
|
||||
case ARG_RAW:
|
||||
if (on_tty()) {
|
||||
log_error("Refusing to write binary data to tty.");
|
||||
@ -1261,7 +1336,7 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (arg_type != 0 && arg_mode != MODE_RESOLVE_RECORD) {
|
||||
if (arg_type != 0 && arg_mode == MODE_RESOLVE_SERVICE) {
|
||||
log_error("--service and --type= may not be combined.");
|
||||
return -EINVAL;
|
||||
}
|
||||
@ -1378,6 +1453,24 @@ int main(int argc, char **argv) {
|
||||
}
|
||||
break;
|
||||
|
||||
case MODE_RESOLVE_TLSA:
|
||||
if (argc < optind + 1) {
|
||||
log_error("Domain name required.");
|
||||
r = -EINVAL;
|
||||
goto finish;
|
||||
|
||||
}
|
||||
|
||||
r = 0;
|
||||
while (optind < argc) {
|
||||
int k;
|
||||
|
||||
k = resolve_tlsa(bus, argv[optind++]);
|
||||
if (k < 0)
|
||||
r = k;
|
||||
}
|
||||
break;
|
||||
|
||||
case MODE_STATISTICS:
|
||||
if (argc > optind) {
|
||||
log_error("Too many arguments.");
|
||||
|
@ -1116,40 +1116,30 @@ const char *dns_resource_record_to_string(DnsResourceRecord *rr) {
|
||||
|
||||
case DNS_TYPE_TLSA: {
|
||||
const char *cert_usage, *selector, *matching_type;
|
||||
char *ss;
|
||||
int n;
|
||||
|
||||
cert_usage = tlsa_cert_usage_to_string(rr->tlsa.cert_usage);
|
||||
selector = tlsa_selector_to_string(rr->tlsa.selector);
|
||||
matching_type = tlsa_matching_type_to_string(rr->tlsa.matching_type);
|
||||
|
||||
r = asprintf(&s, "%s %u %u %u %n",
|
||||
t = hexmem(rr->sshfp.fingerprint, rr->sshfp.fingerprint_size);
|
||||
if (!t)
|
||||
return NULL;
|
||||
|
||||
r = asprintf(&s,
|
||||
"%s %u %u %u %s\n"
|
||||
" -- Cert. usage: %s\n"
|
||||
" -- Selector: %s\n"
|
||||
" -- Matching type: %s",
|
||||
k,
|
||||
rr->tlsa.cert_usage,
|
||||
rr->tlsa.selector,
|
||||
rr->tlsa.matching_type,
|
||||
&n);
|
||||
if (r < 0)
|
||||
return NULL;
|
||||
|
||||
r = base64_append(&s, n,
|
||||
rr->tlsa.data, rr->tlsa.data_size,
|
||||
8, columns());
|
||||
if (r < 0)
|
||||
return NULL;
|
||||
|
||||
r = asprintf(&ss, "%s\n"
|
||||
" -- Cert. usage: %s\n"
|
||||
" -- Selector: %s\n"
|
||||
" -- Matching type: %s",
|
||||
s,
|
||||
t,
|
||||
cert_usage,
|
||||
selector,
|
||||
matching_type);
|
||||
if (r < 0)
|
||||
return NULL;
|
||||
free(s);
|
||||
s = ss;
|
||||
|
||||
break;
|
||||
}
|
||||
@ -1228,13 +1218,16 @@ ssize_t dns_resource_record_payload(DnsResourceRecord *rr, void **out) {
|
||||
case DNS_TYPE_MX:
|
||||
case DNS_TYPE_LOC:
|
||||
case DNS_TYPE_DS:
|
||||
case DNS_TYPE_SSHFP:
|
||||
case DNS_TYPE_DNSKEY:
|
||||
case DNS_TYPE_RRSIG:
|
||||
case DNS_TYPE_NSEC:
|
||||
case DNS_TYPE_NSEC3:
|
||||
return -EINVAL;
|
||||
|
||||
case DNS_TYPE_SSHFP:
|
||||
*out = rr->sshfp.fingerprint;
|
||||
return rr->sshfp.fingerprint_size;
|
||||
|
||||
case DNS_TYPE_TLSA:
|
||||
*out = rr->tlsa.data;
|
||||
return rr->tlsa.data_size;
|
||||
|
Loading…
Reference in New Issue
Block a user