How to use file descriptor in Android?
marco20240618 opened this issue Β· 16 comments
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.
- 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();
- 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);
- 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
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");
it worked. thanks. great project.
@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.
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.
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!
I understand this issue is closed, but for the sake of helping out @yaem1k0:
Make sure your
ANDROID_HOME
,ANDROID_NDK_HOME
andGOPATH
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.jarAdd 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γ
@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
but your AAR version size is approx 11MB for each arch
an AAR includes builds for all archs
How to handle UDP connections too ?
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
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π
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
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?
yea, you can use the rest api in tun2socks