Skip to content

v0.6.9 — systematic netmap null-tolerance

Choose a tag to compare

@GeiserX GeiserX released this 09 Jun 10:20
· 23 commits to main since this release

Fixed

Netmap decode now tolerates null for every sequence/map field (Go omitempty ↔ Rust).

Go marshals empty slices/maps as JSON null, so a control plane (notably an IPv6-off Headscale) sends null for array fields the client modeled as required sequences — failing the netmap decode with invalid type: null, expected a sequence/expected a map and looping the map-poll stream forever.

v0.6.8 fixed only Node.addresses. v0.6.9 is the systematic pass: rather than annotate each field (the per-field approach is what let the gap recur), null tolerance is applied at the struct level via #[serde_with::apply] on every type on the deserialized netmap path — Node, MapResponse, DNSConfig/Resolver, DerpMap/Region/HomeParams, SSHPolicy and its nested rules, ControlDialPlan, and the ts_packetfilter_serde filter/cap-grant types — so any Vec/map field added later is covered automatically.

null, []/{}, and a populated container are accepted interchangeably. Option<…> fields (whose null/absence means unchanged from the prior poll — e.g. peers, packet_filter singular) are deliberately left untouched, preserving delta-poll semantics.

Regression tests decode a full MapResponse + peer Node + DNSConfig, a DERP map, an SSH policy, a packet filter, and a dial plan with null everywhere a sequence/map is expected.


This project is not associated with Tailscale Inc.