diff --git a/config/config.go b/config/config.go index d876ff18..d808d97f 100644 --- a/config/config.go +++ b/config/config.go @@ -39,6 +39,7 @@ type General struct { Mode T.TunnelMode `json:"mode"` LogLevel log.LogLevel `json:"log-level"` IPv6 bool `json:"ipv6"` + Sniffing bool `json:"sniffing"` Interface string `json:"-"` RoutingMark int `json:"-"` Tun Tun `json:"tun"` @@ -182,6 +183,7 @@ type RawConfig struct { Secret string `yaml:"secret"` Interface string `yaml:"interface-name"` RoutingMark int `yaml:"routing-mark"` + Sniffing bool `yaml:"sniffing"` ProxyProvider map[string]map[string]any `yaml:"proxy-providers"` Hosts map[string]string `yaml:"hosts"` @@ -210,6 +212,7 @@ func UnmarshalRawConfig(buf []byte) (*RawConfig, error) { // config with default value rawCfg := &RawConfig{ AllowLan: false, + Sniffing: false, BindAddress: "*", Mode: T.Rule, Authentication: []string{}, @@ -374,6 +377,7 @@ func parseGeneral(cfg *RawConfig) (*General, error) { IPv6: cfg.IPv6, Interface: cfg.Interface, RoutingMark: cfg.RoutingMark, + Sniffing: cfg.Sniffing, Tun: cfg.Tun, }, nil } diff --git a/hub/executor/executor.go b/hub/executor/executor.go index 14857155..e2588311 100644 --- a/hub/executor/executor.go +++ b/hub/executor/executor.go @@ -112,6 +112,7 @@ func GetGeneral() *config.General { Mode: tunnel.Mode(), LogLevel: log.Level(), IPv6: !resolver.DisableIPv6, + Sniffing: tunnel.Sniffing(), Tun: P.GetTunConf(), } @@ -217,6 +218,11 @@ func updateGeneral(general *config.General, force bool) { bindAddress := general.BindAddress P.SetBindAddress(bindAddress) + sniffing := general.Sniffing + tunnel.SetSniffing(sniffing) + + log.Infoln("Use TLS SNI sniffer: %v", sniffing) + tcpIn := tunnel.TCPIn() udpIn := tunnel.UDPIn() diff --git a/hub/route/configs.go b/hub/route/configs.go index 2e749fe6..1a299160 100644 --- a/hub/route/configs.go +++ b/hub/route/configs.go @@ -28,18 +28,19 @@ func configRouter() http.Handler { } type configSchema struct { - Port *int `json:"port"` - SocksPort *int `json:"socks-port"` - RedirPort *int `json:"redir-port"` - TProxyPort *int `json:"tproxy-port"` - MixedPort *int `json:"mixed-port"` - MitmPort *int `json:"mitm-port"` - AllowLan *bool `json:"allow-lan"` - BindAddress *string `json:"bind-address"` - Mode *tunnel.TunnelMode `json:"mode"` - LogLevel *log.LogLevel `json:"log-level"` - IPv6 *bool `json:"ipv6"` - Tun *tunConfigSchema `json:"tun"` + Port *int `json:"port,omitempty"` + SocksPort *int `json:"socks-port,omitempty"` + RedirPort *int `json:"redir-port,omitempty"` + TProxyPort *int `json:"tproxy-port,omitempty"` + MixedPort *int `json:"mixed-port,omitempty"` + MitmPort *int `json:"mitm-port,omitempty"` + AllowLan *bool `json:"allow-lan,omitempty"` + BindAddress *string `json:"bind-address,omitempty"` + Mode *tunnel.TunnelMode `json:"mode,omitempty"` + LogLevel *log.LogLevel `json:"log-level,omitempty"` + IPv6 *bool `json:"ipv6,omitempty"` + Sniffing *bool `json:"sniffing,omitempty"` + Tun *tunConfigSchema `json:"tun,omitempty"` } type tunConfigSchema struct { @@ -104,6 +105,10 @@ func patchConfigs(w http.ResponseWriter, r *http.Request) { resolver.DisableIPv6 = !*general.IPv6 } + if general.Sniffing != nil { + tunnel.SetSniffing(*general.Sniffing) + } + if general.Tun != nil { tunSchema := general.Tun tunConf := P.GetTunConf() diff --git a/tunnel/statistic/sniffing.go b/tunnel/statistic/sniffing.go index 30716a09..5fa0ae69 100644 --- a/tunnel/statistic/sniffing.go +++ b/tunnel/statistic/sniffing.go @@ -26,11 +26,9 @@ func (r *sniffing) Read(b []byte) (int, error) { func (r *sniffing) Write(b []byte) (int, error) { if r.totalWrite.Load() < 128 && r.metadata.Host == "" && (r.metadata.DstPort == "443" || r.metadata.DstPort == "8443" || r.metadata.DstPort == "993" || r.metadata.DstPort == "465" || r.metadata.DstPort == "995") { header, err := tls.SniffTLS(b) - if err != nil { - // log.Errorln("Expect no error but actually %s %s:%s:%s", err.Error(), tt.Metadata.Host, tt.Metadata.DstIP.String(), tt.Metadata.DstPort) - } else { + if err == nil { resolver.InsertHostByIP(r.metadata.DstIP, header.Domain()) - log.Warnln("use sni update host: %s ip: %s", header.Domain(), r.metadata.DstIP.String()) + log.Debugln("[SNIFFER] use sni update host: %s ip: %s", header.Domain(), r.metadata.DstIP.String()) if r.allowBreak { _ = r.Conn.Close() return 0, errors.New("sni update, break current link to avoid leaks") diff --git a/tunnel/statistic/tracker.go b/tunnel/statistic/tracker.go index b86fce6e..c8fb9bba 100644 --- a/tunnel/statistic/tracker.go +++ b/tunnel/statistic/tracker.go @@ -58,13 +58,13 @@ func (tt *tcpTracker) Close() error { } func NewTCPTracker(conn C.Conn, manager *Manager, metadata *C.Metadata, rule C.Rule) C.Conn { - uuid, _ := uuid.NewV4() + uuidM, _ := uuid.NewV4() t := &tcpTracker{ Conn: conn, manager: manager, trackerInfo: &trackerInfo{ - UUID: uuid, + UUID: uuidM, Start: time.Now(), Metadata: metadata, Chain: conn.Chains(), @@ -80,7 +80,7 @@ func NewTCPTracker(conn C.Conn, manager *Manager, metadata *C.Metadata, rule C.R } manager.Join(t) - return NewSniffing(t, metadata, rule) + return t } type udpTracker struct { @@ -115,13 +115,13 @@ func (ut *udpTracker) Close() error { } func NewUDPTracker(conn C.PacketConn, manager *Manager, metadata *C.Metadata, rule C.Rule) *udpTracker { - uuid, _ := uuid.NewV4() + uuidM, _ := uuid.NewV4() ut := &udpTracker{ PacketConn: conn, manager: manager, trackerInfo: &trackerInfo{ - UUID: uuid, + UUID: uuidM, Start: time.Now(), Metadata: metadata, Chain: conn.Chains(), diff --git a/tunnel/tunnel.go b/tunnel/tunnel.go index 6562eb82..03f3bbc0 100644 --- a/tunnel/tunnel.go +++ b/tunnel/tunnel.go @@ -38,6 +38,9 @@ var ( // Outbound Rule mode = Rule + // sniffing switch + sniffing = false + // default timeout for UDP session udpTimeout = 60 * time.Second @@ -99,6 +102,14 @@ func SetMode(m TunnelMode) { mode = m } +func Sniffing() bool { + return sniffing +} + +func SetSniffing(s bool) { + sniffing = s +} + // SetMitmOutbound set the MITM outbound func SetMitmOutbound(outbound C.ProxyAdapter) { if outbound != nil { @@ -341,6 +352,9 @@ func handleTCPConn(connCtx C.ConnContext) { if remoteConn.Chains().Last() != "REJECT" && !isMitmOutbound { remoteConn = statistic.NewTCPTracker(remoteConn, statistic.DefaultManager, metadata, rule) + if sniffing { + remoteConn = statistic.NewSniffing(remoteConn, metadata, rule) + } } defer func(remoteConn C.Conn) {