Skip to content
This repository was archived by the owner on Feb 13, 2025. It is now read-only.

Commit c7fc93d

Browse files
authored
fix: the TLS Sniffer fails when the length of the ClientHello packet exceeds the TCP MSS (#1711)
* chore: add uniformly formatted debug info to sniffDomain * fix: when data is not enough, attempt to peek more data and retry * chore: reduce debug info of sniffDomain
1 parent 5d9d8f4 commit c7fc93d

File tree

2 files changed

+40
-5
lines changed

2 files changed

+40
-5
lines changed

component/sniffer/dispatcher.go

+22-4
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,10 @@ func (sd *Dispatcher) Enable() bool {
145145
}
146146

147147
func (sd *Dispatcher) sniffDomain(conn *N.BufferedConn, metadata *C.Metadata) (string, error) {
148+
//defer func(start time.Time) {
149+
// log.Debugln("[Sniffer] [%s] Sniffing took %s", metadata.DstIP, time.Since(start))
150+
//}(time.Now())
151+
148152
for s := range sd.sniffers {
149153
if s.SupportNetwork() == C.TCP && s.SupportPort(metadata.DstPort) {
150154
_ = conn.SetReadDeadline(time.Now().Add(1 * time.Second))
@@ -154,7 +158,7 @@ func (sd *Dispatcher) sniffDomain(conn *N.BufferedConn, metadata *C.Metadata) (s
154158
_, ok := err.(*net.OpError)
155159
if ok {
156160
sd.cacheSniffFailed(metadata)
157-
log.Errorln("[Sniffer] [%s] may not have any sent data, Consider adding skip", metadata.DstIP.String())
161+
log.Errorln("[Sniffer] [%s] [%s] may not have any sent data, Consider adding skip", metadata.DstIP, s.Protocol())
158162
_ = conn.Close()
159163
}
160164

@@ -164,22 +168,36 @@ func (sd *Dispatcher) sniffDomain(conn *N.BufferedConn, metadata *C.Metadata) (s
164168
bufferedLen := conn.Buffered()
165169
bytes, err := conn.Peek(bufferedLen)
166170
if err != nil {
167-
log.Debugln("[Sniffer] the data length not enough")
171+
log.Debugln("[Sniffer] [%s] [%s] the data length not enough, error: %v", metadata.DstIP, s.Protocol(), err)
168172
continue
169173
}
170174

171175
host, err := s.SniffData(bytes)
176+
var e *errNeedAtLeastData
177+
if errors.As(err, &e) {
178+
//log.Debugln("[Sniffer] [%s] [%s] %v, got length: %d", metadata.DstIP, s.Protocol(), e, len(bytes))
179+
_ = conn.SetReadDeadline(time.Now().Add(1 * time.Second))
180+
bytes, err = conn.Peek(e.length)
181+
_ = conn.SetReadDeadline(time.Time{})
182+
//log.Debugln("[Sniffer] [%s] [%s] try again, got length: %d", metadata.DstIP, s.Protocol(), len(bytes))
183+
if err != nil {
184+
log.Debugln("[Sniffer] [%s] [%s] the data length not enough, error: %v", metadata.DstIP, s.Protocol(), err)
185+
continue
186+
}
187+
host, err = s.SniffData(bytes)
188+
}
172189
if err != nil {
173-
//log.Debugln("[Sniffer] [%s] Sniff data failed %s", s.Protocol(), metadata.DstIP)
190+
//log.Debugln("[Sniffer] [%s] [%s] Sniff data failed, error: %v", metadata.DstIP, s.Protocol(), err)
174191
continue
175192
}
176193

177194
_, err = netip.ParseAddr(host)
178195
if err == nil {
179-
//log.Debugln("[Sniffer] [%s] Sniff data failed %s", s.Protocol(), metadata.DstIP)
196+
//log.Debugln("[Sniffer] [%s] [%s] Sniff data failed, got host [%s]", metadata.DstIP, s.Protocol(), host)
180197
continue
181198
}
182199

200+
//log.Debugln("[Sniffer] [%s] [%s] Sniffed [%s]", metadata.DstIP, s.Protocol(), host)
183201
return host, nil
184202
}
185203
}

component/sniffer/tls_sniffer.go

+18-1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package sniffer
33
import (
44
"encoding/binary"
55
"errors"
6+
"fmt"
67
"strings"
78

89
"github.com/metacubex/mihomo/common/utils"
@@ -15,6 +16,19 @@ var (
1516
errNotClientHello = errors.New("not client hello")
1617
)
1718

19+
type errNeedAtLeastData struct {
20+
length int
21+
err error
22+
}
23+
24+
func (e *errNeedAtLeastData) Error() string {
25+
return fmt.Sprintf("%v, need at least length: %d", e.err, e.length)
26+
}
27+
28+
func (e *errNeedAtLeastData) Unwrap() error {
29+
return e.err
30+
}
31+
1832
var _ sniffer.Sniffer = (*TLSSniffer)(nil)
1933

2034
type TLSSniffer struct {
@@ -160,7 +174,10 @@ func SniffTLS(b []byte) (*string, error) {
160174
}
161175
headerLen := int(binary.BigEndian.Uint16(b[3:5]))
162176
if 5+headerLen > len(b) {
163-
return nil, ErrNoClue
177+
return nil, &errNeedAtLeastData{
178+
length: 5 + headerLen,
179+
err: ErrNoClue,
180+
}
164181
}
165182

166183
domain, err := ReadClientHello(b[5 : 5+headerLen])

0 commit comments

Comments
 (0)