Skip to content

Commit c5f91a8

Browse files
committed
Add wgnet
1 parent 789e878 commit c5f91a8

31 files changed

+1302
-541
lines changed

.vscode/settings.json

+25
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111
"coderdtest",
1212
"codersdk",
1313
"cronstrue",
14+
"DERP",
15+
"derphttp",
1416
"devel",
1517
"drpc",
1618
"drpcconn",
@@ -23,6 +25,7 @@
2325
"goarch",
2426
"gographviz",
2527
"goleak",
28+
"gonet",
2629
"gossh",
2730
"gsyslog",
2831
"hashicorp",
@@ -37,13 +40,21 @@
3740
"Keygen",
3841
"kirsle",
3942
"ldflags",
43+
"magicsock",
4044
"manifoldco",
4145
"mapstructure",
4246
"mattn",
4347
"mitchellh",
4448
"moby",
49+
"namespacing",
50+
"netaddr",
51+
"netmap",
52+
"netns",
53+
"netstack",
54+
"nettype",
4555
"nfpms",
4656
"nhooyr",
57+
"nmcfg",
4758
"nolint",
4859
"nosec",
4960
"ntqry",
@@ -57,6 +68,7 @@
5768
"provisionersdk",
5869
"ptty",
5970
"ptytest",
71+
"reconfig",
6072
"retrier",
6173
"rpty",
6274
"sdkproto",
@@ -65,6 +77,10 @@
6577
"sourcemapped",
6678
"Srcs",
6779
"stretchr",
80+
"stuntest",
81+
"tailcfg",
82+
"tailnet",
83+
"Tailscale",
6884
"TCGETS",
6985
"tcpip",
7086
"TCSETS",
@@ -76,13 +92,22 @@
7692
"tfplan",
7793
"tfstate",
7894
"trimprefix",
95+
"tsdial",
96+
"tslogger",
97+
"tstun",
7998
"turnconn",
8099
"typegen",
81100
"unconvert",
82101
"Untar",
102+
"Userspace",
83103
"VMID",
84104
"weblinks",
85105
"webrtc",
106+
"wgcfg",
107+
"wgconfig",
108+
"wgengine",
109+
"wgmonitor",
110+
"wgnet",
86111
"workspaceagent",
87112
"workspaceapp",
88113
"workspaceapps",

agent/agent.go

+88-24
Original file line numberDiff line numberDiff line change
@@ -28,14 +28,14 @@ import (
2828
gossh "golang.org/x/crypto/ssh"
2929
"golang.org/x/xerrors"
3030
"inet.af/netaddr"
31-
"tailscale.com/types/key"
31+
"tailscale.com/tailcfg"
3232

3333
"cdr.dev/slog"
3434
"github.com/coder/coder/agent/usershell"
3535
"github.com/coder/coder/peer"
36-
"github.com/coder/coder/peer/peerwg"
3736
"github.com/coder/coder/peerbroker"
3837
"github.com/coder/coder/pty"
38+
"github.com/coder/coder/tailnet"
3939
"github.com/coder/retry"
4040
)
4141

@@ -47,30 +47,28 @@ const (
4747

4848
type Options struct {
4949
EnableWireguard bool
50-
UploadWireguardKeys UploadWireguardKeys
51-
ListenWireguardPeers ListenWireguardPeers
50+
UpdateTailscaleNode UpdateTailscaleNode
51+
ListenTailscaleNodes ListenTailscaleNodes
5252
ReconnectingPTYTimeout time.Duration
5353
EnvironmentVariables map[string]string
5454
Logger slog.Logger
5555
}
5656

5757
type Metadata struct {
58-
WireguardAddresses []netaddr.IPPrefix `json:"addresses"`
59-
OwnerEmail string `json:"owner_email"`
60-
OwnerUsername string `json:"owner_username"`
61-
EnvironmentVariables map[string]string `json:"environment_variables"`
62-
StartupScript string `json:"startup_script"`
63-
Directory string `json:"directory"`
64-
}
65-
66-
type WireguardPublicKeys struct {
67-
Public key.NodePublic `json:"public"`
68-
Disco key.DiscoPublic `json:"disco"`
58+
TailscaleAddresses []netaddr.IPPrefix `json:"tailscale_addresses"`
59+
TailscaleDERPMap *tailcfg.DERPMap `json:"tailscale_derpmap"`
60+
61+
OwnerEmail string `json:"owner_email"`
62+
OwnerUsername string `json:"owner_username"`
63+
EnvironmentVariables map[string]string `json:"environment_variables"`
64+
StartupScript string `json:"startup_script"`
65+
Directory string `json:"directory"`
6966
}
7067

7168
type Dialer func(ctx context.Context, logger slog.Logger) (Metadata, *peerbroker.Listener, error)
72-
type UploadWireguardKeys func(ctx context.Context, keys WireguardPublicKeys) error
73-
type ListenWireguardPeers func(ctx context.Context, logger slog.Logger) (<-chan peerwg.Handshake, func(), error)
69+
70+
type UpdateTailscaleNode func(ctx context.Context, node *tailnet.Node) error
71+
type ListenTailscaleNodes func(ctx context.Context, logger slog.Logger) (<-chan *tailnet.Node, func(), error)
7472

7573
func New(dialer Dialer, options *Options) io.Closer {
7674
if options == nil {
@@ -88,8 +86,8 @@ func New(dialer Dialer, options *Options) io.Closer {
8886
closed: make(chan struct{}),
8987
envVars: options.EnvironmentVariables,
9088
enableWireguard: options.EnableWireguard,
91-
postKeys: options.UploadWireguardKeys,
92-
listenWireguardPeers: options.ListenWireguardPeers,
89+
updateTailscaleNode: options.UpdateTailscaleNode,
90+
listenTailscaleNodes: options.ListenTailscaleNodes,
9391
}
9492
server.init(ctx)
9593
return server
@@ -114,9 +112,9 @@ type agent struct {
114112
sshServer *ssh.Server
115113

116114
enableWireguard bool
117-
network *peerwg.Network
118-
postKeys UploadWireguardKeys
119-
listenWireguardPeers ListenWireguardPeers
115+
network *tailnet.Server
116+
updateTailscaleNode UpdateTailscaleNode
117+
listenTailscaleNodes ListenTailscaleNodes
120118
}
121119

122120
func (a *agent) run(ctx context.Context) {
@@ -160,8 +158,9 @@ func (a *agent) run(ctx context.Context) {
160158
}()
161159
}
162160

163-
if a.enableWireguard {
164-
err = a.startWireguard(ctx, metadata.WireguardAddresses)
161+
// We don't want to reinitialize the network if it already exists.
162+
if a.enableWireguard && a.network == nil {
163+
err = a.startWireguard(ctx, metadata.TailscaleAddresses, metadata.TailscaleDERPMap)
165164
if err != nil {
166165
a.logger.Error(ctx, "start wireguard", slog.Error(err))
167166
}
@@ -668,6 +667,71 @@ func (a *agent) handleReconnectingPTY(ctx context.Context, rawID string, conn ne
668667
}
669668
}
670669

670+
func (a *agent) startWireguard(ctx context.Context, addresses []netaddr.IPPrefix, derpMap *tailcfg.DERPMap) error {
671+
var err error
672+
a.network, err = tailnet.New(&tailnet.Options{
673+
Addresses: addresses,
674+
DERPMap: derpMap,
675+
Logger: a.logger.Named("tailnet"),
676+
})
677+
if err != nil {
678+
return err
679+
}
680+
a.network.SetNodeCallback(func(node *tailnet.Node) {
681+
err := a.updateTailscaleNode(ctx, node)
682+
if err != nil {
683+
a.logger.Error(ctx, "update tailscale node", slog.Error(err))
684+
}
685+
})
686+
go func() {
687+
for {
688+
var nodes <-chan *tailnet.Node
689+
var err error
690+
var listenClose func()
691+
for retrier := retry.New(50*time.Millisecond, 10*time.Second); retrier.Wait(ctx); {
692+
nodes, listenClose, err = a.listenTailscaleNodes(ctx, a.logger)
693+
if err != nil {
694+
if errors.Is(err, context.Canceled) {
695+
return
696+
}
697+
a.logger.Warn(ctx, "listen for tailscale nodes", slog.Error(err))
698+
continue
699+
}
700+
defer listenClose()
701+
a.logger.Info(context.Background(), "listening for tailscale nodes")
702+
break
703+
}
704+
for {
705+
var node *tailnet.Node
706+
select {
707+
case <-ctx.Done():
708+
case node = <-nodes:
709+
}
710+
if node == nil {
711+
// The channel ended!
712+
break
713+
}
714+
a.network.UpdateNodes([]*tailnet.Node{node})
715+
}
716+
}
717+
}()
718+
719+
sshListener, err := a.network.Listen("tcp", ":12212")
720+
if err != nil {
721+
return xerrors.Errorf("listen for ssh: %w", err)
722+
}
723+
go func() {
724+
for {
725+
conn, err := sshListener.Accept()
726+
if err != nil {
727+
return
728+
}
729+
go a.sshServer.HandleConn(conn)
730+
}
731+
}()
732+
return nil
733+
}
734+
671735
// dialResponse is written to datachannels with protocol "dial" by the agent as
672736
// the first packet to signify whether the dial succeeded or failed.
673737
type dialResponse struct {

agent/agent_test.go

+5
Original file line numberDiff line numberDiff line change
@@ -395,6 +395,11 @@ func TestAgent(t *testing.T) {
395395
require.ErrorContains(t, err, "no such file")
396396
require.Nil(t, netConn)
397397
})
398+
399+
t.Run("Tailscale", func(t *testing.T) {
400+
t.Parallel()
401+
402+
})
398403
}
399404

400405
func setupSSHCommand(t *testing.T, beforeArgs []string, afterArgs []string) *exec.Cmd {

agent/wireguard.go

-97
This file was deleted.

cli/agent.go

+6-3
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import (
2222
"github.com/coder/coder/agent/reaper"
2323
"github.com/coder/coder/cli/cliflag"
2424
"github.com/coder/coder/codersdk"
25+
"github.com/coder/coder/tailnet"
2526
"github.com/coder/retry"
2627
)
2728

@@ -177,9 +178,11 @@ func workspaceAgent() *cobra.Command {
177178
// shells so "gitssh" works!
178179
"CODER_AGENT_TOKEN": client.SessionToken,
179180
},
180-
EnableWireguard: wireguard,
181-
UploadWireguardKeys: client.UploadWorkspaceAgentKeys,
182-
ListenWireguardPeers: client.WireguardPeerListener,
181+
EnableWireguard: wireguard,
182+
UpdateTailscaleNode: func(ctx context.Context, node *tailnet.Node) error {
183+
return client.UpdateTailscaleNode(ctx, "me", node)
184+
},
185+
ListenTailscaleNodes: client.ListenTailscaleNodes,
183186
})
184187
<-cmd.Context().Done()
185188
return closer.Close()

0 commit comments

Comments
 (0)