Merge remote-tracking branch 'meta/Alpha' into Alpha

This commit is contained in:
Skyxim 2022-05-02 08:28:00 +08:00
commit ebbce4d061
8 changed files with 133 additions and 4 deletions

View file

@ -99,7 +99,13 @@ func (s *Snell) ListenPacketContext(ctx context.Context, metadata *C.Metadata, o
tcpKeepAlive(c)
c = streamConn(c, streamOption{s.psk, s.version, s.addr, s.obfsOption})
return s.ListenPacketOnStreamConn(c, metadata)
err = snell.WriteUDPHeader(c, s.version)
if err != nil {
return nil, err
}
pc := snell.PacketConn(c)
return newPacketConn(pc, s), nil
}
// ListenPacketOnStreamConn implements C.ProxyAdapter

View file

@ -161,7 +161,13 @@ func (t *Trojan) ListenPacketContext(ctx context.Context, metadata *C.Metadata,
}
}
return t.ListenPacketOnStreamConn(c, metadata)
err = t.instance.WriteHeader(c, trojan.CommandUDP, serializesSocksAddr(metadata))
if err != nil {
return nil, err
}
pc := t.instance.PacketConn(c)
return newPacketConn(pc, t), err
}
// ListenPacketOnStreamConn implements C.ProxyAdapter

View file

@ -19,6 +19,7 @@ import (
var (
ErrorUnsupportedSniffer = errors.New("unsupported sniffer")
ErrorSniffFailed = errors.New("all sniffer failed")
ErrNoClue = errors.New("not enough information for making a decision")
)
var Dispatcher SnifferDispatcher

View file

@ -0,0 +1,109 @@
package sniffer
import (
"bytes"
"errors"
C "github.com/Dreamacro/clash/constant"
"net"
"strconv"
"strings"
)
var (
// refer to https://pkg.go.dev/net/http@master#pkg-constants
methods = [...]string{"get", "post", "head", "put", "delete", "options", "connect", "patch", "trace"}
errNotHTTPMethod = errors.New("not an HTTP method")
)
type version byte
const (
HTTP1 version = iota
HTTP2
)
type HTTPSniffer struct {
version version
host string
}
func (http *HTTPSniffer) Protocol() string {
switch http.version {
case HTTP1:
return "http1"
case HTTP2:
return "http2"
default:
return "unknown"
}
}
func (http *HTTPSniffer) SupportNetwork() C.NetWork {
return C.TCP
}
func (http *HTTPSniffer) SniffTCP(bytes []byte) (string, error) {
domain, err := SniffHTTP(bytes)
if err == nil {
return *domain, nil
} else {
return "", err
}
}
func beginWithHTTPMethod(b []byte) error {
for _, m := range &methods {
if len(b) >= len(m) && strings.EqualFold(string(b[:len(m)]), m) {
return nil
}
if len(b) < len(m) {
return ErrNoClue
}
}
return errNotHTTPMethod
}
func SniffHTTP(b []byte) (*string, error) {
if err := beginWithHTTPMethod(b); err != nil {
return nil, err
}
_ = &HTTPSniffer{
version: HTTP1,
}
headers := bytes.Split(b, []byte{'\n'})
for i := 1; i < len(headers); i++ {
header := headers[i]
if len(header) == 0 {
break
}
parts := bytes.SplitN(header, []byte{':'}, 2)
if len(parts) != 2 {
continue
}
key := strings.ToLower(string(parts[0]))
if key == "host" {
port := 80
rawHost := strings.ToLower(string(bytes.TrimSpace(parts[1])))
host, rawPort, err := net.SplitHostPort(rawHost)
if err != nil {
if addrError, ok := err.(*net.AddrError); ok && strings.Contains(addrError.Err, "missing port") {
host = rawHost
} else {
return nil, err
}
} else if len(rawPort) > 0 {
intPort, err := strconv.ParseUint(rawPort, 0, 16)
if err != nil {
return nil, err
}
port = int(intPort)
}
host = net.JoinHostPort(host, strconv.Itoa(port))
return &host, nil
}
}
return nil, ErrNoClue
}

View file

@ -0,0 +1,3 @@
package sniffer
//TODO

View file

@ -11,7 +11,6 @@ import (
var (
errNotTLS = errors.New("not TLS header")
errNotClientHello = errors.New("not client hello")
ErrNoClue = errors.New("not enough information for making a decision")
)
type TLSSniffer struct {

View file

@ -8,10 +8,11 @@ type Sniffer interface {
const (
TLS SnifferType = iota
HTTP SnifferType
)
var (
SnifferList = []SnifferType{TLS}
SnifferList = []SnifferType{TLS, HTTP}
)
type SnifferType int
@ -20,6 +21,8 @@ func (rt SnifferType) String() string {
switch rt {
case TLS:
return "TLS"
case HTTP:
return "HTTP"
default:
return "Unknown"
}

View file

@ -138,6 +138,8 @@ func (dc *quicClient) openSession() (quic.Connection, error) {
quicConfig := &quic.Config{
ConnectionIDLength: 12,
HandshakeIdleTimeout: time.Second * 8,
MaxIncomingStreams: 4,
MaxIdleTimeout: time.Second * 45,
}
log.Debugln("opening session to %s", dc.addr)