diff --git a/doc/ss-server.asciidoc b/doc/ss-server.asciidoc index 0bbe6659..ef070c9a 100644 --- a/doc/ss-server.asciidoc +++ b/doc/ss-server.asciidoc @@ -14,7 +14,7 @@ SYNOPSIS [-t ] [-c ] [-i ] [-a ] [-d ] [-n ] [-b ] [--mtu ] + [--acl ] [--mtu ] [--manager-address ] DESCRIPTION @@ -111,9 +111,6 @@ Enable Multipath TCP. + Only available with MPTCP enabled Linux kernel. ---firewall:: -Setup firewall rules for auto blocking. - --acl :: Enable ACL (Access Control List) and specify config file. diff --git a/src/acl.c b/src/acl.c index 15b9ffaa..84ec0365 100644 --- a/src/acl.c +++ b/src/acl.c @@ -45,218 +45,15 @@ 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 -#include - -#define NO_FIREWALL_MODE 0 -#define IPTABLES_MODE 1 -#define FIREWALLD_MODE 2 - -static FILE *shell_stdin; -static int mode = NO_FIREWALL_MODE; - -static char chain_name[64]; -static char *iptables_init_chain = - "iptables -N %s; iptables -F %s; iptables -A OUTPUT -p tcp --tcp-flags RST RST -j %s"; -static char *iptables_remove_chain = - "iptables -D OUTPUT -p tcp --tcp-flags RST RST -j %s; iptables -F %s; iptables -X %s"; -static char *iptables_add_rule = "iptables -A %s -d %s -j DROP"; -static char *iptables_remove_rule = "iptables -D %s -d %s -j DROP"; - -static char *ip6tables_init_chain = - "ip6tables -N %s; ip6tables -F %s; ip6tables -A OUTPUT -p tcp --tcp-flags RST RST -j %s"; -static char *ip6tables_remove_chain = - "ip6tables -D OUTPUT -p tcp --tcp-flags RST RST -j %s; ip6tables -F %s; ip6tables -X %s"; -static char *ip6tables_add_rule = "ip6tables -A %s -d %s -j DROP"; -static char *ip6tables_remove_rule = "ip6tables -D %s -d %s -j DROP"; - -static char *firewalld_init_chain = - "firewall-cmd --direct --add-chain ipv4 filter %s; \ - firewall-cmd --direct --passthrough ipv4 -F %s; \ - firewall-cmd --direct --passthrough ipv4 -A OUTPUT -p tcp --tcp-flags RST RST -j %s"; -static char *firewalld_remove_chain = - "firewall-cmd --direct --passthrough ipv4 -D OUTPUT -p tcp --tcp-flags RST RST -j %s; \ - firewall-cmd --direct --passthrough ipv4 -F %s; \ - firewall-cmd --direct --remove-chain ipv4 filter %s"; -static char *firewalld_add_rule = "firewall-cmd --direct --passthrough ipv4 -A %s -d %s -j DROP"; -static char *firewalld_remove_rule = "firewall-cmd --direct --passthrough ipv4 -D %s -d %s -j DROP"; - -static char *firewalld6_init_chain = - "firewall-cmd --direct --add-chain ipv6 filter %s; \ - firewall-cmd --direct --passthrough ipv6 -F %s; \ - firewall-cmd --direct --passthrough ipv6 -A OUTPUT -p tcp --tcp-flags RST RST -j %s"; -static char *firewalld6_remove_chain = - "firewall-cmd --direct --passthrough ipv6 -D OUTPUT -p tcp --tcp-flags RST RST -j %s; \ - firewall-cmd --direct --passthrough ipv6 -F %s; \ - firewall-cmd --direct --remove-chain ipv6 filter %s"; -static char *firewalld6_add_rule = "firewall-cmd --direct --passthrough ipv6 -A %s -d %s -j DROP"; -static char *firewalld6_remove_rule = "firewall-cmd --direct --passthrough ipv6 -D %s -d %s -j DROP"; - -static int -run_cmd(const char *cmd) -{ - int ret = 0; - char cmdstring[256]; - - sprintf(cmdstring, "%s\n", cmd); - size_t len = strlen(cmdstring); - - if (shell_stdin != NULL) { - ret = fwrite(cmdstring, 1, len, shell_stdin); - fflush(shell_stdin); - } - - return ret == len; -} - -static int -init_firewall() -{ - int ret = 0; - char cli[256]; - FILE *fp; - - if (getuid() != 0) - return -1; - - sprintf(cli, "firewall-cmd --version 2>&1"); - fp = popen(cli, "r"); - - if (fp == NULL) - return -1; - - if (pclose(fp) == 0) { - mode = FIREWALLD_MODE; - } else { - /* Check whether we have permission to operate iptables. - * Note that checking `iptables --version` is insufficient: - * eg, running within a child user namespace. - */ - sprintf(cli, "iptables -L 2>&1"); - fp = popen(cli, "r"); - if (fp == NULL) - return -1; - if (pclose(fp) == 0) - mode = IPTABLES_MODE; - } - - sprintf(chain_name, "SHADOWSOCKS_LIBEV_%d", getpid()); - - if (mode == FIREWALLD_MODE) { - sprintf(cli, firewalld6_init_chain, chain_name, chain_name, chain_name); - ret |= system(cli); - sprintf(cli, firewalld_init_chain, chain_name, chain_name, chain_name); - ret |= system(cli); - } else if (mode == IPTABLES_MODE) { - sprintf(cli, ip6tables_init_chain, chain_name, chain_name, chain_name); - ret |= system(cli); - sprintf(cli, iptables_init_chain, chain_name, chain_name, chain_name); - ret |= system(cli); - } - - shell_stdin = popen("/bin/sh", "w"); - - return ret; -} - -static int -reset_firewall() -{ - int ret = 0; - char cli[256]; - - if (getuid() != 0) - return -1; - - if (mode == IPTABLES_MODE) { - sprintf(cli, ip6tables_remove_chain, chain_name, chain_name, chain_name); - ret |= system(cli); - sprintf(cli, iptables_remove_chain, chain_name, chain_name, chain_name); - ret |= system(cli); - } else if (mode == FIREWALLD_MODE) { - sprintf(cli, firewalld6_remove_chain, chain_name, chain_name, chain_name); - ret |= system(cli); - sprintf(cli, firewalld_remove_chain, chain_name, chain_name, chain_name); - ret |= system(cli); - } - - if (shell_stdin != NULL) { - run_cmd("exit 0"); - pclose(shell_stdin); - } - - return ret; -} - -static int -set_firewall_rule(char *addr, int add) -{ - char cli[256]; - struct cork_ip ip; - - if (getuid() != 0) - return -1; - - if (cork_ip_init(&ip, addr)) - return -1; - - if (add) { - if (mode == IPTABLES_MODE) - sprintf(cli, ip.version == 4 ? iptables_add_rule : ip6tables_add_rule, - chain_name, addr); - else if (mode == FIREWALLD_MODE) - sprintf(cli, ip.version == 4 ? firewalld_add_rule : firewalld6_add_rule, - chain_name, addr); - return run_cmd(cli); - } else { - if (mode == IPTABLES_MODE) - sprintf(cli, ip.version == 4 ? iptables_remove_rule : ip6tables_remove_rule, - chain_name, addr); - else if (mode == FIREWALLD_MODE) - sprintf(cli, ip.version == 4 ? firewalld_remove_rule : firewalld6_remove_rule, - chain_name, addr); - return run_cmd(cli); - } - - return 0; -} - -static void -free_firewall_rule(void *key, void *element) -{ - if (key == NULL) - return; - char *addr = (char *)key; - set_firewall_rule(addr, 0); - ss_free(element); -} - -#endif - void -init_block_list(int firewall) +init_block_list() { - // Initialize cache -#ifdef __linux__ - if (firewall) - init_firewall(); - else - mode = NO_FIREWALL_MODE; - cache_create(&block_list, 256, free_firewall_rule); -#else cache_create(&block_list, 256, NULL); -#endif } void free_block_list() { -#ifdef __linux__ - if (mode != NO_FIREWALL_MODE) - reset_firewall(); -#endif cache_clear(block_list, 0); // Remove all items } @@ -306,10 +103,6 @@ update_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__ - if (mode != NO_FIREWALL_MODE) - set_firewall_rule(addr, 1); -#endif } return 0; diff --git a/src/acl.h b/src/acl.h index d6f18b80..6e404175 100644 --- a/src/acl.h +++ b/src/acl.h @@ -42,7 +42,7 @@ int acl_remove_ip(const char *ip); int get_acl_mode(void); -void init_block_list(int firewall); +void init_block_list(); void free_block_list(); int check_block_list(char *addr); int update_block_list(char *addr, int err_level); diff --git a/src/local.c b/src/local.c index c33c85a3..e1581313 100644 --- a/src/local.c +++ b/src/local.c @@ -1132,7 +1132,10 @@ signal_cb(EV_P_ ev_signal *w, int revents) switch (w->signum) { #ifndef __MINGW32__ case SIGCHLD: - LOGE("plugin service exit unexpectedly"); + if (!is_plugin_running()) + LOGE("plugin service exit unexpectedly"); + else + return; case SIGUSR1: #endif case SIGINT: diff --git a/src/plugin.c b/src/plugin.c index 65b647c4..dfe2b342 100644 --- a/src/plugin.c +++ b/src/plugin.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include @@ -179,6 +180,14 @@ stop_plugin() } } +int is_plugin_running() +{ + if (sub != NULL) { + return cork_subprocess_is_finished(sub); + } + return 0; +} + #else #include "stdint.h" @@ -210,4 +219,10 @@ stop_plugin() FATAL("Plugin is not supported on MinGW."); } +int +is_plugin_running() +{ + FATAL("Plugin is not supported on MinGW."); +} + #endif diff --git a/src/plugin.h b/src/plugin.h index 1579411e..f74c7861 100644 --- a/src/plugin.h +++ b/src/plugin.h @@ -34,5 +34,6 @@ int start_plugin(const char *plugin, const char *local_port); uint16_t get_local_port(); void stop_plugin(); +int is_plugin_running(); #endif // _PLUGIN_H diff --git a/src/redir.c b/src/redir.c index 87010b96..5c3f7d30 100644 --- a/src/redir.c +++ b/src/redir.c @@ -759,7 +759,10 @@ signal_cb(EV_P_ ev_signal *w, int revents) if (revents & EV_SIGNAL) { switch (w->signum) { case SIGCHLD: - LOGE("plugin service exit unexpectedly"); + if (!is_plugin_running()) + LOGE("plugin service exit unexpectedly"); + else + return; case SIGINT: case SIGTERM: ev_signal_stop(EV_DEFAULT, &sigint_watcher); diff --git a/src/server.c b/src/server.c index 1d8d4392..cfbb71b4 100644 --- a/src/server.c +++ b/src/server.c @@ -80,6 +80,10 @@ #define SSMAXCONN 1024 #endif +#ifndef MAX_FRAG +#define MAX_FRAG 2 +#endif + static void signal_cb(EV_P_ ev_signal *w, int revents); static void accept_cb(EV_P_ ev_io *w, int revents); static void server_send_cb(EV_P_ ev_io *w, int revents); @@ -655,6 +659,13 @@ server_recv_cb(EV_P_ ev_io *w, int revents) tx += r; + if (server->frag >= MAX_FRAG) { + LOGE("fragmentation detected"); + close_and_free_remote(EV_A_ remote); + close_and_free_server(EV_A_ server); + return; + } + if (server->stage == STAGE_ERROR) { server->buf->len = 0; server->buf->idx = 0; @@ -667,6 +678,7 @@ server_recv_cb(EV_P_ ev_io *w, int revents) if (buf->len <= enc_get_iv_len() + 1) { // wait for more + server->frag++; return; } } else { @@ -719,6 +731,7 @@ server_recv_cb(EV_P_ ev_io *w, int revents) } else { if (ret == -1) server->stage = STAGE_ERROR; + server->frag++; server->buf->len = 0; server->buf->idx = 0; return; @@ -1397,6 +1410,7 @@ new_server(int fd, listen_ctx_t *listener) server->send_ctx->server = server; server->send_ctx->connected = 0; server->stage = STAGE_INIT; + server->frag = 0; server->query = NULL; server->listen_ctx = listener; server->remote = NULL; @@ -1492,7 +1506,10 @@ signal_cb(EV_P_ ev_signal *w, int revents) if (revents & EV_SIGNAL) { switch (w->signum) { case SIGCHLD: - LOGE("plugin service exit unexpectedly"); + if (!is_plugin_running()) + LOGE("plugin service exit unexpectedly"); + else + return; case SIGINT: case SIGTERM: ev_signal_stop(EV_DEFAULT, &sigint_watcher); @@ -1559,7 +1576,6 @@ main(int argc, char **argv) int i, c; int pid_flags = 0; int mptcp = 0; - int firewall = 0; int mtu = 0; char *user = NULL; char *password = NULL; @@ -1588,7 +1604,6 @@ main(int argc, char **argv) { "plugin", required_argument, 0, 0 }, #ifdef __linux__ { "mptcp", no_argument, 0, 0 }, - { "firewall", no_argument, 0, 0 }, #endif { 0, 0, 0, 0 } }; @@ -1619,9 +1634,6 @@ main(int argc, char **argv) } else if (option_index == 6) { mptcp = 1; LOGI("enable multipath TCP"); - } else if (option_index == 8) { - firewall = 1; - LOGI("enable firewall rules"); } break; case 's': @@ -1953,14 +1965,11 @@ main(int argc, char **argv) #ifndef __MINGW32__ if (geteuid() == 0) { LOGI("running from root user"); - } else if (firewall) { - LOGE("firewall setup requires running from root user"); - exit(-1); } #endif // init block list - init_block_list(firewall); + init_block_list(); // Init connections cork_dllist_init(&connections); diff --git a/src/server.h b/src/server.h index 84d12f4b..9a3b18b1 100644 --- a/src/server.h +++ b/src/server.h @@ -53,6 +53,7 @@ typedef struct server { int fd; int stage; int auth; + int frag; buffer_t *buf; buffer_t *header_buf; diff --git a/src/tunnel.c b/src/tunnel.c index 8c8c707d..0e87c807 100644 --- a/src/tunnel.c +++ b/src/tunnel.c @@ -723,7 +723,10 @@ signal_cb(EV_P_ ev_signal *w, int revents) if (revents & EV_SIGNAL) { switch (w->signum) { case SIGCHLD: - LOGE("plugin service exit unexpectedly"); + if (!is_plugin_running()) + LOGE("plugin service exit unexpectedly"); + else + return; case SIGINT: case SIGTERM: ev_signal_stop(EV_DEFAULT, &sigint_watcher); diff --git a/src/utils.c b/src/utils.c index c6ec27b8..6183cb54 100644 --- a/src/utils.c +++ b/src/utils.c @@ -356,10 +356,6 @@ usage() #ifdef __linux__ printf( " [--mptcp] Enable Multipath TCP on MPTCP Kernel.\n"); -#ifdef MODULE_REMOTE - printf( - " [--firewall] Setup firewall rules for auto blocking.\n"); -#endif #endif printf( " [--plugin ] Enable SIP003 plugin. (Experimental)\n");