mirror of
https://github.com/shadowsocks/shadowsocks-libev.git
synced 2026-10-22 06:53:46 +00:00
Refine outbound feature #905
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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)))
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
|
||||
|
||||
+5
-7
@@ -24,32 +24,28 @@
|
||||
#define _NETUTILS_H
|
||||
|
||||
#if defined(__linux__)
|
||||
#include <linux/tcp.h>
|
||||
#include <netdb.h>
|
||||
#elif !defined(__MINGW32__)
|
||||
#include <netinet/tcp.h>
|
||||
#else
|
||||
#include "win32.h"
|
||||
#endif
|
||||
|
||||
// only enable TCP_FASTOPEN on linux
|
||||
#if defined(__linux__)
|
||||
|
||||
#include <linux/tcp.h>
|
||||
|
||||
/* 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
|
||||
|
||||
+19
-58
@@ -40,7 +40,6 @@
|
||||
#include <netdb.h>
|
||||
#include <errno.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netdb.h>
|
||||
#include <netinet/in.h>
|
||||
#include <pthread.h>
|
||||
#include <sys/un.h>
|
||||
@@ -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':
|
||||
|
||||
Reference in New Issue
Block a user