Browse Source

Fix stream sniffer

世界 1 year ago
parent
commit
27d6b63e71
2 changed files with 31 additions and 20 deletions
  1. 30 19
      common/sniff/sniff.go
  2. 1 1
      route/router.go

+ 30 - 19
common/sniff/sniff.go

@@ -18,33 +18,44 @@ type (
 	PacketSniffer = func(ctx context.Context, packet []byte) (*adapter.InboundContext, error)
 )
 
+func Skip(metadata adapter.InboundContext) bool {
+	// skip server first protocols
+	switch metadata.Destination.Port {
+	case 25, 465, 587:
+		// SMTP
+		return true
+	case 143, 993:
+		// IMAP
+		return true
+	case 110, 995:
+		// POP3
+		return true
+	}
+	return false
+}
+
 func PeekStream(ctx context.Context, conn net.Conn, buffer *buf.Buffer, timeout time.Duration, sniffers ...StreamSniffer) (*adapter.InboundContext, error) {
 	if timeout == 0 {
 		timeout = C.ReadPayloadTimeout
 	}
 	deadline := time.Now().Add(timeout)
 	var errors []error
-
-	for i := 0; i < 3; i++ {
-		err := conn.SetReadDeadline(deadline)
-		if err != nil {
-			return nil, E.Cause(err, "set read deadline")
-		}
-		_, err = buffer.ReadOnceFrom(conn)
-		err = E.Errors(err, conn.SetReadDeadline(time.Time{}))
-		if err != nil {
-			if i > 0 {
-				break
-			}
-			return nil, E.Cause(err, "read payload")
+	err := conn.SetReadDeadline(deadline)
+	if err != nil {
+		return nil, E.Cause(err, "set read deadline")
+	}
+	defer conn.SetReadDeadline(time.Time{})
+	var metadata *adapter.InboundContext
+	for _, sniffer := range sniffers {
+		if buffer.IsEmpty() {
+			metadata, err = sniffer(ctx, io.TeeReader(conn, buffer))
+		} else {
+			metadata, err = sniffer(ctx, io.MultiReader(bytes.NewReader(buffer.Bytes()), io.TeeReader(conn, buffer)))
 		}
-		for _, sniffer := range sniffers {
-			metadata, err := sniffer(ctx, bytes.NewReader(buffer.Bytes()))
-			if metadata != nil {
-				return metadata, nil
-			}
-			errors = append(errors, err)
+		if metadata != nil {
+			return metadata, nil
 		}
+		errors = append(errors, err)
 	}
 	return nil, E.Errors(errors...)
 }

+ 1 - 1
route/router.go

@@ -832,7 +832,7 @@ func (r *Router) RouteConnection(ctx context.Context, conn net.Conn, metadata ad
 		conn = deadline.NewConn(conn)
 	}
 
-	if metadata.InboundOptions.SniffEnabled {
+	if metadata.InboundOptions.SniffEnabled && !sniff.Skip(metadata) {
 		buffer := buf.NewPacket()
 		sniffMetadata, err := sniff.PeekStream(ctx, conn, buffer, time.Duration(metadata.InboundOptions.SniffTimeout), sniff.StreamDomainNameQuery, sniff.TLSClientHello, sniff.HTTPHost)
 		if sniffMetadata != nil {