【发布时间】:2013-12-14 16:15:51
【问题描述】:
我的应用程序实现了 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 标头、选项和正文。我继续根据协议类型解析正文的字节数组。在这种情况下,我只对带有 TCP 有效负载的 IPv4 感兴趣——在这里我也创建了 TCP 标头、选项和正文的表示。
在获得 IpDatagram 的实例后,我可以确定源 IP 和目标 IP(从 IP 头)和端口(从 TCP 头)。我还确认了请求 TCP 的标志(例如 SYN、ACK 和 PSH)和序列号。在应用程序中:
随后我构造了一个新的 IpDatagram 作为响应,其中:
- 源和目标 IP 与传入请求相反;
- 源端口和目标端口与传入请求相反;
- TCP 确认号设置为传入请求的序列号;
- 提供了一个虚拟 HTTP/1.1 有效负载作为 TCP 的主体。
我将生成的 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 P>
但是,简单的测试会超时;我创建了一个新套接字并将其连接到上面的 IP,但上面提供的响应从未到达。
可能出了什么问题?有什么方法可以解决我的回复未到达的原因吗?
【问题讨论】: