summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile.am4
-rw-r--r--man/systemd-resolve.xml19
-rw-r--r--src/resolve/resolve-tool.c69
-rw-r--r--src/shared/gcrypt-util.c29
-rw-r--r--src/shared/gcrypt-util.h1
5 files changed, 113 insertions, 9 deletions
diff --git a/Makefile.am b/Makefile.am
index d2cf9360ed..e63015476c 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -5291,7 +5291,9 @@ systemd_resolve_SOURCES = \
src/resolve/resolved-dns-question.c \
src/resolve/resolved-dns-question.h \
src/resolve/dns-type.c \
- src/resolve/dns-type.h
+ src/resolve/dns-type.h \
+ src/shared/gcrypt-util.c \
+ src/shared/gcrypt-util.h
nodist_systemd_resolve_SOURCES = \
src/resolve/dns_type-from-name.h \
diff --git a/man/systemd-resolve.xml b/man/systemd-resolve.xml
index f1e663c5bb..0defa2d7fb 100644
--- a/man/systemd-resolve.xml
+++ b/man/systemd-resolve.xml
@@ -79,6 +79,13 @@
<cmdsynopsis>
<command>systemd-resolve</command>
<arg choice="opt" rep="repeat">OPTIONS</arg>
+ <command> --openpgp</command>
+ <arg choice="plain"><replaceable>USER@DOMAIN</replaceable></arg>
+ </cmdsynopsis>
+
+ <cmdsynopsis>
+ <command>systemd-resolve</command>
+ <arg choice="opt" rep="repeat">OPTIONS</arg>
<command> --statistics</command>
</cmdsynopsis>
@@ -114,6 +121,10 @@
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
+ <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>--statistics</option> switch may be used to show resolver statistics, including information about
the number of succesful and failed DNSSEC validations.</para>
@@ -198,6 +209,14 @@
</varlistentry>
<varlistentry>
+ <term><option>--openpgp</option></term>
+
+ <listitem><para>Enables OPENPGPKEY resource record resolution (see above). Specified e-mail
+ addresses are converted to the corresponding DNS domain name, and any OPENPGPKEY keys are
+ printed.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
<term><option>--cname=</option><replaceable>BOOL</replaceable></term>
<listitem><para>Takes a boolean parameter. If true (the default), DNS CNAME or DNAME redirections are
diff --git a/src/resolve/resolve-tool.c b/src/resolve/resolve-tool.c
index 9bee953839..6d1bc6d0f9 100644
--- a/src/resolve/resolve-tool.c
+++ b/src/resolve/resolve-tool.c
@@ -19,6 +19,7 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
+#include <gcrypt.h>
#include <getopt.h>
#include <net/if.h>
@@ -30,6 +31,7 @@
#include "bus-util.h"
#include "escape.h"
#include "in-addr-util.h"
+#include "gcrypt-util.h"
#include "parse-util.h"
#include "resolved-def.h"
#include "resolved-dns-packet.h"
@@ -48,6 +50,7 @@ static enum {
MODE_RESOLVE_HOST,
MODE_RESOLVE_RECORD,
MODE_RESOLVE_SERVICE,
+ MODE_RESOLVE_OPENPGP,
MODE_STATISTICS,
MODE_RESET_STATISTICS,
} arg_mode = MODE_RESOLVE_HOST;
@@ -547,15 +550,10 @@ static int resolve_rfc4501(sd_bus *bus, const char *name) {
} else
n = p;
- if (type == 0)
- type = arg_type;
- if (type == 0)
- type = DNS_TYPE_A;
-
if (class == 0)
- class = arg_class;
- if (class == 0)
- class = DNS_CLASS_IN;
+ class = arg_class ?: DNS_CLASS_IN;
+ if (type == 0)
+ type = arg_type ?: DNS_TYPE_A;
return resolve_record(bus, n, class, type);
@@ -765,6 +763,36 @@ static int resolve_service(sd_bus *bus, const char *name, const char *type, cons
return 0;
}
+static int resolve_openpgp(sd_bus *bus, const char *address) {
+ const char *domain, *full;
+ int r;
+ _cleanup_free_ char *hashed = NULL;
+
+ assert(bus);
+ assert(address);
+
+ domain = strrchr(address, '@');
+ if (!domain) {
+ log_error("Address does not contain '@': \"%s\"", address);
+ return -EINVAL;
+ } else if (domain == address || domain[1] == '\0') {
+ log_error("Address starts or ends with '@': \"%s\"", address);
+ return -EINVAL;
+ }
+ domain++;
+
+ r = string_hashsum(address, domain - 1 - address, GCRY_MD_SHA224, &hashed);
+ if (r < 0)
+ return log_error_errno(r, "Hashing failed: %m");
+
+ full = strjoina(hashed, "._openpgpkey.", domain);
+ log_debug("Looking up \"%s\".", full);
+
+ return resolve_record(bus, full,
+ arg_class ?: DNS_CLASS_IN,
+ arg_type ?: DNS_TYPE_OPENPGPKEY);
+}
+
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;
@@ -947,6 +975,7 @@ static void help(void) {
" --service Resolve service (SRV)\n"
" --service-address=BOOL Do [not] resolve address for services\n"
" --service-txt=BOOL Do [not] resolve TXT records for services\n"
+ " --openpgp Query OpenPGP public key\n"
" --cname=BOOL Do [not] follow CNAME redirects\n"
" --search=BOOL Do [not] use search domains\n"
" --legend=BOOL Do [not] print column headers and meta information\n"
@@ -963,6 +992,7 @@ static int parse_argv(int argc, char *argv[]) {
ARG_CNAME,
ARG_SERVICE_ADDRESS,
ARG_SERVICE_TXT,
+ ARG_OPENPGP,
ARG_SEARCH,
ARG_STATISTICS,
ARG_RESET_STATISTICS,
@@ -980,6 +1010,7 @@ static int parse_argv(int argc, char *argv[]) {
{ "service", no_argument, NULL, ARG_SERVICE },
{ "service-address", required_argument, NULL, ARG_SERVICE_ADDRESS },
{ "service-txt", required_argument, NULL, ARG_SERVICE_TXT },
+ { "openpgp", no_argument, NULL, ARG_OPENPGP },
{ "search", required_argument, NULL, ARG_SEARCH },
{ "statistics", no_argument, NULL, ARG_STATISTICS, },
{ "reset-statistics", no_argument, NULL, ARG_RESET_STATISTICS },
@@ -1089,6 +1120,10 @@ static int parse_argv(int argc, char *argv[]) {
arg_mode = MODE_RESOLVE_SERVICE;
break;
+ case ARG_OPENPGP:
+ arg_mode = MODE_RESOLVE_OPENPGP;
+ break;
+
case ARG_CNAME:
r = parse_boolean(optarg);
if (r < 0)
@@ -1248,6 +1283,24 @@ int main(int argc, char **argv) {
break;
+ case MODE_RESOLVE_OPENPGP:
+ if (argc < optind + 1) {
+ log_error("E-mail address required.");
+ r = -EINVAL;
+ goto finish;
+
+ }
+
+ r = 0;
+ while (optind < argc) {
+ int k;
+
+ k = resolve_openpgp(bus, argv[optind++]);
+ if (k < 0)
+ r = k;
+ }
+ break;
+
case MODE_STATISTICS:
if (argc > optind) {
log_error("Too many arguments.");
diff --git a/src/shared/gcrypt-util.c b/src/shared/gcrypt-util.c
index 3bbc161ef2..b887243849 100644
--- a/src/shared/gcrypt-util.c
+++ b/src/shared/gcrypt-util.c
@@ -38,3 +38,32 @@ void initialize_libgcrypt(bool secmem) {
gcry_control(GCRYCTL_DISABLE_SECMEM);
gcry_control(GCRYCTL_INITIALIZATION_FINISHED, 0);
}
+
+int string_hashsum(const char *s, size_t len, int md_algorithm, char **out) {
+ gcry_md_hd_t md = NULL;
+ size_t hash_size;
+ void *hash;
+ char *enc;
+
+ initialize_libgcrypt(false);
+
+ hash_size = gcry_md_get_algo_dlen(md_algorithm);
+ assert(hash_size > 0);
+
+ gcry_md_open(&md, md_algorithm, 0);
+ if (!md)
+ return -EIO;
+
+ gcry_md_write(md, s, len);
+
+ hash = gcry_md_read(md, 0);
+ if (!hash)
+ return -EIO;
+
+ enc = hexmem(hash, hash_size);
+ if (!enc)
+ return -ENOMEM;
+
+ *out = enc;
+ return 0;
+}
diff --git a/src/shared/gcrypt-util.h b/src/shared/gcrypt-util.h
index 42ce3fd121..c7652c22d1 100644
--- a/src/shared/gcrypt-util.h
+++ b/src/shared/gcrypt-util.h
@@ -22,3 +22,4 @@
#include <stdbool.h>
void initialize_libgcrypt(bool secmem);
+int string_hashsum(const char *s, size_t len, int md_algorithm, char **out);