wulf-pulse/lib/services/rmm/scripts/get-network-discovery.ts
lorentz 1112a06afe feat: RMM Overshell, IT Glue audit/write-back, LogLift, link-aware bundles, dashboard overhaul
- RMM Overshell (migration 077): admin page, dispatch UI, executor/worker, target
  resolver, script registry (AD/DHCP/DNS/event-log/services/software/network/loglift)
- LogLift evidence pipeline (migration 078): upload webhook, B2 storage client,
  receiver/matcher, EventLogCollector PowerShell script
- IT Glue audit + write-back (migrations 075, 076): asset-audit runner, ticket
  xrefs, applications/configurations browse pages + apply/revert/audit endpoints
- Link-aware analyzer bundles (migration 073) + provider toggle (migration 074):
  link-discovery service, OpenRouter LLM provider, related-tickets/itglue-suggestion
  panels, analyze-bundle endpoint
- Endpoint data model + device-link reconciliation (migrations 079, 080): conflicts
  admin page, reconciler service, resolve endpoints
- Dashboard overhaul: integration-health service + alerts, overview/health endpoints
- Permissions: add itglue + rmm scopes; middleware: public /api/rmm/loglift route

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-03 07:13:18 -04:00

67 lines
2.2 KiB
TypeScript

/**
* get-network-discovery — local IP config + ARP table from the WNP. Site-
* anchored. Designed to catch the IP-conflict pattern (the proven test
* case at Hynes had 10.10.110.215 / .253 fought over by two VMware MACs).
*
* Output: own NIC config + parsed ARP table (IP, MAC, type) + a flag for
* any duplicate IPs seen in ARP responses.
*/
import { type RmmScript, parseJsonOutput } from './types';
export const getNetworkDiscovery: RmmScript = {
id: 'get-network-discovery',
name: 'Network discovery (NIC config + ARP)',
description:
'Local NIC IPv4 configuration plus full ARP table (parsed). Flags duplicate IPs seen across MACs.',
target_type: 'site_anchor',
expected_runtime_seconds: 20,
version: 1,
body: `
$ErrorActionPreference = 'SilentlyContinue'
$nics = Get-NetIPConfiguration |
Where-Object { $_.NetAdapter.Status -eq 'Up' } |
ForEach-Object {
[pscustomobject]@{
interface_alias = $_.InterfaceAlias
ipv4_address = ($_.IPv4Address.IPAddress -join ',')
ipv4_default_gateway = ($_.IPv4DefaultGateway.NextHop -join ',')
dns_servers = ($_.DNSServer | Where-Object { $_.AddressFamily -eq 2 }).ServerAddresses -join ','
mac = $_.NetAdapter.LinkLayerAddress
link_speed = $_.NetAdapter.LinkSpeed
}
}
$arpRaw = & arp -a 2>&1
$arp = @()
$dup = @{}
foreach ($line in $arpRaw) {
if ($line -match '^\\s*(\\d+\\.\\d+\\.\\d+\\.\\d+)\\s+([a-fA-F0-9:-]{11,17})\\s+(\\w+)') {
$ip = $Matches[1]
$mac = $Matches[2].ToLower()
$type = $Matches[3]
$arp += [pscustomobject]@{ ip = $ip; mac = $mac; type = $type }
if ($dup.ContainsKey($ip)) { $dup[$ip] = ($dup[$ip] + ',' + $mac) }
else { $dup[$ip] = $mac }
}
}
$conflicts = @()
foreach ($k in $dup.Keys) {
$macs = ($dup[$k] -split ',') | Sort-Object -Unique
if ($macs.Count -gt 1) {
$conflicts += [pscustomobject]@{ ip = $k; macs = $macs }
}
}
@{
hostname = $env:COMPUTERNAME
captured_at_utc = (Get-Date).ToUniversalTime().ToString("o")
nics = $nics
arp_count = $arp.Count
arp = $arp
ip_conflicts = $conflicts
ip_conflict_count = $conflicts.Count
} | ConvertTo-Json -Depth 5 -Compress
`.trim(),
parseOutput: (stdout) => parseJsonOutput(stdout),
};