]> git.ipfire.org Git - thirdparty/knot-resolver.git/commitdiff
daemon: allow opportunistic DNS over TLS to origins
authorMarek Vavruša <mvavrusa@cloudflare.com>
Tue, 31 Jul 2018 22:12:25 +0000 (15:12 -0700)
committerPetr Špaček <petr.spacek@nic.cz>
Wed, 5 Dec 2018 15:21:46 +0000 (15:21 +0000)
This commit allows opportunistic DNS over TLS to origins configured
as supporting DoT on port 853. It also adds interface for clearing
configured TLS clients to allow runtime reconfiguration.

The general mode of operation is as follows:

1. Produce a new outgoing query
2. Check if the selected upstream address has configured TLS support on port 853
 2a. If it does: upgrade to DNS over TLS, it cannot be downgraded from this point
 2b. If not: continue with preferred protocol

This allows further automatic discovery as in [1], but right now it has to be configured
manually.

[1]: https://tools.ietf.org/id/draft-bortzmeyer-dprive-resolver-to-auth-00.html

(cherrypicked from cloudflare branch, need to be adapted)

daemon/bindings.c
daemon/tls.c
daemon/tls.h
daemon/worker.c

index 259c6c7a4d75d1a10766924d5c7baab5f6f9c432..1dbac917e9913b878b2916f99a95c0df6baa75d9 100644 (file)
@@ -599,6 +599,46 @@ static int net_tls_client(lua_State *L)
        return 1;
 }
 
+static int net_tls_client_clear(lua_State *L)
+{
+       struct engine *engine = engine_luaget(L);
+       if (!engine) {
+               return 0;
+       }
+
+       struct network *net = &engine->net;
+       if (!net) {
+               return 0;
+       }
+
+       if (lua_gettop(L) != 1 || !lua_isstring(L, 1)) {
+               format_error(L, "net.tls_client_clear() requires one parameter (\"address\")");
+               lua_error(L);
+       }
+
+       const char *full_addr = lua_tostring(L, 1);
+
+       char addr[INET6_ADDRSTRLEN];
+       uint16_t port = 0;
+       if (kr_straddr_split(full_addr, addr, sizeof(addr), &port) != kr_ok()) {
+               format_error(L, "invalid IP address");
+               lua_error(L);
+       }
+
+       if (port == 0) {
+               port = 853;
+       }
+
+       int r = tls_client_params_clear(&net->tls_client_params, addr, port);
+       if (r != 0) {
+               lua_pushstring(L, kr_strerror(r));
+               lua_error(L);
+       }
+
+       lua_pushboolean(L, true);
+       return 1;
+}
+
 static int net_tls_padding(lua_State *L)
 {
        struct engine *engine = engine_luaget(L);
@@ -852,6 +892,7 @@ int lib_net(lua_State *L)
                { "tls",          net_tls },
                { "tls_server",   net_tls },
                { "tls_client",   net_tls_client },
+               { "tls_client_clear", net_tls_client_clear },
                { "tls_padding",  net_tls_padding },
                { "tls_sticket_secret", net_tls_sticket_secret_string },
                { "tls_sticket_secret_file", net_tls_sticket_secret_file },
index 6b63a9674b97a5a720c8919f901a414797dd008a..bc6e6f073461d7b339817dd98ba5c779f3fa13b6 100644 (file)
@@ -805,6 +805,49 @@ static int client_paramlist_entry_clear(const char *k, void *v, void *baton)
        return client_paramlist_entry_free(entry);
 }
 
+struct tls_client_paramlist_entry *tls_client_try_upgrade(map_t *tls_client_paramlist,
+                         const struct sockaddr *addr)
+{
+       /* Opportunistic upgrade from port 53 -> 853 */
+       if (kr_inaddr_port(addr) != KR_DNS_PORT) {
+               return NULL;
+       }
+
+       static char key[INET6_ADDRSTRLEN + 6];
+       size_t keylen = sizeof(key);
+       if (kr_inaddr_str(addr, key, &keylen) != 0) {
+               return NULL;
+       }
+
+       /* Rewrite 053 -> 853 */
+       strcpy(key + keylen - 3, "853");
+
+       return map_get(tls_client_paramlist, key);
+}
+
+int tls_client_params_clear(map_t *tls_client_paramlist, const char *addr, uint16_t port)
+{
+       if (!tls_client_paramlist || !addr) {
+               return kr_error(EINVAL);
+       }
+
+       /* Parameters are OK */
+
+       char key[INET6_ADDRSTRLEN + 6];
+       size_t keylen = sizeof(key);
+       if (kr_straddr_join(addr, port, key, &keylen) != kr_ok()) {
+               return kr_error(EINVAL);
+       }
+
+       struct tls_client_paramlist_entry *entry = map_get(tls_client_paramlist, key);
+       if (entry != NULL) {
+               client_paramlist_entry_clear(NULL, (void *)entry, NULL);
+               map_del(tls_client_paramlist, key);
+       }
+       
+       return kr_ok();
+}
+
 int tls_client_params_set(map_t *tls_client_paramlist,
                          const char *addr, uint16_t port,
                          const char *param, tls_client_param_t param_type)
index cb3d4a64f1e79b3f7f42254d3416a7991c54ed4f..e57799c5c0e2ab30c68387d810e0c793e86b309d 100644 (file)
@@ -168,6 +168,9 @@ int tls_set_hs_state(struct tls_common_ctx *ctx, tls_hs_state_t state);
 struct tls_client_paramlist_entry *tls_client_try_upgrade(map_t *tls_client_paramlist,
                          const struct sockaddr *addr);
 
+/*! Clear (remove) TLS parameters for given address. */
+int tls_client_params_clear(map_t *tls_client_paramlist, const char *addr, uint16_t port);
+
 /*! Set TLS authentication parameters for given address.
  * Note: hostnames must be imported before ca files,
  *       otherwise ca files will not be imported at all.
index 5173eacd290430813d4ef6612bc31baae40470ed..73639ef8c1b7237eef5889ccf146de5a1ddb8844 100644 (file)
@@ -1401,6 +1401,22 @@ static int qr_task_step(struct qr_task *task,
                choice += 1;
        }
 
+       /* Upgrade to TLS if the upstream address is configured as DoT capable. */
+       struct engine *engine = ctx->worker->engine;
+       struct network *net = &engine->net;
+       const struct sockaddr *addr = packet_source ? packet_source : task->addrlist;
+       struct tls_client_paramlist_entry *tls_entry = NULL;
+       if (kr_inaddr_port(task->addrlist) == KR_DNS_PORT) {
+               tls_entry = tls_client_try_upgrade(&net->tls_client_params, task->addrlist);
+               if (tls_entry != NULL) {
+                       kr_inaddr_set_port(task->addrlist, KR_DNS_TLS_PORT);
+                       sock_type = SOCK_STREAM;
+               }
+       } else if (sock_type == SOCK_STREAM) {
+               const char *key = tcpsess_key(addr);
+               tls_entry = map_get(&net->tls_client_params, key);
+       }
+
        int ret = 0;
        if (sock_type == SOCK_DGRAM) {
                /* Start fast retransmit with UDP. */