add files
This commit is contained in:
parent
b850fff2e0
commit
72f3b6a833
|
@ -0,0 +1 @@
|
||||||
|
.idea
|
|
@ -0,0 +1,9 @@
|
||||||
|
# pihole-opnsense-sync
|
||||||
|
_Sync custom DNS entries in Pi-hole to OPNsense Unbound._
|
||||||
|
|
||||||
|
## Install
|
||||||
|
```shell
|
||||||
|
pip install -r requirements.txt
|
||||||
|
```
|
||||||
|
|
||||||
|
Then get your API auth details.
|
|
@ -0,0 +1,12 @@
|
||||||
|
[Unit]
|
||||||
|
Description=Sync Pi-hole local DNS to OPNsense Unbound
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
User=pihole
|
||||||
|
Group=pihole
|
||||||
|
ExecStart=/opt/icinga2-checks/Other/auto-acknowledge-apt.sh --api https://localhost:5665 --fail --user icingaweb2 --password XXXXX
|
||||||
|
SyslogIdentifier=pihole-opnsense-sync
|
||||||
|
Restart=always
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
|
@ -0,0 +1,2 @@
|
||||||
|
requests==2.31.0
|
||||||
|
watchdog==4.0.0
|
|
@ -0,0 +1,91 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
import argparse
|
||||||
|
import logging
|
||||||
|
import time
|
||||||
|
from datetime import datetime
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
import requests
|
||||||
|
import urllib3
|
||||||
|
from watchdog.events import FileSystemEventHandler
|
||||||
|
from watchdog.observers import Observer
|
||||||
|
|
||||||
|
urllib3.disable_warnings()
|
||||||
|
|
||||||
|
|
||||||
|
class WatchdogHandler(FileSystemEventHandler):
|
||||||
|
def __init__(self, args):
|
||||||
|
self.args = args
|
||||||
|
|
||||||
|
def on_modified(self, event):
|
||||||
|
if event.src_path == args.custom_path:
|
||||||
|
file_modified(args)
|
||||||
|
|
||||||
|
|
||||||
|
def file_modified(args):
|
||||||
|
logger = logging.getLogger()
|
||||||
|
logger.setLevel(logging.INFO)
|
||||||
|
response = requests.get(args.opnsense + "/api/unbound/settings/searchHostOverride", auth=(args.api_key, args.api_secret), verify=args.insecure)
|
||||||
|
|
||||||
|
if response.status_code == 200:
|
||||||
|
data = response.json()
|
||||||
|
current_overrides = set([(x['server'], x['domain']) for x in data.get('rows', []) if x['description'] != 'SAVE'])
|
||||||
|
current_overrides_uuid = {x['domain']: x for x in data.get('rows', [])}
|
||||||
|
pihole_custom = set([(x[0], x[1]) for x in [y.split(' ') for y in Path(args.custom_path).read_text().split('\n')] if len(x) > 1])
|
||||||
|
|
||||||
|
to_remove = current_overrides - pihole_custom
|
||||||
|
to_add = pihole_custom - current_overrides
|
||||||
|
|
||||||
|
for item_ip, item_domain in to_remove:
|
||||||
|
item_data = current_overrides_uuid[item_domain]
|
||||||
|
p = requests.post(args.opnsense + f"/api/unbound/settings/delHostOverride/{item_data['uuid']}", auth=(args.api_key, args.api_secret), verify=args.insecure)
|
||||||
|
if p.status_code != 200:
|
||||||
|
raise Exception(f'Failed to delete item {item_domain}: {p.status_code} - {p.text}')
|
||||||
|
else:
|
||||||
|
logger.info(f'Deleted: {item_domain}')
|
||||||
|
|
||||||
|
now = datetime.now()
|
||||||
|
dt_string = now.strftime("%m/%d/%Y %H:%M:%S")
|
||||||
|
|
||||||
|
for item_ip, item_domain in to_add:
|
||||||
|
p_data = {
|
||||||
|
'host': {
|
||||||
|
'enabled': '1',
|
||||||
|
'hostname': '',
|
||||||
|
'domain': item_domain,
|
||||||
|
'rr': 'A',
|
||||||
|
'mxprio': '',
|
||||||
|
'mx': '',
|
||||||
|
'server': item_ip,
|
||||||
|
'description': f'Synced from Pi-hole {dt_string}'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
p = requests.post(args.opnsense + "/api/unbound/settings/addHostOverride", json=p_data, auth=(args.api_key, args.api_secret), verify=args.insecure)
|
||||||
|
if p.status_code != 200:
|
||||||
|
raise Exception(f'Failed to add item {item_domain}: {p.status_code} - {p.text}')
|
||||||
|
else:
|
||||||
|
logger.info(f'Added: {item_domain}')
|
||||||
|
else:
|
||||||
|
raise Exception(f"Failed to fetch host overrides: {response.status_code} - {response.text}")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
parser = argparse.ArgumentParser(description='Sync custom DNS entries in Pi-hole to OPNsense Unbound.')
|
||||||
|
parser.add_argument('--opnsense', required=True, help='Address of your OPNsense server. Example: https://192.168.1.1')
|
||||||
|
parser.add_argument('--custom-path', default='/etc/pihole/custom.list', help="Path to Pi-hole's custom.list. Default: /etc/pihole/custom.list")
|
||||||
|
parser.add_argument('--api-key', required=True, help='OPNsense API key.')
|
||||||
|
parser.add_argument('--api-secret', required=True, help='OPNsense API secret.')
|
||||||
|
parser.add_argument('--insecure', action='store_true', help="Don't verify SSL.")
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
event_handler = WatchdogHandler(args)
|
||||||
|
observer = Observer()
|
||||||
|
observer.schedule(event_handler, path='/etc/pihole/', recursive=False)
|
||||||
|
observer.start()
|
||||||
|
|
||||||
|
try:
|
||||||
|
while True:
|
||||||
|
time.sleep(1)
|
||||||
|
except KeyboardInterrupt:
|
||||||
|
observer.stop()
|
||||||
|
observer.join()
|
Loading…
Reference in New Issue