mirror of
https://github.com/tailscale/tailscale.git
synced 2025-07-29 15:23:45 +00:00
ipn/ipnlocal: add peerapi endpoint for relay server endpoint allocation
Relay server initialization is performed as part of handling peerapi endpoint allocation requests in similar fashion to SSH server init. The relay server is not supported on iOS for now. Updates tailscale/corp#27502 Signed-off-by: Jordan Whited <jordan@tailscale.com>
This commit is contained in:
parent
9ff9c5af04
commit
559e548e8b
@ -883,6 +883,7 @@ tailscale.com/cmd/k8s-operator dependencies: (generated by github.com/tailscale/
|
||||
tailscale.com/net/tsdial from tailscale.com/control/controlclient+
|
||||
💣 tailscale.com/net/tshttpproxy from tailscale.com/clientupdate/distsign+
|
||||
tailscale.com/net/tstun from tailscale.com/tsd+
|
||||
tailscale.com/net/udprelay from tailscale.com/ipn/ipnlocal
|
||||
tailscale.com/omit from tailscale.com/ipn/conffile
|
||||
tailscale.com/paths from tailscale.com/client/local+
|
||||
💣 tailscale.com/portlist from tailscale.com/ipn/ipnlocal
|
||||
|
@ -333,6 +333,7 @@ tailscale.com/cmd/tailscaled dependencies: (generated by github.com/tailscale/de
|
||||
tailscale.com/net/tsdial from tailscale.com/cmd/tailscaled+
|
||||
💣 tailscale.com/net/tshttpproxy from tailscale.com/clientupdate/distsign+
|
||||
tailscale.com/net/tstun from tailscale.com/cmd/tailscaled+
|
||||
tailscale.com/net/udprelay from tailscale.com/ipn/ipnlocal
|
||||
tailscale.com/omit from tailscale.com/ipn/conffile
|
||||
tailscale.com/paths from tailscale.com/client/local+
|
||||
💣 tailscale.com/portlist from tailscale.com/ipn/ipnlocal
|
||||
|
@ -76,6 +76,7 @@ import (
|
||||
"tailscale.com/net/packet"
|
||||
"tailscale.com/net/tsaddr"
|
||||
"tailscale.com/net/tsdial"
|
||||
"tailscale.com/net/udprelay"
|
||||
"tailscale.com/paths"
|
||||
"tailscale.com/portlist"
|
||||
"tailscale.com/posture"
|
||||
@ -378,6 +379,7 @@ type LocalBackend struct {
|
||||
// c2nUpdateStatus is the status of c2n-triggered client update.
|
||||
c2nUpdateStatus updateStatus
|
||||
currentUser ipnauth.Actor
|
||||
relayServer relayServer // or nil, initialized lazily
|
||||
|
||||
// backgroundProfileResolvers are optional background profile resolvers.
|
||||
backgroundProfileResolvers set.HandleSet[profileResolver]
|
||||
@ -1135,6 +1137,10 @@ func (b *LocalBackend) Shutdown() {
|
||||
b.sshServer.Shutdown()
|
||||
b.sshServer = nil
|
||||
}
|
||||
if b.relayServer != nil {
|
||||
b.relayServer.Close()
|
||||
b.relayServer = nil
|
||||
}
|
||||
b.closePeerAPIListenersLocked()
|
||||
if b.debugSink != nil {
|
||||
b.e.InstallCaptureHook(nil)
|
||||
@ -4609,6 +4615,17 @@ func (b *LocalBackend) setPrefsLockedOnEntry(newp *ipn.Prefs, unlock unlockOnce)
|
||||
b.sshServer = nil
|
||||
}
|
||||
}
|
||||
|
||||
if oldp.RelayServerPort().Valid() && (newp.RelayServerPort == nil ||
|
||||
oldp.RelayServerPort().Get() != *newp.RelayServerPort) {
|
||||
if b.relayServer != nil {
|
||||
b.goTracker.Go(func() {
|
||||
b.relayServer.Close()
|
||||
})
|
||||
b.relayServer = nil
|
||||
}
|
||||
}
|
||||
|
||||
if netMap != nil {
|
||||
newProfile := profileFromView(netMap.UserProfiles[netMap.User()])
|
||||
if newLoginName := newProfile.LoginName; newLoginName != "" {
|
||||
@ -6060,6 +6077,40 @@ func (b *LocalBackend) resetAuthURLLocked() {
|
||||
b.authActor = nil
|
||||
}
|
||||
|
||||
// relayServer is the interface of the conditionally linked net/udprelay.Server.
|
||||
type relayServer interface {
|
||||
// AllocateEndpoint allocates a udprelay.ServerEndpoint for the provided
|
||||
// pair of key.DiscoPublic's. It returns an error (udprelay.ErrServerClosed)
|
||||
// if the server has been closed.
|
||||
AllocateEndpoint(discoA, discoB key.DiscoPublic) (udprelay.ServerEndpoint, error)
|
||||
|
||||
Close() error
|
||||
}
|
||||
|
||||
type newRelayServerFunc func(port int, addrs []netip.Addr) (relayServer, int, error)
|
||||
|
||||
var newRelayServer newRelayServerFunc // or nil
|
||||
|
||||
func registerNewRelayServer(fn newRelayServerFunc) {
|
||||
newRelayServer = fn
|
||||
}
|
||||
|
||||
func (b *LocalBackend) relayServerOrInit() (_ relayServer, err error) {
|
||||
b.mu.Lock()
|
||||
defer b.mu.Unlock()
|
||||
if b.relayServer != nil {
|
||||
return b.relayServer, nil
|
||||
}
|
||||
if newRelayServer == nil {
|
||||
return nil, errors.New("no relay server support")
|
||||
}
|
||||
b.relayServer, _, err = newRelayServer(b.Prefs().RelayServerPort().Get(), []netip.Addr{netip.MustParseAddr("127.0.0.1")})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("newRelayServer: %w", err)
|
||||
}
|
||||
return b.relayServer, nil
|
||||
}
|
||||
|
||||
func (b *LocalBackend) ShouldRunSSH() bool { return b.sshAtomicBool.Load() && envknob.CanSSHD() }
|
||||
|
||||
// ShouldRunWebClient reports whether the web client is being run
|
||||
|
@ -38,6 +38,7 @@ import (
|
||||
"tailscale.com/net/sockstats"
|
||||
"tailscale.com/tailcfg"
|
||||
"tailscale.com/taildrop"
|
||||
"tailscale.com/types/key"
|
||||
"tailscale.com/types/views"
|
||||
"tailscale.com/util/clientmetric"
|
||||
"tailscale.com/util/httphdr"
|
||||
@ -388,6 +389,9 @@ func (h *peerAPIHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
metricIngressCalls.Add(1)
|
||||
h.handleServeIngress(w, r)
|
||||
return
|
||||
case "/v0/relay/endpoint":
|
||||
h.handleServeRelayAllocateEndpoint(w, r)
|
||||
return
|
||||
}
|
||||
if ph, ok := peerAPIHandlers[r.URL.Path]; ok {
|
||||
ph(h, w, r)
|
||||
@ -1194,6 +1198,55 @@ func parseDriveFileExtensionForLog(path string) string {
|
||||
return fileExt
|
||||
}
|
||||
|
||||
func (h *peerAPIHandler) handleServeRelayAllocateEndpoint(w http.ResponseWriter, r *http.Request) {
|
||||
logAndError := func(code int, publicMsg string) {
|
||||
h.logf("relay: error (status=%d) handling request from %v: %s", code, h.remoteAddr, publicMsg)
|
||||
http.Error(w, publicMsg, code)
|
||||
}
|
||||
if !h.ps.b.ShouldRunRelayServer() {
|
||||
logAndError(http.StatusNotFound, "relay not enabled")
|
||||
return
|
||||
}
|
||||
|
||||
if !h.PeerCaps().HasCapability(tailcfg.PeerCapabilityRelay) {
|
||||
logAndError(http.StatusForbidden, "relay not permitted")
|
||||
return
|
||||
}
|
||||
|
||||
if r.Method != httpm.POST {
|
||||
logAndError(http.StatusMethodNotAllowed, "only POST method is allowed")
|
||||
return
|
||||
}
|
||||
|
||||
var allocateEndpointReq struct {
|
||||
DiscoKeys []key.DiscoPublic
|
||||
}
|
||||
err := json.NewDecoder(io.LimitReader(r.Body, 512)).Decode(&allocateEndpointReq)
|
||||
if err != nil {
|
||||
logAndError(http.StatusBadRequest, err.Error())
|
||||
return
|
||||
}
|
||||
if len(allocateEndpointReq.DiscoKeys) != 2 {
|
||||
logAndError(http.StatusBadRequest, "2 disco public keys must be supplied")
|
||||
return
|
||||
}
|
||||
|
||||
rs, err := h.ps.b.relayServerOrInit()
|
||||
if err != nil {
|
||||
logAndError(http.StatusInternalServerError, "error")
|
||||
return
|
||||
}
|
||||
ep, err := rs.AllocateEndpoint(allocateEndpointReq.DiscoKeys[0], allocateEndpointReq.DiscoKeys[1])
|
||||
if err != nil {
|
||||
logAndError(http.StatusInternalServerError, err.Error())
|
||||
return
|
||||
}
|
||||
err = json.NewEncoder(w).Encode(&ep)
|
||||
if err != nil {
|
||||
logAndError(http.StatusInternalServerError, err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
// newFakePeerAPIListener creates a new net.Listener that acts like
|
||||
// it's listening on the provided IP address and on TCP port 1.
|
||||
//
|
||||
|
39
ipn/ipnlocal/relay_default.go
Normal file
39
ipn/ipnlocal/relay_default.go
Normal file
@ -0,0 +1,39 @@
|
||||
// Copyright (c) Tailscale Inc & AUTHORS
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
//go:build !ios
|
||||
|
||||
package ipnlocal
|
||||
|
||||
import (
|
||||
"net/netip"
|
||||
|
||||
"tailscale.com/envknob"
|
||||
"tailscale.com/net/udprelay"
|
||||
"tailscale.com/tailcfg"
|
||||
)
|
||||
|
||||
func init() {
|
||||
// Initialize the relay server constructor on all platforms except iOS (see
|
||||
// build tag at top of file) for now as to limit the impact to binary size
|
||||
// and resulting effect of pushing up against NetworkExtension limits.
|
||||
// Eventually we will want to support the relay server on iOS, specifically
|
||||
// on the Apple TV. Apple TVs are well-fitted to act as underlay relay
|
||||
// servers as they are effectively always-on servers.
|
||||
registerNewRelayServer(func(port int, addrs []netip.Addr) (relayServer, int, error) {
|
||||
return udprelay.NewServer(port, addrs)
|
||||
})
|
||||
}
|
||||
|
||||
// ShouldRunRelayServer returns true if a relay server port has been set in prefs,
|
||||
// TAILSCALE_USE_WIP_CODE environment variable is set, and the node has the
|
||||
// tailcfg.NodeAttrRelayServer tailcfg.NodeCapability.
|
||||
//
|
||||
// TODO(jwhited): remove the envknob guard once APIs (peerapi endpoint,
|
||||
// new disco message types) are stable.
|
||||
func (b *LocalBackend) ShouldRunRelayServer() bool {
|
||||
b.mu.Lock()
|
||||
defer b.mu.Unlock()
|
||||
return b.Prefs().RelayServerPort().Valid() && envknob.UseWIPCode() &&
|
||||
b.netMap != nil && b.netMap.SelfNode.HasCap(tailcfg.NodeAttrRelayServer)
|
||||
}
|
10
ipn/ipnlocal/relay_ios.go
Normal file
10
ipn/ipnlocal/relay_ios.go
Normal file
@ -0,0 +1,10 @@
|
||||
// Copyright (c) Tailscale Inc & AUTHORS
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
//go:build ios
|
||||
|
||||
package ipnlocal
|
||||
|
||||
func (b *LocalBackend) ShouldRunRelayServer() bool {
|
||||
return false
|
||||
}
|
@ -1,6 +1,8 @@
|
||||
// Copyright (c) Tailscale Inc & AUTHORS
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
//go:build !ios
|
||||
|
||||
// Package udprelay contains constructs for relaying Disco and WireGuard packets
|
||||
// between Tailscale clients over UDP. This package is currently considered
|
||||
// experimental.
|
@ -1,6 +1,8 @@
|
||||
// Copyright (c) Tailscale Inc & AUTHORS
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
//go:build !ios
|
||||
|
||||
package udprelay
|
||||
|
||||
import (
|
8
net/udprelay/server_ios.go
Normal file
8
net/udprelay/server_ios.go
Normal file
@ -0,0 +1,8 @@
|
||||
// Copyright (c) Tailscale Inc & AUTHORS
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
//go:build ios
|
||||
|
||||
package udprelay
|
||||
|
||||
type ServerEndpoint struct{}
|
Loading…
x
Reference in New Issue
Block a user