From 7d9a0b7bb11ca99513cb48a6611d7121ecc35868 Mon Sep 17 00:00:00 2001 From: Dirk Engling Date: Sun, 25 Oct 2026 19:13:36 +0100 Subject: Split options parsing and config code from opentracker.c, it has grown humongous --- opentracker.c | 543 ++-------------------------------------------------------- 1 file changed, 15 insertions(+), 528 deletions(-) (limited to 'opentracker.c') diff --git a/opentracker.c b/opentracker.c index 1b0e119..698669c 100644 --- a/opentracker.c +++ b/opentracker.c @@ -27,6 +27,7 @@ /* Opentracker */ #include "ot_accesslist.h" +#include "ot_config.h" #include "ot_hex.h" #include "ot_http.h" #include "ot_ip.h" @@ -41,29 +42,10 @@ /* Globals */ time_t g_now_seconds; -char *g_redirecturl; uint32_t g_tracker_id; volatile int g_opentracker_running = 1; int g_self_pipe[2]; -static char *g_serverdir; -static char *g_serveruser; - -typedef struct { - ot_ip6 ip; - uint16_t port; - PROTO_FLAG proto; - int shared; - int workers; - int64_t sock; -} ot_listen; -#define OT_LISTEN_INHERIT (-1) - -/* Config entries collected from command line and config files */ -static ot_listen *g_listen; -static size_t g_listen_count; -static int g_listen_shared; -static int g_listen_workers; static void panic(const char *routine) __attribute__((noreturn)); static void panic(const char *routine) { @@ -115,42 +97,6 @@ static void install_signal_handlers(void) { pthread_sigmask(SIG_UNBLOCK, &signal_mask, NULL); } -static void usage(char *name) { - fprintf(stderr, - "Usage: %s [-i ip] [-p port] [-P port] [-r redirect] [-d dir] [-u user] [-A ip[/bits]] [-f config] [-s livesyncport]" -#ifdef WANT_ACCESSLIST_BLACK - " [-b blacklistfile]" -#elif defined(WANT_ACCESSLIST_WHITE) - " [-w whitelistfile]" -#endif - "\n", - name); -} - -#define HELPLINE(opt, desc) fprintf(stderr, "\t%-10s%s\n", opt, desc) -static void help(char *name) { - usage(name); - - HELPLINE("-f config", "include and execute the config file"); - HELPLINE("-i ip", "specify ip to bind to with next -[pP] (default: any, overrides preceeding ones)"); - HELPLINE("-p port", "do bind to tcp port (default: 6969, you may specify more than one)"); - HELPLINE("-P port", "do bind to udp port (default: 6969, you may specify more than one)"); - HELPLINE("-r redirecturl", "specify url where / should be redirected to (default none)"); - HELPLINE("-d dir", "specify directory to try to chroot to (default: \".\")"); - HELPLINE("-u user", "specify user under whose privileges opentracker should run (default: \"nobody\")"); - HELPLINE("-A ip[/bits]", "bless an ip address or net as admin address (e.g. to allow syncs from this address)"); -#ifdef WANT_ACCESSLIST_BLACK - HELPLINE("-b file", "specify blacklist file."); -#elif defined(WANT_ACCESSLIST_WHITE) - HELPLINE("-w file", "specify whitelist file."); -#endif - - fprintf(stderr, "\nExample: ./opentracker -i 127.0.0.1 -p 6969 -P 6969 -f ./opentracker.conf -i 10.1.1.23 -p 2710 -p 80\n"); - fprintf(stderr, " Here -i 127.0.0.1 selects the ip address for the next -p 6969 and -P 6969.\n"); - fprintf(stderr, " If no port is bound from config file or command line, the last address given\n"); - fprintf(stderr, " (or ::1 if none is set) will be used on port 6969.\n"); -} -#undef HELPLINE static ssize_t header_complete(char *request, ssize_t byte_count) { ssize_t i = 0, state = 0; @@ -353,91 +299,9 @@ static void *server_mainloop(void *args) { return 0; } -static void listen_append(const ot_ip6 ip, uint16_t port, PROTO_FLAG proto, int shared, int workers) { - ot_listen *grown = realloc(g_listen, (g_listen_count + 1) * sizeof(ot_listen)); - ot_listen *entry; - - if (!grown) - panic("listen_append"); - g_listen = grown; - - entry = g_listen + g_listen_count++; - memcpy(entry->ip, ip, sizeof(ot_ip6)); - entry->port = port; - entry->proto = proto; - entry->shared = shared; - entry->workers = workers; - entry->sock = -1; -} - -typedef enum { LISTEN_OPTION_UNKNOWN, LISTEN_OPTION_SHARED, LISTEN_OPTION_WORKERS } listen_option_kind; - -typedef struct { - const char *name; - size_t len; - listen_option_kind kind; - int takes_value; -} listen_option_key; - -#define LISTEN_OPTION_KEY(s, k, v) {s, sizeof(s) - 1, k, v} - -static const listen_option_key listen_option_keys[] = { - LISTEN_OPTION_KEY("shared", LISTEN_OPTION_SHARED, 0), - LISTEN_OPTION_KEY("workers", LISTEN_OPTION_WORKERS, 1), -}; -static const size_t listen_option_count = sizeof(listen_option_keys) / sizeof(listen_option_keys[0]); - -static listen_option_kind parse_listen_option(char **p) { - size_t i; - - for (i = 0; i < listen_option_count; ++i) { - const listen_option_key *key = &listen_option_keys[i]; - char delimiter = (*p)[key->len]; - - if (strncmp(*p, key->name, key->len)) - continue; - if (key->takes_value ? delimiter != '=' : (delimiter && !isspace((unsigned char)delimiter))) - continue; - - *p += key->len + (key->takes_value ? 1 : 0); - return key->kind; - } - return LISTEN_OPTION_UNKNOWN; -} - -/* Options trailing an address in a listen statement, in any order */ -static int listen_scan_options(char *p, int *shared, int *workers) { - uint64_t value; - - for (;;) { - while (isspace((unsigned char)*p)) - ++p; - if (!*p) - return 1; - - switch (parse_listen_option(&p)) { - case LISTEN_OPTION_SHARED: - *shared = 1; - break; - case LISTEN_OPTION_WORKERS: { - size_t off = scan_udec(p, &value, UINT_MAX); - - if (!off) - return 0; - *workers = (int)value; - p += off; - break; - } - default: - return 0; - } - } -} - -static int listen_option(int value, int fallback) { return value == OT_LISTEN_INHERIT ? fallback : value; } static void listen_bind_one(ot_listen *entry) { - socket_sharing sharing = listen_option(entry->shared, g_listen_shared) ? SOCKET_SHARED : SOCKET_EXCLUSIVE; + socket_sharing sharing = entry->shared ? SOCKET_SHARED : SOCKET_EXCLUSIVE; #ifdef _DEBUG { @@ -482,305 +346,31 @@ static void listen_bind_one(ot_listen *entry) { /* Bound in the order the entries were given. Note: On macOS SO_REUSEPORT delivers everything to the socket that bound last. */ static void listen_bind_all(void) { - size_t i; + size_t count, i; + ot_listen *entries = config_listen_entries(&count); - for (i = 0; i < g_listen_count; ++i) - listen_bind_one(g_listen + i); + for (i = 0; i < count; ++i) + listen_bind_one(entries + i); } static void listen_start_udp_workers(void) { - size_t i; + size_t count, i; + ot_listen *entries = config_listen_entries(&count); udp_init(); - for (i = 0; i < g_listen_count; ++i) { - ot_listen *entry = g_listen + i; - int workers = listen_option(entry->workers, g_listen_workers); + for (i = 0; i < count; ++i) { + ot_listen *entry = entries + i; - if (entry->proto != FLAG_UDP || workers <= 0) + if (entry->proto != FLAG_UDP || entry->workers <= 0) continue; io_block(entry->sock); - udp_workers_install(entry->sock, (unsigned int)workers); + udp_workers_install(entry->sock, (unsigned int)entry->workers); } } -char *set_config_option(char **option, char *value) { -#ifdef _DEBUG - fprintf(stderr, "Setting config option: %s\n", value); -#endif - while (isspace(*value)) - ++value; - free(*option); - return *option = strdup(value); -} -static int scan_ip6_port(const char *src, ot_ip6 ip, uint16_t *port) { - const char *s = src; - uint64_t value; - int off, bracket = 0; - while (isspace(*s)) - ++s; - if (*s == '[') - ++s, ++bracket; /* for v6 style notation */ - if (!(off = ip_scan(s, ip))) - return 0; - s += off; - if (bracket && *s == ']') - ++s; - if (*s == 0 || isspace(*s)) - return s - src; - if (!ip_is_v4mapped(ip)) { - if (*s != ':' && *s != '.') - return 0; - if (!bracket && *(s) == ':') - return 0; - s++; - } else { - if (*(s++) != ':') - return 0; - } - if (!(off = scan_udec(s, &value, 65535))) - return 0; - *port = (uint16_t)value; - return off + s - src; -} - -static int scan_ip6_net(const char *src, ot_net *net) { - const char *s = src; - uint64_t value; - int off; - while (isspace(*s)) - ++s; - if (!(off = ip_scan(s, net->address))) - return 0; - s += off; - if (*s != '/') - net->bits = 128; - else { - s++; - if (!(off = scan_udec(s, &value, 128))) - return 0; - net->bits = (int)value; - if (ip_is_v4mapped(net->address)) - net->bits += 96; - if (net->bits > 128) - return 0; - s += off; - } - return off + s - src; -} - -typedef enum { - CONFIG_UNKNOWN, - CONFIG_TRACKER_ROOTDIR, - CONFIG_TRACKER_USER, - CONFIG_LISTEN_TCP_UDP, - CONFIG_LISTEN_TCP, - CONFIG_LISTEN_UDP, - CONFIG_LISTEN_UDP_WORKERS, - CONFIG_LISTEN_SHARED, - CONFIG_ACCESS_WHITELIST, - CONFIG_ACCESS_BLACKLIST, - CONFIG_ACCESS_FIFO_ADD, - CONFIG_ACCESS_FIFO_DELETE, - CONFIG_ACCESS_STATS, - CONFIG_ACCESS_STATS_PATH, - CONFIG_ACCESS_PROXY, - CONFIG_TRACKER_REDIRECT_URL, - CONFIG_LIVESYNC_CLUSTER_NODE_IP, - CONFIG_LIVESYNC_CLUSTER_LISTEN, -} config_kind; - -typedef struct { - const char *name; - size_t len; - config_kind kind; -} config_key; - -#define CONFIG_KEY(s, k) { s, sizeof(s) - 1, k } - -static const config_key config_keys[] = { - CONFIG_KEY("tracker.rootdir", CONFIG_TRACKER_ROOTDIR), - CONFIG_KEY("tracker.user", CONFIG_TRACKER_USER), - CONFIG_KEY("listen.tcp_udp", CONFIG_LISTEN_TCP_UDP), - CONFIG_KEY("listen.tcp", CONFIG_LISTEN_TCP), - CONFIG_KEY("listen.udp", CONFIG_LISTEN_UDP), - CONFIG_KEY("listen.udp.workers", CONFIG_LISTEN_UDP_WORKERS), - CONFIG_KEY("listen.shared", CONFIG_LISTEN_SHARED), -#ifdef WANT_ACCESSLIST_WHITE - CONFIG_KEY("access.whitelist", CONFIG_ACCESS_WHITELIST), -#elif defined(WANT_ACCESSLIST_BLACK) - CONFIG_KEY("access.blacklist", CONFIG_ACCESS_BLACKLIST), -#endif -#ifdef WANT_DYNAMIC_ACCESSLIST - CONFIG_KEY("access.fifo_add", CONFIG_ACCESS_FIFO_ADD), - CONFIG_KEY("access.fifo_delete", CONFIG_ACCESS_FIFO_DELETE), -#endif -#ifdef WANT_RESTRICT_STATS - CONFIG_KEY("access.stats", CONFIG_ACCESS_STATS), -#endif - CONFIG_KEY("access.stats_path", CONFIG_ACCESS_STATS_PATH), -#ifdef WANT_IP_FROM_PROXY - CONFIG_KEY("access.proxy", CONFIG_ACCESS_PROXY), -#endif - CONFIG_KEY("tracker.redirect_url", CONFIG_TRACKER_REDIRECT_URL), -#ifdef WANT_SYNC_LIVE - CONFIG_KEY("livesync.cluster.node_ip", CONFIG_LIVESYNC_CLUSTER_NODE_IP), - CONFIG_KEY("livesync.cluster.listen", CONFIG_LIVESYNC_CLUSTER_LISTEN), -#endif -}; -static const size_t config_entry_count = sizeof(config_keys) / sizeof(config_keys[0]); - -static config_kind parse_config_key(char **p) { - size_t i; - for (i = 0; i < config_entry_count; ++i) { - const config_key *key = &config_keys[i]; - if (strncmp(*p, key->name, key->len) == 0 && isspace((unsigned char)(*p)[key->len])) { - *p += key->len + 1; - /* Skip white spaces */ - while (isspace((unsigned char)**p)) - ++(*p); - return key->kind; - } - } - return CONFIG_UNKNOWN; -} - -int parse_configfile(char *config_filename) { - FILE *config_file_handle; - char inbuf[512]; - ot_ip6 tmpip; -#if defined(WANT_RESTRICT_STATS) || defined(WANT_IP_FROM_PROXY) || defined(WANT_SYNC_LIVE) - ot_net tmpnet; -#endif - int bound = 0; - - config_file_handle = fopen(config_filename, "r"); - - if (config_file_handle == NULL) { - fprintf(stderr, "Warning: Can't open config file: %s.", config_filename); - return 0; - } - - while (fgets(inbuf, sizeof(inbuf), config_file_handle)) { - char *p = inbuf, *end; - uint64_t value; - uint16_t tmpport = 6969; - config_kind kind; - - /* Skip white spaces */ - while (isspace((unsigned char)*p)) - ++p; - - /* Ignore comments and empty lines */ - if ((*p == '#') || (*p == '\n') || (*p == 0)) - continue; - - /* consume trailing new lines and spaces */ - end = p + strlen(p); - while (end > p && isspace((unsigned char)end[-1])) - *--end = 0; - - /* Scan for commands */ - kind = parse_config_key(&p); - switch (kind) { - case CONFIG_TRACKER_ROOTDIR: - set_config_option(&g_serverdir, p); - break; - case CONFIG_TRACKER_USER: - set_config_option(&g_serveruser, p); - break; - case CONFIG_LISTEN_TCP_UDP: - case CONFIG_LISTEN_TCP: - case CONFIG_LISTEN_UDP: { - int shared = OT_LISTEN_INHERIT; - int workers = OT_LISTEN_INHERIT; - int off = scan_ip6_port(p, tmpip, &tmpport); - - if (!off || !listen_scan_options(p + off, &shared, &workers)) - goto parse_error; - if (kind != CONFIG_LISTEN_UDP) - listen_append(tmpip, tmpport, FLAG_TCP, shared, OT_LISTEN_INHERIT), ++bound; - if (kind != CONFIG_LISTEN_TCP) - listen_append(tmpip, tmpport, FLAG_UDP, shared, workers), ++bound; - break; - } - case CONFIG_LISTEN_UDP_WORKERS: - if (!scan_udec(p, &value, UINT_MAX)) - goto parse_error; - g_listen_workers = (int)value; - break; - case CONFIG_LISTEN_SHARED: - if (!scan_udec(p, &value, 1)) - goto parse_error; - g_listen_shared = (int)value; - break; -#ifdef WANT_ACCESSLIST_WHITE - case CONFIG_ACCESS_WHITELIST: - set_config_option(&g_accesslist_filename, p); - break; -#elif defined(WANT_ACCESSLIST_BLACK) - case CONFIG_ACCESS_BLACKLIST: - set_config_option(&g_accesslist_filename, p); - break; -#endif -#ifdef WANT_DYNAMIC_ACCESSLIST - case CONFIG_ACCESS_FIFO_ADD: - set_config_option(&g_accesslist_pipe_add, p); - break; - case CONFIG_ACCESS_FIFO_DELETE: - set_config_option(&g_accesslist_pipe_delete, p); - break; -#endif -#ifdef WANT_RESTRICT_STATS - case CONFIG_ACCESS_STATS: - if (!scan_ip6_net(p, &tmpnet)) - goto parse_error; - accesslist_bless_net(&tmpnet, OT_PERMISSION_MAY_STAT); - break; -#endif - case CONFIG_ACCESS_STATS_PATH: - set_config_option(&g_stats_path, p); - break; -#ifdef WANT_IP_FROM_PROXY - case CONFIG_ACCESS_PROXY: - if (!scan_ip6_net(p, &tmpnet)) - goto parse_error; - accesslist_bless_net(&tmpnet, OT_PERMISSION_MAY_PROXY); - break; -#endif - case CONFIG_TRACKER_REDIRECT_URL: - set_config_option(&g_redirecturl, p); - break; -#ifdef WANT_SYNC_LIVE - case CONFIG_LIVESYNC_CLUSTER_NODE_IP: - if (!scan_ip6_net(p, &tmpnet)) - goto parse_error; - accesslist_bless_net(&tmpnet, OT_PERMISSION_MAY_LIVESYNC); - break; - case CONFIG_LIVESYNC_CLUSTER_LISTEN: - tmpport = LIVESYNC_PORT; - { - int shared = OT_LISTEN_INHERIT, dummy = OT_LISTEN_INHERIT; - int off = scan_ip6_port(p, tmpip, &tmpport); - - if (!off || !listen_scan_options(p + off, &shared, &dummy)) - goto parse_error; - listen_append(tmpip, tmpport, FLAG_MCA, shared, OT_LISTEN_INHERIT); - } - break; -#endif - default: - fprintf(stderr, "Unhandled line in config file: %s\n", inbuf); - break; - parse_error: - fprintf(stderr, "Parse error in config file: %s\n", inbuf); - } - } - fclose(config_file_handle); - return bound; -} void load_state(const char *const state_filename) { FILE *state_filehandle; @@ -873,114 +463,11 @@ static void *time_caching_worker(void *args) { } int main(int argc, char **argv) { - ot_ip6 serverip; - ot_net tmpnet; - int bound = 0, scanon = 1; - uint64_t value; - char *statefile = 0; pthread_t thread_id; /* time cacher */ - memset(serverip, 0, sizeof(ot_ip6)); -#ifdef WANT_V4_ONLY - serverip[10] = serverip[11] = -1; -#endif - random_init(); + config_parse(argc, argv); - while (scanon) { - switch (getopt(argc, argv, - ":i:p:A:P:d:u:r:s:f:l:v" -#ifdef WANT_ACCESSLIST_BLACK - "b:" -#elif defined(WANT_ACCESSLIST_WHITE) - "w:" -#endif - "h")) { - case -1: - scanon = 0; - break; - case 'i': - if (!ip_scan(optarg, serverip)) { - usage(argv[0]); - exit(1); - } - break; -#ifdef WANT_ACCESSLIST_BLACK - case 'b': - set_config_option(&g_accesslist_filename, optarg); - break; -#elif defined(WANT_ACCESSLIST_WHITE) - case 'w': - set_config_option(&g_accesslist_filename, optarg); - break; -#endif - case 'p': - if (!scan_udec(optarg, &value, 65535)) { - usage(argv[0]); - exit(1); - } - listen_append(serverip, (uint16_t)value, FLAG_TCP, OT_LISTEN_INHERIT, OT_LISTEN_INHERIT); - bound++; - break; - case 'P': - if (!scan_udec(optarg, &value, 65535)) { - usage(argv[0]); - exit(1); - } - listen_append(serverip, (uint16_t)value, FLAG_UDP, OT_LISTEN_INHERIT, OT_LISTEN_INHERIT); - bound++; - break; -#ifdef WANT_SYNC_LIVE - case 's': - if (!scan_udec(optarg, &value, 65535)) { - usage(argv[0]); - exit(1); - } - listen_append(serverip, (uint16_t)value, FLAG_MCA, OT_LISTEN_INHERIT, OT_LISTEN_INHERIT); - break; -#endif - case 'd': - set_config_option(&g_serverdir, optarg); - break; - case 'u': - set_config_option(&g_serveruser, optarg); - break; - case 'r': - set_config_option(&g_redirecturl, optarg); - break; - case 'l': - statefile = optarg; - break; - case 'A': - if (!scan_ip6_net(optarg, &tmpnet)) { - usage(argv[0]); - exit(1); - } - accesslist_bless_net(&tmpnet, 0xffff); /* Allow everything for now */ - break; - case 'f': - bound += parse_configfile(optarg); - break; - case 'h': - help(argv[0]); - exit(0); - case 'v': { - char buffer[8192]; - stats_return_tracker_version(buffer); - fputs(buffer, stderr); - exit(0); - } - default: - case '?': - usage(argv[0]); - exit(1); - } - } - - if (!bound) { - listen_append(serverip, 6969, FLAG_TCP, OT_LISTEN_INHERIT, OT_LISTEN_INHERIT); - listen_append(serverip, 6969, FLAG_UDP, OT_LISTEN_INHERIT, OT_LISTEN_INHERIT); - } listen_bind_all(); @@ -1017,8 +504,8 @@ int main(int argc, char **argv) { fprintf(stderr, "... done.\n"); #endif - if (statefile) - load_state(statefile); + if (g_statefile) + load_state(g_statefile); install_signal_handlers(); -- cgit v1.3