@@ -72,7 +72,8 @@ type wgtun struct {
72
72
id string // id
73
73
addrs []netip.Prefix // interface addresses
74
74
allowed []netip.Prefix // allowed ips (peers)
75
- remote * multihost.MH // remote endpoints
75
+ peers map [string ]any // peer (remote endpoint) public keys
76
+ remote * multihost.MH // peer (remote endpoint) addrs
76
77
status int // status of this interface
77
78
stack * stack.Stack // stack fakes tun device for wg
78
79
ep * channel.Endpoint // reads and writes packets to/from stack
@@ -105,7 +106,7 @@ type wgproxy struct {
105
106
type WgProxy interface {
106
107
Proxy
107
108
tun.Device
108
- canUpdate (id , txt string ) bool
109
+ update (id , txt string ) bool
109
110
IpcSet (txt string ) error
110
111
}
111
112
@@ -183,40 +184,43 @@ func stripPrefixIfNeeded(id string) string {
183
184
return strings .TrimPrefix (id , FAST )
184
185
}
185
186
186
- func (w * wgproxy ) canUpdate (id , txt string ) bool {
187
+ // canUpdate checks if the existing tunnel can be updated in-place;
188
+ // that is, incoming interface config is compatible with the existing tunnel,
189
+ // regardless of whether peer config has changed (which can be updated in-place).
190
+ func (w * wgproxy ) update (id , txt string ) bool {
187
191
const reuse = true // can update in-place; reuse existing tunnel
188
192
const anew = false // cannot update in-place; create new tunnel
189
193
if w .status == END {
190
- log .W ("proxy: wg: !canUpdate (%s<>%s): END; status(%d)" , id , w .id , w .status )
194
+ log .W ("proxy: wg: !update (%s<>%s): END; status(%d)" , id , w .id , w .status )
191
195
return anew
192
196
}
193
197
194
198
incomingPrefersOffload := preferOffload (id )
195
199
if incomingPrefersOffload != w .preferOffload {
196
- log .W ("proxy: wg: !canUpdate (%s): preferOffload() %t != %t" , id , incomingPrefersOffload , w .preferOffload )
200
+ log .W ("proxy: wg: !update (%s): preferOffload() %t != %t" , id , incomingPrefersOffload , w .preferOffload )
197
201
return anew
198
202
}
199
203
200
204
// str copy: go.dev/play/p/eO814kGGNtO
201
205
cptxt := txt
202
- ifaddrs , _ , dnsh , _ , mtu , err := wgIfConfigOf (w .id , & cptxt )
206
+ ifaddrs , allowed , peers , dnsh , peersh , mtu , err := wgIfConfigOf (w .id , & cptxt )
203
207
if err != nil {
204
- log .W ("proxy: wg: !canUpdate (%s): err: %v" , w .id , err )
208
+ log .W ("proxy: wg: !update (%s): err: %v" , w .id , err )
205
209
return anew
206
210
}
207
211
208
212
if len (ifaddrs ) != len (w .addrs ) {
209
- log .D ("proxy: wg: !canUpdate (%s): len(ifaddrs) %d != %d" , w .id , len (ifaddrs ), len (w .addrs ))
213
+ log .D ("proxy: wg: !update (%s): len(ifaddrs) %d != %d" , w .id , len (ifaddrs ), len (w .addrs ))
210
214
return anew
211
215
}
212
216
213
217
actualmtu := calcTunMtu (mtu )
214
218
if w .mtu != actualmtu {
215
- log .D ("proxy: wg: !canUpdate (%s): mtu %d != %d" , w .id , actualmtu , w .mtu )
219
+ log .D ("proxy: wg: !update (%s): mtu %d != %d" , w .id , actualmtu , w .mtu )
216
220
return anew
217
221
}
218
222
if dnsh != nil && ! dnsh .EqualAddrs (w .dns ) {
219
- log .D ("proxy: wg: !canUpdate (%s): new/mismatched dns" , w .id )
223
+ log .D ("proxy: wg: !update (%s): new/mismatched dns" , w .id )
220
224
return anew
221
225
}
222
226
@@ -231,10 +235,20 @@ func (w *wgproxy) canUpdate(id, txt string) bool {
231
235
}
232
236
}
233
237
if ! ipok {
234
- log .D ("proxy: wg: !canUpdate (%s): new ifaddrs (%s) != (%s)" , w .id , ifaddrs , w .addrs )
238
+ log .D ("proxy: wg: !update (%s): new ifaddrs (%s) != (%s)" , w .id , ifaddrs , w .addrs )
235
239
return anew
236
240
}
237
241
}
242
+
243
+ // reusing existing tunnel (interface config unchanged)
244
+ // but peer config may have changed!
245
+ log .I ("proxy: wg: update(%s): reuse; allowed: %d->%d; peers: %d->%d; dns: %d->%d; endpoint: %d->%d" ,
246
+ w .id , len (w .allowed ), len (allowed ), len (w .peers ), len (peers ), w .dns .Len (), dnsh .Len (), w .remote .Len (), peersh .Len ())
247
+ w .allowed = allowed
248
+ w .peers = peers
249
+ w .remote = peersh // requires refresh
250
+ w .dns = dnsh // requires refresh
251
+
238
252
return reuse
239
253
}
240
254
@@ -250,12 +264,13 @@ func wglogger(id string) *device.Logger {
250
264
return logger
251
265
}
252
266
253
- func wgIfConfigOf (id string , txtptr * string ) (ifaddrs []netip.Prefix , allowedaddrs []netip.Prefix , dnsh , endpointh * multihost.MH , mtu int , err error ) {
267
+ func wgIfConfigOf (id string , txtptr * string ) (ifaddrs []netip.Prefix , allowedaddrs []netip.Prefix , peers map [ string ] any , dnsh , endpointh * multihost.MH , mtu int , err error ) {
254
268
txt := * txtptr
255
269
pcfg := strings.Builder {}
256
270
r := bufio .NewScanner (strings .NewReader (txt ))
257
271
dnsh = multihost .New (id + "dns" )
258
272
endpointh = multihost .New (id + "endpoint" )
273
+ peers = make (map [string ]any )
259
274
for r .Scan () {
260
275
line := r .Text ()
261
276
if len (line ) <= 0 {
@@ -270,11 +285,13 @@ func wgIfConfigOf(id string, txtptr *string) (ifaddrs []netip.Prefix, allowedadd
270
285
err = fmt .Errorf ("proxy: wg: %s failed to parse line %q" , id , line )
271
286
return
272
287
}
288
+ untouchedv := v
273
289
k = strings .ToLower (strings .TrimSpace (k ))
274
290
v = strings .ToLower (strings .TrimSpace (v ))
275
291
276
- // process interface config; Address, DNS, ListenPort, MTU
292
+ // process interface & peer config; Address, DNS, ListenPort, MTU, Allowed IPs, Endpoint
277
293
// github.com/WireGuard/wireguard-android/blob/713947e432/tunnel/src/main/java/com/wireguard/config/Interface.java#L232
294
+ // github.com/WireGuard/wireguard-android/blob/713947e432/tunnel/src/main/java/com/wireguard/config/Peer.java#L176
278
295
switch k {
279
296
case "address" : // may exist more than once
280
297
if err = loadIPNets (& ifaddrs , v ); err != nil {
@@ -290,13 +307,18 @@ func wgIfConfigOf(id string, txtptr *string) (ifaddrs []netip.Prefix, allowedadd
290
307
if err = loadIPNets (& allowedaddrs , v ); err != nil {
291
308
return
292
309
}
293
- // carry over allowed_ips
310
+ // peer config: carry over allowed_ips
294
311
log .D ("proxy: wg: %s ifconfig: skipping key %q" , id , k )
295
312
pcfg .WriteString (line + "\n " )
296
313
case "endpoint" : // may exist more than once
297
314
// TODO: endpoint could be v4 or v6 or a hostname
298
315
loadMH (endpointh , v )
299
- // carry over endpoints
316
+ // peer config: carry over endpoints
317
+ log .D ("proxy: wg: %s ifconfig: skipping key %q" , id , k )
318
+ pcfg .WriteString (line + "\n " )
319
+ case "public_key" :
320
+ peers [untouchedv ] = struct {}{}
321
+ // peer config: carry over public keys
300
322
log .D ("proxy: wg: %s ifconfig: skipping key %q" , id , k )
301
323
pcfg .WriteString (line + "\n " )
302
324
default :
@@ -372,14 +394,14 @@ func bindWgSockets(id, addrport string, wgdev *device.Device, ctl protect.Contro
372
394
373
395
// ref: github.com/WireGuard/wireguard-android/blob/713947e432/tunnel/tools/libwg-go/api-android.go#L76
374
396
func NewWgProxy (id string , ctl protect.Controller , cfg string ) (WgProxy , error ) {
375
- ifaddrs , allowedaddrs , dnsh , endpointh , mtu , err := wgIfConfigOf (id , & cfg )
397
+ ifaddrs , allowedaddrs , peers , dnsh , endpointh , mtu , err := wgIfConfigOf (id , & cfg )
376
398
uapicfg := cfg
377
399
if err != nil {
378
400
log .E ("proxy: wg: %s failed to get addrs from config %v" , id , err )
379
401
return nil , err
380
402
}
381
403
382
- wgtun , err := makeWgTun (id , ifaddrs , allowedaddrs , dnsh , endpointh , mtu )
404
+ wgtun , err := makeWgTun (id , ifaddrs , allowedaddrs , peers , dnsh , endpointh , mtu )
383
405
if err != nil {
384
406
log .E ("proxy: wg: %s failed to create tun %v" , id , err )
385
407
return nil , err
@@ -426,13 +448,13 @@ func NewWgProxy(id string, ctl protect.Controller, cfg string) (WgProxy, error)
426
448
w .rd = newRDial (w )
427
449
w .hc = newHTTPClient (w .rd )
428
450
429
- log .D ("proxy: wg: new %s; addrs(%v) mtu(%d/%d) / v4(%t) v6(%t)" , id , ifaddrs , mtu , calcTunMtu (mtu ), wgtun .hasV4 , wgtun .hasV6 )
451
+ log .D ("proxy: wg: new %s; addrs(%v) mtu(%d/%d) peers(%d) / v4(%t) v6(%t)" , id , ifaddrs , mtu , calcTunMtu (mtu ), len ( peers ), wgtun .hasV4 , wgtun .hasV6 )
430
452
431
453
return w , nil
432
454
}
433
455
434
456
// ref: github.com/WireGuard/wireguard-go/blob/469159ecf7/tun/netstack/tun.go#L54
435
- func makeWgTun (id string , ifaddrs , allowedaddrs []netip.Prefix , dnsm , endpointm * multihost.MH , mtu int ) (* wgtun , error ) {
457
+ func makeWgTun (id string , ifaddrs , allowedaddrs []netip.Prefix , peers map [ string ] any , dnsm , endpointm * multihost.MH , mtu int ) (* wgtun , error ) {
436
458
opts := stack.Options {
437
459
NetworkProtocols : []stack.NetworkProtocolFactory {ipv4 .NewProtocol , ipv6 .NewProtocol },
438
460
TransportProtocols : []stack.TransportProtocolFactory {tcp .NewProtocol , udp .NewProtocol , icmp .NewProtocol6 , icmp .NewProtocol4 },
@@ -449,6 +471,7 @@ func makeWgTun(id string, ifaddrs, allowedaddrs []netip.Prefix, dnsm, endpointm
449
471
id : stripPrefixIfNeeded (id ),
450
472
addrs : ifaddrs ,
451
473
allowed : allowedaddrs ,
474
+ peers : peers ,
452
475
remote : endpointm , // may be nil
453
476
ep : ep ,
454
477
stack : s ,
0 commit comments