如何通过 IP 查找给定端口和时间段内的 TCP 连接总数?

如何通过 IP 查找给定端口和时间段内的 TCP 连接总数?

在 Linux 系统上,有很多方法可以列出当前的通过连接 IP 来获取给定端口的 TCP 连接但:如何计算一段时间内每个源 IP 的端口的总连接数?

答案1

打开 iptables 并将其设置LOG为用于传入连接。示例规则:

 -A INPUT --state NEW -p tcp --dport 4711 -j LOG

(其中 4711 是您要跟踪的端口)。

然后通过您喜欢的任何可以为您进行摘要的脚本运行结果日志。

答案2

您可以使用 tcpdump 记录所有 SYN(无 ACK)数据包:

tcpdump "dst port 4711 and tcp[tcpflags] & (tcp-syn|tcp-ack) == tcp-syn"

或者记录所有 SYN+ACK 数据包(已建立的连接):

tcpdump "src port 4711 and tcp[tcpflags] & (tcp-syn|tcp-ack) == (tcp-syn|tcp-ack)"

然后将其与 a 结合起来wc -l计算所有行数

您还需要一种方法来测量固定时间段(您可以让 cron 定期向其发送 SIGINT,tcpdump 将计算字节和数据包,但仅记录时间)

更新:不用多说,看看 tcpdump 的手册页,考虑使用一些选项,如:(-i只监听一个接口)、-p(禁用混杂模式;侵入性较小)或一些输出选项。Tcpdump 需要 root 权限,你的老板可能不喜欢它,因为它是一种黑客工具。另一方面,你不需要触碰系统上的任何东西来运行它(与解决方案相反iptables LOG

还请注意过滤器中的 src/dsk 细微差异。如果您捕获 SYN+ACK 数据包并想要计算连接数端口为 4711 的服务器,您需要 src。如果您要捕获 SYN+!ACK 数据包以获得相同结果,则需要 dst。如果您计算服务器本身上的连接数,则必须始终使用反向。

答案3

SystemTap 解决方案

剧本灵感来自tcp_连接.stp例子:

#!/usr/bin/env stap
# To monitor another TCP port run:
#     stap -G port=80 tcp_connections.stp
# or
#     ./tcp_connections.stp -G port=80
global port = 22
global connections

function report() {
  foreach (addr in connections) {
    printf("%s: %d\n", addr, @count(connections[addr]))
  }
}

probe end {
  printf("\n=== Summary ===\n")
  report()
}

probe kernel.function("tcp_accept").return?,
      kernel.function("inet_csk_accept").return? {
  sock = $return
  if (sock != 0) {
    local_port = inet_get_local_port(sock)
    if (local_port == port) {
      remote_addr = inet_get_ip_source(sock)
      connections[remote_addr] <<< 1
      printf("%s New connection from %s\n", ctime(gettimeofday_s()), remote_addr)
    }
  }
}

输出:

[root@bubu ~]# ./tcp_connections.stp -G port=80
Mon Mar 17 04:13:03 2014 New connection from 192.168.122.1
Mon Mar 17 04:13:04 2014 New connection from 192.168.122.1
Mon Mar 17 04:13:08 2014 New connection from 192.168.122.4
^C
=== Summary ===
192.168.122.1: 2
192.168.122.4: 1

strace 解决方案

在 strace 下启动程序:

strace -r -f -e trace=accept -o /tmp/strace ${PROGRAM} ${ARGS}

或者跟踪一个已经运行的程序:

strace -r -f -e trace=accept -o /tmp/strace -p ${PID_OF_PROGRAM}

-r在进入每个系统调用时打印一个相对时间戳,以防以后需要进行额外的性能分析。-f跟踪子进程,但可能不需要。

输出如下所示:

999        0.000000 accept(3, {sa_family=AF_INET, sin_port=htons(34702), sin_addr=inet_addr("192.168.122.4")}, [16]) = 5
999        0.008079 --- SIGCHLD (Child exited) @ 0 (0) ---
999        1.029846 accept(3, {sa_family=AF_INET, sin_port=htons(34703), sin_addr=inet_addr("192.168.122.4")}, [16]) = 5
999        0.008276 --- SIGCHLD (Child exited) @ 0 (0) ---
999        3.580122 accept(3, {sa_family=AF_INET, sin_port=htons(50114), sin_addr=inet_addr("192.168.122.1")}, [16]) = 5

并可以使用以下方式进行过滤:

# gawk 'match($0, /^([0-9]+)[[:space:]]+([0-9.]+)[[:space:]]+accept\(.*htons\(([^)]+)\),.*inet_addr\("([^"]+)"\).*[[:space:]]+=[[:space:]]+([1-9][0-9]*)/, m) {connections[m[4]]++} END {for (addr in connections) printf("%s: %d\n", addr, connections[addr]); }' /tmp/strace
192.168.122.4: 3
192.168.122.1: 2

AKW 单行命令的简短解释:m[1]是 PID,m[2]是时间戳,m[3]是远程端口,m[4]是远程地址。

优势此解决方案的优点是,如果服务器在同一用户下运行,则不需要 root 权限。坏处是所有连接都计算在内,没有过滤,所以如果应用程序监听多个端口,它将不起作用。

答案4

到目前为止,对我来说最有效的解决方案是每 20 秒抓取一次 /proc/net/ip_conntrack 的内容,将其记录到文件名包含适当时间戳的文件中,并在必要时将其用作任何过滤脚本的输入,甚至用作单行脚本的输入。为了节省您的时间,您可以使用我的脚本。我使用 crontab 条目来确保脚本每分钟运行一次(在当前配置下,它持续 60 秒,请随意修改它 :-)

 cat conn_minute.sh
#!/bin/bash

function save_log {
LOG_DIR=/mnt/logs/ip_conntrack/`date +%Y%m%d`
TEMP_FILE=$LOG_DIR/`date +%Y%m%d_%H%M%S`.gz
LOG_FILE=$LOG_DIR/`date +%Y%m%d_%H`.tar
if [ ! -d $LOG_DIR ]
then
    mkdir $LOG_DIR
fi
gzip -c /proc/net/ip_conntrack > $TEMP_FILE
if [ -f $LOG_FILE ]; then
    tar -rf $LOG_FILE $TEMP_FILE 2> /dev/null
else
    tar -cf $LOG_FILE $TEMP_FILE 2> /dev/null
fi
rm $TEMP_FILE
}
function log_minute {
i=1;
LOOP_COUNTER=3
LOOP_TIME=20
while [ $i -le $LOOP_COUNTER ]; do
    save_log
    i=$[i+1]
    sleep $LOOP_TIME
done
}

log_minute

您可以通过相应地更改 LOOP_COUNTER 和 LOOP_TIME 来调整转储 ip_conntrack 内容的频率。因此,每 5 秒转储一次,则应为:LOOP_COUNTER=12 ,LOOP_TIME=5。LOG_DIR 表示日志的保存位置。

之后,您可以使用 zcat 来 cat 您感兴趣的文件,并使用 grep 来过滤您感兴趣的源 IP/端口(或者只使用 zgrep)。grep -c将计算您想要的任何内容。您也可以使用grep src=1.2.3.4 | grep dport=63793 | sort | uniq | wc -l

相关内容