- mongodb - 在 MongoDB mapreduce 中,如何展平值对象?
- javascript - 对象传播与 Object.assign
- html - 输入类型 ="submit"Vs 按钮标签它们可以互换吗?
- sql - 使用 MongoDB 而不是 MS SQL Server 的优缺点
我正在尝试使用 VpnService for BS 项目为 android 实现一个简单的防火墙。我选择 VpnService 是因为它将在非 root 设备上运行。它将记录连接并让您过滤连接。 (基于IP)
有一个应用程序这样做是可能的。
我做了一些研究,发现 VpnService 创建了一个 Tun 接口(interface)。而已。 (没有 VPN 实现只是一个隧道)它可以让你给这个接口(interface)一个地址并添加路由。它返回一个文件描述符。您可以读取传出包和写入传入包。
我创建了一个 VpnService 派生类并启动了服务。我可以用 VpnService.Builder 类配置 tun0
。当我查看 mobiwol's
与 adb 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)和互联网之间进行封装。我不确定。
我真正的问题是我卡在传入的包线程上。我什么都读不了。没有反应。正如您在屏幕截图中看到的,没有传入数据:
我正在尝试从用于写入 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/
我想使用 li 和 ul 制作一个多级下拉列表,以便显示我博客中按年和月排序的所有文章。我希望我的下拉菜单看起来像 Google Blogspot 下拉菜单: 这是我的 CSS 和 HTML 代码 u
我在 Win 7 64 机器上将 CodeBlocks 与 gcc 4.7.2 和 gmp 5.0.5 结合使用。开始使用 gmpxx 后,我看到一个奇怪的段错误,它不会出现在 +、- 等运算符中,但
我正在使用 tern 为使用 CodeMirror 运行的窗口提供一些增强的智能感知,它工作正常,但我遇到了一个问题,我想添加一些自定义“types”,可以这么说,这样下拉列表中它们旁边就有图标了。我
我正在尝试让我的 PC 成为 Android 2.3.4 设备的 USB 主机,以便能够在不需要实际“附件”的情况下开发 API。为此,我需要将 PC 设置为 USB 主机和“设备”(在我的例子中是运
很难说出这里要问什么。这个问题模棱两可、含糊不清、不完整、过于宽泛或夸夸其谈,无法以目前的形式得到合理的回答。如需帮助澄清此问题以便重新打开,visit the help center . 关闭 9
我在设置服务器方面几乎是个新手,但遇到了一个问题。我有一个 Ubuntu 16.04 VPS 并安装了 Apache2 和 Tomcat7。我正在为 SSL 使用 LetsEncrypt 和 Cert
我在一个基于谷歌地图的项目上工作了超过 6 个月。我使用的是 Google Maps API V1 及其开发人员 API key 。当我尝试发布应用程序时,我了解到 Google API V1 已被弃
我是 Python 的新手,所以如果我对一些简单的事情感到困惑,请原谅。 我有一个这样的对象: class myObject(object): def __init__(self):
这个问题已经有答案了: How can I access object properties containing special characters? (2 个回答) 已关闭 9 年前。 我正在尝
我有下面的 CSS。我想要的是一种流体/液体(因为缺乏正确的术语)css。我正在为移动设备开发,当我改变模式时 从纵向 View 到陆地 View ,我希望它流畅。现在的图像 在陆地 View 中效
我正在尝试使用可以接受参数的缓存属性装饰器。 我查看了这个实现:http://www.daniweb.com/software-development/python/code/217241/a-cac
这个问题在这里已经有了答案: Understanding slicing (36 个答案) 关闭 6 年前。 以a = [1,2,3,4,5]为例。根据我的直觉,我认为 a[::-1] 与 a[0:
mysqldump -t -u root -p mytestdb mytable --where=datetime LIKE '2014-09%' 这就是我正在做的事情,它会返回: mysqldum
我正在制作销售税计算器,除了总支付金额部分外,其他一切都正常。在我的程序中,我希望能够输入一个数字并获得该项目的税额我还希望能够获得支付的总金额,包括交易中的税金。到目前为止,我编写的代码完成了所有这
关闭。这个问题不符合Stack Overflow guidelines .它目前不接受答案。 我们不允许在 Stack Overflow 上提出有关通用计算硬件和软件的问题。您可以编辑问题,使其成为
我是否必须进行任何额外的设置才能让 apache-airflow 在任务失败时向我发送电子邮件。我的配置文件中有以下内容(与默认值保持不变): [email] email_backend = airf
这个问题在这里已经有了答案: What does the $ symbol do in VBA? (5 个回答) 3年前关闭。 使用返回字符串(如 Left)的内置函数有什么区别吗?或使用与 $ 相同
我有一个用VB6编写的应用程序,我需要使用一个用.NET编写的库。有什么方法可以在我的应用程序上使用该库吗? 谢谢 最佳答案 这取决于。您可以控制.NET库吗? 如果是这样,则可以修改您的库,以便可以
当我创建一个以 ^ 开头的类方法时,我尝试调用它,它给了我一个错误。 class C { method ^test () { "Hi" } } dd C.new.test; Too m
我已经使用 bower 安装了 angularjs 和 materialjs。 凉亭安装 Angular Material 并将“ngMaterial”注入(inject)我的应用程序,但出现此错误。
我是一名优秀的程序员,十分优秀!