mirror of
https://github.com/tailscale/tailscale.git
synced 2025-07-15 10:08:41 +00:00
all: detect JetKVM and specialize a handful of things for it
Updates #16524 Change-Id: I183428de8c65d7155d82979d2d33f031c22e3331 Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
This commit is contained in:
parent
bebc796e6c
commit
fbc6a9ec5a
@ -257,14 +257,13 @@ func main() {
|
|||||||
// Only apply a default statepath when neither have been provided, so that a
|
// Only apply a default statepath when neither have been provided, so that a
|
||||||
// user may specify only --statedir if they wish.
|
// user may specify only --statedir if they wish.
|
||||||
if args.statepath == "" && args.statedir == "" {
|
if args.statepath == "" && args.statedir == "" {
|
||||||
if runtime.GOOS == "plan9" {
|
if paths.MakeAutomaticStateDir() {
|
||||||
home, err := os.UserHomeDir()
|
d := paths.DefaultTailscaledStateDir()
|
||||||
if err != nil {
|
if d != "" {
|
||||||
log.Fatalf("failed to get home directory: %v", err)
|
args.statedir = d
|
||||||
}
|
if err := os.MkdirAll(d, 0700); err != nil {
|
||||||
args.statedir = filepath.Join(home, "tailscale-state")
|
log.Fatalf("failed to create state directory: %v", err)
|
||||||
if err := os.MkdirAll(args.statedir, 0700); err != nil {
|
}
|
||||||
log.Fatalf("failed to create state directory: %v", err)
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
args.statepath = paths.DefaultTailscaledStateFile()
|
args.statepath = paths.DefaultTailscaledStateFile()
|
||||||
|
@ -224,6 +224,9 @@ func LogsDir(logf logger.Logf) string {
|
|||||||
logf("logpolicy: using LocalAppData dir %v", dir)
|
logf("logpolicy: using LocalAppData dir %v", dir)
|
||||||
return dir
|
return dir
|
||||||
case "linux":
|
case "linux":
|
||||||
|
if distro.Get() == distro.JetKVM {
|
||||||
|
return "/userdata/tailscale/var"
|
||||||
|
}
|
||||||
// STATE_DIRECTORY is set by systemd 240+ but we support older
|
// STATE_DIRECTORY is set by systemd 240+ but we support older
|
||||||
// systems-d. For example, Ubuntu 18.04 (Bionic Beaver) is 237.
|
// systems-d. For example, Ubuntu 18.04 (Bionic Beaver) is 237.
|
||||||
systemdStateDir := os.Getenv("STATE_DIRECTORY")
|
systemdStateDir := os.Getenv("STATE_DIRECTORY")
|
||||||
|
@ -22,6 +22,7 @@ import (
|
|||||||
"tailscale.com/types/logger"
|
"tailscale.com/types/logger"
|
||||||
"tailscale.com/util/clientmetric"
|
"tailscale.com/util/clientmetric"
|
||||||
"tailscale.com/util/cmpver"
|
"tailscale.com/util/cmpver"
|
||||||
|
"tailscale.com/version/distro"
|
||||||
)
|
)
|
||||||
|
|
||||||
type kv struct {
|
type kv struct {
|
||||||
@ -38,6 +39,10 @@ var publishOnce sync.Once
|
|||||||
//
|
//
|
||||||
// The health tracker may be nil; the knobs may be nil and are ignored on this platform.
|
// The health tracker may be nil; the knobs may be nil and are ignored on this platform.
|
||||||
func NewOSConfigurator(logf logger.Logf, health *health.Tracker, _ *controlknobs.Knobs, interfaceName string) (ret OSConfigurator, err error) {
|
func NewOSConfigurator(logf logger.Logf, health *health.Tracker, _ *controlknobs.Knobs, interfaceName string) (ret OSConfigurator, err error) {
|
||||||
|
if distro.Get() == distro.JetKVM {
|
||||||
|
return NewNoopManager()
|
||||||
|
}
|
||||||
|
|
||||||
env := newOSConfigEnv{
|
env := newOSConfigEnv{
|
||||||
fs: directFS{},
|
fs: directFS{},
|
||||||
dbusPing: dbusPing,
|
dbusPing: dbusPing,
|
||||||
|
@ -24,6 +24,9 @@ import (
|
|||||||
// CrateTAP is the hook set by feature/tap.
|
// CrateTAP is the hook set by feature/tap.
|
||||||
var CreateTAP feature.Hook[func(logf logger.Logf, tapName, bridgeName string) (tun.Device, error)]
|
var CreateTAP feature.Hook[func(logf logger.Logf, tapName, bridgeName string) (tun.Device, error)]
|
||||||
|
|
||||||
|
// modprobeTunHook is a Linux-specific hook to run "/sbin/modprobe tun".
|
||||||
|
var modprobeTunHook feature.Hook[func() error]
|
||||||
|
|
||||||
// New returns a tun.Device for the requested device name, along with
|
// New returns a tun.Device for the requested device name, along with
|
||||||
// the OS-dependent name that was allocated to the device.
|
// the OS-dependent name that was allocated to the device.
|
||||||
func New(logf logger.Logf, tunName string) (tun.Device, string, error) {
|
func New(logf logger.Logf, tunName string) (tun.Device, string, error) {
|
||||||
@ -51,7 +54,22 @@ func New(logf logger.Logf, tunName string) (tun.Device, string, error) {
|
|||||||
if runtime.GOOS == "plan9" {
|
if runtime.GOOS == "plan9" {
|
||||||
cleanUpPlan9Interfaces()
|
cleanUpPlan9Interfaces()
|
||||||
}
|
}
|
||||||
dev, err = tun.CreateTUN(tunName, int(DefaultTUNMTU()))
|
// Try to create the TUN device up to two times. If it fails
|
||||||
|
// the first time and we're on Linux, try a desperate
|
||||||
|
// "modprobe tun" to load the tun module and try again.
|
||||||
|
for try := range 2 {
|
||||||
|
dev, err = tun.CreateTUN(tunName, int(DefaultTUNMTU()))
|
||||||
|
if err == nil || !modprobeTunHook.IsSet() {
|
||||||
|
if try > 0 {
|
||||||
|
logf("created TUN device %q after doing `modprobe tun`", tunName)
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if modprobeTunHook.Get()() != nil {
|
||||||
|
// modprobe failed; no point trying again.
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, "", err
|
return nil, "", err
|
||||||
|
@ -17,6 +17,14 @@ import (
|
|||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
tunDiagnoseFailure = diagnoseLinuxTUNFailure
|
tunDiagnoseFailure = diagnoseLinuxTUNFailure
|
||||||
|
modprobeTunHook.Set(func() error {
|
||||||
|
_, err := modprobeTun()
|
||||||
|
return err
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func modprobeTun() ([]byte, error) {
|
||||||
|
return exec.Command("/sbin/modprobe", "tun").CombinedOutput()
|
||||||
}
|
}
|
||||||
|
|
||||||
func diagnoseLinuxTUNFailure(tunName string, logf logger.Logf, createErr error) {
|
func diagnoseLinuxTUNFailure(tunName string, logf logger.Logf, createErr error) {
|
||||||
@ -36,7 +44,7 @@ func diagnoseLinuxTUNFailure(tunName string, logf logger.Logf, createErr error)
|
|||||||
kernel := utsReleaseField(&un)
|
kernel := utsReleaseField(&un)
|
||||||
logf("Linux kernel version: %s", kernel)
|
logf("Linux kernel version: %s", kernel)
|
||||||
|
|
||||||
modprobeOut, err := exec.Command("/sbin/modprobe", "tun").CombinedOutput()
|
modprobeOut, err := modprobeTun()
|
||||||
if err == nil {
|
if err == nil {
|
||||||
logf("'modprobe tun' successful")
|
logf("'modprobe tun' successful")
|
||||||
// Either tun is currently loaded, or it's statically
|
// Either tun is currently loaded, or it's statically
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
package paths
|
package paths
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"log"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"runtime"
|
"runtime"
|
||||||
@ -70,6 +71,37 @@ func DefaultTailscaledStateFile() string {
|
|||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DefaultTailscaledStateDir returns the default state directory
|
||||||
|
// to use for tailscaled, for use when the user provided neither
|
||||||
|
// a state directory or state file path to use.
|
||||||
|
//
|
||||||
|
// It returns the empty string if there's no reasonable default.
|
||||||
|
func DefaultTailscaledStateDir() string {
|
||||||
|
if runtime.GOOS == "plan9" {
|
||||||
|
home, err := os.UserHomeDir()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("failed to get home directory: %v", err)
|
||||||
|
}
|
||||||
|
return filepath.Join(home, "tailscale-state")
|
||||||
|
}
|
||||||
|
return filepath.Dir(DefaultTailscaledStateFile())
|
||||||
|
}
|
||||||
|
|
||||||
|
// MakeAutomaticStateDir reports whether the platform
|
||||||
|
// automatically creates the state directory for tailscaled
|
||||||
|
// when it's absent.
|
||||||
|
func MakeAutomaticStateDir() bool {
|
||||||
|
switch runtime.GOOS {
|
||||||
|
case "plan9":
|
||||||
|
return true
|
||||||
|
case "linux":
|
||||||
|
if distro.Get() == distro.JetKVM {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
// MkStateDir ensures that dirPath, the daemon's configuration directory
|
// MkStateDir ensures that dirPath, the daemon's configuration directory
|
||||||
// containing machine keys etc, both exists and has the correct permissions.
|
// containing machine keys etc, both exists and has the correct permissions.
|
||||||
// We want it to only be accessible to the user the daemon is running under.
|
// We want it to only be accessible to the user the daemon is running under.
|
||||||
|
@ -21,6 +21,9 @@ func init() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func statePath() string {
|
func statePath() string {
|
||||||
|
if runtime.GOOS == "linux" && distro.Get() == distro.JetKVM {
|
||||||
|
return "/userdata/tailscale/var/tailscaled.state"
|
||||||
|
}
|
||||||
switch runtime.GOOS {
|
switch runtime.GOOS {
|
||||||
case "linux", "illumos", "solaris":
|
case "linux", "illumos", "solaris":
|
||||||
return "/var/lib/tailscale/tailscaled.state"
|
return "/var/lib/tailscale/tailscaled.state"
|
||||||
|
@ -23,6 +23,11 @@ func detectFirewallMode(logf logger.Logf, prefHint string) FirewallMode {
|
|||||||
hostinfo.SetFirewallMode("nft-gokrazy")
|
hostinfo.SetFirewallMode("nft-gokrazy")
|
||||||
return FirewallModeNfTables
|
return FirewallModeNfTables
|
||||||
}
|
}
|
||||||
|
if distro.Get() == distro.JetKVM {
|
||||||
|
// JetKVM doesn't have iptables.
|
||||||
|
hostinfo.SetFirewallMode("nft-jetkvm")
|
||||||
|
return FirewallModeNfTables
|
||||||
|
}
|
||||||
|
|
||||||
mode := envknob.String("TS_DEBUG_FIREWALL_MODE")
|
mode := envknob.String("TS_DEBUG_FIREWALL_MODE")
|
||||||
// If the envknob isn't set, fall back to the pref suggested by c2n or
|
// If the envknob isn't set, fall back to the pref suggested by c2n or
|
||||||
|
@ -688,8 +688,9 @@ func (i *iptablesRunner) DelMagicsockPortRule(port uint16, network string) error
|
|||||||
// IPTablesCleanUp removes all Tailscale added iptables rules.
|
// IPTablesCleanUp removes all Tailscale added iptables rules.
|
||||||
// Any errors that occur are logged to the provided logf.
|
// Any errors that occur are logged to the provided logf.
|
||||||
func IPTablesCleanUp(logf logger.Logf) {
|
func IPTablesCleanUp(logf logger.Logf) {
|
||||||
if distro.Get() == distro.Gokrazy {
|
switch distro.Get() {
|
||||||
// Gokrazy uses nftables and doesn't have the "iptables" command.
|
case distro.Gokrazy, distro.JetKVM:
|
||||||
|
// These use nftables and don't have the "iptables" command.
|
||||||
// Avoid log spam on cleanup. (#12277)
|
// Avoid log spam on cleanup. (#12277)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -31,6 +31,7 @@ const (
|
|||||||
Unraid = Distro("unraid")
|
Unraid = Distro("unraid")
|
||||||
Alpine = Distro("alpine")
|
Alpine = Distro("alpine")
|
||||||
UBNT = Distro("ubnt") // Ubiquiti Networks
|
UBNT = Distro("ubnt") // Ubiquiti Networks
|
||||||
|
JetKVM = Distro("jetkvm")
|
||||||
)
|
)
|
||||||
|
|
||||||
var distro lazy.SyncValue[Distro]
|
var distro lazy.SyncValue[Distro]
|
||||||
@ -102,6 +103,8 @@ func linuxDistro() Distro {
|
|||||||
return Unraid
|
return Unraid
|
||||||
case have("/etc/alpine-release"):
|
case have("/etc/alpine-release"):
|
||||||
return Alpine
|
return Alpine
|
||||||
|
case haveDir("/userdata/jetkvm") && haveDir("/sys/kernel/config/usb_gadget/jetkvm"):
|
||||||
|
return JetKVM
|
||||||
}
|
}
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user