github.com/sagernet/sing-box@v1.2.7/common/sniff/sniff.go (about)

     1  package sniff
     2  
     3  import (
     4  	"bytes"
     5  	"context"
     6  	"io"
     7  	"net"
     8  	"time"
     9  
    10  	"github.com/sagernet/sing-box/adapter"
    11  	C "github.com/sagernet/sing-box/constant"
    12  	"github.com/sagernet/sing/common/buf"
    13  	E "github.com/sagernet/sing/common/exceptions"
    14  )
    15  
    16  type (
    17  	StreamSniffer = func(ctx context.Context, reader io.Reader) (*adapter.InboundContext, error)
    18  	PacketSniffer = func(ctx context.Context, packet []byte) (*adapter.InboundContext, error)
    19  )
    20  
    21  func PeekStream(ctx context.Context, conn net.Conn, buffer *buf.Buffer, timeout time.Duration, sniffers ...StreamSniffer) (*adapter.InboundContext, error) {
    22  	if timeout == 0 {
    23  		timeout = C.ReadPayloadTimeout
    24  	}
    25  	err := conn.SetReadDeadline(time.Now().Add(timeout))
    26  	if err != nil {
    27  		return nil, E.Cause(err, "set read deadline")
    28  	}
    29  	_, err = buffer.ReadOnceFrom(conn)
    30  	err = E.Errors(err, conn.SetReadDeadline(time.Time{}))
    31  	if err != nil {
    32  		return nil, E.Cause(err, "read payload")
    33  	}
    34  	var metadata *adapter.InboundContext
    35  	var errors []error
    36  	for _, sniffer := range sniffers {
    37  		metadata, err = sniffer(ctx, bytes.NewReader(buffer.Bytes()))
    38  		if metadata != nil {
    39  			return metadata, nil
    40  		}
    41  		errors = append(errors, err)
    42  	}
    43  	return nil, E.Errors(errors...)
    44  }
    45  
    46  func PeekPacket(ctx context.Context, packet []byte, sniffers ...PacketSniffer) (*adapter.InboundContext, error) {
    47  	var errors []error
    48  	for _, sniffer := range sniffers {
    49  		metadata, err := sniffer(ctx, packet)
    50  		if metadata != nil {
    51  			return metadata, nil
    52  		}
    53  		errors = append(errors, err)
    54  	}
    55  	return nil, E.Errors(errors...)
    56  }