0

I am creating a VPN Local Service on Android studio as my Thesis project for my university. Specifically, i have the main class on my Java File which is VPNLocalService extends Service, in that class i have another one VpnRunnable implements Runnable. In that class I check if the network packets are TCP or UDP and forward them accordingly.

When I check the packets, I want to display a Dialog with a message when the packet has a local address as a destination. In the yellow underline is the code to display the dialog

Im sending the code snipend to get an understanding(I removed some code from the methods that are not necessary for this to make it smaller)

public class LocalVPNService extends VpnService
{
    private static final String TAG = LocalVPNService.class.getSimpleName();
    private static final String VPN_ADDRESS = "10.0.0.2"; // Only IPv4 support for now
    private static final String VPN_ROUTE = "0.0.0.0"; // Intercept everything

    public static final String BROADCAST_VPN_STATE = "xyz.hexene.localvpn.VPN_STATE";

    private static boolean isRunning = false;

    private ParcelFileDescriptor vpnInterface = null;

    private PendingIntent pendingIntent;

    private ConcurrentLinkedQueue<Packet> deviceToNetworkUDPQueue;
    private ConcurrentLinkedQueue<Packet> deviceToNetworkTCPQueue;
    private ConcurrentLinkedQueue<ByteBuffer> networkToDeviceQueue;
    private ExecutorService executorService;

    private Selector udpSelector;
    private Selector tcpSelector;

    @Override
    public void onCreate()
    {
        super.onCreate();
        isRunning = true;



        setupVPN();
        try
        {
            udpSelector = Selector.open();
            tcpSelector = Selector.open();
            deviceToNetworkUDPQueue = new ConcurrentLinkedQueue<>();
            deviceToNetworkTCPQueue = new ConcurrentLinkedQueue<>();
            networkToDeviceQueue = new ConcurrentLinkedQueue<>();

            executorService = Executors.newFixedThreadPool(5);
            executorService.submit(new UDPInput(networkToDeviceQueue, udpSelector));
            executorService.submit(new UDPOutput(deviceToNetworkUDPQueue, udpSelector, this));
            executorService.submit(new TCPInput(networkToDeviceQueue, tcpSelector));
            executorService.submit(new TCPOutput(deviceToNetworkTCPQueue, networkToDeviceQueue, tcpSelector, this));
            executorService.submit(new VPNRunnable(vpnInterface.getFileDescriptor(),
                    deviceToNetworkUDPQueue, deviceToNetworkTCPQueue, networkToDeviceQueue));
            LocalBroadcastManager.getInstance(this).sendBroadcast(new Intent(BROADCAST_VPN_STATE).putExtra("running", true));
            Log.i(TAG, "Started");
        }
        catch (IOException e)
        {
            // TODO: Here and elsewhere, we should explicitly notify the user of any errors
            // and suggest that they stop the service, since we can't do it ourselves
            Log.e(TAG, "Error starting service", e);
            cleanup();
        }
    }

    private void setupVPN()
    {
        if (vpnInterface == null)
        {
            Builder builder = new Builder();
            builder.addAddress(VPN_ADDRESS, 32);
            //builder.addRoute(VPN_ROUTE, 0);

            builder.addRoute("10.0.0.0", 8);
            builder.addRoute("172.16.0.0", 12);
            builder.addRoute("192.168.0.0", 16);

            vpnInterface = builder.setSession(getString(R.string.app_name)).setConfigureIntent(pendingIntent).establish();
        }
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId)
    {
        return START_STICKY;
    }

    public static boolean isRunning()
    {
    }

    @Override
    public void onDestroy()
    {
    }

    @SuppressLint("NewApi")
    private void cleanup()
    {    }

    // TODO: Move this to a "utils" class for reuse
    private static void closeResources(Closeable... resources)
    {}

    private class VPNRunnable implements Runnable
    {
        ConnectivityManager connectivitymanager = (ConnectivityManager)getSystemService(Context.CONNECTIVITY_SERVICE);
        //PackageManager packageManager = Context.getPackageManager();

        PackageManager packageManager = getPackageManager();
        private final String TAG = VPNRunnable.class.getSimpleName();

        private FileDescriptor vpnFileDescriptor;

        private ConcurrentLinkedQueue<Packet> deviceToNetworkUDPQueue;
        private ConcurrentLinkedQueue<Packet> deviceToNetworkTCPQueue;
        private ConcurrentLinkedQueue<ByteBuffer> networkToDeviceQueue;

        public VPNRunnable(FileDescriptor vpnFileDescriptor,
                           ConcurrentLinkedQueue<Packet> deviceToNetworkUDPQueue,
                           ConcurrentLinkedQueue<Packet> deviceToNetworkTCPQueue,
                           ConcurrentLinkedQueue<ByteBuffer> networkToDeviceQueue)
        {
            this.vpnFileDescriptor = vpnFileDescriptor;
            this.deviceToNetworkUDPQueue = deviceToNetworkUDPQueue;
            this.deviceToNetworkTCPQueue = deviceToNetworkTCPQueue;
            this.networkToDeviceQueue = networkToDeviceQueue;
        }

        @SuppressLint("NewApi")
        @Override
        public void run()
        {
            Log.i(TAG, "Started");

            int uid;
            int isSamePort = 0;
            //List<Integer> ownerUIDs = new ArrayList<Integer>();

            Map<Integer, String> uidToNameMap = new HashMap<Integer, String>();

            String packageName;

            FileChannel vpnInput = new FileInputStream(vpnFileDescriptor).getChannel();
            FileChannel vpnOutput = new FileOutputStream(vpnFileDescriptor).getChannel();

            try
            {
                ByteBuffer bufferToNetwork = null;
                boolean dataSent = true;
                boolean dataReceived;
                while (!Thread.interrupted())
                {
                    if (dataSent)
                        bufferToNetwork = ByteBufferPool.acquire();
                    else
                        bufferToNetwork.clear();

                    // TODO: Block when not connected
                    int readBytes = vpnInput.read(bufferToNetwork);
                    if (readBytes > 0)
                    {
                        dataSent = true;
                        bufferToNetwork.flip();
                        Packet packet = new Packet(bufferToNetwork);
                        if (packet.isUDP())
                        {
                            uid = connectivitymanager.getConnectionOwnerUid (IPPROTO_UDP,new InetSocketAddress(packet.ip4Header.sourceAddress.getHostAddress(), packet.udpHeader.sourcePort), new InetSocketAddress(packet.ip4Header.destinationAddress.getHostAddress(), packet.udpHeader.destinationPort));


                            if(!uidToNameMap.containsKey(uid) && packageManager.getNameForUid(uid) != null){
                                Log.w("Conne", "Im inside the if statement");
                                //ownerUIDs.add(uid);
                                packageName = packageManager.getNameForUid(uid);


                                uidToNameMap.put(uid, packageName);

                                //An intent is used in order to display the dialog for informing the user that an app tries to
                                //access the local network

                                Intent dialogIntent = new Intent(LocalVPNService.this, NetworkAccessDialog.class);
                                dialogIntent.putExtra("packageName", packageName);
                                dialogIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); // You need this flag to start an Activity from a Service
                                startActivity(dialogIntent);


                                //Log.w("Connection","UIDS: " + Integer.toString(uid) + " Package name" + packageName);
                                Log.w("connection", "ATTENTION!: " + packageName + " tries to access local network");

                            }



                            //Log.w("Ip packets", "\n\nIPV4 UDP PACKET:   " + packet.ip4Header.destinationAddress.getHostAddress() + "\n\n");
                            deviceToNetworkUDPQueue.offer(packet);
                        }
                        else if (packet.isTCP())
                        {
                            uid = connectivitymanager.getConnectionOwnerUid (IPPROTO_TCP,new InetSocketAddress(packet.ip4Header.sourceAddress.getHostAddress(), packet.tcpHeader.sourcePort), new InetSocketAddress(packet.ip4Header.destinationAddress.getHostAddress(), packet.tcpHeader.destinationPort));


                            //i hold all the uids-names of the apps that send traffic
                            if(!uidToNameMap.containsKey(uid) && packageManager.getNameForUid(uid) != null){
                                //Log.w("Conne", "Im inside the if statement");
                                //ownerUIDs.add(uid);
                                packageName = packageManager.getNameForUid(uid);

                                uidToNameMap.put(uid, packageName);

                                Intent dialogIntent = new Intent(LocalVPNService.this, NetworkAccessDialog.class);
                                dialogIntent.putExtra("packageName", packageName);
                                dialogIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); // You need this flag to start an Activity from a Service
                                startActivity(dialogIntent);



                                Log.w("connection", "ATTENTION!: " + packageName + " tries to access local network");

                            }
                            //Log.w("Ip packets", "\n\nIPV4 TCP PACKET:   " + packet.ip4Header.destinationAddress.getHostAddress() + "\n\n");
                            deviceToNetworkTCPQueue.offer(packet);
                        }
                        else
                        {
                            Log.w(TAG, "Unknown packet type");
                            Log.w(TAG, packet.ip4Header.toString());
                            dataSent = false;
                        }
                    }
                    else
                    {
                        dataSent = false;
                    }

                    ByteBuffer bufferFromNetwork = networkToDeviceQueue.poll();
                    if (bufferFromNetwork != null)
                    {
                        bufferFromNetwork.flip();
                        while (bufferFromNetwork.hasRemaining())
                            vpnOutput.write(bufferFromNetwork);
                        dataReceived = true;

                        ByteBufferPool.release(bufferFromNetwork);
                    }
                    else
                    {
                        dataReceived = false;
                    }

                    // TODO: Sleep-looping is not very battery-friendly, consider blocking instead
                    // Confirm if throughput with ConcurrentQueue is really higher compared to BlockingQueue
                    if (!dataSent && !dataReceived)
                        Thread.sleep(10);
                }
            }
            catch (InterruptedException e)
            {
                Log.i(TAG, "Stopping");
            }
            catch (IOException e)
            {
                Log.w(TAG, e.toString(), e);
            }
            finally
            {
                closeResources(vpnInput, vpnOutput);
            }
        }
    }
}

I read that since i want to display from a Service i need to create an Activity to be displayed

This is the activity i created for the dialog

I also made sure the activity is reffered on the manifest file

Like this on the manifest file

However, whatever i try, the dialog is not displayed and i get no errors. For some reason that i cannot find, the Activity is not reached iven though i "Call" it in my from the service as shown in the first image.

Is it wrong to choose dialog for this? I read somewhere that notifications hould be used with services but im not sure and dialog is what i want as a UI

I need your help, I hope my explanation is clear enough and understandable.

I thank you all very much in advance for any answers that will help me solve this

1 Answer 1

1
  1. Check below line is reachable and giving logs, startActivity(...) should be called:

Log.w("connection", "ATTENTION!: " + packageName + " tries to access local network");

  1. Dialog is only visible when you create in activity or fragment

I will try to test your codes later, I will let you know

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.