Skip to content

[VM Discovery P3] Network sweep + Active Directory lookup #114

Description

@mayankpande88

Part of epic: nudgebee/nudgebee-enterprise#35404. Start after the P1+P2 end-to-end demo.

What we're building, in one sentence

Two new ways for the forager to find machines it doesn't know about yet: probing its own network segment, and asking Active Directory for its computer list.

These only find machines (IP, name, a few facts). Collecting what's installed stays with discovery_inventory (#113).

Action 1: discovery_sweep

Request:

{"action": "discovery_sweep",
 "params": {"cidrs": ["10.0.1.0/24"], "ports": [22, 3389, 5985],
            "rate_pps": 100, "timeout_ms": 1000,
            "exclusions": ["10.0.1.250/32"]}}

What it does per CIDR:

  1. If the CIDR is the forager's own L2: read the ARP/neighbor table after probing — gives MAC addresses for free.
  2. ICMP echo to each address (is anything there?).
  3. TCP connect to the given ports (22 = Linux/SSH, 3389/5985 = Windows — fingerprint only, we don't inventory Windows yet).
  4. Reverse-DNS lookup for responders.

Response per live host: {"ip": "10.0.1.15", "mac": "aa:bb:...", "rdns": "web-01.corp.local", "open_ports": [22]}.

Safety is part of the spec, not polish:

  • Hard rate cap enforced in the forager (default ≤100 packets/sec) — the server asks, the forager still refuses to exceed it.
  • Exclusion list honored before any packet is sent.
  • Plain well-formed connects only — no raw crafted packets (malformed nmap-style probes crash embedded/OT gear).
  • Open decision inside this ticket: plain net.Dial loop vs a scanning library (e.g. naabu). Try plain first; a /24 at 100 pps is trivial.

Action 2: discovery_ldap

Uses an ldap datasource (unprivileged read-only bind account, credentials via pkg/secrets, configured like the db proxies).

Search: base DN from config, filter (objectCategory=computer), attributes name, dNSHostName, operatingSystem, lastLogonTimestamp, objectGUID.

Skip machines whose lastLogonTimestamp is older than active_within (param, e.g. 90 days) — AD is full of tombstones of machines that died years ago.

Response per computer: {"name": "WEB-01", "dns_name": "web-01.corp.local", "os": "Ubuntu", "last_logon": "...", "object_guid": "..."}. The objectGUID matters: it's a STRONG identity the server can merge on.

Acceptance criteria (each is a test)

  • Sweep of a /24 test network returns every live host with IP + open ports; MAC and rDNS where available.
  • Packet capture during the sweep shows the rate never exceeds rate_pps.
  • Excluded address receives zero packets (verified by capture).
  • LDAP query against a test AD returns active computers; a computer with old lastLogonTimestamp is filtered out.
  • objectGUID arrives server-side and is usable as a merge key.

Design: docs/design/vm-discovery-phase0.md §5, §9 (PR #117).

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions