Feature: make tls sni sniffing switch config

This commit is contained in:
yaling888 2022-05-16 01:34:25 +08:00
parent 891a56fd99
commit 3d25f16b3b
6 changed files with 48 additions and 21 deletions

View File

@ -39,6 +39,7 @@ type General struct {
Mode T.TunnelMode `json:"mode"` Mode T.TunnelMode `json:"mode"`
LogLevel log.LogLevel `json:"log-level"` LogLevel log.LogLevel `json:"log-level"`
IPv6 bool `json:"ipv6"` IPv6 bool `json:"ipv6"`
Sniffing bool `json:"sniffing"`
Interface string `json:"-"` Interface string `json:"-"`
RoutingMark int `json:"-"` RoutingMark int `json:"-"`
Tun Tun `json:"tun"` Tun Tun `json:"tun"`
@ -182,6 +183,7 @@ type RawConfig struct {
Secret string `yaml:"secret"` Secret string `yaml:"secret"`
Interface string `yaml:"interface-name"` Interface string `yaml:"interface-name"`
RoutingMark int `yaml:"routing-mark"` RoutingMark int `yaml:"routing-mark"`
Sniffing bool `yaml:"sniffing"`
ProxyProvider map[string]map[string]any `yaml:"proxy-providers"` ProxyProvider map[string]map[string]any `yaml:"proxy-providers"`
Hosts map[string]string `yaml:"hosts"` Hosts map[string]string `yaml:"hosts"`
@ -210,6 +212,7 @@ func UnmarshalRawConfig(buf []byte) (*RawConfig, error) {
// config with default value // config with default value
rawCfg := &RawConfig{ rawCfg := &RawConfig{
AllowLan: false, AllowLan: false,
Sniffing: false,
BindAddress: "*", BindAddress: "*",
Mode: T.Rule, Mode: T.Rule,
Authentication: []string{}, Authentication: []string{},
@ -374,6 +377,7 @@ func parseGeneral(cfg *RawConfig) (*General, error) {
IPv6: cfg.IPv6, IPv6: cfg.IPv6,
Interface: cfg.Interface, Interface: cfg.Interface,
RoutingMark: cfg.RoutingMark, RoutingMark: cfg.RoutingMark,
Sniffing: cfg.Sniffing,
Tun: cfg.Tun, Tun: cfg.Tun,
}, nil }, nil
} }

View File

@ -112,6 +112,7 @@ func GetGeneral() *config.General {
Mode: tunnel.Mode(), Mode: tunnel.Mode(),
LogLevel: log.Level(), LogLevel: log.Level(),
IPv6: !resolver.DisableIPv6, IPv6: !resolver.DisableIPv6,
Sniffing: tunnel.Sniffing(),
Tun: P.GetTunConf(), Tun: P.GetTunConf(),
} }
@ -217,6 +218,11 @@ func updateGeneral(general *config.General, force bool) {
bindAddress := general.BindAddress bindAddress := general.BindAddress
P.SetBindAddress(bindAddress) P.SetBindAddress(bindAddress)
sniffing := general.Sniffing
tunnel.SetSniffing(sniffing)
log.Infoln("Use TLS SNI sniffer: %v", sniffing)
tcpIn := tunnel.TCPIn() tcpIn := tunnel.TCPIn()
udpIn := tunnel.UDPIn() udpIn := tunnel.UDPIn()

View File

@ -28,18 +28,19 @@ func configRouter() http.Handler {
} }
type configSchema struct { type configSchema struct {
Port *int `json:"port"` Port *int `json:"port,omitempty"`
SocksPort *int `json:"socks-port"` SocksPort *int `json:"socks-port,omitempty"`
RedirPort *int `json:"redir-port"` RedirPort *int `json:"redir-port,omitempty"`
TProxyPort *int `json:"tproxy-port"` TProxyPort *int `json:"tproxy-port,omitempty"`
MixedPort *int `json:"mixed-port"` MixedPort *int `json:"mixed-port,omitempty"`
MitmPort *int `json:"mitm-port"` MitmPort *int `json:"mitm-port,omitempty"`
AllowLan *bool `json:"allow-lan"` AllowLan *bool `json:"allow-lan,omitempty"`
BindAddress *string `json:"bind-address"` BindAddress *string `json:"bind-address,omitempty"`
Mode *tunnel.TunnelMode `json:"mode"` Mode *tunnel.TunnelMode `json:"mode,omitempty"`
LogLevel *log.LogLevel `json:"log-level"` LogLevel *log.LogLevel `json:"log-level,omitempty"`
IPv6 *bool `json:"ipv6"` IPv6 *bool `json:"ipv6,omitempty"`
Tun *tunConfigSchema `json:"tun"` Sniffing *bool `json:"sniffing,omitempty"`
Tun *tunConfigSchema `json:"tun,omitempty"`
} }
type tunConfigSchema struct { type tunConfigSchema struct {
@ -104,6 +105,10 @@ func patchConfigs(w http.ResponseWriter, r *http.Request) {
resolver.DisableIPv6 = !*general.IPv6 resolver.DisableIPv6 = !*general.IPv6
} }
if general.Sniffing != nil {
tunnel.SetSniffing(*general.Sniffing)
}
if general.Tun != nil { if general.Tun != nil {
tunSchema := general.Tun tunSchema := general.Tun
tunConf := P.GetTunConf() tunConf := P.GetTunConf()

View File

@ -26,11 +26,9 @@ func (r *sniffing) Read(b []byte) (int, error) {
func (r *sniffing) Write(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") { 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) header, err := tls.SniffTLS(b)
if err != nil { 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 {
resolver.InsertHostByIP(r.metadata.DstIP, header.Domain()) 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 { if r.allowBreak {
_ = r.Conn.Close() _ = r.Conn.Close()
return 0, errors.New("sni update, break current link to avoid leaks") return 0, errors.New("sni update, break current link to avoid leaks")

View File

@ -58,13 +58,13 @@ func (tt *tcpTracker) Close() error {
} }
func NewTCPTracker(conn C.Conn, manager *Manager, metadata *C.Metadata, rule C.Rule) C.Conn { func NewTCPTracker(conn C.Conn, manager *Manager, metadata *C.Metadata, rule C.Rule) C.Conn {
uuid, _ := uuid.NewV4() uuidM, _ := uuid.NewV4()
t := &tcpTracker{ t := &tcpTracker{
Conn: conn, Conn: conn,
manager: manager, manager: manager,
trackerInfo: &trackerInfo{ trackerInfo: &trackerInfo{
UUID: uuid, UUID: uuidM,
Start: time.Now(), Start: time.Now(),
Metadata: metadata, Metadata: metadata,
Chain: conn.Chains(), Chain: conn.Chains(),
@ -80,7 +80,7 @@ func NewTCPTracker(conn C.Conn, manager *Manager, metadata *C.Metadata, rule C.R
} }
manager.Join(t) manager.Join(t)
return NewSniffing(t, metadata, rule) return t
} }
type udpTracker struct { 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 { func NewUDPTracker(conn C.PacketConn, manager *Manager, metadata *C.Metadata, rule C.Rule) *udpTracker {
uuid, _ := uuid.NewV4() uuidM, _ := uuid.NewV4()
ut := &udpTracker{ ut := &udpTracker{
PacketConn: conn, PacketConn: conn,
manager: manager, manager: manager,
trackerInfo: &trackerInfo{ trackerInfo: &trackerInfo{
UUID: uuid, UUID: uuidM,
Start: time.Now(), Start: time.Now(),
Metadata: metadata, Metadata: metadata,
Chain: conn.Chains(), Chain: conn.Chains(),

View File

@ -38,6 +38,9 @@ var (
// Outbound Rule // Outbound Rule
mode = Rule mode = Rule
// sniffing switch
sniffing = false
// default timeout for UDP session // default timeout for UDP session
udpTimeout = 60 * time.Second udpTimeout = 60 * time.Second
@ -99,6 +102,14 @@ func SetMode(m TunnelMode) {
mode = m mode = m
} }
func Sniffing() bool {
return sniffing
}
func SetSniffing(s bool) {
sniffing = s
}
// SetMitmOutbound set the MITM outbound // SetMitmOutbound set the MITM outbound
func SetMitmOutbound(outbound C.ProxyAdapter) { func SetMitmOutbound(outbound C.ProxyAdapter) {
if outbound != nil { if outbound != nil {
@ -341,6 +352,9 @@ func handleTCPConn(connCtx C.ConnContext) {
if remoteConn.Chains().Last() != "REJECT" && !isMitmOutbound { if remoteConn.Chains().Last() != "REJECT" && !isMitmOutbound {
remoteConn = statistic.NewTCPTracker(remoteConn, statistic.DefaultManager, metadata, rule) remoteConn = statistic.NewTCPTracker(remoteConn, statistic.DefaultManager, metadata, rule)
if sniffing {
remoteConn = statistic.NewSniffing(remoteConn, metadata, rule)
}
} }
defer func(remoteConn C.Conn) { defer func(remoteConn C.Conn) {