几周前,我遇到了一个问题,我在大约 300 个节点的大型网络中更改了 DNS 地址。之后,一些节点仍然继续询问旧的 DNS 服务器,尽管 resolv.conf 没问题,并且 host/nslookup 正在查询新的 DNS 服务器。
查看 tcpdump 并尝试使用 iptables 日志记录请求,我确认确实有一些主机仍在向旧的名称服务器发送查询。
我把其中一台主机从生产中撤出,并开始关闭服务/跟踪进程,试图找出罪魁祸首。
最后 - 它是 lldpd 守护进程,它显然在启动时缓存了名称服务器,甚至没有注意到 resolv.conf 中的变化。
所以,我的问题是 - 有没有更智能的方法来找出哪个 PId 正在生成特定类型的流量?我尝试使用 auditctl,但没有成功。CentOS 6 有问题,但如果有任何 Linux 发行版的解决方案,我将不胜感激。
答案1
auditctl 有什么问题?
你会这样做
1) 定义审计规则以审计 sendmsg 和 sendto 系统调用。这些系统调用在名称解析期间使用。
auditctl -a exit,always -F arch=b64 -S sendmsg -S sendto -k send
2)现在搜索您的审计记录。您可以在此处根据远程 DNS IP 进行 grep
ausearch -k send -i|grep -A2 "serv:53"
在下面的例子中,你可以看到负责系统调用的应用程序名为 dig
ausearch -k send -i|grep -A2 "serv:53"
type=SOCKADDR msg=audit(10/31/2016 15:24:56.264:176998) : saddr=inet host:172.16.0.23 serv:53
type=SYSCALL msg=audit(10/31/2016 15:24:56.264:176998) : arch=x86_64 syscall=sendmsg success=yes exit=29 a0=14 a1=7fa1919f9ac0 a2=0 a3=7fa1919f9780 items=0 ppid=31729 pid=32047 auid=root uid=root gid=root euid=root suid=root fsuid=root egid=root sgid=root fsgid=root tty=pts5 ses=52 comm=dig exe=/usr/bin/dig subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 key=send
comm=dig exe=/usr/bin/dig
区分向哪个远程 DNS 请求发送的方法就在这里。因此,您只需 grep 特定的 DNS 主机即可。
saddr=inet host:172.16.0.23 serv:53
或者更好的是 - 查看使用了哪些 DNS 主机(在这个例子中我只有一个)
ausearch -k send -i|grep "serv:53"|awk '{print $6}'|sort|uniq -c
3 host:172.16.0.23
然后缩小使用这些特定主机的应用程序的范围。
编辑 1:实际上我只是对主机进行了简单的 ping 操作。似乎 sendmsg 并不总是被使用。以下是我所看到的
socket(PF_INET, SOCK_DGRAM|SOCK_NONBLOCK, IPPROTO_IP) = 4
connect(4, {sa_family=AF_INET, sin_port=htons(53), sin_addr=inet_addr("172.16.0.23")}, 16) = 0
gettimeofday({1477929832, 712018}, NULL) = 0
poll([{fd=4, events=POLLOUT}], 1, 0) = 1 ([{fd=4, revents=POLLOUT}])
sendto(4, "\3\326\1\0\0\1\0\0\0\0\0\0\tvkontakte\2ru\0\0\1\0\1", 30, MSG_NOSIGNAL, NULL, 0) = 30
poll([{fd=4, events=POLLIN}], 1, 5000) = 1 ([{fd=4, revents=POLLIN}])
ioctl(4, FIONREAD, [62]) = 0
recvfrom(4, "\3\326\201\200\0\1\0\2\0\0\0\0\tvkontakte\2ru\0\0\1\0\1\300\f"..., 1024, 0, {sa_family=AF_INET, sin_port=htons(53), sin_addr=inet_addr("172.16.0.23")}, [16]) = 62
close(4) = 0
我之前的示例基于 dig 应用程序,它在系统调用方面采用了略有不同的路线。
因此,在大多数情况下,看起来应该是这个规则
auditctl -a exit,always -F arch=b64 -S connect -k connect
随后是 ausearch
ausearch -k connect -i|grep saddr|grep "serv:53"|awk '{print $6}'|sort|uniq -c
答案2
几天前,我也遇到了同样的问题,并想出了一个非常简单的方法。它基于以下事实:发送进程将在发送请求的同一端口上等待 DNS 响应:
- 使用以下命令找出传出 DNS 请求的源端口:
iptables -j LOG
- 用于
lsof -i UDP:<source_port>
找出哪个进程正在该端口上等待响应。
当然,由于响应会在几毫秒内到达,因此您无法手动执行此操作;此外,即使自动执行,也无法保证您能够在 DNS 响应到达之前查询系统,并且发送过程会终止。这就是为什么在执行上述步骤之前,我还将内核流量控制器配置为延迟传出数据包定向到特定的 IP/端口(使用模块tc
)netem
。这样,我就可以控制查询系统哪个 PID 正在等待 DNS 响应的时间窗口,在步骤 1 中获得的源 UDP 端口上。
tc
我已经在一个名为的小脚本中自动执行了上述步骤(包括延迟)。陷阱(这是一个更通用的解决方案,不仅限于 DNS 请求,因此可以使用任何基于 TCP/UDP 的协议检测进程)。借助它,我发现,在我的例子中,联系旧 DNS 服务器的服务是 sendmail。
答案3
有atop
。有一个内核模块(netatop
)和守护进程可以atop
跟踪进程的网络使用情况。
您应该首先安装atop
以下是安装内核模块的方法。在撰写本文时,这种方法是有效的,但可能会过时:
sudo apt install linux-headers-$(uname -r) make zlib1g-dev
wget https://www.atoptool.nl/download/netatop-2.0.tar.gz
tar xvf netatop-2.0.tar.gz
cd netatop-2.0
make
sudo make install
sudo modprobe -v netatop
netatopd.service
如果你有 systemd,请在 中创建服务文件/etc/systemd/system/
。它将包含:
[Unit]
Description=NetAtop Daemon
[Service]
Type=forking
ExecStart=/usr/sbin/netatopd
[Install]
WantedBy=multi-user.target
现在您可以启用守护进程:
sudo systemctl enable netatopd
要查看每个进程的实时网络使用情况:
sudo atop -n
要查看一天中网络占用最大的前 3 个时间:
atopsar -N
man atopsar
以获得更多选项。
答案4
有许多选项可以netstat
显示通过 tcp/udp/both 监听/打开套接字的组合。例如:
$> sudo netstat -pan
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Addr Foreign Addr State PID/Program name
...
tcp 0 1 192.168.66.1:39219 192.168.66.139:2003 SYN_SENT 2045/logstash-forwa
...会给你很多输出,但包括源、目标、端口号和拥有这些端口的进程的 PID。