You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Android代码中实现SSH dynamic port forwarding?jcraft不支持

在Android中实现SSH动态端口转发(SOCKS代理)

我来帮你搞定这个问题!要实现ssh -D 10000 user@host对应的动态端口转发功能(也就是SOCKS5代理),JCraft的库确实不支持这个特性,不过我们可以用Apache MINA SSHD这个成熟的SSH库来实现,它对各种SSH转发模式都有很好的支持。

步骤1:添加依赖

首先在你的Android项目的app/build.gradle(Module级别)中添加Apache MINA SSHD的核心依赖:

dependencies {
    implementation 'org.apache.sshd:sshd-core:2.11.0' // 可选择最新兼容的稳定版本
}

步骤2:实现核心代码

Android不允许在主线程执行网络操作,所以我们需要用协程、线程或者AsyncTask来处理SSH连接和转发逻辑。下面是一个用Kotlin协程实现的示例(Java项目可换成线程或AsyncTask,逻辑一致):

import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import org.apache.sshd.client.SshClient
import org.apache.sshd.client.session.ClientSession
import org.apache.sshd.common.util.net.SshdSocketAddress

class SshDynamicForwardActivity : AppCompatActivity() {
    private lateinit var sshClient: SshClient
    private var clientSession: ClientSession? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        // 在IO线程启动SSH动态转发
        GlobalScope.launch(Dispatchers.IO) {
            setupSshDynamicForward()
        }
    }

    private fun setupSshDynamicForward() {
        // 替换为你的SSH服务器信息
        val sshHost = "your-host-address"
        val sshPort = 22
        val sshUser = "your-username"
        val sshPassword = "your-password"
        val localSocksPort = 10000 // 对应ssh -D后的本地代理端口

        // 初始化SSH客户端
        sshClient = SshClient.setUpDefaultClient()
        sshClient.start()

        try {
            // 建立SSH会话连接
            clientSession = sshClient.connect(sshUser, sshHost, sshPort)
                .verify()
                .session

            // 密码认证(也可以替换为密钥认证)
            clientSession?.addPasswordIdentity(sshPassword)
            clientSession?.auth()?.verify()

            // 启用本地SOCKS5代理转发
            val socksProxy = sshClient.socksProxy
            socksProxy.port = localSocksPort
            socksProxy.start(SshdSocketAddress("127.0.0.1", localSocksPort))

            println("动态端口转发已启动:本地SOCKS5代理端口 $localSocksPort")
        } catch (e: Exception) {
            e.printStackTrace()
            println("SSH连接或转发失败:${e.message}")
        }
    }

    override fun onDestroy() {
        super.onDestroy()
        // 停止转发并清理资源
        runCatching {
            sshClient.socksProxy.stop()
            clientSession?.close()
            sshClient.stop()
        }
    }
}

步骤3:配置权限

在AndroidManifest.xml中添加必要的网络权限:

<uses-permission android:name="android.permission.INTERNET" />

如果你的SSH服务器使用非加密的明文连接(SSH本身是加密协议,通常无需此配置),在Android 9及以上版本需要在application标签中添加:

<application
    ...
    android:usesCleartextTraffic="true">
    ...
</application>

关键说明

  • SOCKS代理使用:启动转发后,你可以在应用的网络请求中配置使用127.0.0.1:10000作为SOCKS5代理,所有请求都会通过SSH隧道转发到目标服务器。
  • 密钥认证替代:如果不想用密码认证,可以换成密钥认证,示例代码如下:
    val privateKeyFile = File("path-to-your-private-key")
    clientSession?.addPublicKeyIdentity(privateKeyFile)
    
  • 异常处理:实际项目中要完善异常处理,比如连接超时、认证失败等场景,给用户友好的提示。
  • 后台运行:如果需要在后台保持转发,建议用Service组件管理SSH会话,避免Activity销毁时断开连接。

内容的提问来源于stack exchange,提问作者Omidreza Bagheri

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 09:42:18