捕获与iptablesbuild立的TCP连接的第一个数据包?

我正在寻找一种方法来检查新build立的TCP连接的第一个数据包(实际有效负载的第一个数据包,即是)。 有没有办法与iptables做到这一点? 匹配ESTABLISHED包将在握手后匹配连接的所有包,对吗?

你可以使用(滥用) iptables来实现你的目标,更具体一些: connbytes match和NFQUEUE target。 connbytes允许您匹配连接中的第N个数据包,而NFQUEUE是一个将匹配iptables规则的数据包传递给用户空间程序的机制。 此外:你将不得不使用一些程序,从内核接收相关数据包并处理它们。

iptables的

我在这里假设你有兴趣捕获服务器端的数据包(如果你对客户端捕获感兴趣,可以改变它)。 在这种情况下,我们需要为每个连接(即三次握手之后的第一个input数据包)捕获第三个input数据包,并将数据包放入netfilter队列(在这种情况下为队列#1)。

 iptables -I INPUT -p tcp -m tcp --dport 12345 -m connbytes --connbytes-mode packets --connbytes-dir original --connbytes 3:3 -j NFQUEUE --queue-num 1 

一旦数据包符合这个规则,它将被传递到绑定到队列#1的用户空间程序。 程序然后可以检查数据包,然后决定接受或丢弃数据包。

该程序

您将需要一个程序,它将使用libnetfilter_queue库来接收用户空间中的数据包。 图书馆的绑定可以使用不同的语言。 以下是用python编写的示例程序:

 import struct from netfilterqueue import NetfilterQueue def ip_to_string(ip): return ".".join(map(lambda n: str(ip>>n & 0xff), [24,16,8,0])) def print_and_accept(pkt): pl = pkt.get_payload() src_ip = struct.unpack('>I', pl[12:16])[0] tcp_offset = (struct.unpack('>B', pl[0:1])[0] & 0xf) * 4 tmp = struct.unpack('>B', pl[tcp_offset+12:tcp_offset+13])[0] data_offset = ((tmp & 0xf0) >> 4) * 4 src_port = struct.unpack('>H', pl[tcp_offset+0:tcp_offset+2])[0] data = pl[tcp_offset + data_offset:] print 'from {}:{}, "{}"'.format(ip_to_string(src_ip), src_port, data) pkt.accept() nfqueue = NetfilterQueue() nfqueue.bind(1, print_and_accept) try: nfqueue.run() except KeyboardInterrupt: print 

该程序假定排队的数据包将是IPv4 TCP数据包,并打印源ip:端口对和数据包的TCP有效负载。

注意事项

  1. 您永远无法确定第一个数据包是否具有完整的TLS客户端hello – TCP可以按照喜欢的方式对该stream进行分段,并且在第一个数据包中接收单个字节也不是不可能的。
  2. TCP Fast Open将打破这种方法的逻辑。 如果启用,则最初的三次握手可能已经传输了数据。 但是现在几乎所有设备上的TFO默认都是禁用的。
  3. 使用NFQUEUE目标时必须小心:如果绑定到队列的用户空间程序挂起,崩溃或处理数据包的速度较慢,则这些程序将被丢弃/卡住,绑定到指定端口的服务将无法访问。 如果没有用户空间程序绑定到指定的队列,你可以将--queue-bypass选项传递给NFQUEUE目标来ACCEPT匹配的数据包:这应该有助于解决程序崩溃的问题,但不会帮助挂起或缓慢程序。

你不能用股票iptables做你正在寻找的东西。 您需要编写一些第7层检查代码。

另一种方法是,如果你愿意忍受一些后期处理,那么将使用tcpdump捕获stream量到PCAP文件中,parsing它们,找出你正在查找的数据包,然后丢弃剩余的数据。 我知道Wireshark的SSLparsing器和一个显示filter可以得到你要找的东西。

如果你不介意你的捕捉会落后于实时,那么你可以很容易地使用tcpdump来捕捉stream量来旋转PCAP文件。 你可以运行一个脚本来监视已经完成的PCAP文件,并用tshark和一个显示filter来分析它们,以便只写出你正在寻找的新PCAP文件。

匹配ESTABLISHED包将在握手后匹配连接的所有包,对吗?

对 !

不知道你是什么意思的“捕获”。 iptables是一件事情,networking数据包捕获( tcpdump )是另一回事。

假设我的理解是“仅logging新的连接”,那么只需要logging符合NEW状态的规则。

让我们使用一个示例,我们只想loggingicmp(ping)请求的新连接:

 # Define LOG settings iptables -N LOG_ACCEPT iptables -A LOG_ACCEPT -j LOG --log-prefix '[IPTABLES ACCEPT] :' iptables -A LOG_ACCEPT -j ACCEPT iptables -A INPUT -p icmp -d 192.168.0.47 -m state --state NEW -j LOG_ACCEPT iptables -A INPUT -p icmp -d 192.168.0.47 -m state --state ESTABLISHED,RELATED -j ACCEPT 

这里我们只是build立NEW连接时的LOG 。 所以我们可以发送1000+ ping(来自同一个源主机),只有第一个数据包会被logging:

 Apr 4 21:28:17 UBN-1 kernel: [78512.613705] [IPTABLES ACCEPT] :IN=eth0 OUT= MAC=00:0c:29:e4:d1:06:10:60:4b:69:7e:fd:08:00 SRC=192.168.0.39 DST=192.168.0.47 LEN=60 TOS=0x00 PREC=0x00 TTL=128 ID=32571 PROTO=ICMP TYPE=8 CODE=0 ID=2 SEQ=47088 

如果将LOG_ACCEPT放在ESTABLISHED,RELATED规则中:

 iptables -A INPUT -p icmp -d 192.168.0.47 -m state --state NEW -j LOG_ACCEPT iptables -A INPUT -p icmp -d 192.168.0.47 -m state --state ESTABLISHED,RELATED -j LOG_ACCEPT 

那么每个ping请求都会被logging下来。 因此,1000+ ping(来自同一个源主机)会在日志中生成1000多个条目:

 Apr 4 21:33:49 UBN-1 kernel: [78844.130615] [IPTABLES ACCEPT] :IN=eth0 OUT= MAC=00:0c:29:e4:d1:06:10:60:4b:69:7e:fd:08:00 SRC=192.168.0.39 DST=192.168.0.47 LEN=60 TOS=0x00 PREC=0x00 TTL=128 ID=244 PROTO=ICMP TYPE=8 CODE=0 ID=2 SEQ=47092 Apr 4 21:33:50 UBN-1 kernel: [78845.130551] [IPTABLES ACCEPT] :IN=eth0 OUT= MAC=00:0c:29:e4:d1:06:10:60:4b:69:7e:fd:08:00 SRC=192.168.0.39 DST=192.168.0.47 LEN=60 TOS=0x00 PREC=0x00 TTL=128 ID=247 PROTO=ICMP TYPE=8 CODE=0 ID=2 SEQ=47093 Apr 4 21:33:51 UBN-1 kernel: [78846.131295] [IPTABLES ACCEPT] :IN=eth0 OUT= MAC=00:0c:29:e4:d1:06:10:60:4b:69:7e:fd:08:00 SRC=192.168.0.39 DST=192.168.0.47 LEN=60 TOS=0x00 PREC=0x00 TTL=128 ID=250 PROTO=ICMP TYPE=8 CODE=0 ID=2 SEQ=47094 Apr 4 21:33:52 UBN-1 kernel: [78847.132160] [IPTABLES ACCEPT] :IN=eth0 OUT= MAC=00:0c:29:e4:d1:06:10:60:4b:69:7e:fd:08:00 SRC=192.168.0.39 DST=192.168.0.47 LEN=60 TOS=0x00 PREC=0x00 TTL=128 ID=252 PROTO=ICMP TYPE=8 CODE=0 ID=2 SEQ=47095 ...... ...... 

希望我已经明白了这个问题!