forked from WireGuard/wireguard-go
-
Notifications
You must be signed in to change notification settings - Fork 225
/
app.go
211 lines (172 loc) · 4.87 KB
/
app.go
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
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
package app
import (
"context"
"errors"
"fmt"
"log/slog"
"net/netip"
"github.com/bepass-org/warp-plus/psiphon"
"github.com/bepass-org/warp-plus/warp"
"github.com/bepass-org/warp-plus/wiresocks"
)
const singleMTU = 1330
const doubleMTU = 1280 // minimum mtu for IPv6, may cause frag reassembly somewhere
type WarpOptions struct {
Bind netip.AddrPort
Endpoint string
License string
Psiphon *PsiphonOptions
Gool bool
Scan *wiresocks.ScanOptions
}
type PsiphonOptions struct {
Country string
}
func RunWarp(ctx context.Context, l *slog.Logger, opts WarpOptions) error {
if opts.Psiphon != nil && opts.Gool {
return errors.New("can't use psiphon and gool at the same time")
}
if opts.Psiphon != nil && opts.Psiphon.Country == "" {
return errors.New("must provide country for psiphon")
}
// create identities
if err := createPrimaryAndSecondaryIdentities(l.With("subsystem", "warp/account"), opts.License); err != nil {
return err
}
// Decide Working Scenario
endpoints := []string{opts.Endpoint, opts.Endpoint}
if opts.Scan != nil {
res, err := wiresocks.RunScan(ctx, l, *opts.Scan)
if err != nil {
return err
}
l.Info("scan results", "endpoints", res)
endpoints = make([]string, len(res))
for i := 0; i < len(res); i++ {
endpoints[i] = res[i].AddrPort.String()
}
}
l.Info("using warp endpoints", "endpoints", endpoints)
var warpErr error
switch {
case opts.Psiphon != nil:
l.Info("running in Psiphon (cfon) mode")
// run primary warp on a random tcp port and run psiphon on bind address
warpErr = runWarpWithPsiphon(ctx, l, opts.Bind, endpoints[0], opts.Psiphon.Country)
case opts.Gool:
l.Info("running in warp-in-warp (gool) mode")
// run warp in warp
warpErr = runWarpInWarp(ctx, l, opts.Bind, endpoints)
default:
l.Info("running in normal warp mode")
// just run primary warp on bindAddress
warpErr = runWarp(ctx, l, opts.Bind, endpoints[0])
}
return warpErr
}
func runWarp(ctx context.Context, l *slog.Logger, bind netip.AddrPort, endpoint string) error {
conf, err := wiresocks.ParseConfig("./stuff/primary/wgcf-profile.ini", endpoint)
if err != nil {
return err
}
conf.Interface.MTU = singleMTU
for i, peer := range conf.Peers {
peer.Trick = true
peer.KeepAlive = 3
conf.Peers[i] = peer
}
tnet, err := wiresocks.StartWireguard(ctx, l, conf)
if err != nil {
return err
}
_, err = tnet.StartProxy(bind)
if err != nil {
return err
}
l.Info("serving proxy", "address", bind)
return nil
}
func runWarpWithPsiphon(ctx context.Context, l *slog.Logger, bind netip.AddrPort, endpoint string, country string) error {
conf, err := wiresocks.ParseConfig("./stuff/primary/wgcf-profile.ini", endpoint)
if err != nil {
return err
}
conf.Interface.MTU = singleMTU
for i, peer := range conf.Peers {
peer.Trick = true
peer.KeepAlive = 3
conf.Peers[i] = peer
}
tnet, err := wiresocks.StartWireguard(ctx, l, conf)
if err != nil {
return err
}
warpBind, err := tnet.StartProxy(netip.MustParseAddrPort("127.0.0.1:0"))
if err != nil {
return err
}
// run psiphon
err = psiphon.RunPsiphon(ctx, l.With("subsystem", "psiphon"), warpBind.String(), bind.String(), country)
if err != nil {
return fmt.Errorf("unable to run psiphon %w", err)
}
l.Info("serving proxy", "address", bind)
return nil
}
func runWarpInWarp(ctx context.Context, l *slog.Logger, bind netip.AddrPort, endpoints []string) error {
// Run outer warp
conf, err := wiresocks.ParseConfig("./stuff/primary/wgcf-profile.ini", endpoints[0])
if err != nil {
return err
}
conf.Interface.MTU = singleMTU
for i, peer := range conf.Peers {
peer.Trick = true
peer.KeepAlive = 3
conf.Peers[i] = peer
}
tnet, err := wiresocks.StartWireguard(ctx, l.With("gool", "outer"), conf)
if err != nil {
return err
}
// Create a UDP port forward between localhost and the remote endpoint
addr, err := wiresocks.NewVtunUDPForwarder(ctx, netip.MustParseAddrPort("127.0.0.1:0"), endpoints[1], tnet, singleMTU)
if err != nil {
return err
}
// Run inner warp
conf, err = wiresocks.ParseConfig("./stuff/secondary/wgcf-profile.ini", addr.String())
if err != nil {
return err
}
conf.Interface.MTU = doubleMTU
for i, peer := range conf.Peers {
peer.KeepAlive = 10
conf.Peers[i] = peer
}
tnet, err = wiresocks.StartWireguard(ctx, l.With("gool", "inner"), conf)
if err != nil {
return err
}
_, err = tnet.StartProxy(bind)
if err != nil {
return err
}
l.Info("serving proxy", "address", bind)
return nil
}
func createPrimaryAndSecondaryIdentities(l *slog.Logger, license string) error {
// make primary identity
err := warp.LoadOrCreateIdentity(l, "./stuff/primary", license)
if err != nil {
l.Error("couldn't load primary warp identity")
return err
}
// make secondary
err = warp.LoadOrCreateIdentity(l, "./stuff/secondary", license)
if err != nil {
l.Error("couldn't load secondary warp identity")
return err
}
return nil
}