diff --git a/src/acl.c b/src/acl.c index 0fc81b51..393ebe32 100644 --- a/src/acl.c +++ b/src/acl.c @@ -45,18 +45,96 @@ static struct ip_set outbound_block_list_ipv4; static struct ip_set outbound_block_list_ipv6; static struct cork_dllist outbound_block_list_rules; +#ifdef __linux__ + +#include + +static int +run_cmd(const char *cmdstring) +{ + pid_t pid; + int status; + if (cmdstring == NULL) { + return 1; + } + if ((pid = fork()) < 0) { + status = -1; + } else if (pid == 0) { + execl("/bin/sh", "sh", "-c", cmdstring, (char *)0); + _exit(127); + } + return status; +} + +static int +init_iptables() +{ + if (geteuid() != 0) + return -1; + char cli[256]; + sprintf(cli, "iptables -N SHADOWSOCKS_LIBEV; \ + iptables -F SHADOWSOCKS_LIBEV; \ + iptables -A OUTPUT -p tcp --tcp-flags FIN FIN -j SHADOWSOCKS_LIBEV"); + return run_cmd(cli); +} + +static int +clean_iptables() +{ + if (geteuid() != 0) + return -1; + char cli[256]; + sprintf(cli, "iptables -D OUTPUT -p tcp --tcp-flags FIN FIN -j SHADOWSOCKS_LIBEV; \ + iptables -F SHADOWSOCKS_LIBEV; \ + iptables -X SHADOWSOCKS_LIBEV"); + return run_cmd(cli); +} + +static int +set_iptables_rules(char *addr, int add) +{ + if (geteuid() != 0) + return -1; + char cli[256]; + if (add) + sprintf(cli, "iptables -A SHADOWSOCKS_LIBEV -d %s -j DROP", addr); + else + sprintf(cli, "iptables -D SHADOWSOCKS_LIBEV -d %s -j DROP", addr); + return run_cmd(cli); +} + +#endif + void init_block_list() { // Initialize cache +#ifdef __linux__ + init_iptables(); +#endif cache_create(&block_list, 256, NULL); } +void +free_block_list() +{ +#ifdef __linux__ + clean_iptables(); +#endif + cache_clear(block_list, 0); // Remove all items +} + + int remove_from_block_list(char *addr) { size_t addr_len = strlen(addr); +#ifdef __linux__ + if (cache_key_exist(block_list, addr, addr_len)) + set_iptables_rules(addr, 0); +#endif + return cache_remove(block_list, addr, addr_len); } @@ -83,6 +161,9 @@ check_block_list(char *addr, int err_level) int *count = (int *)ss_malloc(sizeof(int)); *count = 1; cache_insert(block_list, addr, addr_len, count); +#ifdef __linux__ + set_iptables_rules(addr, 1); +#endif } return 0; diff --git a/src/acl.h b/src/acl.h index 015c1cec..d5e27051 100644 --- a/src/acl.h +++ b/src/acl.h @@ -43,6 +43,7 @@ int acl_remove_ip(const char *ip); int get_acl_mode(void); void init_block_list(); +void free_block_list(); int check_block_list(char *addr, int err_level); int remove_from_block_list(char *addr); diff --git a/src/server.c b/src/server.c index db506d57..b264ab63 100644 --- a/src/server.c +++ b/src/server.c @@ -1866,6 +1866,9 @@ main(int argc, char **argv) LOGI("closed gracefully"); } + // Free block list + free_block_list(); + if (manager_address != NULL) { ev_timer_stop(EV_DEFAULT, &stat_update_watcher); } diff --git a/src/utils.c b/src/utils.c index 367d4c2d..bebf0a45 100644 --- a/src/utils.c +++ b/src/utils.c @@ -109,14 +109,14 @@ run_as(const char *user) if (err == 0 && pwd) { /* setgid first, because we may not be allowed to do it anymore after setuid */ - if (setgid(pwd->pw_gid) != 0) { + if (setresgid(pwd->pw_gid, 0, pwd->pw_gid) != 0) { LOGE( "Could not change group id to that of run_as user '%s': %s", user, strerror(errno)); return 0; } - if (setuid(pwd->pw_uid) != 0) { + if (setresuid(pwd->pw_uid, 0, pwd->pw_uid) != 0) { LOGE( "Could not change user id to that of run_as user '%s': %s", user, strerror(errno)); @@ -150,12 +150,12 @@ run_as(const char *user) return 0; } /* setgid first, because we may not allowed to do it anymore after setuid */ - if (setgid(pwd->pw_gid) != 0) { + if (setresgid(pwd->pw_gid, 0, pwd->pwd_gid) != 0) { LOGE("Could not change group id to that of run_as user '%s': %s", user, strerror(errno)); return 0; } - if (setuid(pwd->pw_uid) != 0) { + if (setresuid(pwd->pw_uid, 0, pwd->pwd_uid) != 0) { LOGE("Could not change user id to that of run_as user '%s': %s", user, strerror(errno)); return 0;