From 74d2e7092c4ecc00fb2064de702d6b92d6a47912 Mon Sep 17 00:00:00 2001 From: "github-action[bot]" Date: Mon, 8 Sep 2025 20:41:11 +0200 Subject: [PATCH] Update On Mon Sep 8 20:41:11 CEST 2025 --- .github/update.log | 1 + clash-meta/common/net/sing.go | 13 +- clash-meta/go.mod | 2 +- clash-meta/go.sum | 4 +- clash-meta/listener/sing/util.go | 5 +- clash-meta/listener/sing_vless/server.go | 35 +- clash-meta/listener/sing_vless/service.go | 304 ++++++++++++++++++ clash-meta/transport/vless/addons.go | 61 ++++ clash-meta/transport/vless/addons_test.go | 95 ++++++ clash-meta/transport/vless/conn.go | 106 +++--- clash-meta/transport/vless/vision/conn.go | 58 ++-- clash-meta/transport/vless/vision/padding.go | 9 +- clash-meta/transport/vless/vision/vision.go | 108 +++++-- clash-meta/transport/vless/vless.go | 4 +- clash-nyanpasu/backend/Cargo.lock | 297 +++++++++-------- clash-nyanpasu/backend/Cargo.toml | 3 + clash-nyanpasu/backend/tauri/Cargo.toml | 12 +- clash-nyanpasu/manifest/version.json | 18 +- clash-nyanpasu/pnpm-lock.yaml | 157 +++++---- clash-nyanpasu/scripts/package.json | 6 +- clash-nyanpasu/scripts/updater-nightly.ts | 9 +- clash-nyanpasu/scripts/updater.ts | 5 +- clash-nyanpasu/scripts/utils/download.ts | 8 +- clash-nyanpasu/scripts/utils/index.ts | 4 +- clash-nyanpasu/scripts/utils/manifest.ts | 16 +- clash-nyanpasu/scripts/utils/resource.ts | 8 +- filebrowser/frontend/src/i18n/it.json | 54 ++-- filebrowser/frontend/src/i18n/uk.json | 8 +- lede/package/utils/mdadm/Makefile | 10 +- .../mdadm/patches/100-cross_compile.patch | 2 +- .../utils/mdadm/patches/200-reduce_size.patch | 4 +- mieru/Makefile | 2 +- .../package/mieru/amd64/debian/DEBIAN/control | 2 +- .../build/package/mieru/amd64/rpm/mieru.spec | 2 +- .../package/mieru/arm64/debian/DEBIAN/control | 2 +- .../build/package/mieru/arm64/rpm/mieru.spec | 2 +- .../package/mita/amd64/debian/DEBIAN/control | 2 +- mieru/build/package/mita/amd64/rpm/mita.spec | 2 +- .../package/mita/arm64/debian/DEBIAN/control | 2 +- mieru/build/package/mita/arm64/rpm/mita.spec | 2 +- mieru/docs/server-install.md | 16 +- mieru/docs/server-install.zh_CN.md | 16 +- mieru/pkg/version/current.go | 2 +- mihomo/common/net/sing.go | 13 +- mihomo/go.mod | 2 +- mihomo/go.sum | 4 +- mihomo/listener/sing/util.go | 5 +- mihomo/listener/sing_vless/server.go | 35 +- mihomo/listener/sing_vless/service.go | 304 ++++++++++++++++++ mihomo/transport/vless/addons.go | 61 ++++ mihomo/transport/vless/addons_test.go | 95 ++++++ mihomo/transport/vless/conn.go | 106 +++--- mihomo/transport/vless/vision/conn.go | 58 ++-- mihomo/transport/vless/vision/padding.go | 9 +- mihomo/transport/vless/vision/vision.go | 108 +++++-- mihomo/transport/vless/vless.go | 4 +- .../model/cbi/passwall/client/type/ray.lua | 26 +- .../cbi/passwall/client/type/sing-box.lua | 22 +- .../luasrc/passwall/util_xray.lua | 4 +- sing-box/.github/workflows/build.yml | 10 +- sing-box/.github/workflows/linux.yml | 4 +- sing-box/common/badtls/raw_conn.go | 7 + sing-box/common/badtls/read_wait.go | 3 + sing-box/common/badversion/version.go | 42 ++- sing-box/common/badversion/version_test.go | 10 +- sing-box/common/ktls/ktls.go | 40 ++- sing-box/common/ktls/ktls_alert.go | 8 +- sing-box/common/ktls/ktls_linux.go | 118 ++++--- sing-box/common/ktls/ktls_stub.go | 4 +- sing-box/common/tls/client.go | 57 +++- sing-box/common/tls/config.go | 6 - sing-box/common/tls/ktls.go | 67 ++++ sing-box/common/tls/reality_client.go | 7 +- sing-box/common/tls/reality_server.go | 9 +- sing-box/common/tls/server.go | 41 ++- sing-box/common/tls/std_client.go | 47 ++- sing-box/common/tls/std_server.go | 54 ++-- sing-box/common/tls/utls_client.go | 47 +-- sing-box/dns/client.go | 2 +- sing-box/dns/transport/https.go | 4 +- sing-box/dns/transport/quic/http3.go | 4 +- sing-box/dns/transport/quic/quic.go | 2 +- sing-box/dns/transport/tls.go | 2 +- sing-box/docs/changelog.md | 5 + sing-box/docs/configuration/shared/tls.md | 56 +++- sing-box/docs/configuration/shared/tls.zh.md | 57 ++++ sing-box/go.mod | 5 +- sing-box/go.sum | 10 +- sing-box/protocol/anytls/outbound.go | 2 +- sing-box/protocol/http/inbound.go | 7 +- sing-box/protocol/http/outbound.go | 2 +- sing-box/protocol/hysteria/outbound.go | 2 +- sing-box/protocol/hysteria2/outbound.go | 2 +- sing-box/protocol/mixed/inbound.go | 33 +- sing-box/protocol/naive/inbound.go | 2 +- sing-box/protocol/shadowtls/outbound.go | 4 +- sing-box/protocol/tailscale/dns_transport.go | 2 +- sing-box/protocol/trojan/inbound.go | 8 +- sing-box/protocol/trojan/outbound.go | 9 +- sing-box/protocol/tuic/outbound.go | 2 +- sing-box/protocol/vless/inbound.go | 11 +- sing-box/protocol/vless/outbound.go | 10 +- sing-box/protocol/vmess/outbound.go | 2 +- sing-box/service/derp/service.go | 4 +- sing-box/service/resolved/transport.go | 4 +- sing-box/transport/sip003/v2ray.go | 3 +- .../model/cbi/passwall/client/type/ray.lua | 26 +- .../cbi/passwall/client/type/sing-box.lua | 22 +- .../luasrc/passwall/util_xray.lua | 4 +- small/v2ray-geodata/Makefile | 2 +- v2rayn/package-appimage.sh | 75 ++++- v2rayn/pkg2appimage.yml | 37 --- v2rayn/v2rayN/Directory.Build.props | 2 +- v2rayn/v2rayN/ServiceLib/Common/Utils.cs | 4 +- .../ViewModels/BackupAndRestoreViewModel.cs | 1 - .../ViewModels/ProfilesSelectViewModel.cs | 17 +- .../ViewModels/RoutingRuleSettingViewModel.cs | 1 + .../Views/ProfilesSelectWindow.axaml.cs | 7 +- .../Views/RoutingRuleDetailsWindow.axaml.cs | 1 - .../Views/SubEditWindow.axaml.cs | 1 - .../v2rayN/Views/ProfilesSelectWindow.xaml.cs | 6 +- .../v2rayN/v2rayN/Views/ProfilesView.xaml.cs | 2 +- .../Views/RoutingRuleDetailsWindow.xaml.cs | 1 - xray-core/proxy/vmess/aead/authid.go | 10 +- xray-core/transport/internet/kcp/cryptreal.go | 2 +- yt-dlp/test/test_utils.py | 10 +- yt-dlp/yt_dlp/extractor/tenplay.py | 18 +- 127 files changed, 2387 insertions(+), 1033 deletions(-) create mode 100644 clash-meta/listener/sing_vless/service.go create mode 100644 clash-meta/transport/vless/addons.go create mode 100644 clash-meta/transport/vless/addons_test.go create mode 100644 mihomo/listener/sing_vless/service.go create mode 100644 mihomo/transport/vless/addons.go create mode 100644 mihomo/transport/vless/addons_test.go create mode 100644 sing-box/common/tls/ktls.go delete mode 100644 v2rayn/pkg2appimage.yml diff --git a/.github/update.log b/.github/update.log index 0e05e4760a..794003e86b 100644 --- a/.github/update.log +++ b/.github/update.log @@ -1114,3 +1114,4 @@ Update On Thu Sep 4 20:39:26 CEST 2025 Update On Fri Sep 5 20:37:42 CEST 2025 Update On Sat Sep 6 20:35:46 CEST 2025 Update On Sun Sep 7 20:32:35 CEST 2025 +Update On Mon Sep 8 20:41:03 CEST 2025 diff --git a/clash-meta/common/net/sing.go b/clash-meta/common/net/sing.go index 5cf9759427..3545b6a407 100644 --- a/clash-meta/common/net/sing.go +++ b/clash-meta/common/net/sing.go @@ -26,11 +26,20 @@ type ReadWaitOptions = network.ReadWaitOptions var NewReadWaitOptions = network.NewReadWaitOptions +type ReaderWithUpstream = network.ReaderWithUpstream +type WithUpstreamReader = network.WithUpstreamReader +type WriterWithUpstream = network.WriterWithUpstream +type WithUpstreamWriter = network.WithUpstreamWriter +type WithUpstream = common.WithUpstream + +var UnwrapReader = network.UnwrapReader +var UnwrapWriter = network.UnwrapWriter + func NewDeadlineConn(conn net.Conn) ExtendedConn { - if deadline.IsPipe(conn) || deadline.IsPipe(network.UnwrapReader(conn)) { + if deadline.IsPipe(conn) || deadline.IsPipe(UnwrapReader(conn)) { return NewExtendedConn(conn) // pipe always have correctly deadline implement } - if deadline.IsConn(conn) || deadline.IsConn(network.UnwrapReader(conn)) { + if deadline.IsConn(conn) || deadline.IsConn(UnwrapReader(conn)) { return NewExtendedConn(conn) // was a *deadline.Conn } return deadline.NewConn(conn) diff --git a/clash-meta/go.mod b/clash-meta/go.mod index faa4acbd27..d413c488f0 100644 --- a/clash-meta/go.mod +++ b/clash-meta/go.mod @@ -25,7 +25,7 @@ require ( github.com/metacubex/randv2 v0.2.0 github.com/metacubex/restls-client-go v0.1.7 github.com/metacubex/sing v0.5.6-0.20250903022707-c9bf6d825f4d - github.com/metacubex/sing-mux v0.3.3-0.20250813083925-d7c9aeaeeaac + github.com/metacubex/sing-mux v0.3.3 github.com/metacubex/sing-quic v0.0.0-20250718154553-1b193bec4cbb github.com/metacubex/sing-shadowsocks v0.2.12 github.com/metacubex/sing-shadowsocks2 v0.2.6 diff --git a/clash-meta/go.sum b/clash-meta/go.sum index 369c23543a..f9547b1cd1 100644 --- a/clash-meta/go.sum +++ b/clash-meta/go.sum @@ -119,8 +119,8 @@ github.com/metacubex/restls-client-go v0.1.7/go.mod h1:BN/U52vPw7j8VTSh2vleD/Mnm github.com/metacubex/sing v0.5.2/go.mod h1:ypf0mjwlZm0sKdQSY+yQvmsbWa0hNPtkeqyRMGgoN+w= github.com/metacubex/sing v0.5.6-0.20250903022707-c9bf6d825f4d h1:oprae0GgOxsKpEDa8+pF0WMPrUhpKDRJtBWPAxcy3yo= github.com/metacubex/sing v0.5.6-0.20250903022707-c9bf6d825f4d/go.mod h1:ypf0mjwlZm0sKdQSY+yQvmsbWa0hNPtkeqyRMGgoN+w= -github.com/metacubex/sing-mux v0.3.3-0.20250813083925-d7c9aeaeeaac h1:wDH/Jh/yqWbzPktqJP+Y1cUG8hchcrzKzUxJiSpnaQs= -github.com/metacubex/sing-mux v0.3.3-0.20250813083925-d7c9aeaeeaac/go.mod h1:3rt1soewn0O6j89GCLmwAQFsq257u0jf2zQSPhTL3Bw= +github.com/metacubex/sing-mux v0.3.3 h1:oqCbUAJgTLsa71vfo8otW8xIhrDfbc/Y2rmtW34sQjg= +github.com/metacubex/sing-mux v0.3.3/go.mod h1:3rt1soewn0O6j89GCLmwAQFsq257u0jf2zQSPhTL3Bw= github.com/metacubex/sing-quic v0.0.0-20250718154553-1b193bec4cbb h1:U/m3h8lp/j7i8zFgfvScLdZa1/Y8dd74oO7iZaQq80s= github.com/metacubex/sing-quic v0.0.0-20250718154553-1b193bec4cbb/go.mod h1:B60FxaPHjR1SeQB0IiLrgwgvKsaoASfOWdiqhLjmMGA= github.com/metacubex/sing-shadowsocks v0.2.12 h1:Wqzo8bYXrK5aWqxu/TjlTnYZzAKtKsaFQBdr6IHFaBE= diff --git a/clash-meta/listener/sing/util.go b/clash-meta/listener/sing/util.go index 306301621b..20d3e9709d 100644 --- a/clash-meta/listener/sing/util.go +++ b/clash-meta/listener/sing/util.go @@ -12,11 +12,14 @@ import ( func (h *ListenerHandler) HandleSocket(target socks5.Addr, conn net.Conn, _additions ...inbound.Addition) { conn, metadata := inbound.NewSocket(target, conn, h.Type, h.Additions...) if h.IsSpecialFqdn(metadata.Host) { - _ = h.ParseSpecialFqdn( + err := h.ParseSpecialFqdn( WithAdditions(context.Background(), _additions...), conn, ConvertMetadata(metadata), ) + if err != nil { + _ = conn.Close() + } } else { inbound.ApplyAdditions(metadata, _additions...) h.Tunnel.HandleTCPConn(conn, metadata) diff --git a/clash-meta/listener/sing_vless/server.go b/clash-meta/listener/sing_vless/server.go index 3a5943b5ab..d4fc397340 100644 --- a/clash-meta/listener/sing_vless/server.go +++ b/clash-meta/listener/sing_vless/server.go @@ -5,9 +5,7 @@ import ( "errors" "net" "net/http" - "reflect" "strings" - "unsafe" "github.com/metacubex/mihomo/adapter/inbound" "github.com/metacubex/mihomo/component/ca" @@ -17,48 +15,19 @@ import ( LC "github.com/metacubex/mihomo/listener/config" "github.com/metacubex/mihomo/listener/reality" "github.com/metacubex/mihomo/listener/sing" - "github.com/metacubex/mihomo/log" "github.com/metacubex/mihomo/transport/gun" "github.com/metacubex/mihomo/transport/vless/encryption" mihomoVMess "github.com/metacubex/mihomo/transport/vmess" - "github.com/metacubex/sing-vmess/vless" "github.com/metacubex/sing/common" "github.com/metacubex/sing/common/metadata" - "github.com/metacubex/sing/common/network" ) -func init() { - vless.RegisterTLS(func(conn net.Conn) (loaded bool, netConn net.Conn, reflectType reflect.Type, reflectPointer unsafe.Pointer) { - tlsConn, loaded := network.CastReader[*reality.Conn](conn) // *utls.Conn - if !loaded { - return - } - return true, tlsConn.NetConn(), reflect.TypeOf(tlsConn).Elem(), unsafe.Pointer(tlsConn) - }) - - vless.RegisterTLS(func(conn net.Conn) (loaded bool, netConn net.Conn, reflectType reflect.Type, reflectPointer unsafe.Pointer) { - tlsConn, loaded := network.CastReader[*tlsC.UConn](conn) // *utls.UConn - if !loaded { - return - } - return true, tlsConn.NetConn(), reflect.TypeOf(tlsConn.Conn).Elem(), unsafe.Pointer(tlsConn.Conn) - }) - - vless.RegisterTLS(func(conn net.Conn) (loaded bool, netConn net.Conn, reflectType reflect.Type, reflectPointer unsafe.Pointer) { - tlsConn, loaded := network.CastReader[*encryption.CommonConn](conn) - if !loaded { - return - } - return true, tlsConn.Conn, reflect.TypeOf(tlsConn).Elem(), unsafe.Pointer(tlsConn) - }) -} - type Listener struct { closed bool config LC.VlessServer listeners []net.Listener - service *vless.Service[string] + service *Service[string] decryption *encryption.ServerInstance } @@ -79,7 +48,7 @@ func New(config LC.VlessServer, tunnel C.Tunnel, additions ...inbound.Addition) return nil, err } - service := vless.NewService[string](log.SingLogger, h) + service := NewService[string](h) service.UpdateUsers( common.Map(config.Users, func(it LC.VlessUser) string { return it.Username diff --git a/clash-meta/listener/sing_vless/service.go b/clash-meta/listener/sing_vless/service.go new file mode 100644 index 0000000000..d30b3c018f --- /dev/null +++ b/clash-meta/listener/sing_vless/service.go @@ -0,0 +1,304 @@ +package sing_vless + +// copy and modify from https://github.com/SagerNet/sing-vmess/tree/3c1cf255413250b09a57e4ecdf1def1fa505e3cc/vless + +import ( + "context" + "encoding/binary" + "io" + "net" + + "github.com/metacubex/mihomo/transport/vless" + "github.com/metacubex/mihomo/transport/vless/vision" + + "github.com/gofrs/uuid/v5" + "github.com/metacubex/sing-vmess" + "github.com/metacubex/sing/common/auth" + "github.com/metacubex/sing/common/buf" + "github.com/metacubex/sing/common/bufio" + E "github.com/metacubex/sing/common/exceptions" + M "github.com/metacubex/sing/common/metadata" + N "github.com/metacubex/sing/common/network" + "google.golang.org/protobuf/proto" +) + +type Service[T comparable] struct { + userMap map[[16]byte]T + userFlow map[T]string + handler Handler +} + +type Handler interface { + N.TCPConnectionHandler + N.UDPConnectionHandler + E.Handler +} + +func NewService[T comparable](handler Handler) *Service[T] { + return &Service[T]{ + handler: handler, + } +} + +func (s *Service[T]) UpdateUsers(userList []T, userUUIDList []string, userFlowList []string) { + userMap := make(map[[16]byte]T) + userFlowMap := make(map[T]string) + for i, userName := range userList { + userID, err := uuid.FromString(userUUIDList[i]) + if err != nil { + userID = uuid.NewV5(uuid.Nil, userUUIDList[i]) + } + userMap[userID] = userName + userFlowMap[userName] = userFlowList[i] + } + s.userMap = userMap + s.userFlow = userFlowMap +} + +var _ N.TCPConnectionHandler = (*Service[int])(nil) + +func (s *Service[T]) NewConnection(ctx context.Context, conn net.Conn, metadata M.Metadata) error { + var version uint8 + err := binary.Read(conn, binary.BigEndian, &version) + if err != nil { + return err + } + if version != vless.Version { + return E.New("unknown version: ", version) + } + + var requestUUID [16]byte + _, err = io.ReadFull(conn, requestUUID[:]) + if err != nil { + return err + } + + var addonsLen uint8 + err = binary.Read(conn, binary.BigEndian, &addonsLen) + if err != nil { + return err + } + + var addons vless.Addons + if addonsLen > 0 { + addonsBytes := make([]byte, addonsLen) + _, err = io.ReadFull(conn, addonsBytes) + if err != nil { + return err + } + + err = proto.Unmarshal(addonsBytes, &addons) + if err != nil { + return err + } + } + + var command byte + err = binary.Read(conn, binary.BigEndian, &command) + if err != nil { + return err + } + + var destination M.Socksaddr + if command != vless.CommandMux { + destination, err = vmess.AddressSerializer.ReadAddrPort(conn) + if err != nil { + return err + } + } + + user, loaded := s.userMap[requestUUID] + if !loaded { + return E.New("unknown UUID: ", uuid.FromBytesOrNil(requestUUID[:])) + } + ctx = auth.ContextWithUser(ctx, user) + metadata.Destination = destination + + userFlow := s.userFlow[user] + requestFlow := addons.Flow + if requestFlow != userFlow && requestFlow != "" { + return E.New("flow mismatch: expected ", flowName(userFlow), ", but got ", flowName(requestFlow)) + } + + responseConn := &serverConn{ExtendedConn: bufio.NewExtendedConn(conn)} + switch requestFlow { + case vless.XRV: + conn, err = vision.NewConn(responseConn, conn, requestUUID) + if err != nil { + return E.Cause(err, "initialize vision") + } + case "": + conn = responseConn + default: + return E.New("unknown flow: ", requestFlow) + } + switch command { + case vless.CommandTCP: + return s.handler.NewConnection(ctx, conn, metadata) + case vless.CommandUDP: + if requestFlow == vless.XRV { + return E.New(vless.XRV, " flow does not support UDP") + } + return s.handler.NewPacketConnection(ctx, &serverPacketConn{ExtendedConn: bufio.NewExtendedConn(conn), destination: destination}, metadata) + case vless.CommandMux: + return vmess.HandleMuxConnection(ctx, conn, metadata, s.handler) + default: + return E.New("unknown command: ", command) + } +} + +func flowName(value string) string { + if value == "" { + return "none" + } + return value +} + +type serverConn struct { + N.ExtendedConn + responseWritten bool +} + +func (c *serverConn) Write(b []byte) (n int, err error) { + if !c.responseWritten { + buffer := buf.NewSize(2 + len(b)) + buffer.WriteByte(vless.Version) + buffer.WriteByte(0) + buffer.Write(b) + _, err = c.ExtendedConn.Write(buffer.Bytes()) + buffer.Release() + if err == nil { + n = len(b) + } + c.responseWritten = true + return + } + return c.ExtendedConn.Write(b) +} + +func (c *serverConn) WriteBuffer(buffer *buf.Buffer) error { + if !c.responseWritten { + header := buffer.ExtendHeader(2) + header[0] = vless.Version + header[1] = 0 + c.responseWritten = true + } + return c.ExtendedConn.WriteBuffer(buffer) +} + +func (c *serverConn) FrontHeadroom() int { + if c.responseWritten { + return 0 + } + return 2 +} + +func (c *serverConn) ReaderReplaceable() bool { + return true +} + +func (c *serverConn) WriterReplaceable() bool { + return c.responseWritten +} + +func (c *serverConn) NeedAdditionalReadDeadline() bool { + return true +} + +func (c *serverConn) Upstream() any { + return c.ExtendedConn +} + +type serverPacketConn struct { + N.ExtendedConn + destination M.Socksaddr + readWaitOptions N.ReadWaitOptions +} + +func (c *serverPacketConn) InitializeReadWaiter(options N.ReadWaitOptions) (needCopy bool) { + c.readWaitOptions = options + return false +} + +func (c *serverPacketConn) WaitReadPacket() (buffer *buf.Buffer, destination M.Socksaddr, err error) { + var packetLen uint16 + err = binary.Read(c.ExtendedConn, binary.BigEndian, &packetLen) + if err != nil { + return + } + + buffer = c.readWaitOptions.NewPacketBuffer() + _, err = buffer.ReadFullFrom(c.ExtendedConn, int(packetLen)) + if err != nil { + buffer.Release() + return + } + c.readWaitOptions.PostReturn(buffer) + + destination = c.destination + return +} + +func (c *serverPacketConn) ReadFrom(p []byte) (n int, addr net.Addr, err error) { + var packetLen uint16 + err = binary.Read(c.ExtendedConn, binary.BigEndian, &packetLen) + if err != nil { + return + } + if len(p) < int(packetLen) { + err = io.ErrShortBuffer + return + } + n, err = io.ReadFull(c.ExtendedConn, p[:packetLen]) + if err != nil { + return + } + if c.destination.IsFqdn() { + addr = c.destination + } else { + addr = c.destination.UDPAddr() + } + return +} + +func (c *serverPacketConn) WriteTo(p []byte, addr net.Addr) (n int, err error) { + err = binary.Write(c.ExtendedConn, binary.BigEndian, uint16(len(p))) + if err != nil { + return + } + return c.ExtendedConn.Write(p) +} + +func (c *serverPacketConn) ReadPacket(buffer *buf.Buffer) (destination M.Socksaddr, err error) { + var packetLen uint16 + err = binary.Read(c.ExtendedConn, binary.BigEndian, &packetLen) + if err != nil { + return + } + + _, err = buffer.ReadFullFrom(c.ExtendedConn, int(packetLen)) + if err != nil { + return + } + + destination = c.destination + return +} + +func (c *serverPacketConn) WritePacket(buffer *buf.Buffer, destination M.Socksaddr) error { + packetLen := buffer.Len() + binary.BigEndian.PutUint16(buffer.ExtendHeader(2), uint16(packetLen)) + return c.ExtendedConn.WriteBuffer(buffer) +} + +func (c *serverPacketConn) FrontHeadroom() int { + return 2 +} + +func (c *serverPacketConn) NeedAdditionalReadDeadline() bool { + return true +} + +func (c *serverPacketConn) Upstream() any { + return c.ExtendedConn +} diff --git a/clash-meta/transport/vless/addons.go b/clash-meta/transport/vless/addons.go new file mode 100644 index 0000000000..2257adeb9f --- /dev/null +++ b/clash-meta/transport/vless/addons.go @@ -0,0 +1,61 @@ +package vless + +import ( + "bytes" + "encoding/binary" + "fmt" + "io" +) + +func ReadAddons(data []byte) (*Addons, error) { + reader := bytes.NewReader(data) + var addons Addons + for reader.Len() > 0 { + protoHeader, err := reader.ReadByte() + if err != nil { + return nil, err + } + switch protoHeader { + case (1 << 3) | 2: + flowLen, err := binary.ReadUvarint(reader) + if err != nil { + return nil, err + } + flowBytes := make([]byte, flowLen) + _, err = io.ReadFull(reader, flowBytes) + if err != nil { + return nil, err + } + addons.Flow = string(flowBytes) + case (2 << 3) | 2: + seedLen, err := binary.ReadUvarint(reader) + if err != nil { + return nil, err + } + seedBytes := make([]byte, seedLen) + _, err = io.ReadFull(reader, seedBytes) + if err != nil { + return nil, err + } + addons.Seed = seedBytes + default: + return nil, fmt.Errorf("unknown protobuf message header: %v", protoHeader) + } + } + return &addons, nil +} + +func WriteAddons(addons *Addons) []byte { + var writer bytes.Buffer + if len(addons.Flow) > 0 { + writer.WriteByte((1 << 3) | 2) + writer.Write(binary.AppendUvarint(nil, uint64(len(addons.Flow)))) + writer.WriteString(addons.Flow) + } + if len(addons.Seed) > 0 { + writer.WriteByte((2 << 3) | 2) + writer.Write(binary.AppendUvarint(nil, uint64(len(addons.Seed)))) + writer.Write(addons.Seed) + } + return writer.Bytes() +} diff --git a/clash-meta/transport/vless/addons_test.go b/clash-meta/transport/vless/addons_test.go new file mode 100644 index 0000000000..60a27a069a --- /dev/null +++ b/clash-meta/transport/vless/addons_test.go @@ -0,0 +1,95 @@ +package vless + +import ( + "bytes" + "strconv" + "testing" + + "google.golang.org/protobuf/proto" +) + +func TestAddons(t *testing.T) { + var tests = []struct { + flow string + seed []byte + }{ + {XRV, nil}, + {XRS, []byte{1, 2, 3}}, + {"", []byte{1, 2, 3}}, + {"", nil}, + } + + for i, test := range tests { + t.Run(strconv.Itoa(i), func(t *testing.T) { + t.Run("proto->handwritten", func(t *testing.T) { + addons := new(Addons) + addons.Flow = test.flow + addons.Seed = test.seed + + addonsBytes, err := proto.Marshal(addons) + if err != nil { + t.Errorf("error marshalling addons: %v", err) + return + } + addons, err = ReadAddons(addonsBytes) + if err != nil { + t.Errorf("error reading addons: %v", err) + return + } + + if addons.Flow != test.flow { + t.Errorf("got %v; want %v", addons.Flow, test.flow) + return + } + if !bytes.Equal(addons.Seed, test.seed) { + t.Errorf("got %v; want %v", addons.Seed, test.seed) + return + } + }) + + t.Run("handwritten->proto", func(t *testing.T) { + addons := new(Addons) + addons.Flow = test.flow + addons.Seed = test.seed + + addonsBytes := WriteAddons(addons) + err := proto.Unmarshal(addonsBytes, addons) + if err != nil { + t.Errorf("error reading addons: %v", err) + return + } + + if addons.Flow != test.flow { + t.Errorf("got %v; want %v", addons.Flow, test.flow) + return + } + if !bytes.Equal(addons.Seed, test.seed) { + t.Errorf("got %v; want %v", addons.Seed, test.seed) + return + } + }) + + t.Run("handwritten->handwritten", func(t *testing.T) { + addons := new(Addons) + addons.Flow = test.flow + addons.Seed = test.seed + + addonsBytes := WriteAddons(addons) + addons, err := ReadAddons(addonsBytes) + if err != nil { + t.Errorf("error reading addons: %v", err) + return + } + + if addons.Flow != test.flow { + t.Errorf("got %v; want %v", addons.Flow, test.flow) + return + } + if !bytes.Equal(addons.Seed, test.seed) { + t.Errorf("got %v; want %v", addons.Seed, test.seed) + return + } + }) + }) + } +} diff --git a/clash-meta/transport/vless/conn.go b/clash-meta/transport/vless/conn.go index 94ae71eee0..f43d77e180 100644 --- a/clash-meta/transport/vless/conn.go +++ b/clash-meta/transport/vless/conn.go @@ -5,7 +5,6 @@ import ( "errors" "io" "net" - "sync" "github.com/metacubex/mihomo/common/buf" N "github.com/metacubex/mihomo/common/net" @@ -16,17 +15,12 @@ import ( ) type Conn struct { - N.ExtendedWriter - N.ExtendedReader - net.Conn + N.ExtendedConn dst *DstAddr - id *uuid.UUID + id uuid.UUID addons *Addons received bool - - handshakeMutex sync.Mutex - needHandshake bool - err error + sent bool } func (vc *Conn) Read(b []byte) (int, error) { @@ -36,7 +30,7 @@ func (vc *Conn) Read(b []byte) (int, error) { } vc.received = true } - return vc.ExtendedReader.Read(b) + return vc.ExtendedConn.Read(b) } func (vc *Conn) ReadBuffer(buffer *buf.Buffer) error { @@ -46,58 +40,39 @@ func (vc *Conn) ReadBuffer(buffer *buf.Buffer) error { } vc.received = true } - return vc.ExtendedReader.ReadBuffer(buffer) + return vc.ExtendedConn.ReadBuffer(buffer) } func (vc *Conn) Write(p []byte) (int, error) { - if vc.needHandshake { - vc.handshakeMutex.Lock() - if vc.needHandshake { - vc.needHandshake = false - if vc.sendRequest(p) { - vc.handshakeMutex.Unlock() - if vc.err != nil { - return 0, vc.err - } - return len(p), vc.err - } - if vc.err != nil { - vc.handshakeMutex.Unlock() - return 0, vc.err - } + if !vc.sent { + if err := vc.sendRequest(p); err != nil { + return 0, err } - vc.handshakeMutex.Unlock() + vc.sent = true + return len(p), nil } - return vc.ExtendedWriter.Write(p) + return vc.ExtendedConn.Write(p) } func (vc *Conn) WriteBuffer(buffer *buf.Buffer) error { - if vc.needHandshake { - vc.handshakeMutex.Lock() - if vc.needHandshake { - vc.needHandshake = false - if vc.sendRequest(buffer.Bytes()) { - vc.handshakeMutex.Unlock() - return vc.err - } - if vc.err != nil { - vc.handshakeMutex.Unlock() - return vc.err - } + if !vc.sent { + if err := vc.sendRequest(buffer.Bytes()); err != nil { + return err } - vc.handshakeMutex.Unlock() + vc.sent = true + return nil } - return vc.ExtendedWriter.WriteBuffer(buffer) + return vc.ExtendedConn.WriteBuffer(buffer) } -func (vc *Conn) sendRequest(p []byte) bool { +func (vc *Conn) sendRequest(p []byte) (err error) { var addonsBytes []byte if vc.addons != nil { - addonsBytes, vc.err = proto.Marshal(vc.addons) - if vc.err != nil { - return true + addonsBytes, err = proto.Marshal(vc.addons) + if err != nil { + return } } @@ -141,15 +116,15 @@ func (vc *Conn) sendRequest(p []byte) bool { buf.Must(buf.Error(buffer.Write(p))) - _, vc.err = vc.ExtendedWriter.Write(buffer.Bytes()) - return true + _, err = vc.ExtendedConn.Write(buffer.Bytes()) + return } -func (vc *Conn) recvResponse() error { +func (vc *Conn) recvResponse() (err error) { var buffer [2]byte - _, vc.err = io.ReadFull(vc.ExtendedReader, buffer[:]) - if vc.err != nil { - return vc.err + _, err = io.ReadFull(vc.ExtendedConn, buffer[:]) + if err != nil { + return err } if buffer[0] != Version { @@ -158,29 +133,35 @@ func (vc *Conn) recvResponse() error { length := int64(buffer[1]) if length != 0 { // addon data length > 0 - io.CopyN(io.Discard, vc.ExtendedReader, length) // just discard + io.CopyN(io.Discard, vc.ExtendedConn, length) // just discard } - return nil + return } func (vc *Conn) Upstream() any { - return vc.Conn + return vc.ExtendedConn +} + +func (vc *Conn) ReaderReplaceable() bool { + return vc.received +} + +func (vc *Conn) WriterReplaceable() bool { + return vc.sent } func (vc *Conn) NeedHandshake() bool { - return vc.needHandshake + return !vc.sent } // newConn return a Conn instance func newConn(conn net.Conn, client *Client, dst *DstAddr) (net.Conn, error) { c := &Conn{ - ExtendedReader: N.NewExtendedReader(conn), - ExtendedWriter: N.NewExtendedWriter(conn), - Conn: conn, - id: client.uuid, - dst: dst, - needHandshake: true, + ExtendedConn: N.NewExtendedConn(conn), + id: client.uuid, + addons: client.Addons, + dst: dst, } if client.Addons != nil { @@ -190,7 +171,6 @@ func newConn(conn net.Conn, client *Client, dst *DstAddr) (net.Conn, error) { if err != nil { return nil, err } - c.addons = client.Addons return visionConn, nil } } diff --git a/clash-meta/transport/vless/vision/conn.go b/clash-meta/transport/vless/vision/conn.go index 7e778cf84c..fd9f787b50 100644 --- a/clash-meta/transport/vless/vision/conn.go +++ b/clash-meta/transport/vless/vision/conn.go @@ -2,7 +2,6 @@ package vision import ( "bytes" - "crypto/subtle" "encoding/binary" "errors" "fmt" @@ -24,15 +23,13 @@ type Conn struct { net.Conn // should be *vless.Conn N.ExtendedReader N.ExtendedWriter - userUUID *uuid.UUID + userUUID uuid.UUID - // tlsConn and it's internal variables - tlsConn net.Conn // maybe [*tls.Conn] or other tls-like conn + // [*tls.Conn] or other tls-like [net.Conn]'s internal variables netConn net.Conn // tlsConn.NetConn() input *bytes.Reader // &tlsConn.input or nil rawInput *bytes.Buffer // &tlsConn.rawInput or nil - needHandshake bool packetsToFilter int isTLS bool isTLS12orAbove bool @@ -46,6 +43,7 @@ type Conn struct { readLastCommand byte writeFilterApplicationData bool writeDirect bool + writeOnceUserUUID []byte } func (vc *Conn) Read(b []byte) (int, error) { @@ -58,8 +56,8 @@ func (vc *Conn) Read(b []byte) (int, error) { } func (vc *Conn) ReadBuffer(buffer *buf.Buffer) error { - toRead := buffer.FreeBytes() if vc.readRemainingContent > 0 { + toRead := buffer.FreeBytes() if vc.readRemainingContent < buffer.FreeLen() { toRead = toRead[:vc.readRemainingContent] } @@ -80,12 +78,12 @@ func (vc *Conn) ReadBuffer(buffer *buf.Buffer) error { switch vc.readLastCommand { case commandPaddingContinue: //if vc.isTLS || vc.packetsToFilter > 0 { - headerUUIDLen := 0 - if vc.readFilterUUID { - headerUUIDLen = uuid.Size + need := PaddingHeaderLen + if !vc.readFilterUUID { + need = PaddingHeaderLen - uuid.Size } var header []byte - if need := headerUUIDLen + PaddingHeaderLen - uuid.Size; buffer.FreeLen() < need { + if buffer.FreeLen() < need { header = make([]byte, need) } else { header = buffer.FreeBytes()[:need] @@ -96,9 +94,8 @@ func (vc *Conn) ReadBuffer(buffer *buf.Buffer) error { } if vc.readFilterUUID { vc.readFilterUUID = false - if subtle.ConstantTimeCompare(vc.userUUID.Bytes(), header[:uuid.Size]) != 1 { - err = fmt.Errorf("XTLS Vision server responded unknown UUID: %s", - uuid.FromBytesOrNil(header[:uuid.Size]).String()) + if !bytes.Equal(vc.userUUID.Bytes(), header[:uuid.Size]) { + err = fmt.Errorf("XTLS Vision server responded unknown UUID: %s", uuid.FromBytesOrNil(header[:uuid.Size])) log.Errorln(err.Error()) return err } @@ -169,36 +166,19 @@ func (vc *Conn) Write(p []byte) (int, error) { } func (vc *Conn) WriteBuffer(buffer *buf.Buffer) (err error) { - if vc.needHandshake { - vc.needHandshake = false - if buffer.IsEmpty() { - ApplyPadding(buffer, commandPaddingContinue, vc.userUUID, true) // we do a long padding to hide vless header - } else { - vc.FilterTLS(buffer.Bytes()) - ApplyPadding(buffer, commandPaddingContinue, vc.userUUID, vc.isTLS) - } - err = vc.ExtendedWriter.WriteBuffer(buffer) - if err != nil { - buffer.Release() - return err - } - err = vc.checkTLSVersion() - if err != nil { - buffer.Release() - return err - } - vc.tlsConn = nil - return nil - } - if vc.writeFilterApplicationData { + if buffer.IsEmpty() { + ApplyPadding(buffer, commandPaddingContinue, &vc.writeOnceUserUUID, true) // we do a long padding to hide vless header + return vc.ExtendedWriter.WriteBuffer(buffer) + } + vc.FilterTLS(buffer.Bytes()) buffers := vc.ReshapeBuffer(buffer) applyPadding := true for i, buffer := range buffers { command := commandPaddingContinue if applyPadding { - if vc.isTLS && buffer.Len() > 6 && bytes.Equal(buffer.To(3), tlsApplicationDataStart) { + if vc.isTLS && buffer.Len() > 6 && bytes.Equal(tlsApplicationDataStart, buffer.To(3)) { command = commandPaddingEnd if vc.enableXTLS { command = commandPaddingDirect @@ -211,7 +191,7 @@ func (vc *Conn) WriteBuffer(buffer *buf.Buffer) (err error) { vc.writeFilterApplicationData = false applyPadding = false } - ApplyPadding(buffer, command, nil, vc.isTLS) + ApplyPadding(buffer, command, &vc.writeOnceUserUUID, vc.isTLS) } err = vc.ExtendedWriter.WriteBuffer(buffer) @@ -234,7 +214,7 @@ func (vc *Conn) WriteBuffer(buffer *buf.Buffer) (err error) { } func (vc *Conn) FrontHeadroom() int { - if vc.readFilterUUID { + if vc.readFilterUUID || vc.writeOnceUserUUID != nil { return PaddingHeaderLen } return PaddingHeaderLen - uuid.Size @@ -245,7 +225,7 @@ func (vc *Conn) RearHeadroom() int { } func (vc *Conn) NeedHandshake() bool { - return vc.needHandshake + return vc.writeOnceUserUUID != nil } func (vc *Conn) Upstream() any { diff --git a/clash-meta/transport/vless/vision/padding.go b/clash-meta/transport/vless/vision/padding.go index 710f64c217..386095528d 100644 --- a/clash-meta/transport/vless/vision/padding.go +++ b/clash-meta/transport/vless/vision/padding.go @@ -5,8 +5,8 @@ import ( "encoding/binary" "github.com/metacubex/mihomo/common/buf" + N "github.com/metacubex/mihomo/common/net" "github.com/metacubex/mihomo/log" - N "github.com/metacubex/sing/common/network" "github.com/gofrs/uuid/v5" "github.com/metacubex/randv2" @@ -20,7 +20,7 @@ const ( commandPaddingDirect byte = 0x02 ) -func ApplyPadding(buffer *buf.Buffer, command byte, userUUID *uuid.UUID, paddingTLS bool) { +func ApplyPadding(buffer *buf.Buffer, command byte, userUUID *[]byte, paddingTLS bool) { contentLen := int32(buffer.Len()) var paddingLen int32 if contentLen < 900 { @@ -35,8 +35,9 @@ func ApplyPadding(buffer *buf.Buffer, command byte, userUUID *uuid.UUID, padding binary.BigEndian.PutUint16(buffer.ExtendHeader(2), uint16(paddingLen)) binary.BigEndian.PutUint16(buffer.ExtendHeader(2), uint16(contentLen)) buffer.ExtendHeader(1)[0] = command - if userUUID != nil { - copy(buffer.ExtendHeader(uuid.Size), userUUID.Bytes()) + if userUUID != nil && *userUUID != nil { + copy(buffer.ExtendHeader(uuid.Size), *userUUID) + *userUUID = nil } buffer.Extend(int(paddingLen)) diff --git a/clash-meta/transport/vless/vision/vision.go b/clash-meta/transport/vless/vision/vision.go index f9158ca4e3..e785c6ad78 100644 --- a/clash-meta/transport/vless/vision/vision.go +++ b/clash-meta/transport/vless/vision/vision.go @@ -12,53 +12,87 @@ import ( N "github.com/metacubex/mihomo/common/net" tlsC "github.com/metacubex/mihomo/component/tls" + "github.com/metacubex/mihomo/log" "github.com/metacubex/mihomo/transport/vless/encryption" "github.com/gofrs/uuid/v5" ) +var ErrNotHandshakeComplete = errors.New("tls connection not handshake complete") var ErrNotTLS13 = errors.New("XTLS Vision based on TLS 1.3 outer connection") -func NewConn(conn net.Conn, tlsConn net.Conn, userUUID *uuid.UUID) (*Conn, error) { +func NewConn(conn net.Conn, tlsConn net.Conn, userUUID uuid.UUID) (*Conn, error) { c := &Conn{ ExtendedReader: N.NewExtendedReader(conn), ExtendedWriter: N.NewExtendedWriter(conn), Conn: conn, userUUID: userUUID, - tlsConn: tlsConn, packetsToFilter: 6, - needHandshake: true, readProcess: true, readFilterUUID: true, writeFilterApplicationData: true, + writeOnceUserUUID: userUUID.Bytes(), } var t reflect.Type var p unsafe.Pointer - switch underlying := tlsConn.(type) { - case *gotls.Conn: - //log.Debugln("type tls") - c.netConn = underlying.NetConn() - t = reflect.TypeOf(underlying).Elem() - p = unsafe.Pointer(underlying) - case *tlsC.Conn: - //log.Debugln("type *tlsC.Conn") - c.netConn = underlying.NetConn() - t = reflect.TypeOf(underlying).Elem() - p = unsafe.Pointer(underlying) - case *tlsC.UConn: - //log.Debugln("type *tlsC.UConn") - c.netConn = underlying.NetConn() - t = reflect.TypeOf(underlying.Conn).Elem() - //log.Debugln("t:%v", t) - p = unsafe.Pointer(underlying.Conn) - case *encryption.CommonConn: - //log.Debugln("type *encryption.CommonConn") - c.netConn = underlying.Conn - t = reflect.TypeOf(underlying).Elem() - p = unsafe.Pointer(underlying) - default: + var upstream any = tlsConn + for { + switch underlying := upstream.(type) { + case *gotls.Conn: + //log.Debugln("type tls") + tlsConn = underlying + c.netConn = underlying.NetConn() + t = reflect.TypeOf(underlying).Elem() + p = unsafe.Pointer(underlying) + break + case *tlsC.Conn: + //log.Debugln("type *tlsC.Conn") + tlsConn = underlying + c.netConn = underlying.NetConn() + t = reflect.TypeOf(underlying).Elem() + p = unsafe.Pointer(underlying) + break + case *tlsC.UConn: + //log.Debugln("type *tlsC.UConn") + tlsConn = underlying + c.netConn = underlying.NetConn() + t = reflect.TypeOf(underlying.Conn).Elem() + //log.Debugln("t:%v", t) + p = unsafe.Pointer(underlying.Conn) + break + case *encryption.CommonConn: + //log.Debugln("type *encryption.CommonConn") + tlsConn = underlying + c.netConn = underlying.Conn + t = reflect.TypeOf(underlying).Elem() + p = unsafe.Pointer(underlying) + break + } + if u, ok := upstream.(N.ReaderWithUpstream); !ok || !u.ReaderReplaceable() { // must replaceable + break + } + if u, ok := upstream.(N.WithUpstreamReader); ok { + upstream = u.UpstreamReader() + continue + } + if u, ok := upstream.(N.WithUpstream); ok { + upstream = u.Upstream() + continue + } + } + if t == nil || p == nil { + log.Warnln("vision: not a valid supported TLS connection: %s", reflect.TypeOf(tlsConn)) return nil, fmt.Errorf(`failed to use vision, maybe "security" is not "tls" or "utls"`) } + + if err := checkTLSVersion(tlsConn); err != nil { + if errors.Is(err, ErrNotHandshakeComplete) { + log.Warnln("vision: TLS connection not handshake complete: %s", reflect.TypeOf(tlsConn)) + } else { + return nil, err + } + } + if i, ok := t.FieldByName("input"); ok { c.input = (*bytes.Reader)(unsafe.Add(p, i.Offset)) } @@ -68,18 +102,30 @@ func NewConn(conn net.Conn, tlsConn net.Conn, userUUID *uuid.UUID) (*Conn, error return c, nil } -func (vc *Conn) checkTLSVersion() error { - switch underlying := vc.tlsConn.(type) { +func checkTLSVersion(tlsConn net.Conn) error { + switch underlying := tlsConn.(type) { case *gotls.Conn: - if underlying.ConnectionState().Version != gotls.VersionTLS13 { + state := underlying.ConnectionState() + if !state.HandshakeComplete { + return ErrNotHandshakeComplete + } + if state.Version != gotls.VersionTLS13 { return ErrNotTLS13 } case *tlsC.Conn: - if underlying.ConnectionState().Version != tlsC.VersionTLS13 { + state := underlying.ConnectionState() + if !state.HandshakeComplete { + return ErrNotHandshakeComplete + } + if state.Version != tlsC.VersionTLS13 { return ErrNotTLS13 } case *tlsC.UConn: - if underlying.ConnectionState().Version != tlsC.VersionTLS13 { + state := underlying.ConnectionState() + if !state.HandshakeComplete { + return ErrNotHandshakeComplete + } + if state.Version != tlsC.VersionTLS13 { return ErrNotTLS13 } } diff --git a/clash-meta/transport/vless/vless.go b/clash-meta/transport/vless/vless.go index 9fb54f9205..4e99b9ba68 100644 --- a/clash-meta/transport/vless/vless.go +++ b/clash-meta/transport/vless/vless.go @@ -42,7 +42,7 @@ type DstAddr struct { // Client is vless connection generator type Client struct { - uuid *uuid.UUID + uuid uuid.UUID Addons *Addons } @@ -63,7 +63,7 @@ func NewClient(uuidStr string, addons *Addons) (*Client, error) { } return &Client{ - uuid: &uid, + uuid: uid, Addons: addons, }, nil } diff --git a/clash-nyanpasu/backend/Cargo.lock b/clash-nyanpasu/backend/Cargo.lock index f4a9dbeaa6..026c41a310 100644 --- a/clash-nyanpasu/backend/Cargo.lock +++ b/clash-nyanpasu/backend/Cargo.lock @@ -237,12 +237,6 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc7eb209b1518d6bb87b283c20095f5228ecda460da70b44f0802523dea6da04" -[[package]] -name = "android-tzdata" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" - [[package]] name = "android_system_properties" version = "0.1.5" @@ -858,7 +852,7 @@ dependencies = [ "bitflags 2.9.4", "cexpr", "clang-sys", - "itertools 0.11.0", + "itertools 0.12.1", "lazy_static", "lazycell", "log", @@ -1347,9 +1341,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.35" +version = "1.2.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "590f9024a68a8c40351881787f1934dc11afd69090f5edb6831464694d836ea3" +checksum = "5252b3d2648e5eedbc1a6f501e3c795e07025c1e93bbf8bbdd6eef7f447a6d54" dependencies = [ "find-msvc-tools", "jobserver", @@ -1416,17 +1410,16 @@ dependencies = [ [[package]] name = "chrono" -version = "0.4.41" +version = "0.4.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c469d952047f47f91b68d1cba3f10d63c11d73e4636f24f08daf0278abf01c4d" +checksum = "145052bdd345b87320e369255277e3fb5152762ad123a901ef5c262dd38fe8d2" dependencies = [ - "android-tzdata", "iana-time-zone", "js-sys", "num-traits", "serde", "wasm-bindgen", - "windows-link", + "windows-link 0.2.0", ] [[package]] @@ -2008,12 +2001,13 @@ dependencies = [ [[package]] name = "ctrlc" -version = "3.4.7" +version = "3.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46f93780a459b7d656ef7f071fe699c4d3d2cb201c4b24d085b6ddc505276e73" +checksum = "881c5d0a13b2f1498e2306e82cbada78390e152d4b1378fb28a84f4dcd0dc4f3" dependencies = [ + "dispatch", "nix 0.30.1", - "windows-sys 0.59.0", + "windows-sys 0.61.0", ] [[package]] @@ -2283,13 +2277,13 @@ dependencies = [ "libc", "option-ext", "redox_users 0.5.2", - "windows-sys 0.60.2", + "windows-sys 0.61.0", ] [[package]] name = "dirs-utils" version = "0.1.0" -source = "git+https://github.com/libnyanpasu/nyanpasu-utils.git#276e9f2d797230ab3f0d8a181c8a9f2d1fb12730" +source = "git+https://github.com/libnyanpasu/nyanpasu-utils.git#4165ebfecccc5606f4a1abc0bbe847cd018123dd" dependencies = [ "dirs 6.0.0", "thiserror 2.0.16", @@ -2444,9 +2438,9 @@ checksum = "d0881ea181b1df73ff77ffaaf9c7544ecc11e82fba9b5f27b262a3c73a332555" [[package]] name = "ecolor" -version = "0.32.1" +version = "0.32.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6a7fc3172c2ef56966b2ce4f84177e159804c40b9a84de8861558ce4a59f422" +checksum = "ebb57dec02e4cca6d70d02e29865f7e52dbd471383f4c3444dda7ee78d467360" dependencies = [ "bytemuck", "emath", @@ -2454,9 +2448,9 @@ dependencies = [ [[package]] name = "eframe" -version = "0.32.1" +version = "0.32.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34037a80dc03a4147e1684bff4e4fdab2b1408d715d7b78470cd3179258964b9" +checksum = "990e96866be6346eff496e4f450616f2a00e462742ad64d955454842dd7aa006" dependencies = [ "ahash", "bytemuck", @@ -2490,9 +2484,9 @@ dependencies = [ [[package]] name = "egui" -version = "0.32.1" +version = "0.32.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49e2be082f77715496b4a39fdc6f5dc7491fefe2833111781b8697ea6ee919a7" +checksum = "40df1115b8b0f3d4f1f9134a26287fd3d0e067fc18f879b8c9641aedf3eecef7" dependencies = [ "accesskit", "ahash", @@ -2508,9 +2502,9 @@ dependencies = [ [[package]] name = "egui-wgpu" -version = "0.32.1" +version = "0.32.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64c7277a171ec1b711080ddb3b0bfa1b3aa9358834d5386d39e83fbc16d61212" +checksum = "80b8ac3f985e46f485daa9c2c357311ac0d13098e08630ec55f3a6ad95192717" dependencies = [ "ahash", "bytemuck", @@ -2528,9 +2522,9 @@ dependencies = [ [[package]] name = "egui-winit" -version = "0.32.1" +version = "0.32.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe6d8b0f8d6de4d43e794e343f03bacc3908aada931f0ed6fd7041871388a590" +checksum = "1abd8326d2be6d0e945dcfe8acd2c07d64be4c977c5e1115f902dc9cd3ff7bf5" dependencies = [ "accesskit_winit", "ahash", @@ -2548,9 +2542,9 @@ dependencies = [ [[package]] name = "egui_extras" -version = "0.32.1" +version = "0.32.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ae8f23013328beb6be7ab29c75807142e8e1c7951643780a813e54cceaa9929" +checksum = "170cac579b8a89dbf128e704afc0aa5c7283c4c462483d07d3564c8070c2a99f" dependencies = [ "ahash", "egui", @@ -2565,9 +2559,9 @@ dependencies = [ [[package]] name = "egui_glow" -version = "0.32.1" +version = "0.32.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ab645760288e42eab70283a5cccf44509a6f43b554351855d3c73594bfe3c23" +checksum = "7baca67871a8b808e2eb0849282f56149673b6842702306860916bf2dd83fca1" dependencies = [ "ahash", "bytemuck", @@ -2603,9 +2597,9 @@ checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" [[package]] name = "emath" -version = "0.32.1" +version = "0.32.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "935df67dc48fdeef132f2f7ada156ddc79e021344dd42c17f066b956bb88dde3" +checksum = "b5c95b6d5571099bfa0ae9f4fdaef2c239bccb01d55339a082070259dc6f3b05" dependencies = [ "bytemuck", ] @@ -2727,9 +2721,9 @@ dependencies = [ [[package]] name = "epaint" -version = "0.32.1" +version = "0.32.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b66fc0a5a9d322917de9bd3ac7d426ca8aa3127fbf1e76fae5b6b25e051e06a3" +checksum = "695fd7b458f31fe515d6a308f46b2936cae9316dc40c960a7ee31ce3a97866b9" dependencies = [ "ab_glyph", "ahash", @@ -2745,9 +2739,9 @@ dependencies = [ [[package]] name = "epaint_default_fonts" -version = "0.32.1" +version = "0.32.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f6cf8ce0fb817000aa24f5e630bda904a353536bd430b83ebc1dceee95b4a3a" +checksum = "bbc9f86ce3eaf9b7fc7179a578af21a6a5cd2d4fd21965564e82a2d009a7dab0" [[package]] name = "equator" @@ -2943,9 +2937,9 @@ dependencies = [ [[package]] name = "find-msvc-tools" -version = "0.1.0" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e178e4fba8a2726903f6ba98a6d221e76f9c12c650d5dc0e6afdc50677b49650" +checksum = "7fd99930f64d146689264c637b5af2f0233a933bef0d8570e2526bf9e083192d" [[package]] name = "fixedbitset" @@ -3387,7 +3381,7 @@ dependencies = [ "js-sys", "libc", "r-efi", - "wasi 0.14.3+wasi-0.2.4", + "wasi 0.14.4+wasi-0.2.4", "wasm-bindgen", ] @@ -3835,6 +3829,15 @@ dependencies = [ "foldhash", ] +[[package]] +name = "hashbrown" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5419bdc4f6a9207fbeba6d11b604d481addf78ecd10c11ad51e76c2f6482748d" +dependencies = [ + "allocator-api2", +] + [[package]] name = "heapless" version = "0.7.17" @@ -4672,9 +4675,9 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.77" +version = "0.3.78" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" +checksum = "0c0b063578492ceec17683ef2f8c5e89121fbd0b172cbc280635ab7567db2738" dependencies = [ "once_cell", "wasm-bindgen", @@ -4800,9 +4803,9 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" [[package]] name = "lebe" -version = "0.5.2" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03087c2bad5e1034e8cace5926dec053fb3790248370865f5117a7d0213354c8" +checksum = "7a79a3332a6609480d7d0c9eab957bca6b455b91bb84e66d19f5ff66294b85b8" [[package]] name = "libappindicator" @@ -5360,7 +5363,7 @@ dependencies = [ [[package]] name = "network-utils" version = "0.1.0" -source = "git+https://github.com/libnyanpasu/nyanpasu-utils.git#276e9f2d797230ab3f0d8a181c8a9f2d1fb12730" +source = "git+https://github.com/libnyanpasu/nyanpasu-utils.git#4165ebfecccc5606f4a1abc0bbe847cd018123dd" dependencies = [ "log", "tempfile", @@ -5679,7 +5682,7 @@ dependencies = [ [[package]] name = "nyanpasu-ipc" version = "1.4.1" -source = "git+https://github.com/libnyanpasu/nyanpasu-service.git#1968d9734f9b78f0df668f6f4e624e8fdbf8a84f" +source = "git+https://github.com/libnyanpasu/nyanpasu-service.git#8f2eada8c8625a6453bdb7a6e617455cf04d857d" dependencies = [ "anyhow", "axum", @@ -5717,7 +5720,7 @@ dependencies = [ [[package]] name = "nyanpasu-utils" version = "0.1.0" -source = "git+https://github.com/libnyanpasu/nyanpasu-utils.git#276e9f2d797230ab3f0d8a181c8a9f2d1fb12730" +source = "git+https://github.com/libnyanpasu/nyanpasu-utils.git#4165ebfecccc5606f4a1abc0bbe847cd018123dd" dependencies = [ "camino", "constcat", @@ -6259,7 +6262,7 @@ dependencies = [ [[package]] name = "os-utils" version = "0.1.0" -source = "git+https://github.com/libnyanpasu/nyanpasu-utils.git#276e9f2d797230ab3f0d8a181c8a9f2d1fb12730" +source = "git+https://github.com/libnyanpasu/nyanpasu-utils.git#4165ebfecccc5606f4a1abc0bbe847cd018123dd" dependencies = [ "nix 0.30.1", "shared_child", @@ -6344,27 +6347,28 @@ dependencies = [ [[package]] name = "oxc_allocator" -version = "0.82.3" +version = "0.87.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e887a8496b18a4bce4a760ae2dbd50e5137fa2a27ee99087797d7b8e860a7b5c" +checksum = "90237f36cf0cd3ea2dcf9682b48fa0c1762a4b407fdcc630f60a72c277877c9f" dependencies = [ "allocator-api2", "bumpalo", - "hashbrown 0.15.5", + "hashbrown 0.16.0", "oxc_data_structures", "rustc-hash 2.1.1", ] [[package]] name = "oxc_ast" -version = "0.82.3" +version = "0.87.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "931e1fae25d9669204681577381f6e90d2c9fe502d306c862f46ff72bcef8cf7" +checksum = "a73ff824d44e51ac6c20381b644d48db4326935e811eeab29d52ca45e4d19670" dependencies = [ "bitflags 2.9.4", "oxc_allocator", "oxc_ast_macros", "oxc_data_structures", + "oxc_diagnostics", "oxc_estree", "oxc_regular_expression", "oxc_span", @@ -6373,11 +6377,11 @@ dependencies = [ [[package]] name = "oxc_ast_macros" -version = "0.82.3" +version = "0.87.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5958a8ac69a955048dabcfcbf8af791dbb7f598bbea5bae33243240f3846457c" +checksum = "4f6af164ffae11248f32c449dad6a15f85d2154fe398bfec75502e0e2af5767a" dependencies = [ - "phf 0.12.1", + "phf 0.13.1", "proc-macro2", "quote", "syn 2.0.106", @@ -6385,9 +6389,9 @@ dependencies = [ [[package]] name = "oxc_ast_visit" -version = "0.82.3" +version = "0.87.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95d2ce2cb5be550d7a94fc3b927d4247d69aea57943baafbf6547362831e69a5" +checksum = "a0ff52052e2cfb72fff062d4b7a393f9e9bded601dc16df796e3e460e17a9031" dependencies = [ "oxc_allocator", "oxc_ast", @@ -6397,15 +6401,15 @@ dependencies = [ [[package]] name = "oxc_data_structures" -version = "0.82.3" +version = "0.87.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67b3258dc882e0348934e2a9973cd0d9e3c465642b729842320d23abf835175a" +checksum = "7f048c4ae3569bcc9dbbed29730b5c5f6dd3a35e9f5c3750cd4b3ed72381fbd0" [[package]] name = "oxc_diagnostics" -version = "0.82.3" +version = "0.87.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5dc24fdf0407c9ecb202efb99fa9870f3623994ae8daae56e696a511894d67ba" +checksum = "7d96c95294deec2f038e8c7749a751f929c263da34cc68a621472c57c916c14e" dependencies = [ "cow-utils", "oxc-miette", @@ -6414,9 +6418,9 @@ dependencies = [ [[package]] name = "oxc_ecmascript" -version = "0.82.3" +version = "0.87.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61cfc9801af5b0068e11061ff8100fb38c2ca0875c696aa405b5505d212b5e2f" +checksum = "aa7b86782020722b3190c083dfc3de59cb73425d1fa275ff6f91b5b4ee509550" dependencies = [ "cow-utils", "num-bigint", @@ -6429,9 +6433,9 @@ dependencies = [ [[package]] name = "oxc_estree" -version = "0.82.3" +version = "0.87.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bac265e2cd8c77ac8d4230f1538e8ff9f6f5d9e41b9107af58f8d3c4626b028" +checksum = "97f7078ef0c6da21657f5dcade4540c65a460d2a26a42e4418d12ecac860143a" [[package]] name = "oxc_index" @@ -6441,9 +6445,9 @@ checksum = "2fa07b0cfa997730afed43705766ef27792873fdf5215b1391949fec678d2392" [[package]] name = "oxc_parser" -version = "0.82.3" +version = "0.87.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b4427e7c4d4507bb4561c113e25bbbb737d03355f311d3fb606f0029fdcb3f6" +checksum = "ef71ea1e9bde8ff15f89b60874363359fc7e9796de7bf6cdff69fa54f6869bba" dependencies = [ "bitflags 2.9.4", "cow-utils", @@ -6464,25 +6468,25 @@ dependencies = [ [[package]] name = "oxc_regular_expression" -version = "0.82.3" +version = "0.87.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17ec07cb1081ed5798e2ef7d3e10154784cd1bf47c5170ff3d519d44bc97ad07" +checksum = "60a4df17b1c47c7fe749208f3a32158dfe90dca5ce630ce86cb9415521f87eb3" dependencies = [ "bitflags 2.9.4", "oxc_allocator", "oxc_ast_macros", "oxc_diagnostics", "oxc_span", - "phf 0.12.1", + "phf 0.13.1", "rustc-hash 2.1.1", "unicode-id-start", ] [[package]] name = "oxc_span" -version = "0.82.3" +version = "0.87.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "008d14e804d79adac31c5cb5b27fbfde52055a0cf86276c9b822cfa40b24d75c" +checksum = "7d88265af3fb8fc2a2317144dfc40b5e120e0ebe21693cfbf7508d4d3ec6d74f" dependencies = [ "compact_str", "oxc-miette", @@ -6493,9 +6497,9 @@ dependencies = [ [[package]] name = "oxc_syntax" -version = "0.82.3" +version = "0.87.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "675313926fe94e71b9cdf6ed0338e0bfb40e827e2b5fd0c65a059aff002e7fa2" +checksum = "b2596e7891b08899f7b74a1fb87b5f5c14153918bb2966648c84581f0a7e6795" dependencies = [ "bitflags 2.9.4", "cow-utils", @@ -6507,7 +6511,7 @@ dependencies = [ "oxc_estree", "oxc_index", "oxc_span", - "phf 0.12.1", + "phf 0.13.1", "rustc-hash 2.1.1", "unicode-id-start", ] @@ -6693,12 +6697,12 @@ dependencies = [ [[package]] name = "phf" -version = "0.12.1" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "913273894cec178f401a31ec4b656318d95473527be05c0752cc41cdc32be8b7" +checksum = "c1562dc717473dbaa4c1f85a36410e03c047b2e7df7f45ee938fbef64ae7fadf" dependencies = [ - "phf_macros 0.12.1", - "phf_shared 0.12.1", + "phf_macros 0.13.1", + "phf_shared 0.13.1", "serde", ] @@ -6754,12 +6758,12 @@ dependencies = [ [[package]] name = "phf_generator" -version = "0.12.1" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2cbb1126afed61dd6368748dae63b1ee7dc480191c6262a3b4ff1e29d86a6c5b" +checksum = "135ace3a761e564ec88c03a77317a7c6b80bb7f7135ef2544dbe054243b89737" dependencies = [ "fastrand", - "phf_shared 0.12.1", + "phf_shared 0.13.1", ] [[package]] @@ -6792,12 +6796,12 @@ dependencies = [ [[package]] name = "phf_macros" -version = "0.12.1" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d713258393a82f091ead52047ca779d37e5766226d009de21696c4e667044368" +checksum = "812f032b54b1e759ccd5f8b6677695d5268c588701effba24601f6932f8269ef" dependencies = [ - "phf_generator 0.12.1", - "phf_shared 0.12.1", + "phf_generator 0.13.1", + "phf_shared 0.13.1", "proc-macro2", "quote", "syn 2.0.106", @@ -6833,9 +6837,9 @@ dependencies = [ [[package]] name = "phf_shared" -version = "0.12.1" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06005508882fb681fd97892ecff4b7fd0fee13ef1aa569f8695dae7ab9099981" +checksum = "e57fef6bc5981e38c2ce2d63bfa546861309f875b8a75f092d1d54ae2d64f266" dependencies = [ "siphasher 1.0.1", ] @@ -7123,9 +7127,9 @@ dependencies = [ [[package]] name = "pxfm" -version = "0.1.21" +version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e6bc742f83b3cc07a6ef04dfc0f3598f8af85405b56fc4f0da6adaa1e542fd3" +checksum = "f55f4fedc84ed39cb7a489322318976425e42a147e2be79d8f878e2884f94e84" dependencies = [ "num-traits", ] @@ -7968,9 +7972,9 @@ checksum = "1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b" [[package]] name = "security-framework-sys" -version = "2.14.0" +version = "2.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49db231d56a190491cb4aeda9527f1ad45345af50b0851622a7adb8c03b01c32" +checksum = "cc1f0cbffaac4852523ce30d8bd3c5cdc873501d96ff467ca09b6767bb8cd5c0" dependencies = [ "core-foundation-sys", "libc", @@ -10054,9 +10058,8 @@ dependencies = [ [[package]] name = "tray-icon" -version = "0.21.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0d92153331e7d02ec09137538996a7786fe679c629c279e82a6be762b7e6fe2" +version = "0.21.0" +source = "git+https://github.com/tauri-apps/tray-icon.git?rev=34a3442#34a3442868725d53c042d619f5c60c84dc5072df" dependencies = [ "crossbeam-channel", "dirs 6.0.0", @@ -10537,9 +10540,9 @@ checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" [[package]] name = "wasi" -version = "0.14.3+wasi-0.2.4" +version = "0.14.4+wasi-0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a51ae83037bdd272a9e28ce236db8c07016dd0d50c27038b3f407533c030c95" +checksum = "88a5f4a424faf49c3c2c344f166f0662341d470ea185e939657aaff130f0ec4a" dependencies = [ "wit-bindgen", ] @@ -10552,21 +10555,22 @@ checksum = "b8dad83b4f25e74f184f64c43b150b91efe7647395b42289f38e50566d82855b" [[package]] name = "wasm-bindgen" -version = "0.2.100" +version = "0.2.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" +checksum = "7e14915cadd45b529bb8d1f343c4ed0ac1de926144b746e2710f9cd05df6603b" dependencies = [ "cfg-if", "once_cell", "rustversion", "wasm-bindgen-macro", + "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-backend" -version = "0.2.100" +version = "0.2.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" +checksum = "e28d1ba982ca7923fd01448d5c30c6864d0a14109560296a162f80f305fb93bb" dependencies = [ "bumpalo", "log", @@ -10578,9 +10582,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-futures" -version = "0.4.50" +version = "0.4.51" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "555d470ec0bc3bb57890405e5d4322cc9ea83cebb085523ced7be4144dac1e61" +checksum = "0ca85039a9b469b38336411d6d6ced91f3fc87109a2a27b0c197663f5144dffe" dependencies = [ "cfg-if", "js-sys", @@ -10591,9 +10595,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.100" +version = "0.2.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" +checksum = "7c3d463ae3eff775b0c45df9da45d68837702ac35af998361e2c84e7c5ec1b0d" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -10601,9 +10605,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.100" +version = "0.2.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" +checksum = "7bb4ce89b08211f923caf51d527662b75bdc9c9c7aab40f86dcb9fb85ac552aa" dependencies = [ "proc-macro2", "quote", @@ -10614,9 +10618,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.100" +version = "0.2.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" +checksum = "f143854a3b13752c6950862c906306adb27c7e839f7414cec8fea35beab624c1" dependencies = [ "unicode-ident", ] @@ -10745,9 +10749,9 @@ dependencies = [ [[package]] name = "web-sys" -version = "0.3.77" +version = "0.3.78" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33b6dd2ef9186f1f2072e409e99cd22a975331a6b3591b12c764e0e55c60d5d2" +checksum = "77e4b637749ff0d92b8fad63aa1f7cff3cbe125fd49c175cd6345e7272638b12" dependencies = [ "js-sys", "wasm-bindgen", @@ -11106,11 +11110,11 @@ checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-util" -version = "0.1.10" +version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0978bf7171b3d90bac376700cb56d606feb40f251a475a5d6634613564460b22" +checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" dependencies = [ - "windows-sys 0.60.2", + "windows-sys 0.61.0", ] [[package]] @@ -11173,7 +11177,7 @@ dependencies = [ "windows-collections", "windows-core 0.61.2", "windows-future", - "windows-link", + "windows-link 0.1.3", "windows-numerics", ] @@ -11229,7 +11233,7 @@ checksum = "c0fdd3ddb90610c7638aa2b3a3ab2904fb9e5cdbecc643ddb3647212781c4ae3" dependencies = [ "windows-implement 0.60.0", "windows-interface 0.59.1", - "windows-link", + "windows-link 0.1.3", "windows-result 0.3.4", "windows-strings 0.4.2", ] @@ -11241,7 +11245,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc6a41e98427b19fe4b73c550f060b59fa592d7d686537eebf9385621bfbad8e" dependencies = [ "windows-core 0.61.2", - "windows-link", + "windows-link 0.1.3", "windows-threading", ] @@ -11306,6 +11310,12 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a" +[[package]] +name = "windows-link" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45e46c0661abb7180e7b9c281db115305d49ca1709ab8242adf09666d2173c65" + [[package]] name = "windows-numerics" version = "0.2.0" @@ -11313,7 +11323,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9150af68066c4c5c07ddc0ce30421554771e528bde427614c61038bc2c92c2b1" dependencies = [ "windows-core 0.61.2", - "windows-link", + "windows-link 0.1.3", ] [[package]] @@ -11333,7 +11343,7 @@ version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b8a9ed28765efc97bbc954883f4e6796c33a06546ebafacbabee9696967499e" dependencies = [ - "windows-link", + "windows-link 0.1.3", "windows-result 0.3.4", "windows-strings 0.4.2", ] @@ -11353,7 +11363,7 @@ version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6" dependencies = [ - "windows-link", + "windows-link 0.1.3", ] [[package]] @@ -11381,7 +11391,7 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "87fa48cc5d406560701792be122a10132491cff9d0aeb23583cc2dcafc847319" dependencies = [ - "windows-link", + "windows-link 0.1.3", ] [[package]] @@ -11390,7 +11400,7 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57" dependencies = [ - "windows-link", + "windows-link 0.1.3", ] [[package]] @@ -11438,6 +11448,15 @@ dependencies = [ "windows-targets 0.53.3", ] +[[package]] +name = "windows-sys" +version = "0.61.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e201184e40b2ede64bc2ea34968b28e33622acdbbf37104f0e4a33f7abe657aa" +dependencies = [ + "windows-link 0.2.0", +] + [[package]] name = "windows-targets" version = "0.42.2" @@ -11490,7 +11509,7 @@ version = "0.53.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d5fe6031c4041849d7c496a8ded650796e7b6ecc19df1a431c1a363342e5dc91" dependencies = [ - "windows-link", + "windows-link 0.1.3", "windows_aarch64_gnullvm 0.53.0", "windows_aarch64_msvc 0.53.0", "windows_i686_gnu 0.53.0", @@ -11507,16 +11526,16 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b66463ad2e0ea3bbf808b7f1d371311c80e115c0b71d60efc142cafbcfb057a6" dependencies = [ - "windows-link", + "windows-link 0.1.3", ] [[package]] name = "windows-version" -version = "0.1.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e04a5c6627e310a23ad2358483286c7df260c964eb2d003d8efd6d0f4e79265c" +checksum = "69e061eb0a22b4a1d778ad70f7575ec7845490abb35b08fa320df7895882cacb" dependencies = [ - "windows-link", + "windows-link 0.2.0", ] [[package]] @@ -11797,9 +11816,9 @@ checksum = "d135d17ab770252ad95e9a872d365cf3090e3be864a34ab46f48555993efc904" [[package]] name = "wit-bindgen" -version = "0.45.0" +version = "0.45.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "052283831dbae3d879dc7f51f3d92703a316ca49f91540417d38591826127814" +checksum = "5c573471f125075647d03df72e026074b7203790d41351cd6edc96f46bcccd36" [[package]] name = "wl-clipboard-rs" @@ -12152,18 +12171,18 @@ dependencies = [ [[package]] name = "zerocopy" -version = "0.8.26" +version = "0.8.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1039dd0d3c310cf05de012d8a39ff557cb0d23087fd44cad61df08fc31907a2f" +checksum = "0894878a5fa3edfd6da3f88c4805f4c8558e2b996227a3d864f47fe11e38282c" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.26" +version = "0.8.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ecf5b4cc5364572d7f4c329661bcc82724222973f2cab6f050a4e5c22f75181" +checksum = "88d2b8d9c68ad2b9e4340d7832716a4d21a22a1154777ad56ea55c51a9cf3831" dependencies = [ "proc-macro2", "quote", @@ -12352,9 +12371,9 @@ dependencies = [ [[package]] name = "zstd-sys" -version = "2.0.15+zstd.1.5.7" +version = "2.0.16+zstd.1.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb81183ddd97d0c74cedf1d50d85c8d08c1b8b68ee863bdee9e706eedba1a237" +checksum = "91e19ebc2adc8f83e43039e79776e3fda8ca919132d68a1fed6a5faca2683748" dependencies = [ "cc", "pkg-config", @@ -12377,9 +12396,9 @@ dependencies = [ [[package]] name = "zune-jpeg" -version = "0.4.20" +version = "0.4.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc1f7e205ce79eb2da3cd71c5f55f3589785cb7c79f6a03d1c8d1491bda5d089" +checksum = "29ce2c8a9384ad323cf564b67da86e21d3cfdff87908bc1223ed5c99bc792713" dependencies = [ "zune-core", ] diff --git a/clash-nyanpasu/backend/Cargo.toml b/clash-nyanpasu/backend/Cargo.toml index d2b9f9cea6..824aeb8e3d 100644 --- a/clash-nyanpasu/backend/Cargo.toml +++ b/clash-nyanpasu/backend/Cargo.toml @@ -2,6 +2,9 @@ resolver = "2" members = ["tauri", "boa_utils", "nyanpasu-macro", "nyanpasu-egui"] +[patch.crates-io] +tray-icon = { git = "https://github.com/tauri-apps/tray-icon.git", rev = "34a3442" } + [workspace.package] repository = "https://github.com/keiko233/clash-nyanpasu.git" edition = "2024" diff --git a/clash-nyanpasu/backend/tauri/Cargo.toml b/clash-nyanpasu/backend/tauri/Cargo.toml index 41dbdce834..407786e598 100644 --- a/clash-nyanpasu/backend/tauri/Cargo.toml +++ b/clash-nyanpasu/backend/tauri/Cargo.toml @@ -170,12 +170,12 @@ display-info = "0.5.0" # should be removed after upgrading to tauri v2 # OXC (The Oxidation Compiler) # We use it to parse and transpile the old script profile to esm based script profile -oxc_parser = "0.82" -oxc_allocator = "0.82" -oxc_span = "0.82" -oxc_ast = "0.82" -oxc_syntax = "0.82" -oxc_ast_visit = "0.82" +oxc_parser = "0.87" +oxc_allocator = "0.87" +oxc_span = "0.87" +oxc_ast = "0.87" +oxc_syntax = "0.87" +oxc_ast_visit = "0.87" # Lua Integration mlua = { version = "0.11", features = [ diff --git a/clash-nyanpasu/manifest/version.json b/clash-nyanpasu/manifest/version.json index 3a5008966c..80e8f96dca 100644 --- a/clash-nyanpasu/manifest/version.json +++ b/clash-nyanpasu/manifest/version.json @@ -2,10 +2,10 @@ "manifest_version": 1, "latest": { "mihomo": "v1.19.13", - "mihomo_alpha": "alpha-fed4b36", + "mihomo_alpha": "alpha-0d3d31d", "clash_rs": "v0.9.0", "clash_premium": "2023-09-05-gdcc8d87", - "clash_rs_alpha": "0.9.0-alpha+sha.37539fb" + "clash_rs_alpha": "0.9.0-alpha+sha.50f295d" }, "arch_template": { "mihomo": { @@ -36,12 +36,12 @@ "windows-i386": "clash-i686-pc-windows-msvc-static-crt.exe", "windows-x86_64": "clash-x86_64-pc-windows-msvc.exe", "windows-arm64": "clash-aarch64-pc-windows-msvc.exe", - "linux-aarch64": "clash-aarch64-unknown-linux-gnu-static-crt", + "linux-aarch64": "clash-aarch64-unknown-linux-gnu", "linux-amd64": "clash-x86_64-unknown-linux-gnu-static-crt", - "linux-i386": "clash-i686-unknown-linux-gnu-static-crt", + "linux-i386": "clash-i686-unknown-linux-gnu", "darwin-arm64": "clash-aarch64-apple-darwin", "darwin-x64": "clash-x86_64-apple-darwin", - "linux-armv7": "clash-armv7-unknown-linux-gnueabi-static-crt", + "linux-armv7": "clash-armv7-unknown-linux-gnueabi", "linux-armv7hf": "clash-armv7-unknown-linux-gnueabihf" }, "clash_premium": { @@ -60,14 +60,14 @@ "windows-i386": "clash-i686-pc-windows-msvc-static-crt.exe", "windows-x86_64": "clash-x86_64-pc-windows-msvc.exe", "windows-arm64": "clash-aarch64-pc-windows-msvc.exe", - "linux-aarch64": "clash-aarch64-unknown-linux-gnu-static-crt", + "linux-aarch64": "clash-aarch64-unknown-linux-gnu", "linux-amd64": "clash-x86_64-unknown-linux-gnu-static-crt", - "linux-i386": "clash-i686-unknown-linux-gnu-static-crt", + "linux-i386": "clash-i686-unknown-linux-gnu", "darwin-arm64": "clash-aarch64-apple-darwin", "darwin-x64": "clash-x86_64-apple-darwin", - "linux-armv7": "clash-armv7-unknown-linux-gnueabi-static-crt", + "linux-armv7": "clash-armv7-unknown-linux-gnueabi", "linux-armv7hf": "clash-armv7-unknown-linux-gnueabihf" } }, - "updated_at": "2025-09-05T22:20:49.036Z" + "updated_at": "2025-09-08T15:12:53.100Z" } diff --git a/clash-nyanpasu/pnpm-lock.yaml b/clash-nyanpasu/pnpm-lock.yaml index 028b23c35e..7997ce8876 100644 --- a/clash-nyanpasu/pnpm-lock.yaml +++ b/clash-nyanpasu/pnpm-lock.yaml @@ -563,8 +563,8 @@ importers: specifier: 7.7.1 version: 7.7.1 figlet: - specifier: 1.8.2 - version: 1.8.2 + specifier: 1.9.0 + version: 1.9.0 filesize: specifier: 11.0.2 version: 11.0.2 @@ -575,8 +575,8 @@ importers: specifier: 7.7.2 version: 7.7.2 zod: - specifier: 4.0.17 - version: 4.0.17 + specifier: 4.1.5 + version: 4.1.5 devDependencies: '@octokit/types': specifier: 14.1.0 @@ -599,12 +599,6 @@ importers: fs-extra: specifier: 11.3.1 version: 11.3.1 - https-proxy-agent: - specifier: 7.0.6 - version: 7.0.6 - node-fetch: - specifier: 3.3.2 - version: 3.3.2 octokit: specifier: 5.0.3 version: 5.0.3 @@ -2256,36 +2250,42 @@ packages: engines: {node: '>=20.0.0'} cpu: [arm64] os: [linux] + libc: [glibc] '@oxc-parser/binding-linux-arm64-musl@0.74.0': resolution: {integrity: sha512-AMY30z/C77HgiRRJX7YtVUaelKq1ex0aaj28XoJu4SCezdS8i0IftUNTtGS1UzGjGZB8zQz5SFwVy4dRu4GLwg==} engines: {node: '>=20.0.0'} cpu: [arm64] os: [linux] + libc: [musl] '@oxc-parser/binding-linux-riscv64-gnu@0.74.0': resolution: {integrity: sha512-/RZAP24TgZo4vV/01TBlzRqs0R7E6xvatww4LnmZEBBulQBU/SkypDywfriFqWuFoa61WFXPV7sLcTjJGjim/w==} engines: {node: '>=20.0.0'} cpu: [riscv64] os: [linux] + libc: [glibc] '@oxc-parser/binding-linux-s390x-gnu@0.74.0': resolution: {integrity: sha512-620J1beNAlGSPBD+Msb3ptvrwxu04B8iULCH03zlf0JSLy/5sqlD6qBs0XUVkUJv1vbakUw1gfVnUQqv0UTuEg==} engines: {node: '>=20.0.0'} cpu: [s390x] os: [linux] + libc: [glibc] '@oxc-parser/binding-linux-x64-gnu@0.74.0': resolution: {integrity: sha512-WBFgQmGtFnPNzHyLKbC1wkYGaRIBxXGofO0+hz1xrrkPgbxbJS1Ukva1EB8sPaVBBQ52Bdc2GjLSp721NWRvww==} engines: {node: '>=20.0.0'} cpu: [x64] os: [linux] + libc: [glibc] '@oxc-parser/binding-linux-x64-musl@0.74.0': resolution: {integrity: sha512-y4mapxi0RGqlp3t6Sm+knJlAEqdKDYrEue2LlXOka/F2i4sRN0XhEMPiSOB3ppHmvK4I2zY2XBYTsX1Fel0fAg==} engines: {node: '>=20.0.0'} cpu: [x64] os: [linux] + libc: [musl] '@oxc-parser/binding-wasm32-wasi@0.74.0': resolution: {integrity: sha512-yDS9bRDh5ymobiS2xBmjlrGdUuU61IZoJBaJC5fELdYT5LJNBXlbr3Yc6m2PWfRJwkH6Aq5fRvxAZ4wCbkGa8w==} @@ -2346,41 +2346,49 @@ packages: resolution: {integrity: sha512-VBZZ/5uYiFs+09h1royv78GAEPPy5Bsro53hPWMlJL/E9pPibaj3fCzZEAnrKSzVpvwf7+QSc5w7ZUrX3xAKpg==} cpu: [arm64] os: [linux] + libc: [glibc] '@oxc-resolver/binding-linux-arm64-musl@11.6.2': resolution: {integrity: sha512-x+LooeNXy3hhvDT7q29jLjh914OYX9YnrQbGT3ogep5EY/LLbUiG3LV8XSrWRqXD5132gea9SOYxmcpF9i6xTQ==} cpu: [arm64] os: [linux] + libc: [musl] '@oxc-resolver/binding-linux-ppc64-gnu@11.6.2': resolution: {integrity: sha512-+CluEbUpAaKvcNREZtUUiunqzo5o0/qp+6xoFkbDAwNhWIw1mtWCg1Di++Fa053Cah/Rx+dRMQteANoMBGCxxg==} cpu: [ppc64] os: [linux] + libc: [glibc] '@oxc-resolver/binding-linux-riscv64-gnu@11.6.2': resolution: {integrity: sha512-OKWK/QvC6gECaeCNjfhuj0yiqMIisS0ewCRAmgT2pyxDwkNWgSm2wli+Tj/gpLjua2HjFDnDEcg0/dOoO6+xQg==} cpu: [riscv64] os: [linux] + libc: [glibc] '@oxc-resolver/binding-linux-riscv64-musl@11.6.2': resolution: {integrity: sha512-YtQ3hLvhVzan3boR44C0qu/jiTanaBAL9uTqs/S2tzOLfpO2PoTDbQDgADvOqYJDTJkOGiofJC2E1lJcRmpbXQ==} cpu: [riscv64] os: [linux] + libc: [musl] '@oxc-resolver/binding-linux-s390x-gnu@11.6.2': resolution: {integrity: sha512-pcX/ih9QHrEWliiXJdZoX/bnfOlr5E0eOWSG2ew5U1HntGket/1AcdcA4UH3MQU/TrOLxxiKhGzeZv+fwewmmA==} cpu: [s390x] os: [linux] + libc: [glibc] '@oxc-resolver/binding-linux-x64-gnu@11.6.2': resolution: {integrity: sha512-LFYSgeYW11u4cQXzgIGthqCRAoLvl0IqbIMGeJLVt1tD7yrpTukfQynMzwP3vuTK5hmWgYc7NfK6G5+Zv/75hw==} cpu: [x64] os: [linux] + libc: [glibc] '@oxc-resolver/binding-linux-x64-musl@11.6.2': resolution: {integrity: sha512-IE13zwhg+XX9FVQHADbIe6RB2MgQeqyKdGyH67meGPgqCbLqT41K9qAm0k2uDlSswjLK8nhNe5Z+hhopBKzRRg==} cpu: [x64] os: [linux] + libc: [musl] '@oxc-resolver/binding-wasm32-wasi@11.6.2': resolution: {integrity: sha512-6nNW/wOKrptS9Rebf83aHvIsIiNcXOEWwUmhMR/4MHrH07zbcptBoZQcWO6362B9Y2lMN7dIF9v7brQcNDs63A==} @@ -2431,30 +2439,35 @@ packages: engines: {node: '>= 10.0.0'} cpu: [arm] os: [linux] + libc: [glibc] '@parcel/watcher-linux-arm64-glibc@2.4.1': resolution: {integrity: sha512-BJ7mH985OADVLpbrzCLgrJ3TOpiZggE9FMblfO65PlOCdG++xJpKUJ0Aol74ZUIYfb8WsRlUdgrZxKkz3zXWYA==} engines: {node: '>= 10.0.0'} cpu: [arm64] os: [linux] + libc: [glibc] '@parcel/watcher-linux-arm64-musl@2.4.1': resolution: {integrity: sha512-p4Xb7JGq3MLgAfYhslU2SjoV9G0kI0Xry0kuxeG/41UfpjHGOhv7UoUDAz/jb1u2elbhazy4rRBL8PegPJFBhA==} engines: {node: '>= 10.0.0'} cpu: [arm64] os: [linux] + libc: [musl] '@parcel/watcher-linux-x64-glibc@2.4.1': resolution: {integrity: sha512-s9O3fByZ/2pyYDPoLM6zt92yu6P4E39a03zvO0qCHOTjxmt3GHRMLuRZEWhWLASTMSrrnVNWdVI/+pUElJBBBg==} engines: {node: '>= 10.0.0'} cpu: [x64] os: [linux] + libc: [glibc] '@parcel/watcher-linux-x64-musl@2.4.1': resolution: {integrity: sha512-L2nZTYR1myLNST0O632g0Dx9LyMNHrn6TOt76sYxWLdff3cB22/GZX2UPtJnaqQPdCRoszoY5rcOj4oMTtp5fQ==} engines: {node: '>= 10.0.0'} cpu: [x64] os: [linux] + libc: [musl] '@parcel/watcher-win32-arm64@2.4.1': resolution: {integrity: sha512-Uq2BPp5GWhrq/lcuItCHoqxjULU1QYEcyjSO5jqqOK8RNFDBQnenMMx4gAl3v8GiWa59E9+uDM7yZ6LxwUIfRg==} @@ -2667,56 +2680,67 @@ packages: resolution: {integrity: sha512-EtP8aquZ0xQg0ETFcxUbU71MZlHaw9MChwrQzatiE8U/bvi5uv/oChExXC4mWhjiqK7azGJBqU0tt5H123SzVA==} cpu: [arm] os: [linux] + libc: [glibc] '@rollup/rollup-linux-arm-musleabihf@4.46.2': resolution: {integrity: sha512-qO7F7U3u1nfxYRPM8HqFtLd+raev2K137dsV08q/LRKRLEc7RsiDWihUnrINdsWQxPR9jqZ8DIIZ1zJJAm5PjQ==} cpu: [arm] os: [linux] + libc: [musl] '@rollup/rollup-linux-arm64-gnu@4.46.2': resolution: {integrity: sha512-3dRaqLfcOXYsfvw5xMrxAk9Lb1f395gkoBYzSFcc/scgRFptRXL9DOaDpMiehf9CO8ZDRJW2z45b6fpU5nwjng==} cpu: [arm64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-arm64-musl@4.46.2': resolution: {integrity: sha512-fhHFTutA7SM+IrR6lIfiHskxmpmPTJUXpWIsBXpeEwNgZzZZSg/q4i6FU4J8qOGyJ0TR+wXBwx/L7Ho9z0+uDg==} cpu: [arm64] os: [linux] + libc: [musl] '@rollup/rollup-linux-loongarch64-gnu@4.46.2': resolution: {integrity: sha512-i7wfGFXu8x4+FRqPymzjD+Hyav8l95UIZ773j7J7zRYc3Xsxy2wIn4x+llpunexXe6laaO72iEjeeGyUFmjKeA==} cpu: [loong64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-ppc64-gnu@4.46.2': resolution: {integrity: sha512-B/l0dFcHVUnqcGZWKcWBSV2PF01YUt0Rvlurci5P+neqY/yMKchGU8ullZvIv5e8Y1C6wOn+U03mrDylP5q9Yw==} cpu: [ppc64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-riscv64-gnu@4.46.2': resolution: {integrity: sha512-32k4ENb5ygtkMwPMucAb8MtV8olkPT03oiTxJbgkJa7lJ7dZMr0GCFJlyvy+K8iq7F/iuOr41ZdUHaOiqyR3iQ==} cpu: [riscv64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-riscv64-musl@4.46.2': resolution: {integrity: sha512-t5B2loThlFEauloaQkZg9gxV05BYeITLvLkWOkRXogP4qHXLkWSbSHKM9S6H1schf/0YGP/qNKtiISlxvfmmZw==} cpu: [riscv64] os: [linux] + libc: [musl] '@rollup/rollup-linux-s390x-gnu@4.46.2': resolution: {integrity: sha512-YKjekwTEKgbB7n17gmODSmJVUIvj8CX7q5442/CK80L8nqOUbMtf8b01QkG3jOqyr1rotrAnW6B/qiHwfcuWQA==} cpu: [s390x] os: [linux] + libc: [glibc] '@rollup/rollup-linux-x64-gnu@4.46.2': resolution: {integrity: sha512-Jj5a9RUoe5ra+MEyERkDKLwTXVu6s3aACP51nkfnK9wJTraCC8IMe3snOfALkrjTYd2G1ViE1hICj0fZ7ALBPA==} cpu: [x64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-x64-musl@4.46.2': resolution: {integrity: sha512-7kX69DIrBeD7yNp4A5b81izs8BqoZkCIaxQaOpumcJ1S/kmqNFjPhDu1LHeVXv0SexfHQv5cqHsxLOjETuqDuA==} cpu: [x64] os: [linux] + libc: [musl] '@rollup/rollup-win32-arm64-msvc@4.46.2': resolution: {integrity: sha512-wiJWMIpeaak/jsbaq2HMh/rzZxHVW1rU6coyeNNpMwk5isiPjSTx0a4YLSlYDwBH/WBvLz+EtsNqQScZTLJy3g==} @@ -2880,24 +2904,28 @@ packages: engines: {node: '>=10'} cpu: [arm64] os: [linux] + libc: [glibc] '@swc/core-linux-arm64-musl@1.13.3': resolution: {integrity: sha512-bc+CXYlFc1t8pv9yZJGus372ldzOVscBl7encUBlU1m/Sig0+NDJLz6cXXRcFyl6ABNOApWeR4Yl7iUWx6C8og==} engines: {node: '>=10'} cpu: [arm64] os: [linux] + libc: [musl] '@swc/core-linux-x64-gnu@1.13.3': resolution: {integrity: sha512-dFXoa0TEhohrKcxn/54YKs1iwNeW6tUkHJgXW33H381SvjKFUV53WR231jh1sWVJETjA3vsAwxKwR23s7UCmUA==} engines: {node: '>=10'} cpu: [x64] os: [linux] + libc: [glibc] '@swc/core-linux-x64-musl@1.13.3': resolution: {integrity: sha512-ieyjisLB+ldexiE/yD8uomaZuZIbTc8tjquYln9Quh5ykOBY7LpJJYBWvWtm1g3pHv6AXlBI8Jay7Fffb6aLfA==} engines: {node: '>=10'} cpu: [x64] os: [linux] + libc: [musl] '@swc/core-win32-arm64-msvc@1.13.3': resolution: {integrity: sha512-elTQpnaX5vESSbhCEgcwXjpMsnUbqqHfEpB7ewpkAsLzKEXZaK67ihSRYAuAx6ewRQTo7DS5iTT6X5aQD3MzMw==} @@ -2974,24 +3002,28 @@ packages: engines: {node: '>= 10'} cpu: [arm64] os: [linux] + libc: [glibc] '@tailwindcss/oxide-linux-arm64-musl@4.1.13': resolution: {integrity: sha512-hZQrmtLdhyqzXHB7mkXfq0IYbxegaqTmfa1p9MBj72WPoDD3oNOh1Lnxf6xZLY9C3OV6qiCYkO1i/LrzEdW2mg==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] + libc: [musl] '@tailwindcss/oxide-linux-x64-gnu@4.1.13': resolution: {integrity: sha512-uaZTYWxSXyMWDJZNY1Ul7XkJTCBRFZ5Fo6wtjrgBKzZLoJNrG+WderJwAjPzuNZOnmdrVg260DKwXCFtJ/hWRQ==} engines: {node: '>= 10'} cpu: [x64] os: [linux] + libc: [glibc] '@tailwindcss/oxide-linux-x64-musl@4.1.13': resolution: {integrity: sha512-oXiPj5mi4Hdn50v5RdnuuIms0PVPI/EG4fxAfFiIKQh5TgQgX7oSuDWntHW7WNIi/yVLAiS+CRGW4RkoGSSgVQ==} engines: {node: '>= 10'} cpu: [x64] os: [linux] + libc: [musl] '@tailwindcss/oxide-wasm32-wasi@4.1.13': resolution: {integrity: sha512-+LC2nNtPovtrDwBc/nqnIKYh/W2+R69FA0hgoeOn64BdCX522u19ryLh3Vf3F8W49XBcMIxSe665kwy21FkhvA==} @@ -3172,30 +3204,35 @@ packages: engines: {node: '>= 10'} cpu: [arm64] os: [linux] + libc: [glibc] '@tauri-apps/cli-linux-arm64-musl@2.8.4': resolution: {integrity: sha512-zumFeaU1Ws5Ay872FTyIm7z8kfzEHu8NcIn8M6TxbJs0a7GRV21KBdpW1zNj2qy7HynnpQCqjAYXTUUmm9JAOw==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] + libc: [musl] '@tauri-apps/cli-linux-riscv64-gnu@2.8.4': resolution: {integrity: sha512-qiqbB3Zz6IyO201f+1ojxLj65WYj8mixL5cOMo63nlg8CIzsP23cPYUrx1YaDPsCLszKZo7tVs14pc7BWf+/aQ==} engines: {node: '>= 10'} cpu: [riscv64] os: [linux] + libc: [glibc] '@tauri-apps/cli-linux-x64-gnu@2.8.4': resolution: {integrity: sha512-TaqaDd9Oy6k45Hotx3pOf+pkbsxLaApv4rGd9mLuRM1k6YS/aw81YrsMryYPThrxrScEIUcmNIHaHsLiU4GMkw==} engines: {node: '>= 10'} cpu: [x64] os: [linux] + libc: [glibc] '@tauri-apps/cli-linux-x64-musl@2.8.4': resolution: {integrity: sha512-ot9STAwyezN8w+bBHZ+bqSQIJ0qPZFlz/AyscpGqB/JnJQVDFQcRDmUPFEaAtt2UUHSWzN3GoTJ5ypqLBp2WQA==} engines: {node: '>= 10'} cpu: [x64] os: [linux] + libc: [musl] '@tauri-apps/cli-win32-arm64-msvc@2.8.4': resolution: {integrity: sha512-+2aJ/g90dhLiOLFSD1PbElXX3SoMdpO7HFPAZB+xot3CWlAZD1tReUFy7xe0L5GAR16ZmrxpIDM9v9gn5xRy/w==} @@ -3629,41 +3666,49 @@ packages: resolution: {integrity: sha512-Cg6xzdkrpltcTPO4At+A79zkC7gPDQIgosJmVV8M104ImB6KZi1MrNXgDYIAfkhUYjPzjNooEDFRAwwPadS7ZA==} cpu: [arm64] os: [linux] + libc: [glibc] '@unrs/resolver-binding-linux-arm64-musl@1.10.1': resolution: {integrity: sha512-aNeg99bVkXa4lt+oZbjNRPC8ZpjJTKxijg/wILrJdzNyAymO2UC/HUK1UfDjt6T7U5p/mK24T3CYOi3/+YEQSA==} cpu: [arm64] os: [linux] + libc: [musl] '@unrs/resolver-binding-linux-ppc64-gnu@1.10.1': resolution: {integrity: sha512-ylz5ojeXrkPrtnzVhpCO+YegG63/aKhkoTlY8PfMfBfLaUG8v6m6iqrL7sBUKdVBgOB4kSTUPt9efQdA/Y3Z/w==} cpu: [ppc64] os: [linux] + libc: [glibc] '@unrs/resolver-binding-linux-riscv64-gnu@1.10.1': resolution: {integrity: sha512-xcWyhmJfXXOxK7lvE4+rLwBq+on83svlc0AIypfe6x4sMJR+S4oD7n9OynaQShfj2SufPw2KJAotnsNb+4nN2g==} cpu: [riscv64] os: [linux] + libc: [glibc] '@unrs/resolver-binding-linux-riscv64-musl@1.10.1': resolution: {integrity: sha512-mW9JZAdOCyorgi1eLJr4gX7xS67WNG9XNPYj5P8VuttK72XNsmdw9yhOO4tDANMgiLXFiSFaiL1gEpoNtRPw/A==} cpu: [riscv64] os: [linux] + libc: [musl] '@unrs/resolver-binding-linux-s390x-gnu@1.10.1': resolution: {integrity: sha512-NZGKhBy6xkJ0k09cWNZz4DnhBcGlhDd3W+j7EYoNvf5TSwj2K6kbmfqTWITEgkvjsMUjm1wsrc4IJaH6VtjyHQ==} cpu: [s390x] os: [linux] + libc: [glibc] '@unrs/resolver-binding-linux-x64-gnu@1.10.1': resolution: {integrity: sha512-VsjgckJ0gNMw7p0d8In6uPYr+s0p16yrT2rvG4v2jUpEMYkpnfnCiALa9SWshbvlGjKQ98Q2x19agm3iFk8w8Q==} cpu: [x64] os: [linux] + libc: [glibc] '@unrs/resolver-binding-linux-x64-musl@1.10.1': resolution: {integrity: sha512-idMnajMeejnaFi0Mx9UTLSYFDAOTfAEP7VjXNgxKApso3Eu2Njs0p2V95nNIyFi4oQVGFmIuCkoznAXtF/Zbmw==} cpu: [x64] os: [linux] + libc: [musl] '@unrs/resolver-binding-wasm32-wasi@1.10.1': resolution: {integrity: sha512-7jyhjIRNFjzlr8x5pth6Oi9hv3a7ubcVYm2GBFinkBQKcFhw4nIs5BtauSNtDW1dPIGrxF0ciynCZqzxMrYMsg==} @@ -3759,10 +3804,6 @@ packages: resolution: {integrity: sha512-TGw5yVi4saajsSEgz25grObGHEUaDrniwvA2qwSC060KfqGPdglhvPMA2lPIoxs3PQIItj2iag35fONcQqgUaQ==} engines: {node: '>=12.0'} - agent-base@7.1.2: - resolution: {integrity: sha512-JVzqkCNRT+VfqzzgPWDPnwvDheSAUdiMUn3NoLXpDJF5lRqeJqyC9iGsAxIOAW+mzIdq+uP1TvcX6bMtrH0agg==} - engines: {node: '>= 14'} - ahooks@3.9.5: resolution: {integrity: sha512-TrjXie49Q8HuHKTa84Fm9A+famMDAG1+7a9S9Gq6RQ0h90Jgqmiq3CkObuRjWT/C4d6nRZCw35Y2k2fmybb5eA==} engines: {node: '>=18'} @@ -4533,10 +4574,6 @@ packages: resolution: {integrity: sha512-wAV9QHOsNbwnWdNW2FYvE1P56wtgSbM+3SZcdGiWQILwVjACCXDCI3Ai8QlCjMDB8YK5zySiXZYBiwGmNY3lnw==} engines: {node: '>=12'} - data-uri-to-buffer@4.0.1: - resolution: {integrity: sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==} - engines: {node: '>= 12'} - data-view-buffer@1.0.1: resolution: {integrity: sha512-0lht7OugA5x3iJLOWFhWK/5ehONdprk0ISXqVFn/NFrDu+cuc8iADFrGQz5BnRK7LLU3JmkbXSxaqX+/mXYtUA==} engines: {node: '>= 0.4'} @@ -5206,13 +5243,9 @@ packages: picomatch: optional: true - fetch-blob@3.2.0: - resolution: {integrity: sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==} - engines: {node: ^12.20 || >= 14.13} - - figlet@1.8.2: - resolution: {integrity: sha512-iPCpE9B/rOcjewIzDnagP9F2eySzGeHReX8WlrZQJkqFBk2wvq8gY0c6U6Hd2y9HnX1LQcYSeP7aEHoPt6sVKQ==} - engines: {node: '>= 0.4.0'} + figlet@1.9.0: + resolution: {integrity: sha512-S+WN3ZIGYgiZUlQD0s3qlAPSOdCdYth0G7PK6DbubfixgorA7jzNl4eae2Hc/rEjQ5UYnf0YkcpCFc/IMklZhg==} + engines: {node: '>= 17.0.0'} hasBin: true file-entry-cache@10.1.4: @@ -5270,10 +5303,6 @@ packages: engines: {node: '>=18.3.0'} hasBin: true - formdata-polyfill@4.0.10: - resolution: {integrity: sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==} - engines: {node: '>=12.20.0'} - fraction.js@4.3.7: resolution: {integrity: sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==} @@ -5574,10 +5603,6 @@ packages: resolution: {integrity: sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg==} engines: {node: '>=10.19.0'} - https-proxy-agent@7.0.6: - resolution: {integrity: sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==} - engines: {node: '>= 14'} - human-signals@2.1.0: resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==} engines: {node: '>=10.17.0'} @@ -6177,24 +6202,28 @@ packages: engines: {node: '>= 12.0.0'} cpu: [arm64] os: [linux] + libc: [glibc] lightningcss-linux-arm64-musl@1.30.1: resolution: {integrity: sha512-jmUQVx4331m6LIX+0wUhBbmMX7TCfjF5FoOH6SD1CttzuYlGNVpA7QnrmLxrsub43ClTINfGSYyHe2HWeLl5CQ==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [linux] + libc: [musl] lightningcss-linux-x64-gnu@1.30.1: resolution: {integrity: sha512-piWx3z4wN8J8z3+O5kO74+yr6ze/dKmPnI7vLqfSqI8bccaTGY5xiSGVIJBDd5K5BHlvVLpUB3S2YCfelyJ1bw==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [linux] + libc: [glibc] lightningcss-linux-x64-musl@1.30.1: resolution: {integrity: sha512-rRomAK7eIkL+tHY0YPxbc5Dra2gXlI63HL+v1Pdi1a3sC+tJTcFrHX+E86sulgAXeI7rSzDYhPSeHHjqFhqfeQ==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [linux] + libc: [musl] lightningcss-win32-arm64-msvc@1.30.1: resolution: {integrity: sha512-mSL4rqPi4iXq5YVqzSsJgMVFENoa4nGTT/GjO2c0Yl9OuQfPsIfncvLrEW6RbbB24WtZ3xP/2CCmI3tNkNV4oA==} @@ -6635,18 +6664,9 @@ packages: node-addon-api@7.1.1: resolution: {integrity: sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==} - node-domexception@1.0.0: - resolution: {integrity: sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==} - engines: {node: '>=10.5.0'} - deprecated: Use your platform's native DOMException instead - node-fetch-native@1.6.4: resolution: {integrity: sha512-IhOigYzAKHd244OC0JIMIUrjzctirCmPkaIfhDeGcEETWof5zKYUW7e7MYvChGWh/4CJeXEgsRyGzuF334rOOQ==} - node-fetch@3.3.2: - resolution: {integrity: sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - node-gyp-build@4.8.1: resolution: {integrity: sha512-OSs33Z9yWr148JZcbZd5WiAXhh/n9z8TxQcdMhIOlpN9AhWpLfvVFO73+m77bBABQMaY9XSvIa+qk0jlI7Gcaw==} hasBin: true @@ -7530,48 +7550,56 @@ packages: engines: {node: '>=14.0.0'} cpu: [arm64] os: [linux] + libc: glibc sass-embedded-linux-arm@1.92.1: resolution: {integrity: sha512-cT3w8yoQTqrtZvWLJeutEGmawITDTY4J6oSVQjeDcPnnoPt0gOFxem8YMznraACXvahw/2+KJDH33BTNgiPo0A==} engines: {node: '>=14.0.0'} cpu: [arm] os: [linux] + libc: glibc sass-embedded-linux-musl-arm64@1.92.1: resolution: {integrity: sha512-TfiEBkCyNzVoOhjHXUT+vZ6+p0ueDbvRw6f4jHdkvljZzXdXMby4wh7BU1odl69rgRTkSvYKhgbErRLDR/F7pQ==} engines: {node: '>=14.0.0'} cpu: [arm64] os: [linux] + libc: musl sass-embedded-linux-musl-arm@1.92.1: resolution: {integrity: sha512-nPBos6lI31ef2zQhqTZhFOU7ar4impJbLIax0XsqS269YsiCwjhk11VmUloJTpFlJuKMiVXNo7dPx+katxhD/Q==} engines: {node: '>=14.0.0'} cpu: [arm] os: [linux] + libc: musl sass-embedded-linux-musl-riscv64@1.92.1: resolution: {integrity: sha512-R+RcJA4EYpJDE9JM1GgPYgZo7x94FlxZ6jPodOQkEaZ1S9kvXVCuP5X/0PXRPhu08KJOfeMsAElzfdAjUf7KJg==} engines: {node: '>=14.0.0'} cpu: [riscv64] os: [linux] + libc: musl sass-embedded-linux-musl-x64@1.92.1: resolution: {integrity: sha512-/HolYRGXJjx8nLw6oj5ZrkR7PFM7X/5kE4MYZaFMpDIPIcw3bqB2fUXLo/MYlRLsw7gBAT6hJAMBrNdKuTphfw==} engines: {node: '>=14.0.0'} cpu: [x64] os: [linux] + libc: musl sass-embedded-linux-riscv64@1.92.1: resolution: {integrity: sha512-b9bxe0CMsbSsLx3nrR0cq8xpIkoAC6X36o4DGMITF3m2v3KsojC7ru9X0Gz+zUFr6rwpq/0lTNzFLNu6sPNo3w==} engines: {node: '>=14.0.0'} cpu: [riscv64] os: [linux] + libc: glibc sass-embedded-linux-x64@1.92.1: resolution: {integrity: sha512-xuiK5Jp5NldW4bvlC7AuX1Wf7o0gLZ3md/hNg+bkTvxtCDgnUHtfdo8Q+xWP11bD9QX31xXFWpmUB8UDLi6XQQ==} engines: {node: '>=14.0.0'} cpu: [x64] os: [linux] + libc: glibc sass-embedded-unknown-all@1.92.1: resolution: {integrity: sha512-AT9oXvtNY4N+Nd0wvoWqq9A5HjdH/X3aUH4boQUtXyaJ/9DUwnQmBpP5Gtn028ZS8exOGBdobmmWAuigv0k/OA==} @@ -8543,10 +8571,6 @@ packages: resolution: {integrity: sha512-3hu+tD8YzSLGuFYtPRb48vdhKMi0KQV5sn+uWr8+7dMEq/2G/dtLrdDinkLjqq5TIbIBjYJ4Ax/n3YiaW7QM8A==} engines: {node: 20 || >=22} - web-streams-polyfill@3.3.3: - resolution: {integrity: sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==} - engines: {node: '>= 8'} - webpack-virtual-modules@0.6.2: resolution: {integrity: sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ==} @@ -8719,9 +8743,6 @@ packages: zod@3.25.76: resolution: {integrity: sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==} - zod@4.0.17: - resolution: {integrity: sha512-1PHjlYRevNxxdy2JZ8JcNAw7rX8V9P1AKkP+x/xZfxB0K5FYfuV+Ug6P/6NVSR2jHQ+FzDDoDHS04nYUsOIyLQ==} - zod@4.1.5: resolution: {integrity: sha512-rcUUZqlLJgBC33IT3PNMgsCq6TzLQEG/Ei/KTCU0PedSWRMAXoOUN+4t/0H+Q8bdnLPdqUYnvboJT0bn/229qg==} @@ -12141,12 +12162,6 @@ snapshots: adm-zip@0.5.16: {} - agent-base@7.1.2: - dependencies: - debug: 4.4.1 - transitivePeerDependencies: - - supports-color - ahooks@3.9.5(react-dom@19.1.1(react@19.1.1))(react@19.1.1): dependencies: '@babel/runtime': 7.28.2 @@ -13005,8 +13020,6 @@ snapshots: dargs@8.1.0: {} - data-uri-to-buffer@4.0.1: {} - data-view-buffer@1.0.1: dependencies: call-bind: 1.0.8 @@ -13921,12 +13934,9 @@ snapshots: optionalDependencies: picomatch: 4.0.3 - fetch-blob@3.2.0: + figlet@1.9.0: dependencies: - node-domexception: 1.0.0 - web-streams-polyfill: 3.3.3 - - figlet@1.8.2: {} + commander: 14.0.0 file-entry-cache@10.1.4: dependencies: @@ -13989,10 +13999,6 @@ snapshots: dependencies: fd-package-json: 2.0.0 - formdata-polyfill@4.0.10: - dependencies: - fetch-blob: 3.2.0 - fraction.js@4.3.7: {} framer-motion@12.23.12(@emotion/is-prop-valid@1.3.0)(react-dom@19.1.1(react@19.1.1))(react@19.1.1): @@ -14380,13 +14386,6 @@ snapshots: quick-lru: 5.1.1 resolve-alpn: 1.2.1 - https-proxy-agent@7.0.6: - dependencies: - agent-base: 7.1.2 - debug: 4.3.7 - transitivePeerDependencies: - - supports-color - human-signals@2.1.0: {} husky@9.1.7: {} @@ -15493,16 +15492,8 @@ snapshots: node-addon-api@7.1.1: optional: true - node-domexception@1.0.0: {} - node-fetch-native@1.6.4: {} - node-fetch@3.3.2: - dependencies: - data-uri-to-buffer: 4.0.1 - fetch-blob: 3.2.0 - formdata-polyfill: 4.0.10 - node-gyp-build@4.8.1: {} node-html-parser@5.4.2: @@ -17594,8 +17585,6 @@ snapshots: walk-up-path@4.0.0: {} - web-streams-polyfill@3.3.3: {} - webpack-virtual-modules@0.6.2: {} websocket@1.0.35: @@ -17799,8 +17788,6 @@ snapshots: zod@3.25.76: {} - zod@4.0.17: {} - zod@4.1.5: {} zwitch@2.0.4: {} diff --git a/clash-nyanpasu/scripts/package.json b/clash-nyanpasu/scripts/package.json index 79aec3e5c0..62cd072dac 100644 --- a/clash-nyanpasu/scripts/package.json +++ b/clash-nyanpasu/scripts/package.json @@ -6,11 +6,11 @@ "@actions/github": "6.0.1", "@types/figlet": "1.7.0", "@types/semver": "7.7.1", - "figlet": "1.8.2", + "figlet": "1.9.0", "filesize": "11.0.2", "p-retry": "7.0.0", "semver": "7.7.2", - "zod": "4.0.17" + "zod": "4.1.5" }, "devDependencies": { "@octokit/types": "14.1.0", @@ -20,8 +20,6 @@ "colorize-template": "1.0.0", "consola": "3.4.2", "fs-extra": "11.3.1", - "https-proxy-agent": "7.0.6", - "node-fetch": "3.3.2", "octokit": "5.0.3", "picocolors": "1.1.1", "tar": "7.4.3", diff --git a/clash-nyanpasu/scripts/updater-nightly.ts b/clash-nyanpasu/scripts/updater-nightly.ts index e2a153459d..299f2ee232 100644 --- a/clash-nyanpasu/scripts/updater-nightly.ts +++ b/clash-nyanpasu/scripts/updater-nightly.ts @@ -2,14 +2,14 @@ import { execSync } from 'child_process' import fs from 'fs/promises' import path from 'path' import { camelCase, upperFirst } from 'lodash-es' -import fetch from 'node-fetch' import semver from 'semver' +import { fetch } from 'undici' import yargs from 'yargs' import { hideBin } from 'yargs/helpers' import { z } from 'zod' import { context, getOctokit } from '@actions/github' import tauriNightly from '../backend/tauri/overrides/nightly.conf.json' -import { getGithubUrl } from './utils' +import { getGithubUrl, getProxyAgent } from './utils' import { colorize, consola } from './utils/logger' const UPDATE_TAG_NAME = 'updater' @@ -59,7 +59,9 @@ async function resolveUpdater() { version: z.string().min(1), }) const latest = schema.parse( - await fetch(latestContent.browser_download_url).then((res) => res.json()), + await fetch(latestContent.browser_download_url, { + dispatcher: getProxyAgent(), + }).then((res) => res.json()), ) const version = semver.parse(latest.version) @@ -302,6 +304,7 @@ async function getSignature(url: string) { const response = await fetch(url, { method: 'GET', headers: { 'Content-Type': 'application/octet-stream' }, + dispatcher: getProxyAgent(), }) return response.text() diff --git a/clash-nyanpasu/scripts/updater.ts b/clash-nyanpasu/scripts/updater.ts index 44fc480f15..0a96e7b11a 100644 --- a/clash-nyanpasu/scripts/updater.ts +++ b/clash-nyanpasu/scripts/updater.ts @@ -1,11 +1,11 @@ import fs from 'fs/promises' import path from 'path' -import fetch from 'node-fetch' +import { fetch } from 'undici' import yargs from 'yargs' import { hideBin } from 'yargs/helpers' import { context, getOctokit } from '@actions/github' import { resolveUpdateLog } from './updatelog' -import { getGithubUrl } from './utils' +import { getGithubUrl, getProxyAgent } from './utils' import { colorize, consola } from './utils/logger' const UPDATE_TAG_NAME = 'updater' @@ -267,6 +267,7 @@ async function getSignature(url: string) { const response = await fetch(url, { method: 'GET', headers: { 'Content-Type': 'application/octet-stream' }, + dispatcher: getProxyAgent(), }) return response.text() diff --git a/clash-nyanpasu/scripts/utils/download.ts b/clash-nyanpasu/scripts/utils/download.ts index 8c45047c77..b1341134b1 100644 --- a/clash-nyanpasu/scripts/utils/download.ts +++ b/clash-nyanpasu/scripts/utils/download.ts @@ -3,9 +3,9 @@ import path from 'path' import zlib from 'zlib' import AdmZip from 'adm-zip' import fs from 'fs-extra' -import fetch, { type RequestInit } from 'node-fetch' import * as tar from 'tar' import { BinInfo } from 'types' +import { fetch, type RequestInit } from 'undici' import { getProxyAgent } from './' import { TAURI_APP_DIR, TEMP_DIR } from './env' import { colorize, consola } from './logger' @@ -19,9 +19,11 @@ export const downloadFile = async (url: string, path: string) => { const httpProxy = getProxyAgent() if (httpProxy) { - options.agent = httpProxy + options.dispatcher = httpProxy } + consola.debug(colorize`download {gray "${url}"} to {gray "${path}"}`) + const response = await fetch(url, { ...options, method: 'GET', @@ -120,7 +122,7 @@ export const resolveSidecar = async ( const writeStream = fs.createWriteStream(sidecarPath) await new Promise((resolve, reject) => { - const onError = (error: any) => { + const onError = (error: Error) => { consola.error(colorize`"${name}" gz failed:`, error) reject(error) } diff --git a/clash-nyanpasu/scripts/utils/index.ts b/clash-nyanpasu/scripts/utils/index.ts index 4dd6744a1a..a3942c006f 100644 --- a/clash-nyanpasu/scripts/utils/index.ts +++ b/clash-nyanpasu/scripts/utils/index.ts @@ -1,7 +1,7 @@ import figlet from 'figlet' import { filesize } from 'filesize' import fs from 'fs-extra' -import { HttpsProxyAgent } from 'https-proxy-agent' +import { ProxyAgent } from 'undici' import { GITHUB_PROXY } from './env' export const getGithubUrl = (url: string) => { @@ -54,7 +54,7 @@ export const HTTP_PROXY = export function getProxyAgent() { if (HTTP_PROXY) { - return new HttpsProxyAgent(HTTP_PROXY) + return new ProxyAgent(HTTP_PROXY) } return undefined diff --git a/clash-nyanpasu/scripts/utils/manifest.ts b/clash-nyanpasu/scripts/utils/manifest.ts index 633266a747..627e31704f 100644 --- a/clash-nyanpasu/scripts/utils/manifest.ts +++ b/clash-nyanpasu/scripts/utils/manifest.ts @@ -1,4 +1,6 @@ +import { fetch } from 'undici' import { SupportedArch } from '../types/index' +import { getProxyAgent } from './' import { consola } from './logger' import { applyProxy, octokit } from './octokit' @@ -46,6 +48,7 @@ export const resolveMihomo = async (): LatestVersionResolver => { export const resolveMihomoAlpha = async (): LatestVersionResolver => { const resp = await fetch( 'https://github.com/MetaCubeX/mihomo/releases/download/Prerelease-Alpha/version.txt', + { dispatcher: getProxyAgent() }, ) const alphaReleaseHash = (await resp.text()).trim() @@ -86,12 +89,12 @@ export const resolveClashRs = async (): LatestVersionResolver => { [SupportedArch.WindowsX86_32]: 'clash-i686-pc-windows-msvc-static-crt.exe', [SupportedArch.WindowsX86_64]: 'clash-x86_64-pc-windows-msvc.exe', [SupportedArch.WindowsArm64]: 'clash-aarch64-pc-windows-msvc.exe', - [SupportedArch.LinuxAarch64]: 'clash-aarch64-unknown-linux-gnu-static-crt', + [SupportedArch.LinuxAarch64]: 'clash-aarch64-unknown-linux-gnu', [SupportedArch.LinuxAmd64]: 'clash-x86_64-unknown-linux-gnu-static-crt', - [SupportedArch.LinuxI386]: 'clash-i686-unknown-linux-gnu-static-crt', + [SupportedArch.LinuxI386]: 'clash-i686-unknown-linux-gnu', [SupportedArch.DarwinArm64]: 'clash-aarch64-apple-darwin', [SupportedArch.DarwinX64]: 'clash-x86_64-apple-darwin', - [SupportedArch.LinuxArmv7]: 'clash-armv7-unknown-linux-gnueabi-static-crt', + [SupportedArch.LinuxArmv7]: 'clash-armv7-unknown-linux-gnueabi', [SupportedArch.LinuxArmv7hf]: 'clash-armv7-unknown-linux-gnueabihf', } satisfies ArchMapping @@ -105,6 +108,7 @@ export const resolveClashRs = async (): LatestVersionResolver => { export const resolveClashRsAlpha = async (): LatestVersionResolver => { const resp = await fetch( 'https://github.com/Watfaq/clash-rs/releases/download/latest/version.txt', + { dispatcher: getProxyAgent() }, ) const alphaVersion = resp.ok @@ -117,12 +121,12 @@ export const resolveClashRsAlpha = async (): LatestVersionResolver => { [SupportedArch.WindowsX86_32]: 'clash-i686-pc-windows-msvc-static-crt.exe', [SupportedArch.WindowsX86_64]: 'clash-x86_64-pc-windows-msvc.exe', [SupportedArch.WindowsArm64]: 'clash-aarch64-pc-windows-msvc.exe', - [SupportedArch.LinuxAarch64]: 'clash-aarch64-unknown-linux-gnu-static-crt', + [SupportedArch.LinuxAarch64]: 'clash-aarch64-unknown-linux-gnu', [SupportedArch.LinuxAmd64]: 'clash-x86_64-unknown-linux-gnu-static-crt', - [SupportedArch.LinuxI386]: 'clash-i686-unknown-linux-gnu-static-crt', + [SupportedArch.LinuxI386]: 'clash-i686-unknown-linux-gnu', [SupportedArch.DarwinArm64]: 'clash-aarch64-apple-darwin', [SupportedArch.DarwinX64]: 'clash-x86_64-apple-darwin', - [SupportedArch.LinuxArmv7]: 'clash-armv7-unknown-linux-gnueabi-static-crt', + [SupportedArch.LinuxArmv7]: 'clash-armv7-unknown-linux-gnueabi', [SupportedArch.LinuxArmv7hf]: 'clash-armv7-unknown-linux-gnueabihf', } satisfies ArchMapping diff --git a/clash-nyanpasu/scripts/utils/resource.ts b/clash-nyanpasu/scripts/utils/resource.ts index cacda57d36..0debc056ef 100644 --- a/clash-nyanpasu/scripts/utils/resource.ts +++ b/clash-nyanpasu/scripts/utils/resource.ts @@ -1,5 +1,5 @@ // import { ArchMapping } from 'utils/manifest'; -import fetch, { type RequestInit } from 'node-fetch' +import { fetch, type RequestInit } from 'undici' import { CLASH_META_ALPHA_MANIFEST, CLASH_META_MANIFEST, @@ -219,7 +219,7 @@ export const getClashRsAlphaLatestVersion = async () => { const httpProxy = getProxyAgent() if (httpProxy) { - opts.agent = httpProxy + opts.dispatcher = httpProxy } const response = await fetch(VERSION_URL!, { @@ -281,7 +281,7 @@ export const getMetaAlphaLatestVersion = async () => { const httpProxy = getProxyAgent() if (httpProxy) { - opts.agent = httpProxy + opts.dispatcher = httpProxy } const response = await fetch(VERSION_URL!, { @@ -307,7 +307,7 @@ export const getNyanpasuServiceLatestVersion = async () => { const httpProxy = getProxyAgent() if (httpProxy) { - opts.agent = httpProxy + opts.dispatcher = httpProxy } const url = new URL('https://github.com') diff --git a/filebrowser/frontend/src/i18n/it.json b/filebrowser/frontend/src/i18n/it.json index bf09156df2..0205b955d1 100644 --- a/filebrowser/frontend/src/i18n/it.json +++ b/filebrowser/frontend/src/i18n/it.json @@ -7,13 +7,13 @@ "copy": "Copia", "copyFile": "Copia file", "copyToClipboard": "Copia negli appunti", - "copyDownloadLinkToClipboard": "Copy download link to clipboard", + "copyDownloadLinkToClipboard": "Copia link di scarica negli appunti", "create": "Crea", "delete": "Elimina", "download": "Scarica", "file": "File", - "folder": "Folder", - "fullScreen": "Toggle full screen", + "folder": "Cartella", + "fullScreen": "Abilita schermo intero", "hideDotfiles": "Nascondi dotfile", "info": "Informazioni", "more": "Altro", @@ -24,7 +24,7 @@ "ok": "OK", "permalink": "Ottieni link permanente", "previous": "Precedente", - "preview": "Preview", + "preview": "Anteprima", "publish": "Publica", "rename": "Rinomina", "replace": "Sostituisci", @@ -36,13 +36,13 @@ "selectMultiple": "Seleziona molteplici", "share": "Condividi", "shell": "Mostra/nascondi shell", - "submit": "Submit", + "submit": "Invia", "switchView": "Cambia vista", "toggleSidebar": "Mostra/nascondi la barra laterale", "update": "Aggiorna", "upload": "Carica", - "openFile": "Open file", - "discardChanges": "Discard" + "openFile": "Apri file", + "discardChanges": "Ignora" }, "download": { "downloadFile": "Scarica file", @@ -50,13 +50,13 @@ "downloadSelected": "Scarica selezionati" }, "upload": { - "abortUpload": "Are you sure you wish to abort?" + "abortUpload": "Sei sicuro di voler abortire la procedura?" }, "errors": { "forbidden": "Non hai i permessi per accedere a questo file.", "internal": "Qualcosa è andato veramente male.", "notFound": "Questo percorso non può essere raggiunto.", - "connection": "The server can't be reached." + "connection": "Il server non è raggiungibile" }, "files": { "body": "Contenuto", @@ -74,7 +74,7 @@ "sortByLastModified": "Ordina per ultima modifica", "sortByName": "Ordina per nome", "sortBySize": "Ordina per dimensione", - "noPreview": "Preview is not available for this file." + "noPreview": "L'anteprima non è disponibile per questo file." }, "help": { "click": "seleziona un file o una cartella", @@ -109,8 +109,8 @@ "currentlyNavigating": "Attualmente navigando su:", "deleteMessageMultiple": "Sei sicuro di voler eliminare {count} file?", "deleteMessageSingle": "Sei sicuro di voler eliminare questo file/cartella?", - "deleteMessageShare": "Are you sure you wish to delete this share({path})?", - "deleteUser": "Are you sure you want to delete this user?", + "deleteMessageShare": "Sei sicuro di voler eliminare questo percorso condiviso ({path})?", + "deleteUser": "Sei sicuro di voler eliminare questo utente?", "deleteTitle": "Elimina", "displayName": "Nome visualizzato:", "download": "Scarica files", @@ -137,11 +137,11 @@ "show": "Mostra", "size": "Dimensione", "upload": "Carica", - "uploadFiles": "Uploading {files} files...", + "uploadFiles": "Inviando {files} file...", "uploadMessage": "Seleziona un'opzione per il caricamento.", - "optionalPassword": "Optional password", - "resolution": "Resolution", - "discardEditorChanges": "Are you sure you wish to discard the changes you've made?" + "optionalPassword": "Password opzionale", + "resolution": "Risoluzione", + "discardEditorChanges": "Sei sicuro di voler scartare le modifiche apportate?" }, "search": { "images": "Immagini", @@ -170,14 +170,14 @@ "commandRunnerHelp": "Qui puoi impostare i comandi da eseguire negli eventi nominati. Ne devi scrivere uno per riga. Le variabili d'ambiente {0} e {1} sono disponibili, essendo {0} relativo a {1}. Per altre informazioni su questa funzionalità e sulle variabili d'ambiente utilizzabili, leggi la {2}.", "commandsUpdated": "Comandi aggiornati!", "createUserDir": "Crea automaticamente la home directory dell'utente quando lo aggiungi", - "minimumPasswordLength": "Minimum password length", - "tusUploads": "Chunked Uploads", - "tusUploadsHelp": "File Browser supports chunked file uploads, allowing for the creation of efficient, reliable, resumable and chunked file uploads even on unreliable networks.", - "tusUploadsChunkSize": "Indicates to maximum size of a request (direct uploads will be used for smaller uploads). You may input a plain integer denoting byte size input or a string like 10MB, 1GB etc.", - "tusUploadsRetryCount": "Number of retries to perform if a chunk fails to upload.", - "userHomeBasePath": "Base path for user home directories", - "userScopeGenerationPlaceholder": "The scope will be auto generated", - "createUserHomeDirectory": "Create user home directory", + "minimumPasswordLength": "Lunghezza minima della password", + "tusUploads": "Tranci di invii", + "tusUploadsHelp": "File Browser supporta tranci di invii fornendo così la possibilità di inviare efficientemente i file anche su reti instabili.", + "tusUploadsChunkSize": "Indica la dimensione massima di una richiesta (invii diretti saranno usati per piccoli invii). Puoi inserire un numero intero per indicare la dimensione in byte, oppure una stringa con l'unità di misura come in 10MB, 1GB, etc.", + "tusUploadsRetryCount": "Numero di tentativi da effettuare se un trancio di file fallisce.", + "userHomeBasePath": "Percorso base per le cartelle utente", + "userScopeGenerationPlaceholder": "La portata verrà autogenerata", + "createUserHomeDirectory": "Crea cartella utente", "customStylesheet": "Foglio di stile personalizzato", "defaultUserDescription": "Queste sono le impostazioni predefinite per i nuovi utenti.", "disableExternalLinks": "Disabilita link esterni (tranne per la documentazione)", @@ -217,14 +217,14 @@ "rules": "Regole", "rulesHelp": "Qui è possibile definire una serie di regole e permessi per questo specifico utente. I file bloccati non appariranno negli elenchi e non saranno accessibili dagli utenti. all'utente. Sia regex che i percorsi relativi all'ambito di applicazione degli utenti sono supportati.\n", "scope": "Scope", - "setDateFormat": "Set exact date format", + "setDateFormat": "Fissa il formato di data esatto", "settingsUpdated": "Impostazioni aggiornate!", "shareDuration": "Durata della condivisione", "shareManagement": "Gestione delle condivisioni", - "shareDeleted": "Share deleted!", + "shareDeleted": "Percorso condiviso eliminato!", "singleClick": "Usa un singolo click per aprire file e cartelle", "themes": { - "default": "System default", + "default": "Impostazione predefinita del sistema", "dark": "Scuro", "light": "Chiaro", "title": "Tema" diff --git a/filebrowser/frontend/src/i18n/uk.json b/filebrowser/frontend/src/i18n/uk.json index aa4080df4b..08bb9cfd86 100644 --- a/filebrowser/frontend/src/i18n/uk.json +++ b/filebrowser/frontend/src/i18n/uk.json @@ -173,15 +173,15 @@ "minimumPasswordLength": "Мінімальна довжина паролю", "tusUploads": "Фрагментовані завантаження", "tusUploadsHelp": "File Browser підтримує завантаження частинами, дозволяючи створення ефективних, надійних, відновлюваних та фрагментованих завантажень навіть при ненадійному з'єднанні.", - "tusUploadsChunkSize": "Вказує на максимальний розмір запиту (для менших завантажень використовуватиметься пряме завантаження). Ви можете ввести цілочисельне значення у байтах або ж рядок на кшталт 10MB, 1GB тощо.", - "tusUploadsRetryCount": "Кількість повторних спроб які потрібно виконати, якщо фрагмент не вдалося завантажити.", + "tusUploadsChunkSize": "Максимальний розмір запиту (для менших завантажень використовуватиметься пряме завантаження). Ви можете ввести цілочисельне значення у байтах або ж рядок на кшталт 10MB, 1GB тощо", + "tusUploadsRetryCount": "Кількість повторних спроб які потрібно виконати, якщо фрагмент не вдалося завантажити", "userHomeBasePath": "Основний шлях для домашніх каталогів користувачів", "userScopeGenerationPlaceholder": "Кореневий каталог буде згенеровано автоматично", "createUserHomeDirectory": "Створити домашній каталог користувача", "customStylesheet": "Свій стиль", "defaultUserDescription": "Це налаштування за замовчуванням для нових користувачів.", "disableExternalLinks": "Вимкнути зовнішні посилання (крім документації)", - "disableUsedDiskPercentage": "Disable used disk percentage graph", + "disableUsedDiskPercentage": "Вимкнути графік використання диску", "documentation": "документація", "examples": "Приклади", "executeOnShell": "Виконати в командному рядку", @@ -231,7 +231,7 @@ }, "user": "Користувач", "userCommands": "Команди", - "userCommandsHelp": "Список команд, доступних користувачу, розділений пробілами. Приклад:\n", + "userCommandsHelp": "Список команд, доступних користувачу, розділений пробілами. Наприклад:\n", "userCreated": "Користувача створено!", "userDefaults": "Налаштування користувача за замовчуванням", "userDeleted": "Користувача видалено!", diff --git a/lede/package/utils/mdadm/Makefile b/lede/package/utils/mdadm/Makefile index 9a56eff8a3..d6eeb69e82 100644 --- a/lede/package/utils/mdadm/Makefile +++ b/lede/package/utils/mdadm/Makefile @@ -8,17 +8,18 @@ include $(TOPDIR)/rules.mk PKG_NAME:=mdadm -PKG_VERSION:=4.2 -PKG_RELEASE:=2 +PKG_VERSION:=4.4 +PKG_RELEASE:=1 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.xz PKG_SOURCE_URL:=@KERNEL/linux/utils/raid/mdadm -PKG_HASH:=461c215670864bb74a4d1a3620684aa2b2f8296dffa06743f26dda5557acf01d +PKG_HASH:=9b488f35ed153df99924b5fe41eed380e8512de8f18a118628cacdd681b1d573 PKG_MAINTAINER:=Felix Fietkau PKG_CPE_ID:=cpe:/a:mdadm_project:mdadm PKG_BUILD_PARALLEL:=1 +PKG_BUILD_FLAGS:=gc-sections include $(INCLUDE_DIR)/package.mk @@ -43,7 +44,6 @@ define Package/mdadm/conffiles endef TARGET_CFLAGS += \ - -ffunction-sections -fdata-sections \ -DHAVE_STDINT_H -DNO_COROSYNC -DNO_DLM -DUSE_PTHREADS \ -DCONFFILE='\"/var/etc/mdadm.conf\"' \ -DMAP_DIR='\"/var/run/mdadm\"' \ @@ -54,8 +54,6 @@ TARGET_CFLAGS += \ TARGET_CXFLAGS = -DNO_LIBUDEV -TARGET_LDFLAGS += -Wl,--gc-sections - MAKE_FLAGS += \ CHECK_RUN_DIR=0 \ CXFLAGS="$(TARGET_CXFLAGS)" diff --git a/lede/package/utils/mdadm/patches/100-cross_compile.patch b/lede/package/utils/mdadm/patches/100-cross_compile.patch index 790d7755b0..2f9772ee75 100644 --- a/lede/package/utils/mdadm/patches/100-cross_compile.patch +++ b/lede/package/utils/mdadm/patches/100-cross_compile.patch @@ -1,6 +1,6 @@ --- a/Makefile +++ b/Makefile -@@ -99,7 +99,7 @@ DLM:=$(shell [ -f /usr/include/libdlm.h +@@ -136,7 +136,7 @@ DLM:=$(shell [ -f /usr/include/libdlm.h ] || echo -DNO_DLM) DIRFLAGS = -DMAP_DIR=\"$(MAP_DIR)\" -DMAP_FILE=\"$(MAP_FILE)\" DIRFLAGS += -DMDMON_DIR=\"$(MDMON_DIR)\" DIRFLAGS += -DFAILED_SLOTS_DIR=\"$(FAILED_SLOTS_DIR)\" diff --git a/lede/package/utils/mdadm/patches/200-reduce_size.patch b/lede/package/utils/mdadm/patches/200-reduce_size.patch index 163e125c22..6c339f6938 100644 --- a/lede/package/utils/mdadm/patches/200-reduce_size.patch +++ b/lede/package/utils/mdadm/patches/200-reduce_size.patch @@ -1,6 +1,6 @@ --- a/Incremental.c +++ b/Incremental.c -@@ -983,6 +983,10 @@ static int array_try_spare(char *devname +@@ -993,6 +993,10 @@ static int array_try_spare(char *devname, int *dfdp, struct dev_policy *pol, goto next; } @@ -13,7 +13,7 @@ /* domain test fails */ --- a/util.c +++ b/util.c -@@ -1147,7 +1147,9 @@ void wait_for(char *dev, int fd) +@@ -1162,7 +1162,9 @@ void wait_for(char *dev, int fd) struct superswitch *superlist[] = { &super0, &super1, diff --git a/mieru/Makefile b/mieru/Makefile index 4782b1504e..eb194f204c 100644 --- a/mieru/Makefile +++ b/mieru/Makefile @@ -32,7 +32,7 @@ PROJECT_NAME=$(shell basename "${ROOT}") # - pkg/version/current.go # # Use `tools/bump_version.sh` script to change all those files at one shot. -VERSION="3.19.1" +VERSION="3.19.2" # Build binaries and installation packages. .PHONY: build diff --git a/mieru/build/package/mieru/amd64/debian/DEBIAN/control b/mieru/build/package/mieru/amd64/debian/DEBIAN/control index 4f72a9f23d..eae05849ce 100755 --- a/mieru/build/package/mieru/amd64/debian/DEBIAN/control +++ b/mieru/build/package/mieru/amd64/debian/DEBIAN/control @@ -1,5 +1,5 @@ Package: mieru -Version: 3.19.1 +Version: 3.19.2 Section: net Priority: optional Architecture: amd64 diff --git a/mieru/build/package/mieru/amd64/rpm/mieru.spec b/mieru/build/package/mieru/amd64/rpm/mieru.spec index b8d5551bcc..6a169a5c04 100644 --- a/mieru/build/package/mieru/amd64/rpm/mieru.spec +++ b/mieru/build/package/mieru/amd64/rpm/mieru.spec @@ -1,5 +1,5 @@ Name: mieru -Version: 3.19.1 +Version: 3.19.2 Release: 1%{?dist} Summary: Mieru proxy client License: GPLv3+ diff --git a/mieru/build/package/mieru/arm64/debian/DEBIAN/control b/mieru/build/package/mieru/arm64/debian/DEBIAN/control index 67d53d3830..58cfd95dae 100755 --- a/mieru/build/package/mieru/arm64/debian/DEBIAN/control +++ b/mieru/build/package/mieru/arm64/debian/DEBIAN/control @@ -1,5 +1,5 @@ Package: mieru -Version: 3.19.1 +Version: 3.19.2 Section: net Priority: optional Architecture: arm64 diff --git a/mieru/build/package/mieru/arm64/rpm/mieru.spec b/mieru/build/package/mieru/arm64/rpm/mieru.spec index b8d5551bcc..6a169a5c04 100644 --- a/mieru/build/package/mieru/arm64/rpm/mieru.spec +++ b/mieru/build/package/mieru/arm64/rpm/mieru.spec @@ -1,5 +1,5 @@ Name: mieru -Version: 3.19.1 +Version: 3.19.2 Release: 1%{?dist} Summary: Mieru proxy client License: GPLv3+ diff --git a/mieru/build/package/mita/amd64/debian/DEBIAN/control b/mieru/build/package/mita/amd64/debian/DEBIAN/control index b4502eb408..d227349d18 100755 --- a/mieru/build/package/mita/amd64/debian/DEBIAN/control +++ b/mieru/build/package/mita/amd64/debian/DEBIAN/control @@ -1,5 +1,5 @@ Package: mita -Version: 3.19.1 +Version: 3.19.2 Section: net Priority: optional Architecture: amd64 diff --git a/mieru/build/package/mita/amd64/rpm/mita.spec b/mieru/build/package/mita/amd64/rpm/mita.spec index 0441fc352b..d4f8c3084c 100644 --- a/mieru/build/package/mita/amd64/rpm/mita.spec +++ b/mieru/build/package/mita/amd64/rpm/mita.spec @@ -1,5 +1,5 @@ Name: mita -Version: 3.19.1 +Version: 3.19.2 Release: 1%{?dist} Summary: Mieru proxy server License: GPLv3+ diff --git a/mieru/build/package/mita/arm64/debian/DEBIAN/control b/mieru/build/package/mita/arm64/debian/DEBIAN/control index c1ba559d3a..5ee1f06bb5 100755 --- a/mieru/build/package/mita/arm64/debian/DEBIAN/control +++ b/mieru/build/package/mita/arm64/debian/DEBIAN/control @@ -1,5 +1,5 @@ Package: mita -Version: 3.19.1 +Version: 3.19.2 Section: net Priority: optional Architecture: arm64 diff --git a/mieru/build/package/mita/arm64/rpm/mita.spec b/mieru/build/package/mita/arm64/rpm/mita.spec index 3d0d26c937..600d6a52af 100644 --- a/mieru/build/package/mita/arm64/rpm/mita.spec +++ b/mieru/build/package/mita/arm64/rpm/mita.spec @@ -1,5 +1,5 @@ Name: mita -Version: 3.19.1 +Version: 3.19.2 Release: 1%{?dist} Summary: Mieru proxy server License: GPLv3+ diff --git a/mieru/docs/server-install.md b/mieru/docs/server-install.md index 3841f856aa..8e11a840a6 100644 --- a/mieru/docs/server-install.md +++ b/mieru/docs/server-install.md @@ -18,32 +18,32 @@ Or you can manually install and configure proxy server using the steps below. ```sh # Debian / Ubuntu - X86_64 -curl -LSO https://github.com/enfein/mieru/releases/download/v3.19.1/mita_3.19.1_amd64.deb +curl -LSO https://github.com/enfein/mieru/releases/download/v3.19.2/mita_3.19.2_amd64.deb # Debian / Ubuntu - ARM 64 -curl -LSO https://github.com/enfein/mieru/releases/download/v3.19.1/mita_3.19.1_arm64.deb +curl -LSO https://github.com/enfein/mieru/releases/download/v3.19.2/mita_3.19.2_arm64.deb # RedHat / CentOS / Rocky Linux - X86_64 -curl -LSO https://github.com/enfein/mieru/releases/download/v3.19.1/mita-3.19.1-1.x86_64.rpm +curl -LSO https://github.com/enfein/mieru/releases/download/v3.19.2/mita-3.19.2-1.x86_64.rpm # RedHat / CentOS / Rocky Linux - ARM 64 -curl -LSO https://github.com/enfein/mieru/releases/download/v3.19.1/mita-3.19.1-1.aarch64.rpm +curl -LSO https://github.com/enfein/mieru/releases/download/v3.19.2/mita-3.19.2-1.aarch64.rpm ``` ## Install mita package ```sh # Debian / Ubuntu - X86_64 -sudo dpkg -i mita_3.19.1_amd64.deb +sudo dpkg -i mita_3.19.2_amd64.deb # Debian / Ubuntu - ARM 64 -sudo dpkg -i mita_3.19.1_arm64.deb +sudo dpkg -i mita_3.19.2_arm64.deb # RedHat / CentOS / Rocky Linux - X86_64 -sudo rpm -Uvh --force mita-3.19.1-1.x86_64.rpm +sudo rpm -Uvh --force mita-3.19.2-1.x86_64.rpm # RedHat / CentOS / Rocky Linux - ARM 64 -sudo rpm -Uvh --force mita-3.19.1-1.aarch64.rpm +sudo rpm -Uvh --force mita-3.19.2-1.aarch64.rpm ``` Those instructions can also be used to upgrade the version of mita software package. diff --git a/mieru/docs/server-install.zh_CN.md b/mieru/docs/server-install.zh_CN.md index 8a8bcd140a..dcb7d675f7 100644 --- a/mieru/docs/server-install.zh_CN.md +++ b/mieru/docs/server-install.zh_CN.md @@ -18,32 +18,32 @@ sudo python3 setup.py --lang=zh ```sh # Debian / Ubuntu - X86_64 -curl -LSO https://github.com/enfein/mieru/releases/download/v3.19.1/mita_3.19.1_amd64.deb +curl -LSO https://github.com/enfein/mieru/releases/download/v3.19.2/mita_3.19.2_amd64.deb # Debian / Ubuntu - ARM 64 -curl -LSO https://github.com/enfein/mieru/releases/download/v3.19.1/mita_3.19.1_arm64.deb +curl -LSO https://github.com/enfein/mieru/releases/download/v3.19.2/mita_3.19.2_arm64.deb # RedHat / CentOS / Rocky Linux - X86_64 -curl -LSO https://github.com/enfein/mieru/releases/download/v3.19.1/mita-3.19.1-1.x86_64.rpm +curl -LSO https://github.com/enfein/mieru/releases/download/v3.19.2/mita-3.19.2-1.x86_64.rpm # RedHat / CentOS / Rocky Linux - ARM 64 -curl -LSO https://github.com/enfein/mieru/releases/download/v3.19.1/mita-3.19.1-1.aarch64.rpm +curl -LSO https://github.com/enfein/mieru/releases/download/v3.19.2/mita-3.19.2-1.aarch64.rpm ``` ## 安装 mita 软件包 ```sh # Debian / Ubuntu - X86_64 -sudo dpkg -i mita_3.19.1_amd64.deb +sudo dpkg -i mita_3.19.2_amd64.deb # Debian / Ubuntu - ARM 64 -sudo dpkg -i mita_3.19.1_arm64.deb +sudo dpkg -i mita_3.19.2_arm64.deb # RedHat / CentOS / Rocky Linux - X86_64 -sudo rpm -Uvh --force mita-3.19.1-1.x86_64.rpm +sudo rpm -Uvh --force mita-3.19.2-1.x86_64.rpm # RedHat / CentOS / Rocky Linux - ARM 64 -sudo rpm -Uvh --force mita-3.19.1-1.aarch64.rpm +sudo rpm -Uvh --force mita-3.19.2-1.aarch64.rpm ``` 上述指令也可以用来升级 mita 软件包的版本。 diff --git a/mieru/pkg/version/current.go b/mieru/pkg/version/current.go index 4a50b3e650..d59fea2da2 100644 --- a/mieru/pkg/version/current.go +++ b/mieru/pkg/version/current.go @@ -16,5 +16,5 @@ package version const ( - AppVersion = "3.19.1" + AppVersion = "3.19.2" ) diff --git a/mihomo/common/net/sing.go b/mihomo/common/net/sing.go index 5cf9759427..3545b6a407 100644 --- a/mihomo/common/net/sing.go +++ b/mihomo/common/net/sing.go @@ -26,11 +26,20 @@ type ReadWaitOptions = network.ReadWaitOptions var NewReadWaitOptions = network.NewReadWaitOptions +type ReaderWithUpstream = network.ReaderWithUpstream +type WithUpstreamReader = network.WithUpstreamReader +type WriterWithUpstream = network.WriterWithUpstream +type WithUpstreamWriter = network.WithUpstreamWriter +type WithUpstream = common.WithUpstream + +var UnwrapReader = network.UnwrapReader +var UnwrapWriter = network.UnwrapWriter + func NewDeadlineConn(conn net.Conn) ExtendedConn { - if deadline.IsPipe(conn) || deadline.IsPipe(network.UnwrapReader(conn)) { + if deadline.IsPipe(conn) || deadline.IsPipe(UnwrapReader(conn)) { return NewExtendedConn(conn) // pipe always have correctly deadline implement } - if deadline.IsConn(conn) || deadline.IsConn(network.UnwrapReader(conn)) { + if deadline.IsConn(conn) || deadline.IsConn(UnwrapReader(conn)) { return NewExtendedConn(conn) // was a *deadline.Conn } return deadline.NewConn(conn) diff --git a/mihomo/go.mod b/mihomo/go.mod index faa4acbd27..d413c488f0 100644 --- a/mihomo/go.mod +++ b/mihomo/go.mod @@ -25,7 +25,7 @@ require ( github.com/metacubex/randv2 v0.2.0 github.com/metacubex/restls-client-go v0.1.7 github.com/metacubex/sing v0.5.6-0.20250903022707-c9bf6d825f4d - github.com/metacubex/sing-mux v0.3.3-0.20250813083925-d7c9aeaeeaac + github.com/metacubex/sing-mux v0.3.3 github.com/metacubex/sing-quic v0.0.0-20250718154553-1b193bec4cbb github.com/metacubex/sing-shadowsocks v0.2.12 github.com/metacubex/sing-shadowsocks2 v0.2.6 diff --git a/mihomo/go.sum b/mihomo/go.sum index 369c23543a..f9547b1cd1 100644 --- a/mihomo/go.sum +++ b/mihomo/go.sum @@ -119,8 +119,8 @@ github.com/metacubex/restls-client-go v0.1.7/go.mod h1:BN/U52vPw7j8VTSh2vleD/Mnm github.com/metacubex/sing v0.5.2/go.mod h1:ypf0mjwlZm0sKdQSY+yQvmsbWa0hNPtkeqyRMGgoN+w= github.com/metacubex/sing v0.5.6-0.20250903022707-c9bf6d825f4d h1:oprae0GgOxsKpEDa8+pF0WMPrUhpKDRJtBWPAxcy3yo= github.com/metacubex/sing v0.5.6-0.20250903022707-c9bf6d825f4d/go.mod h1:ypf0mjwlZm0sKdQSY+yQvmsbWa0hNPtkeqyRMGgoN+w= -github.com/metacubex/sing-mux v0.3.3-0.20250813083925-d7c9aeaeeaac h1:wDH/Jh/yqWbzPktqJP+Y1cUG8hchcrzKzUxJiSpnaQs= -github.com/metacubex/sing-mux v0.3.3-0.20250813083925-d7c9aeaeeaac/go.mod h1:3rt1soewn0O6j89GCLmwAQFsq257u0jf2zQSPhTL3Bw= +github.com/metacubex/sing-mux v0.3.3 h1:oqCbUAJgTLsa71vfo8otW8xIhrDfbc/Y2rmtW34sQjg= +github.com/metacubex/sing-mux v0.3.3/go.mod h1:3rt1soewn0O6j89GCLmwAQFsq257u0jf2zQSPhTL3Bw= github.com/metacubex/sing-quic v0.0.0-20250718154553-1b193bec4cbb h1:U/m3h8lp/j7i8zFgfvScLdZa1/Y8dd74oO7iZaQq80s= github.com/metacubex/sing-quic v0.0.0-20250718154553-1b193bec4cbb/go.mod h1:B60FxaPHjR1SeQB0IiLrgwgvKsaoASfOWdiqhLjmMGA= github.com/metacubex/sing-shadowsocks v0.2.12 h1:Wqzo8bYXrK5aWqxu/TjlTnYZzAKtKsaFQBdr6IHFaBE= diff --git a/mihomo/listener/sing/util.go b/mihomo/listener/sing/util.go index 306301621b..20d3e9709d 100644 --- a/mihomo/listener/sing/util.go +++ b/mihomo/listener/sing/util.go @@ -12,11 +12,14 @@ import ( func (h *ListenerHandler) HandleSocket(target socks5.Addr, conn net.Conn, _additions ...inbound.Addition) { conn, metadata := inbound.NewSocket(target, conn, h.Type, h.Additions...) if h.IsSpecialFqdn(metadata.Host) { - _ = h.ParseSpecialFqdn( + err := h.ParseSpecialFqdn( WithAdditions(context.Background(), _additions...), conn, ConvertMetadata(metadata), ) + if err != nil { + _ = conn.Close() + } } else { inbound.ApplyAdditions(metadata, _additions...) h.Tunnel.HandleTCPConn(conn, metadata) diff --git a/mihomo/listener/sing_vless/server.go b/mihomo/listener/sing_vless/server.go index 3a5943b5ab..d4fc397340 100644 --- a/mihomo/listener/sing_vless/server.go +++ b/mihomo/listener/sing_vless/server.go @@ -5,9 +5,7 @@ import ( "errors" "net" "net/http" - "reflect" "strings" - "unsafe" "github.com/metacubex/mihomo/adapter/inbound" "github.com/metacubex/mihomo/component/ca" @@ -17,48 +15,19 @@ import ( LC "github.com/metacubex/mihomo/listener/config" "github.com/metacubex/mihomo/listener/reality" "github.com/metacubex/mihomo/listener/sing" - "github.com/metacubex/mihomo/log" "github.com/metacubex/mihomo/transport/gun" "github.com/metacubex/mihomo/transport/vless/encryption" mihomoVMess "github.com/metacubex/mihomo/transport/vmess" - "github.com/metacubex/sing-vmess/vless" "github.com/metacubex/sing/common" "github.com/metacubex/sing/common/metadata" - "github.com/metacubex/sing/common/network" ) -func init() { - vless.RegisterTLS(func(conn net.Conn) (loaded bool, netConn net.Conn, reflectType reflect.Type, reflectPointer unsafe.Pointer) { - tlsConn, loaded := network.CastReader[*reality.Conn](conn) // *utls.Conn - if !loaded { - return - } - return true, tlsConn.NetConn(), reflect.TypeOf(tlsConn).Elem(), unsafe.Pointer(tlsConn) - }) - - vless.RegisterTLS(func(conn net.Conn) (loaded bool, netConn net.Conn, reflectType reflect.Type, reflectPointer unsafe.Pointer) { - tlsConn, loaded := network.CastReader[*tlsC.UConn](conn) // *utls.UConn - if !loaded { - return - } - return true, tlsConn.NetConn(), reflect.TypeOf(tlsConn.Conn).Elem(), unsafe.Pointer(tlsConn.Conn) - }) - - vless.RegisterTLS(func(conn net.Conn) (loaded bool, netConn net.Conn, reflectType reflect.Type, reflectPointer unsafe.Pointer) { - tlsConn, loaded := network.CastReader[*encryption.CommonConn](conn) - if !loaded { - return - } - return true, tlsConn.Conn, reflect.TypeOf(tlsConn).Elem(), unsafe.Pointer(tlsConn) - }) -} - type Listener struct { closed bool config LC.VlessServer listeners []net.Listener - service *vless.Service[string] + service *Service[string] decryption *encryption.ServerInstance } @@ -79,7 +48,7 @@ func New(config LC.VlessServer, tunnel C.Tunnel, additions ...inbound.Addition) return nil, err } - service := vless.NewService[string](log.SingLogger, h) + service := NewService[string](h) service.UpdateUsers( common.Map(config.Users, func(it LC.VlessUser) string { return it.Username diff --git a/mihomo/listener/sing_vless/service.go b/mihomo/listener/sing_vless/service.go new file mode 100644 index 0000000000..d30b3c018f --- /dev/null +++ b/mihomo/listener/sing_vless/service.go @@ -0,0 +1,304 @@ +package sing_vless + +// copy and modify from https://github.com/SagerNet/sing-vmess/tree/3c1cf255413250b09a57e4ecdf1def1fa505e3cc/vless + +import ( + "context" + "encoding/binary" + "io" + "net" + + "github.com/metacubex/mihomo/transport/vless" + "github.com/metacubex/mihomo/transport/vless/vision" + + "github.com/gofrs/uuid/v5" + "github.com/metacubex/sing-vmess" + "github.com/metacubex/sing/common/auth" + "github.com/metacubex/sing/common/buf" + "github.com/metacubex/sing/common/bufio" + E "github.com/metacubex/sing/common/exceptions" + M "github.com/metacubex/sing/common/metadata" + N "github.com/metacubex/sing/common/network" + "google.golang.org/protobuf/proto" +) + +type Service[T comparable] struct { + userMap map[[16]byte]T + userFlow map[T]string + handler Handler +} + +type Handler interface { + N.TCPConnectionHandler + N.UDPConnectionHandler + E.Handler +} + +func NewService[T comparable](handler Handler) *Service[T] { + return &Service[T]{ + handler: handler, + } +} + +func (s *Service[T]) UpdateUsers(userList []T, userUUIDList []string, userFlowList []string) { + userMap := make(map[[16]byte]T) + userFlowMap := make(map[T]string) + for i, userName := range userList { + userID, err := uuid.FromString(userUUIDList[i]) + if err != nil { + userID = uuid.NewV5(uuid.Nil, userUUIDList[i]) + } + userMap[userID] = userName + userFlowMap[userName] = userFlowList[i] + } + s.userMap = userMap + s.userFlow = userFlowMap +} + +var _ N.TCPConnectionHandler = (*Service[int])(nil) + +func (s *Service[T]) NewConnection(ctx context.Context, conn net.Conn, metadata M.Metadata) error { + var version uint8 + err := binary.Read(conn, binary.BigEndian, &version) + if err != nil { + return err + } + if version != vless.Version { + return E.New("unknown version: ", version) + } + + var requestUUID [16]byte + _, err = io.ReadFull(conn, requestUUID[:]) + if err != nil { + return err + } + + var addonsLen uint8 + err = binary.Read(conn, binary.BigEndian, &addonsLen) + if err != nil { + return err + } + + var addons vless.Addons + if addonsLen > 0 { + addonsBytes := make([]byte, addonsLen) + _, err = io.ReadFull(conn, addonsBytes) + if err != nil { + return err + } + + err = proto.Unmarshal(addonsBytes, &addons) + if err != nil { + return err + } + } + + var command byte + err = binary.Read(conn, binary.BigEndian, &command) + if err != nil { + return err + } + + var destination M.Socksaddr + if command != vless.CommandMux { + destination, err = vmess.AddressSerializer.ReadAddrPort(conn) + if err != nil { + return err + } + } + + user, loaded := s.userMap[requestUUID] + if !loaded { + return E.New("unknown UUID: ", uuid.FromBytesOrNil(requestUUID[:])) + } + ctx = auth.ContextWithUser(ctx, user) + metadata.Destination = destination + + userFlow := s.userFlow[user] + requestFlow := addons.Flow + if requestFlow != userFlow && requestFlow != "" { + return E.New("flow mismatch: expected ", flowName(userFlow), ", but got ", flowName(requestFlow)) + } + + responseConn := &serverConn{ExtendedConn: bufio.NewExtendedConn(conn)} + switch requestFlow { + case vless.XRV: + conn, err = vision.NewConn(responseConn, conn, requestUUID) + if err != nil { + return E.Cause(err, "initialize vision") + } + case "": + conn = responseConn + default: + return E.New("unknown flow: ", requestFlow) + } + switch command { + case vless.CommandTCP: + return s.handler.NewConnection(ctx, conn, metadata) + case vless.CommandUDP: + if requestFlow == vless.XRV { + return E.New(vless.XRV, " flow does not support UDP") + } + return s.handler.NewPacketConnection(ctx, &serverPacketConn{ExtendedConn: bufio.NewExtendedConn(conn), destination: destination}, metadata) + case vless.CommandMux: + return vmess.HandleMuxConnection(ctx, conn, metadata, s.handler) + default: + return E.New("unknown command: ", command) + } +} + +func flowName(value string) string { + if value == "" { + return "none" + } + return value +} + +type serverConn struct { + N.ExtendedConn + responseWritten bool +} + +func (c *serverConn) Write(b []byte) (n int, err error) { + if !c.responseWritten { + buffer := buf.NewSize(2 + len(b)) + buffer.WriteByte(vless.Version) + buffer.WriteByte(0) + buffer.Write(b) + _, err = c.ExtendedConn.Write(buffer.Bytes()) + buffer.Release() + if err == nil { + n = len(b) + } + c.responseWritten = true + return + } + return c.ExtendedConn.Write(b) +} + +func (c *serverConn) WriteBuffer(buffer *buf.Buffer) error { + if !c.responseWritten { + header := buffer.ExtendHeader(2) + header[0] = vless.Version + header[1] = 0 + c.responseWritten = true + } + return c.ExtendedConn.WriteBuffer(buffer) +} + +func (c *serverConn) FrontHeadroom() int { + if c.responseWritten { + return 0 + } + return 2 +} + +func (c *serverConn) ReaderReplaceable() bool { + return true +} + +func (c *serverConn) WriterReplaceable() bool { + return c.responseWritten +} + +func (c *serverConn) NeedAdditionalReadDeadline() bool { + return true +} + +func (c *serverConn) Upstream() any { + return c.ExtendedConn +} + +type serverPacketConn struct { + N.ExtendedConn + destination M.Socksaddr + readWaitOptions N.ReadWaitOptions +} + +func (c *serverPacketConn) InitializeReadWaiter(options N.ReadWaitOptions) (needCopy bool) { + c.readWaitOptions = options + return false +} + +func (c *serverPacketConn) WaitReadPacket() (buffer *buf.Buffer, destination M.Socksaddr, err error) { + var packetLen uint16 + err = binary.Read(c.ExtendedConn, binary.BigEndian, &packetLen) + if err != nil { + return + } + + buffer = c.readWaitOptions.NewPacketBuffer() + _, err = buffer.ReadFullFrom(c.ExtendedConn, int(packetLen)) + if err != nil { + buffer.Release() + return + } + c.readWaitOptions.PostReturn(buffer) + + destination = c.destination + return +} + +func (c *serverPacketConn) ReadFrom(p []byte) (n int, addr net.Addr, err error) { + var packetLen uint16 + err = binary.Read(c.ExtendedConn, binary.BigEndian, &packetLen) + if err != nil { + return + } + if len(p) < int(packetLen) { + err = io.ErrShortBuffer + return + } + n, err = io.ReadFull(c.ExtendedConn, p[:packetLen]) + if err != nil { + return + } + if c.destination.IsFqdn() { + addr = c.destination + } else { + addr = c.destination.UDPAddr() + } + return +} + +func (c *serverPacketConn) WriteTo(p []byte, addr net.Addr) (n int, err error) { + err = binary.Write(c.ExtendedConn, binary.BigEndian, uint16(len(p))) + if err != nil { + return + } + return c.ExtendedConn.Write(p) +} + +func (c *serverPacketConn) ReadPacket(buffer *buf.Buffer) (destination M.Socksaddr, err error) { + var packetLen uint16 + err = binary.Read(c.ExtendedConn, binary.BigEndian, &packetLen) + if err != nil { + return + } + + _, err = buffer.ReadFullFrom(c.ExtendedConn, int(packetLen)) + if err != nil { + return + } + + destination = c.destination + return +} + +func (c *serverPacketConn) WritePacket(buffer *buf.Buffer, destination M.Socksaddr) error { + packetLen := buffer.Len() + binary.BigEndian.PutUint16(buffer.ExtendHeader(2), uint16(packetLen)) + return c.ExtendedConn.WriteBuffer(buffer) +} + +func (c *serverPacketConn) FrontHeadroom() int { + return 2 +} + +func (c *serverPacketConn) NeedAdditionalReadDeadline() bool { + return true +} + +func (c *serverPacketConn) Upstream() any { + return c.ExtendedConn +} diff --git a/mihomo/transport/vless/addons.go b/mihomo/transport/vless/addons.go new file mode 100644 index 0000000000..2257adeb9f --- /dev/null +++ b/mihomo/transport/vless/addons.go @@ -0,0 +1,61 @@ +package vless + +import ( + "bytes" + "encoding/binary" + "fmt" + "io" +) + +func ReadAddons(data []byte) (*Addons, error) { + reader := bytes.NewReader(data) + var addons Addons + for reader.Len() > 0 { + protoHeader, err := reader.ReadByte() + if err != nil { + return nil, err + } + switch protoHeader { + case (1 << 3) | 2: + flowLen, err := binary.ReadUvarint(reader) + if err != nil { + return nil, err + } + flowBytes := make([]byte, flowLen) + _, err = io.ReadFull(reader, flowBytes) + if err != nil { + return nil, err + } + addons.Flow = string(flowBytes) + case (2 << 3) | 2: + seedLen, err := binary.ReadUvarint(reader) + if err != nil { + return nil, err + } + seedBytes := make([]byte, seedLen) + _, err = io.ReadFull(reader, seedBytes) + if err != nil { + return nil, err + } + addons.Seed = seedBytes + default: + return nil, fmt.Errorf("unknown protobuf message header: %v", protoHeader) + } + } + return &addons, nil +} + +func WriteAddons(addons *Addons) []byte { + var writer bytes.Buffer + if len(addons.Flow) > 0 { + writer.WriteByte((1 << 3) | 2) + writer.Write(binary.AppendUvarint(nil, uint64(len(addons.Flow)))) + writer.WriteString(addons.Flow) + } + if len(addons.Seed) > 0 { + writer.WriteByte((2 << 3) | 2) + writer.Write(binary.AppendUvarint(nil, uint64(len(addons.Seed)))) + writer.Write(addons.Seed) + } + return writer.Bytes() +} diff --git a/mihomo/transport/vless/addons_test.go b/mihomo/transport/vless/addons_test.go new file mode 100644 index 0000000000..60a27a069a --- /dev/null +++ b/mihomo/transport/vless/addons_test.go @@ -0,0 +1,95 @@ +package vless + +import ( + "bytes" + "strconv" + "testing" + + "google.golang.org/protobuf/proto" +) + +func TestAddons(t *testing.T) { + var tests = []struct { + flow string + seed []byte + }{ + {XRV, nil}, + {XRS, []byte{1, 2, 3}}, + {"", []byte{1, 2, 3}}, + {"", nil}, + } + + for i, test := range tests { + t.Run(strconv.Itoa(i), func(t *testing.T) { + t.Run("proto->handwritten", func(t *testing.T) { + addons := new(Addons) + addons.Flow = test.flow + addons.Seed = test.seed + + addonsBytes, err := proto.Marshal(addons) + if err != nil { + t.Errorf("error marshalling addons: %v", err) + return + } + addons, err = ReadAddons(addonsBytes) + if err != nil { + t.Errorf("error reading addons: %v", err) + return + } + + if addons.Flow != test.flow { + t.Errorf("got %v; want %v", addons.Flow, test.flow) + return + } + if !bytes.Equal(addons.Seed, test.seed) { + t.Errorf("got %v; want %v", addons.Seed, test.seed) + return + } + }) + + t.Run("handwritten->proto", func(t *testing.T) { + addons := new(Addons) + addons.Flow = test.flow + addons.Seed = test.seed + + addonsBytes := WriteAddons(addons) + err := proto.Unmarshal(addonsBytes, addons) + if err != nil { + t.Errorf("error reading addons: %v", err) + return + } + + if addons.Flow != test.flow { + t.Errorf("got %v; want %v", addons.Flow, test.flow) + return + } + if !bytes.Equal(addons.Seed, test.seed) { + t.Errorf("got %v; want %v", addons.Seed, test.seed) + return + } + }) + + t.Run("handwritten->handwritten", func(t *testing.T) { + addons := new(Addons) + addons.Flow = test.flow + addons.Seed = test.seed + + addonsBytes := WriteAddons(addons) + addons, err := ReadAddons(addonsBytes) + if err != nil { + t.Errorf("error reading addons: %v", err) + return + } + + if addons.Flow != test.flow { + t.Errorf("got %v; want %v", addons.Flow, test.flow) + return + } + if !bytes.Equal(addons.Seed, test.seed) { + t.Errorf("got %v; want %v", addons.Seed, test.seed) + return + } + }) + }) + } +} diff --git a/mihomo/transport/vless/conn.go b/mihomo/transport/vless/conn.go index 94ae71eee0..f43d77e180 100644 --- a/mihomo/transport/vless/conn.go +++ b/mihomo/transport/vless/conn.go @@ -5,7 +5,6 @@ import ( "errors" "io" "net" - "sync" "github.com/metacubex/mihomo/common/buf" N "github.com/metacubex/mihomo/common/net" @@ -16,17 +15,12 @@ import ( ) type Conn struct { - N.ExtendedWriter - N.ExtendedReader - net.Conn + N.ExtendedConn dst *DstAddr - id *uuid.UUID + id uuid.UUID addons *Addons received bool - - handshakeMutex sync.Mutex - needHandshake bool - err error + sent bool } func (vc *Conn) Read(b []byte) (int, error) { @@ -36,7 +30,7 @@ func (vc *Conn) Read(b []byte) (int, error) { } vc.received = true } - return vc.ExtendedReader.Read(b) + return vc.ExtendedConn.Read(b) } func (vc *Conn) ReadBuffer(buffer *buf.Buffer) error { @@ -46,58 +40,39 @@ func (vc *Conn) ReadBuffer(buffer *buf.Buffer) error { } vc.received = true } - return vc.ExtendedReader.ReadBuffer(buffer) + return vc.ExtendedConn.ReadBuffer(buffer) } func (vc *Conn) Write(p []byte) (int, error) { - if vc.needHandshake { - vc.handshakeMutex.Lock() - if vc.needHandshake { - vc.needHandshake = false - if vc.sendRequest(p) { - vc.handshakeMutex.Unlock() - if vc.err != nil { - return 0, vc.err - } - return len(p), vc.err - } - if vc.err != nil { - vc.handshakeMutex.Unlock() - return 0, vc.err - } + if !vc.sent { + if err := vc.sendRequest(p); err != nil { + return 0, err } - vc.handshakeMutex.Unlock() + vc.sent = true + return len(p), nil } - return vc.ExtendedWriter.Write(p) + return vc.ExtendedConn.Write(p) } func (vc *Conn) WriteBuffer(buffer *buf.Buffer) error { - if vc.needHandshake { - vc.handshakeMutex.Lock() - if vc.needHandshake { - vc.needHandshake = false - if vc.sendRequest(buffer.Bytes()) { - vc.handshakeMutex.Unlock() - return vc.err - } - if vc.err != nil { - vc.handshakeMutex.Unlock() - return vc.err - } + if !vc.sent { + if err := vc.sendRequest(buffer.Bytes()); err != nil { + return err } - vc.handshakeMutex.Unlock() + vc.sent = true + return nil } - return vc.ExtendedWriter.WriteBuffer(buffer) + return vc.ExtendedConn.WriteBuffer(buffer) } -func (vc *Conn) sendRequest(p []byte) bool { +func (vc *Conn) sendRequest(p []byte) (err error) { var addonsBytes []byte if vc.addons != nil { - addonsBytes, vc.err = proto.Marshal(vc.addons) - if vc.err != nil { - return true + addonsBytes, err = proto.Marshal(vc.addons) + if err != nil { + return } } @@ -141,15 +116,15 @@ func (vc *Conn) sendRequest(p []byte) bool { buf.Must(buf.Error(buffer.Write(p))) - _, vc.err = vc.ExtendedWriter.Write(buffer.Bytes()) - return true + _, err = vc.ExtendedConn.Write(buffer.Bytes()) + return } -func (vc *Conn) recvResponse() error { +func (vc *Conn) recvResponse() (err error) { var buffer [2]byte - _, vc.err = io.ReadFull(vc.ExtendedReader, buffer[:]) - if vc.err != nil { - return vc.err + _, err = io.ReadFull(vc.ExtendedConn, buffer[:]) + if err != nil { + return err } if buffer[0] != Version { @@ -158,29 +133,35 @@ func (vc *Conn) recvResponse() error { length := int64(buffer[1]) if length != 0 { // addon data length > 0 - io.CopyN(io.Discard, vc.ExtendedReader, length) // just discard + io.CopyN(io.Discard, vc.ExtendedConn, length) // just discard } - return nil + return } func (vc *Conn) Upstream() any { - return vc.Conn + return vc.ExtendedConn +} + +func (vc *Conn) ReaderReplaceable() bool { + return vc.received +} + +func (vc *Conn) WriterReplaceable() bool { + return vc.sent } func (vc *Conn) NeedHandshake() bool { - return vc.needHandshake + return !vc.sent } // newConn return a Conn instance func newConn(conn net.Conn, client *Client, dst *DstAddr) (net.Conn, error) { c := &Conn{ - ExtendedReader: N.NewExtendedReader(conn), - ExtendedWriter: N.NewExtendedWriter(conn), - Conn: conn, - id: client.uuid, - dst: dst, - needHandshake: true, + ExtendedConn: N.NewExtendedConn(conn), + id: client.uuid, + addons: client.Addons, + dst: dst, } if client.Addons != nil { @@ -190,7 +171,6 @@ func newConn(conn net.Conn, client *Client, dst *DstAddr) (net.Conn, error) { if err != nil { return nil, err } - c.addons = client.Addons return visionConn, nil } } diff --git a/mihomo/transport/vless/vision/conn.go b/mihomo/transport/vless/vision/conn.go index 7e778cf84c..fd9f787b50 100644 --- a/mihomo/transport/vless/vision/conn.go +++ b/mihomo/transport/vless/vision/conn.go @@ -2,7 +2,6 @@ package vision import ( "bytes" - "crypto/subtle" "encoding/binary" "errors" "fmt" @@ -24,15 +23,13 @@ type Conn struct { net.Conn // should be *vless.Conn N.ExtendedReader N.ExtendedWriter - userUUID *uuid.UUID + userUUID uuid.UUID - // tlsConn and it's internal variables - tlsConn net.Conn // maybe [*tls.Conn] or other tls-like conn + // [*tls.Conn] or other tls-like [net.Conn]'s internal variables netConn net.Conn // tlsConn.NetConn() input *bytes.Reader // &tlsConn.input or nil rawInput *bytes.Buffer // &tlsConn.rawInput or nil - needHandshake bool packetsToFilter int isTLS bool isTLS12orAbove bool @@ -46,6 +43,7 @@ type Conn struct { readLastCommand byte writeFilterApplicationData bool writeDirect bool + writeOnceUserUUID []byte } func (vc *Conn) Read(b []byte) (int, error) { @@ -58,8 +56,8 @@ func (vc *Conn) Read(b []byte) (int, error) { } func (vc *Conn) ReadBuffer(buffer *buf.Buffer) error { - toRead := buffer.FreeBytes() if vc.readRemainingContent > 0 { + toRead := buffer.FreeBytes() if vc.readRemainingContent < buffer.FreeLen() { toRead = toRead[:vc.readRemainingContent] } @@ -80,12 +78,12 @@ func (vc *Conn) ReadBuffer(buffer *buf.Buffer) error { switch vc.readLastCommand { case commandPaddingContinue: //if vc.isTLS || vc.packetsToFilter > 0 { - headerUUIDLen := 0 - if vc.readFilterUUID { - headerUUIDLen = uuid.Size + need := PaddingHeaderLen + if !vc.readFilterUUID { + need = PaddingHeaderLen - uuid.Size } var header []byte - if need := headerUUIDLen + PaddingHeaderLen - uuid.Size; buffer.FreeLen() < need { + if buffer.FreeLen() < need { header = make([]byte, need) } else { header = buffer.FreeBytes()[:need] @@ -96,9 +94,8 @@ func (vc *Conn) ReadBuffer(buffer *buf.Buffer) error { } if vc.readFilterUUID { vc.readFilterUUID = false - if subtle.ConstantTimeCompare(vc.userUUID.Bytes(), header[:uuid.Size]) != 1 { - err = fmt.Errorf("XTLS Vision server responded unknown UUID: %s", - uuid.FromBytesOrNil(header[:uuid.Size]).String()) + if !bytes.Equal(vc.userUUID.Bytes(), header[:uuid.Size]) { + err = fmt.Errorf("XTLS Vision server responded unknown UUID: %s", uuid.FromBytesOrNil(header[:uuid.Size])) log.Errorln(err.Error()) return err } @@ -169,36 +166,19 @@ func (vc *Conn) Write(p []byte) (int, error) { } func (vc *Conn) WriteBuffer(buffer *buf.Buffer) (err error) { - if vc.needHandshake { - vc.needHandshake = false - if buffer.IsEmpty() { - ApplyPadding(buffer, commandPaddingContinue, vc.userUUID, true) // we do a long padding to hide vless header - } else { - vc.FilterTLS(buffer.Bytes()) - ApplyPadding(buffer, commandPaddingContinue, vc.userUUID, vc.isTLS) - } - err = vc.ExtendedWriter.WriteBuffer(buffer) - if err != nil { - buffer.Release() - return err - } - err = vc.checkTLSVersion() - if err != nil { - buffer.Release() - return err - } - vc.tlsConn = nil - return nil - } - if vc.writeFilterApplicationData { + if buffer.IsEmpty() { + ApplyPadding(buffer, commandPaddingContinue, &vc.writeOnceUserUUID, true) // we do a long padding to hide vless header + return vc.ExtendedWriter.WriteBuffer(buffer) + } + vc.FilterTLS(buffer.Bytes()) buffers := vc.ReshapeBuffer(buffer) applyPadding := true for i, buffer := range buffers { command := commandPaddingContinue if applyPadding { - if vc.isTLS && buffer.Len() > 6 && bytes.Equal(buffer.To(3), tlsApplicationDataStart) { + if vc.isTLS && buffer.Len() > 6 && bytes.Equal(tlsApplicationDataStart, buffer.To(3)) { command = commandPaddingEnd if vc.enableXTLS { command = commandPaddingDirect @@ -211,7 +191,7 @@ func (vc *Conn) WriteBuffer(buffer *buf.Buffer) (err error) { vc.writeFilterApplicationData = false applyPadding = false } - ApplyPadding(buffer, command, nil, vc.isTLS) + ApplyPadding(buffer, command, &vc.writeOnceUserUUID, vc.isTLS) } err = vc.ExtendedWriter.WriteBuffer(buffer) @@ -234,7 +214,7 @@ func (vc *Conn) WriteBuffer(buffer *buf.Buffer) (err error) { } func (vc *Conn) FrontHeadroom() int { - if vc.readFilterUUID { + if vc.readFilterUUID || vc.writeOnceUserUUID != nil { return PaddingHeaderLen } return PaddingHeaderLen - uuid.Size @@ -245,7 +225,7 @@ func (vc *Conn) RearHeadroom() int { } func (vc *Conn) NeedHandshake() bool { - return vc.needHandshake + return vc.writeOnceUserUUID != nil } func (vc *Conn) Upstream() any { diff --git a/mihomo/transport/vless/vision/padding.go b/mihomo/transport/vless/vision/padding.go index 710f64c217..386095528d 100644 --- a/mihomo/transport/vless/vision/padding.go +++ b/mihomo/transport/vless/vision/padding.go @@ -5,8 +5,8 @@ import ( "encoding/binary" "github.com/metacubex/mihomo/common/buf" + N "github.com/metacubex/mihomo/common/net" "github.com/metacubex/mihomo/log" - N "github.com/metacubex/sing/common/network" "github.com/gofrs/uuid/v5" "github.com/metacubex/randv2" @@ -20,7 +20,7 @@ const ( commandPaddingDirect byte = 0x02 ) -func ApplyPadding(buffer *buf.Buffer, command byte, userUUID *uuid.UUID, paddingTLS bool) { +func ApplyPadding(buffer *buf.Buffer, command byte, userUUID *[]byte, paddingTLS bool) { contentLen := int32(buffer.Len()) var paddingLen int32 if contentLen < 900 { @@ -35,8 +35,9 @@ func ApplyPadding(buffer *buf.Buffer, command byte, userUUID *uuid.UUID, padding binary.BigEndian.PutUint16(buffer.ExtendHeader(2), uint16(paddingLen)) binary.BigEndian.PutUint16(buffer.ExtendHeader(2), uint16(contentLen)) buffer.ExtendHeader(1)[0] = command - if userUUID != nil { - copy(buffer.ExtendHeader(uuid.Size), userUUID.Bytes()) + if userUUID != nil && *userUUID != nil { + copy(buffer.ExtendHeader(uuid.Size), *userUUID) + *userUUID = nil } buffer.Extend(int(paddingLen)) diff --git a/mihomo/transport/vless/vision/vision.go b/mihomo/transport/vless/vision/vision.go index f9158ca4e3..e785c6ad78 100644 --- a/mihomo/transport/vless/vision/vision.go +++ b/mihomo/transport/vless/vision/vision.go @@ -12,53 +12,87 @@ import ( N "github.com/metacubex/mihomo/common/net" tlsC "github.com/metacubex/mihomo/component/tls" + "github.com/metacubex/mihomo/log" "github.com/metacubex/mihomo/transport/vless/encryption" "github.com/gofrs/uuid/v5" ) +var ErrNotHandshakeComplete = errors.New("tls connection not handshake complete") var ErrNotTLS13 = errors.New("XTLS Vision based on TLS 1.3 outer connection") -func NewConn(conn net.Conn, tlsConn net.Conn, userUUID *uuid.UUID) (*Conn, error) { +func NewConn(conn net.Conn, tlsConn net.Conn, userUUID uuid.UUID) (*Conn, error) { c := &Conn{ ExtendedReader: N.NewExtendedReader(conn), ExtendedWriter: N.NewExtendedWriter(conn), Conn: conn, userUUID: userUUID, - tlsConn: tlsConn, packetsToFilter: 6, - needHandshake: true, readProcess: true, readFilterUUID: true, writeFilterApplicationData: true, + writeOnceUserUUID: userUUID.Bytes(), } var t reflect.Type var p unsafe.Pointer - switch underlying := tlsConn.(type) { - case *gotls.Conn: - //log.Debugln("type tls") - c.netConn = underlying.NetConn() - t = reflect.TypeOf(underlying).Elem() - p = unsafe.Pointer(underlying) - case *tlsC.Conn: - //log.Debugln("type *tlsC.Conn") - c.netConn = underlying.NetConn() - t = reflect.TypeOf(underlying).Elem() - p = unsafe.Pointer(underlying) - case *tlsC.UConn: - //log.Debugln("type *tlsC.UConn") - c.netConn = underlying.NetConn() - t = reflect.TypeOf(underlying.Conn).Elem() - //log.Debugln("t:%v", t) - p = unsafe.Pointer(underlying.Conn) - case *encryption.CommonConn: - //log.Debugln("type *encryption.CommonConn") - c.netConn = underlying.Conn - t = reflect.TypeOf(underlying).Elem() - p = unsafe.Pointer(underlying) - default: + var upstream any = tlsConn + for { + switch underlying := upstream.(type) { + case *gotls.Conn: + //log.Debugln("type tls") + tlsConn = underlying + c.netConn = underlying.NetConn() + t = reflect.TypeOf(underlying).Elem() + p = unsafe.Pointer(underlying) + break + case *tlsC.Conn: + //log.Debugln("type *tlsC.Conn") + tlsConn = underlying + c.netConn = underlying.NetConn() + t = reflect.TypeOf(underlying).Elem() + p = unsafe.Pointer(underlying) + break + case *tlsC.UConn: + //log.Debugln("type *tlsC.UConn") + tlsConn = underlying + c.netConn = underlying.NetConn() + t = reflect.TypeOf(underlying.Conn).Elem() + //log.Debugln("t:%v", t) + p = unsafe.Pointer(underlying.Conn) + break + case *encryption.CommonConn: + //log.Debugln("type *encryption.CommonConn") + tlsConn = underlying + c.netConn = underlying.Conn + t = reflect.TypeOf(underlying).Elem() + p = unsafe.Pointer(underlying) + break + } + if u, ok := upstream.(N.ReaderWithUpstream); !ok || !u.ReaderReplaceable() { // must replaceable + break + } + if u, ok := upstream.(N.WithUpstreamReader); ok { + upstream = u.UpstreamReader() + continue + } + if u, ok := upstream.(N.WithUpstream); ok { + upstream = u.Upstream() + continue + } + } + if t == nil || p == nil { + log.Warnln("vision: not a valid supported TLS connection: %s", reflect.TypeOf(tlsConn)) return nil, fmt.Errorf(`failed to use vision, maybe "security" is not "tls" or "utls"`) } + + if err := checkTLSVersion(tlsConn); err != nil { + if errors.Is(err, ErrNotHandshakeComplete) { + log.Warnln("vision: TLS connection not handshake complete: %s", reflect.TypeOf(tlsConn)) + } else { + return nil, err + } + } + if i, ok := t.FieldByName("input"); ok { c.input = (*bytes.Reader)(unsafe.Add(p, i.Offset)) } @@ -68,18 +102,30 @@ func NewConn(conn net.Conn, tlsConn net.Conn, userUUID *uuid.UUID) (*Conn, error return c, nil } -func (vc *Conn) checkTLSVersion() error { - switch underlying := vc.tlsConn.(type) { +func checkTLSVersion(tlsConn net.Conn) error { + switch underlying := tlsConn.(type) { case *gotls.Conn: - if underlying.ConnectionState().Version != gotls.VersionTLS13 { + state := underlying.ConnectionState() + if !state.HandshakeComplete { + return ErrNotHandshakeComplete + } + if state.Version != gotls.VersionTLS13 { return ErrNotTLS13 } case *tlsC.Conn: - if underlying.ConnectionState().Version != tlsC.VersionTLS13 { + state := underlying.ConnectionState() + if !state.HandshakeComplete { + return ErrNotHandshakeComplete + } + if state.Version != tlsC.VersionTLS13 { return ErrNotTLS13 } case *tlsC.UConn: - if underlying.ConnectionState().Version != tlsC.VersionTLS13 { + state := underlying.ConnectionState() + if !state.HandshakeComplete { + return ErrNotHandshakeComplete + } + if state.Version != tlsC.VersionTLS13 { return ErrNotTLS13 } } diff --git a/mihomo/transport/vless/vless.go b/mihomo/transport/vless/vless.go index 9fb54f9205..4e99b9ba68 100644 --- a/mihomo/transport/vless/vless.go +++ b/mihomo/transport/vless/vless.go @@ -42,7 +42,7 @@ type DstAddr struct { // Client is vless connection generator type Client struct { - uuid *uuid.UUID + uuid uuid.UUID Addons *Addons } @@ -63,7 +63,7 @@ func NewClient(uuidStr string, addons *Addons) (*Client, error) { } return &Client{ - uuid: &uid, + uuid: uid, Addons: addons, }, nil } diff --git a/openwrt-passwall/luci-app-passwall/luasrc/model/cbi/passwall/client/type/ray.lua b/openwrt-passwall/luci-app-passwall/luasrc/model/cbi/passwall/client/type/ray.lua index 64e8555e4d..c191f7578f 100644 --- a/openwrt-passwall/luci-app-passwall/luasrc/model/cbi/passwall/client/type/ray.lua +++ b/openwrt-passwall/luci-app-passwall/luasrc/model/cbi/passwall/client/type/ray.lua @@ -98,7 +98,27 @@ end) -- 负载均衡列表 local o = s:option(DynamicList, _n("balancing_node"), translate("Load balancing node list"), translate("Load balancing node list, document")) o:depends({ [_n("protocol")] = "_balancing" }) -for k, v in pairs(nodes_table) do o:value(v.id, v.remark) end +local valid_ids = {} +for k, v in pairs(nodes_table) do + o:value(v.id, v.remark) + valid_ids[v.id] = true +end +-- 去重并禁止自定义非法输入 +function o.custom_write(self, section, value) + local result = {} + if type(value) == "table" then + local seen = {} + for _, v in ipairs(value) do + if v and not seen[v] and valid_ids[v] then + table.insert(result, v) + seen[v] = true + end + end + else + result = { value } + end + api.uci:set_list(appname, section, "balancing_node", result) +end local o = s:option(ListValue, _n("balancingStrategy"), translate("Balancing Strategy")) o:depends({ [_n("protocol")] = "_balancing" }) @@ -677,9 +697,6 @@ o:depends({ [_n("xmux")] = true }) o = s:option(Flag, _n("tcpMptcp"), "tcpMptcp", translate("Enable Multipath TCP, need to be enabled in both server and client configuration.")) o.default = 0 -o = s:option(Flag, _n("tcpNoDelay"), "tcpNoDelay") -o.default = 0 - o = s:option(ListValue, _n("chain_proxy"), translate("Chain Proxy")) o:value("", translate("Close(Not use)")) o:value("1", translate("Preproxy Node")) @@ -706,7 +723,6 @@ end for i, v in ipairs(s.fields[_n("protocol")].keylist) do if not v:find("_") then s.fields[_n("tcpMptcp")]:depends({ [_n("protocol")] = v }) - s.fields[_n("tcpNoDelay")]:depends({ [_n("protocol")] = v }) s.fields[_n("chain_proxy")]:depends({ [_n("protocol")] = v }) end end diff --git a/openwrt-passwall/luci-app-passwall/luasrc/model/cbi/passwall/client/type/sing-box.lua b/openwrt-passwall/luci-app-passwall/luasrc/model/cbi/passwall/client/type/sing-box.lua index 42e12b7c5d..4c6b2f51d9 100644 --- a/openwrt-passwall/luci-app-passwall/luasrc/model/cbi/passwall/client/type/sing-box.lua +++ b/openwrt-passwall/luci-app-passwall/luasrc/model/cbi/passwall/client/type/sing-box.lua @@ -107,7 +107,27 @@ end) --[[ URLTest ]] o = s:option(DynamicList, _n("urltest_node"), translate("URLTest node list"), translate("List of nodes to test, document")) o:depends({ [_n("protocol")] = "_urltest" }) -for k, v in pairs(nodes_table) do o:value(v.id, v.remark) end +local valid_ids = {} +for k, v in pairs(nodes_table) do + o:value(v.id, v.remark) + valid_ids[v.id] = true +end +-- 去重并禁止自定义非法输入 +function o.custom_write(self, section, value) + local result = {} + if type(value) == "table" then + local seen = {} + for _, v in ipairs(value) do + if v and not seen[v] and valid_ids[v] then + table.insert(result, v) + seen[v] = true + end + end + else + result = { value } + end + api.uci:set_list(appname, section, "urltest_node", result) +end o = s:option(Value, _n("urltest_url"), translate("Probe URL")) o:depends({ [_n("protocol")] = "_urltest" }) diff --git a/openwrt-passwall/luci-app-passwall/luasrc/passwall/util_xray.lua b/openwrt-passwall/luci-app-passwall/luasrc/passwall/util_xray.lua index 90e2f9eeca..e495c79fb0 100644 --- a/openwrt-passwall/luci-app-passwall/luasrc/passwall/util_xray.lua +++ b/openwrt-passwall/luci-app-passwall/luasrc/passwall/util_xray.lua @@ -147,7 +147,6 @@ function gen_outbound(flag, node, tag, proxy_table) sockopt = { mark = 255, tcpMptcp = (node.tcpMptcp == "1") and true or nil, - tcpNoDelay = (node.tcpNoDelay == "1") and true or nil, dialerProxy = (fragment or noise) and "dialerproxy" or nil }, network = node.transport, @@ -1477,8 +1476,7 @@ function gen_config(var) }, streamSettings = { sockopt = { - mark = 255, - tcpNoDelay = true + mark = 255 } } }) diff --git a/sing-box/.github/workflows/build.yml b/sing-box/.github/workflows/build.yml index 7983a0a4d1..362ac98a62 100644 --- a/sing-box/.github/workflows/build.yml +++ b/sing-box/.github/workflows/build.yml @@ -46,7 +46,7 @@ jobs: - name: Setup Go uses: actions/setup-go@v5 with: - go-version: ^1.25.0 + go-version: ^1.25.1 - name: Check input version if: github.event_name == 'workflow_dispatch' run: |- @@ -110,7 +110,7 @@ jobs: if: ${{ ! (matrix.legacy_go123 || matrix.legacy_go124) }} uses: actions/setup-go@v5 with: - go-version: ^1.25.0 + go-version: ^1.25.1 - name: Setup Go 1.24 if: matrix.legacy_go124 uses: actions/setup-go@v5 @@ -300,7 +300,7 @@ jobs: - name: Setup Go uses: actions/setup-go@v5 with: - go-version: ^1.25.0 + go-version: ^1.25.1 - name: Setup Android NDK id: setup-ndk uses: nttld/setup-ndk@v1 @@ -380,7 +380,7 @@ jobs: - name: Setup Go uses: actions/setup-go@v5 with: - go-version: ^1.25.0 + go-version: ^1.25.1 - name: Setup Android NDK id: setup-ndk uses: nttld/setup-ndk@v1 @@ -478,7 +478,7 @@ jobs: if: matrix.if uses: actions/setup-go@v5 with: - go-version: ^1.25.0 + go-version: ^1.25.1 - name: Setup Xcode stable if: matrix.if && github.ref == 'refs/heads/main-next' run: |- diff --git a/sing-box/.github/workflows/linux.yml b/sing-box/.github/workflows/linux.yml index a705d7ff19..b43cfb394f 100644 --- a/sing-box/.github/workflows/linux.yml +++ b/sing-box/.github/workflows/linux.yml @@ -30,7 +30,7 @@ jobs: - name: Setup Go uses: actions/setup-go@v5 with: - go-version: ^1.25.0 + go-version: ^1.25.1 - name: Check input version if: github.event_name == 'workflow_dispatch' run: |- @@ -71,7 +71,7 @@ jobs: - name: Setup Go uses: actions/setup-go@v5 with: - go-version: ^1.25.0 + go-version: ^1.25.1 - name: Setup Android NDK if: matrix.os == 'android' uses: nttld/setup-ndk@v1 diff --git a/sing-box/common/badtls/raw_conn.go b/sing-box/common/badtls/raw_conn.go index 3a60bdbe67..1029d66bfc 100644 --- a/sing-box/common/badtls/raw_conn.go +++ b/sing-box/common/badtls/raw_conn.go @@ -36,6 +36,7 @@ type RawConn struct { PacketsSent *int64 ActiveCall *atomic.Int32 + Tmp *[16]byte } func NewRawConn(rawTLSConn tls.Conn) (*RawConn, error) { @@ -153,6 +154,12 @@ func NewRawConn(rawTLSConn tls.Conn) (*RawConn, error) { } conn.ActiveCall = (*atomic.Int32)(unsafe.Pointer(rawActiveCall.UnsafeAddr())) + rawTmp := rawConn.FieldByName("tmp") + if !rawTmp.IsValid() || rawTmp.Kind() != reflect.Array || rawTmp.Len() != 16 || rawTmp.Type().Elem().Kind() != reflect.Uint8 { + return nil, E.New("invalid Conn.tmp") + } + conn.Tmp = (*[16]byte)(unsafe.Pointer(rawTmp.UnsafeAddr())) + return conn, nil } diff --git a/sing-box/common/badtls/read_wait.go b/sing-box/common/badtls/read_wait.go index 47d5b65ee0..d18b4c0e2c 100644 --- a/sing-box/common/badtls/read_wait.go +++ b/sing-box/common/badtls/read_wait.go @@ -17,6 +17,9 @@ type ReadWaitConn struct { } func NewReadWaitConn(conn tls.Conn) (tls.Conn, error) { + if _, isReadWaitConn := conn.(N.ReadWaiter); isReadWaitConn { + return conn, nil + } rawConn, err := NewRawConn(conn) if err != nil { return nil, err diff --git a/sing-box/common/badversion/version.go b/sing-box/common/badversion/version.go index ccff02a696..a84042971b 100644 --- a/sing-box/common/badversion/version.go +++ b/sing-box/common/badversion/version.go @@ -5,6 +5,8 @@ import ( "strings" F "github.com/sagernet/sing/common/format" + + "golang.org/x/mod/semver" ) type Version struct { @@ -16,7 +18,19 @@ type Version struct { PreReleaseVersion int } -func (v Version) After(anotherVersion Version) bool { +func (v Version) LessThan(anotherVersion Version) bool { + return !v.GreaterThanOrEqual(anotherVersion) +} + +func (v Version) LessThanOrEqual(anotherVersion Version) bool { + return v == anotherVersion || anotherVersion.GreaterThan(v) +} + +func (v Version) GreaterThanOrEqual(anotherVersion Version) bool { + return v == anotherVersion || v.GreaterThan(anotherVersion) +} + +func (v Version) GreaterThan(anotherVersion Version) bool { if v.Major > anotherVersion.Major { return true } else if v.Major < anotherVersion.Major { @@ -44,19 +58,29 @@ func (v Version) After(anotherVersion Version) bool { } else if v.PreReleaseVersion < anotherVersion.PreReleaseVersion { return false } - } else if v.PreReleaseIdentifier == "rc" && anotherVersion.PreReleaseIdentifier == "beta" { + } + preReleaseIdentifier := parsePreReleaseIdentifier(v.PreReleaseIdentifier) + anotherPreReleaseIdentifier := parsePreReleaseIdentifier(anotherVersion.PreReleaseIdentifier) + if preReleaseIdentifier < anotherPreReleaseIdentifier { return true - } else if v.PreReleaseIdentifier == "beta" && anotherVersion.PreReleaseIdentifier == "rc" { - return false - } else if v.PreReleaseIdentifier == "beta" && anotherVersion.PreReleaseIdentifier == "alpha" { - return true - } else if v.PreReleaseIdentifier == "alpha" && anotherVersion.PreReleaseIdentifier == "beta" { + } else if preReleaseIdentifier > anotherPreReleaseIdentifier { return false } } return false } +func parsePreReleaseIdentifier(identifier string) int { + if strings.HasPrefix(identifier, "rc") { + return 1 + } else if strings.HasPrefix(identifier, "beta") { + return 2 + } else if strings.HasPrefix(identifier, "alpha") { + return 3 + } + return 0 +} + func (v Version) VersionString() string { return F.ToString(v.Major, ".", v.Minor, ".", v.Patch) } @@ -83,6 +107,10 @@ func (v Version) BadString() string { return version } +func IsValid(versionName string) bool { + return semver.IsValid("v" + versionName) +} + func Parse(versionName string) (version Version) { if strings.HasPrefix(versionName, "v") { versionName = versionName[1:] diff --git a/sing-box/common/badversion/version_test.go b/sing-box/common/badversion/version_test.go index 9d6e8a7c21..d6d5a73c81 100644 --- a/sing-box/common/badversion/version_test.go +++ b/sing-box/common/badversion/version_test.go @@ -10,9 +10,9 @@ func TestCompareVersion(t *testing.T) { t.Parallel() require.Equal(t, "1.3.0-beta.1", Parse("v1.3.0-beta1").String()) require.Equal(t, "1.3-beta1", Parse("v1.3.0-beta.1").BadString()) - require.True(t, Parse("1.3.0").After(Parse("1.3-beta1"))) - require.True(t, Parse("1.3.0").After(Parse("1.3.0-beta1"))) - require.True(t, Parse("1.3.0-beta1").After(Parse("1.3.0-alpha1"))) - require.True(t, Parse("1.3.1").After(Parse("1.3.0"))) - require.True(t, Parse("1.4").After(Parse("1.3"))) + require.True(t, Parse("1.3.0").GreaterThan(Parse("1.3-beta1"))) + require.True(t, Parse("1.3.0").GreaterThan(Parse("1.3.0-beta1"))) + require.True(t, Parse("1.3.0-beta1").GreaterThan(Parse("1.3.0-alpha1"))) + require.True(t, Parse("1.3.1").GreaterThan(Parse("1.3.0"))) + require.True(t, Parse("1.4").GreaterThan(Parse("1.3"))) } diff --git a/sing-box/common/ktls/ktls.go b/sing-box/common/ktls/ktls.go index a3d629b346..36f36b2513 100644 --- a/sing-box/common/ktls/ktls.go +++ b/sing-box/common/ktls/ktls.go @@ -3,6 +3,7 @@ package ktls import ( + "context" "crypto/tls" "io" "net" @@ -10,24 +11,30 @@ import ( "syscall" "github.com/sagernet/sing-box/common/badtls" - // C "github.com/sagernet/sing-box/constant" E "github.com/sagernet/sing/common/exceptions" + "github.com/sagernet/sing/common/logger" N "github.com/sagernet/sing/common/network" aTLS "github.com/sagernet/sing/common/tls" ) type Conn struct { aTLS.Conn + ctx context.Context + logger logger.ContextLogger conn net.Conn rawConn *badtls.RawConn + syscallConn syscall.Conn rawSyscallConn syscall.RawConn readWaitOptions N.ReadWaitOptions kernelTx bool kernelRx bool - tmp [16]byte } -func NewConn(conn aTLS.Conn, txOffload, rxOffload bool) (aTLS.Conn, error) { +func NewConn(ctx context.Context, logger logger.ContextLogger, conn aTLS.Conn, txOffload, rxOffload bool) (aTLS.Conn, error) { + err := Load() + if err != nil { + return nil, err + } syscallConn, isSyscallConn := N.CastReader[interface { io.Reader syscall.Conn @@ -54,14 +61,17 @@ func NewConn(conn aTLS.Conn, txOffload, rxOffload bool) (aTLS.Conn, error) { for rawConn.Hand.Len() > 0 { err = rawConn.HandlePostHandshakeMessage() if err != nil { - return nil, E.Cause(err, "ktls: failed to handle post-handshake messages") + return nil, E.Cause(err, "handle post-handshake messages") } } } kConn := &Conn{ Conn: conn, + ctx: ctx, + logger: logger, conn: conn.NetConn(), rawConn: rawConn, + syscallConn: syscallConn, rawSyscallConn: rawSyscallConn, } err = kConn.setupKernel(txOffload, rxOffload) @@ -72,13 +82,25 @@ func NewConn(conn aTLS.Conn, txOffload, rxOffload bool) (aTLS.Conn, error) { } func (c *Conn) Upstream() any { - return c.conn + return c.Conn } -func (c *Conn) ReaderReplaceable() bool { - return c.kernelRx +func (c *Conn) SyscallConnForRead() syscall.Conn { + if !c.kernelRx { + return nil + } + if !*c.rawConn.IsClient { + c.logger.WarnContext(c.ctx, "ktls: RX splice is unavailable on the server size, since it will cause an unknown failure") + return nil + } + c.logger.DebugContext(c.ctx, "ktls: RX splice requested") + return c.syscallConn } -func (c *Conn) WriterReplaceable() bool { - return c.kernelTx +func (c *Conn) SyscallConnForWrite() syscall.Conn { + if !c.kernelTx { + return nil + } + c.logger.DebugContext(c.ctx, "ktls: TX splice requested") + return c.syscallConn } diff --git a/sing-box/common/ktls/ktls_alert.go b/sing-box/common/ktls/ktls_alert.go index a60f8f2f2f..8c68d36b3a 100644 --- a/sing-box/common/ktls/ktls_alert.go +++ b/sing-box/common/ktls/ktls_alert.go @@ -57,13 +57,13 @@ const ( func (c *Conn) sendAlertLocked(err uint8) error { switch err { case alertNoRenegotiation, alertCloseNotify: - c.tmp[0] = alertLevelWarning + c.rawConn.Tmp[0] = alertLevelWarning default: - c.tmp[0] = alertLevelError + c.rawConn.Tmp[0] = alertLevelError } - c.tmp[1] = byte(err) + c.rawConn.Tmp[1] = byte(err) - _, writeErr := c.writeRecordLocked(recordTypeAlert, c.tmp[0:2]) + _, writeErr := c.writeRecordLocked(recordTypeAlert, c.rawConn.Tmp[0:2]) if err == alertCloseNotify { // closeNotify is a special case in that it isn't an error. return writeErr diff --git a/sing-box/common/ktls/ktls_linux.go b/sing-box/common/ktls/ktls_linux.go index 7b37948bb8..313fe3811e 100644 --- a/sing-box/common/ktls/ktls_linux.go +++ b/sing-box/common/ktls/ktls_linux.go @@ -12,10 +12,11 @@ import ( "syscall" "unsafe" + "github.com/sagernet/sing-box/common/badversion" "github.com/sagernet/sing/common/control" E "github.com/sagernet/sing/common/exceptions" + "github.com/sagernet/sing/common/shell" - "github.com/blang/semver/v4" "golang.org/x/sys/unix" ) @@ -48,73 +49,89 @@ type Support struct { } var KernelSupport = sync.OnceValues(func() (*Support, error) { - _, err := os.Stat("/sys/module/tls") - if err != nil { - return nil, E.New("ktls: kernel module tls not found") - } - var uname unix.Utsname - err = unix.Uname(&uname) + err := unix.Uname(&uname) if err != nil { return nil, err } - kernelVersion, err := semver.Parse(strings.Trim(string(uname.Release[:]), "\x00")) + kernelVersion := badversion.Parse(strings.Trim(string(uname.Release[:]), "\x00")) if err != nil { return nil, err } - kernelVersion.Pre = nil - kernelVersion.Build = nil - var support Support - switch { - case kernelVersion.GTE(semver.Version{Major: 6, Minor: 14}): + case kernelVersion.GreaterThanOrEqual(badversion.Version{Major: 6, Minor: 14}): support.TLS_Version13_KeyUpdate = true fallthrough - case kernelVersion.GTE(semver.Version{Major: 6, Minor: 1}): + case kernelVersion.GreaterThanOrEqual(badversion.Version{Major: 6, Minor: 1}): support.TLS_ARIA_GCM = true fallthrough - case kernelVersion.GTE(semver.Version{Major: 6}): + case kernelVersion.GreaterThanOrEqual(badversion.Version{Major: 6}): support.TLS_Version13_RX = true support.TLS_RX_NOPADDING = true fallthrough - case kernelVersion.GTE(semver.Version{Major: 5, Minor: 19}): + case kernelVersion.GreaterThanOrEqual(badversion.Version{Major: 5, Minor: 19}): support.TLS_TX_ZEROCOPY = true fallthrough - case kernelVersion.GTE(semver.Version{Major: 5, Minor: 16}): + case kernelVersion.GreaterThanOrEqual(badversion.Version{Major: 5, Minor: 16}): support.TLS_SM4 = true fallthrough - case kernelVersion.GTE(semver.Version{Major: 5, Minor: 11}): + case kernelVersion.GreaterThanOrEqual(badversion.Version{Major: 5, Minor: 11}): support.TLS_CHACHA20_POLY1305 = true fallthrough - case kernelVersion.GTE(semver.Version{Major: 5, Minor: 2}): + case kernelVersion.GreaterThanOrEqual(badversion.Version{Major: 5, Minor: 2}): support.TLS_AES_128_CCM = true fallthrough - case kernelVersion.GTE(semver.Version{Major: 5, Minor: 1}): + case kernelVersion.GreaterThanOrEqual(badversion.Version{Major: 5, Minor: 1}): support.TLS_AES_256_GCM = true support.TLS_Version13 = true fallthrough - case kernelVersion.GTE(semver.Version{Major: 4, Minor: 17}): + case kernelVersion.GreaterThanOrEqual(badversion.Version{Major: 4, Minor: 17}): support.TLS_RX = true fallthrough - case kernelVersion.GTE(semver.Version{Major: 4, Minor: 13}): + case kernelVersion.GreaterThanOrEqual(badversion.Version{Major: 4, Minor: 13}): support.TLS = true } + if support.TLS && support.TLS_Version13 { + _, err := os.Stat("/sys/module/tls") + if err != nil { + if os.Getuid() == 0 { + output, err := shell.Exec("modprobe", "tls").Read() + if err != nil { + return nil, E.Extend(E.Cause(err, "modprobe tls"), output) + } + } else { + return nil, E.New("ktls: kernel TLS module not loaded") + } + } + } + return &support, nil }) +func Load() error { + support, err := KernelSupport() + if err != nil { + return E.Cause(err, "ktls: check availability") + } + if !support.TLS || !support.TLS_Version13 { + return E.New("ktls: kernel does not support TLS 1.3") + } + return nil +} + func (c *Conn) setupKernel(txOffload, rxOffload bool) error { if !txOffload && !rxOffload { - return nil + return os.ErrInvalid } support, err := KernelSupport() if err != nil { - return err + return E.Cause(err, "check availability") } - if !support.TLS { - return nil + if !support.TLS || !support.TLS_Version13 { + return E.New("kernel does not support TLS 1.3") } c.rawConn.Out.Lock() defer c.rawConn.Out.Unlock() @@ -122,35 +139,13 @@ func (c *Conn) setupKernel(txOffload, rxOffload bool) error { return syscall.SetsockoptString(int(fd), unix.SOL_TCP, unix.TCP_ULP, "tls") }) if err != nil { - return E.Cause(err, "initialize kernel TLS") - } - - if rxOffload { - rxCrypto := kernelCipher(support, c.rawConn.In, *c.rawConn.CipherSuite, true) - if rxCrypto == nil { - return E.New("kTLS: unsupported cipher suite") - } - err = control.Raw(c.rawSyscallConn, func(fd uintptr) error { - return syscall.SetsockoptString(int(fd), unix.SOL_TLS, TLS_RX, rxCrypto.String()) - }) - if err != nil { - return err - } - if /*config.KernelRXExpectNoPad &&*/ *c.rawConn.Vers >= tls.VersionTLS13 && support.TLS_RX_NOPADDING { - err = control.Raw(c.rawSyscallConn, func(fd uintptr) error { - return syscall.SetsockoptInt(int(fd), unix.SOL_TLS, TLS_RX_EXPECT_NO_PAD, 1) - }) - if err != nil { - return err - } - } - c.kernelRx = true + return os.NewSyscallError("setsockopt", err) } if txOffload { txCrypto := kernelCipher(support, c.rawConn.Out, *c.rawConn.CipherSuite, false) if txCrypto == nil { - return E.New("kTLS: unsupported cipher suite") + return E.New("unsupported cipher suite") } err = control.Raw(c.rawSyscallConn, func(fd uintptr) error { return syscall.SetsockoptString(int(fd), unix.SOL_TLS, TLS_TX, txCrypto.String()) @@ -167,8 +162,31 @@ func (c *Conn) setupKernel(txOffload, rxOffload bool) error { } } c.kernelTx = true + c.logger.DebugContext(c.ctx, "ktls: kernel TLS TX enabled") } + if rxOffload { + rxCrypto := kernelCipher(support, c.rawConn.In, *c.rawConn.CipherSuite, true) + if rxCrypto == nil { + return E.New("unsupported cipher suite") + } + err = control.Raw(c.rawSyscallConn, func(fd uintptr) error { + return syscall.SetsockoptString(int(fd), unix.SOL_TLS, TLS_RX, rxCrypto.String()) + }) + if err != nil { + return err + } + if *c.rawConn.Vers >= tls.VersionTLS13 && support.TLS_RX_NOPADDING { + err = control.Raw(c.rawSyscallConn, func(fd uintptr) error { + return syscall.SetsockoptInt(int(fd), unix.SOL_TLS, TLS_RX_EXPECT_NO_PAD, 1) + }) + if err != nil { + return err + } + } + c.kernelRx = true + c.logger.DebugContext(c.ctx, "ktls: kernel TLS RX enabled") + } return nil } diff --git a/sing-box/common/ktls/ktls_stub.go b/sing-box/common/ktls/ktls_stub.go index ab4fc0b457..66d3e88a70 100644 --- a/sing-box/common/ktls/ktls_stub.go +++ b/sing-box/common/ktls/ktls_stub.go @@ -3,11 +3,13 @@ package ktls import ( + "context" "os" + "github.com/sagernet/sing/common/logger" aTLS "github.com/sagernet/sing/common/tls" ) -func NewConn(conn aTLS.Conn, txOffload, rxOffload bool) (aTLS.Conn, error) { +func NewConn(ctx context.Context, logger logger.ContextLogger, conn aTLS.Conn, txOffload, rxOffload bool) (aTLS.Conn, error) { return nil, os.ErrInvalid } diff --git a/sing-box/common/tls/client.go b/sing-box/common/tls/client.go index d42bebd4cd..a84ce0f5d3 100644 --- a/sing-box/common/tls/client.go +++ b/sing-box/common/tls/client.go @@ -8,36 +8,65 @@ import ( "os" "github.com/sagernet/sing-box/common/badtls" - "github.com/sagernet/sing-box/common/ktls" C "github.com/sagernet/sing-box/constant" "github.com/sagernet/sing-box/option" - E "github.com/sagernet/sing/common/exceptions" + "github.com/sagernet/sing/common/logger" M "github.com/sagernet/sing/common/metadata" N "github.com/sagernet/sing/common/network" aTLS "github.com/sagernet/sing/common/tls" ) -func NewDialerFromOptions(ctx context.Context, dialer N.Dialer, serverAddress string, options option.OutboundTLSOptions) (N.Dialer, error) { +func NewDialerFromOptions(ctx context.Context, logger logger.ContextLogger, dialer N.Dialer, serverAddress string, options option.OutboundTLSOptions) (N.Dialer, error) { if !options.Enabled { return dialer, nil } - config, err := NewClient(ctx, serverAddress, options) + config, err := NewClientWithOptions(ClientOptions{ + Context: ctx, + Logger: logger, + ServerAddress: serverAddress, + Options: options, + }) if err != nil { return nil, err } return NewDialer(dialer, config), nil } -func NewClient(ctx context.Context, serverAddress string, options option.OutboundTLSOptions) (Config, error) { - if !options.Enabled { +func NewClient(ctx context.Context, logger logger.ContextLogger, serverAddress string, options option.OutboundTLSOptions) (Config, error) { + return NewClientWithOptions(ClientOptions{ + Context: ctx, + Logger: logger, + ServerAddress: serverAddress, + Options: options, + }) +} + +type ClientOptions struct { + Context context.Context + Logger logger.ContextLogger + ServerAddress string + Options option.OutboundTLSOptions + KTLSCompatible bool +} + +func NewClientWithOptions(options ClientOptions) (Config, error) { + if !options.Options.Enabled { return nil, nil } - if options.Reality != nil && options.Reality.Enabled { - return NewRealityClient(ctx, serverAddress, options) - } else if options.UTLS != nil && options.UTLS.Enabled { - return NewUTLSClient(ctx, serverAddress, options) + if !options.KTLSCompatible { + if options.Options.KernelTx { + options.Logger.Warn("enabling kTLS TX in current scenarios will definitely reduce performance, please checkout https://sing-box.sagernet.org/configuration/shared/tls/#kernel_tx") + } } - return NewSTDClient(ctx, serverAddress, options) + if options.Options.KernelRx { + options.Logger.Warn("enabling kTLS RX will definitely reduce performance, please checkout https://sing-box.sagernet.org/configuration/shared/tls/#kernel_rx") + } + if options.Options.Reality != nil && options.Options.Reality.Enabled { + return NewRealityClient(options.Context, options.Logger, options.ServerAddress, options.Options) + } else if options.Options.UTLS != nil && options.Options.UTLS.Enabled { + return NewUTLSClient(options.Context, options.Logger, options.ServerAddress, options.Options) + } + return NewSTDClient(options.Context, options.Logger, options.ServerAddress, options.Options) } func ClientHandshake(ctx context.Context, conn net.Conn, config Config) (Conn, error) { @@ -47,12 +76,6 @@ func ClientHandshake(ctx context.Context, conn net.Conn, config Config) (Conn, e if err != nil { return nil, err } - if kConfig, isKConfig := config.(KTLSCapableConfig); isKConfig && (kConfig.KernelTx() || kConfig.KernelRx()) { - if !C.IsLinux { - return nil, E.New("kTLS is only supported on Linux") - } - return ktls.NewConn(tlsConn, kConfig.KernelTx(), kConfig.KernelRx()) - } readWaitConn, err := badtls.NewReadWaitConn(tlsConn) if err == nil { return readWaitConn, nil diff --git a/sing-box/common/tls/config.go b/sing-box/common/tls/config.go index e3f1923937..72bbd19419 100644 --- a/sing-box/common/tls/config.go +++ b/sing-box/common/tls/config.go @@ -21,12 +21,6 @@ type ( CurveID = tls.CurveID ) -type KTLSCapableConfig interface { - Config - KernelTx() bool - KernelRx() bool -} - func ParseTLSVersion(version string) (uint16, error) { switch version { case "1.0": diff --git a/sing-box/common/tls/ktls.go b/sing-box/common/tls/ktls.go new file mode 100644 index 0000000000..dd564f5348 --- /dev/null +++ b/sing-box/common/tls/ktls.go @@ -0,0 +1,67 @@ +package tls + +import ( + "context" + "net" + + "github.com/sagernet/sing-box/common/ktls" + E "github.com/sagernet/sing/common/exceptions" + "github.com/sagernet/sing/common/logger" + aTLS "github.com/sagernet/sing/common/tls" +) + +type KTLSClientConfig struct { + Config + logger logger.ContextLogger + kernelTx, kernelRx bool +} + +func (w *KTLSClientConfig) ClientHandshake(ctx context.Context, conn net.Conn) (aTLS.Conn, error) { + tlsConn, err := aTLS.ClientHandshake(ctx, conn, w.Config) + if err != nil { + return nil, err + } + kConn, err := ktls.NewConn(ctx, w.logger, tlsConn, w.kernelTx, w.kernelRx) + if err != nil { + tlsConn.Close() + return nil, E.Cause(err, "initialize kernel TLS") + } + return kConn, nil +} + +func (w *KTLSClientConfig) Clone() Config { + return &KTLSClientConfig{ + w.Config.Clone(), + w.logger, + w.kernelTx, + w.kernelRx, + } +} + +type KTlSServerConfig struct { + ServerConfig + logger logger.ContextLogger + kernelTx, kernelRx bool +} + +func (w *KTlSServerConfig) ServerHandshake(ctx context.Context, conn net.Conn) (aTLS.Conn, error) { + tlsConn, err := aTLS.ServerHandshake(ctx, conn, w.ServerConfig) + if err != nil { + return nil, err + } + kConn, err := ktls.NewConn(ctx, w.logger, tlsConn, w.kernelTx, w.kernelRx) + if err != nil { + tlsConn.Close() + return nil, E.Cause(err, "initialize kernel TLS") + } + return kConn, nil +} + +func (w *KTlSServerConfig) Clone() Config { + return &KTlSServerConfig{ + w.ServerConfig.Clone().(ServerConfig), + w.logger, + w.kernelTx, + w.kernelRx, + } +} diff --git a/sing-box/common/tls/reality_client.go b/sing-box/common/tls/reality_client.go index d056966c9a..2dcede57fd 100644 --- a/sing-box/common/tls/reality_client.go +++ b/sing-box/common/tls/reality_client.go @@ -32,6 +32,7 @@ import ( "github.com/sagernet/sing/common" "github.com/sagernet/sing/common/debug" E "github.com/sagernet/sing/common/exceptions" + "github.com/sagernet/sing/common/logger" "github.com/sagernet/sing/common/ntp" aTLS "github.com/sagernet/sing/common/tls" @@ -49,12 +50,12 @@ type RealityClientConfig struct { shortID [8]byte } -func NewRealityClient(ctx context.Context, serverAddress string, options option.OutboundTLSOptions) (*RealityClientConfig, error) { +func NewRealityClient(ctx context.Context, logger logger.ContextLogger, serverAddress string, options option.OutboundTLSOptions) (*RealityClientConfig, error) { if options.UTLS == nil || !options.UTLS.Enabled { return nil, E.New("uTLS is required by reality client") } - uClient, err := NewUTLSClient(ctx, serverAddress, options) + uClient, err := NewUTLSClient(ctx, logger, serverAddress, options) if err != nil { return nil, err } @@ -93,7 +94,7 @@ func (e *RealityClientConfig) SetNextProtos(nextProto []string) { e.uClient.SetNextProtos(nextProto) } -func (e *RealityClientConfig) Config() (*STDConfig, error) { +func (e *RealityClientConfig) STDConfig() (*STDConfig, error) { return nil, E.New("unsupported usage for reality") } diff --git a/sing-box/common/tls/reality_server.go b/sing-box/common/tls/reality_server.go index 3a3ae99e7e..f332784d81 100644 --- a/sing-box/common/tls/reality_server.go +++ b/sing-box/common/tls/reality_server.go @@ -119,6 +119,13 @@ func NewRealityServer(ctx context.Context, logger log.Logger, options option.Inb return handshakeDialer.DialContext(ctx, network, M.ParseSocksaddr(addr)) } + if options.ECH != nil && options.ECH.Enabled { + return nil, E.New("Reality is conflict with ECH") + } + if options.KernelRx || options.KernelTx { + return nil, E.New("Reality is conflict with kTLS") + } + return &RealityServerConfig{&tlsConfig}, nil } @@ -138,7 +145,7 @@ func (c *RealityServerConfig) SetNextProtos(nextProto []string) { c.config.NextProtos = nextProto } -func (c *RealityServerConfig) Config() (*tls.Config, error) { +func (c *RealityServerConfig) STDConfig() (*tls.Config, error) { return nil, E.New("unsupported usage for reality") } diff --git a/sing-box/common/tls/server.go b/sing-box/common/tls/server.go index 7265b6d3b8..74b240fc75 100644 --- a/sing-box/common/tls/server.go +++ b/sing-box/common/tls/server.go @@ -6,22 +6,43 @@ import ( "os" "github.com/sagernet/sing-box/common/badtls" - "github.com/sagernet/sing-box/common/ktls" C "github.com/sagernet/sing-box/constant" "github.com/sagernet/sing-box/log" "github.com/sagernet/sing-box/option" - E "github.com/sagernet/sing/common/exceptions" aTLS "github.com/sagernet/sing/common/tls" ) -func NewServer(ctx context.Context, logger log.Logger, options option.InboundTLSOptions) (ServerConfig, error) { - if !options.Enabled { +type ServerOptions struct { + Context context.Context + Logger log.ContextLogger + Options option.InboundTLSOptions + KTLSCompatible bool +} + +func NewServer(ctx context.Context, logger log.ContextLogger, options option.InboundTLSOptions) (ServerConfig, error) { + return NewServerWithOptions(ServerOptions{ + Context: ctx, + Logger: logger, + Options: options, + }) +} + +func NewServerWithOptions(options ServerOptions) (ServerConfig, error) { + if !options.Options.Enabled { return nil, nil } - if options.Reality != nil && options.Reality.Enabled { - return NewRealityServer(ctx, logger, options) + if !options.KTLSCompatible { + if options.Options.KernelTx { + options.Logger.Warn("enabling kTLS TX in current scenarios will definitely reduce performance, please checkout https://sing-box.sagernet.org/configuration/shared/tls/#kernel_tx") + } } - return NewSTDServer(ctx, logger, options) + if options.Options.KernelRx { + options.Logger.Warn("enabling kTLS RX will definitely reduce performance, please checkout https://sing-box.sagernet.org/configuration/shared/tls/#kernel_rx") + } + if options.Options.Reality != nil && options.Options.Reality.Enabled { + return NewRealityServer(options.Context, options.Logger, options.Options) + } + return NewSTDServer(options.Context, options.Logger, options.Options) } func ServerHandshake(ctx context.Context, conn net.Conn, config ServerConfig) (Conn, error) { @@ -31,12 +52,6 @@ func ServerHandshake(ctx context.Context, conn net.Conn, config ServerConfig) (C if err != nil { return nil, err } - if kConfig, isKConfig := config.(KTLSCapableConfig); isKConfig && (kConfig.KernelTx() || kConfig.KernelRx()) { - if !C.IsLinux { - return nil, E.New("kTLS is only supported on Linux") - } - return ktls.NewConn(tlsConn, kConfig.KernelTx(), kConfig.KernelRx()) - } readWaitConn, err := badtls.NewReadWaitConn(tlsConn) if err == nil { return readWaitConn, nil diff --git a/sing-box/common/tls/std_client.go b/sing-box/common/tls/std_client.go index f801b59059..8aebc3f60c 100644 --- a/sing-box/common/tls/std_client.go +++ b/sing-box/common/tls/std_client.go @@ -11,8 +11,10 @@ import ( "github.com/sagernet/sing-box/adapter" "github.com/sagernet/sing-box/common/tlsfragment" + C "github.com/sagernet/sing-box/constant" "github.com/sagernet/sing-box/option" E "github.com/sagernet/sing/common/exceptions" + "github.com/sagernet/sing/common/logger" "github.com/sagernet/sing/common/ntp" ) @@ -22,7 +24,6 @@ type STDClientConfig struct { fragment bool fragmentFallbackDelay time.Duration recordFragment bool - kernelTx, kernelRx bool } func (c *STDClientConfig) ServerName() string { @@ -41,7 +42,7 @@ func (c *STDClientConfig) SetNextProtos(nextProto []string) { c.config.NextProtos = nextProto } -func (c *STDClientConfig) Config() (*STDConfig, error) { +func (c *STDClientConfig) STDConfig() (*STDConfig, error) { return c.config, nil } @@ -59,8 +60,6 @@ func (c *STDClientConfig) Clone() Config { fragment: c.fragment, fragmentFallbackDelay: c.fragmentFallbackDelay, recordFragment: c.recordFragment, - kernelTx: c.kernelTx, - kernelRx: c.kernelRx, } } @@ -72,15 +71,7 @@ func (c *STDClientConfig) SetECHConfigList(EncryptedClientHelloConfigList []byte c.config.EncryptedClientHelloConfigList = EncryptedClientHelloConfigList } -func (c *STDClientConfig) KernelTx() bool { - return c.kernelTx -} - -func (c *STDClientConfig) KernelRx() bool { - return c.kernelRx -} - -func NewSTDClient(ctx context.Context, serverAddress string, options option.OutboundTLSOptions) (Config, error) { +func NewSTDClient(ctx context.Context, logger logger.ContextLogger, serverAddress string, options option.OutboundTLSOptions) (Config, error) { var serverName string if options.ServerName != "" { serverName = options.ServerName @@ -163,18 +154,24 @@ func NewSTDClient(ctx context.Context, serverAddress string, options option.Outb } tlsConfig.RootCAs = certPool } - stdConfig := &STDClientConfig{ - ctx: ctx, - config: &tlsConfig, - fragment: options.Fragment, - fragmentFallbackDelay: time.Duration(options.FragmentFallbackDelay), - recordFragment: options.RecordFragment, - kernelTx: options.KernelTx, - kernelRx: options.KernelRx, - } + var config Config = &STDClientConfig{ctx, &tlsConfig, options.Fragment, time.Duration(options.FragmentFallbackDelay), options.RecordFragment} if options.ECH != nil && options.ECH.Enabled { - return parseECHClientConfig(ctx, stdConfig, options) - } else { - return stdConfig, nil + var err error + config, err = parseECHClientConfig(ctx, config.(ECHCapableConfig), options) + if err != nil { + return nil, err + } } + if options.KernelRx || options.KernelTx { + if !C.IsLinux { + return nil, E.New("kTLS is only supported on Linux") + } + config = &KTLSClientConfig{ + Config: config, + logger: logger, + kernelTx: options.KernelTx, + kernelRx: options.KernelRx, + } + } + return config, nil } diff --git a/sing-box/common/tls/std_server.go b/sing-box/common/tls/std_server.go index 39a959f1f6..5ce12da6d2 100644 --- a/sing-box/common/tls/std_server.go +++ b/sing-box/common/tls/std_server.go @@ -10,6 +10,7 @@ import ( "github.com/sagernet/fswatch" "github.com/sagernet/sing-box/adapter" + C "github.com/sagernet/sing-box/constant" "github.com/sagernet/sing-box/log" "github.com/sagernet/sing-box/option" "github.com/sagernet/sing/common" @@ -20,16 +21,15 @@ import ( var errInsecureUnused = E.New("tls: insecure unused") type STDServerConfig struct { - config *tls.Config - logger log.Logger - kernelTx, kernelRx bool - acmeService adapter.SimpleLifecycle - certificate []byte - key []byte - certificatePath string - keyPath string - echKeyPath string - watcher *fswatch.Watcher + config *tls.Config + logger log.Logger + acmeService adapter.SimpleLifecycle + certificate []byte + key []byte + certificatePath string + keyPath string + echKeyPath string + watcher *fswatch.Watcher } func (c *STDServerConfig) ServerName() string { @@ -56,7 +56,7 @@ func (c *STDServerConfig) SetNextProtos(nextProto []string) { } } -func (c *STDServerConfig) Config() (*STDConfig, error) { +func (c *STDServerConfig) STDConfig() (*STDConfig, error) { return c.config, nil } @@ -70,20 +70,10 @@ func (c *STDServerConfig) Server(conn net.Conn) (Conn, error) { func (c *STDServerConfig) Clone() Config { return &STDServerConfig{ - config: c.config.Clone(), - kernelTx: c.kernelTx, - kernelRx: c.kernelRx, + config: c.config.Clone(), } } -func (c *STDServerConfig) KernelTx() bool { - return c.kernelTx -} - -func (c *STDServerConfig) KernelRx() bool { - return c.kernelRx -} - func (c *STDServerConfig) Start() error { if c.acmeService != nil { return c.acmeService.Start() @@ -171,7 +161,7 @@ func (c *STDServerConfig) Close() error { return nil } -func NewSTDServer(ctx context.Context, logger log.Logger, options option.InboundTLSOptions) (ServerConfig, error) { +func NewSTDServer(ctx context.Context, logger log.ContextLogger, options option.InboundTLSOptions) (ServerConfig, error) { if !options.Enabled { return nil, nil } @@ -273,16 +263,26 @@ func NewSTDServer(ctx context.Context, logger log.Logger, options option.Inbound return nil, err } } - return &STDServerConfig{ + var config ServerConfig = &STDServerConfig{ config: tlsConfig, logger: logger, - kernelTx: options.KernelTx, - kernelRx: options.KernelRx, acmeService: acmeService, certificate: certificate, key: key, certificatePath: options.CertificatePath, keyPath: options.KeyPath, echKeyPath: echKeyPath, - }, nil + } + if options.KernelTx || options.KernelRx { + if !C.IsLinux { + return nil, E.New("kTLS is only supported on Linux") + } + config = &KTlSServerConfig{ + ServerConfig: config, + logger: logger, + kernelTx: options.KernelTx, + kernelRx: options.KernelRx, + } + } + return config, nil } diff --git a/sing-box/common/tls/utls_client.go b/sing-box/common/tls/utls_client.go index 88ea1ada77..dbc1517514 100644 --- a/sing-box/common/tls/utls_client.go +++ b/sing-box/common/tls/utls_client.go @@ -14,8 +14,10 @@ import ( "github.com/sagernet/sing-box/adapter" "github.com/sagernet/sing-box/common/tlsfragment" + C "github.com/sagernet/sing-box/constant" "github.com/sagernet/sing-box/option" E "github.com/sagernet/sing/common/exceptions" + "github.com/sagernet/sing/common/logger" "github.com/sagernet/sing/common/ntp" utls "github.com/metacubex/utls" @@ -29,8 +31,6 @@ type UTLSClientConfig struct { fragment bool fragmentFallbackDelay time.Duration recordFragment bool - kernelTx bool - kernelRx bool } func (c *UTLSClientConfig) ServerName() string { @@ -52,7 +52,7 @@ func (c *UTLSClientConfig) SetNextProtos(nextProto []string) { c.config.NextProtos = nextProto } -func (c *UTLSClientConfig) Config() (*STDConfig, error) { +func (c *UTLSClientConfig) STDConfig() (*STDConfig, error) { return nil, E.New("unsupported usage for uTLS") } @@ -69,7 +69,7 @@ func (c *UTLSClientConfig) SetSessionIDGenerator(generator func(clientHello []by func (c *UTLSClientConfig) Clone() Config { return &UTLSClientConfig{ - c.ctx, c.config.Clone(), c.id, c.fragment, c.fragmentFallbackDelay, c.recordFragment, c.kernelTx, c.kernelRx, + c.ctx, c.config.Clone(), c.id, c.fragment, c.fragmentFallbackDelay, c.recordFragment, } } @@ -81,14 +81,6 @@ func (c *UTLSClientConfig) SetECHConfigList(EncryptedClientHelloConfigList []byt c.config.EncryptedClientHelloConfigList = EncryptedClientHelloConfigList } -func (c *UTLSClientConfig) KernelTx() bool { - return c.kernelTx -} - -func (c *UTLSClientConfig) KernelRx() bool { - return c.kernelRx -} - type utlsConnWrapper struct { *utls.UConn } @@ -149,7 +141,7 @@ func (c *utlsALPNWrapper) HandshakeContext(ctx context.Context) error { return c.UConn.HandshakeContext(ctx) } -func NewUTLSClient(ctx context.Context, serverAddress string, options option.OutboundTLSOptions) (Config, error) { +func NewUTLSClient(ctx context.Context, logger logger.ContextLogger, serverAddress string, options option.OutboundTLSOptions) (Config, error) { var serverName string if options.ServerName != "" { serverName = options.ServerName @@ -224,20 +216,31 @@ func NewUTLSClient(ctx context.Context, serverAddress string, options option.Out if err != nil { return nil, err } - uConfig := &UTLSClientConfig{ctx, &tlsConfig, id, options.Fragment, time.Duration(options.FragmentFallbackDelay), options.RecordFragment, options.KernelTx, options.KernelRx} - if uConfig.kernelTx || uConfig.kernelRx { - if options.Reality != nil && options.Reality.Enabled { - return nil, E.New("Reality is conflict with kTLS") - } - } + var config Config = &UTLSClientConfig{ctx, &tlsConfig, id, options.Fragment, time.Duration(options.FragmentFallbackDelay), options.RecordFragment} if options.ECH != nil && options.ECH.Enabled { if options.Reality != nil && options.Reality.Enabled { return nil, E.New("Reality is conflict with ECH") } - return parseECHClientConfig(ctx, uConfig, options) - } else { - return uConfig, nil + config, err = parseECHClientConfig(ctx, config.(ECHCapableConfig), options) + if err != nil { + return nil, err + } } + if options.KernelRx || options.KernelTx { + if options.Reality != nil && options.Reality.Enabled { + return nil, E.New("Reality is conflict with kTLS") + } + if !C.IsLinux { + return nil, E.New("kTLS is only supported on Linux") + } + config = &KTLSClientConfig{ + Config: config, + logger: logger, + kernelTx: options.KernelTx, + kernelRx: options.KernelRx, + } + } + return config, nil } var ( diff --git a/sing-box/dns/client.go b/sing-box/dns/client.go index 865bdaec8c..0d0e712b91 100644 --- a/sing-box/dns/client.go +++ b/sing-box/dns/client.go @@ -537,7 +537,7 @@ func (c *Client) loadResponse(question dns.Question, transport adapter.DNSTransp } func MessageToAddresses(response *dns.Msg) []netip.Addr { - if response.Rcode != dns.RcodeSuccess { + if response == nil || response.Rcode != dns.RcodeSuccess { return nil } addresses := make([]netip.Addr, 0, len(response.Answer)) diff --git a/sing-box/dns/transport/https.go b/sing-box/dns/transport/https.go index f02fd3302d..d54fb8e38f 100644 --- a/sing-box/dns/transport/https.go +++ b/sing-box/dns/transport/https.go @@ -59,11 +59,11 @@ func NewHTTPS(ctx context.Context, logger log.ContextLogger, tag string, options } tlsOptions := common.PtrValueOrDefault(options.TLS) tlsOptions.Enabled = true - tlsConfig, err := tls.NewClient(ctx, options.Server, tlsOptions) + tlsConfig, err := tls.NewClient(ctx, logger, options.Server, tlsOptions) if err != nil { return nil, err } - if common.Error(tlsConfig.Config()) == nil && !common.Contains(tlsConfig.NextProtos(), http2.NextProtoTLS) { + if common.Error(tlsConfig.STDConfig()) == nil && !common.Contains(tlsConfig.NextProtos(), http2.NextProtoTLS) { tlsConfig.SetNextProtos(append(tlsConfig.NextProtos(), http2.NextProtoTLS)) } if !common.Contains(tlsConfig.NextProtos(), "http/1.1") { diff --git a/sing-box/dns/transport/quic/http3.go b/sing-box/dns/transport/quic/http3.go index fd1591a379..e81e6d159c 100644 --- a/sing-box/dns/transport/quic/http3.go +++ b/sing-box/dns/transport/quic/http3.go @@ -51,11 +51,11 @@ func NewHTTP3(ctx context.Context, logger log.ContextLogger, tag string, options } tlsOptions := common.PtrValueOrDefault(options.TLS) tlsOptions.Enabled = true - tlsConfig, err := tls.NewClient(ctx, options.Server, tlsOptions) + tlsConfig, err := tls.NewClient(ctx, logger, options.Server, tlsOptions) if err != nil { return nil, err } - stdConfig, err := tlsConfig.Config() + stdConfig, err := tlsConfig.STDConfig() if err != nil { return nil, err } diff --git a/sing-box/dns/transport/quic/quic.go b/sing-box/dns/transport/quic/quic.go index 515aff58e3..39bbab8e1d 100644 --- a/sing-box/dns/transport/quic/quic.go +++ b/sing-box/dns/transport/quic/quic.go @@ -48,7 +48,7 @@ func NewQUIC(ctx context.Context, logger log.ContextLogger, tag string, options } tlsOptions := common.PtrValueOrDefault(options.TLS) tlsOptions.Enabled = true - tlsConfig, err := tls.NewClient(ctx, options.Server, tlsOptions) + tlsConfig, err := tls.NewClient(ctx, logger, options.Server, tlsOptions) if err != nil { return nil, err } diff --git a/sing-box/dns/transport/tls.go b/sing-box/dns/transport/tls.go index 9cb35fd9af..932a72a8ef 100644 --- a/sing-box/dns/transport/tls.go +++ b/sing-box/dns/transport/tls.go @@ -49,7 +49,7 @@ func NewTLS(ctx context.Context, logger log.ContextLogger, tag string, options o } tlsOptions := common.PtrValueOrDefault(options.TLS) tlsOptions.Enabled = true - tlsConfig, err := tls.NewClient(ctx, options.Server, tlsOptions) + tlsConfig, err := tls.NewClient(ctx, logger, options.Server, tlsOptions) if err != nil { return nil, err } diff --git a/sing-box/docs/changelog.md b/sing-box/docs/changelog.md index 2ca2f582c0..9ba2b38555 100644 --- a/sing-box/docs/changelog.md +++ b/sing-box/docs/changelog.md @@ -4,8 +4,13 @@ icon: material/alert-decagram #### 1.13.0-alpha.9 +* Add kTLS support **1** * Fixes and improvements +**1**: + +See [TLS](/configuration/shared/tls/). + #### 1.12.4 * Fixes and improvements diff --git a/sing-box/docs/configuration/shared/tls.md b/sing-box/docs/configuration/shared/tls.md index 6fe74846bd..ead462ee94 100644 --- a/sing-box/docs/configuration/shared/tls.md +++ b/sing-box/docs/configuration/shared/tls.md @@ -1,7 +1,12 @@ --- -icon: material/alert-decagram +icon: material/new-box --- +!!! quote "Changes in sing-box 1.13.0" + + :material-plus: [kernel_tx](#kernel_tx) + :material-plus: [kernel_rx](#kernel_rx) + !!! quote "Changes in sing-box 1.12.0" :material-plus: [fragment](#fragment) @@ -28,6 +33,8 @@ icon: material/alert-decagram "certificate_path": "", "key": [], "key_path": "", + "kernel_tx": false, + "kernel_rx": false, "acme": { "domain": [], "data_directory": "", @@ -188,7 +195,8 @@ By default, the maximum version is currently TLS 1.3. #### cipher_suites -A list of enabled TLS 1.0–1.2 cipher suites. The order of the list is ignored. Note that TLS 1.3 cipher suites are not configurable. +A list of enabled TLS 1.0–1.2 cipher suites. The order of the list is ignored. +Note that TLS 1.3 cipher suites are not configurable. If empty, a safe default list is used. The default cipher suites might change over time. @@ -220,6 +228,50 @@ The server private key line array, in PEM format. The path to the server private key, in PEM format. +#### kernel_tx + +!!! question "Since sing-box 1.13.0" + +!!! quote "" + + Only supported on Linux 5.1+, use a newer kernel if possible. + +!!! quote "" + + Only TLS 1.3 is supported. + +!!! warning "" + + uTLS is compatible, but not other custom TLS. + +!!! warning "" + + kTLS TX may only improve performance when `splice(2)` is available (both ends must be TCP or TLS without additional protocols after handshake); otherwise, it will definitely degrade performance. + +Enable kernel TLS transmit support. + +#### kernel_rx + +!!! question "Since sing-box 1.13.0" + +!!! quote "" + + Only supported on Linux 5.1+, use a newer kernel if possible. + +!!! quote "" + + Only TLS 1.3 is supported. + +!!! warning "" + + uTLS is compatible, but not other custom TLS. + +!!! failure "" + + kTLS RX will definitely degrade performance even if `splice(2)` is in use, so enabling it is not recommended. + +Enable kernel TLS receive support. + ## Custom TLS support !!! info "QUIC support" diff --git a/sing-box/docs/configuration/shared/tls.zh.md b/sing-box/docs/configuration/shared/tls.zh.md index b85d32907f..ef8a7c762a 100644 --- a/sing-box/docs/configuration/shared/tls.zh.md +++ b/sing-box/docs/configuration/shared/tls.zh.md @@ -2,6 +2,11 @@ icon: material/alert-decagram --- +!!! quote "sing-box 1.13.0 中的更改" + + :material-plus: [kernel_tx](#kernel_tx) + :material-plus: [kernel_rx](#kernel_rx) + !!! quote "sing-box 1.12.0 中的更改" :material-plus: [tls_fragment](#tls_fragment) @@ -28,6 +33,8 @@ icon: material/alert-decagram "certificate_path": "", "key": [], "key_path": "", + "kernel_tx": false, + "kernel_rx": false, "acme": { "domain": [], "data_directory": "", @@ -216,6 +223,56 @@ TLS 版本值: 服务器 PEM 私钥路径。 +#### kernel_tx + +!!! question "自 sing-box 1.13.0 起" + +!!! quote "" + + 仅支持 Linux 5.1+,如果可能,使用较新的内核。 + +!!! quote "" + + 仅支持 TLS 1.3。 + +!!! warning "" + + 兼容 uTLS,但不兼容其他自定义 TLS。 + +!!! warning "" + + kTLS TX 仅当 `splice(2)` 可用时(两端经过握手后必须为没有附加协议的 TCP 或 TLS)才能提高性能;否则肯定会降低性能。 + +启用内核 TLS 发送支持。 + +#### kernel_rx + +!!! question "自 sing-box 1.13.0 起" + +!!! quote "" + + 仅支持 Linux 5.1+,如果可能,使用较新的内核。 + +!!! quote "" + + 仅支持 TLS 1.3。 + +!!! warning "" + + 兼容 uTLS,但不兼容其他自定义 TLS。 + +!!! failure "" + + 即使使用 `splice(2)`,kTLS RX 也肯定会降低性能,因此不建议启用。 + +启用内核 TLS 接收支持。 + +## 自定义 TLS 支持 + +!!! info "QUIC 支持" + + 只有 ECH 在 QUIC 中被支持. + #### utls ==仅客户端== diff --git a/sing-box/go.mod b/sing-box/go.mod index 036ae02754..e3b91e8c9a 100644 --- a/sing-box/go.mod +++ b/sing-box/go.mod @@ -4,7 +4,6 @@ go 1.23.1 require ( github.com/anytls/sing-anytls v0.0.8 - github.com/blang/semver/v4 v4.0.0 github.com/caddyserver/certmagic v0.23.0 github.com/coder/websocket v1.8.13 github.com/cretz/bine v0.2.0 @@ -28,9 +27,9 @@ require ( github.com/sagernet/gomobile v0.1.8 github.com/sagernet/gvisor v0.0.0-20250822052253-5558536cf237 github.com/sagernet/quic-go v0.52.0-beta.1 - github.com/sagernet/sing v0.7.8-0.20250907125815-3d24f9b5ff7c + github.com/sagernet/sing v0.7.8-0.20250908063931-beb351e61b89 github.com/sagernet/sing-mux v0.3.3 - github.com/sagernet/sing-quic v0.5.1 + github.com/sagernet/sing-quic v0.5.2-0.20250908021228-186e280a524e github.com/sagernet/sing-shadowsocks v0.2.8 github.com/sagernet/sing-shadowsocks2 v0.2.1 github.com/sagernet/sing-shadowtls v0.2.1-0.20250503051639-fcd445d33c11 diff --git a/sing-box/go.sum b/sing-box/go.sum index db3b7df0d7..ed625e3ae0 100644 --- a/sing-box/go.sum +++ b/sing-box/go.sum @@ -12,8 +12,6 @@ github.com/anytls/sing-anytls v0.0.8 h1:1u/fnH1HoeeMV5mX7/eUOjLBvPdkd1UJRmXiRi6V github.com/anytls/sing-anytls v0.0.8/go.mod h1:7rjN6IukwysmdusYsrV51Fgu1uW6vsrdd6ctjnEAln8= github.com/bits-and-blooms/bitset v1.13.0 h1:bAQ9OPNFYbGHV6Nez0tmNI0RiEu7/hxlYJRUA0wFAVE= github.com/bits-and-blooms/bitset v1.13.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8= -github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM= -github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ= github.com/caddyserver/certmagic v0.23.0 h1:CfpZ/50jMfG4+1J/u2LV6piJq4HOfO6ppOnOf7DkFEU= github.com/caddyserver/certmagic v0.23.0/go.mod h1:9mEZIWqqWoI+Gf+4Trh04MOVPD0tGSxtqsxg87hAIH4= github.com/caddyserver/zerossl v0.1.3 h1:onS+pxp3M8HnHpN5MMbOMyNjmTheJyWRaZYwn+YTAyA= @@ -169,12 +167,12 @@ github.com/sagernet/nftables v0.3.0-beta.4/go.mod h1:OQXAjvjNGGFxaTgVCSTRIhYB5/l github.com/sagernet/quic-go v0.52.0-beta.1 h1:hWkojLg64zjV+MJOvJU/kOeWndm3tiEfBLx5foisszs= github.com/sagernet/quic-go v0.52.0-beta.1/go.mod h1:OV+V5kEBb8kJS7k29MzDu6oj9GyMc7HA07sE1tedxz4= github.com/sagernet/sing v0.6.9/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak= -github.com/sagernet/sing v0.7.8-0.20250907125815-3d24f9b5ff7c h1:7jbIoVt3p1vlgQoyWIlzRvwInNwDxe6+tSJME07LTmI= -github.com/sagernet/sing v0.7.8-0.20250907125815-3d24f9b5ff7c/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak= +github.com/sagernet/sing v0.7.8-0.20250908063931-beb351e61b89 h1:Of7kq85JItQmR4Y8m3L/DFFxaxyjK9rJvLMpmXPQ7g0= +github.com/sagernet/sing v0.7.8-0.20250908063931-beb351e61b89/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak= github.com/sagernet/sing-mux v0.3.3 h1:YFgt9plMWzH994BMZLmyKL37PdIVaIilwP0Jg+EcLfw= github.com/sagernet/sing-mux v0.3.3/go.mod h1:pht8iFY4c9Xltj7rhVd208npkNaeCxzyXCgulDPLUDA= -github.com/sagernet/sing-quic v0.5.1 h1:o+mX/schfy6fbbU2rnb6ouUYOL+iUBjA4jOZqyIvDsU= -github.com/sagernet/sing-quic v0.5.1/go.mod h1:evP1e++ZG8TJHVV5HudXV4vWeYzGfCdF4HwSJZcdqkI= +github.com/sagernet/sing-quic v0.5.2-0.20250908021228-186e280a524e h1:l+DICzp1OecGSDoiHE0Ebviaz3zqSp7XM27UcRbGkBM= +github.com/sagernet/sing-quic v0.5.2-0.20250908021228-186e280a524e/go.mod h1:gi/sGED8gTWgTAp3GlzXo2D7mXYY+ERoxtGvSkNx3sI= github.com/sagernet/sing-shadowsocks v0.2.8 h1:PURj5PRoAkqeHh2ZW205RWzN9E9RtKCVCzByXruQWfE= github.com/sagernet/sing-shadowsocks v0.2.8/go.mod h1:lo7TWEMDcN5/h5B8S0ew+r78ZODn6SwVaFhvB6H+PTI= github.com/sagernet/sing-shadowsocks2 v0.2.1 h1:dWV9OXCeFPuYGHb6IRqlSptVnSzOelnqqs2gQ2/Qioo= diff --git a/sing-box/protocol/anytls/outbound.go b/sing-box/protocol/anytls/outbound.go index ce71ed6161..fa5fe2419c 100644 --- a/sing-box/protocol/anytls/outbound.go +++ b/sing-box/protocol/anytls/outbound.go @@ -44,7 +44,7 @@ func NewOutbound(ctx context.Context, router adapter.Router, logger log.ContextL return nil, C.ErrTLSRequired } - tlsConfig, err := tls.NewClient(ctx, options.Server, common.PtrValueOrDefault(options.TLS)) + tlsConfig, err := tls.NewClient(ctx, logger, options.Server, common.PtrValueOrDefault(options.TLS)) if err != nil { return nil, err } diff --git a/sing-box/protocol/http/inbound.go b/sing-box/protocol/http/inbound.go index 68150fa741..e8a9a3daa5 100644 --- a/sing-box/protocol/http/inbound.go +++ b/sing-box/protocol/http/inbound.go @@ -43,7 +43,12 @@ func NewInbound(ctx context.Context, router adapter.Router, logger log.ContextLo authenticator: auth.NewAuthenticator(options.Users), } if options.TLS != nil { - tlsConfig, err := tls.NewServer(ctx, logger, common.PtrValueOrDefault(options.TLS)) + tlsConfig, err := tls.NewServerWithOptions(tls.ServerOptions{ + Context: ctx, + Logger: logger, + Options: common.PtrValueOrDefault(options.TLS), + KTLSCompatible: true, + }) if err != nil { return nil, err } diff --git a/sing-box/protocol/http/outbound.go b/sing-box/protocol/http/outbound.go index 3b631b39b5..48c4be6b62 100644 --- a/sing-box/protocol/http/outbound.go +++ b/sing-box/protocol/http/outbound.go @@ -34,7 +34,7 @@ func NewOutbound(ctx context.Context, router adapter.Router, logger log.ContextL if err != nil { return nil, err } - detour, err := tls.NewDialerFromOptions(ctx, outboundDialer, options.Server, common.PtrValueOrDefault(options.TLS)) + detour, err := tls.NewDialerFromOptions(ctx, logger, outboundDialer, options.Server, common.PtrValueOrDefault(options.TLS)) if err != nil { return nil, err } diff --git a/sing-box/protocol/hysteria/outbound.go b/sing-box/protocol/hysteria/outbound.go index 42a37ee6c1..bcadd878ab 100644 --- a/sing-box/protocol/hysteria/outbound.go +++ b/sing-box/protocol/hysteria/outbound.go @@ -43,7 +43,7 @@ func NewOutbound(ctx context.Context, router adapter.Router, logger log.ContextL if options.TLS == nil || !options.TLS.Enabled { return nil, C.ErrTLSRequired } - tlsConfig, err := tls.NewClient(ctx, options.Server, common.PtrValueOrDefault(options.TLS)) + tlsConfig, err := tls.NewClient(ctx, logger, options.Server, common.PtrValueOrDefault(options.TLS)) if err != nil { return nil, err } diff --git a/sing-box/protocol/hysteria2/outbound.go b/sing-box/protocol/hysteria2/outbound.go index c805f07e39..d4382fdcdf 100644 --- a/sing-box/protocol/hysteria2/outbound.go +++ b/sing-box/protocol/hysteria2/outbound.go @@ -44,7 +44,7 @@ func NewOutbound(ctx context.Context, router adapter.Router, logger log.ContextL if options.TLS == nil || !options.TLS.Enabled { return nil, C.ErrTLSRequired } - tlsConfig, err := tls.NewClient(ctx, options.Server, common.PtrValueOrDefault(options.TLS)) + tlsConfig, err := tls.NewClient(ctx, logger, options.Server, common.PtrValueOrDefault(options.TLS)) if err != nil { return nil, err } diff --git a/sing-box/protocol/mixed/inbound.go b/sing-box/protocol/mixed/inbound.go index fe84aa01a4..5591c31504 100644 --- a/sing-box/protocol/mixed/inbound.go +++ b/sing-box/protocol/mixed/inbound.go @@ -8,10 +8,12 @@ import ( "github.com/sagernet/sing-box/adapter" "github.com/sagernet/sing-box/adapter/inbound" "github.com/sagernet/sing-box/common/listener" + "github.com/sagernet/sing-box/common/tls" "github.com/sagernet/sing-box/common/uot" C "github.com/sagernet/sing-box/constant" "github.com/sagernet/sing-box/log" "github.com/sagernet/sing-box/option" + "github.com/sagernet/sing/common" "github.com/sagernet/sing/common/auth" E "github.com/sagernet/sing/common/exceptions" N "github.com/sagernet/sing/common/network" @@ -33,6 +35,7 @@ type Inbound struct { logger log.ContextLogger listener *listener.Listener authenticator *auth.Authenticator + tlsConfig tls.ServerConfig } func NewInbound(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.HTTPMixedInboundOptions) (adapter.Inbound, error) { @@ -42,6 +45,18 @@ func NewInbound(ctx context.Context, router adapter.Router, logger log.ContextLo logger: logger, authenticator: auth.NewAuthenticator(options.Users), } + if options.TLS != nil { + tlsConfig, err := tls.NewServerWithOptions(tls.ServerOptions{ + Context: ctx, + Logger: logger, + Options: common.PtrValueOrDefault(options.TLS), + KTLSCompatible: true, + }) + if err != nil { + return nil, err + } + inbound.tlsConfig = tlsConfig + } inbound.listener = listener.New(listener.Options{ Context: ctx, Logger: logger, @@ -58,11 +73,20 @@ func (h *Inbound) Start(stage adapter.StartStage) error { if stage != adapter.StartStateStart { return nil } + if h.tlsConfig != nil { + err := h.tlsConfig.Start() + if err != nil { + return E.Cause(err, "create TLS config") + } + } return h.listener.Start() } func (h *Inbound) Close() error { - return h.listener.Close() + return common.Close( + h.listener, + h.tlsConfig, + ) } func (h *Inbound) NewConnectionEx(ctx context.Context, conn net.Conn, metadata adapter.InboundContext, onClose N.CloseHandlerFunc) { @@ -78,6 +102,13 @@ func (h *Inbound) NewConnectionEx(ctx context.Context, conn net.Conn, metadata a } func (h *Inbound) newConnection(ctx context.Context, conn net.Conn, metadata adapter.InboundContext, onClose N.CloseHandlerFunc) error { + if h.tlsConfig != nil { + tlsConn, err := tls.ServerHandshake(ctx, conn, h.tlsConfig) + if err != nil { + return E.Cause(err, "TLS handshake") + } + conn = tlsConn + } reader := std_bufio.NewReader(conn) headerBytes, err := reader.Peek(1) if err != nil { diff --git a/sing-box/protocol/naive/inbound.go b/sing-box/protocol/naive/inbound.go index f6e456f524..21371f49d7 100644 --- a/sing-box/protocol/naive/inbound.go +++ b/sing-box/protocol/naive/inbound.go @@ -88,7 +88,7 @@ func (n *Inbound) Start(stage adapter.StartStage) error { if err != nil { return E.Cause(err, "create TLS config") } - tlsConfig, err = n.tlsConfig.Config() + tlsConfig, err = n.tlsConfig.STDConfig() if err != nil { return err } diff --git a/sing-box/protocol/shadowtls/outbound.go b/sing-box/protocol/shadowtls/outbound.go index 0731b0337b..41a4a6016d 100644 --- a/sing-box/protocol/shadowtls/outbound.go +++ b/sing-box/protocol/shadowtls/outbound.go @@ -43,7 +43,7 @@ func NewOutbound(ctx context.Context, router adapter.Router, logger log.ContextL options.TLS.MinVersion = "1.2" options.TLS.MaxVersion = "1.2" } - tlsConfig, err := tls.NewClient(ctx, options.Server, common.PtrValueOrDefault(options.TLS)) + tlsConfig, err := tls.NewClient(ctx, logger, options.Server, common.PtrValueOrDefault(options.TLS)) if err != nil { return nil, err } @@ -61,7 +61,7 @@ func NewOutbound(ctx context.Context, router adapter.Router, logger log.ContextL return common.Error(tls.ClientHandshake(ctx, conn, tlsConfig)) } } else { - stdTLSConfig, err := tlsConfig.Config() + stdTLSConfig, err := tlsConfig.STDConfig() if err != nil { return nil, err } diff --git a/sing-box/protocol/tailscale/dns_transport.go b/sing-box/protocol/tailscale/dns_transport.go index 51115717cd..521bb55146 100644 --- a/sing-box/protocol/tailscale/dns_transport.go +++ b/sing-box/protocol/tailscale/dns_transport.go @@ -166,7 +166,7 @@ func (t *DNSTransport) createResolver(directDialer func() N.Dialer, resolver *dn if serverAddr.Port == 0 { serverAddr.Port = 443 } - tlsConfig := common.Must1(tls.NewClient(t.ctx, serverAddr.AddrString(), option.OutboundTLSOptions{ + tlsConfig := common.Must1(tls.NewClient(t.ctx, t.logger, serverAddr.AddrString(), option.OutboundTLSOptions{ ALPN: []string{http2.NextProtoTLS, "http/1.1"}, })) return transport.NewHTTPSRaw(t.TransportAdapter, t.logger, myDialer, serverURL, http.Header{}, serverAddr, tlsConfig), nil diff --git a/sing-box/protocol/trojan/inbound.go b/sing-box/protocol/trojan/inbound.go index ec95a81eab..24e8a023c8 100644 --- a/sing-box/protocol/trojan/inbound.go +++ b/sing-box/protocol/trojan/inbound.go @@ -50,7 +50,13 @@ func NewInbound(ctx context.Context, router adapter.Router, logger log.ContextLo users: options.Users, } if options.TLS != nil { - tlsConfig, err := tls.NewServer(ctx, logger, common.PtrValueOrDefault(options.TLS)) + tlsConfig, err := tls.NewServerWithOptions(tls.ServerOptions{ + Context: ctx, + Logger: logger, + Options: common.PtrValueOrDefault(options.TLS), + KTLSCompatible: common.PtrValueOrDefault(options.Transport).Type == "" && + !common.PtrValueOrDefault(options.Multiplex).Enabled, + }) if err != nil { return nil, err } diff --git a/sing-box/protocol/trojan/outbound.go b/sing-box/protocol/trojan/outbound.go index dc2e0fe44f..26c7c81fe8 100644 --- a/sing-box/protocol/trojan/outbound.go +++ b/sing-box/protocol/trojan/outbound.go @@ -51,7 +51,14 @@ func NewOutbound(ctx context.Context, router adapter.Router, logger log.ContextL key: trojan.Key(options.Password), } if options.TLS != nil { - outbound.tlsConfig, err = tls.NewClient(ctx, options.Server, common.PtrValueOrDefault(options.TLS)) + outbound.tlsConfig, err = tls.NewClientWithOptions(tls.ClientOptions{ + Context: ctx, + Logger: logger, + ServerAddress: options.Server, + Options: common.PtrValueOrDefault(options.TLS), + KTLSCompatible: common.PtrValueOrDefault(options.Transport).Type == "" && + !common.PtrValueOrDefault(options.Multiplex).Enabled, + }) if err != nil { return nil, err } diff --git a/sing-box/protocol/tuic/outbound.go b/sing-box/protocol/tuic/outbound.go index a31d48509c..94d3cb774c 100644 --- a/sing-box/protocol/tuic/outbound.go +++ b/sing-box/protocol/tuic/outbound.go @@ -43,7 +43,7 @@ func NewOutbound(ctx context.Context, router adapter.Router, logger log.ContextL if options.TLS == nil || !options.TLS.Enabled { return nil, C.ErrTLSRequired } - tlsConfig, err := tls.NewClient(ctx, options.Server, common.PtrValueOrDefault(options.TLS)) + tlsConfig, err := tls.NewClient(ctx, logger, options.Server, common.PtrValueOrDefault(options.TLS)) if err != nil { return nil, err } diff --git a/sing-box/protocol/vless/inbound.go b/sing-box/protocol/vless/inbound.go index 3cc53db425..1df7cb01f6 100644 --- a/sing-box/protocol/vless/inbound.go +++ b/sing-box/protocol/vless/inbound.go @@ -68,7 +68,16 @@ func NewInbound(ctx context.Context, router adapter.Router, logger log.ContextLo })) inbound.service = service if options.TLS != nil { - inbound.tlsConfig, err = tls.NewServer(ctx, logger, common.PtrValueOrDefault(options.TLS)) + inbound.tlsConfig, err = tls.NewServerWithOptions(tls.ServerOptions{ + Context: ctx, + Logger: logger, + Options: common.PtrValueOrDefault(options.TLS), + KTLSCompatible: common.PtrValueOrDefault(options.Transport).Type == "" && + !common.PtrValueOrDefault(options.Multiplex).Enabled && + common.All(options.Users, func(it option.VLESSUser) bool { + return it.Flow == "" + }), + }) if err != nil { return nil, err } diff --git a/sing-box/protocol/vless/outbound.go b/sing-box/protocol/vless/outbound.go index a96d12a0a3..ab77476067 100644 --- a/sing-box/protocol/vless/outbound.go +++ b/sing-box/protocol/vless/outbound.go @@ -53,7 +53,15 @@ func NewOutbound(ctx context.Context, router adapter.Router, logger log.ContextL serverAddr: options.ServerOptions.Build(), } if options.TLS != nil { - outbound.tlsConfig, err = tls.NewClient(ctx, options.Server, common.PtrValueOrDefault(options.TLS)) + outbound.tlsConfig, err = tls.NewClientWithOptions(tls.ClientOptions{ + Context: ctx, + Logger: logger, + ServerAddress: options.Server, + Options: common.PtrValueOrDefault(options.TLS), + KTLSCompatible: common.PtrValueOrDefault(options.Transport).Type == "" && + !common.PtrValueOrDefault(options.Multiplex).Enabled && + options.Flow == "", + }) if err != nil { return nil, err } diff --git a/sing-box/protocol/vmess/outbound.go b/sing-box/protocol/vmess/outbound.go index 716570f3c3..cb5c674f7f 100644 --- a/sing-box/protocol/vmess/outbound.go +++ b/sing-box/protocol/vmess/outbound.go @@ -53,7 +53,7 @@ func NewOutbound(ctx context.Context, router adapter.Router, logger log.ContextL serverAddr: options.ServerOptions.Build(), } if options.TLS != nil { - outbound.tlsConfig, err = tls.NewClient(ctx, options.Server, common.PtrValueOrDefault(options.TLS)) + outbound.tlsConfig, err = tls.NewClient(ctx, logger, options.Server, common.PtrValueOrDefault(options.TLS)) if err != nil { return nil, err } diff --git a/sing-box/service/derp/service.go b/sing-box/service/derp/service.go index 861bb235f7..de422bb3e6 100644 --- a/sing-box/service/derp/service.go +++ b/sing-box/service/derp/service.go @@ -301,11 +301,11 @@ func (d *Service) startMeshWithHost(derpServer *derp.Server, server *option.DERP } var stdConfig *tls.STDConfig if server.TLS != nil && server.TLS.Enabled { - tlsConfig, err := tls.NewClient(d.ctx, hostname, common.PtrValueOrDefault(server.TLS)) + tlsConfig, err := tls.NewClient(d.ctx, d.logger, hostname, common.PtrValueOrDefault(server.TLS)) if err != nil { return err } - stdConfig, err = tlsConfig.Config() + stdConfig, err = tlsConfig.STDConfig() if err != nil { return err } diff --git a/sing-box/service/resolved/transport.go b/sing-box/service/resolved/transport.go index eb756fdbba..c54a63416c 100644 --- a/sing-box/service/resolved/transport.go +++ b/sing-box/service/resolved/transport.go @@ -129,7 +129,7 @@ func (t *Transport) updateTransports(link *TransportLink) error { return os.ErrInvalid } if link.dnsOverTLS { - tlsConfig := common.Must1(tls.NewClient(t.ctx, serverAddr.String(), option.OutboundTLSOptions{ + tlsConfig := common.Must1(tls.NewClient(t.ctx, t.logger, serverAddr.String(), option.OutboundTLSOptions{ Enabled: true, ServerName: serverAddr.String(), })) @@ -151,7 +151,7 @@ func (t *Transport) updateTransports(link *TransportLink) error { } else { serverName = serverAddr.String() } - tlsConfig := common.Must1(tls.NewClient(t.ctx, serverAddr.String(), option.OutboundTLSOptions{ + tlsConfig := common.Must1(tls.NewClient(t.ctx, t.logger, serverAddr.String(), option.OutboundTLSOptions{ Enabled: true, ServerName: serverName, })) diff --git a/sing-box/transport/sip003/v2ray.go b/sing-box/transport/sip003/v2ray.go index d7b752f6c3..f35e265493 100644 --- a/sing-box/transport/sip003/v2ray.go +++ b/sing-box/transport/sip003/v2ray.go @@ -13,6 +13,7 @@ import ( "github.com/sagernet/sing-vmess" E "github.com/sagernet/sing/common/exceptions" "github.com/sagernet/sing/common/json/badoption" + "github.com/sagernet/sing/common/logger" M "github.com/sagernet/sing/common/metadata" N "github.com/sagernet/sing/common/network" ) @@ -55,7 +56,7 @@ func newV2RayPlugin(ctx context.Context, pluginOpts Args, router adapter.Router, var tlsClient tls.Config var err error if tlsOptions.Enabled { - tlsClient, err = tls.NewClient(ctx, serverAddr.AddrString(), tlsOptions) + tlsClient, err = tls.NewClient(ctx, logger.NOP(), serverAddr.AddrString(), tlsOptions) if err != nil { return nil, err } diff --git a/small/luci-app-passwall/luasrc/model/cbi/passwall/client/type/ray.lua b/small/luci-app-passwall/luasrc/model/cbi/passwall/client/type/ray.lua index 64e8555e4d..c191f7578f 100644 --- a/small/luci-app-passwall/luasrc/model/cbi/passwall/client/type/ray.lua +++ b/small/luci-app-passwall/luasrc/model/cbi/passwall/client/type/ray.lua @@ -98,7 +98,27 @@ end) -- 负载均衡列表 local o = s:option(DynamicList, _n("balancing_node"), translate("Load balancing node list"), translate("Load balancing node list, document")) o:depends({ [_n("protocol")] = "_balancing" }) -for k, v in pairs(nodes_table) do o:value(v.id, v.remark) end +local valid_ids = {} +for k, v in pairs(nodes_table) do + o:value(v.id, v.remark) + valid_ids[v.id] = true +end +-- 去重并禁止自定义非法输入 +function o.custom_write(self, section, value) + local result = {} + if type(value) == "table" then + local seen = {} + for _, v in ipairs(value) do + if v and not seen[v] and valid_ids[v] then + table.insert(result, v) + seen[v] = true + end + end + else + result = { value } + end + api.uci:set_list(appname, section, "balancing_node", result) +end local o = s:option(ListValue, _n("balancingStrategy"), translate("Balancing Strategy")) o:depends({ [_n("protocol")] = "_balancing" }) @@ -677,9 +697,6 @@ o:depends({ [_n("xmux")] = true }) o = s:option(Flag, _n("tcpMptcp"), "tcpMptcp", translate("Enable Multipath TCP, need to be enabled in both server and client configuration.")) o.default = 0 -o = s:option(Flag, _n("tcpNoDelay"), "tcpNoDelay") -o.default = 0 - o = s:option(ListValue, _n("chain_proxy"), translate("Chain Proxy")) o:value("", translate("Close(Not use)")) o:value("1", translate("Preproxy Node")) @@ -706,7 +723,6 @@ end for i, v in ipairs(s.fields[_n("protocol")].keylist) do if not v:find("_") then s.fields[_n("tcpMptcp")]:depends({ [_n("protocol")] = v }) - s.fields[_n("tcpNoDelay")]:depends({ [_n("protocol")] = v }) s.fields[_n("chain_proxy")]:depends({ [_n("protocol")] = v }) end end diff --git a/small/luci-app-passwall/luasrc/model/cbi/passwall/client/type/sing-box.lua b/small/luci-app-passwall/luasrc/model/cbi/passwall/client/type/sing-box.lua index 42e12b7c5d..4c6b2f51d9 100644 --- a/small/luci-app-passwall/luasrc/model/cbi/passwall/client/type/sing-box.lua +++ b/small/luci-app-passwall/luasrc/model/cbi/passwall/client/type/sing-box.lua @@ -107,7 +107,27 @@ end) --[[ URLTest ]] o = s:option(DynamicList, _n("urltest_node"), translate("URLTest node list"), translate("List of nodes to test, document")) o:depends({ [_n("protocol")] = "_urltest" }) -for k, v in pairs(nodes_table) do o:value(v.id, v.remark) end +local valid_ids = {} +for k, v in pairs(nodes_table) do + o:value(v.id, v.remark) + valid_ids[v.id] = true +end +-- 去重并禁止自定义非法输入 +function o.custom_write(self, section, value) + local result = {} + if type(value) == "table" then + local seen = {} + for _, v in ipairs(value) do + if v and not seen[v] and valid_ids[v] then + table.insert(result, v) + seen[v] = true + end + end + else + result = { value } + end + api.uci:set_list(appname, section, "urltest_node", result) +end o = s:option(Value, _n("urltest_url"), translate("Probe URL")) o:depends({ [_n("protocol")] = "_urltest" }) diff --git a/small/luci-app-passwall/luasrc/passwall/util_xray.lua b/small/luci-app-passwall/luasrc/passwall/util_xray.lua index 90e2f9eeca..e495c79fb0 100644 --- a/small/luci-app-passwall/luasrc/passwall/util_xray.lua +++ b/small/luci-app-passwall/luasrc/passwall/util_xray.lua @@ -147,7 +147,6 @@ function gen_outbound(flag, node, tag, proxy_table) sockopt = { mark = 255, tcpMptcp = (node.tcpMptcp == "1") and true or nil, - tcpNoDelay = (node.tcpNoDelay == "1") and true or nil, dialerProxy = (fragment or noise) and "dialerproxy" or nil }, network = node.transport, @@ -1477,8 +1476,7 @@ function gen_config(var) }, streamSettings = { sockopt = { - mark = 255, - tcpNoDelay = true + mark = 255 } } }) diff --git a/small/v2ray-geodata/Makefile b/small/v2ray-geodata/Makefile index 9f3d576287..3e4dd4aa4a 100644 --- a/small/v2ray-geodata/Makefile +++ b/small/v2ray-geodata/Makefile @@ -30,7 +30,7 @@ define Download/geosite HASH:=186158b6c2f67ac59e184ed997ebebcef31938be9874eb8a7d5e3854187f4e8d endef -GEOSITE_IRAN_VER:=202509010047 +GEOSITE_IRAN_VER:=202509080039 GEOSITE_IRAN_FILE:=iran.dat.$(GEOSITE_IRAN_VER) define Download/geosite-ir URL:=https://github.com/bootmortis/iran-hosted-domains/releases/download/$(GEOSITE_IRAN_VER)/ diff --git a/v2rayn/package-appimage.sh b/v2rayn/package-appimage.sh index 77df287ba6..6a8bfcca2f 100644 --- a/v2rayn/package-appimage.sh +++ b/v2rayn/package-appimage.sh @@ -1,14 +1,67 @@ #!/bin/bash +set -euo pipefail +# Install deps sudo apt update -y -sudo apt install -y libfuse2 -wget -O pkg2appimage https://github.com/AppImageCommunity/pkg2appimage/releases/download/continuous/pkg2appimage-1eceb30-x86_64.AppImage -chmod a+x pkg2appimage -export AppImageOutputArch=$OutputArch -export OutputPath=$OutputPath64 -./pkg2appimage ./pkg2appimage.yml -mv out/*.AppImage v2rayN-${AppImageOutputArch}.AppImage -export AppImageOutputArch=$OutputArchArm -export OutputPath=$OutputPathArm64 -./pkg2appimage ./pkg2appimage.yml -mv out/*.AppImage v2rayN-${AppImageOutputArch}.AppImage +sudo apt install -y libfuse2 wget file + +# Get tools +wget -qO appimagetool https://github.com/AppImage/AppImageKit/releases/download/continuous/appimagetool-x86_64.AppImage +chmod +x appimagetool + +# x86_64 AppDir +APPDIR_X64="AppDir-x86_64" +rm -rf "$APPDIR_X64" +mkdir -p "$APPDIR_X64/usr/lib/v2rayN" "$APPDIR_X64/usr/bin" "$APPDIR_X64/usr/share/applications" "$APPDIR_X64/usr/share/pixmaps" +cp -rf "$OutputPath64"/* "$APPDIR_X64/usr/lib/v2rayN" || true +[ -f "$APPDIR_X64/usr/lib/v2rayN/v2rayN.png" ] && cp "$APPDIR_X64/usr/lib/v2rayN/v2rayN.png" "$APPDIR_X64/usr/share/pixmaps/v2rayN.png" || true +[ -f "$APPDIR_X64/usr/lib/v2rayN/v2rayN.png" ] && cp "$APPDIR_X64/usr/lib/v2rayN/v2rayN.png" "$APPDIR_X64/v2rayN.png" || true + +printf '%s\n' '#!/bin/sh' 'HERE="$(dirname "$(readlink -f "$0")")"' 'cd "$HERE/usr/lib/v2rayN"' 'exec "$HERE/usr/lib/v2rayN/v2rayN" "$@"' > "$APPDIR_X64/AppRun" +chmod +x "$APPDIR_X64/AppRun" +ln -sf usr/lib/v2rayN/v2rayN "$APPDIR_X64/usr/bin/v2rayN" +cat > "$APPDIR_X64/v2rayN.desktop" < "$APPDIR_ARM64/AppRun" +chmod +x "$APPDIR_ARM64/AppRun" +ln -sf usr/lib/v2rayN/v2rayN "$APPDIR_ARM64/usr/bin/v2rayN" +cat > "$APPDIR_ARM64/v2rayN.desktop" < usr/lib/v2rayN/NotStoreConfigHere.txt - - ln -sf usr/lib/v2rayN/v2rayN usr/bin/v2rayN - - chmod a+x usr/lib/v2rayN/v2rayN - - find usr -type f -exec sh -c 'file "{}" | grep -qi "executable" && chmod +x "{}"' \; - - install -Dm644 usr/lib/v2rayN/v2rayN.png v2rayN.png - - install -Dm644 usr/lib/v2rayN/v2rayN.png usr/share/pixmaps/v2rayN.png - - cat > v2rayN.desktop < AppRun <<\EOF - - #!/bin/sh - - HERE="$(dirname "$(readlink -f "${0}")")" - - cd ${HERE}/usr/lib/v2rayN - - exec ${HERE}/usr/lib/v2rayN/v2rayN $@ - - EOF - - chmod a+x AppRun diff --git a/v2rayn/v2rayN/Directory.Build.props b/v2rayn/v2rayN/Directory.Build.props index 9ab2dc8eaa..6d911c660e 100644 --- a/v2rayn/v2rayN/Directory.Build.props +++ b/v2rayn/v2rayN/Directory.Build.props @@ -1,7 +1,7 @@ - 7.14.7 + 7.14.8 diff --git a/v2rayn/v2rayN/ServiceLib/Common/Utils.cs b/v2rayn/v2rayN/ServiceLib/Common/Utils.cs index 38869ebb2b..49a359c014 100644 --- a/v2rayn/v2rayN/ServiceLib/Common/Utils.cs +++ b/v2rayn/v2rayN/ServiceLib/Common/Utils.cs @@ -582,9 +582,9 @@ public class Utils if (host.StartsWith("#")) continue; var hostItem = host.Split(new[] { ' ', '\t' }, StringSplitOptions.RemoveEmptyEntries); - if (hostItem.Length != 2) + if (hostItem.Length < 2) continue; - systemHosts.Add(hostItem.Last(), hostItem.First()); + systemHosts.Add(hostItem[1], hostItem[0]); } } } diff --git a/v2rayn/v2rayN/ServiceLib/ViewModels/BackupAndRestoreViewModel.cs b/v2rayn/v2rayN/ServiceLib/ViewModels/BackupAndRestoreViewModel.cs index 80336c5d57..5a96a04d8c 100644 --- a/v2rayn/v2rayN/ServiceLib/ViewModels/BackupAndRestoreViewModel.cs +++ b/v2rayn/v2rayN/ServiceLib/ViewModels/BackupAndRestoreViewModel.cs @@ -1,7 +1,6 @@ using System.Reactive; using ReactiveUI; using ReactiveUI.Fody.Helpers; -using Splat; namespace ServiceLib.ViewModels; diff --git a/v2rayn/v2rayN/ServiceLib/ViewModels/ProfilesSelectViewModel.cs b/v2rayn/v2rayN/ServiceLib/ViewModels/ProfilesSelectViewModel.cs index ff6d787faa..8742755e99 100644 --- a/v2rayn/v2rayN/ServiceLib/ViewModels/ProfilesSelectViewModel.cs +++ b/v2rayn/v2rayN/ServiceLib/ViewModels/ProfilesSelectViewModel.cs @@ -1,27 +1,22 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Reactive; using System.Reactive.Linq; -using System.Text; -using System.Threading.Tasks; using DynamicData; using DynamicData.Binding; using ReactiveUI; using ReactiveUI.Fody.Helpers; -using Splat; namespace ServiceLib.ViewModels; + public class ProfilesSelectViewModel : MyReactiveObject { #region private prop - private List _lstProfile; private string _serverFilter = string.Empty; private Dictionary _dicHeaderSort = new(); private string _subIndexId = string.Empty; + // ConfigType filter state: default include-mode with all types selected private List _filterConfigTypes = new(); + private bool _filterExclude = false; #endregion private prop @@ -66,6 +61,7 @@ public class ProfilesSelectViewModel : MyReactiveObject _config = AppManager.Instance.Config; _updateView = updateView; _subIndexId = _config.SubIndexId ?? string.Empty; + #region WhenAnyValue && ReactiveCommand this.WhenAnyValue( @@ -130,6 +126,7 @@ public class ProfilesSelectViewModel : MyReactiveObject _updateView?.Invoke(EViewAction.CloseWindow, null); return true; } + #endregion Actions #region Servers && Groups @@ -168,7 +165,6 @@ public class ProfilesSelectViewModel : MyReactiveObject private async Task RefreshServersBiz() { var lstModel = await GetProfileItemsEx(_subIndexId, _serverFilter); - _lstProfile = JsonUtils.Deserialize>(JsonUtils.Serialize(lstModel)) ?? []; ProfileItems.Clear(); ProfileItems.AddRange(lstModel); @@ -211,9 +207,6 @@ public class ProfilesSelectViewModel : MyReactiveObject private async Task?> GetProfileItemsEx(string subid, string filter) { var lstModel = await AppManager.Instance.ProfileItems(_subIndexId, filter); - - //await ConfigHandler.SetDefaultServer(_config, lstModel); - lstModel = (from t in lstModel select new ProfileItemModel { diff --git a/v2rayn/v2rayN/ServiceLib/ViewModels/RoutingRuleSettingViewModel.cs b/v2rayn/v2rayN/ServiceLib/ViewModels/RoutingRuleSettingViewModel.cs index f176e29b3b..4b192f04a8 100644 --- a/v2rayn/v2rayN/ServiceLib/ViewModels/RoutingRuleSettingViewModel.cs +++ b/v2rayn/v2rayN/ServiceLib/ViewModels/RoutingRuleSettingViewModel.cs @@ -13,6 +13,7 @@ public class RoutingRuleSettingViewModel : MyReactiveObject [Reactive] public RoutingItem SelectedRouting { get; set; } + public IObservableCollection RulesItems { get; } = new ObservableCollectionExtended(); [Reactive] diff --git a/v2rayn/v2rayN/v2rayN.Desktop/Views/ProfilesSelectWindow.axaml.cs b/v2rayn/v2rayN/v2rayN.Desktop/Views/ProfilesSelectWindow.axaml.cs index 5df0251acf..b3319154b6 100644 --- a/v2rayn/v2rayN/v2rayN.Desktop/Views/ProfilesSelectWindow.axaml.cs +++ b/v2rayn/v2rayN/v2rayN.Desktop/Views/ProfilesSelectWindow.axaml.cs @@ -1,17 +1,12 @@ -using System.Linq; using System.Reactive.Disposables; -using System.Threading.Tasks; using Avalonia; using Avalonia.Controls; -using Avalonia.Controls.Primitives; using Avalonia.Input; using Avalonia.Interactivity; -using Avalonia.Markup.Xaml; -using Avalonia.VisualTree; using Avalonia.ReactiveUI; +using Avalonia.VisualTree; using ReactiveUI; using ServiceLib.Manager; -using v2rayN.Desktop.Common; namespace v2rayN.Desktop.Views; diff --git a/v2rayn/v2rayN/v2rayN.Desktop/Views/RoutingRuleDetailsWindow.axaml.cs b/v2rayn/v2rayN/v2rayN.Desktop/Views/RoutingRuleDetailsWindow.axaml.cs index 04b1219ce8..b19fc923b2 100644 --- a/v2rayn/v2rayN/v2rayN.Desktop/Views/RoutingRuleDetailsWindow.axaml.cs +++ b/v2rayn/v2rayN/v2rayN.Desktop/Views/RoutingRuleDetailsWindow.axaml.cs @@ -3,7 +3,6 @@ using Avalonia.Controls; using Avalonia.Interactivity; using ReactiveUI; using v2rayN.Desktop.Base; -using System.Threading.Tasks; namespace v2rayN.Desktop.Views; diff --git a/v2rayn/v2rayN/v2rayN.Desktop/Views/SubEditWindow.axaml.cs b/v2rayn/v2rayN/v2rayN.Desktop/Views/SubEditWindow.axaml.cs index 486be1dd32..d030ba028b 100644 --- a/v2rayn/v2rayN/v2rayN.Desktop/Views/SubEditWindow.axaml.cs +++ b/v2rayn/v2rayN/v2rayN.Desktop/Views/SubEditWindow.axaml.cs @@ -3,7 +3,6 @@ using Avalonia; using Avalonia.Interactivity; using ReactiveUI; using v2rayN.Desktop.Base; -using System.Threading.Tasks; namespace v2rayN.Desktop.Views; diff --git a/v2rayn/v2rayN/v2rayN/Views/ProfilesSelectWindow.xaml.cs b/v2rayn/v2rayN/v2rayN/Views/ProfilesSelectWindow.xaml.cs index e9e33ec5ec..c6c82928ba 100644 --- a/v2rayn/v2rayN/v2rayN/Views/ProfilesSelectWindow.xaml.cs +++ b/v2rayn/v2rayN/v2rayN/Views/ProfilesSelectWindow.xaml.cs @@ -3,10 +3,8 @@ using System.Windows; using System.Windows.Controls; using System.Windows.Controls.Primitives; using System.Windows.Input; -using System.Windows.Threading; using ReactiveUI; using ServiceLib.Manager; -using Splat; using v2rayN.Base; namespace v2rayN.Views; @@ -34,7 +32,6 @@ public partial class ProfilesSelectWindow ViewModel = new ProfilesSelectViewModel(UpdateViewHandler); - this.WhenActivated(disposables => { this.OneWayBind(ViewModel, vm => vm.ProfileItems, v => v.lstProfiles.ItemsSource).DisposeWith(disposables); @@ -44,6 +41,8 @@ public partial class ProfilesSelectWindow this.Bind(ViewModel, vm => vm.SelectedSub, v => v.lstGroup.SelectedItem).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.ServerFilter, v => v.txtServerFilter.Text).DisposeWith(disposables); }); + + WindowsUtils.SetDarkBorder(this, AppManager.Instance.Config.UiItem.CurrentTheme); } public void AllowMultiSelect(bool allow) @@ -190,5 +189,6 @@ public partial class ProfilesSelectWindow // Trigger selection finalize when Confirm is clicked ViewModel?.SelectFinish(); } + #endregion Event } diff --git a/v2rayn/v2rayN/v2rayN/Views/ProfilesView.xaml.cs b/v2rayn/v2rayN/v2rayN/Views/ProfilesView.xaml.cs index c03fb0bd77..54e9218164 100644 --- a/v2rayn/v2rayN/v2rayN/Views/ProfilesView.xaml.cs +++ b/v2rayn/v2rayN/v2rayN/Views/ProfilesView.xaml.cs @@ -119,7 +119,7 @@ public partial class ProfilesView if (obj is null) return false; WindowsUtils.SetClipboardData((string)obj); - break; + break; case EViewAction.ProfilesFocus: lstProfiles.Focus(); diff --git a/v2rayn/v2rayN/v2rayN/Views/RoutingRuleDetailsWindow.xaml.cs b/v2rayn/v2rayN/v2rayN/Views/RoutingRuleDetailsWindow.xaml.cs index 806dde654c..0c1d2a91b4 100644 --- a/v2rayn/v2rayN/v2rayN/Views/RoutingRuleDetailsWindow.xaml.cs +++ b/v2rayn/v2rayN/v2rayN/Views/RoutingRuleDetailsWindow.xaml.cs @@ -1,6 +1,5 @@ using System.Reactive.Disposables; using System.Windows; -using System.Windows.Threading; using ReactiveUI; using ServiceLib.Manager; diff --git a/xray-core/proxy/vmess/aead/authid.go b/xray-core/proxy/vmess/aead/authid.go index 2ec48f1108..7309010aa5 100644 --- a/xray-core/proxy/vmess/aead/authid.go +++ b/xray-core/proxy/vmess/aead/authid.go @@ -17,8 +17,10 @@ import ( ) var ( - ErrNotFound = errors.New("user do not exist") - ErrReplay = errors.New("replayed request") + ErrNotFound = errors.New("user do not exist") + ErrNeagtiveTime = errors.New("timestamp is negative") + ErrInvalidTime = errors.New("invalid timestamp, perhaps unsynchronized time") + ErrReplay = errors.New("replayed request") ) func CreateAuthID(cmdKey []byte, time int64) [16]byte { @@ -102,11 +104,11 @@ func (a *AuthIDDecoderHolder) Match(authID [16]byte) (interface{}, error) { } if t < 0 { - continue + return nil, ErrNeagtiveTime } if math.Abs(math.Abs(float64(t))-float64(time.Now().Unix())) > 120 { - continue + return nil, ErrInvalidTime } if !a.filter.Check(authID[:]) { diff --git a/xray-core/transport/internet/kcp/cryptreal.go b/xray-core/transport/internet/kcp/cryptreal.go index 391d714e43..cd33a6f3c6 100644 --- a/xray-core/transport/internet/kcp/cryptreal.go +++ b/xray-core/transport/internet/kcp/cryptreal.go @@ -9,5 +9,5 @@ import ( func NewAEADAESGCMBasedOnSeed(seed string) cipher.AEAD { hashedSeed := sha256.Sum256([]byte(seed)) - return crypto.NewAesGcm(hashedSeed[:]) + return crypto.NewAesGcm(hashedSeed[:16]) } diff --git a/yt-dlp/test/test_utils.py b/yt-dlp/test/test_utils.py index 9e70ad480c..83916b46d9 100644 --- a/yt-dlp/test/test_utils.py +++ b/yt-dlp/test/test_utils.py @@ -12,6 +12,7 @@ import datetime as dt import io import itertools import json +import ntpath import pickle import subprocess import unittest @@ -253,12 +254,6 @@ class TestUtil(unittest.TestCase): self.assertEqual(sanitize_path('abc.../def...'), 'abc..#\\def..#') self.assertEqual(sanitize_path('C:\\abc:%(title)s.%(ext)s'), 'C:\\abc#%(title)s.%(ext)s') - # Check with nt._path_normpath if available - try: - from nt import _path_normpath as nt_path_normpath - except ImportError: - nt_path_normpath = None - for test, expected in [ ('C:\\', 'C:\\'), ('../abc', '..\\abc'), @@ -276,8 +271,7 @@ class TestUtil(unittest.TestCase): result = sanitize_path(test) assert result == expected, f'{test} was incorrectly resolved' assert result == sanitize_path(result), f'{test} changed after sanitizing again' - if nt_path_normpath: - assert result == nt_path_normpath(test), f'{test} does not match nt._path_normpath' + assert result == ntpath.normpath(test), f'{test} does not match ntpath.normpath' def test_sanitize_url(self): self.assertEqual(sanitize_url('//foo.bar'), 'http://foo.bar') diff --git a/yt-dlp/yt_dlp/extractor/tenplay.py b/yt-dlp/yt_dlp/extractor/tenplay.py index dd4ea56580..9dc1de6b78 100644 --- a/yt-dlp/yt_dlp/extractor/tenplay.py +++ b/yt-dlp/yt_dlp/extractor/tenplay.py @@ -2,7 +2,14 @@ import itertools from .common import InfoExtractor from ..networking import HEADRequest -from ..utils import int_or_none, traverse_obj, url_or_none, urljoin +from ..utils import ( + ExtractorError, + int_or_none, + update_url_query, + url_or_none, + urljoin, +) +from ..utils.traversal import traverse_obj class TenPlayIE(InfoExtractor): @@ -102,14 +109,19 @@ class TenPlayIE(InfoExtractor): video_data = self._download_json( f'https://vod.ten.com.au/api/videos/bcquery?command=find_videos_by_id&video_id={data["altId"]}', content_id, 'Downloading video JSON') + # Dash URL 403s, changing the m3u8 format works m3u8_url = self._request_webpage( - HEADRequest(video_data['items'][0]['HLSURL']), + HEADRequest(update_url_query(video_data['items'][0]['dashManifestUrl'], { + 'manifest': 'm3u', + })), content_id, 'Checking stream URL').url if '10play-not-in-oz' in m3u8_url: self.raise_geo_restricted(countries=['AU']) + if '10play_unsupported' in m3u8_url: + raise ExtractorError('Unable to extract stream') # Attempt to get a higher quality stream formats = self._extract_m3u8_formats( - m3u8_url.replace(',150,75,55,0000', ',300,150,75,55,0000'), + m3u8_url.replace(',150,75,55,0000', ',500,300,150,75,55,0000'), content_id, 'mp4', fatal=False) if not formats: formats = self._extract_m3u8_formats(m3u8_url, content_id, 'mp4')