1

我正在使用 TUNTAP 进行 Python 隧道项目。在 TUNTAP 接口上接收的数据包含原始 IP 数据包,包括所有标头。我可以做两件事之一。

在接收端,我正在用 Twisted 收听。在传出端,我将有一个转储 IP 数据包的原始套接字。在转储数据包之前,程序将源地址与服务器的源地址交换。它还重新计算 TCP 和 UDP 校验和。它还使用以下方法之一交换端口。此信息在 NAT 表中进行跟踪

1)每个用户使用一个端口,例如

 US.ER.01.IP:10000 ----> SE.RV.ER.IP:3000 ----> facebook.com:80
 US.ER.01.IP:10001 ----> SE.RV.ER.IP:3000 ----> facebook.com:80
 US.ER.02.IP:3000 ----> SE.RV.ER.IP:3001 ----> facebook.com:80

如果第二个用户同时请求 1 个 facebook,这会导致问题吗?系统如何知道如何路由 facebook 的回复。它在端口 3000 上传入,因此属于 user1,但它是否被映射回 10000 或 10001?

2)为每个连接使用一个唯一的端口,例如

 US.ER.01.IP:10000 ----> SE.RV.ER.IP:3000 ----> facebook.com:80
 US.ER.01.IP:10001 ----> SE.RV.ER.IP:3001 ----> facebook.com:80
 US.ER.02.IP:3000 ----> SE.RV.ER.IP:3002 ----> remoteHost.com:22

我怎么知道何时从 NAT 表中删除条目?使用这种方法,我可以看到 NAT 表很快填满。对此的解决方案是:

  I could wit for FIN packets from the server.  This will not work with UDP though.
  I could age the NAT entry on each hit.  I could then run garbage collection 
     every N seconds.  I see this being an issue if garbage collection runs
     and how would a server's delayed response get to the proper host if it gets
     deleted from the table.

还有从原始套接字读取的问题。我知道如何发送一个,但是否可以接收单独的 IP 数据包。原始套接字能否在每个 sock.recieve(65535) 调用中接收一个数据包,是否可能接收多个 IP 数据包?

哪种实现最好?我应该注意的任何其他提示或事项?

编辑:

好的,所以我有很多客户。如果您误解了我,则在客户端和自身之间使用 enitre /30。这只是使隧道成为可能的抽象。我也不认为这很重要,但是 websocket 实际上通过 LAN 上的“代理”(IPdata 只是重新打包到一个新的 websocket 中,但是映射是唯一的)。我不想让解释变得如此混乱。我看不出这有什么改变。

      Client PC     CLIENT PC              Client PC----->LAN                               INTERNET    
 Client 1: 10.1.1.2 ----> 10.1.1.1 ----> Websocket(IPdata) ----> Browser ---> newWebSocket(IPData) ----> SE.RV.ER.IP
 Client 2: 10.1.1.4 ----> 10.1.1.3 ----> Websocket(IPdata) ----> Browser ---> newWebSocket(IPData) ----> SE.RV.ER.IP
 Client 3: 10.1.1.6 ----> 10.1.1.5 ----> Websocket(IPdata) ----> Browser ---> newWebSocket(IPData) ----> SE.RV.ER.IP

每个客户端都将其默认路由设置为隧道端点(例如 10.1.1.1)。客户端获取 IP 数据报,将其放入 websocket,将 websocket 发送到 LAN 上的浏览​​器,然后将其发送到服务器(或者可能是另一个代理)。websocket 内部包含原始 IP 数据报(源为 10.1.1.2 或其他一些内部 IP)。

需要注意的是,服务器从 Internet 接收到包含货物的 websocket 消息(带有私有源地址)。python服务器将如何使用它?自己创建一个新隧道,然后将数据包原始转储到隧道中并适当地路由?

或者也许我可以使用映射?

我如何能够在这个 websocket 链上“映射”隧道抽象?客户端没有通往互联网的路线,但可以访问可以访问互联网的“浏览器”。这似乎与 VPN 隧道的情况相同。抽象如下:

 Client 1: 10.1.1.2 ----> 10.1.1.1 ----> Websocket(IPdata) ----> Browser ---> newWebSocket(IPData) ----> SE.RV.ER.IP -> Internet
           10.1.2.2------------------------------------------------------------------------------------> 10.1.2.1 ----> Internet

如果您知道任何让我走上正轨的资源,那就太好了!

4

1 回答 1

5

实施 NAT

您必须为每个连接使用一个唯一端口,而不是每个用户使用一个端口,这正是您在问题中概述的原因:如果您不这样做,那么您可以(并且将会!)最终使用相同的 5 个连接-tuple (protocol,local-address,local-port,remote-address,remote-port),您将无法消除它们的歧义。

此外,如果您想与一些执行 NAT 遍历的协议配合得很好,那么您应该尽可能重新映射原始源端口,也就是说,仅在它与现有连接冲突时重新映射(到新的随机端口)你正在跟踪。

要正确实施 NAT,您必须跟踪每个连接的状态。

对于 TCP,这意味着观察标志,当你看到 a 时设置新状态,当你从两边SYN看到 s 时拆除状态。FIN您跟踪的状态必须至少包含原始源端口和重新映射的源端口(可能相同,见上文)。如果您想支持 FTP,那么您还必须嗅探 FTP TCP 控制连接的内容并重写其中包含的 IP 地址(这意味着您将需要跟踪更多的状态,因为您有时可能需要扩大一个 TCP 段,意味着您需要开始重新映射序列号)。您还应该与每个跟踪的连接关联一个超时,以便在端点消失而没有正确关闭连接的情况下摆脱它。

对于 UDP,这意味着查看本地和远程端口号的组合,并为您看到的每个唯一组合(地址和端口的 4 元组)创建状态。因为 UDP 是无连接的,所以您必须根据超时使此状态信息过期。此超时将比您用于 TCP 的超时短得多(大约几分钟而不是几小时),以防止您的状态表变得太大。

对于 ICMP 回显请求,您应该以类似于 UDP 的方式进行处理,其中 icmp_id 扮演端口号的角色。

对于其他类型的 ICMP,如目标不可达,您必须检查 ICMP 数据包以查看它是否是您正在跟踪的 TCP 或 UDP 连接的一部分,并尝试将其转换回原始源。

为了防止路由循环,您还应该在转发已转换的数据包时减少 IP TTL。

我可能忘记了一些更重要的部分。简而言之,实现 NAT 很像为路由器实现 IP 堆栈!这就是为什么 NAT 是虚拟的,总是固定在内核中的 IP 堆栈上,而不是在用户空间中实现。

发送和接收数据包

所以我理解的架构是这样的:

  1. 客户端发起一个进入 TUNTAP 接口的数据包
  2. 您的软件获取此数据包,将其封装在 Websocket 消息中,然后发送出去
  3. 你的 Twisted 服务器得到它并发挥它的魔力
  4. 翻译后的数据包通过原始套接字从服务器发出

返回路径:

  1. 回复以某种方式返回到您的服务器(可能是libpcap
  2. 您的代码具有相反的魔力
  3. 您的服务器通过 Websocket 将结果传输回客户端
  4. 客户端通过 TUNTAP 接口看到返回的结果。

我认为处理前向路径最后一步和返回路径第一步的最简单方法是第二个 TUNTAP 设备:tun服务器上的一个接口。

于 2012-11-05T03:40:16.540 回答