slackhq/nebula · error

invalid vpn addr for v1 handleHostQuery

Error message

invalid vpn addr for v1 handleHostQuery

What it means

In handleHostQuery, when the selected certificate encoding version is cert.Version1, the queried VPN address must be an IPv4 address (Is4), because the v1 wire format stores only a 32-bit OldVpnAddr. An IPv6 or non-v4 address cannot be encoded for v1 recipients.

Source

Thrown at lighthouse.go:1222

		} else {
			crt := targetHI.GetCert().Certificate
			useVersion = crt.Version()
			// we can only retarget if we have a hostinfo
			newDest, ok := findNetworkUnion(crt.Networks(), fromVpnAddrs)
			if ok {
				whereToPunch = newDest
			} else {
				if lhh.l.Enabled(context.Background(), slog.LevelDebug) {
					lhh.l.Debug("unable to punch to host, no addresses in common",
						"to", crt.Networks(),
					)
				}
			}
		}

		if useVersion == cert.Version1 {
			if !whereToPunch.Is4() {
				return 0, fmt.Errorf("invalid vpn addr for v1 handleHostQuery")
			}
			b := whereToPunch.As4()
			n.Details.OldVpnAddr = binary.BigEndian.Uint32(b[:])
		} else if useVersion == cert.Version2 {
			n.Details.VpnAddr = netAddrToProtoAddr(whereToPunch)
		} else {
			return 0, errors.New("unsupported version")
		}
		lhh.coalesceAnswers(useVersion, c, n)

		return n.MarshalTo(lhh.pb)
	})

	if !found {
		return
	}

	if err != nil {

View on GitHub (pinned to dd8f660c0a)

Solutions

  1. Upgrade all nodes/certs to Version2 so v6 VPN addresses can be encoded
  2. Restrict VPN addresses to IPv4 while v1 peers remain in the network
  3. Filter the host query response to only v4 targets when answering v1 peers

Example fix

// before
if useVersion == cert.Version1 {
    if !whereToPunch.Is4() {
        return 0, fmt.Errorf("invalid vpn addr for v1 handleHostQuery")
    }
// after: prefer v2 when the target is not v4
if !whereToPunch.Is4() && canUseV2 {
    useVersion = cert.Version2
}
Defensive patterns

Strategy: type-guard

Validate before calling

if useVersion == cert.Version1 && !whereToPunch.Is4() {
    // skip or convert target before responding
}

Type guard

func v1SafeAddr(a netip.Addr) bool { return a.Is4() }

Prevention

When it happens

Trigger: A host query answer targets a dual-stack/v6 VPN address while the requesting peer (or reply encoding) uses cert.Version1, so whereToPunch.Is4() fails.

Common situations: IPv6-enabled VPN network (v2 certs) with legacy v1-cert lighthouses/peers; lighthouse replying to an old node about a v6 address; mixed cert-version upgrade.

Related errors


AI-assisted analysis of slackhq/nebula@dd8f660c0a (2026-09-03). Data as JSON: /api/errors/8e48bba693fb248f. Report an issue: GitHub.