I am running tcpdump
from within Python and I would like to know how many packets are dropped by the kernel.
When run on a command line, tcpdump looks like this:
me@mypc:$ sudo tcpdump -w myPackets.cap -i eth0 ip
tcpdump: listening on eth2, link-type EN10MB (Ethernet), capture size 65535 bytes
^C28 packets captured
28 packets received by filter
0 packets dropped by kernel
This is how I call tcpdump
in my Python script:
f_out = open("tcpdumpSTDOUT", "w")
f_err = open("tcpdumpSTDERR", "w")
tcpdumpProcess = subprocess.Popen(['tcpdump',
'-w', 'myPackets.cap', '-i', 'eth0', '-n','ip'],
stdout=f_out,
stderr=f_err)
# a few seconds later:
tcpdumpProcess.kill()
f_in.close()
f_out.close()
Now, if I look at tcpdumpSTDERR
, I only see the first of the usual output lines:
tcpdump: listening on eth0, link-type EN10MB (Ethernet), capture size 65535 bytes
Where's all the rest?
EDIT I tried a different approach:
>>> myProcess = subprocess.Popen("tcpdump -w myPackets.cap -i eth2 ip", shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
>>> myProcess.communicate()
Then I killed tcpdump from a different shell, and the output of commnunicate() was displayed:
('', 'tcpdump: listening on eth2, link-type EN10MB (Ethernet), capture size 65535 bytes\n')
... still the first line only!
EDIT 2 Interestingly:
>>> import shlex
>>> a = subprocess.Popen(shlex.split("tcpdump -w myPackets.cap -i eth2 ip"), stdout=subprocess.PIPE, stderr=subprocess.PIPE)
>>> a.terminate()
>>> a.communicate()
('', 'tcpdump: listening on eth2, link-type EN10MB (Ethernet), capture size 65535 bytes\n221 packets captured\n221 packets received by filter\n0 packets dropped by kernel\n')
The problem was that I called kill()
on the process instead of terminate()
. With the latter, all messages get stored in whatever I specified as stderr
(tcpdump, for some reason, writes to stderr and not to stdout).
So, in case it might help others, I decided to redirect stderr to subprocess.PIPE
and parse the string directly in Python:
>>> tcpdumpProcess = subprocess.Popen(['tcpdump',
'-w', 'myPackets.cap', '-i', 'eth0', '-n','ip'],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
>>> tcpdumpProcess.terminate()
# stdout in [0], stderr in [1]
>>> tcpdump_stderr = tcpdumpProcess.communicate()[1]
>>> print tcpdump_stderr
tcpdump: listening on eth2, link-type EN10MB (Ethernet), capture size 65535 bytes
40 packets captured
40 packets received by filter
0 packets dropped by kernel