Linux – How to find out PID of the process sending packets (generating network traffic)

auditdlinuxnetworking

Couple of weeks ago I had an issue where I changed DNS addresses in large network of around 300 nodes. After that, some of the nodes still continued to ask old DNS servers, although resolv.conf was ok, and host/nslookup were querying new DNS servers.

Looking at tcpdump and trying to record requests with iptables logging, I confirmed that indeed some of the hosts were still sending queries to old nameservers.

I took one of the hosts out of production and started shutting down services / stracing processes in an attempt to find out the culprit.

At the end – it was lldpd daemon, which obviously cached nameservers at startup and didn't even notice changes in resolv.conf.

So, my question is – is there a more intelligent way to find out which PId is generating specific kind of traffic? I tried with auditctl but without much success. CentOS 6 is in question but if there is solution for any Linux distro, I would appreciate it.

Best Answer

What's wrong with the auditctl?

You would do it like this

1) Define your audit rule to audit sendmsg and sendto system calls. These system calls are used during name resolution.

auditctl -a exit,always -F arch=b64 -S sendmsg -S sendto -k send

2) Now search for your audit records. You can grep based on the remote DNS IP here

ausearch -k send -i|grep -A2 "serv:53"

In the below example you can see that application which was responsible for the systemcall is called 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

And the way to differentiate to which remote DNS request is send is here. So you would just have to grep for a particular DNS host.

saddr=inet host:172.16.0.23 serv:53 

Or even better - see what DNS hosts are used (I have only one in this example)

ausearch -k send -i|grep "serv:53"|awk '{print $6}'|sort|uniq -c
      3 host:172.16.0.23

And then narrow down which apps are using those particular hosts.

Edit 1: Actually I just did strace of a simple ping to a host. Seems like sendmsg is not always used. Here is what I see

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

My previous example was based on dig app, which takes slightly different route in terms of system calls.
So it looks like in majority of cases it would be this rule

auditctl -a exit,always -F arch=b64 -S connect -k connect

Followed by ausearch

ausearch -k connect -i|grep saddr|grep "serv:53"|awk '{print $6}'|sort|uniq -c