Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,10 @@ rpm/BUILDROOT/
*.rpm
*.deb

# Ignore files for clangd language server
.cache/
compile_commands.json

# Ignore per-project vim config
.vimrc

Expand Down
1 change: 1 addition & 0 deletions doc/shadowsocks-libev.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,7 @@ The config file equivalent of command line options is listed as example below.
| --no-delay | "no_delay": true
| --plugin "obfs-server" | "plugin": "obfs-server"
| --plugin-opts "obfs=http" | "plugin_opts": "obfs=http"
| --plugin-mode "tcp_only" | "plugin_mode": "tcp_only"
| -6 | "ipv6_first": true
| -n "/etc/nofile" | "nofile": "/etc/nofile"
| -d "8.8.8.8" | "nameserver": "8.8.8.8"
Expand Down
1 change: 1 addition & 0 deletions src/common.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ enum {
GETOPT_VAL_MPTCP,
GETOPT_VAL_PLUGIN,
GETOPT_VAL_PLUGIN_OPTS,
GETOPT_VAL_PLUGIN_MODE,
GETOPT_VAL_PASSWORD,
GETOPT_VAL_KEY,
GETOPT_VAL_MANAGER_ADDRESS,
Expand Down
21 changes: 21 additions & 0 deletions src/jconf.c
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,11 @@ read_jconf(const char *file)
}
} else if (strcmp(name, "plugin_opts") == 0) {
conf.plugin_opts = to_string(value);
} else if (strcmp(name, "plugin_mode") == 0) {
/* plugin_mode: "tcp_only", "udp_only" or "tcp_and_udp" */
char *mode_str = to_string(value);
conf.plugin_mode = parse_plugin_mode(mode_str);
ss_free(mode_str);
} else if (strcmp(name, "fast_open") == 0) {
check_json_value_type(value, json_boolean,
"invalid config file: option 'fast_open' must be a boolean");
Expand Down Expand Up @@ -377,3 +382,19 @@ read_jconf(const char *file)
json_value_free(obj);
return &conf;
}

int
parse_plugin_mode(const char *mode_str)
{
if (mode_str == NULL)
return TCP_ONLY;
if (strcmp(mode_str, "tcp_only") == 0)
return TCP_ONLY;
if (strcmp(mode_str, "udp_only") == 0)
return UDP_ONLY;
if (strcmp(mode_str, "tcp_and_udp") == 0)
return TCP_AND_UDP;
/* default */
LOGI("ignore unknown plugin_mode: %s, use tcp_only as fallback", mode_str);
return TCP_ONLY;
}
2 changes: 2 additions & 0 deletions src/jconf.h
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ typedef struct {
char *user;
char *plugin;
char *plugin_opts;
int plugin_mode;
int fast_open;
int reuse_port;
int tcp_incoming_sndbuf;
Expand All @@ -95,5 +96,6 @@ typedef struct {
jconf_t *read_jconf(const char *file);
void parse_addr(const char *str, ss_addr_t *addr);
void free_addr(ss_addr_t *addr);
int parse_plugin_mode(const char *mode_str);

#endif // _JCONF_H
27 changes: 24 additions & 3 deletions src/local.c
Original file line number Diff line number Diff line change
Expand Up @@ -1441,6 +1441,7 @@ main(int argc, char **argv)

char *plugin = NULL;
char *plugin_opts = NULL;
int plugin_mode = TCP_ONLY;
char *plugin_host = NULL;
char *plugin_port = NULL;
char tmp_port[8];
Expand All @@ -1465,6 +1466,7 @@ main(int argc, char **argv)
{ "mptcp", no_argument, NULL, GETOPT_VAL_MPTCP },
{ "plugin", required_argument, NULL, GETOPT_VAL_PLUGIN },
{ "plugin-opts", required_argument, NULL, GETOPT_VAL_PLUGIN_OPTS },
{ "plugin-mode", required_argument, NULL, GETOPT_VAL_PLUGIN_MODE },
{ "password", required_argument, NULL, GETOPT_VAL_PASSWORD },
{ "key", required_argument, NULL, GETOPT_VAL_KEY },
{ "help", no_argument, NULL, GETOPT_VAL_HELP },
Expand Down Expand Up @@ -1509,6 +1511,9 @@ main(int argc, char **argv)
case GETOPT_VAL_PLUGIN_OPTS:
plugin_opts = optarg;
break;
case GETOPT_VAL_PLUGIN_MODE:
plugin_mode = parse_plugin_mode(optarg);
break;
case GETOPT_VAL_KEY:
key = optarg;
break;
Expand Down Expand Up @@ -1651,6 +1656,9 @@ main(int argc, char **argv)
if (plugin_opts == NULL) {
plugin_opts = conf->plugin_opts;
}
if (plugin_mode == TCP_ONLY) {
plugin_mode = conf->plugin_mode;
}
if (reuse_port == 0) {
reuse_port = conf->reuse_port;
}
Expand Down Expand Up @@ -1751,7 +1759,11 @@ main(int argc, char **argv)
}

if (plugin != NULL) {
uint16_t port = get_local_port();
if (plugin_mode == UDP_ONLY && mode == TCP_AND_UDP) {
FATAL("plugin_mode cannot be 'udp_only' when both TCP and UDP relay are enabled");
}
int with_udp = mode != TCP_ONLY && plugin_mode != TCP_ONLY;
uint16_t port = get_local_port(with_udp);
if (port == 0) {
FATAL("failed to find a free port");
}
Expand All @@ -1765,7 +1777,7 @@ main(int argc, char **argv)

#ifdef __MINGW32__
memset(&plugin_watcher, 0, sizeof(plugin_watcher));
plugin_watcher.port = get_local_port();
plugin_watcher.port = get_local_port(0);
if (plugin_watcher.port == 0) {
LOGE("failed to assign a control port for plugin");
}
Expand Down Expand Up @@ -1860,6 +1872,9 @@ main(int argc, char **argv)
#endif

if (plugin != NULL) {
if (plugin_mode == UDP_ONLY && mode == TCP_AND_UDP) {
FATAL("plugin_mode cannot be udp_only when both TCP and UDP relay are enabled");
}
int len = 0;
size_t buf_size = 256 * remote_num;
char *remote_str = ss_malloc(buf_size);
Expand All @@ -1870,12 +1885,14 @@ main(int argc, char **argv)
snprintf(remote_str + len, buf_size - len, "|%s", remote_addr[i].host);
len = strlen(remote_str);
}
// according to SIP003u, the plugin does not need to know the plugin_mode
// it can always listen on both TCP and UDP ports
int err = start_plugin(plugin, plugin_opts, remote_str,
remote_port, plugin_host, plugin_port,
#ifdef __MINGW32__
plugin_watcher.port,
#endif
MODE_CLIENT);
ROLE_CLIENT);
if (err) {
ERROR("start_plugin");
FATAL("failed to start the plugin");
Expand Down Expand Up @@ -1966,6 +1983,10 @@ main(int argc, char **argv)
LOGI("udprelay enabled");
char *host = remote_addr[0].host;
char *port = remote_addr[0].port == NULL ? remote_port : remote_addr[0].port;
if (plugin != NULL && plugin_mode != TCP_ONLY) {
host = plugin_host;
port = plugin_port;
}
struct sockaddr_storage *storage = ss_malloc(sizeof(struct sockaddr_storage));
memset(storage, 0, sizeof(struct sockaddr_storage));
if (get_sockaddr(host, port, storage, 1, ipv6first) == -1) {
Expand Down
25 changes: 25 additions & 0 deletions src/manager.c
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,8 @@ destroy_server(struct server *server)
ss_free(server->plugin);
if (server->plugin_opts)
ss_free(server->plugin_opts);
if (server->plugin_mode)
ss_free(server->plugin_mode);
if (server->mode)
ss_free(server->mode);
}
Expand Down Expand Up @@ -135,6 +137,8 @@ build_config(char *prefix, struct manager_ctx *manager, struct server *server)
fprintf(f, ",\n\"plugin\":\"%s\"", server->plugin);
if (server->plugin_opts)
fprintf(f, ",\n\"plugin_opts\":\"%s\"", server->plugin_opts);
if (server->plugin_mode)
fprintf(f, ",\n\"plugin_mode\":\"%s\"", server->plugin_mode);
fprintf(f, "\n}\n");
fclose(f);
ss_free(path);
Expand Down Expand Up @@ -214,6 +218,14 @@ construct_command_line(struct manager_ctx *manager, struct server *server)
int len = strlen(cmd);
snprintf(cmd + len, BUF_SIZE - len, " --plugin-opts \"%s\"", manager->plugin_opts);
}
if (server->plugin_mode == NULL && manager->plugin_mode == UDP_ONLY) {
int len = strlen(cmd);
snprintf(cmd + len, BUF_SIZE - len, " --plugin-mode \"udp_only\"");
}
if (server->plugin_mode == NULL && manager->plugin_mode == TCP_AND_UDP) {
int len = strlen(cmd);
snprintf(cmd + len, BUF_SIZE - len, " --plugin-mode \"tcp_and_udp\"");
}
if (manager->nameservers) {
int len = strlen(cmd);
snprintf(cmd + len, BUF_SIZE - len, " -d \"%s\"", manager->nameservers);
Expand Down Expand Up @@ -322,6 +334,10 @@ get_server(char *buf, int len)
if (value->type == json_string) {
server->plugin_opts = strdup(value->u.string.ptr);
}
} else if (strcmp(name, "plugin_mode") == 0) {
if (value->type == json_string) {
server->plugin_mode = strdup(value->u.string.ptr);
}
} else if (strcmp(name, "mode") == 0) {
if (value->type == json_string) {
server->mode = strdup(value->u.string.ptr);
Expand Down Expand Up @@ -868,6 +884,7 @@ main(int argc, char **argv)
char *manager_address = NULL;
char *plugin = NULL;
char *plugin_opts = NULL;
int plugin_mode = TCP_ONLY;
char *workdir = NULL;

int fast_open = 0;
Expand Down Expand Up @@ -900,6 +917,7 @@ main(int argc, char **argv)
{ "mtu", required_argument, NULL, GETOPT_VAL_MTU },
{ "plugin", required_argument, NULL, GETOPT_VAL_PLUGIN },
{ "plugin-opts", required_argument, NULL, GETOPT_VAL_PLUGIN_OPTS },
{ "plugin-mode", required_argument, NULL, GETOPT_VAL_PLUGIN_MODE },
{ "password", required_argument, NULL, GETOPT_VAL_PASSWORD },
{ "workdir", required_argument, NULL, GETOPT_VAL_WORKDIR },
{ "help", no_argument, NULL, GETOPT_VAL_HELP },
Expand Down Expand Up @@ -940,6 +958,9 @@ main(int argc, char **argv)
case GETOPT_VAL_PLUGIN_OPTS:
plugin_opts = optarg;
break;
case GETOPT_VAL_PLUGIN_MODE:
plugin_mode = parse_plugin_mode(optarg);
break;
case 's':
if (server_num < MAX_REMOTE_NUM) {
server_host[server_num++] = optarg;
Expand Down Expand Up @@ -1054,6 +1075,9 @@ main(int argc, char **argv)
if (plugin_opts == NULL) {
plugin_opts = conf->plugin_opts;
}
if (plugin_mode == TCP_ONLY) {
plugin_mode = conf->plugin_mode;
}
if (ipv6first == 0) {
ipv6first = conf->ipv6_first;
}
Expand Down Expand Up @@ -1184,6 +1208,7 @@ main(int argc, char **argv)
manager.mtu = mtu;
manager.plugin = plugin;
manager.plugin_opts = plugin_opts;
manager.plugin_mode = plugin_mode;
manager.ipv6first = ipv6first;
manager.workdir = workdir;
#ifdef HAVE_SETRLIMIT
Expand Down
2 changes: 2 additions & 0 deletions src/manager.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ struct manager_ctx {
char *user;
char *plugin;
char *plugin_opts;
int plugin_mode;
char *manager_address;
char **hosts;
int host_num;
Expand All @@ -74,6 +75,7 @@ struct server {
char *method;
char *plugin;
char *plugin_opts;
char *plugin_mode;
uint64_t traffic;
};

Expand Down
34 changes: 27 additions & 7 deletions src/plugin.c
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ start_ss_plugin(const char *plugin,
const char *remote_port,
const char *local_host,
const char *local_port,
enum plugin_mode mode)
enum plugin_role role)
{
cork_env_add(env, "SS_REMOTE_HOST", remote_host);
cork_env_add(env, "SS_REMOTE_PORT", remote_port);
Expand Down Expand Up @@ -162,7 +162,7 @@ start_obfsproxy(const char *plugin,
const char *remote_port,
const char *local_host,
const char *local_port,
enum plugin_mode mode)
enum plugin_role role)
{
char *pch;
char *opts_dump = NULL;
Expand Down Expand Up @@ -204,7 +204,7 @@ start_obfsproxy(const char *plugin,
}

/* The rest options */
if (mode == MODE_CLIENT) {
if (role == ROLE_CLIENT) {
/* Client mode */
cork_exec_add_param(exec, "--dest");
snprintf(buf, buf_size, "%s:%s", remote_host, remote_port);
Expand Down Expand Up @@ -243,7 +243,7 @@ start_plugin(const char *plugin,
#ifdef __MINGW32__
uint16_t control_port,
#endif
enum plugin_mode mode)
enum plugin_role role)
{
#ifndef __MINGW32__
char *new_path = NULL;
Expand Down Expand Up @@ -288,10 +288,10 @@ start_plugin(const char *plugin,

if (!strncmp(plugin, "obfsproxy", strlen("obfsproxy")))
ret = start_obfsproxy(plugin, plugin_opts, remote_host, remote_port,
local_host, local_port, mode);
local_host, local_port, role);
else
ret = start_ss_plugin(plugin, plugin_opts, remote_host, remote_port,
local_host, local_port, mode);
local_host, local_port, role);
#ifndef __MINGW32__
ss_free(new_path);
#endif
Expand All @@ -300,7 +300,7 @@ start_plugin(const char *plugin,
}

uint16_t
get_local_port()
get_local_port(int with_udp)
{
int sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock < 0) {
Expand All @@ -322,6 +322,26 @@ get_local_port()
close(sock);
return 0;
}

if (with_udp) {
int udp_sock = socket(AF_INET, SOCK_DGRAM, 0);
if (udp_sock < 0) {
close(sock);
return 0;
}

if (bind(udp_sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {
close(udp_sock);
close(sock);
return 0;
}

if (close(udp_sock) < 0) {
close(sock);
return 0;
}
}

if (close(sock) < 0) {
return 0;
}
Expand Down
10 changes: 5 additions & 5 deletions src/plugin.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,9 @@
#define PLUGIN_EXIT_NORMAL -1
#define PLUGIN_RUNNING 0

enum plugin_mode {
MODE_CLIENT,
MODE_SERVER
enum plugin_role {
ROLE_CLIENT,
ROLE_SERVER
};

/*
Expand Down Expand Up @@ -72,8 +72,8 @@ int start_plugin(const char *plugin,
#ifdef __MINGW32__
uint16_t control_port,
#endif
enum plugin_mode mode);
uint16_t get_local_port();
enum plugin_role mode);
uint16_t get_local_port(int with_udp);
void stop_plugin();
int is_plugin_running();

Expand Down
Loading