Mapping the entire internet is a massive challenge. If you try to scan large blocks of IPv4 addresses from a single server, you will get rate-limited, blocklisted, or network-saturated almost immediately.

To conduct community-driven security auditing without dropping thousands of dollars on enterprise hosting networks, we need a distributed approach. By dividing up the target IP space into manageable scopes and spreading the work across dozens of volunteer nodes, we can map systems safely and efficiently.

To handle this orchestration, I helped build the fn0rd.io Scanner — a lightweight, high-performance distributed scanning client written in Go that connects to a central coordinator over secure, bi-directional RPC streams.

sequenceDiagram
    participant W as fn0rd-scanner Worker
    participant C as Central Coordinator
    participant I as Target Internet Space

    W->>C: Connect & Handshake (Ed25519 Signed)
    C-->>W: Stream Assigned IP Target Range
    Note over W: Initialize local nmap wrapper
    W->>I: Scan open TCP/UDP ports
    I-->>W: Port states, banners, vulns
    W->>C: Stream Scan Result JSON (Compressed)
    Note over C: Aggregate & index services

Cryptographic node identities

Because volunteer-driven scanning networks are inherently public, they are prime targets for malicious actors. If an attacker can spoof a scanner node, they can inject poisoned scan results, leading to false indicators across the entire index.

To prevent this, the fn0rd.io Scanner utilizes standard Ed25519 public-key cryptography for node authentication. On startup, the scanner client loads a cryptographic private key.

Every single request, handshake ping, and result upload payload is signed on the wire. The central coordinator verifies these signatures against a database of whitelisted node public keys, ensuring that rogue workers can never poison our security metrics.

Orchestrating native Nmap with Go

Rather than writing a raw TCP syn-scanner from scratch (which is highly complex and prone to edge-case bugs), the scanner worker takes advantage of the industry standard nmap tool chain.

It wraps Nmap execution inside a Go package using the Ullaakut/nmap/v3 library. This allows us to parse target schemas, set aggressive timing thresholds, filter out closed ports, and leverage powerful Nmap scripts (like banner and vulners) to map active daemon versions and vulnerabilities.

func (ns *NmapScanner) New(ctx context.Context, targets string, iface string, udp bool) (common.Scanner, error) {
	var opts []nmap.Option
	opts = append(opts,
		nmap.WithTargets(targets),
		nmap.WithTimingTemplate(nmap.TimingAggressive),
		nmap.WithOpenOnly(),
		nmap.WithReason(),
		nmap.WithServiceInfo(),
		nmap.WithConnectScan(),
		nmap.WithSkipHostDiscovery(),
		nmap.WithSystemDNS(),
		nmap.WithPorts(portsToString(common.Ports, udp)),
		nmap.WithScripts("vulners", "banner"),
		nmap.WithMaxRetries(1),
	)
	if iface != "" {
		opts = append(opts, nmap.WithInterface(iface))
	}
	if udp {
		opts = append(opts, nmap.WithUDPScan())
	}
	// Create and initialize the executor
	scanner, err := nmap.NewScanner(ctx, opts...)
	if err != nil {
		return nil, fmt.Errorf("failed to create Nmap scanner: %w", err)
	}
	return &NmapScanner{scanner: scanner}, nil
}

The output of the scan is serialized into raw JSON and shipped back to the coordinator over a gRPC stream.

Resilient streaming connection pipelines

The network connection between workers and the coordinator relies on ConnectRPC (a highly optimized implementation of gRPC) over HTTP/2.

Because volunteer nodes are hosted on residential connections or erratic cloud servers, the connection manager is built with aggressive resilience in mind. It uses a dedicated Goroutine queue running a tick-based ping loop to monitor connectivity.

If a connection drops or times out, the client kicks off an exponential backoff-and-jitter loop to re-establish the stream without blocking active local scanner processes.

It is a incredibly efficient, robust security tool that helps keep a pulse on global internet health.