mirror of
https://github.com/shadowsocks/shadowsocks-libev.git
synced 2026-10-30 05:11:14 +00:00
add ip addr support
This commit is contained in:
+121
-24
@@ -47,6 +47,7 @@
|
||||
#include <pthread.h>
|
||||
#include <sys/un.h>
|
||||
#include <sys/socket.h>
|
||||
#include <pwd.h>
|
||||
#endif
|
||||
|
||||
#include <libcork/core.h>
|
||||
@@ -71,6 +72,7 @@
|
||||
|
||||
int verbose = 0;
|
||||
char *executable = "ss-server";
|
||||
char working_dir[128];
|
||||
|
||||
static struct cork_hash_table *server_table;
|
||||
|
||||
@@ -91,9 +93,9 @@ static char *construct_command_line(struct manager_ctx *manager, struct server *
|
||||
|
||||
memset(cmd, 0, BUF_SIZE);
|
||||
snprintf(cmd, BUF_SIZE,
|
||||
"%s -p %s -m %s -k %s --manager-address %s -f %s_%s.pid", executable,
|
||||
"%s -p %s -m %s -k %s --manager-address %s -f %s/.shadowsocks_%s.pid", executable,
|
||||
server->port, manager->method, server->password, manager->manager_address,
|
||||
manager->manager_address, server->port);
|
||||
working_dir, server->port);
|
||||
if (manager->acl != NULL) {
|
||||
int len = strlen(cmd);
|
||||
snprintf(cmd + len, BUF_SIZE - len, " --acl %s", manager->acl);
|
||||
@@ -261,7 +263,7 @@ static void stop_server(char *prefix, char *port)
|
||||
{
|
||||
char path[128];
|
||||
int pid;
|
||||
snprintf(path, 128, "%s_%s.pid", prefix, port);
|
||||
snprintf(path, 128, "%s/.shadowsocks_%s.pid", prefix, port);
|
||||
FILE *f = fopen(path, "r");
|
||||
if (f == NULL) {
|
||||
if (verbose) {
|
||||
@@ -334,7 +336,7 @@ static void manager_recv_cb(EV_P_ ev_io *w, int revents)
|
||||
goto ERROR_MSG;
|
||||
}
|
||||
|
||||
remove_server(manager->manager_address, server->port);
|
||||
remove_server(working_dir, server->port);
|
||||
add_server(manager, server);
|
||||
|
||||
char msg[3] = "ok";
|
||||
@@ -353,7 +355,7 @@ static void manager_recv_cb(EV_P_ ev_io *w, int revents)
|
||||
goto ERROR_MSG;
|
||||
}
|
||||
|
||||
remove_server(manager->manager_address, server->port);
|
||||
remove_server(working_dir, server->port);
|
||||
free(server);
|
||||
|
||||
char msg[3] = "ok";
|
||||
@@ -432,6 +434,84 @@ static void signal_cb(EV_P_ ev_signal *w, int revents)
|
||||
}
|
||||
}
|
||||
|
||||
int create_server_socket(const char *host, const char *port)
|
||||
{
|
||||
struct addrinfo hints;
|
||||
struct addrinfo *result, *rp, *ipv4v6bindall;
|
||||
int s, server_sock;
|
||||
|
||||
memset(&hints, 0, sizeof(struct addrinfo));
|
||||
hints.ai_family = AF_UNSPEC; /* Return IPv4 and IPv6 choices */
|
||||
hints.ai_socktype = SOCK_DGRAM; /* We want a UDP socket */
|
||||
hints.ai_flags = AI_PASSIVE | AI_ADDRCONFIG; /* For wildcard IP address */
|
||||
hints.ai_protocol = IPPROTO_UDP;
|
||||
|
||||
s = getaddrinfo(host, port, &hints, &result);
|
||||
if (s != 0) {
|
||||
LOGE("getaddrinfo: %s", gai_strerror(s));
|
||||
return -1;
|
||||
}
|
||||
|
||||
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) {
|
||||
server_sock = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
|
||||
if (server_sock == -1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (rp->ai_family == AF_INET6) {
|
||||
int ipv6only = host ? 1 : 0;
|
||||
setsockopt(server_sock, IPPROTO_IPV6, IPV6_V6ONLY, &ipv6only, sizeof(ipv6only));
|
||||
}
|
||||
|
||||
int opt = 1;
|
||||
setsockopt(server_sock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
|
||||
#ifdef SO_NOSIGPIPE
|
||||
set_nosigpipe(server_sock);
|
||||
#endif
|
||||
|
||||
s = bind(server_sock, rp->ai_addr, rp->ai_addrlen);
|
||||
if (s == 0) {
|
||||
/* We managed to bind successfully! */
|
||||
break;
|
||||
} else {
|
||||
ERROR("bind");
|
||||
}
|
||||
|
||||
close(server_sock);
|
||||
}
|
||||
|
||||
if (rp == NULL) {
|
||||
LOGE("cannot bind");
|
||||
return -1;
|
||||
}
|
||||
|
||||
freeaddrinfo(result);
|
||||
|
||||
return server_sock;
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
|
||||
@@ -634,6 +714,16 @@ int main(int argc, char **argv)
|
||||
run_as(user);
|
||||
}
|
||||
|
||||
struct passwd *pw = getpwuid(getuid());
|
||||
const char *homedir = pw->pw_dir;
|
||||
snprintf(working_dir, 128, "%s/.shadowsocks", homedir);
|
||||
|
||||
int err = mkdir(working_dir, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
|
||||
if (err != 0 && errno != EEXIST) {
|
||||
ERROR("mkdir");
|
||||
FATAL("unable to create working directory");
|
||||
}
|
||||
|
||||
server_table = cork_string_hash_table_new(MAX_PORT_NUM, 0);
|
||||
|
||||
if (conf != NULL) {
|
||||
@@ -645,30 +735,37 @@ int main(int argc, char **argv)
|
||||
}
|
||||
}
|
||||
|
||||
struct sockaddr_un svaddr;
|
||||
int sfd;
|
||||
ss_addr_t ip_addr = { .host = NULL, .port = NULL };
|
||||
parse_addr(manager_address, &ip_addr);
|
||||
|
||||
sfd = socket(AF_UNIX, SOCK_DGRAM, 0); /* Create server socket */
|
||||
if (sfd == -1) {
|
||||
FATAL("socket");
|
||||
}
|
||||
if (ip_addr.host == NULL || ip_addr.port == NULL) {
|
||||
struct sockaddr_un svaddr;
|
||||
sfd = socket(AF_UNIX, SOCK_DGRAM, 0); /* Create server socket */
|
||||
if (sfd == -1) {
|
||||
FATAL("socket");
|
||||
}
|
||||
|
||||
setnonblocking(sfd);
|
||||
setnonblocking(sfd);
|
||||
|
||||
/* Construct well-known address and bind server socket to it */
|
||||
if (remove(manager_address) == -1 && errno != ENOENT) {
|
||||
ERROR("bind");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (remove(manager_address) == -1 && errno != ENOENT) {
|
||||
ERROR("bind");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
memset(&svaddr, 0, sizeof(struct sockaddr_un));
|
||||
svaddr.sun_family = AF_UNIX;
|
||||
strncpy(svaddr.sun_path, manager_address, sizeof(svaddr.sun_path) - 1);
|
||||
|
||||
memset(&svaddr, 0, sizeof(struct sockaddr_un));
|
||||
svaddr.sun_family = AF_UNIX;
|
||||
strncpy(svaddr.sun_path, manager_address, sizeof(svaddr.sun_path) - 1);
|
||||
|
||||
if (bind(sfd, (struct sockaddr *) &svaddr, sizeof(struct sockaddr_un)) == -1) {
|
||||
ERROR("bind");
|
||||
exit(EXIT_FAILURE);
|
||||
if (bind(sfd, (struct sockaddr *) &svaddr, sizeof(struct sockaddr_un)) == -1) {
|
||||
ERROR("bind");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
} else {
|
||||
sfd = create_server_socket(ip_addr.host, ip_addr.port);
|
||||
if (sfd == -1) {
|
||||
FATAL("socket");
|
||||
}
|
||||
}
|
||||
|
||||
manager.fd = sfd;
|
||||
@@ -690,7 +787,7 @@ int main(int argc, char **argv)
|
||||
|
||||
while((entry = cork_hash_table_iterator_next(&server_iter)) != NULL) {
|
||||
struct server *server = (struct server*)entry->value;
|
||||
stop_server(manager_address, server->port);
|
||||
stop_server(working_dir, server->port);
|
||||
}
|
||||
|
||||
#ifdef __MINGW32__
|
||||
|
||||
+60
-28
@@ -60,6 +60,7 @@
|
||||
#define SET_INTERFACE
|
||||
#endif
|
||||
|
||||
#include "netutils.h"
|
||||
#include "utils.h"
|
||||
#include "acl.h"
|
||||
#include "server.h"
|
||||
@@ -127,7 +128,7 @@ static struct cork_dllist connections;
|
||||
static void stat_update_cb(EV_P_ ev_timer *watcher, int revents)
|
||||
{
|
||||
struct sockaddr_un svaddr, claddr;
|
||||
int sfd;
|
||||
int sfd = -1;
|
||||
size_t msgLen;
|
||||
char resp[BUF_SIZE];
|
||||
|
||||
@@ -135,38 +136,69 @@ static void stat_update_cb(EV_P_ ev_timer *watcher, int revents)
|
||||
LOGI("update traffic stat: tx: %"PRIu64" rx: %"PRIu64"", tx, rx);
|
||||
}
|
||||
|
||||
sfd = socket(AF_UNIX, SOCK_DGRAM, 0);
|
||||
if (sfd == -1) {
|
||||
ERROR("stat_socket");
|
||||
return;
|
||||
}
|
||||
|
||||
memset(&claddr, 0, sizeof(struct sockaddr_un));
|
||||
claddr.sun_family = AF_UNIX;
|
||||
snprintf(claddr.sun_path, sizeof(claddr.sun_path), "/tmp/shadowsocks.%s", server_port);
|
||||
|
||||
unlink(claddr.sun_path);
|
||||
|
||||
if (bind(sfd, (struct sockaddr *) &claddr, sizeof(struct sockaddr_un)) == -1) {
|
||||
ERROR("stat_bind");
|
||||
close(sfd);
|
||||
return;
|
||||
}
|
||||
|
||||
memset(&svaddr, 0, sizeof(struct sockaddr_un));
|
||||
svaddr.sun_family = AF_UNIX;
|
||||
strncpy(svaddr.sun_path, manager_address, sizeof(svaddr.sun_path) - 1);
|
||||
|
||||
snprintf(resp, BUF_SIZE, "stat: {\"%s\":%"PRIu64"}", server_port, tx + rx);
|
||||
msgLen = strlen(resp) + 1;
|
||||
if (sendto(sfd, resp, strlen(resp) + 1, 0, (struct sockaddr *) &svaddr,
|
||||
sizeof(struct sockaddr_un)) != msgLen) {
|
||||
ERROR("stat_sendto");
|
||||
return;
|
||||
|
||||
ss_addr_t ip_addr = { .host = NULL, .port = NULL };
|
||||
parse_addr(manager_address, &ip_addr);
|
||||
|
||||
if (ip_addr.host == NULL || ip_addr.port == NULL) {
|
||||
sfd = socket(AF_UNIX, SOCK_DGRAM, 0);
|
||||
if (sfd == -1) {
|
||||
ERROR("stat_socket");
|
||||
return;
|
||||
}
|
||||
|
||||
memset(&claddr, 0, sizeof(struct sockaddr_un));
|
||||
claddr.sun_family = AF_UNIX;
|
||||
snprintf(claddr.sun_path, sizeof(claddr.sun_path), "/tmp/shadowsocks.%s", server_port);
|
||||
|
||||
unlink(claddr.sun_path);
|
||||
|
||||
if (bind(sfd, (struct sockaddr *) &claddr, sizeof(struct sockaddr_un)) == -1) {
|
||||
ERROR("stat_bind");
|
||||
close(sfd);
|
||||
return;
|
||||
}
|
||||
|
||||
memset(&svaddr, 0, sizeof(struct sockaddr_un));
|
||||
svaddr.sun_family = AF_UNIX;
|
||||
strncpy(svaddr.sun_path, manager_address, sizeof(svaddr.sun_path) - 1);
|
||||
|
||||
if (sendto(sfd, resp, strlen(resp) + 1, 0, (struct sockaddr *) &svaddr,
|
||||
sizeof(struct sockaddr_un)) != msgLen) {
|
||||
ERROR("stat_sendto");
|
||||
close(sfd);
|
||||
return;
|
||||
}
|
||||
|
||||
unlink(claddr.sun_path);
|
||||
|
||||
} else {
|
||||
struct sockaddr_storage storage;
|
||||
memset(&storage, 0, sizeof(struct sockaddr_storage));
|
||||
if (get_sockaddr(ip_addr.host, ip_addr.port, &storage, 0) == -1) {
|
||||
ERROR("failed to parse the manager addr");
|
||||
return;
|
||||
}
|
||||
|
||||
sfd = socket(storage.ss_family, SOCK_DGRAM, 0);
|
||||
|
||||
if (sfd == -1) {
|
||||
ERROR("stat_socket");
|
||||
return;
|
||||
}
|
||||
|
||||
size_t addr_len = get_sockaddr_len((struct sockaddr *)&storage);
|
||||
if (sendto(sfd, resp, strlen(resp) + 1, 0, (struct sockaddr *)&storage,
|
||||
addr_len) != msgLen) {
|
||||
ERROR("stat_sendto");
|
||||
close(sfd);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
close(sfd);
|
||||
unlink(claddr.sun_path);
|
||||
}
|
||||
|
||||
static void free_connections(struct ev_loop *loop)
|
||||
|
||||
Reference in New Issue
Block a user