slackhq/nebula · warning

ErrNoMatchingRule

ErrNoMatchingRule

Error message

no matching rule in firewall table

What it means

ErrNoMatchingRule is the sentinel error declared at firewall.go:422 with message "no matching rule in firewall table". Firewall.Drop returns it when the packet passed all address/certificate checks but no rule in the firewall rule table matches (firewall.go:473: table.match returns false). It is the library's way of saying 'default deny': nebula's firewall is allow-list only, so any flow not explicitly permitted is dropped with this error.

Source

Thrown at firewall.go:422

				"rule", i,
				"warning", warning,
			)
		}

		err = fw.AddRule(inbound, proto, startPort, endPort, r.Groups, r.Host, r.Cidr, r.LocalCidr, r.CAName, r.CASha)
		if err != nil {
			return fmt.Errorf("%s rule #%v; `%s`", table, i, err)
		}
	}

	return nil
}

var ErrUnknownNetworkType = errors.New("unknown network type")
var ErrPeerRejected = errors.New("remote address is not within a network that we handle")
var ErrInvalidRemoteIP = errors.New("remote address is not in remote certificate networks")
var ErrInvalidLocalIP = errors.New("local address is not in list of handled local addresses")
var ErrNoMatchingRule = errors.New("no matching rule in firewall table")

// Drop returns an error if the packet should be dropped, explaining why. It
// returns nil if the packet should not be dropped.
func (f *Firewall) Drop(fp firewall.Packet, incoming bool, h *HostInfo, caPool *cert.CAPool, localCache firewall.ConntrackCache) error {
	// Make sure remote address matches nebula certificate, and determine how to treat it
	if h.networks == nil {
		// Simple case: Certificate has one address and no unsafe networks
		if h.vpnAddrs[0] != fp.RemoteAddr {
			f.metrics(incoming).droppedRemoteAddr.Inc(1)
			return ErrInvalidRemoteIP
		}
	} else {
		nwType, ok := h.networks.Lookup(fp.RemoteAddr)
		if !ok {
			f.metrics(incoming).droppedRemoteAddr.Inc(1)
			return ErrInvalidRemoteIP
		}
		switch nwType {

View on GitHub (pinned to dd8f660c0a)

Solutions

  1. Add an explicit firewall rule allowing the flow (from group/CIDR, port, protocol) in the nebula config and reload
  2. Check rule direction: inbound traffic needs a rule whose 'port'/'from' side matches the sender's cert groups and the local listening port
  3. Verify the peer certificate's groups match the groups named in the rule
  4. For established flows failing after a rule reload, ensure conntrack cache is handled/reset consistently
  5. For v6 traffic, add the corresponding IPv6 rules — v4 rules do not match v6 packets

Example fix

// before: no inbound SSH rule -> Drop returns ErrNoMatchingRule
firewall:
  inbound:
    - port: 80
      proto: tcp
      group: app
// after
firewall:
  inbound:
    - port: 80
      proto: tcp
      group: app
    - port: 22
      proto: tcp
      group: admin
Defensive patterns

Strategy: fallback

Validate before calling

// dry-check the rule set before deploying: ensure the intended flow matches at least one rule
if !fw.RuleMatchesExactlyOnce(flow) && !conntrackHas(flow) {
    // Drop will return ErrNoMatchingRule; add an allow rule first
}

Try / catch

if err := fw.Drop(pkt, incoming, host, caPool, cache); err != nil {
    if errors.Is(err, firewall.ErrNoMatchingRule) {
        // default-deny hit: log flow (proto, port, groups, direction) for rule authoring
        // do not blanket-allow; add a targeted rule instead
    }
}

Prevention

When it happens

Trigger: Firewall.Drop reaches the final rule-matching stage (firewall.go:473) and table.match(fp, incoming, peerCert, caPool) finds no matching rule for the packet's protocol/port/groups. Returned by Drop for both inbound and outbound packets; exercised by tests like TestFirewall_Drop, TestFirewall_Drop2/3, TestFirewall_DropV6, TestFirewall_DropConntrackReload.

Common situations: Missing firewall rule for the intended service (e.g. no inbound rule for the port a peer connects on); direction mismatch — rule defined for outbound but traffic is inbound (see firewall_test.go:215 where outbound drops with ErrNoMatchingRule while a conntrack entry allows inbound); rule's group/port/proto constraints don't match the peer certificate's groups; rules reloaded while an existing conntrack entry was reset (TestFirewall_DropConntrackReload); IPv6 rules missing when traffic is v6.

Related errors


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