mirror of
https://github.com/shadowsocks/shadowsocks-libev.git
synced 2026-11-03 00:13:42 +00:00
Allow bind to local IPv4/v6 addresses. Fix #2372
This commit is contained in:
@@ -103,10 +103,10 @@ Not available in redir mode.
|
||||
-b <local_address>::
|
||||
Specify the local address to bind.
|
||||
+
|
||||
For servers: Specify the local address to use while this server is making
|
||||
For servers: Specify the local address to use while this server is making
|
||||
outbound connections to remote servers on behalf of the clients.
|
||||
+
|
||||
For clients: Specify the local address to use while this client is making
|
||||
For clients: Specify the local address to use while this client is making
|
||||
outbound connections to the server.
|
||||
+
|
||||
Not available in manager mode.
|
||||
@@ -178,6 +178,8 @@ The config file equivalent of command line options is listed as example below.
|
||||
| -s some.server.net -p 1234 (client) | "server": "some.server.net:1234"
|
||||
| -p 1234 | "server_port": "1234"
|
||||
| -b 0.0.0.0 | "local_address": "0.0.0.0"
|
||||
| -b 10.0.0.2 | "local_ipv4_address": "10.0.0.2"
|
||||
| -b 2620:129:35::33 | "local_ipv6_address": "2620:129:35::33"
|
||||
| -l 4321 | "local_port": "4321"
|
||||
| -k "PasSworD" | "password": "PasSworD"
|
||||
| -m "aes-256-cfb" | "method": "aes-256-cfb"
|
||||
|
||||
@@ -241,6 +241,10 @@ read_jconf(const char *file)
|
||||
conf.remote_port = to_string(value);
|
||||
} else if (strcmp(name, "local_address") == 0) {
|
||||
conf.local_addr = to_string(value);
|
||||
} else if (strcmp(name, "local_ipv4_address") == 0) {
|
||||
conf.local_addr_v4 = to_string(value);
|
||||
} else if (strcmp(name, "local_ipv6_address") == 0) {
|
||||
conf.local_addr_v6 = to_string(value);
|
||||
} else if (strcmp(name, "local_port") == 0) {
|
||||
conf.local_port = to_string(value);
|
||||
} else if (strcmp(name, "password") == 0) {
|
||||
|
||||
@@ -60,6 +60,8 @@ typedef struct {
|
||||
ss_port_password_t port_password[MAX_PORT_NUM];
|
||||
char *remote_port;
|
||||
char *local_addr;
|
||||
char *local_addr_v4;
|
||||
char *local_addr_v6;
|
||||
char *local_port;
|
||||
char *password;
|
||||
char *key;
|
||||
|
||||
+24
-11
@@ -86,32 +86,45 @@ setinterface(int socket_fd, const char *interface_name)
|
||||
#endif
|
||||
|
||||
int
|
||||
bind_to_address(int socket_fd, const char *host)
|
||||
parse_local_addr(struct sockaddr_storage *storage_v4,
|
||||
struct sockaddr_storage *storage_v6,
|
||||
const char *host)
|
||||
{
|
||||
static struct sockaddr_storage storage = { 0 };
|
||||
if (storage.ss_family == AF_INET) {
|
||||
return bind(socket_fd, (struct sockaddr *)&storage, sizeof(struct sockaddr_in));
|
||||
} else if (storage.ss_family == AF_INET6) {
|
||||
return bind(socket_fd, (struct sockaddr *)&storage, sizeof(struct sockaddr_in6));
|
||||
} else if (host != NULL) {
|
||||
if (host != NULL) {
|
||||
struct cork_ip ip;
|
||||
if (cork_ip_init(&ip, host) != -1) {
|
||||
if (ip.version == 4) {
|
||||
struct sockaddr_in *addr = (struct sockaddr_in *)&storage;
|
||||
memset(storage_v4, 0, sizeof(struct sockaddr_storage));
|
||||
struct sockaddr_in *addr = (struct sockaddr_in *)storage_v4;
|
||||
inet_pton(AF_INET, host, &addr->sin_addr);
|
||||
addr->sin_family = AF_INET;
|
||||
return bind(socket_fd, (struct sockaddr *)addr, sizeof(struct sockaddr_in));
|
||||
LOGI("binding to outbound IPv4 addr: %s", host);
|
||||
return 0;
|
||||
} else if (ip.version == 6) {
|
||||
struct sockaddr_in6 *addr = (struct sockaddr_in6 *)&storage;
|
||||
memset(storage_v6, 0, sizeof(struct sockaddr_storage));
|
||||
struct sockaddr_in6 *addr = (struct sockaddr_in6 *)storage_v6;
|
||||
inet_pton(AF_INET6, host, &addr->sin6_addr);
|
||||
addr->sin6_family = AF_INET6;
|
||||
return bind(socket_fd, (struct sockaddr *)addr, sizeof(struct sockaddr_in6));
|
||||
LOGI("binding to outbound IPv6 addr: %s", host);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int
|
||||
bind_to_addr(struct sockaddr_storage *storage,
|
||||
int socket_fd)
|
||||
{
|
||||
if (storage->ss_family == AF_INET) {
|
||||
return bind(socket_fd, (struct sockaddr *)storage, sizeof(struct sockaddr_in));
|
||||
} else if (storage->ss_family == AF_INET6) {
|
||||
return bind(socket_fd, (struct sockaddr *)storage, sizeof(struct sockaddr_in6));
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
ssize_t
|
||||
get_sockaddr(char *host, char *port,
|
||||
struct sockaddr_storage *storage, int block,
|
||||
|
||||
+5
-1
@@ -88,7 +88,11 @@ int set_reuseport(int socket);
|
||||
int setinterface(int socket_fd, const char *interface_name);
|
||||
#endif
|
||||
|
||||
int bind_to_address(int socket_fd, const char *address);
|
||||
int parse_local_addr(struct sockaddr_storage *storage_v4,
|
||||
struct sockaddr_storage *storage_v6,
|
||||
const char *host);
|
||||
|
||||
int bind_to_addr(struct sockaddr_storage *storage, int socket_fd);
|
||||
|
||||
/**
|
||||
* Compare two sockaddrs. Imposes an ordering on the addresses.
|
||||
|
||||
+20
-7
@@ -109,7 +109,10 @@ static void resolv_free_cb(void *data);
|
||||
|
||||
int verbose = 0;
|
||||
int reuse_port = 0;
|
||||
char *local_addr = NULL;
|
||||
|
||||
int is_bind_local_addr = 0;
|
||||
struct sockaddr_storage local_addr_v4;
|
||||
struct sockaddr_storage local_addr_v6;
|
||||
|
||||
static crypto_t *crypto;
|
||||
|
||||
@@ -496,12 +499,16 @@ connect_to_remote(EV_P_ struct addrinfo *res,
|
||||
if (setnonblocking(sockfd) == -1)
|
||||
ERROR("setnonblocking");
|
||||
|
||||
if (local_addr != NULL)
|
||||
if (bind_to_address(sockfd, local_addr) == -1) {
|
||||
ERROR("bind_to_address");
|
||||
if (is_bind_local_addr)
|
||||
{
|
||||
struct sockaddr_storage *local_addr =
|
||||
res->ai_family == AF_INET ? &local_addr_v4 : &local_addr_v6;
|
||||
if (bind_to_addr(local_addr, sockfd) == -1) {
|
||||
ERROR("bind_to_addr");
|
||||
close(sockfd);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef SET_INTERFACE
|
||||
if (iface) {
|
||||
@@ -1678,7 +1685,8 @@ main(int argc, char **argv)
|
||||
}
|
||||
break;
|
||||
case 'b':
|
||||
local_addr = optarg;
|
||||
if (parse_local_addr(&local_addr_v4, &local_addr_v6, optarg) == 0)
|
||||
is_bind_local_addr = 1;
|
||||
break;
|
||||
case 'p':
|
||||
server_port = optarg;
|
||||
@@ -1801,8 +1809,13 @@ main(int argc, char **argv)
|
||||
if (fast_open == 0) {
|
||||
fast_open = conf->fast_open;
|
||||
}
|
||||
if (local_addr == NULL) {
|
||||
local_addr = conf->local_addr;
|
||||
if (is_bind_local_addr == 0) {
|
||||
if (parse_local_addr(&local_addr_v4, &local_addr_v6, conf->local_addr) == 0)
|
||||
is_bind_local_addr = 1;
|
||||
if (parse_local_addr(&local_addr_v4, &local_addr_v6, conf->local_addr_v4) == 0)
|
||||
is_bind_local_addr = 1;
|
||||
if (parse_local_addr(&local_addr_v4, &local_addr_v6, conf->local_addr_v6) == 0)
|
||||
is_bind_local_addr = 1;
|
||||
}
|
||||
#ifdef HAVE_SETRLIMIT
|
||||
if (nofile == 0) {
|
||||
|
||||
+10
-7
@@ -98,7 +98,10 @@ extern int reuse_port;
|
||||
#ifdef MODULE_REMOTE
|
||||
extern uint64_t tx;
|
||||
extern uint64_t rx;
|
||||
extern char *local_addr;
|
||||
|
||||
extern int is_bind_local_addr;
|
||||
extern struct sockaddr_storage local_addr_v4;
|
||||
extern struct sockaddr_storage local_addr_v6;
|
||||
#endif
|
||||
|
||||
static int packet_size = DEFAULT_PACKET_SIZE;
|
||||
@@ -371,9 +374,9 @@ create_remote_socket(int ipv6)
|
||||
return -1;
|
||||
}
|
||||
#ifdef MODULE_REMOTE
|
||||
if (local_addr != NULL) {
|
||||
if (bind_to_address(remote_sock, local_addr) == -1) {
|
||||
ERROR("bind_to_address");
|
||||
if (is_bind_local_addr) {
|
||||
if (bind_to_addr(&local_addr_v6, remote_sock) == -1) {
|
||||
ERROR("bind_to_addr");
|
||||
FATAL("[udp] cannot bind remote");
|
||||
return -1;
|
||||
}
|
||||
@@ -399,9 +402,9 @@ create_remote_socket(int ipv6)
|
||||
return -1;
|
||||
}
|
||||
#ifdef MODULE_REMOTE
|
||||
if (local_addr != NULL) {
|
||||
if (bind_to_address(remote_sock, local_addr) == -1) {
|
||||
ERROR("bind_to_address");
|
||||
if (is_bind_local_addr) {
|
||||
if (bind_to_addr(&local_addr_v4, remote_sock) == -1) {
|
||||
ERROR("bind_to_addr");
|
||||
FATAL("[udp] cannot bind remote");
|
||||
return -1;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user