From 4e08ec08eac38ed4828c72ead66874747930be45 Mon Sep 17 00:00:00 2001 From: Mostafa Moradian Date: Mon, 2 Jan 2023 19:19:09 +0100 Subject: [PATCH 1/5] Extract if-statement for checking connection close from server into a separate function Add function to check if the connection timed out --- network/proxy.go | 2 +- network/utils.go | 15 +++++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/network/proxy.go b/network/proxy.go index 0cb8412e..d9eccc6c 100644 --- a/network/proxy.go +++ b/network/proxy.go @@ -262,7 +262,7 @@ func (pr *ProxyImpl) PassThrough(gconn gnet.Conn) *gerr.GatewayDError { // The connection to the server is closed, so we MUST reconnect, // otherwise the client will be stuck. - if received == 0 && err != nil && errors.Is(err.Unwrap(), io.EOF) { + if IsConnClosed(received, err) || IsConnTimedOut(err) { pr.logger.Debug().Fields( map[string]interface{}{ "function": "proxy.passthrough", diff --git a/network/utils.go b/network/utils.go index 964c44a4..d3ebb4df 100644 --- a/network/utils.go +++ b/network/utils.go @@ -4,7 +4,9 @@ import ( "crypto/sha256" "encoding/base64" "encoding/hex" + "errors" "fmt" + "io" "net" "syscall" @@ -118,3 +120,16 @@ func extractFieldValue(result map[string]interface{}, fieldName string) ([]byte, } return data, err, conversionErr } + +func IsConnTimedOut(err *gerr.GatewayDError) bool { + if err != nil && err.Unwrap() != nil { + if neterr, ok := err.Unwrap().(net.Error); ok && neterr.Timeout() { + return true + } + } + return false +} + +func IsConnClosed(received int, err *gerr.GatewayDError) bool { + return received == 0 && err != nil && err.Unwrap() != nil && errors.Is(err.Unwrap(), io.EOF) +} From c42811f5f17a04c8347ec65dafc02f6abb95243a Mon Sep 17 00:00:00 2001 From: Mostafa Moradian Date: Mon, 2 Jan 2023 19:21:56 +0100 Subject: [PATCH 2/5] Chain switch cases --- network/server.go | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/network/server.go b/network/server.go index b3094345..86e58a2a 100644 --- a/network/server.go +++ b/network/server.go @@ -220,13 +220,13 @@ func (s *Server) OnTraffic(gconn gnet.Conn) gnet.Action { if err := s.proxy.PassThrough(gconn); err != nil { s.logger.Error().Err(err).Msg("Failed to pass through traffic") switch { - case errors.Is(err, gerr.ErrPoolExhausted): - case errors.Is(err, gerr.ErrCastFailed): - case errors.Is(err, gerr.ErrClientNotFound): - case errors.Is(err, gerr.ErrClientNotConnected): - case errors.Is(err, gerr.ErrClientSendFailed): - case errors.Is(err, gerr.ErrClientReceiveFailed): - case errors.Is(err.Unwrap(), io.EOF): + case errors.Is(err, gerr.ErrPoolExhausted), + errors.Is(err, gerr.ErrCastFailed), + errors.Is(err, gerr.ErrClientNotFound), + errors.Is(err, gerr.ErrClientNotConnected), + errors.Is(err, gerr.ErrClientSendFailed), + errors.Is(err, gerr.ErrClientReceiveFailed), + errors.Is(err.Unwrap(), io.EOF): return gnet.Close } } From c20056a35c7a885238686d7b1dce087147bcae01 Mon Sep 17 00:00:00 2001 From: Mostafa Moradian Date: Mon, 2 Jan 2023 19:22:21 +0100 Subject: [PATCH 3/5] Fail early to prevent connection from hanging --- network/proxy.go | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/network/proxy.go b/network/proxy.go index d9eccc6c..04a378a7 100644 --- a/network/proxy.go +++ b/network/proxy.go @@ -2,8 +2,6 @@ package network import ( "context" - "errors" - "io" gerr "github.com/gatewayd-io/gatewayd/errors" "github.com/gatewayd-io/gatewayd/plugin" @@ -289,6 +287,17 @@ func (pr *ProxyImpl) PassThrough(gconn gnet.Conn) *gerr.GatewayDError { } } + // If the response is empty, don't send anything, instead just close the ingress connection. + if received == 0 { + pr.logger.Debug().Fields( + map[string]interface{}{ + "function": "proxy.passthrough", + "local": client.Conn.LocalAddr().String(), + "remote": client.Conn.RemoteAddr().String(), + }).Msg("No data to send to client") + return err + } + // Run the OnEgressTraffic hooks. result, err = pr.hookConfig.Run( context.Background(), From 8681a7fbc82afa88986cd502b5360fc37dca2c6f Mon Sep 17 00:00:00 2001 From: Mostafa Moradian Date: Mon, 2 Jan 2023 19:25:12 +0100 Subject: [PATCH 4/5] Lower log level, as it is not an actual error, rather a warning --- network/server.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/network/server.go b/network/server.go index 86e58a2a..b4c4a677 100644 --- a/network/server.go +++ b/network/server.go @@ -218,7 +218,7 @@ func (s *Server) OnTraffic(gconn gnet.Conn) gnet.Action { // Pass the traffic from the client to server and vice versa. // If there is an error, log it and close the connection. if err := s.proxy.PassThrough(gconn); err != nil { - s.logger.Error().Err(err).Msg("Failed to pass through traffic") + s.logger.Warn().Err(err).Msg("Failed to pass through traffic") switch { case errors.Is(err, gerr.ErrPoolExhausted), errors.Is(err, gerr.ErrCastFailed), From fd130da5e62310340c48a10ae8b4a2b138f07389 Mon Sep 17 00:00:00 2001 From: Mostafa Moradian Date: Mon, 2 Jan 2023 19:32:08 +0100 Subject: [PATCH 5/5] Fix error wrap issue reported by errorlint --- network/utils.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/network/utils.go b/network/utils.go index d3ebb4df..e434ac43 100644 --- a/network/utils.go +++ b/network/utils.go @@ -123,7 +123,8 @@ func extractFieldValue(result map[string]interface{}, fieldName string) ([]byte, func IsConnTimedOut(err *gerr.GatewayDError) bool { if err != nil && err.Unwrap() != nil { - if neterr, ok := err.Unwrap().(net.Error); ok && neterr.Timeout() { + var netErr net.Error + if ok := errors.As(err.Unwrap(), &netErr); ok && netErr.Timeout() { return true } }