diff options
Diffstat (limited to 'main.c')
-rw-r--r-- | main.c | 163 |
1 files changed, 86 insertions, 77 deletions
@@ -42,10 +42,11 @@ long int udp_end_port = 0; | |||
42 | char config_path[500] = "/etc/tuntox/"; | 42 | char config_path[500] = "/etc/tuntox/"; |
43 | 43 | ||
44 | /* Limit hostname and port in server */ | 44 | /* Limit hostname and port in server */ |
45 | int nrules = 0; | 45 | int tunnel_target_whitelist_size = 0; |
46 | char rules_file[500] = "/etc/tuntox/rules"; | 46 | char *tunnel_target_whitelist_file; |
47 | bool enforce_whitelist = false; | 47 | bool tunnel_target_whitelist_enforced = false; |
48 | rule *rules = NULL; | 48 | rule *tunnel_target_whitelist_rules = NULL; |
49 | time_t tunnel_target_whitelist_mtime = 0; | ||
49 | 50 | ||
50 | /* Ports and hostname for port forwarding */ | 51 | /* Ports and hostname for port forwarding */ |
51 | int remote_port = 0; | 52 | int remote_port = 0; |
@@ -422,13 +423,16 @@ int handle_ping_frame(protocol_frame *rcvd_frame) | |||
422 | return 0; | 423 | return 0; |
423 | } | 424 | } |
424 | 425 | ||
426 | void tunnel_target_whitelist_load(); | ||
425 | bool check_requested_tunnel_against_rules(char *hostname, in_port_t port) | 427 | bool check_requested_tunnel_against_rules(char *hostname, in_port_t port) |
426 | { | 428 | { |
427 | if (!enforce_whitelist) return true; | 429 | if (!tunnel_target_whitelist_enforced) return true; |
428 | 430 | ||
429 | if (nrules <= 0) | 431 | tunnel_target_whitelist_load(); |
432 | |||
433 | if (tunnel_target_whitelist_size <= 0) | ||
430 | { | 434 | { |
431 | log_printf(l_warning, "filter option active but no allowed host/port. all requests will be dropped.\n"); | 435 | log_printf(L_WARNING, "Whitelist enforced, but no whitelisted entries. All requests will be dropped.\n"); |
432 | return false; | 436 | return false; |
433 | } | 437 | } |
434 | 438 | ||
@@ -436,11 +440,7 @@ bool check_requested_tunnel_against_rules(char *hostname, in_port_t port) | |||
436 | candidate.host = hostname; | 440 | candidate.host = hostname; |
437 | candidate.port = port; | 441 | candidate.port = port; |
438 | 442 | ||
439 | LL_SEARCH(rules, found, &candidate, rule_match); | 443 | LL_SEARCH(tunnel_target_whitelist_rules, found, &candidate, rule_match); |
440 | if(!found) | ||
441 | { | ||
442 | log_printf(L_WARNING, "Rejected, request not in rules\n"); | ||
443 | } | ||
444 | return found; | 444 | return found; |
445 | } | 445 | } |
446 | 446 | ||
@@ -473,6 +473,8 @@ int handle_request_tunnel_frame(protocol_frame *rcvd_frame) | |||
473 | 473 | ||
474 | if (!check_requested_tunnel_against_rules(hostname, port)) | 474 | if (!check_requested_tunnel_against_rules(hostname, port)) |
475 | { | 475 | { |
476 | log_printf(L_WARNING, "Rejected tunnel request from #%d to non-whitelisted target host:port (%s:%d)", | ||
477 | rcvd_frame->friendnumber, hostname, port); | ||
476 | free(hostname); | 478 | free(hostname); |
477 | return -1; | 479 | return -1; |
478 | } | 480 | } |
@@ -791,71 +793,89 @@ static size_t load_save(uint8_t **out_data) | |||
791 | } | 793 | } |
792 | } | 794 | } |
793 | 795 | ||
796 | void tunnel_target_whitelist_clear(); | ||
794 | /* Loads a list of allowed hostnames and ports from file. Format is hostname:port*/ | 797 | /* Loads a list of allowed hostnames and ports from file. Format is hostname:port*/ |
795 | void load_rules() | 798 | void tunnel_target_whitelist_load() |
796 | { | 799 | { |
797 | char *ahost=NULL; | 800 | char *ahost=NULL; |
798 | int aport=0; | 801 | int aport=0; |
799 | char line[100 + 1] = ""; | 802 | char line[1024]; |
800 | FILE *file = NULL; | 803 | FILE *file = NULL; |
801 | rule *rule_obj = NULL; | 804 | rule *rule_obj = NULL; |
802 | int valid_rules = 0; | ||
803 | 805 | ||
804 | file = fopen(rules_file, "r"); | 806 | if (!tunnel_target_whitelist_enforced) return; |
805 | |||
806 | if (file == NULL) { | ||
807 | log_printf(L_WARNING, "Could not open rules file (%s)\n", rules_file); | ||
808 | return; | ||
809 | } | ||
810 | 807 | ||
811 | while (fgets(line, sizeof(line), file)) { | 808 | /* If we have existing rules, check to see if we need to continue. */ |
812 | /* allow comments & white lines */ | 809 | if(tunnel_target_whitelist_rules) |
813 | if (line[0]=='#'||line[0]=='\n') { | 810 | { |
814 | continue; | 811 | struct stat buf; |
812 | if (stat(tunnel_target_whitelist_file, &buf) < 0) | ||
813 | { | ||
814 | /* File removed? Better clear the whitelist. */ | ||
815 | tunnel_target_whitelist_mtime = 0; | ||
816 | tunnel_target_whitelist_clear(); | ||
817 | return; | ||
815 | } | 818 | } |
816 | if (parse_pipe_port_forward(line, &ahost, &aport) >= 0) { | 819 | if (buf.st_mtime == tunnel_target_whitelist_mtime) return; |
817 | if (aport > 0 && aport < 65535) { | ||
818 | 820 | ||
819 | rule_obj = (rule *)calloc(sizeof(rule), 1); | 821 | tunnel_target_whitelist_mtime = buf.st_mtime; |
820 | if(!rule_obj) | 822 | tunnel_target_whitelist_clear(); |
821 | { | 823 | } |
822 | log_printf(L_ERROR, "Could not allocate memory for rule"); | ||
823 | exit(1); | ||
824 | } | ||
825 | 824 | ||
826 | rule_obj->port = aport; | 825 | file = fopen(tunnel_target_whitelist_file, "r"); |
827 | rule_obj->host = strdup(ahost); | ||
828 | 826 | ||
829 | LL_APPEND(rules, rule_obj); | 827 | if(file == NULL) { |
830 | valid_rules++; | 828 | log_printf(L_WARNING, "Could not open rules file (%s)\n", tunnel_target_whitelist_file); |
831 | } else { | 829 | return; |
832 | log_printf(L_WARNING, "Invalid port in line: %s\n", line); | 830 | } |
831 | |||
832 | while(fgets(line, sizeof(line), file)) | ||
833 | { | ||
834 | strtok(line, "#\n"); /* Chop line at first hash */ | ||
835 | char *orig_line = strdup(line); /* Not quite the original line; keeps | ||
836 | newline and comments out of logs */ | ||
837 | if(parse_pipe_port_forward(line, &ahost, &aport)) | ||
838 | { | ||
839 | rule_obj = (rule *)calloc(sizeof(rule), 1); | ||
840 | if(!rule_obj) | ||
841 | { | ||
842 | log_printf(L_ERROR, "Could not allocate memory for rule"); | ||
843 | exit(1); | ||
833 | } | 844 | } |
834 | } else { | 845 | |
835 | log_printf(L_WARNING, "Could not parse line: %s\n", line); | 846 | rule_obj->port = aport; |
847 | rule_obj->host = strdup(ahost); | ||
848 | |||
849 | LL_APPEND(tunnel_target_whitelist_rules, rule_obj); | ||
850 | tunnel_target_whitelist_size++; | ||
851 | } | ||
852 | else | ||
853 | { | ||
854 | log_printf(L_WARNING, "Could not parse line: %s\n", orig_line); | ||
836 | } | 855 | } |
856 | free(orig_line); | ||
837 | } | 857 | } |
838 | fclose(file); | 858 | fclose(file); |
839 | 859 | ||
840 | /* save valid rules in global variable */ | 860 | log_printf(L_INFO, "Loaded %d rules\n", tunnel_target_whitelist_size); |
841 | nrules = valid_rules; | 861 | if (tunnel_target_whitelist_size == 0 && tunnel_target_whitelist_enforced){ |
842 | |||
843 | log_printf(L_INFO, "Loaded %d rules\n", nrules); | ||
844 | if (nrules==0 && enforce_whitelist){ | ||
845 | log_printf(L_WARNING, "No rules loaded! NO CONNECTIONS WILL BE ALLOWED!\n"); | 862 | log_printf(L_WARNING, "No rules loaded! NO CONNECTIONS WILL BE ALLOWED!\n"); |
846 | } | 863 | } |
847 | } | 864 | } |
848 | 865 | ||
849 | /* Clear rules loaded into memory */ | 866 | /* Clear rules loaded into memory */ |
850 | void clear_rules() | 867 | void tunnel_target_whitelist_clear() |
851 | { | 868 | { |
852 | rule * elt, *tmp; | 869 | rule * elt, *tmp; |
853 | /* delete each elemen using the safe iterator */ | 870 | /* delete each elemen using the safe iterator */ |
854 | LL_FOREACH_SAFE(rules,elt,tmp) { | 871 | LL_FOREACH_SAFE(tunnel_target_whitelist_rules,elt,tmp) { |
855 | LL_DELETE(rules,elt); | 872 | LL_DELETE(tunnel_target_whitelist_rules,elt); |
856 | free(elt->host); | 873 | free(elt->host); |
857 | free(elt); | 874 | free(elt); |
858 | } | 875 | } |
876 | free(tunnel_target_whitelist_rules); | ||
877 | tunnel_target_whitelist_rules = NULL; | ||
878 | tunnel_target_whitelist_size = 0; | ||
859 | } | 879 | } |
860 | 880 | ||
861 | void accept_friend_request(Tox *tox, const uint8_t *public_key, const uint8_t *message, size_t length, void *userdata) | 881 | void accept_friend_request(Tox *tox, const uint8_t *public_key, const uint8_t *message, size_t length, void *userdata) |
@@ -914,12 +934,17 @@ void accept_friend_request(Tox *tox, const uint8_t *public_key, const uint8_t *m | |||
914 | } | 934 | } |
915 | 935 | ||
916 | /* Callback for tox_callback_self_connection_status() */ | 936 | /* Callback for tox_callback_self_connection_status() */ |
917 | void handle_connection_status_change(Tox *tox, TOX_CONNECTION p_connection_status, void *user_data) | 937 | void handle_connection_status_change(Tox *tox, TOX_CONNECTION new_connection_status, void *user_data) |
918 | { | 938 | { |
919 | const char *status = NULL; | 939 | connection_status = new_connection_status; |
920 | connection_status = p_connection_status; | 940 | if (connection_status) |
921 | status = readable_connection_status(connection_status); | 941 | { |
922 | log_printf(L_INFO, "Connection status changed: %s", status); | 942 | log_printf(L_INFO, "Connected to Tox network: %s\n", readable_connection_status(connection_status)); |
943 | } | ||
944 | else | ||
945 | { | ||
946 | log_printf(L_INFO, "Disconnected from Tox network\n"); | ||
947 | } | ||
923 | } | 948 | } |
924 | 949 | ||
925 | #ifdef LOG_IP_ADDRESS | 950 | #ifdef LOG_IP_ADDRESS |
@@ -971,7 +996,6 @@ int do_server_loop() | |||
971 | unsigned char tox_packet_buf[PROTOCOL_MAX_PACKET_SIZE]; | 996 | unsigned char tox_packet_buf[PROTOCOL_MAX_PACKET_SIZE]; |
972 | tunnel *tun = NULL; | 997 | tunnel *tun = NULL; |
973 | tunnel *tmp = NULL; | 998 | tunnel *tmp = NULL; |
974 | TOX_CONNECTION connected = 0; | ||
975 | int sent_data = 0; | 999 | int sent_data = 0; |
976 | 1000 | ||
977 | tox_callback_friend_lossless_packet(tox, parse_lossless_packet); | 1001 | tox_callback_friend_lossless_packet(tox, parse_lossless_packet); |
@@ -997,20 +1021,6 @@ int do_server_loop() | |||
997 | log_printf(L_DEBUG2, "Iteration interval: %dms\n", tox_do_interval_ms); | 1021 | log_printf(L_DEBUG2, "Iteration interval: %dms\n", tox_do_interval_ms); |
998 | gettimeofday(&tv_start, NULL); | 1022 | gettimeofday(&tv_start, NULL); |
999 | 1023 | ||
1000 | /* Check change in connection state */ | ||
1001 | if(connection_status != connected) | ||
1002 | { | ||
1003 | connected = connection_status; | ||
1004 | if(connected) | ||
1005 | { | ||
1006 | log_printf(L_DEBUG, "Connected to Tox network\n"); | ||
1007 | } | ||
1008 | else | ||
1009 | { | ||
1010 | log_printf(L_DEBUG, "Disconnected from Tox network\n"); | ||
1011 | } | ||
1012 | } | ||
1013 | |||
1014 | fds = master_server_fds; | 1024 | fds = master_server_fds; |
1015 | 1025 | ||
1016 | /* Poll for data from our client connection */ | 1026 | /* Poll for data from our client connection */ |
@@ -1304,7 +1314,7 @@ int main(int argc, char *argv[]) | |||
1304 | /* Local port forwarding */ | 1314 | /* Local port forwarding */ |
1305 | client_mode = 1; | 1315 | client_mode = 1; |
1306 | client_local_port_mode = 1; | 1316 | client_local_port_mode = 1; |
1307 | if(parse_local_port_forward(optarg, &local_port, &remote_host, &remote_port) < 0) | 1317 | if(!parse_local_port_forward(optarg, &local_port, &remote_host, &remote_port)) |
1308 | { | 1318 | { |
1309 | log_printf(L_ERROR, "Invalid value for -L option - use something like -L 22:127.0.0.1:22\n"); | 1319 | log_printf(L_ERROR, "Invalid value for -L option - use something like -L 22:127.0.0.1:22\n"); |
1310 | exit(1); | 1320 | exit(1); |
@@ -1319,7 +1329,7 @@ int main(int argc, char *argv[]) | |||
1319 | /* Pipe forwarding */ | 1329 | /* Pipe forwarding */ |
1320 | client_mode = 1; | 1330 | client_mode = 1; |
1321 | client_pipe_mode = 1; | 1331 | client_pipe_mode = 1; |
1322 | if(parse_pipe_port_forward(optarg, &remote_host, &remote_port) < 0) | 1332 | if(!parse_pipe_port_forward(optarg, &remote_host, &remote_port) || remote_port == 0) |
1323 | { | 1333 | { |
1324 | log_printf(L_ERROR, "Invalid value for -W option - use something like -W 127.0.0.1:22\n"); | 1334 | log_printf(L_ERROR, "Invalid value for -W option - use something like -W 127.0.0.1:22\n"); |
1325 | exit(1); | 1335 | exit(1); |
@@ -1369,9 +1379,9 @@ int main(int argc, char *argv[]) | |||
1369 | load_saved_toxid_in_client_mode = 1; | 1379 | load_saved_toxid_in_client_mode = 1; |
1370 | break; | 1380 | break; |
1371 | case 'f': | 1381 | case 'f': |
1372 | strncpy(rules_file, optarg, sizeof(rules_file) - 1); | 1382 | tunnel_target_whitelist_file = strdup(optarg); |
1373 | enforce_whitelist = true; | 1383 | tunnel_target_whitelist_enforced = true; |
1374 | log_printf(L_INFO, "Filter policy set to VALIDATE\n"); | 1384 | log_printf(L_INFO, "Whitelist enforced on outgoing connections: only matched hosts/ports will be allowed.\n"); |
1375 | break; | 1385 | break; |
1376 | case 's': | 1386 | case 's': |
1377 | /* Shared secret */ | 1387 | /* Shared secret */ |
@@ -1471,9 +1481,9 @@ int main(int argc, char *argv[]) | |||
1471 | log_printf(L_INFO, "Server in ToxID whitelisting mode - only clients listed with -i can connect"); | 1481 | log_printf(L_INFO, "Server in ToxID whitelisting mode - only clients listed with -i can connect"); |
1472 | } | 1482 | } |
1473 | 1483 | ||
1474 | if((!client_mode) && enforce_whitelist) | 1484 | if(!client_mode && tunnel_target_whitelist_enforced) |
1475 | { | 1485 | { |
1476 | load_rules(); | 1486 | tunnel_target_whitelist_load(); |
1477 | } | 1487 | } |
1478 | 1488 | ||
1479 | /* If shared secret has not been provided via -s, read from TUNTOX_SHARED_SECRET env variable */ | 1489 | /* If shared secret has not been provided via -s, read from TUNTOX_SHARED_SECRET env variable */ |
@@ -1589,7 +1599,6 @@ int main(int argc, char *argv[]) | |||
1589 | { | 1599 | { |
1590 | tox_callback_friend_request(tox, accept_friend_request); | 1600 | tox_callback_friend_request(tox, accept_friend_request); |
1591 | do_server_loop(); | 1601 | do_server_loop(); |
1592 | clear_rules(); | ||
1593 | } | 1602 | } |
1594 | } | 1603 | } |
1595 | 1604 | ||