Browse Source

Obfsproxy standalone mode (#1156)

* ss-libev: Introduce mode parameter for start_plugin

Since obfsproxy handles client and server in different ways, no matter
standalone or manged mode, so introduce the mode for start_plugin() to
support obfsproxy.

With more comments added to plugin.h for later developers.

Signed-off-by: Adam Anonymous <anonymous_temp_mail@yahoo.co.jp>

* ss-libev: Move SS protocol plugin initialization code to start_ss_plugin

Move SS protocol plugin initialization to start_ss_plugin() function, as
the support for obfsproxy will not use that environment.

Also, remove the use of get_current_dir_name() which is a glibc
extension, such macro hack will just make code less readable.
Not to mention it already screw up code folding of vim.

Signed-off-by: Adam Anonymous <anonymous_temp_mail@yahoo.co.jp>

* ss-libev: Introduce obfsproxy standalone mode support as plugin

Now shadowsocks-libev supports to use obfsproxy as plugin.

Currently we only support to use standalone(proxy) mode of obfsproxy, as
managed mode needs to use SOCKS5 as upstream forward, while ss-libev
doesn't support it yet.

And the output from plugin is just trashed for now.
Support to pipe them into stdout/stderr will be added later.

Signed-off-by: Adam Anonymous <anonymous_temp_mail@yahoo.co.jp>

* ss-libev: doc: Fix wrong cmdline parameter for plugin options

Command line option for plugin options is "--plugin-opts", not the json
option "--plugin_opts"

Fix it.

Signed-off-by: Adam Anonymous <anonymous_temp_mail@yahoo.co.jp>
pull/1165/head
anonymous-contributor 8 years ago
committed by Max Lv
parent
commit
98c51cd0d5
11 changed files with 195 additions and 50 deletions
  1. 4
      doc/ss-local.asciidoc
  2. 4
      doc/ss-manager.asciidoc
  3. 4
      doc/ss-redir.asciidoc
  4. 4
      doc/ss-server.asciidoc
  5. 4
      doc/ss-tunnel.asciidoc
  6. 2
      src/local.c
  7. 178
      src/plugin.c
  8. 39
      src/plugin.h
  9. 2
      src/redir.c
  10. 2
      src/server.c
  11. 2
      src/tunnel.c

4
doc/ss-local.asciidoc

@ -14,7 +14,7 @@ SYNOPSIS
[-t <timeout>] [-c <config_file>] [-i <interface>]
[-a <user_name>] [-b <local_address] [-n <nofile>]
[--fast-open] [--acl <acl_config>] [--mtu <MTU>]
[--plugin <plugin_name>] [--plugin_opts <plugin_options]
[--plugin <plugin_name>] [--plugin-opts <plugin_options]
DESCRIPTION
-----------
@ -119,7 +119,7 @@ Only available with MPTCP enabled Linux kernel.
--plugin <plugin_name>::
Enable SIP003 plugin. (Experimental)
--plugin_opts <plugin_options>::
--plugin-opts <plugin_options>::
Set SIP003 plugin options. (Experimental)
-v::

4
doc/ss-manager.asciidoc

@ -15,7 +15,7 @@ SYNOPSIS
[-b <local_addr>] [-a <user_name>]
[--manager-address <path_to_unix_domain>]
[--executable <path_to_server_executable>]
[--plugin <plugin_name>] [--plugin_opts <plugin_options>]
[--plugin <plugin_name>] [--plugin-opts <plugin_options>]
DESCRIPTION
-----------
@ -109,7 +109,7 @@ Only available in manager mode.
--plugin <plugin_name>::
Enable SIP003 plugin. (Experimental)
--plugin_opts <plugin_options>::
--plugin-opts <plugin_options>::
Set SIP003 plugin options. (Experimental)
-v::

4
doc/ss-redir.asciidoc

@ -13,7 +13,7 @@ SYNOPSIS
[-k <password>] [-m <encrypt_method>] [-f <pid_file>]
[-t <timeout>] [-c <config_file>] [-b <local_address>]
[-a <user_name>] [-n <nofile>] [--mtu <MTU>]
[--plugin <plugin_name>] [--plugin_opts <plugin_options]
[--plugin <plugin_name>] [--plugin-opts <plugin_options]
DESCRIPTION
-----------
@ -105,7 +105,7 @@ Only available with MPTCP enabled Linux kernel.
--plugin <plugin_name>::
Enable SIP003 plugin. (Experimental)
--plugin_opts <plugin_options>::
--plugin-opts <plugin_options>::
Set SIP003 plugin options. (Experimental)
-v::

4
doc/ss-server.asciidoc

@ -16,7 +16,7 @@ SYNOPSIS
[-b <local_address] [--fast-open] [--mptcp]
[--acl <acl_config>] [--mtu <MTU>]
[--manager-address <path_to_unix_domain>]
[--plugin <plugin_name>] [--plugin_opts <plugin_options]
[--plugin <plugin_name>] [--plugin-opts <plugin_options]
DESCRIPTION
-----------
@ -126,7 +126,7 @@ Only available with MPTCP enabled Linux kernel.
--plugin <plugin_name>::
Enable SIP003 plugin. (Experimental)
--plugin_opts <plugin_options>::
--plugin-opts <plugin_options>::
Set SIP003 plugin options. (Experimental)
-v::

4
doc/ss-tunnel.asciidoc

@ -14,7 +14,7 @@ SYNOPSIS
[-t <timeout>] [-c <config_file>] [-i <interface>]
[-b <local_addr>] [-a <user_name>] [-n <nofile>]
[-L addr:port] [--mtu <MTU>]
[--plugin <plugin_name>] [--plugin_opts <plugin_options]
[--plugin <plugin_name>] [--plugin-opts <plugin_options]
DESCRIPTION
-----------
@ -116,7 +116,7 @@ Only available with MPTCP enabled Linux kernel.
--plugin <plugin_name>::
Enable SIP003 plugin. (Experimental)
--plugin_opts <plugin_options>::
--plugin-opts <plugin_options>::
Set SIP003 plugin options. (Experimental)
-v::

2
src/local.c

@ -1453,7 +1453,7 @@ main(int argc, char **argv)
len = strlen(remote_str);
}
int err = start_plugin(plugin, plugin_opts, remote_str,
remote_port, plugin_host, plugin_port);
remote_port, plugin_host, plugin_port, MODE_CLIENT);
if (err) {
FATAL("failed to start the plugin");
}

178
src/plugin.c

@ -78,51 +78,23 @@ struct cork_stream_consumer plugin_log = {
.free = plugin_log__free,
};
int
start_plugin(const char *plugin,
const char *plugin_opts,
const char *remote_host,
const char *remote_port,
const char *local_host,
const char *local_port)
static int start_ss_plugin(const char *plugin,
const char *plugin_opts,
const char *remote_host,
const char *remote_port,
const char *local_host,
const char *local_port,
enum plugin_mode mode)
{
char *new_path = NULL;
char *cmd = NULL;
if (plugin == NULL)
return -1;
if (strlen(plugin) == 0)
return 0;
size_t plugin_len = strlen(plugin);
size_t cmd_len = plugin_len + CMD_RESRV_LEN;
cmd = ss_malloc(cmd_len);
snprintf(cmd, cmd_len, "exec %s", plugin);
env = cork_env_clone_current();
const char *path = cork_env_get(env, "PATH");
if (path != NULL) {
#ifdef __GLIBC__
char *cwd = get_current_dir_name();
if (cwd) {
#else
char cwd[PATH_MAX];
if (!getcwd(cwd, PATH_MAX)) {
#endif
size_t path_len = strlen(path) + strlen(cwd) + 2;
new_path = ss_malloc(path_len);
snprintf(new_path, path_len, "%s:%s", cwd, path);
#ifdef __GLIBC__
free(cwd);
#endif
}
}
if (new_path != NULL)
cork_env_add(env, "PATH", new_path);
cork_env_add(env, "SS_REMOTE_HOST", remote_host);
cork_env_add(env, "SS_REMOTE_PORT", remote_port);
@ -148,6 +120,142 @@ start_plugin(const char *plugin,
return err;
}
#define OBFSPROXY_OPTS_MAX 4096
/*
* For obfsproxy, we use standalone mode for now.
* Managed mode needs to use SOCKS5 proxy as forwarder, which is not supported
* yet.
*
* The idea of using standalone mode is quite simple, just assemble the
* internal port into obfsproxy parameters.
*
* Using manually ran scramblesuit as an example:
* obfsproxy \
* --data-dir /tmp/ss_libev_plugin_with_suffix \
* scramblesuit \
* --password SOMEMEANINGLESSPASSWORDASEXAMPLE \
* --dest some.server.org:12345 \
* client \
* 127.0.0.1:54321
*
* In above case, @plugin = "obfsproxy",
* @plugin_opts = "scramblesuit --password SOMEMEANINGLESSPASSWORDASEXAMPLE"
* For obfs3, it's even easier, just pass @plugin = "obfsproxy"
* @plugin_opts = "obfs3"
*
* And the rest parameters are all assembled here.
* Some old obfsproxy will not be supported as it doesn't even support
* "--data-dir" option
*/
static int start_obfsproxy(const char *plugin,
const char *plugin_opts,
const char *remote_host,
const char *remote_port,
const char *local_host,
const char *local_port,
enum plugin_mode mode)
{
char *pch;
char *opts_dump;
char buf[PATH_MAX];
int ret;
opts_dump = strndup(plugin_opts, OBFSPROXY_OPTS_MAX);
if (!opts_dump) {
ERROR("start_obfsproxy strndup failed");
return -ENOMEM;
}
exec = cork_exec_new(plugin);
/* The first parameter will be skipped, so pass @plugin again */
cork_exec_add_param(exec, plugin);
cork_exec_add_param(exec, "--data-dir");
snprintf(buf, PATH_MAX, "/tmp/%s_%s:%s_%s:%s", plugin,
remote_host, remote_port, local_host, local_port);
cork_exec_add_param(exec, buf);
/*
* Iterate @plugin_opts by space
*/
pch = strtok(opts_dump, " ");
while (pch) {
cork_exec_add_param(exec, pch);
pch = strtok(NULL, " ");
}
/* The rest options */
if (mode == MODE_CLIENT) {
/* Client mode */
cork_exec_add_param(exec, "--dest");
snprintf(buf, PATH_MAX, "%s:%s", remote_host, remote_port);
cork_exec_add_param(exec, buf);
cork_exec_add_param(exec, "client");
snprintf(buf, PATH_MAX, "%s:%s", local_host, local_port);
cork_exec_add_param(exec, buf);
} else {
/* Server mode */
cork_exec_add_param(exec, "--dest");
snprintf(buf, PATH_MAX, "%s:%s", local_host, local_port);
cork_exec_add_param(exec, buf);
cork_exec_add_param(exec, "server");
snprintf(buf, PATH_MAX, "%s:%s", remote_host, remote_port);
cork_exec_add_param(exec, buf);
}
cork_exec_set_env(exec, env);
sub = cork_subprocess_new_exec(exec, NULL, NULL, &exit_code);
ret = cork_subprocess_start(sub);
ss_free(opts_dump);
return ret;
}
int
start_plugin(const char *plugin,
const char *plugin_opts,
const char *remote_host,
const char *remote_port,
const char *local_host,
const char *local_port,
enum plugin_mode mode)
{
char *new_path = NULL;
const char *current_path;
char cwd[PATH_MAX];
size_t new_path_len;
int ret;
if (plugin == NULL)
return -1;
if (strlen(plugin) == 0)
return 0;
/*
* Add current dir to PATH, so we can search plugin in current dir
*/
env = cork_env_clone_current();
current_path = cork_env_get(env, "PATH");
if (current_path != NULL) {
if (!getcwd(cwd, PATH_MAX)) {
new_path_len = strlen(current_path) + strlen(cwd) + 2;
new_path = ss_malloc(new_path_len);
snprintf(new_path, new_path_len, "%s:%s", cwd, current_path);
}
}
if (new_path != NULL)
cork_env_add(env, "PATH", new_path);
if (!strncmp(plugin, "obfsproxy", strlen("obfsproxy")))
ret = start_obfsproxy(plugin, plugin_opts, remote_host, remote_port,
local_host, local_port, mode);
else
ret = start_ss_plugin(plugin, plugin_opts, remote_host, remote_port,
local_host, local_port, mode);
ss_free(new_path);
env = NULL;
return ret;
}
uint16_t
get_local_port()
{

39
src/plugin.h

@ -27,12 +27,49 @@
#define PLUGIN_EXIT_NORMAL -1
#define PLUGIN_RUNNING 0
enum plugin_mode {
MODE_CLIENT,
MODE_SERVER
};
/*
* XXX: Since we have SS plugins and obfsproxy support, for now we will
* do extra check against the plugin name.
* For obfsproxy, we will not follow the SS specified protocol and
* do special routine for obfsproxy.
* This may change when the protocol is finally settled
*
* Main function to start a plugin.
*
* @plugin: name of the plugin
* search from PATH and current directory.
* @plugin_opts: Special options for plugin
* @remote_host:
* CLIENT mode:
* The remote server address, which also runs corresponding plugin
* SERVER mode:
* The real listen address, which plugin will listen to
* @remote_port:
* CLIENT mode:
* The remote server port, which corresponding plugin is listening to
* SERVER mode:
* The real listen port, which plugin will listen to
* @local_host:
* Where ss-libev will connect/listen to.
* Normally localhost for both modes.
* @local_port:
* Where ss-libev will connect/listen to.
* Internal user port.
* @mode:
* Indicates which mode the plugin should run at.
*/
int start_plugin(const char *plugin,
const char *plugin_opts,
const char *remote_host,
const char *remote_port,
const char *local_host,
const char *local_port);
const char *local_port,
enum plugin_mode mode);
uint16_t get_local_port();
void stop_plugin();
int is_plugin_running();

2
src/redir.c

@ -1028,7 +1028,7 @@ main(int argc, char **argv)
len = strlen(remote_str);
}
int err = start_plugin(plugin, plugin_opts, remote_str,
remote_port, plugin_host, plugin_port);
remote_port, plugin_host, plugin_port, MODE_CLIENT);
if (err) {
FATAL("failed to start the plugin");
}

2
src/server.c

@ -1884,7 +1884,7 @@ main(int argc, char **argv)
}
int err = start_plugin(plugin, plugin_opts, server_str,
plugin_port, "127.0.0.1", server_port);
plugin_port, "127.0.0.1", server_port, MODE_SERVER);
if (err) {
FATAL("failed to start the plugin");
}

2
src/tunnel.c

@ -1011,7 +1011,7 @@ main(int argc, char **argv)
len = strlen(remote_str);
}
int err = start_plugin(plugin, plugin_opts, remote_str,
remote_port, plugin_host, plugin_port);
remote_port, plugin_host, plugin_port, MODE_CLIENT);
if (err) {
FATAL("failed to start the plugin");
}

Loading…
Cancel
Save