Grabbing Currently Connected MACS from a DD-WRT device with netmiko
Before we dive into migrating my old database, I thought it would be important to show how I yank MAC addresses from one of my network devices. My current home wireless setup uses a router with DD-WRT installed on it. Yanking MAC addresses from my router is real easy with python by using the netmiko module.
Let’s start with my import statements first. Here’s a list with a quick description of what each does for my project:
from netmiko import ConnectHandler # connects to devices and runs commands
import dotenv # imports network device variable
import os # imports network device variable
import ast # imports variable as dict
import re # searches for macs from device response
The first step in a netmiko project is to define a device type. This consists of basic connection information such as the IP/hostname, username, device type, etc. The netmiko maintainer has a great list of examples that can help get you started. In my case, I store my device information as an environment variable in a .env file and simply import it with dotenv. The variable is loaded as a string so I use the ast module to make sure it’s imported how netmiko wants it: as a dictionary. Output of this is shown below:
# Load switch information from .env
dotenv.load_dotenv()
switch = ast.literal_eval(os.environ.get("MAC_LOC"))
I box my project into function that is composed into two major parts: retrieving output from the device and searching for MACS (and discarding the rest) from the output. Device connection and command response retrieval is as simple as:
device = ConnectHandler(**switch)
device_info = device.send_command('wl_atheros assoclist')
The device variable uses netmiko’s ConnectHandler and the switch information we assigned earlier from our .env file. The device_info variable takes the output of a command sent to the device in the line above. In my case, I issue the wl_atheros assoclist command to retrieve wireless mac associations from my DD-WRT device. The output of that command from comes with some extra information and netmiko converts it to a string and adds newlines:
# Output from device
assoclist AC:67:84:85:06:9E
assoclist 30:FD:38:86:69:84
assoclist D8:6C:63:4A:89:86
assoclist B0:2A:43:13:57:1D
# netmiko's interpretation of the above (aka the device_info variable)
'assoclist AC:67:84:85:06:9E\nassoclist 30:FD:38:86:69:84\nassoclist D8:6C:63:4A:89:86\nassoclist B0:2A:43:13:57:1D'
The next portion of my function aims to strip out the MAC addresses and give us a list response. For this I use the re module to define what a mac address should look like. Luckily this question has been asked several times on stackoverflow so I didn’t have to struggle too hard working with regex.
mac_format = re.compile(r'(?:[0-9a-fA-F]:?){12}')
mac_list = re.findall(mac_format, device_info)
With the few lines above I create a function I can then call from elsewhere. In the end, the code looks as follows:
from netmiko import ConnectHandler
import dotenv
import os
import ast
import re
# Load switch information from .env
dotenv.load_dotenv()
switch = ast.literal_eval(os.environ.get("MAC_LOC"))
# Get a list of mac addresses in list form from a ddwrt device
def get_wrt_macs():
# Connect to access points and run command
device = ConnectHandler(**switch)
device_info = device.send_command('wl_atheros assoclist')
# Strip out macs into a list
mac_format = re.compile(r'(?:[0-9a-fA-F]:?){12}')
mac_list = re.findall(mac_format, device_info)
return mac_list
And the output of the function looks like:
You can use netmiko to connect to devices other than DD-WRT and run other commands. If you do use something besides DD-WRT, your output will likely be different than mine and may need some regex tweaking (good luck!). In my case, I have other projects where I use get_cisco_blah or get_linux_bleh if the situation calls for it. However, I think yanking MAC addresses like this, is a great introduction to netmiko and was one of the first network related projects I worked on.