Skip to content

Instantly share code, notes, and snippets.

@schossel
Last active June 13, 2026 22:57
Show Gist options
  • Select an option

  • Save schossel/c49477f1fed7591223e056cf02ca4b84 to your computer and use it in GitHub Desktop.

Select an option

Save schossel/c49477f1fed7591223e056cf02ca4b84 to your computer and use it in GitHub Desktop.
Get OPNSense DHCP Leases by python script
#!/usr/bin/env python3
# Scrapes pfSense DHCP Leases into List of (IP, MAC, Hostname, Description) format.
# Change URL/Username/Password below ... pip install lxml ... then you are all set.
#
# Modified 6/23/2019 (FryGuy)
# Edits: Aligned IP/MAC/Hostname into struct accounting for blank lines
# Minor: Cleaned up spacing, created global url/user/password vars, removed write to file
# Original Code/Inspiration: https://gist.github.com/pletch/037a4a01c95688fff65752379534455f
# Modified 03/14/2023 (schossel)
# Added Field Description and changed CSRF to work with OPNsense
import sys
import requests
from lxml import html # pip install lxml
import re
import time
import json
# Change these to your network
url = "https://yourIP:yourPort/status_dhcp_leases.php" #change url to match your pfsense machine address
user = 'yourUsername'
password = 'yourPassword'
def scrape_opnsense_dhcp(url, user, password):
ip = []
mac = []
dhcp_name = []
descr = []
s = requests.session()
r = s.get(url,verify = False)
head= { 'Content-Type':'application/x-www-form-urlencoded',
'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36'
}
print(r.cookies)
match_csrf_token = '"X-CSRFToken",\s"(.*)".+\);'
match_csrf_name = '<form.*id="iform".*name="(.*?)".*new-password"'
csrf_token = re.search(match_csrf_token,str(r.text)).group(1)
csrf_name = re.search(match_csrf_name,str(r.text)).group(1)
#print(name.group(1))
payload = {
csrf_name : csrf_token,
'login' : 'Login',
'usernamefld' : user,
'passwordfld' : password
}
r = s.post(url,data=payload,cookies=r.cookies,headers=head,verify = False)
s.headers.update(head)
r = s.get(url,verify = False)
tree = html.fromstring(r.content)
ip.extend([element.text for element in tree.xpath('//body[1]//table[1]//tbody[1]//tr//td[2]')])
mac.extend([element.text for element in tree.xpath('//body[1]//table[1]//tbody[1]//tr//td[3]')])
for node_dhcp_name in tree.xpath('//body[1]//table[1]//tbody[1]//tr//td[4]'):
if node_dhcp_name.text is None:
dhcp_name.append('no_hostname')
else:
dhcp_name.append(node_dhcp_name.text)
for node_descr in tree.xpath('//body[1]//table[1]//tbody[1]//tr//td[5]'):
if node_descr.text is None:
descr.append('no_description')
else:
descr.append(node_descr.text)
for i in range(len(mac)):
mac[i] = mac[i].strip()
dhcp = zip(ip, mac, dhcp_name, descr)
return(dhcp)
if __name__ == "__main__":
dhcp_list = scrape_opnsense_dhcp(url, user, password)
for x in dhcp_list:
print(x)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment