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();
}
/** 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");
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));
}
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)
{
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);
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;
* 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;
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;
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) {
struct session {
bool outgoing;
bool throttled;
+ bool has_tls;
uv_timer_t timeout;
struct qr_task *buffering;
array_t(struct qr_task *) tasks;
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);
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"
{
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;
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'},
{"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;
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;
+ }
}
}
worker_reclaim(worker);
mp_delete(pool.ctx);
array_clear(addr_set);
+ array_clear(tls_set);
kr_crypto_cleanup();
return ret;
}
/** 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) {
}
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;
}
}
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. */
NET_DOWN = 0 << 0,
NET_UDP = 1 << 0,
NET_TCP = 1 << 1,
+ NET_TLS = 1 << 2,
};
struct endpoint {
* 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) */