Skip to content

Commit 155fce3

Browse files
committed
ipn/wg: store peer keys; keep other peercfg updated
1 parent 6e4a45b commit 155fce3

File tree

2 files changed

+44
-21
lines changed

2 files changed

+44
-21
lines changed

intra/ipn/proxy.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,10 @@ func (pxr *proxifier) addProxy(id, txt string) (p Proxy, err error) {
3131
// wireguard proxies have IDs starting with "wg"
3232
if strings.HasPrefix(id, WG) {
3333
if p, _ = pxr.ProxyFor(id); p != nil {
34-
if wgp, ok := p.(WgProxy); ok && wgp.canUpdate(id, txt) {
34+
if wgp, ok := p.(WgProxy); ok && wgp.update(id, txt) {
3535
log.I("proxy: updating wg %s/%s", id, p.GetAddr())
3636

37-
ifaddrs, _, dnsh, _, mtu, err0 := wgIfConfigOf(id, &txt) // removes wg ifconfig from txt
37+
ifaddrs, _, _, dnsh, _, mtu, err0 := wgIfConfigOf(id, &txt) // removes wg ifconfig from txt
3838
if err0 != nil {
3939
log.W("proxy: err0 updating wg(%s); %v", id, err0)
4040
return nil, err0

intra/ipn/wgproxy.go

Lines changed: 42 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,8 @@ type wgtun struct {
7272
id string // id
7373
addrs []netip.Prefix // interface addresses
7474
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
7677
status int // status of this interface
7778
stack *stack.Stack // stack fakes tun device for wg
7879
ep *channel.Endpoint // reads and writes packets to/from stack
@@ -105,7 +106,7 @@ type wgproxy struct {
105106
type WgProxy interface {
106107
Proxy
107108
tun.Device
108-
canUpdate(id, txt string) bool
109+
update(id, txt string) bool
109110
IpcSet(txt string) error
110111
}
111112

@@ -183,40 +184,43 @@ func stripPrefixIfNeeded(id string) string {
183184
return strings.TrimPrefix(id, FAST)
184185
}
185186

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 {
187191
const reuse = true // can update in-place; reuse existing tunnel
188192
const anew = false // cannot update in-place; create new tunnel
189193
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)
191195
return anew
192196
}
193197

194198
incomingPrefersOffload := preferOffload(id)
195199
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)
197201
return anew
198202
}
199203

200204
// str copy: go.dev/play/p/eO814kGGNtO
201205
cptxt := txt
202-
ifaddrs, _, dnsh, _, mtu, err := wgIfConfigOf(w.id, &cptxt)
206+
ifaddrs, allowed, peers, dnsh, peersh, mtu, err := wgIfConfigOf(w.id, &cptxt)
203207
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)
205209
return anew
206210
}
207211

208212
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))
210214
return anew
211215
}
212216

213217
actualmtu := calcTunMtu(mtu)
214218
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)
216220
return anew
217221
}
218222
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)
220224
return anew
221225
}
222226

@@ -231,10 +235,20 @@ func (w *wgproxy) canUpdate(id, txt string) bool {
231235
}
232236
}
233237
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)
235239
return anew
236240
}
237241
}
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+
238252
return reuse
239253
}
240254

@@ -250,12 +264,13 @@ func wglogger(id string) *device.Logger {
250264
return logger
251265
}
252266

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) {
254268
txt := *txtptr
255269
pcfg := strings.Builder{}
256270
r := bufio.NewScanner(strings.NewReader(txt))
257271
dnsh = multihost.New(id + "dns")
258272
endpointh = multihost.New(id + "endpoint")
273+
peers = make(map[string]any)
259274
for r.Scan() {
260275
line := r.Text()
261276
if len(line) <= 0 {
@@ -270,11 +285,13 @@ func wgIfConfigOf(id string, txtptr *string) (ifaddrs []netip.Prefix, allowedadd
270285
err = fmt.Errorf("proxy: wg: %s failed to parse line %q", id, line)
271286
return
272287
}
288+
untouchedv := v
273289
k = strings.ToLower(strings.TrimSpace(k))
274290
v = strings.ToLower(strings.TrimSpace(v))
275291

276-
// process interface config; Address, DNS, ListenPort, MTU
292+
// process interface & peer config; Address, DNS, ListenPort, MTU, Allowed IPs, Endpoint
277293
// 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
278295
switch k {
279296
case "address": // may exist more than once
280297
if err = loadIPNets(&ifaddrs, v); err != nil {
@@ -290,13 +307,18 @@ func wgIfConfigOf(id string, txtptr *string) (ifaddrs []netip.Prefix, allowedadd
290307
if err = loadIPNets(&allowedaddrs, v); err != nil {
291308
return
292309
}
293-
// carry over allowed_ips
310+
// peer config: carry over allowed_ips
294311
log.D("proxy: wg: %s ifconfig: skipping key %q", id, k)
295312
pcfg.WriteString(line + "\n")
296313
case "endpoint": // may exist more than once
297314
// TODO: endpoint could be v4 or v6 or a hostname
298315
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
300322
log.D("proxy: wg: %s ifconfig: skipping key %q", id, k)
301323
pcfg.WriteString(line + "\n")
302324
default:
@@ -372,14 +394,14 @@ func bindWgSockets(id, addrport string, wgdev *device.Device, ctl protect.Contro
372394

373395
// ref: github.com/WireGuard/wireguard-android/blob/713947e432/tunnel/tools/libwg-go/api-android.go#L76
374396
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)
376398
uapicfg := cfg
377399
if err != nil {
378400
log.E("proxy: wg: %s failed to get addrs from config %v", id, err)
379401
return nil, err
380402
}
381403

382-
wgtun, err := makeWgTun(id, ifaddrs, allowedaddrs, dnsh, endpointh, mtu)
404+
wgtun, err := makeWgTun(id, ifaddrs, allowedaddrs, peers, dnsh, endpointh, mtu)
383405
if err != nil {
384406
log.E("proxy: wg: %s failed to create tun %v", id, err)
385407
return nil, err
@@ -426,13 +448,13 @@ func NewWgProxy(id string, ctl protect.Controller, cfg string) (WgProxy, error)
426448
w.rd = newRDial(w)
427449
w.hc = newHTTPClient(w.rd)
428450

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)
430452

431453
return w, nil
432454
}
433455

434456
// 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) {
436458
opts := stack.Options{
437459
NetworkProtocols: []stack.NetworkProtocolFactory{ipv4.NewProtocol, ipv6.NewProtocol},
438460
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
449471
id: stripPrefixIfNeeded(id),
450472
addrs: ifaddrs,
451473
allowed: allowedaddrs,
474+
peers: peers,
452475
remote: endpointm, // may be nil
453476
ep: ep,
454477
stack: s,

0 commit comments

Comments
 (0)