chore: add early conn interface to decrease unneeded write
This commit is contained in:
parent
c8c078e78a
commit
c1199f1a8a
14 changed files with 144 additions and 62 deletions
|
@ -6,7 +6,9 @@ import (
|
|||
"fmt"
|
||||
"net"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
N "github.com/Dreamacro/clash/common/net"
|
||||
"github.com/Dreamacro/clash/common/structure"
|
||||
"github.com/Dreamacro/clash/component/dialer"
|
||||
C "github.com/Dreamacro/clash/constant"
|
||||
|
@ -103,9 +105,17 @@ func (ss *ShadowSocks) streamConn(c net.Conn, metadata *C.Metadata) (net.Conn, e
|
|||
}
|
||||
}
|
||||
if metadata.NetWork == C.UDP && ss.option.UDPOverTCP {
|
||||
if N.NeedHandshake(c) {
|
||||
return ss.method.DialEarlyConn(c, M.ParseSocksaddr(uot.UOTMagicAddress+":443")), nil
|
||||
} else {
|
||||
return ss.method.DialConn(c, M.ParseSocksaddr(uot.UOTMagicAddress+":443"))
|
||||
}
|
||||
}
|
||||
if N.NeedHandshake(c) {
|
||||
return ss.method.DialEarlyConn(c, M.ParseSocksaddr(metadata.RemoteAddress())), nil
|
||||
} else {
|
||||
return ss.method.DialConn(c, M.ParseSocksaddr(metadata.RemoteAddress()))
|
||||
}
|
||||
}
|
||||
|
||||
// DialContext implements C.ProxyAdapter
|
||||
|
@ -184,7 +194,7 @@ func (ss *ShadowSocks) SupportUOT() bool {
|
|||
|
||||
func NewShadowSocks(option ShadowSocksOption) (*ShadowSocks, error) {
|
||||
addr := net.JoinHostPort(option.Server, strconv.Itoa(option.Port))
|
||||
method, err := shadowimpl.FetchMethod(option.Cipher, option.Password)
|
||||
method, err := shadowimpl.FetchMethod(option.Cipher, option.Password, time.Now)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("ss %s initialize error: %w", addr, err)
|
||||
}
|
||||
|
|
|
@ -11,6 +11,7 @@ import (
|
|||
"strings"
|
||||
"sync"
|
||||
|
||||
N "github.com/Dreamacro/clash/common/net"
|
||||
"github.com/Dreamacro/clash/component/dialer"
|
||||
"github.com/Dreamacro/clash/component/resolver"
|
||||
tlsC "github.com/Dreamacro/clash/component/tls"
|
||||
|
@ -213,12 +214,24 @@ func (v *Vmess) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, error) {
|
|||
}
|
||||
if metadata.NetWork == C.UDP {
|
||||
if v.option.XUDP {
|
||||
if N.NeedHandshake(c) {
|
||||
return v.client.DialEarlyXUDPPacketConn(c, M.ParseSocksaddr(metadata.RemoteAddress())), nil
|
||||
} else {
|
||||
return v.client.DialEarlyPacketConn(c, M.ParseSocksaddr(metadata.RemoteAddress())), nil
|
||||
return v.client.DialXUDPPacketConn(c, M.ParseSocksaddr(metadata.RemoteAddress()))
|
||||
}
|
||||
} else {
|
||||
if N.NeedHandshake(c) {
|
||||
return v.client.DialEarlyPacketConn(c, M.ParseSocksaddr(metadata.RemoteAddress())), nil
|
||||
} else {
|
||||
return v.client.DialPacketConn(c, M.ParseSocksaddr(metadata.RemoteAddress()))
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if N.NeedHandshake(c) {
|
||||
return v.client.DialEarlyConn(c, M.ParseSocksaddr(metadata.RemoteAddress())), nil
|
||||
} else {
|
||||
return v.client.DialConn(c, M.ParseSocksaddr(metadata.RemoteAddress()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -289,9 +302,17 @@ func (v *Vmess) ListenPacketContext(ctx context.Context, metadata *C.Metadata, o
|
|||
}(c)
|
||||
|
||||
if v.option.XUDP {
|
||||
if N.NeedHandshake(c) {
|
||||
c = v.client.DialEarlyXUDPPacketConn(c, M.ParseSocksaddr(metadata.RemoteAddress()))
|
||||
} else {
|
||||
c, err = v.client.DialXUDPPacketConn(c, M.ParseSocksaddr(metadata.RemoteAddress()))
|
||||
}
|
||||
} else {
|
||||
if N.NeedHandshake(c) {
|
||||
c = v.client.DialEarlyPacketConn(c, M.ParseSocksaddr(metadata.RemoteAddress()))
|
||||
} else {
|
||||
c, err = v.client.DialPacketConn(c, M.ParseSocksaddr(metadata.RemoteAddress()))
|
||||
}
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
|
|
|
@ -8,6 +8,7 @@ import (
|
|||
|
||||
"github.com/Dreamacro/clash/adapter/outbound"
|
||||
"github.com/Dreamacro/clash/common/callback"
|
||||
N "github.com/Dreamacro/clash/common/net"
|
||||
"github.com/Dreamacro/clash/component/dialer"
|
||||
C "github.com/Dreamacro/clash/constant"
|
||||
"github.com/Dreamacro/clash/constant/provider"
|
||||
|
@ -35,6 +36,7 @@ func (f *Fallback) DialContext(ctx context.Context, metadata *C.Metadata, opts .
|
|||
f.onDialFailed(proxy.Type(), err)
|
||||
}
|
||||
|
||||
if N.NeedHandshake(c) {
|
||||
c = &callback.FirstWriteCallBackConn{
|
||||
Conn: c,
|
||||
Callback: func(err error) {
|
||||
|
@ -45,6 +47,7 @@ func (f *Fallback) DialContext(ctx context.Context, metadata *C.Metadata, opts .
|
|||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
return c, err
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@ import (
|
|||
"github.com/Dreamacro/clash/common/cache"
|
||||
"github.com/Dreamacro/clash/common/callback"
|
||||
"github.com/Dreamacro/clash/common/murmur3"
|
||||
N "github.com/Dreamacro/clash/common/net"
|
||||
"github.com/Dreamacro/clash/component/dialer"
|
||||
C "github.com/Dreamacro/clash/constant"
|
||||
"github.com/Dreamacro/clash/constant/provider"
|
||||
|
@ -92,6 +93,7 @@ func (lb *LoadBalance) DialContext(ctx context.Context, metadata *C.Metadata, op
|
|||
lb.onDialFailed(proxy.Type(), err)
|
||||
}
|
||||
|
||||
if N.NeedHandshake(c) {
|
||||
c = &callback.FirstWriteCallBackConn{
|
||||
Conn: c,
|
||||
Callback: func(err error) {
|
||||
|
@ -102,6 +104,8 @@ func (lb *LoadBalance) DialContext(ctx context.Context, metadata *C.Metadata, op
|
|||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@ import (
|
|||
|
||||
"github.com/Dreamacro/clash/adapter/outbound"
|
||||
"github.com/Dreamacro/clash/common/callback"
|
||||
N "github.com/Dreamacro/clash/common/net"
|
||||
"github.com/Dreamacro/clash/common/singledo"
|
||||
"github.com/Dreamacro/clash/component/dialer"
|
||||
C "github.com/Dreamacro/clash/constant"
|
||||
|
@ -43,6 +44,7 @@ func (u *URLTest) DialContext(ctx context.Context, metadata *C.Metadata, opts ..
|
|||
u.onDialFailed(proxy.Type(), err)
|
||||
}
|
||||
|
||||
if N.NeedHandshake(c) {
|
||||
c = &callback.FirstWriteCallBackConn{
|
||||
Conn: c,
|
||||
Callback: func(err error) {
|
||||
|
@ -53,6 +55,8 @@ func (u *URLTest) DialContext(ctx context.Context, metadata *C.Metadata, opts ..
|
|||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
return c, err
|
||||
}
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@ import (
|
|||
"math/rand"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/gofrs/uuid"
|
||||
)
|
||||
|
@ -317,6 +318,6 @@ func SetUserAgent(header http.Header) {
|
|||
}
|
||||
|
||||
func VerifyMethod(cipher, password string) (err error) {
|
||||
_, err = shadowimpl.FetchMethod(cipher, password)
|
||||
_, err = shadowimpl.FetchMethod(cipher, password, time.Now)
|
||||
return
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ import (
|
|||
"context"
|
||||
"net"
|
||||
|
||||
"github.com/sagernet/sing/common"
|
||||
"github.com/sagernet/sing/common/bufio"
|
||||
"github.com/sagernet/sing/common/network"
|
||||
)
|
||||
|
@ -16,6 +17,13 @@ type ExtendedConn = network.ExtendedConn
|
|||
type ExtendedWriter = network.ExtendedWriter
|
||||
type ExtendedReader = network.ExtendedReader
|
||||
|
||||
func NeedHandshake(conn any) bool {
|
||||
if earlyConn, isEarlyConn := common.Cast[network.EarlyConn](conn); isEarlyConn && earlyConn.NeedHandshake() {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Relay copies between left and right bidirectionally.
|
||||
func Relay(leftConn, rightConn net.Conn) {
|
||||
_ = bufio.CopyConn(context.TODO(), leftConn, rightConn)
|
||||
|
|
|
@ -105,6 +105,10 @@ func (c *tfoConn) Upstream() any {
|
|||
return c.Conn
|
||||
}
|
||||
|
||||
func (c *tfoConn) NeedHandshake() bool {
|
||||
return c.Conn == nil
|
||||
}
|
||||
|
||||
func dialTFO(ctx context.Context, netDialer net.Dialer, network, address string) (net.Conn, error) {
|
||||
ctx, cancel := context.WithCancel(ctx)
|
||||
dialer := tfo.Dialer{Dialer: netDialer, DisableTFO: false}
|
||||
|
|
6
go.mod
6
go.mod
|
@ -19,16 +19,16 @@ require (
|
|||
github.com/lunixbochs/struc v0.0.0-20200707160740-784aaebc1d40
|
||||
github.com/mdlayher/netlink v1.7.2-0.20221213171556-9881fafed8c7
|
||||
github.com/metacubex/quic-go v0.32.0
|
||||
github.com/metacubex/sing-shadowsocks v0.1.1-0.20230202072246-e2bef5f088c7
|
||||
github.com/metacubex/sing-shadowsocks v0.1.1-0.20230226153717-4e80da7e6947
|
||||
github.com/metacubex/sing-tun v0.1.1-0.20230222113101-fbfa2dab826d
|
||||
github.com/metacubex/sing-wireguard v0.0.0-20230213124601-d04406a109b4
|
||||
github.com/miekg/dns v1.1.50
|
||||
github.com/mroth/weightedrand/v2 v2.0.0
|
||||
github.com/oschwald/geoip2-golang v1.8.0
|
||||
github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97
|
||||
github.com/sagernet/sing v0.1.8-0.20230226133421-e83948367009
|
||||
github.com/sagernet/sing v0.1.8-0.20230226150041-83d9121b04c6
|
||||
github.com/sagernet/sing-shadowtls v0.0.0-20230221130515-dac782ca098e
|
||||
github.com/sagernet/sing-vmess v0.1.2
|
||||
github.com/sagernet/sing-vmess v0.1.3-0.20230226144228-40c1abdb85be
|
||||
github.com/sagernet/tfo-go v0.0.0-20230207095944-549363a7327d
|
||||
github.com/sagernet/utls v0.0.0-20230220130002-c08891932056
|
||||
github.com/sagernet/wireguard-go v0.0.0-20221116151939-c99467f53f2c
|
||||
|
|
12
go.sum
12
go.sum
|
@ -91,8 +91,8 @@ github.com/metacubex/gvisor v0.0.0-20230222112937-bdbcd206ec65 h1:WUINdCB/UvSX9I
|
|||
github.com/metacubex/gvisor v0.0.0-20230222112937-bdbcd206ec65/go.mod h1:e3lCxh3TozKMWAsYTC7nBVnepAxPL/sNyScUFvmEoec=
|
||||
github.com/metacubex/quic-go v0.32.0 h1:dSD8LB4MSeBuD4otd8y1DUZcRdDcEB0Ax5esPOqn2Hw=
|
||||
github.com/metacubex/quic-go v0.32.0/go.mod h1:yParIzDYUd/t/pzFlDtZKhnvSqbUu0bPChlKEGmJStA=
|
||||
github.com/metacubex/sing-shadowsocks v0.1.1-0.20230202072246-e2bef5f088c7 h1:MNCGIpXhxXn9ck5bxfm/cW9Nr2FGQ5cakcGK0yKZcak=
|
||||
github.com/metacubex/sing-shadowsocks v0.1.1-0.20230202072246-e2bef5f088c7/go.mod h1:8pBSYDKVxTtqUtGZyEh4ZpFJXwP6wBVVKrs6oQiOwmQ=
|
||||
github.com/metacubex/sing-shadowsocks v0.1.1-0.20230226153717-4e80da7e6947 h1:NnjC2+aIiyzzvFlo+C2WzBOJdsp+HAtu18FZomqYhUE=
|
||||
github.com/metacubex/sing-shadowsocks v0.1.1-0.20230226153717-4e80da7e6947/go.mod h1:U2gwhxzqgbhKCgn2B4z3t0Cj0LpMWFl/02BGCoG421w=
|
||||
github.com/metacubex/sing-tun v0.1.1-0.20230222113101-fbfa2dab826d h1:oMzkrEoBdwn2/Vyu0n6/LAmvjxqsyFs+f2kqeg7kI8U=
|
||||
github.com/metacubex/sing-tun v0.1.1-0.20230222113101-fbfa2dab826d/go.mod h1:WmbtxVPpJulKoQGwfnBMk4KSWzZ68sE/myTrQeN/5GE=
|
||||
github.com/metacubex/sing-wireguard v0.0.0-20230213124601-d04406a109b4 h1:d96mCF/LYyC9kULd2xwcXfP0Jd8klrOngmRxuUIZg/8=
|
||||
|
@ -127,12 +127,12 @@ github.com/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61/go.mod h
|
|||
github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 h1:iL5gZI3uFp0X6EslacyapiRz7LLSJyr4RajF/BhMVyE=
|
||||
github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97/go.mod h1:xLnfdiJbSp8rNqYEdIW/6eDO4mVoogml14Bh2hSiFpM=
|
||||
github.com/sagernet/sing v0.0.0-20220817130738-ce854cda8522/go.mod h1:QVsS5L/ZA2Q5UhQwLrn0Trw+msNd/NPGEhBKR/ioWiY=
|
||||
github.com/sagernet/sing v0.1.8-0.20230226133421-e83948367009 h1:KjrXGv09UlBl3Rj57XInk6u2TAxqpPfOJ2kUgV5B2lw=
|
||||
github.com/sagernet/sing v0.1.8-0.20230226133421-e83948367009/go.mod h1:jt1w2u7lJQFFSGLiRrRIs5YWmx4kAPfWuOejuDW9qMk=
|
||||
github.com/sagernet/sing v0.1.8-0.20230226150041-83d9121b04c6 h1:enq0WDXPUI2QyUUypRd2uiScoWKcs8jo+yB+K5hrdc8=
|
||||
github.com/sagernet/sing v0.1.8-0.20230226150041-83d9121b04c6/go.mod h1:jt1w2u7lJQFFSGLiRrRIs5YWmx4kAPfWuOejuDW9qMk=
|
||||
github.com/sagernet/sing-shadowtls v0.0.0-20230221130515-dac782ca098e h1:S1fd0kB9aEU68dd269AQy783sUlFu/2fSh/4YYVJ/Oc=
|
||||
github.com/sagernet/sing-shadowtls v0.0.0-20230221130515-dac782ca098e/go.mod h1:Kn1VUIprdkwCgkS6SXYaLmIpKzQbqBIKJBMY+RvBhYc=
|
||||
github.com/sagernet/sing-vmess v0.1.2 h1:RbOZNAId2LrCai8epMoQXlf0XTrou0bfcw08hNBg6lM=
|
||||
github.com/sagernet/sing-vmess v0.1.2/go.mod h1:9NSj8mZTx1JIY/HF9LaYRppUsVkysIN5tEFpNZujXxY=
|
||||
github.com/sagernet/sing-vmess v0.1.3-0.20230226144228-40c1abdb85be h1:FoaWiy89hyRkP/KilUoGn6W/seyVBDZcdsYcJQEx5Hk=
|
||||
github.com/sagernet/sing-vmess v0.1.3-0.20230226144228-40c1abdb85be/go.mod h1:9NSj8mZTx1JIY/HF9LaYRppUsVkysIN5tEFpNZujXxY=
|
||||
github.com/sagernet/tfo-go v0.0.0-20230207095944-549363a7327d h1:trP/l6ZPWvQ/5Gv99Z7/t/v8iYy06akDMejxW1sznUk=
|
||||
github.com/sagernet/tfo-go v0.0.0-20230207095944-549363a7327d/go.mod h1:jk6Ii8Y3En+j2KQDLgdgQGwb3M6y7EL567jFnGYhN9g=
|
||||
github.com/sagernet/utls v0.0.0-20230220130002-c08891932056 h1:gDXi/0uYe8dA48UyUI1LM2la5QYN0IvsDvR2H2+kFnA=
|
||||
|
|
|
@ -5,6 +5,7 @@ import (
|
|||
"fmt"
|
||||
"net"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/Dreamacro/clash/adapter/inbound"
|
||||
"github.com/Dreamacro/clash/common/sockopt"
|
||||
|
@ -63,7 +64,7 @@ func New(config LC.ShadowsocksServer, tcpIn chan<- C.ConnContext, udpIn chan<- C
|
|||
case common.Contains(shadowaead.List, config.Cipher):
|
||||
sl.service, err = shadowaead.NewService(config.Cipher, nil, config.Password, udpTimeout, h)
|
||||
case common.Contains(shadowaead_2022.List, config.Cipher):
|
||||
sl.service, err = shadowaead_2022.NewServiceWithPassword(config.Cipher, config.Password, udpTimeout, h)
|
||||
sl.service, err = shadowaead_2022.NewServiceWithPassword(config.Cipher, config.Password, udpTimeout, h, time.Now)
|
||||
default:
|
||||
err = fmt.Errorf("shadowsocks: unsupported method: %s", config.Cipher)
|
||||
return embedSS.New(config, tcpIn, udpIn)
|
||||
|
|
|
@ -430,6 +430,15 @@ func (vc *Conn) Upstream() any {
|
|||
return vc.tlsConn
|
||||
}
|
||||
|
||||
func (vc *Conn) NeedHandshake() bool {
|
||||
select {
|
||||
case <-vc.handshake:
|
||||
return true
|
||||
default:
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (vc *Conn) IsXTLSVisionEnabled() bool {
|
||||
return vc.addons != nil && vc.addons.Flow == XRV
|
||||
}
|
||||
|
|
|
@ -301,15 +301,27 @@ func (wsedc *websocketWithEarlyDataConn) SetWriteDeadline(t time.Time) error {
|
|||
return wsedc.Conn.SetWriteDeadline(t)
|
||||
}
|
||||
|
||||
func (wsedc *websocketWithEarlyDataConn) LazyHeadroom() bool {
|
||||
return wsedc.Conn == nil
|
||||
func (wsedc *websocketWithEarlyDataConn) FrontHeadroom() int {
|
||||
return 14
|
||||
}
|
||||
|
||||
func (wsedc *websocketWithEarlyDataConn) Upstream() any {
|
||||
if wsedc.Conn == nil { // ensure return a nil interface not an interface with nil value
|
||||
return nil
|
||||
return wsedc.underlay
|
||||
}
|
||||
return wsedc.Conn
|
||||
|
||||
//func (wsedc *websocketWithEarlyDataConn) LazyHeadroom() bool {
|
||||
// return wsedc.Conn == nil
|
||||
//}
|
||||
//
|
||||
//func (wsedc *websocketWithEarlyDataConn) Upstream() any {
|
||||
// if wsedc.Conn == nil { // ensure return a nil interface not an interface with nil value
|
||||
// return nil
|
||||
// }
|
||||
// return wsedc.Conn
|
||||
//}
|
||||
|
||||
func (wsedc *websocketWithEarlyDataConn) NeedHandshake() bool {
|
||||
return wsedc.Conn == nil
|
||||
}
|
||||
|
||||
func streamWebsocketWithEarlyDataConn(conn net.Conn, c *WebsocketConfig) (net.Conn, error) {
|
||||
|
|
|
@ -13,6 +13,7 @@ import (
|
|||
|
||||
"github.com/jpillora/backoff"
|
||||
|
||||
N "github.com/Dreamacro/clash/common/net"
|
||||
"github.com/Dreamacro/clash/component/nat"
|
||||
P "github.com/Dreamacro/clash/component/process"
|
||||
"github.com/Dreamacro/clash/component/resolver"
|
||||
|
@ -367,7 +368,7 @@ func handleTCPConn(connCtx C.ConnContext) {
|
|||
}
|
||||
|
||||
conn := connCtx.Conn()
|
||||
conn.ResetPeeked()
|
||||
conn.ResetPeeked() // reset before sniffer
|
||||
if sniffer.Dispatcher.Enable() && sniffingEnable {
|
||||
sniffer.Dispatcher.TCPSniff(conn, metadata)
|
||||
}
|
||||
|
@ -415,6 +416,7 @@ func handleTCPConn(connCtx C.ConnContext) {
|
|||
return remoteConn, nil
|
||||
}
|
||||
}
|
||||
if N.NeedHandshake(remoteConn) {
|
||||
peekMutex.Lock()
|
||||
defer peekMutex.Unlock()
|
||||
peekBytes, _ = conn.Peek(conn.Buffered())
|
||||
|
@ -425,6 +427,7 @@ func handleTCPConn(connCtx C.ConnContext) {
|
|||
if peekLen = len(peekBytes); peekLen > 0 {
|
||||
_, _ = conn.Discard(peekLen)
|
||||
}
|
||||
}
|
||||
return remoteConn, err
|
||||
}, func(err error) {
|
||||
if rule == nil {
|
||||
|
@ -469,8 +472,10 @@ func handleTCPConn(connCtx C.ConnContext) {
|
|||
)
|
||||
}
|
||||
|
||||
_ = conn.SetReadDeadline(time.Now()) // stop unfinished peek
|
||||
peekMutex.Lock()
|
||||
defer peekMutex.Unlock()
|
||||
_ = conn.SetReadDeadline(time.Time{}) // reset
|
||||
handleSocket(connCtx, remoteConn)
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue