I'm trying to send packets via a VPN out of the VPN onto the proper hardware without any real VPN server used, so I can log the packets being sent through.
I'm able to get an InetAddress
for the wlan0
interface I want the packet to actually go to, but I'm not too sure if that's the right place at all (it shows my current IP address).
I then use a DatagramChannel
(called socket
and the IntetAddress
is uplink
) on it:
socket.connect(new InetSocketAddress(uplink, 0));
And write packets to it:
socket.write(packet);
But nothing sticks, I just get
java.net.SocketException: sendto failed: EINVAL (Invalid argument)
I'm trying to do something similar in creating a firewall/filtering application for Android. I'm in the middle of this, so take what I say with the appropriate sized grain of salt. :-)
The trouble with your/my situation is that you're taking packets off the virtual network interface given to you by VpnService, but then you're taking those packets and writing them out with a socket. A socket is intended to handle the transfer of application payload between client and server, not packets.
The socket will take any data you hand it, and wrap that data within a packet of its own creation (TCP if using Socket, UDP if using DatagramSocket as you are). In your case, the data you are handing the socket is itself a packet, and thus you end up with a packet within a packet (likely a TCP packet inside a UDP packet).
When the wrapped packet arrives at the server for your socket, the network interface and ServerSocket on that end will unwrap the payload and find that it is another packet. Probably not going to work because whatever is reading from the server-side socket (e.g. web server) is expecting application payload (e.g. HTTP headers/etc.).
Now, when you have a real VPN tunnel, the server-side of that tunnel is probably pulling your 'wrapped packet' payload out of the UDP packet it receives and is then handing that packet directly to a network interface that can interpret the packet itself.
Without this real VPN tunnel, your VpnService impl essentially has to become a virtual network interface itself, handling the TCP/UDP/etc. protocol between the virtual network interface and your code. Basically, packets read from your VPN interface have to be treated as an application data stream (packets collated and reassembled) before writing to your outgoing socket. Then, you have to somehow acknowledge the packets you just consumed from the interface. Then, you have to take incoming data from your Socket (which is a payload data stream), and break it up into packets that you can then send back to the output stream of your VPN interface. Finally, you need to handle acknowledgement traffic your virtual VPN interface will send in response to the packets you send it. This is not trivial to do.
I really hope I'm wrong about all this, and someone has a simple 'virtual network interface' written in Java that could be used to take the place of the real VPN tunnel. I haven't been able to find it.
You can use NetworkInterface APIs to get wlan0 address programmatically.
I'm also trying to do similar thing.. I'm able to see packets at virtual interface.. But I'm not able to send packet via local interface..
I'm able to connect to wlan0 with DatagramChannel, but connection to outside server from wlan0 is stuck at SYN_SEND..
You can try a higher port. This works for me:
InetSocketAddress(uplink, 3022)
I do not know how to make sure the port is not in use.
How did you get the address of the wlan0?
I used adb shell ifconfig and pasted the address.