使用套接字AF_PACKET/SOCK_RAW,但告诉内核不要发送RST [英] Using socket AF_PACKET / SOCK_RAW but tell kernel to not send RST

查看:87
本文介绍了使用套接字AF_PACKET/SOCK_RAW,但告诉内核不要发送RST的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的问题已在此处进行了粗略讨论.

而tl; dr解决方案是:

And the tl;dr solution is to do:

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.

现在,我不太在乎事物的优雅.
但是我确实很在乎学习.因此,我深入研究了Linux源代码(目前主要对基于Linux的机器感兴趣),并按照我认为的

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 the socket.bind method in order to find anything related to instructing the kernel that "we" are actively monitoring a TCP port.

我假设套接字库通知内核一些特定端口绑定到应用程序的情况,这样内核就不会自动以 RST 数据包响应客户端连接,提示连接被拒绝" .

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".

但是,我在源代码中找不到这样的代码.
packet 手册页也没有告诉我有关如何通知内核忽略/接受来自特定端口的数据包.

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).

但是,我的问题是,只要客户端连接到任何给定的端口,内核就会按预期方式发送传入的 Ethernet + IP + TCP 数据帧-但它也会立即发送发出带有反向"源端口和目标端口以及设置了 RST 标志的响应.我应该告诉哪个,但不应该在特定端口上.问题是,如何告诉内核我正在监视特定端口?

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. 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?

一个选择是(如在其他论坛和其他各种SO线程上所讨论的)-在该端口上创建一个虚拟套接字.

One option would be to (as discussed in some other forums and on other various SO threads) - create a dummy socket on that port.

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.

解决方案或技巧也可以在 C 和/或内核模块中,只是为了指示内核所需的信息.我知道所有这些事情都在内核中消失了,在下面的注释和一个备受赞赏的解决方案思路之后,我现在知道这件事没有用户空间功能.我可能可以/轻松地将其移植到cPython模块,或者使用内核模块/扩展将其轻松转换为Python代码.但是我真的不知道设置这些功能的内核功能在哪里,或者它们叫什么.

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. 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. But I really have no idea where the kernel functions for setting these things are, or what they are called.

我已经挖掘了很深,很深的深度.但是,似乎没有其他人有这样做的必要.主要是因为混杂的套接字旨在获取流量并对其进行分析.但是 .bind((interface,protocol))也在那里,并且面临着相同的问题,一种不进入混杂模式,而只是通过执行来接收TCP数据包的方式..bind((interface,0x0800)).

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)).

我可能在这里有些不知所措,但是也许 man 7 netdevice 给了我一个主意.我正在尝试设置 SystemTap 以检查调用 ioctl()的作用以及 socket()对象如何请求文件描述符.可能是有关所有情况如何下降的线索.要让SystemTap正常工作还很棘手.

I might be out on a limb here, but maybe man 7 netdevice just gave me an idea. I'm trying to setup SystemTap to check what calls ioctl() does and how socket() object asks for a file descriptor. Might be a clue as to how this all goes down. Tricky getting SystemTap to work tho.

有人有其他线索可以解决这个问题吗?或者曾经碰到过这个问题?

Anyone have any other clues how to go about this problem or have bumped into this before?

Ps.对一个模糊的问题很抱歉,我不知道这些低级事物的正确术语是什么.因为它们对我来说还很新.

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.

根据这里 af_inet 并做了很多表垃圾..我仍然没有找到解决方法,但是也许是在迈出一步……或者最坏的情况下,又是一次鹅狩猎.

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. 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.

进一步深入研究, selinux/hooks.c 也包含一些绑定功能.也许与安全性有关,但仍然值得我调查.仍然无法解决这个该死的谜语.

Going further down the rabbit hole, selinux/hooks.c contains some bind functionality as well. Maybe more security related, but still worth my investigation. Still no where near solving this darn riddle.

推荐答案

这里的问题是,您正在寻找一种方法来告诉内核实际上为我做了这100件事,但忽略了这一特定细节"."坦白地说,我认为iptables解决方案是最简单,最干净的.

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." Frankly, I think the iptables solution is the easiest and cleanest.

不过,另一种选择是要求内核执行所有其他操作,而是自己承担更多工作.具体来说,请建立您自己的IP地址,然后开始使用它.唯一的缺点是您必须接管内核为您所做的另一项重要工作:响应ARP(ARP用于发现拥有给定IP地址的站点的MAC [Ethernet]地址).简而言之,我建议您:

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. 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). In brief, I'm suggesting you:

  1. 选择本地子网中未使用的IP地址.
  2. 组成一个MAC地址供您使用.(并非绝对必要,但可以更轻松地区分您的"流量.)
  3. 打开一个原始数据包套接字而不是原始IP套接字( https://linux.die.net/man/7/packet ).
  4. 撰写并发送ARP请求以发现要发送到的站点的MAC地址(如果在本地LAN上,则为下一跳[路由器] IP地址的MAC).
  5. 接收ARP答复并记录另一个站点的MAC.
  6. 从您自己的MAC地址构造SYN数据包并将其发送到目标站的MAC.(使用您选择的源IP和目标IP,端口等)
  7. 侦听您的IP的返回ARP,并根据需要进行回复.
  8. 接收SYN + ACK响应.由于内核不知道目标IP地址(由您组成的目标IP地址)属于您的系统,因此内核将不会用RST(或其他任何东西)响应SYN + ACK.
  9. 做您想做的下一步...

如果您使用的MAC地址不是分配给接口的MAC地址,那么您当然必须进行混杂捕获.对于原始数据包套接字,这是非常典型的.另外,您将为所有流量构造以太网头,IP头和TCP头(嗯,对于ARP请求,以太网+ ARP),因此您将学到很多东西.

You will of course have to be capturing promiscuously if you use a MAC address other than the one assigned to the interface. 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.

这篇关于使用套接字AF_PACKET/SOCK_RAW,但告诉内核不要发送RST的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆