github.com/yaling888/clash@v1.53.0/tunnel/statistic/sniffing.go (about)

     1  package statistic
     2  
     3  import (
     4  	"errors"
     5  	"strings"
     6  
     7  	"github.com/phuslu/log"
     8  	"go.uber.org/atomic"
     9  
    10  	"github.com/yaling888/clash/common/snifer/tls"
    11  	"github.com/yaling888/clash/component/resolver"
    12  	C "github.com/yaling888/clash/constant"
    13  )
    14  
    15  type sniffing struct {
    16  	C.Conn
    17  
    18  	metadata   *C.Metadata
    19  	totalWrite *atomic.Uint64
    20  	allowBreak bool
    21  }
    22  
    23  func (r *sniffing) Read(b []byte) (int, error) {
    24  	return r.Conn.Read(b)
    25  }
    26  
    27  func (r *sniffing) Write(b []byte) (int, error) {
    28  	if r.totalWrite.Load() < 128 && r.metadata.Host == "" &&
    29  		(r.metadata.DstPort == 443 || r.metadata.DstPort == 8443 || r.metadata.DstPort == 993 ||
    30  			r.metadata.DstPort == 465 || r.metadata.DstPort == 995) {
    31  		header, err := tls.SniffTLS(b)
    32  		if err == nil && strings.Index(header.Domain(), ".") > 0 {
    33  			log.Debug().
    34  				Str("host", header.Domain()).
    35  				NetIPAddr("ip", r.metadata.DstIP).
    36  				Msg("[Sniffer] update sni")
    37  
    38  			resolver.InsertHostByIP(r.metadata.DstIP, header.Domain())
    39  
    40  			if r.allowBreak {
    41  				_ = r.Conn.Close()
    42  				return 0, errors.New("sni update, break current link to avoid leaks")
    43  			} else {
    44  				r.metadata.Host = header.Domain()
    45  			}
    46  		}
    47  	}
    48  
    49  	n, err := r.Conn.Write(b)
    50  	r.totalWrite.Add(uint64(n))
    51  
    52  	return n, err
    53  }
    54  
    55  func (r *sniffing) Close() error {
    56  	return r.Conn.Close()
    57  }
    58  
    59  func NewSniffing(conn C.Conn, metadata *C.Metadata, rule C.Rule) C.Conn {
    60  	return &sniffing{
    61  		Conn:       conn,
    62  		metadata:   metadata,
    63  		totalWrite: atomic.NewUint64(0),
    64  		allowBreak: rule != nil,
    65  	}
    66  }