当前位置: 首页 > 知识库问答 >
问题:

写入VpnService输出流不提供响应

马清野
2023-03-14

我的应用程序实现了VpnService来拦截流量并提供量身定制的响应。目标是处理到特定地址的流量,并丢弃其他请求。

目前,我成功地解析了传入的请求,构建并发送了响应。然而,问题是这些响应并不是对原始请求的实际响应;使用套接字连接进行测试只是超时。

为了进行这一区分,我目前正在解析VPN服务输入流中的原始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 html" target="_blank">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是一个类,通过它可以将字节数组解析为IP数据包的表示形式,其中包含IP标头、选项和正文。我继续根据协议类型解析正文的字节数组。在本例中,我只对具有TCP负载的IPv4感兴趣,这里我创建了TCP头、选项和主体的表示。

获取IpDatagram实例后,我可以确定源和目标IP(从IP标头)和端口(从TCP标头)。我还确认请求TCP的标志(例如SYN、确认字符和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数据包:

450000BB30394000800613194FAA5A3B0A0203040050B92400A00000858BC52B501820001FAB00004854502F312E3120323030204F4B0A446174653A2054752C2C303139204E6F762032303133203132A303320474D540A436F6E74656E742D547970653A20746742F68746D6C0A436E74656E742D64C6656E677683A2031320A457870697265733A20323A203139204E6F7620323031332031323A332333A303320474D540A0A48656C6C6F20776F726C6421

然而,一个简单的测试只是超时;我创建了一个新的套接字并将其连接到上面的IP,但上面提供的响应从未到达。

可能出了什么问题?有什么方法可以解决为什么我的回复没有到达的问题吗?

共有1个答案

司马宏邈
2023-03-14

此TCP/IP响应不包含有效的TCP标头校验和:

450000BB30394000800613194FAA5A3B0A0203040500B92400A00000858BC52B501820001AB000048554502F312E3120323030204F4B0A446174653A2054752C203139204E6F7620331332031323A332333A303320474D540A436E74656E74656E742D6C0436E74656E742D6D6C656E677446E774683A2031320A45787065733A205475A45787065733A205475D6A2C203139204E6F7620323031332031323A332333A303320474D540A0A48656C6C6F20776F726C6421

一般来说,请求和响应机制非常挑剔。当然,这是由于网络的本质,并且由于内核负责确保响应良好以及响应应该发送到哪个端口,任何不计算的内容都将作为坏数据包被丢弃。当您在网络层上操作时,从VPN服务的输出流响应时,这也是正确的。

返回到上面的特定情况:IP数据包正确(包括校验和),但TCP数据包不正确。您不仅需要在TCP数据包上计算TCP报头校验和,还需要以伪报头为前缀,如下所示:

然后应计算以下字节:

 类似资料:
  • 问题内容: 所以我在bash上运行它: 该命令的作用是一直保持运行状态,并且每当我的设备发送某个数据时,例如说它检测到温度变化,它就会输出类似的内容 而且这只会继续运行,并且一旦有任何原因就会输出一些东西。因此,执行无止境。 没有回声运行完美,但是当我尝试使用’>’运算符时,这似乎没有写入文件。 例如 这不能正常工作,my_record_file只获取 间隔 写入的数据,但是我想立即写入。 有任何

  • 我有几个输出侦听器正在实现。它可以是写到stdout或文件的,也可以是写到内存或任何其他输出目标;因此,我在方法中指定作为(an)参数。 现在,我收到了。在这里向流写入的最佳方式是什么? 我应该只使用吗?我可以给它字节,但如果目标流是字符流,那么它会自动转换吗? 我需要用这里的一些桥流来代替吗?

  • 问题内容: 我有几个正在实现OutputStream的输出侦听器。它可以是写到stdout或文件的PrintStream,也可以写到内存或任何其他输出目标。因此,我在方法中将OutputStream指定为参数。 现在,我已经收到了字符串。在此处写入流的最佳方法是什么? 我应该只使用Writer.write(message.getBytes())吗?我可以给它提供字节,但是如果目标流是字符流,那么它

  • 我有一个输入流,我想将其写入HttpServletResponse。有一种方法,由于使用字节[],需要花费的时间太长 我想知道在速度和效率方面,什么可能是最好的方法。

  • 现在准备要构建一个工具,用来把前面idata.txt里的数据按group分行显示,就像这样: 2 9 10 3 1 2 3 我们可以借助语法分析树的Listener机制来对词法分析结束后生成的记号流进行改写,我们不需要实现每一个Listener接口方法,只需要在捕获到group的时候把换行符插到它末尾就行。实现改写的代码如下所示: import org.antlr.v4.runtime.Toke

  • 本小节将会介绍基本输入输出的 Java 标准类,通过本小节的学习,你将了解到什么是输入和输入,什么是流;输入输出流的应用场景,File类的使用,什么是文件,Java 提供的输入输出流相关 API 等内容。 1. 什么是输入和输出(I / O) 1.1 基本概念 输入/输出这个概念,对于计算机相关专业的同学并不陌生,在计算中,输入/输出(Input / Output,缩写为 I / O)是信息处理系