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