summaryrefslogtreecommitdiffhomepage
path: root/ipn/ipnlocal/peerapi_macios_ext.go
blob: 497bebe71a7bf6f8628bd5312c5a32323b8e1143 (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
53
54
55
56
// Copyright (c) 2021 Tailscale Inc & AUTHORS All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

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

package ipnlocal

import (
	"errors"
	"fmt"
	"net"
	"syscall"

	"inet.af/netaddr"
	"tailscale.com/net/interfaces"
	"tailscale.com/net/netns"
)

func init() {
	initListenConfig = initListenConfigNetworkExtension
	peerDialControlFunc = peerDialControlFuncNetworkExtension
}

// initListenConfigNetworkExtension configures nc for listening on IP
// through the iOS/macOS Network/System Extension (Packet Tunnel
// Provider) sandbox.
func initListenConfigNetworkExtension(nc *net.ListenConfig, ip netaddr.IP, st *interfaces.State, tunIfName string) error {
	tunIf, ok := st.Interface[tunIfName]
	if !ok {
		return fmt.Errorf("no interface with name %q", tunIfName)
	}
	return netns.SetListenConfigInterfaceIndex(nc, tunIf.Index)
}

func peerDialControlFuncNetworkExtension(b *LocalBackend) func(network, address string, c syscall.RawConn) error {
	b.mu.Lock()
	defer b.mu.Unlock()
	st := b.prevIfState
	pas := b.peerAPIServer
	index := -1
	if st != nil && pas != nil && pas.tunName != "" {
		if tunIf, ok := st.Interface[pas.tunName]; ok {
			index = tunIf.Index
		}
	}
	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)
	}
}