![]() |
version seven.   http://demongin.org |
Stupid Linux Tricks: Avoid Unnecessary System Calls with /proc/net/arp
How to use new-style arp tables to ping better.
Sunday, 2010-03-28 | AlmostEffortless, Careerism, Programming
/proc is, for anyone interested in what's happening under the hood, an endless source of awesomeness. I recently experienced a bit of /proc awesomeness when sitting down to refactor an old VPN monitoring project using python.
Long story short, OpenVPN (http://openvpn.net/) prints a log called "openvpn-status.log" at fixed intervals. Contained within this log are the MAC addresses and common names of the VPN clients currently connected to the VPN server. The goal of the project was to take that log, swap the MAC addresses for local IP addresses and reprint the log on an intranet webpage.
The old way of doing this involved pinging all of the IP addresses on our subnet within the range of addresses that we had set aside for VPN clients and then scraping the output from # /usr/bin/arp -a to assign MAC addresses to IP addresses. This was alright, but in my program it required making a system (or, more specifically, a subprocess) call with python. Not optimal.
The new way of doing this is via the new awesomeness: /proc/net/arp. The setup is the same: you ping all the IP addresses in the range alotted for VPN clients to fill the arp cache but then, instead of working with the output from the arp program, you simply create a file-like object /proc/net/arp and work with that much simpler, easy to manipulate output.
To illustrate the difference, allow me to cut and paste both outputs. /usr/bin/arp -a first:
virginia:/var/log/openvpn# arp -v -a ? (192.168.2.89) at <incomplete> on br0 ? (192.168.2.85) at </incomplete><incomplete> on br0 ? (192.168.2.82) at 00:FF:49:56:76:30 [ether] on br0 ? (192.168.2.87) at </incomplete><incomplete> on br0 ? (192.168.2.83) at 00:FF:2D:53:53:20 [ether] on br0</incomplete>
virginia:/var/log/openvpn# cat /proc/net/arp IP address HW type Flags HW address Mask Device 192.168.2.85 0x1 0x0 00:00:00:00:00:00 * br0 192.168.2.89 0x1 0x0 00:00:00:00:00:00 * br0 192.168.2.82 0x1 0x2 00:FF:49:56:76:30 * br0 192.168.2.87 0x1 0x0 00:00:00:00:00:00 * br0 192.168.2.83 0x1 0x2 00:FF:2D:53:53:20 * br0
f = file("/proc/net/arp")
output = [line.strip().split() for line in f.readlines()]
Finally, the awesomeness isn't limited to python: when I'm trying to track down switches or other devices on the network that might not necessarily want to be found, all I've got to do to is rattle off the following bas one-liner and I've got all the data I need to start poking around:
cat /proc/net/arp |awk '{print $1 " " $4}'
