@ -14,6 +14,7 @@ import (
"io"
"io"
"net"
"net"
"net/netip"
"net/netip"
"reflect"
"runtime"
"runtime"
"strconv"
"strconv"
"strings"
"strings"
@ -311,6 +312,12 @@ type Conn struct {
// lastEPERMRebind tracks the last time a rebind was performed
// lastEPERMRebind tracks the last time a rebind was performed
// after experiencing a syscall.EPERM.
// after experiencing a syscall.EPERM.
lastEPERMRebind syncs . AtomicValue [ time . Time ]
lastEPERMRebind syncs . AtomicValue [ time . Time ]
// staticEndpoints are user set endpoints that this node should
// advertise amongst its wireguard endpoints. It is user's
// responsibility to ensure that traffic from these endpoints is routed
// to the node.
staticEndpoints views . Slice [ netip . AddrPort ]
}
}
// SetDebugLoggingEnabled controls whether spammy debug logging is enabled.
// SetDebugLoggingEnabled controls whether spammy debug logging is enabled.
@ -636,6 +643,22 @@ func (c *Conn) setEndpoints(endpoints []tailcfg.Endpoint) (changed bool) {
return true
return true
}
}
// SetStaticEndpoints sets static endpoints to the provided value and triggers
// an asynchronous update of the endpoints that this node advertises.
// Static endpoints are endpoints explicitly configured by user.
func ( c * Conn ) SetStaticEndpoints ( ep views . Slice [ netip . AddrPort ] ) {
c . mu . Lock ( )
if reflect . DeepEqual ( c . staticEndpoints . AsSlice ( ) , ep . AsSlice ( ) ) {
return
}
c . staticEndpoints = ep
c . mu . Unlock ( )
// Technically this is not a reSTUNning, but ReSTUN does what we need at
// this point- calls updateEndpoints or queues an update if there is
// already an in-progress update.
c . ReSTUN ( "static-endpoint-change" )
}
// setNetInfoHavePortMap updates NetInfo.HavePortMap to true.
// setNetInfoHavePortMap updates NetInfo.HavePortMap to true.
func ( c * Conn ) setNetInfoHavePortMap ( ) {
func ( c * Conn ) setNetInfoHavePortMap ( ) {
c . mu . Lock ( )
c . mu . Lock ( )
@ -845,8 +868,10 @@ func (c *Conn) DiscoPublicKey() key.DiscoPublic {
return c . discoPublic
return c . discoPublic
}
}
// determineEndpoints returns the machine's endpoint addresses. It
// determineEndpoints returns the machine's endpoint addresses. It does a STUN
// does a STUN lookup (via netcheck) to determine its public address.
// lookup (via netcheck) to determine its public address. Additionally any
// static enpoints provided by user are always added to the returned endpoints
// without validating if the node can be reached via those endpoints.
//
//
// c.mu must NOT be held.
// c.mu must NOT be held.
func ( c * Conn ) determineEndpoints ( ctx context . Context ) ( [ ] tailcfg . Endpoint , error ) {
func ( c * Conn ) determineEndpoints ( ctx context . Context ) ( [ ] tailcfg . Endpoint , error ) {
@ -943,6 +968,10 @@ func (c *Conn) determineEndpoints(ctx context.Context) ([]tailcfg.Endpoint, erro
// re-run.
// re-run.
eps = c . endpointTracker . update ( time . Now ( ) , eps )
eps = c . endpointTracker . update ( time . Now ( ) , eps )
for i := range c . staticEndpoints . Len ( ) {
addAddr ( c . staticEndpoints . At ( i ) , tailcfg . EndpointExplicitConf )
}
if localAddr := c . pconn4 . LocalAddr ( ) ; localAddr . IP . IsUnspecified ( ) {
if localAddr := c . pconn4 . LocalAddr ( ) ; localAddr . IP . IsUnspecified ( ) {
ips , loopback , err := netmon . LocalAddresses ( )
ips , loopback , err := netmon . LocalAddresses ( )
if err != nil {
if err != nil {
@ -2359,6 +2388,8 @@ func (c *Conn) onPortMapChanged() { c.ReSTUN("portmap-changed") }
// ReSTUN triggers an address discovery.
// ReSTUN triggers an address discovery.
// The provided why string is for debug logging only.
// The provided why string is for debug logging only.
// If Conn.staticEndpoints have been updated, calling ReSTUN will also result in
// the new endpoints being advertised.
func ( c * Conn ) ReSTUN ( why string ) {
func ( c * Conn ) ReSTUN ( why string ) {
c . mu . Lock ( )
c . mu . Lock ( )
defer c . mu . Unlock ( )
defer c . mu . Unlock ( )