Просмотр исходного кода

Change port forward failure logging

- Only log UDP failure details at "debug" level
- Check for specific resource exhaustion port
  forward dial errors and emit specific log
Rod Hynes 9 лет назад
Родитель
Сommit
a04d9a453b
2 измененных файлов с 32 добавлено и 3 удалено
  1. 29 1
      psiphon/server/tunnelServer.go
  2. 3 2
      psiphon/server/udp.go

+ 29 - 1
psiphon/server/tunnelServer.go

@@ -29,6 +29,7 @@ import (
 	"strconv"
 	"sync"
 	"sync/atomic"
+	"syscall"
 	"time"
 
 	"github.com/Psiphon-Inc/crypto/ssh"
@@ -628,6 +629,33 @@ func (sshServer *sshServer) handleClient(tunnelProtocol string, clientConn net.C
 	sshClient.run(clientConn)
 }
 
+func (sshServer *sshServer) handlePortForwardDialError(err error) {
+
+	// "err" is the error returned from a failed TCP or UDP port
+	// forward dial. Certain system error codes indicate low resource
+	// conditions: insufficient file descriptors, ephemeral ports, or
+	// memory. For these cases, log an alert.
+
+	// TODO: also temporarily suspend new clients
+
+	// Note: don't log net.OpError.Error() as the full error string
+	// may contain client destination addresses.
+
+	opErr, ok := err.(*net.OpError)
+	if ok {
+		if opErr.Err == syscall.EADDRNOTAVAIL ||
+			opErr.Err == syscall.EAGAIN ||
+			opErr.Err == syscall.ENOMEM ||
+			opErr.Err == syscall.EMFILE ||
+			opErr.Err == syscall.ENFILE {
+
+			log.WithContextFields(
+				LogFields{"error": opErr.Err}).Error(
+				"port forward dial failed due to unavailable resource")
+		}
+	}
+}
+
 type sshClient struct {
 	sync.Mutex
 	sshServer              *sshServer
@@ -1544,7 +1572,6 @@ func (sshClient *sshClient) handleTCPChannel(
 	dialStartTime := monotime.Now()
 
 	go func() {
-		// TODO: on EADDRNOTAVAIL, temporarily suspend new clients
 		conn, err := net.DialTimeout(
 			"tcp", remoteAddr, SSH_TCP_PORT_FORWARD_DIAL_TIMEOUT)
 		dialResultChannel <- &dialTCPResult{conn, err}
@@ -1563,6 +1590,7 @@ func (sshClient *sshClient) handleTCPChannel(
 		dialResult.err == nil, monotime.Since(dialStartTime))
 
 	if dialResult.err != nil {
+		sshClient.sshServer.handlePortForwardDialError(dialResult.err)
 		sshClient.rejectNewChannel(
 			newChannel, ssh.ConnectionFailed, fmt.Sprintf("DialTimeout failed: %s", dialResult.err))
 		return

+ 3 - 2
psiphon/server/udp.go

@@ -195,12 +195,13 @@ func (mux *udpPortForwardMultiplexer) run() {
 					"remoteAddr": fmt.Sprintf("%s:%d", dialIP.String(), dialPort),
 					"connID":     message.connID}).Debug("dialing")
 
-			// TODO: on EADDRNOTAVAIL, temporarily suspend new clients
 			udpConn, err := net.DialUDP(
 				"udp", nil, &net.UDPAddr{IP: dialIP, Port: dialPort})
 			if err != nil {
 				mux.sshClient.closedPortForward(portForwardTypeUDP, 0, 0)
-				log.WithContextFields(LogFields{"error": err}).Warning("DialUDP failed")
+				mux.sshClient.sshServer.handlePortForwardDialError(err)
+				// Note: Debug level, as logMessage may contain user traffic destination address information
+				log.WithContextFields(LogFields{"error": err}).Debug("DialUDP failed")
 				continue
 			}