Android Firewall mit VpnService
Ich versuche zu implementieren, die eine einfache firewall für android-mit VpnService für das BS-Projekt. Ich wähle VpnService, weil es das arbeiten auf nicht-gerooteten Geräten. Es werden verbindungen protokollieren und lassen Sie filter-Verbindung. (Basierend auf IP)
Es ist eine Anwendung, dies zu tun, so dass es möglich ist.
Ich Tat etwas Forschung und fand, dass VpnService schafft eine Tun-Schnittstelle. Nichts mehr. (Keine VPN-Implementierung nur ein tunnel), die Es Ihnen ermöglicht, eine Adresse zu dieser Schnittstelle und Routen hinzufügen. Es gibt einen file-Deskriptor. Lesen Sie ausgehende Pakete und schreiben Sie die eingehenden Pakete.
Erstellte ich eine VpnService-Klasse abgeleitete Klasse und ich begann service. Ich kann konfigurieren tun0
mit VpnService.Builder-Klasse. Wenn ich mir mobiwol's
Verbindung mit adb shell netcfg
es schafft eine tun0
Schnittstelle mit 10.2.3.4/32 Adresse. Es leitet alle Pakete, die zu diesem privaten Netzwerk und senden an internet. Ich versuche das gleiche. Erstellt eine Schnittstelle mit 10.0.0.2/32 Adresse. Hinzugefügt eine route mit addRoute Funktion. 0.0.0.0/0 also ich kann erfassen alle Pakete von allen Netzwerk-soweit ich das verstanden habe. (Ich bin ziemlich neu in diesem Thema und immer noch lernen. Ich fand Stücke über das internet, also bin ich nicht wirklich sicher. Korrigiert mich wenn ich falsch Liege.)
Erstellte ich 2 threads im service. Man liest von Datei-Deskriptor und schreibt es auf 127.0.0.1 mit geschützter Buchse. ( Ich bin nicht wirklich sicher, ob ich sollte Lesen/schreiben auf 127.0.0.1. Vielleicht ist das das problem. )
Habe ich analysiert Pakete, die ich Lesen aus Datei-Deskriptor. Zum Beispiel:
01000101 byte:69 //ipv4 20byte header
00000000 byte:0 //TOS
00000000 byte:0 //Total Length
00111100 byte:60 //Total Length
11111100 byte:-4 //ID
11011011 byte:-37 //ID
01000000 byte:64 //fragment
00000000 byte:0 //"
01000000 byte:64 //TTL
00000110 byte:6 //Protocol 6 -> TCP
01011110 byte:94 //Header checksum
11001111 byte:-49 //Header checksum
00001010 byte:10 //10.0.0.2
00000000 byte:0
00000000 byte:0
00000010 byte:2
10101101 byte:-83 //173.194.39.78 //google
00111110 byte:-62
00100111 byte:39
******** byte:78
10110100 byte:-76 //IP option
01100101 byte:101
00000001 byte:1
10111011 byte:-69
//20byte IP haeder
01101101 byte:109
. . //40byte data (i couldnt parse TCP header,
I think its not needed when I route this in IP layer)
. .
. .
00000110 byte:6
Ich nicht finden, alle anderen IP-header in den rest der Daten. Ich denke, es sollte eine Kapselung zwischen 10.0.0.2 Netzwerk zum lokalen Netzwerk (192.168.2.1) und internet. Ich bin mir nicht sicher.
Mein eigentliches problem ist, dass ich fest auf die eingehenden Pakete-thread. Ich kann nicht alles Lesen. Keine Antwort. Wie man sehen kann im screenshot keine eingehenden Daten:
Ich versuche zu Lesen, aus der gleichen Verbindung, die ich für das schreiben auf 127.0.0.1 mit geschützter Buchse.
Android <-> Tun-Interface (tun0) <-> Internet-Verbindung
Alle Pakete <-> 10.0.0.2 <-> 127.0.0.1? <-> 192.168.2.1 <-> Internet?
Konnte ich nicht finden, alles, was hilfreich über VpnService. (ToyVPN Beispiel ist einfach nutzlos) ich lese die Dokumente über Linux Tun/Tap aber seine über Tunnelbau zwischen host und remote. Ich will host und remote, auf demselben Gerät. Nicht wie tunneling.
Wie kann ich dies tun?
Edit: Code angefordert. Es ist in einem sehr frühen Stadium. Wie ich bereits erwähnt, ist es ein VpnService-Klasse abgeleitete Klasse. 2 threads (Lesen und schreiben) erstellt, im service-thread.
package com.git.firewall;
public class GITVpnService extends VpnService implements Handler.Callback, Runnable {
private static final String TAG = "GITVpnService";
private String mServerAddress = "127.0.0.1";
private int mServerPort = 55555;
private PendingIntent mConfigureIntent;
private Handler mHandler;
private Thread mThread;
private ParcelFileDescriptor mInterface;
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
//The handler is only used to show messages.
if (mHandler == null) {
mHandler = new Handler(this);
}
//Stop the previous session by interrupting the thread.
if (mThread != null) {
mThread.interrupt();
}
//Start a new session by creating a new thread.
mThread = new Thread(this, "VpnThread");
mThread.start();
return START_STICKY;
}
@Override
public void onDestroy() {
if (mThread != null) {
mThread.interrupt();
}
}
@Override
public boolean handleMessage(Message message) {
if (message != null) {
Toast.makeText(this, (String)message.obj, Toast.LENGTH_SHORT).show();
}
return true;
}
@Override
public synchronized void run() {
try {
Log.i(TAG, "Starting");
InetSocketAddress server = new InetSocketAddress(
mServerAddress, mServerPort);
run(server);
} catch (Exception e) {
Log.e(TAG, "Got " + e.toString());
try {
mInterface.close();
} catch (Exception e2) {
//ignore
}
Message msgObj = mHandler.obtainMessage();
msgObj.obj = "Disconnected";
mHandler.sendMessage(msgObj);
} finally {
}
}
DatagramChannel mTunnel = null;
private boolean run(InetSocketAddress server) throws Exception {
boolean connected = false;
android.os.Debug.waitForDebugger();
//Create a DatagramChannel as the VPN tunnel.
mTunnel = DatagramChannel.open();
//Protect the tunnel before connecting to avoid loopback.
if (!protect(mTunnel.socket())) {
throw new IllegalStateException("Cannot protect the tunnel");
}
//Connect to the server.
mTunnel.connect(server);
//For simplicity, we use the same thread for both reading and
//writing. Here we put the tunnel into non-blocking mode.
mTunnel.configureBlocking(false);
//Authenticate and configure the virtual network interface.
handshake();
//Now we are connected. Set the flag and show the message.
connected = true;
Message msgObj = mHandler.obtainMessage();
msgObj.obj = "Connected";
mHandler.sendMessage(msgObj);
new Thread ()
{
public void run ()
{
//Packets to be sent are queued in this input stream.
FileInputStream in = new FileInputStream(mInterface.getFileDescriptor());
//Allocate the buffer for a single packet.
ByteBuffer packet = ByteBuffer.allocate(32767);
int length;
try
{
while (true)
{
while ((length = in.read(packet.array())) > 0) {
//Write the outgoing packet to the tunnel.
packet.limit(length);
debugPacket(packet); //Packet size, Protocol, source, destination
mTunnel.write(packet);
packet.clear();
}
}
}
catch (IOException e)
{
e.printStackTrace();
}
}
}.start();
new Thread ()
{
public void run ()
{
DatagramChannel tunnel = mTunnel;
//Allocate the buffer for a single packet.
ByteBuffer packet = ByteBuffer.allocate(8096);
//Packets received need to be written to this output stream.
FileOutputStream out = new FileOutputStream(mInterface.getFileDescriptor());
while (true)
{
try
{
//Read the incoming packet from the tunnel.
int length;
while ((length = tunnel.read(packet)) > 0)
{
//Write the incoming packet to the output stream.
out.write(packet.array(), 0, length);
packet.clear();
}
}
catch (IOException ioe)
{
ioe.printStackTrace();
}
}
}
}.start();
return connected;
}
private void handshake() throws Exception {
if (mInterface == null)
{
Builder builder = new Builder();
builder.setMtu(1500);
builder.addAddress("10.0.0.2",32);
builder.addRoute("0.0.0.0", 0);
//builder.addRoute("192.168.2.0",24);
//builder.addDnsServer("8.8.8.8");
//Close the old interface since the parameters have been changed.
try {
mInterface.close();
} catch (Exception e) {
//ignore
}
//Create a new interface using the builder and save the parameters.
mInterface = builder.setSession("GIT VPN")
.setConfigureIntent(mConfigureIntent)
.establish();
}
}
private void debugPacket(ByteBuffer packet)
{
/*
for(int i = 0; i < length; ++i)
{
byte buffer = packet.get();
Log.d(TAG, "byte:"+buffer);
}*/
int buffer = packet.get();
int version;
int headerlength;
version = buffer >> 4;
headerlength = buffer & 0x0F;
headerlength *= 4;
Log.d(TAG, "IP Version:"+version);
Log.d(TAG, "Header Length:"+headerlength);
String status = "";
status += "Header Length:"+headerlength;
buffer = packet.get(); //DSCP + EN
buffer = packet.getChar(); //Total Length
Log.d(TAG, "Total Length:"+buffer);
buffer = packet.getChar(); //Identification
buffer = packet.getChar(); //Flags + Fragment Offset
buffer = packet.get(); //Time to Live
buffer = packet.get(); //Protocol
Log.d(TAG, "Protocol:"+buffer);
status += " Protocol:"+buffer;
buffer = packet.getChar(); //Header checksum
String sourceIP = "";
buffer = packet.get(); //Source IP 1st Octet
sourceIP += buffer;
sourceIP += ".";
buffer = packet.get(); //Source IP 2nd Octet
sourceIP += buffer;
sourceIP += ".";
buffer = packet.get(); //Source IP 3rd Octet
sourceIP += buffer;
sourceIP += ".";
buffer = packet.get(); //Source IP 4th Octet
sourceIP += buffer;
Log.d(TAG, "Source IP:"+sourceIP);
status += " Source IP:"+sourceIP;
String destIP = "";
buffer = packet.get(); //Destination IP 1st Octet
destIP += buffer;
destIP += ".";
buffer = packet.get(); //Destination IP 2nd Octet
destIP += buffer;
destIP += ".";
buffer = packet.get(); //Destination IP 3rd Octet
destIP += buffer;
destIP += ".";
buffer = packet.get(); //Destination IP 4th Octet
destIP += buffer;
Log.d(TAG, "Destination IP:"+destIP);
status += " Destination IP:"+destIP;
/*
msgObj = mHandler.obtainMessage();
msgObj.obj = status;
mHandler.sendMessage(msgObj);
*/
//Log.d(TAG, "version:"+packet.getInt());
//Log.d(TAG, "version:"+packet.getInt());
//Log.d(TAG, "version:"+packet.getInt());
}
}
InformationsquelleAutor der Frage fatihdurmus | 2013-11-27
Du musst angemeldet sein, um einen Kommentar abzugeben.
Eine ähnliche Frage wurde vor ein paar Monatenund während die Antworten gibt es nicht sehr aufschlussreich, die Kommentare in der akzeptierten Antworten geben einen Einblick in das, was möglicherweise schief gehen.
Sollten Sie im Hinterkopf behalten, welche Ebene in das OSI-Modell Ihre Logik liegt:
Eingehenden und ausgehenden Ströme der VpnService sind in der Netzwerk-Schicht; Sie erhalten (und sollte wiederum übertragen werden), raw-IP-Pakete, wie Sie in Ihrer Frage beschreiben.
Probe byte-stream, kann man sehen, dass der ankommende byte-Strom ist ein IPv4-Datagramm als die ersten vier bits sind
0100
(4). Konsultieren dieses Paket-Struktur Spezifikation für details auf IPv4.Bei der Weiterleitung der Anfragen, die Sie in der application-Schicht; Sie sollten die übertragung der Inhalt des UDP-oder TCP-Nutzdaten (D. H. nur Ihre Daten, nicht die überschriften selbst) mit jeweils einem DatagramSocket oder ein Socket.
Beachten Sie, dass diese überspringt die transport-Schicht als die Implementierungen kümmern sich um den Bau der UDP-header (im Falle von DatagramSocket) und den TCP-header und Optionen (im Fall von Socket).
Ihre Anwendung im wesentlichen in der Lage sein müssen, zu interpretieren und zu konstruieren, die IPv4-und IPv6-Header und die Optionen wie die IP-Nutzlast der UDP-Header und TCP-Header und Optionen.
InformationsquelleAutor der Antwort Paul Lammertsma
Vielleicht ist es besser, sich für open-source-Projekte wie OpenVpn . Es funktioniert in der API-level 14+ (Ice Cream Sandwich) ohne Root-Zugriff .
InformationsquelleAutor der Antwort Ali