mirror of
https://github.com/tailscale/tailscale.git
synced 2025-04-06 00:05:54 +00:00
net/tstun: move TAP support out to separate package feature/tap
Still behind the same ts_omit_tap build tag. See #14738 for background on the pattern. Updates #12614 Change-Id: I03fb3d2bf137111e727415bd8e713d8568156ecc Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
This commit is contained in:
parent
f1710f4a42
commit
d6abbc2e61
@ -140,7 +140,7 @@ tailscale.com/cmd/k8s-operator dependencies: (generated by github.com/tailscale/
|
|||||||
github.com/gorilla/securecookie from github.com/gorilla/csrf
|
github.com/gorilla/securecookie from github.com/gorilla/csrf
|
||||||
github.com/hdevalence/ed25519consensus from tailscale.com/clientupdate/distsign+
|
github.com/hdevalence/ed25519consensus from tailscale.com/clientupdate/distsign+
|
||||||
L 💣 github.com/illarion/gonotify/v2 from tailscale.com/net/dns
|
L 💣 github.com/illarion/gonotify/v2 from tailscale.com/net/dns
|
||||||
L github.com/insomniacslk/dhcp/dhcpv4 from tailscale.com/net/tstun
|
L github.com/insomniacslk/dhcp/dhcpv4 from tailscale.com/feature/tap
|
||||||
L github.com/insomniacslk/dhcp/iana from github.com/insomniacslk/dhcp/dhcpv4
|
L github.com/insomniacslk/dhcp/iana from github.com/insomniacslk/dhcp/dhcpv4
|
||||||
L github.com/insomniacslk/dhcp/interfaces from github.com/insomniacslk/dhcp/dhcpv4
|
L github.com/insomniacslk/dhcp/interfaces from github.com/insomniacslk/dhcp/dhcpv4
|
||||||
L github.com/insomniacslk/dhcp/rfc1035label from github.com/insomniacslk/dhcp/dhcpv4
|
L github.com/insomniacslk/dhcp/rfc1035label from github.com/insomniacslk/dhcp/dhcpv4
|
||||||
@ -302,7 +302,7 @@ tailscale.com/cmd/k8s-operator dependencies: (generated by github.com/tailscale/
|
|||||||
gvisor.dev/gvisor/pkg/tcpip/network/internal/fragmentation from gvisor.dev/gvisor/pkg/tcpip/network/ipv4+
|
gvisor.dev/gvisor/pkg/tcpip/network/internal/fragmentation from gvisor.dev/gvisor/pkg/tcpip/network/ipv4+
|
||||||
gvisor.dev/gvisor/pkg/tcpip/network/internal/ip from gvisor.dev/gvisor/pkg/tcpip/network/ipv4+
|
gvisor.dev/gvisor/pkg/tcpip/network/internal/ip from gvisor.dev/gvisor/pkg/tcpip/network/ipv4+
|
||||||
gvisor.dev/gvisor/pkg/tcpip/network/internal/multicast from gvisor.dev/gvisor/pkg/tcpip/network/ipv4+
|
gvisor.dev/gvisor/pkg/tcpip/network/internal/multicast from gvisor.dev/gvisor/pkg/tcpip/network/ipv4+
|
||||||
gvisor.dev/gvisor/pkg/tcpip/network/ipv4 from tailscale.com/net/tstun+
|
gvisor.dev/gvisor/pkg/tcpip/network/ipv4 from tailscale.com/feature/tap+
|
||||||
gvisor.dev/gvisor/pkg/tcpip/network/ipv6 from tailscale.com/wgengine/netstack+
|
gvisor.dev/gvisor/pkg/tcpip/network/ipv6 from tailscale.com/wgengine/netstack+
|
||||||
gvisor.dev/gvisor/pkg/tcpip/ports from gvisor.dev/gvisor/pkg/tcpip/stack+
|
gvisor.dev/gvisor/pkg/tcpip/ports from gvisor.dev/gvisor/pkg/tcpip/stack+
|
||||||
gvisor.dev/gvisor/pkg/tcpip/seqnum from gvisor.dev/gvisor/pkg/tcpip/header+
|
gvisor.dev/gvisor/pkg/tcpip/seqnum from gvisor.dev/gvisor/pkg/tcpip/header+
|
||||||
@ -801,8 +801,9 @@ tailscale.com/cmd/k8s-operator dependencies: (generated by github.com/tailscale/
|
|||||||
tailscale.com/drive from tailscale.com/client/tailscale+
|
tailscale.com/drive from tailscale.com/client/tailscale+
|
||||||
tailscale.com/envknob from tailscale.com/client/tailscale+
|
tailscale.com/envknob from tailscale.com/client/tailscale+
|
||||||
tailscale.com/envknob/featureknob from tailscale.com/client/web+
|
tailscale.com/envknob/featureknob from tailscale.com/client/web+
|
||||||
tailscale.com/feature from tailscale.com/feature/wakeonlan
|
tailscale.com/feature from tailscale.com/feature/wakeonlan+
|
||||||
tailscale.com/feature/condregister from tailscale.com/tsnet
|
tailscale.com/feature/condregister from tailscale.com/tsnet
|
||||||
|
L tailscale.com/feature/tap from tailscale.com/feature/condregister
|
||||||
tailscale.com/feature/wakeonlan from tailscale.com/feature/condregister
|
tailscale.com/feature/wakeonlan from tailscale.com/feature/condregister
|
||||||
tailscale.com/health from tailscale.com/control/controlclient+
|
tailscale.com/health from tailscale.com/control/controlclient+
|
||||||
tailscale.com/health/healthmsg from tailscale.com/ipn/ipnlocal
|
tailscale.com/health/healthmsg from tailscale.com/ipn/ipnlocal
|
||||||
|
@ -112,7 +112,7 @@ tailscale.com/cmd/tailscaled dependencies: (generated by github.com/tailscale/de
|
|||||||
github.com/gorilla/securecookie from github.com/gorilla/csrf
|
github.com/gorilla/securecookie from github.com/gorilla/csrf
|
||||||
github.com/hdevalence/ed25519consensus from tailscale.com/clientupdate/distsign+
|
github.com/hdevalence/ed25519consensus from tailscale.com/clientupdate/distsign+
|
||||||
L 💣 github.com/illarion/gonotify/v2 from tailscale.com/net/dns
|
L 💣 github.com/illarion/gonotify/v2 from tailscale.com/net/dns
|
||||||
L github.com/insomniacslk/dhcp/dhcpv4 from tailscale.com/net/tstun
|
L github.com/insomniacslk/dhcp/dhcpv4 from tailscale.com/feature/tap
|
||||||
L github.com/insomniacslk/dhcp/iana from github.com/insomniacslk/dhcp/dhcpv4
|
L github.com/insomniacslk/dhcp/iana from github.com/insomniacslk/dhcp/dhcpv4
|
||||||
L github.com/insomniacslk/dhcp/interfaces from github.com/insomniacslk/dhcp/dhcpv4
|
L github.com/insomniacslk/dhcp/interfaces from github.com/insomniacslk/dhcp/dhcpv4
|
||||||
L github.com/insomniacslk/dhcp/rfc1035label from github.com/insomniacslk/dhcp/dhcpv4
|
L github.com/insomniacslk/dhcp/rfc1035label from github.com/insomniacslk/dhcp/dhcpv4
|
||||||
@ -214,7 +214,7 @@ tailscale.com/cmd/tailscaled dependencies: (generated by github.com/tailscale/de
|
|||||||
gvisor.dev/gvisor/pkg/tcpip/network/internal/fragmentation from gvisor.dev/gvisor/pkg/tcpip/network/ipv4+
|
gvisor.dev/gvisor/pkg/tcpip/network/internal/fragmentation from gvisor.dev/gvisor/pkg/tcpip/network/ipv4+
|
||||||
gvisor.dev/gvisor/pkg/tcpip/network/internal/ip from gvisor.dev/gvisor/pkg/tcpip/network/ipv4+
|
gvisor.dev/gvisor/pkg/tcpip/network/internal/ip from gvisor.dev/gvisor/pkg/tcpip/network/ipv4+
|
||||||
gvisor.dev/gvisor/pkg/tcpip/network/internal/multicast from gvisor.dev/gvisor/pkg/tcpip/network/ipv4+
|
gvisor.dev/gvisor/pkg/tcpip/network/internal/multicast from gvisor.dev/gvisor/pkg/tcpip/network/ipv4+
|
||||||
gvisor.dev/gvisor/pkg/tcpip/network/ipv4 from tailscale.com/net/tstun+
|
gvisor.dev/gvisor/pkg/tcpip/network/ipv4 from tailscale.com/feature/tap+
|
||||||
gvisor.dev/gvisor/pkg/tcpip/network/ipv6 from tailscale.com/wgengine/netstack+
|
gvisor.dev/gvisor/pkg/tcpip/network/ipv6 from tailscale.com/wgengine/netstack+
|
||||||
gvisor.dev/gvisor/pkg/tcpip/ports from gvisor.dev/gvisor/pkg/tcpip/stack+
|
gvisor.dev/gvisor/pkg/tcpip/ports from gvisor.dev/gvisor/pkg/tcpip/stack+
|
||||||
gvisor.dev/gvisor/pkg/tcpip/seqnum from gvisor.dev/gvisor/pkg/tcpip/header+
|
gvisor.dev/gvisor/pkg/tcpip/seqnum from gvisor.dev/gvisor/pkg/tcpip/header+
|
||||||
@ -259,8 +259,9 @@ tailscale.com/cmd/tailscaled dependencies: (generated by github.com/tailscale/de
|
|||||||
tailscale.com/drive/driveimpl/shared from tailscale.com/drive/driveimpl+
|
tailscale.com/drive/driveimpl/shared from tailscale.com/drive/driveimpl+
|
||||||
tailscale.com/envknob from tailscale.com/client/tailscale+
|
tailscale.com/envknob from tailscale.com/client/tailscale+
|
||||||
tailscale.com/envknob/featureknob from tailscale.com/client/web+
|
tailscale.com/envknob/featureknob from tailscale.com/client/web+
|
||||||
tailscale.com/feature from tailscale.com/feature/wakeonlan
|
tailscale.com/feature from tailscale.com/feature/wakeonlan+
|
||||||
tailscale.com/feature/condregister from tailscale.com/cmd/tailscaled
|
tailscale.com/feature/condregister from tailscale.com/cmd/tailscaled
|
||||||
|
L tailscale.com/feature/tap from tailscale.com/feature/condregister
|
||||||
tailscale.com/feature/wakeonlan from tailscale.com/feature/condregister
|
tailscale.com/feature/wakeonlan from tailscale.com/feature/condregister
|
||||||
tailscale.com/health from tailscale.com/control/controlclient+
|
tailscale.com/health from tailscale.com/control/controlclient+
|
||||||
tailscale.com/health/healthmsg from tailscale.com/ipn/ipnlocal
|
tailscale.com/health/healthmsg from tailscale.com/ipn/ipnlocal
|
||||||
|
8
feature/condregister/maybe_tap.go
Normal file
8
feature/condregister/maybe_tap.go
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
// Copyright (c) Tailscale Inc & AUTHORS
|
||||||
|
// SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
|
||||||
|
//go:build linux && !ts_omit_tap
|
||||||
|
|
||||||
|
package condregister
|
||||||
|
|
||||||
|
import _ "tailscale.com/feature/tap"
|
@ -4,6 +4,8 @@
|
|||||||
// Package feature tracks which features are linked into the binary.
|
// Package feature tracks which features are linked into the binary.
|
||||||
package feature
|
package feature
|
||||||
|
|
||||||
|
import "reflect"
|
||||||
|
|
||||||
var in = map[string]bool{}
|
var in = map[string]bool{}
|
||||||
|
|
||||||
// Register notes that the named feature is linked into the binary.
|
// Register notes that the named feature is linked into the binary.
|
||||||
@ -13,3 +15,40 @@ func Register(name string) {
|
|||||||
}
|
}
|
||||||
in[name] = true
|
in[name] = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Hook is a func that can only be set once.
|
||||||
|
//
|
||||||
|
// It is not safe for concurrent use.
|
||||||
|
type Hook[Func any] struct {
|
||||||
|
f Func
|
||||||
|
ok bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsSet reports whether the hook has been set.
|
||||||
|
func (h *Hook[Func]) IsSet() bool {
|
||||||
|
return h.ok
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set sets the hook function, panicking if it's already been set
|
||||||
|
// or f is the zero value.
|
||||||
|
//
|
||||||
|
// It's meant to be called in init.
|
||||||
|
func (h *Hook[Func]) Set(f Func) {
|
||||||
|
if h.ok {
|
||||||
|
panic("Set on already-set feature hook")
|
||||||
|
}
|
||||||
|
if reflect.ValueOf(f).IsZero() {
|
||||||
|
panic("Set with zero value")
|
||||||
|
}
|
||||||
|
h.f = f
|
||||||
|
h.ok = true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get returns the hook function, or panics if it hasn't been set.
|
||||||
|
// Use IsSet to check if it's been set.
|
||||||
|
func (h *Hook[Func]) Get() Func {
|
||||||
|
if !h.ok {
|
||||||
|
panic("Get on unset feature hook, without IsSet")
|
||||||
|
}
|
||||||
|
return h.f
|
||||||
|
}
|
||||||
|
@ -1,9 +1,8 @@
|
|||||||
// Copyright (c) Tailscale Inc & AUTHORS
|
// Copyright (c) Tailscale Inc & AUTHORS
|
||||||
// SPDX-License-Identifier: BSD-3-Clause
|
// SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
|
||||||
//go:build !ts_omit_tap
|
// Package tap registers Tailscale's experimental (demo) Linux TAP (Layer 2) support.
|
||||||
|
package tap
|
||||||
package tstun
|
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
@ -26,6 +25,7 @@ import (
|
|||||||
"tailscale.com/net/netaddr"
|
"tailscale.com/net/netaddr"
|
||||||
"tailscale.com/net/packet"
|
"tailscale.com/net/packet"
|
||||||
"tailscale.com/net/tsaddr"
|
"tailscale.com/net/tsaddr"
|
||||||
|
"tailscale.com/net/tstun"
|
||||||
"tailscale.com/syncs"
|
"tailscale.com/syncs"
|
||||||
"tailscale.com/types/ipproto"
|
"tailscale.com/types/ipproto"
|
||||||
"tailscale.com/types/logger"
|
"tailscale.com/types/logger"
|
||||||
@ -38,7 +38,11 @@ import (
|
|||||||
// For now just hard code it.
|
// For now just hard code it.
|
||||||
var ourMAC = net.HardwareAddr{0x30, 0x2D, 0x66, 0xEC, 0x7A, 0x93}
|
var ourMAC = net.HardwareAddr{0x30, 0x2D, 0x66, 0xEC, 0x7A, 0x93}
|
||||||
|
|
||||||
func init() { createTAP = createTAPLinux }
|
const tapDebug = tstun.TAPDebug
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
tstun.CreateTAP.Set(createTAPLinux)
|
||||||
|
}
|
||||||
|
|
||||||
func createTAPLinux(logf logger.Logf, tapName, bridgeName string) (tun.Device, error) {
|
func createTAPLinux(logf logger.Logf, tapName, bridgeName string) (tun.Device, error) {
|
||||||
fd, err := unix.Open("/dev/net/tun", unix.O_RDWR, 0)
|
fd, err := unix.Open("/dev/net/tun", unix.O_RDWR, 0)
|
||||||
@ -87,7 +91,10 @@ var (
|
|||||||
etherTypeIPv6 = etherType{0x86, 0xDD}
|
etherTypeIPv6 = etherType{0x86, 0xDD}
|
||||||
)
|
)
|
||||||
|
|
||||||
const ipv4HeaderLen = 20
|
const (
|
||||||
|
ipv4HeaderLen = 20
|
||||||
|
ethernetFrameSize = 14 // 2 six byte MACs, 2 bytes ethertype
|
||||||
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
consumePacket = true
|
consumePacket = true
|
||||||
@ -186,6 +193,11 @@ var (
|
|||||||
cgnatNetMask = net.IPMask(net.ParseIP("255.192.0.0").To4())
|
cgnatNetMask = net.IPMask(net.ParseIP("255.192.0.0").To4())
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// parsedPacketPool holds a pool of Parsed structs for use in filtering.
|
||||||
|
// This is needed because escape analysis cannot see that parsed packets
|
||||||
|
// do not escape through {Pre,Post}Filter{In,Out}.
|
||||||
|
var parsedPacketPool = sync.Pool{New: func() any { return new(packet.Parsed) }}
|
||||||
|
|
||||||
// handleDHCPRequest handles receiving a raw TAP ethernet frame and reports whether
|
// 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
|
// 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.
|
// be ignored by the caller and not passed on.
|
||||||
@ -392,7 +404,7 @@ type tapDevice struct {
|
|||||||
destMACAtomic syncs.AtomicValue[[6]byte]
|
destMACAtomic syncs.AtomicValue[[6]byte]
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ setIPer = (*tapDevice)(nil)
|
var _ tstun.SetIPer = (*tapDevice)(nil)
|
||||||
|
|
||||||
func (t *tapDevice) SetIP(ipV4, ipV6TODO netip.Addr) error {
|
func (t *tapDevice) SetIP(ipV4, ipV6TODO netip.Addr) error {
|
||||||
t.clientIPv4.Store(ipV4.String())
|
t.clientIPv4.Store(ipV4.String())
|
@ -14,11 +14,12 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/tailscale/wireguard-go/tun"
|
"github.com/tailscale/wireguard-go/tun"
|
||||||
|
"tailscale.com/feature"
|
||||||
"tailscale.com/types/logger"
|
"tailscale.com/types/logger"
|
||||||
)
|
)
|
||||||
|
|
||||||
// createTAP is non-nil on Linux.
|
// CrateTAP is the hook set by feature/tap.
|
||||||
var createTAP func(logf logger.Logf, tapName, bridgeName string) (tun.Device, error)
|
var CreateTAP feature.Hook[func(logf logger.Logf, tapName, bridgeName string) (tun.Device, error)]
|
||||||
|
|
||||||
// New returns a tun.Device for the requested device name, along with
|
// New returns a tun.Device for the requested device name, along with
|
||||||
// the OS-dependent name that was allocated to the device.
|
// the OS-dependent name that was allocated to the device.
|
||||||
@ -29,7 +30,7 @@ func New(logf logger.Logf, tunName string) (tun.Device, string, error) {
|
|||||||
if runtime.GOOS != "linux" {
|
if runtime.GOOS != "linux" {
|
||||||
return nil, "", errors.New("tap only works on Linux")
|
return nil, "", errors.New("tap only works on Linux")
|
||||||
}
|
}
|
||||||
if createTAP == nil { // if the ts_omit_tap tag is used
|
if !CreateTAP.IsSet() { // if the ts_omit_tap tag is used
|
||||||
return nil, "", errors.New("tap is not supported in this build")
|
return nil, "", errors.New("tap is not supported in this build")
|
||||||
}
|
}
|
||||||
f := strings.Split(tunName, ":")
|
f := strings.Split(tunName, ":")
|
||||||
@ -42,7 +43,7 @@ func New(logf logger.Logf, tunName string) (tun.Device, string, error) {
|
|||||||
default:
|
default:
|
||||||
return nil, "", errors.New("bogus tap argument")
|
return nil, "", errors.New("bogus tap argument")
|
||||||
}
|
}
|
||||||
dev, err = createTAP(logf, tapName, bridgeName)
|
dev, err = CreateTAP.Get()(logf, tapName, bridgeName)
|
||||||
} else {
|
} else {
|
||||||
dev, err = tun.CreateTUN(tunName, int(DefaultTUNMTU()))
|
dev, err = tun.CreateTUN(tunName, int(DefaultTUNMTU()))
|
||||||
}
|
}
|
||||||
|
@ -53,7 +53,8 @@ const PacketStartOffset = device.MessageTransportHeaderSize
|
|||||||
// of a packet that can be injected into a tstun.Wrapper.
|
// of a packet that can be injected into a tstun.Wrapper.
|
||||||
const MaxPacketSize = device.MaxContentSize
|
const MaxPacketSize = device.MaxContentSize
|
||||||
|
|
||||||
const tapDebug = false // for super verbose TAP debugging
|
// TAPDebug is whether super verbose TAP debugging is enabled.
|
||||||
|
const TAPDebug = false
|
||||||
|
|
||||||
var (
|
var (
|
||||||
// ErrClosed is returned when attempting an operation on a closed Wrapper.
|
// ErrClosed is returned when attempting an operation on a closed Wrapper.
|
||||||
@ -459,7 +460,7 @@ func (t *Wrapper) pollVector() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
n, err = reader(t.vectorBuffer[:], sizes, readOffset)
|
n, err = reader(t.vectorBuffer[:], sizes, readOffset)
|
||||||
if t.isTAP && tapDebug {
|
if t.isTAP && TAPDebug {
|
||||||
s := fmt.Sprintf("% x", t.vectorBuffer[0][:])
|
s := fmt.Sprintf("% x", t.vectorBuffer[0][:])
|
||||||
for strings.HasSuffix(s, " 00") {
|
for strings.HasSuffix(s, " 00") {
|
||||||
s = strings.TrimSuffix(s, " 00")
|
s = strings.TrimSuffix(s, " 00")
|
||||||
@ -792,7 +793,9 @@ func (pc *peerConfigTable) outboundPacketIsJailed(p *packet.Parsed) bool {
|
|||||||
return c.jailed
|
return c.jailed
|
||||||
}
|
}
|
||||||
|
|
||||||
type setIPer interface {
|
// SetIPer is the interface expected to be implemented by the TAP implementation
|
||||||
|
// of tun.Device.
|
||||||
|
type SetIPer interface {
|
||||||
// SetIP sets the IP addresses of the TAP device.
|
// SetIP sets the IP addresses of the TAP device.
|
||||||
SetIP(ipV4, ipV6 netip.Addr) error
|
SetIP(ipV4, ipV6 netip.Addr) error
|
||||||
}
|
}
|
||||||
@ -800,7 +803,7 @@ type setIPer interface {
|
|||||||
// SetWGConfig is called when a new NetworkMap is received.
|
// SetWGConfig is called when a new NetworkMap is received.
|
||||||
func (t *Wrapper) SetWGConfig(wcfg *wgcfg.Config) {
|
func (t *Wrapper) SetWGConfig(wcfg *wgcfg.Config) {
|
||||||
if t.isTAP {
|
if t.isTAP {
|
||||||
if sip, ok := t.tdev.(setIPer); ok {
|
if sip, ok := t.tdev.(SetIPer); ok {
|
||||||
sip.SetIP(findV4(wcfg.Addresses), findV6(wcfg.Addresses))
|
sip.SetIP(findV4(wcfg.Addresses), findV6(wcfg.Addresses))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user