ONVIF WS-Discovery scanner for cameras and NVRs. Ask it what is on a local network, and it answers with the devices that responded and the services they advertise. Discovery is read-only and needs no credentials.
Built for integrators and anyone who inherits a mixed camera fleet: bring the infrastructure you already own, find out what it speaks, and skip the spreadsheet archaeology.
Prebuilt binaries are published per tag in Releases: download the asset for
your platform, check it against sha256sums.txt, and run it. Linux builds
are static (musl); Windows ships camera-discovery.exe inside a .zip. No
Rust toolchain needed.
$ sha256sum -c sha256sums.txt
$ tar -xzf camera-discovery-v0.1.0-x86_64-unknown-linux-musl.tar.gz
$ ./camera-discovery-v0.1.0-x86_64-unknown-linux-musl/camera-discovery --timeout 5Or build from source:
cargo install --path .
camera-discovery --timeout 5
camera-discovery --network 192.168.1.0/24 --timeout 10
camera-discovery --jsonThe probe goes to the WS-Discovery multicast group
239.255.255.250:3702. Devices must be on the same layer-2 network as the
machine running the scan. --network filters responses by the IPv4 address in
each advertised XAddr; it does not change the multicast scope.
Text output:
http://192.168.1.64/onvif/device_service
onvif://www.onvif.org/name/West%20Entrance onvif://www.onvif.org/type/video_encoder
http://192.168.1.72/onvif/device_service
onvif://www.onvif.org/name/Loading%20Bay
--json prints an array in response order:
[
{
"xaddrs": [
"http://192.168.1.64/onvif/device_service"
],
"scopes": "onvif://www.onvif.org/name/West%20Entrance onvif://www.onvif.org/type/video_encoder",
"types": "dn:NetworkVideoTransmitter"
}
]An empty result is a successful scan: text prints No ONVIF devices found.
and JSON prints []. Exit codes are 0 for a completed scan (including an
empty one), 1 for a runtime or configuration error, and 2 for command-line
usage errors.
Does: send one WS-Discovery Probe for dn:NetworkVideoTransmitter, collect
ProbeMatch responses for the requested timeout, and report XAddrs, scopes and
types exactly as sent.
Does not: log in during discovery, change camera settings, pull video, scan ports, test credentials, or claim that a response is trustworthy. Any host on the local network can answer, and a responder can put anything in its scopes or XAddrs.
The library also exposes resolve, a read-only ONVIF source resolver for
callers that supply credentials. It performs GetDeviceInformation,
GetProfiles and GetStreamUri (plus GetReplayUri when the device
advertises replay). The returned authenticated RTSP URI is a secret; print
stream_uri_redacted instead.
use std::time::Duration;
#[tokio::main]
async fn main() -> Result<(), alecto_discovery::DiscoveryError> {
let devices = alecto_discovery::discover(
Some("192.168.1.0/24"),
Duration::from_secs(5),
)
.await?;
println!("{}", alecto_discovery::render_text(&devices));
Ok(())
}The crate is alecto-discovery; the command is camera-discovery. The plain
camera-discovery crate name is already used by an unrelated project on
crates.io, so the import name carries the vendor prefix.
- IPv4 only. No IPv6 multicast, no unicast sweep, no ONVIF port scan.
- One probe, one timeout. Packet loss and slow responders are not retried.
- Responses are not correlated to the probe's message id. Any ProbeMatch seen during the window is reported, and any local host can spoof one.
- Devices that do not answer as
NetworkVideoTransmitterare missed, including some NVRs that only advertise a device service. - Responses are unauthenticated and unverified. Treat the output as leads, not as an inventory of record.
- The OS chooses the egress interface; there is no
--interfaceoption. - The XML reader is deliberately small and not namespace-aware; malformed or hostile documents can be ignored or misreported.
- Duplicate responses are reported as separate entries.
--networkis a post-filter over advertised XAddrs; a device with no XAddr is dropped when the filter is set.- ONVIF resolution uses plain HTTP and ONVIF password digest. The password is not sent in clear text, but the conversation is not encrypted. Use it only on networks you trust.
- Resolution follows service XAddrs supplied by the device. A malicious device can point credential-bearing requests at another host. Redirects and environment proxies are disabled, but the device-supplied URL itself is not pinned.
- ONVIF response bodies are capped at 4 MiB; a larger response fails.
- No vendor-specific NVR APIs, no stream playback check, no retention or replay verification.
- No rate limiting or result cap. A hostile local host can flood the scan.
The full behavior and output contract is in docs/SPEC.md.
Please report vulnerabilities through GitHub's private security advisories on this repository, not in a public issue. See SECURITY.md.
Scan only networks you own or are authorized to assess.
Apache-2.0. See LICENSE.