1+ // Package gohpts transform SOCKS5 proxy into HTTP(S) proxy with support for Transparent Proxy (Redirect and TProxy), Proxychains and Traffic Sniffing
12package gohpts
23
34import (
@@ -52,11 +53,19 @@ var (
5253 supportedChainTypes = []string {"strict" , "dynamic" , "random" , "round_robin" }
5354 SupportedTProxyModes = []string {"redirect" , "tproxy" }
5455 errInvalidWrite = errors .New ("invalid write result" )
55- ipPortPattern = regexp .MustCompile (`\b(?:\d{1,3}\.){3}\d{1,3}(?::(6553[0-5]|655[0-2]\d|65[0-4]\d{2}|6[0-4]\d{3}|[1-5]?\d{1,4}))?\b` )
56- domainPattern = regexp .MustCompile (`\b(?:[a-zA-Z0-9-]{1,63}\.)+(?:com|net|org|io|co|uk|ru|de|edu|gov|info|biz|dev|app|ai)(?::(6553[0-5]|655[0-2]\d|65[0-4]\d{2}|6[0-4]\d{3}|[1-5]?\d{1,4}))?\b` )
57- jwtPattern = regexp .MustCompile (`\beyJ[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}\b` )
58- authPattern = regexp .MustCompile (`(?i)(?:"|')?(authorization|auth[_-]?token|access[_-]?token|api[_-]?key|secret|token)(?:"|')?\s*[:=]\s*(?:"|')?([^\s"'&]+)` )
59- credsPattern = regexp .MustCompile (`(?i)(?:"|')?(username|user|login|email|password|pass|pwd)(?:"|')?\s*[:=]\s*(?:"|')?([^\s"'&]+)` )
56+ ipPortPattern = regexp .MustCompile (
57+ `\b(?:\d{1,3}\.){3}\d{1,3}(?::(6553[0-5]|655[0-2]\d|65[0-4]\d{2}|6[0-4]\d{3}|[1-5]?\d{1,4}))?\b` ,
58+ )
59+ domainPattern = regexp .MustCompile (
60+ `\b(?:[a-zA-Z0-9-]{1,63}\.)+(?:com|net|org|io|co|uk|ru|de|edu|gov|info|biz|dev|app|ai)(?::(6553[0-5]|655[0-2]\d|65[0-4]\d{2}|6[0-4]\d{3}|[1-5]?\d{1,4}))?\b` ,
61+ )
62+ jwtPattern = regexp .MustCompile (`\beyJ[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}\b` )
63+ authPattern = regexp .MustCompile (
64+ `(?i)(?:"|')?(authorization|auth[_-]?token|access[_-]?token|api[_-]?key|secret|token)(?:"|')?\s*[:=]\s*(?:"|')?([^\s"'&]+)` ,
65+ )
66+ credsPattern = regexp .MustCompile (
67+ `(?i)(?:"|')?(username|user|login|email|password|pass|pwd)(?:"|')?\s*[:=]\s*(?:"|')?([^\s"'&]+)` ,
68+ )
6069)
6170
6271// Hop-by-hop headers
@@ -90,7 +99,7 @@ type Config struct {
9099 Mark uint
91100 LogFilePath string
92101 Debug bool
93- Json bool
102+ JSON bool
94103 Sniff bool
95104 SniffLogFile string
96105 NoColor bool
@@ -152,12 +161,12 @@ func randColor() func(string) *colors.Color {
152161 return rColors [randIndex ]
153162}
154163
155- func (p * proxyapp ) getId () string {
164+ func (p * proxyapp ) getID () string {
156165 id := uuid .New ()
157166 if p .nocolor {
158- return fmt . Sprintf ( "%s" , colors .WrapBrackets (id .String () ))
167+ return colors .WrapBrackets (id .String ())
159168 }
160- return randColor ()(fmt . Sprintf ( "%s" , colors .WrapBrackets (id .String () ))).String ()
169+ return randColor ()(colors .WrapBrackets (id .String ())).String ()
161170}
162171
163172func (p * proxyapp ) colorizeStatus (code int , status string , bg bool ) string {
@@ -181,7 +190,13 @@ func (p *proxyapp) colorizeStatus(code int, status string, bg bool) string {
181190 return status
182191}
183192
184- func (p * proxyapp ) colorizeHTTP (req * http.Request , resp * http.Response , reqBodySaved , respBodySaved * []byte , id string , ts bool ) string {
193+ func (p * proxyapp ) colorizeHTTP (
194+ req * http.Request ,
195+ resp * http.Response ,
196+ reqBodySaved , respBodySaved * []byte ,
197+ id string ,
198+ ts bool ,
199+ ) string {
185200 var sb strings.Builder
186201 if ts {
187202 sb .WriteString (fmt .Sprintf ("%s " , p .colorizeTimestamp ()))
@@ -190,7 +205,7 @@ func (p *proxyapp) colorizeHTTP(req *http.Request, resp *http.Response, reqBodyS
190205 sb .WriteString (id )
191206 sb .WriteString (fmt .Sprintf (" %s %s %s " , req .Method , req .URL , req .Proto ))
192207 if req .UserAgent () != "" {
193- sb .WriteString (fmt . Sprintf ( "%s" , colors .WrapBrackets (req .UserAgent () )))
208+ sb .WriteString (colors .WrapBrackets (req .UserAgent ()))
194209 }
195210 if req .ContentLength > 0 {
196211 sb .WriteString (fmt .Sprintf (" Len: %d" , req .ContentLength ))
@@ -224,7 +239,7 @@ func (p *proxyapp) colorizeHTTP(req *http.Request, resp *http.Response, reqBodyS
224239 sb .WriteString (colors .YellowBg (fmt .Sprintf ("%s " , req .URL )).String ())
225240 sb .WriteString (colors .BlueBg (fmt .Sprintf ("%s " , req .Proto )).String ())
226241 if req .UserAgent () != "" {
227- sb .WriteString (colors .Gray (fmt . Sprintf ( "%s" , colors .WrapBrackets (req .UserAgent () ))).String ())
242+ sb .WriteString (colors .Gray (colors .WrapBrackets (req .UserAgent ())).String ())
228243 }
229244 if req .ContentLength > 0 {
230245 sb .WriteString (colors .BeigeBg (fmt .Sprintf (" Len: %d" , req .ContentLength )).String ())
@@ -814,7 +829,7 @@ func (p *proxyapp) handleForward(w http.ResponseWriter, r *http.Request) {
814829 }
815830 p .snifflogger .Log ().Msg (fmt .Sprintf ("[%s]" , strings .Join (sniffheader , "," )))
816831 } else {
817- id := p .getId ()
832+ id := p .getID ()
818833 p .snifflogger .Log ().Msg (p .colorizeHTTP (req , resp , & reqBodySaved , & respBodySaved , id , false ))
819834 }
820835 }
@@ -943,10 +958,13 @@ func (p *proxyapp) handleTunnel(w http.ResponseWriter, r *http.Request) {
943958 if p .sniff {
944959 wg .Add (1 )
945960 sniffheader := make ([]string , 0 , 6 )
946- id := p .getId ()
961+ id := p .getID ()
947962 if p .json {
948- sniffheader = append (sniffheader , fmt .Sprintf ("{\" connection\" :{\" src_remote\" :%s,\" src_local\" :%s,\" dst_local\" :%s,\" dst_remote\" :%s}}" ,
949- srcConn .RemoteAddr (), srcConn .LocalAddr (), dstConn .LocalAddr (), dstConn .RemoteAddr ()))
963+ sniffheader = append (
964+ sniffheader ,
965+ fmt .Sprintf ("{\" connection\" :{\" src_remote\" :%s,\" src_local\" :%s,\" dst_local\" :%s,\" dst_remote\" :%s}}" ,
966+ srcConn .RemoteAddr (), srcConn .LocalAddr (), dstConn .LocalAddr (), dstConn .RemoteAddr ()),
967+ )
950968 j , err := json .Marshal (& layers.HTTPMessage {Request : r })
951969 if err == nil {
952970 sniffheader = append (sniffheader , string (j ))
@@ -1009,7 +1027,7 @@ func (p *proxyapp) sniffreporter(wg *sync.WaitGroup, sniffheader *[]string, reqC
10091027 if p .json {
10101028 p .snifflogger .Log ().Msg (fmt .Sprintf ("[%s]" , strings .Join (* sniffheader , "," )))
10111029 } else {
1012- p .snifflogger .Log ().Msg (fmt . Sprintf ( "%s" , strings .Join (* sniffheader , "\n " ) ))
1030+ p .snifflogger .Log ().Msg (strings .Join (* sniffheader , "\n " ))
10131031 }
10141032 }
10151033 * sniffheader = (* sniffheader )[:sniffheaderlen ]
@@ -1089,7 +1107,13 @@ readLoop:
10891107 return written , err
10901108}
10911109
1092- func (p * proxyapp ) transfer (wg * sync.WaitGroup , dst net.Conn , src net.Conn , destName , srcName string , msgChan chan <- layers.Layer ) {
1110+ func (p * proxyapp ) transfer (
1111+ wg * sync.WaitGroup ,
1112+ dst net.Conn ,
1113+ src net.Conn ,
1114+ destName , srcName string ,
1115+ msgChan chan <- layers.Layer ,
1116+ ) {
10931117 defer func () {
10941118 wg .Done ()
10951119 close (msgChan )
@@ -1173,10 +1197,10 @@ func (p *proxyapp) applyRedirectRules() string {
11731197 }
11741198 cmdInit := exec .Command ("bash" , "-c" , `
11751199 set -ex
1176- iptables -t nat -N GOHPTS 2>/dev/null
1177- iptables -t nat -F GOHPTS
1178-
1179- iptables -t nat -A GOHPTS -d 127.0.0.0/8 -j RETURN
1200+ iptables -t nat -N GOHPTS 2>/dev/null
1201+ iptables -t nat -F GOHPTS
1202+
1203+ iptables -t nat -A GOHPTS -d 127.0.0.0/8 -j RETURN
11801204 iptables -t nat -A GOHPTS -p tcp --dport 22 -j RETURN
11811205 ` )
11821206 cmdInit .Stdout = os .Stdout
@@ -1186,13 +1210,13 @@ func (p *proxyapp) applyRedirectRules() string {
11861210 }
11871211 if p .httpServerAddr != "" {
11881212 _ , httpPort , _ := net .SplitHostPort (p .httpServerAddr )
1189- cmdHttp := exec .Command ("bash" , "-c" , fmt .Sprintf (`
1213+ cmdHTTP := exec .Command ("bash" , "-c" , fmt .Sprintf (`
11901214 set -ex
11911215 iptables -t nat -A GOHPTS -p tcp --dport %s -j RETURN
11921216 ` , httpPort ))
1193- cmdHttp .Stdout = os .Stdout
1194- cmdHttp .Stderr = os .Stderr
1195- if err := cmdHttp .Run (); err != nil {
1217+ cmdHTTP .Stdout = os .Stdout
1218+ cmdHTTP .Stderr = os .Stderr
1219+ if err := cmdHTTP .Run (); err != nil {
11961220 p .logger .Fatal ().Err (err ).Msg ("Failed while configuring iptables. Are you root?" )
11971221 }
11981222 }
@@ -1241,7 +1265,7 @@ func (p *proxyapp) applyRedirectRules() string {
12411265 for subnet in $(docker network inspect $(docker network ls -q) --format '{{range .IPAM.Config}}{{.Subnet}}{{end}}'); do
12421266 iptables -t nat -A GOHPTS -d "$subnet" -j RETURN
12431267 done
1244- fi
1268+ fi
12451269
12461270 iptables -t nat -A GOHPTS -p tcp -j REDIRECT --to-ports %s
12471271
@@ -1514,7 +1538,7 @@ func getFullAddress(v string, all bool) (string, error) {
15141538 if v == "" {
15151539 return "" , nil
15161540 }
1517- var ip string = "127.0.0.1"
1541+ ip : = "127.0.0.1"
15181542 if all {
15191543 ip = "0.0.0.0"
15201544 }
@@ -1549,30 +1573,30 @@ func expandPath(p string) string {
15491573func New (conf * Config ) * proxyapp {
15501574 var logger , snifflogger zerolog.Logger
15511575 var p proxyapp
1552- var logfile * os. File = os .Stdout
1576+ logfile : = os .Stdout
15531577 var snifflog * os.File
15541578 var err error
15551579 p .sniff = conf .Sniff
15561580 p .body = conf .Body
1557- p .json = conf .Json
1581+ p .json = conf .JSON
15581582 if conf .LogFilePath != "" {
1559- f , err := os .OpenFile (conf .LogFilePath , os .O_CREATE | os .O_APPEND | os .O_WRONLY , 0644 )
1583+ f , err := os .OpenFile (conf .LogFilePath , os .O_CREATE | os .O_APPEND | os .O_WRONLY , 0o644 )
15601584 if err != nil {
15611585 log .Fatalf ("Failed to open log file: %v" , err )
15621586 }
15631587 logfile = f
15641588 }
15651589 if conf .SniffLogFile != "" && conf .SniffLogFile != conf .LogFilePath {
1566- f , err := os .OpenFile (conf .SniffLogFile , os .O_CREATE | os .O_APPEND | os .O_WRONLY , 0644 )
1590+ f , err := os .OpenFile (conf .SniffLogFile , os .O_CREATE | os .O_APPEND | os .O_WRONLY , 0o644 )
15671591 if err != nil {
15681592 log .Fatalf ("Failed to open sniff log file: %v" , err )
15691593 }
15701594 snifflog = f
15711595 } else {
15721596 snifflog = logfile
15731597 }
1574- p .nocolor = conf .Json || conf .NoColor
1575- if conf .Json {
1598+ p .nocolor = conf .JSON || conf .NoColor
1599+ if conf .JSON {
15761600 log .SetFlags (0 )
15771601 jsonWriter := jsonLogWriter {file : logfile }
15781602 log .SetOutput (jsonWriter )
@@ -1597,7 +1621,7 @@ func New(conf *Config) *proxyapp {
15971621 }
15981622 s := i .(string )
15991623 if p .nocolor {
1600- return fmt . Sprintf ( "%s" , s )
1624+ return s
16011625 }
16021626 result := ipPortPattern .ReplaceAllStringFunc (s , func (match string ) string {
16031627 return colors .Gray (match ).String ()
@@ -1615,7 +1639,7 @@ func New(conf *Config) *proxyapp {
16151639 output .FormatErrFieldValue = func (i any ) string {
16161640 s := i .(string )
16171641 if p .nocolor {
1618- return fmt . Sprintf ( "%s" , s )
1642+ return s
16191643 }
16201644 result := ipPortPattern .ReplaceAllStringFunc (s , func (match string ) string {
16211645 return colors .Red (match ).String ()
@@ -1624,7 +1648,6 @@ func New(conf *Config) *proxyapp {
16241648 return colors .Red (match ).String ()
16251649 })
16261650 return result
1627-
16281651 }
16291652 logger = zerolog .New (output ).With ().Timestamp ().Logger ()
16301653 sniffoutput := zerolog.ConsoleWriter {Out : snifflog , TimeFormat : time .RFC3339 , NoColor : p .nocolor , PartsExclude : []string {"level" }}
@@ -1648,7 +1671,7 @@ func New(conf *Config) *proxyapp {
16481671 sniffoutput .FormatErrFieldValue = func (i any ) string {
16491672 s := i .(string )
16501673 if p .nocolor {
1651- return fmt . Sprintf ( "%s" , s )
1674+ return s
16521675 }
16531676 result := ipPortPattern .ReplaceAllStringFunc (s , func (match string ) string {
16541677 return colors .Red (match ).String ()
@@ -1657,7 +1680,6 @@ func New(conf *Config) *proxyapp {
16571680 return colors .Red (match ).String ()
16581681 })
16591682 return result
1660-
16611683 }
16621684 snifflogger = zerolog .New (sniffoutput ).With ().Timestamp ().Logger ()
16631685 }
0 commit comments