erebe / wstunnel

Tunnel all your traffic over Websocket or HTTP2 - Bypass firewalls/DPI - Static binary available
Other
3.17k stars 287 forks source link

Wstunnel for android implementation #253

Open evangelme opened 1 month ago

evangelme commented 1 month ago

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() {
    }
}
alou-S commented 1 month ago

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.

evangelme commented 1 month ago

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

erebe commented 1 month ago

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