@@ -13,7 +13,6 @@ import (
1313 "math/rand"
1414 "net"
1515 "net/http"
16- "net/netip"
1716 "os"
1817 "os/signal"
1918 "runtime"
@@ -22,14 +21,11 @@ import (
2221 "strings"
2322 "sync"
2423 "sync/atomic"
25- "syscall"
2624 "time"
27- "unsafe"
2825
2926 "github.com/goccy/go-yaml"
3027 "github.com/rs/zerolog"
3128 "golang.org/x/net/proxy"
32- "golang.org/x/sys/unix"
3329)
3430
3531const (
@@ -81,7 +77,7 @@ func delHopHeaders(header http.Header) {
8177// https://datatracker.ietf.org/doc/html/rfc7230#section-6.1
8278func delConnectionHeaders (h http.Header ) {
8379 for _ , f := range h ["Connection" ] {
84- for _ , sf := range strings .Split (f , "," ) {
80+ for sf := range strings .SplitSeq (f , "," ) {
8581 if sf = strings .TrimSpace (sf ); sf != "" {
8682 h .Del (sf )
8783 }
@@ -270,7 +266,7 @@ func (p *proxyapp) getSocks() (proxy.Dialer, *http.Client, error) {
270266 }
271267 }
272268 startIdx := int (start % uint32 (len (p .availProxyList )))
273- for i := 0 ; i < chainLength ; i ++ {
269+ for i := range chainLength {
274270 idx := (startIdx + i ) % len (p .availProxyList )
275271 copyProxyList = append (copyProxyList , p .availProxyList [idx ])
276272 }
@@ -632,188 +628,14 @@ func (p *proxyapp) handler() http.HandlerFunc {
632628 }
633629}
634630
635- type tproxyServer struct {
636- listener net.Listener
637- quit chan struct {}
638- wg sync.WaitGroup
639- pa * proxyapp
640- }
641-
642- func newTproxyServer (pa * proxyapp ) * tproxyServer {
643- ts := & tproxyServer {
644- quit : make (chan struct {}),
645- pa : pa ,
646- }
647- // https://iximiuz.com/en/posts/go-net-http-setsockopt-example/
648- lc := net.ListenConfig {
649- Control : func (network , address string , conn syscall.RawConn ) error {
650- var operr error
651- if err := conn .Control (func (fd uintptr ) {
652- operr = unix .SetsockoptInt (int (fd ), unix .IPPROTO_TCP , unix .TCP_USER_TIMEOUT , int (timeout * 1000 ))
653- operr = unix .SetsockoptInt (int (fd ), unix .SOL_SOCKET , unix .SO_REUSEADDR , 1 )
654- if ts .pa .tproxyMode == "tproxy" {
655- operr = unix .SetsockoptInt (int (fd ), unix .SOL_IP , unix .IP_TRANSPARENT , 1 )
656- }
657- }); err != nil {
658- return err
659- }
660- return operr
661- },
662- }
663-
664- ln , err := lc .Listen (context .Background (), "tcp4" , ts .pa .tproxyAddr )
665- if err != nil {
666- var msg string
667- if errors .Is (err , unix .EPERM ) {
668- msg = "try `sudo setcap 'cap_net_admin+ep` for the binary:"
669- }
670- ts .pa .logger .Fatal ().Err (err ).Msg (msg )
671- }
672- ts .listener = ln
673- return ts
674- }
675-
676- func (ts * tproxyServer ) ListenAndServe () {
677- ts .wg .Add (1 )
678- go ts .serve ()
679- }
680-
681- func (ts * tproxyServer ) serve () {
682- defer ts .wg .Done ()
683-
684- for {
685- conn , err := ts .listener .Accept ()
686- if err != nil {
687- select {
688- case <- ts .quit :
689- return
690- default :
691- ts .pa .logger .Error ().Err (err ).Msg ("" )
692- }
693- } else {
694- ts .wg .Add (1 )
695- err := conn .SetDeadline (time .Now ().Add (timeout ))
696- if err != nil {
697- ts .pa .logger .Error ().Err (err ).Msg ("" )
698- }
699- go func () {
700- ts .handleConnection (conn )
701- ts .wg .Done ()
702- }()
703- }
704- }
705- }
706-
707- func getsockopt (s int , level int , optname int , optval unsafe.Pointer , optlen * uint32 ) (err error ) {
708- _ , _ , e := unix .Syscall6 (unix .SYS_GETSOCKOPT , uintptr (s ), uintptr (level ), uintptr (optname ), uintptr (optval ), uintptr (unsafe .Pointer (optlen )), 0 )
709- if e != 0 {
710- return e
711- }
712- return nil
713- }
714-
715- func (ts * tproxyServer ) getOriginalDst (rawConn syscall.RawConn ) (string , error ) {
716- var originalDst unix.RawSockaddrInet4
717- err := rawConn .Control (func (fd uintptr ) {
718- optlen := uint32 (unsafe .Sizeof (originalDst ))
719- err := getsockopt (int (fd ), unix .SOL_IP , unix .SO_ORIGINAL_DST , unsafe .Pointer (& originalDst ), & optlen )
720- if err != nil {
721- ts .pa .logger .Error ().Err (err ).Msg ("[tproxy] getsockopt SO_ORIGINAL_DST failed" )
722- }
723- })
724- if err != nil {
725- ts .pa .logger .Error ().Err (err ).Msg ("[tproxy] Failed invoking control connection" )
726- return "" , err
727- }
728- dstHost := netip .AddrFrom4 (originalDst .Addr )
729- dstPort := uint16 (originalDst .Port << 8 ) | originalDst .Port >> 8
730- return fmt .Sprintf ("%s:%d" , dstHost , dstPort ), nil
731- }
732-
733- func (ts * tproxyServer ) handleConnection (srcConn net.Conn ) {
734- var (
735- dstConn net.Conn
736- dst string
737- err error
738- )
739- defer srcConn .Close ()
740- switch ts .pa .tproxyMode {
741- case "redirect" :
742- rawConn , err := srcConn .(* net.TCPConn ).SyscallConn ()
743- if err != nil {
744- ts .pa .logger .Error ().Err (err ).Msg ("[tproxy] Failed to get raw connection" )
745- return
746- }
747- dst , err = ts .getOriginalDst (rawConn )
748- if err != nil {
749- ts .pa .logger .Error ().Err (err ).Msg ("[tproxy] Failed to get destination address" )
750- return
751- }
752- ts .pa .logger .Debug ().Msgf ("[tproxy] getsockopt SO_ORIGINAL_DST %s" , dst )
753- case "tproxy" :
754- dst = srcConn .LocalAddr ().String ()
755- ts .pa .logger .Debug ().Msgf ("[tproxy] IP_TRANSPARENT %s" , dst )
756- default :
757- ts .pa .logger .Fatal ().Msg ("Unknown tproxyMode" )
758- }
759- if isLocalAddress (dst ) {
760- dstConn , err = net .DialTimeout ("tcp" , dst , timeout )
761- if err != nil {
762- ts .pa .logger .Error ().Err (err ).Msgf ("[tproxy] Failed connecting to %s" , dst )
763- return
764- }
765- } else {
766- sockDialer , _ , err := ts .pa .getSocks ()
767- if err != nil {
768- ts .pa .logger .Error ().Err (err ).Msg ("[tproxy] Failed getting SOCKS5 client" )
769- return
770- }
771- ctx , cancel := context .WithTimeout (context .Background (), timeout )
772- defer cancel ()
773- dstConn , err = sockDialer .(proxy.ContextDialer ).DialContext (ctx , "tcp" , dst )
774- if err != nil {
775- ts .pa .logger .Error ().Err (err ).Msgf ("[tproxy] Failed connecting to %s" , dst )
776- return
777- }
778- }
779- defer dstConn .Close ()
780-
781- dstConnStr := fmt .Sprintf ("%s->%s->%s" , dstConn .LocalAddr ().String (), dstConn .RemoteAddr ().String (), dst )
782- srcConnStr := fmt .Sprintf ("%s->%s" , srcConn .LocalAddr ().String (), srcConn .RemoteAddr ().String ())
783-
784- ts .pa .logger .Debug ().Msgf ("[tproxy] src: %s - dst: %s" , srcConnStr , dstConnStr )
785-
786- var wg sync.WaitGroup
787- wg .Add (2 )
788- go ts .pa .transfer (& wg , dstConn , srcConn , dstConnStr , srcConnStr )
789- go ts .pa .transfer (& wg , srcConn , dstConn , srcConnStr , dstConnStr )
790- wg .Wait ()
791- }
792-
793- func (ts * tproxyServer ) Shutdown () {
794- close (ts .quit )
795- ts .listener .Close ()
796- done := make (chan struct {})
797- go func () {
798- ts .wg .Wait ()
799- close (done )
800- }()
801-
802- select {
803- case <- done :
804- ts .pa .logger .Info ().Msg ("[tproxy] Server gracefully shutdown" )
805- return
806- case <- time .After (timeout ):
807- ts .pa .logger .Error ().Msg ("[tproxy] Server timed out waiting for connections to finish" )
808- return
809- }
810- }
811-
812631func (p * proxyapp ) Run () {
813632 done := make (chan bool )
814633 quit := make (chan os.Signal , 1 )
815634 signal .Notify (quit , os .Interrupt )
816- tproxyServer := newTproxyServer (p )
635+ var tproxyServer * tproxyServer
636+ if p .tproxyAddr != "" {
637+ tproxyServer = newTproxyServer (p )
638+ }
817639 if p .proxylist != nil {
818640 chainType := p .proxychain .Type
819641 go func () {
@@ -827,7 +649,7 @@ func (p *proxyapp) Run() {
827649 if p .httpServer != nil {
828650 go func () {
829651 <- quit
830- if p . tproxyAddr != "" {
652+ if tproxyServer != nil {
831653 p .logger .Info ().Msg ("[tproxy] Server is shutting down..." )
832654 tproxyServer .Shutdown ()
833655 }
@@ -841,7 +663,7 @@ func (p *proxyapp) Run() {
841663 }
842664 close (done )
843665 }()
844- if p . tproxyAddr != "" {
666+ if tproxyServer != nil {
845667 go tproxyServer .ListenAndServe ()
846668 }
847669 if p .user != "" && p .pass != "" {
0 commit comments