diff options
Diffstat (limited to 'opentracker.c')
| -rw-r--r-- | opentracker.c | 261 |
1 files changed, 165 insertions, 96 deletions
diff --git a/opentracker.c b/opentracker.c index f63db72..f218589 100644 --- a/opentracker.c +++ b/opentracker.c | |||
| @@ -5,7 +5,6 @@ | |||
| 5 | $Id$ */ | 5 | $Id$ */ |
| 6 | 6 | ||
| 7 | /* System */ | 7 | /* System */ |
| 8 | #include <arpa/inet.h> | ||
| 9 | #include <ctype.h> | 8 | #include <ctype.h> |
| 10 | #include <errno.h> | 9 | #include <errno.h> |
| 11 | #include <pthread.h> | 10 | #include <pthread.h> |
| @@ -21,7 +20,6 @@ | |||
| 21 | #endif | 20 | #endif |
| 22 | 21 | ||
| 23 | /* Libowfat */ | 22 | /* Libowfat */ |
| 24 | #include "byte.h" | ||
| 25 | #include "io.h" | 23 | #include "io.h" |
| 26 | #include "iob.h" | 24 | #include "iob.h" |
| 27 | #include "ip6.h" | 25 | #include "ip6.h" |
| @@ -30,9 +28,11 @@ | |||
| 30 | 28 | ||
| 31 | /* Opentracker */ | 29 | /* Opentracker */ |
| 32 | #include "ot_accesslist.h" | 30 | #include "ot_accesslist.h" |
| 31 | #include "ot_hex.h" | ||
| 33 | #include "ot_http.h" | 32 | #include "ot_http.h" |
| 34 | #include "ot_livesync.h" | 33 | #include "ot_livesync.h" |
| 35 | #include "ot_mutex.h" | 34 | #include "ot_mutex.h" |
| 35 | #include "ot_random.h" | ||
| 36 | #include "ot_stats.h" | 36 | #include "ot_stats.h" |
| 37 | #include "ot_udp.h" | 37 | #include "ot_udp.h" |
| 38 | #include "trackerlogic.h" | 38 | #include "trackerlogic.h" |
| @@ -296,13 +296,7 @@ static void *server_mainloop(void *args) { | |||
| 296 | if (!ws.inbuf || !ws.outbuf) | 296 | if (!ws.inbuf || !ws.outbuf) |
| 297 | panic("Initializing worker failed"); | 297 | panic("Initializing worker failed"); |
| 298 | 298 | ||
| 299 | #ifdef WANT_ARC4RANDOM | 299 | random_bytes(ws.rand48_state, sizeof(ws.rand48_state)); |
| 300 | arc4random_buf(&ws.rand48_state[0], 3 * sizeof(uint16_t)); | ||
| 301 | #else | ||
| 302 | ws.rand48_state[0] = (uint16_t)random(); | ||
| 303 | ws.rand48_state[1] = (uint16_t)random(); | ||
| 304 | ws.rand48_state[2] = (uint16_t)random(); | ||
| 305 | #endif | ||
| 306 | 300 | ||
| 307 | for (;;) { | 301 | for (;;) { |
| 308 | int64 sock; | 302 | int64 sock; |
| @@ -438,8 +432,82 @@ static int scan_ip6_net(const char *src, ot_net *net) { | |||
| 438 | return off + s - src; | 432 | return off + s - src; |
| 439 | } | 433 | } |
| 440 | 434 | ||
| 435 | typedef enum { | ||
| 436 | CONFIG_UNKNOWN, | ||
| 437 | CONFIG_TRACKER_ROOTDIR, | ||
| 438 | CONFIG_TRACKER_USER, | ||
| 439 | CONFIG_LISTEN_TCP_UDP, | ||
| 440 | CONFIG_LISTEN_TCP, | ||
| 441 | CONFIG_LISTEN_UDP, | ||
| 442 | CONFIG_LISTEN_UDP_WORKERS, | ||
| 443 | CONFIG_ACCESS_WHITELIST, | ||
| 444 | CONFIG_ACCESS_BLACKLIST, | ||
| 445 | CONFIG_ACCESS_FIFO_ADD, | ||
| 446 | CONFIG_ACCESS_FIFO_DELETE, | ||
| 447 | CONFIG_ACCESS_STATS, | ||
| 448 | CONFIG_ACCESS_STATS_PATH, | ||
| 449 | CONFIG_ACCESS_PROXY, | ||
| 450 | CONFIG_TRACKER_REDIRECT_URL, | ||
| 451 | CONFIG_LIVESYNC_CLUSTER_NODE_IP, | ||
| 452 | CONFIG_LIVESYNC_CLUSTER_LISTEN, | ||
| 453 | } config_kind; | ||
| 454 | |||
| 455 | typedef struct { | ||
| 456 | const char *name; | ||
| 457 | size_t len; | ||
| 458 | config_kind kind; | ||
| 459 | } config_key; | ||
| 460 | |||
| 461 | #define CONFIG_KEY(s, k) { s, sizeof(s) - 1, k } | ||
| 462 | |||
| 463 | static const config_key config_keys[] = { | ||
| 464 | CONFIG_KEY("tracker.rootdir", CONFIG_TRACKER_ROOTDIR), | ||
| 465 | CONFIG_KEY("tracker.user", CONFIG_TRACKER_USER), | ||
| 466 | CONFIG_KEY("listen.tcp_udp", CONFIG_LISTEN_TCP_UDP), | ||
| 467 | CONFIG_KEY("listen.tcp", CONFIG_LISTEN_TCP), | ||
| 468 | CONFIG_KEY("listen.udp", CONFIG_LISTEN_UDP), | ||
| 469 | CONFIG_KEY("listen.udp.workers", CONFIG_LISTEN_UDP_WORKERS), | ||
| 470 | #ifdef WANT_ACCESSLIST_WHITE | ||
| 471 | CONFIG_KEY("access.whitelist", CONFIG_ACCESS_WHITELIST), | ||
| 472 | #elif defined(WANT_ACCESSLIST_BLACK) | ||
| 473 | CONFIG_KEY("access.blacklist", CONFIG_ACCESS_BLACKLIST), | ||
| 474 | #endif | ||
| 475 | #ifdef WANT_DYNAMIC_ACCESSLIST | ||
| 476 | CONFIG_KEY("access.fifo_add", CONFIG_ACCESS_FIFO_ADD), | ||
| 477 | CONFIG_KEY("access.fifo_delete", CONFIG_ACCESS_FIFO_DELETE), | ||
| 478 | #endif | ||
| 479 | #ifdef WANT_RESTRICT_STATS | ||
| 480 | CONFIG_KEY("access.stats", CONFIG_ACCESS_STATS), | ||
| 481 | #endif | ||
| 482 | CONFIG_KEY("access.stats_path", CONFIG_ACCESS_STATS_PATH), | ||
| 483 | #ifdef WANT_IP_FROM_PROXY | ||
| 484 | CONFIG_KEY("access.proxy", CONFIG_ACCESS_PROXY), | ||
| 485 | #endif | ||
| 486 | CONFIG_KEY("tracker.redirect_url", CONFIG_TRACKER_REDIRECT_URL), | ||
| 487 | #ifdef WANT_SYNC_LIVE | ||
| 488 | CONFIG_KEY("livesync.cluster.node_ip", CONFIG_LIVESYNC_CLUSTER_NODE_IP), | ||
| 489 | CONFIG_KEY("livesync.cluster.listen", CONFIG_LIVESYNC_CLUSTER_LISTEN), | ||
| 490 | #endif | ||
| 491 | }; | ||
| 492 | static const size_t config_entry_count = sizeof(config_keys) / sizeof(config_keys[0]); | ||
| 493 | |||
| 494 | static config_kind parse_config_key(char **p) { | ||
| 495 | size_t i; | ||
| 496 | for (i = 0; i < config_entry_count; ++i) { | ||
| 497 | const config_key *key = &config_keys[i]; | ||
| 498 | if (strncmp(*p, key->name, key->len) == 0 && isspace((unsigned char)(*p)[key->len])) { | ||
| 499 | *p += key->len + 1; | ||
| 500 | /* Skip white spaces */ | ||
| 501 | while (isspace((unsigned char)**p)) | ||
| 502 | ++(*p); | ||
| 503 | return key->kind; | ||
| 504 | } | ||
| 505 | } | ||
| 506 | return CONFIG_UNKNOWN; | ||
| 507 | } | ||
| 508 | |||
| 441 | int parse_configfile(char *config_filename) { | 509 | int parse_configfile(char *config_filename) { |
| 442 | FILE *accesslist_filehandle; | 510 | FILE *config_file_handle; |
| 443 | char inbuf[512]; | 511 | char inbuf[512]; |
| 444 | ot_ip6 tmpip; | 512 | ot_ip6 tmpip; |
| 445 | #if defined(WANT_RESTRICT_STATS) || defined(WANT_IP_FROM_PROXY) || defined(WANT_SYNC_LIVE) | 513 | #if defined(WANT_RESTRICT_STATS) || defined(WANT_IP_FROM_PROXY) || defined(WANT_SYNC_LIVE) |
| @@ -447,19 +515,19 @@ int parse_configfile(char *config_filename) { | |||
| 447 | #endif | 515 | #endif |
| 448 | int bound = 0; | 516 | int bound = 0; |
| 449 | 517 | ||
| 450 | accesslist_filehandle = fopen(config_filename, "r"); | 518 | config_file_handle = fopen(config_filename, "r"); |
| 451 | 519 | ||
| 452 | if (accesslist_filehandle == NULL) { | 520 | if (config_file_handle == NULL) { |
| 453 | fprintf(stderr, "Warning: Can't open config file: %s.", config_filename); | 521 | fprintf(stderr, "Warning: Can't open config file: %s.", config_filename); |
| 454 | return 0; | 522 | return 0; |
| 455 | } | 523 | } |
| 456 | 524 | ||
| 457 | while (fgets(inbuf, sizeof(inbuf), accesslist_filehandle)) { | 525 | while (fgets(inbuf, sizeof(inbuf), config_file_handle)) { |
| 458 | char *p = inbuf; | 526 | char *p = inbuf, *end; |
| 459 | size_t strl; | 527 | uint16_t tmpport = 6969; |
| 460 | 528 | ||
| 461 | /* Skip white spaces */ | 529 | /* Skip white spaces */ |
| 462 | while (isspace(*p)) | 530 | while (isspace((unsigned char)*p)) |
| 463 | ++p; | 531 | ++p; |
| 464 | 532 | ||
| 465 | /* Ignore comments and empty lines */ | 533 | /* Ignore comments and empty lines */ |
| @@ -467,87 +535,98 @@ int parse_configfile(char *config_filename) { | |||
| 467 | continue; | 535 | continue; |
| 468 | 536 | ||
| 469 | /* consume trailing new lines and spaces */ | 537 | /* consume trailing new lines and spaces */ |
| 470 | strl = strlen(p); | 538 | end = p + strlen(p); |
| 471 | while (strl && isspace(p[strl - 1])) | 539 | while (end > p && isspace((unsigned char)end[-1])) |
| 472 | p[--strl] = 0; | 540 | *--end = 0; |
| 473 | 541 | ||
| 474 | /* Scan for commands */ | 542 | /* Scan for commands */ |
| 475 | if (!byte_diff(p, 15, "tracker.rootdir") && isspace(p[15])) { | 543 | switch (parse_config_key(&p)) { |
| 476 | set_config_option(&g_serverdir, p + 16); | 544 | case CONFIG_TRACKER_ROOTDIR: |
| 477 | } else if (!byte_diff(p, 12, "tracker.user") && isspace(p[12])) { | 545 | set_config_option(&g_serverdir, p); |
| 478 | set_config_option(&g_serveruser, p + 13); | 546 | break; |
| 479 | } else if (!byte_diff(p, 14, "listen.tcp_udp") && isspace(p[14])) { | 547 | case CONFIG_TRACKER_USER: |
| 480 | uint16_t tmpport = 6969; | 548 | set_config_option(&g_serveruser, p); |
| 481 | if (!scan_ip6_port(p + 15, tmpip, &tmpport)) | 549 | break; |
| 482 | goto parse_error; | 550 | case CONFIG_LISTEN_TCP_UDP: |
| 483 | ot_try_bind(tmpip, tmpport, FLAG_TCP); | 551 | if (!scan_ip6_port(p, tmpip, &tmpport)) |
| 484 | ++bound; | 552 | goto parse_error; |
| 485 | ot_try_bind(tmpip, tmpport, FLAG_UDP); | 553 | ot_try_bind(tmpip, tmpport, FLAG_TCP); |
| 486 | ++bound; | 554 | ++bound; |
| 487 | } else if (!byte_diff(p, 10, "listen.tcp") && isspace(p[10])) { | 555 | ot_try_bind(tmpip, tmpport, FLAG_UDP); |
| 488 | uint16_t tmpport = 6969; | 556 | ++bound; |
| 489 | if (!scan_ip6_port(p + 11, tmpip, &tmpport)) | 557 | break; |
| 490 | goto parse_error; | 558 | case CONFIG_LISTEN_TCP: |
| 491 | ot_try_bind(tmpip, tmpport, FLAG_TCP); | 559 | if (!scan_ip6_port(p, tmpip, &tmpport)) |
| 492 | ++bound; | 560 | goto parse_error; |
| 493 | } else if (!byte_diff(p, 10, "listen.udp") && isspace(p[10])) { | 561 | ot_try_bind(tmpip, tmpport, FLAG_TCP); |
| 494 | uint16_t tmpport = 6969; | 562 | ++bound; |
| 495 | if (!scan_ip6_port(p + 11, tmpip, &tmpport)) | 563 | break; |
| 496 | goto parse_error; | 564 | case CONFIG_LISTEN_UDP: |
| 497 | ot_try_bind(tmpip, tmpport, FLAG_UDP); | 565 | if (!scan_ip6_port(p, tmpip, &tmpport)) |
| 498 | ++bound; | 566 | goto parse_error; |
| 499 | } else if (!byte_diff(p, 18, "listen.udp.workers") && isspace(p[18])) { | 567 | ot_try_bind(tmpip, tmpport, FLAG_UDP); |
| 500 | char *value = p + 18; | 568 | ++bound; |
| 501 | while (isspace(*value)) | 569 | case CONFIG_LISTEN_UDP_WORKERS: |
| 502 | ++value; | 570 | scan_uint(p, &g_udp_workers); |
| 503 | scan_uint(value, &g_udp_workers); | 571 | break; |
| 504 | #ifdef WANT_ACCESSLIST_WHITE | 572 | #ifdef WANT_ACCESSLIST_WHITE |
| 505 | } else if (!byte_diff(p, 16, "access.whitelist") && isspace(p[16])) { | 573 | case CONFIG_ACCESS_WHITELIST: |
| 506 | set_config_option(&g_accesslist_filename, p + 17); | 574 | set_config_option(&g_accesslist_filename, p); |
| 575 | break; | ||
| 507 | #elif defined(WANT_ACCESSLIST_BLACK) | 576 | #elif defined(WANT_ACCESSLIST_BLACK) |
| 508 | } else if (!byte_diff(p, 16, "access.blacklist") && isspace(p[16])) { | 577 | case CONFIG_ACCESS_BLACKLIST: |
| 509 | set_config_option(&g_accesslist_filename, p + 17); | 578 | set_config_option(&g_accesslist_filename, p); |
| 579 | break; | ||
| 510 | #endif | 580 | #endif |
| 511 | #ifdef WANT_DYNAMIC_ACCESSLIST | 581 | #ifdef WANT_DYNAMIC_ACCESSLIST |
| 512 | } else if (!byte_diff(p, 15, "access.fifo_add") && isspace(p[15])) { | 582 | case CONFIG_ACCESS_FIFO_ADD: |
| 513 | set_config_option(&g_accesslist_pipe_add, p + 16); | 583 | set_config_option(&g_accesslist_pipe_add, p); |
| 514 | } else if (!byte_diff(p, 18, "access.fifo_delete") && isspace(p[18])) { | 584 | break; |
| 515 | set_config_option(&g_accesslist_pipe_delete, p + 19); | 585 | case CONFIG_ACCESS_FIFO_DELETE: |
| 586 | set_config_option(&g_accesslist_pipe_delete, p); | ||
| 587 | break; | ||
| 516 | #endif | 588 | #endif |
| 517 | #ifdef WANT_RESTRICT_STATS | 589 | #ifdef WANT_RESTRICT_STATS |
| 518 | } else if (!byte_diff(p, 12, "access.stats") && isspace(p[12])) { | 590 | case CONFIG_ACCESS_STATS: |
| 519 | if (!scan_ip6_net(p + 13, &tmpnet)) | 591 | if (!scan_ip6_net(p, &tmpnet)) |
| 520 | goto parse_error; | 592 | goto parse_error; |
| 521 | accesslist_bless_net(&tmpnet, OT_PERMISSION_MAY_STAT); | 593 | accesslist_bless_net(&tmpnet, OT_PERMISSION_MAY_STAT); |
| 594 | break; | ||
| 522 | #endif | 595 | #endif |
| 523 | } else if (!byte_diff(p, 17, "access.stats_path") && isspace(p[17])) { | 596 | case CONFIG_ACCESS_STATS_PATH: |
| 524 | set_config_option(&g_stats_path, p + 18); | 597 | set_config_option(&g_stats_path, p); |
| 598 | break; | ||
| 525 | #ifdef WANT_IP_FROM_PROXY | 599 | #ifdef WANT_IP_FROM_PROXY |
| 526 | } else if (!byte_diff(p, 12, "access.proxy") && isspace(p[12])) { | 600 | case CONFIG_ACCESS_PROXY: |
| 527 | if (!scan_ip6_net(p + 13, &tmpnet)) | 601 | if (!scan_ip6_net(p, &tmpnet)) |
| 528 | goto parse_error; | 602 | goto parse_error; |
| 529 | accesslist_bless_net(&tmpnet, OT_PERMISSION_MAY_PROXY); | 603 | accesslist_bless_net(&tmpnet, OT_PERMISSION_MAY_PROXY); |
| 604 | break; | ||
| 530 | #endif | 605 | #endif |
| 531 | } else if (!byte_diff(p, 20, "tracker.redirect_url") && isspace(p[20])) { | 606 | case CONFIG_TRACKER_REDIRECT_URL: |
| 532 | set_config_option(&g_redirecturl, p + 21); | 607 | set_config_option(&g_redirecturl, p); |
| 608 | break; | ||
| 533 | #ifdef WANT_SYNC_LIVE | 609 | #ifdef WANT_SYNC_LIVE |
| 534 | } else if (!byte_diff(p, 24, "livesync.cluster.node_ip") && isspace(p[24])) { | 610 | case CONFIG_LIVESYNC_CLUSTER_NODE_IP: |
| 535 | if (!scan_ip6_net(p + 25, &tmpnet)) | 611 | if (!scan_ip6_net(p, &tmpnet)) |
| 536 | goto parse_error; | 612 | goto parse_error; |
| 537 | accesslist_bless_net(&tmpnet, OT_PERMISSION_MAY_LIVESYNC); | 613 | accesslist_bless_net(&tmpnet, OT_PERMISSION_MAY_LIVESYNC); |
| 538 | } else if (!byte_diff(p, 23, "livesync.cluster.listen") && isspace(p[23])) { | 614 | break; |
| 539 | uint16_t tmpport = LIVESYNC_PORT; | 615 | case CONFIG_LIVESYNC_CLUSTER_LISTEN: |
| 540 | if (!scan_ip6_port(p + 24, tmpip, &tmpport)) | 616 | tmpport = LIVESYNC_PORT; |
| 541 | goto parse_error; | 617 | if (!scan_ip6_port(p, tmpip, &tmpport)) |
| 542 | livesync_bind_mcast(tmpip, tmpport); | 618 | goto parse_error; |
| 619 | livesync_bind_mcast(tmpip, tmpport); | ||
| 620 | break; | ||
| 543 | #endif | 621 | #endif |
| 544 | } else | 622 | default: |
| 545 | fprintf(stderr, "Unhandled line in config file: %s\n", inbuf); | 623 | fprintf(stderr, "Unhandled line in config file: %s\n", inbuf); |
| 546 | continue; | 624 | break; |
| 547 | parse_error: | 625 | parse_error: |
| 548 | fprintf(stderr, "Parse error in config file: %s\n", inbuf); | 626 | fprintf(stderr, "Parse error in config file: %s\n", inbuf); |
| 627 | } | ||
| 549 | } | 628 | } |
| 550 | fclose(accesslist_filehandle); | 629 | fclose(config_file_handle); |
| 551 | return bound; | 630 | return bound; |
| 552 | } | 631 | } |
| 553 | 632 | ||
| @@ -568,16 +647,10 @@ void load_state(const char *const state_filename) { | |||
| 568 | /* We do ignore anything that is not of the form "^[:xdigit:]:\d+:\d+" */ | 647 | /* We do ignore anything that is not of the form "^[:xdigit:]:\d+:\d+" */ |
| 569 | while (fgets(inbuf, sizeof(inbuf), state_filehandle)) { | 648 | while (fgets(inbuf, sizeof(inbuf), state_filehandle)) { |
| 570 | size_t i; | 649 | size_t i; |
| 571 | for (i = 0; i < sizeof(ot_hash); ++i) { | ||
| 572 | int eger = 16 * scan_fromhex(inbuf[2 * i]) + scan_fromhex(inbuf[1 + 2 * i]); | ||
| 573 | if (eger < 0) | ||
| 574 | continue; | ||
| 575 | infohash[i] = eger; | ||
| 576 | } | ||
| 577 | 650 | ||
| 578 | if (i != sizeof(ot_hash)) | 651 | if (!hex_tohash(infohash, inbuf)) |
| 579 | continue; | 652 | continue; |
| 580 | i *= 2; | 653 | i = 2 * sizeof(ot_hash); |
| 581 | 654 | ||
| 582 | if (inbuf[i++] != ':' || !(consumed = scan_ulonglong(inbuf + i, &base))) | 655 | if (inbuf[i++] != ':' || !(consumed = scan_ulonglong(inbuf + i, &base))) |
| 583 | continue; | 656 | continue; |
| @@ -660,11 +733,7 @@ int main(int argc, char **argv) { | |||
| 660 | serverip[10] = serverip[11] = -1; | 733 | serverip[10] = serverip[11] = -1; |
| 661 | #endif | 734 | #endif |
| 662 | 735 | ||
| 663 | #ifdef WANT_DEV_RANDOM | 736 | random_init(); |
| 664 | srandomdev(); | ||
| 665 | #else | ||
| 666 | srandom(time(NULL)); | ||
| 667 | #endif | ||
| 668 | 737 | ||
| 669 | while (scanon) { | 738 | while (scanon) { |
| 670 | switch (getopt(argc, argv, | 739 | switch (getopt(argc, argv, |
