summaryrefslogtreecommitdiff
path: root/minecproxy
diff options
context:
space:
mode:
authorDavid Härdeman <david@hardeman.nu>2020-06-23 21:00:15 +0200
committerDavid Härdeman <david@hardeman.nu>2020-06-23 21:00:15 +0200
commitb02e89b8b82f0534fd1490a8780ac89d707181b6 (patch)
tree6911057d68a4cad04605f0d1622320a724713d9a /minecproxy
parentea053d96f7e89e053d4af8d39b04c5428760345f (diff)
Move config-parser to shared lib
Diffstat (limited to 'minecproxy')
-rw-r--r--minecproxy/config-parser.c490
-rw-r--r--minecproxy/config-parser.h59
-rw-r--r--minecproxy/meson.build1
3 files changed, 0 insertions, 550 deletions
diff --git a/minecproxy/config-parser.c b/minecproxy/config-parser.c
deleted file mode 100644
index 9c89cf2..0000000
--- a/minecproxy/config-parser.c
+++ /dev/null
@@ -1,490 +0,0 @@
-#define _GNU_SOURCE
-#include <stdio.h>
-#include <ctype.h>
-#include <string.h>
-#include <stdbool.h>
-#include <errno.h>
-#include <unistd.h>
-#include <arpa/inet.h>
-#include <inttypes.h>
-
-#include "utils.h"
-#include "config-parser.h"
-
-static void
-eat_whitespace_and_comments(char **pos)
-{
- assert_return(pos && *pos);
-
- while (true) {
- while (isspace(**pos))
- (*pos)++;
-
- if (**pos != '#')
- return;
-
- while (**pos != '\r' && **pos != '\n' && **pos != '\0')
- (*pos)++;
- }
-}
-
-static char *
-get_line(char **pos)
-{
- char *begin, *end;
-
- assert_return(pos && *pos, NULL);
-
- begin = *pos;
- while (isspace(*begin))
- begin++;
-
- if (*begin == '\0')
- return NULL;
-
- end = begin;
- while (*end != '\n' && *end != '\0')
- end++;
-
- if (*end == '\0')
- *pos = end;
- else
- *pos = end + 1;
-
- while (isspace(*end)) {
- *end = '\0';
- end--;
- }
-
- return begin;
-}
-
-static bool
-dnslookup(const char *name, uint16_t port, struct cfg_value *rvalue, bool async)
-{
- struct sockaddr_in *in4;
- struct sockaddr_in6 *in6;
- struct dns_async tmp;
- struct dns_async *dns;
- int mode = async ? GAI_NOWAIT : GAI_WAIT;
- struct addrinfo *results = NULL, *ai;
- struct saddr *saddr = NULL;
- bool rv = false;
- int r;
-
- assert_return(!empty_str(name) && strlen(name) < sizeof(dns->name) && port > 0 && rvalue, false);
-
- if (async) {
- rvalue->type = CFG_VAL_TYPE_ASYNC_ADDRS;
- rvalue->dns_async = NULL;
- dns = zmalloc(sizeof(*dns));
- if (!dns) {
- error("async DNS lookup of %s failed: %m", name);
- goto out;
- }
- debug(DBG_DNS, "doing async DNS lookup of %s: %p", name, dns);
- } else {
- memset(&tmp, 0, sizeof(tmp));
- dns = &tmp;
- debug(DBG_DNS, "doing sync DNS lookup of %s", name);
- }
-
- sprintf(dns->name, "%s", name);
- sprintf(dns->port, "%" PRIu16, port);
-
- dns->req.ai_family = AF_UNSPEC;
- dns->req.ai_socktype = SOCK_STREAM;
- dns->req.ai_protocol = 0;
- dns->req.ai_flags = AI_NUMERICSERV;
-
- dns->sev.sigev_notify = SIGEV_SIGNAL;
- dns->sev.sigev_signo = SIGUSR1;
- dns->sev.sigev_value.sival_ptr = dns;
-
- dns->gcb.ar_name = dns->name;
- dns->gcb.ar_service = dns->port;
- dns->gcb.ar_request = &dns->req;
-
- struct gaicb *gcbs[] = { &dns->gcb };
-
- r = getaddrinfo_a(mode, gcbs, ARRAY_SIZE(gcbs), &dns->sev);
- if (r != 0) {
- error("getaddrinfo(%s:%" PRIu16 "): %s", name, port, gai_strerror(r));
- goto out;
- }
-
- if (async) {
- rvalue->dns_async = dns;
- rv = true;
- goto out;
- }
-
- results = dns->gcb.ar_result;
-
- for (ai = results; ai; ai = ai->ai_next) {
- saddr = zmalloc(sizeof(*saddr));
- if (!saddr) {
- error("sync DNS lookup of %s failed: %m", name);
- 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);
- error("addrstr: %s", saddr->addrstr);
- list_add(&saddr->list, &rvalue->saddrs);
- break;
-
- case AF_INET6:
- in6 = (struct sockaddr_in6 *)ai->ai_addr;
- saddr_set_ipv6(saddr, &in6->sin6_addr, in6->sin6_port);
- error("addrstr: %s", saddr->addrstr);
- list_add(&saddr->list, &rvalue->saddrs);
- break;
-
- default:
- error("getaddrinfo(%s:%s): unknown address family (%i)",
- dns->name, dns->port, ai->ai_family);
- xfree(saddr);
- break;
- }
- }
-
- rv = true;
-
-out:
- freeaddrinfo(results);
- return rv;
-}
-
-static bool
-strtosockaddrs(const char *str, struct cfg_value *rvalue, bool async)
-{
- struct saddr *saddr;
- uint16_t port;
- char *tmp;
- struct list_head *list;
- unsigned naddrs = 0;
-
- assert_return(!empty_str(str) && rvalue, false);
-
- rvalue->type = CFG_VAL_TYPE_ADDRS;
- list = &rvalue->saddrs;
- list_init(list);
-
- if (*str == '[') {
- /* IPv6, [a:b:c...h]:p or [*]:p */
- debug(DBG_CFG, "attempting to parse IPv6 addr (%s)", str);
-
- str++;
- tmp = strchr(str, ']');
- if (!tmp)
- goto error;
- *tmp = '\0';
-
- saddr = zmalloc(sizeof(*saddr));
- if (!saddr)
- goto error;
-
- /* early list_add to make sure saddr is free():d on error */
- list_add(&saddr->list, list);
-
- if (streq(str, "*"))
- saddr->in6.sin6_addr = in6addr_any;
- else if (inet_pton(AF_INET6, str, &saddr->in6.sin6_addr) <= 0)
- goto error;
-
- tmp++;
- if (*tmp != ':')
- goto error;
-
- tmp++;
- if (strtou16_strict(tmp, &port) < 0)
- goto error;
-
- saddr_set_ipv6(saddr, NULL, htons(port));
- naddrs++;
-
- } else if (*str == '*') {
- /* IPv4, *:p */
- debug(DBG_CFG, "attempting to parse IPv4 addr (%s)", str);
-
- str++;
- if (*str != ':')
- goto error;
-
- str++;
- if (strtou16_strict(str, &port) < 0)
- goto error;
-
- saddr = zmalloc(sizeof(*saddr));
- if (!saddr)
- goto error;
-
- saddr_set_ipv4(saddr, INADDR_ANY, htons(port));
- list_add(&saddr->list, list);
- naddrs++;
-
- } else if ((tmp = strchr(str, ':'))) {
- /* IPv4, a.b.c.d:p or IPv4/6 hostname:p */
- debug(DBG_CFG, "attempting to parse IPv4 addr or hostname (%s)", str);
-
- *tmp = '\0';
- tmp++;
- if (strtou16_strict(tmp, &port) < 0)
- goto error;
-
- saddr = zmalloc(sizeof(*saddr));
- if (!saddr)
- goto error;
-
- if (inet_pton(AF_INET, str, &saddr->in4.sin_addr) > 0) {
- debug(DBG_CFG, "got an IPv4:port (%s:%" PRIu16 ")", str, port);
- saddr_set_ipv4(saddr, saddr->in4.sin_addr.s_addr, htons(port));
- list_add(&saddr->list, list);
- naddrs++;
- goto success;
- }
-
- xfree(saddr);
- debug(DBG_CFG, "maybe got a hostname:port (%s:%" PRIu16 ")", str, port);
- if (!dnslookup(str, port, rvalue, async))
- goto error;
-
- } else if (strtou16_strict(tmp, &port) == 0) {
- /* Port */
- debug(DBG_CFG, "attempting to parse a port number (%s)", str);
-
- saddr = zmalloc(sizeof(*saddr));
- if (!saddr)
- goto error;
-
- saddr_set_ipv6(saddr, &in6addr_any, htons(port));
- list_add(&saddr->list, list);
- naddrs++;
-
- saddr = zmalloc(sizeof(*saddr));
- if (!saddr)
- goto error;
-
- saddr_set_ipv4(saddr, INADDR_ANY, htons(port));
- list_add(&saddr->list, list);
- naddrs++;
-
- } else {
- /* Unknown */
- error("unable to parse address: %s", str);
- goto error;
- }
-
-success:
- switch (rvalue->type) {
- case CFG_VAL_TYPE_ADDRS:
- if (list_empty(list) || naddrs == 0) {
- error("empty address list");
- return false;
- }
-
- debug(DBG_CFG, "parsed to %u addresses", naddrs);
- return true;
-
- case CFG_VAL_TYPE_ASYNC_ADDRS:
- debug(DBG_CFG, "looking up address asynchronously");
- return true;
-
- default:
- error("invalid rvalue type");
- rvalue->type = CFG_VAL_TYPE_INVALID;
- break;
- }
-
-error:
- if (rvalue->type == CFG_VAL_TYPE_ADDRS && !list_empty(list)) {
- struct saddr *tmp;
-
- list_for_each_entry_safe(saddr, tmp, list, list) {
- list_del(&saddr->list);
- xfree(saddr);
- }
- }
- return false;
-}
-
-/* Returns true if there's data left to parse in buf */
-bool
-config_parse_line(const char *filename, char **buf,
- struct cfg_key_value_map *kvmap, int *rkey,
- const char **rkeyname, struct cfg_value *rvalue)
-{
- char *line, *tmp, *key;
- int i;
-
- assert_return(buf && *buf && kvmap && rkey && rkeyname && rvalue, false);
-
- eat_whitespace_and_comments(buf);
- line = get_line(buf);
- if (!line)
- return false;
-
- debug(DBG_CFG, "%s: parsing config line: %s", filename, line);
-
- tmp = line;
- while (isspace(*tmp))
- tmp++;
-
- if (*tmp == '\0')
- goto error;
-
- key = tmp;
- while (*tmp != '\0' && !isspace(*tmp))
- tmp++;
-
- if (*tmp == '\0')
- goto error;
-
- *tmp = '\0';
- tmp++;
-
- while (isspace(*tmp))
- tmp++;
-
- if (*tmp != '=')
- goto error;
-
- tmp++;
- while (isspace(*tmp))
- tmp++;
-
- if (*tmp == '\0')
- goto error;
-
- for (i = 0; kvmap[i].key_name; i++) {
- if (!streq(kvmap[i].key_name, key))
- continue;
-
- switch (kvmap[i].value_type) {
-
- case CFG_VAL_TYPE_STRING:
- rvalue->type = CFG_VAL_TYPE_STRING;
- rvalue->str = tmp;
- break;
-
- case CFG_VAL_TYPE_UINT16: {
- uint16_t v;
-
- if (strtou16_strict(tmp, &v) < 0)
- goto error;
-
- rvalue->type = CFG_VAL_TYPE_UINT16;
- rvalue->uint16 = v;
- break;
- }
-
- case CFG_VAL_TYPE_ADDRS:
- if (!strtosockaddrs(tmp, rvalue, false))
- goto error;
-
- if (rvalue->type != CFG_VAL_TYPE_ADDRS) {
- error("invalid type returned from strtosockaddrs");
- goto error;
- }
-
- if (list_empty(&rvalue->saddrs)) {
- error("empty address list");
- goto error;
- }
- break;
-
- case CFG_VAL_TYPE_ASYNC_ADDRS:
- if (!strtosockaddrs(tmp, rvalue, true))
- goto error;
-
- switch (rvalue->type) {
- case CFG_VAL_TYPE_ADDRS:
- if (list_empty(&rvalue->saddrs)) {
- error("empty address list");
- goto error;
- }
- break;
-
- case CFG_VAL_TYPE_ASYNC_ADDRS:
- if (!rvalue->dns_async) {
- error("dns_async not set");
- goto error;
- }
- break;
-
- default:
- error("invalid type returned from strtosockaddrs");
- goto error;
- }
-
- break;
-
- case CFG_VAL_TYPE_BOOL:
- if (strcaseeq(tmp, "yes") || strcaseeq(tmp, "true")) {
- rvalue->type = CFG_VAL_TYPE_BOOL;
- rvalue->boolean = true;
- } else if (strcaseeq(tmp, "no") || strcaseeq(tmp, "false")) {
- rvalue->type = CFG_VAL_TYPE_BOOL;
- rvalue->boolean = false;
- } else {
- error("invalid boolean value (%s)", tmp);
- goto error;
- }
- break;
-
- case CFG_VAL_TYPE_INVALID:
- /* fall through */
- default:
- goto error;
- }
-
- /* sanity check */
- if ((rvalue->type != kvmap[i].value_type) &&
- ((kvmap[i].value_type != CFG_VAL_TYPE_ASYNC_ADDRS) &&
- (rvalue->type != CFG_VAL_TYPE_ADDRS))) {
- error("rvalue->type != kvmap->type");
- goto error;
- }
-
- *rkey = kvmap[i].key_value;
- *rkeyname = kvmap[i].key_name;
- return true;
- }
-
-error:
- /* FIXME: the line is already mangled here, a line number would be nice */
- error("%s: invalid config line: %s", filename, line);
- rvalue->type = CFG_VAL_TYPE_INVALID;
- *rkey = 0;
- *rkeyname = NULL;
- return true;
-}
-
-bool
-config_parse_header(const char *filename, const char *title, char **buf)
-{
- char *line;
-
- assert_return(!empty_str(filename) && !empty_str(title) && buf && *buf, false);
-
- eat_whitespace_and_comments(buf);
-
- line = get_line(buf);
- if (!line) {
- error("%s: missing header in configuration file", filename);
- return false;
- } else {
- char titlehdr[strlen(title) + 3];
-
- sprintf(titlehdr, "[%s]", title);
- if (!streq(line, titlehdr)) {
- error("%s: incorrect header in configuration file", filename);
- return false;
- }
- }
-
- return true;
-}
diff --git a/minecproxy/config-parser.h b/minecproxy/config-parser.h
deleted file mode 100644
index 3a117a3..0000000
--- a/minecproxy/config-parser.h
+++ /dev/null
@@ -1,59 +0,0 @@
-#ifndef fooconfigparserhfoo
-#define fooconfigparserhfoo
-
-#define _GNU_SOURCE
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netdb.h>
-#include <signal.h>
-
-enum cfg_value_type {
- CFG_VAL_TYPE_INVALID,
- CFG_VAL_TYPE_STRING,
- CFG_VAL_TYPE_UINT16,
- CFG_VAL_TYPE_ADDRS,
- CFG_VAL_TYPE_ASYNC_ADDRS,
- CFG_VAL_TYPE_BOOL,
-};
-
-struct dns_async;
-
-typedef void (dns_cb_t)(struct dns_async *);
-
-struct dns_async {
- char name[FQDN_STR_LEN + 1];
- char port[PORT_STR_LEN + 1];
- struct addrinfo req;
- struct gaicb gcb;
- struct sigevent sev;
- dns_cb_t *cb;
- void *priv;
- struct list_head list;
-};
-
-struct cfg_key_value_map {
- const char *key_name;
- int key_value;
- enum cfg_value_type value_type;
-};
-
-struct cfg_value {
- enum cfg_value_type type;
- union {
- const char *str;
- uint16_t uint16;
- struct list_head saddrs;
- struct dns_async *dns_async;
- bool boolean;
- };
-};
-
-bool config_parse_line(const char *filename, char **buf,
- struct cfg_key_value_map *kvmap,
- int *rkey, const char **rkeyname,
- struct cfg_value *rvalue);
-
-bool config_parse_header(const char *filename,
- const char *title, char **buf);
-
-#endif
diff --git a/minecproxy/meson.build b/minecproxy/meson.build
index db6a31b..7023f10 100644
--- a/minecproxy/meson.build
+++ b/minecproxy/meson.build
@@ -7,7 +7,6 @@ minecproxy_sources = [
'server-config.c',
'server-rcon.c',
'announce.c',
- 'config-parser.c',
'idle.c',
'ptimer.c',
'igmp.c',