Skip to content

fix(onvif): discovery correctness and reliability issues#61

Merged
Liuhaai merged 1 commit into
mainfrom
fix-onvif-discovery-bugs
Apr 22, 2026
Merged

fix(onvif): discovery correctness and reliability issues#61
Liuhaai merged 1 commit into
mainfrom
fix-onvif-discovery-bugs

Conversation

@Liuhaai
Copy link
Copy Markdown
Collaborator

@Liuhaai Liuhaai commented Apr 22, 2026

Summary

This PR fixes 6 correctness and reliability bugs in ONVIF discovery and RTSP resolution.

Fixes

Severity Issue Fix
High WS-Discovery failures (socket errors, offline hosts) abort the entire discovery pipeline instead of falling back to subnet scan. discover_cameras() now wraps _discover_cameras_probe() in try/except OSError. Subnet scan runs on any UDP multicast failure.
High HTTPS ONVIF endpoints with no explicit port are incorrectly parsed as port 80. _camera_info_from_probe_response() now inspects urlparse(...).scheme and defaults HTTPS → 443, HTTP → 80.
Medium RTSP fallback probe sends a fake Digest realm="", nonce="" header, causing strict cameras to return 400 Bad Request (false negative). _probe_rtsp_paths() no longer sends auth on the first probe. 401 responses are still treated as "path exists".
Medium Subnet scan depends on a UDP connect to 8.8.8.8, so isolated LANs / air-gapped networks never get scanned. _get_local_ip() now prefers hostname resolution first, then falls back to the public DNS trick.
Low WS-Discovery MessageID is hardcoded to uuid:trio-edge-discover. Each probe now generates a unique uuid.uuid4() MessageID.
Low Scope names only decode %20, not other percent-encoded characters. _name_from_scopes() now uses urllib.parse.unquote().
Low get_rtsp_uri() silently swallows all exceptions, making debugging impossible. Exceptions are now logged via logging.getLogger(__name__).exception().

Tests

Added 9 characterization tests covering:

  • Probe OSError → subnet fallback
  • HTTPS default port 443
  • HTTP default port 80
  • Fake Digest auth removal
  • Exception logging via caplog
  • Unique MessageID per probe
  • unquote scope decoding
  • Hostname-based local IP discovery (prefers hostname over UDP)

All 15 tests pass. Lint and format checks pass.

@Liuhaai Liuhaai force-pushed the fix-onvif-discovery-bugs branch from 85190f8 to f323757 Compare April 22, 2026 18:42
**High:**
- _discover_cameras_probe() is now wrapped in try/except OSError inside
discover_cameras(). UDP multicast failures (getaddrinfo, socket creation,
sendto, recvfrom) no longer abort the entire discovery pipeline; the subnet
scan fallback now runs as documented.
- _camera_info_from_probe_response() defaults HTTPS XAddr to port 443 and
HTTP to port 80. Previously, https://host/path fell back to port 80, which
caused RTSP resolution to probe the wrong ONVIF service.

**Medium:**
- _probe_rtsp_paths() no longer sends a fake Digest auth header. The malformed
Authorization: Digest realm="", nonce="" string could trigger 400 Bad
Request from strict RTSP servers, giving false negatives. We now do the first
probe without auth and treat 401 as "path exists" per existing logic.
- _get_local_ip() now prefers hostname resolution before falling back to UDP
connect to 8.8.8.8. Isolated LANs and air-gapped networks without a default
route can now discover cameras via subnet scan.

**Smaller:**
- WS-Discovery MessageID is now unique per probe (uuid.uuid4()) instead of a
static string, reducing response caching issues on some cameras.
- _name_from_scopes() uses urllib.parse.unquote() instead of only replacing
%20, properly decoding all percent-encoded characters.
- get_rtsp_uri() now logs exceptions via logging.getLogger(__name__).exception()
instead of silently swallowing them.
- Add 9 characterization tests covering probe fallback, HTTPS default port,
RTSP request shape, exception logging, unique MessageID, unquote decoding,
and hostname-based local IP discovery.
@Liuhaai Liuhaai force-pushed the fix-onvif-discovery-bugs branch from f323757 to ebafc82 Compare April 22, 2026 18:54
@Liuhaai Liuhaai merged commit f865a74 into main Apr 22, 2026
7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant