Skip to content

Commit 92ebdae

Browse files
authored
feat: force legacy tunnels to new version (coder#2914)
1 parent 59de95b commit 92ebdae

File tree

2 files changed

+39
-65
lines changed

2 files changed

+39
-65
lines changed

coderd/devtunnel/servers.go

+3-1
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ type Region struct {
2020

2121
type Node struct {
2222
ID int `json:"id"`
23+
RegionID int `json:"region_id"`
2324
HostnameHTTPS string `json:"hostname_https"`
2425
HostnameWireguard string `json:"hostname_wireguard"`
2526
WireguardPort uint16 `json:"wireguard_port"`
@@ -29,11 +30,12 @@ type Node struct {
2930

3031
var Regions = []Region{
3132
{
32-
ID: 1,
33+
ID: 0,
3334
LocationName: "US East Pittsburgh",
3435
Nodes: []Node{
3536
{
3637
ID: 1,
38+
RegionID: 0,
3739
HostnameHTTPS: "pit-1.try.coder.app",
3840
HostnameWireguard: "pit-1.try.coder.app",
3941
WireguardPort: 55551,

coderd/devtunnel/tunnel.go

+36-64
Original file line numberDiff line numberDiff line change
@@ -3,52 +3,42 @@ package devtunnel
33
import (
44
"bytes"
55
"context"
6-
"encoding/base64"
76
"encoding/hex"
87
"encoding/json"
98
"fmt"
10-
"io"
119
"net"
1210
"net/http"
1311
"net/netip"
1412
"os"
1513
"path/filepath"
1614
"time"
1715

18-
"github.com/google/uuid"
16+
"github.com/briandowns/spinner"
1917
"golang.org/x/xerrors"
2018
"golang.zx2c4.com/wireguard/conn"
2119
"golang.zx2c4.com/wireguard/device"
2220
"golang.zx2c4.com/wireguard/tun/netstack"
2321
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
2422

2523
"cdr.dev/slog"
24+
"github.com/coder/coder/cli/cliui"
2625
"github.com/coder/coder/cryptorand"
2726
)
2827

29-
var (
30-
v0EndpointHTTPS = "wg-tunnel.coder.app"
31-
32-
v0ServerPublicKey = "+KNSMwed/IlqoesvTMSBNsHFaKVLrmmaCkn0bxIhUg0="
33-
v0ServerIP = netip.AddrFrom16(uuid.MustParse("fcad0000-0000-4000-8000-000000000001"))
34-
)
35-
3628
type Tunnel struct {
3729
URL string
3830
Listener net.Listener
3931
}
4032

4133
type Config struct {
4234
Version int `json:"version"`
43-
ID uuid.UUID `json:"id"`
4435
PrivateKey device.NoisePrivateKey `json:"private_key"`
4536
PublicKey device.NoisePublicKey `json:"public_key"`
4637

4738
Tunnel Node `json:"tunnel"`
4839
}
4940
type configExt struct {
5041
Version int `json:"-"`
51-
ID uuid.UUID `json:"id"`
5242
PrivateKey device.NoisePrivateKey `json:"-"`
5343
PublicKey device.NoisePublicKey `json:"public_key"`
5444

@@ -146,7 +136,7 @@ func startUpdateRoutine(ctx context.Context, logger slog.Logger, cfg Config) (Se
146136
endCh := make(chan struct{})
147137
go func() {
148138
defer close(endCh)
149-
ticker := time.NewTicker(30 * time.Second)
139+
ticker := time.NewTicker(10 * time.Second)
150140
defer ticker.Stop()
151141

152142
for {
@@ -179,22 +169,9 @@ func sendConfigToServer(ctx context.Context, cfg Config) (ServerResponse, error)
179169
return ServerResponse{}, xerrors.Errorf("marshal config: %w", err)
180170
}
181171

182-
var req *http.Request
183-
switch cfg.Version {
184-
case 0:
185-
req, err = http.NewRequestWithContext(ctx, "POST", "https://"+v0EndpointHTTPS+"/tun", bytes.NewReader(raw))
186-
if err != nil {
187-
return ServerResponse{}, xerrors.Errorf("new request: %w", err)
188-
}
189-
190-
case 1:
191-
req, err = http.NewRequestWithContext(ctx, "POST", "https://"+cfg.Tunnel.HostnameHTTPS+"/tun", bytes.NewReader(raw))
192-
if err != nil {
193-
return ServerResponse{}, xerrors.Errorf("new request: %w", err)
194-
}
195-
196-
default:
197-
return ServerResponse{}, xerrors.Errorf("unknown config version: %d", cfg.Version)
172+
req, err := http.NewRequestWithContext(ctx, "POST", "https://"+cfg.Tunnel.HostnameHTTPS+"/tun", bytes.NewReader(raw))
173+
if err != nil {
174+
return ServerResponse{}, xerrors.Errorf("new request: %w", err)
198175
}
199176

200177
res, err := http.DefaultClient.Do(req)
@@ -204,23 +181,9 @@ func sendConfigToServer(ctx context.Context, cfg Config) (ServerResponse, error)
204181
defer res.Body.Close()
205182

206183
var resp ServerResponse
207-
switch cfg.Version {
208-
case 0:
209-
_, _ = io.Copy(io.Discard, res.Body)
210-
resp.Hostname = fmt.Sprintf("%s.%s", cfg.ID, v0EndpointHTTPS)
211-
resp.ServerIP = v0ServerIP
212-
resp.ServerPublicKey = encodeBase64ToHex(v0ServerPublicKey)
213-
resp.ClientIP = netip.AddrFrom16(cfg.ID)
214-
215-
case 1:
216-
err := json.NewDecoder(res.Body).Decode(&resp)
217-
if err != nil {
218-
return ServerResponse{}, xerrors.Errorf("decode response: %w", err)
219-
}
220-
221-
default:
222-
_, _ = io.Copy(io.Discard, res.Body)
223-
return ServerResponse{}, xerrors.Errorf("unknown config version: %d", cfg.Version)
184+
err = json.NewDecoder(res.Body).Decode(&resp)
185+
if err != nil {
186+
return ServerResponse{}, xerrors.Errorf("decode response: %w", err)
224187
}
225188

226189
return resp, nil
@@ -273,12 +236,22 @@ func readOrGenerateConfig() (Config, error) {
273236
}
274237

275238
if cfg.Version == 0 {
276-
cfg.Tunnel = Node{
277-
ID: 0,
278-
HostnameHTTPS: "wg-tunnel.coder.app",
279-
HostnameWireguard: "wg-tunnel-udp.coder.app",
280-
WireguardPort: 55555,
239+
_, _ = fmt.Println()
240+
_, _ = fmt.Println(cliui.Styles.Error.Render("You're running a deprecated tunnel version!"))
241+
_, _ = fmt.Println(cliui.Styles.Error.Render("Upgrading you to the new version now. You will need to rebuild running workspaces."))
242+
_, _ = fmt.Println()
243+
244+
cfg, err := GenerateConfig()
245+
if err != nil {
246+
return Config{}, xerrors.Errorf("generate config: %w", err)
247+
}
248+
249+
err = writeConfig(cfg)
250+
if err != nil {
251+
return Config{}, xerrors.Errorf("write config: %w", err)
281252
}
253+
254+
return cfg, nil
282255
}
283256

284257
return cfg, nil
@@ -291,15 +264,27 @@ func GenerateConfig() (Config, error) {
291264
}
292265
pub := priv.PublicKey()
293266

267+
spin := spinner.New(spinner.CharSets[39], 350*time.Millisecond)
268+
spin.Suffix = " Finding the closest tunnel region..."
269+
spin.Start()
270+
294271
node, err := FindClosestNode()
295272
if err != nil {
273+
// If we fail to find the closest node, default to US East.
296274
region := Regions[0]
297275
n, _ := cryptorand.Intn(len(region.Nodes))
298276
node = region.Nodes[n]
277+
spin.Stop()
299278
_, _ = fmt.Println("Error picking closest dev tunnel:", err)
300279
_, _ = fmt.Println("Defaulting to", Regions[0].LocationName)
301280
}
302281

282+
spin.Stop()
283+
_, _ = fmt.Printf("Using tunnel in %s with latency %s.\n",
284+
cliui.Styles.Keyword.Render(Regions[node.RegionID].LocationName),
285+
cliui.Styles.Code.Render(node.AvgLatency.String()),
286+
)
287+
303288
return Config{
304289
Version: 1,
305290
PrivateKey: device.NoisePrivateKey(priv),
@@ -326,16 +311,3 @@ func writeConfig(cfg Config) error {
326311

327312
return nil
328313
}
329-
330-
func encodeBase64ToHex(key string) string {
331-
decoded, err := base64.StdEncoding.DecodeString(key)
332-
if err != nil {
333-
panic(err)
334-
}
335-
336-
if len(decoded) != 32 {
337-
panic((xerrors.New("key should be 32 bytes: " + key)))
338-
}
339-
340-
return hex.EncodeToString(decoded)
341-
}

0 commit comments

Comments
 (0)