iptables:只匹配build立的TCP连接的第一个数据包

在我的Apache日志文件中,我发现了很多包含"GET /w00tw00t.at.ISC.SANS.DFind:) HTTP/1.1" 400或类似垃圾的条目。 他们来自非RFC2616连接(HTTP / 1.1没有主机名)。

我不希望我的日志文件垃圾邮件与此消息。 所以我想用iptables拒绝这些连接。 因此,我想在数据包有效负载中searchstring“HTTP / 1.1”,然后search两个后续的CR / LF(CR / LF / CR / LF)(总共给出了hex串485454502f312e310d0a0d0a )。

但是,当我知道它是在第一个数据包时,它在所有的TPC数据包中search这个string都是浪费CPU周期的愚蠢。 它甚至会是错误的,因为后面跟着两个CR / LF的“HTTP / 1.1”可能是http请求有效载荷内合法的传输部分。

这里http://spamcleaner.org/en/misc/w00tw00t.html是这个问题的一个解决scheme,但我不明白标识build立的tcp连接的第一个数据包的部分。

我不明白的是,为什么在INPUT-Chain中只能看到初始TCP-Handshake(SYN,ACK + SYN,ACK)的所有3个数据包,或者只能从INPUT到达的链中。 据我了解iptables及其链,第二个数据包(ACK + SYN)永远不会经过INPUT。 我认为它传递OUTPUT是因为它发送它的我(即服务器)。

这是spamcleaner.org的脚本,我在脚本的第一部分只改了一些注释,但是我保留了所有的命令:

 #!/bin/bash # allow loopback iptables -A INPUT -i lo -j ACCEPT # DROP any IP that is in the blacklist "w00tlist" and set the # blacklist-timeout to 6 hour iptables -A INPUT -p tcp -m recent --name w00tlist --update --seconds 21600 -j DROP # create the chain "w00tchain" iptables -N w00tchain # this chain will add the IP to the blacklist "w00tlist" # and will reset the connection: iptables -A w00tchain -m recent --set --name w00tlist -p tcp \ -j REJECT --reject-with tcp-reset # create another chain named "w00t". It's purpose is to identify the first packet # of an newly established tcp-connection and to search for a string in it: iptables -N w00t # redirect all incoming (no outgoing!) TCP packets to the chain "w00t": iptables -A INPUT -p tcp -j w00t # all remaining rules are part of the chain "w00t" #--------------------------------------------------------------- # all following comments in lowercase are unchanged from spamcleaner.org # COMMENTS IN UPPERCASE ARE FROM ME #--------------------------------------------------------------- # look for the SYN packet and create the list : iptables -A w00t -m recent -p tcp --syn --dport 80 --set # look for the SYN,ACK packet and update the list : iptables -A w00t -m recent -p tcp --tcp-flags PSH,SYN,ACK SYN,ACK --sport 80 --update #--------------------------------------------------------------------------------- # THIS IS WHAT I DON'T UNDERSTAND: # THE CHAIN w00t CAN ONLY BE REACHED FROM THE CHAIN INPUT. SO WE ARE DEALING HERE # WITH PACKETS THAT THE CLIENT IS SENDING AND THAT THE SERVER IS RECEIVING. BUT IN # STEP 2 OF TCP-HANDSHAKE ITS THE SERVER WHO IS SENDING AND THE CLIENT WHO IS # RECEIVING. SO THE PACKET WITH SYN AND ACK SET AND WITH sport 80 GOES THROUGH THE # CHAIN "OUTPUT", NOT "INPUT". SO HOW CAN IT BE DETECTED IN CHAIN w00t? #--------------------------------------------------------------------------------- # look for the ACK packet and update the list : iptables -A w00t -m recent -p tcp --tcp-flags PSH,SYN,ACK ACK --dport 80 --update # look for the hexadecimal string in the first PSH+ACK. # If found, redirect to w00tchain in order to blacklist the IP and # to close the connection. # Delete our list, we do not want to filter any further packet from that connection : iptables -A w00t -m recent -p tcp --tcp-flags PSH,ACK PSH,ACK --dport 80 --remove \ -m string --to 80 --algo bm --hex-string '|485454502f312e310d0a0d0a|' -j w00tchain 

还有一个我不明白的地方:

最后一条规则是search包含PSH-和ACK-flags的数据包中的hexstring。 但我怎么能确定,PSH是为我的数据包设置的? 我不确定,但我认为它可能合法发送的PSH标志未设置的TCP数据包。

编辑:有一个第三个问题:如果服务器同时从相同的IP地址(每个请求具有自己的端口号)接收两个通过TCP的HTTP请求?

忘记IPTables。 您可以简单地使用mod_security和nolog操作。 像这样(未经testing):

 SecRule REQUEST_URI "^/w00tw00t\.at\.ISC\.SANS\.DFind" phase:1,nolog,deny,id:1000 

或者,您可以使用单独的日志创build一个虚拟虚拟主机,它只是拒绝所有请求并将其configuration为第一个。 不提供主机名或提供未知主机名的客户端将始终在那里结束。