{"record":{"id":"df08df63b8516e53","repo":"slackhq/nebula","slug":"errinvalidremoteip","errorCode":"ErrInvalidRemoteIP","errorMessage":"remote address is not in remote certificate networks","messagePattern":"remote address is not in remote certificate networks","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"firewall.go","lineNumber":420,"sourceCode":"\t\t\tl.Warn(\"firewall rule sanity check\",\n\t\t\t\t\"table\", table,\n\t\t\t\t\"rule\", i,\n\t\t\t\t\"warning\", warning,\n\t\t\t)\n\t\t}\n\n\t\terr = fw.AddRule(inbound, proto, startPort, endPort, r.Groups, r.Host, r.Cidr, r.LocalCidr, r.CAName, r.CASha)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"%s rule #%v; `%s`\", table, i, err)\n\t\t}\n\t}\n\n\treturn nil\n}\n\nvar ErrUnknownNetworkType = errors.New(\"unknown network type\")\nvar ErrPeerRejected = errors.New(\"remote address is not within a network that we handle\")\nvar ErrInvalidRemoteIP = errors.New(\"remote address is not in remote certificate networks\")\nvar ErrInvalidLocalIP = errors.New(\"local address is not in list of handled local addresses\")\nvar ErrNoMatchingRule = errors.New(\"no matching rule in firewall table\")\n\n// Drop returns an error if the packet should be dropped, explaining why. It\n// returns nil if the packet should not be dropped.\nfunc (f *Firewall) Drop(fp firewall.Packet, incoming bool, h *HostInfo, caPool *cert.CAPool, localCache firewall.ConntrackCache) error {\n\t// Make sure remote address matches nebula certificate, and determine how to treat it\n\tif h.networks == nil {\n\t\t// Simple case: Certificate has one address and no unsafe networks\n\t\tif h.vpnAddrs[0] != fp.RemoteAddr {\n\t\t\tf.metrics(incoming).droppedRemoteAddr.Inc(1)\n\t\t\treturn ErrInvalidRemoteIP\n\t\t}\n\t} else {\n\t\tnwType, ok := h.networks.Lookup(fp.RemoteAddr)\n\t\tif !ok {\n\t\t\tf.metrics(incoming).droppedRemoteAddr.Inc(1)\n\t\t\treturn ErrInvalidRemoteIP","sourceCodeStart":402,"sourceCodeEnd":438,"githubUrl":"https://github.com/slackhq/nebula/blob/dd8f660c0ac37903ec4080ca4d3c861ba9342ceb/firewall.go#L402-L438","documentation":"ErrInvalidRemoteIP is a sentinel error declared at firewall.go:420 with message \"remote address is not in remote certificate networks\". Firewall.Drop returns it during the remote-address sanity check: for hosts with a single VPN network, if the packet's remote address does not exactly equal the host's expected vpnAddrs[0], or (otherwise) if the remote address is not contained in any of the host's certificate networks, the packet is treated as spoofed and dropped. It is the IP-spoofing guard tied to the remote peer's certificate.","triggerScenarios":"1) firewall.go:432 — host has one VPN network and fp.RemoteAddr != h.vpnAddrs[0]. 2) firewall.go:438 — the remote address fails a prefix lookup in the host's networks table. Any Drop() call where the source IP of the packet does not match the address/networks bound to the remote peer's certificate triggers it.","commonSituations":"NAT or encapsulation rewriting the outer source address so it no longer matches the certified tunnel address; a host behind NAT sending packets from a different source IP than its certificate lists; misconfigured static_host_map / advertised networks; buggy code reusing a HostInfo for the wrong remote; testing with fabricated packet source addresses.","solutions":["Verify the packet's source address matches the address in the remote peer's certificate; fix NAT/addressing so the certified address is the actual packet source","If the peer legitimately has multiple addresses, ensure they are listed in the certificate's networks so the prefix lookup at firewall.go:438 succeeds","Regenerate/reissue the remote peer's certificate with the correct networks entry for its current address","Check for load-balancer or NAT44 devices rewriting source IPs on the tunnel and add NAT exceptions","Confirm the HostInfo used in Drop() corresponds to the actual sender, not a cached entry for another peer"],"exampleFix":"// before: certificate issued without the NATed address\n//   nebula-cert sign -name hostA -ip 10.0.0.5\n//   packets arrive from 203.0.113.9 -> Drop returns ErrInvalidRemoteIP\n// after: include the real address in the cert networks\n//   nebula-cert sign -name hostA -ip 10.0.0.5 -subnets 203.0.113.9/32","handlingStrategy":"try-catch","validationCode":"// confirm the packet source matches the HostInfo's certified address before Drop\nif len(h.vpnAddrs) == 1 && fp.RemoteAddr != h.vpnAddrs[0] {\n    // Drop WILL return ErrInvalidRemoteIP; fix the addressing/NAT first\n}","typeGuard":null,"tryCatchPattern":"if err := fw.Drop(pkt, incoming, host, caPool, cache); err != nil {\n    if errors.Is(err, firewall.ErrInvalidRemoteIP) {\n        // treat as possible spoofing or NAT mismatch: log remote addr vs cert networks\n        // and do NOT retry the same packet\n    }\n}","preventionTips":["Ensure the certified address is the on-the-wire packet source (configure NAT preservation for the tunnel)","List every legitimate secondary address of a peer in its certificate's subnets/networks field","Reissue certificates after re-addressing hosts; never reuse stale HostInfo entries across peers","Watch the droppedRemoteAddr metric for spikes indicating NAT/spoofing issues"],"tags":["firewall","ip-spoofing","certificate","packet-drop"],"backgroundTag":"ip-spoofing-detected","analyzedSha":"dd8f660c0ac37903ec4080ca4d3c861ba9342ceb","analyzedAt":"2026-09-03T11:13:55.444Z","contentChangedAt":"2026-09-03T11:13:55.444Z","schemaVersion":2},"datasetVersion":"2026-09-10T17:17:09.494Z"}