Skip to content

Commit fa0be64

Browse files
committed
ipn/wg: proton as rpn
1 parent 1187776 commit fa0be64

File tree

9 files changed

+1926
-24
lines changed

9 files changed

+1926
-24
lines changed

intra/backend/ipn_proxies.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ const ( // see ipn/proxies.go
1616
Auto = "Auto" // auto uses ipn.Exit or any of the RPN proxies
1717
RpnWg = WG + "w" + RPN // RPN Warp
1818
RpnAmz = WG + "a" + RPN // RPN Amnezia
19+
RpnPro = WG + "p" + RPN // RPN Proton
1920
RpnWs = PIPWS + RPN // RPN WebSockets
2021
RpnH2 = PIPH2 + RPN // RPN HTTP/2
2122
Rpn64 = NAT64 + RPN // RPN Exit hopping over NAT64
@@ -61,16 +62,22 @@ type Rpn interface {
6162
RegisterSE() error
6263
// RegisterAmnezia registers a new Amnezia installation.
6364
RegisterAmnezia(publicKeyBase64 string) (json []byte, err error)
65+
// RegisterProton registers a new Proton installation.
66+
RegisterProton(existingStateJson []byte, serversFile string) (json []byte, err error)
6467
// TestWarp connects to some Warp IPs and returns reachable ones.
6568
TestWarp() (ips string, errs error)
6669
// TestAmnezia connects to the Amnezia gateway and returns its IP if reachable.
6770
TestAmnezia() (ips string, errs error)
71+
// TestProton connects to the Proton gateway and returns its IP if reachable.
72+
TestProton() (ips string, errs error)
6873
// TestSE connects to some SurfEasy IPs and returns reachable ones.
6974
TestSE() (ips string, errs error)
7075
// TestExit64 connects to public NAT64 endpoints and returns reachable ones.
7176
TestExit64() (ips string, errs error)
7277
// Warp returns a RpnWg proxy.
7378
Warp() (wg Proxy, err error)
79+
// Proton returns a Proton WireGuard proxy.
80+
Proton() (wg Proxy, err error)
7481
// Amnezia returns a Amnezia WireGuard proxy.
7582
Amnezia() (awg Proxy, err error)
7683
// Pip returns a RpnWs proxy.

intra/backend/ipn_wgkeygen.go

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
package backend
1515

1616
import (
17+
"crypto/ed25519"
1718
"crypto/rand"
1819
"crypto/subtle"
1920
"encoding/base64"
@@ -26,7 +27,7 @@ import (
2627

2728
// from: github.com/WireGuard/wireguard-windows/blob/dcc0eb72a/conf/parser.go#L121
2829

29-
const klen = 32
30+
const klen = ed25519.SeedSize
3031

3132
type (
3233
eckey [klen]byte
@@ -83,6 +84,12 @@ func NewWgPrivateKey() (WgKey, error) {
8384
return k, nil
8485
}
8586

87+
func NewWgPrivateKeyFrom(k [klen]byte) WgKey {
88+
k[0] &= 248
89+
k[31] = (k[31] & 127) | 64
90+
return (*eckey)(&k)
91+
}
92+
8693
func parseKeyBase64(s string) (*eckey, error) {
8794
k, err := base64.StdEncoding.DecodeString(s)
8895
if err != nil {

intra/core/sched.go

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
// Copyright (c) 2024 RethinkDNS and its authors.
2+
//
3+
// This Source Code Form is subject to the terms of the Mozilla Public
4+
// License, v. 2.0. If a copy of the MPL was not distributed with this
5+
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
6+
7+
package core
8+
9+
import (
10+
"context"
11+
"errors"
12+
"sync"
13+
"time"
14+
)
15+
16+
var errNewJob = errors.New("sched: replaced by newer job")
17+
18+
type Job func() error
19+
20+
type ctl struct {
21+
who context.Context
22+
cancel context.CancelCauseFunc
23+
}
24+
25+
type Scheduler struct {
26+
ctx context.Context
27+
28+
mu sync.Mutex
29+
jobctl map[string]*ctl
30+
}
31+
32+
func NewScheduler(ctx context.Context) *Scheduler {
33+
return &Scheduler{
34+
ctx: ctx,
35+
jobctl: make(map[string]*ctl),
36+
}
37+
}
38+
39+
// At runs f at time t; accepts a Context to cancel it.
40+
func (s *Scheduler) At(id string, t time.Time, f Job) context.Context {
41+
s.mu.Lock()
42+
ctx, done := context.WithCancelCause(s.ctx)
43+
if c := s.jobctl[id]; c != nil {
44+
c.cancel(errNewJob) // dispose existing job
45+
}
46+
s.jobctl[id] = &ctl{who: ctx, cancel: done}
47+
s.mu.Unlock()
48+
49+
Go("at."+id, func() {
50+
var cause error
51+
52+
defer func() {
53+
done(cause)
54+
s.mu.Lock()
55+
if c := s.jobctl[id]; c != nil && c.who == ctx {
56+
delete(s.jobctl, id)
57+
}
58+
s.mu.Unlock()
59+
}()
60+
61+
select {
62+
case <-s.ctx.Done():
63+
cause = s.ctx.Err()
64+
return
65+
case <-time.After(time.Until(t)):
66+
cause = f()
67+
return
68+
}
69+
})
70+
return ctx
71+
}

intra/ipn/auto.go

Lines changed: 59 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ func (h *auto) dial(network, local, remote string) (protect.Conn, error) {
7474
exit, exerr := h.pxr.ProxyFor(Exit)
7575
exit64, ex64err := h.pxr.ProxyFor(Rpn64)
7676
warp, waerr := h.pxr.ProxyFor(RpnWg)
77+
pro, proerr := h.pxr.ProxyFor(RpnPro)
7778
amz, amzerr := h.pxr.ProxyFor(RpnAmz)
7879
sep, seerr := h.pxr.ProxyFor(RpnSE)
7980

@@ -104,6 +105,25 @@ func (h *auto) dial(network, local, remote string) (protect.Conn, error) {
104105
return h.dialIfReachable(exit, network, local, remote)
105106
}, func(ctx context.Context) (protect.Conn, error) {
106107
const myidx = 1
108+
if pro == nil { // exit must always be present
109+
return nil, proerr
110+
}
111+
if recent {
112+
if previdx != myidx {
113+
return nil, errNotPinned
114+
}
115+
// ip pinned to this proxy
116+
h.dialIfHealthy(pro, network, local, remote)
117+
}
118+
119+
select {
120+
case <-ctx.Done():
121+
return nil, ctx.Err()
122+
case <-time.After(shortdelay * myidx): // 100ms
123+
}
124+
return h.dialIfReachable(pro, network, local, remote)
125+
}, func(ctx context.Context) (protect.Conn, error) {
126+
const myidx = 2
107127
if warp == nil {
108128
return nil, waerr
109129
}
@@ -118,11 +138,11 @@ func (h *auto) dial(network, local, remote string) (protect.Conn, error) {
118138
select {
119139
case <-ctx.Done():
120140
return nil, ctx.Err()
121-
case <-time.After(shortdelay): // 100ms
141+
case <-time.After(shortdelay * myidx): // 200ms
122142
}
123143
return h.dialIfHealthy(warp, network, local, remote)
124144
}, func(ctx context.Context) (protect.Conn, error) {
125-
const myidx = 2
145+
const myidx = 3
126146
if exit64 == nil {
127147
return nil, ex64err
128148
}
@@ -137,11 +157,11 @@ func (h *auto) dial(network, local, remote string) (protect.Conn, error) {
137157
select {
138158
case <-ctx.Done():
139159
return nil, ctx.Err()
140-
case <-time.After(shortdelay * 2): // 200ms
160+
case <-time.After(shortdelay * myidx): // 300ms
141161
}
142162
return h.dialIfHealthy(exit64, network, local, remote)
143163
}, func(ctx context.Context) (protect.Conn, error) {
144-
const myidx = 3
164+
const myidx = 4
145165
if amz == nil {
146166
return nil, amzerr
147167
}
@@ -156,11 +176,11 @@ func (h *auto) dial(network, local, remote string) (protect.Conn, error) {
156176
select {
157177
case <-ctx.Done():
158178
return nil, ctx.Err()
159-
case <-time.After(shortdelay * 3): // 300ms
179+
case <-time.After(shortdelay * myidx): // 400ms
160180
}
161181
return h.dialIfHealthy(amz, network, local, remote)
162182
}, func(ctx context.Context) (protect.Conn, error) {
163-
const myidx = 4
183+
const myidx = 5
164184
if sep == nil {
165185
return nil, seerr
166186
}
@@ -175,7 +195,7 @@ func (h *auto) dial(network, local, remote string) (protect.Conn, error) {
175195
select {
176196
case <-ctx.Done():
177197
return nil, ctx.Err()
178-
case <-time.After(shortdelay * 4): // 400ms
198+
case <-time.After(shortdelay * myidx): // 500ms
179199
}
180200
return h.dialIfHealthy(sep, network, local, remote)
181201
},
@@ -201,6 +221,7 @@ func (h *auto) Announce(network, local string) (protect.PacketConn, error) {
201221

202222
exit, exerr := h.pxr.ProxyFor(Exit)
203223
warp, waerr := h.pxr.ProxyFor(RpnWg)
224+
pro, proerr := h.pxr.ProxyFor(RpnPro)
204225
amz, amzerr := h.pxr.ProxyFor(RpnAmz)
205226

206227
previdx, recent := h.exp.Get(local)
@@ -224,6 +245,24 @@ func (h *auto) Announce(network, local string) (protect.PacketConn, error) {
224245
return h.announceIfHealthy(exit, network, local)
225246
}, func(ctx context.Context) (protect.PacketConn, error) {
226247
const myidx = 1
248+
if pro == nil {
249+
return nil, proerr
250+
}
251+
if recent {
252+
if previdx != myidx {
253+
return nil, errNotPinned
254+
}
255+
// ip pinned to this proxy
256+
return h.announceIfHealthy(pro, network, local)
257+
}
258+
select {
259+
case <-ctx.Done():
260+
return nil, ctx.Err()
261+
case <-time.After(shortdelay * myidx): // 100ms
262+
}
263+
return h.announceIfHealthy(pro, network, local)
264+
}, func(ctx context.Context) (protect.PacketConn, error) {
265+
const myidx = 2
227266
if warp == nil {
228267
return nil, waerr
229268
}
@@ -237,11 +276,11 @@ func (h *auto) Announce(network, local string) (protect.PacketConn, error) {
237276
select {
238277
case <-ctx.Done():
239278
return nil, ctx.Err()
240-
case <-time.After(shortdelay): // 100ms
279+
case <-time.After(shortdelay * myidx): // 200ms
241280
}
242281
return h.announceIfHealthy(warp, network, local)
243282
}, func(ctx context.Context) (protect.PacketConn, error) {
244-
const myidx = 2
283+
const myidx = 3
245284
if amz == nil {
246285
return nil, amzerr
247286
}
@@ -255,7 +294,7 @@ func (h *auto) Announce(network, local string) (protect.PacketConn, error) {
255294
select {
256295
case <-ctx.Done():
257296
return nil, ctx.Err()
258-
case <-time.After(shortdelay * 2): // 200ms
297+
case <-time.After(shortdelay * myidx): // 300ms
259298
}
260299
return h.announceIfHealthy(amz, network, local)
261300
}, // seasy-proxy does not support udp?
@@ -286,7 +325,7 @@ func (h *auto) Probe(network, local string) (pc protect.PacketConn, err error) {
286325
if h.status.Load() == END {
287326
return nil, errProxyStopped
288327
}
289-
// todo: rpnwg, rpnamz
328+
// todo: rpnwg, rpnamz, rpnpro
290329
exit, err := h.pxr.ProxyFor(Exit)
291330
if err == nil {
292331
pc, err = exit.Dialer().Probe(network, local)
@@ -332,21 +371,24 @@ func (h *auto) Hop(p Proxy) error {
332371
return errProxyStopped
333372
}
334373

335-
var warp, sep, amz Proxy
336-
var waerr, seerr, amzerr error
374+
var warp, sep, amz, pro Proxy
375+
var waerr, seerr, amzerr, proerr error
337376
old := h.via.Tango(p)
338377
if warp, waerr = h.pxr.ProxyFor(RpnWg); warp != nil {
339-
warp.Hop(p)
378+
waerr = warp.Hop(p)
379+
}
380+
if pro, proerr = h.pxr.ProxyFor(RpnPro); pro != nil {
381+
proerr = pro.Hop(p)
340382
}
341383
if amz, amzerr = h.pxr.ProxyFor(RpnAmz); amz != nil {
342-
amz.Hop(p)
384+
amzerr = amz.Hop(p)
343385
}
344386
if sep, seerr = h.pxr.ProxyFor(RpnSE); sep != nil {
345-
sep.Hop(p)
387+
seerr = sep.Hop(p)
346388
}
347389

348390
log.I("proxy: auto: hop(%s) => %s; errs? %v",
349-
idhandle(old), idhandle(p), core.JoinErr(waerr, seerr, amzerr))
391+
idhandle(old), idhandle(p), core.JoinErr(waerr, seerr, amzerr, proerr))
350392
return nil
351393
}
352394

0 commit comments

Comments
 (0)