Android: 使用ssh + sshd实现socks代理服务器

ssh的全称为Secure Shell, 通常我们用它来登录到提供sshd service的主机,以便使用这台主机上的资源。或者用来建一条遂道,使得两台非公网的主机能够通过一台公网主机进行相互访问->@<- 。当然,你还可以如标题所述,使用ssh + sshd实现socks代理服务器。对于提供ssh/sshd命令的Linux系统来说,实现一个socks proxy server是一件很容易的事。对于android系统来说,由于系统中没有ssh/sshd命令(至少对于android-5.1.1_r15来说),有没有办法使用ssh/sshd来实现一个socks代理服务器呢?

  • 原理

ssh的帮助手册(man ssh)提到:

-D [bind_address:]port

Specifies a local dynamic application-level port forwarding. This works by allocating a socket to listen to port on the local side, optionally bound to the specified bind_address. Whenever a connection is made to this port, the connection is forwarded over the secure channel, and the application protocol is then used to determine where to connect to from the remote machine. Currently the SOCKS4 and SOCKS5 protocols are supported, and ssh will act as a SOCKS server. Only root can forward privileged ports. Dynamic port forwardings can also be specified in the configuration file.

IPv6 addresses can be specified by enclosing the address in square brackets.  Only the superuser can forward privileged ports. By default, the local port is bound in accordance with the GatewayPorts setting. However, an explicit bind_address may be used to bind the connection to a specific address. The bind_address of localhost indicates that the listening port be bound for local use only, while an empty address or `*’ indicates that the port should be available from all interfaces.

也就是说,假设ssh服务器的ip地址为123.57.161.90, 用户hzak可以远程登录到该服务器上,那么在本地或者远程主机上执行如下命令,就可以在本地或者远程主机上建立一个socks代理服务器(ip 127.0.0.1, port 1080):

$ ssh -f -N -D 127.0.0.1:1080 hzak@123.57.161.90 -p 22

由此看来,我们首先需要在Android系统中安装一个sshd服务,其次还需要执行ssh命令来建立代理服务器。

openssh对socks server的支持情况也可以通过external/openssh/channels.c文件查看,支持socks4,socks4a,socks5。

  • 环境

Android系统版本:android-5.1.1_r15 @Nexus 4, 在项目中编译。

  • 代码

1. external/openssh代码

android-5.1.1_r15分支上由于没有别的模块依赖于openssh, 它的代码已经被删除,但你还是可以从external/openssh将代码checkout出来:

commit 6dd962236c57f327b92b0c8f09f649279980023c
Author: dcashman <dcashman@google.com>
Date:   Mon Jul 7 16:20:40 2014 -0700

    Remove sshd.
    
    This may require changes to other code, such as fastbootd, which relies on this
    service.  sshd is not currently, used, however, so this change will force any
    such code to be changed.
    
    Bug: 11594902
    Change-Id: I07e52008290dab5825be2ad062cbe730fa7dff71

由于openssh代码已经很长时间没有更新,我更新了external/openssh,可以将android-6.0.1_r22标签上的代码checkout出来:

$ git clone https://android.googlesource.com/platform/external/openssh
$ git checkout android-6.0.1_r22

2. 创建ssh host key

参考external/openssh/start-ssh shell脚本的做法,先创建dsa key:

ssh-keygen -t dsa -f [dataDir]/ssh/ssh_host_dsa_key -N ""

执行这个命令之后,会生成两个文件:

a. ssh_host_dsa_key: 将这个文件的mode设为0600

b. ssh_host_dsa_key.pub: 将这个文件的mode设为0644

再创建rsa key:

ssh-keygen -t rsa -f [dataDir]/ssh/ssh_host_rsa_key -N ""

同样会生成两个文件:

a. ssh_host_rsa_key: 将这个文件的mode设为0600

b. ssh_host_rsa_key.pub: 将这个文件的mode设为0644

3. 创建ssh client key并创建authorized_keys

创建client所需要key, 类型为rsa key:

ssh-keygen -t rsa -f [dataDir]/ssh/id_rsa -N ""

复制或重命名id_rsa.pub文件为authorized_keys

4. 创建sshd配置文件sshd_config

在[dataDir]目录下创建ssh_config文件,文件内容如下:

Protocol 2

HostKey /data/data/<package name>/ssh/ssh_host_rsa_key
HostKey /data/data/<package name>/ssh/ssh_host_dsa_key

AuthorizedKeysFile	/data/data/<package name>/ssh/authorized_keys

PasswordAuthentication no

UsePrivilegeSeparation no

<package name>替换成apk的包名,并使用public key进行认证。

5. 运行sshd server

/data/data/<package name>/bin/sshd -f /data/data/<package name>/ssh/sshd_config -D

5. 通过ssh创建socks4/socks4a/socks5服务器

/data/data/<package name>/ -f -N -D 127.0.0.1:1080 127.0.0.1 -p 8022 -i /data/data/<package name>/ssh/id_rsa -o "StrictHostKeyChecking no"

为了避免进入交互模式,不进行host keys的检查。

=== 待续 ===

相关的参考文档:

  1. http://www.openssh.com/
  2. https://en.wikipedia.org/wiki/Secure_Shell
  3. https://www.ietf.org/rfc/rfc1928.txt
  4. http://www.linux-magazine.com/content/download/62784/486055/version/1/file/Socks_v5_Proxy_Protocol.pdf

发表评论

电子邮件地址不会被公开。 必填项已用*标注