如何获取重定向UDP报文的原始目的端口?

发布于 2024-10-31 14:46:45 字数 206 浏览 9 评论 0原文

使用这个东西我可以获得原始目标IP地址socket(PF_INET, SOCK_DGRAM, 0) 套接字。

如何获取原目的港?

Using this thing I can obtain original destination IP address of socket(PF_INET, SOCK_DGRAM, 0) socket.

How to get original destination port?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

剩一世无双 2024-11-07 14:46:45

取决于重定向机制。如果您使用 REDIRECT(即底层的 NAT),则需要使用 SO_ORIGINAL_DST 或 libnetfilter_conntrack 在应用 NAT 之前查询连接的原始目标。然而,由于您可以使用同一个侦听器套接字提供多个连接,因此必须对每个数据包进行此查找。

您可以使用 conntrack 命令行工具试验 libnetfilter_conntrack 及其提供的服务。

另一种选择是使用 TPROXY 进行重定向,这本来是在这种情况下使用的。在那里,您可以使用 recvmsg() 使用辅助消息获取数据包的原始目的地。要查找的关键是 IP_RECVORIGDST setsockopt。

有关 TPROXY 的更多信息可以在内核文档目录中名为 tproxy.txt 的文件中找到。它使用起来有点困难,但工作起来更可靠,因为它是由堆栈实现的,而不是包过滤子系统。

编辑:添加如何使用TProxy查询UDP目标地址。

  1. 打开 UDP 套接字,将其绑定到 0.0.0.0 或更具体的 IP
  2. 通过setsockopt(fd, SOL_IP, IP_RECVORIGDSTADDR, ...) 启用 IP_RECVORIGDST
  3. 您使用 recvmsg() 而不是 recvfrom()/recv() 来接收帧
  4. recvmsg() 将返回数据包和一系列辅助消息,
  5. 迭代辅助消息,并定位级别为 SOL_IP、索引为 IP_ORIGDSTADDR 的 CMSG 块,
  6. 此 CMSG 块将包含一个 struct sockaddr_in,其中包含 IP 和端口信息。

编辑: SO_ORIGINAL_DST 与 udp

SO_ORIGINAL_DST 应该与 udp 套接字一起使用,但是内核不允许您指定连接端点,它将使用您调用 SO_ORIGINAL_DST 的套接字来获取此地址信息。

这意味着只有当 UDP 套接字正确绑定(到重定向到的地址/端口)并连接(到相关客户端)时,它才会起作用。您的侦听器套接字可能绑定到 0.0.0.0,并且不仅为单个客户端提供服务,而且为多个客户端提供服务。

但是,您不需要使用实际的侦听器套接字来查询目标地址。由于 UDP 在建立连接时不会传输数据报,因此您可以创建一个新的 UDP 套接字,将其绑定到重定向地址并将其连接到客户端(您知道该地址,因为它已将第一个数据包发送到您的侦听器)。然后你可以使用这个套接字来运行 SO_ORIGINAL_DST ,但是有罪魁祸首:

  1. 一旦你打开这样一个套接字,内核会更喜欢客户端在第一个数据包之后发送额外的数据包,而不是你的侦听器套接字
  2. ,这本质上是有问题的,因为当您的应用程序有机会调用 SO_ORIGINAL_DST 时,conntrack 条目可能已超时。
  3. 它很慢并且开销很大

基于 TProxy 的方法显然更好。

Depends on the redirection mechanism. If you are using REDIRECT (which is NAT under the hood), then you need to use SO_ORIGINAL_DST, or libnetfilter_conntrack to query the original destination of the connection before NAT was applied. However since you can serve several connections with the same listener socket, this lookup has to be done for every packet.

You can experiment with libnetfilter_conntrack and the services it provides using the conntrack command line tool.

An alterntive is to use TPROXY for the redirection, which was meant to be used in cases like this. There you can get the original destination of the packet using an ancillirary message using recvmsg(). The key to look for is the IP_RECVORIGDST setsockopt.

More information on TPROXY can be found in the kernel Documentation directory, in a file called tproxy.txt. It is a bit difficult to use, but works more reliably as it is implemented by the stack, rather than the packet filtering subsystem.

Edited: to add how to query UDP destination addresses with TProxy.

  1. open an UDP socket, bind it to 0.0.0.0 or to a more specific IP
  2. you enable IP_RECVORIGDST via setsockopt(fd, SOL_IP, IP_RECVORIGDSTADDR, ...)
  3. you use recvmsg() instead of recvfrom()/recv() to receive frames
  4. recvmsg() will return the packet and a series of ancillary messages,
  5. iterate the ancillary messages, and locate the CMSG block with level SOL_IP, index IP_ORIGDSTADDR
  6. this CMSG block will contain a struct sockaddr_in with both the IP and the port information.

Edited: SO_ORIGINAL_DST vs. udp

SO_ORIGINAL_DST should work with udp sockets, however the kernel doesn't let you specify the connection endpoints, it'll use the socket that you call SO_ORIGINAL_DST on to get this address information.

This means that it'll only work, if the UDP socket is properly bound (to the redirected-to address/port) and connected (to the client in question). Your listener socket is probably bound to 0.0.0.0 and is servicing not just a single, but mulitple clients.

However, you don't need to use your actual listener socket to query the destination address. Since since UDP doesn't transmit datagrams on connection establishment, you can create a new UDP socket, bind it to the redirect address and connect it to the client (whose address you know since it sent the first packet to your listener anyway). Then you could use this socket to run SO_ORIGINAL_DST on, however there are culprits:

  1. once you open such a socket, the kernel will prefer that if the client would send additional packets after the first one, not your listener socket
  2. this is inherently racy, since by the time your application has a chance to call SO_ORIGINAL_DST, the conntrack entry may have timed out.
  3. it is slow and a lot of overhead

The TProxy based method is clearly better.

谷夏 2024-11-07 14:46:45

尝试解析 /proc/net/nf_conntrack

Try parsing /proc/net/nf_conntrack

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文