xjasonlyu / tun2socks

tun2socks - powered by gVisor TCP/IP stack
https://github.com/xjasonlyu/tun2socks/wiki
GNU General Public License v3.0
2.85k stars 406 forks source link

How to use file descriptor in Android? #123

Closed marco20240618 closed 3 weeks ago

marco20240618 commented 2 years ago

Description

Related to issue #71 Sorry to bother, I appended my quesiton to issuse #71 , but no response. so I opened a new issuse.

In badvpn([https://github.com/ambrop72/badvpn]()), I see this command tun2socks --netif-ipaddr 26.26.26.2 --netif-netmask 255.255.255.0 --socks-server-addr 127.0.0.1:1080 --tunmtu 1500 --loglevel notice --enable-udprelay --sock-path /tmp/sock_path

and then send the file desriptor of the tun0 device to --sock-path

To be more specific, this is how badvpn-tun2socks works in Android.

  1. create a tun device
    android.net.VpnService.Builder builder = new android.net.VpnService.Builder()
                    .setMtu(1500)
                    .addAddress("26.26.26.1", 24)
                    .addDnsServer("8.8.8.8")
                    .addRoute("0.0.0.0", 0);
    mInterface = builder.establish();
  2. run tun2socks
    String tun2socks_command = String.format(java.util.Locale.US, "%s/libtun2socks.so --netif-ipaddr 26.26.26.2 --netif-netmask 255.255.255.0 --socks-server-addr 127.0.0.1:1080 --tunmtu 1500 --loglevel notice --enable-udprelay --sock-path %s/sock_path", this.getApplicationInfo().nativeLibraryDir, this.getApplicationInfo().dataDir);
    Runtime.getRuntime().exec(tun2socks_command);
  3. send file descriptor of tun0 to sock-path
            int tries = 0;
            while (true) {
                try {
                    Thread.sleep(1000L * tries);
                    android.net.LocalSocket ls = new android.net.LocalSocket();
                    ls.connect(new android.net.LocalSocketAddress(getApplicationInfo().dataDir + "/sock_path", android.net.LocalSocketAddress.Namespace.FILESYSTEM));
                    ls.setFileDescriptorsForSend(new java.io.FileDescriptor[]{mInterface.getFileDescriptor()});
                    ls.getOutputStream().write(42);
                    break;
                } catch (Exception e) {
                    if (tries > 5) {
                        break;
                    }
                    ++tries;
                    Util.myLog(this, "fd send error, tries: " + tries);
                }
            }

Is this feature related to a specific bug?

No response

Do you have a specific solution in mind?

No response

tabjy commented 2 years ago

I had success using gomobile bind to directly compile this project into an Android library (.aar). Therefore, sharing descriptor across processes is no longer required:

ParcelFileDescriptor tunDevice = new Builder()
    .addAddress(VPN_ADDRESS, 32)
    .addRoute(VPN_ROUTE, 0)
    .addDnsServer(VPN_DNS)
    .addAllowedApplication("com.google.android.tethering")
    .establish();

engine.Key key = new engine.Key();
key.setMark(0);
key.setMTU(0);
key.setDevice("fd://" + tunDevice.getFd()); // <--- here
key.setInterface("");
key.setLogLevel("debug");
key.setProxy("socks5://127.0.0.1:1080"); // <--- and here
key.setRestAPI("");
key.setTCPSendBufferSize("");
key.setTCPReceiveBufferSize("");
key.setTCPModerateReceiveBuffer(false);

engine.Engine.insert(key);
engine.Engine.start();

In my case, it was acceptable to use SOCKS5 over TCP as my VPN service is configured not routing packets from my own application. No loopback is going to happen. You probably gonna want to protect your SOCKS5 connections or use an Unix Domain Socket to your local SOCKS5 server:

key.setProxy("socks5:///path/to/unix/domain/socket");
marco20240618 commented 2 years ago

it worked. thanks. great project.

yaem1k0 commented 2 years ago

@tabjy Can you tell me how to build it? I want to use this library in my Android project, but i am totally inexperienced for Golang programming. I tried to build it use gomobile into tun2socks.aar many times but all failed.

tabjy commented 2 years ago

I understand this issue is closed, but for the sake of helping out @yaem1k0:

Make sure your ANDROID_HOME, ANDROID_NDK_HOME and GOPATH are set:

$ go install golang.org/x/mobile/cmd/gomobile@latest
$ go get golang.org/x/mobile/bind
$ gomobile init
$ go install github.com/xjasonlyu/tun2socks/v2@latest
$ export DEST=$(pwd)/app/libs
$ mkdir -p DEST
$ cd $GOPATH/src/github.com/xjasonlyu/tun2socks
$ gomobile bind -o $DEST/tun2socks.aar -target android $GOPATH/src/github.com/xjasonlyu/tun2socks/engine
$ ls $DEST # you should see tun2socks.aar and tun2socks-sources.jar

Add the following to your settings.gradle:

 dependencyResolutionManagement {
     repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
     repositories {
         google()
         mavenCentral()
+        flatDir {
+            dirs 'app/libs'
+        }
     }
 }

Add the dependency to your app/build.gradle:

 dependencies {
+    implementation (name:'tun2socks', ext:'aar')

     implementation 'androidx.core:core-ktx:1.7.0'
     // omitted...
}

Execute "Sync Project with Gradle Files" action in Android Studio. Then the engine package would be added to your build path:

import engine.Engine;

See my previous reply for usage. Note that it seemed necessary to set empty values even for unused options.

yaem1k0 commented 1 year ago

It worked, thanks a lot. @tabjy

zmou commented 1 year ago

I had success using gomobile bind to directly compile this project into an Android library (.aar). Therefore, sharing descriptor across processes is no longer required:

ParcelFileDescriptor tunDevice = new Builder()
    .addAddress(VPN_ADDRESS, 32)
    .addRoute(VPN_ROUTE, 0)
    .addDnsServer(VPN_DNS)
    .addAllowedApplication("com.google.android.tethering")
    .establish();

engine.Key key = new engine.Key();
key.setMark(0);
key.setMTU(0);
key.setDevice("fd://" + tunDevice.getFd()); // <--- here
key.setInterface("");
key.setLogLevel("debug");
key.setProxy("socks5://127.0.0.1:1080"); // <--- and here
key.setRestAPI("");
key.setTCPSendBufferSize("");
key.setTCPReceiveBufferSize("");
key.setTCPModerateReceiveBuffer(false);

engine.Engine.insert(key);
engine.Engine.start();

In my case, it was acceptable to use SOCKS5 over TCP as my VPN service is configured not routing packets from my own application. No loopback is going to happen. You probably gonna want to protect your SOCKS5 connections or use an Unix Domain Socket to your local SOCKS5 server:

key.setProxy("socks5:///path/to/unix/domain/socket");

How to protect socket, thank you!

ukhack commented 1 year ago

I understand this issue is closed, but for the sake of helping out @yaem1k0:

Make sure your ANDROID_HOME, ANDROID_NDK_HOME and GOPATH are set:

$ go install golang.org/x/mobile/cmd/gomobile@latest
$ go get golang.org/x/mobile/bind
$ gomobile init
$ go install github.com/xjasonlyu/tun2socks/v2@latest
$ export DEST=$(pwd)/app/libs
$ mkdir -p DEST
$ cd $GOPATH/src/github.com/xjasonlyu/tun2socks
$ gomobile bind -o $DEST/tun2socks.aar -target android $GOPATH/src/github.com/xjasonlyu/tun2socks/engine
$ ls $DEST # you should see tun2socks.aar and tun2socks-sources.jar

Add the following to your settings.gradle:

 dependencyResolutionManagement {
     repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
     repositories {
         google()
         mavenCentral()
+        flatDir {
+            dirs 'app/libs'
+        }
     }
 }

Add the dependency to your app/build.gradle:

 dependencies {
+    implementation (name:'tun2socks', ext:'aar')

     implementation 'androidx.core:core-ktx:1.7.0'
     // omitted...
}

Execute "Sync Project with Gradle Files" action in Android Studio. Then the engine package would be added to your build path:

import engine.Engine;

See my previous reply for usage. Note that it seemed necessary to set empty values even for unused options.

On my device, dns request not through the Proxy。

Ali-Khazaee commented 1 year ago

@tabjy Default libtun2socks.so size is approx 200KB for each arch, but your AAR version size is approx 11MB for each arch

why is that ?

I did build tun2socks and yes it's size is approx 9MB

tabjy commented 1 year ago

@Ali-Khazaee

but your AAR version size is approx 11MB for each arch

an AAR includes builds for all archs

Screenshot_2023-03-13-15-18-02_4880x3040

saaam000 commented 1 year ago

How to handle UDP connections too ?

sonvirgo commented 11 months ago

In Android there is already some tun2socks app work flawless, with per app tun features. It mean loop-free with localhost 127.0.0.1 socks For example SocksDroid

bigfoxtail commented 5 months ago

I had success using gomobile bind to directly compile this project into an Android library (.aar). Therefore, sharing descriptor across processes is no longer required:

ParcelFileDescriptor tunDevice = new Builder()
    .addAddress(VPN_ADDRESS, 32)
    .addRoute(VPN_ROUTE, 0)
    .addDnsServer(VPN_DNS)
    .addAllowedApplication("com.google.android.tethering")
    .establish();

engine.Key key = new engine.Key();
key.setMark(0);
key.setMTU(0);
key.setDevice("fd://" + tunDevice.getFd()); // <--- here
key.setInterface("");
key.setLogLevel("debug");
key.setProxy("socks5://127.0.0.1:1080"); // <--- and here
key.setRestAPI("");
key.setTCPSendBufferSize("");
key.setTCPReceiveBufferSize("");
key.setTCPModerateReceiveBuffer(false);

engine.Engine.insert(key);
engine.Engine.start();

In my case, it was acceptable to use SOCKS5 over TCP as my VPN service is configured not routing packets from my own application. No loopback is going to happen. You probably gonna want to protect your SOCKS5 connections or use an Unix Domain Socket to your local SOCKS5 server:

key.setProxy("socks5:///path/to/unix/domain/socket");

How can I use engine.Engine.start(); engine.Engine.stop(); in an Android VPN application to start and stop tun2socks? Sorry, I'm a beginner and not quite sure. Thanks😀

ys1231 commented 1 month ago

Develop according to the above, the log shows connect: connection refused ,I need help Trying to use other proxy software to connect is successful and no password is required.

image image
anasfanani commented 3 weeks ago

This is not for file descriptor, while read documentation and click on Android section is show me this issue.

Use tun2socks all internet except dns with root.

# id
uid=0(root) gid=0(root) groups=0(root) context=u:r:magisk:s0

Create interface

ip tuntap add mode tun dev tun0
ip addr add 198.18.0.1/15 dev tun0
ip link set dev tun0 up

Socks server: 72.210.221.197:4145. Create iptables rule

iptables -t mangle -N TUNSOCKS 2>/dev/null
iptables -t mangle -F TUNSOCKS
iptables -t mangle -I OUTPUT -j TUNSOCKS
iptables -t mangle -I TUNSOCKS -p tcp -d 72.210.221.197 --dport 4145 -j RETURN
# iptables -t mangle -I TUNSOCKS -m owner --uid-owner "root" --gid-owner "net_bt_admin" -j RETURN
iptables -t mangle -I TUNSOCKS -p udp --dport 53 -j RETURN
iptables -t mangle -A TUNSOCKS -j MARK --set-mark 1337
ip route add default dev tun0 table 21 metric 1
ip rule add fwmark 1337 lookup 21 pref 10

Run program

./tun2socks-linux-arm64 -device tun0 -proxy socks5://72.210.221.197:4145 -loglevel debug 

Revert back / delete iptables route

# del route
iptables -t mangle -F TUNSOCKS
iptables -t mangle -D OUTPUT -j TUNSOCKS
iptables -t mangle -X TUNSOCKS
ip route del default dev tun0 table 21 metric 1
ip rule del fwmark 1337 lookup 21 pref 10
# del interface
ip addr del 198.18.0.1/15 dev tun0
ip link set dev tun0 down
ip tuntap del mode tun dev tun0

If the server running local, run server program with

busybox setuidgid "root:net_bt_admin" ./socks-server

Use this to bypass server traffict

iptables -t mangle -I TUNSOCKS -m owner --uid-owner "root" --gid-owner "net_bt_admin" -j RETURN
misa3l commented 3 weeks ago

Is there a way to get the Tx and Rx of the connection established with the Socks5 server? Is there a method to obtain these connection statistics?

xjasonlyu commented 3 weeks ago

yea, you can use the rest api in tun2socks