- android - RelativeLayout 背景可绘制重叠内容
- android - 如何链接 cpufeatures lib 以获取 native android 库?
- java - OnItemClickListener 不起作用,但 OnLongItemClickListener 在自定义 ListView 中起作用
- java - Android 文件转字符串
我的应用程序实现 VpnService 来拦截网络流量并提供定制的响应。目标是处理到特定地址的流量,并丢弃其他请求。
目前,我已成功解析传入请求以及构建和发送响应。然而,问题是这些响应并不是作为对原始请求的实际响应到达的;使用套接字连接进行测试会超时。
为了做出这种区分,我目前正在解析来自 VpnService 输入流的原始 IP 数据包,如下所示:
VpnService.Builder b = new VpnService.Builder();
b.addAddress("10.2.3.4", 28);
b.addRoute("0.0.0.0", 0);
b.setMtu(1500);
...
ParcelFileDescriptor vpnInterface = b.establish();
final FileInputStream in = new FileInputStream(
vpnInterface.getFileDescriptor());
final FileOutputStream out = new FileOutputStream(
vpnInterface.getFileDescriptor());
// Allocate the buffer for a single packet.
ByteBuffer packet = ByteBuffer.allocate(32767);
// We keep forwarding packets till something goes wrong.
try {
while (vpnInterface != null && vpnInterface.getFileDescriptor() != null
&& vpnInterface.getFileDescriptor().valid()) {
packet.clear();
SystemClock.sleep(10);
// Read the outgoing packet from the input stream.
final byte[] data = packet.array();
int length = in.read(data);
if (length > 0) {
packet.limit(length);
/*
1. Parse the TCP/UDP header
2. Create an own socket with the same src/dest port/ip
3. Use protect() on this socket so it not routed over tun0
4. Send the packet body (excluding the header)
5. Obtain the response
6. Add the TCP header to the response and forward it
*/
final IpDatagram ip = IpDatagram.create(packet);
...
}
}
IpDatagram 是一个类,create()
通过该类将字节数组解析为 IP 数据包的表示形式,其中包含 IP header 、选项和主体。我继续根据协议(protocol)类型解析正文的字节数组。在这种情况下,我只对具有 TCP 有效负载的 IPv4 感兴趣——我在这里也创建了 TCP header 、选项和正文的表示。
在获得 IpDatagram 实例后,我可以确定源 IP 和目标 IP(来自 IP header )和端口(来自 TCP header )。我还确认请求的 TCP 标志(如 SYN、ACK 和 PSH)和序列号。在应用程序中:
随后我构造一个新的 IpDatagram 作为响应,其中:
我将生成的 IpDatagram 转换为字节数组并将其写入 VpnServer 的输出流:
TcpDatagram tcp = new TcpDatagram(tcpHeader, tcpOptions, tcpBody);
IpDatagram ip = new Ip4Datagram(ipHeader, ipOptions, tcp);
out.write(ip.toBytes());
我的应用程序按应有的方式显示传出数据报,但是所有连接仍然超时。
这是一个十六进制的传入 TCP/IP 数据包示例:
4500003c7de04000400605f10a0203044faa5a3bb9240050858bc52b00000000a00239089a570000020405b40402080a00bfb8cb0000000001030306
以及生成的十六进制传出 TCP/IP 数据包:
450000bb30394000800613194faa5a3b0a0203040050b92400a00000858bc52b501820001fab0000485454502f312e3120323030204f4b0a446174653a205475652c203139204e6f7620323031332031323a32333a303320474d540a436f6e74656e742d547970653a20746578742f68746d6c0a436f6e74656e742d4c656e6774683a2031320a457870697265733a205475652c203139204e6f7620323031332031323a32333a303320474d540a0a48656c6c6f20776f726c6421
但是,一个简单的测试就会超时;我创建了一个新套接字并将其连接到上面的 IP,但上面提供的响应从未到达。
可能出了什么问题?有什么方法可以排查我的回复未送达的原因吗?
最佳答案
此 TCP/IP 响应不包含有效的 TCP header 校验和:
450000bb30394000800613194faa5a3b0a0203040050b92400a00000858bc52b501820001fab0000485454502f312e3120323030204f4b0a446174653a205475652c203139204e6f7620323031332031323a32333a303320474d540a436f6e74656e742d547970653a20746578742f68746d6c0a436f6e74656e742d4c656e6774683a2031320a457870697265733a205475652c203139204e6f7620323031332031323a32333a303320474d540a0a48656c6c6f20776f726c6421
更一般地说,请求和响应机制是非常挑剔的。由于网络的本质,这当然是这种情况,并且由于内核负责确保响应良好以及应该将响应发送到哪个端口,任何不计算的东西都会被简单地丢弃为坏数据包.当您在网络层上操作时,从 VpnService 的输出流响应时也是如此。
回到上面的具体情况:IP 数据包正确(包括校验和)但 TCP 数据包不正确。您不仅需要计算 TCP 数据包的 TCP header 校验和,还需要以伪 header 为前缀,如下所示:
(来源:tcpipguide.com)
然后应该根据以下字节计算它:
关于android - 写入 VpnService 输出流没有响应,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20269283/
我有这个代码 var myChart = new FusionCharts("../themes/clean/charts/hbullet.swf", "myChartId", "400", "75
既然写入是立即进行的(复制到内核缓冲区并返回),那么使用 io_submit 进行写入有什么好处? 事实上,它 (aio/io_submit) 看起来更糟,因为您必须在堆上分配写入缓冲区并且不能使用基
我正在使用 mootool 的 Request.JSON 从 Twitter 检索推文。收到它后,我将写入目标 div 的 .innerHTML 属性。当我在本地将其作为文件进行测试时,即 file:
最终,我想将 Vertica DB 中的数据抓取到 Spark 中,训练机器学习模型,进行预测,并将这些预测存储到另一个 Vertica DB 中。 当前的问题是确定流程最后部分的瓶颈:将 Spark
我使用 WEKA 库编写了一个 Java 程序, 训练分类算法 使用经过训练的算法对未标记的数据集运行预测 将结果写入 .csv 文件 问题在于它当前写出离散分类结果(即算法猜测一行属于哪个类别)。我
背景 - 我正在考虑使用 clickonce 通过 clickonce(通过网站)部署 WinForms 应用程序。相对简单的应用程序的要素是: - 它是一个可执行文件和一个数据库文件(sqlite)
是否有更好的解决方案来快速初始化 C 数组(在堆上创建)?就像我们使用大括号一样 double** matrix_multiply(const double **l_matrix, const dou
我正在读取 JSON 文件,取出值并进行一些更改。 基本上我向数组添加了一些值。之后我想将其写回到文件中。当我将 JSONArray 写回文件时,会被写入字符串而不是 JSONArray 对象。怎样才
我为两个应用程序使用嵌入式数据库,其中一个是服务器,另一个是客户端。客户端应用程序。可以向服务器端发送获取数据请求以检索数据并显示在表格(或其他)中。问题是这样的:如何将获取的数据保存(写入)到页面文
是否有更好的解决方案来快速初始化 C 数组(在堆上创建)?就像我们使用大括号一样 double** matrix_multiply(const double **l_matrix, const dou
从问题得出问题:找到所有 result = new ArrayList(); for (int i = 2; i >(i%8) & 0x1) == 0) { result.add(i
由于某种原因,它没有写入 CSV。谁能明白为什么它不写吗? def main(): list_of_emails = read_email_csv() #read input file, cr
关闭。 这个问题是 not reproducible or was caused by typos 。它目前不接受答案。 这个问题是由于错别字或无法再重现的问题引起的。虽然类似的问题可能在这里出现,
我目前正在开发一个保存和加载程序,但我无法获得正确的结果。 编写程序: #include #include #define FILENAME "Save" #define COUNT 6 type
import java.io.*; public class Main2 { public static void main(String[] args) throws Exception {
我需要使用预定义位置字符串“Office”从所有日历中检索所有 iOS 事件,然后将结果写入 NSLog 和 UITextView。 到目前为止,这是我的代码: #import "ViewCo
我正在尝试将 BOOL 值写入 PFInstallation 中的列,但会不停地崩溃: - (IBAction)pushSwitch:(id)sender { NSUserDefaults *push
我以前在学校学过一些简单的数据库编程,但现在我正在尝试学习最佳实践,因为我正在编写更复杂的应用程序。写入 MySQL 数据库并不难,但我想知道让分布式应用程序写入 Amazon EC2 上的远程数据库
是否可以写回到ResourceBundle?目前我正在使用 ResourceBundle 来存储信息,在运行时使用以下内容读取信息 while(ResourceBundle.getBundle("bu
关闭。这个问题是not reproducible or was caused by typos .它目前不接受答案。 这个问题是由于错别字或无法再重现的问题引起的。虽然类似的问题可能是on-topi
我是一名优秀的程序员,十分优秀!