mirror of
https://github.com/tailscale/tailscale.git
synced 2024-12-02 06:25:37 +00:00
wip
This commit is contained in:
parent
1ae16546af
commit
d32aaffca6
@ -1417,6 +1417,14 @@ func (lc *LocalClient) CheckUpdate(ctx context.Context) (*tailcfg.ClientVersion,
|
|||||||
return &cv, nil
|
return &cv, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (lc *LocalClient) SuggestExitNode(ctx context.Context) error {
|
||||||
|
body, err := lc.send(ctx, "POST", "/localapi/v0/suggest-exit-node", 200, nil)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("error %w: %s", err, body)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// IPNBusWatcher is an active subscription (watch) of the local tailscaled IPN bus.
|
// IPNBusWatcher is an active subscription (watch) of the local tailscaled IPN bus.
|
||||||
// It's returned by LocalClient.WatchIPNBus.
|
// It's returned by LocalClient.WatchIPNBus.
|
||||||
//
|
//
|
||||||
|
@ -64,7 +64,7 @@ func newSetFlagSet(goos string, setArgs *setArgsT) *flag.FlagSet {
|
|||||||
setf.StringVar(&setArgs.profileName, "nickname", "", "nickname for the current account")
|
setf.StringVar(&setArgs.profileName, "nickname", "", "nickname for the current account")
|
||||||
setf.BoolVar(&setArgs.acceptRoutes, "accept-routes", false, "accept routes advertised by other Tailscale nodes")
|
setf.BoolVar(&setArgs.acceptRoutes, "accept-routes", false, "accept routes advertised by other Tailscale nodes")
|
||||||
setf.BoolVar(&setArgs.acceptDNS, "accept-dns", false, "accept DNS configuration from the admin panel")
|
setf.BoolVar(&setArgs.acceptDNS, "accept-dns", false, "accept DNS configuration from the admin panel")
|
||||||
setf.StringVar(&setArgs.exitNodeIP, "exit-node", "", "Tailscale exit node (IP or base name) for internet traffic, or empty string to not use an exit node")
|
setf.StringVar(&setArgs.exitNodeIP, "exit-node", "", "Tailscale exit node (IP or base name) for internet traffic, or empty string to not use an exit node. Input suggest as the string for Tailscale to pick the best exit node.")
|
||||||
setf.BoolVar(&setArgs.exitNodeAllowLANAccess, "exit-node-allow-lan-access", false, "Allow direct access to the local network when routing traffic via an exit node")
|
setf.BoolVar(&setArgs.exitNodeAllowLANAccess, "exit-node-allow-lan-access", false, "Allow direct access to the local network when routing traffic via an exit node")
|
||||||
setf.BoolVar(&setArgs.shieldsUp, "shields-up", false, "don't allow incoming connections")
|
setf.BoolVar(&setArgs.shieldsUp, "shields-up", false, "don't allow incoming connections")
|
||||||
setf.BoolVar(&setArgs.runSSH, "ssh", false, "run an SSH server, permitting access per tailnet admin's declared policy")
|
setf.BoolVar(&setArgs.runSSH, "ssh", false, "run an SSH server, permitting access per tailnet admin's declared policy")
|
||||||
@ -128,6 +128,12 @@ func runSet(ctx context.Context, args []string) (retErr error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if setArgs.exitNodeIP != "" {
|
if setArgs.exitNodeIP != "" {
|
||||||
|
if setArgs.exitNodeIP == "suggest" {
|
||||||
|
err := localClient.SuggestExitNode(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
if err := maskedPrefs.Prefs.SetExitNodeIP(setArgs.exitNodeIP, st); err != nil {
|
if err := maskedPrefs.Prefs.SetExitNodeIP(setArgs.exitNodeIP, st); err != nil {
|
||||||
var e ipn.ExitNodeLocalIPError
|
var e ipn.ExitNodeLocalIPError
|
||||||
if errors.As(err, &e) {
|
if errors.As(err, &e) {
|
||||||
@ -136,6 +142,7 @@ func runSet(ctx context.Context, args []string) (retErr error) {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
warnOnAdvertiseRouts(ctx, &maskedPrefs.Prefs)
|
warnOnAdvertiseRouts(ctx, &maskedPrefs.Prefs)
|
||||||
var advertiseExitNodeSet, advertiseRoutesSet bool
|
var advertiseExitNodeSet, advertiseRoutesSet bool
|
||||||
|
@ -13,6 +13,7 @@
|
|||||||
"io"
|
"io"
|
||||||
"log"
|
"log"
|
||||||
"maps"
|
"maps"
|
||||||
|
"math"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/netip"
|
"net/netip"
|
||||||
@ -107,6 +108,8 @@
|
|||||||
|
|
||||||
var controlDebugFlags = getControlDebugFlags()
|
var controlDebugFlags = getControlDebugFlags()
|
||||||
|
|
||||||
|
const derpPrefix = "127.3.3.40:"
|
||||||
|
|
||||||
func getControlDebugFlags() []string {
|
func getControlDebugFlags() []string {
|
||||||
if e := envknob.String("TS_DEBUG_CONTROL_FLAGS"); e != "" {
|
if e := envknob.String("TS_DEBUG_CONTROL_FLAGS"); e != "" {
|
||||||
return strings.Split(e, ",")
|
return strings.Split(e, ",")
|
||||||
@ -307,6 +310,7 @@ type LocalBackend struct {
|
|||||||
|
|
||||||
// Last ClientVersion received in MapResponse, guarded by mu.
|
// Last ClientVersion received in MapResponse, guarded by mu.
|
||||||
lastClientVersion *tailcfg.ClientVersion
|
lastClientVersion *tailcfg.ClientVersion
|
||||||
|
suggestedExitNodeMap map[tailcfg.NodeID]tailcfg.DERPRegion
|
||||||
}
|
}
|
||||||
|
|
||||||
type updateStatus struct {
|
type updateStatus struct {
|
||||||
@ -1431,7 +1435,6 @@ func setExitNodeID(prefs *ipn.Prefs, nm *netmap.NetworkMap) (prefsChanged bool)
|
|||||||
return oldExitNodeID != prefs.ExitNodeID
|
return oldExitNodeID != prefs.ExitNodeID
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return prefsChanged
|
return prefsChanged
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -5909,3 +5912,36 @@ func mayDeref[T any](p *T) (v T) {
|
|||||||
}
|
}
|
||||||
return *p
|
return *p
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (b *LocalBackend) SuggestExitNode() error {
|
||||||
|
//b.mu.Lock()
|
||||||
|
netMap := b.netMap
|
||||||
|
peers := netMap.Peers
|
||||||
|
lastReport := b.MagicConn().GetLastNetcheckReport()
|
||||||
|
var fastestRegionLatency = time.Duration(math.MaxInt64)
|
||||||
|
var preferredExitNodeID tailcfg.StableNodeID
|
||||||
|
for _, peer := range peers {
|
||||||
|
if tsaddr.ContainsExitRoutes(peer.AllowedIPs()) && strings.HasPrefix(peer.DERP(), derpPrefix) {
|
||||||
|
ipp, _ := netip.ParseAddrPort(peer.DERP())
|
||||||
|
regionID := int(ipp.Port())
|
||||||
|
if lastReport.RegionLatency[regionID] < fastestRegionLatency {
|
||||||
|
fastestRegionLatency = lastReport.RegionLatency[regionID]
|
||||||
|
preferredExitNodeID = peer.StableID()
|
||||||
|
b.logf("fastest region latency %v preferred exit node id %v", lastReport.RegionLatency[regionID], peer.StableID())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// b.mu.Unlock()
|
||||||
|
prefs := b.Prefs().AsStruct()
|
||||||
|
prefs.ExitNodeID = preferredExitNodeID
|
||||||
|
_, err := b.EditPrefs(&ipn.MaskedPrefs{
|
||||||
|
Prefs: ipn.Prefs{
|
||||||
|
ExitNodeID: preferredExitNodeID,
|
||||||
|
},
|
||||||
|
ExitNodeIDSet: true,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Failed to suggest exit node %v, err %v", preferredExitNodeID, err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
@ -129,6 +129,7 @@
|
|||||||
"update/check": (*Handler).serveUpdateCheck,
|
"update/check": (*Handler).serveUpdateCheck,
|
||||||
"update/install": (*Handler).serveUpdateInstall,
|
"update/install": (*Handler).serveUpdateInstall,
|
||||||
"update/progress": (*Handler).serveUpdateProgress,
|
"update/progress": (*Handler).serveUpdateProgress,
|
||||||
|
"suggest-exit-node": (*Handler).serveSuggestExitNode,
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@ -2504,3 +2505,19 @@ func (h *Handler) serveUpdateProgress(w http.ResponseWriter, r *http.Request) {
|
|||||||
// User-visible LocalAPI endpoints.
|
// User-visible LocalAPI endpoints.
|
||||||
metricFilePutCalls = clientmetric.NewCounter("localapi_file_put")
|
metricFilePutCalls = clientmetric.NewCounter("localapi_file_put")
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func (h *Handler) serveSuggestExitNode(w http.ResponseWriter, r *http.Request) {
|
||||||
|
if !h.PermitWrite {
|
||||||
|
http.Error(w, "access denied", http.StatusForbidden)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if r.Method != "POST" {
|
||||||
|
http.Error(w, "want POST", http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err := h.b.SuggestExitNode()
|
||||||
|
if err != nil {
|
||||||
|
writeErrorJSON(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -799,6 +799,7 @@ func (p *Prefs) SetExitNodeIP(s string, st *ipnstate.Status) error {
|
|||||||
if err == nil {
|
if err == nil {
|
||||||
p.ExitNodeIP = ip
|
p.ExitNodeIP = ip
|
||||||
}
|
}
|
||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user