From: Marek Vavrusa Date: Fri, 8 Jul 2016 03:22:51 +0000 (-0700) Subject: daemon: ported DNS/TLS preparation code to 1.1 X-Git-Tag: v1.1.0~7^2~24 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=f22f5226bebcc27dbc7667e1bdba2b91111baaf4;p=thirdparty%2Fknot-resolver.git daemon: ported DNS/TLS preparation code to 1.1 --- diff --git a/daemon/bindings.c b/daemon/bindings.c index 3653f5d39..573a47fd1 100644 --- a/daemon/bindings.c +++ b/daemon/bindings.c @@ -150,6 +150,8 @@ static int net_list_add(const char *key, void *val, void *ext) lua_setfield(L, -2, "udp"); lua_pushboolean(L, ep->flags & NET_TCP); lua_setfield(L, -2, "tcp"); + lua_pushboolean(L, ep->flags & NET_TLS); + lua_setfield(L, -2, "tls"); } lua_setfield(L, -2, key); return kr_ok(); @@ -165,7 +167,7 @@ static int net_list(lua_State *L) } /** Listen on interface address list. */ -static int net_listen_iface(lua_State *L, int port) +static int net_listen_iface(lua_State *L, int port, int flags) { /* Expand 'addr' key if exists */ lua_getfield(L, 1, "addr"); @@ -180,7 +182,7 @@ static int net_listen_iface(lua_State *L, int port) for (size_t i = 0; i < count; ++i) { lua_rawgeti(L, -1, i + 1); int ret = network_listen(&engine->net, lua_tostring(L, -1), - port, NET_TCP|NET_UDP); + port, flags); if (ret != 0) { kr_log_info("[system] bind to '%s#%d' %s\n", lua_tostring(L, -1), port, kr_strerror(ret)); } @@ -191,6 +193,17 @@ static int net_listen_iface(lua_State *L, int port) return 1; } +static bool table_get_flag(lua_State *L, int index, const char *key, bool def) +{ + bool result = def; + lua_getfield(L, index, key); + if (lua_isboolean(L, -1)) { + result = lua_toboolean(L, -1); + } + lua_pop(L, 1); + return result; +} + /** Listen on endpoint. */ static int net_listen(lua_State *L) { @@ -200,18 +213,23 @@ static int net_listen(lua_State *L) if (n > 1 && lua_isnumber(L, 2)) { port = lua_tointeger(L, 2); } + bool tls = (port == KR_DNS_TLS_PORT); + if (n > 2 && lua_istable(L, 3)) { + tls = table_get_flag(L, 3, "tls", tls); + } - /* Process interface or (address, port) pair. */ + /* Process interface or (address, port, flags) triple. */ + int flags = tls ? (NET_TCP|NET_TLS) : (NET_TCP|NET_UDP); if (lua_istable(L, 1)) { - return net_listen_iface(L, port); + return net_listen_iface(L, port, flags); } else if (n < 1 || !lua_isstring(L, 1)) { - format_error(L, "expected 'listen(string addr, number port = 53)'"); + format_error(L, "expected 'listen(string addr, number port = 53[, bool tls = false])'"); lua_error(L); } /* Open resolution context cache */ struct engine *engine = engine_luaget(L); - int ret = network_listen(&engine->net, lua_tostring(L, 1), port, NET_TCP|NET_UDP); + int ret = network_listen(&engine->net, lua_tostring(L, 1), port, flags); if (ret != 0) { format_error(L, kr_strerror(ret)); lua_error(L); diff --git a/daemon/io.c b/daemon/io.c index 11e4f0e35..4058029fc 100644 --- a/daemon/io.c +++ b/daemon/io.c @@ -224,7 +224,7 @@ static void tcp_recv(uv_stream_t *handle, ssize_t nread, const uv_buf_t *buf) mp_flush(worker->pkt_pool.ctx); } -static void tcp_accept(uv_stream_t *master, int status) +static void _tcp_accept(uv_stream_t *master, int status, bool tls) { if (status != 0) { return; @@ -244,6 +244,7 @@ static void tcp_accept(uv_stream_t *master, int status) * It will re-check every half of a request time limit if the connection * is idle and should be terminated, this is an educated guess. */ struct session *session = client->data; + session->has_tls = tls; uv_timer_t *timer = &session->timeout; uv_timer_init(master->loop, timer); timer->data = client; @@ -251,6 +252,16 @@ static void tcp_accept(uv_stream_t *master, int status) io_start_read((uv_handle_t *)client); } +static void tcp_accept(uv_stream_t *master, int status) +{ + _tcp_accept(master, status, false); +} + +static void tls_accept(uv_stream_t *master, int status) +{ + _tcp_accept(master, status, true); +} + static int set_tcp_option(uv_handle_t *handle, int option, int val) { uv_os_fd_t fd = 0; @@ -307,6 +318,11 @@ int tcp_bind(uv_tcp_t *handle, struct sockaddr *addr) return _tcp_bind(handle, addr, tcp_accept); } +int tcp_bind_tls(uv_tcp_t *handle, struct sockaddr *addr) +{ + return _tcp_bind(handle, addr, tls_accept); +} + int tcp_bindfd(uv_tcp_t *handle, int fd) { if (!handle) { diff --git a/daemon/io.h b/daemon/io.h index c4974ddad..ba29cf1e2 100644 --- a/daemon/io.h +++ b/daemon/io.h @@ -28,6 +28,7 @@ struct qr_task; struct session { bool outgoing; bool throttled; + bool has_tls; uv_timer_t timeout; struct qr_task *buffering; array_t(struct qr_task *) tasks; @@ -39,6 +40,7 @@ struct session *session_new(void); int udp_bind(uv_udp_t *handle, struct sockaddr *addr); int udp_bindfd(uv_udp_t *handle, int fd); int tcp_bind(uv_tcp_t *handle, struct sockaddr *addr); +int tcp_bind_tls(uv_tcp_t *handle, struct sockaddr *addr); int tcp_bindfd(uv_tcp_t *handle, int fd); void io_create(uv_loop_t *loop, uv_handle_t *handle, int type); diff --git a/daemon/main.c b/daemon/main.c index 5bf56c726..a4b3df654 100644 --- a/daemon/main.c +++ b/daemon/main.c @@ -276,6 +276,7 @@ static void help(int argc, char *argv[]) printf("Usage: %s [parameters] [rundir]\n", argv[0]); printf("\nParameters:\n" " -a, --addr=[addr] Server address (default: localhost#53).\n" + " -t, --addr=[addr] Server address for TLS (default: off).\n" " -S, --fd=[fd] Listen on given fd (handed out by supervisor).\n" " -c, --config=[path] Config file path (relative to [rundir]) (default: config).\n" " -k, --keyfile=[path] File containing trust anchors (DS or DNSKEY).\n" @@ -382,7 +383,9 @@ int main(int argc, char **argv) { int forks = 1; array_t(char*) addr_set; + array_t(char*) tls_set; array_init(addr_set); + array_init(tls_set); array_t(int) fd_set; array_init(fd_set); char *keyfile = NULL; @@ -394,6 +397,7 @@ int main(int argc, char **argv) int c = 0, li = 0, ret = 0; struct option opts[] = { {"addr", required_argument, 0, 'a'}, + {"tls", required_argument, 0, 't'}, {"fd", required_argument, 0, 'S'}, {"config", required_argument, 0, 'c'}, {"keyfile",required_argument, 0, 'k'}, @@ -404,12 +408,15 @@ int main(int argc, char **argv) {"help", no_argument, 0, 'h'}, {0, 0, 0, 0} }; - while ((c = getopt_long(argc, argv, "a:S:c:f:k:vqVh", opts, &li)) != -1) { + while ((c = getopt_long(argc, argv, "a:t:S:c:f:k:vqVh", opts, &li)) != -1) { switch (c) { case 'a': array_push(addr_set, optarg); break; + case 't': + array_push(tls_set, optarg); + break; case 'S': array_push(fd_set, atoi(optarg)); break; @@ -556,16 +563,33 @@ int main(int argc, char **argv) if (ret != 0) { kr_log_error("[system] listen on fd=%d %s\n", fd_set.at[i], kr_strerror(ret)); ret = EXIT_FAILURE; + break; } } /* Bind to sockets and run */ - for (size_t i = 0; i < addr_set.len; ++i) { - int port = 53; - const char *addr = set_addr(addr_set.at[i], &port); - ret = network_listen(&engine.net, addr, (uint16_t)port, NET_UDP|NET_TCP); - if (ret != 0) { - kr_log_error("[system] bind to '%s#%d' %s\n", addr, port, kr_strerror(ret)); - ret = EXIT_FAILURE; + if (ret == 0) { + for (size_t i = 0; i < addr_set.len; ++i) { + int port = 53; + const char *addr = set_addr(addr_set.at[i], &port); + ret = network_listen(&engine.net, addr, (uint16_t)port, NET_UDP|NET_TCP); + if (ret != 0) { + kr_log_error("[system] bind to '%s#%d' %s\n", addr, port, kr_strerror(ret)); + ret = EXIT_FAILURE; + break; + } + } + } + /* Bind to TLS sockets */ + if (ret == 0) { + for (size_t i = 0; i < tls_set.len; ++i) { + int port = 853; + const char *addr = set_addr(tls_set.at[i], &port); + ret = network_listen(&engine.net, addr, (uint16_t)port, NET_TCP|NET_TLS); + if (ret != 0) { + kr_log_error("[system] bind to '%s#%d' (TLS) %s\n", addr, port, kr_strerror(ret)); + ret = EXIT_FAILURE; + break; + } } } @@ -604,6 +628,7 @@ int main(int argc, char **argv) worker_reclaim(worker); mp_delete(pool.ctx); array_clear(addr_set); + array_clear(tls_set); kr_crypto_cleanup(); return ret; } diff --git a/daemon/network.c b/daemon/network.c index 4ad0e45d4..e0e46e355 100644 --- a/daemon/network.c +++ b/daemon/network.c @@ -130,6 +130,7 @@ static int insert_endpoint(struct network *net, const char *addr, struct endpoin /** Open endpoint protocols. */ static int open_endpoint(struct network *net, struct endpoint *ep, struct sockaddr *sa, uint32_t flags) { + int ret = 0; if (flags & NET_UDP) { ep->udp = malloc(sizeof(*ep->udp)); if (!ep->udp) { @@ -137,7 +138,7 @@ static int open_endpoint(struct network *net, struct endpoint *ep, struct sockad } memset(ep->udp, 0, sizeof(*ep->udp)); handle_init(udp, net->loop, ep->udp, sa->sa_family); - int ret = udp_bind(ep->udp, sa); + ret = udp_bind(ep->udp, sa); if (ret != 0) { return ret; } @@ -150,13 +151,18 @@ static int open_endpoint(struct network *net, struct endpoint *ep, struct sockad } memset(ep->tcp, 0, sizeof(*ep->tcp)); handle_init(tcp, net->loop, ep->tcp, sa->sa_family); - int ret = tcp_bind(ep->tcp, sa); + if (flags & NET_TLS) { + ret = tcp_bind_tls(ep->tcp, sa); + ep->flags |= NET_TLS; + } else { + ret = tcp_bind(ep->tcp, sa); + } if (ret != 0) { return ret; } ep->flags |= NET_TCP; } - return kr_ok(); + return ret; } /** Open fd as endpoint. */ diff --git a/daemon/network.h b/daemon/network.h index 9816420c1..14e91edbe 100644 --- a/daemon/network.h +++ b/daemon/network.h @@ -25,6 +25,7 @@ enum endpoint_flag { NET_DOWN = 0 << 0, NET_UDP = 1 << 0, NET_TCP = 1 << 1, + NET_TLS = 1 << 2, }; struct endpoint { diff --git a/lib/defines.h b/lib/defines.h index 0acc273a1..a9baf643b 100644 --- a/lib/defines.h +++ b/lib/defines.h @@ -61,6 +61,7 @@ static inline int __attribute__((__cold__)) kr_error(int x) { * Defines. */ #define KR_DNS_PORT 53 +#define KR_DNS_TLS_PORT 853 #define KR_EDNS_VERSION 0 #define KR_EDNS_PAYLOAD 4096 /* Default UDP payload (max unfragmented UDP is 1452B) */