summaryrefslogtreecommitdiff
path: root/cfgdir.c
diff options
context:
space:
mode:
authorDavid Härdeman <david@hardeman.nu>2020-06-19 19:11:48 +0200
committerDavid Härdeman <david@hardeman.nu>2020-06-19 19:11:48 +0200
commit91a7ca50f3f8a2c7bb01113fa3849cb5e153a70f (patch)
tree18c5b7c76f4ec3069e9033a1c222eefd2c945da6 /cfgdir.c
parent445647adc4475c0b8264ce8b6c97d748eec69e7b (diff)
Add support for async DNS
Diffstat (limited to 'cfgdir.c')
-rw-r--r--cfgdir.c174
1 files changed, 143 insertions, 31 deletions
diff --git a/cfgdir.c b/cfgdir.c
index 436fe13..d6c48e1 100644
--- a/cfgdir.c
+++ b/cfgdir.c
@@ -1,3 +1,4 @@
+#define _GNU_SOURCE
#include <stdio.h>
#include <ctype.h>
#include <string.h>
@@ -5,9 +6,6 @@
#include <sys/inotify.h>
#include <dirent.h>
#include <errno.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netdb.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <inttypes.h>
@@ -18,6 +16,98 @@
#include "config.h"
#include "server.h"
+static void
+scfg_dns_cb(struct dns_async *dns, bool (*server_cb)(struct cfg *, struct server *, struct saddr *))
+{
+ struct server *scfg;
+ struct cfg *cfg;
+ struct sockaddr_in *in4;
+ struct sockaddr_in6 *in6;
+ struct saddr *saddr;
+ struct addrinfo *results = NULL, *ai;
+ int r;
+
+ if (!dns || !dns->priv || !server_cb) {
+ error("invalid arguments\n");
+ return;
+ }
+
+ scfg = dns->priv;
+ cfg = scfg->cfg;
+
+ debug(DBG_DNS, "called, dns: %p, name: %s, scfg: %p, scfg->name: %s\n",
+ dns, dns->name, scfg, scfg->name);
+
+ r = gai_error(&dns->gcb);
+ if (r == EAI_INPROGRESS) {
+ /* This shouldn't happen, assume we'll get called again */
+ error("called with request in progress\n");
+ return;
+ } else if (r == EAI_CANCELED) {
+ /* The server must be in the process of going away */
+ goto out;
+ } else if (r < 0) {
+ error("DNS lookup of %s:%s failed: %s\n",
+ dns->name, dns->port, gai_strerror(r));
+ goto out;
+ }
+
+ results = dns->gcb.ar_result;
+
+ for (ai = results; ai; ai = ai->ai_next) {
+ saddr = zmalloc(sizeof(*saddr));
+ if (!saddr) {
+ error("DNS lookup of %s:%s failed: %m\n", dns->name, dns->port);
+ goto out;
+ }
+
+ switch (ai->ai_family) {
+ case AF_INET:
+ in4 = (struct sockaddr_in *)ai->ai_addr;
+ saddr_set_ipv4(saddr, in4->sin_addr.s_addr, in4->sin_port);
+ server_cb(cfg, scfg, saddr);
+ break;
+
+ case AF_INET6:
+ in6 = (struct sockaddr_in6 *)ai->ai_addr;
+ saddr_set_ipv6(saddr, &in6->sin6_addr, in6->sin6_port);
+ server_cb(cfg, scfg, saddr);
+ break;
+
+ default:
+ error("getaddrinfo(%s:%s): unknown address family (%i)\n",
+ dns->name, dns->port, ai->ai_family);
+ xfree(saddr);
+ break;
+ }
+ }
+
+out:
+ freeaddrinfo(results);
+ list_del(&dns->list);
+ xfree(dns);
+ uring_task_put(cfg, &scfg->task);
+ server_commit(cfg, scfg);
+}
+
+static void
+scfg_local_dns_cb(struct dns_async *dns)
+{
+ scfg_dns_cb(dns, server_add_local);
+}
+
+static void
+scfg_remote_dns_cb(struct dns_async *dns)
+{
+ scfg_dns_cb(dns, server_add_remote);
+}
+
+static void
+scfg_rcon_dns_cb(struct dns_async *dns)
+{
+ scfg_dns_cb(dns, server_add_rcon);
+}
+
enum scfg_keys {
SCFG_KEY_INVALID = 0,
SCFG_KEY_TYPE,
@@ -51,11 +141,11 @@ struct cfg_key_value_map scfg_key_map[] = {
}, {
.key_name = "local",
.key_value = SCFG_KEY_LOCAL,
- .value_type = CFG_VAL_TYPE_ADDRS,
+ .value_type = CFG_VAL_TYPE_ASYNC_ADDRS,
}, {
.key_name = "remote",
.key_value = SCFG_KEY_REMOTE,
- .value_type = CFG_VAL_TYPE_ADDRS,
+ .value_type = CFG_VAL_TYPE_ASYNC_ADDRS,
}, {
.key_name = "idle_timeout",
.key_value = SCFG_KEY_IDLE_TIMEOUT,
@@ -79,7 +169,7 @@ struct cfg_key_value_map scfg_key_map[] = {
}, {
.key_name = "rcon",
.key_value = SCFG_KEY_RCON,
- .value_type = CFG_VAL_TYPE_ADDRS,
+ .value_type = CFG_VAL_TYPE_ASYNC_ADDRS,
}, {
.key_name = "rcon_password",
.key_value = SCFG_KEY_RCON_PASSWORD,
@@ -95,6 +185,40 @@ struct cfg_key_value_map scfg_key_map[] = {
}
};
+static bool
+handle_dns(struct cfg *cfg, struct server *scfg, const char *type,
+ struct cfg_value *value, dns_callback_t *async_cb,
+ bool (*sync_cb)(struct cfg *, struct server *, struct saddr *))
+{
+ struct saddr *saddr, *tmp;
+ struct dns_async *dns;
+
+ switch (value->type) {
+ case CFG_VAL_TYPE_ADDRS:
+ debug(DBG_DNS, "%s: got immediate addrs\n", type);
+
+ list_for_each_entry_safe(saddr, tmp, &value->saddrs, list) {
+ list_del(&saddr->list);
+ sync_cb(cfg, scfg, saddr);
+ }
+ return true;
+
+ case CFG_VAL_TYPE_ASYNC_ADDRS:
+ debug(DBG_DNS, "%s: doing async lookup of DNS record: %p\n",
+ type, value->dns_async);
+
+ dns = value->dns_async;
+ dns->callback = async_cb;
+ dns->priv = scfg;
+ list_add(&dns->list, &scfg->dnslookups);
+ uring_task_get(cfg, &scfg->task);
+ return true;
+
+ default:
+ return false;
+ }
+}
+
static void
scfg_parse(struct cfg *cfg, struct server *scfg)
{
@@ -106,7 +230,7 @@ scfg_parse(struct cfg *cfg, struct server *scfg)
while (true) {
int key;
const char *keyname;
- union cfg_value value;
+ struct cfg_value value;
if (!config_parse_line(cfg, scfg->name, &pos, scfg_key_map,
&key, &keyname, &value))
@@ -139,25 +263,17 @@ scfg_parse(struct cfg *cfg, struct server *scfg)
return;
break;
- case SCFG_KEY_LOCAL: {
- struct saddr *saddr, *tmp;
-
- list_for_each_entry_safe(saddr, tmp, &value.saddrs, list) {
- list_del(&saddr->list);
- server_add_local(cfg, scfg, saddr);
- }
+ case SCFG_KEY_LOCAL:
+ if (!handle_dns(cfg, scfg, "local", &value,
+ scfg_local_dns_cb, server_add_local))
+ return;
break;
- }
-
- case SCFG_KEY_REMOTE: {
- struct saddr *saddr, *tmp;
- list_for_each_entry_safe(saddr, tmp, &value.saddrs, list) {
- list_del(&saddr->list);
- server_add_remote(cfg, scfg, saddr);
- }
+ case SCFG_KEY_REMOTE:
+ if (!handle_dns(cfg, scfg, "remote", &value,
+ scfg_remote_dns_cb, server_add_remote))
+ return;
break;
- }
case SCFG_KEY_IDLE_TIMEOUT:
if (!server_set_idle_timeout(cfg, scfg, value.uint16))
@@ -197,15 +313,11 @@ scfg_parse(struct cfg *cfg, struct server *scfg)
return;
break;
- case SCFG_KEY_RCON: {
- struct saddr *saddr, *tmp;
-
- list_for_each_entry_safe(saddr, tmp, &value.saddrs, list) {
- list_del(&saddr->list);
- server_add_rcon(cfg, scfg, saddr);
- }
+ case SCFG_KEY_RCON:
+ if (!handle_dns(cfg, scfg, "rcon", &value,
+ scfg_rcon_dns_cb, server_add_rcon))
+ return;
break;
- }
case SCFG_KEY_RCON_PASSWORD:
if (!server_set_rcon_password(cfg, scfg, value.str))