Documentation
¶
Overview ¶
Package classify turns probe results into a NAT-type verdict.
Classification follows RFC 5780 mapping-behavior categories (Endpoint-Independent, Address-Dependent, Address and Port-Dependent) and emits legacy RFC 3489 terms ("cone", "symmetric") for human readers. Optional filtering data (RFC 5780 §4.4) refines the WebRTC forecast when the target server supports CHANGE-REQUEST. See docs/design.md.
Index ¶
Constants ¶
const ( WarnAllProbesFailed = "all_probes_failed" WarnADMOrStricter = "adm_or_stricter" WarnCGNATDetected = "cgnat_detected" WarnInsufficientProbes = "insufficient_probes" WarnFilteringBehaviorNotTested = "filtering_behavior_not_tested" WarnFilteringSkippedNoChangeRequest = "filtering_skipped_no_change_request" WarnMixedAddressFamilyProbes = "mixed_address_family_probes" WarnHairpinUntested = "hairpin_untested" )
Stable warning vocabulary for the JSON API.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type FilteringBehavior ¶ added in v0.1.2
type FilteringBehavior int
FilteringBehavior is the RFC 5780 §4.4 filtering category.
const ( // FilteringUntested is the zero value: no §4.4 sequence ran (server didn't // support OTHER-ADDRESS, or filtering wasn't attempted). FilteringUntested FilteringBehavior = iota // FilteringEndpointIndependent: replies arrive from any source the server // is asked to use (Test 2 + Test 3 both received). FilteringEndpointIndependent // FilteringAddressDependent: replies arrive when source IP matches a peer // the client has communicated with (Test 2 dropped, Test 3 received). FilteringAddressDependent // FilteringAddressAndPortDependent: replies arrive only when both source // IP and port match (Test 2 + Test 3 both dropped). FilteringAddressAndPortDependent )
func (FilteringBehavior) String ¶ added in v0.1.2
func (b FilteringBehavior) String() string
String returns the canonical wire name (matches the JSON enum).
type Forecast ¶
type Forecast struct {
DirectP2P string // "likely" | "possible" | "unlikely" | "unknown"
TURNRequired bool
}
Forecast is the WebRTC direct-P2P prediction.
type NATType ¶
type NATType int
NATType is the RFC 5780 mapping-behavior category.
const ( // Unknown indicates classification could not be determined from the // available probes (typically only one successful probe — no comparison // point for mapping behavior). Unknown NATType = iota // EndpointIndependentMapping: same mapped endpoint across servers. // RFC 5780. Legacy term "cone". EndpointIndependentMapping // AddressDependentMapping: mapped endpoint varies by destination address. // RFC 5780. v0.1 reports this for any case where mapped endpoints differ // across servers; ADM vs APDM cannot be distinguished without // CHANGE-REQUEST. AddressDependentMapping // AddressPortDependentMapping: mapped endpoint varies by destination // address and port. RFC 5780. Legacy term "symmetric". v0.1 does not // emit this category directly (see AddressDependentMapping note). AddressPortDependentMapping // Blocked: no probe succeeded. Network rejects outbound STUN, all target // servers are unreachable, or the caller's timeout fired too early. Blocked )
type Verdict ¶
type Verdict struct {
Type NATType
LegacyName string // "cone", "symmetric", "" when unknown/blocked
PublicEndpoint netip.AddrPort
CGNAT bool
// Filtering is the RFC 5780 §4.4 outcome; FilteringUntested when the
// §4.4 sequence did not run (no OTHER-ADDRESS support, or not attempted).
Filtering FilteringBehavior
// FilteringTestedAgainst is the server the §4.4 sequence ran against.
// Zero-value (Server{}) when Filtering == FilteringUntested, which
// happens in any of these cases:
// - no FilteringResult was supplied (filtering not attempted);
// - the server did not advertise OTHER-ADDRESS (ErrFilteringNotSupported);
// - the initial Test 1 binding probe failed (ErrTest1Failed);
// - the (T2=true, T3=false) RFC-impossible state was observed.
FilteringTestedAgainst probe.Server
// Hairpinning is tri-state per docs/design.md:361:
// - nil: not tested (probe didn't run / socket setup failed)
// - &true: tagged loopback packet arrived
// - &false: listen window elapsed without the packet (may be a true
// negative OR a per-NAT filtering false-negative on the
// hairpin path; see docs/design.md:428)
// Carried through Classify unchanged in v0.1.4; forecast logic does NOT
// shift on this value yet. Hairpinning only matters for same-NAT (LAN)
// peers, while the natcheck user's question is about inter-NAT WebRTC.
// Future releases may revisit if real-world data justifies a shift.
Hairpinning *bool
Warnings []string
Forecast Forecast
}
Verdict is the final classification output.
func Classify ¶
func Classify(results []probe.Result, filtering *probe.FilteringResult, hairpinning *probe.HairpinningResult) Verdict
Classify turns probe results into a Verdict. Pure function: no I/O, no goroutines, deterministic for a given input.
A probe.Result is treated as successful only when Err == nil AND Mapped.IsValid(). This guards against buggy Prober implementations that might report nil-error with a zero mapped endpoint.
filtering may be nil; in that case Verdict.Filtering stays Untested and the existing WarnFilteringBehaviorNotTested warning is emitted. When filtering is non-nil, its Test2/Test3 booleans drive the FilteringBehavior and the WebRTC forecast for EIM mappings (RFC 5780 §4.4 outcomes).
hairpinning may be nil; in that case Verdict.Hairpinning stays nil and WarnHairpinUntested is emitted. When hairpinning is non-nil, the value is carried through to Verdict.Hairpinning unchanged. v0.1.4 does NOT shift the forecast based on this value — hairpinning only matters for same-NAT (LAN) peers, which is not the natcheck user's question. See the Verdict field doc and docs/design.md:478.