Development
This commit is contained in:
parent
d6f1a74684
commit
f518f0e86b
3 changed files with 25 additions and 20 deletions
|
|
@ -1,4 +1,5 @@
|
||||||
import ipaddress
|
import ipaddress
|
||||||
|
import json
|
||||||
import os
|
import os
|
||||||
import glob
|
import glob
|
||||||
from datetime import datetime, timezone
|
from datetime import datetime, timezone
|
||||||
|
|
@ -46,26 +47,10 @@ def _vendor_cell(vendor):
|
||||||
|
|
||||||
|
|
||||||
def _get_arp_table():
|
def _get_arp_table():
|
||||||
"""Return {mac_lower: entry} from /proc/net/arp (host-mounted). ATF_COM (0x2) flag means
|
"""Return {mac_lower: entry} from the ARP cache written by maintenance.py."""
|
||||||
the entry is complete; entries without it (incomplete) are excluded."""
|
|
||||||
try:
|
try:
|
||||||
entries = {}
|
with open('/var/lib/misc/arp-cache.json') as f:
|
||||||
with open('/host/proc/net/arp') as f:
|
return json.load(f)
|
||||||
next(f) # skip header line
|
|
||||||
for line in f:
|
|
||||||
parts = line.split()
|
|
||||||
if len(parts) < 6:
|
|
||||||
continue
|
|
||||||
ip = parts[0]
|
|
||||||
flags = int(parts[2], 16)
|
|
||||||
mac = parts[3].lower()
|
|
||||||
iface = parts[5]
|
|
||||||
if not (flags & 0x2):
|
|
||||||
continue
|
|
||||||
if mac == '00:00:00:00:00:00':
|
|
||||||
continue
|
|
||||||
entries[mac] = {'ip': ip, 'iface': iface, 'state': 'REACHABLE'}
|
|
||||||
return entries
|
|
||||||
except Exception:
|
except Exception:
|
||||||
return {}
|
return {}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,6 @@ services:
|
||||||
- /sys/devices:/sys/devices:ro
|
- /sys/devices:/sys/devices:ro
|
||||||
- /etc/localtime:/etc/localtime:ro
|
- /etc/localtime:/etc/localtime:ro
|
||||||
- /var/lib/misc:/var/lib/misc:ro
|
- /var/lib/misc:/var/lib/misc:ro
|
||||||
- /proc/net/arp:/host/proc/net/arp:ro
|
|
||||||
- /var/log/freeradius:/var/log/freeradius
|
- /var/log/freeradius:/var/log/freeradius
|
||||||
environment:
|
environment:
|
||||||
- PYTHONPATH=/routlin_location
|
- PYTHONPATH=/routlin_location
|
||||||
|
|
|
||||||
|
|
@ -38,6 +38,7 @@ CONFIG_FILE = SCRIPT_DIR / "config.json"
|
||||||
CACHE_SERVICE_FILE = SCRIPT_DIR / ".ddns-last-service"
|
CACHE_SERVICE_FILE = SCRIPT_DIR / ".ddns-last-service"
|
||||||
LOG_FILE = SCRIPT_DIR / "ddns.log"
|
LOG_FILE = SCRIPT_DIR / "ddns.log"
|
||||||
RADIUS_LOG_FILE = Path("/var/log/freeradius/radius.log")
|
RADIUS_LOG_FILE = Path("/var/log/freeradius/radius.log")
|
||||||
|
ARP_CACHE_FILE = Path("/var/lib/misc/arp-cache.json")
|
||||||
|
|
||||||
# log is assigned in setup_logging() after config is loaded
|
# log is assigned in setup_logging() after config is loaded
|
||||||
log = None
|
log = None
|
||||||
|
|
@ -534,6 +535,25 @@ def rotate_radius_log(radius_cfg):
|
||||||
# Main
|
# Main
|
||||||
# ===================================================================
|
# ===================================================================
|
||||||
|
|
||||||
|
def refresh_arp_cache():
|
||||||
|
try:
|
||||||
|
result = subprocess.run(['ip', 'neigh'], capture_output=True, text=True, timeout=5)
|
||||||
|
entries = {}
|
||||||
|
for line in result.stdout.splitlines():
|
||||||
|
parts = line.split()
|
||||||
|
if 'lladdr' not in parts:
|
||||||
|
continue
|
||||||
|
state = parts[-1]
|
||||||
|
if state in ('FAILED', 'PERMANENT', 'NOARP', 'INCOMPLETE'):
|
||||||
|
continue
|
||||||
|
idx = parts.index('lladdr')
|
||||||
|
mac = parts[idx + 1].lower()
|
||||||
|
entries[mac] = {'ip': parts[0], 'state': state}
|
||||||
|
ARP_CACHE_FILE.write_text(json.dumps(entries))
|
||||||
|
except Exception as exc:
|
||||||
|
print(f"WARNING: Could not refresh ARP cache: {exc}")
|
||||||
|
|
||||||
|
|
||||||
def run_update(cfg, force=False, getip_only=False):
|
def run_update(cfg, force=False, getip_only=False):
|
||||||
"""Perform a single DDNS update pass.
|
"""Perform a single DDNS update pass.
|
||||||
If force=True, bypasses the cached IP check and always updates.
|
If force=True, bypasses the cached IP check and always updates.
|
||||||
|
|
@ -593,6 +613,7 @@ def main():
|
||||||
run_update(cfg, force=args.force)
|
run_update(cfg, force=args.force)
|
||||||
|
|
||||||
rotate_radius_log(cfg.get("_radius", {}))
|
rotate_radius_log(cfg.get("_radius", {}))
|
||||||
|
refresh_arp_cache()
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
main()
|
main()
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue