Update dependencies

This commit is contained in:
bluepython508
2024-11-01 17:33:34 +00:00
parent 033ac0b400
commit 5cdfab398d
3596 changed files with 1033483 additions and 259 deletions

58
vendor/tailscale.com/net/tstun/fake.go generated vendored Normal file
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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

File diff suppressed because it is too large Load Diff

82
vendor/tailscale.com/net/tstun/wrap_linux.go generated vendored Normal file
View 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
View 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() {}