mirror of
https://github.com/shadowsocks/shadowsocks-libev.git
synced 2026-10-29 04:03:45 +00:00
Dual mode IPv4/IPv6 stack support
Listen on all IP address (ipv4 and ipv6 dual mode) in single bind by default if not specify '-s' Create an IPv6 server socket that can also accept IPv4 connections. To do so, create a regular IPv6 socket, turn off the socket option IPV6_V6ONLY, bind it to the "any" address, and start receiving. IPv4 addresses will be presented as IPv6 addresses, in the IPv4-mapped format.
This commit is contained in:
+35
-4
@@ -147,12 +147,14 @@ int setinterface(int socket_fd, const char * interface_name)
|
||||
int create_and_bind(const char *host, const char *port)
|
||||
{
|
||||
struct addrinfo hints;
|
||||
struct addrinfo *result, *rp;
|
||||
struct addrinfo *result, *rp, *ipv4v6bindall;
|
||||
int s, listen_sock;
|
||||
|
||||
memset(&hints, 0, sizeof(struct addrinfo));
|
||||
hints.ai_family = AF_UNSPEC; /* Return IPv4 and IPv6 choices */
|
||||
hints.ai_socktype = SOCK_STREAM; /* We want a TCP socket */
|
||||
hints.ai_flags = AI_ALL|AI_V4MAPPED|AI_PASSIVE|AI_ADDRCONFIG; /* For wildcard IP address */
|
||||
hints.ai_protocol = IPPROTO_TCP;
|
||||
|
||||
s = getaddrinfo(host, port, &hints, &result);
|
||||
if (s != 0) {
|
||||
@@ -160,7 +162,29 @@ int create_and_bind(const char *host, const char *port)
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (rp = result; rp != NULL; rp = rp->ai_next) {
|
||||
rp = result;
|
||||
|
||||
/*
|
||||
On Linux, with net.ipv6.bindv6only = 0 (the default), getaddrinfo(NULL) with
|
||||
AI_PASSIVE returns 0.0.0.0 and :: (in this order). AI_PASSIVE was meant to
|
||||
return a list of addresses to listen on, but it is impossible to listen on
|
||||
0.0.0.0 and :: at the same time, if :: implies dualstack mode.
|
||||
*/
|
||||
if (!host) {
|
||||
ipv4v6bindall = result;
|
||||
|
||||
/* Loop over all address infos found until a IPV6 address is found. */
|
||||
while (ipv4v6bindall) {
|
||||
if (ipv4v6bindall->ai_family == AF_INET6) {
|
||||
rp = ipv4v6bindall; /* Take first IPV6 address available */
|
||||
break;
|
||||
}
|
||||
|
||||
ipv4v6bindall= ipv4v6bindall->ai_next; /* Get next address info, if any */
|
||||
}
|
||||
}
|
||||
|
||||
for (/*rp = result*/; rp != NULL; rp = rp->ai_next) {
|
||||
listen_sock = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
|
||||
if (listen_sock == -1) {
|
||||
continue;
|
||||
@@ -168,7 +192,11 @@ int create_and_bind(const char *host, const char *port)
|
||||
|
||||
int opt = 1;
|
||||
|
||||
setsockopt(listen_sock, IPPROTO_IPV6, IPV6_V6ONLY, &opt, sizeof(opt));
|
||||
if (rp->ai_family == AF_INET6) {
|
||||
int ipv6only = 0;
|
||||
if (host) ipv6only = 1;
|
||||
setsockopt(listen_sock, IPPROTO_IPV6, IPV6_V6ONLY, &ipv6only, sizeof(ipv6only));
|
||||
}
|
||||
|
||||
setsockopt(listen_sock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
|
||||
#ifdef SO_NOSIGPIPE
|
||||
@@ -1104,6 +1132,10 @@ int main(int argc, char **argv)
|
||||
}
|
||||
}
|
||||
|
||||
if (server_num == 0) {
|
||||
server_host[server_num++]=NULL;
|
||||
}
|
||||
|
||||
if (server_num == 0 || server_port == NULL || password == NULL) {
|
||||
usage();
|
||||
exit(EXIT_FAILURE);
|
||||
@@ -1244,4 +1276,3 @@ int main(int argc, char **argv)
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user