Paul Lammertsma Paul Lammertsma - 2 months ago 23
Android Question

Protect a socket in VpnService

I'm exploring the capabilities of Android's VpnService. Presently, I've built a very rudimentary request forwarder by essentially rebuilding the IP stack in user space: I read IP packets from the VpnService's input stream, parse them, and for connections I don't want to forward, I attempt to recreate those socket connections outside the VPN connection.

I've understood that this last bit is facilitated by

VpnService.protect()
and have tried implementing it as follows:

Socket socket = new Socket();
vpnService.protect(socket);
socket.connect(new InetSocketAddress(
header.getDestinationAddress(), // From my IP datagram header
body.getDestinationPort())); // From the TCP datagram header


Unfortunately, this approach is causing a loopback into the VPN interface.

Whereas the above code will simply block and eventually time out, I observe the loopback by calling
Socket.connect(InetSocketAddress)
from a separate thread; the connection comes straight back into my VpnService's input stream and the process repeats.

Needless to say, this causes a loop. I get the feeling that the reason for this is that at the time of socket creation (and subsequently, the call to
VpnService.protect(Socket)
), I haven't set the destination IP & port yet.

This seems to indeed be the case, as the by overriding
VpnService.protect(Socket)
and
VpnService.protect(int)
in my VpnService implementation and calling the supers in both cases returns false.

How can I properly protect a socket connection?

Answer

The following code works.

Socket socket = SocketChannel.open().socket();
if ((null != socket) && (null != vpnService)) {
    vpnService.protect(socket);
}
socket.connect(...);

new Socket() doesn't have a valid file descriptor, so it cannot be protected.

Comments