Skip to content

Instantly share code, notes, and snippets.

@cjnaz
Forked from pletch/scrape_pfsense_dhcp_leases.py
Created November 7, 2021 21:32
Show Gist options
  • Save cjnaz/ae742ff7b034c467690d3bc8c6bd5ac0 to your computer and use it in GitHub Desktop.
Save cjnaz/ae742ff7b034c467690d3bc8c6bd5ac0 to your computer and use it in GitHub Desktop.
Scrape PFSense DHCP Leases Status Page and Export Results to JSON
#!/usr/bin/env python3
# # This python script provides a function to query the pfsense (+v2.4) dhcp leases status page and return a list of tuples including
# ip, hostname, and mac address. To use, ensure LXML is installed via package manager or via pip.
#
# 16-Dec-2016 - Original release
# 3-Sep-2020 - Minor update to match formatting of leases page in latest pfSense version (2.4.5).
# 9-Sep-2020 - Backported improvements to handle table rows with missing data, use global variables for user/pass/server_ip,
# and return list from scrape function as implemented by fryguy04 in fork here:
# https://gist.github.com/fryguy04/7d12b789260c47c571f42e5bc733a813
# 9-Sep-2020 - Added parsing of pfSense lease table header. Discovered that adding element of ClientID in the static dhcp
# definitions alters the column sequence. This modification ensures that the correct columns are found and parsed.
# 9-Sep-2020 - Removed file export function
#
import sys
import requests
from lxml import html
import re
url = "http://192.168.1.1/status_dhcp_leases.php" #change url to match your pfsense machine address. Note http or https!
user = 'your_username' #Username for pfSense login
password = 'your_password' #Password for pfSense login
def scrape_pfsense_dhcp(url, user, password):
ip = []
mac = []
dhcp_name = []
s = requests.session()
r = s.get(url,verify = False)
matchme = 'csrfMagicToken = "(.*)";var'
csrf = re.search(matchme,str(r.text))
payload = {
'__csrf_magic' : csrf.group(1),
'login' : 'Login',
'usernamefld' : user,
'passwordfld' : password
}
r = s.post(url,data=payload,verify = False)
r = s.get(url,verify = False)
tree = html.fromstring(r.content)
tr_elements = tree.xpath('//tr')
headers = [header.text for header in tr_elements[0]]
ip.extend(tree.xpath('//body[1]//div[1]//div[2]//div[2]//table[1]//tbody//tr//td[' + str(headers.index('IP address') + 1) +']//text()'))
mac.extend(tree.xpath('//body[1]//div[1]//div[2]//div[2]//table[1]//tbody//tr//td['+ str(headers.index('MAC address') + 1) +']//text()'))
for node in tree.xpath('//body[1]//div[1]//div[2]//div[2]//table[1]//tbody//tr//td['+ str(headers.index('Hostname') + 1) +']'):
if node.text is None:
dhcp_name.append('no_hostname')
else:
dhcp_name.append(node.text)
for i in range(len(mac)):
mac[i] = mac[i].strip()
return(list(zip(ip, mac, dhcp_name)))
if __name__ == "__main__":
dhcp_list = scrape_pfsense_dhcp(url, user, password)
for entry in dhcp_list:
print(entry)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment