It’s no secret that I’m a big fan of computer systems that are running a Unix-like or Unix-derived operating system. There are quite a few around me right now, running FreeBSD, Linux-Mint and Mac OS X Lion. I have a couple more that I keep around in Virtualbox, but don’t use that often. What I really like about Unix , second to its excellent and massive documentation, is its logfiles. Nearly everything you can think of is – or can be – logged into a simple human readable textfile. One of the first things you’d learn using Unix is that syslog will handle logfiles for most of the entire system.“Most? Not all?” Yes, that’s true. Not everything is handled by syslog. A noticeable exception on BSD systems is the PF logging daemon. From the manual-page:
pflogd is a background daemon which reads packets logged by pf(4) to a pflog(4) interface, normally pflog0, and writes the packets to a logfile (normally /var/log/pflog) in tcpdump(1) binary format.
Although tcpdump’s binary format (pcap!) is truly magnificent, as you can feed it to wireshark and replay recorded sessions and stuff like that, it was for me the start of a small shell scripting exercise to get it back to text and syslog so I can read it without too much fancy tooling. Here’s the result:
#!/bin/sh # -- Globals export PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin SCRIPT="`basename $0 | sed 's/\..*//'`" LOCKFILE="/var/run/$SCRIPT" # -- Functions warn() { echo "$@" >&2 return 0 } die() { warn "$@. Aborted" exit 1 } clear_lock() { rm -f "$LOCKFILE" >/dev/null 2>&1 return 0 } clean_exit() { clear_lock exit 0 } bailout() { clear_lock die "Something went wrong. Removed lock ${LOCKFILE}. Please fix" } # -- Sanity checking if [ -f "$LOCKFILE" ]; then die "Lockfile $LOCKFILE exists. Another instance active?" fi touch "$LOCKFILE" || die "Failed to create lockfile $LOCKFILE" # -- Main trap bailout 2 3 6 15 /usr/sbin/tcpdump -l -n -v -s 0 -i pflog0 action block | /usr/bin/logger -p security.info -t "PFLOG-FIREWALL-BLOCKED"
This script will run from root’s crontab and log blocked packets in the security-log. No more, no less. It really is that simple.
### WARNING! THE FOLLOWING COMMANDS REQUIRE ROOT PRIVILEGES AND MAY DAMAGE YOUR COMPUTER SYSTEM AND EVERYTHING ON IT ### USE AT OWN RISC OR DO NOT PROCEED ###
Installing it is quite simple:
- Become root on your BSD-box (su -), then
- use cron (crontab -e) to run this script every 5 minutes or so.
The script will terminate if a previous placed lockfile is present, it is safe to do something like:
*/5 * * * * /root/bin/log-blocked.sh >/dev/null 2>&1
…In which /root/bin/log-blocked.sh is the script. Make sure that it is executable (chmod 755 /root/bin/log-blocked.sh).
If you’ve left /etc/syslog.conf as it was installed with the operating system, your security-logfile will be in /var/log/security, on FreeBSD. You can watch the logfile grow using the tail (-f) command on that file and watch for blocked packets. Please note that you will only see blocked traffic if you’ve configured PF to do so (it’s in /etc/pf.conf), and pflogd is running (check /etc/rc.conf). I’d highly recommend using a “block log all” as a default PF policy. This will ensure traffic being dropped that you did not specifically allow in the first place.
…But if you’ve done all that, you will – eventually – see quite some bizar internet traffic, such as:
Nov 13 21:10:22 gromit PFLOG-FIREWALL-BLOCKED: 21:10:21.170001 IP (tos 0x0, ttl 49, id 0, offset 0, flags [DF], proto UDP (17), length 998) Nov 13 21:10:22 gromit PFLOG-FIREWALL-BLOCKED: 212.175.16.5.5060 > 83.163.213.6.5060: SIP, length: 970 Nov 13 21:10:22 gromit PFLOG-FIREWALL-BLOCKED: INVITE sip:67209983373663@83.163.213.6 SIP/2.0 Nov 13 21:10:22 gromit PFLOG-FIREWALL-BLOCKED: Via: SIP/2.0/UDP 212.175.16.5;branch=z9hG4bKjgJbEocO3Fv4;rport Nov 13 21:10:22 gromit PFLOG-FIREWALL-BLOCKED: From: "unknown" <sip:unknown@212.175.16.5>;tag=WRLzuKbXWq Nov 13 21:10:22 gromit PFLOG-FIREWALL-BLOCKED: To: <sip:67209983373663@83.163.213.6> Nov 13 21:10:22 gromit PFLOG-FIREWALL-BLOCKED: Contact: <sip:unknown@212.175.16.5> Nov 13 21:10:22 gromit PFLOG-FIREWALL-BLOCKED: Call-ID: aJf94c9870e0RoUjIPFedqaUFV2bywf1@212.175.16.5 Nov 13 21:10:22 gromit PFLOG-FIREWALL-BLOCKED: CSeq: 101 INVITE Nov 13 21:10:22 gromit PFLOG-FIREWALL-BLOCKED: User-Agent: CALXNP9NDmrYroPbmPFQ Nov 13 21:10:22 gromit PFLOG-FIREWALL-BLOCKED: Max-Forwards: 70 Nov 13 21:10:22 gromit PFLOG-FIREWALL-BLOCKED: Allow: INVITE, ACK, CANCEL, BYE Nov 13 21:10:22 gromit PFLOG-FIREWALL-BLOCKED: Content-Type: application/sdp Nov 13 21:10:22 gromit PFLOG-FIREWALL-BLOCKED: Content-Length: 510 Nov 13 21:10:22 gromit PFLOG-FIREWALL-BLOCKED: Nov 13 21:10:22 gromit PFLOG-FIREWALL-BLOCKED: v=0 Nov 13 21:10:22 gromit PFLOG-FIREWALL-BLOCKED: o=unknown 12493 12493 IN IP4 2.3.4.5 Nov 13 21:10:22 gromit PFLOG-FIREWALL-BLOCKED: s=unknown Nov 13 21:10:22 gromit PFLOG-FIREWALL-BLOCKED: c=IN IP4 2.3.4.5 Nov 13 21:10:22 gromit PFLOG-FIREWALL-BLOCKED: t=0 0 Nov 13 21:10:22 gromit PFLOG-FIREWALL-BLOCKED: m=audio 10318 RTP/AVP 10 4 3 0 8 112 5 7 18 111 101 Nov 13 21:10:22 gromit PFLOG-FIREWALL-BLOCKED: a=rtpmap:10 L16/8000 Nov 13 21:10:22 gromit PFLOG-FIREWALL-BLOCKED: a=rtpmap:4 G723/8000 Nov 13 21:10:22 gromit PFLOG-FIREWALL-BLOCKED: a=fmtp:4 annexa=no Nov 13 21:10:22 gromit PFLOG-FIREWALL-BLOCKED: a=rtpmap:3 GSM/8000 Nov 13 21:10:22 gromit PFLOG-FIREWALL-BLOCKED: a=rtpmap:0 PCMU/8000 Nov 13 21:10:22 gromit PFLOG-FIREWALL-BLOCKED: a=rtpmap:8 PCMA/8000 Nov 13 21:10:22 gromit PFLOG-FIREWALL-BLOCKED: a=rtpmap:112 AAL2-G726-32/8000 Nov 13 21:10:22 gromit PFLOG-FIREWALL-BLOCKED: a=rtpmap:5 DVI4/8000 Nov 13 21:10:22 gromit PFLOG-FIREWALL-BLOCKED: a=rtpmap:7 LPC/8000 Nov 13 21:10:22 gromit PFLOG-FIREWALL-BLOCKED: a=rtpmap:18 G729/8000 Nov 13 21:10:22 gromit PFLOG-FIREWALL-BLOCKED: a=fmtp:18 annexb=no Nov 13 21:10:22 gromit PFLOG-FIREWALL-BLOCKED: a=rtpmap:111 G726-32/8000 Nov 13 21:10:22 gromit PFLOG-FIREWALL-BLOCKED: a=rtpmap:101 telephone-event/8000 Nov 13 21:10:22 gromit PFLOG-FIREWALL-BLOCKED: a=fmtp:101 0-16 Nov 13 21:10:22 gromit PFLOG-FIREWALL-BLOCKED: a=silenceSupp:off - - - - Nov 13 21:10:22 gromit PFLOG-FIREWALL-BLOCKED: a=ptime:20 Nov 13 21:10:22 gromit PFLOG-FIREWALL-BLOCKED: a=sendrecv Nov 13 21:10:22 gromit PFLOG-FIREWALL-BLOCKED:
Epilogue
When I first wrote this script I tried to make it a Unix daemon (Unix slang for “service”), with a nice rc-script. As it turned out: Unix shell script works perfectly, but isn’t really suited for more serious programming tasks as that script soon became hideously complex and had numerous bugs. The “solution” presented in this article isn’t perfect either as logging when scheduled from cron allows time-gaps in the logfile. Fixing these blind-spots can not be solved easily without modifying pflogd itself. If you think you can, then please share your thoughts!