mirror of
https://github.com/tailscale/tailscale.git
synced 2026-05-05 20:26:47 +02:00
fixes tailscale/tailscale#18418 Both Serve and PeerAPI broke when we moved the TailscaleInterfaceName into State, which is updated asynchronously and may not be available when we configure the listeners. This extracts the explicit interface name property from netmon.State and adds as a static struct with getters that have proper error handling. The bug is only found in sandboxed Darwin clients, where we need to know the Tailscale interface details in order to set up the listeners correctly (they must bind to our interface explicitly to escape the network sandboxing that is applied by NECP). Currently set only sandboxed macOS and Plan9 set this but it will also be useful on Windows to simplify interface filtering in netns. Signed-off-by: Jonathan Nobels <jonathan@tailscale.com>
104 lines
2.7 KiB
Go
104 lines
2.7 KiB
Go
// Copyright (c) Tailscale Inc & AUTHORS
|
||
// SPDX-License-Identifier: BSD-3-Clause
|
||
|
||
package netmon
|
||
|
||
import (
|
||
"errors"
|
||
"net"
|
||
|
||
"tailscale.com/syncs"
|
||
)
|
||
|
||
type ifProps struct {
|
||
mu syncs.Mutex
|
||
name string // interface name, if known/set
|
||
index int // interface index, if known/set
|
||
}
|
||
|
||
// tsIfProps tracks the properties (name and index) of the tailscale interface.
|
||
// There is only one tailscale interface per tailscaled instance.
|
||
var tsIfProps ifProps
|
||
|
||
func (p *ifProps) tsIfName() string {
|
||
p.mu.Lock()
|
||
defer p.mu.Unlock()
|
||
return p.name
|
||
}
|
||
|
||
func (p *ifProps) tsIfIndex() int {
|
||
p.mu.Lock()
|
||
defer p.mu.Unlock()
|
||
return p.index
|
||
}
|
||
|
||
func (p *ifProps) set(ifName string, ifIndex int) {
|
||
p.mu.Lock()
|
||
defer p.mu.Unlock()
|
||
p.name = ifName
|
||
p.index = ifIndex
|
||
}
|
||
|
||
// TODO (barnstar): This doesn't need the Monitor receiver anymore but we're
|
||
// keeping it for API compatibility to avoid a breaking change. This can be
|
||
// removed when the various clients have switched to SetTailscaleInterfaceProps
|
||
func (m *Monitor) SetTailscaleInterfaceName(ifName string) {
|
||
SetTailscaleInterfaceProps(ifName, 0)
|
||
}
|
||
|
||
// SetTailscaleInterfaceProps sets the name of the Tailscale interface and
|
||
// its index for use by various listeners/dialers. If the index is zero,
|
||
// an attempt will be made to look it up by name. This makes no attempt
|
||
// to validate that the interface exists at the time of calling.
|
||
//
|
||
// If this method is called, it is the responsibility of the caller to
|
||
// update the interface name and index if they change.
|
||
//
|
||
// This should be called as early as possible during tailscaled startup.
|
||
func SetTailscaleInterfaceProps(ifName string, ifIndex int) {
|
||
if ifIndex != 0 {
|
||
tsIfProps.set(ifName, ifIndex)
|
||
return
|
||
}
|
||
|
||
ifaces, err := net.Interfaces()
|
||
if err != nil {
|
||
return
|
||
}
|
||
|
||
for _, iface := range ifaces {
|
||
if iface.Name == ifName {
|
||
ifIndex = iface.Index
|
||
break
|
||
}
|
||
}
|
||
|
||
tsIfProps.set(ifName, ifIndex)
|
||
}
|
||
|
||
// TailscaleInterfaceName returns the name of the Tailscale interface.
|
||
// For example, "tailscale0", "tun0", "utun3", etc or an error if unset.
|
||
//
|
||
// Callers must handle errors, as the Tailscale interface
|
||
// name may not be set in some environments.
|
||
func TailscaleInterfaceName() (string, error) {
|
||
name := tsIfProps.tsIfName()
|
||
if name == "" {
|
||
return "", errors.New("Tailscale interface name not set")
|
||
}
|
||
return name, nil
|
||
}
|
||
|
||
// TailscaleInterfaceIndex returns the index of the Tailscale interface or
|
||
// an error if unset.
|
||
//
|
||
// Callers must handle errors, as the Tailscale interface
|
||
// index may not be set in some environments.
|
||
func TailscaleInterfaceIndex() (int, error) {
|
||
index := tsIfProps.tsIfIndex()
|
||
if index == 0 {
|
||
return 0, errors.New("Tailscale interface index not set")
|
||
}
|
||
return index, nil
|
||
}
|