【发布时间】:2018-02-20 18:14:24
【问题描述】:
我的问题已经大致讨论过here。
tl;dr 的解决方案是:
iptables -A OUTPUT -p tcp --tcp-flags RST RST -j DROP
您可以修改它以仅阻止您正在监听的端口。
但正如上面问题中提到的,以及here,这些都不是优雅的解决方案。
现在,我并不真正关心事物的优雅。
但我确实关心学习。所以我深入研究了 Linux 源代码(目前主要对基于 Linux 的机器感兴趣) 并整理了我认为的 socket.bind 方法,以便找到与指导内核相关的任何内容“我们”正在积极监控 TCP 端口。
我假设套接字库通知内核一些如何将特定端口绑定到应用程序,这样内核就不会自动以 RST 数据包响应客户端连接,提示 “连接被拒绝”。
但是,我在源代码中找不到这样的代码。
packet 手册页也没有告诉我如何通知内核忽略/接受来自特定端口的数据包。
我有一个漂亮的basic socket 设置为以混杂模式收听(这是它自己的故事)。
但是,我的问题是,一旦客户端连接,在任何给定端口上 - 内核按预期方式发送传入的 Ethernet+IP+TCP 数据帧 - 但它也会立即发送带有“反向”源的响应和目标端口和RST 标志集。它应该,但不是在我告诉它的特定端口上。问题是,我如何告诉内核我正在监视一个特定的端口?
一种选择是(正如在其他一些论坛和其他各种 SO 线程中所讨论的) - 在该端口上创建一个虚拟套接字。
s = socket()
s.bind(('', <port>))
然而,这会导致一堆其他问题(其中一个是它会有一个缓冲区,很快就会被填满),最重要的是,仍然没有教我如何使用这些魔法发生。如果没有其他方法,上述两个解决方案是最后的手段,但我觉得我比以往任何时候都更接近但也比以往任何时候都更难以找到解决这个问题的适当解决方案。
解决方案或提示也可以在 C 中,和/或内核模块中,只是为了向内核指示所需信息。我知道这一切都在内核中下降,并且在下面的 cmets 和一个非常感谢的解决方案想法之后,我现在知道这个东西没有用户空间功能。我可能/很容易将它移植到 cPython 模块,或者使用内核模块/扩展轻松地将其转换为 Python 代码。但是我真的不知道设置这些东西的内核函数在哪里,或者它们叫什么。
我已经挖得很深,很深很浅.. 但似乎没有其他人需要这样做。主要是因为混杂套接字旨在获取流量并对其进行分析。但是.bind((interface, protocol)) 也在那里,它面临着同样的问题,一种不进入混杂模式的方式,而是通过执行.bind((interface, 0x0800)) 来接收 TCP 数据包。
我在这里可能会遇到困难,但也许man 7 netdevice 只是给了我一个想法。我正在尝试设置SystemTap 来检查调用ioctl() 的功能以及socket() 对象如何请求文件描述符。可能是关于这一切如何发生的线索。让 SystemTap 工作很棘手。
任何人有任何其他线索如何解决这个问题或以前遇到过这个问题?
附言。抱歉,这个问题很模糊,我不知道这些低级事物的正确术语是什么。因为它们对我来说很新。
编辑:我可能一直在寻找 bind() 的错误位置,根据 ipv4.af_inet 实现它会尝试调用套接字 bind() 函数,但如果不是,它会尝试设置很多魔法在这里。和here 他们在af_inet 上铿锵作响,做了很多桌子垃圾。我还没有找到解决方案,但可能会在路上迈出一步……或者最坏的情况,又一次打鹅。
进一步深入兔子洞,selinux/hooks.c 也包含一些绑定功能。也许更多的安全相关,但仍然值得我调查。仍然没有解决这个该死的谜题。
【问题讨论】:
-
我认为您的问题没有“适当”的解决方案。内核将为它实现的协议(TCP/UDP、ICMP、SCTP 等)处理传入的数据包,并且除了安装 iptables 过滤器之外,没有旋钮/ioctl/socketoption/api 调用来关闭该处理。跨度>
-
@nos 我的观点是,已经实现的协议处理让我们说 TCP 或 UDP,有一种方法可以告诉内核不要对某个端口进行处理。内核如何跟踪某个应用程序(在这种情况下,它更像是某个地方的注册文件描述符) - 可以完全控制端口上的任何数据流。我想告诉内核同样的事情,“不要弄乱这个端口,
已经弄清楚了” - 或者类似这样的事情:) -
不,不是。协议处理(例如 TCP 或 UDP)在内核中处理,而不是由应用程序或任何套接字库处理。因此,任何地方都没有条目表明应用程序可以完全控制端口。内核中有一个关于例如状态的条目。一个 TCP 端口。如果任何应用程序绑定到特定端口,则发往该端口的 TCP 数据包完全在内核中处理(并且内核处理 TCP 协议后的任何 TCP 有效负载数据都会发送到绑定到该端口/套接字的应用程序。 )
-
@nos 我对编写一个内核模块的想法并不陌生,我可以调用它来做我的竞标。考虑到这一点,这可能吗?知道在哪里寻找如何设置此状态吗?我在 Python 中这样做的唯一原因是对最终产品进行模拟,一个与用户空间通信的内核模块现在可以工作。最终产品很可能必须是内核模块和 c 代码。
-
我认为模块真的没有任何地方可以影响这一点,至少不是 iptables 无法做到的事情。 TCP 数据包结束并由现有套接字进一步处理的地方,或者发送 RST,因为没有人在监听:elixir.bootlin.com/linux/v4.13/source/net/ipv4/tcp_ipv4.c#L1645
标签: python linux sockets linux-kernel raw-sockets