Skip to content

Commit b0b43dc

Browse files
authored
Add option to specify DERP servers (#45)
Allow users to specify a custom DERP configuration file via the `--derp-config-file` flag in multiple commands. This provides flexibility to use different DERP servers, enhancing connectivity options. Closes #43
1 parent 7664832 commit b0b43dc

File tree

5 files changed

+89
-34
lines changed

5 files changed

+89
-34
lines changed

cmd/wush/cp.go

+42-10
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package main
22

33
import (
4+
"encoding/json"
45
"errors"
56
"fmt"
67
"io"
@@ -19,6 +20,7 @@ import (
1920
"github.com/coder/wush/tsserver"
2021
"github.com/schollz/progressbar/v3"
2122
"tailscale.com/net/netns"
23+
"tailscale.com/tailcfg"
2224
"tailscale.com/types/ptr"
2325
)
2426

@@ -65,13 +67,10 @@ func initAuth(authFlag *string, ca *overlay.ClientAuth) serpent.MiddlewareFunc {
6567
}
6668
}
6769

68-
func sendOverlayMW(opts *sendOverlayOpts, send **overlay.Send, logger *slog.Logger, logf *func(str string, args ...any)) serpent.MiddlewareFunc {
70+
func sendOverlayMW(opts *sendOverlayOpts, send **overlay.Send, logger *slog.Logger, dm *tailcfg.DERPMap, logf *func(str string, args ...any)) serpent.MiddlewareFunc {
6971
return func(next serpent.HandlerFunc) serpent.HandlerFunc {
7072
return func(i *serpent.Invocation) error {
71-
dm, err := tsserver.DERPMapTailscale(i.Context())
72-
if err != nil {
73-
return err
74-
}
73+
var err error
7574

7675
newSend := overlay.NewSendOverlay(logger, dm)
7776
newSend.Auth = opts.clientAuth
@@ -90,6 +89,30 @@ func sendOverlayMW(opts *sendOverlayOpts, send **overlay.Send, logger *slog.Logg
9089
}
9190
}
9291

92+
func derpMap(fi *string, dm *tailcfg.DERPMap) serpent.MiddlewareFunc {
93+
return func(next serpent.HandlerFunc) serpent.HandlerFunc {
94+
return func(i *serpent.Invocation) error {
95+
if *fi == "" {
96+
_dm, err := tsserver.DERPMapTailscale(i.Context())
97+
if err != nil {
98+
return fmt.Errorf("request derpmap from tailscale: %w", err)
99+
}
100+
*dm = *_dm
101+
} else {
102+
data, err := os.ReadFile(*fi)
103+
if err != nil {
104+
return fmt.Errorf("read derp config file: %w", err)
105+
}
106+
if err := json.Unmarshal(data, dm); err != nil {
107+
return fmt.Errorf("unmarshal derp config: %w", err)
108+
}
109+
}
110+
111+
return next(i)
112+
}
113+
}
114+
}
115+
93116
type sendOverlayOpts struct {
94117
authKey string
95118
clientAuth overlay.ClientAuth
@@ -99,10 +122,12 @@ type sendOverlayOpts struct {
99122

100123
func cpCmd() *serpent.Command {
101124
var (
102-
verbose bool
103-
logger = new(slog.Logger)
104-
logf = func(str string, args ...any) {}
125+
verbose bool
126+
derpmapFi string
127+
logger = new(slog.Logger)
128+
logf = func(str string, args ...any) {}
105129

130+
dm = new(tailcfg.DERPMap)
106131
overlayOpts = new(sendOverlayOpts)
107132
send = new(overlay.Send)
108133
)
@@ -119,12 +144,13 @@ func cpCmd() *serpent.Command {
119144
serpent.RequireNArgs(1),
120145
initLogger(&verbose, ptr.To(false), logger, &logf),
121146
initAuth(&overlayOpts.authKey, &overlayOpts.clientAuth),
122-
sendOverlayMW(overlayOpts, &send, logger, &logf),
147+
derpMap(&derpmapFi, dm),
148+
sendOverlayMW(overlayOpts, &send, logger, dm, &logf),
123149
),
124150
Handler: func(inv *serpent.Invocation) error {
125151
ctx := inv.Context()
126152

127-
s, err := tsserver.NewServer(ctx, logger, send)
153+
s, err := tsserver.NewServer(ctx, logger, send, dm)
128154
if err != nil {
129155
return err
130156
}
@@ -215,6 +241,12 @@ func cpCmd() *serpent.Command {
215241
Default: "",
216242
Value: serpent.StringOf(&overlayOpts.authKey),
217243
},
244+
{
245+
Flag: "derp-config-file",
246+
Description: "File which specifies the DERP config to use. In the structure of https://pkg.go.dev/[email protected]/tailcfg#DERPMap. By default, https://controlplane.tailscale.com/derpmap/default is used.",
247+
Default: "",
248+
Value: serpent.StringOf(&derpmapFi),
249+
},
218250
{
219251
Flag: "stun-ip-override",
220252
Default: "",

cmd/wush/portforward.go

+15-7
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import (
1515

1616
"golang.org/x/xerrors"
1717
"tailscale.com/net/netns"
18+
"tailscale.com/tailcfg"
1819
"tailscale.com/tsnet"
1920
"tailscale.com/types/ptr"
2021

@@ -27,10 +28,12 @@ import (
2728

2829
func portForwardCmd() *serpent.Command {
2930
var (
30-
verbose bool
31-
logger = new(slog.Logger)
32-
logf = func(str string, args ...any) {}
31+
verbose bool
32+
derpmapFi string
33+
logger = new(slog.Logger)
34+
logf = func(str string, args ...any) {}
3335

36+
dm = new(tailcfg.DERPMap)
3437
overlayOpts = new(sendOverlayOpts)
3538
send = new(overlay.Send)
3639
tcpForwards []string // <port>:<port>
@@ -64,7 +67,8 @@ func portForwardCmd() *serpent.Command {
6467
Middleware: serpent.Chain(
6568
initLogger(&verbose, ptr.To(false), logger, &logf),
6669
initAuth(&overlayOpts.authKey, &overlayOpts.clientAuth),
67-
sendOverlayMW(overlayOpts, &send, logger, &logf),
70+
derpMap(nil, dm),
71+
sendOverlayMW(overlayOpts, &send, logger, dm, &logf),
6872
),
6973
Handler: func(inv *serpent.Invocation) error {
7074
ctx, cancel := context.WithCancel(inv.Context())
@@ -78,7 +82,7 @@ func portForwardCmd() *serpent.Command {
7882
return errors.New("no port-forwards requested")
7983
}
8084

81-
s, err := tsserver.NewServer(ctx, logger, send)
85+
s, err := tsserver.NewServer(ctx, logger, send, dm)
8286
if err != nil {
8387
return err
8488
}
@@ -97,8 +101,6 @@ func portForwardCmd() *serpent.Command {
97101
if err != nil {
98102
return err
99103
}
100-
ts.Logf = func(string, ...any) {}
101-
ts.UserLogf = func(string, ...any) {}
102104

103105
logf("Bringing WireGuard up..")
104106
ts.Up(ctx)
@@ -179,6 +181,12 @@ func portForwardCmd() *serpent.Command {
179181
Default: "",
180182
Value: serpent.StringOf(&overlayOpts.authKey),
181183
},
184+
{
185+
Flag: "derp-config-file",
186+
Description: "File which specifies the DERP config to use. In the structure of https://pkg.go.dev/[email protected]/tailcfg#DERPMap.",
187+
Default: "",
188+
Value: serpent.StringOf(&derpmapFi),
189+
},
182190
{
183191
Flag: "stun-ip-override",
184192
Default: "",

cmd/wush/serve.go

+15-5
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import (
2020
"golang.org/x/xerrors"
2121
"tailscale.com/ipn/store"
2222
"tailscale.com/net/netns"
23+
"tailscale.com/tailcfg"
2324
"tailscale.com/tsnet"
2425

2526
cslog "cdr.dev/slog"
@@ -38,12 +39,18 @@ func serveCmd() *serpent.Command {
3839
verbose bool
3940
enabled = []string{}
4041
disabled = []string{}
42+
derpmapFi string
43+
44+
dm = new(tailcfg.DERPMap)
4145
)
4246
return &serpent.Command{
4347
Use: "serve",
4448
Aliases: []string{"host"},
4549
Short: "Run the wush server.",
4650
Long: "Runs the wush server. Allows other wush CLIs to connect to this computer.",
51+
Middleware: serpent.Chain(
52+
derpMap(&derpmapFi, dm),
53+
),
4754
Handler: func(inv *serpent.Invocation) error {
4855
ctx := inv.Context()
4956
var logSink io.Writer = io.Discard
@@ -54,12 +61,9 @@ func serveCmd() *serpent.Command {
5461
hlog := func(format string, args ...any) {
5562
fmt.Fprintf(inv.Stderr, format+"\n", args...)
5663
}
57-
dm, err := tsserver.DERPMapTailscale(ctx)
58-
if err != nil {
59-
return err
60-
}
6164
r := overlay.NewReceiveOverlay(logger, hlog, dm)
6265

66+
var err error
6367
switch overlayType {
6468
case "derp":
6569
err = r.PickDERPHome(ctx)
@@ -89,7 +93,7 @@ func serveCmd() *serpent.Command {
8993
hlog("The auth key has been printed to stdout")
9094
}
9195

92-
s, err := tsserver.NewServer(ctx, logger, r)
96+
s, err := tsserver.NewServer(ctx, logger, r, dm)
9397
if err != nil {
9498
return err
9599
}
@@ -209,6 +213,12 @@ func serveCmd() *serpent.Command {
209213
Default: "",
210214
Value: serpent.EnumArrayOf(&disabled, "ssh", "cp", "port-forward"),
211215
},
216+
{
217+
Flag: "derp-config-file",
218+
Description: "File which specifies the DERP config to use. In the structure of https://pkg.go.dev/[email protected]/tailcfg#DERPMap.",
219+
Default: "",
220+
Value: serpent.StringOf(&derpmapFi),
221+
},
212222
},
213223
}
214224
}

cmd/wush/ssh.go

+16-6
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,13 @@ import (
2121

2222
func sshCmd() *serpent.Command {
2323
var (
24-
verbose bool
25-
quiet bool
26-
logger = new(slog.Logger)
27-
logf = func(str string, args ...any) {}
24+
verbose bool
25+
quiet bool
26+
derpmapFi string
27+
logger = new(slog.Logger)
28+
logf = func(str string, args ...any) {}
29+
30+
dm = new(tailcfg.DERPMap)
2831
overlayOpts = new(sendOverlayOpts)
2932
send = new(overlay.Send)
3033
)
@@ -37,12 +40,13 @@ func sshCmd() *serpent.Command {
3740
Middleware: serpent.Chain(
3841
initLogger(&verbose, &quiet, logger, &logf),
3942
initAuth(&overlayOpts.authKey, &overlayOpts.clientAuth),
40-
sendOverlayMW(overlayOpts, &send, logger, &logf),
43+
derpMap(&derpmapFi, dm),
44+
sendOverlayMW(overlayOpts, &send, logger, dm, &logf),
4145
),
4246
Handler: func(inv *serpent.Invocation) error {
4347
ctx := inv.Context()
4448

45-
s, err := tsserver.NewServer(ctx, logger, send)
49+
s, err := tsserver.NewServer(ctx, logger, send, dm)
4650
if err != nil {
4751
return err
4852
}
@@ -93,6 +97,12 @@ func sshCmd() *serpent.Command {
9397
Default: "",
9498
Value: serpent.StringOf(&overlayOpts.authKey),
9599
},
100+
{
101+
Flag: "derp-config-file",
102+
Description: "File which specifies the DERP config to use. In the structure of https://pkg.go.dev/[email protected]/tailcfg#DERPMap.",
103+
Default: "",
104+
Value: serpent.StringOf(&derpmapFi),
105+
},
96106
{
97107
Flag: "stun-ip-override",
98108
Default: "",

tsserver/server.go

+1-6
Original file line numberDiff line numberDiff line change
@@ -64,12 +64,7 @@ func DERPMapTailscale(ctx context.Context) (*tailcfg.DERPMap, error) {
6464
return dm, nil
6565
}
6666

67-
func NewServer(ctx context.Context, logger *slog.Logger, ov overlay.Overlay) (*server, error) {
68-
dm, err := DERPMapTailscale(ctx)
69-
if err != nil {
70-
return nil, err
71-
}
72-
67+
func NewServer(ctx context.Context, logger *slog.Logger, ov overlay.Overlay, dm *tailcfg.DERPMap) (*server, error) {
7368
s := &server{
7469
logger: logger,
7570
noisePrivateKey: key.NewMachine(),

0 commit comments

Comments
 (0)