1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
|
package client
import (
"context"
"encoding/json"
"errors"
"sync"
"codeberg.org/eduVPN/proxyguard"
"github.com/eduvpn/eduvpn-common/i18nerr"
"github.com/eduvpn/eduvpn-common/internal/log"
"github.com/eduvpn/eduvpn-common/types/cookie"
)
// ProxyLogger is defined here such that we can update the proxyguard logger
type ProxyLogger struct{}
// Logf logs a message with parameters
func (pl *ProxyLogger) Logf(msg string, params ...interface{}) {
log.Logger.Infof("[Proxyguard] "+msg, params...)
}
// Log logs a message
func (pl *ProxyLogger) Log(msg string) {
log.Logger.Infof("[Proxyguard] %s", msg)
}
// Proxy is a wrapper around ProxyGuard
// that has the client
// and a cancel for cancellation by common
// and a mutex to protect against race conditions
type Proxy struct {
c *proxyguard.Client
mu sync.Mutex
cancel context.CancelFunc
}
// NewClient creates a new ProxyGuard wrapper from client `c`
func (p *Proxy) NewClient(c *proxyguard.Client) {
p.mu.Lock()
defer p.mu.Unlock()
p.c = c
}
// Delete sets the inner client to nil
func (p *Proxy) Delete() {
p.mu.Lock()
defer p.mu.Unlock()
p.c = nil
}
// ErrNoProxyGuardCancel indicates that no ProxyGuard cancel function
// was ever defined. You probably forgot to call `Tunnel`
var ErrNoProxyGuardCancel = errors.New("no ProxyGuard cancel function")
// Cancel cancels a running ProxyGuard tunnel
// it returns an error if it cannot be canceled
func (p *Proxy) Cancel() error {
p.mu.Lock()
defer p.mu.Unlock()
if p.cancel == nil {
return ErrNoProxyGuardCancel
}
p.cancel()
p.cancel = nil
return nil
}
// ErrNoProxyGuardClient is an error that is returned when no ProxyGuard client is created
var ErrNoProxyGuardClient = errors.New("no ProxyGuard client created")
// Tunnel is a wrapper around ProxyGuard tunnel that
// that creates a new context that can be canceled
func (p *Proxy) Tunnel(ctx context.Context, peer string) error {
p.mu.Lock()
if p.c == nil {
p.mu.Unlock()
return ErrNoProxyGuardClient
}
cctx, cf := context.WithCancel(ctx)
p.cancel = cf
p.mu.Unlock()
defer func() {
p.mu.Lock()
p.cancel = nil
p.mu.Unlock()
}()
// we set peer IPs to nil here as proxyguard already does a DNS request for us
return p.c.Tunnel(cctx, peer, nil)
}
// StartProxyguard starts proxyguard for proxied WireGuard connections
func (c *Client) StartProxyguard(ck *cookie.Cookie, listen string, tcpsp int, peer string, gotFD func(fd int, pips string), ready func()) error {
var err error
proxyguard.UpdateLogger(&ProxyLogger{})
proxyc := proxyguard.Client{
Listen: listen,
TCPSourcePort: tcpsp,
SetupSocket: func(fd int, pips []string) {
if gotFD == nil {
return
}
b, err := json.Marshal(pips)
if err != nil {
log.Logger.Errorf("marshalling peer IPs failed: %v", err)
return
}
gotFD(fd, string(b))
},
Ready: ready,
}
c.proxy.NewClient(&proxyc)
defer c.proxy.Delete()
err = c.proxy.Tunnel(ck.Context(), peer)
if err != nil {
return i18nerr.Wrap(err, "The VPN proxy exited")
}
return err
}
|