exit node dst wip

enable-exit-node-dst-logs
Claire Wang 2 months ago
parent 92d3f64e95
commit 78c36f53fe

@ -42,6 +42,7 @@ type setArgsT struct {
acceptDNS bool
exitNodeIP string
exitNodeAllowLANAccess bool
exitDestinationFlowLogs bool
shieldsUp bool
runSSH bool
runWebClient bool
@ -66,6 +67,7 @@ func newSetFlagSet(goos string, setArgs *setArgsT) *flag.FlagSet {
setf.BoolVar(&setArgs.acceptDNS, "accept-dns", false, "accept DNS configuration from the admin panel")
setf.StringVar(&setArgs.exitNodeIP, "exit-node", "", "Tailscale exit node (IP or base name) for internet traffic, or empty string to not use an exit node")
setf.BoolVar(&setArgs.exitNodeAllowLANAccess, "exit-node-allow-lan-access", false, "Allow direct access to the local network when routing traffic via an exit node")
setf.BoolVar(&setArgs.exitDestinationFlowLogs, "exit-destination-flow-logs", false, "Enable exit node destination in network flow logs")
setf.BoolVar(&setArgs.shieldsUp, "shields-up", false, "don't allow incoming connections")
setf.BoolVar(&setArgs.runSSH, "ssh", false, "run an SSH server, permitting access per tailnet admin's declared policy")
setf.StringVar(&setArgs.hostname, "hostname", "", "hostname to use instead of the one provided by the OS")
@ -110,6 +112,7 @@ func runSet(ctx context.Context, args []string) (retErr error) {
RouteAll: setArgs.acceptRoutes,
CorpDNS: setArgs.acceptDNS,
ExitNodeAllowLANAccess: setArgs.exitNodeAllowLANAccess,
ExitDestinationFlowLogs: setArgs.exitDestinationFlowLogs,
ShieldsUp: setArgs.shieldsUp,
RunSSH: setArgs.runSSH,
RunWebClient: setArgs.runWebClient,

@ -723,6 +723,7 @@ func init() {
addPrefFlagMapping("auto-update", "AutoUpdate.Apply")
addPrefFlagMapping("advertise-connector", "AppConnector")
addPrefFlagMapping("posture-checking", "PostureChecking")
addPrefFlagMapping("exit-destination-flow-logs", "ExitDestinationFlowLogs")
}
func addPrefFlagMapping(flagName string, prefNames ...string) {
@ -951,6 +952,8 @@ func prefsToFlags(env upCheckEnv, prefs *ipn.Prefs) (flagVal map[string]any) {
set(exitNodeIPStr())
case "exit-node-allow-lan-access":
set(prefs.ExitNodeAllowLANAccess)
case "exit-destination-flow-logs":
set(prefs.ExitDestinationFlowLogs)
case "advertise-tags":
set(strings.Join(prefs.AdvertiseTags, ","))
case "hostname":

@ -1150,6 +1150,9 @@ func (b *LocalBackend) SetControlClientStatus(c controlclient.Client, st control
if setExitNodeID(prefs, st.NetMap) {
prefsChanged = true
}
if setExitDstFlowLogs(prefs) {
prefsChanged = true
}
if applySysPolicy(prefs) {
prefsChanged = true
}
@ -1335,6 +1338,15 @@ func applySysPolicy(prefs *ipn.Prefs) (anyChange bool) {
return anyChange
}
func setExitDstFlowLogs(prefs *ipn.Prefs) (anyChange bool) {
fmt.Printf("set exit dst flow pref")
if enable, err := syspolicy.GetBoolean(syspolicy.ExitDestinationFlowLogs, prefs.ExitDestinationFlowLogs); err == nil && prefs.ExitDestinationFlowLogs != enable {
prefs.ExitDestinationFlowLogs = enable
anyChange = true
}
return anyChange
}
var _ controlclient.NetmapDeltaUpdater = (*LocalBackend)(nil)
// UpdateNetmapDelta implements controlclient.NetmapDeltaUpdater.
@ -3247,6 +3259,7 @@ func (b *LocalBackend) setPrefsLockedOnEntry(caller string, newp *ipn.Prefs) ipn
// everything in this function treats b.prefs as completely new
// anyway. No-op if no exit node resolution is needed.
setExitNodeID(newp, netMap)
setExitDstFlowLogs(newp)
// applySysPolicy does likewise so we can also ignore its return value.
applySysPolicy(newp)
// We do this to avoid holding the lock while doing everything else.
@ -3628,6 +3641,8 @@ func (b *LocalBackend) authReconfig() {
return
}
cfg.NetworkLogging.ExitDestinationFlowLogs = prefs.ExitDestinationFlowLogs()
oneCGNATRoute := shouldUseOneCGNATRoute(b.logf, b.sys.ControlKnobs(), version.OS())
rcfg := b.routerConfig(cfg, prefs, oneCGNATRoute)

@ -109,6 +109,9 @@ type Prefs struct {
// routed directly or via the exit node.
ExitNodeAllowLANAccess bool
// ExitDestinationFlowLogs indicates whether exit node destination is recorded in network flow logs.
ExitDestinationFlowLogs bool
// CorpDNS specifies whether to install the Tailscale network's
// DNS configuration, if it exists.
CorpDNS bool
@ -277,6 +280,7 @@ type MaskedPrefs struct {
ControlURLSet bool `json:",omitempty"`
RouteAllSet bool `json:",omitempty"`
AllowSingleHostsSet bool `json:",omitempty"`
ExitDestinationFlowLogsSet bool `json:",omitempty"`
ExitNodeIDSet bool `json:",omitempty"`
ExitNodeIPSet bool `json:",omitempty"`
ExitNodeAllowLANAccessSet bool `json:",omitempty"`
@ -475,6 +479,9 @@ func (p *Prefs) pretty(goos string) string {
if p.ShieldsUp {
sb.WriteString("shields=true ")
}
if p.ExitDestinationFlowLogs {
sb.WriteString("exitdestinationflowlogs=true ")
}
if p.ExitNodeIP.IsValid() {
fmt.Fprintf(&sb, "exit=%v lan=%t ", p.ExitNodeIP, p.ExitNodeAllowLANAccess)
} else if !p.ExitNodeID.IsZero() {
@ -545,6 +552,7 @@ func (p *Prefs) Equals(p2 *Prefs) bool {
p.ExitNodeID == p2.ExitNodeID &&
p.ExitNodeIP == p2.ExitNodeIP &&
p.ExitNodeAllowLANAccess == p2.ExitNodeAllowLANAccess &&
p.ExitDestinationFlowLogs == p2.ExitDestinationFlowLogs &&
p.CorpDNS == p2.CorpDNS &&
p.RunSSH == p2.RunSSH &&
p.RunWebClient == p2.RunWebClient &&

@ -67,7 +67,7 @@ const (
// The default is 0 unless otherwise stated.
LogSCMInteractions Key = "LogSCMInteractions"
FlushDNSOnSessionUnlock Key = "FlushDNSOnSessionUnlock"
ExitDestinationFlowLogs Key = "ExitDestinationFlowLogs"
// PostureChecking indicates if posture checking is enabled and the client shall gather
// posture data.
// Key is a string value that specifies an option: "always", "never", "user-decides".

@ -92,7 +92,7 @@ var testClient *http.Client
// The IP protocol and source port are always zero.
// The sock is used to populated the PhysicalTraffic field in Message.
// The netMon parameter is optional; if non-nil it's used to do faster interface lookups.
func (nl *Logger) Startup(nodeID tailcfg.StableNodeID, nodeLogID, domainLogID logid.PrivateID, tun, sock Device, netMon *netmon.Monitor) error {
func (nl *Logger) Startup(nodeID tailcfg.StableNodeID, nodeLogID, domainLogID logid.PrivateID, tun, sock Device, netMon *netmon.Monitor, enableExitDstFlowLogs bool) error {
nl.mu.Lock()
defer nl.mu.Unlock()
if nl.logger != nil {
@ -130,7 +130,7 @@ func (nl *Logger) Startup(nodeID tailcfg.StableNodeID, nodeLogID, domainLogID lo
addrs := nl.addrs
prefixes := nl.prefixes
nl.mu.Unlock()
recordStatistics(nl.logger, nodeID, start, end, virtual, physical, addrs, prefixes)
recordStatistics(nl.logger, nodeID, start, end, virtual, physical, addrs, prefixes, enableExitDstFlowLogs)
})
// Register the connection tracker into the TUN device.
@ -150,7 +150,7 @@ func (nl *Logger) Startup(nodeID tailcfg.StableNodeID, nodeLogID, domainLogID lo
return nil
}
func recordStatistics(logger *logtail.Logger, nodeID tailcfg.StableNodeID, start, end time.Time, connstats, sockStats map[netlogtype.Connection]netlogtype.Counts, addrs map[netip.Addr]bool, prefixes map[netip.Prefix]bool) {
func recordStatistics(logger *logtail.Logger, nodeID tailcfg.StableNodeID, start, end time.Time, connstats, sockStats map[netlogtype.Connection]netlogtype.Counts, addrs map[netip.Addr]bool, prefixes map[netip.Prefix]bool, enableExitDstFlowLogs bool) {
m := netlogtype.Message{NodeID: nodeID, Start: start.UTC(), End: end.UTC()}
classifyAddr := func(a netip.Addr) (isTailscale, withinRoute bool) {
@ -179,7 +179,7 @@ func recordStatistics(logger *logtail.Logger, nodeID tailcfg.StableNodeID, start
m.SubnetTraffic = append(m.SubnetTraffic, netlogtype.ConnectionCounts{Connection: conn, Counts: cnts})
default:
const anonymize = true
if anonymize {
if anonymize && !enableExitDstFlowLogs {
// Only preserve the address if it is a Tailscale IP address.
srcOrig, dstOrig := conn.Src, conn.Dst
conn = netlogtype.Connection{} // scrub everything by default

@ -932,8 +932,9 @@ func (e *userspaceEngine) Reconfig(cfg *wgcfg.Config, routerCfg *router.Config,
if netLogRunning && !e.networkLogger.Running() {
nid := cfg.NetworkLogging.NodeID
tid := cfg.NetworkLogging.DomainID
enableExitDstFlowLogs := cfg.NetworkLogging.ExitDestinationFlowLogs
e.logf("wgengine: Reconfig: starting up network logger (node:%s tailnet:%s)", nid.Public(), tid.Public())
if err := e.networkLogger.Startup(cfg.NodeID, nid, tid, e.tundev, e.magicConn, e.netMon); err != nil {
if err := e.networkLogger.Startup(cfg.NodeID, nid, tid, e.tundev, e.magicConn, e.netMon, enableExitDstFlowLogs); err != nil {
e.logf("wgengine: Reconfig: error starting up network logger: %v", err)
}
e.networkLogger.ReconfigRoutes(routerCfg)

@ -30,6 +30,7 @@ type Config struct {
NetworkLogging struct {
NodeID logid.PrivateID
DomainID logid.PrivateID
ExitDestinationFlowLogs bool
}
}

Loading…
Cancel
Save