1
+ // SPDX-License-Identifier: BSD-3-Clause, CC0-1.0
1
2
// Package tsserver implements the Tailscale coordination protocol for a single
2
- // client. Heavy inspiration was taken from https://github.com/juanfont/headscale
3
+ // client. Heavy inspiration and code was taken from https://github.com/juanfont/headscale.
4
+ // As such, this file is dual licensed under BSD-3-Clause and CC0-1.0.
3
5
package tsserver
4
6
5
7
import (
@@ -22,9 +24,7 @@ import (
22
24
"sync/atomic"
23
25
"time"
24
26
25
- "github.com/coder/wush/overlay"
26
27
"github.com/go-chi/chi/v5"
27
- "github.com/google/uuid"
28
28
"github.com/klauspost/compress/zstd"
29
29
"github.com/puzpuzpuz/xsync/v3"
30
30
"github.com/valyala/fasthttp/fasthttputil"
@@ -39,6 +39,8 @@ import (
39
39
"tailscale.com/types/key"
40
40
"tailscale.com/types/opt"
41
41
"tailscale.com/types/ptr"
42
+
43
+ "github.com/coder/wush/overlay"
42
44
)
43
45
44
46
func DERPMapTailscale (ctx context.Context ) (* tailcfg.DERPMap , error ) {
@@ -242,7 +244,8 @@ func (s *server) NoiseUpgradeHandler(w http.ResponseWriter, r *http.Request) {
242
244
logger : s .logger ,
243
245
derpMap : s .derpMap ,
244
246
challenge : key .NewChallenge (),
245
- updates : s .peerMapUpdate ,
247
+ peers : xsync .NewMapOf [tailcfg.NodeID , * tailcfg.Node ](),
248
+ peerUpdate : s .peerMapUpdate ,
246
249
node : & s .node ,
247
250
nodeUpdate : s .nodeUpdate ,
248
251
getIP : s .overlay .IP ,
@@ -332,7 +335,9 @@ type noiseServer struct {
332
335
derpMap * tailcfg.DERPMap
333
336
getIP func () netip.Addr
334
337
335
- updates chan update
338
+ peers * xsync.MapOf [tailcfg.NodeID , * tailcfg.Node ]
339
+ peerUpdate chan update
340
+
336
341
node * atomic.Pointer [tailcfg.Node ]
337
342
nodeUpdate chan struct {}
338
343
@@ -341,37 +346,6 @@ type noiseServer struct {
341
346
protocolVersion int
342
347
}
343
348
344
- func maskUUID (uid uuid.UUID ) uuid.UUID {
345
- // This is Tailscale's ephemeral service prefix. This can be changed easily
346
- // later-on, because all of our nodes are ephemeral.
347
- // fd7a:115c:a1e0
348
- uid [0 ] = 0xfd
349
- uid [1 ] = 0x7a
350
- uid [2 ] = 0x11
351
- uid [3 ] = 0x5c
352
- uid [4 ] = 0xa1
353
- uid [5 ] = 0xe0
354
- return uid
355
- }
356
-
357
- // IP generates a random IP with a static service prefix.
358
- func IP () netip.Addr {
359
- uid := maskUUID (uuid .New ())
360
- return netip .AddrFrom16 (uid )
361
- }
362
-
363
- // func IP4r() netip.Addr {
364
- // return netip.AddrFrom4([4]byte{100, 64, 1, 1})
365
- // }
366
- // func IP4s() netip.Addr {
367
- // return netip.AddrFrom4([4]byte{100, 64, 2, 2})
368
- // }
369
-
370
- // IP generates a new IP from a UUID.
371
- func IPFromUUID (uid uuid.UUID ) netip.Addr {
372
- return netip .AddrFrom16 (maskUUID (uid ))
373
- }
374
-
375
349
func (ns * noiseServer ) notifyUpdate () {
376
350
ns .nodeUpdate <- struct {}{}
377
351
}
@@ -389,17 +363,6 @@ func (ns *noiseServer) NoiseRegistrationHandler(w http.ResponseWriter, r *http.R
389
363
sp := strings .SplitN (registerRequest .Auth .AuthKey , "-" , 2 )
390
364
391
365
ip := ns .getIP ()
392
- // var ip netip.Addr
393
- // switch registerRequest.Auth.AuthKey {
394
- // case "receive":
395
- // ip = IP4r()
396
- // case "send":
397
- // ip = IP4s()
398
- // default:
399
- // http.Error(w, fmt.Sprintf("unknown authkey: %q", registerRequest.Auth.AuthKey), http.StatusBadRequest)
400
- // return
401
- // }
402
- // try insecureskipverify
403
366
404
367
resp := tailcfg.RegisterResponse {}
405
368
resp .MachineAuthorized = true
@@ -506,17 +469,21 @@ func (ns *noiseServer) NoisePollNetMapHandler(
506
469
func (ns * noiseServer ) peerMap () []* tailcfg.Node {
507
470
peers := []* tailcfg.Node {}
508
471
509
- // TOOD: get peers
472
+ ns .peers .Range (func (key tailcfg.NodeID , value * tailcfg.Node ) bool {
473
+ peers = append (peers , value .Clone ())
474
+ return true
475
+ })
476
+ xslices .SortFunc (peers , func (a , b * tailcfg.Node ) int {
477
+ return cmp .Compare (a .ID , b .ID )
478
+ })
510
479
511
480
return peers
512
481
}
513
482
514
483
func (ns * noiseServer ) handleStreaming (ctx context.Context , w http.ResponseWriter , req * tailcfg.MapRequest ) {
515
- // Upgrade the writer to a ResponseController
516
484
rc := http .NewResponseController (w )
517
-
518
- // Longpolling will break if there is a write timeout,
519
- // so it needs to be disabled.
485
+ // Longpolling will break if there is a write timeout, so it needs to be
486
+ // disabled.
520
487
rc .SetWriteDeadline (time.Time {})
521
488
522
489
node := ns .getSelfNode ()
@@ -552,13 +519,14 @@ func (ns *noiseServer) handleStreaming(ctx context.Context, w http.ResponseWrite
552
519
select {
553
520
case <- ctx .Done ():
554
521
return
555
- case upd := <- ns .updates :
522
+ case upd := <- ns .peerUpdate :
556
523
res := & tailcfg.MapResponse {
557
524
KeepAlive : false ,
558
525
ControlTime : ptr .To (time .Now ()),
559
526
}
560
527
if upd .ty == updateTypeNewPeer {
561
- res .Peers = []* tailcfg.Node {upd .node }
528
+ ns .peers .Store (upd .node .ID , upd .node .Clone ())
529
+ res .Peers = ns .peerMap ()
562
530
} else if upd .ty == updateTypePeerUpdate {
563
531
res .PeersChangedPatch = []* tailcfg.PeerChange {upd .update }
564
532
}
@@ -590,7 +558,6 @@ func (ns *noiseServer) handleStreaming(ctx context.Context, w http.ResponseWrite
590
558
}
591
559
}
592
560
}
593
-
594
561
}
595
562
596
563
func writeMapResponse (w http.ResponseWriter , req * tailcfg.MapRequest , res * tailcfg.MapResponse ) error {
@@ -751,7 +718,6 @@ func peerChange(req *tailcfg.MapRequest, node *tailcfg.Node) tailcfg.PeerChange
751
718
}
752
719
}
753
720
754
- // TODO(kradalby): Find a good way to compare updates
755
721
ret .Endpoints = req .Endpoints
756
722
757
723
ret .LastSeen = ptr .To (time .Now ())
@@ -831,6 +797,8 @@ const (
831
797
earlyPayloadMagic = "\xff \xff \xff TS"
832
798
)
833
799
800
+ var _ = (* noiseServer )(nil ).earlyNoise
801
+
834
802
func (ns * noiseServer ) earlyNoise (protocolVersion int , writer io.Writer ) error {
835
803
ns .logger .Info ("early noise" )
836
804
if protocolVersion < earlyNoiseCapabilityVersion {
0 commit comments