使用 JSch SSH 连接的 Android VpnService:它连接到服务器,但无法访问互联网

问题描述 投票:0回答:1

我正在使用下面的源通过 SSH 连接到服务器。程序没有任何错误。

手机屏幕顶部将出现钥匙图标:

VPN Connected Image1.

但是我无法访问互联网:

No Internet Access Image.

我用其他软件测试过,例如napsternetV和NetMod(SSH),问题不在于VPS。为什么无法连接互联网?

主要活动

package com.example.myapplication;
    import androidx.appcompat.app.AppCompatActivity;
    import android.content.Intent;
    import android.net.VpnService;
    import android.os.Bundle;
    import android.util.Log;
    import android.widget.Button;

    public class MainActivity extends AppCompatActivity {
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            Button startVpnButton = findViewById(R.id.start_vpn_button);
            startVpnButton.setOnClickListener(v -> {
                Intent intent = VpnService.prepare(getApplicationContext());
                if (intent != null) {
                    startActivityForResult(intent, 0);
                } else {
                    onActivityResult(0, RESULT_OK, null);
                }
            });
            Button stopVpnButton = findViewById(R.id.stop_vpn_button);
            stopVpnButton.setOnClickListener(v -> {
                Intent intent = new Intent(getApplicationContext(), MyVpnService.class);
                stopService(intent);
            });
        }
        @Override
        protected void onActivityResult(int requestCode, int resultCode, Intent data) {
            super.onActivityResult(requestCode, resultCode, data);
            if (resultCode == RESULT_OK) {
                Intent intent = new Intent(getApplicationContext(), MyVpnService.class);
                startService(intent);
            }
        }
    }

我的VPN服务

    package com.example.myapplication;
    import android.content.Intent;
    import android.net.VpnService;
    import android.os.ParcelFileDescriptor;
    import android.system.OsConstants;
    import android.util.Log;
    import com.jcraft.jsch.JSch;
    import com.jcraft.jsch.JSchException;
    import com.jcraft.jsch.Session;
    import java.io.IOException;

    public class MyVpnService extends VpnService {
        private ParcelFileDescriptor vpnInterface;
        private Session sshSession;

        // Implement onCreate, onStartCommand, and onDestroy methods
        @Override
        public void onCreate() {
            super.onCreate();
            // Initialize JSch and set up the SSH connection
            JSch jsch = new JSch();
            try {
                sshSession = jsch.getSession("SERVER_USERNAME", "SERVER_IP", SERVER_PORT);
            } catch (JSchException e) {

                throw new RuntimeException(e);
            }
            sshSession.setPassword("SERVER_PASSWORD");
            sshSession.setConfig("StrictHostKeyChecking", "no");
        }
        @Override
        public int onStartCommand(Intent intent, int flags, int startId) {
            Thread vpnThread = new Thread(() -> {
                try {

                    sshSession.connect();
                    int port_forwarded = sshSession.setPortForwardingL(0, "localhost", 1080);

                    // Configure the VPN connection
                    VpnService.Builder builder = new VpnService.Builder();
                    builder.setSession("MyVpnService")
                            .addAddress("10.0.0.1", 24)
                            .addRoute("0.0.0.0", 0)
                            .addDnsServer("8.8.8.8")
                            .setBlocking(true)
                            .establish();

                    vpnInterface = builder.establish();

                    // Add this line to route all traffic through the VPN
                    builder.allowFamily(OsConstants.AF_INET);

                } catch (Exception e) {

                    e.printStackTrace();
                }
            });
            vpnThread.start();
            return START_STICKY;
        }

        @Override
        public void onDestroy() {
            if (vpnInterface != null) {
                try {
                    vpnInterface.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (sshSession != null) {
                sshSession.disconnect();
            }
            super.onDestroy();
        }

    }

AndroidManifest

    <?xml version="1.0" encoding="utf-8"?>
    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools">
        <uses-permission android:name="android.permission.INTERNET" />
        <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
        <uses-permission android:name="android.permission.BIND_VPN_SERVICE"
            tools:ignore="ProtectedPermissions" />
        <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />

        <application
            android:allowBackup="true"
            android:dataExtractionRules="@xml/data_extraction_rules"
            android:fullBackupContent="@xml/backup_rules"
            android:icon="@mipmap/ic_launcher"
            android:label="@string/app_name"
            android:roundIcon="@mipmap/ic_launcher_round"
            android:supportsRtl="true"
            android:theme="@style/Theme.MyApplication"
            tools:targetApi="31">
            <activity
                android:name=".MainActivity"
                android:exported="true">
                <intent-filter>
                    <action android:name="android.intent.action.MAIN" />

                    <category android:name="android.intent.category.LAUNCHER" />
                </intent-filter>
            </activity>

            <service
                android:name=".MyVpnService"
                android:permission="android.permission.BIND_VPN_SERVICE"
                android:exported="true">
                <intent-filter>
                    <action android:name="android.net.VpnService" />
                </intent-filter>
            </service>

        </application>

    </manifest>

日志中没有任何错误,程序运行完美。我什至输入了错误的服务器信息,程序无法连接到服务器。意思是代码运行正常,但是不知道为什么无法连接互联网。

MainScreen Image

java android ssh vpn jsch
1个回答
0
投票

您提到的应用程序使用由 SSH 的动态端口转发创建的 SOCKS 代理。 (

ssh -D
)

目前,您的应用程序不处理任何由VPN接口拦截的数据包。

要实现此目的,您需要能够将 VPN 接口拦截的数据包转发到 SOCKS 代理,并从该 SOCKS 代理接收数据包并将其转发到 VPN 接口。

这项任务并不容易,因为 VPN 和 SOCKS 代理位于 OSI 模型的不同层。但幸运的是,已经有一个名为 Tun2Socks 的开源库可以将您的 VPN 接口连接到 SOCKS 代理。 您需要 JNI 才能使用它,因为它是用 C 编写的。

此外,JSch 库不提供对动态端口转发的支持。 JSch 库的替代方案是 Apache MINA-sshd,它提供对各种 SSH 选项的支持,包括动态端口转发。

© www.soinside.com 2019 - 2024. All rights reserved.