Update dependencies
This commit is contained in:
58
vendor/tailscale.com/net/tstun/fake.go
generated
vendored
Normal file
58
vendor/tailscale.com/net/tstun/fake.go
generated
vendored
Normal file
@@ -0,0 +1,58 @@
|
||||
// Copyright (c) Tailscale Inc & AUTHORS
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
package tstun
|
||||
|
||||
import (
|
||||
"io"
|
||||
"os"
|
||||
|
||||
"github.com/tailscale/wireguard-go/tun"
|
||||
)
|
||||
|
||||
type fakeTUN struct {
|
||||
evchan chan tun.Event
|
||||
closechan chan struct{}
|
||||
}
|
||||
|
||||
// NewFake returns a tun.Device that does nothing.
|
||||
func NewFake() tun.Device {
|
||||
return &fakeTUN{
|
||||
evchan: make(chan tun.Event),
|
||||
closechan: make(chan struct{}),
|
||||
}
|
||||
}
|
||||
|
||||
func (t *fakeTUN) File() *os.File {
|
||||
panic("fakeTUN.File() called, which makes no sense")
|
||||
}
|
||||
|
||||
func (t *fakeTUN) Close() error {
|
||||
close(t.closechan)
|
||||
close(t.evchan)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *fakeTUN) Read(out [][]byte, sizes []int, offset int) (int, error) {
|
||||
<-t.closechan
|
||||
return 0, io.EOF
|
||||
}
|
||||
|
||||
func (t *fakeTUN) Write(b [][]byte, n int) (int, error) {
|
||||
select {
|
||||
case <-t.closechan:
|
||||
return 0, ErrClosed
|
||||
default:
|
||||
}
|
||||
return 1, nil
|
||||
}
|
||||
|
||||
// FakeTUNName is the name of the fake TUN device.
|
||||
const FakeTUNName = "FakeTUN"
|
||||
|
||||
func (t *fakeTUN) Flush() error { return nil }
|
||||
func (t *fakeTUN) MTU() (int, error) { return 1500, nil }
|
||||
func (t *fakeTUN) Name() (string, error) { return FakeTUNName, nil }
|
||||
func (t *fakeTUN) Events() <-chan tun.Event { return t.evchan }
|
||||
func (t *fakeTUN) BatchSize() int { return 1 }
|
||||
func (t *fakeTUN) IsFakeTun() bool { return true }
|
||||
18
vendor/tailscale.com/net/tstun/ifstatus_noop.go
generated
vendored
Normal file
18
vendor/tailscale.com/net/tstun/ifstatus_noop.go
generated
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
// Copyright (c) Tailscale Inc & AUTHORS
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
//go:build !windows
|
||||
|
||||
package tstun
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/tailscale/wireguard-go/tun"
|
||||
"tailscale.com/types/logger"
|
||||
)
|
||||
|
||||
// Dummy implementation that does nothing.
|
||||
func waitInterfaceUp(iface tun.Device, timeout time.Duration, logf logger.Logf) error {
|
||||
return nil
|
||||
}
|
||||
109
vendor/tailscale.com/net/tstun/ifstatus_windows.go
generated
vendored
Normal file
109
vendor/tailscale.com/net/tstun/ifstatus_windows.go
generated
vendored
Normal file
@@ -0,0 +1,109 @@
|
||||
// Copyright (c) Tailscale Inc & AUTHORS
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
package tstun
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/tailscale/wireguard-go/tun"
|
||||
"golang.zx2c4.com/wireguard/windows/tunnel/winipcfg"
|
||||
"tailscale.com/types/logger"
|
||||
)
|
||||
|
||||
// ifaceWatcher waits for an interface to be up.
|
||||
type ifaceWatcher struct {
|
||||
logf logger.Logf
|
||||
luid winipcfg.LUID
|
||||
|
||||
mu sync.Mutex // guards following
|
||||
done bool
|
||||
sig chan bool
|
||||
}
|
||||
|
||||
// callback is the callback we register with Windows to call when IP interface changes.
|
||||
func (iw *ifaceWatcher) callback(notificationType winipcfg.MibNotificationType, iface *winipcfg.MibIPInterfaceRow) {
|
||||
// Probably should check only when MibParameterNotification, but just in case included MibAddInstance also.
|
||||
if notificationType == winipcfg.MibParameterNotification || notificationType == winipcfg.MibAddInstance {
|
||||
// Out of paranoia, start a goroutine to finish our work, to return to Windows out of this callback.
|
||||
go iw.isUp()
|
||||
}
|
||||
}
|
||||
|
||||
func (iw *ifaceWatcher) isUp() bool {
|
||||
iw.mu.Lock()
|
||||
defer iw.mu.Unlock()
|
||||
|
||||
if iw.done {
|
||||
// We already know that it's up
|
||||
return true
|
||||
}
|
||||
|
||||
if iw.getOperStatus() != winipcfg.IfOperStatusUp {
|
||||
return false
|
||||
}
|
||||
|
||||
iw.done = true
|
||||
iw.sig <- true
|
||||
return true
|
||||
}
|
||||
|
||||
func (iw *ifaceWatcher) getOperStatus() winipcfg.IfOperStatus {
|
||||
ifc, err := iw.luid.Interface()
|
||||
if err != nil {
|
||||
iw.logf("iw.luid.Interface error: %v", err)
|
||||
return 0
|
||||
}
|
||||
return ifc.OperStatus
|
||||
}
|
||||
|
||||
func waitInterfaceUp(iface tun.Device, timeout time.Duration, logf logger.Logf) error {
|
||||
iw := &ifaceWatcher{
|
||||
luid: winipcfg.LUID(iface.(*tun.NativeTun).LUID()),
|
||||
logf: logger.WithPrefix(logf, "waitInterfaceUp: "),
|
||||
}
|
||||
|
||||
// Just in case check the status first
|
||||
if iw.getOperStatus() == winipcfg.IfOperStatusUp {
|
||||
iw.logf("TUN interface already up; no need to wait")
|
||||
return nil
|
||||
}
|
||||
|
||||
iw.sig = make(chan bool, 1)
|
||||
cb, err := winipcfg.RegisterInterfaceChangeCallback(iw.callback)
|
||||
if err != nil {
|
||||
iw.logf("RegisterInterfaceChangeCallback error: %v", err)
|
||||
return err
|
||||
}
|
||||
defer cb.Unregister()
|
||||
|
||||
t0 := time.Now()
|
||||
expires := t0.Add(timeout)
|
||||
ticker := time.NewTicker(10 * time.Second)
|
||||
defer ticker.Stop()
|
||||
|
||||
for {
|
||||
iw.logf("waiting for TUN interface to come up...")
|
||||
|
||||
select {
|
||||
case <-iw.sig:
|
||||
iw.logf("TUN interface is up after %v", time.Since(t0))
|
||||
return nil
|
||||
case <-ticker.C:
|
||||
}
|
||||
|
||||
if iw.isUp() {
|
||||
// Very unlikely to happen - either NotifyIpInterfaceChange doesn't work
|
||||
// or it came up in the same moment as tick. Indicate this in the log message.
|
||||
iw.logf("TUN interface is up after %v (on poll, without notification)", time.Since(t0))
|
||||
return nil
|
||||
}
|
||||
|
||||
if expires.Before(time.Now()) {
|
||||
iw.logf("timeout waiting %v for TUN interface to come up", timeout)
|
||||
return fmt.Errorf("timeout waiting for TUN interface to come up")
|
||||
}
|
||||
}
|
||||
}
|
||||
63
vendor/tailscale.com/net/tstun/linkattrs_linux.go
generated
vendored
Normal file
63
vendor/tailscale.com/net/tstun/linkattrs_linux.go
generated
vendored
Normal file
@@ -0,0 +1,63 @@
|
||||
// Copyright (c) Tailscale Inc & AUTHORS
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
package tstun
|
||||
|
||||
import (
|
||||
"github.com/mdlayher/genetlink"
|
||||
"github.com/mdlayher/netlink"
|
||||
"github.com/tailscale/wireguard-go/tun"
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
// setLinkSpeed sets the advertised link speed of the TUN interface.
|
||||
func setLinkSpeed(iface tun.Device, mbps int) error {
|
||||
name, err := iface.Name()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
conn, err := genetlink.Dial(&netlink.Config{Strict: true})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
defer conn.Close()
|
||||
|
||||
f, err := conn.GetFamily(unix.ETHTOOL_GENL_NAME)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ae := netlink.NewAttributeEncoder()
|
||||
ae.Nested(unix.ETHTOOL_A_LINKMODES_HEADER, func(nae *netlink.AttributeEncoder) error {
|
||||
nae.String(unix.ETHTOOL_A_HEADER_DEV_NAME, name)
|
||||
return nil
|
||||
})
|
||||
ae.Uint32(unix.ETHTOOL_A_LINKMODES_SPEED, uint32(mbps))
|
||||
|
||||
b, err := ae.Encode()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = conn.Execute(
|
||||
genetlink.Message{
|
||||
Header: genetlink.Header{
|
||||
Command: unix.ETHTOOL_MSG_LINKMODES_SET,
|
||||
Version: unix.ETHTOOL_GENL_VERSION,
|
||||
},
|
||||
Data: b,
|
||||
},
|
||||
f.ID,
|
||||
netlink.Request|netlink.Acknowledge,
|
||||
)
|
||||
return err
|
||||
}
|
||||
|
||||
// setLinkAttrs sets up link attributes that can be queried by external tools.
|
||||
// Its failure is non-fatal to interface bringup.
|
||||
func setLinkAttrs(iface tun.Device) error {
|
||||
// By default the link speed is 10Mbps, which is easily exceeded and causes monitoring tools to complain (#3933).
|
||||
return setLinkSpeed(iface, unix.SPEED_UNKNOWN)
|
||||
}
|
||||
12
vendor/tailscale.com/net/tstun/linkattrs_notlinux.go
generated
vendored
Normal file
12
vendor/tailscale.com/net/tstun/linkattrs_notlinux.go
generated
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
// Copyright (c) Tailscale Inc & AUTHORS
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
//go:build !linux
|
||||
|
||||
package tstun
|
||||
|
||||
import "github.com/tailscale/wireguard-go/tun"
|
||||
|
||||
func setLinkAttrs(iface tun.Device) error {
|
||||
return nil
|
||||
}
|
||||
161
vendor/tailscale.com/net/tstun/mtu.go
generated
vendored
Normal file
161
vendor/tailscale.com/net/tstun/mtu.go
generated
vendored
Normal file
@@ -0,0 +1,161 @@
|
||||
// Copyright (c) Tailscale Inc & AUTHORS
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
package tstun
|
||||
|
||||
import (
|
||||
"tailscale.com/envknob"
|
||||
)
|
||||
|
||||
// The MTU (Maximum Transmission Unit) of a network interface is the largest
|
||||
// packet that can be sent or received through that interface, including all
|
||||
// headers above the link layer (e.g. IP headers, UDP headers, Wireguard
|
||||
// headers, etc.). We have to think about several different values of MTU:
|
||||
//
|
||||
// Wire MTU: The MTU of an interface underneath the tailscale TUN, e.g. an
|
||||
// Ethernet network card will default to a 1500 byte MTU. The user may change
|
||||
// this MTU at any time.
|
||||
//
|
||||
// TUN MTU: The current MTU of the tailscale TUN. This MTU is adjusted downward
|
||||
// to make room for the wireguard/tailscale headers. For example, if the
|
||||
// underlying network interface's MTU is 1500 bytes, the maximum size of a
|
||||
// packet entering the tailscale TUN is 1420 bytes. The user may change this MTU
|
||||
// at any time via the OS's tools (ifconfig, ip, etc.).
|
||||
//
|
||||
// User configured initial MTU: The MTU the tailscale TUN should be created
|
||||
// with, set by the user via TS_DEBUG_MTU. It should be adjusted down from the
|
||||
// underlying interface MTU by 80 bytes to make room for the wireguard
|
||||
// headers. This envknob is mostly for debugging. This value is used once at TUN
|
||||
// creation and ignored thereafter.
|
||||
//
|
||||
// User configured current MTU: The MTU set via the OS's tools (ifconfig, ip,
|
||||
// etc.). This MTU can change at any time. Setting the MTU this way goes through
|
||||
// the MTU() method of tailscale's TUN wrapper.
|
||||
//
|
||||
// Maximum probed MTU: This is the largest MTU size that we send probe packets
|
||||
// for.
|
||||
//
|
||||
// Safe MTU: If the tailscale TUN MTU is set to this value, almost all packets
|
||||
// will get to their destination. Tailscale defaults to this MTU in the absence
|
||||
// of path MTU probe information or user MTU configuration. We may occasionally
|
||||
// find a path that needs a smaller MTU but it is very rare.
|
||||
//
|
||||
// Peer MTU: This is the path MTU to a peer's current best endpoint. It defaults
|
||||
// to the Safe MTU unless we have path MTU probe results that tell us otherwise.
|
||||
//
|
||||
// Initial MTU: This is the MTU tailscaled creates the TUN with. In order of
|
||||
// priority, it is:
|
||||
//
|
||||
// 1. If set, the value of TS_DEBUG_MTU clamped to a maximum of 65536
|
||||
// 2. If TS_DEBUG_ENABLE_PMTUD is set, the maximum size MTU we probe, minus wg
|
||||
// overhead
|
||||
// 3. If TS_DEBUG_ENABLE_PMTUD is not set, the Safe MTU
|
||||
//
|
||||
// Current MTU: This the MTU of the tailscale TUN at any given moment
|
||||
// after TUN creation. In order of priority, it is:
|
||||
//
|
||||
// 1. The MTU set by the user via the OS, if it has ever been set
|
||||
// 2. If TS_DEBUG_ENABLE_PMTUD is set, the maximum size MTU we probe, minus wg
|
||||
// overhead
|
||||
// 4. If TS_DEBUG_ENABLE_PMTUD is not set, the Safe MTU
|
||||
|
||||
// TUNMTU is the MTU for the tailscale TUN.
|
||||
type TUNMTU uint32
|
||||
|
||||
// WireMTU is the MTU for the underlying network devices.
|
||||
type WireMTU uint32
|
||||
|
||||
const (
|
||||
// maxTUNMTU is the largest MTU we will consider for the Tailscale
|
||||
// TUN. This is inherited from wireguard-go and can be surprisingly
|
||||
// small; on Windows it is currently 2048 - 32 bytes and iOS it is 1700
|
||||
// - 32 bytes.
|
||||
// TODO(val,raggi): On Windows this seems to derive from RIO driver
|
||||
// constraints in Wireguard but we don't use RIO so could probably make
|
||||
// this bigger.
|
||||
maxTUNMTU TUNMTU = TUNMTU(MaxPacketSize)
|
||||
// safeTUNMTU is the default "safe" MTU for the Tailscale TUN that we
|
||||
// use in the absence of other information such as path MTU probes.
|
||||
safeTUNMTU TUNMTU = 1280
|
||||
)
|
||||
|
||||
// WireMTUsToProbe is a list of the on-the-wire MTUs we want to probe. Each time
|
||||
// magicsock discovery begins, it will send a set of pings, one of each size
|
||||
// listed below.
|
||||
var WireMTUsToProbe = []WireMTU{
|
||||
WireMTU(safeTUNMTU), // Tailscale over Tailscale :)
|
||||
TUNToWireMTU(safeTUNMTU), // Smallest MTU allowed for IPv6, current default
|
||||
1400, // Most common MTU minus a few bytes for tunnels
|
||||
1500, // Most common MTU
|
||||
8000, // Should fit inside all jumbo frame sizes
|
||||
9000, // Most jumbo frames are this size or larger
|
||||
}
|
||||
|
||||
// wgHeaderLen is the length of all the headers Wireguard adds to a packet
|
||||
// in the worst case (IPv6). This constant is for use when we can't or
|
||||
// shouldn't use information about the IP version of a specific packet
|
||||
// (e.g., calculating the MTU for the Tailscale interface.
|
||||
//
|
||||
// A Wireguard header includes:
|
||||
//
|
||||
// - 20-byte IPv4 header or 40-byte IPv6 header
|
||||
// - 8-byte UDP header
|
||||
// - 4-byte type
|
||||
// - 4-byte key index
|
||||
// - 8-byte nonce
|
||||
// - 16-byte authentication tag
|
||||
const wgHeaderLen = 40 + 8 + 4 + 4 + 8 + 16
|
||||
|
||||
// TUNToWireMTU takes the MTU that the Tailscale TUN presents to the user and
|
||||
// returns the on-the-wire MTU necessary to transmit the largest packet that
|
||||
// will fit through the TUN, given that we have to add wireguard headers.
|
||||
func TUNToWireMTU(t TUNMTU) WireMTU {
|
||||
return WireMTU(t + wgHeaderLen)
|
||||
}
|
||||
|
||||
// WireToTUNMTU takes the MTU of an underlying network device and returns the
|
||||
// largest possible MTU for a Tailscale TUN operating on top of that device,
|
||||
// given that we have to add wireguard headers.
|
||||
func WireToTUNMTU(w WireMTU) TUNMTU {
|
||||
if w < wgHeaderLen {
|
||||
return 0
|
||||
}
|
||||
return TUNMTU(w - wgHeaderLen)
|
||||
}
|
||||
|
||||
// DefaultTUNMTU returns the MTU we use to set the Tailscale TUN
|
||||
// MTU. It is also the path MTU that we default to if we have no
|
||||
// information about the path to a peer.
|
||||
//
|
||||
// 1. If set, the value of TS_DEBUG_MTU clamped to a maximum of MaxTUNMTU
|
||||
// 2. If TS_DEBUG_ENABLE_PMTUD is set, the maximum size MTU we probe, minus wg overhead
|
||||
// 3. If TS_DEBUG_ENABLE_PMTUD is not set, the Safe MTU
|
||||
func DefaultTUNMTU() TUNMTU {
|
||||
if m, ok := envknob.LookupUintSized("TS_DEBUG_MTU", 10, 32); ok {
|
||||
return min(TUNMTU(m), maxTUNMTU)
|
||||
}
|
||||
|
||||
debugPMTUD, _ := envknob.LookupBool("TS_DEBUG_ENABLE_PMTUD")
|
||||
if debugPMTUD {
|
||||
// TODO: While we are just probing MTU but not generating PTB,
|
||||
// this has to continue to return the safe MTU. When we add the
|
||||
// code to generate PTB, this will be:
|
||||
//
|
||||
// return WireToTUNMTU(maxProbedWireMTU)
|
||||
return safeTUNMTU
|
||||
}
|
||||
|
||||
return safeTUNMTU
|
||||
}
|
||||
|
||||
// SafeWireMTU returns the wire MTU that is safe to use if we have no
|
||||
// information about the path MTU to this peer.
|
||||
func SafeWireMTU() WireMTU {
|
||||
return TUNToWireMTU(safeTUNMTU)
|
||||
}
|
||||
|
||||
// DefaultWireMTU returns the default TUN MTU, adjusted for wireguard
|
||||
// overhead.
|
||||
func DefaultWireMTU() WireMTU {
|
||||
return TUNToWireMTU(DefaultTUNMTU())
|
||||
}
|
||||
453
vendor/tailscale.com/net/tstun/tap_linux.go
generated
vendored
Normal file
453
vendor/tailscale.com/net/tstun/tap_linux.go
generated
vendored
Normal file
@@ -0,0 +1,453 @@
|
||||
// Copyright (c) Tailscale Inc & AUTHORS
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
//go:build !ts_omit_tap
|
||||
|
||||
package tstun
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"net/netip"
|
||||
"os"
|
||||
"os/exec"
|
||||
"sync"
|
||||
|
||||
"github.com/insomniacslk/dhcp/dhcpv4"
|
||||
"github.com/tailscale/wireguard-go/tun"
|
||||
"golang.org/x/sys/unix"
|
||||
"gvisor.dev/gvisor/pkg/tcpip"
|
||||
"gvisor.dev/gvisor/pkg/tcpip/checksum"
|
||||
"gvisor.dev/gvisor/pkg/tcpip/header"
|
||||
"gvisor.dev/gvisor/pkg/tcpip/network/ipv4"
|
||||
"gvisor.dev/gvisor/pkg/tcpip/transport/udp"
|
||||
"tailscale.com/net/netaddr"
|
||||
"tailscale.com/net/packet"
|
||||
"tailscale.com/types/ipproto"
|
||||
"tailscale.com/util/multierr"
|
||||
)
|
||||
|
||||
// TODO: this was randomly generated once. Maybe do it per process start? But
|
||||
// then an upgraded tailscaled would be visible to devices behind it. So
|
||||
// maybe instead make it a function of the tailscaled's wireguard public key?
|
||||
// For now just hard code it.
|
||||
var ourMAC = net.HardwareAddr{0x30, 0x2D, 0x66, 0xEC, 0x7A, 0x93}
|
||||
|
||||
func init() { createTAP = createTAPLinux }
|
||||
|
||||
func createTAPLinux(tapName, bridgeName string) (tun.Device, error) {
|
||||
fd, err := unix.Open("/dev/net/tun", unix.O_RDWR, 0)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
dev, err := openDevice(fd, tapName, bridgeName)
|
||||
if err != nil {
|
||||
unix.Close(fd)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return dev, nil
|
||||
}
|
||||
|
||||
func openDevice(fd int, tapName, bridgeName string) (tun.Device, error) {
|
||||
ifr, err := unix.NewIfreq(tapName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Flags are stored as a uint16 in the ifreq union.
|
||||
ifr.SetUint16(unix.IFF_TAP | unix.IFF_NO_PI)
|
||||
if err := unix.IoctlIfreq(fd, unix.TUNSETIFF, ifr); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := run("ip", "link", "set", "dev", tapName, "up"); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if bridgeName != "" {
|
||||
if err := run("brctl", "addif", bridgeName, tapName); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return newTAPDevice(fd, tapName)
|
||||
}
|
||||
|
||||
type etherType [2]byte
|
||||
|
||||
var (
|
||||
etherTypeARP = etherType{0x08, 0x06}
|
||||
etherTypeIPv4 = etherType{0x08, 0x00}
|
||||
etherTypeIPv6 = etherType{0x86, 0xDD}
|
||||
)
|
||||
|
||||
const ipv4HeaderLen = 20
|
||||
|
||||
const (
|
||||
consumePacket = true
|
||||
passOnPacket = false
|
||||
)
|
||||
|
||||
// handleTAPFrame handles receiving a raw TAP ethernet frame and reports whether
|
||||
// it's been handled (that is, whether it should NOT be passed to wireguard).
|
||||
func (t *Wrapper) handleTAPFrame(ethBuf []byte) bool {
|
||||
|
||||
if len(ethBuf) < ethernetFrameSize {
|
||||
// Corrupt. Ignore.
|
||||
if tapDebug {
|
||||
t.logf("tap: short TAP frame")
|
||||
}
|
||||
return consumePacket
|
||||
}
|
||||
ethDstMAC, ethSrcMAC := ethBuf[:6], ethBuf[6:12]
|
||||
_ = ethDstMAC
|
||||
et := etherType{ethBuf[12], ethBuf[13]}
|
||||
switch et {
|
||||
default:
|
||||
if tapDebug {
|
||||
t.logf("tap: ignoring etherType %v", et)
|
||||
}
|
||||
return consumePacket // filter out packet we should ignore
|
||||
case etherTypeIPv6:
|
||||
// TODO: support DHCPv6/ND/etc later. For now pass all to WireGuard.
|
||||
if tapDebug {
|
||||
t.logf("tap: ignoring IPv6 %v", et)
|
||||
}
|
||||
return passOnPacket
|
||||
case etherTypeIPv4:
|
||||
if len(ethBuf) < ethernetFrameSize+ipv4HeaderLen {
|
||||
// Bogus IPv4. Eat.
|
||||
if tapDebug {
|
||||
t.logf("tap: short ipv4")
|
||||
}
|
||||
return consumePacket
|
||||
}
|
||||
return t.handleDHCPRequest(ethBuf)
|
||||
case etherTypeARP:
|
||||
arpPacket := header.ARP(ethBuf[ethernetFrameSize:])
|
||||
if !arpPacket.IsValid() {
|
||||
// Bogus ARP. Eat.
|
||||
return consumePacket
|
||||
}
|
||||
switch arpPacket.Op() {
|
||||
case header.ARPRequest:
|
||||
req := arpPacket // better name at this point
|
||||
buf := make([]byte, header.EthernetMinimumSize+header.ARPSize)
|
||||
|
||||
// Our ARP "Table" of one:
|
||||
var srcMAC [6]byte
|
||||
copy(srcMAC[:], ethSrcMAC)
|
||||
if old := t.destMAC(); old != srcMAC {
|
||||
t.destMACAtomic.Store(srcMAC)
|
||||
}
|
||||
|
||||
eth := header.Ethernet(buf)
|
||||
eth.Encode(&header.EthernetFields{
|
||||
SrcAddr: tcpip.LinkAddress(ourMAC[:]),
|
||||
DstAddr: tcpip.LinkAddress(ethSrcMAC),
|
||||
Type: 0x0806, // arp
|
||||
})
|
||||
res := header.ARP(buf[header.EthernetMinimumSize:])
|
||||
res.SetIPv4OverEthernet()
|
||||
res.SetOp(header.ARPReply)
|
||||
|
||||
// If the client's asking about their own IP, tell them it's
|
||||
// their own MAC. TODO(bradfitz): remove String allocs.
|
||||
if net.IP(req.ProtocolAddressTarget()).String() == theClientIP {
|
||||
copy(res.HardwareAddressSender(), ethSrcMAC)
|
||||
} else {
|
||||
copy(res.HardwareAddressSender(), ourMAC[:])
|
||||
}
|
||||
|
||||
copy(res.ProtocolAddressSender(), req.ProtocolAddressTarget())
|
||||
copy(res.HardwareAddressTarget(), req.HardwareAddressSender())
|
||||
copy(res.ProtocolAddressTarget(), req.ProtocolAddressSender())
|
||||
|
||||
// TODO(raggi): reduce allocs!
|
||||
n, err := t.tdev.Write([][]byte{buf}, 0)
|
||||
if tapDebug {
|
||||
t.logf("tap: wrote ARP reply %v, %v", n, err)
|
||||
}
|
||||
}
|
||||
|
||||
return consumePacket
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(bradfitz): remove these hard-coded values and move from a /24 to a /10 CGNAT as the range.
|
||||
const theClientIP = "100.70.145.3" // TODO: make dynamic from netmap
|
||||
const routerIP = "100.70.145.1" // must be in same netmask (currently hack at /24) as theClientIP
|
||||
|
||||
// handleDHCPRequest handles receiving a raw TAP ethernet frame and reports whether
|
||||
// it's been handled as a DHCP request. That is, it reports whether the frame should
|
||||
// be ignored by the caller and not passed on.
|
||||
func (t *Wrapper) handleDHCPRequest(ethBuf []byte) bool {
|
||||
const udpHeader = 8
|
||||
if len(ethBuf) < ethernetFrameSize+ipv4HeaderLen+udpHeader {
|
||||
if tapDebug {
|
||||
t.logf("tap: DHCP short")
|
||||
}
|
||||
return passOnPacket
|
||||
}
|
||||
ethDstMAC, ethSrcMAC := ethBuf[:6], ethBuf[6:12]
|
||||
|
||||
if string(ethDstMAC) != "\xff\xff\xff\xff\xff\xff" {
|
||||
// Not a broadcast
|
||||
if tapDebug {
|
||||
t.logf("tap: dhcp no broadcast")
|
||||
}
|
||||
return passOnPacket
|
||||
}
|
||||
|
||||
p := parsedPacketPool.Get().(*packet.Parsed)
|
||||
defer parsedPacketPool.Put(p)
|
||||
p.Decode(ethBuf[ethernetFrameSize:])
|
||||
|
||||
if p.IPProto != ipproto.UDP || p.Src.Port() != 68 || p.Dst.Port() != 67 {
|
||||
// Not a DHCP request.
|
||||
if tapDebug {
|
||||
t.logf("tap: DHCP wrong meta")
|
||||
}
|
||||
return passOnPacket
|
||||
}
|
||||
|
||||
dp, err := dhcpv4.FromBytes(ethBuf[ethernetFrameSize+ipv4HeaderLen+udpHeader:])
|
||||
if err != nil {
|
||||
// Bogus. Trash it.
|
||||
if tapDebug {
|
||||
t.logf("tap: DHCP FromBytes bad")
|
||||
}
|
||||
return consumePacket
|
||||
}
|
||||
if tapDebug {
|
||||
t.logf("tap: DHCP request: %+v", dp)
|
||||
}
|
||||
switch dp.MessageType() {
|
||||
case dhcpv4.MessageTypeDiscover:
|
||||
offer, err := dhcpv4.New(
|
||||
dhcpv4.WithReply(dp),
|
||||
dhcpv4.WithMessageType(dhcpv4.MessageTypeOffer),
|
||||
dhcpv4.WithRouter(net.ParseIP(routerIP)), // the default route
|
||||
dhcpv4.WithDNS(net.ParseIP("100.100.100.100")),
|
||||
dhcpv4.WithServerIP(net.ParseIP("100.100.100.100")), // TODO: what is this?
|
||||
dhcpv4.WithOption(dhcpv4.OptServerIdentifier(net.ParseIP("100.100.100.100"))),
|
||||
dhcpv4.WithYourIP(net.ParseIP(theClientIP)),
|
||||
dhcpv4.WithLeaseTime(3600), // hour works
|
||||
//dhcpv4.WithHwAddr(ethSrcMAC),
|
||||
dhcpv4.WithNetmask(net.IPMask(net.ParseIP("255.255.255.0").To4())), // TODO: wrong
|
||||
//dhcpv4.WithTransactionID(dp.TransactionID),
|
||||
)
|
||||
if err != nil {
|
||||
t.logf("error building DHCP offer: %v", err)
|
||||
return consumePacket
|
||||
}
|
||||
// Make a layer 2 packet to write out:
|
||||
pkt := packLayer2UDP(
|
||||
offer.ToBytes(),
|
||||
ourMAC, ethSrcMAC,
|
||||
netip.AddrPortFrom(netaddr.IPv4(100, 100, 100, 100), 67), // src
|
||||
netip.AddrPortFrom(netaddr.IPv4(255, 255, 255, 255), 68), // dst
|
||||
)
|
||||
|
||||
// TODO(raggi): reduce allocs!
|
||||
n, err := t.tdev.Write([][]byte{pkt}, 0)
|
||||
if tapDebug {
|
||||
t.logf("tap: wrote DHCP OFFER %v, %v", n, err)
|
||||
}
|
||||
case dhcpv4.MessageTypeRequest:
|
||||
ack, err := dhcpv4.New(
|
||||
dhcpv4.WithReply(dp),
|
||||
dhcpv4.WithMessageType(dhcpv4.MessageTypeAck),
|
||||
dhcpv4.WithDNS(net.ParseIP("100.100.100.100")),
|
||||
dhcpv4.WithRouter(net.ParseIP(routerIP)), // the default route
|
||||
dhcpv4.WithServerIP(net.ParseIP("100.100.100.100")), // TODO: what is this?
|
||||
dhcpv4.WithOption(dhcpv4.OptServerIdentifier(net.ParseIP("100.100.100.100"))),
|
||||
dhcpv4.WithYourIP(net.ParseIP(theClientIP)), // Hello world
|
||||
dhcpv4.WithLeaseTime(3600), // hour works
|
||||
dhcpv4.WithNetmask(net.IPMask(net.ParseIP("255.255.255.0").To4())),
|
||||
)
|
||||
if err != nil {
|
||||
t.logf("error building DHCP ack: %v", err)
|
||||
return consumePacket
|
||||
}
|
||||
// Make a layer 2 packet to write out:
|
||||
pkt := packLayer2UDP(
|
||||
ack.ToBytes(),
|
||||
ourMAC, ethSrcMAC,
|
||||
netip.AddrPortFrom(netaddr.IPv4(100, 100, 100, 100), 67), // src
|
||||
netip.AddrPortFrom(netaddr.IPv4(255, 255, 255, 255), 68), // dst
|
||||
)
|
||||
// TODO(raggi): reduce allocs!
|
||||
n, err := t.tdev.Write([][]byte{pkt}, 0)
|
||||
if tapDebug {
|
||||
t.logf("tap: wrote DHCP ACK %v, %v", n, err)
|
||||
}
|
||||
default:
|
||||
if tapDebug {
|
||||
t.logf("tap: unknown DHCP type")
|
||||
}
|
||||
}
|
||||
return consumePacket
|
||||
}
|
||||
|
||||
func packLayer2UDP(payload []byte, srcMAC, dstMAC net.HardwareAddr, src, dst netip.AddrPort) []byte {
|
||||
buf := make([]byte, header.EthernetMinimumSize+header.UDPMinimumSize+header.IPv4MinimumSize+len(payload))
|
||||
payloadStart := len(buf) - len(payload)
|
||||
copy(buf[payloadStart:], payload)
|
||||
srcB := src.Addr().As4()
|
||||
srcIP := tcpip.AddrFromSlice(srcB[:])
|
||||
dstB := dst.Addr().As4()
|
||||
dstIP := tcpip.AddrFromSlice(dstB[:])
|
||||
// Ethernet header
|
||||
eth := header.Ethernet(buf)
|
||||
eth.Encode(&header.EthernetFields{
|
||||
SrcAddr: tcpip.LinkAddress(srcMAC),
|
||||
DstAddr: tcpip.LinkAddress(dstMAC),
|
||||
Type: ipv4.ProtocolNumber,
|
||||
})
|
||||
// IP header
|
||||
ipbuf := buf[header.EthernetMinimumSize:]
|
||||
ip := header.IPv4(ipbuf)
|
||||
ip.Encode(&header.IPv4Fields{
|
||||
TotalLength: uint16(len(ipbuf)),
|
||||
TTL: 65,
|
||||
Protocol: uint8(udp.ProtocolNumber),
|
||||
SrcAddr: srcIP,
|
||||
DstAddr: dstIP,
|
||||
})
|
||||
ip.SetChecksum(^ip.CalculateChecksum())
|
||||
// UDP header
|
||||
u := header.UDP(buf[header.EthernetMinimumSize+header.IPv4MinimumSize:])
|
||||
u.Encode(&header.UDPFields{
|
||||
SrcPort: src.Port(),
|
||||
DstPort: dst.Port(),
|
||||
Length: uint16(header.UDPMinimumSize + len(payload)),
|
||||
})
|
||||
// Calculate the UDP pseudo-header checksum.
|
||||
xsum := header.PseudoHeaderChecksum(udp.ProtocolNumber, srcIP, dstIP, uint16(len(u)))
|
||||
// Calculate the UDP checksum and set it.
|
||||
xsum = checksum.Checksum(payload, xsum)
|
||||
u.SetChecksum(^u.CalculateChecksum(xsum))
|
||||
return []byte(buf)
|
||||
}
|
||||
|
||||
func run(prog string, args ...string) error {
|
||||
cmd := exec.Command(prog, args...)
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
if err := cmd.Run(); err != nil {
|
||||
return fmt.Errorf("error running %v: %v", cmd, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *Wrapper) destMAC() [6]byte {
|
||||
return t.destMACAtomic.Load()
|
||||
}
|
||||
|
||||
func newTAPDevice(fd int, tapName string) (tun.Device, error) {
|
||||
err := unix.SetNonblock(fd, true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
file := os.NewFile(uintptr(fd), "/dev/tap")
|
||||
d := &tapDevice{
|
||||
file: file,
|
||||
events: make(chan tun.Event),
|
||||
name: tapName,
|
||||
}
|
||||
return d, nil
|
||||
}
|
||||
|
||||
var (
|
||||
_ setWrapperer = &tapDevice{}
|
||||
)
|
||||
|
||||
type tapDevice struct {
|
||||
file *os.File
|
||||
events chan tun.Event
|
||||
name string
|
||||
wrapper *Wrapper
|
||||
closeOnce sync.Once
|
||||
}
|
||||
|
||||
func (t *tapDevice) setWrapper(wrapper *Wrapper) {
|
||||
t.wrapper = wrapper
|
||||
}
|
||||
|
||||
func (t *tapDevice) File() *os.File {
|
||||
return t.file
|
||||
}
|
||||
|
||||
func (t *tapDevice) Name() (string, error) {
|
||||
return t.name, nil
|
||||
}
|
||||
|
||||
func (t *tapDevice) Read(buffs [][]byte, sizes []int, offset int) (int, error) {
|
||||
n, err := t.file.Read(buffs[0][offset:])
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
sizes[0] = n
|
||||
return 1, nil
|
||||
}
|
||||
|
||||
func (t *tapDevice) Write(buffs [][]byte, offset int) (int, error) {
|
||||
errs := make([]error, 0)
|
||||
wrote := 0
|
||||
for _, buff := range buffs {
|
||||
if offset < ethernetFrameSize {
|
||||
errs = append(errs, fmt.Errorf("[unexpected] weird offset %d for TAP write", offset))
|
||||
return 0, multierr.New(errs...)
|
||||
}
|
||||
eth := buff[offset-ethernetFrameSize:]
|
||||
dst := t.wrapper.destMAC()
|
||||
copy(eth[:6], dst[:])
|
||||
copy(eth[6:12], ourMAC[:])
|
||||
et := etherTypeIPv4
|
||||
if buff[offset]>>4 == 6 {
|
||||
et = etherTypeIPv6
|
||||
}
|
||||
eth[12], eth[13] = et[0], et[1]
|
||||
if tapDebug {
|
||||
t.wrapper.logf("tap: tapWrite off=%v % x", offset, buff)
|
||||
}
|
||||
_, err := t.file.Write(buff[offset-ethernetFrameSize:])
|
||||
if err != nil {
|
||||
errs = append(errs, err)
|
||||
} else {
|
||||
wrote++
|
||||
}
|
||||
}
|
||||
return wrote, multierr.New(errs...)
|
||||
}
|
||||
|
||||
func (t *tapDevice) MTU() (int, error) {
|
||||
ifr, err := unix.NewIfreq(t.name)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
err = unix.IoctlIfreq(int(t.file.Fd()), unix.SIOCGIFMTU, ifr)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return int(ifr.Uint32()), nil
|
||||
}
|
||||
|
||||
func (t *tapDevice) Events() <-chan tun.Event {
|
||||
return t.events
|
||||
}
|
||||
|
||||
func (t *tapDevice) Close() error {
|
||||
var err error
|
||||
t.closeOnce.Do(func() {
|
||||
close(t.events)
|
||||
err = t.file.Close()
|
||||
})
|
||||
return err
|
||||
}
|
||||
|
||||
func (t *tapDevice) BatchSize() int {
|
||||
return 1
|
||||
}
|
||||
8
vendor/tailscale.com/net/tstun/tap_unsupported.go
generated
vendored
Normal file
8
vendor/tailscale.com/net/tstun/tap_unsupported.go
generated
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
// Copyright (c) Tailscale Inc & AUTHORS
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
//go:build !linux || ts_omit_tap
|
||||
|
||||
package tstun
|
||||
|
||||
func (*Wrapper) handleTAPFrame([]byte) bool { panic("unreachable") }
|
||||
19
vendor/tailscale.com/net/tstun/tstun_stub.go
generated
vendored
Normal file
19
vendor/tailscale.com/net/tstun/tstun_stub.go
generated
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
// Copyright (c) Tailscale Inc & AUTHORS
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
//go:build plan9 || aix
|
||||
|
||||
package tstun
|
||||
|
||||
import (
|
||||
"github.com/tailscale/wireguard-go/tun"
|
||||
"tailscale.com/types/logger"
|
||||
)
|
||||
|
||||
func New(logf logger.Logf, tunName string) (tun.Device, string, error) {
|
||||
panic("not implemented")
|
||||
}
|
||||
|
||||
func Diagnose(logf logger.Logf, tunName string, err error) {
|
||||
panic("not implemented")
|
||||
}
|
||||
84
vendor/tailscale.com/net/tstun/tun.go
generated
vendored
Normal file
84
vendor/tailscale.com/net/tstun/tun.go
generated
vendored
Normal file
@@ -0,0 +1,84 @@
|
||||
// Copyright (c) Tailscale Inc & AUTHORS
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
//go:build !wasm && !plan9 && !tamago && !aix
|
||||
|
||||
// Package tun creates a tuntap device, working around OS-specific
|
||||
// quirks if necessary.
|
||||
package tstun
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"runtime"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/tailscale/wireguard-go/tun"
|
||||
"tailscale.com/types/logger"
|
||||
)
|
||||
|
||||
// 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")
|
||||
}
|
||||
if createTAP == nil { // if the ts_omit_tap tag is used
|
||||
return nil, "", errors.New("tap is not supported in this build")
|
||||
}
|
||||
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, int(DefaultTUNMTU()))
|
||||
}
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
if err := waitInterfaceUp(dev, 90*time.Second, logf); err != nil {
|
||||
dev.Close()
|
||||
return nil, "", err
|
||||
}
|
||||
if err := setLinkAttrs(dev); err != nil {
|
||||
logf("setting link attributes: %v", 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, err error)
|
||||
|
||||
// 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.
|
||||
//
|
||||
// The tunName is the name of the tun device that was requested but failed.
|
||||
// The err error is how the tun creation failed.
|
||||
func Diagnose(logf logger.Logf, tunName string, err error) {
|
||||
if tunDiagnoseFailure != nil {
|
||||
tunDiagnoseFailure(tunName, logf, err)
|
||||
} else {
|
||||
logf("no TUN failure diagnostics for OS %q", runtime.GOOS)
|
||||
}
|
||||
}
|
||||
103
vendor/tailscale.com/net/tstun/tun_linux.go
generated
vendored
Normal file
103
vendor/tailscale.com/net/tstun/tun_linux.go
generated
vendored
Normal file
@@ -0,0 +1,103 @@
|
||||
// Copyright (c) Tailscale Inc & AUTHORS
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
package tstun
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strings"
|
||||
"syscall"
|
||||
|
||||
"tailscale.com/types/logger"
|
||||
"tailscale.com/version/distro"
|
||||
)
|
||||
|
||||
func init() {
|
||||
tunDiagnoseFailure = diagnoseLinuxTUNFailure
|
||||
}
|
||||
|
||||
func diagnoseLinuxTUNFailure(tunName string, logf logger.Logf, createErr error) {
|
||||
if errors.Is(createErr, syscall.EBUSY) {
|
||||
logf("TUN device %s is busy; another process probably still has it open (from old version of Tailscale that had a bug)", tunName)
|
||||
logf("To fix, kill the process that has it open. Find with:\n\n$ sudo lsof -n /dev/net/tun\n\n")
|
||||
logf("... and then kill those PID(s)")
|
||||
return
|
||||
}
|
||||
|
||||
var un syscall.Utsname
|
||||
err := syscall.Uname(&un)
|
||||
if err != nil {
|
||||
logf("no TUN, and failed to look up kernel version: %v", err)
|
||||
return
|
||||
}
|
||||
kernel := utsReleaseField(&un)
|
||||
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, []byte(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, []byte(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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func utsReleaseField(u *syscall.Utsname) string {
|
||||
var sb strings.Builder
|
||||
for _, v := range u.Release {
|
||||
if v == 0 {
|
||||
break
|
||||
}
|
||||
sb.WriteByte(byte(v))
|
||||
}
|
||||
return strings.TrimSpace(sb.String())
|
||||
}
|
||||
25
vendor/tailscale.com/net/tstun/tun_macos.go
generated
vendored
Normal file
25
vendor/tailscale.com/net/tstun/tun_macos.go
generated
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
// Copyright (c) Tailscale Inc & AUTHORS
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
//go:build darwin && !ios
|
||||
|
||||
package tstun
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"tailscale.com/types/logger"
|
||||
)
|
||||
|
||||
func init() {
|
||||
tunDiagnoseFailure = diagnoseDarwinTUNFailure
|
||||
}
|
||||
|
||||
func diagnoseDarwinTUNFailure(tunName string, logf logger.Logf, err error) {
|
||||
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)
|
||||
}
|
||||
}
|
||||
12
vendor/tailscale.com/net/tstun/tun_notwindows.go
generated
vendored
Normal file
12
vendor/tailscale.com/net/tstun/tun_notwindows.go
generated
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
// Copyright (c) Tailscale Inc & AUTHORS
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
//go:build !windows
|
||||
|
||||
package tstun
|
||||
|
||||
import "github.com/tailscale/wireguard-go/tun"
|
||||
|
||||
func interfaceName(dev tun.Device) (string, error) {
|
||||
return dev.Name()
|
||||
}
|
||||
27
vendor/tailscale.com/net/tstun/tun_windows.go
generated
vendored
Normal file
27
vendor/tailscale.com/net/tstun/tun_windows.go
generated
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
// Copyright (c) Tailscale Inc & AUTHORS
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
package tstun
|
||||
|
||||
import (
|
||||
"github.com/tailscale/wireguard-go/tun"
|
||||
"golang.org/x/sys/windows"
|
||||
"golang.zx2c4.com/wireguard/windows/tunnel/winipcfg"
|
||||
)
|
||||
|
||||
func init() {
|
||||
tun.WintunTunnelType = "Tailscale"
|
||||
guid, err := windows.GUIDFromString("{37217669-42da-4657-a55b-0d995d328250}")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
tun.WintunStaticRequestedGUID = &guid
|
||||
}
|
||||
|
||||
func interfaceName(dev tun.Device) (string, error) {
|
||||
guid, err := winipcfg.LUID(dev.(*tun.NativeTun).LUID()).GUID()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return guid.String(), nil
|
||||
}
|
||||
1513
vendor/tailscale.com/net/tstun/wrap.go
generated
vendored
Normal file
1513
vendor/tailscale.com/net/tstun/wrap.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
82
vendor/tailscale.com/net/tstun/wrap_linux.go
generated
vendored
Normal file
82
vendor/tailscale.com/net/tstun/wrap_linux.go
generated
vendored
Normal file
@@ -0,0 +1,82 @@
|
||||
// Copyright (c) Tailscale Inc & AUTHORS
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
package tstun
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net/netip"
|
||||
"runtime"
|
||||
|
||||
"github.com/tailscale/wireguard-go/tun"
|
||||
"golang.org/x/sys/unix"
|
||||
"gvisor.dev/gvisor/pkg/tcpip"
|
||||
"gvisor.dev/gvisor/pkg/tcpip/checksum"
|
||||
"gvisor.dev/gvisor/pkg/tcpip/header"
|
||||
"tailscale.com/envknob"
|
||||
"tailscale.com/net/tsaddr"
|
||||
)
|
||||
|
||||
// SetLinkFeaturesPostUp configures link features on t based on select TS_TUN_
|
||||
// environment variables and OS feature tests. Callers should ensure t is
|
||||
// up prior to calling, otherwise OS feature tests may be inconclusive.
|
||||
func (t *Wrapper) SetLinkFeaturesPostUp() {
|
||||
if t.isTAP || runtime.GOOS == "android" {
|
||||
return
|
||||
}
|
||||
if groDev, ok := t.tdev.(tun.GRODevice); ok {
|
||||
if envknob.Bool("TS_TUN_DISABLE_UDP_GRO") {
|
||||
groDev.DisableUDPGRO()
|
||||
}
|
||||
if envknob.Bool("TS_TUN_DISABLE_TCP_GRO") {
|
||||
groDev.DisableTCPGRO()
|
||||
}
|
||||
err := probeTCPGRO(groDev)
|
||||
if errors.Is(err, unix.EINVAL) {
|
||||
groDev.DisableTCPGRO()
|
||||
groDev.DisableUDPGRO()
|
||||
t.logf("disabled TUN TCP & UDP GRO due to GRO probe error: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func probeTCPGRO(dev tun.GRODevice) error {
|
||||
ipPort := netip.MustParseAddrPort(tsaddr.TailscaleServiceIPString + ":0")
|
||||
fingerprint := []byte("tailscale-probe-tun-gro")
|
||||
segmentSize := len(fingerprint)
|
||||
iphLen := 20
|
||||
tcphLen := 20
|
||||
totalLen := iphLen + tcphLen + segmentSize
|
||||
ipAs4 := ipPort.Addr().As4()
|
||||
bufs := make([][]byte, 2)
|
||||
for i := range bufs {
|
||||
bufs[i] = make([]byte, PacketStartOffset+totalLen, PacketStartOffset+(totalLen*2))
|
||||
ipv4H := header.IPv4(bufs[i][PacketStartOffset:])
|
||||
ipv4H.Encode(&header.IPv4Fields{
|
||||
SrcAddr: tcpip.AddrFromSlice(ipAs4[:]),
|
||||
DstAddr: tcpip.AddrFromSlice(ipAs4[:]),
|
||||
Protocol: unix.IPPROTO_TCP,
|
||||
// Use a zero value TTL as best effort means to reduce chance of
|
||||
// probe packet leaking further than it needs to.
|
||||
TTL: 0,
|
||||
TotalLength: uint16(totalLen),
|
||||
})
|
||||
tcpH := header.TCP(bufs[i][PacketStartOffset+iphLen:])
|
||||
tcpH.Encode(&header.TCPFields{
|
||||
SrcPort: ipPort.Port(),
|
||||
DstPort: ipPort.Port(),
|
||||
SeqNum: 1 + uint32(i*segmentSize),
|
||||
AckNum: 1,
|
||||
DataOffset: 20,
|
||||
Flags: header.TCPFlagAck,
|
||||
WindowSize: 3000,
|
||||
})
|
||||
copy(bufs[i][PacketStartOffset+iphLen+tcphLen:], fingerprint)
|
||||
ipv4H.SetChecksum(^ipv4H.CalculateChecksum())
|
||||
pseudoCsum := header.PseudoHeaderChecksum(unix.IPPROTO_TCP, ipv4H.SourceAddress(), ipv4H.DestinationAddress(), uint16(tcphLen+segmentSize))
|
||||
pseudoCsum = checksum.Checksum(bufs[i][PacketStartOffset+iphLen+tcphLen:], pseudoCsum)
|
||||
tcpH.SetChecksum(^tcpH.CalculateChecksum(pseudoCsum))
|
||||
}
|
||||
_, err := dev.Write(bufs, PacketStartOffset)
|
||||
return err
|
||||
}
|
||||
8
vendor/tailscale.com/net/tstun/wrap_noop.go
generated
vendored
Normal file
8
vendor/tailscale.com/net/tstun/wrap_noop.go
generated
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
// Copyright (c) Tailscale Inc & AUTHORS
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
//go:build !linux
|
||||
|
||||
package tstun
|
||||
|
||||
func (t *Wrapper) SetLinkFeaturesPostUp() {}
|
||||
Reference in New Issue
Block a user