Просмотр исходного кода

tailcfg: add some omitzero, adjust some omitempty to omitzero

Updates tailscale/corp#25406

Change-Id: I7832dbe3dce3774bcc831e3111feb75bcc9e021d
Signed-off-by: Brad Fitzpatrick <[email protected]>
Brad Fitzpatrick 3 месяцев назад
Родитель
Сommit
5b0c57f497
1 измененных файлов с 114 добавлено и 114 удалено
  1. 114 114
      tailcfg/tailcfg.go

+ 114 - 114
tailcfg/tailcfg.go

@@ -255,9 +255,9 @@ func (u StableNodeID) IsZero() bool {
 // have a general gmail address login associated with the user.
 type User struct {
 	ID            UserID
-	DisplayName   string // if non-empty overrides Login field
-	ProfilePicURL string // if non-empty overrides Login field
-	Created       time.Time
+	DisplayName   string    // if non-empty overrides Login field
+	ProfilePicURL string    `json:",omitzero"` // if non-empty overrides Login field
+	Created       time.Time `json:",omitzero"`
 }
 
 // Login is a user from a specific identity provider, not associated with any
@@ -268,7 +268,7 @@ type Login struct {
 	Provider      string  // "google", "github", "okta_foo", etc.
 	LoginName     string  // an email address or "email-ish" string (like alice@github)
 	DisplayName   string  // from the IdP
-	ProfilePicURL string  // from the IdP
+	ProfilePicURL string  `json:",omitzero"` // from the IdP
 }
 
 // A UserProfile is display-friendly data for a [User].
@@ -278,7 +278,7 @@ type UserProfile struct {
 	ID            UserID
 	LoginName     string // "[email protected]"; for display purposes only (provider is not listed)
 	DisplayName   string // "Alice Smith"
-	ProfilePicURL string `json:",omitempty"`
+	ProfilePicURL string `json:",omitzero"`
 }
 
 func (p *UserProfile) Equal(p2 *UserProfile) bool {
@@ -345,13 +345,13 @@ type Node struct {
 	User UserID
 
 	// Sharer, if non-zero, is the user who shared this node, if different than User.
-	Sharer UserID `json:",omitempty"`
+	Sharer UserID `json:",omitzero"`
 
 	Key          key.NodePublic
-	KeyExpiry    time.Time                  // the zero value if this node does not expire
+	KeyExpiry    time.Time                  `json:",omitzero"` // the zero value if this node does not expire
 	KeySignature tkatype.MarshaledSignature `json:",omitempty"`
-	Machine      key.MachinePublic
-	DiscoKey     key.DiscoPublic
+	Machine      key.MachinePublic          `json:",omitzero"`
+	DiscoKey     key.DiscoPublic            `json:",omitzero"`
 
 	// Addresses are the IP addresses of this Node directly.
 	Addresses []netip.Prefix
@@ -361,7 +361,7 @@ type Node struct {
 	// As of CapabilityVersion 112, this may be nil (null or undefined) on the wire
 	// to mean the same as Addresses. Internally, it is always filled in with
 	// its possibly-implicit value.
-	AllowedIPs []netip.Prefix
+	AllowedIPs []netip.Prefix `json:",omitzero"` // _not_ omitempty; only nil is special
 
 	Endpoints []netip.AddrPort `json:",omitempty"` // IP+port (public via STUN, and local LANs)
 
@@ -375,18 +375,18 @@ type Node struct {
 	// this field. See tailscale/tailscale#14636. Do not use this field in code
 	// other than in the upgradeNode func, which canonicalizes it to HomeDERP
 	// if it arrives as a LegacyDERPString string on the wire.
-	LegacyDERPString string `json:"DERP,omitempty"` // DERP-in-IP:port ("127.3.3.40:N") endpoint
+	LegacyDERPString string `json:"DERP,omitzero"` // DERP-in-IP:port ("127.3.3.40:N") endpoint
 
 	// HomeDERP is the modern version of the DERP string field, with just an
 	// integer. The client advertises support for this as of capver 111.
 	//
 	// HomeDERP may be zero if not (yet) known, but ideally always be non-zero
 	// for magicsock connectivity to function normally.
-	HomeDERP int `json:",omitempty"` // DERP region ID of the node's home DERP
+	HomeDERP int `json:",omitzero"` // DERP region ID of the node's home DERP
 
-	Hostinfo HostinfoView
-	Created  time.Time
-	Cap      CapabilityVersion `json:",omitempty"` // if non-zero, the node's capability version; old servers might not send
+	Hostinfo HostinfoView      `json:",omitzero"`
+	Created  time.Time         `json:",omitzero"`
+	Cap      CapabilityVersion `json:",omitzero"` // if non-zero, the node's capability version; old servers might not send
 
 	// Tags are the list of ACL tags applied to this node.
 	// Tags take the form of `tag:<value>` where value starts
@@ -453,25 +453,25 @@ type Node struct {
 	// it do anything. It is the tailscaled client's job to double-check the
 	// MapResponse's PacketFilter to verify that its AllowedIPs will not be
 	// accepted by the packet filter.
-	UnsignedPeerAPIOnly bool `json:",omitempty"`
+	UnsignedPeerAPIOnly bool `json:",omitzero"`
 
 	// The following three computed fields hold the various names that can
 	// be used for this node in UIs. They are populated from controlclient
 	// (not from control) by calling node.InitDisplayNames. These can be
 	// used directly or accessed via node.DisplayName or node.DisplayNames.
 
-	ComputedName            string `json:",omitempty"` // MagicDNS base name (for normal non-shared-in nodes), FQDN (without trailing dot, for shared-in nodes), or Hostname (if no MagicDNS)
+	ComputedName            string `json:",omitzero"` // MagicDNS base name (for normal non-shared-in nodes), FQDN (without trailing dot, for shared-in nodes), or Hostname (if no MagicDNS)
 	computedHostIfDifferent string // hostname, if different than ComputedName, otherwise empty
-	ComputedNameWithHost    string `json:",omitempty"` // either "ComputedName" or "ComputedName (computedHostIfDifferent)", if computedHostIfDifferent is set
+	ComputedNameWithHost    string `json:",omitzero"` // either "ComputedName" or "ComputedName (computedHostIfDifferent)", if computedHostIfDifferent is set
 
 	// DataPlaneAuditLogID is the per-node logtail ID used for data plane audit logging.
-	DataPlaneAuditLogID string `json:",omitempty"`
+	DataPlaneAuditLogID string `json:",omitzero"`
 
 	// Expired is whether this node's key has expired. Control may send
 	// this; clients are only allowed to set this from false to true. On
 	// the client, this is calculated client-side based on a timestamp sent
 	// from control, to avoid clock skew issues.
-	Expired bool `json:",omitempty"`
+	Expired bool `json:",omitzero"`
 
 	// SelfNodeV4MasqAddrForThisPeer is the IPv4 that this peer knows the current node as.
 	// It may be empty if the peer knows the current node by its native
@@ -486,7 +486,7 @@ type Node struct {
 	// This only applies to traffic originating from the current node to the
 	// peer or any of its subnets. Traffic originating from subnet routes will
 	// not be masqueraded (e.g. in case of --snat-subnet-routes).
-	SelfNodeV4MasqAddrForThisPeer *netip.Addr `json:",omitempty"`
+	SelfNodeV4MasqAddrForThisPeer *netip.Addr `json:",omitzero"` // TODO: de-pointer: tailscale/tailscale#17978
 
 	// SelfNodeV6MasqAddrForThisPeer is the IPv6 that this peer knows the current node as.
 	// It may be empty if the peer knows the current node by its native
@@ -501,17 +501,17 @@ type Node struct {
 	// This only applies to traffic originating from the current node to the
 	// peer or any of its subnets. Traffic originating from subnet routes will
 	// not be masqueraded (e.g. in case of --snat-subnet-routes).
-	SelfNodeV6MasqAddrForThisPeer *netip.Addr `json:",omitempty"`
+	SelfNodeV6MasqAddrForThisPeer *netip.Addr `json:",omitzero"` // TODO: de-pointer: tailscale/tailscale#17978
 
 	// IsWireGuardOnly indicates that this is a non-Tailscale WireGuard peer, it
 	// is not expected to speak Disco or DERP, and it must have Endpoints in
 	// order to be reachable.
-	IsWireGuardOnly bool `json:",omitempty"`
+	IsWireGuardOnly bool `json:",omitzero"`
 
 	// IsJailed indicates that this node is jailed and should not be allowed
 	// initiate connections, however outbound connections to it should still be
 	// allowed.
-	IsJailed bool `json:",omitempty"`
+	IsJailed bool `json:",omitzero"`
 
 	// ExitNodeDNSResolvers is the list of DNS servers that should be used when this
 	// node is marked IsWireGuardOnly and being used as an exit node.
@@ -827,10 +827,10 @@ type Location struct {
 // Because it contains pointers (slices), this type should not be used
 // as a value type.
 type Hostinfo struct {
-	IPNVersion    string `json:",omitempty"` // version of this code (in version.Long format)
-	FrontendLogID string `json:",omitempty"` // logtail ID of frontend instance
-	BackendLogID  string `json:",omitempty"` // logtail ID of backend instance
-	OS            string `json:",omitempty"` // operating system the client runs on (a version.OS value)
+	IPNVersion    string `json:",omitzero"` // version of this code (in version.Long format)
+	FrontendLogID string `json:",omitzero"` // logtail ID of frontend instance
+	BackendLogID  string `json:",omitzero"` // logtail ID of backend instance
+	OS            string `json:",omitzero"` // operating system the client runs on (a version.OS value)
 
 	// OSVersion is the version of the OS, if available.
 	//
@@ -842,25 +842,25 @@ type Hostinfo struct {
 	// string on Linux, like "Debian 10.4; kernel=xxx; container; env=kn" and so
 	// on. As of Tailscale 1.32, this is simply the kernel version on Linux, like
 	// "5.10.0-17-amd64".
-	OSVersion string `json:",omitempty"`
+	OSVersion string `json:",omitzero"`
 
-	Container      opt.Bool `json:",omitempty"` // best-effort whether the client is running in a container
-	Env            string   `json:",omitempty"` // a hostinfo.EnvType in string form
-	Distro         string   `json:",omitempty"` // "debian", "ubuntu", "nixos", ...
-	DistroVersion  string   `json:",omitempty"` // "20.04", ...
-	DistroCodeName string   `json:",omitempty"` // "jammy", "bullseye", ...
+	Container      opt.Bool `json:",omitzero"` // best-effort whether the client is running in a container
+	Env            string   `json:",omitzero"` // a hostinfo.EnvType in string form
+	Distro         string   `json:",omitzero"` // "debian", "ubuntu", "nixos", ...
+	DistroVersion  string   `json:",omitzero"` // "20.04", ...
+	DistroCodeName string   `json:",omitzero"` // "jammy", "bullseye", ...
 
 	// App is used to disambiguate Tailscale clients that run using tsnet.
-	App string `json:",omitempty"` // "k8s-operator", "golinks", ...
-
-	Desktop         opt.Bool `json:",omitempty"` // if a desktop was detected on Linux
-	Package         string   `json:",omitempty"` // Tailscale package to disambiguate ("choco", "appstore", etc; "" for unknown)
-	DeviceModel     string   `json:",omitempty"` // mobile phone model ("Pixel 3a", "iPhone12,3")
-	PushDeviceToken string   `json:",omitempty"` // macOS/iOS APNs device token for notifications (and Android in the future)
-	Hostname        string   `json:",omitempty"` // name of the host the client runs on
-	ShieldsUp       bool     `json:",omitempty"` // indicates whether the host is blocking incoming connections
-	ShareeNode      bool     `json:",omitempty"` // indicates this node exists in netmap because it's owned by a shared-to user
-	NoLogsNoSupport bool     `json:",omitempty"` // indicates that the user has opted out of sending logs and support
+	App string `json:",omitzero"` // "k8s-operator", "golinks", ...
+
+	Desktop         opt.Bool `json:",omitzero"` // if a desktop was detected on Linux
+	Package         string   `json:",omitzero"` // Tailscale package to disambiguate ("choco", "appstore", etc; "" for unknown)
+	DeviceModel     string   `json:",omitzero"` // mobile phone model ("Pixel 3a", "iPhone12,3")
+	PushDeviceToken string   `json:",omitzero"` // macOS/iOS APNs device token for notifications (and Android in the future)
+	Hostname        string   `json:",omitzero"` // name of the host the client runs on
+	ShieldsUp       bool     `json:",omitzero"` // indicates whether the host is blocking incoming connections
+	ShareeNode      bool     `json:",omitzero"` // indicates this node exists in netmap because it's owned by a shared-to user
+	NoLogsNoSupport bool     `json:",omitzero"` // indicates that the user has opted out of sending logs and support
 	// WireIngress indicates that the node would like to be wired up server-side
 	// (DNS, etc) to be able to use Tailscale Funnel, even if it's not currently
 	// enabled. For example, the user might only use it for intermittent
@@ -868,38 +868,38 @@ type Hostinfo struct {
 	// away, even if it's disabled most of the time. As an optimization, this is
 	// only sent if IngressEnabled is false, as IngressEnabled implies that this
 	// option is true.
-	WireIngress     bool           `json:",omitempty"`
-	IngressEnabled  bool           `json:",omitempty"` // if the node has any funnel endpoint enabled
-	AllowsUpdate    bool           `json:",omitempty"` // indicates that the node has opted-in to admin-console-drive remote updates
-	Machine         string         `json:",omitempty"` // the current host's machine type (uname -m)
-	GoArch          string         `json:",omitempty"` // GOARCH value (of the built binary)
-	GoArchVar       string         `json:",omitempty"` // GOARM, GOAMD64, etc (of the built binary)
-	GoVersion       string         `json:",omitempty"` // Go version binary was built with
+	WireIngress     bool           `json:",omitzero"`
+	IngressEnabled  bool           `json:",omitzero"`  // if the node has any funnel endpoint enabled
+	AllowsUpdate    bool           `json:",omitzero"`  // indicates that the node has opted-in to admin-console-drive remote updates
+	Machine         string         `json:",omitzero"`  // the current host's machine type (uname -m)
+	GoArch          string         `json:",omitzero"`  // GOARCH value (of the built binary)
+	GoArchVar       string         `json:",omitzero"`  // GOARM, GOAMD64, etc (of the built binary)
+	GoVersion       string         `json:",omitzero"`  // Go version binary was built with
 	RoutableIPs     []netip.Prefix `json:",omitempty"` // set of IP ranges this client can route
 	RequestTags     []string       `json:",omitempty"` // set of ACL tags this node wants to claim
 	WoLMACs         []string       `json:",omitempty"` // MAC address(es) to send Wake-on-LAN packets to wake this node (lowercase hex w/ colons)
 	Services        []Service      `json:",omitempty"` // services advertised by this machine
-	NetInfo         *NetInfo       `json:",omitempty"`
+	NetInfo         *NetInfo       `json:",omitzero"`
 	SSH_HostKeys    []string       `json:"sshHostKeys,omitempty"` // if advertised
-	Cloud           string         `json:",omitempty"`
-	Userspace       opt.Bool       `json:",omitempty"` // if the client is running in userspace (netstack) mode
-	UserspaceRouter opt.Bool       `json:",omitempty"` // if the client's subnet router is running in userspace (netstack) mode
-	AppConnector    opt.Bool       `json:",omitempty"` // if the client is running the app-connector service
-	ServicesHash    string         `json:",omitempty"` // opaque hash of the most recent list of tailnet services, change in hash indicates config should be fetched via c2n
-	ExitNodeID      StableNodeID   `json:",omitzero"`  // the client’s selected exit node, empty when unselected.
+	Cloud           string         `json:",omitzero"`
+	Userspace       opt.Bool       `json:",omitzero"` // if the client is running in userspace (netstack) mode
+	UserspaceRouter opt.Bool       `json:",omitzero"` // if the client's subnet router is running in userspace (netstack) mode
+	AppConnector    opt.Bool       `json:",omitzero"` // if the client is running the app-connector service
+	ServicesHash    string         `json:",omitzero"` // opaque hash of the most recent list of tailnet services, change in hash indicates config should be fetched via c2n
+	ExitNodeID      StableNodeID   `json:",omitzero"` // the client’s selected exit node, empty when unselected.
 
 	// Location represents geographical location data about a
 	// Tailscale host. Location is optional and only set if
 	// explicitly declared by a node.
-	Location *Location `json:",omitempty"`
+	Location *Location `json:",omitzero"`
 
-	TPM *TPMInfo `json:",omitempty"` // TPM device metadata, if available
+	TPM *TPMInfo `json:",omitzero"` // TPM device metadata, if available
 	// StateEncrypted reports whether the node state is stored encrypted on
 	// disk. The actual mechanism is platform-specific:
 	//   * Apple nodes use the Keychain
 	//   * Linux and Windows nodes use the TPM
 	//   * Android apps use EncryptedSharedPreferences
-	StateEncrypted opt.Bool `json:",omitempty"`
+	StateEncrypted opt.Bool `json:",omitzero"`
 
 	// NOTE: any new fields containing pointers in this type
 	//       require changes to Hostinfo.Equal.
@@ -913,25 +913,25 @@ type TPMInfo struct {
 	// https://trustedcomputinggroup.org/resource/vendor-id-registry/,
 	// for example "MSFT" for Microsoft.
 	// Read from TPM_PT_MANUFACTURER.
-	Manufacturer string `json:",omitempty"`
+	Manufacturer string `json:",omitzero"`
 	// Vendor is a vendor ID string, up to 16 characters.
 	// Read from TPM_PT_VENDOR_STRING_*.
-	Vendor string `json:",omitempty"`
+	Vendor string `json:",omitzero"`
 	// Model is a vendor-defined TPM model.
 	// Read from TPM_PT_VENDOR_TPM_TYPE.
-	Model int `json:",omitempty"`
+	Model int `json:",omitzero"`
 	// FirmwareVersion is the version number of the firmware.
 	// Read from TPM_PT_FIRMWARE_VERSION_*.
-	FirmwareVersion uint64 `json:",omitempty"`
+	FirmwareVersion uint64 `json:",omitzero"`
 	// SpecRevision is the TPM 2.0 spec revision encoded as a single number. All
 	// revisions can be found at
 	// https://trustedcomputinggroup.org/resource/tpm-library-specification/.
 	// Before revision 184, TCG used the "01.83" format for revision 183.
-	SpecRevision int `json:",omitempty"`
+	SpecRevision int `json:",omitzero"`
 
 	// FamilyIndicator is the TPM spec family, like "2.0".
 	// Read from TPM_PT_FAMILY_INDICATOR.
-	FamilyIndicator string `json:",omitempty"`
+	FamilyIndicator string `json:",omitzero"`
 }
 
 // Present reports whether a TPM device is present on this machine.
@@ -1016,37 +1016,37 @@ func (v HostinfoView) TailscaleSSHEnabled() bool { return v.ж.TailscaleSSHEnabl
 type NetInfo struct {
 	// MappingVariesByDestIP says whether the host's NAT mappings
 	// vary based on the destination IP.
-	MappingVariesByDestIP opt.Bool
+	MappingVariesByDestIP opt.Bool `json:",omitzero"`
 
 	// WorkingIPv6 is whether the host has IPv6 internet connectivity.
-	WorkingIPv6 opt.Bool
+	WorkingIPv6 opt.Bool `json:",omitzero"`
 
 	// OSHasIPv6 is whether the OS supports IPv6 at all, regardless of
 	// whether IPv6 internet connectivity is available.
-	OSHasIPv6 opt.Bool
+	OSHasIPv6 opt.Bool `json:",omitzero"`
 
 	// WorkingUDP is whether the host has UDP internet connectivity.
-	WorkingUDP opt.Bool
+	WorkingUDP opt.Bool `json:",omitzero"`
 
 	// WorkingICMPv4 is whether ICMPv4 works.
 	// Empty means not checked.
-	WorkingICMPv4 opt.Bool
+	WorkingICMPv4 opt.Bool `json:",omitzero"`
 
 	// HavePortMap is whether we have an existing portmap open
 	// (UPnP, PMP, or PCP).
-	HavePortMap bool `json:",omitempty"`
+	HavePortMap bool `json:",omitzero"`
 
 	// UPnP is whether UPnP appears present on the LAN.
 	// Empty means not checked.
-	UPnP opt.Bool
+	UPnP opt.Bool `json:",omitzero"`
 
 	// PMP is whether NAT-PMP appears present on the LAN.
 	// Empty means not checked.
-	PMP opt.Bool
+	PMP opt.Bool `json:",omitzero"`
 
 	// PCP is whether PCP appears present on the LAN.
 	// Empty means not checked.
-	PCP opt.Bool
+	PCP opt.Bool `json:",omitzero"`
 
 	// PreferredDERP is this node's preferred (home) DERP region ID.
 	// This is where the node expects to be contacted to begin a
@@ -1055,10 +1055,10 @@ type NetInfo struct {
 	// that are located elsewhere) but PreferredDERP is the region ID
 	// that the node subscribes to traffic at.
 	// Zero means disconnected or unknown.
-	PreferredDERP int
+	PreferredDERP int `json:",omitzero"`
 
 	// LinkType is the current link type, if known.
-	LinkType string `json:",omitempty"` // "wired", "wifi", "mobile" (LTE, 4G, 3G, etc)
+	LinkType string `json:",omitzero"` // "wired", "wifi", "mobile" (LTE, 4G, 3G, etc)
 
 	// DERPLatency is the fastest recent time to reach various
 	// DERP STUN servers, in seconds. The map key is the
@@ -1076,7 +1076,7 @@ type NetInfo struct {
 	// "{nft,ift}-REASON", like "nft-forced" or "ipt-default". Empty means
 	// either not Linux or a configuration in which the host firewall rules
 	// are not managed by tailscaled.
-	FirewallMode string `json:",omitempty"`
+	FirewallMode string `json:",omitzero"`
 
 	// Update BasicallyEqual when adding fields.
 }
@@ -1364,8 +1364,8 @@ type MapRequest struct {
 	// For current values and history, see the CapabilityVersion type's docs.
 	Version CapabilityVersion
 
-	Compress  string // "zstd" or "" (no compression)
-	KeepAlive bool   // whether server should send keep-alives back to us
+	Compress  string `json:",omitzero"` // "zstd" or "" (no compression)
+	KeepAlive bool   `json:",omitzero"` // whether server should send keep-alives back to us
 	NodeKey   key.NodePublic
 	DiscoKey  key.DiscoPublic
 
@@ -1388,7 +1388,7 @@ type MapRequest struct {
 	//
 	// If true and Version >= 68, the server should treat this as a read-only
 	// request and ignore any Hostinfo or other fields that might be set.
-	Stream bool
+	Stream bool `json:",omitzero"`
 
 	// Hostinfo is the client's current Hostinfo. Although it is always included
 	// in the request, the server may choose to ignore it when Stream is true
@@ -1405,14 +1405,14 @@ type MapRequest struct {
 	//
 	// The server may choose to ignore the request for any reason and start a
 	// new map session. This is only applicable when Stream is true.
-	MapSessionHandle string `json:",omitempty"`
+	MapSessionHandle string `json:",omitzero"`
 
 	// MapSessionSeq is the sequence number in the map session identified by
 	// MapSesssionHandle that was most recently processed by the client.
 	// It is only applicable when MapSessionHandle is specified.
 	// If the server chooses to honor the MapSessionHandle request, only sequence
 	// numbers greater than this value will be returned.
-	MapSessionSeq int64 `json:",omitempty"`
+	MapSessionSeq int64 `json:",omitzero"`
 
 	// Endpoints are the client's magicsock UDP ip:port endpoints (IPv4 or IPv6).
 	// These can be ignored if Stream is true and Version >= 68.
@@ -1423,7 +1423,7 @@ type MapRequest struct {
 	// TKAHead describes the hash of the latest AUM applied to the local
 	// tailnet key authority, if one is operating.
 	// It is encoded as tka.AUMHash.MarshalText.
-	TKAHead string `json:",omitempty"`
+	TKAHead string `json:",omitzero"`
 
 	// ReadOnly was set when client just wanted to fetch the MapResponse,
 	// without updating their Endpoints. The intended use was for clients to
@@ -1431,7 +1431,7 @@ type MapRequest struct {
 	// update.
 	//
 	// Deprecated: always false as of Version 68.
-	ReadOnly bool `json:",omitempty"`
+	ReadOnly bool `json:",omitzero"`
 
 	// OmitPeers is whether the client is okay with the Peers list being omitted
 	// in the response.
@@ -1447,7 +1447,7 @@ type MapRequest struct {
 	// If OmitPeers is true, Stream is false, but ReadOnly is true,
 	// then all the response fields are included. (This is what the client does
 	// when initially fetching the DERP map.)
-	OmitPeers bool `json:",omitempty"`
+	OmitPeers bool `json:",omitzero"`
 
 	// DebugFlags is a list of strings specifying debugging and
 	// development features to enable in handling this map
@@ -1467,7 +1467,7 @@ type MapRequest struct {
 	// identifies this specific connection to the server. The server may choose to
 	// use this handle to identify the connection for debugging or testing
 	// purposes. It has no semantic meaning.
-	ConnectionHandleForTest string `json:",omitempty"`
+	ConnectionHandleForTest string `json:",omitzero"`
 }
 
 // PortRange represents a range of UDP or TCP port numbers.
@@ -1758,7 +1758,7 @@ type DNSConfig struct {
 	// in the network map, aka MagicDNS.
 	// Despite the (legacy) name, does not necessarily cause request
 	// proxying to be enabled.
-	Proxied bool `json:",omitempty"`
+	Proxied bool `json:",omitzero"`
 
 	// Nameservers are the IP addresses of the global nameservers to use.
 	//
@@ -1795,7 +1795,7 @@ type DNSConfig struct {
 	// TempCorpIssue13969 is a temporary (2023-08-16) field for an internal hack day prototype.
 	// It contains a user inputed URL that should have a list of domains to be blocked.
 	// See https://github.com/tailscale/corp/issues/13969.
-	TempCorpIssue13969 string `json:",omitempty"`
+	TempCorpIssue13969 string `json:",omitzero"`
 }
 
 // DNSRecord is an extra DNS record to add to MagicDNS.
@@ -1807,7 +1807,7 @@ type DNSRecord struct {
 	// Type is the DNS record type.
 	// Empty means A or AAAA, depending on value.
 	// Other values are currently ignored.
-	Type string `json:",omitempty"`
+	Type string `json:",omitzero"`
 
 	// Value is the IP address in string form.
 	// TODO(bradfitz): if we ever add support for record types
@@ -1855,11 +1855,11 @@ type PingRequest struct {
 
 	// URLIsNoise, if true, means that the client should hit URL over the Noise
 	// transport instead of TLS.
-	URLIsNoise bool `json:",omitempty"`
+	URLIsNoise bool `json:",omitzero"`
 
 	// Log is whether to log about this ping in the success case.
 	// For failure cases, the client will log regardless.
-	Log bool `json:",omitempty"`
+	Log bool `json:",omitzero"`
 
 	// Types is the types of ping that are initiated. Can be any PingType, comma
 	// separated, e.g. "disco,TSMP"
@@ -1869,10 +1869,10 @@ type PingRequest struct {
 	// node's c2n handler and the HTTP response sent in a POST to URL. For c2n,
 	// the value of URLIsNoise is ignored and only the Noise transport (back to
 	// the control plane) will be used, as if URLIsNoise were true.
-	Types string `json:",omitempty"`
+	Types string `json:",omitzero"`
 
 	// IP is the ping target, when needed by the PingType(s) given in Types.
-	IP netip.Addr
+	IP netip.Addr `json:",omitzero"`
 
 	// Payload is the ping payload.
 	//
@@ -3043,29 +3043,29 @@ type SSHRecordingAttempt struct {
 // See QueryFeatureResponse for response structure.
 type QueryFeatureRequest struct {
 	// Feature is the string identifier for a feature.
-	Feature string `json:",omitempty"`
+	Feature string `json:",omitzero"`
 	// NodeKey is the client's current node key.
-	NodeKey key.NodePublic `json:",omitempty"`
+	NodeKey key.NodePublic `json:",omitzero"`
 }
 
 // QueryFeatureResponse is the response to an QueryFeatureRequest.
 // See cli.enableFeatureInteractive for usage.
 type QueryFeatureResponse struct {
 	// Complete is true when the feature is already enabled.
-	Complete bool `json:",omitempty"`
+	Complete bool `json:",omitzero"`
 
 	// Text holds lines to display in the CLI with information
 	// about the feature and how to enable it.
 	//
 	// Lines are separated by newline characters. The final
 	// newline may be omitted.
-	Text string `json:",omitempty"`
+	Text string `json:",omitzero"`
 
 	// URL is the link for the user to visit to take action on
 	// enabling the feature.
 	//
 	// When empty, there is no action for this user to take.
-	URL string `json:",omitempty"`
+	URL string `json:",omitzero"`
 
 	// ShouldWait specifies whether the CLI should block and
 	// wait for the user to enable the feature.
@@ -3078,7 +3078,7 @@ type QueryFeatureResponse struct {
 	//
 	// The CLI can watch the IPN notification bus for changes in
 	// required node capabilities to know when to continue.
-	ShouldWait bool `json:",omitempty"`
+	ShouldWait bool `json:",omitzero"`
 }
 
 // WebClientAuthResponse is the response to a web client authentication request
@@ -3088,15 +3088,15 @@ type WebClientAuthResponse struct {
 	// ID is a unique identifier for the session auth request.
 	// It can be supplied to "/machine/webclient/wait" to pause until
 	// the session authentication has been completed.
-	ID string `json:",omitempty"`
+	ID string `json:",omitzero"`
 
 	// URL is the link for the user to visit to authenticate the session.
 	//
 	// When empty, there is no action for the user to take.
-	URL string `json:",omitempty"`
+	URL string `json:",omitzero"`
 
 	// Complete is true when the session authentication has been completed.
-	Complete bool `json:",omitempty"`
+	Complete bool `json:",omitzero"`
 }
 
 // OverTLSPublicKeyResponse is the JSON response to /key?v=<n>
@@ -3172,10 +3172,10 @@ type PeerChange struct {
 
 	// DERPRegion, if non-zero, means that NodeID's home DERP
 	// region ID is now this number.
-	DERPRegion int `json:",omitempty"`
+	DERPRegion int `json:",omitzero"`
 
 	// Cap, if non-zero, means that NodeID's capability version has changed.
-	Cap CapabilityVersion `json:",omitempty"`
+	Cap CapabilityVersion `json:",omitzero"`
 
 	// CapMap, if non-nil, means that NodeID's capability map has changed.
 	CapMap NodeCapMap `json:",omitempty"`
@@ -3185,23 +3185,23 @@ type PeerChange struct {
 	Endpoints []netip.AddrPort `json:",omitempty"`
 
 	// Key, if non-nil, means that the NodeID's wireguard public key changed.
-	Key *key.NodePublic `json:",omitempty"`
+	Key *key.NodePublic `json:",omitzero"` // TODO: de-pointer: tailscale/tailscale#17978
 
 	// KeySignature, if non-nil, means that the signature of the wireguard
 	// public key has changed.
 	KeySignature tkatype.MarshaledSignature `json:",omitempty"`
 
 	// DiscoKey, if non-nil, means that the NodeID's discokey changed.
-	DiscoKey *key.DiscoPublic `json:",omitempty"`
+	DiscoKey *key.DiscoPublic `json:",omitzero"` // TODO: de-pointer: tailscale/tailscale#17978
 
 	// Online, if non-nil, means that the NodeID's online status changed.
-	Online *bool `json:",omitempty"`
+	Online *bool `json:",omitzero"`
 
 	// LastSeen, if non-nil, means that the NodeID's online status changed.
-	LastSeen *time.Time `json:",omitempty"`
+	LastSeen *time.Time `json:",omitzero"` // TODO: de-pointer: tailscale/tailscale#17978
 
 	// KeyExpiry, if non-nil, changes the NodeID's key expiry.
-	KeyExpiry *time.Time `json:",omitempty"`
+	KeyExpiry *time.Time `json:",omitzero"` // TODO: de-pointer: tailscale/tailscale#17978
 }
 
 // DerpMagicIP is a fake WireGuard endpoint IP address that means to
@@ -3279,14 +3279,14 @@ const (
 // POST https://<control-plane>/machine/audit-log
 type AuditLogRequest struct {
 	// Version is the client's current CapabilityVersion.
-	Version CapabilityVersion `json:",omitempty"`
+	Version CapabilityVersion `json:",omitzero"`
 	// NodeKey is the client's current node key.
 	NodeKey key.NodePublic `json:",omitzero"`
 	// Action is the action to be logged. It must correspond to a known action in the control plane.
-	Action ClientAuditAction `json:",omitempty"`
+	Action ClientAuditAction `json:",omitzero"`
 	// Details is an opaque string, specific to the action being logged.  Empty strings may not
 	// be valid depending on the action being logged.
-	Details string `json:",omitempty"`
+	Details string `json:",omitzero"`
 	// Timestamp is the time at which the audit log was generated on the node.
 	Timestamp time.Time `json:",omitzero"`
 }