mirror of
https://github.com/tailscale/tailscale.git
synced 2024-11-29 13:05:46 +00:00
wgengine: remove Config.TUNName, require caller to create device.
Also factors out device creation and associated OS workarounds to net/tun. Signed-off-by: David Anderson <danderson@tailscale.com>
This commit is contained in:
parent
0a84aaca0a
commit
44d9929208
@ -105,6 +105,7 @@ tailscale.com/cmd/tailscaled dependencies: (generated by github.com/tailscale/de
|
|||||||
tailscale.com/net/tlsdial from tailscale.com/control/controlclient+
|
tailscale.com/net/tlsdial from tailscale.com/control/controlclient+
|
||||||
tailscale.com/net/tsaddr from tailscale.com/ipn/ipnlocal+
|
tailscale.com/net/tsaddr from tailscale.com/ipn/ipnlocal+
|
||||||
💣 tailscale.com/net/tshttpproxy from tailscale.com/control/controlclient+
|
💣 tailscale.com/net/tshttpproxy from tailscale.com/control/controlclient+
|
||||||
|
tailscale.com/net/tun from tailscale.com/cmd/tailscaled
|
||||||
tailscale.com/paths from tailscale.com/cmd/tailscaled+
|
tailscale.com/paths from tailscale.com/cmd/tailscaled+
|
||||||
tailscale.com/portlist from tailscale.com/ipn/ipnlocal
|
tailscale.com/portlist from tailscale.com/ipn/ipnlocal
|
||||||
tailscale.com/safesocket from tailscale.com/ipn/ipnserver
|
tailscale.com/safesocket from tailscale.com/ipn/ipnserver
|
||||||
|
@ -32,6 +32,7 @@
|
|||||||
"tailscale.com/ipn/ipnserver"
|
"tailscale.com/ipn/ipnserver"
|
||||||
"tailscale.com/logpolicy"
|
"tailscale.com/logpolicy"
|
||||||
"tailscale.com/net/socks5"
|
"tailscale.com/net/socks5"
|
||||||
|
"tailscale.com/net/tun"
|
||||||
"tailscale.com/paths"
|
"tailscale.com/paths"
|
||||||
"tailscale.com/types/flagtype"
|
"tailscale.com/types/flagtype"
|
||||||
"tailscale.com/types/logger"
|
"tailscale.com/types/logger"
|
||||||
@ -316,18 +317,7 @@ func createEngine(logf logger.Logf, linkMon *monitor.Mon) (e wgengine.Engine, is
|
|||||||
var errs []error
|
var errs []error
|
||||||
for _, name := range strings.Split(args.tunname, ",") {
|
for _, name := range strings.Split(args.tunname, ",") {
|
||||||
logf("wgengine.NewUserspaceEngine(tun %q) ...", name)
|
logf("wgengine.NewUserspaceEngine(tun %q) ...", name)
|
||||||
conf := wgengine.Config{
|
e, isUserspace, err = tryEngine(logf, linkMon, name)
|
||||||
ListenPort: args.port,
|
|
||||||
LinkMonitor: linkMon,
|
|
||||||
}
|
|
||||||
isUserspace = name == "userspace-networking"
|
|
||||||
if isUserspace {
|
|
||||||
conf.TUN = tstun.NewFakeTUN()
|
|
||||||
conf.RouterGen = router.NewFake
|
|
||||||
} else {
|
|
||||||
conf.TUNName = name
|
|
||||||
}
|
|
||||||
e, err := wgengine.NewUserspaceEngine(logf, conf)
|
|
||||||
if err == nil {
|
if err == nil {
|
||||||
return e, isUserspace, nil
|
return e, isUserspace, nil
|
||||||
}
|
}
|
||||||
@ -337,6 +327,29 @@ func createEngine(logf logger.Logf, linkMon *monitor.Mon) (e wgengine.Engine, is
|
|||||||
return nil, false, multierror.New(errs)
|
return nil, false, multierror.New(errs)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func tryEngine(logf logger.Logf, linkMon *monitor.Mon, name string) (e wgengine.Engine, isUserspace bool, err error) {
|
||||||
|
conf := wgengine.Config{
|
||||||
|
ListenPort: args.port,
|
||||||
|
LinkMonitor: linkMon,
|
||||||
|
}
|
||||||
|
isUserspace = name == "userspace-networking"
|
||||||
|
if isUserspace {
|
||||||
|
conf.TUN = tstun.NewFakeTUN()
|
||||||
|
conf.RouterGen = router.NewFake
|
||||||
|
} else {
|
||||||
|
dev, err := tun.New(logf, name)
|
||||||
|
if err != nil {
|
||||||
|
return nil, false, err
|
||||||
|
}
|
||||||
|
conf.TUN = dev
|
||||||
|
}
|
||||||
|
e, err = wgengine.NewUserspaceEngine(logf, conf)
|
||||||
|
if err != nil {
|
||||||
|
return nil, isUserspace, err
|
||||||
|
}
|
||||||
|
return e, isUserspace, nil
|
||||||
|
}
|
||||||
|
|
||||||
func newDebugMux() *http.ServeMux {
|
func newDebugMux() *http.ServeMux {
|
||||||
mux := http.NewServeMux()
|
mux := http.NewServeMux()
|
||||||
mux.HandleFunc("/debug/pprof/", pprof.Index)
|
mux.HandleFunc("/debug/pprof/", pprof.Index)
|
||||||
|
@ -30,6 +30,7 @@
|
|||||||
"golang.zx2c4.com/wireguard/windows/tunnel/winipcfg"
|
"golang.zx2c4.com/wireguard/windows/tunnel/winipcfg"
|
||||||
"tailscale.com/ipn/ipnserver"
|
"tailscale.com/ipn/ipnserver"
|
||||||
"tailscale.com/logpolicy"
|
"tailscale.com/logpolicy"
|
||||||
|
"tailscale.com/net/tun"
|
||||||
"tailscale.com/tempfork/wireguard-windows/firewall"
|
"tailscale.com/tempfork/wireguard-windows/firewall"
|
||||||
"tailscale.com/types/logger"
|
"tailscale.com/types/logger"
|
||||||
"tailscale.com/version"
|
"tailscale.com/version"
|
||||||
@ -159,11 +160,16 @@ func startIPNServer(ctx context.Context, logid string) error {
|
|||||||
var err error
|
var err error
|
||||||
|
|
||||||
getEngine := func() (wgengine.Engine, error) {
|
getEngine := func() (wgengine.Engine, error) {
|
||||||
|
dev, err := tun.New(logf, "Tailscale")
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
eng, err := wgengine.NewUserspaceEngine(logf, wgengine.Config{
|
eng, err := wgengine.NewUserspaceEngine(logf, wgengine.Config{
|
||||||
TUNName: "Tailscale",
|
TUN: dev,
|
||||||
ListenPort: 41641,
|
ListenPort: 41641,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
dev.Close()
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return wgengine.NewWatchdog(eng), nil
|
return wgengine.NewWatchdog(eng), nil
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
// +build !windows
|
// +build !windows
|
||||||
|
|
||||||
package wgengine
|
package tun
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"time"
|
"time"
|
@ -2,7 +2,7 @@
|
|||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
package wgengine
|
package tun
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
128
net/tun/tun.go
Normal file
128
net/tun/tun.go
Normal file
@ -0,0 +1,128 @@
|
|||||||
|
// Copyright (c) 2021 Tailscale Inc & AUTHORS All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// Package tun creates a tuntap device, working around OS-specific
|
||||||
|
// quirks if necessary.
|
||||||
|
package tun
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
"runtime"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/tailscale/wireguard-go/tun"
|
||||||
|
"tailscale.com/types/logger"
|
||||||
|
"tailscale.com/version/distro"
|
||||||
|
)
|
||||||
|
|
||||||
|
// minimalMTU is the MTU we set on tailscale's TUN
|
||||||
|
// interface. wireguard-go defaults to 1420 bytes, which only works if
|
||||||
|
// the "outer" MTU is 1500 bytes. This breaks on DSL connections
|
||||||
|
// (typically 1492 MTU) and on GCE (1460 MTU?!).
|
||||||
|
//
|
||||||
|
// 1280 is the smallest MTU allowed for IPv6, which is a sensible
|
||||||
|
// "probably works everywhere" setting until we develop proper PMTU
|
||||||
|
// discovery.
|
||||||
|
const minimalMTU = 1280
|
||||||
|
|
||||||
|
func New(logf logger.Logf, tunName string) (tun.Device, error) {
|
||||||
|
dev, err := tun.CreateTUN(tunName, minimalMTU)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if err := waitInterfaceUp(dev, 90*time.Second, logf); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return dev, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Diagnose tries to explain a tuntap device creation failure.
|
||||||
|
// It pokes around the system and logs some diagnostic info that might
|
||||||
|
// help debug why tun creation failed. Because device creation has
|
||||||
|
// already failed and the program's about to end, log a lot.
|
||||||
|
func Diagnose(logf logger.Logf, tunName string) {
|
||||||
|
switch runtime.GOOS {
|
||||||
|
case "linux":
|
||||||
|
diagnoseLinuxTUNFailure(tunName, logf)
|
||||||
|
case "darwin":
|
||||||
|
diagnoseDarwinTUNFailure(tunName, logf)
|
||||||
|
default:
|
||||||
|
logf("no TUN failure diagnostics for OS %q", runtime.GOOS)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func diagnoseDarwinTUNFailure(tunName string, logf logger.Logf) {
|
||||||
|
if os.Getuid() != 0 {
|
||||||
|
logf("failed to create TUN device as non-root user; use 'sudo tailscaled', or run under launchd with 'sudo tailscaled install-system-daemon'")
|
||||||
|
}
|
||||||
|
if tunName != "utun" {
|
||||||
|
logf("failed to create TUN device %q; try using tun device \"utun\" instead for automatic selection", tunName)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func diagnoseLinuxTUNFailure(tunName string, logf logger.Logf) {
|
||||||
|
kernel, err := exec.Command("uname", "-r").Output()
|
||||||
|
kernel = bytes.TrimSpace(kernel)
|
||||||
|
if err != nil {
|
||||||
|
logf("no TUN, and failed to look up kernel version: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
logf("Linux kernel version: %s", kernel)
|
||||||
|
|
||||||
|
modprobeOut, err := exec.Command("/sbin/modprobe", "tun").CombinedOutput()
|
||||||
|
if err == nil {
|
||||||
|
logf("'modprobe tun' successful")
|
||||||
|
// Either tun is currently loaded, or it's statically
|
||||||
|
// compiled into the kernel (which modprobe checks
|
||||||
|
// with /lib/modules/$(uname -r)/modules.builtin)
|
||||||
|
//
|
||||||
|
// So if there's a problem at this point, it's
|
||||||
|
// probably because /dev/net/tun doesn't exist.
|
||||||
|
const dev = "/dev/net/tun"
|
||||||
|
if fi, err := os.Stat(dev); err != nil {
|
||||||
|
logf("tun module loaded in kernel, but %s does not exist", dev)
|
||||||
|
} else {
|
||||||
|
logf("%s: %v", dev, fi.Mode())
|
||||||
|
}
|
||||||
|
|
||||||
|
// We failed to find why it failed. Just let our
|
||||||
|
// caller report the error it got from wireguard-go.
|
||||||
|
return
|
||||||
|
}
|
||||||
|
logf("is CONFIG_TUN enabled in your kernel? `modprobe tun` failed with: %s", modprobeOut)
|
||||||
|
|
||||||
|
switch distro.Get() {
|
||||||
|
case distro.Debian:
|
||||||
|
dpkgOut, err := exec.Command("dpkg", "-S", "kernel/drivers/net/tun.ko").CombinedOutput()
|
||||||
|
if len(bytes.TrimSpace(dpkgOut)) == 0 || err != nil {
|
||||||
|
logf("tun module not loaded nor found on disk")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if !bytes.Contains(dpkgOut, kernel) {
|
||||||
|
logf("kernel/drivers/net/tun.ko found on disk, but not for current kernel; are you in middle of a system update and haven't rebooted? found: %s", dpkgOut)
|
||||||
|
}
|
||||||
|
case distro.Arch:
|
||||||
|
findOut, err := exec.Command("find", "/lib/modules/", "-path", "*/net/tun.ko*").CombinedOutput()
|
||||||
|
if len(bytes.TrimSpace(findOut)) == 0 || err != nil {
|
||||||
|
logf("tun module not loaded nor found on disk")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if !bytes.Contains(findOut, kernel) {
|
||||||
|
logf("kernel/drivers/net/tun.ko found on disk, but not for current kernel; are you in middle of a system update and haven't rebooted? found: %s", findOut)
|
||||||
|
}
|
||||||
|
case distro.OpenWrt:
|
||||||
|
out, err := exec.Command("opkg", "list-installed").CombinedOutput()
|
||||||
|
if err != nil {
|
||||||
|
logf("error querying OpenWrt installed packages: %s", out)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for _, pkg := range []string{"kmod-tun", "ca-bundle"} {
|
||||||
|
if !bytes.Contains(out, []byte(pkg+" - ")) {
|
||||||
|
logf("Missing required package %s; run: opkg install %s", pkg, pkg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -14,7 +14,6 @@
|
|||||||
"io"
|
"io"
|
||||||
"net"
|
"net"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
|
||||||
"runtime"
|
"runtime"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
@ -43,7 +42,6 @@
|
|||||||
"tailscale.com/types/netmap"
|
"tailscale.com/types/netmap"
|
||||||
"tailscale.com/types/wgkey"
|
"tailscale.com/types/wgkey"
|
||||||
"tailscale.com/version"
|
"tailscale.com/version"
|
||||||
"tailscale.com/version/distro"
|
|
||||||
"tailscale.com/wgengine/filter"
|
"tailscale.com/wgengine/filter"
|
||||||
"tailscale.com/wgengine/magicsock"
|
"tailscale.com/wgengine/magicsock"
|
||||||
"tailscale.com/wgengine/monitor"
|
"tailscale.com/wgengine/monitor"
|
||||||
@ -53,16 +51,6 @@
|
|||||||
"tailscale.com/wgengine/wglog"
|
"tailscale.com/wgengine/wglog"
|
||||||
)
|
)
|
||||||
|
|
||||||
// minimalMTU is the MTU we set on tailscale's TUN
|
|
||||||
// interface. wireguard-go defaults to 1420 bytes, which only works if
|
|
||||||
// the "outer" MTU is 1500 bytes. This breaks on DSL connections
|
|
||||||
// (typically 1492 MTU) and on GCE (1460 MTU?!).
|
|
||||||
//
|
|
||||||
// 1280 is the smallest MTU allowed for IPv6, which is a sensible
|
|
||||||
// "probably works everywhere" setting until we develop proper PMTU
|
|
||||||
// discovery.
|
|
||||||
const minimalMTU = 1280
|
|
||||||
|
|
||||||
const magicDNSPort = 53
|
const magicDNSPort = 53
|
||||||
|
|
||||||
var magicDNSIP = netaddr.IPv4(100, 100, 100, 100)
|
var magicDNSIP = netaddr.IPv4(100, 100, 100, 100)
|
||||||
@ -150,13 +138,8 @@ func (e *userspaceEngine) GetInternals() (*tstun.TUN, *magicsock.Conn) {
|
|||||||
// Config is the engine configuration.
|
// Config is the engine configuration.
|
||||||
type Config struct {
|
type Config struct {
|
||||||
// TUN is the TUN device used by the engine.
|
// TUN is the TUN device used by the engine.
|
||||||
// Exactly one of either TUN or TUNName must be specified.
|
|
||||||
TUN tun.Device
|
TUN tun.Device
|
||||||
|
|
||||||
// TUNName is the TUN device to create.
|
|
||||||
// Exactly one of either TUN or TUNName must be specified.
|
|
||||||
TUNName string
|
|
||||||
|
|
||||||
// RouterGen is the function used to instantiate the router.
|
// RouterGen is the function used to instantiate the router.
|
||||||
// If nil, wgengine/router.New is used.
|
// If nil, wgengine/router.New is used.
|
||||||
RouterGen RouterGen
|
RouterGen RouterGen
|
||||||
@ -186,42 +169,18 @@ func NewFakeUserspaceEngine(logf logger.Logf, listenPort uint16) (Engine, error)
|
|||||||
|
|
||||||
// NewUserspaceEngine creates the named tun device and returns a
|
// NewUserspaceEngine creates the named tun device and returns a
|
||||||
// Tailscale Engine running on it.
|
// Tailscale Engine running on it.
|
||||||
func NewUserspaceEngine(logf logger.Logf, conf Config) (Engine, error) {
|
func NewUserspaceEngine(logf logger.Logf, conf Config) (_ Engine, reterr error) {
|
||||||
if conf.TUN != nil && conf.TUNName != "" {
|
if conf.TUN == nil {
|
||||||
return nil, errors.New("TUN and TUNName are mutually exclusive")
|
return nil, errors.New("TUN is required")
|
||||||
}
|
}
|
||||||
if conf.TUN == nil && conf.TUNName == "" {
|
|
||||||
return nil, errors.New("either TUN or TUNName are required")
|
|
||||||
}
|
|
||||||
tunDev := conf.TUN
|
|
||||||
var err error
|
|
||||||
if tunName := conf.TUNName; tunName != "" {
|
|
||||||
logf("Starting userspace wireguard engine with tun device %q", tunName)
|
|
||||||
tunDev, err = tun.CreateTUN(tunName, minimalMTU)
|
|
||||||
if err != nil {
|
|
||||||
diagnoseTUNFailure(tunName, logf)
|
|
||||||
logf("CreateTUN: %v", err)
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
logf("CreateTUN ok.")
|
|
||||||
|
|
||||||
if err := waitInterfaceUp(tunDev, 90*time.Second, logf); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if conf.RouterGen == nil {
|
if conf.RouterGen == nil {
|
||||||
conf.RouterGen = router.New
|
conf.RouterGen = router.New
|
||||||
}
|
}
|
||||||
|
|
||||||
return newUserspaceEngine(logf, tunDev, conf)
|
|
||||||
}
|
|
||||||
|
|
||||||
func newUserspaceEngine(logf logger.Logf, rawTUNDev tun.Device, conf Config) (_ Engine, reterr error) {
|
|
||||||
var closePool closeOnErrorPool
|
var closePool closeOnErrorPool
|
||||||
defer closePool.closeAllIfError(&reterr)
|
defer closePool.closeAllIfError(&reterr)
|
||||||
|
|
||||||
tsTUNDev := tstun.WrapTUN(logf, rawTUNDev)
|
tsTUNDev := tstun.WrapTUN(logf, conf.TUN)
|
||||||
closePool.add(tsTUNDev)
|
closePool.add(tsTUNDev)
|
||||||
|
|
||||||
e := &userspaceEngine{
|
e := &userspaceEngine{
|
||||||
@ -1554,94 +1513,6 @@ func (e *userspaceEngine) peerForIP(ip netaddr.IP) (n *tailcfg.Node, err error)
|
|||||||
return nil, fmt.Errorf("node %q found, but not using its %v route", bestInNM.ComputedNameWithHost, bestInNMPrefix)
|
return nil, fmt.Errorf("node %q found, but not using its %v route", bestInNM.ComputedNameWithHost, bestInNMPrefix)
|
||||||
}
|
}
|
||||||
|
|
||||||
// diagnoseTUNFailure is called if tun.CreateTUN fails, to poke around
|
|
||||||
// the system and log some diagnostic info that might help debug why
|
|
||||||
// TUN failed. Because TUN's already failed and things the program's
|
|
||||||
// about to end, we might as well log a lot.
|
|
||||||
func diagnoseTUNFailure(tunName string, logf logger.Logf) {
|
|
||||||
switch runtime.GOOS {
|
|
||||||
case "linux":
|
|
||||||
diagnoseLinuxTUNFailure(tunName, logf)
|
|
||||||
case "darwin":
|
|
||||||
diagnoseDarwinTUNFailure(tunName, logf)
|
|
||||||
default:
|
|
||||||
logf("no TUN failure diagnostics for OS %q", runtime.GOOS)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func diagnoseDarwinTUNFailure(tunName string, logf logger.Logf) {
|
|
||||||
if os.Getuid() != 0 {
|
|
||||||
logf("failed to create TUN device as non-root user; use 'sudo tailscaled', or run under launchd with 'sudo tailscaled install-system-daemon'")
|
|
||||||
}
|
|
||||||
if tunName != "utun" {
|
|
||||||
logf("failed to create TUN device %q; try using tun device \"utun\" instead for automatic selection", tunName)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func diagnoseLinuxTUNFailure(tunName string, logf logger.Logf) {
|
|
||||||
kernel, err := exec.Command("uname", "-r").Output()
|
|
||||||
kernel = bytes.TrimSpace(kernel)
|
|
||||||
if err != nil {
|
|
||||||
logf("no TUN, and failed to look up kernel version: %v", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
logf("Linux kernel version: %s", kernel)
|
|
||||||
|
|
||||||
modprobeOut, err := exec.Command("/sbin/modprobe", "tun").CombinedOutput()
|
|
||||||
if err == nil {
|
|
||||||
logf("'modprobe tun' successful")
|
|
||||||
// Either tun is currently loaded, or it's statically
|
|
||||||
// compiled into the kernel (which modprobe checks
|
|
||||||
// with /lib/modules/$(uname -r)/modules.builtin)
|
|
||||||
//
|
|
||||||
// So if there's a problem at this point, it's
|
|
||||||
// probably because /dev/net/tun doesn't exist.
|
|
||||||
const dev = "/dev/net/tun"
|
|
||||||
if fi, err := os.Stat(dev); err != nil {
|
|
||||||
logf("tun module loaded in kernel, but %s does not exist", dev)
|
|
||||||
} else {
|
|
||||||
logf("%s: %v", dev, fi.Mode())
|
|
||||||
}
|
|
||||||
|
|
||||||
// We failed to find why it failed. Just let our
|
|
||||||
// caller report the error it got from wireguard-go.
|
|
||||||
return
|
|
||||||
}
|
|
||||||
logf("is CONFIG_TUN enabled in your kernel? `modprobe tun` failed with: %s", modprobeOut)
|
|
||||||
|
|
||||||
switch distro.Get() {
|
|
||||||
case distro.Debian:
|
|
||||||
dpkgOut, err := exec.Command("dpkg", "-S", "kernel/drivers/net/tun.ko").CombinedOutput()
|
|
||||||
if len(bytes.TrimSpace(dpkgOut)) == 0 || err != nil {
|
|
||||||
logf("tun module not loaded nor found on disk")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if !bytes.Contains(dpkgOut, kernel) {
|
|
||||||
logf("kernel/drivers/net/tun.ko found on disk, but not for current kernel; are you in middle of a system update and haven't rebooted? found: %s", dpkgOut)
|
|
||||||
}
|
|
||||||
case distro.Arch:
|
|
||||||
findOut, err := exec.Command("find", "/lib/modules/", "-path", "*/net/tun.ko*").CombinedOutput()
|
|
||||||
if len(bytes.TrimSpace(findOut)) == 0 || err != nil {
|
|
||||||
logf("tun module not loaded nor found on disk")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if !bytes.Contains(findOut, kernel) {
|
|
||||||
logf("kernel/drivers/net/tun.ko found on disk, but not for current kernel; are you in middle of a system update and haven't rebooted? found: %s", findOut)
|
|
||||||
}
|
|
||||||
case distro.OpenWrt:
|
|
||||||
out, err := exec.Command("opkg", "list-installed").CombinedOutput()
|
|
||||||
if err != nil {
|
|
||||||
logf("error querying OpenWrt installed packages: %s", out)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
for _, pkg := range []string{"kmod-tun", "ca-bundle"} {
|
|
||||||
if !bytes.Contains(out, []byte(pkg+" - ")) {
|
|
||||||
logf("Missing required package %s; run: opkg install %s", pkg, pkg)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type closeOnErrorPool []func()
|
type closeOnErrorPool []func()
|
||||||
|
|
||||||
func (p *closeOnErrorPool) add(c io.Closer) { *p = append(*p, func() { c.Close() }) }
|
func (p *closeOnErrorPool) add(c io.Closer) { *p = append(*p, func() { c.Close() }) }
|
||||||
|
Loading…
Reference in New Issue
Block a user