summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDirk Engling <erdgeist@erdgeist.org>2026-10-25 19:13:36 +0100
committerDirk Engling <erdgeist@erdgeist.org>2026-10-25 19:13:36 +0100
commit7d9a0b7bb11ca99513cb48a6611d7121ecc35868 (patch)
treedd8b0df7df4ac80152406005c5a97e2b4acedcbd
parent28f43d02149c96b87555e08f79e0c33c7a07e1af (diff)
Split options parsing and config code from opentracker.c, it has grown humongous
-rw-r--r--Makefile4
-rw-r--r--opentracker.c543
-rw-r--r--ot_config.c565
-rw-r--r--ot_config.h35
4 files changed, 617 insertions, 530 deletions
diff --git a/Makefile b/Makefile
index 9ba0e2d..55be5ba 100644
--- a/Makefile
+++ b/Makefile
@@ -68,8 +68,8 @@ CFLAGS+=-I$(LIBOWFAT_HEADERS) -DGIT_VERSION=$(GIT_VERSION) -Wall -pipe -pthread
68LDFLAGS+=-L$(LIBOWFAT_LIBRARY) -lowfat -pthread 68LDFLAGS+=-L$(LIBOWFAT_LIBRARY) -lowfat -pthread
69 69
70BINARY =opentracker 70BINARY =opentracker
71HEADERS=trackerlogic.h scan_urlencoded_query.h ot_buf.h ot_hex.h ot_ip.h ot_scan.h ot_socket.h ot_mutex.h ot_random.h ot_stats.h ot_vector.h ot_clean.h ot_udp.h ot_iovec.h ot_fullscrape.h ot_accesslist.h ot_http.h ot_livesync.h ot_rijndael.h 71HEADERS=trackerlogic.h scan_urlencoded_query.h ot_buf.h ot_hex.h ot_ip.h ot_config.h ot_scan.h ot_socket.h ot_mutex.h ot_random.h ot_stats.h ot_vector.h ot_clean.h ot_udp.h ot_iovec.h ot_fullscrape.h ot_accesslist.h ot_http.h ot_livesync.h ot_rijndael.h
72SOURCES=opentracker.c trackerlogic.c scan_urlencoded_query.c ot_buf.c ot_hex.c ot_ip.c ot_scan.c ot_socket.c ot_mutex.c ot_random.c ot_stats.c ot_vector.c ot_clean.c ot_udp.c ot_iovec.c ot_fullscrape.c ot_accesslist.c ot_http.c ot_livesync.c ot_rijndael.c 72SOURCES=opentracker.c trackerlogic.c scan_urlencoded_query.c ot_buf.c ot_hex.c ot_ip.c ot_config.c ot_scan.c ot_socket.c ot_mutex.c ot_random.c ot_stats.c ot_vector.c ot_clean.c ot_udp.c ot_iovec.c ot_fullscrape.c ot_accesslist.c ot_http.c ot_livesync.c ot_rijndael.c
73SOURCES_proxy=proxy.c ot_vector.c ot_mutex.c ot_random.c ot_scan.c ot_ip.c ot_socket.c 73SOURCES_proxy=proxy.c ot_vector.c ot_mutex.c ot_random.c ot_scan.c ot_ip.c ot_socket.c
74 74
75OBJECTS = $(SOURCES:%.c=%.o) 75OBJECTS = $(SOURCES:%.c=%.o)
diff --git a/opentracker.c b/opentracker.c
index 1b0e119..698669c 100644
--- a/opentracker.c
+++ b/opentracker.c
@@ -27,6 +27,7 @@
27 27
28/* Opentracker */ 28/* Opentracker */
29#include "ot_accesslist.h" 29#include "ot_accesslist.h"
30#include "ot_config.h"
30#include "ot_hex.h" 31#include "ot_hex.h"
31#include "ot_http.h" 32#include "ot_http.h"
32#include "ot_ip.h" 33#include "ot_ip.h"
@@ -41,29 +42,10 @@
41 42
42/* Globals */ 43/* Globals */
43time_t g_now_seconds; 44time_t g_now_seconds;
44char *g_redirecturl;
45uint32_t g_tracker_id; 45uint32_t g_tracker_id;
46volatile int g_opentracker_running = 1; 46volatile int g_opentracker_running = 1;
47int g_self_pipe[2]; 47int g_self_pipe[2];
48 48
49static char *g_serverdir;
50static char *g_serveruser;
51
52typedef struct {
53 ot_ip6 ip;
54 uint16_t port;
55 PROTO_FLAG proto;
56 int shared;
57 int workers;
58 int64_t sock;
59} ot_listen;
60#define OT_LISTEN_INHERIT (-1)
61
62/* Config entries collected from command line and config files */
63static ot_listen *g_listen;
64static size_t g_listen_count;
65static int g_listen_shared;
66static int g_listen_workers;
67 49
68static void panic(const char *routine) __attribute__((noreturn)); 50static void panic(const char *routine) __attribute__((noreturn));
69static void panic(const char *routine) { 51static void panic(const char *routine) {
@@ -115,42 +97,6 @@ static void install_signal_handlers(void) {
115 pthread_sigmask(SIG_UNBLOCK, &signal_mask, NULL); 97 pthread_sigmask(SIG_UNBLOCK, &signal_mask, NULL);
116} 98}
117 99
118static void usage(char *name) {
119 fprintf(stderr,
120 "Usage: %s [-i ip] [-p port] [-P port] [-r redirect] [-d dir] [-u user] [-A ip[/bits]] [-f config] [-s livesyncport]"
121#ifdef WANT_ACCESSLIST_BLACK
122 " [-b blacklistfile]"
123#elif defined(WANT_ACCESSLIST_WHITE)
124 " [-w whitelistfile]"
125#endif
126 "\n",
127 name);
128}
129
130#define HELPLINE(opt, desc) fprintf(stderr, "\t%-10s%s\n", opt, desc)
131static void help(char *name) {
132 usage(name);
133
134 HELPLINE("-f config", "include and execute the config file");
135 HELPLINE("-i ip", "specify ip to bind to with next -[pP] (default: any, overrides preceeding ones)");
136 HELPLINE("-p port", "do bind to tcp port (default: 6969, you may specify more than one)");
137 HELPLINE("-P port", "do bind to udp port (default: 6969, you may specify more than one)");
138 HELPLINE("-r redirecturl", "specify url where / should be redirected to (default none)");
139 HELPLINE("-d dir", "specify directory to try to chroot to (default: \".\")");
140 HELPLINE("-u user", "specify user under whose privileges opentracker should run (default: \"nobody\")");
141 HELPLINE("-A ip[/bits]", "bless an ip address or net as admin address (e.g. to allow syncs from this address)");
142#ifdef WANT_ACCESSLIST_BLACK
143 HELPLINE("-b file", "specify blacklist file.");
144#elif defined(WANT_ACCESSLIST_WHITE)
145 HELPLINE("-w file", "specify whitelist file.");
146#endif
147
148 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");
149 fprintf(stderr, " Here -i 127.0.0.1 selects the ip address for the next -p 6969 and -P 6969.\n");
150 fprintf(stderr, " If no port is bound from config file or command line, the last address given\n");
151 fprintf(stderr, " (or ::1 if none is set) will be used on port 6969.\n");
152}
153#undef HELPLINE
154 100
155static ssize_t header_complete(char *request, ssize_t byte_count) { 101static ssize_t header_complete(char *request, ssize_t byte_count) {
156 ssize_t i = 0, state = 0; 102 ssize_t i = 0, state = 0;
@@ -353,91 +299,9 @@ static void *server_mainloop(void *args) {
353 return 0; 299 return 0;
354} 300}
355 301
356static void listen_append(const ot_ip6 ip, uint16_t port, PROTO_FLAG proto, int shared, int workers) {
357 ot_listen *grown = realloc(g_listen, (g_listen_count + 1) * sizeof(ot_listen));
358 ot_listen *entry;
359
360 if (!grown)
361 panic("listen_append");
362 g_listen = grown;
363
364 entry = g_listen + g_listen_count++;
365 memcpy(entry->ip, ip, sizeof(ot_ip6));
366 entry->port = port;
367 entry->proto = proto;
368 entry->shared = shared;
369 entry->workers = workers;
370 entry->sock = -1;
371}
372
373typedef enum { LISTEN_OPTION_UNKNOWN, LISTEN_OPTION_SHARED, LISTEN_OPTION_WORKERS } listen_option_kind;
374
375typedef struct {
376 const char *name;
377 size_t len;
378 listen_option_kind kind;
379 int takes_value;
380} listen_option_key;
381
382#define LISTEN_OPTION_KEY(s, k, v) {s, sizeof(s) - 1, k, v}
383
384static const listen_option_key listen_option_keys[] = {
385 LISTEN_OPTION_KEY("shared", LISTEN_OPTION_SHARED, 0),
386 LISTEN_OPTION_KEY("workers", LISTEN_OPTION_WORKERS, 1),
387};
388static const size_t listen_option_count = sizeof(listen_option_keys) / sizeof(listen_option_keys[0]);
389
390static listen_option_kind parse_listen_option(char **p) {
391 size_t i;
392
393 for (i = 0; i < listen_option_count; ++i) {
394 const listen_option_key *key = &listen_option_keys[i];
395 char delimiter = (*p)[key->len];
396
397 if (strncmp(*p, key->name, key->len))
398 continue;
399 if (key->takes_value ? delimiter != '=' : (delimiter && !isspace((unsigned char)delimiter)))
400 continue;
401
402 *p += key->len + (key->takes_value ? 1 : 0);
403 return key->kind;
404 }
405 return LISTEN_OPTION_UNKNOWN;
406}
407
408/* Options trailing an address in a listen statement, in any order */
409static int listen_scan_options(char *p, int *shared, int *workers) {
410 uint64_t value;
411
412 for (;;) {
413 while (isspace((unsigned char)*p))
414 ++p;
415 if (!*p)
416 return 1;
417
418 switch (parse_listen_option(&p)) {
419 case LISTEN_OPTION_SHARED:
420 *shared = 1;
421 break;
422 case LISTEN_OPTION_WORKERS: {
423 size_t off = scan_udec(p, &value, UINT_MAX);
424
425 if (!off)
426 return 0;
427 *workers = (int)value;
428 p += off;
429 break;
430 }
431 default:
432 return 0;
433 }
434 }
435}
436
437static int listen_option(int value, int fallback) { return value == OT_LISTEN_INHERIT ? fallback : value; }
438 302
439static void listen_bind_one(ot_listen *entry) { 303static void listen_bind_one(ot_listen *entry) {
440 socket_sharing sharing = listen_option(entry->shared, g_listen_shared) ? SOCKET_SHARED : SOCKET_EXCLUSIVE; 304 socket_sharing sharing = entry->shared ? SOCKET_SHARED : SOCKET_EXCLUSIVE;
441 305
442#ifdef _DEBUG 306#ifdef _DEBUG
443 { 307 {
@@ -482,305 +346,31 @@ static void listen_bind_one(ot_listen *entry) {
482/* Bound in the order the entries were given. 346/* Bound in the order the entries were given.
483 Note: On macOS SO_REUSEPORT delivers everything to the socket that bound last. */ 347 Note: On macOS SO_REUSEPORT delivers everything to the socket that bound last. */
484static void listen_bind_all(void) { 348static void listen_bind_all(void) {
485 size_t i; 349 size_t count, i;
350 ot_listen *entries = config_listen_entries(&count);
486 351
487 for (i = 0; i < g_listen_count; ++i) 352 for (i = 0; i < count; ++i)
488 listen_bind_one(g_listen + i); 353 listen_bind_one(entries + i);
489} 354}
490 355
491static void listen_start_udp_workers(void) { 356static void listen_start_udp_workers(void) {
492 size_t i; 357 size_t count, i;
358 ot_listen *entries = config_listen_entries(&count);
493 359
494 udp_init(); 360 udp_init();
495 361
496 for (i = 0; i < g_listen_count; ++i) { 362 for (i = 0; i < count; ++i) {
497 ot_listen *entry = g_listen + i; 363 ot_listen *entry = entries + i;
498 int workers = listen_option(entry->workers, g_listen_workers);
499 364
500 if (entry->proto != FLAG_UDP || workers <= 0) 365 if (entry->proto != FLAG_UDP || entry->workers <= 0)
501 continue; 366 continue;
502 367
503 io_block(entry->sock); 368 io_block(entry->sock);
504 udp_workers_install(entry->sock, (unsigned int)workers); 369 udp_workers_install(entry->sock, (unsigned int)entry->workers);
505 }
506}
507
508char *set_config_option(char **option, char *value) {
509#ifdef _DEBUG
510 fprintf(stderr, "Setting config option: %s\n", value);
511#endif
512 while (isspace(*value))
513 ++value;
514 free(*option);
515 return *option = strdup(value);
516}
517
518static int scan_ip6_port(const char *src, ot_ip6 ip, uint16_t *port) {
519 const char *s = src;
520 uint64_t value;
521 int off, bracket = 0;
522 while (isspace(*s))
523 ++s;
524 if (*s == '[')
525 ++s, ++bracket; /* for v6 style notation */
526 if (!(off = ip_scan(s, ip)))
527 return 0;
528 s += off;
529 if (bracket && *s == ']')
530 ++s;
531 if (*s == 0 || isspace(*s))
532 return s - src;
533 if (!ip_is_v4mapped(ip)) {
534 if (*s != ':' && *s != '.')
535 return 0;
536 if (!bracket && *(s) == ':')
537 return 0;
538 s++;
539 } else {
540 if (*(s++) != ':')
541 return 0;
542 }
543 if (!(off = scan_udec(s, &value, 65535)))
544 return 0;
545 *port = (uint16_t)value;
546 return off + s - src;
547}
548
549static int scan_ip6_net(const char *src, ot_net *net) {
550 const char *s = src;
551 uint64_t value;
552 int off;
553 while (isspace(*s))
554 ++s;
555 if (!(off = ip_scan(s, net->address)))
556 return 0;
557 s += off;
558 if (*s != '/')
559 net->bits = 128;
560 else {
561 s++;
562 if (!(off = scan_udec(s, &value, 128)))
563 return 0;
564 net->bits = (int)value;
565 if (ip_is_v4mapped(net->address))
566 net->bits += 96;
567 if (net->bits > 128)
568 return 0;
569 s += off;
570 } 370 }
571 return off + s - src;
572}
573
574typedef enum {
575 CONFIG_UNKNOWN,
576 CONFIG_TRACKER_ROOTDIR,
577 CONFIG_TRACKER_USER,
578 CONFIG_LISTEN_TCP_UDP,
579 CONFIG_LISTEN_TCP,
580 CONFIG_LISTEN_UDP,
581 CONFIG_LISTEN_UDP_WORKERS,
582 CONFIG_LISTEN_SHARED,
583 CONFIG_ACCESS_WHITELIST,
584 CONFIG_ACCESS_BLACKLIST,
585 CONFIG_ACCESS_FIFO_ADD,
586 CONFIG_ACCESS_FIFO_DELETE,
587 CONFIG_ACCESS_STATS,
588 CONFIG_ACCESS_STATS_PATH,
589 CONFIG_ACCESS_PROXY,
590 CONFIG_TRACKER_REDIRECT_URL,
591 CONFIG_LIVESYNC_CLUSTER_NODE_IP,
592 CONFIG_LIVESYNC_CLUSTER_LISTEN,
593} config_kind;
594
595typedef struct {
596 const char *name;
597 size_t len;
598 config_kind kind;
599} config_key;
600
601#define CONFIG_KEY(s, k) { s, sizeof(s) - 1, k }
602
603static const config_key config_keys[] = {
604 CONFIG_KEY("tracker.rootdir", CONFIG_TRACKER_ROOTDIR),
605 CONFIG_KEY("tracker.user", CONFIG_TRACKER_USER),
606 CONFIG_KEY("listen.tcp_udp", CONFIG_LISTEN_TCP_UDP),
607 CONFIG_KEY("listen.tcp", CONFIG_LISTEN_TCP),
608 CONFIG_KEY("listen.udp", CONFIG_LISTEN_UDP),
609 CONFIG_KEY("listen.udp.workers", CONFIG_LISTEN_UDP_WORKERS),
610 CONFIG_KEY("listen.shared", CONFIG_LISTEN_SHARED),
611#ifdef WANT_ACCESSLIST_WHITE
612 CONFIG_KEY("access.whitelist", CONFIG_ACCESS_WHITELIST),
613#elif defined(WANT_ACCESSLIST_BLACK)
614 CONFIG_KEY("access.blacklist", CONFIG_ACCESS_BLACKLIST),
615#endif
616#ifdef WANT_DYNAMIC_ACCESSLIST
617 CONFIG_KEY("access.fifo_add", CONFIG_ACCESS_FIFO_ADD),
618 CONFIG_KEY("access.fifo_delete", CONFIG_ACCESS_FIFO_DELETE),
619#endif
620#ifdef WANT_RESTRICT_STATS
621 CONFIG_KEY("access.stats", CONFIG_ACCESS_STATS),
622#endif
623 CONFIG_KEY("access.stats_path", CONFIG_ACCESS_STATS_PATH),
624#ifdef WANT_IP_FROM_PROXY
625 CONFIG_KEY("access.proxy", CONFIG_ACCESS_PROXY),
626#endif
627 CONFIG_KEY("tracker.redirect_url", CONFIG_TRACKER_REDIRECT_URL),
628#ifdef WANT_SYNC_LIVE
629 CONFIG_KEY("livesync.cluster.node_ip", CONFIG_LIVESYNC_CLUSTER_NODE_IP),
630 CONFIG_KEY("livesync.cluster.listen", CONFIG_LIVESYNC_CLUSTER_LISTEN),
631#endif
632};
633static const size_t config_entry_count = sizeof(config_keys) / sizeof(config_keys[0]);
634
635static config_kind parse_config_key(char **p) {
636 size_t i;
637 for (i = 0; i < config_entry_count; ++i) {
638 const config_key *key = &config_keys[i];
639 if (strncmp(*p, key->name, key->len) == 0 && isspace((unsigned char)(*p)[key->len])) {
640 *p += key->len + 1;
641 /* Skip white spaces */
642 while (isspace((unsigned char)**p))
643 ++(*p);
644 return key->kind;
645 }
646 }
647 return CONFIG_UNKNOWN;
648} 371}
649 372
650int parse_configfile(char *config_filename) {
651 FILE *config_file_handle;
652 char inbuf[512];
653 ot_ip6 tmpip;
654#if defined(WANT_RESTRICT_STATS) || defined(WANT_IP_FROM_PROXY) || defined(WANT_SYNC_LIVE)
655 ot_net tmpnet;
656#endif
657 int bound = 0;
658 373
659 config_file_handle = fopen(config_filename, "r");
660
661 if (config_file_handle == NULL) {
662 fprintf(stderr, "Warning: Can't open config file: %s.", config_filename);
663 return 0;
664 }
665
666 while (fgets(inbuf, sizeof(inbuf), config_file_handle)) {
667 char *p = inbuf, *end;
668 uint64_t value;
669 uint16_t tmpport = 6969;
670 config_kind kind;
671
672 /* Skip white spaces */
673 while (isspace((unsigned char)*p))
674 ++p;
675
676 /* Ignore comments and empty lines */
677 if ((*p == '#') || (*p == '\n') || (*p == 0))
678 continue;
679
680 /* consume trailing new lines and spaces */
681 end = p + strlen(p);
682 while (end > p && isspace((unsigned char)end[-1]))
683 *--end = 0;
684
685 /* Scan for commands */
686 kind = parse_config_key(&p);
687 switch (kind) {
688 case CONFIG_TRACKER_ROOTDIR:
689 set_config_option(&g_serverdir, p);
690 break;
691 case CONFIG_TRACKER_USER:
692 set_config_option(&g_serveruser, p);
693 break;
694 case CONFIG_LISTEN_TCP_UDP:
695 case CONFIG_LISTEN_TCP:
696 case CONFIG_LISTEN_UDP: {
697 int shared = OT_LISTEN_INHERIT;
698 int workers = OT_LISTEN_INHERIT;
699 int off = scan_ip6_port(p, tmpip, &tmpport);
700
701 if (!off || !listen_scan_options(p + off, &shared, &workers))
702 goto parse_error;
703 if (kind != CONFIG_LISTEN_UDP)
704 listen_append(tmpip, tmpport, FLAG_TCP, shared, OT_LISTEN_INHERIT), ++bound;
705 if (kind != CONFIG_LISTEN_TCP)
706 listen_append(tmpip, tmpport, FLAG_UDP, shared, workers), ++bound;
707 break;
708 }
709 case CONFIG_LISTEN_UDP_WORKERS:
710 if (!scan_udec(p, &value, UINT_MAX))
711 goto parse_error;
712 g_listen_workers = (int)value;
713 break;
714 case CONFIG_LISTEN_SHARED:
715 if (!scan_udec(p, &value, 1))
716 goto parse_error;
717 g_listen_shared = (int)value;
718 break;
719#ifdef WANT_ACCESSLIST_WHITE
720 case CONFIG_ACCESS_WHITELIST:
721 set_config_option(&g_accesslist_filename, p);
722 break;
723#elif defined(WANT_ACCESSLIST_BLACK)
724 case CONFIG_ACCESS_BLACKLIST:
725 set_config_option(&g_accesslist_filename, p);
726 break;
727#endif
728#ifdef WANT_DYNAMIC_ACCESSLIST
729 case CONFIG_ACCESS_FIFO_ADD:
730 set_config_option(&g_accesslist_pipe_add, p);
731 break;
732 case CONFIG_ACCESS_FIFO_DELETE:
733 set_config_option(&g_accesslist_pipe_delete, p);
734 break;
735#endif
736#ifdef WANT_RESTRICT_STATS
737 case CONFIG_ACCESS_STATS:
738 if (!scan_ip6_net(p, &tmpnet))
739 goto parse_error;
740 accesslist_bless_net(&tmpnet, OT_PERMISSION_MAY_STAT);
741 break;
742#endif
743 case CONFIG_ACCESS_STATS_PATH:
744 set_config_option(&g_stats_path, p);
745 break;
746#ifdef WANT_IP_FROM_PROXY
747 case CONFIG_ACCESS_PROXY:
748 if (!scan_ip6_net(p, &tmpnet))
749 goto parse_error;
750 accesslist_bless_net(&tmpnet, OT_PERMISSION_MAY_PROXY);
751 break;
752#endif
753 case CONFIG_TRACKER_REDIRECT_URL:
754 set_config_option(&g_redirecturl, p);
755 break;
756#ifdef WANT_SYNC_LIVE
757 case CONFIG_LIVESYNC_CLUSTER_NODE_IP:
758 if (!scan_ip6_net(p, &tmpnet))
759 goto parse_error;
760 accesslist_bless_net(&tmpnet, OT_PERMISSION_MAY_LIVESYNC);
761 break;
762 case CONFIG_LIVESYNC_CLUSTER_LISTEN:
763 tmpport = LIVESYNC_PORT;
764 {
765 int shared = OT_LISTEN_INHERIT, dummy = OT_LISTEN_INHERIT;
766 int off = scan_ip6_port(p, tmpip, &tmpport);
767
768 if (!off || !listen_scan_options(p + off, &shared, &dummy))
769 goto parse_error;
770 listen_append(tmpip, tmpport, FLAG_MCA, shared, OT_LISTEN_INHERIT);
771 }
772 break;
773#endif
774 default:
775 fprintf(stderr, "Unhandled line in config file: %s\n", inbuf);
776 break;
777 parse_error:
778 fprintf(stderr, "Parse error in config file: %s\n", inbuf);
779 }
780 }
781 fclose(config_file_handle);
782 return bound;
783}
784 374
785void load_state(const char *const state_filename) { 375void load_state(const char *const state_filename) {
786 FILE *state_filehandle; 376 FILE *state_filehandle;
@@ -873,114 +463,11 @@ static void *time_caching_worker(void *args) {
873} 463}
874 464
875int main(int argc, char **argv) { 465int main(int argc, char **argv) {
876 ot_ip6 serverip;
877 ot_net tmpnet;
878 int bound = 0, scanon = 1;
879 uint64_t value;
880 char *statefile = 0;
881 pthread_t thread_id; /* time cacher */ 466 pthread_t thread_id; /* time cacher */
882 467
883 memset(serverip, 0, sizeof(ot_ip6));
884#ifdef WANT_V4_ONLY
885 serverip[10] = serverip[11] = -1;
886#endif
887
888 random_init(); 468 random_init();
469 config_parse(argc, argv);
889 470
890 while (scanon) {
891 switch (getopt(argc, argv,
892 ":i:p:A:P:d:u:r:s:f:l:v"
893#ifdef WANT_ACCESSLIST_BLACK
894 "b:"
895#elif defined(WANT_ACCESSLIST_WHITE)
896 "w:"
897#endif
898 "h")) {
899 case -1:
900 scanon = 0;
901 break;
902 case 'i':
903 if (!ip_scan(optarg, serverip)) {
904 usage(argv[0]);
905 exit(1);
906 }
907 break;
908#ifdef WANT_ACCESSLIST_BLACK
909 case 'b':
910 set_config_option(&g_accesslist_filename, optarg);
911 break;
912#elif defined(WANT_ACCESSLIST_WHITE)
913 case 'w':
914 set_config_option(&g_accesslist_filename, optarg);
915 break;
916#endif
917 case 'p':
918 if (!scan_udec(optarg, &value, 65535)) {
919 usage(argv[0]);
920 exit(1);
921 }
922 listen_append(serverip, (uint16_t)value, FLAG_TCP, OT_LISTEN_INHERIT, OT_LISTEN_INHERIT);
923 bound++;
924 break;
925 case 'P':
926 if (!scan_udec(optarg, &value, 65535)) {
927 usage(argv[0]);
928 exit(1);
929 }
930 listen_append(serverip, (uint16_t)value, FLAG_UDP, OT_LISTEN_INHERIT, OT_LISTEN_INHERIT);
931 bound++;
932 break;
933#ifdef WANT_SYNC_LIVE
934 case 's':
935 if (!scan_udec(optarg, &value, 65535)) {
936 usage(argv[0]);
937 exit(1);
938 }
939 listen_append(serverip, (uint16_t)value, FLAG_MCA, OT_LISTEN_INHERIT, OT_LISTEN_INHERIT);
940 break;
941#endif
942 case 'd':
943 set_config_option(&g_serverdir, optarg);
944 break;
945 case 'u':
946 set_config_option(&g_serveruser, optarg);
947 break;
948 case 'r':
949 set_config_option(&g_redirecturl, optarg);
950 break;
951 case 'l':
952 statefile = optarg;
953 break;
954 case 'A':
955 if (!scan_ip6_net(optarg, &tmpnet)) {
956 usage(argv[0]);
957 exit(1);
958 }
959 accesslist_bless_net(&tmpnet, 0xffff); /* Allow everything for now */
960 break;
961 case 'f':
962 bound += parse_configfile(optarg);
963 break;
964 case 'h':
965 help(argv[0]);
966 exit(0);
967 case 'v': {
968 char buffer[8192];
969 stats_return_tracker_version(buffer);
970 fputs(buffer, stderr);
971 exit(0);
972 }
973 default:
974 case '?':
975 usage(argv[0]);
976 exit(1);
977 }
978 }
979
980 if (!bound) {
981 listen_append(serverip, 6969, FLAG_TCP, OT_LISTEN_INHERIT, OT_LISTEN_INHERIT);
982 listen_append(serverip, 6969, FLAG_UDP, OT_LISTEN_INHERIT, OT_LISTEN_INHERIT);
983 }
984 471
985 listen_bind_all(); 472 listen_bind_all();
986 473
@@ -1017,8 +504,8 @@ int main(int argc, char **argv) {
1017 fprintf(stderr, "... done.\n"); 504 fprintf(stderr, "... done.\n");
1018#endif 505#endif
1019 506
1020 if (statefile) 507 if (g_statefile)
1021 load_state(statefile); 508 load_state(g_statefile);
1022 509
1023 install_signal_handlers(); 510 install_signal_handlers();
1024 511
diff --git a/ot_config.c b/ot_config.c
new file mode 100644
index 0000000..43c07c5
--- /dev/null
+++ b/ot_config.c
@@ -0,0 +1,565 @@
1/* This software was written by Dirk Engling <erdgeist@erdgeist.org>
2 It is considered beerware. Prost. Skol. Cheers or whatever.
3
4 $id$ */
5
6/* System */
7#include <ctype.h>
8#include <errno.h>
9#include <limits.h>
10#include <stdio.h>
11#include <stdlib.h>
12#include <string.h>
13#include <unistd.h>
14
15/* Opentracker */
16#include "ot_accesslist.h"
17#include "ot_config.h"
18#include "ot_http.h"
19#include "ot_ip.h"
20#include "ot_livesync.h"
21#include "ot_scan.h"
22#include "ot_stats.h"
23#include "trackerlogic.h"
24
25char *g_redirecturl;
26char *g_serverdir;
27char *g_serveruser;
28char *g_statefile;
29
30#define OT_LISTEN_INHERIT (-1)
31
32static ot_listen *g_listen;
33static size_t g_listen_count;
34static int g_listen_shared;
35static int g_listen_workers;
36
37static void panic(const char *routine) __attribute__((noreturn));
38static void panic(const char *routine) {
39 fprintf(stderr, "%s: %s\n", routine, strerror(errno));
40 exit(111);
41}
42
43static void listen_append(const ot_ip6 ip, uint16_t port, PROTO_FLAG proto, int shared, int workers) {
44 ot_listen *grown = realloc(g_listen, (g_listen_count + 1) * sizeof(ot_listen));
45 ot_listen *entry;
46
47 if (!grown)
48 panic("listen_append");
49 g_listen = grown;
50
51 entry = g_listen + g_listen_count++;
52 memcpy(entry->ip, ip, sizeof(ot_ip6));
53 entry->port = port;
54 entry->proto = proto;
55 entry->shared = shared;
56 entry->workers = workers;
57 entry->sock = -1;
58}
59
60typedef enum { LISTEN_OPTION_UNKNOWN, LISTEN_OPTION_SHARED, LISTEN_OPTION_WORKERS } listen_option_kind;
61
62typedef struct {
63 const char *name;
64 size_t len;
65 listen_option_kind kind;
66 int takes_value;
67} listen_option_key;
68
69#define LISTEN_OPTION_KEY(s, k, v) {s, sizeof(s) - 1, k, v}
70
71static const listen_option_key listen_option_keys[] = {
72 LISTEN_OPTION_KEY("shared", LISTEN_OPTION_SHARED, 0),
73 LISTEN_OPTION_KEY("workers", LISTEN_OPTION_WORKERS, 1),
74};
75static const size_t listen_option_count = sizeof(listen_option_keys) / sizeof(listen_option_keys[0]);
76
77static listen_option_kind parse_listen_option(char **p) {
78 size_t i;
79
80 for (i = 0; i < listen_option_count; ++i) {
81 const listen_option_key *key = &listen_option_keys[i];
82 char delimiter = (*p)[key->len];
83
84 if (strncmp(*p, key->name, key->len))
85 continue;
86 if (key->takes_value ? delimiter != '=' : (delimiter && !isspace((unsigned char)delimiter)))
87 continue;
88
89 *p += key->len + (key->takes_value ? 1 : 0);
90 return key->kind;
91 }
92 return LISTEN_OPTION_UNKNOWN;
93}
94
95/* Options trailing an address in a listen statement, in any order */
96static int listen_scan_options(char *p, int *shared, int *workers) {
97 uint64_t value;
98
99 for (;;) {
100 while (isspace((unsigned char)*p))
101 ++p;
102 if (!*p)
103 return 1;
104
105 switch (parse_listen_option(&p)) {
106 case LISTEN_OPTION_SHARED:
107 *shared = 1;
108 break;
109 case LISTEN_OPTION_WORKERS: {
110 size_t off = scan_udec(p, &value, UINT_MAX);
111
112 if (!off)
113 return 0;
114 *workers = (int)value;
115 p += off;
116 break;
117 }
118 default:
119 return 0;
120 }
121 }
122}
123
124
125char *set_config_option(char **option, char *value) {
126#ifdef _DEBUG
127 fprintf(stderr, "Setting config option: %s\n", value);
128#endif
129 while (isspace(*value))
130 ++value;
131 free(*option);
132 return *option = strdup(value);
133}
134
135static int scan_ip6_port(const char *src, ot_ip6 ip, uint16_t *port) {
136 const char *s = src;
137 uint64_t value;
138 int off, bracket = 0;
139 while (isspace(*s))
140 ++s;
141 if (*s == '[')
142 ++s, ++bracket; /* for v6 style notation */
143 if (!(off = ip_scan(s, ip)))
144 return 0;
145 s += off;
146 if (bracket && *s == ']')
147 ++s;
148 if (*s == 0 || isspace(*s))
149 return s - src;
150 if (!ip_is_v4mapped(ip)) {
151 if (*s != ':' && *s != '.')
152 return 0;
153 if (!bracket && *(s) == ':')
154 return 0;
155 s++;
156 } else {
157 if (*(s++) != ':')
158 return 0;
159 }
160 if (!(off = scan_udec(s, &value, 65535)))
161 return 0;
162 *port = (uint16_t)value;
163 return off + s - src;
164}
165
166static int scan_ip6_net(const char *src, ot_net *net) {
167 const char *s = src;
168 uint64_t value;
169 int off;
170 while (isspace(*s))
171 ++s;
172 if (!(off = ip_scan(s, net->address)))
173 return 0;
174 s += off;
175 if (*s != '/')
176 net->bits = 128;
177 else {
178 s++;
179 if (!(off = scan_udec(s, &value, 128)))
180 return 0;
181 net->bits = (int)value;
182 if (ip_is_v4mapped(net->address))
183 net->bits += 96;
184 if (net->bits > 128)
185 return 0;
186 s += off;
187 }
188 return off + s - src;
189}
190
191typedef enum {
192 CONFIG_UNKNOWN,
193 CONFIG_TRACKER_ROOTDIR,
194 CONFIG_TRACKER_USER,
195 CONFIG_LISTEN_TCP_UDP,
196 CONFIG_LISTEN_TCP,
197 CONFIG_LISTEN_UDP,
198 CONFIG_LISTEN_UDP_WORKERS,
199 CONFIG_LISTEN_SHARED,
200 CONFIG_ACCESS_WHITELIST,
201 CONFIG_ACCESS_BLACKLIST,
202 CONFIG_ACCESS_FIFO_ADD,
203 CONFIG_ACCESS_FIFO_DELETE,
204 CONFIG_ACCESS_STATS,
205 CONFIG_ACCESS_STATS_PATH,
206 CONFIG_ACCESS_PROXY,
207 CONFIG_TRACKER_REDIRECT_URL,
208 CONFIG_LIVESYNC_CLUSTER_NODE_IP,
209 CONFIG_LIVESYNC_CLUSTER_LISTEN,
210} config_kind;
211
212typedef struct {
213 const char *name;
214 size_t len;
215 config_kind kind;
216} config_key;
217
218#define CONFIG_KEY(s, k) { s, sizeof(s) - 1, k }
219
220static const config_key config_keys[] = {
221 CONFIG_KEY("tracker.rootdir", CONFIG_TRACKER_ROOTDIR),
222 CONFIG_KEY("tracker.user", CONFIG_TRACKER_USER),
223 CONFIG_KEY("listen.tcp_udp", CONFIG_LISTEN_TCP_UDP),
224 CONFIG_KEY("listen.tcp", CONFIG_LISTEN_TCP),
225 CONFIG_KEY("listen.udp", CONFIG_LISTEN_UDP),
226 CONFIG_KEY("listen.udp.workers", CONFIG_LISTEN_UDP_WORKERS),
227 CONFIG_KEY("listen.shared", CONFIG_LISTEN_SHARED),
228#ifdef WANT_ACCESSLIST_WHITE
229 CONFIG_KEY("access.whitelist", CONFIG_ACCESS_WHITELIST),
230#elif defined(WANT_ACCESSLIST_BLACK)
231 CONFIG_KEY("access.blacklist", CONFIG_ACCESS_BLACKLIST),
232#endif
233#ifdef WANT_DYNAMIC_ACCESSLIST
234 CONFIG_KEY("access.fifo_add", CONFIG_ACCESS_FIFO_ADD),
235 CONFIG_KEY("access.fifo_delete", CONFIG_ACCESS_FIFO_DELETE),
236#endif
237#ifdef WANT_RESTRICT_STATS
238 CONFIG_KEY("access.stats", CONFIG_ACCESS_STATS),
239#endif
240 CONFIG_KEY("access.stats_path", CONFIG_ACCESS_STATS_PATH),
241#ifdef WANT_IP_FROM_PROXY
242 CONFIG_KEY("access.proxy", CONFIG_ACCESS_PROXY),
243#endif
244 CONFIG_KEY("tracker.redirect_url", CONFIG_TRACKER_REDIRECT_URL),
245#ifdef WANT_SYNC_LIVE
246 CONFIG_KEY("livesync.cluster.node_ip", CONFIG_LIVESYNC_CLUSTER_NODE_IP),
247 CONFIG_KEY("livesync.cluster.listen", CONFIG_LIVESYNC_CLUSTER_LISTEN),
248#endif
249};
250static const size_t config_entry_count = sizeof(config_keys) / sizeof(config_keys[0]);
251
252static config_kind parse_config_key(char **p) {
253 size_t i;
254 for (i = 0; i < config_entry_count; ++i) {
255 const config_key *key = &config_keys[i];
256 if (strncmp(*p, key->name, key->len) == 0 && isspace((unsigned char)(*p)[key->len])) {
257 *p += key->len + 1;
258 /* Skip white spaces */
259 while (isspace((unsigned char)**p))
260 ++(*p);
261 return key->kind;
262 }
263 }
264 return CONFIG_UNKNOWN;
265}
266
267int parse_configfile(char *config_filename) {
268 FILE *config_file_handle;
269 char inbuf[512];
270 ot_ip6 tmpip;
271#if defined(WANT_RESTRICT_STATS) || defined(WANT_IP_FROM_PROXY) || defined(WANT_SYNC_LIVE)
272 ot_net tmpnet;
273#endif
274 int bound = 0;
275
276 config_file_handle = fopen(config_filename, "r");
277
278 if (config_file_handle == NULL) {
279 fprintf(stderr, "Warning: Can't open config file: %s.", config_filename);
280 return 0;
281 }
282
283 while (fgets(inbuf, sizeof(inbuf), config_file_handle)) {
284 char *p = inbuf, *end;
285 uint64_t value;
286 uint16_t tmpport = 6969;
287 config_kind kind;
288
289 /* Skip white spaces */
290 while (isspace((unsigned char)*p))
291 ++p;
292
293 /* Ignore comments and empty lines */
294 if ((*p == '#') || (*p == '\n') || (*p == 0))
295 continue;
296
297 /* consume trailing new lines and spaces */
298 end = p + strlen(p);
299 while (end > p && isspace((unsigned char)end[-1]))
300 *--end = 0;
301
302 /* Scan for commands */
303 kind = parse_config_key(&p);
304 switch (kind) {
305 case CONFIG_TRACKER_ROOTDIR:
306 set_config_option(&g_serverdir, p);
307 break;
308 case CONFIG_TRACKER_USER:
309 set_config_option(&g_serveruser, p);
310 break;
311 case CONFIG_LISTEN_TCP_UDP:
312 case CONFIG_LISTEN_TCP:
313 case CONFIG_LISTEN_UDP: {
314 int shared = OT_LISTEN_INHERIT;
315 int workers = OT_LISTEN_INHERIT;
316 int off = scan_ip6_port(p, tmpip, &tmpport);
317
318 if (!off || !listen_scan_options(p + off, &shared, &workers))
319 goto parse_error;
320 if (kind != CONFIG_LISTEN_UDP)
321 listen_append(tmpip, tmpport, FLAG_TCP, shared, OT_LISTEN_INHERIT), ++bound;
322 if (kind != CONFIG_LISTEN_TCP)
323 listen_append(tmpip, tmpport, FLAG_UDP, shared, workers), ++bound;
324 break;
325 }
326 case CONFIG_LISTEN_UDP_WORKERS:
327 if (!scan_udec(p, &value, UINT_MAX))
328 goto parse_error;
329 g_listen_workers = (int)value;
330 break;
331 case CONFIG_LISTEN_SHARED:
332 if (!scan_udec(p, &value, 1))
333 goto parse_error;
334 g_listen_shared = (int)value;
335 break;
336#ifdef WANT_ACCESSLIST_WHITE
337 case CONFIG_ACCESS_WHITELIST:
338 set_config_option(&g_accesslist_filename, p);
339 break;
340#elif defined(WANT_ACCESSLIST_BLACK)
341 case CONFIG_ACCESS_BLACKLIST:
342 set_config_option(&g_accesslist_filename, p);
343 break;
344#endif
345#ifdef WANT_DYNAMIC_ACCESSLIST
346 case CONFIG_ACCESS_FIFO_ADD:
347 set_config_option(&g_accesslist_pipe_add, p);
348 break;
349 case CONFIG_ACCESS_FIFO_DELETE:
350 set_config_option(&g_accesslist_pipe_delete, p);
351 break;
352#endif
353#ifdef WANT_RESTRICT_STATS
354 case CONFIG_ACCESS_STATS:
355 if (!scan_ip6_net(p, &tmpnet))
356 goto parse_error;
357 accesslist_bless_net(&tmpnet, OT_PERMISSION_MAY_STAT);
358 break;
359#endif
360 case CONFIG_ACCESS_STATS_PATH:
361 set_config_option(&g_stats_path, p);
362 break;
363#ifdef WANT_IP_FROM_PROXY
364 case CONFIG_ACCESS_PROXY:
365 if (!scan_ip6_net(p, &tmpnet))
366 goto parse_error;
367 accesslist_bless_net(&tmpnet, OT_PERMISSION_MAY_PROXY);
368 break;
369#endif
370 case CONFIG_TRACKER_REDIRECT_URL:
371 set_config_option(&g_redirecturl, p);
372 break;
373#ifdef WANT_SYNC_LIVE
374 case CONFIG_LIVESYNC_CLUSTER_NODE_IP:
375 if (!scan_ip6_net(p, &tmpnet))
376 goto parse_error;
377 accesslist_bless_net(&tmpnet, OT_PERMISSION_MAY_LIVESYNC);
378 break;
379 case CONFIG_LIVESYNC_CLUSTER_LISTEN:
380 tmpport = LIVESYNC_PORT;
381 {
382 int shared = OT_LISTEN_INHERIT, dummy = OT_LISTEN_INHERIT;
383 int off = scan_ip6_port(p, tmpip, &tmpport);
384
385 if (!off || !listen_scan_options(p + off, &shared, &dummy))
386 goto parse_error;
387 listen_append(tmpip, tmpport, FLAG_MCA, shared, OT_LISTEN_INHERIT);
388 }
389 break;
390#endif
391 default:
392 fprintf(stderr, "Unhandled line in config file: %s\n", inbuf);
393 break;
394 parse_error:
395 fprintf(stderr, "Parse error in config file: %s\n", inbuf);
396 }
397 }
398 fclose(config_file_handle);
399 return bound;
400}
401
402static void usage(char *name) {
403 fprintf(stderr,
404 "Usage: %s [-i ip] [-p port] [-P port] [-r redirect] [-d dir] [-u user] [-A ip[/bits]] [-f config] [-s livesyncport]"
405#ifdef WANT_ACCESSLIST_BLACK
406 " [-b blacklistfile]"
407#elif defined(WANT_ACCESSLIST_WHITE)
408 " [-w whitelistfile]"
409#endif
410 "\n",
411 name);
412}
413
414#define HELPLINE(opt, desc) fprintf(stderr, "\t%-10s%s\n", opt, desc)
415static void help(char *name) {
416 usage(name);
417
418 HELPLINE("-f config", "include and execute the config file");
419 HELPLINE("-i ip", "specify ip to bind to with next -[pP] (default: any, overrides preceeding ones)");
420 HELPLINE("-p port", "do bind to tcp port (default: 6969, you may specify more than one)");
421 HELPLINE("-P port", "do bind to udp port (default: 6969, you may specify more than one)");
422 HELPLINE("-r redirecturl", "specify url where / should be redirected to (default none)");
423 HELPLINE("-d dir", "specify directory to try to chroot to (default: \".\")");
424 HELPLINE("-u user", "specify user under whose privileges opentracker should run (default: \"nobody\")");
425 HELPLINE("-A ip[/bits]", "bless an ip address or net as admin address (e.g. to allow syncs from this address)");
426#ifdef WANT_ACCESSLIST_BLACK
427 HELPLINE("-b file", "specify blacklist file.");
428#elif defined(WANT_ACCESSLIST_WHITE)
429 HELPLINE("-w file", "specify whitelist file.");
430#endif
431
432 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");
433 fprintf(stderr, " Here -i 127.0.0.1 selects the ip address for the next -p 6969 and -P 6969.\n");
434 fprintf(stderr, " If no port is bound from config file or command line, the last address given\n");
435 fprintf(stderr, " (or ::1 if none is set) will be used on port 6969.\n");
436}
437#undef HELPLINE
438
439
440static void listen_resolve_defaults(void) {
441 size_t i;
442
443 for (i = 0; i < g_listen_count; ++i) {
444 ot_listen *entry = g_listen + i;
445
446 if (entry->shared == OT_LISTEN_INHERIT)
447 entry->shared = g_listen_shared;
448 if (entry->workers == OT_LISTEN_INHERIT)
449 entry->workers = g_listen_workers;
450 }
451}
452
453ot_listen *config_listen_entries(size_t *count) {
454 *count = g_listen_count;
455 return g_listen;
456}
457
458void config_parse(int argc, char **argv) {
459 ot_ip6 serverip;
460 ot_net tmpnet;
461 int bound = 0, scanon = 1;
462 uint64_t value;
463
464 memset(serverip, 0, sizeof(ot_ip6));
465#ifdef WANT_V4_ONLY
466 serverip[10] = serverip[11] = -1;
467#endif
468
469 while (scanon) {
470 switch (getopt(argc, argv,
471 ":i:p:A:P:d:u:r:s:f:l:v"
472#ifdef WANT_ACCESSLIST_BLACK
473 "b:"
474#elif defined(WANT_ACCESSLIST_WHITE)
475 "w:"
476#endif
477 "h")) {
478 case -1:
479 scanon = 0;
480 break;
481 case 'i':
482 if (!ip_scan(optarg, serverip)) {
483 usage(argv[0]);
484 exit(1);
485 }
486 break;
487#ifdef WANT_ACCESSLIST_BLACK
488 case 'b':
489 set_config_option(&g_accesslist_filename, optarg);
490 break;
491#elif defined(WANT_ACCESSLIST_WHITE)
492 case 'w':
493 set_config_option(&g_accesslist_filename, optarg);
494 break;
495#endif
496 case 'p':
497 if (!scan_udec(optarg, &value, 65535)) {
498 usage(argv[0]);
499 exit(1);
500 }
501 listen_append(serverip, (uint16_t)value, FLAG_TCP, OT_LISTEN_INHERIT, OT_LISTEN_INHERIT);
502 bound++;
503 break;
504 case 'P':
505 if (!scan_udec(optarg, &value, 65535)) {
506 usage(argv[0]);
507 exit(1);
508 }
509 listen_append(serverip, (uint16_t)value, FLAG_UDP, OT_LISTEN_INHERIT, OT_LISTEN_INHERIT);
510 bound++;
511 break;
512#ifdef WANT_SYNC_LIVE
513 case 's':
514 if (!scan_udec(optarg, &value, 65535)) {
515 usage(argv[0]);
516 exit(1);
517 }
518 listen_append(serverip, (uint16_t)value, FLAG_MCA, OT_LISTEN_INHERIT, OT_LISTEN_INHERIT);
519 break;
520#endif
521 case 'd':
522 set_config_option(&g_serverdir, optarg);
523 break;
524 case 'u':
525 set_config_option(&g_serveruser, optarg);
526 break;
527 case 'r':
528 set_config_option(&g_redirecturl, optarg);
529 break;
530 case 'l':
531 g_statefile = optarg;
532 break;
533 case 'A':
534 if (!scan_ip6_net(optarg, &tmpnet)) {
535 usage(argv[0]);
536 exit(1);
537 }
538 accesslist_bless_net(&tmpnet, 0xffff); /* Allow everything for now */
539 break;
540 case 'f':
541 bound += parse_configfile(optarg);
542 break;
543 case 'h':
544 help(argv[0]);
545 exit(0);
546 case 'v': {
547 char buffer[8192];
548 stats_return_tracker_version(buffer);
549 fputs(buffer, stderr);
550 exit(0);
551 }
552 default:
553 case '?':
554 usage(argv[0]);
555 exit(1);
556 }
557 }
558
559 if (!bound) {
560 listen_append(serverip, 6969, FLAG_TCP, OT_LISTEN_INHERIT, OT_LISTEN_INHERIT);
561 listen_append(serverip, 6969, FLAG_UDP, OT_LISTEN_INHERIT, OT_LISTEN_INHERIT);
562 }
563
564 listen_resolve_defaults();
565}
diff --git a/ot_config.h b/ot_config.h
new file mode 100644
index 0000000..ab25e2c
--- /dev/null
+++ b/ot_config.h
@@ -0,0 +1,35 @@
1/* This software was written by Dirk Engling <erdgeist@erdgeist.org>
2 It is considered beerware. Prost. Skol. Cheers or whatever.
3
4 $id$ */
5
6#ifndef OT_CONFIG_H__
7#define OT_CONFIG_H__
8
9#include <stdint.h>
10
11#include "trackerlogic.h"
12
13/* An address opentracker was asked to listen on. Options the statement did
14 not name have been filled in from the file wide defaults by the time these
15 are handed out. sock is filled in by whoever binds them. */
16typedef struct {
17 ot_ip6 ip;
18 uint16_t port;
19 PROTO_FLAG proto;
20 int shared;
21 int workers;
22 int64_t sock;
23} ot_listen;
24
25extern char *g_redirecturl;
26extern char *g_serverdir;
27extern char *g_serveruser;
28extern char *g_statefile;
29
30/* Reads the command line and every config file it names. Exits on error. */
31void config_parse(int argc, char **argv);
32
33ot_listen *config_listen_entries(size_t *count);
34
35#endif