mirror of
https://github.com/tailscale/tailscale.git
synced 2025-04-19 05:02:34 +00:00
tailcfg: Add FirewallMode to NetInfo to record wether host using iptables or nftables
To record wether user is using iptables or nftables after we add support to nftables on linux, we are adding a field FirewallMode to NetInfo in HostInfo to reflect what firewall mode the host is running, and form metrics. The information is gained from a global constant in hostinfo.go. We set it when selection heuristic made the decision, and magicsock reports this to control. Updates: tailscale/corp#13943 Signed-off-by: KevinLiang10 <kevinliang@tailscale.com>
This commit is contained in:
parent
95d776bd8c
commit
7ed3681cbe
@ -171,6 +171,7 @@ var (
|
|||||||
desktopAtomic atomic.Value // of opt.Bool
|
desktopAtomic atomic.Value // of opt.Bool
|
||||||
packagingType atomic.Value // of string
|
packagingType atomic.Value // of string
|
||||||
appType atomic.Value // of string
|
appType atomic.Value // of string
|
||||||
|
firewallMode atomic.Value // of string
|
||||||
)
|
)
|
||||||
|
|
||||||
// SetPushDeviceToken sets the device token for use in Hostinfo updates.
|
// SetPushDeviceToken sets the device token for use in Hostinfo updates.
|
||||||
@ -182,6 +183,9 @@ func SetDeviceModel(model string) { deviceModelAtomic.Store(model) }
|
|||||||
// SetOSVersion sets the OS version.
|
// SetOSVersion sets the OS version.
|
||||||
func SetOSVersion(v string) { osVersionAtomic.Store(v) }
|
func SetOSVersion(v string) { osVersionAtomic.Store(v) }
|
||||||
|
|
||||||
|
// SetFirewallMode sets the firewall mode for the app.
|
||||||
|
func SetFirewallMode(v string) { firewallMode.Store(v) }
|
||||||
|
|
||||||
// SetPackage sets the packaging type for the app.
|
// SetPackage sets the packaging type for the app.
|
||||||
//
|
//
|
||||||
// As of 2022-03-25, this is used by Android ("nogoogle" for the
|
// As of 2022-03-25, this is used by Android ("nogoogle" for the
|
||||||
@ -203,6 +207,13 @@ func pushDeviceToken() string {
|
|||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FirewallMode returns the firewall mode for the app.
|
||||||
|
// It is empty if unset.
|
||||||
|
func FirewallMode() string {
|
||||||
|
s, _ := firewallMode.Load().(string)
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
func desktop() (ret opt.Bool) {
|
func desktop() (ret opt.Bool) {
|
||||||
if runtime.GOOS != "linux" {
|
if runtime.GOOS != "linux" {
|
||||||
return opt.Bool("")
|
return opt.Bool("")
|
||||||
|
@ -734,6 +734,11 @@ type NetInfo struct {
|
|||||||
// the control plane.
|
// the control plane.
|
||||||
DERPLatency map[string]float64 `json:",omitempty"`
|
DERPLatency map[string]float64 `json:",omitempty"`
|
||||||
|
|
||||||
|
// FirewallMode is the current firewall utility in use by router (iptables, nftables).
|
||||||
|
// FirewallMode ipt means iptables, nft means nftables. When it's empty user is not using
|
||||||
|
// our netfilter runners to manage firewall rules.
|
||||||
|
FirewallMode string `json:",omitempty"`
|
||||||
|
|
||||||
// Update BasicallyEqual when adding fields.
|
// Update BasicallyEqual when adding fields.
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -741,10 +746,10 @@ func (ni *NetInfo) String() string {
|
|||||||
if ni == nil {
|
if ni == nil {
|
||||||
return "NetInfo(nil)"
|
return "NetInfo(nil)"
|
||||||
}
|
}
|
||||||
return fmt.Sprintf("NetInfo{varies=%v hairpin=%v ipv6=%v ipv6os=%v udp=%v icmpv4=%v derp=#%v portmap=%v link=%q}",
|
return fmt.Sprintf("NetInfo{varies=%v hairpin=%v ipv6=%v ipv6os=%v udp=%v icmpv4=%v derp=#%v portmap=%v link=%q firewallmode=%q}",
|
||||||
ni.MappingVariesByDestIP, ni.HairPinning, ni.WorkingIPv6,
|
ni.MappingVariesByDestIP, ni.HairPinning, ni.WorkingIPv6,
|
||||||
ni.OSHasIPv6, ni.WorkingUDP, ni.WorkingICMPv4,
|
ni.OSHasIPv6, ni.WorkingUDP, ni.WorkingICMPv4,
|
||||||
ni.PreferredDERP, ni.portMapSummary(), ni.LinkType)
|
ni.PreferredDERP, ni.portMapSummary(), ni.LinkType, ni.FirewallMode)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ni *NetInfo) portMapSummary() string {
|
func (ni *NetInfo) portMapSummary() string {
|
||||||
@ -792,7 +797,8 @@ func (ni *NetInfo) BasicallyEqual(ni2 *NetInfo) bool {
|
|||||||
ni.PMP == ni2.PMP &&
|
ni.PMP == ni2.PMP &&
|
||||||
ni.PCP == ni2.PCP &&
|
ni.PCP == ni2.PCP &&
|
||||||
ni.PreferredDERP == ni2.PreferredDERP &&
|
ni.PreferredDERP == ni2.PreferredDERP &&
|
||||||
ni.LinkType == ni2.LinkType
|
ni.LinkType == ni2.LinkType &&
|
||||||
|
ni.FirewallMode == ni2.FirewallMode
|
||||||
}
|
}
|
||||||
|
|
||||||
// Equal reports whether h and h2 are equal.
|
// Equal reports whether h and h2 are equal.
|
||||||
|
@ -195,6 +195,7 @@ var _NetInfoCloneNeedsRegeneration = NetInfo(struct {
|
|||||||
PreferredDERP int
|
PreferredDERP int
|
||||||
LinkType string
|
LinkType string
|
||||||
DERPLatency map[string]float64
|
DERPLatency map[string]float64
|
||||||
|
FirewallMode string
|
||||||
}{})
|
}{})
|
||||||
|
|
||||||
// Clone makes a deep copy of Login.
|
// Clone makes a deep copy of Login.
|
||||||
|
@ -571,6 +571,7 @@ func TestNetInfoFields(t *testing.T) {
|
|||||||
"PreferredDERP",
|
"PreferredDERP",
|
||||||
"LinkType",
|
"LinkType",
|
||||||
"DERPLatency",
|
"DERPLatency",
|
||||||
|
"FirewallMode",
|
||||||
}
|
}
|
||||||
if have := fieldsOf(reflect.TypeOf(NetInfo{})); !reflect.DeepEqual(have, handled) {
|
if have := fieldsOf(reflect.TypeOf(NetInfo{})); !reflect.DeepEqual(have, handled) {
|
||||||
t.Errorf("NetInfo.Clone/BasicallyEqually check might be out of sync\nfields: %q\nhandled: %q\n",
|
t.Errorf("NetInfo.Clone/BasicallyEqually check might be out of sync\nfields: %q\nhandled: %q\n",
|
||||||
|
@ -408,6 +408,7 @@ func (v NetInfoView) PreferredDERP() int { return v.ж.PreferredDER
|
|||||||
func (v NetInfoView) LinkType() string { return v.ж.LinkType }
|
func (v NetInfoView) LinkType() string { return v.ж.LinkType }
|
||||||
|
|
||||||
func (v NetInfoView) DERPLatency() views.Map[string, float64] { return views.MapOf(v.ж.DERPLatency) }
|
func (v NetInfoView) DERPLatency() views.Map[string, float64] { return views.MapOf(v.ж.DERPLatency) }
|
||||||
|
func (v NetInfoView) FirewallMode() string { return v.ж.FirewallMode }
|
||||||
func (v NetInfoView) String() string { return v.ж.String() }
|
func (v NetInfoView) String() string { return v.ж.String() }
|
||||||
|
|
||||||
// A compilation failure here means this code must be regenerated, with the command at the top of this file.
|
// A compilation failure here means this code must be regenerated, with the command at the top of this file.
|
||||||
@ -425,6 +426,7 @@ var _NetInfoViewNeedsRegeneration = NetInfo(struct {
|
|||||||
PreferredDERP int
|
PreferredDERP int
|
||||||
LinkType string
|
LinkType string
|
||||||
DERPLatency map[string]float64
|
DERPLatency map[string]float64
|
||||||
|
FirewallMode string
|
||||||
}{})
|
}{})
|
||||||
|
|
||||||
// View returns a readonly view of Login.
|
// View returns a readonly view of Login.
|
||||||
|
@ -640,6 +640,7 @@ func (c *Conn) updateNetInfo(ctx context.Context) (*netcheck.Report, error) {
|
|||||||
if !c.setNearestDERP(ni.PreferredDERP) {
|
if !c.setNearestDERP(ni.PreferredDERP) {
|
||||||
ni.PreferredDERP = 0
|
ni.PreferredDERP = 0
|
||||||
}
|
}
|
||||||
|
ni.FirewallMode = hostinfo.FirewallMode()
|
||||||
|
|
||||||
c.callNetInfoCallback(ni)
|
c.callNetInfoCallback(ni)
|
||||||
return report, nil
|
return report, nil
|
||||||
|
@ -22,6 +22,7 @@ import (
|
|||||||
"golang.org/x/sys/unix"
|
"golang.org/x/sys/unix"
|
||||||
"golang.org/x/time/rate"
|
"golang.org/x/time/rate"
|
||||||
"tailscale.com/envknob"
|
"tailscale.com/envknob"
|
||||||
|
"tailscale.com/hostinfo"
|
||||||
"tailscale.com/net/netmon"
|
"tailscale.com/net/netmon"
|
||||||
"tailscale.com/types/logger"
|
"tailscale.com/types/logger"
|
||||||
"tailscale.com/types/preftype"
|
"tailscale.com/types/preftype"
|
||||||
@ -97,29 +98,36 @@ func chooseFireWallMode(logf logger.Logf, det tableDetector) linuxfw.FirewallMod
|
|||||||
case envknob.String("TS_DEBUG_FIREWALL_MODE") == "nftables":
|
case envknob.String("TS_DEBUG_FIREWALL_MODE") == "nftables":
|
||||||
// TODO(KevinLiang10): Updates to a flag
|
// TODO(KevinLiang10): Updates to a flag
|
||||||
logf("router: envknob TS_DEBUG_FIREWALL_MODE=nftables set")
|
logf("router: envknob TS_DEBUG_FIREWALL_MODE=nftables set")
|
||||||
|
hostinfo.SetFirewallMode("nft-forced")
|
||||||
return linuxfw.FirewallModeNfTables
|
return linuxfw.FirewallModeNfTables
|
||||||
case envknob.String("TS_DEBUG_FIREWALL_MODE") == "iptables":
|
case envknob.String("TS_DEBUG_FIREWALL_MODE") == "iptables":
|
||||||
logf("router: envknob TS_DEBUG_FIREWALL_MODE=iptables set")
|
logf("router: envknob TS_DEBUG_FIREWALL_MODE=iptables set")
|
||||||
|
hostinfo.SetFirewallMode("ipt-forced")
|
||||||
return linuxfw.FirewallModeIPTables
|
return linuxfw.FirewallModeIPTables
|
||||||
case nftRuleCount > 0 && iptRuleCount == 0:
|
case nftRuleCount > 0 && iptRuleCount == 0:
|
||||||
logf("router: nftables is currently in use")
|
logf("router: nftables is currently in use")
|
||||||
|
hostinfo.SetFirewallMode("nft-inuse")
|
||||||
return linuxfw.FirewallModeNfTables
|
return linuxfw.FirewallModeNfTables
|
||||||
case iptRuleCount > 0 && nftRuleCount == 0:
|
case iptRuleCount > 0 && nftRuleCount == 0:
|
||||||
logf("router: iptables is currently in use")
|
logf("router: iptables is currently in use")
|
||||||
|
hostinfo.SetFirewallMode("ipt-inuse")
|
||||||
return linuxfw.FirewallModeIPTables
|
return linuxfw.FirewallModeIPTables
|
||||||
case nftAva:
|
case nftAva:
|
||||||
// if both iptables and nftables are available but
|
// if both iptables and nftables are available but
|
||||||
// neither/both are currently used, use nftables.
|
// neither/both are currently used, use nftables.
|
||||||
logf("router: nftables is available")
|
logf("router: nftables is available")
|
||||||
|
hostinfo.SetFirewallMode("nft")
|
||||||
return linuxfw.FirewallModeNfTables
|
return linuxfw.FirewallModeNfTables
|
||||||
case iptAva:
|
case iptAva:
|
||||||
logf("router: iptables is available")
|
logf("router: iptables is available")
|
||||||
|
hostinfo.SetFirewallMode("ipt")
|
||||||
return linuxfw.FirewallModeIPTables
|
return linuxfw.FirewallModeIPTables
|
||||||
default:
|
default:
|
||||||
// if neither iptables nor nftables are available, use iptablesRunner as a dummy
|
// if neither iptables nor nftables are available, use iptablesRunner as a dummy
|
||||||
// runner which exists but won't do anything. Creating iptablesRunner errors only
|
// runner which exists but won't do anything. Creating iptablesRunner errors only
|
||||||
// if the iptables command is missing or doesn’t support "--version", as long as it
|
// if the iptables command is missing or doesn’t support "--version", as long as it
|
||||||
// can determine a version then it’ll carry on.
|
// can determine a version then it’ll carry on.
|
||||||
|
hostinfo.SetFirewallMode("ipt-fb")
|
||||||
return linuxfw.FirewallModeIPTables
|
return linuxfw.FirewallModeIPTables
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user