简体   繁体   English

使用套接字 AF_PACKET / SOCK_RAW 但告诉内核不要发送 RST

[英]Using socket AF_PACKET / SOCK_RAW but tell kernel to not send RST

My question has roughly been discussed here .我的问题在这里已经大致讨论过

And the tl;dr solution is to do:而 tl;dr 解决方案是:

iptables -A OUTPUT -p tcp --tcp-flags RST RST -j DROP

And you could modify this to only block the port you're actively listening after.您可以修改它以仅阻止您正在积极侦听的端口。
But as mentioned in the above question, and here , these are not elegant solutions.但是正如上面的问题和这里提到的,这些都不是优雅的解决方案。

Now, I don't really care about the elegance of things.现在,我真的不在乎事物的优雅。
But I do care about learning.但我确实在乎学习。 So I've dug deep into the Linux source code (mostly interested in Linux based machines for now) and sorted through what I think is thesocket.bind method in order to find anything related to instructing the kernel that "we" are actively monitoring a TCP port.因此,我深入研究了 Linux 源代码(目前主要对基于 Linux 的机器感兴趣)并整理了我认为的socket.bind方法,以便找到与指示“我们”正在积极监视的内核相关的任何内容一个 TCP 端口。

I assumed that the socket library informed the kernel some how about a specific port being bound to a application, this so that the kernel don't automatically respond with a RST packet to the client connecting, prompting a "Connection refused" .我假设套接字库通知内核一些特定端口绑定到应用程序的情况,这样内核就不会自动使用RST数据包响应客户端连接,提示“连接被拒绝”

However, I find no such code in the source code.但是,我在源代码中找不到这样的代码。
Nor does the packet man page tell me anything about how to inform the kernel to ignore/accept packets coming in on a specific port.数据包手册页也没有告诉我如何通知内核忽略/接受来自特定端口的数据包。

I've got a pretty basic socket set up to listen with promiscuous mode (that is a tale of it's own) .我有一个非常基本的套接字设置来以混杂模式收听(这是它自己的故事)

However, my problem is that as soon as a client connects, on any given port - the kernel sends the incoming Ethernet+IP+TCP data frame my way as expected - but it also instantly sends out a response with "reversed" source and destination ports and the RST flag set.但是,我的问题是,一旦客户端在任何给定端口上连接 - 内核按预期的方式发送传入的Ethernet+IP+TCP数据帧 - 但它也会立即发送具有“反向”源和目标的响应端口和RST标志集。 Which it should, but not on a specific port I tell it to.它应该,但不是在我告诉它的特定端口上。 Problem is, how do I tell the kernel I'm monitoring a specific port?问题是,我如何告诉内核我正在监视特定端口?

One option would be to (as discussed in some other forums and on other various SO threads) - create a dummy socket on that port.一种选择是(如在其他一些论坛和其他各种 SO 线程中讨论的那样) - 在该端口上创建一个虚拟套接字。

s = socket()
s.bind(('', <port>))

However, that causes a bunch of other problems (one of which is that this will have a buffer that will quickly be filled) and most importantly, still doesn't teach me how all this magic happens.然而,这会导致一系列其他问题(其中一个是这将有一个很快就会被填满的缓冲区) ,最重要的是,仍然没有告诉我所有这些魔法是如何发生的。 The two above solutions are last resort if there's no other ways, but I feel I'm closer than ever yet more stuck than ever too in finding a proper solution to this problem.如果没有其他方法,上述两种解决方案是最后的手段,但我觉得我比以往任何时候都更接近,但也比以往任何时候都更难找到解决这个问题的适当方法。

The solution or tips could be in C as well , and/ or a kernel module just for the sake of instructing the kernel of the needed information.解决方案或提示也可以在C 中,和/或内核模块,只是为了指示内核所需的信息。 I knew all this was going down in the kernel, and after the comments below and a much appreciate solution idea, I now get that there's no userspace function for this very thing.我知道这一切都在内核中发生了,在下面的评论和一个非常感谢的解决方案想法之后,我现在知道没有用户空间功能可以解决这个问题。 I could probably/easily port it to a cPython module or warp it around to Python code easily enough with a kernel module/extension.我可能/轻松地将它移植到 cPython 模块,或者使用内核模块/扩展轻松地将它转换为 Python 代码。 But I really have no idea where the kernel functions for setting these things are, or what they are called.但是我真的不知道设置这些东西的内核函数在哪里,或者它们叫什么。

I've dug deep, far and shallow.. But it doesn't appear anyone else has had the need to do this.我挖得很深,很远很浅。但似乎没有其他人需要这样做。 Mostly because a promiscuous socket is meant to pick up traffic and analyze it.主要是因为混杂的套接字旨在获取流量并对其进行分析。 But also the .bind((interface, protocol)) is out there and it faces the same issue, a way of not going into promiscuous mode but instead just receive TCP packets for instance by doing .bind((interface, 0x0800)) ..bind((interface, protocol))也在那里,它面临着同样的问题,一种不进入混杂模式而是只接收 TCP 数据包的方法,例如通过执行.bind((interface, 0x0800))

I might be out on a limb here, but maybe man 7 netdevice just gave me an idea.我可能在这里man 7 netdevice了,但也许man 7 netdevice只是给了我一个想法。 I'm trying to setup SystemTap to check what calls ioctl() does and how socket() object asks for a file descriptor.我正在尝试设置SystemTap以检查调用ioctl()作用以及socket()对象如何请求文件描述符。 Might be a clue as to how this all goes down.可能是关于这一切如何发生的线索。 Tricky getting SystemTap to work tho.让 SystemTap 工作很棘手。

Anyone have any other clues how to go about this problem or have bumped into this before?任何人都有任何其他线索如何解决这个问题或以前遇到过这个问题?

Ps.附言。 Sorry for a fuzzy question, I have no idea what the correct terminology is for these lower level things.对不起,我问了一个模糊的问题,我不知道这些低级事物的正确术语是什么。 As they are quite new to me.因为他们对我来说很新。

Edit: I might have been looking in the wrong place for bind() , according to the ipv4.af_inet implementation it will try to call the sockets bind() function, but if not, it will try to setup a lot of magic in here.编辑:我可能一直在寻找错误的地方bind() ,根据ipv4.af_inet实现,它将尝试调用套接字bind()函数,但如果没有,它将尝试在这里设置很多魔法. And here they clank down on af_inet and does a lot of table junk.. I still haven't found a solution, but a step on the way perhaps... Or worst case, another goose hunt. 在这里,他们在af_inetaf_inet ,做了很多表垃圾..我仍然没有找到解决方案,但也许已经迈出了一步......或者最坏的情况是,又一次鹅狩猎。

Going further down the rabbit hole, selinux/hooks.c contains some bind functionality as well.更进一步, selinux/hooks.c 也包含一些绑定功能。 Maybe more security related, but still worth my investigation.也许更多的安全相关,但仍然值得我调查。 Still no where near solving this darn riddle.仍然无法解决这个该死的谜语。

The problem here is that you're asking for a way to tell the kernel in effect "do these 100 things for me, but leave this one particular detail out."这里的问题是,您正在寻求一种方法来告诉内核实际上“为我做这 100 件事,但忽略这个特定的细节”。 Frankly, I think the iptables solution is the easiest and cleanest.坦率地说,我认为 iptables 的解决方案是最简单和最干净的。

Another option, though, is to not ask the kernel to do all those other bits, and instead to take on more work yourself.但是,另一种选择是要求内核完成所有其他工作,而是自己承担更多工作。 Specifically, make up your own IP address, and start using it.具体来说,自己编一个IP地址,然后开始使用。 The only downside is that you have to take over another important thing that the kernel has been doing for you: responding to ARPs (ARP is used to discover the MAC [Ethernet] address of the station that owns a given IP address).唯一的缺点是你必须接管内核一直在为你做的另一件重要的事情:响应 ARP(ARP 用于发现拥有给定 IP 地址的站的 MAC [以太网] 地址)。 In brief, I'm suggesting you:简而言之,我建议你:

  1. Choose an unused IP address on your local subnet.在本地子网上选择一个未使用的 IP 地址。
  2. Make up a MAC address for your use.组成一个 MAC 地址供您使用。 (Not strictly necessary but will make it easier to distinguish "your" traffic.) (并非绝对必要,但可以更轻松地区分“您的”流量。)
  3. Open a raw packet socket instead of raw IP socket ( https://linux.die.net/man/7/packet ).打开原始数据包套接字而不是原始 IP 套接字 ( https://linux.die.net/man/7/packet )。
  4. Compose and send an ARP request to discover the MAC address of the station you're sending to (if on local LAN, else the MAC of the next hop [router] IP address).编写并发送 ARP 请求以发现您要发送到的站的 MAC 地址(如果在本地 LAN 上,否则为下一跳 [路由器] IP 地址的 MAC)。
  5. Receive the ARP reply and record the other station's MAC.收到ARP回复,记录对方的MAC。
  6. Construct and send your SYN packet from your own MAC address to the MAC of the destination station.构建您的 SYN 数据包并将其从您自己的 MAC 地址发送到目标站的 MAC。 (With your chosen source and dest IPs, ports, etc.) (使用您选择的源和目标 IP、端口等)
  7. Listen for a return ARP for your IP and reply as needed.侦听您的 IP 的返回 ARP 并根据需要进行回复。
  8. Receive the SYN+ACK response.接收 SYN+ACK 响应。 Since the destination IP address (the one you made up) is not known to the kernel to belong to your system, the kernel will not respond to the SYN+ACK with RST (or anything else).由于内核不知道目标 IP 地址(您创建的 IP 地址)属于您的系统,因此内核不会使用 RST(或其他任何内容)响应 SYN+ACK。
  9. Do whatever it is you want to do next...做你接下来想做的事……

You will of course have to be capturing promiscuously if you use a MAC address other than the one assigned to the interface.如果您使用的 MAC 地址不是分配给接口的 MAC 地址,则您当然必须进行混杂的捕获。 That is pretty typical with a raw packet socket.这对于原始数据包套接字来说非常典型。 Also, you will be constructing Ethernet header, IP header, and TCP headers for all traffic (well, Ethernet + ARP for the ARP requests) so you will learn a lot.此外,您将为所有流量构建以太网标头、IP 标头和 TCP 标头(嗯,用于 ARP 请求的以太网 + ARP),因此您将学到很多东西。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM