Брандмауэр Android с VpnService

Я пытаюсь реализовать простой брандмауэр для Android с проектом VpnService для BS. Я выбираю VpnService, потому что он будет работать с ненарушенными устройствами. Он будет регистрировать подключения и позволяет фильтровать соединение. (На основе IP)

Существует приложение, делающее это, так что это возможно.

Магазин приложений Google Play

Я провел некоторое исследование и обнаружил, что VpnService создает интерфейс Tun. Больше ничего. (Нет реализации VPN только туннеля). Это позволяет вам указать адрес этого интерфейса и добавить маршруты. Он возвращает дескриптор файла. Вы можете читать исходящие пакеты и записывать входящие пакеты.

Я создал производный class VpnService, и я начал службу. Я могу настроить tun0 с помощью classа VpnService.Builder. Когда я смотрю на соединение mobiwol's с adb shell netcfg он создает интерфейс tun0 с адресом 10.2.3.4/32. Он направляет все пакеты в эту частную сеть и отправляет в Интернет. Я пытаюсь сделать то же самое. Создал интерфейс с адресом 10.0.0.2/32. Добавлен маршрут с функцией addRoute. 0.0.0.0/0, поэтому я могу захватить все пакеты из всей сети, насколько я понимаю. (Я довольно новичок в этом вопросе и до сих пор учился. Я нашел fragmentы через Интернет, поэтому я не уверен. Исправьте меня, если я ошибаюсь.)

Я создал 2 streamа в сервисе. Один читается из дескриптора файла и записывает его в 127.0.0.1 с защищенным сокетом. (Я не уверен, что мне следует читать / писать до 127.0.0.1. Может быть, это и есть проблема.)

Я проанализировал пакеты, которые я прочитал из дескриптора файла. Например:

 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 

В остальных данных я не нашел другого IP-заголовка. Я думаю, что должна быть инкапсуляция между сетью 10.0.0.2 в локальную сеть (192.168.2.1) и интернет. Я не уверен.

Моя реальная проблема в том, что я застрял в streamе входящих пакетов. Я ничего не умею читать. Нет ответа. Как вы можете видеть на снимке экрана нет входящих данных:

Скриншот

Я пытаюсь читать из того же соединения, которое я использую для записи в 127.0.0.1 с защищенным сокетом.

Android Интерфейс туннеля (tun0) Подключение к Интернету

Все пакеты 10.0.0.2 127.0.0.1? 192.168.2.1 Интернет?

Я не мог найти ничего полезного в VpnService. (Пример ToyVPN просто бесполезен) Я читал документы о Linux Tun / Tap, но о туннелировании между хостом и удаленным. Я хочу, чтобы хост и удаленный доступ на одном устройстве. Не похоже на туннелирование.

Как я могу это сделать?

Изменить: запрошенный код. Это на очень ранней стадии. Как я уже говорил, это производный class VpnService. 2 streamа (чтение и запись), созданных в streamе службы.

 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 > 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()); } } 

Аналогичный вопрос был задан несколько месяцев назад , и хотя ответы там не очень проницательны, комментарии в принятом ответе дают некоторое представление о том, что может произойти неправильно.

Вы должны иметь в виду, какой слой в модели OSI находится в вашей логике:

  • Входящие и исходящие streamи VpnService находятся в сетевом уровне; вы получаете (и должны, в свою очередь, передавать) необработанные IP-пакеты, как вы описали в своем вопросе.

    Вы можете видеть, что входящий stream байтов является дейтаграммой IPv4, поскольку первые четыре бита – 0100 (4). Проконсультируйтесь с этой спецификацией структуры пакетов для получения подробной информации о IPv4.

  • При пересылке запросов вы находитесь в прикладном уровне; вы должны передавать содержимое полезной нагрузки UDP или TCP (то есть только их данные, а не сами заголовки), используя соответственно DatagramSocket или Socket.

    Имейте в виду, что это пропускает транспортный уровень, поскольку эти реализации заботятся о построении UDP-заголовка (в случае DatagramSocket) и заголовка и опций TCP (в случае Socket).

Ваше приложение по существу должно уметь интерпретировать и создавать заголовки и параметры IPv4 и IPv6, а также в качестве полезной нагрузки IP, заголовки UDP и заголовки и опции TCP.

Может быть, лучше искать проекты с открытым исходным кодом, такие как OpenVpn . Он работает на уровне API 14+ (Ice Cream Sandwhich) без Root Access.

  • как скачать изображение с любой веб-страницы в java
  • Исходный ресурс Android не найден?
  • Изменение цвета фона отдельных элементов меню навигации
  • Как вы реализуете FileObserver из службы Android
  • Есть ли способ разбивки запросов путем комбинирования курсоров запросов с использованием FirestoreRecyclerAdapter?
  • Как отсортировать ArrayList в Java в порядке убывания?
  • Java: индекс массива из исключения исключений
  • Почему константы массива могут использоваться только в инициализаторах?
  • Как получить текущее местоположение в Android
  • создание Hashmap из строки JSON
  • Android: Dex не может анализировать код байта версии 52
  • Давайте будем гением компьютера.