From cfae8dcfccf6cb0c1ea6b55905513e91a0586fb1 Mon Sep 17 00:00:00 2001 From: Max Lv Date: Sat, 29 Oct 2016 08:11:53 +0800 Subject: [PATCH] Refine outbound feature #905 --- acl/server_block_chn.acl | 2 +- src/acl.c | 82 ++++++++++------------------------------ src/acl.h | 3 +- src/netutils.c | 44 +++++++++++++++++++++ src/netutils.h | 12 +++--- src/server.c | 77 ++++++++++--------------------------- 6 files changed, 89 insertions(+), 131 deletions(-) diff --git a/acl/server_block_chn.acl b/acl/server_block_chn.acl index 604519ef..aa1102af 100644 --- a/acl/server_block_chn.acl +++ b/acl/server_block_chn.acl @@ -3,7 +3,7 @@ # # The IPs bellow are all IPs in CHN. It'll block ss-server to access all # CHN hosts by command -# `ss-server -s:: -p 8388 -k123456 --outbound-block acl/server_block_chn.acl` +# `ss-server -s:: -p 8388 -k 123456 --acl acl/server_block_chn.acl` [outbound_block_list] 103.235.44.0/22 diff --git a/src/acl.c b/src/acl.c index 66cea2be..0fc81b51 100644 --- a/src/acl.c +++ b/src/acl.c @@ -43,6 +43,7 @@ static struct cache *block_list; static struct ip_set outbound_block_list_ipv4; static struct ip_set outbound_block_list_ipv6; +static struct cork_dllist outbound_block_list_rules; void init_block_list() @@ -142,9 +143,12 @@ init_acl(const char *path) ipset_init(&white_list_ipv6); ipset_init(&black_list_ipv4); ipset_init(&black_list_ipv6); + ipset_init(&outbound_block_list_ipv4); + ipset_init(&outbound_block_list_ipv6); cork_dllist_init(&black_list_rules); cork_dllist_init(&white_list_rules); + cork_dllist_init(&outbound_block_list_rules); struct ip_set *list_ipv4 = &black_list_ipv4; struct ip_set *list_ipv6 = &black_list_ipv6; @@ -176,8 +180,13 @@ init_acl(const char *path) continue; } - if (strcmp(line, "[black_list]") == 0 - || strcmp(line, "[bypass_list]") == 0) { + if (strcmp(line, "[outbound_block_list]") == 0) { + list_ipv4 = &outbound_block_list_ipv4; + list_ipv6 = &outbound_block_list_ipv6; + rules = &outbound_block_list_rules; + continue; + } else if (strcmp(line, "[black_list]") == 0 + || strcmp(line, "[bypass_list]") == 0) { list_ipv4 = &black_list_ipv4; list_ipv6 = &black_list_ipv6; rules = &black_list_rules; @@ -331,76 +340,23 @@ acl_remove_ip(const char *ip) return 0; } -int -init_outbound_block(const char *path) -{ - // initialize ipset - ipset_init_library(); - - ipset_init(&outbound_block_list_ipv4); - ipset_init(&outbound_block_list_ipv6); - - FILE *f = fopen(path, "r"); - if (f == NULL) { - LOGE("Invalid outbound block list path."); - return -1; - } - - char buf[257]; - while (!feof(f)) - if (fgets(buf, 256, f)) { - // Trim the newline - int len = strlen(buf); - if (len > 0 && buf[len - 1] == '\n') { - buf[len - 1] = '\0'; - } - - char *line = trimwhitespace(buf); - - if (line[0] == '#') continue; // Skip comment line - if (strlen(line) == 0) continue; // Skip empty line - if (strcmp(line, "[outbound_block_list]") == 0) continue; // Skip section line - - char host[257]; - int cidr; - parse_addr_cidr(line, host, &cidr); - - struct cork_ip addr; - int err = cork_ip_init(&addr, host); - if (!err) { - if (addr.version == 4) { - if (cidr >= 0) { - ipset_ipv4_add_network(&outbound_block_list_ipv4, &(addr.ip.v4), cidr); - } else { - ipset_ipv4_add(&outbound_block_list_ipv4, &(addr.ip.v4)); - } - } else if (addr.version == 6) { - if (cidr >= 0) { - ipset_ipv6_add_network(&outbound_block_list_ipv6, &(addr.ip.v6), cidr); - } else { - ipset_ipv6_add(&outbound_block_list_ipv6, &(addr.ip.v6)); - } - } - } - } - - fclose(f); - - return 0; -} - /* * Return 0, if not match. * Return 1, if match black list. */ int -outbound_block_match_host(const char *ipstr) +outbound_block_match_host(const char *host) { struct cork_ip addr; int ret = 0; - int err = cork_ip_init(&addr, ipstr); + int err = cork_ip_init(&addr, host); - if (err) return 0; + if (err) { + int host_len = strlen(host); + if (lookup_rule(&outbound_block_list_rules, host, host_len) != NULL) + ret = 1; + return ret; + } if (addr.version == 4) { if (ipset_contains_ipv4(&outbound_block_list_ipv4, &(addr.ip.v4))) diff --git a/src/acl.h b/src/acl.h index b91b90ee..015c1cec 100644 --- a/src/acl.h +++ b/src/acl.h @@ -43,10 +43,9 @@ int acl_remove_ip(const char *ip); int get_acl_mode(void); void init_block_list(); -int check_block_list(char* addr, int err_level); +int check_block_list(char *addr, int err_level); int remove_from_block_list(char *addr); -int init_outbound_block(const char *path); int outbound_block_match_host(const char *host); #endif // _ACL_H diff --git a/src/netutils.c b/src/netutils.c index 72634da6..dd69f50d 100644 --- a/src/netutils.c +++ b/src/netutils.c @@ -299,3 +299,47 @@ validate_hostname(const char *hostname, const int hostname_len) return 1; } + +void +print_addrinfo(struct addrinfo *ai) +{ + char ipstr[INET6_ADDRSTRLEN]; + unsigned short int port = 0; + bzero(ipstr, INET6_ADDRSTRLEN); + + printf("addrinfo=>{"); + printf("ai_flags="); + switch (ai->ai_flags) { + case AI_PASSIVE: printf("AI_PASSIVE"); break; + case AI_CANONNAME: printf("AI_CANONNAME"); break; + default: printf("ERROR(%d)", ai->ai_flags); + } + printf(", ai_family="); + switch (ai->ai_family) { + case AF_INET: + dns_ntop(AF_INET, &(((struct sockaddr_in *)ai->ai_addr)->sin_addr), ipstr, INET_ADDRSTRLEN); + port = htons(((struct sockaddr_in *)ai->ai_addr)->sin_port); + printf("AF_INET"); + break; + case AF_INET6: + dns_ntop(AF_INET6, &(((struct sockaddr_in6 *)ai->ai_addr)->sin6_addr), ipstr, INET6_ADDRSTRLEN); + port = htons(((struct sockaddr_in6 *)ai->ai_addr)->sin6_port); + printf("AF_INET6"); + break; + case AF_UNSPEC: printf("AF_UNSPEC"); break; + default: printf("ERROR(%d)", ai->ai_family); + } + printf(", ai_socktype="); + switch (ai->ai_socktype) { + case SOCK_STREAM: printf("SOCK_STREAM"); break; + case SOCK_DGRAM: printf("SOCK_SGRAM"); break; + default: printf("ERROR(%d)", ai->ai_socktype); + } + printf(", ai_protocol=%d", ai->ai_protocol); + printf(", ai_addrlen=%d", ai->ai_addrlen); + printf(", ai_addr=%s:%d", ipstr, port); + printf(", ai_canonname=%s", ai->ai_canonname); + printf(", ai_next=%p", ai->ai_next); + printf("}\n"); +} + diff --git a/src/netutils.h b/src/netutils.h index d80bf265..6d11f519 100644 --- a/src/netutils.h +++ b/src/netutils.h @@ -24,32 +24,28 @@ #define _NETUTILS_H #if defined(__linux__) -#include +#include #elif !defined(__MINGW32__) #include +#else +#include "win32.h" #endif // only enable TCP_FASTOPEN on linux #if defined(__linux__) - #include - /* conditional define for TCP_FASTOPEN */ #ifndef TCP_FASTOPEN #define TCP_FASTOPEN 23 #endif - /* conditional define for MSG_FASTOPEN */ #ifndef MSG_FASTOPEN #define MSG_FASTOPEN 0x20000000 #endif - #elif !defined(__APPLE__) - #ifdef TCP_FASTOPEN #undef TCP_FASTOPEN #endif - #endif /* Backward compatibility for MPTCP_ENABLED between kernel 3 & 4 */ @@ -99,4 +95,6 @@ int sockaddr_cmp_addr(struct sockaddr_storage *addr1, int validate_hostname(const char *hostname, const int hostname_len); +void print_addrinfo(struct addrinfo *ai); + #endif diff --git a/src/server.c b/src/server.c index 1c78dba3..1b254d96 100644 --- a/src/server.c +++ b/src/server.c @@ -40,7 +40,6 @@ #include #include #include -#include #include #include #include @@ -115,8 +114,6 @@ static int mode = TCP_ONLY; static int auth = 0; static int ipv6first = 0; -static int outbound_block = 0; - static int fast_open = 0; #ifdef HAVE_SETRLIMIT static int nofile = 0; @@ -465,49 +462,6 @@ create_and_bind(const char *host, const char *port, int mptcp) return listen_sock; } -void print_addrinfo(struct addrinfo *ai) -{ - // TODO: move this function to somewhere like 'debug.c' - char ipstr[INET6_ADDRSTRLEN]; - unsigned short int port = 0; - bzero(ipstr, INET6_ADDRSTRLEN); - - printf("addrinfo=>{"); - printf("ai_flags="); - switch (ai->ai_flags) { - case AI_PASSIVE: printf("AI_PASSIVE"); break; - case AI_CANONNAME: printf("AI_CANONNAME"); break; - default: printf("ERROR(%d)", ai->ai_flags); - } - printf(", ai_family="); - switch (ai->ai_family) { - case AF_INET: - inet_ntop(AF_INET, &(((struct sockaddr_in *)ai->ai_addr)->sin_addr), ipstr, INET_ADDRSTRLEN); - port = htons(((struct sockaddr_in *)ai->ai_addr)->sin_port); - printf("AF_INET"); - break; - case AF_INET6: - inet_ntop(AF_INET6, &(((struct sockaddr_in6 *)ai->ai_addr)->sin6_addr), ipstr, INET6_ADDRSTRLEN); - port = htons(((struct sockaddr_in6 *)ai->ai_addr)->sin6_port); - printf("AF_INET6"); - break; - case AF_UNSPEC: printf("AF_UNSPEC"); break; - default: printf("ERROR(%d)", ai->ai_family); - } - printf(", ai_socktype="); - switch (ai->ai_socktype) { - case SOCK_STREAM: printf("SOCK_STREAM"); break; - case SOCK_DGRAM: printf("SOCK_SGRAM"); break; - default: printf("ERROR(%d)", ai->ai_socktype); - } - printf(", ai_protocol=%d", ai->ai_protocol); - printf(", ai_addrlen=%d", ai->ai_addrlen); - printf(", ai_addr=%s:%d", ipstr, port); - printf(", ai_canonname=%s", ai->ai_canonname); - printf(", ai_next=%p", ai->ai_next); - printf("}\n"); -} - static remote_t * connect_to_remote(struct addrinfo *res, server_t *server) @@ -517,13 +471,21 @@ connect_to_remote(struct addrinfo *res, const char *iface = server->listen_ctx->iface; #endif - if (outbound_block) { + if (acl) { char ipstr[INET6_ADDRSTRLEN]; bzero(ipstr, INET6_ADDRSTRLEN); - inet_ntop(AF_INET, &(((struct sockaddr_in *)res->ai_addr)->sin_addr), ipstr, INET_ADDRSTRLEN); + if (res->ai_addr->sa_family == AF_INET) { + struct sockaddr_in *s = (struct sockaddr_in *)res->ai_addr; + dns_ntop(AF_INET, &s->sin_addr, ipstr, INET_ADDRSTRLEN); + } else if (res->ai_addr->sa_family == AF_INET6) { + struct sockaddr_in6 *s = (struct sockaddr_in6 *)res->ai_addr; + dns_ntop(AF_INET6, &s->sin6_addr, ipstr, INET6_ADDRSTRLEN); + } + if (outbound_block_match_host(ipstr) == 1) { - LOGI("outbound blocked %s", ipstr); + if (verbose) + LOGI("outbound blocked %s", ipstr); return NULL; } } @@ -670,7 +632,6 @@ server_recv_cb(EV_P_ ev_io *w, int revents) // wait for more return; } - } else { buf->len = r; } @@ -841,6 +802,12 @@ server_recv_cb(EV_P_ ev_io *w, int revents) close_and_free_server(EV_A_ server); return; } + if (outbound_block_match_host(host) == 1) { + if (verbose) + LOGI("outbound blocked %s", host); + close_and_free_server(EV_A_ server); + return; + } struct cork_ip ip; if (cork_ip_init(&ip, host) != -1) { info.ai_socktype = SOCK_STREAM; @@ -1109,8 +1076,6 @@ server_resolve_cb(struct sockaddr *addr, void *data) remote_t *remote = connect_to_remote(&info, server); if (remote == NULL) { - if (!outbound_block) - LOGE("connect error"); close_and_free_server(EV_A_ server); } else { server->remote = remote; @@ -1392,7 +1357,7 @@ new_server(int fd, listen_ctx_t *listener) } int request_timeout = min(MAX_REQUEST_TIMEOUT, listener->timeout) - + rand() % MAX_REQUEST_TIMEOUT; + + rand() % MAX_REQUEST_TIMEOUT; ev_io_init(&server->recv_ctx->io, server_recv_cb, fd, EV_READ); ev_io_init(&server->send_ctx->io, server_send_cb, fd, EV_WRITE); @@ -1496,7 +1461,7 @@ accept_cb(EV_P_ ev_io *w, int revents) int in_white_list = 0; if (acl) { if ((get_acl_mode() == BLACK_LIST && acl_match_host(peer_name) == 1) - || (get_acl_mode() == WHITE_LIST && acl_match_host(peer_name) >= 0)) { + || (get_acl_mode() == WHITE_LIST && acl_match_host(peer_name) >= 0)) { LOGE("Access denied from %s", peer_name); close(serverfd); return; @@ -1556,7 +1521,6 @@ main(int argc, char **argv) { "mtu", required_argument, 0, 0 }, { "mptcp", no_argument, 0, 0 }, { "help", no_argument, 0, 0 }, - { "outbound-block", required_argument, 0, 0 }, { 0, 0, 0, 0 } }; @@ -1584,9 +1548,6 @@ main(int argc, char **argv) } else if (option_index == 5) { usage(); exit(EXIT_SUCCESS); - } else if (option_index == 6) { - LOGI("initializing outbound block..."); - outbound_block = !init_outbound_block(optarg); } break; case 's':