networkmatch

package
v0.0.310 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 30, 2026 License: Apache-2.0 Imports: 3 Imported by: 0

README

networkmatch

Wildcard-aware matchers for the NetworkNeighbor.IPAddresses and NetworkNeighbor.DNSNames fields, used by node-agent's CEL functions nn.was_address_in_{egress,ingress} and nn.is_domain_in_{egress,ingress}.

This package is the runtime counterpart to the spec sections §5.7 (IP) and §5.8 (DNS) at https://billofbehavior.fusioncore.ai/bob/docs/drafts/spec-v0.0.2/.

Wildcard token vocabulary

Same tokens as the path / argv matchers in dynamicpathdetector — see that package's coverage_test.go for the contract.

Token IP semantics DNS semantics
Literal byte-equality after canonicalization (net.IP) byte-equality after trailing-dot normalization
CIDR (a.b.c.d/n) net.IPNet.Contains(observed)
* as full entry sugar for 0.0.0.0/0::/0 (any IP)
*.<suffix> (leading) RFC 4592 — exactly one DNS label before <suffix>
<a>.⋯.<b> (mid) DynamicIdentifier — exactly one DNS label between <a> and <b>
<prefix>.* (trailing) one or more DNS labels after <prefix> (never zero)
** reserved (rejected at admission) reserved (rejected at admission)

API

// MatchIP reports whether observedIP matches any of the profile entries.
// Each entry MAY be: a literal IP, a CIDR, or the "*" sentinel.
//
// observedIP is matched as text (the function calls net.ParseIP internally
// so the caller does not need to pre-parse it). Empty profile slice
// returns false (no entries → nothing to match against). Empty observedIP
// returns false (no observation to match).
//
// Compile-once contract: callers running this in a hot path SHOULD wrap
// it in a closure that captures pre-compiled *IPNet values across calls
// (the caller knows the profile's lifecycle, this function does not).
func MatchIP(profileEntries []string, observedIP string) bool

// MatchDNS reports whether observedName matches any of the profile entries.
// Each entry MAY use the wildcard tokens above.
//
// Both profile entries and observedName are normalized before
// comparison: a trailing dot is stripped if present, and labels are
// lowercased for case-insensitive equality.
func MatchDNS(profileEntries []string, observedName string) bool

Performance contract

Both functions are called per network event from R0005 / R0011 / R1003 / R1009. The benchmarks in bench_test.go track:

  • BenchmarkMatchIP_Literal — baseline byte-equality
  • BenchmarkMatchIP_CIDR — single CIDR match
  • BenchmarkMatchIP_LongMixedList — 10-entry mixed list, observed IP not in list (worst case)
  • BenchmarkMatchDNS_Literal — baseline
  • BenchmarkMatchDNS_LeadingWildcard — RFC 4592
  • BenchmarkMatchDNS_DeepName — 10-label observed name against a leading-* profile

Targets (CI runner reference):

  • IP literal / CIDR: < 200 ns per call
  • DNS literal: < 300 ns per call
  • DNS wildcard: < 600 ns per call

Beat or hold these on every change; the matcher fires on every network event captured by the eBPF tracers.

Testing

match_ip_test.go and match_dns_test.go are the contract pinning. The fixtures in node-agent/tests/resources/network-wildcards/ are the end-to-end examples; both layers MUST agree.

Documentation

Overview

Package networkmatch provides wildcard-aware matchers for the NetworkNeighbor.IPAddresses and NetworkNeighbor.DNSNames profile fields.

It is the runtime counterpart to spec sections §5.7 (IP) and §5.8 (DNS) of the BoB specification (v0.0.2).

See README.md for the wildcard token vocabulary, public API, and performance contract.

Index

Constants

View Source
const (
	// DNSDynamicLabel is U+22EF — matches exactly one DNS label in
	// the middle of a pattern (mirror of dynamicpathdetector.DynamicIdentifier).
	DNSDynamicLabel = "⋯"

	// DNSWildcardLabel is "*" — matches exactly one label when it's the
	// LEADING label (RFC 4592), or one or more labels when it's the
	// TRAILING label (project extension, spec §5.8 row 3).
	DNSWildcardLabel = "*"
)

DNS wildcard tokens. These mirror the path/argv tokens in dynamicpathdetector but apply with DNS-label semantics.

View Source
const AnyIPSentinel = "*"

AnyIPSentinel is the profile entry that matches any valid IP address. Equivalent to the union of 0.0.0.0/0 and ::/0. Spec §5.7.

Variables

This section is empty.

Functions

func MatchDNS

func MatchDNS(profileEntries []string, observed string) bool

MatchDNS is the convenience wrapper. Hot paths SHOULD reuse a compiled *DNSMatcher built once via CompileDNS.

func MatchIP

func MatchIP(profileEntries []string, observedIP string) bool

MatchIP is the convenience wrapper that compiles + matches in one call. Use this only on cold paths; hot paths SHOULD reuse a cached *IPMatcher constructed via CompileIP.

Empty profile or empty observation returns false.

func ValidateDNSEntry

func ValidateDNSEntry(entry string) error

ValidateDNSEntry returns an error describing why entry is not a valid member of a DNSNames[] list, or nil if it is valid.

Valid forms (spec §5.8):

  • literal name (with or without trailing dot)
  • leading "*" (only as the first label, RFC 4592)
  • trailing "*" (only as the last label)
  • mid "⋯" (DynamicLabel, anywhere)

Rejected:

  • "**" anywhere (recursive — reserved)
  • empty inner labels (e.g. "foo..bar")
  • "*" in any position other than first or last
  • lone "*" with no fixed anchor (degenerate single-label pattern)

func ValidateIPEntry

func ValidateIPEntry(entry string) error

ValidateIPEntry returns an error describing why entry is not a valid member of an IPAddresses[] list, or nil if it is valid.

Valid forms:

  • literal IP (parsed by net.ParseIP)
  • CIDR (parsed by net.ParseCIDR)
  • the AnyIPSentinel ("*")

This is the admission-time defence; runtime MatchIP also tolerates malformed entries (silently skips them) so a bad write doesn't kill the whole match.

Types

type DNSMatcher

type DNSMatcher struct {
	// contains filtered or unexported fields
}

DNSMatcher is the compiled form of a DNS profile. Each entry compiles into one dnsPattern struct.

func CompileDNS

func CompileDNS(profileEntries []string) *DNSMatcher

CompileDNS builds a DNSMatcher from profile entries. Malformed entries (empty, "**", empty inner labels) are silently skipped.

func (*DNSMatcher) Match

func (m *DNSMatcher) Match(observed string) bool

Match reports whether the observed DNS name is admitted by this matcher.

type IPMatcher

type IPMatcher struct {
	// contains filtered or unexported fields
}

IPMatcher is the compiled form of an IP profile. Callers in the hot path (CEL functions, runtime rules) build one per profile and reuse it across every observed event for that profile.

func CompileIP

func CompileIP(profileEntries []string) *IPMatcher

CompileIP builds an IPMatcher from a profile entry list. Malformed entries are silently dropped (validation is the admission layer's job). Returns a usable matcher even on an empty / all-malformed input — Match will return false.

func (*IPMatcher) Match

func (m *IPMatcher) Match(observedIP string) bool

Match reports whether the observed IP text is admitted by this matcher.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL