diff --git a/.gitignore b/.gitignore index 8ab417910..67d49ef03 100644 --- a/.gitignore +++ b/.gitignore @@ -51,6 +51,10 @@ rpm/BUILDROOT/ *.rpm *.deb +# Ignore files for clangd language server +.cache/ +compile_commands.json + # Ignore per-project vim config .vimrc diff --git a/doc/shadowsocks-libev.asciidoc b/doc/shadowsocks-libev.asciidoc index 4a283dd66..b3e27f3eb 100644 --- a/doc/shadowsocks-libev.asciidoc +++ b/doc/shadowsocks-libev.asciidoc @@ -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" diff --git a/src/common.h b/src/common.h index 66e985cd4..398ef1d71 100644 --- a/src/common.h +++ b/src/common.h @@ -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, diff --git a/src/jconf.c b/src/jconf.c index d2815eff8..08876d7b2 100644 --- a/src/jconf.c +++ b/src/jconf.c @@ -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"); @@ -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; +} \ No newline at end of file diff --git a/src/jconf.h b/src/jconf.h index 544011d3d..eb684a5b5 100644 --- a/src/jconf.h +++ b/src/jconf.h @@ -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; @@ -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 diff --git a/src/local.c b/src/local.c index fa1ca7b31..886b914ca 100644 --- a/src/local.c +++ b/src/local.c @@ -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]; @@ -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 }, @@ -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; @@ -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; } @@ -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"); } @@ -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"); } @@ -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); @@ -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"); @@ -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) { diff --git a/src/manager.c b/src/manager.c index 8a229d094..799ae6752 100644 --- a/src/manager.c +++ b/src/manager.c @@ -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); } @@ -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); @@ -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); @@ -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); @@ -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; @@ -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 }, @@ -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; @@ -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; } @@ -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 diff --git a/src/manager.h b/src/manager.h index d5aa83276..0e2b28ad4 100644 --- a/src/manager.h +++ b/src/manager.h @@ -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; @@ -74,6 +75,7 @@ struct server { char *method; char *plugin; char *plugin_opts; + char *plugin_mode; uint64_t traffic; }; diff --git a/src/plugin.c b/src/plugin.c index b67a9a4f6..da44fcae5 100644 --- a/src/plugin.c +++ b/src/plugin.c @@ -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); @@ -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; @@ -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); @@ -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; @@ -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 @@ -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) { @@ -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; } diff --git a/src/plugin.h b/src/plugin.h index 1a6d4b474..d12c697c1 100644 --- a/src/plugin.h +++ b/src/plugin.h @@ -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 }; /* @@ -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(); diff --git a/src/redir.c b/src/redir.c index d36fe3fe7..663f3a028 100644 --- a/src/redir.c +++ b/src/redir.c @@ -909,6 +909,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]; @@ -928,6 +929,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 }, { "reuse-port", no_argument, NULL, GETOPT_VAL_REUSE_PORT }, { "tcp-incoming-sndbuf", required_argument, NULL, GETOPT_VAL_TCP_INCOMING_SNDBUF }, { "tcp-incoming-rcvbuf", required_argument, NULL, GETOPT_VAL_TCP_INCOMING_RCVBUF }, @@ -969,6 +971,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; @@ -1104,6 +1109,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 (mode == TCP_ONLY) { mode = conf->mode; } @@ -1156,7 +1164,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"); } @@ -1264,8 +1276,10 @@ 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, MODE_CLIENT); + remote_port, plugin_host, plugin_port, ROLE_CLIENT); if (err) { FATAL("failed to start the plugin"); } @@ -1348,6 +1362,10 @@ main(int argc, char **argv) LOGI("UDP relay 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) { diff --git a/src/server.c b/src/server.c index 73b65996d..d545c9d69 100644 --- a/src/server.c +++ b/src/server.c @@ -1802,6 +1802,7 @@ main(int argc, char **argv) char *server_port = NULL; char *plugin_opts = NULL; + int plugin_mode = TCP_ONLY; char *plugin_host = NULL; char *plugin_port = NULL; char tmp_port[8]; @@ -1828,6 +1829,7 @@ main(int argc, char **argv) { "help", no_argument, NULL, GETOPT_VAL_HELP }, { "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 }, #ifdef __linux__ @@ -1870,6 +1872,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_MPTCP: mptcp = get_mptcp(1); if (mptcp) @@ -2009,6 +2014,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 (mode == TCP_ONLY) { mode = conf->mode; } @@ -2118,7 +2126,11 @@ main(int argc, char **argv) #endif 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"); } @@ -2266,13 +2278,14 @@ main(int argc, char **argv) snprintf(server_str + len, buf_size - len, "|%s", server_addr[i].host); len = strlen(server_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, server_str, plugin_port, plugin_host, server_port, #ifdef __MINGW32__ plugin_watcher.port, #endif - MODE_SERVER); + ROLE_SERVER); if (err) { ERROR("start_plugin"); FATAL("failed to start the plugin"); @@ -2337,9 +2350,24 @@ main(int argc, char **argv) for (int i = 0; i < server_num; i++) { const char *host = server_addr[i].host; const char *port = server_addr[i].port ? server_addr[i].port : server_port; + if (plugin != NULL) { - port = plugin_port; + // if plugin exists, the plugin_port is set to the original server_port + // and the server_port is the temporary port + // i.e. the plugin acts as a server, listen to server_host:server_port + // and the server recvs from the plugin via 127.0.0.1:temp_port + + // for udp relay, the plugin mode by default is TCP_ONLY, so the udp server should directly + // listen on the original server_host:server_port + if (plugin_mode == TCP_ONLY) { + port = plugin_port; // plugin_port is the original server_port + } else { + // plugin_mode == TCP_AND_UDP or UDP_ONLY, the plugin handles UDP relay + // so the server should listen on 127.0.0.1:temp_port + host = plugin_host; // plugin_host is 127.0.0.1 + } } + if (host && ss_is_ipv6addr(host)) LOGI("udp server listening at [%s]:%s", host, port); else diff --git a/src/tunnel.c b/src/tunnel.c index 99ed41287..21e21df2f 100644 --- a/src/tunnel.c +++ b/src/tunnel.c @@ -902,6 +902,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]; @@ -922,6 +923,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 }, { "reuse-port", no_argument, NULL, GETOPT_VAL_REUSE_PORT }, { "tcp-incoming-sndbuf", required_argument, NULL, GETOPT_VAL_TCP_INCOMING_SNDBUF }, { "tcp-incoming-rcvbuf", required_argument, NULL, GETOPT_VAL_TCP_INCOMING_RCVBUF }, @@ -967,6 +969,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; @@ -1110,6 +1115,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 (tunnel_addr_str == NULL) { tunnel_addr_str = conf->tunnel_address; } @@ -1193,7 +1201,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"); } @@ -1207,7 +1219,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"); } @@ -1314,12 +1326,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"); @@ -1402,6 +1416,10 @@ main(int argc, char **argv) LOGI("UDP relay 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) { diff --git a/src/utils.c b/src/utils.c index d3ff2aba6..0c0fb53d2 100644 --- a/src/utils.c +++ b/src/utils.c @@ -431,6 +431,8 @@ usage() " [--plugin ] Enable SIP003 plugin. (Experimental)\n"); printf( " [--plugin-opts ] Set SIP003 plugin options. (Experimental)\n"); + printf( + " [--plugin-mode ] Set plugin mode (Defined in SIP003u): tcp_only(default), udp_only or tcp_and_udp. (Experimental)\n"); printf("\n"); printf( " [-v] Verbose mode.\n");