diff options
Diffstat (limited to 'ot_config.c')
| -rw-r--r-- | ot_config.c | 565 |
1 files changed, 565 insertions, 0 deletions
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 | |||
| 25 | char *g_redirecturl; | ||
| 26 | char *g_serverdir; | ||
| 27 | char *g_serveruser; | ||
| 28 | char *g_statefile; | ||
| 29 | |||
| 30 | #define OT_LISTEN_INHERIT (-1) | ||
| 31 | |||
| 32 | static ot_listen *g_listen; | ||
| 33 | static size_t g_listen_count; | ||
| 34 | static int g_listen_shared; | ||
| 35 | static int g_listen_workers; | ||
| 36 | |||
| 37 | static void panic(const char *routine) __attribute__((noreturn)); | ||
| 38 | static void panic(const char *routine) { | ||
| 39 | fprintf(stderr, "%s: %s\n", routine, strerror(errno)); | ||
| 40 | exit(111); | ||
| 41 | } | ||
| 42 | |||
| 43 | static 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 | |||
| 60 | typedef enum { LISTEN_OPTION_UNKNOWN, LISTEN_OPTION_SHARED, LISTEN_OPTION_WORKERS } listen_option_kind; | ||
| 61 | |||
| 62 | typedef 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 | |||
| 71 | static 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 | }; | ||
| 75 | static const size_t listen_option_count = sizeof(listen_option_keys) / sizeof(listen_option_keys[0]); | ||
| 76 | |||
| 77 | static 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 */ | ||
| 96 | static 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 | |||
| 125 | char *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 | |||
| 135 | static 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 | |||
| 166 | static 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 | |||
| 191 | typedef 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 | |||
| 212 | typedef 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 | |||
| 220 | static 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 | }; | ||
| 250 | static const size_t config_entry_count = sizeof(config_keys) / sizeof(config_keys[0]); | ||
| 251 | |||
| 252 | static 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 | |||
| 267 | int 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 | |||
| 402 | static 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) | ||
| 415 | static 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 | |||
| 440 | static 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 | |||
| 453 | ot_listen *config_listen_entries(size_t *count) { | ||
| 454 | *count = g_listen_count; | ||
| 455 | return g_listen; | ||
| 456 | } | ||
| 457 | |||
| 458 | void 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 | } | ||
