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
57
58
59
60
61
62
63
64
65
//go:build darwin || (linux && !android)
package egress
import (
"net"
"net/netip"
"os"
"strings"
"syscall"
)
// keepRoute binds a socket to the network its destination's best route
// uses: on Linux an unbound socket would still follow the TUN's rules
// (all DNS goes into the TUN), so the route is kept by binding to it.
func keepRoute(c syscall.RawConn, v6 bool, index uint32) error {
return bind(c, v6, index)
}
// interfaceUp reports whether interface index is up and has a link.
func interfaceUp(index int) bool {
iface, err := net.InterfaceByIndex(index)
return err == nil && iface.Flags&net.FlagUp != 0 && iface.Flags&net.FlagRunning != 0
}
// resolvConf lists the nameservers of a resolv.conf file.
func resolvConf(path string) []netip.Addr {
data, err := os.ReadFile(path)
if err != nil {
return nil
}
var servers []netip.Addr
for _, line := range strings.Split(string(data), "\n") {
f := strings.Fields(line)
if len(f) >= 2 && f[0] == "nameserver" {
if a, err := netip.ParseAddr(f[1]); err == nil {
servers = append(servers, a.Unmap())
}
}
}
return servers
}
// dnsPorts makes servers DNS addresses: IPv4 first, without duplicates or
// the addresses reached through the TUN (its own DNS server) or on this
// computer.
func dnsPorts(servers []netip.Addr, st *tunState) []netip.AddrPort {
seen := map[netip.Addr]bool{}
var v4, v6 []netip.AddrPort
for _, a := range servers {
if seen[a] || !a.IsValid() || a.IsLoopback() || a.IsUnspecified() {
continue
}
seen[a] = true
if best, ok := bestInterface(a); ok && best == st.index {
continue
}
if a.Is4() {
v4 = append(v4, netip.AddrPortFrom(a, 53))
} else {
v6 = append(v6, netip.AddrPortFrom(a, 53))
}
}
return append(v4, v6...)
}