gpt4 book ai didi

java - 带有 VpnService 的 Android 防火墙

转载 作者:IT老高 更新时间:2023-10-28 21:09:08 26 4
gpt4 key购买 nike

我正在尝试使用 VpnService for BS 项目为 android 实现一个简单的防火墙。我选择 VpnService 是因为它将在非 root 设备上运行。它将记录连接并让您过滤连接。 (基于IP)

有一个应用程序这样做是可能的。

Google play app store

我做了一些研究,发现 VpnService 创建了一个 Tun 接口(interface)。而已。 (没有 VPN 实现只是一个隧道)它可以让你给这个接口(interface)一个地址并添加路由。它返回一个文件描述符。您可以读取传出包和写入传入包。

我创建了一个 VpnService 派生类并启动了服务。我可以用 VpnService.Builder 类配置 tun0 。当我查看 mobiwol'sadb shell netcfg 的连接时,它会创建一个具有 10.2.3.4/32 地址的 tun0 接口(interface)。它将所有包裹路由到这个专用网络并发送到互联网。我也在尝试同样的方法。创建了一个地址为 10.0.0.2/32 的接口(interface)。添加了带有 addRoute 功能的路线。 0.0.0.0/0 所以据我所知,我可以从所有网络捕获所有包。 (我对这个主题还很陌生,还在学习。我在网上找到了一些 fragment ,所以我不太确定。如果我错了,请纠正我。)

我在服务中创建了 2 个线程。一个从文件描述符中读取并使用 protected 套接字将其写入 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 header 。我认为应该在 10.0.0.2 网络到本地网络(192.168.2.1)和互联网之间进行封装。我不确定。

我真正的问题是我卡在传入的包线程上。我什么都读不了。没有反应。正如您在屏幕截图中看到的,没有传入数据:

screenshot

我正在尝试从用于写入 127.0.0.1 的同一个连接中读取数据,并使用 protected 套接字。

Android <-> Tun 接口(interface) (tun0) <-> 互联网连接

所有包<-> 10.0.0.2 <-> 127.0.0.1? <-> 192.168.2.1 <-> 互联网?

我找不到任何关于 VpnService 的有用信息。 (ToyVPN 的例子没用)我阅读了关于 Linux Tun/Tap 的文档,但它是关于主机和远程之间的隧道的。我希望主机和远程在同一设备上。不像隧道。

我该怎么做?

编辑:请求的代码。它处于非常早期的阶段。正如我之前提到的,它是一个 VpnService 派生类。在服务线程中创建了 2 个线程(读取和写入)。

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

}

}

最佳答案

A similar question was asked a few months ago ,虽然那里的答案不是很有见地,但接受的答案中的评论可以让您深入了解可能出现的问题。

您应该记住 the OSI model 中的哪一层你的逻辑是:

  • VpnService的传入和传出流在网络层;正如您在问题中描述的那样,您正在接收(并且应该反过来传输)原始 IP 数据包。

    在您的示例字节流中,您可以看到传入的字节流是 IPv4 数据报,因为前四位是 0100 (4)。咨询this packet structure specification有关 IPv4 的详细信息。

  • 转发请求时,你在应用层;您应该分别使用 DatagramSocket 或 Socket 传输 UDP 或 TCP 有效负载的内容(即仅它们的数据,而不是 header 本身)。

    请记住,这会跳过传输层,因为这些实现负责构建 UDP header (在 DatagramSocket 的情况下)以及 TCP header 和选项(在 Socket 的情况下)。

您的应用程序本质上需要能够解释和构造 IPv4 和 IPv6 header 和选项,以及作为 IP 有效负载的 UDP header 和 TCP header 和选项。

关于java - 带有 VpnService 的 Android 防火墙,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20237743/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com