A firewall for Android with VpnService. Responses are delivered, but a SocketTimeoutException is thrown

Maksim Dmitriev

I am implementing a simple firewall for Android using VpnService. My app is similar to ToyVpnService, but it doesn't send raw IP packets to a remote VPN server which would forward them to their destinations.

My implementation is here: https://bitbucket.org/MaksimDmitriev/norootfirewall/src/006f7c33cd1cd4055f372ed3a88664fe2a4be3dd/src/com/norootfw/NoRootFwService.java?at=unix

Can I do all this forwarding routine locally? That's what I'm trying to implement.

I initialize a TUN device and its file descriptors:

mInterface = new Builder().setSession(getString(R.string.app_name))
                .addAddress("10.0.2.1", 24)
                .addRoute("0.0.0.0", 1)
                .addRoute("128.0.0.0", 1)
                .establish();

in = new FileInputStream(mInterface.getFileDescriptor());
out = new FileOutputStream(mInterface.getFileDescriptor());

I assign 0.0.0.0/1 and 128.0.0.0/1 to the TUN device to make it more preferable than the default route with 0.0.0.0/0. I used 0.0.0.0/0 and ran into the same exception which is below.

And here is a sample UDP request.

1). I read an IP packet from the TUN device.

05-06 00:46:52.749: D/UDPChecksum(31077): Sent == [69, 0, 0, 36, 0, 0, 64, 0, 64, 17, 108, 91, 10, 0, 2, 1, -64, -88, 1, -59, -53, 1, -50, -87, 0, 16, 89, -114, 85, 68, 80, 95, 68, 65, 84, 65]

Please consider the IPv4 packet structure here. For example, the first number 69 (0100 0101 in binary) means that the version of the IP protocol is 4 (4 high-order bits). And the 4 low-order bits stand for the Internet Header Length (IHL) in 32-bit words.

2). Then a create a protected DatagramSocket and send the data (without its IP and UDP headers) to the destination address I'd read from the captured IP packet.

3). I receive a response from the remote machine and want to send it back to the app which initialized the request.

4). I swap the source and destination IP addresses and port numbers in the IP packet, calculate the IPv4 header checksum and the UDP checksum (having constructed an IPv4 pseudo header).

05-06 00:46:52.889: D/UDPChecksum(31077): mIpv4PseudoHeader == [-64, -88, 1, -59, 10, 0, 2, 1, 0, 17, 0, 14]

5). Afterwards I set the calculated checksums to the corresponding indexes of the IP packet and write the IP packet to out, the output stream of the TUN device.

05-06 00:46:52.889: D/UDPChecksum(31077): To TUN == [69, 0, 0, 34, 0, 0, 64, 0, 64, 17, 108, 93, -64, -88, 1, -59, 10, 0, 2, 1, -50, -87, -53, 1, 0, 14, -105, -72, 85, 68, 80, 95, 79, 75]

The response reaches my app. The DatagramSocket which has been blocked after calling its receive() method fills the buffer I provide.

        byte[] responseBuffer = new byte[RESPONSE_SIZE];
        try {
            mDatagramSocket.send(mDatagramPacket);
            final DatagramPacket response = new DatagramPacket(responseBuffer, responseBuffer.length);
            mDatagramSocket.receive(response);
        } catch (IOException e) {
            Log.e("NoRootFwService", "error: " + Arrays.toString(responseBuffer)); // I can see the correct response here.
            logException(e);
        }

But its socket throws an exception when the timeout is exceeded.

05-05 23:46:58.389: E/CLIENT(20553): java.net.SocketTimeoutException
05-05 23:46:58.389: E/CLIENT(20553):    at libcore.io.IoBridge.maybeThrowAfterRecvfrom(IoBridge.java:551)
05-05 23:46:58.389: E/CLIENT(20553):    at libcore.io.IoBridge.recvfrom(IoBridge.java:509)
05-05 23:46:58.389: E/CLIENT(20553):    at java.net.PlainDatagramSocketImpl.doRecv(PlainDatagramSocketImpl.java:161)
05-05 23:46:58.389: E/CLIENT(20553):    at java.net.PlainDatagramSocketImpl.receive(PlainDatagramSocketImpl.java:169)
05-05 23:46:58.389: E/CLIENT(20553):    at java.net.DatagramSocket.receive(DatagramSocket.java:250)
05-05 23:46:58.389: E/CLIENT(20553):    at socket.client.MainActivity$UdpThread.run(MainActivity.java:195)
05-05 23:46:58.389: E/CLIENT(20553): Caused by: libcore.io.ErrnoException: recvfrom failed: EAGAIN (Try again)
05-05 23:46:58.389: E/CLIENT(20553):    at libcore.io.Posix.recvfromBytes(Native Method)
05-05 23:46:58.389: E/CLIENT(20553):    at libcore.io.Posix.recvfrom(Posix.java:141)
05-05 23:46:58.389: E/CLIENT(20553):    at libcore.io.BlockGuardOs.recvfrom(BlockGuardOs.java:164)
05-05 23:46:58.389: E/CLIENT(20553):    at libcore.io.IoBridge.recvfrom(IoBridge.java:506)
05-05 23:46:58.389: E/CLIENT(20553):    ... 4 more

Everything works properly without the firewall. I read these discussions, but they weren't helpful:

Maksim Dmitriev

The point was that I used a wrong IPv4 pseudo header to compute the checksum. It contained neither the packet UDP header nor the transmitted data. Since I included the UDP header and the data, I haven't seen the exception from the original question.

enter image description here

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related

Android firewall with VpnService

java.net.SocketTimeoutException thrown only on some Android devices

Android VpnService - How to check VpnService if it was started?

Android Management API and VpnService

Android VpnService 'protect' method not working

Android VpnService with multiple addresses and routes?

Android: Delivered SMS pendingIntent

Android SocketTimeoutException reasons

cases for SocketTimeoutException in android

App crashes on SocketTimeoutException in Android

SocketTimeoutException android retrofit

Android sending email SocketTimeoutException

Xamarin Android - VpnService is blocking all apps

what is Android VpnService.Builder setBlocking

Issue about Android understanding VpnService code

Android FCM Push notification is NOT delivered

SocketTimeoutException in CodeNameOne build on Android device

Android VpnService protect socket that's stored in native code?

Android VpnService start on Device ACTION_BOOT_COMPLETED not working

Android VpnService to capture packets won't capture packets

Is Spotify Android API audio delivered in raw PCM?

Path delivered by getExternalStoragePublicDirectory does not work on Android 5.0

Retrofit SocketTimeOutException in sending multiparty or JSON data in android

Multiprocess Python but running on different terminals to separately track responses delivered in each of the codes in Visual Studio Code

ConcurrentModificationException thrown on for each in android

Android: IllegalStateException - When is it thrown?

Mock Api Responses in Android Testing

Xamarin.Android: Detect SMS in SMS Delivered Broadcast Receiver

Getting java.net.SocketTimeoutException: Connection timed out in android