]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
resolved: refactor GnuTLS specific code in separate source file
authorIwan Timmer <irtimmer@gmail.com>
Tue, 17 Jul 2018 06:34:29 +0000 (23:34 -0700)
committerIwan Timmer <irtimmer@gmail.com>
Fri, 27 Jul 2018 20:23:17 +0000 (21:23 +0100)
This is a first step towards supporting alternative TLS implementations for DNS-over-TLS.

Co-authored-by: Filipe Brandenburger <filbranden@google.com>
src/resolve/meson.build
src/resolve/resolved-dns-server.c
src/resolve/resolved-dns-server.h
src/resolve/resolved-dns-stream.c
src/resolve/resolved-dns-stream.h
src/resolve/resolved-dns-transaction.c
src/resolve/resolved-dnstls-gnutls.c [new file with mode: 0644]
src/resolve/resolved-dnstls-gnutls.h [new file with mode: 0644]
src/resolve/resolved-dnstls.h [new file with mode: 0644]

index 15f3835d5570526b13c7fb5efdf357bcf081889d..5955875f59a1719728b35c1b1c69a7666afa3bdc 100644 (file)
@@ -63,6 +63,7 @@ systemd_resolved_sources = files('''
         resolved-dns-stub.c
         resolved-etc-hosts.h
         resolved-etc-hosts.c
+        resolved-dnstls.h
 '''.split())
 
 resolvectl_sources = files('''
@@ -141,6 +142,7 @@ systemd_resolved_sources += [resolved_gperf_c, resolved_dnssd_gperf_c]
 
 systemd_resolved_dependencies = [threads, libgpg_error, libm, libidn]
 if conf.get('ENABLE_DNS_OVER_TLS') == 1
+        systemd_resolved_sources += [files(['resolved-dnstls-gnutls.c', 'resolved-dnstls-gnutls.h'])]
         systemd_resolved_dependencies += [libgnutls]
 endif
 
index 6645db467cb2b87d6eeaea723e5d5310cf7d3225..eff3dbb2752daab006c4544a34338ea79ee96077 100644 (file)
@@ -81,8 +81,7 @@ int dns_server_new(
         s->linked = true;
 
 #if ENABLE_DNS_OVER_TLS
-        /* Do not verify cerificate */
-        gnutls_certificate_allocate_credentials(&s->tls_cert_cred);
+        dnstls_server_init(s);
 #endif
 
         /* A new DNS server that isn't fallback is added and the one
@@ -122,11 +121,7 @@ DnsServer* dns_server_unref(DnsServer *s)  {
         dns_stream_unref(s->stream);
 
 #if ENABLE_DNS_OVER_TLS
-        if (s->tls_cert_cred)
-                gnutls_certificate_free_credentials(s->tls_cert_cred);
-
-        if (s->tls_session_data.data)
-                gnutls_free(s->tls_session_data.data);
+        dnstls_server_free(s);
 #endif
 
         free(s->server_string);
index 53d45a63614c2cb297153eaec9447b304572b7e1..fda12510495ad8f1a2335273a27a964a8df0d546 100644 (file)
@@ -3,10 +3,6 @@
 
 #include "in-addr-util.h"
 
-#if ENABLE_DNS_OVER_TLS
-#include <gnutls/gnutls.h>
-#endif
-
 typedef struct DnsServer DnsServer;
 
 typedef enum DnsServerType {
@@ -41,6 +37,9 @@ int dns_server_feature_level_from_string(const char *s) _pure_;
 
 #include "resolved-link.h"
 #include "resolved-manager.h"
+#if ENABLE_DNS_OVER_TLS
+#include "resolved-dnstls.h"
+#endif
 
 struct DnsServer {
         Manager *manager;
@@ -58,8 +57,7 @@ struct DnsServer {
         DnsStream *stream;
 
 #if ENABLE_DNS_OVER_TLS
-        gnutls_certificate_credentials_t tls_cert_cred;
-        gnutls_datum_t tls_session_data;
+        DnsTlsServerData dnstls_data;
 #endif
 
         DnsServerFeatureLevel verified_feature_level;
index 066daef96e8a9603851c4fb1648ad88d8e5dbeea..ee392efb9da13fb9146fea82649602e8f3ae1762 100644 (file)
@@ -11,8 +11,6 @@
 #define DNS_STREAM_TIMEOUT_USEC (10 * USEC_PER_SEC)
 #define DNS_STREAMS_MAX 128
 
-#define WRITE_TLS_DATA 1
-
 static void dns_stream_stop(DnsStream *s) {
         assert(s);
 
@@ -45,14 +43,11 @@ static int dns_stream_complete(DnsStream *s, int error) {
         assert(s);
 
 #if ENABLE_DNS_OVER_TLS
-        if (s->tls_session && IN_SET(error, ETIMEDOUT, 0)) {
+        if (s->encrypted) {
                 int r;
 
-                r = gnutls_bye(s->tls_session, GNUTLS_SHUT_RDWR);
-                if (r == GNUTLS_E_AGAIN && !s->tls_bye) {
-                        dns_stream_ref(s); /* keep reference for closing TLS session */
-                        s->tls_bye = true;
-                } else
+                r = dnstls_stream_shutdown(s, error);
+                if (r != -EAGAIN)
                         dns_stream_stop(s);
         } else
 #endif
@@ -191,32 +186,22 @@ static int dns_stream_identify(DnsStream *s) {
         return 0;
 }
 
-static ssize_t dns_stream_writev(DnsStream *s, const struct iovec *iov, size_t iovcnt, int flags) {
+ssize_t dns_stream_writev(DnsStream *s, const struct iovec *iov, size_t iovcnt, int flags) {
         ssize_t r;
 
         assert(s);
         assert(iov);
 
 #if ENABLE_DNS_OVER_TLS
-        if (s->tls_session && !(flags & WRITE_TLS_DATA)) {
+        if (s->encrypted && !(flags & DNS_STREAM_WRITE_TLS_DATA)) {
                 ssize_t ss;
                 size_t i;
 
                 r = 0;
                 for (i = 0; i < iovcnt; i++) {
-                        ss = gnutls_record_send(s->tls_session, iov[i].iov_base, iov[i].iov_len);
-                        if (ss < 0) {
-                                switch(ss) {
-
-                                case GNUTLS_E_INTERRUPTED:
-                                        return -EINTR;
-                                case GNUTLS_E_AGAIN:
-                                        return -EAGAIN;
-                                default:
-                                        log_debug("Failed to invoke gnutls_record_send: %s", gnutls_strerror(ss));
-                                        return -EIO;
-                                }
-                        }
+                        ss = dnstls_stream_write(s, iov[i].iov_base, iov[i].iov_len);
+                        if (ss < 0)
+                                return ss;
 
                         r += ss;
                         if (ss != (ssize_t) iov[i].iov_len)
@@ -258,28 +243,9 @@ static ssize_t dns_stream_read(DnsStream *s, void *buf, size_t count) {
         ssize_t ss;
 
 #if ENABLE_DNS_OVER_TLS
-        if (s->tls_session) {
-                ss = gnutls_record_recv(s->tls_session, buf, count);
-                if (ss < 0) {
-                        switch(ss) {
-
-                        case GNUTLS_E_INTERRUPTED:
-                                return -EINTR;
-                        case GNUTLS_E_AGAIN:
-                                return -EAGAIN;
-                        default:
-                                log_debug("Failed to invoke gnutls_record_send: %s", gnutls_strerror(ss));
-                                return -EIO;
-                        }
-                } else if (s->on_connection) {
-                        int r;
-
-                        r = s->on_connection(s);
-                        s->on_connection = NULL; /* only call once */
-                        if (r < 0)
-                                return r;
-                }
-        } else
+        if (s->encrypted)
+                ss = dnstls_stream_read(s, buf, count);
+        else
 #endif
         {
                 ss = read(s->fd, buf, count);
@@ -290,22 +256,6 @@ static ssize_t dns_stream_read(DnsStream *s, void *buf, size_t count) {
         return ss;
 }
 
-#if ENABLE_DNS_OVER_TLS
-static ssize_t dns_stream_tls_writev(gnutls_transport_ptr_t p, const giovec_t * iov, int iovcnt) {
-        int r;
-
-        assert(p);
-
-        r = dns_stream_writev((DnsStream*) p, (struct iovec*) iov, iovcnt, WRITE_TLS_DATA);
-        if (r < 0) {
-                errno = -r;
-                return -1;
-        }
-
-        return r;
-}
-#endif
-
 static int on_stream_timeout(sd_event_source *es, usec_t usec, void *userdata) {
         DnsStream *s = userdata;
 
@@ -321,36 +271,13 @@ static int on_stream_io(sd_event_source *es, int fd, uint32_t revents, void *use
         assert(s);
 
 #if ENABLE_DNS_OVER_TLS
-        if (s->tls_bye) {
-                assert(s->tls_session);
-
-                r = gnutls_bye(s->tls_session, GNUTLS_SHUT_RDWR);
-                if (r != GNUTLS_E_AGAIN) {
-                        s->tls_bye = false;
-                        dns_stream_unref(s);
-                }
-
-                return 0;
-        }
-
-        if (s->tls_handshake < 0) {
-                assert(s->tls_session);
-
-                s->tls_handshake = gnutls_handshake(s->tls_session);
-                if (s->tls_handshake >= 0) {
-                        if (s->on_connection && !(gnutls_session_get_flags(s->tls_session) & GNUTLS_SFLAGS_FALSE_START)) {
-                                r = s->on_connection(s);
-                                s->on_connection = NULL; /* only call once */
-                                if (r < 0)
-                                        return r;
-                        }
-                } else {
-                        if (gnutls_error_is_fatal(s->tls_handshake))
-                                return dns_stream_complete(s, ECONNREFUSED);
-                        else
-                                return 0;
-                }
+        if (s->encrypted) {
+                r = dnstls_stream_on_io(s);
 
+                if (r == DNSTLS_STREAM_CLOSED || r == -EAGAIN)
+                        return 0;
+                else if (r < 0)
+                        return dns_stream_complete(s, -r);
         }
 #endif
 
@@ -506,8 +433,8 @@ DnsStream *dns_stream_unref(DnsStream *s) {
         }
 
 #if ENABLE_DNS_OVER_TLS
-        if (s->tls_session)
-                gnutls_deinit(s->tls_session);
+        if (s->encrypted)
+                dnstls_stream_free(s);
 #endif
 
         ORDERED_SET_FOREACH(p, s->write_queue, i)
@@ -586,21 +513,6 @@ int dns_stream_new(Manager *m, DnsStream **ret, DnsProtocol protocol, int fd, co
         return 0;
 }
 
-#if ENABLE_DNS_OVER_TLS
-int dns_stream_connect_tls(DnsStream *s, gnutls_session_t tls_session) {
-        gnutls_transport_set_ptr2(tls_session, (gnutls_transport_ptr_t) (long) s->fd, s);
-        gnutls_transport_set_vec_push_function(tls_session, &dns_stream_tls_writev);
-
-        s->encrypted = true;
-        s->tls_session = tls_session;
-        s->tls_handshake = gnutls_handshake(tls_session);
-        if (s->tls_handshake < 0 && gnutls_error_is_fatal(s->tls_handshake))
-                return -ECONNREFUSED;
-
-        return 0;
-}
-#endif
-
 int dns_stream_write_packet(DnsStream *s, DnsPacket *p) {
         int r;
 
index 9a0da226d834e641631bd5960589236f90f16bc6..d64dc3b1d42ab386bba79e8591037c4d84e942dc 100644 (file)
@@ -8,11 +8,12 @@ typedef struct DnsStream DnsStream;
 #include "resolved-dns-packet.h"
 #include "resolved-dns-transaction.h"
 #include "resolved-manager.h"
-
 #if ENABLE_DNS_OVER_TLS
-#include <gnutls/gnutls.h>
+#include "resolved-dnstls.h"
 #endif
 
+#define DNS_STREAM_WRITE_TLS_DATA 1
+
 /* Streams are used by three subsystems:
  *
  *   1. The normal transaction logic when doing a DNS or LLMNR lookup via TCP
@@ -40,9 +41,7 @@ struct DnsStream {
         socklen_t tfo_salen;
 
 #if ENABLE_DNS_OVER_TLS
-        gnutls_session_t tls_session;
-        int tls_handshake;
-        bool tls_bye;
+        DnsTlsStreamData dnstls_data;
 #endif
 
         sd_event_source *io_event_source;
@@ -69,7 +68,7 @@ struct DnsStream {
 
 int dns_stream_new(Manager *m, DnsStream **s, DnsProtocol protocol, int fd, const union sockaddr_union *tfo_address);
 #if ENABLE_DNS_OVER_TLS
-int dns_stream_connect_tls(DnsStream *s, gnutls_session_t tls_session);
+int dns_stream_connect_tls(DnsStream *s, void *tls_session);
 #endif
 DnsStream *dns_stream_unref(DnsStream *s);
 DnsStream *dns_stream_ref(DnsStream *s);
@@ -77,6 +76,7 @@ DnsStream *dns_stream_ref(DnsStream *s);
 DEFINE_TRIVIAL_CLEANUP_FUNC(DnsStream*, dns_stream_unref);
 
 int dns_stream_write_packet(DnsStream *s, DnsPacket *p);
+ssize_t dns_stream_writev(DnsStream *s, const struct iovec *iov, size_t iovcnt, int flags);
 
 static inline bool DNS_STREAM_QUEUED(DnsStream *s) {
         assert(s);
index 89d311811a7dbb5271f0f114e6671d87e8535390..db30997d04e8ea30a71ebcfe7633e1fec6d6e0a2 100644 (file)
 #include "resolved-dns-cache.h"
 #include "resolved-dns-transaction.h"
 #include "resolved-llmnr.h"
-#include "string-table.h"
-
 #if ENABLE_DNS_OVER_TLS
-#include <gnutls/socket.h>
+#include "resolved-dnstls.h"
 #endif
+#include "string-table.h"
 
 #define TRANSACTIONS_MAX 4096
 #define TRANSACTION_TCP_TIMEOUT_USEC (10U*USEC_PER_SEC)
@@ -503,20 +502,6 @@ static int dns_transaction_on_stream_packet(DnsTransaction *t, DnsPacket *p) {
         return 0;
 }
 
-static int on_stream_connection(DnsStream *s) {
-#if ENABLE_DNS_OVER_TLS
-        /* Store TLS Ticket for faster succesive TLS handshakes */
-        if (s->tls_session && s->server) {
-                if (s->server->tls_session_data.data)
-                        gnutls_free(s->server->tls_session_data.data);
-
-                gnutls_session_get_data2(s->tls_session, &s->server->tls_session_data);
-        }
-#endif
-
-        return 0;
-}
-
 static int on_stream_complete(DnsStream *s, int error) {
         _cleanup_(dns_stream_unrefp) DnsStream *p = NULL;
         DnsTransaction *t, *n;
@@ -578,9 +563,6 @@ static int dns_transaction_emit_tcp(DnsTransaction *t) {
         _cleanup_(dns_stream_unrefp) DnsStream *s = NULL;
         union sockaddr_union sa;
         int r;
-#if ENABLE_DNS_OVER_TLS
-        gnutls_session_t gs;
-#endif
 
         assert(t);
 
@@ -655,32 +637,12 @@ static int dns_transaction_emit_tcp(DnsTransaction *t) {
 #if ENABLE_DNS_OVER_TLS
                 if (DNS_SERVER_FEATURE_LEVEL_IS_TLS(t->current_feature_level)) {
                         assert(t->server);
-
-                        r = gnutls_init(&gs, GNUTLS_CLIENT | GNUTLS_ENABLE_FALSE_START | GNUTLS_NONBLOCK);
-                        if (r < 0)
-                                return r;
-
-                        /* As DNS-over-TLS is a recent protocol, older TLS versions can be disabled */
-                        r = gnutls_priority_set_direct(gs, "NORMAL:-VERS-ALL:+VERS-TLS1.2", NULL);
-                        if (r < 0)
-                                return r;
-
-                        r = gnutls_credentials_set(gs, GNUTLS_CRD_CERTIFICATE, t->server->tls_cert_cred);
-                        if (r < 0)
-                                return r;
-
-                        if (t->server->tls_session_data.size > 0)
-                                gnutls_session_set_data(gs, t->server->tls_session_data.data, t->server->tls_session_data.size);
-
-                        gnutls_handshake_set_timeout(gs, GNUTLS_DEFAULT_HANDSHAKE_TIMEOUT);
-
-                        r = dns_stream_connect_tls(s, gs);
+                        r = dnstls_stream_connect_tls(s, t->server);
                         if (r < 0)
                                 return r;
                 }
 #endif
 
-                s->on_connection = on_stream_connection;
                 s->complete = on_stream_complete;
                 s->on_packet = dns_stream_on_packet;
 
diff --git a/src/resolve/resolved-dnstls-gnutls.c b/src/resolve/resolved-dnstls-gnutls.c
new file mode 100644 (file)
index 0000000..9c348ce
--- /dev/null
@@ -0,0 +1,198 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+
+#if !ENABLE_DNS_OVER_TLS || !HAVE_GNUTLS
+#error This source file requires DNS-over-TLS to be enabled and GnuTLS to be available.
+#endif
+
+#include "resolved-dnstls.h"
+#include "resolved-dns-stream.h"
+
+#include <gnutls/socket.h>
+
+DEFINE_TRIVIAL_CLEANUP_FUNC(gnutls_session_t, gnutls_deinit);
+
+static ssize_t dnstls_stream_writev(gnutls_transport_ptr_t p, const giovec_t *iov, int iovcnt) {
+        int r;
+
+        assert(p);
+
+        r = dns_stream_writev((DnsStream*) p, (const struct iovec*) iov, iovcnt, DNS_STREAM_WRITE_TLS_DATA);
+        if (r < 0) {
+                errno = -r;
+                return -1;
+        }
+
+        return r;
+}
+
+int dnstls_stream_connect_tls(DnsStream *stream, DnsServer *server) {
+        _cleanup_(gnutls_deinitp) gnutls_session_t gs;
+        int r;
+
+        assert(stream);
+        assert(server);
+
+        r = gnutls_init(&gs, GNUTLS_CLIENT | GNUTLS_ENABLE_FALSE_START | GNUTLS_NONBLOCK);
+        if (r < 0)
+                return r;
+
+        /* As DNS-over-TLS is a recent protocol, older TLS versions can be disabled */
+        r = gnutls_priority_set_direct(gs, "NORMAL:-VERS-ALL:+VERS-TLS1.2", NULL);
+        if (r < 0)
+                return r;
+
+        r = gnutls_credentials_set(gs, GNUTLS_CRD_CERTIFICATE, server->dnstls_data.cert_cred);
+        if (r < 0)
+                return r;
+
+        if (server->dnstls_data.session_data.size > 0) {
+                gnutls_session_set_data(gs, server->dnstls_data.session_data.data, server->dnstls_data.session_data.size);
+
+                // Clear old session ticket
+                gnutls_free(server->dnstls_data.session_data.data);
+                server->dnstls_data.session_data.data = NULL;
+                server->dnstls_data.session_data.size = 0;
+        }
+
+        gnutls_handshake_set_timeout(gs, GNUTLS_DEFAULT_HANDSHAKE_TIMEOUT);
+
+        gnutls_transport_set_ptr2(gs, (gnutls_transport_ptr_t) (long) stream->fd, stream);
+        gnutls_transport_set_vec_push_function(gs, &dnstls_stream_writev);
+
+        stream->encrypted = true;
+        stream->dnstls_data.handshake = gnutls_handshake(gs);
+        if (stream->dnstls_data.handshake < 0 && gnutls_error_is_fatal(stream->dnstls_data.handshake))
+                return -ECONNREFUSED;
+
+        stream->dnstls_data.session = TAKE_PTR(gs);
+
+        return 0;
+}
+
+void dnstls_stream_free(DnsStream *stream) {
+        assert(stream);
+        assert(stream->encrypted);
+
+        if (stream->dnstls_data.session)
+                gnutls_deinit(stream->dnstls_data.session);
+}
+
+int dnstls_stream_on_io(DnsStream *stream) {
+        int r;
+
+        assert(stream);
+        assert(stream->encrypted);
+        assert(stream->dnstls_data.session);
+
+        if (stream->dnstls_data.shutdown) {
+                r = gnutls_bye(stream->dnstls_data.session, GNUTLS_SHUT_RDWR);
+                if (r == GNUTLS_E_AGAIN)
+                        return -EAGAIN;
+                else if (r < 0)
+                        log_debug("Failed to invoke gnutls_bye: %s", gnutls_strerror(r));
+
+                stream->dnstls_data.shutdown = false;
+                dns_stream_unref(stream);
+                return DNSTLS_STREAM_CLOSED;
+        } else if (stream->dnstls_data.handshake < 0) {
+                stream->dnstls_data.handshake = gnutls_handshake(stream->dnstls_data.session);
+                if (stream->dnstls_data.handshake == GNUTLS_E_AGAIN)
+                        return -EAGAIN;
+                else if (stream->dnstls_data.handshake < 0) {
+                        log_debug("Failed to invoke gnutls_handshake: %s", gnutls_strerror(stream->dnstls_data.handshake));
+                        if (gnutls_error_is_fatal(stream->dnstls_data.handshake))
+                                return -ECONNREFUSED;
+                }
+        }
+
+        return 0;
+}
+
+int dnstls_stream_shutdown(DnsStream *stream, int error) {
+        int r;
+
+        assert(stream);
+        assert(stream->encrypted);
+        assert(stream->dnstls_data.session);
+
+        /* Store TLS Ticket for faster succesive TLS handshakes */
+        if (stream->server && stream->server->dnstls_data.session_data.size == 0 && stream->dnstls_data.handshake == GNUTLS_E_SUCCESS)
+                gnutls_session_get_data2(stream->dnstls_data.session, &stream->server->dnstls_data.session_data);
+
+        if (IN_SET(error, ETIMEDOUT, 0)) {
+                r = gnutls_bye(stream->dnstls_data.session, GNUTLS_SHUT_RDWR);
+                if (r == GNUTLS_E_AGAIN) {
+                        if (!stream->dnstls_data.shutdown) {
+                                stream->dnstls_data.shutdown = true;
+                                dns_stream_ref(stream);
+                                return -EAGAIN;
+                        }
+                } else if (r < 0)
+                        log_debug("Failed to invoke gnutls_bye: %s", gnutls_strerror(r));
+        }
+
+        return 0;
+}
+
+ssize_t dnstls_stream_write(DnsStream *stream, const char *buf, size_t count) {
+        ssize_t ss;
+
+        assert(stream);
+        assert(stream->encrypted);
+        assert(stream->dnstls_data.session);
+        assert(buf);
+
+        ss = gnutls_record_send(stream->dnstls_data.session, buf, count);
+        if (ss < 0)
+                switch(ss) {
+                case GNUTLS_E_INTERRUPTED:
+                        return -EINTR;
+                case GNUTLS_E_AGAIN:
+                        return -EAGAIN;
+                default:
+                        log_debug("Failed to invoke gnutls_record_send: %s", gnutls_strerror(ss));
+                        return -EPIPE;
+                }
+
+        return ss;
+}
+
+ssize_t dnstls_stream_read(DnsStream *stream, void *buf, size_t count) {
+        ssize_t ss;
+
+        assert(stream);
+        assert(stream->encrypted);
+        assert(stream->dnstls_data.session);
+        assert(buf);
+
+        ss = gnutls_record_recv(stream->dnstls_data.session, buf, count);
+        if (ss < 0)
+                switch(ss) {
+                case GNUTLS_E_INTERRUPTED:
+                        return -EINTR;
+                case GNUTLS_E_AGAIN:
+                        return -EAGAIN;
+                default:
+                        log_debug("Failed to invoke gnutls_record_recv: %s", gnutls_strerror(ss));
+                        return -EPIPE;
+                }
+
+        return ss;
+}
+
+void dnstls_server_init(DnsServer *server) {
+        assert(server);
+
+        /* Do not verify cerificate */
+        gnutls_certificate_allocate_credentials(&server->dnstls_data.cert_cred);
+}
+
+void dnstls_server_free(DnsServer *server) {
+        assert(server);
+
+        if (server->dnstls_data.cert_cred)
+                gnutls_certificate_free_credentials(server->dnstls_data.cert_cred);
+
+        if (server->dnstls_data.session_data.data)
+                gnutls_free(server->dnstls_data.session_data.data);
+}
diff --git a/src/resolve/resolved-dnstls-gnutls.h b/src/resolve/resolved-dnstls-gnutls.h
new file mode 100644 (file)
index 0000000..8309f8d
--- /dev/null
@@ -0,0 +1,21 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+#pragma once
+
+#if !ENABLE_DNS_OVER_TLS || !HAVE_GNUTLS
+#error This source file requires DNS-over-TLS to be enabled and GnuTLS to be available.
+#endif
+
+#include <stdbool.h>
+
+#include <gnutls/gnutls.h>
+
+struct DnsTlsServerData {
+        gnutls_certificate_credentials_t cert_cred;
+        gnutls_datum_t session_data;
+};
+
+struct DnsTlsStreamData {
+        gnutls_session_t session;
+        int handshake;
+        bool shutdown;
+};
diff --git a/src/resolve/resolved-dnstls.h b/src/resolve/resolved-dnstls.h
new file mode 100644 (file)
index 0000000..32befc6
--- /dev/null
@@ -0,0 +1,28 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+#pragma once
+
+#if !ENABLE_DNS_OVER_TLS
+#error This source file requires DNS-over-TLS to be enabled
+#endif
+
+typedef struct DnsTlsServerData DnsTlsServerData;
+typedef struct DnsTlsStreamData DnsTlsStreamData;
+
+#if HAVE_GNUTLS
+#include "resolved-dnstls-gnutls.h"
+#endif
+
+#include "resolved-dns-stream.h"
+#include "resolved-dns-transaction.h"
+
+#define DNSTLS_STREAM_CLOSED 1
+
+int dnstls_stream_connect_tls(DnsStream *stream, DnsServer *server);
+void dnstls_stream_free(DnsStream *stream);
+int dnstls_stream_on_io(DnsStream *stream);
+int dnstls_stream_shutdown(DnsStream *stream, int error);
+ssize_t dnstls_stream_write(DnsStream *stream, const char *buf, size_t count);
+ssize_t dnstls_stream_read(DnsStream *stream, void *buf, size_t count);
+
+void dnstls_server_init(DnsServer *server);
+void dnstls_server_free(DnsServer *server);