@@ -23,14 +23,14 @@ import (
23
23
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
24
24
25
25
"cdr.dev/slog"
26
+ "github.com/coder/coder/cryptorand"
26
27
)
27
28
28
- const (
29
- EndpointWireguard = "wg-tunnel-udp.coder.app"
30
- EndpointHTTPS = "wg-tunnel.coder.app"
29
+ var (
30
+ v0EndpointHTTPS = "wg-tunnel.coder.app"
31
31
32
- ServerPublicKey = "+KNSMwed/IlqoesvTMSBNsHFaKVLrmmaCkn0bxIhUg0="
33
- ServerUUID = "fcad0000-0000-4000-8000-000000000001"
32
+ v0ServerPublicKey = "+KNSMwed/IlqoesvTMSBNsHFaKVLrmmaCkn0bxIhUg0="
33
+ v0ServerIP = netip . AddrFrom16 ( uuid . MustParse ( "fcad0000-0000-4000-8000-000000000001" ))
34
34
)
35
35
36
36
type Tunnel struct {
@@ -39,47 +39,54 @@ type Tunnel struct {
39
39
}
40
40
41
41
type Config struct {
42
+ Version int `json:"version"`
42
43
ID uuid.UUID `json:"id"`
43
44
PrivateKey device.NoisePrivateKey `json:"private_key"`
44
45
PublicKey device.NoisePublicKey `json:"public_key"`
46
+
47
+ Tunnel Node `json:"tunnel"`
45
48
}
46
49
type configExt struct {
50
+ Version int `json:"-"`
47
51
ID uuid.UUID `json:"id"`
48
52
PrivateKey device.NoisePrivateKey `json:"-"`
49
53
PublicKey device.NoisePublicKey `json:"public_key"`
54
+
55
+ Tunnel Node `json:"-"`
50
56
}
51
57
52
58
// NewWithConfig calls New with the given config. For documentation, see New.
53
59
func NewWithConfig (ctx context.Context , logger slog.Logger , cfg Config ) (* Tunnel , <- chan error , error ) {
54
- routineEnd , err := startUpdateRoutine (ctx , logger , cfg )
60
+ server , routineEnd , err := startUpdateRoutine (ctx , logger , cfg )
55
61
if err != nil {
56
62
return nil , nil , xerrors .Errorf ("start update routine: %w" , err )
57
63
}
58
64
59
65
tun , tnet , err := netstack .CreateNetTUN (
60
- []netip.Addr {netip . AddrFrom16 ( cfg . ID ) },
66
+ []netip.Addr {server . ClientIP },
61
67
[]netip.Addr {netip .AddrFrom4 ([4 ]byte {1 , 1 , 1 , 1 })},
62
68
1280 ,
63
69
)
64
70
if err != nil {
65
71
return nil , nil , xerrors .Errorf ("create net TUN: %w" , err )
66
72
}
67
73
68
- wgip , err := net .ResolveIPAddr ("ip" , EndpointWireguard )
74
+ wgip , err := net .ResolveIPAddr ("ip" , cfg . Tunnel . HostnameWireguard )
69
75
if err != nil {
70
76
return nil , nil , xerrors .Errorf ("resolve endpoint: %w" , err )
71
77
}
72
78
73
79
dev := device .NewDevice (tun , conn .NewDefaultBind (), device .NewLogger (device .LogLevelSilent , "" ))
74
80
err = dev .IpcSet (fmt .Sprintf (`private_key=%s
75
81
public_key=%s
76
- endpoint=%s:55555
82
+ endpoint=%s:%d
77
83
persistent_keepalive_interval=21
78
84
allowed_ip=%s/128` ,
79
85
hex .EncodeToString (cfg .PrivateKey [:]),
80
- encodeBase64ToHex ( ServerPublicKey ) ,
86
+ server . ServerPublicKey ,
81
87
wgip .IP .String (),
82
- netip .AddrFrom16 (uuid .MustParse (ServerUUID )).String (),
88
+ cfg .Tunnel .WireguardPort ,
89
+ server .ServerIP .String (),
83
90
))
84
91
if err != nil {
85
92
return nil , nil , xerrors .Errorf ("configure wireguard ipc: %w" , err )
@@ -110,7 +117,7 @@ allowed_ip=%s/128`,
110
117
}()
111
118
112
119
return & Tunnel {
113
- URL : fmt .Sprintf ("https://%s.%s " , cfg . ID , EndpointHTTPS ),
120
+ URL : fmt .Sprintf ("https://%s" , server . Hostname ),
114
121
Listener : wgListen ,
115
122
}, ch , nil
116
123
}
@@ -129,11 +136,11 @@ func New(ctx context.Context, logger slog.Logger) (*Tunnel, <-chan error, error)
129
136
return NewWithConfig (ctx , logger , cfg )
130
137
}
131
138
132
- func startUpdateRoutine (ctx context.Context , logger slog.Logger , cfg Config ) (<- chan struct {}, error ) {
139
+ func startUpdateRoutine (ctx context.Context , logger slog.Logger , cfg Config ) (ServerResponse , <- chan struct {}, error ) {
133
140
// Ensure we send the first config before spawning in the background.
134
- _ , err := sendConfigToServer (ctx , cfg )
141
+ res , err := sendConfigToServer (ctx , cfg )
135
142
if err != nil {
136
- return nil , xerrors .Errorf ("send config to server: %w" , err )
143
+ return ServerResponse {}, nil , xerrors .Errorf ("send config to server: %w" , err )
137
144
}
138
145
139
146
endCh := make (chan struct {})
@@ -156,29 +163,67 @@ func startUpdateRoutine(ctx context.Context, logger slog.Logger, cfg Config) (<-
156
163
}
157
164
}
158
165
}()
159
- return endCh , nil
166
+ return res , endCh , nil
167
+ }
168
+
169
+ type ServerResponse struct {
170
+ Hostname string `json:"hostname"`
171
+ ServerIP netip.Addr `json:"server_ip"`
172
+ ServerPublicKey string `json:"server_public_key"` // hex
173
+ ClientIP netip.Addr `json:"client_ip"`
160
174
}
161
175
162
- func sendConfigToServer (ctx context.Context , cfg Config ) (created bool , err error ) {
176
+ func sendConfigToServer (ctx context.Context , cfg Config ) (ServerResponse , error ) {
163
177
raw , err := json .Marshal (configExt (cfg ))
164
178
if err != nil {
165
- return false , xerrors .Errorf ("marshal config: %w" , err )
179
+ return ServerResponse {} , xerrors .Errorf ("marshal config: %w" , err )
166
180
}
167
181
168
- req , err := http .NewRequestWithContext (ctx , "POST" , "https://" + EndpointHTTPS + "/tun" , bytes .NewReader (raw ))
169
- if err != nil {
170
- return false , xerrors .Errorf ("new request: %w" , err )
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 )
171
198
}
172
199
173
200
res , err := http .DefaultClient .Do (req )
174
201
if err != nil {
175
- return false , xerrors .Errorf ("do request: %w" , err )
202
+ return ServerResponse {} , xerrors .Errorf ("do request: %w" , err )
176
203
}
204
+ defer res .Body .Close ()
205
+
206
+ 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
+ }
177
220
178
- _ , _ = io .Copy (io .Discard , res .Body )
179
- _ = res .Body .Close ()
221
+ default :
222
+ _ , _ = io .Copy (io .Discard , res .Body )
223
+ return ServerResponse {}, xerrors .Errorf ("unknown config version: %d" , cfg .Version )
224
+ }
180
225
181
- return res . StatusCode == http . StatusCreated , nil
226
+ return resp , nil
182
227
}
183
228
184
229
func cfgPath () (string , error ) {
@@ -227,6 +272,15 @@ func readOrGenerateConfig() (Config, error) {
227
272
return Config {}, xerrors .Errorf ("unmarshal config: %w" , err )
228
273
}
229
274
275
+ 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 ,
281
+ }
282
+ }
283
+
230
284
return cfg , nil
231
285
}
232
286
@@ -235,25 +289,25 @@ func GenerateConfig() (Config, error) {
235
289
if err != nil {
236
290
return Config {}, xerrors .Errorf ("generate private key: %w" , err )
237
291
}
238
-
239
292
pub := priv .PublicKey ()
240
293
294
+ node , err := FindClosestNode ()
295
+ if err != nil {
296
+ region := Regions [0 ]
297
+ n , _ := cryptorand .Intn (len (region .Nodes ))
298
+ node = region .Nodes [n ]
299
+ _ , _ = fmt .Println ("Error picking closest dev tunnel:" , err )
300
+ _ , _ = fmt .Println ("Defaulting to" , Regions [0 ].LocationName )
301
+ }
302
+
241
303
return Config {
242
- ID : newUUID () ,
304
+ Version : 1 ,
243
305
PrivateKey : device .NoisePrivateKey (priv ),
244
306
PublicKey : device .NoisePublicKey (pub ),
307
+ Tunnel : node ,
245
308
}, nil
246
309
}
247
310
248
- func newUUID () uuid.UUID {
249
- u := uuid .New ()
250
- // 0xfc is the IPV6 prefix for internal networks.
251
- u [0 ] = 0xfc
252
- u [1 ] = 0xca
253
-
254
- return u
255
- }
256
-
257
311
func writeConfig (cfg Config ) error {
258
312
cfgFi , err := cfgPath ()
259
313
if err != nil {
0 commit comments