@@ -7,10 +7,13 @@ import (
7
7
"context"
8
8
"errors"
9
9
"fmt"
10
+ "maps"
10
11
"net"
11
12
"net/netip"
12
13
"os"
13
14
"os/exec"
15
+ "slices"
16
+ "strings"
14
17
"sync"
15
18
"syscall"
16
19
"time"
@@ -254,12 +257,34 @@ func getBaseDialer(timeout time.Duration, mark uint) *net.Dialer {
254
257
return dialer
255
258
}
256
259
257
- func (ts * tproxyServer ) applyRedirectRules () string {
260
+ func (ts * tproxyServer ) createSysctlOptCmd (opt , value , setex string , opts map [string ]string ) * exec.Cmd {
261
+ cmdCat := exec .Command ("bash" , "-c" , fmt .Sprintf (`
262
+ cat /proc/sys/%s
263
+ ` , strings .ReplaceAll (opt , "." , "/" )))
264
+ output , err := cmdCat .CombinedOutput ()
265
+ if err != nil {
266
+ ts .p .logger .Fatal ().Err (err ).Msg ("Failed while configuring iptables. Are you root?" )
267
+ }
268
+ opts [opt ] = string (output )
269
+ cmd := exec .Command ("bash" , "-c" , fmt .Sprintf (`
270
+ %s
271
+ sysctl -w %s=%s
272
+ ` , setex , opt , value ))
273
+ cmd .Stdout = os .Stdout
274
+ cmd .Stderr = os .Stderr
275
+ if ! ts .p .debug {
276
+ cmd .Stdout = nil
277
+ }
278
+ return cmd
279
+ }
280
+
281
+ func (ts * tproxyServer ) applyRedirectRules () map [string ]string {
258
282
_ , tproxyPort , _ := net .SplitHostPort (ts .p .tproxyAddr )
259
283
var setex string
260
284
if ts .p .debug {
261
285
setex = "set -ex"
262
286
}
287
+ ipv4Settings := make (map [string ]string , 5 )
263
288
switch ts .p .tproxyMode {
264
289
case "redirect" :
265
290
cmdClear := exec .Command ("bash" , "-c" , fmt .Sprintf (`
@@ -427,23 +452,21 @@ func (ts *tproxyServer) applyRedirectRules() string {
427
452
default :
428
453
ts .p .logger .Fatal ().Msgf ("Unreachable, unknown mode: %s" , ts .p .tproxyMode )
429
454
}
430
- cmdCat := exec .Command ("bash" , "-c" , `
431
- cat /proc/sys/net/ipv4/ip_forward
432
- ` )
433
- output , err := cmdCat .CombinedOutput ()
434
- if err != nil {
435
- ts .p .logger .Fatal ().Err (err ).Msg ("Failed while configuring iptables. Are you root?" )
436
- }
437
- cmdForward := exec .Command ("bash" , "-c" , fmt .Sprintf (`
455
+ _ = ts .createSysctlOptCmd ("net.ipv4.ip_forward" , "1" , setex , ipv4Settings ).Run ()
456
+ cmdCheckBBR := exec .Command ("bash" , "-c" , fmt .Sprintf (`
438
457
%s
439
- sysctl -w net.ipv4.ip_forward=1
458
+ lsmod | grep -q '^tcp_bbr' || modprobe tcp_bbr
440
459
` , setex ))
441
- cmdForward .Stdout = os .Stdout
442
- cmdForward .Stderr = os .Stderr
460
+ cmdCheckBBR .Stdout = os .Stdout
461
+ cmdCheckBBR .Stderr = os .Stderr
443
462
if ! ts .p .debug {
444
- cmdForward .Stdout = nil
463
+ cmdCheckBBR .Stdout = nil
445
464
}
446
- _ = cmdForward .Run ()
465
+ _ = cmdCheckBBR .Run ()
466
+ _ = ts .createSysctlOptCmd ("net.ipv4.tcp_congestion_control" , "bbr" , setex , ipv4Settings ).Run ()
467
+ _ = ts .createSysctlOptCmd ("net.core.default_qdisc" , "fq" , setex , ipv4Settings ).Run ()
468
+ _ = ts .createSysctlOptCmd ("net.ipv4.tcp_tw_reuse" , "1" , setex , ipv4Settings ).Run ()
469
+ _ = ts .createSysctlOptCmd ("net.ipv4.tcp_fin_timeout" , "15" , setex , ipv4Settings ).Run ()
447
470
cmdClearForward := exec .Command ("bash" , "-c" , fmt .Sprintf (`
448
471
%s
449
472
iptables -t filter -F GOHPTS 2>/dev/null || true
@@ -456,6 +479,7 @@ func (ts *tproxyServer) applyRedirectRules() string {
456
479
ts .p .logger .Fatal ().Err (err ).Msg ("Failed while configuring iptables. Are you root?" )
457
480
}
458
481
var iface * net.Interface
482
+ var err error
459
483
if ts .p .iface != nil {
460
484
iface = ts .p .iface
461
485
} else {
@@ -477,10 +501,10 @@ func (ts *tproxyServer) applyRedirectRules() string {
477
501
if err := cmdForwardFilter .Run (); err != nil {
478
502
ts .p .logger .Fatal ().Err (err ).Msg ("Failed while configuring iptables. Are you root?" )
479
503
}
480
- return string ( output )
504
+ return ipv4Settings
481
505
}
482
506
483
- func (ts * tproxyServer ) clearRedirectRules (output string ) error {
507
+ func (ts * tproxyServer ) clearRedirectRules (opts map [ string ] string ) error {
484
508
var setex string
485
509
if ts .p .debug {
486
510
setex = "set -ex"
@@ -496,6 +520,20 @@ func (ts *tproxyServer) clearRedirectRules(output string) error {
496
520
if err := cmdClear .Run (); err != nil {
497
521
ts .p .logger .Fatal ().Err (err ).Msg ("Failed while configuring iptables. Are you root?" )
498
522
}
523
+ cmds := make ([]string , 0 , len (opts ))
524
+ for _ , cmd := range slices .Sorted (maps .Keys (opts )) {
525
+ cmds = append (cmds , fmt .Sprintf ("sysctl -w %s=%s" , cmd , opts [cmd ]))
526
+ }
527
+ cmdRestoreOpts := exec .Command ("bash" , "-c" , fmt .Sprintf (`
528
+ %s
529
+ %s
530
+ ` , setex , strings .Join (cmds , "\n " )))
531
+ cmdRestoreOpts .Stdout = os .Stdout
532
+ cmdRestoreOpts .Stderr = os .Stderr
533
+ if ! ts .p .debug {
534
+ cmdRestoreOpts .Stdout = nil
535
+ }
536
+ _ = cmdRestoreOpts .Run ()
499
537
var cmd * exec.Cmd
500
538
switch ts .p .tproxyMode {
501
539
case "redirect" :
@@ -505,8 +543,7 @@ func (ts *tproxyServer) clearRedirectRules(output string) error {
505
543
iptables -t nat -D OUTPUT -p tcp -j GOHPTS 2>/dev/null || true
506
544
iptables -t nat -F GOHPTS 2>/dev/null || true
507
545
iptables -t nat -X GOHPTS 2>/dev/null || true
508
- sysctl -w net.ipv4.ip_forward=%s
509
- ` , setex , output ))
546
+ ` , setex ))
510
547
cmd .Stdout = os .Stdout
511
548
cmd .Stderr = os .Stderr
512
549
case "tproxy" :
@@ -521,8 +558,7 @@ func (ts *tproxyServer) clearRedirectRules(output string) error {
521
558
522
559
ip rule del fwmark 1 lookup 100 2>/dev/null || true
523
560
ip route flush table 100 2>/dev/null || true
524
- sysctl -w net.ipv4.ip_forward=%s
525
- ` , setex , output ))
561
+ ` , setex ))
526
562
cmd .Stdout = os .Stdout
527
563
cmd .Stderr = os .Stderr
528
564
if ! ts .p .debug {
0 commit comments