使用 iptables 捕获已建立的 TCP 连接的第一个数据包?

使用 iptables 捕获已建立的 TCP 连接的第一个数据包?

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

答案1

您可以使用(滥用)来实现您的目标iptables,更具体地说:connbytes匹配和NFQUEUE目标。connbytes允许您匹配连接中的第 N 个数据包,并且NFQUEUE是一种将匹配 iptables 规则的数据包传递给用户空间程序的机制。此外:您必须使用一些程序,该程序将从内核接收相关数据包并对其进行处理。

iptables

我在这里假设你有兴趣在服务器端捕获数据包(如果你有兴趣在客户端捕获,可以更改)。在这种情况下,我们需要捕获第三次来袭为每个连接提取一个数据包(即三次握手后的第一个传入数据包)并将数据包放入 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 可以随意对流进行分段,并且在第一个数据包中接收单个字节并非不可能。
  2. TCP 快速打开会破坏此方法的逻辑。如果启用,初始三次握手可能已经传输数据。但目前几乎所有设备上的 TFO 都默认禁用。
  3. 使用目标时必须小心NFQUEUE:如果绑定到队列的用户空间程序挂起、崩溃或处理数据包的速度很慢,这些数据包将被丢弃/卡住,并且绑定到指定端口的服务将无法访问。如果没有用户空间程序绑定到指定队列,您可以将选项传递--queue-bypassNFQUEUE目标以ACCEPT匹配数据包:这应该有助于解决程序崩溃的问题,但对挂起或缓慢的程序无济于事。

答案2

您无法使用 stock 执行您要查找的操作iptables。您需要编写一些第 7 层检查代码。

如果您愿意忍受一些后期处理,另一种方法是将流量捕获到tcpdumpPCAP 文件中,解析它们以获取您要查找的数据包,然后丢弃其余数据包。我知道 Wireshark 的 SSL 解析器和显示过滤器可以得到您想要的东西。

如果您不介意捕获速度比实时速度稍慢,您可以轻松使用tcpdump它来捕获轮换 PCAP 文件的流量。您可以运行一个脚本来监视已完成的 PCAP 文件并使用tshark显示过滤器对其进行解析,以便只将您要查找的内容写入新的 PCAP 文件。

答案3

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

正确的 !

不确定您所说的“捕获”是什么意思。iptables是一个东西,网络数据包捕获(tcpdump)是另一回事。

假设我的理解是“仅记录新连接”,那么您将必须仅记录与状态匹配的规则NEW

让我们使用一个示例案例,其中我们只想记录 icmp(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

这里我们只记录建立连接的LOG时间NEW。因此我们可以发送 1000 次以上的 ping(来自同一源主机),只有第一个数据包会被记录:

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 请求都会被记录。因此 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
......
......

希望我已经理解了这个问题!

相关内容