wstunnel icon indicating copy to clipboard operation
wstunnel copied to clipboard

Wstunnel for android implementation

Open evangelme opened this issue 1 year ago • 10 comments

hi i made the windows app and it work just fine. for android i tried the file arm Linux for android but it dose not work so i tried to made a connection to server by myself but the Websocket gives me error.

should i request with a custom header or something like that? my IP is wss://85.239.61.247 should i add any prefix like wss://85.239.61.247/wstunnel to it because when i try to connect to it it gives me this ERROR Expected HTTP 101 response but was '400 Bad Request'

i can send you the whole java code if you want as well

my java code is this if you can help me i reeeeaaaaaaaalllllllyyyy appreciated

package com.example.vpn;

import android.util.Log;

import androidx.annotation.NonNull;

import io.flutter.embedding.engine.plugins.FlutterPlugin;
import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel;
import io.flutter.embedding.engine.plugins.activity.ActivityAware;
import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding;

import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import okhttp3.*;
import okhttp3.WebSocket;
import okio.ByteString;

import javax.net.ssl.*;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;

public class TunnelingPlugin implements FlutterPlugin, MethodChannel.MethodCallHandler, ActivityAware {
    private static final String CHANNEL_NAME = "tunneling_channel";

    private DatagramSocket udpSocket;
    private boolean isRunning = true;

    @Override
    public void onAttachedToEngine(@NonNull FlutterPluginBinding flutterPluginBinding) {
        final MethodChannel channel = new MethodChannel(flutterPluginBinding.getBinaryMessenger(), CHANNEL_NAME);
        channel.setMethodCallHandler(this);
    }

    @Override
    public void onDetachedFromEngine(@NonNull FlutterPluginBinding binding) {
        stopUDPTunneling();
    }

    @Override
    public void onMethodCall(@NonNull MethodCall call, @NonNull MethodChannel.Result result) {
        if (call.method.equals("startTunnel")) {
            startUDPTunneling();
            result.success(null);
        } else {
            result.notImplemented();
        }
    }

    private void startUDPTunneling() {
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    udpSocket = new DatagramSocket(51820); // Listen for UDP packets on port 51820
                    byte[] buffer = new byte[1024];
                    DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
                    while (isRunning) {
                        udpSocket.receive(packet);
                        // Forward the UDP packet to the WebSocket server
                        forwardPacketToWebSocket(packet.getData(), packet.getLength());
                    }
                } catch (Exception e) {
                    Log.e("TunnelingPlugin", "Error starting UDP tunneling: " + e.getMessage());
                    e.printStackTrace(); // Print the stack trace of the exception
                }
            }
        }).start();
    }

    private void forwardPacketToWebSocket(byte[] data, int length) {
        try {
            // Create an SSLContext that trusts all certificates
            TrustManager[] trustAllCerts = new TrustManager[] {
                new X509TrustManager() {
                    @Override
                    public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
                        // No need to implement if only server validation is required
                    }

                    @Override
                    public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
                        // Accept all certificates
                    }

                    @Override
                    public X509Certificate[] getAcceptedIssuers() {
                        return new X509Certificate[0];
                    }
                }
            };
            SSLContext sslContext = SSLContext.getInstance("TLS");
            sslContext.init(null, trustAllCerts, new SecureRandom());

            // Create OkHttpClient with SSLContext that trusts all certificates
            OkHttpClient client = new OkHttpClient.Builder()
                    .sslSocketFactory(sslContext.getSocketFactory(), (X509TrustManager) trustAllCerts[0])
                    .hostnameVerifier((hostname, session) -> true) // Allow all hostnames
                    .build();

            // Create WebSocket request
            Request request = new Request.Builder()
                    .url("wss://85.239.61.247")               
                    .build();

            // Create WebSocket instance
            WebSocket webSocket = client.newWebSocket(request, new WebSocketListener() {
                @Override
                public void onOpen(WebSocket webSocket, Response response) {
                    Log.d("TunnelingPlugin", "WebSocket connection opened");
                }

                @Override
                public void onMessage(WebSocket webSocket, String text) {
                    Log.d("TunnelingPlugin", "Received message from WebSocket: " + text);
                }

                @Override
                public void onClosed(WebSocket webSocket, int code, String reason) {
                    Log.d("TunnelingPlugin", "WebSocket connection closed: " + reason);
                }

                @Override
                public void onFailure(WebSocket webSocket, Throwable t, Response response) {
                    Log.e("TunnelingPlugin", "WebSocket connection failure: " + t.getMessage());
                }
            });

            // Send UDP packet message over WebSocket
            webSocket.send(ByteString.of(data, 0, length));
        } catch (Exception e) {
            Log.e("TunnelingPlugin", "Error forwarding packet to WebSocket: " + e.getMessage());
        }
    }

    private void stopUDPTunneling() {
        isRunning = false;
        if (udpSocket != null) {
            udpSocket.close();
        }
    }

    @Override
    public void onAttachedToActivity(@NonNull ActivityPluginBinding binding) {
    }

    @Override
    public void onDetachedFromActivityForConfigChanges() {
    }

    @Override
    public void onReattachedToActivityForConfigChanges(@NonNull ActivityPluginBinding binding) {
    }

    @Override
    public void onDetachedFromActivity() {
    }
}

evangelme avatar Apr 03 '24 01:04 evangelme

Actually this should be much more easier than before since its now written in rust a binary can be directly compiled for Android.

Before this was way more difficult since it was written in haskell.

alou-S avatar Apr 05 '24 05:04 alou-S

i think if we want to use it in android it should give us wstunnel.so file but it dose not give me that they say you should put lib.rs in it for that but i do not know rust can you help me and tell me how to implement it in android? i reallly appreciated it if you help me because i really need it, @alou-S if you can help me can you tell me how can i contact you i will do anything for this if you help me to do that. thank you.

for example can you change the code put lib.rs in it so i can call a function to start client wstunnel with some parameters pragmatically? if you do that and send me you make my world a better place to live pleeeeeaaasee thank youuuu

evangelme avatar Apr 05 '24 23:04 evangelme

last time someone checked, the linux arm was working on android.

Regarding building a .so, that's at the moment not possible without refactoring a lot main.rs, as for now the project build only a binary and not a lib + binary that use this lib

erebe avatar Apr 08 '24 16:04 erebe

Tried linux arm on an android 10, it didn't work.

Jim-Young avatar May 13 '24 22:05 Jim-Young

At some point I thought it's talking about running the binary inside termux.

Screenshot_2024-05-25-01-31-23-15_84d3000e3f4017145260f7618db1d683

ikhwanperwira avatar May 24 '24 18:05 ikhwanperwira

Indeed, maybe it was with termux. I have added 2 builds for android specifically in latest release https://github.com/erebe/wstunnel/releases/tag/v9.6.0 Let me know if it helps / works for you

binary names : wstunnel_9.6.0_android_arm64.tar.gz wstunnel_9.6.0_android_armv7.tar.gz

erebe avatar May 25 '24 12:05 erebe

Indeed, maybe it was with termux. I have added 2 builds for android specifically in latest release https://github.com/erebe/wstunnel/releases/tag/v9.6.0 Let me know if it helps / works for you

binary names : wstunnel_9.6.0_android_arm64.tar.gz wstunnel_9.6.0_android_armv7.tar.gz

It's worked on me:

  • Realme 5 (arm64)
  • Android 10
  • No root

Usually, I combine wstunnel with socks5 client that act as VPN interface, such as V2rayNG.

Here is command that I used:

wstunnel client -L socks5://127.0.0.1:10808 ws://<ip>:2052 -H "Host: wstunnel.<domain>" -c 2 --websocket-ping-frequency-sec 5 --log-lvl INFO

ikhwanperwira avatar May 25 '24 14:05 ikhwanperwira

@ikhwanperwira I don't have a lot of experience with android, but how do you run the binary from within android (without termux) ?

Do you package it in an app or something ? For me it is not possible to have a shell on an adroid phone to execute binary directly.

I am interested to know more about it ;-)

erebe avatar May 25 '24 15:05 erebe

@ikhwanperwira I don't have a lot of experience with android, but how do you run the binary from within android (without termux) ?

Do you package it in an app or something ? For me it is not possible to have a shell on an adroid phone to execute binary directly.

I am interested to know more about it ;-)

@erebe Okay I need to clarify, Indeed I have used termux to run the binary.

As you see my command was opening local listener with socks5 127.0.0.1:10808.

It's no use to just opening socks5 server. So I need 3rd app of socks5 client that convert socks5 traffic (layer 4) into/from network traffic (layer 3) a.k.a VPN. The socks5 client I have used is V2rayNG, all I need to do is, specify the socks5 server IP which is 127.0.0.1 and its port 10808.

Screenshot_2024-05-26-01-32-12-11_4212e40b9225be51d3d564b7661326c8.jpg

In a nutshell, running the binary inside termux as socks5 server, and V2rayNG as socks5 client.

FYI, the command option I have used is intended for my goal which is for free internet. As long as my cellular ISP don't block one of cloudflare IPs, then I can exploit it. That's the reason why there is -H "Host: wstunnel.dom.com" since cloudflare identify origin server in Host header.

The wstunnel server (origin server) is on linux machine where it's sitting on my campus laboratory and keep on 24 hours.

So, I abuse both, my cellular ISP and my campus's server to keep connected on internet for free >:)

ikhwanperwira avatar May 25 '24 18:05 ikhwanperwira

Thank you @ikhwanperwira , it makes more sense to me know ;-)

erebe avatar May 26 '24 10:05 erebe

New release has android build. Not sure what I can do more. feel free to re-open if needed

erebe avatar Jun 07 '24 20:06 erebe

New release has android build. Not sure what I can do more. feel free to re-open if needed

I don't know what is the difference between android-arm64 and linux-arm64. Both of them is compatible in android who uses arm64.

ikhwanperwira avatar Jun 07 '24 21:06 ikhwanperwira

If i understand correctly, the -android build has been compiled with the android ndk. So it is possible to package the wstunnel binary inside an android app and invoke it directly from the app.

With the -linux it is not possible to do that.

erebe avatar Jun 08 '24 07:06 erebe

@ikhwanperwira I don't have a lot of experience with android, but how do you run the binary from within android (without termux) ? Do you package it in an app or something ? For me it is not possible to have a shell on an adroid phone to execute binary directly. I am interested to know more about it ;-)

@erebe Okay I need to clarify, Indeed I have used termux to run the binary.

As you see my command was opening local listener with socks5 127.0.0.1:10808.

It's no use to just opening socks5 server. So I need 3rd app of socks5 client that convert socks5 traffic (layer 4) into/from network traffic (layer 3) a.k.a VPN. The socks5 client I have used is V2rayNG, all I need to do is, specify the socks5 server IP which is 127.0.0.1 and its port 10808.

Screenshot_2024-05-26-01-32-12-11_4212e40b9225be51d3d564b7661326c8.jpg

In a nutshell, running the binary inside termux as socks5 server, and V2rayNG as socks5 client.

FYI, the command option I have used is intended for my goal which is for free internet. As long as my cellular ISP don't block one of cloudflare IPs, then I can exploit it. That's the reason why there is -H "Host: wstunnel.dom.com" since cloudflare identify origin server in Host header.

The wstunnel server (origin server) is on linux machine where it's sitting on my campus laboratory and keep on 24 hours.

So, I abuse both, my cellular ISP and my campus's server to keep connected on internet for free >:)

can you please help me regarding android? I am developing wireguard vpn with wstunnel but I am facing issues.

mnaveedpaki avatar Jul 24 '24 16:07 mnaveedpaki