You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
feat(dgw): align gateway scans with local planning (#1776)
## Summary
Brings the gateway's `/jet/net/scan` API closer to feature parity with
the local network scanner, so the same scan request shape can drive
both.
### New query parameters
- **Targets** — combinable `target=<ip>` (single host) and
`range=<lower>-<upper>`. IPv4/IPv6 family validation; rejects ranges
over 65 536 addresses with HTTP 400.
- **Source selection** — repeatable `interface_id=<id>` plus
`range_interface_policy=intersect_selected_interfaces|allow_cross_interface_range`.
Missing/down/loopback-only/no-scan-capable sources or out-of-interface
ranges return a structured 400 (`{ error, interfaceId, reason }` or `{
error, ranges, interfaceIds }`).
- **Probe controls** — `enable_tcp_probes=false` suppresses all TCP
probes regardless of `probe=`; otherwise `probe=22|rdp|https|...` sets
the probe list. An explicit probe list (even just `probe=ping`) is
honored verbatim — the default `COMMON_PORTS` fallback only kicks in
when the caller sends no `probe=` at all.
- **Result toggles** — `report_ping_start`, `report_ping_success`,
`report_ping_failure`, `report_tcp_failure`, `include_host_results`. The
previous `enable_failure` and `enable_ping_start` flags remain as
deprecated aliases (see "Behavior changes" below for the
`enable_failure` semantics split).
- **Concurrency** — `max_concurrency`, `max_ping_concurrency`,
`max_tcp_probe_concurrency`.
- **Strict bind** — `interface_bind_strict=true` fails the scan if a
per-interface socket bind doesn't take effect (default: warn and fall
back).
### New endpoint
`GET /jet/net/interfaces` (v2): returns each scan source with a stable
`id`, address, `startAddress`/`endAddress`, broadcast address, prefix
length, link metadata (MAC, MTU, speed, link type), and per-source
capability flags (`ipv4`, `ipv6`, `subnet`, `broadcast`, `zeroConf`,
`tcpProbe`, `dnsResolve`). The `id` is what `interface_id=` accepts.
The legacy `GET /jet/net/config` is retained and now carries RFC 8594
`Deprecation: true` plus `Link: rel="successor-version"` headers
pointing at `/jet/net/interfaces`. (No `Sunset` date until product
confirms one.)
### New result format
`response_format=network_scan_result_v1` opts into a new wire shape:
```json
{ "kind": "host", "address": "...", "source": "gateway", "discoverySource": "subnet", "isReachable": true, "hostScanState": "reachable", "responseTimeMs": 7, "interfaceId": "...", "interfaceName": "..." }
{ "kind": "service", "address": "...", "source": "gateway", "discoverySource": "tcp_probe", "isReachable": true, "port": 3389, "serviceLabel": "RDP", "serviceType": "RDP", "responseTimeMs": 12 }
```
Fields are camelCase with closed lowercase enums (`hostScanState ∈ {
queued, probing, reachable, unreachable }`, `discoverySource ∈ { subnet,
broadcast, tcp_probe, gateway, zero_conf }`). `macAddress` is in the
schema but only populated when neighbor-discovery information is
available; it is omitted from the JSON otherwise.
Without the parameter, the legacy event format continues to be emitted
unchanged.
### Internals
- Per-interface socket bind for ping and TCP probes on Linux
(`IP_UNICAST_IF`/`IPV6_UNICAST_IF`), macOS
(`IP_BOUND_IF`/`IPV6_BOUND_IF`), and Windows (`IP_UNICAST_IF`). Other
targets fail to compile (`compile_error!`).
- Event-bus capacity raised to 8192 and `TypedReceiver::recv` now treats
`RecvError::Lagged` as recoverable (warn-and-continue) instead of
terminating its consumer task. This fixes a class of dropouts where a
wave of timeouts could starve the forwarder and cause subsequent
successful events to be lost.
- `ScannerConfig` decomposed into `{ ports, timing, limits, targeting }`
sub-structs.
- Discovered hosts/services emit explicit `ServiceReachability` and
`LinkType` ADTs instead of bare booleans/strings.
- OpenAPI schema regenerated to cover the new query parameters, the new
endpoint, and the v1 result DTOs.
## Behavior changes worth flagging
These are intentional and align the API with the design plan that drove
this PR, but they will surprise any client relying on the pre-PR
semantics. None of them affect a client that sends no query parameters
at all (the default behavior is unchanged).
1. **`enable_failure=true` now controls only ping-failure events.**
Pre-PR it enabled both ping-failure and TCP-probe failure entries in one
knob, which generated a lot of noise that callers were filtering out
client-side. The two streams are now independently gated — to restore
the old "both at once" semantics, send
`enable_failure=true&report_tcp_failure=true` together. New clients
should prefer the explicit `report_ping_failure=true` /
`report_tcp_failure=true` flags.
2. **`probe=ping` no longer triggers the COMMON_PORTS fallback.** An
explicit probe list is taken literally. To also scan the default port
list, either omit `probe=` entirely or list the ports explicitly.
3. **`probe=ping` no longer auto-emits ping-failure events.** Matches
pre-PR baseline of start + success only. To receive failure events when
`probe=ping` is set, add `report_ping_failure=true` (preferred) or
`enable_failure=true` (legacy alias).
4. **`/jet/net/config` now sets `Deprecation: true`** plus a `Link: ...;
rel="successor-version"` pointing to `/jet/net/interfaces`. No `Sunset`
header yet, so clients have unbounded migration time — but they should
plan to migrate.
5. **`response_format=network_scan_result_v1` is opt-in.** Legacy is
still the default. Anyone parsing the legacy shape needs no change.
6. **The `report_ping_status` parameter was added and then removed in
the course of this PR review** and was never shipped to a release.
Clients should use the three explicit
`report_ping_{start,success,failure}` flags directly.
## Test plan
- [x] `cargo +nightly fmt --all -- --check`
- [x] `cargo clippy -p devolutions-gateway -p network-scanner --tests --
-D warnings`
- [x] `cargo test -p devolutions-gateway --lib api::net`
- [x] `cargo test -p testsuite --test integration_tests --
network_scanner`
- [x] Cross-platform target builds — covered by CI
- [x] Manual smoke test via a standalone Angular/JS harness exercising
the new wire shapes and toggles end-to-end
0 commit comments