mirror of
https://github.com/shtorm-7/sing-box-extended.git
synced 2026-07-21 06:43:30 +03:00
Refactor TrustTunnel
This commit is contained in:
@@ -8,7 +8,7 @@ Sing-box with extended features.
|
|||||||
|
|
||||||
## 🔥 Features
|
## 🔥 Features
|
||||||
|
|
||||||
### Outbounds
|
### Protocols
|
||||||
- **WARP** — Cloudflare WARP integration through WireGuard
|
- **WARP** — Cloudflare WARP integration through WireGuard
|
||||||
- **MASQUE** — Cloudflare MASQUE proxy over QUIC / HTTP-2
|
- **MASQUE** — Cloudflare MASQUE proxy over QUIC / HTTP-2
|
||||||
- **MTProxy** — Telegram MTProxy server with FakeTLS and domain fronting
|
- **MTProxy** — Telegram MTProxy server with FakeTLS and domain fronting
|
||||||
|
|||||||
@@ -26,13 +26,13 @@ type TrustTunnelOutboundOptions struct {
|
|||||||
DialerOptions
|
DialerOptions
|
||||||
ServerOptions
|
ServerOptions
|
||||||
OutboundTLSOptionsContainer
|
OutboundTLSOptionsContainer
|
||||||
Username string `json:"username,omitempty"`
|
Username string `json:"username,omitempty"`
|
||||||
Password string `json:"password,omitempty"`
|
Password string `json:"password,omitempty"`
|
||||||
Network NetworkList `json:"network,omitempty"`
|
Network NetworkList `json:"network,omitempty"`
|
||||||
HealthCheck bool `json:"health_check,omitempty"`
|
HealthCheck bool `json:"health_check,omitempty"`
|
||||||
QUIC bool `json:"quic,omitempty"`
|
QUIC bool `json:"quic,omitempty"`
|
||||||
CongestionController string `json:"congestion_controller,omitempty"`
|
CongestionController string `json:"congestion_controller,omitempty"`
|
||||||
BBRProfile string `json:"bbr_profile,omitempty"`
|
BBRProfile string `json:"bbr_profile,omitempty"`
|
||||||
CWND int `json:"cwnd,omitempty"`
|
CWND int `json:"cwnd,omitempty"`
|
||||||
Multiplex *TrustTunnelMultiplexOptions `json:"multiplex,omitempty"`
|
Multiplex *TrustTunnelMultiplexOptions `json:"multiplex,omitempty"`
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,8 @@ import (
|
|||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/sagernet/quic-go"
|
||||||
|
"github.com/sagernet/quic-go/http3"
|
||||||
"github.com/sagernet/sing-box/adapter"
|
"github.com/sagernet/sing-box/adapter"
|
||||||
"github.com/sagernet/sing-box/adapter/inbound"
|
"github.com/sagernet/sing-box/adapter/inbound"
|
||||||
"github.com/sagernet/sing-box/common/listener"
|
"github.com/sagernet/sing-box/common/listener"
|
||||||
@@ -14,11 +16,13 @@ import (
|
|||||||
"github.com/sagernet/sing-box/log"
|
"github.com/sagernet/sing-box/log"
|
||||||
"github.com/sagernet/sing-box/option"
|
"github.com/sagernet/sing-box/option"
|
||||||
"github.com/sagernet/sing-box/transport/trusttunnel"
|
"github.com/sagernet/sing-box/transport/trusttunnel"
|
||||||
|
"github.com/sagernet/sing-quic"
|
||||||
"github.com/sagernet/sing/common"
|
"github.com/sagernet/sing/common"
|
||||||
"github.com/sagernet/sing/common/auth"
|
"github.com/sagernet/sing/common/auth"
|
||||||
"github.com/sagernet/sing/common/logger"
|
"github.com/sagernet/sing/common/logger"
|
||||||
M "github.com/sagernet/sing/common/metadata"
|
M "github.com/sagernet/sing/common/metadata"
|
||||||
N "github.com/sagernet/sing/common/network"
|
N "github.com/sagernet/sing/common/network"
|
||||||
|
"github.com/sagernet/sing/common/ntp"
|
||||||
aTLS "github.com/sagernet/sing/common/tls"
|
aTLS "github.com/sagernet/sing/common/tls"
|
||||||
|
|
||||||
"golang.org/x/net/http2"
|
"golang.org/x/net/http2"
|
||||||
@@ -31,36 +35,34 @@ func RegisterInbound(registry *inbound.Registry) {
|
|||||||
|
|
||||||
type Inbound struct {
|
type Inbound struct {
|
||||||
inbound.Adapter
|
inbound.Adapter
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
router adapter.Router
|
router adapter.Router
|
||||||
logger logger.ContextLogger
|
logger logger.ContextLogger
|
||||||
listener *listener.Listener
|
options option.TrustTunnelInboundOptions
|
||||||
tlsConfig tls.ServerConfig
|
listener *listener.Listener
|
||||||
service *trusttunnel.Service
|
service *trusttunnel.Service
|
||||||
httpServer *http.Server
|
httpServer *http.Server
|
||||||
quicService *trusttunnel.QUICService
|
http3Server *http3.Server
|
||||||
network []string
|
httpTLSConfig tls.ServerConfig
|
||||||
|
http3TLSConfig tls.ServerConfig
|
||||||
|
network []string
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewInbound(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.TrustTunnelInboundOptions) (adapter.Inbound, error) {
|
func NewInbound(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.TrustTunnelInboundOptions) (adapter.Inbound, error) {
|
||||||
if options.TLS == nil || !options.TLS.Enabled {
|
if options.TLS == nil || !options.TLS.Enabled {
|
||||||
return nil, C.ErrTLSRequired
|
return nil, C.ErrTLSRequired
|
||||||
}
|
}
|
||||||
tlsConfig, err := tls.NewServer(ctx, logger, common.PtrValueOrDefault(options.TLS))
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
networkList := options.Network.Build()
|
networkList := options.Network.Build()
|
||||||
if len(networkList) == 0 {
|
if len(networkList) == 0 {
|
||||||
networkList = []string{N.NetworkTCP}
|
networkList = []string{N.NetworkTCP}
|
||||||
}
|
}
|
||||||
inbound := &Inbound{
|
inbound := &Inbound{
|
||||||
Adapter: inbound.NewAdapter(C.TypeTrustTunnel, tag),
|
Adapter: inbound.NewAdapter(C.TypeTrustTunnel, tag),
|
||||||
ctx: ctx,
|
ctx: ctx,
|
||||||
router: router,
|
router: router,
|
||||||
logger: logger,
|
logger: logger,
|
||||||
tlsConfig: tlsConfig,
|
options: options,
|
||||||
network: networkList,
|
network: networkList,
|
||||||
listener: listener.New(listener.Options{
|
listener: listener.New(listener.Options{
|
||||||
Context: ctx,
|
Context: ctx,
|
||||||
Logger: logger,
|
Logger: logger,
|
||||||
@@ -78,9 +80,6 @@ func NewInbound(ctx context.Context, router adapter.Router, logger log.ContextLo
|
|||||||
}
|
}
|
||||||
service.UpdateUsers(userMap)
|
service.UpdateUsers(userMap)
|
||||||
inbound.service = service
|
inbound.service = service
|
||||||
if common.Contains(networkList, N.NetworkUDP) {
|
|
||||||
inbound.quicService = trusttunnel.NewQUICService(service, options.CongestionController, options.CWND, options.BBRProfile)
|
|
||||||
}
|
|
||||||
return inbound, nil
|
return inbound, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -88,14 +87,9 @@ func (h *Inbound) Start(stage adapter.StartStage) error {
|
|||||||
if stage != adapter.StartStateStart {
|
if stage != adapter.StartStateStart {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
if h.tlsConfig != nil {
|
var err error
|
||||||
err := h.tlsConfig.Start()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if common.Contains(h.network, N.NetworkTCP) {
|
if common.Contains(h.network, N.NetworkTCP) {
|
||||||
tcpListener, err := h.listener.ListenTCP()
|
listener, err := h.listener.ListenTCP()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -105,31 +99,70 @@ func (h *Inbound) Start(stage adapter.StartStage) error {
|
|||||||
return h.ctx
|
return h.ctx
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
h.httpTLSConfig, err = tls.NewServer(h.ctx, h.logger, common.PtrValueOrDefault(h.options.TLS))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if len(h.httpTLSConfig.NextProtos()) == 0 {
|
||||||
|
h.httpTLSConfig.SetNextProtos([]string{http2.NextProtoTLS})
|
||||||
|
} else if !common.Contains(h.httpTLSConfig.NextProtos(), http2.NextProtoTLS) {
|
||||||
|
h.httpTLSConfig.SetNextProtos(append([]string{http2.NextProtoTLS}, h.httpTLSConfig.NextProtos()...))
|
||||||
|
}
|
||||||
|
err = h.httpTLSConfig.Start()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
listener = aTLS.NewListener(listener, h.httpTLSConfig)
|
||||||
go func() {
|
go func() {
|
||||||
var l net.Listener = tcpListener
|
sErr := h.httpServer.Serve(listener)
|
||||||
if h.tlsConfig != nil {
|
|
||||||
if len(h.tlsConfig.NextProtos()) == 0 {
|
|
||||||
h.tlsConfig.SetNextProtos([]string{http2.NextProtoTLS})
|
|
||||||
} else if !common.Contains(h.tlsConfig.NextProtos(), http2.NextProtoTLS) {
|
|
||||||
h.tlsConfig.SetNextProtos(append([]string{http2.NextProtoTLS}, h.tlsConfig.NextProtos()...))
|
|
||||||
}
|
|
||||||
l = aTLS.NewListener(tcpListener, h.tlsConfig)
|
|
||||||
}
|
|
||||||
sErr := h.httpServer.Serve(l)
|
|
||||||
if sErr != nil && !errors.Is(sErr, http.ErrServerClosed) {
|
if sErr != nil && !errors.Is(sErr, http.ErrServerClosed) {
|
||||||
h.logger.Error("HTTP server error: ", sErr)
|
h.logger.Error("HTTP server error: ", sErr)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
if common.Contains(h.network, N.NetworkUDP) {
|
if common.Contains(h.network, N.NetworkUDP) {
|
||||||
|
h.http3TLSConfig, err = tls.NewServer(h.ctx, h.logger, common.PtrValueOrDefault(h.options.TLS))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := qtls.ConfigureHTTP3(h.http3TLSConfig); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = h.http3TLSConfig.Start()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
udpConn, err := h.listener.ListenUDP()
|
udpConn, err := h.listener.ListenUDP()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
err = h.quicService.Start(h.ctx, udpConn, h.tlsConfig)
|
congestionControlFactory, err := trusttunnel.NewCongestionControl(
|
||||||
|
h.options.CongestionController,
|
||||||
|
h.options.CWND,
|
||||||
|
h.options.BBRProfile,
|
||||||
|
ntp.TimeFuncFromContext(h.ctx),
|
||||||
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
h.http3Server = &http3.Server{
|
||||||
|
Handler: h.service,
|
||||||
|
ConnContext: func(ctx context.Context, conn *quic.Conn) context.Context {
|
||||||
|
conn.SetCongestionControl(congestionControlFactory(conn))
|
||||||
|
return ctx
|
||||||
|
},
|
||||||
|
}
|
||||||
|
quicListener, err := qtls.ListenEarly(udpConn, h.http3TLSConfig, &quic.Config{
|
||||||
|
MaxIdleTimeout: trusttunnel.DefaultSessionTimeout * 2,
|
||||||
|
MaxIncomingStreams: 1 << 60,
|
||||||
|
Allow0RTT: true,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
go func() {
|
||||||
|
_ = h.http3Server.ServeListener(quicListener)
|
||||||
|
}()
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -138,8 +171,9 @@ func (h *Inbound) Close() error {
|
|||||||
return common.Close(
|
return common.Close(
|
||||||
h.listener,
|
h.listener,
|
||||||
common.PtrOrNil(h.httpServer),
|
common.PtrOrNil(h.httpServer),
|
||||||
common.PtrOrNil(h.quicService),
|
common.PtrOrNil(h.http3Server),
|
||||||
h.tlsConfig,
|
h.httpTLSConfig,
|
||||||
|
h.http3TLSConfig,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -18,8 +18,6 @@ import (
|
|||||||
"github.com/sagernet/sing/common/logger"
|
"github.com/sagernet/sing/common/logger"
|
||||||
M "github.com/sagernet/sing/common/metadata"
|
M "github.com/sagernet/sing/common/metadata"
|
||||||
N "github.com/sagernet/sing/common/network"
|
N "github.com/sagernet/sing/common/network"
|
||||||
|
|
||||||
"golang.org/x/net/http2"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func RegisterOutbound(registry *outbound.Registry) {
|
func RegisterOutbound(registry *outbound.Registry) {
|
||||||
@@ -42,7 +40,13 @@ func NewOutbound(ctx context.Context, router adapter.Router, logger log.ContextL
|
|||||||
}
|
}
|
||||||
serverAddr := options.ServerOptions.Build()
|
serverAddr := options.ServerOptions.Build()
|
||||||
networkList := options.Network.Build()
|
networkList := options.Network.Build()
|
||||||
|
tlsConfig, err := tls.NewClient(ctx, logger, options.Server, common.PtrValueOrDefault(options.TLS))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
clientOpts := trusttunnel.ClientOptions{
|
clientOpts := trusttunnel.ClientOptions{
|
||||||
|
Dialer: outboundDialer,
|
||||||
|
TLSConfig: tlsConfig,
|
||||||
Server: serverAddr,
|
Server: serverAddr,
|
||||||
Username: options.Username,
|
Username: options.Username,
|
||||||
Password: options.Password,
|
Password: options.Password,
|
||||||
@@ -52,26 +56,6 @@ func NewOutbound(ctx context.Context, router adapter.Router, logger log.ContextL
|
|||||||
BBRProfile: options.BBRProfile,
|
BBRProfile: options.BBRProfile,
|
||||||
HealthCheck: options.HealthCheck,
|
HealthCheck: options.HealthCheck,
|
||||||
}
|
}
|
||||||
if options.QUIC {
|
|
||||||
tlsConfig, err := tls.NewClient(ctx, logger, options.Server, common.PtrValueOrDefault(options.TLS))
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if len(tlsConfig.NextProtos()) == 0 {
|
|
||||||
tlsConfig.SetNextProtos([]string{"h3"})
|
|
||||||
}
|
|
||||||
clientOpts.QUICDialer = outboundDialer
|
|
||||||
clientOpts.QUICTLSConfig = tlsConfig
|
|
||||||
} else {
|
|
||||||
tlsConfig, err := tls.NewClient(ctx, logger, options.Server, common.PtrValueOrDefault(options.TLS))
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if len(tlsConfig.NextProtos()) == 0 {
|
|
||||||
tlsConfig.SetNextProtos([]string{http2.NextProtoTLS})
|
|
||||||
}
|
|
||||||
clientOpts.TLSDialer = tls.NewDialer(outboundDialer, tlsConfig)
|
|
||||||
}
|
|
||||||
var client trusttunnel.Dialer
|
var client trusttunnel.Dialer
|
||||||
if options.Multiplex != nil && options.Multiplex.Enabled {
|
if options.Multiplex != nil && options.Multiplex.Enabled {
|
||||||
clientOpts.MaxConnections = options.Multiplex.MaxConnections
|
clientOpts.MaxConnections = options.Multiplex.MaxConnections
|
||||||
|
|||||||
@@ -16,9 +16,9 @@ import (
|
|||||||
|
|
||||||
"github.com/sagernet/sing-box/common/tls"
|
"github.com/sagernet/sing-box/common/tls"
|
||||||
C "github.com/sagernet/sing-box/constant"
|
C "github.com/sagernet/sing-box/constant"
|
||||||
|
"github.com/sagernet/sing/common/bufio"
|
||||||
M "github.com/sagernet/sing/common/metadata"
|
M "github.com/sagernet/sing/common/metadata"
|
||||||
N "github.com/sagernet/sing/common/network"
|
N "github.com/sagernet/sing/common/network"
|
||||||
"github.com/sagernet/sing/common/bufio"
|
|
||||||
"github.com/sagernet/sing/common/ntp"
|
"github.com/sagernet/sing/common/ntp"
|
||||||
|
|
||||||
"github.com/sagernet/quic-go"
|
"github.com/sagernet/quic-go"
|
||||||
@@ -42,9 +42,8 @@ type Dialer interface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type ClientOptions struct {
|
type ClientOptions struct {
|
||||||
TLSDialer tls.Dialer
|
Dialer N.Dialer
|
||||||
QUICDialer N.Dialer
|
TLSConfig tls.Config
|
||||||
QUICTLSConfig tls.Config
|
|
||||||
Server M.Socksaddr
|
Server M.Socksaddr
|
||||||
Username string
|
Username string
|
||||||
Password string
|
Password string
|
||||||
@@ -87,17 +86,20 @@ func NewClient(ctx context.Context, options ClientOptions) (*Client, error) {
|
|||||||
cancel()
|
cancel()
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
if len(options.TLSConfig.NextProtos()) == 0 {
|
||||||
|
options.TLSConfig.SetNextProtos([]string{"h3"})
|
||||||
|
}
|
||||||
client.roundTripper = &http3.Transport{
|
client.roundTripper = &http3.Transport{
|
||||||
QUICConfig: &quic.Config{
|
QUICConfig: &quic.Config{
|
||||||
MaxIdleTimeout: DefaultSessionTimeout * 2,
|
MaxIdleTimeout: DefaultSessionTimeout * 2,
|
||||||
KeepAlivePeriod: DefaultHealthCheckTimeout,
|
KeepAlivePeriod: DefaultHealthCheckTimeout,
|
||||||
},
|
},
|
||||||
Dial: func(ctx context.Context, addr string, tlsCfg *stdtls.Config, cfg *quic.Config) (*quic.Conn, error) {
|
Dial: func(ctx context.Context, addr string, tlsCfg *stdtls.Config, cfg *quic.Config) (*quic.Conn, error) {
|
||||||
udpConn, err := options.QUICDialer.DialContext(ctx, N.NetworkUDP, client.server)
|
udpConn, err := options.Dialer.DialContext(ctx, N.NetworkUDP, client.server)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
conn, err := qtls.DialEarly(ctx, bufio.NewUnbindPacketConn(udpConn), udpConn.RemoteAddr(), options.QUICTLSConfig, cfg)
|
conn, err := qtls.DialEarly(ctx, bufio.NewUnbindPacketConn(udpConn), udpConn.RemoteAddr(), options.TLSConfig, cfg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -106,9 +108,13 @@ func NewClient(ctx context.Context, options ClientOptions) (*Client, error) {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
if len(options.TLSConfig.NextProtos()) == 0 {
|
||||||
|
options.TLSConfig.SetNextProtos([]string{http2.NextProtoTLS})
|
||||||
|
}
|
||||||
|
tlsDialer := tls.NewDialer(options.Dialer, options.TLSConfig)
|
||||||
client.roundTripper = &http2.Transport{
|
client.roundTripper = &http2.Transport{
|
||||||
DialTLSContext: func(ctx context.Context, network, addr string, _ *stdtls.Config) (net.Conn, error) {
|
DialTLSContext: func(ctx context.Context, network, addr string, _ *stdtls.Config) (net.Conn, error) {
|
||||||
return options.TLSDialer.DialContext(ctx, network, client.server)
|
return tlsDialer.DialContext(ctx, network, client.server)
|
||||||
},
|
},
|
||||||
AllowHTTP: true,
|
AllowHTTP: true,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,62 +0,0 @@
|
|||||||
package trusttunnel
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/binary"
|
|
||||||
"net/netip"
|
|
||||||
|
|
||||||
"github.com/sagernet/sing/common/buf"
|
|
||||||
)
|
|
||||||
|
|
||||||
type IcmpConn struct {
|
|
||||||
httpConn
|
|
||||||
}
|
|
||||||
|
|
||||||
func (i *IcmpConn) WritePing(id uint16, destination netip.Addr, sequenceNumber uint16, ttl uint8, size uint16) error {
|
|
||||||
request := buf.NewSize(2 + 16 + 2 + 1 + 2)
|
|
||||||
defer request.Release()
|
|
||||||
must(binary.Write(request, binary.BigEndian, id))
|
|
||||||
destinationAddress := buildPaddingIP(destination)
|
|
||||||
must1(request.Write(destinationAddress[:]))
|
|
||||||
must(binary.Write(request, binary.BigEndian, sequenceNumber))
|
|
||||||
must(binary.Write(request, binary.BigEndian, ttl))
|
|
||||||
must(binary.Write(request, binary.BigEndian, size))
|
|
||||||
_, err := i.writeFlush(request.Bytes())
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (i *IcmpConn) ReadPing() (id uint16, sourceAddress netip.Addr, icmpType uint8, code uint8, sequenceNumber uint16, err error) {
|
|
||||||
err = i.waitCreated()
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
response := buf.NewSize(2 + 16 + 1 + 1 + 2)
|
|
||||||
defer response.Release()
|
|
||||||
_, err = response.ReadFullFrom(i.body, response.FreeLen())
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
must(binary.Read(response, binary.BigEndian, &id))
|
|
||||||
var sourceAddressBuffer [16]byte
|
|
||||||
must1(response.Read(sourceAddressBuffer[:]))
|
|
||||||
sourceAddress = parse16BytesIP(sourceAddressBuffer)
|
|
||||||
must(binary.Read(response, binary.BigEndian, &icmpType))
|
|
||||||
must(binary.Read(response, binary.BigEndian, &code))
|
|
||||||
must(binary.Read(response, binary.BigEndian, &sequenceNumber))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (i *IcmpConn) Close() error {
|
|
||||||
return i.httpConn.Close()
|
|
||||||
}
|
|
||||||
|
|
||||||
func must(err error) {
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func must1[T any](_ T, err error) {
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,22 +1,15 @@
|
|||||||
package trusttunnel
|
package trusttunnel
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
"errors"
|
|
||||||
"net"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/sagernet/quic-go"
|
"github.com/sagernet/quic-go"
|
||||||
"github.com/sagernet/quic-go/congestion"
|
"github.com/sagernet/quic-go/congestion"
|
||||||
"github.com/sagernet/quic-go/http3"
|
|
||||||
"github.com/sagernet/sing-box/common/tls"
|
|
||||||
E "github.com/sagernet/sing/common/exceptions"
|
|
||||||
qtls "github.com/sagernet/sing-quic"
|
|
||||||
"github.com/sagernet/sing-quic/congestion_bbr1"
|
"github.com/sagernet/sing-quic/congestion_bbr1"
|
||||||
"github.com/sagernet/sing-quic/congestion_bbr2"
|
"github.com/sagernet/sing-quic/congestion_bbr2"
|
||||||
congestion_meta1 "github.com/sagernet/sing-quic/congestion_meta1"
|
congestion_meta1 "github.com/sagernet/sing-quic/congestion_meta1"
|
||||||
congestion_meta2 "github.com/sagernet/sing-quic/congestion_meta2"
|
congestion_meta2 "github.com/sagernet/sing-quic/congestion_meta2"
|
||||||
"github.com/sagernet/sing/common/ntp"
|
E "github.com/sagernet/sing/common/exceptions"
|
||||||
)
|
)
|
||||||
|
|
||||||
func NewCongestionControl(name string, cwnd int, bbrProfile string, timeFunc func() time.Time) (func(conn *quic.Conn) congestion.CongestionControl, error) {
|
func NewCongestionControl(name string, cwnd int, bbrProfile string, timeFunc func() time.Time) (func(conn *quic.Conn) congestion.CongestionControl, error) {
|
||||||
@@ -82,62 +75,3 @@ func NewCongestionControl(name string, cwnd int, bbrProfile string, timeFunc fun
|
|||||||
return nil, E.New("unknown congestion control: ", name)
|
return nil, E.New("unknown congestion control: ", name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type QUICService struct {
|
|
||||||
service *Service
|
|
||||||
h3Server *http3.Server
|
|
||||||
udpConn net.PacketConn
|
|
||||||
congestionControl string
|
|
||||||
cwnd int
|
|
||||||
bbrProfile string
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewQUICService(service *Service, congestionControl string, cwnd int, bbrProfile string) *QUICService {
|
|
||||||
return &QUICService{
|
|
||||||
service: service,
|
|
||||||
congestionControl: congestionControl,
|
|
||||||
cwnd: cwnd,
|
|
||||||
bbrProfile: bbrProfile,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *QUICService) Start(ctx context.Context, udpConn net.PacketConn, tlsConfig tls.ServerConfig) error {
|
|
||||||
s.udpConn = udpConn
|
|
||||||
congestionControlFactory, err := NewCongestionControl(s.congestionControl, s.cwnd, s.bbrProfile, ntp.TimeFuncFromContext(ctx))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
s.h3Server = &http3.Server{
|
|
||||||
Handler: s.service,
|
|
||||||
ConnContext: func(ctx context.Context, conn *quic.Conn) context.Context {
|
|
||||||
conn.SetCongestionControl(congestionControlFactory(conn))
|
|
||||||
return ctx
|
|
||||||
},
|
|
||||||
}
|
|
||||||
if err := qtls.ConfigureHTTP3(tlsConfig); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
quicListener, err := qtls.ListenEarly(udpConn, tlsConfig, &quic.Config{
|
|
||||||
MaxIdleTimeout: DefaultSessionTimeout * 2,
|
|
||||||
MaxIncomingStreams: 1 << 60,
|
|
||||||
Allow0RTT: true,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
go func() {
|
|
||||||
_ = s.h3Server.ServeListener(quicListener)
|
|
||||||
}()
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *QUICService) Close() error {
|
|
||||||
var errs []error
|
|
||||||
if s.h3Server != nil {
|
|
||||||
errs = append(errs, s.h3Server.Close())
|
|
||||||
}
|
|
||||||
if s.udpConn != nil {
|
|
||||||
errs = append(errs, s.udpConn.Close())
|
|
||||||
}
|
|
||||||
return errors.Join(errs...)
|
|
||||||
}
|
|
||||||
|
|||||||
Reference in New Issue
Block a user