mirror of
https://github.com/tailscale/tailscale.git
synced 2025-04-21 06:01:42 +00:00
exit node dst wip
This commit is contained in:
parent
92d3f64e95
commit
78c36f53fe
@ -42,6 +42,7 @@ type setArgsT struct {
|
|||||||
acceptDNS bool
|
acceptDNS bool
|
||||||
exitNodeIP string
|
exitNodeIP string
|
||||||
exitNodeAllowLANAccess bool
|
exitNodeAllowLANAccess bool
|
||||||
|
exitDestinationFlowLogs bool
|
||||||
shieldsUp bool
|
shieldsUp bool
|
||||||
runSSH bool
|
runSSH bool
|
||||||
runWebClient 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.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.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.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.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.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")
|
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,
|
RouteAll: setArgs.acceptRoutes,
|
||||||
CorpDNS: setArgs.acceptDNS,
|
CorpDNS: setArgs.acceptDNS,
|
||||||
ExitNodeAllowLANAccess: setArgs.exitNodeAllowLANAccess,
|
ExitNodeAllowLANAccess: setArgs.exitNodeAllowLANAccess,
|
||||||
|
ExitDestinationFlowLogs: setArgs.exitDestinationFlowLogs,
|
||||||
ShieldsUp: setArgs.shieldsUp,
|
ShieldsUp: setArgs.shieldsUp,
|
||||||
RunSSH: setArgs.runSSH,
|
RunSSH: setArgs.runSSH,
|
||||||
RunWebClient: setArgs.runWebClient,
|
RunWebClient: setArgs.runWebClient,
|
||||||
|
@ -723,6 +723,7 @@ func init() {
|
|||||||
addPrefFlagMapping("auto-update", "AutoUpdate.Apply")
|
addPrefFlagMapping("auto-update", "AutoUpdate.Apply")
|
||||||
addPrefFlagMapping("advertise-connector", "AppConnector")
|
addPrefFlagMapping("advertise-connector", "AppConnector")
|
||||||
addPrefFlagMapping("posture-checking", "PostureChecking")
|
addPrefFlagMapping("posture-checking", "PostureChecking")
|
||||||
|
addPrefFlagMapping("exit-destination-flow-logs", "ExitDestinationFlowLogs")
|
||||||
}
|
}
|
||||||
|
|
||||||
func addPrefFlagMapping(flagName string, prefNames ...string) {
|
func addPrefFlagMapping(flagName string, prefNames ...string) {
|
||||||
@ -951,6 +952,8 @@ func prefsToFlags(env upCheckEnv, prefs *ipn.Prefs) (flagVal map[string]any) {
|
|||||||
set(exitNodeIPStr())
|
set(exitNodeIPStr())
|
||||||
case "exit-node-allow-lan-access":
|
case "exit-node-allow-lan-access":
|
||||||
set(prefs.ExitNodeAllowLANAccess)
|
set(prefs.ExitNodeAllowLANAccess)
|
||||||
|
case "exit-destination-flow-logs":
|
||||||
|
set(prefs.ExitDestinationFlowLogs)
|
||||||
case "advertise-tags":
|
case "advertise-tags":
|
||||||
set(strings.Join(prefs.AdvertiseTags, ","))
|
set(strings.Join(prefs.AdvertiseTags, ","))
|
||||||
case "hostname":
|
case "hostname":
|
||||||
|
@ -1150,6 +1150,9 @@ func (b *LocalBackend) SetControlClientStatus(c controlclient.Client, st control
|
|||||||
if setExitNodeID(prefs, st.NetMap) {
|
if setExitNodeID(prefs, st.NetMap) {
|
||||||
prefsChanged = true
|
prefsChanged = true
|
||||||
}
|
}
|
||||||
|
if setExitDstFlowLogs(prefs) {
|
||||||
|
prefsChanged = true
|
||||||
|
}
|
||||||
if applySysPolicy(prefs) {
|
if applySysPolicy(prefs) {
|
||||||
prefsChanged = true
|
prefsChanged = true
|
||||||
}
|
}
|
||||||
@ -1335,6 +1338,15 @@ func applySysPolicy(prefs *ipn.Prefs) (anyChange bool) {
|
|||||||
return anyChange
|
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)
|
var _ controlclient.NetmapDeltaUpdater = (*LocalBackend)(nil)
|
||||||
|
|
||||||
// UpdateNetmapDelta implements controlclient.NetmapDeltaUpdater.
|
// 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
|
// everything in this function treats b.prefs as completely new
|
||||||
// anyway. No-op if no exit node resolution is needed.
|
// anyway. No-op if no exit node resolution is needed.
|
||||||
setExitNodeID(newp, netMap)
|
setExitNodeID(newp, netMap)
|
||||||
|
setExitDstFlowLogs(newp)
|
||||||
// applySysPolicy does likewise so we can also ignore its return value.
|
// applySysPolicy does likewise so we can also ignore its return value.
|
||||||
applySysPolicy(newp)
|
applySysPolicy(newp)
|
||||||
// We do this to avoid holding the lock while doing everything else.
|
// We do this to avoid holding the lock while doing everything else.
|
||||||
@ -3628,6 +3641,8 @@ func (b *LocalBackend) authReconfig() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cfg.NetworkLogging.ExitDestinationFlowLogs = prefs.ExitDestinationFlowLogs()
|
||||||
|
|
||||||
oneCGNATRoute := shouldUseOneCGNATRoute(b.logf, b.sys.ControlKnobs(), version.OS())
|
oneCGNATRoute := shouldUseOneCGNATRoute(b.logf, b.sys.ControlKnobs(), version.OS())
|
||||||
rcfg := b.routerConfig(cfg, prefs, oneCGNATRoute)
|
rcfg := b.routerConfig(cfg, prefs, oneCGNATRoute)
|
||||||
|
|
||||||
|
@ -109,6 +109,9 @@ type Prefs struct {
|
|||||||
// routed directly or via the exit node.
|
// routed directly or via the exit node.
|
||||||
ExitNodeAllowLANAccess bool
|
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
|
// CorpDNS specifies whether to install the Tailscale network's
|
||||||
// DNS configuration, if it exists.
|
// DNS configuration, if it exists.
|
||||||
CorpDNS bool
|
CorpDNS bool
|
||||||
@ -277,6 +280,7 @@ type MaskedPrefs struct {
|
|||||||
ControlURLSet bool `json:",omitempty"`
|
ControlURLSet bool `json:",omitempty"`
|
||||||
RouteAllSet bool `json:",omitempty"`
|
RouteAllSet bool `json:",omitempty"`
|
||||||
AllowSingleHostsSet bool `json:",omitempty"`
|
AllowSingleHostsSet bool `json:",omitempty"`
|
||||||
|
ExitDestinationFlowLogsSet bool `json:",omitempty"`
|
||||||
ExitNodeIDSet bool `json:",omitempty"`
|
ExitNodeIDSet bool `json:",omitempty"`
|
||||||
ExitNodeIPSet bool `json:",omitempty"`
|
ExitNodeIPSet bool `json:",omitempty"`
|
||||||
ExitNodeAllowLANAccessSet bool `json:",omitempty"`
|
ExitNodeAllowLANAccessSet bool `json:",omitempty"`
|
||||||
@ -475,6 +479,9 @@ func (p *Prefs) pretty(goos string) string {
|
|||||||
if p.ShieldsUp {
|
if p.ShieldsUp {
|
||||||
sb.WriteString("shields=true ")
|
sb.WriteString("shields=true ")
|
||||||
}
|
}
|
||||||
|
if p.ExitDestinationFlowLogs {
|
||||||
|
sb.WriteString("exitdestinationflowlogs=true ")
|
||||||
|
}
|
||||||
if p.ExitNodeIP.IsValid() {
|
if p.ExitNodeIP.IsValid() {
|
||||||
fmt.Fprintf(&sb, "exit=%v lan=%t ", p.ExitNodeIP, p.ExitNodeAllowLANAccess)
|
fmt.Fprintf(&sb, "exit=%v lan=%t ", p.ExitNodeIP, p.ExitNodeAllowLANAccess)
|
||||||
} else if !p.ExitNodeID.IsZero() {
|
} else if !p.ExitNodeID.IsZero() {
|
||||||
@ -545,6 +552,7 @@ func (p *Prefs) Equals(p2 *Prefs) bool {
|
|||||||
p.ExitNodeID == p2.ExitNodeID &&
|
p.ExitNodeID == p2.ExitNodeID &&
|
||||||
p.ExitNodeIP == p2.ExitNodeIP &&
|
p.ExitNodeIP == p2.ExitNodeIP &&
|
||||||
p.ExitNodeAllowLANAccess == p2.ExitNodeAllowLANAccess &&
|
p.ExitNodeAllowLANAccess == p2.ExitNodeAllowLANAccess &&
|
||||||
|
p.ExitDestinationFlowLogs == p2.ExitDestinationFlowLogs &&
|
||||||
p.CorpDNS == p2.CorpDNS &&
|
p.CorpDNS == p2.CorpDNS &&
|
||||||
p.RunSSH == p2.RunSSH &&
|
p.RunSSH == p2.RunSSH &&
|
||||||
p.RunWebClient == p2.RunWebClient &&
|
p.RunWebClient == p2.RunWebClient &&
|
||||||
|
@ -67,7 +67,7 @@ const (
|
|||||||
// The default is 0 unless otherwise stated.
|
// The default is 0 unless otherwise stated.
|
||||||
LogSCMInteractions Key = "LogSCMInteractions"
|
LogSCMInteractions Key = "LogSCMInteractions"
|
||||||
FlushDNSOnSessionUnlock Key = "FlushDNSOnSessionUnlock"
|
FlushDNSOnSessionUnlock Key = "FlushDNSOnSessionUnlock"
|
||||||
|
ExitDestinationFlowLogs Key = "ExitDestinationFlowLogs"
|
||||||
// PostureChecking indicates if posture checking is enabled and the client shall gather
|
// PostureChecking indicates if posture checking is enabled and the client shall gather
|
||||||
// posture data.
|
// posture data.
|
||||||
// Key is a string value that specifies an option: "always", "never", "user-decides".
|
// 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 IP protocol and source port are always zero.
|
||||||
// The sock is used to populated the PhysicalTraffic field in Message.
|
// 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.
|
// 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()
|
nl.mu.Lock()
|
||||||
defer nl.mu.Unlock()
|
defer nl.mu.Unlock()
|
||||||
if nl.logger != nil {
|
if nl.logger != nil {
|
||||||
@ -130,7 +130,7 @@ func (nl *Logger) Startup(nodeID tailcfg.StableNodeID, nodeLogID, domainLogID lo
|
|||||||
addrs := nl.addrs
|
addrs := nl.addrs
|
||||||
prefixes := nl.prefixes
|
prefixes := nl.prefixes
|
||||||
nl.mu.Unlock()
|
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.
|
// Register the connection tracker into the TUN device.
|
||||||
@ -150,7 +150,7 @@ func (nl *Logger) Startup(nodeID tailcfg.StableNodeID, nodeLogID, domainLogID lo
|
|||||||
return nil
|
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()}
|
m := netlogtype.Message{NodeID: nodeID, Start: start.UTC(), End: end.UTC()}
|
||||||
|
|
||||||
classifyAddr := func(a netip.Addr) (isTailscale, withinRoute bool) {
|
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})
|
m.SubnetTraffic = append(m.SubnetTraffic, netlogtype.ConnectionCounts{Connection: conn, Counts: cnts})
|
||||||
default:
|
default:
|
||||||
const anonymize = true
|
const anonymize = true
|
||||||
if anonymize {
|
if anonymize && !enableExitDstFlowLogs {
|
||||||
// Only preserve the address if it is a Tailscale IP address.
|
// Only preserve the address if it is a Tailscale IP address.
|
||||||
srcOrig, dstOrig := conn.Src, conn.Dst
|
srcOrig, dstOrig := conn.Src, conn.Dst
|
||||||
conn = netlogtype.Connection{} // scrub everything by default
|
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() {
|
if netLogRunning && !e.networkLogger.Running() {
|
||||||
nid := cfg.NetworkLogging.NodeID
|
nid := cfg.NetworkLogging.NodeID
|
||||||
tid := cfg.NetworkLogging.DomainID
|
tid := cfg.NetworkLogging.DomainID
|
||||||
|
enableExitDstFlowLogs := cfg.NetworkLogging.ExitDestinationFlowLogs
|
||||||
e.logf("wgengine: Reconfig: starting up network logger (node:%s tailnet:%s)", nid.Public(), tid.Public())
|
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.logf("wgengine: Reconfig: error starting up network logger: %v", err)
|
||||||
}
|
}
|
||||||
e.networkLogger.ReconfigRoutes(routerCfg)
|
e.networkLogger.ReconfigRoutes(routerCfg)
|
||||||
|
@ -30,6 +30,7 @@ type Config struct {
|
|||||||
NetworkLogging struct {
|
NetworkLogging struct {
|
||||||
NodeID logid.PrivateID
|
NodeID logid.PrivateID
|
||||||
DomainID logid.PrivateID
|
DomainID logid.PrivateID
|
||||||
|
ExitDestinationFlowLogs bool
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user