96 lines
2.6 KiB
Go
96 lines
2.6 KiB
Go
// 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.
|
|
|
|
//go:build !js
|
|
// +build !js
|
|
|
|
// Package tun creates a tuntap device, working around OS-specific
|
|
// quirks if necessary.
|
|
package tstun
|
|
|
|
import (
|
|
"errors"
|
|
"os"
|
|
"runtime"
|
|
"strconv"
|
|
"strings"
|
|
"time"
|
|
|
|
"golang.zx2c4.com/wireguard/tun"
|
|
"tailscale.com/types/logger"
|
|
)
|
|
|
|
// tunMTU 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.
|
|
var tunMTU = 1280
|
|
|
|
func init() {
|
|
if mtu, _ := strconv.Atoi(os.Getenv("TS_DEBUG_MTU")); mtu != 0 {
|
|
tunMTU = mtu
|
|
}
|
|
}
|
|
|
|
// createTAP is non-nil on Linux.
|
|
var createTAP func(tapName, bridgeName string) (tun.Device, error)
|
|
|
|
// New returns a tun.Device for the requested device name, along with
|
|
// the OS-dependent name that was allocated to the device.
|
|
func New(logf logger.Logf, tunName string) (tun.Device, string, error) {
|
|
var dev tun.Device
|
|
var err error
|
|
if strings.HasPrefix(tunName, "tap:") {
|
|
if runtime.GOOS != "linux" {
|
|
return nil, "", errors.New("tap only works on Linux")
|
|
}
|
|
f := strings.Split(tunName, ":")
|
|
var tapName, bridgeName string
|
|
switch len(f) {
|
|
case 2:
|
|
tapName = f[1]
|
|
case 3:
|
|
tapName, bridgeName = f[1], f[2]
|
|
default:
|
|
return nil, "", errors.New("bogus tap argument")
|
|
}
|
|
dev, err = createTAP(tapName, bridgeName)
|
|
} else {
|
|
dev, err = tun.CreateTUN(tunName, tunMTU)
|
|
}
|
|
if err != nil {
|
|
return nil, "", err
|
|
}
|
|
if err := waitInterfaceUp(dev, 90*time.Second, logf); err != nil {
|
|
dev.Close()
|
|
return nil, "", err
|
|
}
|
|
name, err := interfaceName(dev)
|
|
if err != nil {
|
|
dev.Close()
|
|
return nil, "", err
|
|
}
|
|
return dev, name, nil
|
|
}
|
|
|
|
// tunDiagnoseFailure, if non-nil, does OS-specific diagnostics of why
|
|
// TUN failed to work.
|
|
var tunDiagnoseFailure func(tunName string, logf logger.Logf)
|
|
|
|
// 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) {
|
|
if tunDiagnoseFailure != nil {
|
|
tunDiagnoseFailure(tunName, logf)
|
|
} else {
|
|
logf("no TUN failure diagnostics for OS %q", runtime.GOOS)
|
|
}
|
|
}
|