Commit Graph
22 Commits
Author SHA1 Message Date
Christian Manivong 8d3c443159 feat(firewall): implement apply_firewall_rule + commit_firewall_rules
CI / test (3.10) (push) Failing after 7s
CI / test (3.11) (push) Failing after 7s
CI / test (3.12) (push) Failing after 8s
CI / test (3.9) (push) Failing after 7s
OPNsense-specific half of the FirewallDriver diff/apply mechanism added
in napalm-device-types: translates the vendor-neutral rule dict into the
/api/firewall/filter/addRule or setRule/<uuid> payload (string "1"/"0"
booleans, empty interface = floating rule -- same shape as the existing
SNMP self-provisioning rule in _action_fix_snmp), and commit_firewall_rules
reloads the filter via /api/firewall/filter/apply. get_firewall_rules()
already returns compatible field names, no changes needed there.
2026-07-20 15:05:53 +02:00
Christian Manivong d6a0b21dc6 refactor(warnings): report raw signal only, no severity/presentation
CI / test (3.10) (push) Failing after 8s
CI / test (3.11) (push) Failing after 7s
CI / test (3.12) (push) Failing after 8s
CI / test (3.9) (push) Failing after 7s
get_device_warnings() now returns only {code, meta} — severity, title,
message, and action are resolved centrally by netork's
WARNING_CATALOG (netork/core/device_warnings.py), not by the driver.
Keeps this driver independent of netork and avoids per-vendor drift in
how the same warning code is presented.
2026-07-20 09:54:14 +02:00
Christian Manivong 20d9d9651a fix(freeradius): return the created entry's remote id from create_radius_*
CI / test (3.10) (push) Failing after 8s
CI / test (3.11) (push) Failing after 7s
CI / test (3.12) (push) Failing after 7s
CI / test (3.9) (push) Failing after 7s
add_client/add_user's response carries no id, so create_radius_client()
and create_radius_user() now look the new entry up via
get_radius_clients()/get_radius_users() (matched by name/username)
immediately after creation. Callers need this id to address the entry in
later set_*/del_* calls -- without it there was no way to store a
reference to what was just created.
2026-07-15 15:30:06 +02:00
Christian Manivong e51607a020 feat(freeradius): add NAS client and user CRUD driver methods
CI / test (3.10) (push) Failing after 7s
CI / test (3.11) (push) Failing after 7s
CI / test (3.12) (push) Failing after 8s
CI / test (3.9) (push) Failing after 7s
get/create/delete_radius_client and get/create/delete_radius_user, backed
by /api/freeradius/{client,user}/{search,add,del}_* and a reconfigure call
to apply changes. Endpoints and field names (client.ip, not ipaddr) verified
against a live OPNsense 24.7 instance via a real add -> search/get -> set ->
del round trip, cleaned up immediately after.
2026-07-15 15:26:05 +02:00
Christian Manivong c8caa14176 feat(dyndns): add get_ddns_status() for os-ddclient enabled/running state
CI / test (3.10) (push) Failing after 8s
CI / test (3.11) (push) Failing after 7s
CI / test (3.12) (push) Failing after 7s
CI / test (3.9) (push) Failing after 7s
Verified against a live OPNsense 24.7 instance: the service id is
"ddclient" but the REST module is "dyndns" (/api/ddclient/* all 404).
Scoped to enabled/running only -- no ddclient/dyndns account was
configured on the test device to verify a per-account "registered IP"
shape against, so that comparison is deliberately left out rather than
guessed.
2026-07-15 13:52:20 +02:00
Christian Manivong 26470676ce feat(trust): add get_certificates() for Trust store certificate inventory
CI / test (3.10) (push) Failing after 8s
CI / test (3.11) (push) Failing after 7s
CI / test (3.12) (push) Failing after 8s
CI / test (3.9) (push) Failing after 7s
Reads certificates via POST /api/trust/cert/search, normalising each row
to {name, issuer, valid_from, valid_to, in_use_by}. Field mapping (Unix
timestamps for validity, %caref for the resolved issuer label) verified
against a live OPNsense 24.7 instance. Never surfaces crt_payload/
prv_payload/csr_payload -- those carry private key material.
2026-07-15 12:26:36 +02:00
Christian Manivong 62424cfd71 feat(opnsense): implement send_wake_on_lan() via the os-wol plugin API
CI / test (3.10) (push) Failing after 7s
CI / test (3.11) (push) Failing after 8s
CI / test (3.12) (push) Failing after 7s
CI / test (3.9) (push) Failing after 7s
Calls POST /api/wol/wol/set with no uuid in the payload, which makes
the os-wol plugin's WolController::setAction validate and wake
immediately without persisting a host to config.xml. Requires the
os-wol plugin installed and the target interface to have a static
IPv4 (OPNsense derives the broadcast address from the interface's own
IP/subnet). Endpoint/payload verified against the plugin's source
(opnsense/plugins net/wol), not guessed.
2026-07-12 11:17:48 +02:00
Christian ManivongandClaude Sonnet 5 b8a68fc3a8 fix(opnsense): correct Kea leases4 del_lease endpoint — path param, not body
CI / test (3.10) (push) Failing after 7s
CI / test (3.11) (push) Failing after 7s
CI / test (3.12) (push) Failing after 8s
CI / test (3.9) (push) Failing after 7s
The lease-delete call never actually worked: it posted {"ip-address": ip}
to /api/kea/leases4/delLease, both wrong. Verified live against a real
OPNsense instance while cleaning up stale leases left by failed NetOrk VM
provisioning attempts — every call returned {"status": "error", "message":
"Missing lease IP parameter"} despite three different body-parameter
guesses (ips as list, ips as string, ip singular). The official API docs
(docs.opnsense.org/development/api/core/kea.html) show LeasesController as
"Abstract [non-callable]" with a del_lease($ips=null) action; despite that
signature looking like a body field, the concrete leases4 route only
accepts the IP as a URL path segment: POST /api/kea/leases4/del_lease/{ip}
confirmed {"status": "ok"} and the lease actually gone from a follow-up
search.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-09 10:31:05 +02:00
Christian ManivongandClaude Sonnet 5 b8dac1db63 feat(opnsense): add delete_dhcp_reservation_and_lease() for Kea DHCPv4
CI / test (3.10) (push) Failing after 7s
CI / test (3.11) (push) Failing after 7s
CI / test (3.12) (push) Failing after 7s
CI / test (3.9) (push) Failing after 7s
Combined removal of a static reservation and its active lease, needed by
NetOrk's VM-deletion cleanup flow. Reservation deletion follows the same
search-then-del<X>/{uuid} + reconfigure pattern as create_dhcp_reservation
and raises on failure; lease deletion is best-effort/non-fatal since the
Kea lease-delete endpoint shape is unverified against a real box.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-08 19:24:04 +02:00
Christian Manivong c12065c114 Merge feature/dhcp-static-reservation: create_dhcp_reservation() for Kea DHCPv4
CI / test (3.10) (push) Failing after 8s
CI / test (3.11) (push) Failing after 7s
CI / test (3.12) (push) Failing after 7s
CI / test (3.9) (push) Failing after 7s
2026-07-08 09:09:45 +02:00
Christian Manivong 806a23018d feat(opnsense): add create_dhcp_reservation() for Kea DHCPv4 static mappings
Only Kea (os-kea plugin) is supported — no active OPNsense environment
with legacy ISC DHCP was available to verify a second code path against.
Payload/response shapes (searchSubnet, searchReservation, addReservation,
setReservation, delReservation, service/reconfigure) were confirmed
against a real OPNsense box via a live add + verify + delete cycle
before writing this method and its tests.
2026-07-08 09:09:41 +02:00
Christian ManivongandClaude Sonnet 4.6 e3c36a1d34 feat: Fingerprint-Attribute für Discovery-Scoring
CI / test (3.10) (push) Failing after 7s
CI / test (3.11) (push) Failing after 7s
CI / test (3.12) (push) Failing after 7s
CI / test (3.9) (push) Failing after 7s
Ergänzt DRIVER_NAME, HTTP_FINGERPRINT, SNMP_FINGERPRINT, SSH_FINGERPRINT,
PORT_SPECS und SNMP_OBJECT_ID_PREFIX gemäß docs/DISCOVERY_FINGERPRINTING.md.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-24 14:47:08 +02:00
Christian ManivongandClaude Sonnet 4.6 629822c055 fix: set listen IP in _action_fix_snmp so snmpd binds to management IF
Without an explicit listen address, os-net-snmp on OPNsense may not
respond on non-loopback interfaces. The fix sets
listen = {self.hostname: {"selected": 1}} which is always the
management IP used to reach this device in netOrk.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-20 03:46:48 +02:00
Christian ManivongandClaude Sonnet 4.6 9f9fafb6f5 fix: _action_fix_snmp skips reinstall if plugin already present
Calling firmware/install on an already-installed os-net-snmp plugin
triggers an async reinstall that overwrites the config with factory
defaults a few minutes later — causing SNMP to stop working again.
Now checks /api/netsnmp/general/get first and only installs if the
plugin is genuinely absent.

Also adds a lightweight UDP/161 probe to verify SNMP is actually
reachable after the fix (falls back to API config check if the
socket probe is unavailable).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-20 03:41:18 +02:00
Christian ManivongandClaude Sonnet 4.6 8e413e4c60 fix: _action_fix_snmp adds floating firewall rule for UDP/161
OPNsense default-drops traffic arriving on non-LAN interfaces (e.g.
WireGuard tunnels used as management networks). Even with os-net-snmp
running and configured, SNMP is unreachable from external management
hosts because no firewall rule allows it.

Now adds a floating pass rule for UDP/161 → (self) after configuring
the service, then applies the firewall. Skips the rule if one with
the same description already exists (idempotent).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-20 02:24:21 +02:00
Christian ManivongandClaude Sonnet 4.6 0928584b5d feat: DNS host overrides — ptrrecord support, dedup, arpa guard
- _get_unbound_host_overrides: deduplicate by (hostname, domain, ip, rr)
  to suppress alias rows that OPNsense returns alongside parent records
- _get_unbound_host_overrides: read ptrrecord field so callers know which
  A records have an auto-managed PTR in the reverse zone
- sync_dns_zone: set ptrrecord=1 when creating A/AAAA host overrides so
  OPNsense Unbound manages the PTR record internally
- sync_dns_zone: refuse arpa zone names with ValueError — PTR records
  must never be written back via the host override API

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-19 15:02:04 +02:00
Christian ManivongandClaude Sonnet 4.6 b93628ac57 feat: include VLAN tag in get_networks() output
Routed subnets on 802.1Q sub-interfaces now report their vlan_id so
callers can associate a subnet with the VLAN it belongs to. None for
untagged interfaces.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-12 17:17:15 +02:00
Christian ManivongandClaude Sonnet 4.6 5d5bd77b08 feat: get_route_to() — Protokoll aus BSD-Flags, family-Feld, OSPF-Enrichment
- Protokoll-Erkennung aus flags: S=static, kein Gateway=connected, sonst=kernel
- Optionale OSPF-Anreicherung via /api/quagga/ospf/routes (FRR)
- family-Feld (ipv4/ipv6) aus Netzadresse abgeleitet
- link#X und 0.0.0.0 als Next-Hop bereinigt
- API-Response kann Liste oder Dict sein (beide Formate unterstützt)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-06 15:46:55 +02:00
Christian ManivongandClaude Sonnet 4.6 908024345e fix: get_interfaces_ip() uses overview/export statt addresses/export
Das /api/interfaces/addresses/export Endpoint existiert nicht auf allen
OPNsense-Versionen. Stattdessen wird /api/interfaces/overview/export
genutzt (gleiche Quelle wie get_interfaces()), um addr4/addr6 zu parsen.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-06 15:00:38 +02:00
Christian ManivongandClaude Sonnet 4.6 4434d4195f fix: accept verify_ssl/ssl_verify optional args; add get_firewall_aliases/rules
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-04 10:07:45 +02:00
Christian ManivongandClaude Sonnet 4.6 d926218eff feat: SNMP support — get_snmp_config(), fix_snmp action
get_snmp_config() calls GET /api/netsnmp/general/get with 5s timeout (plugin
may not be installed). fix_snmp installs os-net-snmp package, configures via
POST /api/netsnmp/general/set with community 'public', restarts service.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-01 13:09:57 +02:00
Christian Manivong ae27cd5469 initial commit 2026-05-29 09:22:10 +02:00