2024-02-12 14:25:37 +08:00
|
|
|
package udp
|
|
|
|
|
|
|
|
import (
|
|
|
|
"github.com/apernet/OpenGFW/analyzer"
|
|
|
|
"github.com/apernet/OpenGFW/analyzer/internal"
|
|
|
|
"github.com/apernet/OpenGFW/analyzer/udp/internal/quic"
|
|
|
|
"github.com/apernet/OpenGFW/analyzer/utils"
|
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
|
|
|
quicInvalidCountThreshold = 4
|
|
|
|
)
|
|
|
|
|
|
|
|
var (
|
|
|
|
_ analyzer.UDPAnalyzer = (*QUICAnalyzer)(nil)
|
|
|
|
_ analyzer.UDPStream = (*quicStream)(nil)
|
|
|
|
)
|
|
|
|
|
|
|
|
type QUICAnalyzer struct{}
|
|
|
|
|
|
|
|
func (a *QUICAnalyzer) Name() string {
|
|
|
|
return "quic"
|
|
|
|
}
|
|
|
|
|
|
|
|
func (a *QUICAnalyzer) Limit() int {
|
|
|
|
return 0
|
|
|
|
}
|
|
|
|
|
|
|
|
func (a *QUICAnalyzer) NewUDP(info analyzer.UDPInfo, logger analyzer.Logger) analyzer.UDPStream {
|
|
|
|
return &quicStream{logger: logger}
|
|
|
|
}
|
|
|
|
|
|
|
|
type quicStream struct {
|
|
|
|
logger analyzer.Logger
|
|
|
|
invalidCount int
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *quicStream) Feed(rev bool, data []byte) (u *analyzer.PropUpdate, done bool) {
|
2024-03-12 03:35:01 +08:00
|
|
|
// minimal data size: protocol version (2 bytes) + random (32 bytes) +
|
|
|
|
// + session ID (1 byte) + cipher suites (4 bytes) +
|
|
|
|
// + compression methods (2 bytes) + no extensions
|
|
|
|
const minDataSize = 41
|
|
|
|
|
2024-02-12 14:25:37 +08:00
|
|
|
if rev {
|
|
|
|
// We don't support server direction for now
|
|
|
|
s.invalidCount++
|
|
|
|
return nil, s.invalidCount >= quicInvalidCountThreshold
|
|
|
|
}
|
2024-03-12 03:35:01 +08:00
|
|
|
|
2024-02-12 14:25:37 +08:00
|
|
|
pl, err := quic.ReadCryptoPayload(data)
|
2024-03-12 03:35:01 +08:00
|
|
|
if err != nil || len(pl) < 4 { // FIXME: isn't length checked inside quic.ReadCryptoPayload? Also, what about error handling?
|
2024-02-12 14:25:37 +08:00
|
|
|
s.invalidCount++
|
|
|
|
return nil, s.invalidCount >= quicInvalidCountThreshold
|
|
|
|
}
|
2024-03-12 03:35:01 +08:00
|
|
|
|
|
|
|
if pl[0] != internal.TypeClientHello {
|
2024-02-12 14:25:37 +08:00
|
|
|
s.invalidCount++
|
|
|
|
return nil, s.invalidCount >= quicInvalidCountThreshold
|
|
|
|
}
|
2024-03-12 03:35:01 +08:00
|
|
|
|
2024-02-12 14:25:37 +08:00
|
|
|
chLen := int(pl[1])<<16 | int(pl[2])<<8 | int(pl[3])
|
2024-03-12 03:35:01 +08:00
|
|
|
if chLen < minDataSize {
|
2024-02-12 14:25:37 +08:00
|
|
|
s.invalidCount++
|
|
|
|
return nil, s.invalidCount >= quicInvalidCountThreshold
|
|
|
|
}
|
2024-03-12 03:35:01 +08:00
|
|
|
|
|
|
|
m := internal.ParseTLSClientHelloMsgData(&utils.ByteBuffer{Buf: pl[4:]})
|
2024-02-12 14:25:37 +08:00
|
|
|
if m == nil {
|
|
|
|
s.invalidCount++
|
|
|
|
return nil, s.invalidCount >= quicInvalidCountThreshold
|
|
|
|
}
|
2024-03-12 03:35:01 +08:00
|
|
|
|
2024-02-12 14:25:37 +08:00
|
|
|
return &analyzer.PropUpdate{
|
|
|
|
Type: analyzer.PropUpdateMerge,
|
|
|
|
M: analyzer.PropMap{"req": m},
|
|
|
|
}, true
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *quicStream) Close(limited bool) *analyzer.PropUpdate {
|
|
|
|
return nil
|
|
|
|
}
|