@@ -14,6 +14,7 @@ import (
14
14
15
15
const singleMTU = 1330
16
16
const doubleMTU = 1280 // minimum mtu for IPv6, may cause frag reassembly somewhere
17
+ const connTestEndpoint = "http://1.1.1.1:80/"
17
18
18
19
type WarpOptions struct {
19
20
Bind netip.AddrPort
@@ -22,12 +23,17 @@ type WarpOptions struct {
22
23
Psiphon * PsiphonOptions
23
24
Gool bool
24
25
Scan * wiresocks.ScanOptions
26
+ Tun * TunOptions
25
27
}
26
28
27
29
type PsiphonOptions struct {
28
30
Country string
29
31
}
30
32
33
+ type TunOptions struct {
34
+ FwMark uint32
35
+ }
36
+
31
37
func RunWarp (ctx context.Context , l * slog.Logger , opts WarpOptions ) error {
32
38
if opts .Psiphon != nil && opts .Gool {
33
39
return errors .New ("can't use psiphon and gool at the same time" )
@@ -37,6 +43,10 @@ func RunWarp(ctx context.Context, l *slog.Logger, opts WarpOptions) error {
37
43
return errors .New ("must provide country for psiphon" )
38
44
}
39
45
46
+ if opts .Psiphon != nil && opts .Tun != nil {
47
+ return errors .New ("can't use psiphon and tun at the same time" )
48
+ }
49
+
40
50
// create identities
41
51
if err := createPrimaryAndSecondaryIdentities (l .With ("subsystem" , "warp/account" ), opts .License ); err != nil {
42
52
return err
@@ -69,123 +79,211 @@ func RunWarp(ctx context.Context, l *slog.Logger, opts WarpOptions) error {
69
79
case opts .Gool :
70
80
l .Info ("running in warp-in-warp (gool) mode" )
71
81
// run warp in warp
72
- warpErr = runWarpInWarp (ctx , l , opts .Bind , endpoints )
82
+ warpErr = runWarpInWarp (ctx , l , opts .Bind , endpoints , opts . Tun )
73
83
default :
74
84
l .Info ("running in normal warp mode" )
75
85
// just run primary warp on bindAddress
76
- warpErr = runWarp (ctx , l , opts .Bind , endpoints [0 ])
86
+ warpErr = runWarp (ctx , l , opts .Bind , endpoints [0 ], opts . Tun )
77
87
}
78
88
79
89
return warpErr
80
90
}
81
91
82
- func runWarp (ctx context.Context , l * slog.Logger , bind netip.AddrPort , endpoint string ) error {
92
+ func runWarp (ctx context.Context , l * slog.Logger , bind netip.AddrPort , endpoint string , tun * TunOptions ) error {
93
+ // Set up primary/outer warp config
83
94
conf , err := wiresocks .ParseConfig ("./stuff/primary/wgcf-profile.ini" , endpoint )
84
95
if err != nil {
85
96
return err
86
97
}
98
+
99
+ // Set up MTU
87
100
conf .Interface .MTU = singleMTU
88
101
102
+ // Enable trick and keepalive on all peers in config
89
103
for i , peer := range conf .Peers {
90
104
peer .Trick = true
91
105
peer .KeepAlive = 3
92
106
conf .Peers [i ] = peer
93
107
}
94
108
95
- tnet , err := wiresocks .StartWireguard (ctx , l , conf )
109
+ if tun != nil {
110
+ // Create a new tun interface
111
+ tunDev , err := newNormalTun ()
112
+ if err != nil {
113
+ return err
114
+ }
115
+
116
+ // Establish wireguard tunnel on tun interface
117
+ if err := establishWireguard (l , conf , tunDev , tun .FwMark ); err != nil {
118
+ return err
119
+ }
120
+ l .Info ("serving tun" , "interface" , "warp0" )
121
+ return nil
122
+ }
123
+
124
+ // Create userspace tun network stack
125
+ tunDev , tnet , err := newUsermodeTun (conf )
96
126
if err != nil {
97
127
return err
98
128
}
99
129
100
- _ , err = tnet .StartProxy (bind )
130
+ // Establish wireguard on userspace stack
131
+ if err := establishWireguard (l , conf , tunDev , 0 ); err != nil {
132
+ return err
133
+ }
134
+
135
+ // Test wireguard connectivity
136
+ if err := usermodeTunTest (ctx , l , tnet ); err != nil {
137
+ return err
138
+ }
139
+
140
+ // Run a proxy on the userspace stack
141
+ _ , err = wiresocks .StartProxy (ctx , l , tnet , bind )
101
142
if err != nil {
102
143
return err
103
144
}
104
145
105
146
l .Info ("serving proxy" , "address" , bind )
106
-
107
147
return nil
108
148
}
109
149
110
- func runWarpWithPsiphon (ctx context.Context , l * slog.Logger , bind netip.AddrPort , endpoint string , country string ) error {
111
- conf , err := wiresocks .ParseConfig ("./stuff/primary/wgcf-profile.ini" , endpoint )
150
+ func runWarpInWarp (ctx context.Context , l * slog.Logger , bind netip.AddrPort , endpoints []string , tun * TunOptions ) error {
151
+ // Set up primary/outer warp config
152
+ conf , err := wiresocks .ParseConfig ("./stuff/primary/wgcf-profile.ini" , endpoints [0 ])
112
153
if err != nil {
113
154
return err
114
155
}
156
+
157
+ // Set up MTU
115
158
conf .Interface .MTU = singleMTU
116
159
160
+ // Enable trick and keepalive on all peers in config
117
161
for i , peer := range conf .Peers {
118
162
peer .Trick = true
119
163
peer .KeepAlive = 3
120
164
conf .Peers [i ] = peer
121
165
}
122
166
123
- tnet , err := wiresocks .StartWireguard (ctx , l , conf )
167
+ // Create userspace tun network stack
168
+ tunDev , tnet , err := newUsermodeTun (conf )
124
169
if err != nil {
125
170
return err
126
171
}
127
172
128
- warpBind , err := tnet .StartProxy (netip .MustParseAddrPort ("127.0.0.1:0" ))
173
+ // Establish wireguard on userspace stack
174
+ if err := establishWireguard (l .With ("gool" , "outer" ), conf , tunDev , 0 ); err != nil {
175
+ return err
176
+ }
177
+
178
+ // Test wireguard connectivity
179
+ if err := usermodeTunTest (ctx , l , tnet ); err != nil {
180
+ return err
181
+ }
182
+
183
+ // Create a UDP port forward between localhost and the remote endpoint
184
+ addr , err := wiresocks .NewVtunUDPForwarder (ctx , netip .MustParseAddrPort ("127.0.0.1:0" ), endpoints [0 ], tnet , singleMTU )
129
185
if err != nil {
130
186
return err
131
187
}
132
188
133
- // run psiphon
134
- err = psiphon . RunPsiphon ( ctx , l . With ( "subsystem" , "psiphon" ), warpBind .String (), bind . String (), country )
189
+ // Set up secondary/inner warp config
190
+ conf , err = wiresocks . ParseConfig ( "./stuff/secondary/wgcf-profile.ini" , addr .String ())
135
191
if err != nil {
136
- return fmt . Errorf ( "unable to run psiphon %w" , err )
192
+ return err
137
193
}
138
194
139
- l .Info ("serving proxy" , "address" , bind )
195
+ // Set up MTU
196
+ conf .Interface .MTU = doubleMTU
197
+
198
+ // Enable keepalive on all peers in config
199
+ for i , peer := range conf .Peers {
200
+ peer .KeepAlive = 10
201
+ conf .Peers [i ] = peer
202
+ }
203
+
204
+ if tun != nil {
205
+ // Create a new tun interface
206
+ tunDev , err := newNormalTun ()
207
+ if err != nil {
208
+ return err
209
+ }
210
+
211
+ // Establish wireguard tunnel on tun interface
212
+ if err := establishWireguard (l .With ("gool" , "inner" ), conf , tunDev , tun .FwMark ); err != nil {
213
+ return err
214
+ }
215
+ l .Info ("serving tun" , "interface" , "warp0" )
216
+ return nil
217
+ }
218
+
219
+ // Create userspace tun network stack
220
+ tunDev , tnet , err = newUsermodeTun (conf )
221
+ if err != nil {
222
+ return err
223
+ }
224
+
225
+ // Establish wireguard on userspace stack
226
+ if err := establishWireguard (l .With ("gool" , "inner" ), conf , tunDev , 0 ); err != nil {
227
+ return err
228
+ }
229
+
230
+ // Test wireguard connectivity
231
+ if err := usermodeTunTest (ctx , l , tnet ); err != nil {
232
+ return err
233
+ }
234
+
235
+ _ , err = wiresocks .StartProxy (ctx , l , tnet , bind )
236
+ if err != nil {
237
+ return err
238
+ }
140
239
240
+ l .Info ("serving proxy" , "address" , bind )
141
241
return nil
142
242
}
143
243
144
- func runWarpInWarp (ctx context.Context , l * slog.Logger , bind netip.AddrPort , endpoints [] string ) error {
145
- // Run outer warp
146
- conf , err := wiresocks .ParseConfig ("./stuff/primary/wgcf-profile.ini" , endpoints [ 0 ] )
244
+ func runWarpWithPsiphon (ctx context.Context , l * slog.Logger , bind netip.AddrPort , endpoint string , country string ) error {
245
+ // Set up primary/ outer warp config
246
+ conf , err := wiresocks .ParseConfig ("./stuff/primary/wgcf-profile.ini" , endpoint )
147
247
if err != nil {
148
248
return err
149
249
}
250
+
251
+ // Set up MTU
150
252
conf .Interface .MTU = singleMTU
151
253
254
+ // Enable trick and keepalive on all peers in config
152
255
for i , peer := range conf .Peers {
153
256
peer .Trick = true
154
257
peer .KeepAlive = 3
155
258
conf .Peers [i ] = peer
156
259
}
157
260
158
- tnet , err := wiresocks .StartWireguard (ctx , l .With ("gool" , "outer" ), conf )
261
+ // Create userspace tun network stack
262
+ tunDev , tnet , err := newUsermodeTun (conf )
159
263
if err != nil {
160
264
return err
161
265
}
162
266
163
- // Create a UDP port forward between localhost and the remote endpoint
164
- addr , err := wiresocks .NewVtunUDPForwarder (ctx , netip .MustParseAddrPort ("127.0.0.1:0" ), endpoints [1 ], tnet , singleMTU )
165
- if err != nil {
267
+ // Establish wireguard on userspace stack
268
+ if err := establishWireguard (l , conf , tunDev , 0 ); err != nil {
166
269
return err
167
270
}
168
271
169
- // Run inner warp
170
- conf , err = wiresocks .ParseConfig ("./stuff/secondary/wgcf-profile.ini" , addr .String ())
171
- if err != nil {
272
+ // Test wireguard connectivity
273
+ if err := usermodeTunTest (ctx , l , tnet ); err != nil {
172
274
return err
173
275
}
174
- conf .Interface .MTU = doubleMTU
175
-
176
- for i , peer := range conf .Peers {
177
- peer .KeepAlive = 10
178
- conf .Peers [i ] = peer
179
- }
180
276
181
- tnet , err = wiresocks .StartWireguard (ctx , l .With ("gool" , "inner" ), conf )
277
+ // Run a proxy on the userspace stack
278
+ warpBind , err := wiresocks .StartProxy (ctx , l , tnet , netip .MustParseAddrPort ("127.0.0.1:0" ))
182
279
if err != nil {
183
280
return err
184
281
}
185
282
186
- _ , err = tnet .StartProxy (bind )
283
+ // run psiphon
284
+ err = psiphon .RunPsiphon (ctx , l .With ("subsystem" , "psiphon" ), warpBind .String (), bind .String (), country )
187
285
if err != nil {
188
- return err
286
+ return fmt . Errorf ( "unable to run psiphon %w" , err )
189
287
}
190
288
191
289
l .Info ("serving proxy" , "address" , bind )
0 commit comments