summaryrefslogtreecommitdiffhomepage
path: root/net/tsdial/peerapi_macios_ext.go
blob: fa40feef045242e82316d68468e2e60b36823a5b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
// Copyright (c) Tailscale Inc & contributors
// SPDX-License-Identifier: BSD-3-Clause

// This file's built on iOS and on two of three macOS build variants:
// the two GUI variants that both use Extensions (Network Extension
// and System Extension). It's not used on tailscaled-on-macOS.

//go:build ts_macext && (darwin || ios)

package tsdial

import (
	"errors"
	"net"
	"syscall"

	"tailscale.com/net/netns"
)

func init() {
	peerDialControlFunc = peerDialControlFuncNetworkExtension
}

func peerDialControlFuncNetworkExtension(d *Dialer) func(network, address string, c syscall.RawConn) error {
	d.mu.Lock()
	defer d.mu.Unlock()

	index := -1
	if x, ok := interfaceIndexLocked(d); ok {
		index = x
	}
	var lc net.ListenConfig
	netns.SetListenConfigInterfaceIndex(&lc, index)
	return func(network, address string, c syscall.RawConn) error {
		if index == -1 {
			return errors.New("failed to find TUN interface to bind to")
		}
		return lc.Control(network, address, c)
	}
}

func interfaceIndexLocked(d *Dialer) (index int, ok bool) {
	if d.netMon == nil {
		return 0, false
	}
	st := d.netMon.InterfaceState()
	iface, ok := st.Interface[d.tunName]
	if !ok {
		return 0, false
	}
	return iface.Index, true
}