mirror of
https://github.com/juanfont/headscale.git
synced 2026-03-23 18:01:19 +01:00
Add hscontrol/util/zlog package with: - zf subpackage: field name constants for compile-time safety - SafeHostinfo: wrapper that redacts device fingerprinting data - SafeMapRequest: wrapper that redacts client endpoints The zf (zerolog fields) subpackage provides short constant names (e.g., zf.NodeID instead of inline "node.id" strings) ensuring consistent field naming across all log statements. Security considerations: - SafeHostinfo never logs: OSVersion, DeviceModel, DistroName - SafeMapRequest only logs endpoint counts, not actual IPs
62 lines
2.0 KiB
Go
62 lines
2.0 KiB
Go
package zlog
|
|
|
|
import (
|
|
"github.com/juanfont/headscale/hscontrol/util/zlog/zf"
|
|
"github.com/rs/zerolog"
|
|
"tailscale.com/tailcfg"
|
|
)
|
|
|
|
// SafeHostinfo wraps tailcfg.Hostinfo for safe logging.
|
|
//
|
|
// SECURITY: This wrapper intentionally redacts device fingerprinting data
|
|
// that could be used to identify or track specific devices:
|
|
// - OSVersion, DeviceModel, DistroName, DistroVersion (device fingerprinting)
|
|
// - IPNVersion (client version fingerprinting)
|
|
// - Machine, FrontendLogID (device identifiers)
|
|
//
|
|
// Only safe fields are logged:
|
|
// - hostname: The device hostname
|
|
// - os: The OS family (e.g., "linux", "windows") without version
|
|
// - routable_ips_count: Number of advertised routes (not the actual routes)
|
|
// - request_tags: Tags requested by the client
|
|
// - derp: Preferred DERP region ID
|
|
type SafeHostinfo struct {
|
|
hi *tailcfg.Hostinfo
|
|
}
|
|
|
|
// Hostinfo creates a SafeHostinfo wrapper for safe logging.
|
|
func Hostinfo(hi *tailcfg.Hostinfo) SafeHostinfo {
|
|
return SafeHostinfo{hi: hi}
|
|
}
|
|
|
|
// MarshalZerologObject implements zerolog.LogObjectMarshaler.
|
|
func (s SafeHostinfo) MarshalZerologObject(e *zerolog.Event) {
|
|
if s.hi == nil {
|
|
return
|
|
}
|
|
|
|
// Safe fields only - no device fingerprinting data.
|
|
e.Str(zf.Hostname, s.hi.Hostname)
|
|
e.Str(zf.OS, s.hi.OS) // OS family only, NOT version
|
|
|
|
if len(s.hi.RoutableIPs) > 0 {
|
|
e.Int(zf.RoutableIPCount, len(s.hi.RoutableIPs))
|
|
}
|
|
|
|
if len(s.hi.RequestTags) > 0 {
|
|
e.Strs(zf.RequestTags, s.hi.RequestTags)
|
|
}
|
|
|
|
if s.hi.NetInfo != nil && s.hi.NetInfo.PreferredDERP != 0 {
|
|
e.Int(zf.DERP, s.hi.NetInfo.PreferredDERP)
|
|
}
|
|
|
|
// SECURITY: The following fields are intentionally NOT logged:
|
|
// - OSVersion, DistroName, DistroVersion, DistroCodeName: device fingerprinting
|
|
// - DeviceModel: device fingerprinting
|
|
// - IPNVersion: client version fingerprinting
|
|
// - Machine, FrontendLogID: device identifiers
|
|
// - GoArch, GoArchVar, GoVersion: build environment fingerprinting
|
|
// - Userspace, UserspaceRouter: network configuration details
|
|
}
|