mirror of
https://github.com/fosrl/olm.git
synced 2026-07-17 19:39:53 +00:00
Groundwork for monitoring and updating the dns
This commit is contained in:
@@ -741,6 +741,16 @@ func (p *DNSProxy) SetJITHandler(handler func(siteId int)) {
|
||||
p.jitHandler = handler
|
||||
}
|
||||
|
||||
// SetUpstreamDNS replaces the list of upstream DNS servers used to forward
|
||||
// queries that are not served by local records. The servers must be in
|
||||
// "host:port" format (e.g. "8.8.8.8:53").
|
||||
func (p *DNSProxy) SetUpstreamDNS(servers []string) {
|
||||
if len(servers) == 0 {
|
||||
return
|
||||
}
|
||||
p.upstreamDNS = servers
|
||||
}
|
||||
|
||||
// AddDNSRecord adds a DNS record to the local store
|
||||
// domain should be a domain name (e.g., "example.com" or "example.com.")
|
||||
// ip should be a valid IPv4 or IPv6 address
|
||||
|
||||
177
dns/sysresolver.go
Normal file
177
dns/sysresolver.go
Normal file
@@ -0,0 +1,177 @@
|
||||
package dns
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net"
|
||||
"net/netip"
|
||||
"sort"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/fosrl/newt/logger"
|
||||
)
|
||||
|
||||
const defaultPollInterval = 30 * time.Second
|
||||
|
||||
// SystemDNSMonitor monitors the host system's DNS configuration and notifies
|
||||
// callers when it changes. The reported servers are in "host:port" format
|
||||
// (e.g. "8.8.8.8:53") and can be used directly as UpstreamDNS and PublicDNS.
|
||||
//
|
||||
// Platform behaviour:
|
||||
// - Linux: reads /run/systemd/resolve/resolv.conf when present (updated by
|
||||
// systemd-resolved on every DHCP change), then falls back to
|
||||
// /etc/resolv.conf.olm.backup (written before olm overrides DNS), and
|
||||
// finally /etc/resolv.conf.
|
||||
// - macOS: reads /etc/resolv.conf, which is never modified by olm's
|
||||
// supplemental scutil DNS override.
|
||||
// - Windows: enumerates DHCP-assigned DNS servers from every network adapter
|
||||
// in the registry.
|
||||
// - Other platforms: returns an empty list (no-op monitor).
|
||||
type SystemDNSMonitor struct {
|
||||
mu sync.RWMutex
|
||||
current []string
|
||||
onChange func(servers []string)
|
||||
interval time.Duration
|
||||
stopCh chan struct{}
|
||||
excludeMu sync.RWMutex
|
||||
excludeIPs map[netip.Addr]bool
|
||||
}
|
||||
|
||||
// NewSystemDNSMonitor creates a new monitor. onChange is called with the new
|
||||
// server list whenever a change is detected; it is also called once from Start
|
||||
// with the initial values. A zero interval uses the 30-second default.
|
||||
func NewSystemDNSMonitor(interval time.Duration, onChange func(servers []string)) *SystemDNSMonitor {
|
||||
if interval <= 0 {
|
||||
interval = defaultPollInterval
|
||||
}
|
||||
return &SystemDNSMonitor{
|
||||
interval: interval,
|
||||
onChange: onChange,
|
||||
stopCh: make(chan struct{}),
|
||||
excludeIPs: make(map[netip.Addr]bool),
|
||||
}
|
||||
}
|
||||
|
||||
// SetExcludeIP registers an IP address that must never appear in the reported
|
||||
// DNS server list. Call this after olm's DNS proxy is created to prevent the
|
||||
// proxy's own IP from being returned as an upstream server when the OS DNS has
|
||||
// been overridden to point at the proxy.
|
||||
func (m *SystemDNSMonitor) SetExcludeIP(ip netip.Addr) {
|
||||
m.excludeMu.Lock()
|
||||
m.excludeIPs[ip.Unmap()] = true
|
||||
m.excludeMu.Unlock()
|
||||
}
|
||||
|
||||
// Start reads the current system DNS immediately, fires onChange, then polls
|
||||
// in the background until Stop is called or ctx is cancelled.
|
||||
func (m *SystemDNSMonitor) Start(ctx context.Context) {
|
||||
servers := m.readFiltered()
|
||||
m.mu.Lock()
|
||||
m.current = servers
|
||||
m.mu.Unlock()
|
||||
|
||||
if m.onChange != nil && len(servers) > 0 {
|
||||
m.onChange(servers)
|
||||
}
|
||||
|
||||
go m.run(ctx)
|
||||
}
|
||||
|
||||
// Stop halts the background polling goroutine.
|
||||
func (m *SystemDNSMonitor) Stop() {
|
||||
select {
|
||||
case <-m.stopCh:
|
||||
default:
|
||||
close(m.stopCh)
|
||||
}
|
||||
}
|
||||
|
||||
// Current returns the most recently observed system DNS servers.
|
||||
func (m *SystemDNSMonitor) Current() []string {
|
||||
m.mu.RLock()
|
||||
defer m.mu.RUnlock()
|
||||
out := make([]string, len(m.current))
|
||||
copy(out, m.current)
|
||||
return out
|
||||
}
|
||||
|
||||
// readFiltered calls the platform-specific readSystemDNS and removes any
|
||||
// addresses that have been excluded via SetExcludeIP. If all addresses are
|
||||
// excluded the function returns nil so the caller can retain the last
|
||||
// known-good value.
|
||||
func (m *SystemDNSMonitor) readFiltered() []string {
|
||||
raw := readSystemDNS()
|
||||
|
||||
m.excludeMu.RLock()
|
||||
excludeIPs := m.excludeIPs
|
||||
m.excludeMu.RUnlock()
|
||||
|
||||
if len(excludeIPs) == 0 {
|
||||
return raw
|
||||
}
|
||||
|
||||
var filtered []string
|
||||
for _, s := range raw {
|
||||
host, _, err := net.SplitHostPort(s)
|
||||
if err != nil {
|
||||
filtered = append(filtered, s)
|
||||
continue
|
||||
}
|
||||
addr, err := netip.ParseAddr(host)
|
||||
if err != nil || excludeIPs[addr.Unmap()] {
|
||||
continue
|
||||
}
|
||||
filtered = append(filtered, s)
|
||||
}
|
||||
return filtered
|
||||
}
|
||||
|
||||
func (m *SystemDNSMonitor) run(ctx context.Context) {
|
||||
ticker := time.NewTicker(m.interval)
|
||||
defer ticker.Stop()
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return
|
||||
case <-m.stopCh:
|
||||
return
|
||||
case <-ticker.C:
|
||||
servers := m.readFiltered()
|
||||
if len(servers) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
m.mu.Lock()
|
||||
changed := !dnsSlicesEqual(m.current, servers)
|
||||
if changed {
|
||||
m.current = servers
|
||||
}
|
||||
m.mu.Unlock()
|
||||
|
||||
if changed && m.onChange != nil {
|
||||
logger.Info("System DNS changed: %v", servers)
|
||||
m.onChange(servers)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// dnsSlicesEqual reports whether two server lists are equal regardless of order.
|
||||
func dnsSlicesEqual(a, b []string) bool {
|
||||
if len(a) != len(b) {
|
||||
return false
|
||||
}
|
||||
ac := make([]string, len(a))
|
||||
bc := make([]string, len(b))
|
||||
copy(ac, a)
|
||||
copy(bc, b)
|
||||
sort.Strings(ac)
|
||||
sort.Strings(bc)
|
||||
for i := range ac {
|
||||
if ac[i] != bc[i] {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
58
dns/sysresolver_darwin.go
Normal file
58
dns/sysresolver_darwin.go
Normal file
@@ -0,0 +1,58 @@
|
||||
//go:build darwin && !ios
|
||||
|
||||
package dns
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"net"
|
||||
"net/netip"
|
||||
"os"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// readSystemDNS returns the current system DNS servers in "host:53" format.
|
||||
//
|
||||
// On macOS, olm adds supplemental DNS entries via scutil without modifying
|
||||
// /etc/resolv.conf or the primary network service DNS. Reading /etc/resolv.conf
|
||||
// therefore always yields the physical-network DNS supplied by DHCP or the user.
|
||||
// /etc/resolv.conf on macOS is a regular file managed by mDNSResponder and is
|
||||
// updated whenever the network configuration changes.
|
||||
func readSystemDNS() []string {
|
||||
return parseMacResolvConf("/etc/resolv.conf")
|
||||
}
|
||||
|
||||
func parseMacResolvConf(path string) []string {
|
||||
f, err := os.Open(path)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
var result []string
|
||||
seen := make(map[string]bool)
|
||||
|
||||
scanner := bufio.NewScanner(f)
|
||||
for scanner.Scan() {
|
||||
line := strings.TrimSpace(scanner.Text())
|
||||
if !strings.HasPrefix(line, "nameserver") {
|
||||
continue
|
||||
}
|
||||
fields := strings.Fields(line)
|
||||
if len(fields) < 2 {
|
||||
continue
|
||||
}
|
||||
addr, err := netip.ParseAddr(fields[1])
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
if addr.IsLoopback() || addr.IsLinkLocalUnicast() {
|
||||
continue
|
||||
}
|
||||
s := net.JoinHostPort(addr.String(), "53")
|
||||
if !seen[s] {
|
||||
seen[s] = true
|
||||
result = append(result, s)
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
84
dns/sysresolver_linux.go
Normal file
84
dns/sysresolver_linux.go
Normal file
@@ -0,0 +1,84 @@
|
||||
//go:build linux && !android
|
||||
|
||||
package dns
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"net"
|
||||
"net/netip"
|
||||
"os"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// readSystemDNS returns the current system DNS servers in "host:53" format.
|
||||
//
|
||||
// Resolution order:
|
||||
// 1. /run/systemd/resolve/resolv.conf — maintained by systemd-resolved with
|
||||
// the real per-link DNS servers; updated on every DHCP change and never
|
||||
// touched by olm's D-Bus DNS override.
|
||||
// 2. /etc/resolv.conf.olm.backup — written by olm before it overrides
|
||||
// /etc/resolv.conf on non-systemd systems.
|
||||
// 3. /etc/resolv.conf — plain fallback.
|
||||
//
|
||||
// Loopback and link-local addresses (e.g. 127.0.0.53, ::1) are excluded
|
||||
// because they are stub resolver addresses, not real upstream servers.
|
||||
func readSystemDNS() []string {
|
||||
// Prefer systemd-resolved's resolved (non-stub) resolv.conf.
|
||||
if servers := parseResolvConf("/run/systemd/resolve/resolv.conf"); len(servers) > 0 {
|
||||
return servers
|
||||
}
|
||||
|
||||
// If olm has already overridden /etc/resolv.conf the backup holds the
|
||||
// original pre-override DNS servers.
|
||||
if _, err := os.Stat("/etc/resolv.conf.olm.backup"); err == nil {
|
||||
if servers := parseResolvConf("/etc/resolv.conf.olm.backup"); len(servers) > 0 {
|
||||
return servers
|
||||
}
|
||||
}
|
||||
|
||||
return parseResolvConf("/etc/resolv.conf")
|
||||
}
|
||||
|
||||
// parseResolvConf reads nameserver lines from a resolv.conf-style file,
|
||||
// skipping loopback and link-local addresses.
|
||||
func parseResolvConf(path string) []string {
|
||||
f, err := os.Open(path)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
var result []string
|
||||
seen := make(map[string]bool)
|
||||
|
||||
scanner := bufio.NewScanner(f)
|
||||
for scanner.Scan() {
|
||||
line := strings.TrimSpace(scanner.Text())
|
||||
if !strings.HasPrefix(line, "nameserver") {
|
||||
continue
|
||||
}
|
||||
fields := strings.Fields(line)
|
||||
if len(fields) < 2 {
|
||||
continue
|
||||
}
|
||||
addr, err := netip.ParseAddr(fields[1])
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
if addr.IsLoopback() || addr.IsLinkLocalUnicast() {
|
||||
continue
|
||||
}
|
||||
s := addrToHostPort(addr)
|
||||
if !seen[s] {
|
||||
seen[s] = true
|
||||
result = append(result, s)
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// addrToHostPort converts a netip.Addr to "addr:53" format, wrapping IPv6
|
||||
// addresses in brackets as required by net.JoinHostPort.
|
||||
func addrToHostPort(addr netip.Addr) string {
|
||||
return net.JoinHostPort(addr.String(), "53")
|
||||
}
|
||||
10
dns/sysresolver_stub.go
Normal file
10
dns/sysresolver_stub.go
Normal file
@@ -0,0 +1,10 @@
|
||||
//go:build !linux && !darwin && !windows
|
||||
|
||||
package dns
|
||||
|
||||
// readSystemDNS returns nil on platforms where automatic DNS discovery is not
|
||||
// implemented (android, ios, freebsd, etc.). Callers should fall back to a
|
||||
// statically configured DNS server.
|
||||
func readSystemDNS() []string {
|
||||
return nil
|
||||
}
|
||||
103
dns/sysresolver_windows.go
Normal file
103
dns/sysresolver_windows.go
Normal file
@@ -0,0 +1,103 @@
|
||||
//go:build windows
|
||||
|
||||
package dns
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"net/netip"
|
||||
|
||||
"golang.org/x/sys/windows/registry"
|
||||
)
|
||||
|
||||
const (
|
||||
tcpipInterfacesPath = `SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\Interfaces`
|
||||
dhcpNameServerKey = "DhcpNameServer"
|
||||
staticNameServerKey = "NameServer"
|
||||
)
|
||||
|
||||
// readSystemDNS returns the current system DNS servers in "host:53" format by
|
||||
// enumerating every network adapter in the Windows registry.
|
||||
//
|
||||
// For each adapter olm reads the DHCP-assigned DNS servers (DhcpNameServer).
|
||||
// Static DNS (NameServer) is ignored on the assumption that it belongs to the
|
||||
// olm WireGuard adapter or another VPN; DHCP-assigned servers always reflect
|
||||
// the physical network's DNS. Loopback and link-local addresses are excluded.
|
||||
func readSystemDNS() []string {
|
||||
key, err := registry.OpenKey(registry.LOCAL_MACHINE, tcpipInterfacesPath, registry.ENUMERATE_SUB_KEYS)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
defer key.Close()
|
||||
|
||||
subkeys, err := key.ReadSubKeyNames(-1)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
seen := make(map[string]bool)
|
||||
var result []string
|
||||
|
||||
for _, guid := range subkeys {
|
||||
path := fmt.Sprintf(`%s\%s`, tcpipInterfacesPath, guid)
|
||||
iKey, err := registry.OpenKey(registry.LOCAL_MACHINE, path, registry.QUERY_VALUE)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
dhcp, _, err := iKey.GetStringValue(dhcpNameServerKey)
|
||||
iKey.Close()
|
||||
if err != nil || dhcp == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
for _, s := range splitWinDNSList(dhcp) {
|
||||
addr, err := netip.ParseAddr(s)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
if addr.IsLoopback() || addr.IsLinkLocalUnicast() {
|
||||
continue
|
||||
}
|
||||
hp := net.JoinHostPort(addr.String(), "53")
|
||||
if !seen[hp] {
|
||||
seen[hp] = true
|
||||
result = append(result, hp)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// splitWinDNSList splits a Windows DNS server list that may be comma- or
|
||||
// space-separated.
|
||||
func splitWinDNSList(s string) []string {
|
||||
var out []string
|
||||
for _, part := range splitByRunes(s, []rune{',', ' '}) {
|
||||
if part != "" {
|
||||
out = append(out, part)
|
||||
}
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func splitByRunes(s string, delims []rune) []string {
|
||||
var result []string
|
||||
start := 0
|
||||
for i, r := range s {
|
||||
for _, d := range delims {
|
||||
if r == d {
|
||||
if i > start {
|
||||
result = append(result, s[start:i])
|
||||
}
|
||||
start = i + len(string(r))
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
if start < len(s) {
|
||||
result = append(result, s[start:])
|
||||
}
|
||||
return result
|
||||
}
|
||||
2
go.mod
2
go.mod
@@ -32,4 +32,4 @@ require (
|
||||
)
|
||||
|
||||
// To be used ONLY for local development
|
||||
// replace github.com/fosrl/newt => ../newt
|
||||
replace github.com/fosrl/newt => ../newt
|
||||
|
||||
@@ -150,6 +150,14 @@ func (o *Olm) handleConnect(msg websocket.WSMessage) {
|
||||
logger.Error("Failed to create DNS proxy: %v", err)
|
||||
}
|
||||
|
||||
// Tell the system DNS monitor to exclude the proxy IP so that subsequent
|
||||
// polls never mistake the proxy for a real upstream server (on Linux the OS
|
||||
// DNS is overridden to point at this IP, which would otherwise feed back
|
||||
// into UpstreamDNS or PublicDNS on the next poll).
|
||||
if o.dnsMonitor != nil && o.dnsProxy != nil {
|
||||
o.dnsMonitor.SetExcludeIP(o.dnsProxy.GetProxyIP())
|
||||
}
|
||||
|
||||
if err = network.ConfigureInterface(o.tunnelConfig.InterfaceName, wgData.TunnelIP, o.tunnelConfig.MTU); err != nil {
|
||||
logger.Error("Failed to o.tunnelConfigure interface: %v", err)
|
||||
}
|
||||
|
||||
62
olm/olm.go
62
olm/olm.go
@@ -44,6 +44,7 @@ type Olm struct {
|
||||
sharedBind *bind.SharedBind
|
||||
|
||||
dnsProxy *dns.DNSProxy
|
||||
dnsMonitor *dns.SystemDNSMonitor
|
||||
apiServer *api.API
|
||||
websocket *websocket.Client
|
||||
holePunchManager *holepunch.Manager
|
||||
@@ -392,11 +393,55 @@ func (o *Olm) StartTunnel(config TunnelConfig) {
|
||||
o.tunnelRunning = true // Also set it here in case it is called externally
|
||||
o.tunnelConfig = config
|
||||
|
||||
// TODO: we are hardcoding this for now but we should really pull it from the current config of the system
|
||||
if o.tunnelConfig.DNS != "" {
|
||||
o.tunnelConfig.PublicDNS = []string{o.tunnelConfig.DNS + ":53"}
|
||||
} else {
|
||||
o.tunnelConfig.PublicDNS = []string{"8.8.8.8:53"}
|
||||
// Determine whether the system DNS monitor should also manage UpstreamDNS.
|
||||
// If the caller did not provide an explicit UpstreamDNS (it was defaulted to
|
||||
// 8.8.8.8:53 by the API handler), we want the monitor to keep it updated
|
||||
// with whatever DNS the host network is currently using.
|
||||
upstreamFromConfig := len(config.UpstreamDNS) > 0 &&
|
||||
!(len(config.UpstreamDNS) == 1 && config.UpstreamDNS[0] == "8.8.8.8:53")
|
||||
|
||||
// Start the system DNS monitor. The callback fires synchronously once with
|
||||
// the initial values so that PublicDNS (and optionally UpstreamDNS) are
|
||||
// populated before the tunnel goroutine proceeds.
|
||||
o.dnsMonitor = dns.NewSystemDNSMonitor(0, func(servers []string) {
|
||||
if len(servers) == 0 {
|
||||
return
|
||||
}
|
||||
logger.Info("Applying system DNS: %v", servers)
|
||||
|
||||
// PublicDNS must always reflect the physical-network DNS so that
|
||||
// WireGuard endpoint hostnames and hole-punch targets can be resolved
|
||||
// even after the system resolver has been overridden by olm.
|
||||
o.tunnelConfig.PublicDNS = servers
|
||||
if o.holePunchManager != nil {
|
||||
o.holePunchManager.SetPublicDNS(servers)
|
||||
}
|
||||
if pm := o.getPeerManager(); pm != nil {
|
||||
pm.SetPublicDNS(servers)
|
||||
}
|
||||
|
||||
// UpstreamDNS is updated only when the caller did not supply an
|
||||
// explicit value; dynamic updates keep the proxy forwarding to the
|
||||
// network's real resolver as the host moves between networks.
|
||||
if !upstreamFromConfig {
|
||||
o.tunnelConfig.UpstreamDNS = servers
|
||||
if o.dnsProxy != nil {
|
||||
o.dnsProxy.SetUpstreamDNS(servers)
|
||||
}
|
||||
}
|
||||
})
|
||||
o.dnsMonitor.Start(o.olmCtx)
|
||||
|
||||
// Fall back to hardcoded DNS if the system monitor could not detect any.
|
||||
if len(o.tunnelConfig.PublicDNS) == 0 {
|
||||
if o.tunnelConfig.DNS != "" {
|
||||
o.tunnelConfig.PublicDNS = []string{o.tunnelConfig.DNS + ":53"}
|
||||
} else {
|
||||
o.tunnelConfig.PublicDNS = []string{"8.8.8.8:53"}
|
||||
}
|
||||
}
|
||||
if len(o.tunnelConfig.UpstreamDNS) == 0 {
|
||||
o.tunnelConfig.UpstreamDNS = []string{"8.8.8.8:53"}
|
||||
}
|
||||
|
||||
// Reset terminated status when tunnel starts
|
||||
@@ -659,6 +704,13 @@ func (o *Olm) Close() {
|
||||
o.holePunchManager = nil
|
||||
}
|
||||
|
||||
// Stop the system DNS monitor after hole punch is stopped (it feeds
|
||||
// publicDNS into the hole punch manager).
|
||||
if o.dnsMonitor != nil {
|
||||
o.dnsMonitor.Stop()
|
||||
o.dnsMonitor = nil
|
||||
}
|
||||
|
||||
// Close() also calls Stop() internally
|
||||
o.peerManagerMu.Lock()
|
||||
if o.peerManager != nil {
|
||||
|
||||
@@ -103,6 +103,21 @@ func (pm *PeerManager) GetPeerMonitor() *monitor.PeerMonitor {
|
||||
return pm.peerMonitor
|
||||
}
|
||||
|
||||
// SetPublicDNS replaces the DNS servers used to resolve WireGuard peer
|
||||
// endpoints and hole-punch targets. The servers must be in "host:port" format
|
||||
// (e.g. "8.8.8.8:53"). The change takes effect for all future peer
|
||||
// configuration calls; existing WireGuard peers are not re-resolved.
|
||||
func (pm *PeerManager) SetPublicDNS(servers []string) {
|
||||
pm.mu.Lock()
|
||||
pm.publicDNS = servers
|
||||
mon := pm.peerMonitor
|
||||
pm.mu.Unlock()
|
||||
|
||||
if mon != nil {
|
||||
mon.SetPublicDNS(servers)
|
||||
}
|
||||
}
|
||||
|
||||
func (pm *PeerManager) GetAllPeers() []SiteConfig {
|
||||
pm.mu.RLock()
|
||||
defer pm.mu.RUnlock()
|
||||
|
||||
@@ -36,7 +36,7 @@ type PeerMonitor struct {
|
||||
timeout time.Duration
|
||||
maxAttempts int
|
||||
wsClient *websocket.Client
|
||||
publicDNS []string
|
||||
publicDNS []string
|
||||
|
||||
// Relay sender tracking
|
||||
relaySends map[string]func()
|
||||
@@ -85,8 +85,8 @@ type PeerMonitor struct {
|
||||
apiServer *api.API
|
||||
|
||||
// WG connection status tracking
|
||||
wgConnectionStatus map[int]bool // siteID -> WG connected status
|
||||
wgConnectionRTT map[int]time.Duration // siteID -> last known RTT
|
||||
wgConnectionStatus map[int]bool // siteID -> WG connected status
|
||||
wgConnectionRTT map[int]time.Duration // siteID -> last known RTT
|
||||
statusChangeCallback func(siteId int) // called when any peer's connection status changes
|
||||
}
|
||||
|
||||
@@ -106,7 +106,7 @@ func NewPeerMonitor(wsClient *websocket.Client, middleDev *middleDevice.MiddleDe
|
||||
wsClient: wsClient,
|
||||
middleDev: middleDev,
|
||||
localIP: localIP,
|
||||
publicDNS: publicDNS,
|
||||
publicDNS: publicDNS,
|
||||
activePorts: make(map[uint16]bool),
|
||||
nsCtx: ctx,
|
||||
nsCancel: cancel,
|
||||
@@ -148,6 +148,19 @@ func NewPeerMonitor(wsClient *websocket.Client, middleDev *middleDevice.MiddleDe
|
||||
return pm
|
||||
}
|
||||
|
||||
// SetPublicDNS replaces the DNS servers used to resolve peer endpoints and
|
||||
// hole-punch exit nodes. The servers must be in "host:port" format.
|
||||
func (pm *PeerMonitor) SetPublicDNS(servers []string) {
|
||||
pm.mutex.Lock()
|
||||
pm.publicDNS = servers
|
||||
tester := pm.holepunchTester
|
||||
pm.mutex.Unlock()
|
||||
|
||||
if tester != nil {
|
||||
tester.SetPublicDNS(servers)
|
||||
}
|
||||
}
|
||||
|
||||
// SetInterval changes how frequently peers are checked
|
||||
func (pm *PeerMonitor) SetPeerInterval(minInterval, maxInterval time.Duration) {
|
||||
pm.mutex.Lock()
|
||||
|
||||
Reference in New Issue
Block a user