How I can identify which process is making UDP traffic on Linux?
Solution 1:
Linux auditing can help. It will at least locate users and processes making datagram network connections. UDP packets are datagrams.
First, install the auditd
framework on your platform and ensure that auditctl -l
returns something, even if it says that no rules are defined.
Then, add a rule to watch the system call socket()
and tag it for easy finding later (-k
). I need to assume that you are on a 64-bit architecture, but you can substitute b32
in place of the b64
if you aren't.
auditctl -a exit,always -F arch=b64 -F a0=2 -F a1\&=2 -S socket -k SOCKET
You have to pick through man pages and header files to build this, but what it captures is essentially this system call: socket(PF_INET, SOCK_DGRAM|X, Y)
, where the third parameter is unspecified but frequently zero. PF_INET
is 2 and SOCK_DGRAM
is 2. TCP connections would use SOCK_STREAM
which would set a1=1
. (SOCK_DGRAM
in the second parameter may be ORed with SOCK_NONBLOCK
or SOCK_CLOEXEC
, hence the &=
comparison.) The -k SOCKET
is our keyword we want to use when searching audit trails later. It can be anything, but I like to keep it simple.
Let a few moments go by and review the audit trails. Optionally, you could force a couple of packets by pinging a host out on the net, which will cause a DNS lookup to occur, which uses UDP, which should trip our audit alert.
ausearch -i -ts today -k SOCKET
And output similar to the section below will appear. I'm abbreviating it to highlight the important parts
type=SYSCALL ... arch=x86_64 syscall=socket success=yes exit=1 a0=2 a1=2 ... pid=14510 ... auid=zlagtime uid=zlagtime ... euid=zlagtime ... comm=ping exe=/usr/bin/ping key=SOCKET
In the above output, we can see that the ping
command caused the socket to be opened. I could then run strace -p 14510
on the process, if it was still running. The ppid
(parent process ID) is also listed in case it is a script that spawns the problem child a lot.
Now, if you have a lot of UDP traffic, this isn't going to be good enough and you'll have to resort to OProfile or SystemTap, both of which are currently beyond my expertise.
This should help narrow things down in the general case.
When you are done, remove the audit rule by using the same line you used to create it, only substitute -a
with -d
.
auditctl -d exit,always -F arch=b64 -F a0=2 -F a1\&=2 -S socket -k SOCKET
Solution 2:
You can use netstat, but you need the right flags, and it only works if the process that is sending the data is still alive. It won't find the traces of something that came briefly to life, sent UDP traffic, then went away. It also requires local root privileges. That said:
Here's me starting an ncat on my local host, sending UDP traffic to port 2345 on a (non-existent) machine 10.11.12.13:
[madhatta@risby]$ ncat -u 10.11.12.13 2345 < /dev/urandom
Here's some tcpdump output proving that the traffic is going:
[root@risby ~]# tcpdump -n -n port 2345
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), capture size 65535 bytes
12:41:32.391750 IP 192.168.3.11.57550 > 10.11.12.13.2345: UDP, length 8192
12:41:32.399723 IP 192.168.3.11.57550 > 10.11.12.13.2345: UDP, length 8192
12:41:32.401817 IP 192.168.3.11.57550 > 10.11.12.13.2345: UDP, length 8192
12:41:32.407051 IP 192.168.3.11.57550 > 10.11.12.13.2345: UDP, length 8192
12:41:32.413492 IP 192.168.3.11.57550 > 10.11.12.13.2345: UDP, length 8192
12:41:32.417417 IP 192.168.3.11.57550 > 10.11.12.13.2345: UDP, length 8192
Here's the useful bit, using netstat with the -a flag (to see port details) and the -p flag to see process ID details. It's the -p flag that requires root privileges:
[root@risby ~]# netstat -apn|grep -w 2345
udp 0 0 192.168.3.11:57550 10.11.12.13:2345 ESTABLISHED 9152/ncat
As you can see, pid 9152 is fingered as having a connection open to port 2345 on the specified remote host. Netstat helpfully also runs that through ps and tells me the process name is ncat
.
Hopefully that's of some use.
Solution 3:
I had exactly the same problem and unfortunately auditd
didn't do much for me.
I had traffic from some of my servers going towards google DNS addresses, 8.8.8.8
and 8.8.4.4
. Now, my network admin has mild OCD and he wanted to clean all the unnecessary traffic since we have our intern DNS caches. He wanted to disable outgoing port 53 for everyone except those cache servers.
So, after failing with auditctl
, I dig into systemtap
. I come up with the following script:
# cat >> udp_detect_domain.stp <<EOF
probe udp.sendmsg {
if ( dport == 53 && daddr == "8.8.8.8" ) {
printf ("PID %5d (%s) sent UDP to %15s 53\n", pid(), execname(), daddr)
}
}
EOF
Then simply run:
stap -v udp_detect_domain.stp
This is the output that I got:
PID 3501 (python) sent UDP to 8.8.8.8 53
PID 3501 (python) sent UDP to 8.8.8.8 53
PID 3506 (python) sent UDP to 8.8.8.8 53
That's it! After changing resolv.conf
those PIDs didn't pick up the changes.
Hope this helps :)
Solution 4:
Here's a systemtap option, using the netfilter probes available in stap verson 1.8 and later. See also man probe::netfilter.ip.local_out
.
# stap -e 'probe netfilter.ip.local_out {
if (dport == 53) # or parametrize
printf("%s[%d] %s:%d\n", execname(), pid(), daddr, dport)
}'
ping[24738] 192.168.1.10:53
ping[24738] 192.168.1.10:53
^C
Solution 5:
I would use a net-sniffer like tcpdump or wireshark to view the DNS requests. The contents of the query can give an idea of what program is issuing them.