From 213168f183185cb78356c3e08a11c8b8866438c1 Mon Sep 17 00:00:00 2001 From: shadowy-pycoder <35629483+shadowy-pycoder@users.noreply.github.com> Date: Wed, 18 Jun 2025 08:15:47 +0300 Subject: [PATCH 1/2] made colored output optional, fixed linter warnings, optimized parser switch statement --- cmd/gohpts/cli.go | 7 ++++--- gohpts.go | 38 +++++++++++++------------------------- 2 files changed, 17 insertions(+), 28 deletions(-) diff --git a/cmd/gohpts/cli.go b/cmd/gohpts/cli.go index 2790384..f17b025 100644 --- a/cmd/gohpts/cli.go +++ b/cmd/gohpts/cli.go @@ -13,9 +13,9 @@ import ( const ( app string = "gohpts" - addrSOCKS = "127.0.0.1:1080" - addrHTTP = "127.0.0.1:8080" - tproxyOS = "linux" + addrSOCKS string = "127.0.0.1:1080" + addrHTTP string = "127.0.0.1:8080" + tproxyOS string = "linux" ) const usagePrefix string = ` _____ _ _ _____ _______ _____ @@ -61,6 +61,7 @@ func root(args []string) error { flags.BoolVar(&conf.Json, "j", false, "Show logs in JSON format") flags.BoolVar(&conf.Sniff, "sniff", false, "Enable traffic sniffing for HTTP and TLS") flags.StringVar(&conf.SniffLogFile, "snifflog", "", "Sniffed traffic log file path (Default: the same as -logfile)") + flags.BoolVar(&conf.Color, "color", false, "Enable colored output for logs in stdout (no effect if log file provided or -j flag specified)") flags.BoolFunc("v", "print version", func(flagValue string) error { fmt.Println(gohpts.Version) os.Exit(0) diff --git a/gohpts.go b/gohpts.go index 453fab2..721e6eb 100644 --- a/gohpts.go +++ b/gohpts.go @@ -543,7 +543,7 @@ func (p *proxyapp) sniffreporter(wg *sync.WaitGroup, sniffheader *[]string, reqC } } -func sniff(data []byte, logger *zerolog.Logger) ([]byte, error) { +func sniff(data []byte) ([]byte, error) { // TODO: check if it is http or tls beforehand h := &layers.HTTPMessage{} if err := h.Parse(data); err == nil && !h.IsEmpty() { @@ -559,26 +559,13 @@ func sniff(data []byte, logger *zerolog.Logger) ([]byte, error) { if len(m.Records) > 0 { hsrec := m.Records[0] if hsrec.ContentType == layers.HandshakeTLSVal { // TODO: add more cases, parse all records - parser := layers.HSTLSParserByType(hsrec.Data[0]) - switch parser.(type) { - case *layers.TLSClientHello: - tc := parser.(*layers.TLSClientHello) - err := tc.ParseHS(hsrec.Data) + switch parser := layers.HSTLSParserByType(hsrec.Data[0]).(type) { + case *layers.TLSClientHello, *layers.TLSServerHello: + err := parser.ParseHS(hsrec.Data) if err != nil { return nil, err } - j, err := json.Marshal(tc) - if err != nil { - return nil, err - } - return j, nil - case *layers.TLSServerHello: - ts := parser.(*layers.TLSServerHello) - err := ts.ParseHS(hsrec.Data) - if err != nil { - return nil, err - } - j, err := json.Marshal(ts) + j, err := json.Marshal(parser) if err != nil { return nil, err } @@ -605,7 +592,7 @@ func (p *proxyapp) copyWithTimeout(dst net.Conn, src net.Conn, msgChan chan<- [] break } if p.sniff { - s, err := sniff(buf[0:nr], p.logger) + s, err := sniff(buf[0:nr]) if err == nil { msgChan <- s } @@ -665,7 +652,7 @@ func parseProxyAuth(auth string) (username, password string, ok bool) { return "", "", false } const prefix = "Basic " - if len(auth) < len(prefix) || strings.ToLower(prefix) != strings.ToLower(auth[:len(prefix)]) { + if len(auth) < len(prefix) || !strings.EqualFold(prefix, auth[:len(prefix)]) { return "", "", false } c, err := base64.StdEncoding.DecodeString(auth[len(prefix):]) @@ -797,6 +784,7 @@ type Config struct { Json bool Sniff bool SniffLogFile string + Color bool } type logWriter struct { @@ -804,7 +792,7 @@ type logWriter struct { } func (writer logWriter) Write(bytes []byte) (int, error) { - return fmt.Fprintf(writer.file, fmt.Sprintf("%s | ERROR | %s", time.Now().Format(time.RFC3339), string(bytes))) + return fmt.Fprintf(writer.file, "%s ERR %s", time.Now().Format(time.RFC3339), string(bytes)) } type jsonLogWriter struct { @@ -812,8 +800,8 @@ type jsonLogWriter struct { } func (writer jsonLogWriter) Write(bytes []byte) (int, error) { - return fmt.Fprintf(writer.file, fmt.Sprintf("{\"level\":\"error\",\"time\":\"%s\",\"message\":\"%s\"}\n", - time.Now().Format(time.RFC3339), strings.TrimRight(string(bytes), "\n"))) + return fmt.Fprintf(writer.file, "{\"level\":\"error\",\"time\":\"%s\",\"message\":\"%s\"}\n", + time.Now().Format(time.RFC3339), strings.TrimRight(string(bytes), "\n")) } type proxyEntry struct { @@ -902,8 +890,8 @@ func New(conf *Config) *proxyapp { log.SetFlags(0) logWriter := logWriter{file: logfile} log.SetOutput(logWriter) - noColor := logfile != os.Stdout - sniffNoColor := snifflog != os.Stdout + noColor := !conf.Color || logfile != os.Stdout + sniffNoColor := !conf.Color || snifflog != os.Stdout output := zerolog.ConsoleWriter{Out: logfile, TimeFormat: time.RFC3339, NoColor: noColor} logger = zerolog.New(output).With().Timestamp().Logger() sniffoutput := zerolog.ConsoleWriter{Out: snifflog, TimeFormat: time.RFC3339, NoColor: sniffNoColor} From fc7af7de3f3ec402350c458244eee83ec06c4ecb Mon Sep 17 00:00:00 2001 From: shadowy-pycoder <35629483+shadowy-pycoder@users.noreply.github.com> Date: Wed, 18 Jun 2025 08:27:31 +0300 Subject: [PATCH 2/2] updated README.md, bumped to v1.7.1 --- README.md | 38 ++++++++++++++++++++------------------ gohpts.go | 2 +- version.go | 2 +- 3 files changed, 22 insertions(+), 20 deletions(-) diff --git a/README.md b/README.md index ba39a6e..39aa445 100644 --- a/README.md +++ b/README.md @@ -93,7 +93,7 @@ You can download the binary for your platform from [Releases](https://github.com Example: ```shell -HPTS_RELEASE=v1.7.0; wget -v https://github.com/shadowy-pycoder/go-http-proxy-to-socks/releases/download/$HPTS_RELEASE/gohpts-$HPTS_RELEASE-linux-amd64.tar.gz -O gohpts && tar xvzf gohpts && mv -f gohpts-$HPTS_RELEASE-linux-amd64 gohpts && ./gohpts -h +HPTS_RELEASE=v1.7.1; wget -v https://github.com/shadowy-pycoder/go-http-proxy-to-socks/releases/download/$HPTS_RELEASE/gohpts-$HPTS_RELEASE-linux-amd64.tar.gz -O gohpts && tar xvzf gohpts && mv -f gohpts-$HPTS_RELEASE-linux-amd64 gohpts && ./gohpts -h ``` Alternatively, you can install it using `go install` command (requires Go [1.24](https://go.dev/doc/install) or later): @@ -132,36 +132,38 @@ GitHub: https://github.com/shadowy-pycoder/go-http-proxy-to-socks Usage: gohpts [OPTIONS] Options: -h Show this help message and exit. - -D Run as a daemon (provide -logfile to see logs) + -D Run as a daemon (provide -logfile to see logs) -M value - Transparent proxy mode: [redirect tproxy] + Transparent proxy mode: [redirect tproxy] -T string - Address of transparent proxy server (no HTTP) + Address of transparent proxy server (no HTTP) -U string - User for HTTP proxy (basic auth). This flag invokes prompt for password (not echoed to terminal) + User for HTTP proxy (basic auth). This flag invokes prompt for password (not echoed to terminal) -c string - Path to certificate PEM encoded file - -d Show logs in DEBUG mode + Path to certificate PEM encoded file + -color + Enable colored output for logs in stdout (no effect if log file provided or -j flag specified) + -d Show logs in DEBUG mode -f string - Path to server configuration file in YAML format - -j Show logs in JSON format + Path to server configuration file in YAML format + -j Show logs in JSON format -k string - Path to private key PEM encoded file + Path to private key PEM encoded file -l string - Address of HTTP proxy server (default "127.0.0.1:8080") + Address of HTTP proxy server (default "127.0.0.1:8080") -logfile string - Log file path (Default: stdout) + Log file path (Default: stdout) -s string - Address of SOCKS5 proxy server (default "127.0.0.1:1080") + Address of SOCKS5 proxy server (default "127.0.0.1:1080") -sniff - Enable traffic sniffing for HTTP and TLS + Enable traffic sniffing for HTTP and TLS -snifflog string - Sniffed traffic log file path (Default: the same as -logfile) + Sniffed traffic log file path (Default: the same as -logfile) -t string - Address of transparent proxy server (it starts along with HTTP proxy server) + Address of transparent proxy server (it starts along with HTTP proxy server) -u string - User for SOCKS5 proxy authentication. This flag invokes prompt for password (not echoed to terminal) - -v print version + User for SOCKS5 proxy authentication. This flag invokes prompt for password (not echoed to terminal) + -v print version ``` ### Configuration via CLI flags diff --git a/gohpts.go b/gohpts.go index 721e6eb..2f10534 100644 --- a/gohpts.go +++ b/gohpts.go @@ -532,7 +532,7 @@ func (p *proxyapp) sniffreporter(wg *sync.WaitGroup, sniffheader *[]string, reqC defer wg.Done() sniffheaderlen := len(*sniffheader) for { - req, okreq := <-reqChan // if resp comes first it blocks + req, okreq := <-reqChan // FIX: if resp comes first it blocks resp, okresp := <-respChan if !okreq || !okresp { return diff --git a/version.go b/version.go index 79dc9e6..f6e0722 100644 --- a/version.go +++ b/version.go @@ -1,3 +1,3 @@ package gohpts -const Version string = "gohpts v1.7.0" +const Version string = "gohpts v1.7.1"