Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Quiet down TCP RST packet error on read operation #9007

Merged
merged 2 commits into from
Sep 14, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 26 additions & 2 deletions pkg/tcp/proxy.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
package tcp

import (
"errors"
"fmt"
"io"
"net"
"syscall"
"time"

"github.com/pires/go-proxyproto"
Expand Down Expand Up @@ -74,7 +76,14 @@ func (p *Proxy) ServeTCP(conn WriteCloser) {

err = <-errChan
if err != nil {
log.WithoutContext().Errorf("Error during connection: %v", err)
// Treat connection reset error during a read operation with a lower log level.
// This allows to not report an RST packet sent by the peer as an error,
// as it is an abrupt but possible end for the TCP session
if isReadConnResetError(err) {
log.WithoutContext().Debugf("Error during connection: %v", err)
} else {
log.WithoutContext().Errorf("Error during connection: %v", err)
}
}

<-errChan
Expand All @@ -101,9 +110,18 @@ func (p Proxy) connCopy(dst, src WriteCloser, errCh chan error) {
_, err := io.Copy(dst, src)
errCh <- err

// Ends the connection with the dst connection peer.
// It corresponds to sending a FIN packet to gracefully end the TCP session.
errClose := dst.CloseWrite()
if errClose != nil {
log.WithoutContext().Debugf("Error while terminating connection: %v", errClose)
// Calling CloseWrite() on a connection which have a socket which is "not connected" is expected to fail.
// It happens notably when the dst connection has ended receiving an RST packet from the peer (within the other connCopy call).
// In that case, logging the error is superfluous,
// as in the first place we should not have needed to call CloseWrite.
if !isSocketNotConnectedError(errClose) {
log.WithoutContext().Debugf("Error while terminating connection: %v", errClose)
}

return
}

Expand All @@ -114,3 +132,9 @@ func (p Proxy) connCopy(dst, src WriteCloser, errCh chan error) {
}
}
}

// isSocketNotConnectedError reports whether err is a socket not connected error.
func isSocketNotConnectedError(err error) bool {
var oerr *net.OpError
return errors.As(err, &oerr) && errors.Is(err, syscall.ENOTCONN)
}
16 changes: 16 additions & 0 deletions pkg/tcp/proxy_unix.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
//go:build !windows
// +build !windows

package tcp

import (
"errors"
"net"
"syscall"
)

// isReadConnResetError reports whether err is a connection reset error during a read operation.
func isReadConnResetError(err error) bool {
var oerr *net.OpError
return errors.As(err, &oerr) && oerr.Op == "read" && errors.Is(err, syscall.ECONNRESET)
}
16 changes: 16 additions & 0 deletions pkg/tcp/proxy_windows.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
//go:build windows
// +build windows

package tcp

import (
"errors"
"net"
"syscall"
)

// isReadConnResetError reports whether err is a connection reset error during a read operation.
func isReadConnResetError(err error) bool {
var oerr *net.OpError
return errors.As(err, &oerr) && oerr.Op == "read" && errors.Is(err, syscall.WSAECONNRESET)
}