2017-01-24 141 views
0

目前试图建立iptables的以允许客户端连接到服务器通过TCP 收听消息流。事情是,我们希望阻止客户端连接后发送任何消息(如果客户端是DROP'在这种情况下编辑')。iptables的允许入站连接,但不允许入站流量

有没有办法允许客户端连接并强制从服务器到客户端的单向通信?

需要此功能纯粹在iptables(无类似软件代理的解决方案)中工作。

回答

0

这里要解决的主要问题是,我们不能关闭全部建立连接后来自客户端的流量,因为TCP是肯定确认协议。如果服务器没有收到来自客户端的确认,它将重新发送,并最终超时。接下来,我将假设我们正在使用IPV4。

所以我们要做的是允许建立连接,然后只允许来自客户端的确认,即不包含TCP有效载荷的数据包。

不幸的是,TCP有效载荷的长度在TCP header中没有明确表示。我们可以尝试使用IP header中的总长度,但由于IP报头和TCP报头包含可变长度选项字段这一事实使情况变得复杂,所以有很多可能的总长度不包含有效载荷。

由于IP选项很少使用并且经常被过滤,所以我们首先丢弃所有包含IP报头选项的数据包(如果防火墙尚未这样做的话),从而简化事情。这样做的含义详见here

要做到这一点,我们将所有的流量下降到我们的服务器(这里取为10.2.3.4:1234),其中IP报头的长度(比特在IP报头字节0 4-7)不是5:

iptables -A INPUT -p tcp -d 10.2.3.4 --dport 1234 \ 
    -m u32 --u32 "0>>24&0xF=6:0xF" -j DROP 

这使用iptablesu32模块抓住从分组的4个字节处开始的字节0,24位右移它,掩盖低半字节,然后丢弃该数据包,如果这是在范围6-15。请注意,5实际上是IP标头的最小尺寸。

TCP选项的情况有点复杂。在建立连接时,可以使用许多不同的选项,例如,协商窗口缩放。但是,一旦建立连接,我们唯一需要担心的就是TCP时间戳和选择性确认。因此,让我们让连接建立:

iptables -A INPUT -p tcp -d 10.2.3.4 --dport 1234 \ 
    --tcp-flags SYN SYN -j ACCEPT 

注意,有可能在一个SYN数据包发送有效载荷,所以在这里我们并没有完全满足您的要求。尽管TCP fast open确实如此,但大多数普通的TCP实现不会这样做。如果你想减轻这一点,你可以丢弃是分片的SYN数据包(可能会重新组合成非常大的数据包),并将非分片的SYN数据包的总长度限制在合理的范围内,以允许通常的选项存在TCP三方握手。请注意,上述规则已添加到INPUT链,在 IP分段重组之后处理

好的,我们可以建立TCP连接,IP头限制为5个字(20个字节)。

但是,TCP标头可能包含选择性ack,tcp时间戳,两者或两者都不包含。我们从没有选项的TCP头开始。没有选项且没有有效负载的确认将由5字IP标头,后跟5字TCP标头,然后是无数据组成。所以IP头部的总长度应该是40.如果数据包是一个片段,它可能会在后续片段中隐藏一个有效载荷,但由于我们正在使用在IP碎片重组后处理的INPUT链,因此我们不会不得不担心这一点。

iptables -A INPUT -p tcp -d 10.2.3.4 --dport 1234 \ 
    -m u32 --u32 "32>>28=5 && 0&0xFFFF=40" -j ACCEPT 

IP报头是20个字节和数据偏移半字节是在字节12中,因此服用4个字节处开始的字节32 = 20 + 12,我们向下移动半字节,并将其与5,然后请确保IP标头的字0的字节2和字节3的总长度为40.

如果TCP标头中有TCP时间戳,则TCP中会有额外的12个字节(3个字)头。我们可以以类似的方式接受:

iptables -A INPUT -p tcp -d 10.2.3.4 --dport 1234 \ 
    -m u32 --u32 "32>>28=8 && 0&0xFFFF=52" -j ACCEPT 

我会把它作为练习,让读者去计算其他组合。 (请注意,处理选择性确认有几种情况,因为可以有1-4个选择性确认块或1-3个具有时间戳的选择性确认块。)

免责声明:我没有真正尝试过这一点,所以我很抱歉如果有一个错字或者我忽略了一些东西。我相信策略是健全的,如果有任何错误或遗漏,请让我知道,我会纠正。