From 2fb70bdb58fd27ea004fd2936b4c3270aed54ae0 Mon Sep 17 00:00:00 2001 From: Haruue Icymoon Date: Thu, 25 Aug 2022 00:32:47 +0800 Subject: [PATCH] feat: log http proxy error goproxy actually discard all upstream errors, you can find its error handling here [1], the upstream error from proxy.connectDial() is always hidden in the two if branches, and never got logged. we need to log hysteria layer errors by ourselves. [1] https://github.com/elazarl/goproxy/blob/8ea89ba92021a445673ddc24d6da7a4af7d75249/https.go#L321-L328 according to some bug reports (such like #404 and the resolve_preference one report via telegram private message), some users use http proxy, got a http 502 error without any useful logs. --- cmd/client.go | 9 +++++++-- pkg/http/server.go | 31 +++++++++++++++++++++++++------ 2 files changed, 32 insertions(+), 8 deletions(-) diff --git a/cmd/client.go b/cmd/client.go index 92811c8..63b6698 100644 --- a/cmd/client.go +++ b/cmd/client.go @@ -228,14 +228,19 @@ func client(config *clientConfig) { } } proxy, err := hyHTTP.NewProxyHTTPServer(client, transport.DefaultClientTransport, - time.Duration(config.HTTP.Timeout)*time.Second, aclEngine, + time.Duration(config.HTTP.Timeout)*time.Second, aclEngine, authFunc, func(reqAddr string, action acl.Action, arg string) { logrus.WithFields(logrus.Fields{ "action": actionToString(action, arg), "dst": defaultIPMasker.Mask(reqAddr), }).Debug("HTTP request") }, - authFunc) + func(reqAddr string, err error) { + logrus.WithFields(logrus.Fields{ + "error": err, + "dst": defaultIPMasker.Mask(reqAddr), + }).Info("HTTP error") + }) if err != nil { logrus.WithField("error", err).Fatal("Failed to initialize HTTP server") } diff --git a/pkg/http/server.go b/pkg/http/server.go index f44eff3..68da69d 100644 --- a/pkg/http/server.go +++ b/pkg/http/server.go @@ -18,8 +18,10 @@ import ( ) func NewProxyHTTPServer(hyClient *core.Client, transport *transport.ClientTransport, idleTimeout time.Duration, - aclEngine *acl.Engine, newDialFunc func(reqAddr string, action acl.Action, arg string), + aclEngine *acl.Engine, basicAuthFunc func(user, password string) bool, + newDialFunc func(reqAddr string, action acl.Action, arg string), + proxyErrorFunc func(reqAddr string, err error), ) (*goproxy.ProxyHttpServer, error) { proxy := goproxy.NewProxyHttpServer() proxy.Logger = &nopLogger{} @@ -46,27 +48,44 @@ func NewProxyHTTPServer(hyClient *core.Client, transport *transport.ClientTransp if resErr != nil { return nil, resErr } - return transport.DialTCP(&net.TCPAddr{ + conn, err := transport.DialTCP(&net.TCPAddr{ IP: ipAddr.IP, Port: int(port), Zone: ipAddr.Zone, }) + if err != nil { + proxyErrorFunc(addr, err) + } + return conn, err case acl.ActionProxy: - return hyClient.DialTCP(addr) + conn, err := hyClient.DialTCP(addr) + if err != nil { + proxyErrorFunc(addr, err) + } + return conn, err case acl.ActionBlock: - return nil, errors.New("blocked by ACL") + err := errors.New("blocked by ACL") + proxyErrorFunc(addr, err) + return nil, err case acl.ActionHijack: hijackIPAddr, err := transport.ResolveIPAddr(arg) if err != nil { + proxyErrorFunc(addr, err) return nil, err } - return transport.DialTCP(&net.TCPAddr{ + conn, err := transport.DialTCP(&net.TCPAddr{ IP: hijackIPAddr.IP, Port: int(port), Zone: hijackIPAddr.Zone, }) + if err != nil { + proxyErrorFunc(addr, err) + } + return conn, err default: - return nil, fmt.Errorf("unknown action %d", action) + err := fmt.Errorf("unknown action %d", action) + proxyErrorFunc(addr, err) + return nil, err } }, IdleConnTimeout: idleTimeout,