Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| dd9c9f6844 |
@@ -361,6 +361,13 @@ func newIPN(jsConfig js.Value) map[string]any {
|
|||||||
"suggestExitNode": js.FuncOf(func(this js.Value, args []js.Value) any {
|
"suggestExitNode": js.FuncOf(func(this js.Value, args []js.Value) any {
|
||||||
return jsIPN.suggestExitNode()
|
return jsIPN.suggestExitNode()
|
||||||
}),
|
}),
|
||||||
|
"setServices": js.FuncOf(func(this js.Value, args []js.Value) any {
|
||||||
|
if len(args) != 1 {
|
||||||
|
log.Printf("Usage: setServices(services)")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return jsIPN.setServices(args[0])
|
||||||
|
}),
|
||||||
"localAPI": js.FuncOf(func(this js.Value, args []js.Value) any {
|
"localAPI": js.FuncOf(func(this js.Value, args []js.Value) any {
|
||||||
if len(args) < 2 {
|
if len(args) < 2 {
|
||||||
log.Printf("Usage: localAPI(method, path[, body])")
|
log.Printf("Usage: localAPI(method, path[, body])")
|
||||||
@@ -467,6 +474,7 @@ func (i *jsIPN) run(jsCallbacks js.Value) {
|
|||||||
NodeKey: nm.NodeKey.String(),
|
NodeKey: nm.NodeKey.String(),
|
||||||
MachineKey: nm.MachineKey.String(),
|
MachineKey: nm.MachineKey.String(),
|
||||||
PeerAPIURL: selfPeerAPIURL,
|
PeerAPIURL: selfPeerAPIURL,
|
||||||
|
Services: userServicesFromView(nm.SelfNode.Hostinfo().Services()),
|
||||||
},
|
},
|
||||||
MachineStatus: jsMachineStatus[nm.GetMachineStatus()],
|
MachineStatus: jsMachineStatus[nm.GetMachineStatus()],
|
||||||
},
|
},
|
||||||
@@ -516,6 +524,7 @@ func (i *jsIPN) run(jsCallbacks js.Value) {
|
|||||||
MachineKey: p.Machine().String(),
|
MachineKey: p.Machine().String(),
|
||||||
NodeKey: p.Key().String(),
|
NodeKey: p.Key().String(),
|
||||||
PeerAPIURL: peerURL,
|
PeerAPIURL: peerURL,
|
||||||
|
Services: userServicesFromView(p.Hostinfo().Services()),
|
||||||
},
|
},
|
||||||
Online: p.Online().Clone(),
|
Online: p.Online().Clone(),
|
||||||
TailscaleSSHEnabled: p.Hostinfo().TailscaleSSHEnabled(),
|
TailscaleSSHEnabled: p.Hostinfo().TailscaleSSHEnabled(),
|
||||||
@@ -1328,6 +1337,39 @@ func (i *jsIPN) suggestExitNode() js.Value {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (i *jsIPN) setServices(jsServices js.Value) js.Value {
|
||||||
|
return makePromise(func() (any, error) {
|
||||||
|
n := jsServices.Length()
|
||||||
|
svcs := make([]tailcfg.Service, 0, n)
|
||||||
|
for idx := range n {
|
||||||
|
s := jsServices.Index(idx)
|
||||||
|
proto := tailcfg.ServiceProto(s.Get("proto").String())
|
||||||
|
port := uint16(s.Get("port").Int())
|
||||||
|
var desc string
|
||||||
|
if d := s.Get("description"); d.Type() == js.TypeString {
|
||||||
|
desc = d.String()
|
||||||
|
}
|
||||||
|
svcs = append(svcs, tailcfg.Service{Proto: proto, Port: port, Description: desc})
|
||||||
|
}
|
||||||
|
i.lb.SetExplicitServices(svcs)
|
||||||
|
return nil, nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// userServicesFromView converts a hostinfo services slice to jsService entries,
|
||||||
|
// filtering out internal peerapi protocol entries (already reflected in peerAPIURL).
|
||||||
|
func userServicesFromView(svcs views.Slice[tailcfg.Service]) []jsService {
|
||||||
|
var out []jsService
|
||||||
|
for _, s := range svcs.All() {
|
||||||
|
switch s.Proto {
|
||||||
|
case tailcfg.PeerAPI4, tailcfg.PeerAPI6, tailcfg.PeerAPIDNS:
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
out = append(out, jsService{Proto: string(s.Proto), Port: s.Port, Description: s.Description})
|
||||||
|
}
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
func (i *jsIPN) localAPI(method, path, body string) js.Value {
|
func (i *jsIPN) localAPI(method, path, body string) js.Value {
|
||||||
return makePromise(func() (any, error) {
|
return makePromise(func() (any, error) {
|
||||||
h := localapi.NewHandler(localapi.HandlerConfig{
|
h := localapi.NewHandler(localapi.HandlerConfig{
|
||||||
@@ -1564,12 +1606,19 @@ type jsNetMap struct {
|
|||||||
LockedOut bool `json:"lockedOut"`
|
LockedOut bool `json:"lockedOut"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type jsService struct {
|
||||||
|
Proto string `json:"proto"`
|
||||||
|
Port uint16 `json:"port"`
|
||||||
|
Description string `json:"description,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
type jsNetMapNode struct {
|
type jsNetMapNode struct {
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Addresses []string `json:"addresses"`
|
Addresses []string `json:"addresses"`
|
||||||
MachineKey string `json:"machineKey"`
|
MachineKey string `json:"machineKey"`
|
||||||
NodeKey string `json:"nodeKey"`
|
NodeKey string `json:"nodeKey"`
|
||||||
PeerAPIURL string `json:"peerAPIURL,omitempty"`
|
PeerAPIURL string `json:"peerAPIURL,omitempty"`
|
||||||
|
Services []jsService `json:"services,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type jsNetMapSelfNode struct {
|
type jsNetMapSelfNode struct {
|
||||||
|
|||||||
+21
-1
@@ -294,6 +294,7 @@ type LocalBackend struct {
|
|||||||
capTailnetLock bool // whether netMap contains the tailnet lock capability
|
capTailnetLock bool // whether netMap contains the tailnet lock capability
|
||||||
// hostinfo is mutated in-place while mu is held.
|
// hostinfo is mutated in-place while mu is held.
|
||||||
hostinfo *tailcfg.Hostinfo // TODO(nickkhyl): move to nodeBackend
|
hostinfo *tailcfg.Hostinfo // TODO(nickkhyl): move to nodeBackend
|
||||||
|
explicitServices []tailcfg.Service // services set explicitly via SetExplicitServices; always uploaded
|
||||||
nmExpiryTimer tstime.TimerController // for updating netMap on node expiry; can be nil; TODO(nickkhyl): move to nodeBackend
|
nmExpiryTimer tstime.TimerController // for updating netMap on node expiry; can be nil; TODO(nickkhyl): move to nodeBackend
|
||||||
activeLogin string // last logged LoginName from netMap; TODO(nickkhyl): move to nodeBackend (or remove? it's in [ipn.LoginProfile]).
|
activeLogin string // last logged LoginName from netMap; TODO(nickkhyl): move to nodeBackend (or remove? it's in [ipn.LoginProfile]).
|
||||||
engineStatus ipn.EngineStatus
|
engineStatus ipn.EngineStatus
|
||||||
@@ -4967,6 +4968,23 @@ func (b *LocalBackend) setPortlistServices(sl []tailcfg.Service) {
|
|||||||
b.doSetHostinfoFilterServices()
|
b.doSetHostinfoFilterServices()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetExplicitServices sets the services this node advertises on the netmap.
|
||||||
|
// Unlike the OS port-scan path (setPortlistServices), services set here are
|
||||||
|
// always uploaded to the control server regardless of the ShouldUploadServices
|
||||||
|
// hook — suitable for environments like browser WASM where OS port scanning is
|
||||||
|
// unavailable and services are declared programmatically.
|
||||||
|
func (b *LocalBackend) SetExplicitServices(sl []tailcfg.Service) {
|
||||||
|
b.mu.Lock()
|
||||||
|
if b.hostinfo == nil {
|
||||||
|
b.hostinfo = new(tailcfg.Hostinfo)
|
||||||
|
}
|
||||||
|
b.hostinfo.Services = sl
|
||||||
|
b.explicitServices = sl
|
||||||
|
b.mu.Unlock()
|
||||||
|
|
||||||
|
b.doSetHostinfoFilterServices()
|
||||||
|
}
|
||||||
|
|
||||||
// doSetHostinfoFilterServices calls SetHostinfo on the controlclient,
|
// doSetHostinfoFilterServices calls SetHostinfo on the controlclient,
|
||||||
// possibly after mangling the given hostinfo.
|
// possibly after mangling the given hostinfo.
|
||||||
//
|
//
|
||||||
@@ -5011,7 +5029,9 @@ func (b *LocalBackend) hostInfoWithServicesLocked() *tailcfg.Hostinfo {
|
|||||||
// Make a shallow copy of hostinfo so we can mutate
|
// Make a shallow copy of hostinfo so we can mutate
|
||||||
// at the Service field.
|
// at the Service field.
|
||||||
if f, ok := b.extHost.Hooks().ShouldUploadServices.GetOk(); !ok || !f() {
|
if f, ok := b.extHost.Hooks().ShouldUploadServices.GetOk(); !ok || !f() {
|
||||||
hi.Services = []tailcfg.Service{}
|
if len(b.explicitServices) == 0 {
|
||||||
|
hi.Services = []tailcfg.Service{}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Don't mutate hi.Service's underlying array. Append to
|
// Don't mutate hi.Service's underlying array. Append to
|
||||||
|
|||||||
Reference in New Issue
Block a user