Update On Wed Aug 27 20:38:34 CEST 2025

This commit is contained in:
github-action[bot]
2025-08-27 20:38:34 +02:00
parent 7518b3dffc
commit 17c84694e5
172 changed files with 3738 additions and 2222 deletions
+1
View File
@@ -1102,3 +1102,4 @@ Update On Sat Aug 23 20:35:18 CEST 2025
Update On Sun Aug 24 20:36:09 CEST 2025
Update On Mon Aug 25 20:39:10 CEST 2025
Update On Tue Aug 26 20:39:16 CEST 2025
Update On Wed Aug 27 20:38:26 CEST 2025
+2 -2
View File
@@ -46,8 +46,8 @@ subprojects {
minSdk = 21
targetSdk = 35
versionName = "2.11.15"
versionCode = 211015
versionName = "2.11.16"
versionCode = 211016
resValue("string", "release_name", "v$versionName")
resValue("integer", "release_code", "$versionCode")
@@ -80,6 +80,13 @@ jobs:
- { goos: android, goarch: arm, ndk: armv7a-linux-androideabi34, output: armv7 }
- { goos: android, goarch: arm64, ndk: aarch64-linux-android34, output: arm64-v8 }
# Go 1.24 with special patch can work on Windows 7
# https://github.com/MetaCubeX/go/commits/release-branch.go1.24/
- { goos: windows, goarch: '386', output: '386-go124', goversion: '1.24' }
- { goos: windows, goarch: amd64, goamd64: v1, output: amd64-v1-go124, goversion: '1.24' }
- { goos: windows, goarch: amd64, goamd64: v2, output: amd64-v2-go124, goversion: '1.24' }
- { goos: windows, goarch: amd64, goamd64: v3, output: amd64-v3-go124, goversion: '1.24' }
# Go 1.23 with special patch can work on Windows 7
# https://github.com/MetaCubeX/go/commits/release-branch.go1.23/
- { goos: windows, goarch: '386', output: '386-go123', goversion: '1.23' }
@@ -108,6 +115,12 @@ jobs:
- { goos: windows, goarch: amd64, goamd64: v2, output: amd64-v2-go120, goversion: '1.20' }
- { goos: windows, goarch: amd64, goamd64: v3, output: amd64-v3-go120, goversion: '1.20' }
# Go 1.24 is the last release that will run on macOS 11 Big Sur. Go 1.25 will require macOS 12 Monterey or later.
- { goos: darwin, goarch: arm64, output: arm64-go124, goversion: '1.24' }
- { goos: darwin, goarch: amd64, goamd64: v1, output: amd64-v1-go124, goversion: '1.24' }
- { goos: darwin, goarch: amd64, goamd64: v2, output: amd64-v2-go124, goversion: '1.24' }
- { goos: darwin, goarch: amd64, goamd64: v3, output: amd64-v3-go124, goversion: '1.24' }
# Go 1.22 is the last release that will run on macOS 10.15 Catalina. Go 1.23 will require macOS 11 Big Sur or later.
- { goos: darwin, goarch: arm64, output: arm64-go122, goversion: '1.22' }
- { goos: darwin, goarch: amd64, goamd64: v1, output: amd64-v1-go122, goversion: '1.22' }
@@ -139,7 +152,7 @@ jobs:
if: ${{ matrix.jobs.goversion == '' && matrix.jobs.abi != '1' }}
uses: actions/setup-go@v5
with:
go-version: '1.24'
go-version: '1.25'
- name: Set up Go
if: ${{ matrix.jobs.goversion != '' && matrix.jobs.abi != '1' }}
@@ -154,6 +167,25 @@ jobs:
sudo tar zxf go1.24.0.linux-amd64-abi1.tar.gz -C /usr/local
echo "/usr/local/go/bin" >> $GITHUB_PATH
# modify from https://github.com/restic/restic/issues/4636#issuecomment-1896455557
# this patch file only works on golang1.25.x
# that means after golang1.26 release it must be changed
# see: https://github.com/MetaCubeX/go/commits/release-branch.go1.25/
# revert:
# 693def151adff1af707d82d28f55dba81ceb08e1: "crypto/rand,runtime: switch RtlGenRandom for ProcessPrng"
# 7c1157f9544922e96945196b47b95664b1e39108: "net: remove sysSocket fallback for Windows 7"
# 48042aa09c2f878c4faa576948b07fe625c4707a: "syscall: remove Windows 7 console handle workaround"
# a17d959debdb04cd550016a3501dd09d50cd62e7: "runtime: always use LoadLibraryEx to load system libraries"
- name: Revert Golang1.25 commit for Windows7/8
if: ${{ matrix.jobs.goos == 'windows' && matrix.jobs.goversion == '' }}
run: |
alias curl='curl -H "Authorization: Bearer ${{ secrets.GITHUB_TOKEN }}"'
cd $(go env GOROOT)
curl https://github.com/MetaCubeX/go/commit/8cb5472d94c34b88733a81091bd328e70ee565a4.diff | patch --verbose -p 1
curl https://github.com/MetaCubeX/go/commit/6788c4c6f9fafb56729bad6b660f7ee2272d699f.diff | patch --verbose -p 1
curl https://github.com/MetaCubeX/go/commit/a5b2168bb836ed9d6601c626f95e56c07923f906.diff | patch --verbose -p 1
curl https://github.com/MetaCubeX/go/commit/f56f1e23507e646c85243a71bde7b9629b2f970c.diff | patch --verbose -p 1
# modify from https://github.com/restic/restic/issues/4636#issuecomment-1896455557
# this patch file only works on golang1.24.x
# that means after golang1.25 release it must be changed
@@ -164,8 +196,9 @@ jobs:
# 48042aa09c2f878c4faa576948b07fe625c4707a: "syscall: remove Windows 7 console handle workaround"
# a17d959debdb04cd550016a3501dd09d50cd62e7: "runtime: always use LoadLibraryEx to load system libraries"
- name: Revert Golang1.24 commit for Windows7/8
if: ${{ matrix.jobs.goos == 'windows' && matrix.jobs.goversion == '' }}
if: ${{ matrix.jobs.goos == 'windows' && matrix.jobs.goversion == '1.24' }}
run: |
alias curl='curl -H "Authorization: Bearer ${{ secrets.GITHUB_TOKEN }}"'
cd $(go env GOROOT)
curl https://github.com/MetaCubeX/go/commit/2a406dc9f1ea7323d6ca9fccb2fe9ddebb6b1cc8.diff | patch --verbose -p 1
curl https://github.com/MetaCubeX/go/commit/7b1fd7d39c6be0185fbe1d929578ab372ac5c632.diff | patch --verbose -p 1
@@ -184,6 +217,7 @@ jobs:
- name: Revert Golang1.23 commit for Windows7/8
if: ${{ matrix.jobs.goos == 'windows' && matrix.jobs.goversion == '1.23' }}
run: |
alias curl='curl -H "Authorization: Bearer ${{ secrets.GITHUB_TOKEN }}"'
cd $(go env GOROOT)
curl https://github.com/MetaCubeX/go/commit/9ac42137ef6730e8b7daca016ece831297a1d75b.diff | patch --verbose -p 1
curl https://github.com/MetaCubeX/go/commit/21290de8a4c91408de7c2b5b68757b1e90af49dd.diff | patch --verbose -p 1
@@ -202,6 +236,7 @@ jobs:
- name: Revert Golang1.22 commit for Windows7/8
if: ${{ matrix.jobs.goos == 'windows' && matrix.jobs.goversion == '1.22' }}
run: |
alias curl='curl -H "Authorization: Bearer ${{ secrets.GITHUB_TOKEN }}"'
cd $(go env GOROOT)
curl https://github.com/MetaCubeX/go/commit/9779155f18b6556a034f7bb79fb7fb2aad1e26a9.diff | patch --verbose -p 1
curl https://github.com/MetaCubeX/go/commit/ef0606261340e608017860b423ffae5c1ce78239.diff | patch --verbose -p 1
@@ -212,6 +247,7 @@ jobs:
- name: Revert Golang1.21 commit for Windows7/8
if: ${{ matrix.jobs.goos == 'windows' && matrix.jobs.goversion == '1.21' }}
run: |
alias curl='curl -H "Authorization: Bearer ${{ secrets.GITHUB_TOKEN }}"'
cd $(go env GOROOT)
curl https://github.com/golang/go/commit/9e43850a3298a9b8b1162ba0033d4c53f8637571.diff | patch --verbose -R -p 1
@@ -24,6 +24,7 @@ jobs:
- 'ubuntu-24.04-arm' # arm64 linux
- 'macos-13' # amd64 macos
go-version:
- '1.25'
- '1.24'
- '1.23'
- '1.22'
@@ -47,6 +48,25 @@ jobs:
with:
go-version: ${{ matrix.go-version }}
# modify from https://github.com/restic/restic/issues/4636#issuecomment-1896455557
# this patch file only works on golang1.25.x
# that means after golang1.26 release it must be changed
# see: https://github.com/MetaCubeX/go/commits/release-branch.go1.25/
# revert:
# 693def151adff1af707d82d28f55dba81ceb08e1: "crypto/rand,runtime: switch RtlGenRandom for ProcessPrng"
# 7c1157f9544922e96945196b47b95664b1e39108: "net: remove sysSocket fallback for Windows 7"
# 48042aa09c2f878c4faa576948b07fe625c4707a: "syscall: remove Windows 7 console handle workaround"
# a17d959debdb04cd550016a3501dd09d50cd62e7: "runtime: always use LoadLibraryEx to load system libraries"
- name: Revert Golang1.25 commit for Windows7/8
if: ${{ matrix.jobs.goos == 'windows' && matrix.jobs.goversion == '1.25' }}
run: |
alias curl='curl -H "Authorization: Bearer ${{ secrets.GITHUB_TOKEN }}"'
cd $(go env GOROOT)
curl https://github.com/MetaCubeX/go/commit/8cb5472d94c34b88733a81091bd328e70ee565a4.diff | patch --verbose -p 1
curl https://github.com/MetaCubeX/go/commit/6788c4c6f9fafb56729bad6b660f7ee2272d699f.diff | patch --verbose -p 1
curl https://github.com/MetaCubeX/go/commit/a5b2168bb836ed9d6601c626f95e56c07923f906.diff | patch --verbose -p 1
curl https://github.com/MetaCubeX/go/commit/f56f1e23507e646c85243a71bde7b9629b2f970c.diff | patch --verbose -p 1
# modify from https://github.com/restic/restic/issues/4636#issuecomment-1896455557
# this patch file only works on golang1.24.x
# that means after golang1.25 release it must be changed
@@ -59,6 +79,7 @@ jobs:
- name: Revert Golang1.24 commit for Windows7/8
if: ${{ runner.os == 'Windows' && matrix.go-version == '1.24' }}
run: |
alias curl='curl -H "Authorization: Bearer ${{ secrets.GITHUB_TOKEN }}"'
cd $(go env GOROOT)
curl https://github.com/MetaCubeX/go/commit/2a406dc9f1ea7323d6ca9fccb2fe9ddebb6b1cc8.diff | patch --verbose -p 1
curl https://github.com/MetaCubeX/go/commit/7b1fd7d39c6be0185fbe1d929578ab372ac5c632.diff | patch --verbose -p 1
@@ -77,6 +98,7 @@ jobs:
- name: Revert Golang1.23 commit for Windows7/8
if: ${{ runner.os == 'Windows' && matrix.go-version == '1.23' }}
run: |
alias curl='curl -H "Authorization: Bearer ${{ secrets.GITHUB_TOKEN }}"'
cd $(go env GOROOT)
curl https://github.com/MetaCubeX/go/commit/9ac42137ef6730e8b7daca016ece831297a1d75b.diff | patch --verbose -p 1
curl https://github.com/MetaCubeX/go/commit/21290de8a4c91408de7c2b5b68757b1e90af49dd.diff | patch --verbose -p 1
@@ -95,6 +117,7 @@ jobs:
- name: Revert Golang1.22 commit for Windows7/8
if: ${{ runner.os == 'Windows' && matrix.go-version == '1.22' }}
run: |
alias curl='curl -H "Authorization: Bearer ${{ secrets.GITHUB_TOKEN }}"'
cd $(go env GOROOT)
curl https://github.com/MetaCubeX/go/commit/9779155f18b6556a034f7bb79fb7fb2aad1e26a9.diff | patch --verbose -p 1
curl https://github.com/MetaCubeX/go/commit/ef0606261340e608017860b423ffae5c1ce78239.diff | patch --verbose -p 1
@@ -105,6 +128,7 @@ jobs:
- name: Revert Golang1.21 commit for Windows7/8
if: ${{ runner.os == 'Windows' && matrix.go-version == '1.21' }}
run: |
alias curl='curl -H "Authorization: Bearer ${{ secrets.GITHUB_TOKEN }}"'
cd $(go env GOROOT)
curl https://github.com/golang/go/commit/9e43850a3298a9b8b1162ba0033d4c53f8637571.diff | patch --verbose -R -p 1
@@ -172,7 +172,7 @@ func NewHysteria(option HysteriaOption) (*Hysteria, error) {
return nil, err
}
if len(option.ALPN) > 0 {
if option.ALPN != nil { // structure's Decode will ensure value not nil when input has value even it was set an empty array
tlsConfig.NextProtos = option.ALPN
} else {
tlsConfig.NextProtos = []string{DefaultALPN}
@@ -153,7 +153,7 @@ func NewHysteria2(option Hysteria2Option) (*Hysteria2, error) {
return nil, err
}
if len(option.ALPN) > 0 {
if option.ALPN != nil { // structure's Decode will ensure value not nil when input has value even it was set an empty array
tlsConfig.NextProtos = option.ALPN
}
@@ -28,15 +28,16 @@ type Mieru struct {
type MieruOption struct {
BasicOption
Name string `proxy:"name"`
Server string `proxy:"server"`
Port int `proxy:"port,omitempty"`
PortRange string `proxy:"port-range,omitempty"`
Transport string `proxy:"transport"`
UDP bool `proxy:"udp,omitempty"`
UserName string `proxy:"username"`
Password string `proxy:"password"`
Multiplexing string `proxy:"multiplexing,omitempty"`
Name string `proxy:"name"`
Server string `proxy:"server"`
Port int `proxy:"port,omitempty"`
PortRange string `proxy:"port-range,omitempty"`
Transport string `proxy:"transport"`
UDP bool `proxy:"udp,omitempty"`
UserName string `proxy:"username"`
Password string `proxy:"password"`
Multiplexing string `proxy:"multiplexing,omitempty"`
HandshakeMode string `proxy:"handshake-mode,omitempty"`
}
// DialContext implements C.ProxyAdapter
@@ -245,6 +246,9 @@ func buildMieruClientConfig(option MieruOption) (*mieruclient.ClientConfig, erro
Level: mierupb.MultiplexingLevel(multiplexing).Enum(),
}
}
if handshakeMode, ok := mierupb.HandshakeMode_value[option.HandshakeMode]; ok {
config.Profile.HandshakeMode = (*mierupb.HandshakeMode)(&handshakeMode)
}
return config, nil
}
@@ -294,6 +298,11 @@ func validateMieruOption(option MieruOption) error {
return fmt.Errorf("invalid multiplexing level: %s", option.Multiplexing)
}
}
if option.HandshakeMode != "" {
if _, ok := mierupb.HandshakeMode_value[option.HandshakeMode]; !ok {
return fmt.Errorf("invalid handshake mode: %s", option.HandshakeMode)
}
}
return nil
}
@@ -95,7 +95,7 @@ func (t *Trojan) StreamConnContext(ctx context.Context, c net.Conn, metadata *C.
}
alpn := trojan.DefaultWebsocketALPN
if len(t.option.ALPN) != 0 {
if t.option.ALPN != nil { // structure's Decode will ensure value not nil when input has value even it was set an empty array
alpn = t.option.ALPN
}
@@ -119,7 +119,7 @@ func (t *Trojan) StreamConnContext(ctx context.Context, c net.Conn, metadata *C.
// default tcp network
// handle TLS
alpn := trojan.DefaultALPN
if len(t.option.ALPN) != 0 {
if t.option.ALPN != nil { // structure's Decode will ensure value not nil when input has value even it was set an empty array
alpn = t.option.ALPN
}
c, err = vmess.StreamTLSConn(ctx, c, &vmess.TLSConfig{
@@ -3,14 +3,10 @@ package outbound
import (
"context"
"crypto/tls"
"encoding/binary"
"errors"
"fmt"
"io"
"net"
"net/http"
"strconv"
"sync"
"github.com/metacubex/mihomo/common/convert"
N "github.com/metacubex/mihomo/common/net"
@@ -23,6 +19,7 @@ import (
C "github.com/metacubex/mihomo/constant"
"github.com/metacubex/mihomo/transport/gun"
"github.com/metacubex/mihomo/transport/vless"
"github.com/metacubex/mihomo/transport/vless/encryption"
"github.com/metacubex/mihomo/transport/vmess"
vmessSing "github.com/metacubex/sing-vmess"
@@ -30,16 +27,13 @@ import (
M "github.com/metacubex/sing/common/metadata"
)
const (
// max packet length
maxLength = 1024 << 3
)
type Vless struct {
*Base
client *vless.Client
option *VlessOption
encryption *encryption.ClientInstance
// for gun mux
gunTLSConfig *tls.Config
gunConfig *gun.Config
@@ -62,6 +56,7 @@ type VlessOption struct {
PacketAddr bool `proxy:"packet-addr,omitempty"`
XUDP bool `proxy:"xudp,omitempty"`
PacketEncoding string `proxy:"packet-encoding,omitempty"`
Encryption string `proxy:"encryption,omitempty"`
Network string `proxy:"network,omitempty"`
ECHOpts ECHOptions `proxy:"ech-opts,omitempty"`
RealityOpts RealityOptions `proxy:"reality-opts,omitempty"`
@@ -173,6 +168,12 @@ func (v *Vless) streamConnContext(ctx context.Context, c net.Conn, metadata *C.M
done := N.SetupContextForConn(ctx, c)
defer done(&err)
}
if v.encryption != nil {
c, err = v.encryption.Handshake(c)
if err != nil {
return
}
}
if metadata.NetWork == C.UDP {
if v.option.PacketAddr {
metadata = &C.Metadata{
@@ -188,9 +189,6 @@ func (v *Vless) streamConnContext(ctx context.Context, c net.Conn, metadata *C.M
}
}
conn, err = v.client.StreamConn(c, parseVlessAddr(metadata, v.option.XUDP))
if v.option.PacketAddr {
conn = packetaddr.NewBindConn(conn)
}
} else {
conn, err = v.client.StreamConn(c, parseVlessAddr(metadata, false))
}
@@ -352,12 +350,11 @@ func (v *Vless) ListenPacketOnStreamConn(ctx context.Context, c net.Conn, metada
), v), nil
} else if v.option.PacketAddr {
return newPacketConn(N.NewThreadSafePacketConn(
packetaddr.NewConn(&vlessPacketConn{
Conn: c, rAddr: metadata.UDPAddr(),
}, M.SocksaddrFromNet(metadata.UDPAddr())),
packetaddr.NewConn(v.client.PacketConn(c, metadata.UDPAddr()),
M.SocksaddrFromNet(metadata.UDPAddr())),
), v), nil
}
return newPacketConn(N.NewThreadSafePacketConn(&vlessPacketConn{Conn: c, rAddr: metadata.UDPAddr()}), v), nil
return newPacketConn(N.NewThreadSafePacketConn(v.client.PacketConn(c, metadata.UDPAddr())), v), nil
}
// SupportUOT implements C.ProxyAdapter
@@ -408,98 +405,6 @@ func parseVlessAddr(metadata *C.Metadata, xudp bool) *vless.DstAddr {
}
}
type vlessPacketConn struct {
net.Conn
rAddr net.Addr
remain int
mux sync.Mutex
cache [2]byte
}
func (c *vlessPacketConn) writePacket(payload []byte) (int, error) {
binary.BigEndian.PutUint16(c.cache[:], uint16(len(payload)))
if _, err := c.Conn.Write(c.cache[:]); err != nil {
return 0, err
}
return c.Conn.Write(payload)
}
func (c *vlessPacketConn) WriteTo(b []byte, addr net.Addr) (int, error) {
total := len(b)
if total == 0 {
return 0, nil
}
if total <= maxLength {
return c.writePacket(b)
}
offset := 0
for offset < total {
cursor := offset + maxLength
if cursor > total {
cursor = total
}
n, err := c.writePacket(b[offset:cursor])
if err != nil {
return offset + n, err
}
offset = cursor
if offset == total {
break
}
}
return total, nil
}
func (c *vlessPacketConn) ReadFrom(b []byte) (int, net.Addr, error) {
c.mux.Lock()
defer c.mux.Unlock()
if c.remain > 0 {
length := len(b)
if c.remain < length {
length = c.remain
}
n, err := c.Conn.Read(b[:length])
if err != nil {
return 0, c.rAddr, err
}
c.remain -= n
return n, c.rAddr, nil
}
if _, err := c.Conn.Read(b[:2]); err != nil {
return 0, c.rAddr, err
}
total := int(binary.BigEndian.Uint16(b[:2]))
if total == 0 {
return 0, c.rAddr, nil
}
length := len(b)
if length > total {
length = total
}
if _, err := io.ReadFull(c.Conn, b[:length]); err != nil {
return 0, c.rAddr, errors.New("read packet error")
}
c.remain = total - length
return length, c.rAddr, nil
}
func NewVless(option VlessOption) (*Vless, error) {
var addons *vless.Addons
if option.Network != "ws" && len(option.Flow) >= 16 {
@@ -547,6 +452,11 @@ func NewVless(option VlessOption) (*Vless, error) {
option: &option,
}
v.encryption, err = encryption.NewClient(option.Encryption)
if err != nil {
return nil, err
}
v.realityConfig, err = v.option.RealityOpts.Parse()
if err != nil {
return nil, err
@@ -87,15 +87,26 @@ type WireGuardPeerOption struct {
}
type AmneziaWGOption struct {
JC int `proxy:"jc"`
JMin int `proxy:"jmin"`
JMax int `proxy:"jmax"`
S1 int `proxy:"s1"`
S2 int `proxy:"s2"`
H1 uint32 `proxy:"h1"`
H2 uint32 `proxy:"h2"`
H3 uint32 `proxy:"h3"`
H4 uint32 `proxy:"h4"`
JC int `proxy:"jc,omitempty"`
JMin int `proxy:"jmin,omitempty"`
JMax int `proxy:"jmax,omitempty"`
S1 int `proxy:"s1,omitempty"`
S2 int `proxy:"s2,omitempty"`
H1 uint32 `proxy:"h1,omitempty"`
H2 uint32 `proxy:"h2,omitempty"`
H3 uint32 `proxy:"h3,omitempty"`
H4 uint32 `proxy:"h4,omitempty"`
// AmneziaWG v1.5
I1 string `proxy:"i1,omitempty"`
I2 string `proxy:"i2,omitempty"`
I3 string `proxy:"i3,omitempty"`
I4 string `proxy:"i4,omitempty"`
I5 string `proxy:"i5,omitempty"`
J1 string `proxy:"j1,omitempty"`
J2 string `proxy:"j2,omitempty"`
J3 string `proxy:"j3,omitempty"`
Itime int64 `proxy:"itime,omitempty"`
}
type wgSingErrorHandler struct {
@@ -386,15 +397,60 @@ func (w *WireGuard) genIpcConf(ctx context.Context, updateOnly bool) (string, er
if !updateOnly {
ipcConf += "private_key=" + w.option.PrivateKey + "\n"
if w.option.AmneziaWGOption != nil {
ipcConf += "jc=" + strconv.Itoa(w.option.AmneziaWGOption.JC) + "\n"
ipcConf += "jmin=" + strconv.Itoa(w.option.AmneziaWGOption.JMin) + "\n"
ipcConf += "jmax=" + strconv.Itoa(w.option.AmneziaWGOption.JMax) + "\n"
ipcConf += "s1=" + strconv.Itoa(w.option.AmneziaWGOption.S1) + "\n"
ipcConf += "s2=" + strconv.Itoa(w.option.AmneziaWGOption.S2) + "\n"
ipcConf += "h1=" + strconv.FormatUint(uint64(w.option.AmneziaWGOption.H1), 10) + "\n"
ipcConf += "h2=" + strconv.FormatUint(uint64(w.option.AmneziaWGOption.H2), 10) + "\n"
ipcConf += "h3=" + strconv.FormatUint(uint64(w.option.AmneziaWGOption.H3), 10) + "\n"
ipcConf += "h4=" + strconv.FormatUint(uint64(w.option.AmneziaWGOption.H4), 10) + "\n"
if w.option.AmneziaWGOption.JC != 0 {
ipcConf += "jc=" + strconv.Itoa(w.option.AmneziaWGOption.JC) + "\n"
}
if w.option.AmneziaWGOption.JMin != 0 {
ipcConf += "jmin=" + strconv.Itoa(w.option.AmneziaWGOption.JMin) + "\n"
}
if w.option.AmneziaWGOption.JMax != 0 {
ipcConf += "jmax=" + strconv.Itoa(w.option.AmneziaWGOption.JMax) + "\n"
}
if w.option.AmneziaWGOption.S1 != 0 {
ipcConf += "s1=" + strconv.Itoa(w.option.AmneziaWGOption.S1) + "\n"
}
if w.option.AmneziaWGOption.S2 != 0 {
ipcConf += "s2=" + strconv.Itoa(w.option.AmneziaWGOption.S2) + "\n"
}
if w.option.AmneziaWGOption.H1 != 0 {
ipcConf += "h1=" + strconv.FormatUint(uint64(w.option.AmneziaWGOption.H1), 10) + "\n"
}
if w.option.AmneziaWGOption.H2 != 0 {
ipcConf += "h2=" + strconv.FormatUint(uint64(w.option.AmneziaWGOption.H2), 10) + "\n"
}
if w.option.AmneziaWGOption.H3 != 0 {
ipcConf += "h3=" + strconv.FormatUint(uint64(w.option.AmneziaWGOption.H3), 10) + "\n"
}
if w.option.AmneziaWGOption.H4 != 0 {
ipcConf += "h4=" + strconv.FormatUint(uint64(w.option.AmneziaWGOption.H4), 10) + "\n"
}
if w.option.AmneziaWGOption.I1 != "" {
ipcConf += "i1=" + w.option.AmneziaWGOption.I1 + "\n"
}
if w.option.AmneziaWGOption.I2 != "" {
ipcConf += "i2=" + w.option.AmneziaWGOption.I2 + "\n"
}
if w.option.AmneziaWGOption.I3 != "" {
ipcConf += "i3=" + w.option.AmneziaWGOption.I3 + "\n"
}
if w.option.AmneziaWGOption.I4 != "" {
ipcConf += "i4=" + w.option.AmneziaWGOption.I4 + "\n"
}
if w.option.AmneziaWGOption.I5 != "" {
ipcConf += "i5=" + w.option.AmneziaWGOption.I5 + "\n"
}
if w.option.AmneziaWGOption.J1 != "" {
ipcConf += "j1=" + w.option.AmneziaWGOption.J1 + "\n"
}
if w.option.AmneziaWGOption.J2 != "" {
ipcConf += "j2=" + w.option.AmneziaWGOption.J2 + "\n"
}
if w.option.AmneziaWGOption.J3 != "" {
ipcConf += "j3=" + w.option.AmneziaWGOption.J3 + "\n"
}
if w.option.AmneziaWGOption.Itime != 0 {
ipcConf += "itime=" + strconv.FormatInt(int64(w.option.AmneziaWGOption.Itime), 10) + "\n"
}
}
}
if len(w.option.Peers) > 0 {
@@ -5,58 +5,50 @@ import (
"sync/atomic"
)
func DefaultValue[T any]() T {
var defaultValue T
return defaultValue
}
type TypedValue[T any] struct {
_ noCopy
value atomic.Value
value atomic.Pointer[T]
}
// tValue is a struct with determined type to resolve atomic.Value usages with interface types
// https://github.com/golang/go/issues/22550
//
// The intention to have an atomic value store for errors. However, running this code panics:
// panic: sync/atomic: store of inconsistently typed value into Value
// This is because atomic.Value requires that the underlying concrete type be the same (which is a reasonable expectation for its implementation).
// When going through the atomic.Value.Store method call, the fact that both these are of the error interface is lost.
type tValue[T any] struct {
value T
func (t *TypedValue[T]) Load() (v T) {
v, _ = t.LoadOk()
return
}
func (t *TypedValue[T]) Load() T {
value, _ := t.LoadOk()
return value
}
func (t *TypedValue[T]) LoadOk() (_ T, ok bool) {
func (t *TypedValue[T]) LoadOk() (v T, ok bool) {
value := t.value.Load()
if value == nil {
return DefaultValue[T](), false
return
}
return value.(tValue[T]).value, true
return *value, true
}
func (t *TypedValue[T]) Store(value T) {
t.value.Store(tValue[T]{value})
t.value.Store(&value)
}
func (t *TypedValue[T]) Swap(new T) T {
old := t.value.Swap(tValue[T]{new})
func (t *TypedValue[T]) Swap(new T) (v T) {
old := t.value.Swap(&new)
if old == nil {
return DefaultValue[T]()
return
}
return old.(tValue[T]).value
return *old
}
func (t *TypedValue[T]) CompareAndSwap(old, new T) bool {
return t.value.CompareAndSwap(tValue[T]{old}, tValue[T]{new}) ||
// In the edge-case where [atomic.Value.Store] is uninitialized
// and trying to compare with the zero value of T,
// then compare-and-swap with the nil any value.
(any(old) == any(DefaultValue[T]()) && t.value.CompareAndSwap(any(nil), tValue[T]{new}))
for {
currentP := t.value.Load()
var currentValue T
if currentP != nil {
currentValue = *currentP
}
// Compare old and current via runtime equality check.
if any(currentValue) != any(old) {
return false
}
if t.value.CompareAndSwap(currentP, &new) {
return true
}
}
}
func (t *TypedValue[T]) MarshalJSON() ([]byte, error) {
@@ -89,9 +81,3 @@ func NewTypedValue[T any](t T) (v TypedValue[T]) {
v.Store(t)
return
}
type noCopy struct{}
// Lock is a no-op used by -copylocks checker from `go vet`.
func (*noCopy) Lock() {}
func (*noCopy) Unlock() {}
@@ -7,20 +7,6 @@ import (
)
func TestTypedValue(t *testing.T) {
{
// Always wrapping should not allocate for simple values
// because tValue[T] has the same memory layout as T.
var v TypedValue[bool]
bools := []bool{true, false}
if n := int(testing.AllocsPerRun(1000, func() {
for _, b := range bools {
v.Store(b)
}
})); n != 0 {
t.Errorf("AllocsPerRun = %d, want 0", n)
}
}
{
var v TypedValue[int]
got, gotOk := v.LoadOk()
@@ -58,20 +44,126 @@ func TestTypedValue(t *testing.T) {
}
}
{
e1, e2, e3 := io.EOF, &os.PathError{}, &os.PathError{}
var v TypedValue[error]
if v.CompareAndSwap(e1, e2) != false {
t.Fatalf("CompareAndSwap = true, want false")
}
if value := v.Load(); value != nil {
t.Fatalf("Load = (%v), want (%v)", value, nil)
}
if v.CompareAndSwap(nil, e1) != true {
t.Fatalf("CompareAndSwap = false, want true")
}
if value := v.Load(); value != e1 {
t.Fatalf("Load = (%v), want (%v)", value, e1)
}
if v.CompareAndSwap(e2, e3) != false {
t.Fatalf("CompareAndSwap = true, want false")
}
if value := v.Load(); value != e1 {
t.Fatalf("Load = (%v), want (%v)", value, e1)
}
if v.CompareAndSwap(e1, e2) != true {
t.Fatalf("CompareAndSwap = false, want true")
}
if value := v.Load(); value != e2 {
t.Fatalf("Load = (%v), want (%v)", value, e2)
}
if v.CompareAndSwap(e3, e2) != false {
t.Fatalf("CompareAndSwap = true, want false")
}
if value := v.Load(); value != e2 {
t.Fatalf("Load = (%v), want (%v)", value, e2)
}
if v.CompareAndSwap(nil, e3) != false {
t.Fatalf("CompareAndSwap = true, want false")
}
if value := v.Load(); value != e2 {
t.Fatalf("Load = (%v), want (%v)", value, e2)
}
}
{
c1, c2, c3 := make(chan struct{}), make(chan struct{}), make(chan struct{})
var v TypedValue[chan struct{}]
if v.CompareAndSwap(c1, c2) != false {
t.Fatalf("CompareAndSwap = true, want false")
}
if value := v.Load(); value != nil {
t.Fatalf("Load = (%v), want (%v)", value, nil)
}
if v.CompareAndSwap(nil, c1) != true {
t.Fatalf("CompareAndSwap = false, want true")
}
if value := v.Load(); value != c1 {
t.Fatalf("Load = (%v), want (%v)", value, c1)
}
if v.CompareAndSwap(c2, c3) != false {
t.Fatalf("CompareAndSwap = true, want false")
}
if value := v.Load(); value != c1 {
t.Fatalf("Load = (%v), want (%v)", value, c1)
}
if v.CompareAndSwap(c1, c2) != true {
t.Fatalf("CompareAndSwap = false, want true")
}
if value := v.Load(); value != c2 {
t.Fatalf("Load = (%v), want (%v)", value, c2)
}
if v.CompareAndSwap(c3, c2) != false {
t.Fatalf("CompareAndSwap = true, want false")
}
if value := v.Load(); value != c2 {
t.Fatalf("Load = (%v), want (%v)", value, c2)
}
if v.CompareAndSwap(nil, c3) != false {
t.Fatalf("CompareAndSwap = true, want false")
}
if value := v.Load(); value != c2 {
t.Fatalf("Load = (%v), want (%v)", value, c2)
}
}
{
c1, c2, c3 := &io.LimitedReader{}, &io.SectionReader{}, &io.SectionReader{}
var v TypedValue[io.Reader]
if v.CompareAndSwap(c1, c2) != false {
t.Fatalf("CompareAndSwap = true, want false")
}
if value := v.Load(); value != nil {
t.Fatalf("Load = (%v), want (%v)", value, nil)
}
if v.CompareAndSwap(nil, c1) != true {
t.Fatalf("CompareAndSwap = false, want true")
}
if value := v.Load(); value != c1 {
t.Fatalf("Load = (%v), want (%v)", value, c1)
}
if v.CompareAndSwap(c2, c3) != false {
t.Fatalf("CompareAndSwap = true, want false")
}
if value := v.Load(); value != c1 {
t.Fatalf("Load = (%v), want (%v)", value, c1)
}
if v.CompareAndSwap(c1, c2) != true {
t.Fatalf("CompareAndSwap = false, want true")
}
if value := v.Load(); value != c2 {
t.Fatalf("Load = (%v), want (%v)", value, c2)
}
if v.CompareAndSwap(c3, c2) != false {
t.Fatalf("CompareAndSwap = true, want false")
}
if value := v.Load(); value != c2 {
t.Fatalf("Load = (%v), want (%v)", value, c2)
}
if v.CompareAndSwap(nil, c3) != false {
t.Fatalf("CompareAndSwap = true, want false")
}
if value := v.Load(); value != c2 {
t.Fatalf("Load = (%v), want (%v)", value, c2)
}
}
}
@@ -14,6 +14,7 @@ var NewPacket = buf.NewPacket
var NewSize = buf.NewSize
var With = buf.With
var As = buf.As
var ReleaseMulti = buf.ReleaseMulti
var (
Must = common.Must
@@ -221,6 +221,9 @@ func ConvertsV2Ray(buf []byte) ([]map[string]any, error) {
if flow := query.Get("flow"); flow != "" {
vless["flow"] = strings.ToLower(flow)
}
if encryption := query.Get("encryption"); encryption != "" {
vless["encryption"] = encryption
}
proxies = append(proxies, vless)
case "vmess":
@@ -149,6 +149,10 @@ func (c *Conn) ReaderReplaceable() bool {
return c.disablePipe.Load() || c.deadline.Load().IsZero()
}
func (c *Conn) WriterReplaceable() bool {
return true
}
func (c *Conn) Upstream() any {
return c.ExtendedConn
}
@@ -22,6 +22,10 @@ type ExtendedReader = network.ExtendedReader
var WriteBuffer = bufio.WriteBuffer
type ReadWaitOptions = network.ReadWaitOptions
var NewReadWaitOptions = network.NewReadWaitOptions
func NewDeadlineConn(conn net.Conn) ExtendedConn {
if deadline.IsPipe(conn) || deadline.IsPipe(network.UnwrapReader(conn)) {
return NewExtendedConn(conn) // pipe always have correctly deadline implement
@@ -1,49 +0,0 @@
package generater
import (
"encoding/base64"
"fmt"
"github.com/metacubex/mihomo/component/ech"
"github.com/gofrs/uuid/v5"
)
func Main(args []string) {
if len(args) < 1 {
panic("Using: generate uuid/reality-keypair/wg-keypair/ech-keypair")
}
switch args[0] {
case "uuid":
newUUID, err := uuid.NewV4()
if err != nil {
panic(err)
}
fmt.Println(newUUID.String())
case "reality-keypair":
privateKey, err := GeneratePrivateKey()
if err != nil {
panic(err)
}
publicKey := privateKey.PublicKey()
fmt.Println("PrivateKey: " + base64.RawURLEncoding.EncodeToString(privateKey[:]))
fmt.Println("PublicKey: " + base64.RawURLEncoding.EncodeToString(publicKey[:]))
case "wg-keypair":
privateKey, err := GeneratePrivateKey()
if err != nil {
panic(err)
}
fmt.Println("PrivateKey: " + privateKey.String())
fmt.Println("PublicKey: " + privateKey.PublicKey().String())
case "ech-keypair":
if len(args) < 2 {
panic("Using: generate ech-keypair <plain_server_name>")
}
configBase64, keyPem, err := ech.GenECHConfig(args[1])
if err != nil {
panic(err)
}
fmt.Println("Config:", configBase64)
fmt.Println("Key:", keyPem)
}
}
@@ -1,97 +0,0 @@
// Copy from https://github.com/WireGuard/wgctrl-go/blob/a9ab2273dd1075ea74b88c76f8757f8b4003fcbf/wgtypes/types.go#L71-L155
package generater
import (
"crypto/rand"
"encoding/base64"
"fmt"
"golang.org/x/crypto/curve25519"
)
// KeyLen is the expected key length for a WireGuard key.
const KeyLen = 32 // wgh.KeyLen
// A Key is a public, private, or pre-shared secret key. The Key constructor
// functions in this package can be used to create Keys suitable for each of
// these applications.
type Key [KeyLen]byte
// GenerateKey generates a Key suitable for use as a pre-shared secret key from
// a cryptographically safe source.
//
// The output Key should not be used as a private key; use GeneratePrivateKey
// instead.
func GenerateKey() (Key, error) {
b := make([]byte, KeyLen)
if _, err := rand.Read(b); err != nil {
return Key{}, fmt.Errorf("wgtypes: failed to read random bytes: %v", err)
}
return NewKey(b)
}
// GeneratePrivateKey generates a Key suitable for use as a private key from a
// cryptographically safe source.
func GeneratePrivateKey() (Key, error) {
key, err := GenerateKey()
if err != nil {
return Key{}, err
}
// Modify random bytes using algorithm described at:
// https://cr.yp.to/ecdh.html.
key[0] &= 248
key[31] &= 127
key[31] |= 64
return key, nil
}
// NewKey creates a Key from an existing byte slice. The byte slice must be
// exactly 32 bytes in length.
func NewKey(b []byte) (Key, error) {
if len(b) != KeyLen {
return Key{}, fmt.Errorf("wgtypes: incorrect key size: %d", len(b))
}
var k Key
copy(k[:], b)
return k, nil
}
// ParseKey parses a Key from a base64-encoded string, as produced by the
// Key.String method.
func ParseKey(s string) (Key, error) {
b, err := base64.StdEncoding.DecodeString(s)
if err != nil {
return Key{}, fmt.Errorf("wgtypes: failed to parse base64-encoded key: %v", err)
}
return NewKey(b)
}
// PublicKey computes a public key from the private key k.
//
// PublicKey should only be called when k is a private key.
func (k Key) PublicKey() Key {
var (
pub [KeyLen]byte
priv = [KeyLen]byte(k)
)
// ScalarBaseMult uses the correct base value per https://cr.yp.to/ecdh.html,
// so no need to specify it.
curve25519.ScalarBaseMult(&pub, &priv)
return Key(pub)
}
// String returns the base64-encoded string representation of a Key.
//
// ParseKey can be used to produce a new Key from this string.
func (k Key) String() string {
return base64.StdEncoding.EncodeToString(k[:])
}
@@ -0,0 +1,73 @@
package generator
import (
"encoding/base64"
"fmt"
"github.com/metacubex/mihomo/component/ech"
"github.com/metacubex/mihomo/transport/vless/encryption"
"github.com/gofrs/uuid/v5"
)
func Main(args []string) {
if len(args) < 1 {
panic("Using: generate uuid/reality-keypair/wg-keypair/ech-keypair/vless-mlkem768/vless-x25519")
}
switch args[0] {
case "uuid":
newUUID, err := uuid.NewV4()
if err != nil {
panic(err)
}
fmt.Println(newUUID.String())
case "reality-keypair":
privateKey, err := GenX25519PrivateKey()
if err != nil {
panic(err)
}
fmt.Println("PrivateKey: " + base64.RawURLEncoding.EncodeToString(privateKey.Bytes()))
fmt.Println("PublicKey: " + base64.RawURLEncoding.EncodeToString(privateKey.PublicKey().Bytes()))
case "wg-keypair":
privateKey, err := GenX25519PrivateKey()
if err != nil {
panic(err)
}
fmt.Println("PrivateKey: " + base64.StdEncoding.EncodeToString(privateKey.Bytes()))
fmt.Println("PublicKey: " + base64.StdEncoding.EncodeToString(privateKey.PublicKey().Bytes()))
case "ech-keypair":
if len(args) < 2 {
panic("Using: generate ech-keypair <plain_server_name>")
}
configBase64, keyPem, err := ech.GenECHConfig(args[1])
if err != nil {
panic(err)
}
fmt.Println("Config:", configBase64)
fmt.Println("Key:", keyPem)
case "vless-mlkem768":
var seed string
if len(args) > 1 {
seed = args[1]
}
seedBase64, clientBase64, hash32Base64, err := encryption.GenMLKEM768(seed)
if err != nil {
panic(err)
}
fmt.Println("Seed: " + seedBase64)
fmt.Println("Client: " + clientBase64)
fmt.Println("Hash32: " + hash32Base64)
case "vless-x25519":
var privateKey string
if len(args) > 1 {
privateKey = args[1]
}
privateKeyBase64, passwordBase64, hash32Base64, err := encryption.GenX25519(privateKey)
if err != nil {
panic(err)
}
fmt.Println("PrivateKey: " + privateKeyBase64)
fmt.Println("Password: " + passwordBase64)
fmt.Println("Hash32: " + hash32Base64)
}
}
@@ -0,0 +1,27 @@
package generator
import (
"crypto/ecdh"
"crypto/rand"
)
const X25519KeySize = 32
func GenX25519PrivateKey() (*ecdh.PrivateKey, error) {
var privateKey [X25519KeySize]byte
_, err := rand.Read(privateKey[:])
if err != nil {
return nil, err
}
// Avoid generating equivalent X25519 private keys
// https://github.com/XTLS/Xray-core/pull/1747
//
// Modify random bytes using algorithm described at:
// https://cr.yp.to/ecdh.html.
privateKey[0] &= 248
privateKey[31] &= 127
privateKey[31] |= 64
return ecdh.X25519().NewPrivateKey(privateKey[:])
}
@@ -10,27 +10,27 @@ import (
)
var (
keepAliveIdle = atomic.NewTypedValue[time.Duration](0 * time.Second)
keepAliveInterval = atomic.NewTypedValue[time.Duration](0 * time.Second)
keepAliveIdle = atomic.NewInt64(0)
keepAliveInterval = atomic.NewInt64(0)
disableKeepAlive = atomic.NewBool(false)
SetDisableKeepAliveCallback = utils.NewCallback[bool]()
)
func SetKeepAliveIdle(t time.Duration) {
keepAliveIdle.Store(t)
keepAliveIdle.Store(int64(t))
}
func SetKeepAliveInterval(t time.Duration) {
keepAliveInterval.Store(t)
keepAliveInterval.Store(int64(t))
}
func KeepAliveIdle() time.Duration {
return keepAliveIdle.Load()
return time.Duration(keepAliveIdle.Load())
}
func KeepAliveInterval() time.Duration {
return keepAliveInterval.Load()
return time.Duration(keepAliveInterval.Load())
}
func SetDisableKeepAlive(disable bool) {
@@ -170,7 +170,7 @@ type realityVerifier struct {
//var pOffset = utils.MustOK(reflect.TypeOf((*utls.Conn)(nil)).Elem().FieldByName("peerCertificates")).Offset
func (c *realityVerifier) VerifyPeerCertificate(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error {
//log.Debugln("REALITY localAddr: %v\t is using X25519MLKEM768 for TLS' communication: %v", c.RemoteAddr(), c.HandshakeState.ServerHello.SelectedGroup == utls.X25519MLKEM768)
log.Debugln("REALITY localAddr: %v is using X25519MLKEM768 for TLS' communication: %v", c.RemoteAddr(), c.HandshakeState.ServerHello.ServerShare.Group == utls.X25519MLKEM768)
//p, _ := reflect.TypeOf(c.Conn).Elem().FieldByName("peerCertificates")
//certs := *(*[]*x509.Certificate)(unsafe.Add(unsafe.Pointer(c.Conn), pOffset))
certs := c.Conn.PeerCertificates()
@@ -8,6 +8,7 @@ import (
"io"
"net/http"
"os"
"os/exec"
"path/filepath"
"runtime"
"strings"
@@ -33,6 +34,11 @@ const (
MaxPackageFileSize = 32 * 1024 * 1024
)
const (
ReleaseChannel = "release"
AlphaChannel = "alpha"
)
// CoreUpdater is the mihomo updater.
// modify from https://github.com/AdguardTeam/AdGuardHome/blob/595484e0b3fb4c457f9bb727a6b94faa78a66c5f/internal/updater/updater.go
type CoreUpdater struct {
@@ -69,20 +75,28 @@ func (u *CoreUpdater) CoreBaseName() string {
}
}
func (u *CoreUpdater) Update(currentExePath string) (err error) {
func (u *CoreUpdater) Update(currentExePath string, channel string, force bool) (err error) {
u.mu.Lock()
defer u.mu.Unlock()
_, err = os.Stat(currentExePath)
info, err := os.Stat(currentExePath)
if err != nil {
return fmt.Errorf("check currentExePath %q: %w", currentExePath, err)
}
baseURL := baseAlphaURL
versionURL := versionAlphaURL
if !strings.HasPrefix(C.Version, "alpha") {
switch strings.ToLower(channel) {
case ReleaseChannel:
baseURL = baseReleaseURL
versionURL = versionReleaseURL
case AlphaChannel:
break
default: // auto
if !strings.HasPrefix(C.Version, "alpha") {
baseURL = baseReleaseURL
versionURL = versionReleaseURL
}
}
latestVersion, err := u.getLatestVersion(versionURL)
@@ -91,7 +105,7 @@ func (u *CoreUpdater) Update(currentExePath string) (err error) {
}
log.Infoln("current version %s, latest version %s", C.Version, latestVersion)
if latestVersion == C.Version {
if latestVersion == C.Version && !force {
// don't change this output, some downstream dependencies on the upgrader's output fields
return fmt.Errorf("update error: already using latest version %s", C.Version)
}
@@ -136,7 +150,7 @@ func (u *CoreUpdater) Update(currentExePath string) (err error) {
return fmt.Errorf("downloading: %w", err)
}
err = u.unpack(updateDir, packagePath)
err = u.unpack(updateDir, packagePath, info.Mode())
if err != nil {
return fmt.Errorf("unpacking: %w", err)
}
@@ -146,7 +160,7 @@ func (u *CoreUpdater) Update(currentExePath string) (err error) {
return fmt.Errorf("backuping: %w", err)
}
err = u.replace(updateExePath, currentExePath)
err = u.copyFile(updateExePath, currentExePath)
if err != nil {
return fmt.Errorf("replacing: %w", err)
}
@@ -230,16 +244,16 @@ func (u *CoreUpdater) download(updateDir, packagePath, packageURL string) (err e
}
// unpack extracts the files from the downloaded archive.
func (u *CoreUpdater) unpack(updateDir, packagePath string) error {
func (u *CoreUpdater) unpack(updateDir, packagePath string, fileMode os.FileMode) error {
log.Infoln("updater: unpacking package")
if strings.HasSuffix(packagePath, ".zip") {
_, err := u.zipFileUnpack(packagePath, updateDir)
_, err := u.zipFileUnpack(packagePath, updateDir, fileMode)
if err != nil {
return fmt.Errorf(".zip unpack failed: %w", err)
}
} else if strings.HasSuffix(packagePath, ".gz") {
_, err := u.gzFileUnpack(packagePath, updateDir)
_, err := u.gzFileUnpack(packagePath, updateDir, fileMode)
if err != nil {
return fmt.Errorf(".gz unpack failed: %w", err)
}
@@ -271,21 +285,6 @@ func (u *CoreUpdater) backup(currentExePath, backupExePath, backupDir string) (e
return nil
}
// replace moves the current executable with the updated one
func (u *CoreUpdater) replace(updateExePath, currentExePath string) error {
log.Infoln("replacing: %s to %s", updateExePath, currentExePath)
// Use copyFile to retain the original file attributes
err := u.copyFile(updateExePath, currentExePath)
if err != nil {
return err
}
log.Infoln("updater: copy: %s to %s", updateExePath, currentExePath)
return nil
}
// clean removes the temporary directory itself and all it's contents.
func (u *CoreUpdater) clean(updateDir string) {
_ = os.RemoveAll(updateDir)
@@ -295,7 +294,7 @@ func (u *CoreUpdater) clean(updateDir string) {
// Existing files are overwritten
// All files are created inside outDir, subdirectories are not created
// Return the output file name
func (u *CoreUpdater) gzFileUnpack(gzfile, outDir string) (outputName string, err error) {
func (u *CoreUpdater) gzFileUnpack(gzfile, outDir string, fileMode os.FileMode) (outputName string, err error) {
f, err := os.Open(gzfile)
if err != nil {
return "", fmt.Errorf("os.Open(): %w", err)
@@ -330,7 +329,7 @@ func (u *CoreUpdater) gzFileUnpack(gzfile, outDir string) (outputName string, er
outputName = filepath.Join(outDir, originalName)
// Create the output file
wc, err := os.OpenFile(outputName, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0o755)
wc, err := os.OpenFile(outputName, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, fileMode)
if err != nil {
return "", fmt.Errorf("os.OpenFile(%s): %w", outputName, err)
}
@@ -355,7 +354,7 @@ func (u *CoreUpdater) gzFileUnpack(gzfile, outDir string) (outputName string, er
// Existing files are overwritten
// All files are created inside 'outDir', subdirectories are not created
// Return the output file name
func (u *CoreUpdater) zipFileUnpack(zipfile, outDir string) (outputName string, err error) {
func (u *CoreUpdater) zipFileUnpack(zipfile, outDir string, fileMode os.FileMode) (outputName string, err error) {
zrc, err := zip.OpenReader(zipfile)
if err != nil {
return "", fmt.Errorf("zip.OpenReader(): %w", err)
@@ -394,7 +393,7 @@ func (u *CoreUpdater) zipFileUnpack(zipfile, outDir string) (outputName string,
}
var wc io.WriteCloser
wc, err = os.OpenFile(outputName, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, fi.Mode())
wc, err = os.OpenFile(outputName, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, fileMode)
if err != nil {
return "", fmt.Errorf("os.OpenFile(): %w", err)
}
@@ -437,7 +436,16 @@ func (u *CoreUpdater) copyFile(src, dst string) (err error) {
// otherwise truncates it before writing, without changing permissions.
wc, err := os.OpenFile(dst, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, info.Mode())
if err != nil {
return fmt.Errorf("os.OpenFile(%s): %w", dst, err)
// On some file system (such as Android's /data) maybe return error: "text file busy"
// Let's delete the target file and recreate it
err = os.Remove(dst)
if err != nil {
return fmt.Errorf("os.Remove(%s): %w", dst, err)
}
wc, err = os.OpenFile(dst, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, info.Mode())
if err != nil {
return fmt.Errorf("os.OpenFile(%s): %w", dst, err)
}
}
defer func() {
@@ -452,5 +460,13 @@ func (u *CoreUpdater) copyFile(src, dst string) (err error) {
return fmt.Errorf("io.Copy(): %w", err)
}
if runtime.GOOS == "darwin" {
err = exec.Command("/usr/bin/codesign", "--sign", "-", dst).Run()
if err != nil {
log.Warnln("codesign failed: %v", err)
}
}
log.Infoln("updater: copy: %s to %s", src, dst)
return nil
}
@@ -1,3 +1,12 @@
// Package wildcard modified IGLOU-EU/go-wildcard to support:
//
// `*` matches zero or more characters
// `?` matches exactly one character
//
// The original go-wildcard library used `.` to match exactly one character, and `?` to match zero or one character.
// `.` is a valid delimiter in domain name matching and should not be used as a wildcard.
// The `?` matching logic strictly matches only one character in most scenarios.
// So, the `?` matching logic in the original go-wildcard library has been removed and its wildcard `.` has been replaced with `?`.
package wildcard
// copy and modified from https://github.com/IGLOU-EU/go-wildcard/tree/ce22b7af48e487517a492d3727d9386492043e21
@@ -16,12 +25,10 @@ func Match(pattern, s string) bool {
}
func matchByString(pattern, s string) bool {
var lastErotemeCluster byte
var patternIndex, sIndex, lastStar, lastEroteme int
var patternIndex, sIndex, lastStar int
patternLen := len(pattern)
sLen := len(s)
star := -1
eroteme := -1
Loop:
if sIndex >= sLen {
@@ -38,14 +45,8 @@ Loop:
return false
}
switch pattern[patternIndex] {
// Removed dot matching as it conflicts with dot in domains.
// case '.':
// It matches any single character. So, we don't need to check anything.
case '?':
// '?' matches one character. Store its position and match exactly one character in the string.
eroteme = patternIndex
lastEroteme = sIndex
lastErotemeCluster = byte(s[sIndex])
// It matches any single character. So, we don't need to check anything.
case '*':
// '*' matches zero or more characters. Store its position and increment the pattern index.
star = patternIndex
@@ -53,15 +54,8 @@ Loop:
patternIndex++
goto Loop
default:
// If the characters don't match, check if there was a previous '?' or '*' to backtrack.
// If the characters don't match, check if there was a previous '*' to backtrack.
if pattern[patternIndex] != s[sIndex] {
if eroteme != -1 {
patternIndex = eroteme + 1
sIndex = lastEroteme
eroteme = -1
goto Loop
}
if star != -1 {
patternIndex = star + 1
lastStar++
@@ -71,29 +65,18 @@ Loop:
return false
}
// If the characters match, check if it was not the same to validate the eroteme.
if eroteme != -1 && lastErotemeCluster != byte(s[sIndex]) {
eroteme = -1
}
}
patternIndex++
sIndex++
goto Loop
// Check if the remaining pattern characters are '*' or '?', which can match the end of the string.
// Check if the remaining pattern characters are '*', which can match the end of the string.
checkPattern:
if patternIndex < patternLen {
if pattern[patternIndex] == '*' {
patternIndex++
goto checkPattern
} else if pattern[patternIndex] == '?' {
if sIndex >= sLen {
sIndex--
}
patternIndex++
goto checkPattern
}
}
@@ -25,31 +25,17 @@ func TestMatch(t *testing.T) {
{"", "", true},
{"", "*", true},
{"", "**", true},
{"", "?", true},
{"", "??", true},
{"", "?*", true},
{"", "*?", true},
{"", ".", false},
{"", ".?", false},
{"", "?.", false},
{"", ".*", false},
{"", "*.", false},
{"", "*.?", false},
{"", "?.*", false},
{"", "?", false},
{"", "?*", false},
{"", "*?", false},
{"a", "", false},
{"a", "a", true},
{"a", "*", true},
{"a", "**", true},
{"a", "?", true},
{"a", "??", true},
{"a", ".", false},
{"a", ".?", false},
{"a", "?.", false},
{"a", ".*", false},
{"a", "*.", false},
{"a", "*.?", false},
{"a", "?.*", false},
{"a", "?*", true},
{"a", "*?", true},
{"match the exact string", "match the exact string", true},
{"do not match a different string", "this is a different string", false},
@@ -68,22 +54,27 @@ func TestMatch(t *testing.T) {
{"match a string with a ?", "match ? string with a ?", true},
{"match a string with a ? at the beginning", "?atch a string with a ? at the beginning", true},
{"match a string with two ?", "match a string with two ??", true},
{"match a optional char with a ?", "match a optional? char with a ?", true},
{"match a optional char with a ?", "match a optional? char with a ?", true},
{"do not match a string with extra and a ?", "do not match ? string with extra and a ? like this", false},
{"match a string with two ?", "match a ??ring with two ?", true},
{"do not match a string with extra ?", "do not match a string with extra ??", false},
{"do not match a string with a .", "do not match . string with a .", false},
{"do not match a string with a . at the beginning", "do not .atch a string with a . at the beginning", false},
{"do not match a string with two .", "do not match a ..ring with two .", false},
{"do not match a string with extra .", "do not match a string with extra ..", false},
{"abc.edf.hjg", "abc.edf.hjg", true},
{"abc.edf.hjg", "ab.cedf.hjg", false},
{"abc.edf.hjg", "abc.edfh.jg", false},
{"abc.edf.hjg", "abc.edf.hjq", false},
{"A big brown fox jumps over the lazy dog, with all there wildcards friends", ". big?brown fox jumps over * wildcard. friend??", false},
{"A big brown fox fails to jump over the lazy dog, with all there wildcards friends", ". big?brown fox jumps over * wildcard. friend??", false},
{"abc.edf.hjg", "abc.*.hjg", true},
{"abc.edf.hjg", "abc.*.hjq", false},
{"abc.edf.hjg", "abc*hjg", true},
{"abc.edf.hjg", "abc*hjq", false},
{"abc.edf.hjg", "a*g", true},
{"abc.edf.hjg", "a*q", false},
{"domain a.b.c", "domain a.b.c", true},
{"domain adb.c", "domain a.b.c", false},
{"aaaa", "a*a", true},
{"abc.edf.hjg", "ab?.edf.hjg", true},
{"abc.edf.hjg", "?b?.edf.hjg", true},
{"abc.edf.hjg", "??c.edf.hjg", true},
{"abc.edf.hjg", "a??.edf.hjg", true},
{"abc.edf.hjg", "ab??.edf.hjg", false},
{"abc.edf.hjg", "??.edf.hjg", false},
}
for i, c := range cases {
@@ -96,10 +87,106 @@ func TestMatch(t *testing.T) {
}
}
func match(pattern, name string) bool { // https://research.swtch.com/glob
px := 0
nx := 0
nextPx := 0
nextNx := 0
for px < len(pattern) || nx < len(name) {
if px < len(pattern) {
c := pattern[px]
switch c {
default: // ordinary character
if nx < len(name) && name[nx] == c {
px++
nx++
continue
}
case '?': // single-character wildcard
if nx < len(name) {
px++
nx++
continue
}
case '*': // zero-or-more-character wildcard
// Try to match at nx.
// If that doesn't work out,
// restart at nx+1 next.
nextPx = px
nextNx = nx + 1
px++
continue
}
}
// Mismatch. Maybe restart.
if 0 < nextNx && nextNx <= len(name) {
px = nextPx
nx = nextNx
continue
}
return false
}
// Matched all of pattern to all of name. Success.
return true
}
func FuzzMatch(f *testing.F) {
f.Fuzz(func(t *testing.T, s string) {
if !Match(string(s), string(s)) {
t.Fatalf("%s does not match %s", s, s)
f.Fuzz(func(t *testing.T, pattern, name string) {
result1 := Match(pattern, name)
result2 := match(pattern, name)
if result1 != result2 {
t.Fatalf("Match failed for pattern `%s` and name `%s`", pattern, name)
}
})
}
func BenchmarkMatch(b *testing.B) {
cases := []struct {
s string
pattern string
result bool
}{
{"abc.edf.hjg", "abc.edf.hjg", true},
{"abc.edf.hjg", "ab.cedf.hjg", false},
{"abc.edf.hjg", "abc.edfh.jg", false},
{"abc.edf.hjg", "abc.edf.hjq", false},
{"abc.edf.hjg", "abc.*.hjg", true},
{"abc.edf.hjg", "abc.*.hjq", false},
{"abc.edf.hjg", "abc*hjg", true},
{"abc.edf.hjg", "abc*hjq", false},
{"abc.edf.hjg", "a*g", true},
{"abc.edf.hjg", "a*q", false},
{"abc.edf.hjg", "ab?.edf.hjg", true},
{"abc.edf.hjg", "?b?.edf.hjg", true},
{"abc.edf.hjg", "??c.edf.hjg", true},
{"abc.edf.hjg", "a??.edf.hjg", true},
{"abc.edf.hjg", "ab??.edf.hjg", false},
{"abc.edf.hjg", "??.edf.hjg", false},
{"r4.cdn-aa-wow-this-is-long-a1.video-yajusenpai1145141919810-oh-hell-yeah-this-is-also-very-long-and-sukka-the-fox-has-a-very-big-fluffy-fox-tail-ao-wu-ao-wu-regex-and-wildcard-both-might-have-deadly-back-tracing-issue-be-careful-or-use-linear-matching.com", "*.cdn-*-*.video**.com", true},
}
b.Run("Match", func(b *testing.B) {
for i := 0; i < b.N; i++ {
for _, c := range cases {
result := Match(c.pattern, c.s)
if c.result != result {
b.Errorf("Test %d: Expected `%v`, found `%v`; With Pattern: `%s` and String: `%s`", i+1, c.result, result, c.pattern, c.s)
}
}
}
})
b.Run("match", func(b *testing.B) {
for i := 0; i < b.N; i++ {
for _, c := range cases {
result := match(c.pattern, c.s)
if c.result != result {
b.Errorf("Test %d: Expected `%v`, found `%v`; With Pattern: `%s` and String: `%s`", i+1, c.result, result, c.pattern, c.s)
}
}
}
})
}
@@ -81,8 +81,8 @@ func (h *ResolverEnhancer) InsertHostByIP(ip netip.Addr, host string) {
}
func (h *ResolverEnhancer) FlushFakeIP() error {
if h.fakePool != nil {
return h.fakePool.FlushFakeIP()
if pool := h.fakePool; pool != nil {
return pool.FlushFakeIP()
}
return nil
}
@@ -632,6 +632,21 @@ proxies: # socks5
# fingerprint: xxxx
# skip-cert-verify: true
- name: "vless-encryption"
type: vless
server: server
port: 443
uuid: uuid
network: tcp
# -------------------------
# vless encryption客户端配置:
# native/xorpub 的 XTLS 可以 Splice。只使用 1-RTT 模式 / 若服务端发的 ticket 中秒数不为零则 0-RTT 复用)
# / 是只能选一个,后面 base64 至少一个,无限串联,使用 mihomo generate vless-x25519 和 mihomo generate vless-mlkem768 生成,替换值时需去掉括号
# -------------------------
encryption: "mlkem768x25519plus.native/xorpub/random.1rtt/0rtt.(X25519 Password).(ML-KEM-768 Client)..."
tls: false #可以不开启tls
udp: true
- name: "vless-reality-vision"
type: vless
server: server
@@ -846,6 +861,16 @@ proxies: # socks5
# h2: 67543
# h4: 32345
# h3: 123123
# # AmneziaWG v1.5
# i1: <b 0xf6ab3267fa><c><b 0xf6ab><t><r 10><wt 10>
# i2: <b 0xf6ab3267fa><r 100>
# i3: ""
# i4: ""
# i5: ""
# j1: <b 0xffffffff><c><b 0xf6ab><t><r 10>
# j2: <c><b 0xf6ab><t><wt 1000>
# j3: <t><b 0xf6ab><c><r 10>
# itime: 60
# tuic
- name: tuic
@@ -922,6 +947,8 @@ proxies: # socks5
password: password
# 可以使用的值包括 MULTIPLEXING_OFF, MULTIPLEXING_LOW, MULTIPLEXING_MIDDLE, MULTIPLEXING_HIGH。其中 MULTIPLEXING_OFF 会关闭多路复用功能。默认值为 MULTIPLEXING_LOW。
# multiplexing: MULTIPLEXING_LOW
# 如果想开启 0-RTT 握手,请设置为 HANDSHAKE_NO_WAIT,否则请设置为 HANDSHAKE_STANDARD。默认值为 HANDSHAKE_STANDARD
# handshake-mode: HANDSHAKE_STANDARD
# anytls
- name: anytls
@@ -1336,6 +1363,12 @@ listeners:
flow: xtls-rprx-vision
# ws-path: "/" # 如果不为空则开启 websocket 传输层
# grpc-service-name: "GunService" # 如果不为空则开启 grpc 传输层
# -------------------------
# vless encryption服务端配置:
# (原生外观 / 只 XOR 公钥 / 全随机数。只允许 1-RTT 模式 / 同时允许 1-RTT 模式与 600 秒复用的 0-RTT 模式)
# / 是只能选一个,后面 base64 至少一个,无限串联,使用 mihomo generate vless-x25519 和 mihomo generate vless-mlkem768 生成,替换值时需去掉括号
# -------------------------
# decryption: "mlkem768x25519plus.native/xorpub/random.1rtt/600s.(X25519 PrivateKey).(ML-KEM-768 Seed)..."
# 下面两项如果填写则开启 tls(需要同时填写)
# certificate: ./server.crt
# private-key: ./server.key
@@ -1364,7 +1397,7 @@ listeners:
after-bytes: 0 # 传输指定字节后开始限速
bytes-per-sec: 0 # 基准速率(字节/秒)
burst-bytes-per-sec: 0 # 突发速率(字节/秒),大于 bytesPerSec 时生效
### 注意,对于vless listener, 至少需要填写 “certificate和private-key” 或 “reality-config” 的其中一项 ###
### 注意,对于vless listener, 至少需要填写 “certificate和private-key” 或 “reality-config” 或 “decryption” 的其中一项 ###
- name: anytls-in-1
type: anytls
@@ -1462,6 +1495,7 @@ listeners:
# masquerade: http://127.0.0.1:8080 #作为反向代理
# masquerade: https://127.0.0.1:8080 #作为反向代理
# 注意,listeners中的tun仅提供给高级用户使用,普通用户应使用顶层配置中的tun
- name: tun-in-1
type: tun
# rule: sub-rule-name1 # 默认使用 rules,如果未找到 sub-rule 则直接使用 rules
@@ -3,40 +3,40 @@ module github.com/metacubex/mihomo
go 1.20
require (
github.com/3andne/restls-client-go v0.1.6
github.com/bahlo/generic-list-go v0.2.0
github.com/coreos/go-iptables v0.8.0
github.com/dlclark/regexp2 v1.11.5
github.com/enfein/mieru/v3 v3.16.1
github.com/go-chi/chi/v5 v5.2.2
github.com/enfein/mieru/v3 v3.19.1
github.com/go-chi/chi/v5 v5.2.3
github.com/go-chi/render v1.0.3
github.com/gobwas/ws v1.4.0
github.com/gofrs/uuid/v5 v5.3.2
github.com/insomniacslk/dhcp v0.0.0-20250109001534-8abf58130905
github.com/klauspost/compress v1.17.9 // lastest version compatible with golang1.20
github.com/lunixbochs/struc v0.0.0-20200707160740-784aaebc1d40
github.com/mdlayher/netlink v1.7.2
github.com/metacubex/amneziawg-go v0.0.0-20240922133038-fdf3a4d5a4ab
github.com/metacubex/amneziawg-go v0.0.0-20250820070344-732c0c9d418a
github.com/metacubex/bart v0.20.5
github.com/metacubex/bbolt v0.0.0-20250725135710-010dbbbb7a5b
github.com/metacubex/blake3 v0.1.0
github.com/metacubex/chacha v0.1.5
github.com/metacubex/fswatch v0.1.1
github.com/metacubex/gopacket v1.1.20-0.20230608035415-7e2f98a3e759
github.com/metacubex/quic-go v0.53.1-0.20250628094454-fda5262d1d9c
github.com/metacubex/quic-go v0.54.1-0.20250730114134-a1ae705fe295
github.com/metacubex/randv2 v0.2.0
github.com/metacubex/sing v0.5.4
github.com/metacubex/sing-mux v0.3.2
github.com/metacubex/restls-client-go v0.1.7
github.com/metacubex/sing v0.5.5
github.com/metacubex/sing-mux v0.3.3-0.20250813083925-d7c9aeaeeaac
github.com/metacubex/sing-quic v0.0.0-20250718154553-1b193bec4cbb
github.com/metacubex/sing-shadowsocks v0.2.11
github.com/metacubex/sing-shadowsocks2 v0.2.5
github.com/metacubex/sing-shadowsocks v0.2.12
github.com/metacubex/sing-shadowsocks2 v0.2.6
github.com/metacubex/sing-shadowtls v0.0.0-20250503063515-5d9f966d17a2
github.com/metacubex/sing-tun v0.4.7-0.20250721020617-8e7c37ed3d97
github.com/metacubex/sing-vmess v0.2.3
github.com/metacubex/sing-tun v0.4.7
github.com/metacubex/sing-vmess v0.2.4-0.20250822020810-4856053566f0
github.com/metacubex/sing-wireguard v0.0.0-20250503063753-2dc62acc626f
github.com/metacubex/smux v0.0.0-20250503055512-501391591dee
github.com/metacubex/tfo-go v0.0.0-20250516165257-e29c16ae41d4
github.com/metacubex/utls v1.8.0
github.com/metacubex/wireguard-go v0.0.0-20240922131502-c182e7471181
github.com/metacubex/tfo-go v0.0.0-20250827083229-aa432b865617
github.com/metacubex/utls v1.8.1-0.20250823120917-12f5ba126142
github.com/metacubex/wireguard-go v0.0.0-20250820062549-a6cecdd7f57f
github.com/miekg/dns v1.1.63 // lastest version compatible with golang1.20
github.com/mroth/weightedrand/v2 v2.1.0
github.com/openacid/low v0.1.21
@@ -46,7 +46,7 @@ require (
github.com/samber/lo v1.51.0
github.com/shirou/gopsutil/v4 v4.25.1 // lastest version compatible with golang1.20
github.com/sirupsen/logrus v1.9.3
github.com/stretchr/testify v1.10.0
github.com/stretchr/testify v1.11.0
github.com/vmihailenco/msgpack/v5 v5.4.1
github.com/wk8/go-ordered-map/v2 v2.1.8
gitlab.com/go-extension/aes-ccm v0.0.0-20230221065045-e58665ef23c7
@@ -59,7 +59,6 @@ require (
golang.org/x/sys v0.30.0 // lastest version compatible with golang1.20
google.golang.org/protobuf v1.34.2 // lastest version compatible with golang1.20
gopkg.in/yaml.v3 v3.0.1
lukechampine.com/blake3 v1.3.0 // lastest version compatible with golang1.20
)
require (
@@ -69,7 +68,7 @@ require (
github.com/andybalholm/brotli v1.0.6 // indirect
github.com/buger/jsonparser v1.1.1 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/ebitengine/purego v0.8.3 // indirect
github.com/ebitengine/purego v0.8.4 // indirect
github.com/ericlagergren/aegis v0.0.0-20250325060835-cd0defd64358 // indirect
github.com/ericlagergren/polyval v0.0.0-20220411101811-e25bc10ba391 // indirect
github.com/ericlagergren/siv v0.0.0-20220507050439-0b757b3aa5f1 // indirect
@@ -85,11 +84,11 @@ require (
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38 // indirect
github.com/hashicorp/yamux v0.1.2 // indirect
github.com/josharian/native v1.1.0 // indirect
github.com/klauspost/cpuid/v2 v2.2.9 // indirect
github.com/kr/text v0.2.0 // indirect
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect
github.com/mailru/easyjson v0.7.7 // indirect
github.com/mdlayher/socket v0.4.1 // indirect
github.com/metacubex/ascon v0.1.0 // indirect
github.com/metacubex/gvisor v0.0.0-20250324165734-5857f47bd43b // indirect
github.com/metacubex/nftables v0.0.0-20250503052935-30a69ab87793 // indirect
github.com/oasisprotocol/deoxysii v0.0.0-20220228165953-2091330c22b7 // indirect
@@ -1,5 +1,3 @@
github.com/3andne/restls-client-go v0.1.6 h1:tRx/YilqW7iHpgmEL4E1D8dAsuB0tFF3uvncS+B6I08=
github.com/3andne/restls-client-go v0.1.6/go.mod h1:iEdTZNt9kzPIxjIGSMScUFSBrUH6bFRNg0BWlP4orEY=
github.com/RyuaNerin/go-krypto v1.3.0 h1:smavTzSMAx8iuVlGb4pEwl9MD2qicqMzuXR2QWp2/Pg=
github.com/RyuaNerin/go-krypto v1.3.0/go.mod h1:9R9TU936laAIqAmjcHo/LsaXYOZlymudOAxjaBf62UM=
github.com/RyuaNerin/testingutil v0.1.0 h1:IYT6JL57RV3U2ml3dLHZsVtPOP6yNK7WUVdzzlpNrss=
@@ -25,10 +23,10 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dlclark/regexp2 v1.11.5 h1:Q/sSnsKerHeCkc/jSTNq1oCm7KiVgUMZRDUoRu0JQZQ=
github.com/dlclark/regexp2 v1.11.5/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
github.com/ebitengine/purego v0.8.3 h1:K+0AjQp63JEZTEMZiwsI9g0+hAMNohwUOtY0RPGexmc=
github.com/ebitengine/purego v0.8.3/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ=
github.com/enfein/mieru/v3 v3.16.1 h1:CfIt1pQCCQbohkw+HBD2o8V9tnhZvB5yuXGGQIXTLOs=
github.com/enfein/mieru/v3 v3.16.1/go.mod h1:zJBUCsi5rxyvHM8fjFf+GLaEl4OEjjBXr1s5F6Qd3hM=
github.com/ebitengine/purego v0.8.4 h1:CF7LEKg5FFOsASUj0+QwaXf8Ht6TlFxg09+S9wz0omw=
github.com/ebitengine/purego v0.8.4/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ=
github.com/enfein/mieru/v3 v3.19.1 h1:19b9kgFC7oJXX9RLEO5Pi1gO6yek5cWlpK7IJVUoE8I=
github.com/enfein/mieru/v3 v3.19.1/go.mod h1:zJBUCsi5rxyvHM8fjFf+GLaEl4OEjjBXr1s5F6Qd3hM=
github.com/ericlagergren/aegis v0.0.0-20250325060835-cd0defd64358 h1:kXYqH/sL8dS/FdoFjr12ePjnLPorPo2FsnrHNuXSDyo=
github.com/ericlagergren/aegis v0.0.0-20250325060835-cd0defd64358/go.mod h1:hkIFzoiIPZYxdFOOLyDho59b7SrDfo+w3h+yWdlg45I=
github.com/ericlagergren/polyval v0.0.0-20220411101811-e25bc10ba391 h1:8j2RH289RJplhA6WfdaPqzg1MjH2K8wX5e0uhAxrw2g=
@@ -42,8 +40,8 @@ github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S
github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
github.com/gaukas/godicttls v0.0.4 h1:NlRaXb3J6hAnTmWdsEKb9bcSBD6BvcIjdGdeb0zfXbk=
github.com/gaukas/godicttls v0.0.4/go.mod h1:l6EenT4TLWgTdwslVb4sEMOCf7Bv0JAK67deKr9/NCI=
github.com/go-chi/chi/v5 v5.2.2 h1:CMwsvRVTbXVytCk1Wd72Zy1LAsAh9GxMmSNWLHCG618=
github.com/go-chi/chi/v5 v5.2.2/go.mod h1:L2yAIGWB3H+phAw1NxKwWM+7eUH/lU8pOMm5hHcoops=
github.com/go-chi/chi/v5 v5.2.3 h1:WQIt9uxdsAbgIYgid+BpYc+liqQZGMHRaUwp0JUcvdE=
github.com/go-chi/chi/v5 v5.2.3/go.mod h1:L2yAIGWB3H+phAw1NxKwWM+7eUH/lU8pOMm5hHcoops=
github.com/go-chi/render v1.0.3 h1:AsXqd2a1/INaIfUSKq3G5uA8weYx20FOsM7uSoCyyt4=
github.com/go-chi/render v1.0.3/go.mod h1:/gr3hVkmYR0YlEy3LxCuVRFzEu9Ruok+gFqbIofjao0=
github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ=
@@ -81,27 +79,27 @@ github.com/josharian/native v1.1.0 h1:uuaP0hAbW7Y4l0ZRQ6C9zfb7Mg1mbFKry/xzDAfmtL
github.com/josharian/native v1.1.0/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w=
github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA=
github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
github.com/klauspost/cpuid/v2 v2.2.9 h1:66ze0taIn2H33fBvCkXuv9BmCwDfafmiIVpKV9kKGuY=
github.com/klauspost/cpuid/v2 v2.2.9/go.mod h1:rqkxqrZ1EhYM9G+hXH7YdowN5R5RGN6NK4QwQ3WMXF8=
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ81pIr0yLvtUWk2if982qA3F3QD6H4=
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I=
github.com/lunixbochs/struc v0.0.0-20200707160740-784aaebc1d40 h1:EnfXoSqDfSNJv0VBNqY/88RNnhSGYkrHaO0mmFGbVsc=
github.com/lunixbochs/struc v0.0.0-20200707160740-784aaebc1d40/go.mod h1:vy1vK6wD6j7xX6O6hXe621WabdtNkou2h7uRtTfRMyg=
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
github.com/mdlayher/netlink v1.7.2 h1:/UtM3ofJap7Vl4QWCPDGXY8d3GIY2UGSDbK+QWmY8/g=
github.com/mdlayher/netlink v1.7.2/go.mod h1:xraEF7uJbxLhc5fpHL4cPe221LI2bdttWlU+ZGLfQSw=
github.com/mdlayher/socket v0.4.1 h1:eM9y2/jlbs1M615oshPQOHZzj6R6wMT7bX5NPiQvn2U=
github.com/mdlayher/socket v0.4.1/go.mod h1:cAqeGjoufqdxWkD7DkpyS+wcefOtmu5OQ8KuoJGIReA=
github.com/metacubex/amneziawg-go v0.0.0-20240922133038-fdf3a4d5a4ab h1:Chbw+/31UC14YFNr78pESt5Vowlc62zziw05JCUqoL4=
github.com/metacubex/amneziawg-go v0.0.0-20240922133038-fdf3a4d5a4ab/go.mod h1:xVKK8jC5Sd3hfh7WjmCq+HorehIbrBijaUWmcuKjPcI=
github.com/metacubex/amneziawg-go v0.0.0-20250820070344-732c0c9d418a h1:c1QSGpacSeQdBdWcEKZKGuWLcqIG2wxHEygAcXuDwS4=
github.com/metacubex/amneziawg-go v0.0.0-20250820070344-732c0c9d418a/go.mod h1:MsM/5czONyXMJ3PRr5DbQ4O/BxzAnJWOIcJdLzW6qHY=
github.com/metacubex/ascon v0.1.0 h1:6ZWxmXYszT1XXtwkf6nxfFhc/OTtQ9R3Vyj1jN32lGM=
github.com/metacubex/ascon v0.1.0/go.mod h1:eV5oim4cVPPdEL8/EYaTZ0iIKARH9pnhAK/fcT5Kacc=
github.com/metacubex/bart v0.20.5 h1:XkgLZ17QxfxkqKdGsojoM2Zu01mmHyyQSFzt2/calTM=
github.com/metacubex/bart v0.20.5/go.mod h1:DCcyfP4MC+Zy7sLK7XeGuMw+P5K9mIRsYOBgiE8icsI=
github.com/metacubex/bbolt v0.0.0-20250725135710-010dbbbb7a5b h1:j7dadXD8I2KTmMt8jg1JcaP1ANL3JEObJPdANKcSYPY=
github.com/metacubex/bbolt v0.0.0-20250725135710-010dbbbb7a5b/go.mod h1:+WmP0VJZDkDszvpa83HzfUp6QzARl/IKkMorH4+nODw=
github.com/metacubex/blake3 v0.1.0 h1:KGnjh/56REO7U+cgZA8dnBhxdP7jByrG7hTP+bu6cqY=
github.com/metacubex/blake3 v0.1.0/go.mod h1:CCkLdzFrqf7xmxCdhQFvJsRRV2mwOLDoSPg6vUTB9Uk=
github.com/metacubex/chacha v0.1.5 h1:fKWMb/5c7ZrY8Uoqi79PPFxl+qwR7X/q0OrsAubyX2M=
github.com/metacubex/chacha v0.1.5/go.mod h1:Djn9bPZxLTXbJFSeyo0/qzEzQI+gUSSzttuzZM75GH8=
github.com/metacubex/fswatch v0.1.1 h1:jqU7C/v+g0qc2RUFgmAOPoVvfl2BXXUXEumn6oQuxhU=
@@ -112,37 +110,39 @@ github.com/metacubex/gvisor v0.0.0-20250324165734-5857f47bd43b h1:RUh4OdVPz/jDrM
github.com/metacubex/gvisor v0.0.0-20250324165734-5857f47bd43b/go.mod h1:8LpS0IJW1VmWzUm3ylb0e2SK5QDm5lO/2qwWLZgRpBU=
github.com/metacubex/nftables v0.0.0-20250503052935-30a69ab87793 h1:1Qpuy+sU3DmyX9HwI+CrBT/oLNJngvBorR2RbajJcqo=
github.com/metacubex/nftables v0.0.0-20250503052935-30a69ab87793/go.mod h1:RjRNb4G52yAgfR+Oe/kp9G4PJJ97Fnj89eY1BFO3YyA=
github.com/metacubex/quic-go v0.53.1-0.20250628094454-fda5262d1d9c h1:ABQzmOaZddM3q0OYeoZEc0XF+KW+dUdPNvY/c5rsunI=
github.com/metacubex/quic-go v0.53.1-0.20250628094454-fda5262d1d9c/go.mod h1:eWlAK3zsKI0P8UhYpXlIsl3mtW4D6MpMNuYLIu8CKWI=
github.com/metacubex/quic-go v0.54.1-0.20250730114134-a1ae705fe295 h1:8JVlYuE8uSJAvmyCd4TjvDxs57xjb0WxEoaWafK5+qs=
github.com/metacubex/quic-go v0.54.1-0.20250730114134-a1ae705fe295/go.mod h1:1lktQFtCD17FZliVypbrDHwbsFSsmz2xz2TRXydvB5c=
github.com/metacubex/randv2 v0.2.0 h1:uP38uBvV2SxYfLj53kuvAjbND4RUDfFJjwr4UigMiLs=
github.com/metacubex/randv2 v0.2.0/go.mod h1:kFi2SzrQ5WuneuoLLCMkABtiBu6VRrMrWFqSPyj2cxY=
github.com/metacubex/restls-client-go v0.1.7 h1:eCwiXCTQb5WJu9IlgYvDBA1OgrINv58dEe7hcN5H15k=
github.com/metacubex/restls-client-go v0.1.7/go.mod h1:BN/U52vPw7j8VTSh2vleD/MnmVKCov84mS5VcjVHH4g=
github.com/metacubex/sing v0.5.2/go.mod h1:ypf0mjwlZm0sKdQSY+yQvmsbWa0hNPtkeqyRMGgoN+w=
github.com/metacubex/sing v0.5.4 h1:a4kAOZmF+OXosbzPEcrSc5QD35/ex+MNuZsrcuWskHk=
github.com/metacubex/sing v0.5.4/go.mod h1:ypf0mjwlZm0sKdQSY+yQvmsbWa0hNPtkeqyRMGgoN+w=
github.com/metacubex/sing-mux v0.3.2 h1:nJv52pyRivHcaZJKk2JgxpaVvj1GAXG81scSa9N7ncw=
github.com/metacubex/sing-mux v0.3.2/go.mod h1:3rt1soewn0O6j89GCLmwAQFsq257u0jf2zQSPhTL3Bw=
github.com/metacubex/sing v0.5.5 h1:m5U8iHvRAUxlme3FZlE/LPIGHjU8oMCUzXWGbQQAC1E=
github.com/metacubex/sing v0.5.5/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-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.11 h1:p2NGNOdF95e6XvdDKipLj1FRRqR8dnbfC/7pw2CCTlw=
github.com/metacubex/sing-shadowsocks v0.2.11/go.mod h1:bT1PCTV316zFnlToRMk5zt9HmIQYRBveiT71mplYPfc=
github.com/metacubex/sing-shadowsocks2 v0.2.5 h1:MnPn0hbcDkSJt6TlpI15XImHKK6IqaOwBUGPKyMnJnE=
github.com/metacubex/sing-shadowsocks2 v0.2.5/go.mod h1:Zyh+rAQRyevYfG/COCvDs1c/YMhGqCuknn7QrGmoQIw=
github.com/metacubex/sing-shadowsocks v0.2.12 h1:Wqzo8bYXrK5aWqxu/TjlTnYZzAKtKsaFQBdr6IHFaBE=
github.com/metacubex/sing-shadowsocks v0.2.12/go.mod h1:2e5EIaw0rxKrm1YTRmiMnDulwbGxH9hAFlrwQLQMQkU=
github.com/metacubex/sing-shadowsocks2 v0.2.6 h1:ZR1kYT0f0Vi64iQSS09OdhFfppiNkh7kjgRdMm0SB98=
github.com/metacubex/sing-shadowsocks2 v0.2.6/go.mod h1:vOEbfKC60txi0ca+yUlqEwOGc3Obl6cnSgx9Gf45KjE=
github.com/metacubex/sing-shadowtls v0.0.0-20250503063515-5d9f966d17a2 h1:gXU+MYPm7Wme3/OAY2FFzVq9d9GxPHOqu5AQfg/ddhI=
github.com/metacubex/sing-shadowtls v0.0.0-20250503063515-5d9f966d17a2/go.mod h1:mbfboaXauKJNIHJYxQRa+NJs4JU9NZfkA+I33dS2+9E=
github.com/metacubex/sing-tun v0.4.7-0.20250721020617-8e7c37ed3d97 h1:YYpc60UZE2G0pUeHbRw9erDrUDZrPQy8QzWFqA3kHsk=
github.com/metacubex/sing-tun v0.4.7-0.20250721020617-8e7c37ed3d97/go.mod h1:2YywXPWW8Z97kTH7RffOeykKzU+l0aiKlglWV1PAS64=
github.com/metacubex/sing-vmess v0.2.3 h1:QKLdIk5A2FcR3Y7m2/JO1XhfzgDA8tF4W9/ffsH9opo=
github.com/metacubex/sing-vmess v0.2.3/go.mod h1:21R5R1u90uUvBQF0owoooEu96/SAYYD56nDrwm6nFaM=
github.com/metacubex/sing-tun v0.4.7 h1:ZDY/W+1c7PeWWKeKRyUo18fySF/TWjB0i5ui81Ar778=
github.com/metacubex/sing-tun v0.4.7/go.mod h1:xHecZRwBnKWe6zG9amAK9cXf91lF6blgjBqm+VvOrmU=
github.com/metacubex/sing-vmess v0.2.4-0.20250822020810-4856053566f0 h1:WZepq4TOZa6WewB8tGAZrrL+bL2R2ivoBzuEgAeolWc=
github.com/metacubex/sing-vmess v0.2.4-0.20250822020810-4856053566f0/go.mod h1:21R5R1u90uUvBQF0owoooEu96/SAYYD56nDrwm6nFaM=
github.com/metacubex/sing-wireguard v0.0.0-20250503063753-2dc62acc626f h1:Sr/DYKYofKHKc4GF3qkRGNuj6XA6c0eqPgEDN+VAsYU=
github.com/metacubex/sing-wireguard v0.0.0-20250503063753-2dc62acc626f/go.mod h1:jpAkVLPnCpGSfNyVmj6Cq4YbuZsFepm/Dc+9BAOcR80=
github.com/metacubex/smux v0.0.0-20250503055512-501391591dee h1:lp6hJ+4wCLZu113awp7P6odM2okB5s60HUyF0FMqKmo=
github.com/metacubex/smux v0.0.0-20250503055512-501391591dee/go.mod h1:4bPD8HWx9jPJ9aE4uadgyN7D1/Wz3KmPy+vale8sKLE=
github.com/metacubex/tfo-go v0.0.0-20250516165257-e29c16ae41d4 h1:j1VRTiC9JLR4nUbSikx9OGdu/3AgFDqgcLj4GoqyQkc=
github.com/metacubex/tfo-go v0.0.0-20250516165257-e29c16ae41d4/go.mod h1:l9oLnLoEXyGZ5RVLsh7QCC5XsouTUyKk4F2nLm2DHLw=
github.com/metacubex/utls v1.8.0 h1:mSYi6FMnmc5riARl5UZDmWVy710z+P5b7xuGW0lV9ac=
github.com/metacubex/utls v1.8.0/go.mod h1:FdjYzVfCtgtna19hX0ER1Xsa5uJInwdQ4IcaaI98lEQ=
github.com/metacubex/wireguard-go v0.0.0-20240922131502-c182e7471181 h1:hJLQviGySBuaynlCwf/oYgIxbVbGRUIKZCxdya9YrbQ=
github.com/metacubex/wireguard-go v0.0.0-20240922131502-c182e7471181/go.mod h1:phewKljNYiTVT31Gcif8RiCKnTUOgVWFJjccqYM8s+Y=
github.com/metacubex/tfo-go v0.0.0-20250827083229-aa432b865617 h1:yN3mQ4cT9sPUciw/rO0Isc/8QlO86DB6g9SEMRgQ8Cw=
github.com/metacubex/tfo-go v0.0.0-20250827083229-aa432b865617/go.mod h1:l9oLnLoEXyGZ5RVLsh7QCC5XsouTUyKk4F2nLm2DHLw=
github.com/metacubex/utls v1.8.1-0.20250823120917-12f5ba126142 h1:csEbKOzRAxJXffOeZnnS3/kA/F55JiTbKv5jcYqCXms=
github.com/metacubex/utls v1.8.1-0.20250823120917-12f5ba126142/go.mod h1:67I3skhEY4Sya8f1YxELwWPoeQdXqZCrWNYLvq8gn2U=
github.com/metacubex/wireguard-go v0.0.0-20250820062549-a6cecdd7f57f h1:FGBPRb1zUabhPhDrlKEjQ9lgIwQ6cHL4x8M9lrERhbk=
github.com/metacubex/wireguard-go v0.0.0-20250820062549-a6cecdd7f57f/go.mod h1:oPGcV994OGJedmmxrcK9+ni7jUEMGhR+uVQAdaduIP4=
github.com/miekg/dns v1.1.63 h1:8M5aAw6OMZfFXTT7K5V0Eu5YiiL8l7nUAkyN6C9YwaY=
github.com/miekg/dns v1.1.63/go.mod h1:6NGHfjhpmr5lt3XPLuyfDJi5AXbNIPM9PY6H6sF1Nfs=
github.com/mroth/weightedrand/v2 v2.1.0 h1:o1ascnB1CIVzsqlfArQQjeMy1U0NcIbBO5rfd5E/OeU=
@@ -196,8 +196,8 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/stretchr/testify v1.11.0 h1:ib4sjIrwZKxE5u/Japgo/7SJV3PvgjGiRNAvTVGqQl8=
github.com/stretchr/testify v1.11.0/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFAEVmqU=
github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI=
github.com/tklauser/numcpus v0.6.1 h1:ng9scYS7az0Bk4OZLvrNXNSAO2Pxr1XXRAPyjhIx+Fk=
@@ -279,5 +279,3 @@ gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
lukechampine.com/blake3 v1.3.0 h1:sJ3XhFINmHSrYCgl958hscfIa3bw8x4DqMP3u1YvoYE=
lukechampine.com/blake3 v1.3.0/go.mod h1:0OFRp7fBtAylGVCO40o87sbupkyIGgbpv1+M1k1LM6k=
@@ -32,7 +32,11 @@ func upgradeCore(w http.ResponseWriter, r *http.Request) {
return
}
err = updater.DefaultCoreUpdater.Update(execPath)
query := r.URL.Query()
channel := query.Get("channel")
force := query.Get("force") == "true"
err = updater.DefaultCoreUpdater.Update(execPath, channel, force)
if err != nil {
log.Warnln("%s", err)
render.Status(r, http.StatusInternalServerError)
@@ -7,9 +7,9 @@ import (
"errors"
"net"
"strings"
"sync/atomic"
"github.com/metacubex/mihomo/adapter/inbound"
"github.com/metacubex/mihomo/common/atomic"
"github.com/metacubex/mihomo/common/buf"
"github.com/metacubex/mihomo/component/ca"
"github.com/metacubex/mihomo/component/ech"
@@ -31,7 +31,7 @@ type Listener struct {
listeners []net.Listener
tlsConfig *tlsC.Config
userMap map[[32]byte]string
padding atomic.TypedValue[*padding.PaddingFactory]
padding atomic.Pointer[padding.PaddingFactory]
}
func New(config LC.AnyTLSServer, tunnel C.Tunnel, additions ...inbound.Addition) (sl *Listener, err error) {
@@ -17,6 +17,7 @@ type VlessServer struct {
Enable bool
Listen string
Users []VlessUser
Decryption string
WsPath string
GrpcServiceName string
Certificate string
@@ -1,6 +1,7 @@
package inbound_test
import (
"bytes"
"context"
"crypto/rand"
"crypto/tls"
@@ -10,16 +11,18 @@ import (
"net"
"net/http"
"net/netip"
"strconv"
"sync"
"testing"
"time"
N "github.com/metacubex/mihomo/common/net"
"github.com/metacubex/mihomo/common/pool"
"github.com/metacubex/mihomo/common/utils"
"github.com/metacubex/mihomo/component/ca"
"github.com/metacubex/mihomo/component/dialer"
"github.com/metacubex/mihomo/component/ech"
"github.com/metacubex/mihomo/component/generater"
"github.com/metacubex/mihomo/component/generator"
tlsC "github.com/metacubex/mihomo/component/tls"
C "github.com/metacubex/mihomo/constant"
@@ -30,7 +33,7 @@ import (
)
var httpPath = "/inbound_test"
var httpData = make([]byte, 10240)
var httpData = make([]byte, 2*pool.RelayBufferSize)
var remoteAddr = netip.MustParseAddr("1.2.3.4")
var userUUID = utils.NewUUIDV4().String()
var tlsCertificate, tlsPrivateKey, tlsFingerprint, _ = ca.NewRandomTLSKeyPair(ca.KeyPairTypeP256)
@@ -46,13 +49,12 @@ var echConfigBase64, echKeyPem, _ = ech.GenECHConfig(echPublicSni)
func init() {
rand.Read(httpData)
privateKey, err := generater.GeneratePrivateKey()
privateKey, err := generator.GenX25519PrivateKey()
if err != nil {
panic(err)
}
publicKey := privateKey.PublicKey()
realityPrivateKey = base64.RawURLEncoding.EncodeToString(privateKey[:])
realityPublickey = base64.RawURLEncoding.EncodeToString(publicKey[:])
realityPrivateKey = base64.RawURLEncoding.EncodeToString(privateKey.Bytes())
realityPublickey = base64.RawURLEncoding.EncodeToString(privateKey.PublicKey().Bytes())
}
type TestTunnel struct {
@@ -134,14 +136,22 @@ func NewHttpTestTunnel() *TestTunnel {
r := chi.NewRouter()
r.Get(httpPath, func(w http.ResponseWriter, r *http.Request) {
render.Data(w, r, httpData)
query := r.URL.Query()
size, err := strconv.Atoi(query.Get("size"))
if err != nil {
render.Status(r, http.StatusBadRequest)
render.PlainText(w, r, err.Error())
return
}
io.Copy(io.Discard, r.Body)
render.Data(w, r, httpData[:size])
})
h2Server := &http2.Server{}
server := http.Server{Handler: r}
_ = http2.ConfigureServer(&server, h2Server)
go server.Serve(ln)
testFn := func(t *testing.T, proxy C.ProxyAdapter, proto string) {
req, err := http.NewRequest(http.MethodGet, fmt.Sprintf("%s://%s%s", proto, remoteAddr, httpPath), nil)
testFn := func(t *testing.T, proxy C.ProxyAdapter, proto string, size int) {
req, err := http.NewRequest(http.MethodGet, fmt.Sprintf("%s://%s%s?size=%d", proto, remoteAddr, httpPath, size), bytes.NewReader(httpData[:size]))
if !assert.NoError(t, err) {
return
}
@@ -200,7 +210,7 @@ func NewHttpTestTunnel() *TestTunnel {
if !assert.NoError(t, err) {
return
}
assert.Equal(t, httpData, data)
assert.Equal(t, httpData[:size], data)
}
tunnel := &TestTunnel{
HandleTCPConnFn: func(conn net.Conn, metadata *C.Metadata) {
@@ -241,27 +251,30 @@ func NewHttpTestTunnel() *TestTunnel {
},
CloseFn: ln.Close,
DoTestFn: func(t *testing.T, proxy C.ProxyAdapter) {
// Sequential testing for debugging
t.Run("Sequential", func(t *testing.T) {
testFn(t, proxy, "http")
testFn(t, proxy, "https")
testFn(t, proxy, "http", len(httpData))
testFn(t, proxy, "https", len(httpData))
})
// Concurrent testing to detect stress
t.Run("Concurrent", func(t *testing.T) {
wg := sync.WaitGroup{}
const num = 50
for i := 0; i < num; i++ {
num := len(httpData) / 1024
for i := 1; i <= num; i++ {
i := i
wg.Add(1)
go func() {
testFn(t, proxy, "https")
testFn(t, proxy, "https", i*1024)
defer wg.Done()
}()
}
for i := 0; i < num; i++ {
for i := 1; i <= num; i++ {
i := i
wg.Add(1)
go func() {
testFn(t, proxy, "http")
testFn(t, proxy, "http", i*1024)
defer wg.Done()
}()
}
@@ -8,7 +8,7 @@ import (
"github.com/stretchr/testify/assert"
)
var singMuxProtocolList = []string{"h2mux", "smux"} // don't test "yamux" because it has some confused bugs
var singMuxProtocolList = []string{"smux"} // don't test "h2mux" and "yamux" because it has some confused bugs
// notCloseProxyAdapter is a proxy adapter that does not close the underlying outbound.ProxyAdapter.
// The outbound.SingMux will close the underlying outbound.ProxyAdapter when it is closed, but we don't want to close it.
@@ -12,6 +12,7 @@ import (
type VlessOption struct {
BaseOption
Users []VlessUser `inbound:"users"`
Decryption string `inbound:"decryption,omitempty"`
WsPath string `inbound:"ws-path,omitempty"`
GrpcServiceName string `inbound:"grpc-service-name,omitempty"`
Certificate string `inbound:"certificate,omitempty"`
@@ -58,6 +59,7 @@ func NewVless(options *VlessOption) (*Vless, error) {
Enable: true,
Listen: base.RawAddress(),
Users: users,
Decryption: options.Decryption,
WsPath: options.WsPath,
GrpcServiceName: options.GrpcServiceName,
Certificate: options.Certificate,
@@ -7,6 +7,7 @@ import (
"github.com/metacubex/mihomo/adapter/outbound"
"github.com/metacubex/mihomo/listener/inbound"
"github.com/metacubex/mihomo/transport/vless/encryption"
"github.com/stretchr/testify/assert"
)
@@ -87,6 +88,41 @@ func TestInboundVless_TLS(t *testing.T) {
})
}
func TestInboundVless_Encryption(t *testing.T) {
seedBase64, clientBase64, _, err := encryption.GenMLKEM768("")
if err != nil {
t.Fatal(err)
return
}
privateKeyBase64, passwordBase64, _, err := encryption.GenX25519("")
if err != nil {
t.Fatal(err)
return
}
var modes = []string{
"native",
"xorpub",
"random",
}
for i := range modes {
mode := modes[i]
t.Run(mode, func(t *testing.T) {
inboundOptions := inbound.VlessOption{
Decryption: "mlkem768x25519plus." + mode + ".600s." + privateKeyBase64 + "." + seedBase64,
}
outboundOptions := outbound.VlessOption{
Encryption: "mlkem768x25519plus." + mode + ".0rtt." + passwordBase64 + "." + clientBase64,
}
testInboundVless(t, inboundOptions, outboundOptions)
t.Run("xtls-rprx-vision", func(t *testing.T) {
outboundOptions := outboundOptions
outboundOptions.Flow = "xtls-rprx-vision"
testInboundVless(t, inboundOptions, outboundOptions)
})
})
}
}
func TestInboundVless_Wss1(t *testing.T) {
inboundOptions := inbound.VlessOption{
Certificate: tlsCertificate,
@@ -113,3 +113,11 @@ func (c realityConnWrapper) Upstream() any {
func (c realityConnWrapper) CloseWrite() error {
return c.Close()
}
func (c realityConnWrapper) ReaderReplaceable() bool {
return true
}
func (c realityConnWrapper) WriterReplaceable() bool {
return true
}
@@ -16,6 +16,7 @@ import (
mux "github.com/metacubex/sing-mux"
vmess "github.com/metacubex/sing-vmess"
"github.com/metacubex/sing-vmess/packetaddr"
"github.com/metacubex/sing/common"
"github.com/metacubex/sing/common/buf"
"github.com/metacubex/sing/common/bufio"
@@ -145,6 +146,10 @@ func (h *ListenerHandler) NewConnection(ctx context.Context, conn net.Conn, meta
}
func (h *ListenerHandler) NewPacketConnection(ctx context.Context, conn network.PacketConn, metadata M.Metadata) error {
if metadata.Destination.Fqdn == packetaddr.SeqPacketMagicAddress {
conn = packetaddr.NewConn(bufio.NewNetPacketConn(conn), M.Socksaddr{})
}
defer func() { _ = conn.Close() }()
mutex := sync.Mutex{}
writer := bufio.NewNetPacketWriter(conn) // a new interface to set nil in defer
@@ -19,16 +19,18 @@ import (
"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 := common.Cast[*reality.Conn](conn) // *utls.Conn
tlsConn, loaded := network.CastReader[*reality.Conn](conn) // *utls.Conn
if !loaded {
return
}
@@ -36,19 +38,28 @@ func init() {
})
vless.RegisterTLS(func(conn net.Conn) (loaded bool, netConn net.Conn, reflectType reflect.Type, reflectPointer unsafe.Pointer) {
tlsConn, loaded := common.Cast[*tlsC.UConn](conn) // *utls.UConn
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]
closed bool
config LC.VlessServer
listeners []net.Listener
service *vless.Service[string]
decryption *encryption.ServerInstance
}
func New(config LC.VlessServer, tunnel C.Tunnel, additions ...inbound.Addition) (sl *Listener, err error) {
@@ -80,7 +91,20 @@ func New(config LC.VlessServer, tunnel C.Tunnel, additions ...inbound.Addition)
return it.Flow
}))
sl = &Listener{false, config, nil, service}
sl = &Listener{config: config, service: service}
sl.decryption, err = encryption.NewServer(config.Decryption)
if err != nil {
return nil, err
}
if sl.decryption != nil {
defer func() { // decryption must be closed to avoid the goroutine leak
if err != nil {
_ = sl.decryption.Close()
sl.decryption = nil
}
}()
}
tlsConfig := &tlsC.Config{}
var realityBuilder *reality.Builder
@@ -149,8 +173,8 @@ func New(config LC.VlessServer, tunnel C.Tunnel, additions ...inbound.Addition)
} else {
l = tlsC.NewListener(l, tlsConfig)
}
} else {
return nil, errors.New("disallow using Vless without both certificates/reality config")
} else if sl.decryption == nil {
return nil, errors.New("disallow using Vless without any certificates/reality/decryption config")
}
sl.listeners = append(sl.listeners, l)
@@ -185,6 +209,9 @@ func (l *Listener) Close() error {
retErr = err
}
}
if l.decryption != nil {
_ = l.decryption.Close()
}
return retErr
}
@@ -201,6 +228,13 @@ func (l *Listener) AddrList() (addrList []net.Addr) {
func (l *Listener) HandleConn(conn net.Conn, tunnel C.Tunnel, additions ...inbound.Addition) {
ctx := sing.WithAdditions(context.TODO(), additions...)
if l.decryption != nil {
var err error
conn, err = l.decryption.Handshake(conn)
if err != nil {
return
}
}
err := l.service.NewConnection(ctx, conn, metadata.Metadata{
Protocol: "vless",
Source: metadata.SocksaddrFromNet(conn.RemoteAddr()),
@@ -14,7 +14,7 @@ import (
"strings"
"syscall"
"github.com/metacubex/mihomo/component/generater"
"github.com/metacubex/mihomo/component/generator"
"github.com/metacubex/mihomo/component/geodata"
"github.com/metacubex/mihomo/component/updater"
"github.com/metacubex/mihomo/config"
@@ -73,7 +73,7 @@ func main() {
}
if len(os.Args) > 1 && os.Args[1] == "generate" {
generater.Main(os.Args[2:])
generator.Main(os.Args[2:])
return
}
@@ -5,9 +5,9 @@ import (
"crypto/sha256"
"encoding/binary"
"net"
"sync/atomic"
"time"
"github.com/metacubex/mihomo/common/atomic"
"github.com/metacubex/mihomo/common/buf"
"github.com/metacubex/mihomo/transport/anytls/padding"
"github.com/metacubex/mihomo/transport/anytls/session"
@@ -33,7 +33,7 @@ type Client struct {
dialer N.Dialer
server M.Socksaddr
sessionClient *session.Client
padding atomic.TypedValue[*padding.PaddingFactory]
padding atomic.Pointer[padding.PaddingFactory]
}
func NewClient(ctx context.Context, config ClientConfig) *Client {
@@ -7,8 +7,8 @@ import (
"math/big"
"strconv"
"strings"
"sync/atomic"
"github.com/metacubex/mihomo/common/atomic"
"github.com/metacubex/mihomo/transport/anytls/util"
)
@@ -31,7 +31,7 @@ type PaddingFactory struct {
Md5 string
}
func UpdatePaddingScheme(rawScheme []byte, to *atomic.TypedValue[*PaddingFactory]) bool {
func UpdatePaddingScheme(rawScheme []byte, to *atomic.Pointer[PaddingFactory]) bool {
if p := NewPaddingFactory(rawScheme); p != nil {
to.Store(p)
return true
@@ -7,9 +7,9 @@ import (
"math"
"net"
"sync"
"sync/atomic"
"time"
"github.com/metacubex/mihomo/common/atomic"
"github.com/metacubex/mihomo/transport/anytls/padding"
"github.com/metacubex/mihomo/transport/anytls/skiplist"
"github.com/metacubex/mihomo/transport/anytls/util"
@@ -29,13 +29,13 @@ type Client struct {
sessions map[uint64]*Session
sessionsLock sync.Mutex
padding *atomic.TypedValue[*padding.PaddingFactory]
padding *atomic.Pointer[padding.PaddingFactory]
idleSessionTimeout time.Duration
minIdleSession int
}
func NewClient(ctx context.Context, dialOut util.DialOutFunc, _padding *atomic.TypedValue[*padding.PaddingFactory], idleSessionCheckInterval, idleSessionTimeout time.Duration, minIdleSession int) *Client {
func NewClient(ctx context.Context, dialOut util.DialOutFunc, _padding *atomic.Pointer[padding.PaddingFactory], idleSessionCheckInterval, idleSessionTimeout time.Duration, minIdleSession int) *Client {
c := &Client{
sessions: make(map[uint64]*Session),
dialOut: dialOut,
@@ -9,9 +9,9 @@ import (
"runtime/debug"
"strconv"
"sync"
"sync/atomic"
"time"
"github.com/metacubex/mihomo/common/atomic"
"github.com/metacubex/mihomo/common/buf"
"github.com/metacubex/mihomo/common/pool"
"github.com/metacubex/mihomo/constant"
@@ -38,7 +38,7 @@ type Session struct {
// pool
seq uint64
idleSince time.Time
padding *atomic.TypedValue[*padding.PaddingFactory]
padding *atomic.Pointer[padding.PaddingFactory]
peerVersion byte
@@ -53,7 +53,7 @@ type Session struct {
onNewStream func(stream *Stream)
}
func NewClientSession(conn net.Conn, _padding *atomic.TypedValue[*padding.PaddingFactory]) *Session {
func NewClientSession(conn net.Conn, _padding *atomic.Pointer[padding.PaddingFactory]) *Session {
s := &Session{
conn: conn,
isClient: true,
@@ -65,7 +65,7 @@ func NewClientSession(conn net.Conn, _padding *atomic.TypedValue[*padding.Paddin
return s
}
func NewServerSession(conn net.Conn, onNewStream func(stream *Stream), _padding *atomic.TypedValue[*padding.PaddingFactory]) *Session {
func NewServerSession(conn net.Conn, onNewStream func(stream *Stream), _padding *atomic.Pointer[padding.PaddingFactory]) *Session {
s := &Session{
conn: conn,
onNewStream: onNewStream,
@@ -1,7 +1,6 @@
package core
import (
"bytes"
"context"
"errors"
"fmt"
@@ -16,7 +15,6 @@ import (
"github.com/metacubex/mihomo/transport/hysteria/transport"
"github.com/metacubex/mihomo/transport/hysteria/utils"
"github.com/lunixbochs/struc"
"github.com/metacubex/quic-go"
"github.com/metacubex/quic-go/congestion"
"github.com/metacubex/randv2"
@@ -104,31 +102,23 @@ func (c *Client) connectToServer(dialer utils.PacketDialer) error {
}
func (c *Client) handleControlStream(qs *quic.Conn, stream *quic.Stream) (bool, string, error) {
// Send protocol version
_, err := stream.Write([]byte{protocolVersion})
if err != nil {
return false, "", err
}
// Send client hello
err = struc.Pack(stream, &clientHello{
Rate: transmissionRate{
SendBPS: c.sendBPS,
RecvBPS: c.recvBPS,
},
Auth: c.auth,
err := WriteClientHello(stream, ClientHello{
SendBPS: c.sendBPS,
RecvBPS: c.recvBPS,
Auth: c.auth,
})
if err != nil {
return false, "", err
}
// Receive server hello
var sh serverHello
err = struc.Unpack(stream, &sh)
sh, err := ReadServerHello(stream)
if err != nil {
return false, "", err
}
// Set the congestion accordingly
if sh.OK && c.congestionFactory != nil {
qs.SetCongestionControl(c.congestionFactory(sh.Rate.RecvBPS))
qs.SetCongestionControl(c.congestionFactory(sh.RecvBPS))
}
return sh.OK, sh.Message, nil
}
@@ -140,7 +130,7 @@ func (c *Client) handleMessage(qs *quic.Conn) {
break
}
var udpMsg udpMessage
err = struc.Unpack(bytes.NewBuffer(msg), &udpMsg)
err = udpMsg.Unpack(msg)
if err != nil {
continue
}
@@ -200,7 +190,7 @@ func (c *Client) DialTCP(host string, port uint16, dialer utils.PacketDialer) (n
return nil, err
}
// Send request
err = struc.Pack(stream, &clientRequest{
err = WriteClientRequest(stream, ClientRequest{
UDP: false,
Host: host,
Port: port,
@@ -213,8 +203,8 @@ func (c *Client) DialTCP(host string, port uint16, dialer utils.PacketDialer) (n
// and defer the response handling to the first Read() call
if !c.fastOpen {
// Read response
var sr serverResponse
err = struc.Unpack(stream, &sr)
var sr *ServerResponse
sr, err = ReadServerResponse(stream)
if err != nil {
_ = stream.Close()
return nil, err
@@ -239,16 +229,16 @@ func (c *Client) DialUDP(dialer utils.PacketDialer) (UDPConn, error) {
return nil, err
}
// Send request
err = struc.Pack(stream, &clientRequest{
UDP: true,
err = WriteClientRequest(stream, ClientRequest{
UDP: false,
})
if err != nil {
_ = stream.Close()
return nil, err
}
// Read response
var sr serverResponse
err = struc.Unpack(stream, &sr)
var sr *ServerResponse
sr, err = ReadServerResponse(stream)
if err != nil {
_ = stream.Close()
return nil, err
@@ -306,8 +296,8 @@ type quicConn struct {
func (w *quicConn) Read(b []byte) (n int, err error) {
if !w.Established {
var sr serverResponse
err := struc.Unpack(w.Orig, &sr)
var sr *ServerResponse
sr, err = ReadServerResponse(w.Orig)
if err != nil {
_ = w.Close()
return 0, err
@@ -401,9 +391,7 @@ func (c *quicPktConn) WriteTo(p []byte, addr string) error {
Data: p,
}
// try no frag first
var msgBuf bytes.Buffer
_ = struc.Pack(&msgBuf, &msg)
err = c.Session.SendDatagram(msgBuf.Bytes())
err = c.Session.SendDatagram(msg.Pack())
if err != nil {
var errSize *quic.DatagramTooLargeError
if errors.As(err, &errSize) {
@@ -411,9 +399,7 @@ func (c *quicPktConn) WriteTo(p []byte, addr string) error {
msg.MsgID = uint16(randv2.IntN(0xFFFF)) + 1 // msgID must be > 0 when fragCount > 1
fragMsgs := fragUDPMessage(msg, int(errSize.MaxDatagramPayloadSize))
for _, fragMsg := range fragMsgs {
msgBuf.Reset()
_ = struc.Pack(&msgBuf, &fragMsg)
err = c.Session.SendDatagram(msgBuf.Bytes())
err = c.Session.SendDatagram(fragMsg.Pack())
if err != nil {
return err
}
@@ -18,7 +18,6 @@ func fragUDPMessage(m udpMessage, maxSize int) []udpMessage {
frag := m
frag.FragID = fragID
frag.FragCount = fragCount
frag.DataLen = uint16(payloadSize)
frag.Data = fullPayload[off : off+payloadSize]
frags = append(frags, frag)
off += payloadSize
@@ -56,7 +55,6 @@ func (d *defragger) Feed(m udpMessage) *udpMessage {
for _, frag := range d.frags {
data = append(data, frag.Data...)
}
m.DataLen = uint16(len(data))
m.Data = data
m.FragID = 0
m.FragCount = 1
@@ -20,13 +20,11 @@ func Test_fragUDPMessage(t *testing.T) {
args{
udpMessage{
SessionID: 123,
HostLen: 4,
Host: "test",
Port: 123,
MsgID: 123,
FragID: 0,
FragCount: 1,
DataLen: 5,
Data: []byte("hello"),
},
100,
@@ -34,13 +32,11 @@ func Test_fragUDPMessage(t *testing.T) {
[]udpMessage{
udpMessage{
SessionID: 123,
HostLen: 4,
Host: "test",
Port: 123,
MsgID: 123,
FragID: 0,
FragCount: 1,
DataLen: 5,
Data: []byte("hello"),
},
},
@@ -50,13 +46,11 @@ func Test_fragUDPMessage(t *testing.T) {
args{
udpMessage{
SessionID: 123,
HostLen: 4,
Host: "test",
Port: 123,
MsgID: 123,
FragID: 0,
FragCount: 1,
DataLen: 5,
Data: []byte("hello"),
},
22,
@@ -64,24 +58,20 @@ func Test_fragUDPMessage(t *testing.T) {
[]udpMessage{
udpMessage{
SessionID: 123,
HostLen: 4,
Host: "test",
Port: 123,
MsgID: 123,
FragID: 0,
FragCount: 2,
DataLen: 4,
Data: []byte("hell"),
},
udpMessage{
SessionID: 123,
HostLen: 4,
Host: "test",
Port: 123,
MsgID: 123,
FragID: 1,
FragCount: 2,
DataLen: 1,
Data: []byte("o"),
},
},
@@ -91,13 +81,11 @@ func Test_fragUDPMessage(t *testing.T) {
args{
udpMessage{
SessionID: 123,
HostLen: 4,
Host: "test",
Port: 123,
MsgID: 123,
FragID: 0,
FragCount: 1,
DataLen: 20,
Data: []byte("wow wow wow lol lmao"),
},
23,
@@ -105,46 +93,38 @@ func Test_fragUDPMessage(t *testing.T) {
[]udpMessage{
udpMessage{
SessionID: 123,
HostLen: 4,
Host: "test",
Port: 123,
MsgID: 123,
FragID: 0,
FragCount: 4,
DataLen: 5,
Data: []byte("wow w"),
},
udpMessage{
SessionID: 123,
HostLen: 4,
Host: "test",
Port: 123,
MsgID: 123,
FragID: 1,
FragCount: 4,
DataLen: 5,
Data: []byte("ow wo"),
},
udpMessage{
SessionID: 123,
HostLen: 4,
Host: "test",
Port: 123,
MsgID: 123,
FragID: 2,
FragCount: 4,
DataLen: 5,
Data: []byte("w lol"),
},
udpMessage{
SessionID: 123,
HostLen: 4,
Host: "test",
Port: 123,
MsgID: 123,
FragID: 3,
FragCount: 4,
DataLen: 5,
Data: []byte(" lmao"),
},
},
@@ -174,25 +154,21 @@ func Test_defragger_Feed(t *testing.T) {
args{
udpMessage{
SessionID: 123,
HostLen: 4,
Host: "test",
Port: 123,
MsgID: 123,
FragID: 0,
FragCount: 1,
DataLen: 5,
Data: []byte("hello"),
},
},
&udpMessage{
SessionID: 123,
HostLen: 4,
Host: "test",
Port: 123,
MsgID: 123,
FragID: 0,
FragCount: 1,
DataLen: 5,
Data: []byte("hello"),
},
},
@@ -201,13 +177,11 @@ func Test_defragger_Feed(t *testing.T) {
args{
udpMessage{
SessionID: 123,
HostLen: 4,
Host: "test",
Port: 123,
MsgID: 666,
FragID: 0,
FragCount: 3,
DataLen: 5,
Data: []byte("hello"),
},
},
@@ -218,13 +192,11 @@ func Test_defragger_Feed(t *testing.T) {
args{
udpMessage{
SessionID: 123,
HostLen: 4,
Host: "test",
Port: 123,
MsgID: 666,
FragID: 1,
FragCount: 3,
DataLen: 8,
Data: []byte(" shitty "),
},
},
@@ -235,25 +207,21 @@ func Test_defragger_Feed(t *testing.T) {
args{
udpMessage{
SessionID: 123,
HostLen: 4,
Host: "test",
Port: 123,
MsgID: 666,
FragID: 2,
FragCount: 3,
DataLen: 7,
Data: []byte("world!!"),
},
},
&udpMessage{
SessionID: 123,
HostLen: 4,
Host: "test",
Port: 123,
MsgID: 666,
FragID: 0,
FragCount: 1,
DataLen: 20,
Data: []byte("hello shitty world!!"),
},
},
@@ -262,13 +230,11 @@ func Test_defragger_Feed(t *testing.T) {
args{
udpMessage{
SessionID: 123,
HostLen: 4,
Host: "test",
Port: 123,
MsgID: 777,
FragID: 0,
FragCount: 2,
DataLen: 5,
Data: []byte("hello"),
},
},
@@ -279,13 +245,11 @@ func Test_defragger_Feed(t *testing.T) {
args{
udpMessage{
SessionID: 123,
HostLen: 4,
Host: "test",
Port: 123,
MsgID: 778,
FragID: 1,
FragCount: 2,
DataLen: 5,
Data: []byte(" moto"),
},
},
@@ -296,13 +260,11 @@ func Test_defragger_Feed(t *testing.T) {
args{
udpMessage{
SessionID: 123,
HostLen: 4,
Host: "test",
Port: 123,
MsgID: 777,
FragID: 1,
FragCount: 2,
DataLen: 5,
Data: []byte(" moto"),
},
},
@@ -313,25 +275,21 @@ func Test_defragger_Feed(t *testing.T) {
args{
udpMessage{
SessionID: 123,
HostLen: 4,
Host: "test",
Port: 123,
MsgID: 777,
FragID: 0,
FragCount: 2,
DataLen: 5,
Data: []byte("hello"),
},
},
&udpMessage{
SessionID: 123,
HostLen: 4,
Host: "test",
Port: 123,
MsgID: 777,
FragID: 0,
FragCount: 1,
DataLen: 10,
Data: []byte("hello moto"),
},
},
@@ -1,60 +1,241 @@
package core
import (
"bytes"
"encoding/binary"
"errors"
"io"
"time"
)
const (
protocolVersion = uint8(3)
protocolVersionV2 = uint8(2)
protocolTimeout = 10 * time.Second
protocolVersion = uint8(3)
protocolTimeout = 10 * time.Second
closeErrorCodeGeneric = 0
closeErrorCodeProtocol = 1
closeErrorCodeAuth = 2
)
type transmissionRate struct {
type ClientHello struct {
SendBPS uint64
RecvBPS uint64
}
type clientHello struct {
Rate transmissionRate
AuthLen uint16 `struc:"sizeof=Auth"`
Auth []byte
}
type serverHello struct {
OK bool
Rate transmissionRate
MessageLen uint16 `struc:"sizeof=Message"`
Message string
func WriteClientHello(stream io.Writer, hello ClientHello) error {
var requestLen int
requestLen += 1 // version
requestLen += 8 // sendBPS
requestLen += 8 // recvBPS
requestLen += 2 // auth len
requestLen += len(hello.Auth)
request := make([]byte, requestLen)
request[0] = protocolVersion
binary.BigEndian.PutUint64(request[1:9], hello.SendBPS)
binary.BigEndian.PutUint64(request[9:17], hello.RecvBPS)
binary.BigEndian.PutUint16(request[17:19], uint16(len(hello.Auth)))
copy(request[19:], hello.Auth)
_, err := stream.Write(request)
return err
}
type clientRequest struct {
UDP bool
HostLen uint16 `struc:"sizeof=Host"`
Host string
Port uint16
func ReadClientHello(stream io.Reader) (*ClientHello, error) {
var responseLen int
responseLen += 1 // ok
responseLen += 8 // sendBPS
responseLen += 8 // recvBPS
responseLen += 2 // auth len
response := make([]byte, responseLen)
_, err := io.ReadFull(stream, response)
if err != nil {
return nil, err
}
if response[0] != protocolVersion {
return nil, errors.New("unsupported client version")
}
var clientHello ClientHello
clientHello.SendBPS = binary.BigEndian.Uint64(response[1:9])
clientHello.RecvBPS = binary.BigEndian.Uint64(response[9:17])
authLen := binary.BigEndian.Uint16(response[17:19])
if clientHello.SendBPS == 0 || clientHello.RecvBPS == 0 {
return nil, errors.New("invalid rate from client")
}
authBytes := make([]byte, authLen)
_, err = io.ReadFull(stream, authBytes)
if err != nil {
return nil, err
}
clientHello.Auth = authBytes
return &clientHello, nil
}
type serverResponse struct {
type ServerHello struct {
OK bool
SendBPS uint64
RecvBPS uint64
Message string
}
func ReadServerHello(stream io.Reader) (*ServerHello, error) {
var responseLen int
responseLen += 1 // ok
responseLen += 8 // sendBPS
responseLen += 8 // recvBPS
responseLen += 2 // message len
response := make([]byte, responseLen)
_, err := io.ReadFull(stream, response)
if err != nil {
return nil, err
}
var serverHello ServerHello
serverHello.OK = response[0] == 1
serverHello.SendBPS = binary.BigEndian.Uint64(response[1:9])
serverHello.RecvBPS = binary.BigEndian.Uint64(response[9:17])
messageLen := binary.BigEndian.Uint16(response[17:19])
if messageLen == 0 {
return &serverHello, nil
}
message := make([]byte, messageLen)
_, err = io.ReadFull(stream, message)
if err != nil {
return nil, err
}
serverHello.Message = string(message)
return &serverHello, nil
}
func WriteServerHello(stream io.Writer, hello ServerHello) error {
var responseLen int
responseLen += 1 // ok
responseLen += 8 // sendBPS
responseLen += 8 // recvBPS
responseLen += 2 // message len
responseLen += len(hello.Message)
response := make([]byte, responseLen)
if hello.OK {
response[0] = 1
} else {
response[0] = 0
}
binary.BigEndian.PutUint64(response[1:9], hello.SendBPS)
binary.BigEndian.PutUint64(response[9:17], hello.RecvBPS)
binary.BigEndian.PutUint16(response[17:19], uint16(len(hello.Message)))
copy(response[19:], hello.Message)
_, err := stream.Write(response)
return err
}
type ClientRequest struct {
UDP bool
Host string
Port uint16
}
func ReadClientRequest(stream io.Reader) (*ClientRequest, error) {
var clientRequest ClientRequest
err := binary.Read(stream, binary.BigEndian, &clientRequest.UDP)
if err != nil {
return nil, err
}
var hostLen uint16
err = binary.Read(stream, binary.BigEndian, &hostLen)
if err != nil {
return nil, err
}
host := make([]byte, hostLen)
_, err = io.ReadFull(stream, host)
if err != nil {
return nil, err
}
clientRequest.Host = string(host)
err = binary.Read(stream, binary.BigEndian, &clientRequest.Port)
if err != nil {
return nil, err
}
return &clientRequest, nil
}
func WriteClientRequest(stream io.Writer, request ClientRequest) error {
var requestLen int
requestLen += 1 // udp
requestLen += 2 // host len
requestLen += len(request.Host)
requestLen += 2 // port
buffer := make([]byte, requestLen)
if request.UDP {
buffer[0] = 1
} else {
buffer[0] = 0
}
binary.BigEndian.PutUint16(buffer[1:3], uint16(len(request.Host)))
n := copy(buffer[3:], request.Host)
binary.BigEndian.PutUint16(buffer[3+n:3+n+2], request.Port)
_, err := stream.Write(buffer)
return err
}
type ServerResponse struct {
OK bool
UDPSessionID uint32
MessageLen uint16 `struc:"sizeof=Message"`
Message string
}
func ReadServerResponse(stream io.Reader) (*ServerResponse, error) {
var responseLen int
responseLen += 1 // ok
responseLen += 4 // udp session id
responseLen += 2 // message len
response := make([]byte, responseLen)
_, err := io.ReadFull(stream, response)
if err != nil {
return nil, err
}
var serverResponse ServerResponse
serverResponse.OK = response[0] == 1
serverResponse.UDPSessionID = binary.BigEndian.Uint32(response[1:5])
messageLen := binary.BigEndian.Uint16(response[5:7])
if messageLen == 0 {
return &serverResponse, nil
}
message := make([]byte, messageLen)
_, err = io.ReadFull(stream, message)
if err != nil {
return nil, err
}
serverResponse.Message = string(message)
return &serverResponse, nil
}
func WriteServerResponse(stream io.Writer, response ServerResponse) error {
var responseLen int
responseLen += 1 // ok
responseLen += 4 // udp session id
responseLen += 2 // message len
responseLen += len(response.Message)
buffer := make([]byte, responseLen)
if response.OK {
buffer[0] = 1
} else {
buffer[0] = 0
}
binary.BigEndian.PutUint32(buffer[1:5], response.UDPSessionID)
binary.BigEndian.PutUint16(buffer[5:7], uint16(len(response.Message)))
copy(buffer[7:], response.Message)
_, err := stream.Write(buffer)
return err
}
type udpMessage struct {
SessionID uint32
HostLen uint16 `struc:"sizeof=Host"`
Host string
Port uint16
MsgID uint16 // doesn't matter when not fragmented, but must not be 0 when fragmented
FragID uint8 // doesn't matter when not fragmented, starts at 0 when fragmented
FragCount uint8 // must be 1 when not fragmented
DataLen uint16 `struc:"sizeof=Data"`
Data []byte
}
@@ -66,11 +247,62 @@ func (m udpMessage) Size() int {
return m.HeaderSize() + len(m.Data)
}
type udpMessageV2 struct {
SessionID uint32
HostLen uint16 `struc:"sizeof=Host"`
Host string
Port uint16
DataLen uint16 `struc:"sizeof=Data"`
Data []byte
func (m udpMessage) Pack() []byte {
data := make([]byte, m.Size())
buffer := bytes.NewBuffer(data)
_ = binary.Write(buffer, binary.BigEndian, m.SessionID)
_ = binary.Write(buffer, binary.BigEndian, uint16(len(m.Host)))
buffer.WriteString(m.Host)
_ = binary.Write(buffer, binary.BigEndian, m.Port)
_ = binary.Write(buffer, binary.BigEndian, m.MsgID)
_ = binary.Write(buffer, binary.BigEndian, m.FragID)
_ = binary.Write(buffer, binary.BigEndian, m.FragCount)
_ = binary.Write(buffer, binary.BigEndian, uint16(len(m.Data)))
buffer.Write(m.Data)
return buffer.Bytes()
}
func (m *udpMessage) Unpack(data []byte) error {
reader := bytes.NewReader(data)
err := binary.Read(reader, binary.BigEndian, &m.SessionID)
if err != nil {
return err
}
var hostLen uint16
err = binary.Read(reader, binary.BigEndian, &hostLen)
if err != nil {
return err
}
hostBytes := make([]byte, hostLen)
_, err = io.ReadFull(reader, hostBytes)
if err != nil {
return err
}
m.Host = string(hostBytes)
err = binary.Read(reader, binary.BigEndian, &m.Port)
if err != nil {
return err
}
err = binary.Read(reader, binary.BigEndian, &m.MsgID)
if err != nil {
return err
}
err = binary.Read(reader, binary.BigEndian, &m.FragID)
if err != nil {
return err
}
err = binary.Read(reader, binary.BigEndian, &m.FragCount)
if err != nil {
return err
}
var dataLen uint16
err = binary.Read(reader, binary.BigEndian, &dataLen)
if err != nil {
return err
}
if reader.Len() != int(dataLen) {
return errors.New("invalid data length")
}
m.Data = data[len(data)-reader.Len():]
return nil
}
@@ -4,7 +4,7 @@ import (
"context"
"net"
tls "github.com/3andne/restls-client-go"
tls "github.com/metacubex/restls-client-go"
)
const (
@@ -8,8 +8,8 @@ import (
"net/netip"
"strconv"
"github.com/metacubex/blake3"
"github.com/metacubex/quic-go"
"lukechampine.com/blake3"
C "github.com/metacubex/mihomo/constant"
"github.com/metacubex/mihomo/transport/socks5"
@@ -30,26 +30,22 @@ type Conn struct {
}
func (vc *Conn) Read(b []byte) (int, error) {
if vc.received {
return vc.ExtendedReader.Read(b)
if !vc.received {
if err := vc.recvResponse(); err != nil {
return 0, err
}
vc.received = true
}
if err := vc.recvResponse(); err != nil {
return 0, err
}
vc.received = true
return vc.ExtendedReader.Read(b)
}
func (vc *Conn) ReadBuffer(buffer *buf.Buffer) error {
if vc.received {
return vc.ExtendedReader.ReadBuffer(buffer)
if !vc.received {
if err := vc.recvResponse(); err != nil {
return err
}
vc.received = true
}
if err := vc.recvResponse(); err != nil {
return err
}
vc.received = true
return vc.ExtendedReader.ReadBuffer(buffer)
}
@@ -105,26 +101,20 @@ func (vc *Conn) sendRequest(p []byte) bool {
}
}
var buffer *buf.Buffer
if vc.IsXTLSVisionEnabled() {
buffer = buf.New()
defer buffer.Release()
} else {
requestLen := 1 // protocol version
requestLen += 16 // UUID
requestLen += 1 // addons length
requestLen += len(addonsBytes)
requestLen += 1 // command
if !vc.dst.Mux {
requestLen += 2 // port
requestLen += 1 // addr type
requestLen += len(vc.dst.Addr)
}
requestLen += len(p)
buffer = buf.NewSize(requestLen)
defer buffer.Release()
requestLen := 1 // protocol version
requestLen += 16 // UUID
requestLen += 1 // addons length
requestLen += len(addonsBytes)
requestLen += 1 // command
if !vc.dst.Mux {
requestLen += 2 // port
requestLen += 1 // addr type
requestLen += len(vc.dst.Addr)
}
requestLen += len(p)
buffer := buf.NewSize(requestLen)
defer buffer.Release()
buf.Must(
buffer.WriteByte(Version), // protocol version
@@ -182,10 +172,6 @@ func (vc *Conn) NeedHandshake() bool {
return vc.needHandshake
}
func (vc *Conn) IsXTLSVisionEnabled() bool {
return vc.addons != nil && vc.addons.Flow == XRV
}
// newConn return a Conn instance
func newConn(conn net.Conn, client *Client, dst *DstAddr) (net.Conn, error) {
c := &Conn{
@@ -200,7 +186,7 @@ func newConn(conn net.Conn, client *Client, dst *DstAddr) (net.Conn, error) {
if client.Addons != nil {
switch client.Addons.Flow {
case XRV:
visionConn, err := vision.NewConn(c, c.id)
visionConn, err := vision.NewConn(c, conn, c.id)
if err != nil {
return nil, err
}
@@ -0,0 +1,201 @@
package encryption
import (
"crypto/cipher"
"crypto/ecdh"
"crypto/rand"
"errors"
"io"
"net"
"sync"
"time"
"github.com/metacubex/blake3"
"github.com/metacubex/utls/mlkem"
)
type ClientInstance struct {
NfsPKeys []any
NfsPKeysBytes [][]byte
Hash32s [][32]byte
RelaysLength int
XorMode uint32
Seconds uint32
RWLock sync.RWMutex
Expire time.Time
PfsKey []byte
Ticket []byte
}
func (i *ClientInstance) Init(nfsPKeysBytes [][]byte, xorMode, seconds uint32) (err error) {
if i.NfsPKeys != nil {
err = errors.New("already initialized")
return
}
l := len(nfsPKeysBytes)
if l == 0 {
err = errors.New("empty nfsPKeysBytes")
return
}
i.NfsPKeys = make([]any, l)
i.NfsPKeysBytes = nfsPKeysBytes
i.Hash32s = make([][32]byte, l)
for j, k := range nfsPKeysBytes {
if len(k) == 32 {
if i.NfsPKeys[j], err = ecdh.X25519().NewPublicKey(k); err != nil {
return
}
i.RelaysLength += 32 + 32
} else {
if i.NfsPKeys[j], err = mlkem.NewEncapsulationKey768(k); err != nil {
return
}
i.RelaysLength += 1088 + 32
}
i.Hash32s[j] = blake3.Sum256(k)
}
i.RelaysLength -= 32
i.XorMode = xorMode
i.Seconds = seconds
return
}
func (i *ClientInstance) Handshake(conn net.Conn) (*CommonConn, error) {
if i.NfsPKeys == nil {
return nil, errors.New("uninitialized")
}
c := &CommonConn{Conn: conn}
ivAndRealysLength := 16 + i.RelaysLength
pfsKeyExchangeLength := 18 + 1184 + 32 + 16
paddingLength := int(randBetween(100, 1000))
clientHello := make([]byte, ivAndRealysLength+pfsKeyExchangeLength+paddingLength)
iv := clientHello[:16]
rand.Read(iv)
relays := clientHello[16:ivAndRealysLength]
var nfsKey []byte
var lastCTR cipher.Stream
for j, k := range i.NfsPKeys {
var index = 32
if k, ok := k.(*ecdh.PublicKey); ok {
privateKey, _ := ecdh.X25519().GenerateKey(rand.Reader)
copy(relays, privateKey.PublicKey().Bytes())
var err error
nfsKey, err = privateKey.ECDH(k)
if err != nil {
return nil, err
}
}
if k, ok := k.(*mlkem.EncapsulationKey768); ok {
var ciphertext []byte
nfsKey, ciphertext = k.Encapsulate()
copy(relays, ciphertext)
index = 1088
}
if i.XorMode > 0 { // this xor can (others can't) be recovered by client's config, revealing an X25519 public key / ML-KEM-768 ciphertext, that's why "native" values
NewCTR(i.NfsPKeysBytes[j], iv).XORKeyStream(relays, relays[:index]) // make X25519 public key / ML-KEM-768 ciphertext distinguishable from random bytes
}
if lastCTR != nil {
lastCTR.XORKeyStream(relays, relays[:32]) // make this relay irreplaceable
}
if j == len(i.NfsPKeys)-1 {
break
}
lastCTR = NewCTR(nfsKey, iv)
lastCTR.XORKeyStream(relays[index:], i.Hash32s[j+1][:])
relays = relays[index+32:]
}
nfsGCM := NewGCM(iv, nfsKey)
if i.Seconds > 0 {
i.RWLock.RLock()
if time.Now().Before(i.Expire) {
c.Client = i
c.UnitedKey = append(i.PfsKey, nfsKey...) // different unitedKey for each connection
nfsGCM.Seal(clientHello[:ivAndRealysLength], nil, EncodeLength(32), nil)
nfsGCM.Seal(clientHello[:ivAndRealysLength+18], nil, i.Ticket, nil)
i.RWLock.RUnlock()
c.PreWrite = clientHello[:ivAndRealysLength+18+32]
c.GCM = NewGCM(clientHello[ivAndRealysLength+18:ivAndRealysLength+18+32], c.UnitedKey)
if i.XorMode == 2 {
c.Conn = NewXorConn(conn, NewCTR(c.UnitedKey, iv), nil, len(c.PreWrite), 16)
}
return c, nil
}
i.RWLock.RUnlock()
}
pfsKeyExchange := clientHello[ivAndRealysLength : ivAndRealysLength+pfsKeyExchangeLength]
nfsGCM.Seal(pfsKeyExchange[:0], nil, EncodeLength(pfsKeyExchangeLength-18), nil)
mlkem768DKey, _ := mlkem.GenerateKey768()
x25519SKey, _ := ecdh.X25519().GenerateKey(rand.Reader)
pfsPublicKey := append(mlkem768DKey.EncapsulationKey().Bytes(), x25519SKey.PublicKey().Bytes()...)
nfsGCM.Seal(pfsKeyExchange[:18], nil, pfsPublicKey, nil)
padding := clientHello[ivAndRealysLength+pfsKeyExchangeLength:]
nfsGCM.Seal(padding[:0], nil, EncodeLength(paddingLength-18), nil)
nfsGCM.Seal(padding[:18], nil, padding[18:paddingLength-16], nil)
if _, err := conn.Write(clientHello); err != nil {
return nil, err
}
// padding can be sent in a fragmented way, to create variable traffic pattern, before inner VLESS flow takes control
encryptedPfsPublicKey := make([]byte, 1088+32+16)
if _, err := io.ReadFull(conn, encryptedPfsPublicKey); err != nil {
return nil, err
}
nfsGCM.Open(encryptedPfsPublicKey[:0], MaxNonce, encryptedPfsPublicKey, nil)
mlkem768Key, err := mlkem768DKey.Decapsulate(encryptedPfsPublicKey[:1088])
if err != nil {
return nil, err
}
peerX25519PKey, err := ecdh.X25519().NewPublicKey(encryptedPfsPublicKey[1088 : 1088+32])
if err != nil {
return nil, err
}
x25519Key, err := x25519SKey.ECDH(peerX25519PKey)
if err != nil {
return nil, err
}
pfsKey := make([]byte, 32+32) // no more capacity
copy(pfsKey, mlkem768Key)
copy(pfsKey[32:], x25519Key)
c.UnitedKey = append(pfsKey, nfsKey...)
c.GCM = NewGCM(pfsPublicKey, c.UnitedKey)
c.PeerGCM = NewGCM(encryptedPfsPublicKey[:1088+32], c.UnitedKey)
encryptedTicket := make([]byte, 32)
if _, err := io.ReadFull(conn, encryptedTicket); err != nil {
return nil, err
}
if _, err := c.PeerGCM.Open(encryptedTicket[:0], nil, encryptedTicket, nil); err != nil {
return nil, err
}
seconds := DecodeLength(encryptedTicket)
if i.Seconds > 0 && seconds > 0 {
i.RWLock.Lock()
i.Expire = time.Now().Add(time.Duration(seconds) * time.Second)
i.PfsKey = pfsKey
i.Ticket = encryptedTicket[:16]
i.RWLock.Unlock()
}
encryptedLength := make([]byte, 18)
if _, err := io.ReadFull(conn, encryptedLength); err != nil {
return nil, err
}
if _, err := c.PeerGCM.Open(encryptedLength[:0], nil, encryptedLength, nil); err != nil {
return nil, err
}
length := DecodeLength(encryptedLength[:2])
c.PeerPadding = make([]byte, length) // important: allows server sends padding slowly, eliminating 1-RTT's traffic pattern
if i.XorMode == 2 {
c.Conn = NewXorConn(conn, NewCTR(c.UnitedKey, iv), NewCTR(c.UnitedKey, encryptedTicket[:16]), 0, length)
}
return c, nil
}
@@ -0,0 +1,220 @@
package encryption
import (
"bytes"
"crypto/aes"
"crypto/cipher"
"crypto/rand"
"errors"
"fmt"
"io"
"math/big"
"net"
"strings"
"time"
"github.com/metacubex/blake3"
)
type CommonConn struct {
net.Conn
Client *ClientInstance
UnitedKey []byte
PreWrite []byte
GCM *GCM
PeerPadding []byte
PeerGCM *GCM
input bytes.Reader // PeerCache
}
func (c *CommonConn) Write(b []byte) (int, error) {
if len(b) == 0 {
return 0, nil
}
var data []byte
for n := 0; n < len(b); {
b := b[n:]
if len(b) > 8192 {
b = b[:8192] // for avoiding another copy() in peer's Read()
}
n += len(b)
data = make([]byte, 5+len(b)+16)
EncodeHeader(data, len(b)+16)
max := false
if bytes.Equal(c.GCM.Nonce[:], MaxNonce) {
max = true
}
c.GCM.Seal(data[:5], nil, b, data[:5])
if max {
c.GCM = NewGCM(data[5:], c.UnitedKey)
}
if c.PreWrite != nil {
data = append(c.PreWrite, data...)
c.PreWrite = nil
}
if _, err := c.Conn.Write(data); err != nil {
return 0, err
}
}
return len(b), nil
}
func (c *CommonConn) Read(b []byte) (int, error) {
if len(b) == 0 {
return 0, nil
}
if c.PeerGCM == nil { // client's 0-RTT
serverRandom := make([]byte, 16)
if _, err := io.ReadFull(c.Conn, serverRandom); err != nil {
return 0, err
}
c.PeerGCM = NewGCM(serverRandom, c.UnitedKey)
if xorConn, ok := c.Conn.(*XorConn); ok {
xorConn.PeerCTR = NewCTR(c.UnitedKey, serverRandom)
}
}
if c.PeerPadding != nil { // client's 1-RTT
if _, err := io.ReadFull(c.Conn, c.PeerPadding); err != nil {
return 0, err
}
if _, err := c.PeerGCM.Open(c.PeerPadding[:0], nil, c.PeerPadding, nil); err != nil {
return 0, err
}
c.PeerPadding = nil
}
if c.input.Len() > 0 {
return c.input.Read(b)
}
h, l, err := ReadAndDecodeHeader(c.Conn) // l: 17~17000
if err != nil {
if c.Client != nil && strings.HasPrefix(err.Error(), "invalid header: ") { // client's 0-RTT
c.Client.RWLock.Lock()
if bytes.HasPrefix(c.UnitedKey, c.Client.PfsKey) {
c.Client.Expire = time.Now() // expired
}
c.Client.RWLock.Unlock()
return 0, errors.New("new handshake needed")
}
return 0, err
}
c.Client = nil
peerData := make([]byte, l)
if _, err := io.ReadFull(c.Conn, peerData); err != nil {
return 0, err
}
dst := peerData[:l-16]
if len(dst) <= len(b) {
dst = b[:len(dst)] // avoids another copy()
}
var newGCM *GCM
if bytes.Equal(c.PeerGCM.Nonce[:], MaxNonce) {
newGCM = NewGCM(peerData, c.UnitedKey)
}
_, err = c.PeerGCM.Open(dst[:0], nil, peerData, h)
if newGCM != nil {
c.PeerGCM = newGCM
}
if err != nil {
return 0, err
}
if len(dst) > len(b) {
c.input.Reset(dst[copy(b, dst):])
dst = b // for len(dst)
}
return len(dst), nil
}
type GCM struct {
cipher.AEAD
Nonce [12]byte
}
func NewGCM(ctx, key []byte) *GCM {
k := make([]byte, 32)
blake3.DeriveKey(k, string(ctx), key)
block, _ := aes.NewCipher(k)
aead, _ := cipher.NewGCM(block)
return &GCM{AEAD: aead}
//chacha20poly1305.New()
}
func (a *GCM) Seal(dst, nonce, plaintext, additionalData []byte) []byte {
if nonce == nil {
nonce = IncreaseNonce(a.Nonce[:])
}
return a.AEAD.Seal(dst, nonce, plaintext, additionalData)
}
func (a *GCM) Open(dst, nonce, ciphertext, additionalData []byte) ([]byte, error) {
if nonce == nil {
nonce = IncreaseNonce(a.Nonce[:])
}
return a.AEAD.Open(dst, nonce, ciphertext, additionalData)
}
func IncreaseNonce(nonce []byte) []byte {
for i := 0; i < 12; i++ {
nonce[11-i]++
if nonce[11-i] != 0 {
break
}
}
return nonce
}
var MaxNonce = bytes.Repeat([]byte{255}, 12)
func EncodeLength(l int) []byte {
return []byte{byte(l >> 8), byte(l)}
}
func DecodeLength(b []byte) int {
return int(b[0])<<8 | int(b[1])
}
func EncodeHeader(h []byte, l int) {
h[0] = 23
h[1] = 3
h[2] = 3
h[3] = byte(l >> 8)
h[4] = byte(l)
}
func DecodeHeader(h []byte) (l int, err error) {
l = int(h[3])<<8 | int(h[4])
if h[0] != 23 || h[1] != 3 || h[2] != 3 {
l = 0
}
if l < 17 || l > 17000 { // TODO: TLSv1.3 max length
err = fmt.Errorf("invalid header: %v", h[:5]) // DO NOT CHANGE: relied by client's Read()
}
return
}
func ReadAndDecodeHeader(conn net.Conn) (h []byte, l int, err error) {
h = make([]byte, 5)
if _, err = io.ReadFull(conn, h); err != nil {
return
}
l, err = DecodeHeader(h)
return
}
func ReadAndDiscardPaddings(conn net.Conn) (h []byte, l int, err error) {
for {
if h, l, err = ReadAndDecodeHeader(conn); err != nil {
return
}
if _, err = io.ReadFull(conn, make([]byte, l)); err != nil {
return
}
}
}
func randBetween(from int64, to int64) int64 {
if from == to {
return from
}
bigInt, _ := rand.Int(rand.Reader, big.NewInt(to-from))
return from + bigInt.Int64()
}
@@ -0,0 +1,23 @@
// Package encryption copy and modify from xray-core
// https://github.com/XTLS/Xray-core/commit/f61c14e9c63dc41a8a09135db3aea337974f3f37
// https://github.com/XTLS/Xray-core/commit/3e19bf9233bdd9bafc073a71c65b737cc1ffba5e
// https://github.com/XTLS/Xray-core/commit/7ffb555fc8ec51bd1e3e60f26f1d6957984dba80
// https://github.com/XTLS/Xray-core/commit/ec1cc35188c1a5f38a2ff75e88b5d043ffdc59da
// https://github.com/XTLS/Xray-core/commit/5c611420487a92f931faefc01d4bf03869f477f6
// https://github.com/XTLS/Xray-core/commit/23d7aad461d232bc5bed52dd6aaa731ecd88ad35
// https://github.com/XTLS/Xray-core/commit/3c20bddfcfd8999be5f9a2ac180dc959950e4c61
// https://github.com/XTLS/Xray-core/commit/1720be168fa069332c418503d30341fc6e01df7f
// https://github.com/XTLS/Xray-core/commit/0fd7691d6b28e05922d7a5a9313d97745a51ea63
// https://github.com/XTLS/Xray-core/commit/09cc92c61d9067e0d65c1cae9124664ecfc78f43
// https://github.com/XTLS/Xray-core/commit/2807ee432a1fbeb301815647189eacd650b12a8b
// https://github.com/XTLS/Xray-core/commit/bfe4820f2f086daf639b1957eb23dc13c843cad1
// https://github.com/XTLS/Xray-core/commit/d1fb48521271251a8c74bd64fcc2fc8700717a3b
// https://github.com/XTLS/Xray-core/commit/49580705f6029648399304b816a2737f991582a8
// https://github.com/XTLS/Xray-core/commit/84835bec7d0d8555d0dd30953ed26a272de814c4
// https://github.com/XTLS/Xray-core/commit/373558ed7abdbac3de41745cf30ec04c9adde604
// https://github.com/XTLS/Xray-core/commit/38cc306c955c362f044e074049a5e67b6b9fb389
// https://github.com/XTLS/Xray-core/commit/b33555cc0a52d0af3c23d2af8fca42f8a685d9af
// https://github.com/XTLS/Xray-core/commit/ad7140641c44239c9dcdc3d7215ea639b1f0841c
// https://github.com/XTLS/Xray-core/commit/0199dea39988a1a1b846d0bf8598631bade40902
// https://github.com/XTLS/Xray-core/commit/fce1195b60f48ca18a953dbd5c7d991869de9a5e
package encryption
@@ -0,0 +1,104 @@
package encryption
import (
"encoding/base64"
"fmt"
"strconv"
"strings"
)
// NewClient new client from encryption string
// maybe return a nil *ClientInstance without any error, that means don't need to encrypt
func NewClient(encryption string) (*ClientInstance, error) {
switch encryption {
case "", "none": // We will not reject empty string like xray-core does, because we need to ensure compatibility
return nil, nil
}
if s := strings.Split(encryption, "."); len(s) >= 4 && s[0] == "mlkem768x25519plus" {
var xorMode uint32
switch s[1] {
case "native":
case "xorpub":
xorMode = 1
case "random":
xorMode = 2
default:
return nil, fmt.Errorf("invaild vless encryption value: %s", encryption)
}
var seconds uint32
switch s[2] {
case "1rtt":
case "0rtt":
seconds = 1
default:
return nil, fmt.Errorf("invaild vless encryption value: %s", encryption)
}
var nfsPKeysBytes [][]byte
for _, r := range s[3:] {
b, err := base64.RawURLEncoding.DecodeString(r)
if err != nil {
return nil, fmt.Errorf("invaild vless encryption value: %s", encryption)
}
if len(b) != X25519PasswordSize && len(b) != MLKEM768ClientLength {
return nil, fmt.Errorf("invaild vless encryption value: %s", encryption)
}
nfsPKeysBytes = append(nfsPKeysBytes, b)
}
client := &ClientInstance{}
if err := client.Init(nfsPKeysBytes, xorMode, seconds); err != nil {
return nil, fmt.Errorf("failed to use encryption: %w", err)
}
return client, nil
}
return nil, fmt.Errorf("invaild vless encryption value: %s", encryption)
}
// NewServer new server from decryption string
// maybe return a nil *ServerInstance without any error, that means don't need to decrypt
func NewServer(decryption string) (*ServerInstance, error) {
switch decryption {
case "", "none": // We will not reject empty string like xray-core does, because we need to ensure compatibility
return nil, nil
}
if s := strings.Split(decryption, "."); len(s) >= 4 && s[0] == "mlkem768x25519plus" {
var xorMode uint32
switch s[1] {
case "native":
case "xorpub":
xorMode = 1
case "random":
xorMode = 2
default:
return nil, fmt.Errorf("invaild vless decryption value: %s", decryption)
}
var seconds uint32
if s[2] != "1rtt" {
t := strings.TrimSuffix(s[2], "s")
if t == s[0] {
return nil, fmt.Errorf("invaild vless decryption value: %s", decryption)
}
i, err := strconv.Atoi(t)
if err != nil {
return nil, fmt.Errorf("invaild vless decryption value: %s", decryption)
}
seconds = uint32(i)
}
var nfsSKeysBytes [][]byte
for _, r := range s[3:] {
b, err := base64.RawURLEncoding.DecodeString(r)
if err != nil {
return nil, fmt.Errorf("invaild vless decryption value: %s", decryption)
}
if len(b) != X25519PrivateKeySize && len(b) != MLKEM768SeedLength {
return nil, fmt.Errorf("invaild vless decryption value: %s", decryption)
}
nfsSKeysBytes = append(nfsSKeysBytes, b)
}
server := &ServerInstance{}
if err := server.Init(nfsSKeysBytes, xorMode, seconds); err != nil {
return nil, fmt.Errorf("failed to use decryption: %w", err)
}
return server, nil
}
return nil, fmt.Errorf("invaild vless decryption value: %s", decryption)
}
@@ -0,0 +1,79 @@
package encryption
import (
"crypto/ecdh"
"crypto/rand"
"encoding/base64"
"fmt"
"github.com/metacubex/blake3"
"github.com/metacubex/utls/mlkem"
)
const MLKEM768SeedLength = mlkem.SeedSize
const MLKEM768ClientLength = mlkem.EncapsulationKeySize768
const X25519PasswordSize = 32
const X25519PrivateKeySize = 32
func GenMLKEM768(seedStr string) (seedBase64, clientBase64, hash32Base64 string, err error) {
var seed [MLKEM768SeedLength]byte
if len(seedStr) > 0 {
s, _ := base64.RawURLEncoding.DecodeString(seedStr)
if len(s) != MLKEM768SeedLength {
err = fmt.Errorf("invalid length of ML-KEM-768 seed: %s", seedStr)
return
}
seed = [MLKEM768SeedLength]byte(s)
} else {
_, err = rand.Read(seed[:])
if err != nil {
return
}
}
key, _ := mlkem.NewDecapsulationKey768(seed[:])
client := key.EncapsulationKey().Bytes()
hash32 := blake3.Sum256(client)
seedBase64 = base64.RawURLEncoding.EncodeToString(seed[:])
clientBase64 = base64.RawURLEncoding.EncodeToString(client)
hash32Base64 = base64.RawURLEncoding.EncodeToString(hash32[:])
return
}
func GenX25519(privateKeyStr string) (privateKeyBase64, passwordBase64, hash32Base64 string, err error) {
var privateKey [X25519PrivateKeySize]byte
if len(privateKeyStr) > 0 {
s, _ := base64.RawURLEncoding.DecodeString(privateKeyStr)
if len(s) != X25519PrivateKeySize {
err = fmt.Errorf("invalid length of X25519 private key: %s", privateKeyStr)
return
}
privateKey = [X25519PrivateKeySize]byte(s)
} else {
_, err = rand.Read(privateKey[:])
if err != nil {
return
}
}
// Avoid generating equivalent X25519 private keys
// https://github.com/XTLS/Xray-core/pull/1747
//
// Modify random bytes using algorithm described at:
// https://cr.yp.to/ecdh.html.
privateKey[0] &= 248
privateKey[31] &= 127
privateKey[31] |= 64
key, err := ecdh.X25519().NewPrivateKey(privateKey[:])
if err != nil {
fmt.Println(err.Error())
return
}
password := key.PublicKey().Bytes()
hash32 := blake3.Sum256(password)
privateKeyBase64 = base64.RawURLEncoding.EncodeToString(privateKey[:])
passwordBase64 = base64.RawURLEncoding.EncodeToString(password)
hash32Base64 = base64.RawURLEncoding.EncodeToString(hash32[:])
return
}
@@ -0,0 +1,281 @@
package encryption
import (
"bytes"
"crypto/cipher"
"crypto/ecdh"
"crypto/rand"
"errors"
"fmt"
"io"
"net"
"sync"
"time"
"github.com/metacubex/blake3"
"github.com/metacubex/utls/mlkem"
)
type ServerSession struct {
Expire time.Time
PfsKey []byte
NfsKeys sync.Map
}
type ServerInstance struct {
NfsSKeys []any
NfsPKeysBytes [][]byte
Hash32s [][32]byte
RelaysLength int
XorMode uint32
Seconds uint32
RWLock sync.RWMutex
Sessions map[[16]byte]*ServerSession
Closed bool
}
func (i *ServerInstance) Init(nfsSKeysBytes [][]byte, xorMode, seconds uint32) (err error) {
if i.NfsSKeys != nil {
err = errors.New("already initialized")
return
}
l := len(nfsSKeysBytes)
if l == 0 {
err = errors.New("empty nfsSKeysBytes")
return
}
i.NfsSKeys = make([]any, l)
i.NfsPKeysBytes = make([][]byte, l)
i.Hash32s = make([][32]byte, l)
for j, k := range nfsSKeysBytes {
if len(k) == 32 {
if i.NfsSKeys[j], err = ecdh.X25519().NewPrivateKey(k); err != nil {
return
}
i.NfsPKeysBytes[j] = i.NfsSKeys[j].(*ecdh.PrivateKey).PublicKey().Bytes()
i.RelaysLength += 32 + 32
} else {
if i.NfsSKeys[j], err = mlkem.NewDecapsulationKey768(k); err != nil {
return
}
i.NfsPKeysBytes[j] = i.NfsSKeys[j].(*mlkem.DecapsulationKey768).EncapsulationKey().Bytes()
i.RelaysLength += 1088 + 32
}
i.Hash32s[j] = blake3.Sum256(i.NfsPKeysBytes[j])
}
i.RelaysLength -= 32
i.XorMode = xorMode
if seconds > 0 {
i.Seconds = seconds
i.Sessions = make(map[[16]byte]*ServerSession)
go func() {
for {
time.Sleep(time.Minute)
i.RWLock.Lock()
if i.Closed {
i.RWLock.Unlock()
return
}
now := time.Now()
for ticket, session := range i.Sessions {
if now.After(session.Expire) {
delete(i.Sessions, ticket)
}
}
i.RWLock.Unlock()
}
}()
}
return
}
func (i *ServerInstance) Close() (err error) {
i.RWLock.Lock()
i.Closed = true
i.RWLock.Unlock()
return
}
func (i *ServerInstance) Handshake(conn net.Conn) (*CommonConn, error) {
if i.NfsSKeys == nil {
return nil, errors.New("uninitialized")
}
c := &CommonConn{Conn: conn}
ivAndRelays := make([]byte, 16+i.RelaysLength)
if _, err := io.ReadFull(conn, ivAndRelays); err != nil {
return nil, err
}
iv := ivAndRelays[:16]
relays := ivAndRelays[16:]
var nfsKey []byte
var lastCTR cipher.Stream
for j, k := range i.NfsSKeys {
if lastCTR != nil {
lastCTR.XORKeyStream(relays, relays[:32]) // recover this relay
}
var index = 32
if _, ok := k.(*mlkem.DecapsulationKey768); ok {
index = 1088
}
if i.XorMode > 0 {
NewCTR(i.NfsPKeysBytes[j], iv).XORKeyStream(relays, relays[:index]) // we don't use buggy elligator, because we have PSK :)
}
if k, ok := k.(*ecdh.PrivateKey); ok {
publicKey, err := ecdh.X25519().NewPublicKey(relays[:index])
if err != nil {
return nil, err
}
nfsKey, err = k.ECDH(publicKey)
if err != nil {
return nil, err
}
}
if k, ok := k.(*mlkem.DecapsulationKey768); ok {
var err error
nfsKey, err = k.Decapsulate(relays[:index])
if err != nil {
return nil, err
}
}
if j == len(i.NfsSKeys)-1 {
break
}
relays = relays[index:]
lastCTR = NewCTR(nfsKey, iv)
lastCTR.XORKeyStream(relays, relays[:32])
if !bytes.Equal(relays[:32], i.Hash32s[j+1][:]) {
return nil, fmt.Errorf("unexpected hash32: %v", relays[:32])
}
relays = relays[32:]
}
nfsGCM := NewGCM(iv, nfsKey)
encryptedLength := make([]byte, 18)
if _, err := io.ReadFull(conn, encryptedLength); err != nil {
return nil, err
}
if _, err := nfsGCM.Open(encryptedLength[:0], nil, encryptedLength, nil); err != nil {
return nil, err
}
length := DecodeLength(encryptedLength[:2])
if length == 32 {
if i.Seconds == 0 {
return nil, errors.New("0-RTT is not allowed")
}
encryptedTicket := make([]byte, 32)
if _, err := io.ReadFull(conn, encryptedTicket); err != nil {
return nil, err
}
ticket, err := nfsGCM.Open(nil, nil, encryptedTicket, nil)
if err != nil {
return nil, err
}
i.RWLock.RLock()
s := i.Sessions[[16]byte(ticket)]
i.RWLock.RUnlock()
if s == nil {
noises := make([]byte, randBetween(1268, 2268)) // matches 1-RTT's server hello length for "random", though it is not important, just for example
var err error
for err == nil {
rand.Read(noises)
_, err = DecodeHeader(noises)
}
conn.Write(noises) // make client do new handshake
return nil, errors.New("expired ticket")
}
if _, loaded := s.NfsKeys.LoadOrStore([32]byte(nfsKey), true); loaded { // prevents bad client also
return nil, errors.New("replay detected")
}
c.UnitedKey = append(s.PfsKey, nfsKey...) // the same nfsKey links the upload & download (prevents server -> client's another request)
c.PreWrite = make([]byte, 16)
rand.Read(c.PreWrite) // always trust yourself, not the client (also prevents being parsed as TLS thus causing false interruption for "native" and "xorpub")
c.GCM = NewGCM(c.PreWrite, c.UnitedKey)
c.PeerGCM = NewGCM(encryptedTicket, c.UnitedKey) // unchangeable ctx (prevents server -> server), and different ctx length for upload / download (prevents client -> client)
if i.XorMode == 2 {
c.Conn = NewXorConn(conn, NewCTR(c.UnitedKey, c.PreWrite), NewCTR(c.UnitedKey, iv), 16, 0) // it doesn't matter if the attacker sends client's iv back to the client
}
return c, nil
}
if length < 1184+32+16 { // client may send more public keys in the future's version
return nil, errors.New("too short length")
}
encryptedPfsPublicKey := make([]byte, length)
if _, err := io.ReadFull(conn, encryptedPfsPublicKey); err != nil {
return nil, err
}
if _, err := nfsGCM.Open(encryptedPfsPublicKey[:0], nil, encryptedPfsPublicKey, nil); err != nil {
return nil, err
}
mlkem768EKey, err := mlkem.NewEncapsulationKey768(encryptedPfsPublicKey[:1184])
if err != nil {
return nil, err
}
mlkem768Key, encapsulatedPfsKey := mlkem768EKey.Encapsulate()
peerX25519PKey, err := ecdh.X25519().NewPublicKey(encryptedPfsPublicKey[1184 : 1184+32])
if err != nil {
return nil, err
}
x25519SKey, _ := ecdh.X25519().GenerateKey(rand.Reader)
x25519Key, err := x25519SKey.ECDH(peerX25519PKey)
if err != nil {
return nil, err
}
pfsKey := make([]byte, 32+32) // no more capacity
copy(pfsKey, mlkem768Key)
copy(pfsKey[32:], x25519Key)
pfsPublicKey := append(encapsulatedPfsKey, x25519SKey.PublicKey().Bytes()...)
c.UnitedKey = append(pfsKey, nfsKey...)
c.GCM = NewGCM(pfsPublicKey, c.UnitedKey)
c.PeerGCM = NewGCM(encryptedPfsPublicKey[:1184+32], c.UnitedKey)
ticket := make([]byte, 16)
rand.Read(ticket)
copy(ticket, EncodeLength(int(i.Seconds*4/5)))
pfsKeyExchangeLength := 1088 + 32 + 16
encryptedTicketLength := 32
paddingLength := int(randBetween(100, 1000))
serverHello := make([]byte, pfsKeyExchangeLength+encryptedTicketLength+paddingLength)
nfsGCM.Seal(serverHello[:0], MaxNonce, pfsPublicKey, nil)
c.GCM.Seal(serverHello[:pfsKeyExchangeLength], nil, ticket, nil)
padding := serverHello[pfsKeyExchangeLength+encryptedTicketLength:]
c.GCM.Seal(padding[:0], nil, EncodeLength(paddingLength-18), nil)
c.GCM.Seal(padding[:18], nil, padding[18:paddingLength-16], nil)
if _, err := conn.Write(serverHello); err != nil {
return nil, err
}
// padding can be sent in a fragmented way, to create variable traffic pattern, before inner VLESS flow takes control
if i.Seconds > 0 {
i.RWLock.Lock()
i.Sessions[[16]byte(ticket)] = &ServerSession{
Expire: time.Now().Add(time.Duration(i.Seconds) * time.Second),
PfsKey: pfsKey,
}
i.RWLock.Unlock()
}
// important: allows client sends padding slowly, eliminating 1-RTT's traffic pattern
if _, err := io.ReadFull(conn, encryptedLength); err != nil {
return nil, err
}
if _, err := nfsGCM.Open(encryptedLength[:0], nil, encryptedLength, nil); err != nil {
return nil, err
}
encryptedPadding := make([]byte, DecodeLength(encryptedLength[:2]))
if _, err := io.ReadFull(conn, encryptedPadding); err != nil {
return nil, err
}
if _, err := nfsGCM.Open(encryptedPadding[:0], nil, encryptedPadding, nil); err != nil {
return nil, err
}
if i.XorMode == 2 {
c.Conn = NewXorConn(conn, NewCTR(c.UnitedKey, ticket), NewCTR(c.UnitedKey, iv), 0, 0)
}
return c, nil
}
@@ -0,0 +1,93 @@
package encryption
import (
"crypto/aes"
"crypto/cipher"
"net"
"github.com/metacubex/blake3"
)
func NewCTR(key, iv []byte) cipher.Stream {
k := make([]byte, 32)
blake3.DeriveKey(k, "VLESS", key) // avoids using key directly
block, _ := aes.NewCipher(k)
return cipher.NewCTR(block, iv)
//chacha20.NewUnauthenticatedCipher()
}
type XorConn struct {
net.Conn
CTR cipher.Stream
PeerCTR cipher.Stream
OutSkip int
OutHeader []byte
InSkip int
InHeader []byte
}
func NewXorConn(conn net.Conn, ctr, peerCTR cipher.Stream, outSkip, inSkip int) *XorConn {
return &XorConn{
Conn: conn,
CTR: ctr,
PeerCTR: peerCTR,
OutSkip: outSkip,
OutHeader: make([]byte, 0, 5), // important
InSkip: inSkip,
InHeader: make([]byte, 0, 5), // important
}
}
func (c *XorConn) Write(b []byte) (int, error) {
if len(b) == 0 {
return 0, nil
}
for p := b; ; {
if len(p) <= c.OutSkip {
c.OutSkip -= len(p)
break
}
p = p[c.OutSkip:]
c.OutSkip = 0
need := 5 - len(c.OutHeader)
if len(p) < need {
c.OutHeader = append(c.OutHeader, p...)
c.CTR.XORKeyStream(p, p)
break
}
c.OutSkip, _ = DecodeHeader(append(c.OutHeader, p[:need]...))
c.OutHeader = c.OutHeader[:0]
c.CTR.XORKeyStream(p[:need], p[:need])
p = p[need:]
}
if _, err := c.Conn.Write(b); err != nil {
return 0, err
}
return len(b), nil
}
func (c *XorConn) Read(b []byte) (int, error) {
if len(b) == 0 {
return 0, nil
}
n, err := c.Conn.Read(b)
for p := b[:n]; ; {
if len(p) <= c.InSkip {
c.InSkip -= len(p)
break
}
p = p[c.InSkip:]
c.InSkip = 0
need := 5 - len(c.InHeader)
if len(p) < need {
c.PeerCTR.XORKeyStream(p, p)
c.InHeader = append(c.InHeader, p...)
break
}
c.PeerCTR.XORKeyStream(p[:need], p[:need])
c.InSkip, _ = DecodeHeader(append(c.InHeader, p[:need]...))
c.InHeader = c.InHeader[:0]
p = p[need:]
}
return n, err
}
@@ -0,0 +1,57 @@
package vless
import (
"encoding/binary"
"io"
"net"
"github.com/metacubex/mihomo/common/pool"
)
type PacketConn struct {
net.Conn
rAddr net.Addr
}
func (c *PacketConn) WriteTo(b []byte, addr net.Addr) (int, error) {
err := binary.Write(c.Conn, binary.BigEndian, uint16(len(b)))
if err != nil {
return 0, err
}
return c.Conn.Write(b)
}
func (c *PacketConn) ReadFrom(b []byte) (int, net.Addr, error) {
var length uint16
err := binary.Read(c.Conn, binary.BigEndian, &length)
if err != nil {
return 0, nil, err
}
if len(b) < int(length) {
return 0, nil, io.ErrShortBuffer
}
n, err := io.ReadFull(c.Conn, b[:length])
return n, c.rAddr, err
}
func (c *PacketConn) WaitReadFrom() (data []byte, put func(), addr net.Addr, err error) {
var length uint16
err = binary.Read(c.Conn, binary.BigEndian, &length)
if err != nil {
return
}
readBuf := pool.Get(int(length))
put = func() {
_ = pool.Put(readBuf)
}
n, err := io.ReadFull(c.Conn, readBuf)
if err != nil {
put()
put = nil
return
}
data = readBuf[:n]
addr = c.rAddr
return
}
@@ -3,7 +3,6 @@ package vision
import (
"bytes"
"crypto/subtle"
gotls "crypto/tls"
"encoding/binary"
"errors"
"fmt"
@@ -12,7 +11,6 @@ import (
"github.com/metacubex/mihomo/common/buf"
N "github.com/metacubex/mihomo/common/net"
tlsC "github.com/metacubex/mihomo/component/tls"
"github.com/metacubex/mihomo/log"
"github.com/gofrs/uuid/v5"
@@ -23,15 +21,16 @@ var (
)
type Conn struct {
net.Conn
net.Conn // should be *vless.Conn
N.ExtendedReader
N.ExtendedWriter
upstream net.Conn
userUUID *uuid.UUID
tlsConn net.Conn
input *bytes.Reader
rawInput *bytes.Buffer
// tlsConn and it's internal variables
tlsConn net.Conn // maybe [*tls.Conn] or other tls-like conn
netConn net.Conn // tlsConn.NetConn()
input *bytes.Reader // &tlsConn.input or nil
rawInput *bytes.Buffer // &tlsConn.rawInput or nil
needHandshake bool
packetsToFilter int
@@ -145,7 +144,7 @@ func (vc *Conn) ReadBuffer(buffer *buf.Buffer) error {
}
if vc.input == nil && vc.rawInput == nil {
vc.readProcess = false
vc.ExtendedReader = N.NewExtendedReader(vc.Conn)
vc.ExtendedReader = N.NewExtendedReader(vc.netConn)
log.Debugln("XTLS Vision direct read start")
}
if needReturn {
@@ -171,7 +170,7 @@ func (vc *Conn) WriteBuffer(buffer *buf.Buffer) (err error) {
if vc.needHandshake {
vc.needHandshake = false
if buffer.IsEmpty() {
ApplyPadding(buffer, commandPaddingContinue, vc.userUUID, false)
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)
@@ -181,72 +180,47 @@ func (vc *Conn) WriteBuffer(buffer *buf.Buffer) (err error) {
buffer.Release()
return err
}
switch underlying := vc.tlsConn.(type) {
case *gotls.Conn:
if underlying.ConnectionState().Version != gotls.VersionTLS13 {
buffer.Release()
return ErrNotTLS13
}
case *tlsC.UConn:
if underlying.ConnectionState().Version != tlsC.VersionTLS13 {
buffer.Release()
return ErrNotTLS13
}
err = vc.checkTLSVersion()
if err != nil {
buffer.Release()
return err
}
vc.tlsConn = nil
return nil
}
if vc.writeFilterApplicationData {
buffer2 := ReshapeBuffer(buffer)
defer buffer2.Release()
vc.FilterTLS(buffer.Bytes())
command := commandPaddingContinue
if !vc.isTLS {
command = commandPaddingEnd
// disable XTLS
//vc.readProcess = false
vc.writeFilterApplicationData = false
vc.packetsToFilter = 0
} else if buffer.Len() > 6 && bytes.Equal(buffer.To(3), tlsApplicationDataStart) || vc.packetsToFilter <= 0 {
command = commandPaddingEnd
if vc.enableXTLS {
command = commandPaddingDirect
vc.writeDirect = true
}
vc.writeFilterApplicationData = false
}
ApplyPadding(buffer, command, nil, vc.isTLS)
err = vc.ExtendedWriter.WriteBuffer(buffer)
if err != nil {
return err
}
if vc.writeDirect {
vc.ExtendedWriter = N.NewExtendedWriter(vc.Conn)
log.Debugln("XTLS Vision direct write start")
//time.Sleep(5 * time.Millisecond)
}
if buffer2 != nil {
if vc.writeDirect || !vc.isTLS {
return vc.ExtendedWriter.WriteBuffer(buffer2)
}
vc.FilterTLS(buffer2.Bytes())
command = commandPaddingContinue
if buffer2.Len() > 6 && bytes.Equal(buffer2.To(3), tlsApplicationDataStart) || vc.packetsToFilter <= 0 {
command = commandPaddingEnd
if vc.enableXTLS {
command = commandPaddingDirect
vc.writeDirect = true
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) {
command = commandPaddingEnd
if vc.enableXTLS {
command = commandPaddingDirect
vc.writeDirect = true
}
vc.writeFilterApplicationData = false
applyPadding = false
} else if !vc.isTLS12orAbove && vc.packetsToFilter <= 1 {
command = commandPaddingEnd
vc.writeFilterApplicationData = false
applyPadding = false
}
vc.writeFilterApplicationData = false
ApplyPadding(buffer, command, nil, vc.isTLS)
}
ApplyPadding(buffer2, command, nil, vc.isTLS)
err = vc.ExtendedWriter.WriteBuffer(buffer2)
if vc.writeDirect {
vc.ExtendedWriter = N.NewExtendedWriter(vc.Conn)
err = vc.ExtendedWriter.WriteBuffer(buffer)
if err != nil {
buf.ReleaseMulti(buffers[i:]) // release unwritten buffers
return
}
if command == commandPaddingDirect {
vc.ExtendedWriter = N.NewExtendedWriter(vc.netConn)
log.Debugln("XTLS Vision direct write start")
//time.Sleep(10 * time.Millisecond)
//time.Sleep(5 * time.Millisecond)
}
}
return err
@@ -275,9 +249,9 @@ func (vc *Conn) NeedHandshake() bool {
func (vc *Conn) Upstream() any {
if vc.writeDirect ||
vc.readLastCommand == commandPaddingDirect {
return vc.Conn
return vc.netConn
}
return vc.upstream
return vc.Conn
}
func (vc *Conn) ReaderPossiblyReplaceable() bool {
@@ -302,3 +276,10 @@ func (vc *Conn) WriterReplaceable() bool {
}
return false
}
func (vc *Conn) Close() error {
if vc.ReaderReplaceable() || vc.WriterReplaceable() { // ignore send closeNotify alert in tls.Conn
return vc.netConn.Close()
}
return vc.Conn.Close()
}
@@ -6,6 +6,7 @@ import (
"github.com/metacubex/mihomo/common/buf"
"github.com/metacubex/mihomo/log"
N "github.com/metacubex/sing/common/network"
"github.com/gofrs/uuid/v5"
"github.com/metacubex/randv2"
@@ -19,30 +20,6 @@ const (
commandPaddingDirect byte = 0x02
)
func WriteWithPadding(buffer *buf.Buffer, p []byte, command byte, userUUID *uuid.UUID, paddingTLS bool) {
contentLen := int32(len(p))
var paddingLen int32
if contentLen < 900 {
if paddingTLS {
//log.Debugln("long padding")
paddingLen = randv2.Int32N(500) + 900 - contentLen
} else {
paddingLen = randv2.Int32N(256)
}
}
if userUUID != nil {
buffer.Write(userUUID.Bytes())
}
buffer.WriteByte(command)
binary.BigEndian.PutUint16(buffer.Extend(2), uint16(contentLen))
binary.BigEndian.PutUint16(buffer.Extend(2), uint16(paddingLen))
buffer.Write(p)
buffer.Extend(int(paddingLen))
log.Debugln("XTLS Vision write padding1: command=%v, payloadLen=%v, paddingLen=%v", command, contentLen, paddingLen)
}
func ApplyPadding(buffer *buf.Buffer, command byte, userUUID *uuid.UUID, paddingTLS bool) {
contentLen := int32(buffer.Len())
var paddingLen int32
@@ -63,19 +40,20 @@ func ApplyPadding(buffer *buf.Buffer, command byte, userUUID *uuid.UUID, padding
}
buffer.Extend(int(paddingLen))
log.Debugln("XTLS Vision write padding2: command=%d, payloadLen=%d, paddingLen=%d", command, contentLen, paddingLen)
log.Debugln("XTLS Vision write padding: command=%d, payloadLen=%d, paddingLen=%d", command, contentLen, paddingLen)
}
func ReshapeBuffer(buffer *buf.Buffer) *buf.Buffer {
if buffer.Len() <= buf.BufferSize-PaddingHeaderLen {
return nil
func (vc *Conn) ReshapeBuffer(buffer *buf.Buffer) []*buf.Buffer {
const xrayBufSize = 8192
if buffer.Len() <= xrayBufSize-PaddingHeaderLen {
return []*buf.Buffer{buffer}
}
cutAt := bytes.LastIndex(buffer.Bytes(), tlsApplicationDataStart)
if cutAt == -1 {
cutAt = buf.BufferSize / 2
cutAt = xrayBufSize / 2
}
buffer2 := buf.New()
buffer2 := N.NewReadWaitOptions(nil, vc).NewBuffer() // ensure the new buffer can send used in vc.WriteBuffer
buffer2.Write(buffer.From(cutAt))
buffer.Truncate(cutAt)
return buffer2
return []*buf.Buffer{buffer, buffer2}
}
@@ -12,24 +12,20 @@ import (
N "github.com/metacubex/mihomo/common/net"
tlsC "github.com/metacubex/mihomo/component/tls"
"github.com/metacubex/mihomo/transport/vless/encryption"
"github.com/gofrs/uuid/v5"
"github.com/metacubex/sing/common"
)
var ErrNotTLS13 = errors.New("XTLS Vision based on TLS 1.3 outer connection")
type connWithUpstream interface {
net.Conn
common.WithUpstream
}
func NewConn(conn connWithUpstream, 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),
upstream: conn,
Conn: conn,
userUUID: userUUID,
tlsConn: tlsConn,
packetsToFilter: 6,
needHandshake: true,
readProcess: true,
@@ -38,32 +34,54 @@ func NewConn(conn connWithUpstream, userUUID *uuid.UUID) (*Conn, error) {
}
var t reflect.Type
var p unsafe.Pointer
switch underlying := conn.Upstream().(type) {
switch underlying := tlsConn.(type) {
case *gotls.Conn:
//log.Debugln("type tls")
c.Conn = underlying.NetConn()
c.tlsConn = underlying
c.netConn = underlying.NetConn()
t = reflect.TypeOf(underlying).Elem()
p = unsafe.Pointer(underlying)
case *tlsC.Conn:
//log.Debugln("type *tlsC.Conn")
c.Conn = underlying.NetConn()
c.tlsConn = underlying
c.netConn = underlying.NetConn()
t = reflect.TypeOf(underlying).Elem()
p = unsafe.Pointer(underlying)
case *tlsC.UConn:
//log.Debugln("type *tlsC.UConn")
c.Conn = underlying.NetConn()
c.tlsConn = underlying
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:
return nil, fmt.Errorf(`failed to use vision, maybe "security" is not "tls" or "utls"`)
}
i, _ := t.FieldByName("input")
r, _ := t.FieldByName("rawInput")
c.input = (*bytes.Reader)(unsafe.Add(p, i.Offset))
c.rawInput = (*bytes.Buffer)(unsafe.Add(p, r.Offset))
if i, ok := t.FieldByName("input"); ok {
c.input = (*bytes.Reader)(unsafe.Add(p, i.Offset))
}
if r, ok := t.FieldByName("rawInput"); ok {
c.rawInput = (*bytes.Buffer)(unsafe.Add(p, r.Offset))
}
return c, nil
}
func (vc *Conn) checkTLSVersion() error {
switch underlying := vc.tlsConn.(type) {
case *gotls.Conn:
if underlying.ConnectionState().Version != gotls.VersionTLS13 {
return ErrNotTLS13
}
case *tlsC.Conn:
if underlying.ConnectionState().Version != tlsC.VersionTLS13 {
return ErrNotTLS13
}
case *tlsC.UConn:
if underlying.ConnectionState().Version != tlsC.VersionTLS13 {
return ErrNotTLS13
}
}
return nil
}
@@ -51,6 +51,10 @@ func (c *Client) StreamConn(conn net.Conn, dst *DstAddr) (net.Conn, error) {
return newConn(conn, c, dst)
}
func (c *Client) PacketConn(conn net.Conn, rAddr net.Addr) net.PacketConn {
return &PacketConn{conn, rAddr}
}
// NewClient return Client instance
func NewClient(uuidStr string, addons *Addons) (*Client, error) {
uid, err := utils.UUIDMap(uuidStr)
+17 -18
View File
@@ -5,7 +5,6 @@ go 1.20
require cfa v0.0.0
require (
github.com/3andne/restls-client-go v0.1.6 // indirect
github.com/RyuaNerin/go-krypto v1.3.0 // indirect
github.com/Yawning/aez v0.0.0-20211027044916-e49e68abd344 // indirect
github.com/ajg/form v1.5.1 // indirect
@@ -14,15 +13,15 @@ require (
github.com/buger/jsonparser v1.1.1 // indirect
github.com/coreos/go-iptables v0.8.0 // indirect
github.com/dlclark/regexp2 v1.11.5 // indirect
github.com/ebitengine/purego v0.8.3 // indirect
github.com/enfein/mieru/v3 v3.16.1 // indirect
github.com/ebitengine/purego v0.8.4 // indirect
github.com/enfein/mieru/v3 v3.19.1 // indirect
github.com/ericlagergren/aegis v0.0.0-20250325060835-cd0defd64358 // indirect
github.com/ericlagergren/polyval v0.0.0-20220411101811-e25bc10ba391 // indirect
github.com/ericlagergren/siv v0.0.0-20220507050439-0b757b3aa5f1 // indirect
github.com/ericlagergren/subtle v0.0.0-20220507045147-890d697da010 // indirect
github.com/fsnotify/fsnotify v1.9.0 // indirect
github.com/gaukas/godicttls v0.0.4 // indirect
github.com/go-chi/chi/v5 v5.2.2 // indirect
github.com/go-chi/chi/v5 v5.2.3 // indirect
github.com/go-chi/render v1.0.3 // indirect
github.com/go-ole/go-ole v1.3.0 // indirect
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect
@@ -37,36 +36,37 @@ require (
github.com/insomniacslk/dhcp v0.0.0-20250109001534-8abf58130905 // indirect
github.com/josharian/native v1.1.0 // indirect
github.com/klauspost/compress v1.17.9 // indirect
github.com/klauspost/cpuid/v2 v2.2.9 // indirect
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect
github.com/lunixbochs/struc v0.0.0-20200707160740-784aaebc1d40 // indirect
github.com/mailru/easyjson v0.7.7 // indirect
github.com/mdlayher/netlink v1.7.2 // indirect
github.com/mdlayher/socket v0.4.1 // indirect
github.com/metacubex/amneziawg-go v0.0.0-20240922133038-fdf3a4d5a4ab // indirect
github.com/metacubex/amneziawg-go v0.0.0-20250820070344-732c0c9d418a // indirect
github.com/metacubex/ascon v0.1.0 // indirect
github.com/metacubex/bart v0.20.5 // indirect
github.com/metacubex/bbolt v0.0.0-20250725135710-010dbbbb7a5b // indirect
github.com/metacubex/blake3 v0.1.0 // indirect
github.com/metacubex/chacha v0.1.5 // indirect
github.com/metacubex/fswatch v0.1.1 // indirect
github.com/metacubex/gopacket v1.1.20-0.20230608035415-7e2f98a3e759 // indirect
github.com/metacubex/gvisor v0.0.0-20250324165734-5857f47bd43b // indirect
github.com/metacubex/mihomo v1.7.0 // indirect
github.com/metacubex/nftables v0.0.0-20250503052935-30a69ab87793 // indirect
github.com/metacubex/quic-go v0.53.1-0.20250628094454-fda5262d1d9c // indirect
github.com/metacubex/quic-go v0.54.1-0.20250730114134-a1ae705fe295 // indirect
github.com/metacubex/randv2 v0.2.0 // indirect
github.com/metacubex/sing v0.5.4 // indirect
github.com/metacubex/sing-mux v0.3.2 // indirect
github.com/metacubex/restls-client-go v0.1.7 // indirect
github.com/metacubex/sing v0.5.5 // indirect
github.com/metacubex/sing-mux v0.3.3-0.20250813083925-d7c9aeaeeaac // indirect
github.com/metacubex/sing-quic v0.0.0-20250718154553-1b193bec4cbb // indirect
github.com/metacubex/sing-shadowsocks v0.2.11 // indirect
github.com/metacubex/sing-shadowsocks2 v0.2.5 // indirect
github.com/metacubex/sing-shadowsocks v0.2.12 // indirect
github.com/metacubex/sing-shadowsocks2 v0.2.6 // indirect
github.com/metacubex/sing-shadowtls v0.0.0-20250503063515-5d9f966d17a2 // indirect
github.com/metacubex/sing-tun v0.4.7-0.20250721020617-8e7c37ed3d97 // indirect
github.com/metacubex/sing-vmess v0.2.3 // indirect
github.com/metacubex/sing-tun v0.4.7 // indirect
github.com/metacubex/sing-vmess v0.2.4-0.20250822020810-4856053566f0 // indirect
github.com/metacubex/sing-wireguard v0.0.0-20250503063753-2dc62acc626f // indirect
github.com/metacubex/smux v0.0.0-20250503055512-501391591dee // indirect
github.com/metacubex/tfo-go v0.0.0-20250516165257-e29c16ae41d4 // indirect
github.com/metacubex/utls v1.8.0 // indirect
github.com/metacubex/wireguard-go v0.0.0-20240922131502-c182e7471181 // indirect
github.com/metacubex/tfo-go v0.0.0-20250827083229-aa432b865617 // indirect
github.com/metacubex/utls v1.8.1-0.20250823120917-12f5ba126142 // indirect
github.com/metacubex/wireguard-go v0.0.0-20250820062549-a6cecdd7f57f // indirect
github.com/miekg/dns v1.1.63 // indirect
github.com/mroth/weightedrand/v2 v2.1.0 // indirect
github.com/oasisprotocol/deoxysii v0.0.0-20220228165953-2091330c22b7 // indirect
@@ -107,7 +107,6 @@ require (
golang.org/x/tools v0.24.0 // indirect
google.golang.org/protobuf v1.34.2 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
lukechampine.com/blake3 v1.3.0 // indirect
)
replace cfa => ../../main/golang
+35 -37
View File
@@ -1,5 +1,3 @@
github.com/3andne/restls-client-go v0.1.6 h1:tRx/YilqW7iHpgmEL4E1D8dAsuB0tFF3uvncS+B6I08=
github.com/3andne/restls-client-go v0.1.6/go.mod h1:iEdTZNt9kzPIxjIGSMScUFSBrUH6bFRNg0BWlP4orEY=
github.com/RyuaNerin/go-krypto v1.3.0 h1:smavTzSMAx8iuVlGb4pEwl9MD2qicqMzuXR2QWp2/Pg=
github.com/RyuaNerin/go-krypto v1.3.0/go.mod h1:9R9TU936laAIqAmjcHo/LsaXYOZlymudOAxjaBf62UM=
github.com/RyuaNerin/testingutil v0.1.0 h1:IYT6JL57RV3U2ml3dLHZsVtPOP6yNK7WUVdzzlpNrss=
@@ -24,10 +22,10 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dlclark/regexp2 v1.11.5 h1:Q/sSnsKerHeCkc/jSTNq1oCm7KiVgUMZRDUoRu0JQZQ=
github.com/dlclark/regexp2 v1.11.5/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
github.com/ebitengine/purego v0.8.3 h1:K+0AjQp63JEZTEMZiwsI9g0+hAMNohwUOtY0RPGexmc=
github.com/ebitengine/purego v0.8.3/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ=
github.com/enfein/mieru/v3 v3.16.1 h1:CfIt1pQCCQbohkw+HBD2o8V9tnhZvB5yuXGGQIXTLOs=
github.com/enfein/mieru/v3 v3.16.1/go.mod h1:zJBUCsi5rxyvHM8fjFf+GLaEl4OEjjBXr1s5F6Qd3hM=
github.com/ebitengine/purego v0.8.4 h1:CF7LEKg5FFOsASUj0+QwaXf8Ht6TlFxg09+S9wz0omw=
github.com/ebitengine/purego v0.8.4/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ=
github.com/enfein/mieru/v3 v3.19.1 h1:19b9kgFC7oJXX9RLEO5Pi1gO6yek5cWlpK7IJVUoE8I=
github.com/enfein/mieru/v3 v3.19.1/go.mod h1:zJBUCsi5rxyvHM8fjFf+GLaEl4OEjjBXr1s5F6Qd3hM=
github.com/ericlagergren/aegis v0.0.0-20250325060835-cd0defd64358 h1:kXYqH/sL8dS/FdoFjr12ePjnLPorPo2FsnrHNuXSDyo=
github.com/ericlagergren/aegis v0.0.0-20250325060835-cd0defd64358/go.mod h1:hkIFzoiIPZYxdFOOLyDho59b7SrDfo+w3h+yWdlg45I=
github.com/ericlagergren/polyval v0.0.0-20220411101811-e25bc10ba391 h1:8j2RH289RJplhA6WfdaPqzg1MjH2K8wX5e0uhAxrw2g=
@@ -41,8 +39,8 @@ github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S
github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
github.com/gaukas/godicttls v0.0.4 h1:NlRaXb3J6hAnTmWdsEKb9bcSBD6BvcIjdGdeb0zfXbk=
github.com/gaukas/godicttls v0.0.4/go.mod h1:l6EenT4TLWgTdwslVb4sEMOCf7Bv0JAK67deKr9/NCI=
github.com/go-chi/chi/v5 v5.2.2 h1:CMwsvRVTbXVytCk1Wd72Zy1LAsAh9GxMmSNWLHCG618=
github.com/go-chi/chi/v5 v5.2.2/go.mod h1:L2yAIGWB3H+phAw1NxKwWM+7eUH/lU8pOMm5hHcoops=
github.com/go-chi/chi/v5 v5.2.3 h1:WQIt9uxdsAbgIYgid+BpYc+liqQZGMHRaUwp0JUcvdE=
github.com/go-chi/chi/v5 v5.2.3/go.mod h1:L2yAIGWB3H+phAw1NxKwWM+7eUH/lU8pOMm5hHcoops=
github.com/go-chi/render v1.0.3 h1:AsXqd2a1/INaIfUSKq3G5uA8weYx20FOsM7uSoCyyt4=
github.com/go-chi/render v1.0.3/go.mod h1:/gr3hVkmYR0YlEy3LxCuVRFzEu9Ruok+gFqbIofjao0=
github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ=
@@ -80,24 +78,24 @@ github.com/josharian/native v1.1.0 h1:uuaP0hAbW7Y4l0ZRQ6C9zfb7Mg1mbFKry/xzDAfmtL
github.com/josharian/native v1.1.0/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w=
github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA=
github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
github.com/klauspost/cpuid/v2 v2.2.9 h1:66ze0taIn2H33fBvCkXuv9BmCwDfafmiIVpKV9kKGuY=
github.com/klauspost/cpuid/v2 v2.2.9/go.mod h1:rqkxqrZ1EhYM9G+hXH7YdowN5R5RGN6NK4QwQ3WMXF8=
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ81pIr0yLvtUWk2if982qA3F3QD6H4=
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I=
github.com/lunixbochs/struc v0.0.0-20200707160740-784aaebc1d40 h1:EnfXoSqDfSNJv0VBNqY/88RNnhSGYkrHaO0mmFGbVsc=
github.com/lunixbochs/struc v0.0.0-20200707160740-784aaebc1d40/go.mod h1:vy1vK6wD6j7xX6O6hXe621WabdtNkou2h7uRtTfRMyg=
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
github.com/mdlayher/netlink v1.7.2 h1:/UtM3ofJap7Vl4QWCPDGXY8d3GIY2UGSDbK+QWmY8/g=
github.com/mdlayher/netlink v1.7.2/go.mod h1:xraEF7uJbxLhc5fpHL4cPe221LI2bdttWlU+ZGLfQSw=
github.com/mdlayher/socket v0.4.1 h1:eM9y2/jlbs1M615oshPQOHZzj6R6wMT7bX5NPiQvn2U=
github.com/mdlayher/socket v0.4.1/go.mod h1:cAqeGjoufqdxWkD7DkpyS+wcefOtmu5OQ8KuoJGIReA=
github.com/metacubex/amneziawg-go v0.0.0-20240922133038-fdf3a4d5a4ab h1:Chbw+/31UC14YFNr78pESt5Vowlc62zziw05JCUqoL4=
github.com/metacubex/amneziawg-go v0.0.0-20240922133038-fdf3a4d5a4ab/go.mod h1:xVKK8jC5Sd3hfh7WjmCq+HorehIbrBijaUWmcuKjPcI=
github.com/metacubex/amneziawg-go v0.0.0-20250820070344-732c0c9d418a h1:c1QSGpacSeQdBdWcEKZKGuWLcqIG2wxHEygAcXuDwS4=
github.com/metacubex/amneziawg-go v0.0.0-20250820070344-732c0c9d418a/go.mod h1:MsM/5czONyXMJ3PRr5DbQ4O/BxzAnJWOIcJdLzW6qHY=
github.com/metacubex/ascon v0.1.0 h1:6ZWxmXYszT1XXtwkf6nxfFhc/OTtQ9R3Vyj1jN32lGM=
github.com/metacubex/ascon v0.1.0/go.mod h1:eV5oim4cVPPdEL8/EYaTZ0iIKARH9pnhAK/fcT5Kacc=
github.com/metacubex/bart v0.20.5 h1:XkgLZ17QxfxkqKdGsojoM2Zu01mmHyyQSFzt2/calTM=
github.com/metacubex/bart v0.20.5/go.mod h1:DCcyfP4MC+Zy7sLK7XeGuMw+P5K9mIRsYOBgiE8icsI=
github.com/metacubex/bbolt v0.0.0-20250725135710-010dbbbb7a5b h1:j7dadXD8I2KTmMt8jg1JcaP1ANL3JEObJPdANKcSYPY=
github.com/metacubex/bbolt v0.0.0-20250725135710-010dbbbb7a5b/go.mod h1:+WmP0VJZDkDszvpa83HzfUp6QzARl/IKkMorH4+nODw=
github.com/metacubex/blake3 v0.1.0 h1:KGnjh/56REO7U+cgZA8dnBhxdP7jByrG7hTP+bu6cqY=
github.com/metacubex/blake3 v0.1.0/go.mod h1:CCkLdzFrqf7xmxCdhQFvJsRRV2mwOLDoSPg6vUTB9Uk=
github.com/metacubex/chacha v0.1.5 h1:fKWMb/5c7ZrY8Uoqi79PPFxl+qwR7X/q0OrsAubyX2M=
github.com/metacubex/chacha v0.1.5/go.mod h1:Djn9bPZxLTXbJFSeyo0/qzEzQI+gUSSzttuzZM75GH8=
github.com/metacubex/fswatch v0.1.1 h1:jqU7C/v+g0qc2RUFgmAOPoVvfl2BXXUXEumn6oQuxhU=
@@ -108,37 +106,39 @@ github.com/metacubex/gvisor v0.0.0-20250324165734-5857f47bd43b h1:RUh4OdVPz/jDrM
github.com/metacubex/gvisor v0.0.0-20250324165734-5857f47bd43b/go.mod h1:8LpS0IJW1VmWzUm3ylb0e2SK5QDm5lO/2qwWLZgRpBU=
github.com/metacubex/nftables v0.0.0-20250503052935-30a69ab87793 h1:1Qpuy+sU3DmyX9HwI+CrBT/oLNJngvBorR2RbajJcqo=
github.com/metacubex/nftables v0.0.0-20250503052935-30a69ab87793/go.mod h1:RjRNb4G52yAgfR+Oe/kp9G4PJJ97Fnj89eY1BFO3YyA=
github.com/metacubex/quic-go v0.53.1-0.20250628094454-fda5262d1d9c h1:ABQzmOaZddM3q0OYeoZEc0XF+KW+dUdPNvY/c5rsunI=
github.com/metacubex/quic-go v0.53.1-0.20250628094454-fda5262d1d9c/go.mod h1:eWlAK3zsKI0P8UhYpXlIsl3mtW4D6MpMNuYLIu8CKWI=
github.com/metacubex/quic-go v0.54.1-0.20250730114134-a1ae705fe295 h1:8JVlYuE8uSJAvmyCd4TjvDxs57xjb0WxEoaWafK5+qs=
github.com/metacubex/quic-go v0.54.1-0.20250730114134-a1ae705fe295/go.mod h1:1lktQFtCD17FZliVypbrDHwbsFSsmz2xz2TRXydvB5c=
github.com/metacubex/randv2 v0.2.0 h1:uP38uBvV2SxYfLj53kuvAjbND4RUDfFJjwr4UigMiLs=
github.com/metacubex/randv2 v0.2.0/go.mod h1:kFi2SzrQ5WuneuoLLCMkABtiBu6VRrMrWFqSPyj2cxY=
github.com/metacubex/restls-client-go v0.1.7 h1:eCwiXCTQb5WJu9IlgYvDBA1OgrINv58dEe7hcN5H15k=
github.com/metacubex/restls-client-go v0.1.7/go.mod h1:BN/U52vPw7j8VTSh2vleD/MnmVKCov84mS5VcjVHH4g=
github.com/metacubex/sing v0.5.2/go.mod h1:ypf0mjwlZm0sKdQSY+yQvmsbWa0hNPtkeqyRMGgoN+w=
github.com/metacubex/sing v0.5.4 h1:a4kAOZmF+OXosbzPEcrSc5QD35/ex+MNuZsrcuWskHk=
github.com/metacubex/sing v0.5.4/go.mod h1:ypf0mjwlZm0sKdQSY+yQvmsbWa0hNPtkeqyRMGgoN+w=
github.com/metacubex/sing-mux v0.3.2 h1:nJv52pyRivHcaZJKk2JgxpaVvj1GAXG81scSa9N7ncw=
github.com/metacubex/sing-mux v0.3.2/go.mod h1:3rt1soewn0O6j89GCLmwAQFsq257u0jf2zQSPhTL3Bw=
github.com/metacubex/sing v0.5.5 h1:m5U8iHvRAUxlme3FZlE/LPIGHjU8oMCUzXWGbQQAC1E=
github.com/metacubex/sing v0.5.5/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-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.11 h1:p2NGNOdF95e6XvdDKipLj1FRRqR8dnbfC/7pw2CCTlw=
github.com/metacubex/sing-shadowsocks v0.2.11/go.mod h1:bT1PCTV316zFnlToRMk5zt9HmIQYRBveiT71mplYPfc=
github.com/metacubex/sing-shadowsocks2 v0.2.5 h1:MnPn0hbcDkSJt6TlpI15XImHKK6IqaOwBUGPKyMnJnE=
github.com/metacubex/sing-shadowsocks2 v0.2.5/go.mod h1:Zyh+rAQRyevYfG/COCvDs1c/YMhGqCuknn7QrGmoQIw=
github.com/metacubex/sing-shadowsocks v0.2.12 h1:Wqzo8bYXrK5aWqxu/TjlTnYZzAKtKsaFQBdr6IHFaBE=
github.com/metacubex/sing-shadowsocks v0.2.12/go.mod h1:2e5EIaw0rxKrm1YTRmiMnDulwbGxH9hAFlrwQLQMQkU=
github.com/metacubex/sing-shadowsocks2 v0.2.6 h1:ZR1kYT0f0Vi64iQSS09OdhFfppiNkh7kjgRdMm0SB98=
github.com/metacubex/sing-shadowsocks2 v0.2.6/go.mod h1:vOEbfKC60txi0ca+yUlqEwOGc3Obl6cnSgx9Gf45KjE=
github.com/metacubex/sing-shadowtls v0.0.0-20250503063515-5d9f966d17a2 h1:gXU+MYPm7Wme3/OAY2FFzVq9d9GxPHOqu5AQfg/ddhI=
github.com/metacubex/sing-shadowtls v0.0.0-20250503063515-5d9f966d17a2/go.mod h1:mbfboaXauKJNIHJYxQRa+NJs4JU9NZfkA+I33dS2+9E=
github.com/metacubex/sing-tun v0.4.7-0.20250721020617-8e7c37ed3d97 h1:YYpc60UZE2G0pUeHbRw9erDrUDZrPQy8QzWFqA3kHsk=
github.com/metacubex/sing-tun v0.4.7-0.20250721020617-8e7c37ed3d97/go.mod h1:2YywXPWW8Z97kTH7RffOeykKzU+l0aiKlglWV1PAS64=
github.com/metacubex/sing-vmess v0.2.3 h1:QKLdIk5A2FcR3Y7m2/JO1XhfzgDA8tF4W9/ffsH9opo=
github.com/metacubex/sing-vmess v0.2.3/go.mod h1:21R5R1u90uUvBQF0owoooEu96/SAYYD56nDrwm6nFaM=
github.com/metacubex/sing-tun v0.4.7 h1:ZDY/W+1c7PeWWKeKRyUo18fySF/TWjB0i5ui81Ar778=
github.com/metacubex/sing-tun v0.4.7/go.mod h1:xHecZRwBnKWe6zG9amAK9cXf91lF6blgjBqm+VvOrmU=
github.com/metacubex/sing-vmess v0.2.4-0.20250822020810-4856053566f0 h1:WZepq4TOZa6WewB8tGAZrrL+bL2R2ivoBzuEgAeolWc=
github.com/metacubex/sing-vmess v0.2.4-0.20250822020810-4856053566f0/go.mod h1:21R5R1u90uUvBQF0owoooEu96/SAYYD56nDrwm6nFaM=
github.com/metacubex/sing-wireguard v0.0.0-20250503063753-2dc62acc626f h1:Sr/DYKYofKHKc4GF3qkRGNuj6XA6c0eqPgEDN+VAsYU=
github.com/metacubex/sing-wireguard v0.0.0-20250503063753-2dc62acc626f/go.mod h1:jpAkVLPnCpGSfNyVmj6Cq4YbuZsFepm/Dc+9BAOcR80=
github.com/metacubex/smux v0.0.0-20250503055512-501391591dee h1:lp6hJ+4wCLZu113awp7P6odM2okB5s60HUyF0FMqKmo=
github.com/metacubex/smux v0.0.0-20250503055512-501391591dee/go.mod h1:4bPD8HWx9jPJ9aE4uadgyN7D1/Wz3KmPy+vale8sKLE=
github.com/metacubex/tfo-go v0.0.0-20250516165257-e29c16ae41d4 h1:j1VRTiC9JLR4nUbSikx9OGdu/3AgFDqgcLj4GoqyQkc=
github.com/metacubex/tfo-go v0.0.0-20250516165257-e29c16ae41d4/go.mod h1:l9oLnLoEXyGZ5RVLsh7QCC5XsouTUyKk4F2nLm2DHLw=
github.com/metacubex/utls v1.8.0 h1:mSYi6FMnmc5riARl5UZDmWVy710z+P5b7xuGW0lV9ac=
github.com/metacubex/utls v1.8.0/go.mod h1:FdjYzVfCtgtna19hX0ER1Xsa5uJInwdQ4IcaaI98lEQ=
github.com/metacubex/wireguard-go v0.0.0-20240922131502-c182e7471181 h1:hJLQviGySBuaynlCwf/oYgIxbVbGRUIKZCxdya9YrbQ=
github.com/metacubex/wireguard-go v0.0.0-20240922131502-c182e7471181/go.mod h1:phewKljNYiTVT31Gcif8RiCKnTUOgVWFJjccqYM8s+Y=
github.com/metacubex/tfo-go v0.0.0-20250827083229-aa432b865617 h1:yN3mQ4cT9sPUciw/rO0Isc/8QlO86DB6g9SEMRgQ8Cw=
github.com/metacubex/tfo-go v0.0.0-20250827083229-aa432b865617/go.mod h1:l9oLnLoEXyGZ5RVLsh7QCC5XsouTUyKk4F2nLm2DHLw=
github.com/metacubex/utls v1.8.1-0.20250823120917-12f5ba126142 h1:csEbKOzRAxJXffOeZnnS3/kA/F55JiTbKv5jcYqCXms=
github.com/metacubex/utls v1.8.1-0.20250823120917-12f5ba126142/go.mod h1:67I3skhEY4Sya8f1YxELwWPoeQdXqZCrWNYLvq8gn2U=
github.com/metacubex/wireguard-go v0.0.0-20250820062549-a6cecdd7f57f h1:FGBPRb1zUabhPhDrlKEjQ9lgIwQ6cHL4x8M9lrERhbk=
github.com/metacubex/wireguard-go v0.0.0-20250820062549-a6cecdd7f57f/go.mod h1:oPGcV994OGJedmmxrcK9+ni7jUEMGhR+uVQAdaduIP4=
github.com/miekg/dns v1.1.63 h1:8M5aAw6OMZfFXTT7K5V0Eu5YiiL8l7nUAkyN6C9YwaY=
github.com/miekg/dns v1.1.63/go.mod h1:6NGHfjhpmr5lt3XPLuyfDJi5AXbNIPM9PY6H6sF1Nfs=
github.com/mroth/weightedrand/v2 v2.1.0 h1:o1ascnB1CIVzsqlfArQQjeMy1U0NcIbBO5rfd5E/OeU=
@@ -191,7 +191,7 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
github.com/stretchr/testify v1.11.0 h1:ib4sjIrwZKxE5u/Japgo/7SJV3PvgjGiRNAvTVGqQl8=
github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFAEVmqU=
github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI=
github.com/tklauser/numcpus v0.6.1 h1:ng9scYS7az0Bk4OZLvrNXNSAO2Pxr1XXRAPyjhIx+Fk=
@@ -271,5 +271,3 @@ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
lukechampine.com/blake3 v1.3.0 h1:sJ3XhFINmHSrYCgl958hscfIa3bw8x4DqMP3u1YvoYE=
lukechampine.com/blake3 v1.3.0/go.mod h1:0OFRp7fBtAylGVCO40o87sbupkyIGgbpv1+M1k1LM6k=
+17 -18
View File
@@ -12,7 +12,6 @@ require (
replace github.com/metacubex/mihomo => ../../foss/golang/clash
require (
github.com/3andne/restls-client-go v0.1.6 // indirect
github.com/RyuaNerin/go-krypto v1.3.0 // indirect
github.com/Yawning/aez v0.0.0-20211027044916-e49e68abd344 // indirect
github.com/ajg/form v1.5.1 // indirect
@@ -20,15 +19,15 @@ require (
github.com/bahlo/generic-list-go v0.2.0 // indirect
github.com/buger/jsonparser v1.1.1 // indirect
github.com/coreos/go-iptables v0.8.0 // indirect
github.com/ebitengine/purego v0.8.3 // indirect
github.com/enfein/mieru/v3 v3.16.1 // indirect
github.com/ebitengine/purego v0.8.4 // indirect
github.com/enfein/mieru/v3 v3.19.1 // indirect
github.com/ericlagergren/aegis v0.0.0-20250325060835-cd0defd64358 // indirect
github.com/ericlagergren/polyval v0.0.0-20220411101811-e25bc10ba391 // indirect
github.com/ericlagergren/siv v0.0.0-20220507050439-0b757b3aa5f1 // indirect
github.com/ericlagergren/subtle v0.0.0-20220507045147-890d697da010 // indirect
github.com/fsnotify/fsnotify v1.9.0 // indirect
github.com/gaukas/godicttls v0.0.4 // indirect
github.com/go-chi/chi/v5 v5.2.2 // indirect
github.com/go-chi/chi/v5 v5.2.3 // indirect
github.com/go-chi/render v1.0.3 // indirect
github.com/go-ole/go-ole v1.3.0 // indirect
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect
@@ -44,35 +43,36 @@ require (
github.com/insomniacslk/dhcp v0.0.0-20250109001534-8abf58130905 // indirect
github.com/josharian/native v1.1.0 // indirect
github.com/klauspost/compress v1.17.9 // indirect
github.com/klauspost/cpuid/v2 v2.2.9 // indirect
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect
github.com/lunixbochs/struc v0.0.0-20200707160740-784aaebc1d40 // indirect
github.com/mailru/easyjson v0.7.7 // indirect
github.com/mdlayher/netlink v1.7.2 // indirect
github.com/mdlayher/socket v0.4.1 // indirect
github.com/metacubex/amneziawg-go v0.0.0-20240922133038-fdf3a4d5a4ab // indirect
github.com/metacubex/amneziawg-go v0.0.0-20250820070344-732c0c9d418a // indirect
github.com/metacubex/ascon v0.1.0 // indirect
github.com/metacubex/bart v0.20.5 // indirect
github.com/metacubex/bbolt v0.0.0-20250725135710-010dbbbb7a5b // indirect
github.com/metacubex/blake3 v0.1.0 // indirect
github.com/metacubex/chacha v0.1.5 // indirect
github.com/metacubex/fswatch v0.1.1 // indirect
github.com/metacubex/gopacket v1.1.20-0.20230608035415-7e2f98a3e759 // indirect
github.com/metacubex/gvisor v0.0.0-20250324165734-5857f47bd43b // indirect
github.com/metacubex/nftables v0.0.0-20250503052935-30a69ab87793 // indirect
github.com/metacubex/quic-go v0.53.1-0.20250628094454-fda5262d1d9c // indirect
github.com/metacubex/quic-go v0.54.1-0.20250730114134-a1ae705fe295 // indirect
github.com/metacubex/randv2 v0.2.0 // indirect
github.com/metacubex/sing v0.5.4 // indirect
github.com/metacubex/sing-mux v0.3.2 // indirect
github.com/metacubex/restls-client-go v0.1.7 // indirect
github.com/metacubex/sing v0.5.5 // indirect
github.com/metacubex/sing-mux v0.3.3-0.20250813083925-d7c9aeaeeaac // indirect
github.com/metacubex/sing-quic v0.0.0-20250718154553-1b193bec4cbb // indirect
github.com/metacubex/sing-shadowsocks v0.2.11 // indirect
github.com/metacubex/sing-shadowsocks2 v0.2.5 // indirect
github.com/metacubex/sing-shadowsocks v0.2.12 // indirect
github.com/metacubex/sing-shadowsocks2 v0.2.6 // indirect
github.com/metacubex/sing-shadowtls v0.0.0-20250503063515-5d9f966d17a2 // indirect
github.com/metacubex/sing-tun v0.4.7-0.20250721020617-8e7c37ed3d97 // indirect
github.com/metacubex/sing-vmess v0.2.3 // indirect
github.com/metacubex/sing-tun v0.4.7 // indirect
github.com/metacubex/sing-vmess v0.2.4-0.20250822020810-4856053566f0 // indirect
github.com/metacubex/sing-wireguard v0.0.0-20250503063753-2dc62acc626f // indirect
github.com/metacubex/smux v0.0.0-20250503055512-501391591dee // indirect
github.com/metacubex/tfo-go v0.0.0-20250516165257-e29c16ae41d4 // indirect
github.com/metacubex/utls v1.8.0 // indirect
github.com/metacubex/wireguard-go v0.0.0-20240922131502-c182e7471181 // indirect
github.com/metacubex/tfo-go v0.0.0-20250827083229-aa432b865617 // indirect
github.com/metacubex/utls v1.8.1-0.20250823120917-12f5ba126142 // indirect
github.com/metacubex/wireguard-go v0.0.0-20250820062549-a6cecdd7f57f // indirect
github.com/miekg/dns v1.1.63 // indirect
github.com/mroth/weightedrand/v2 v2.1.0 // indirect
github.com/oasisprotocol/deoxysii v0.0.0-20220228165953-2091330c22b7 // indirect
@@ -111,5 +111,4 @@ require (
golang.org/x/time v0.7.0 // indirect
golang.org/x/tools v0.24.0 // indirect
google.golang.org/protobuf v1.34.2 // indirect
lukechampine.com/blake3 v1.3.0 // indirect
)
+35 -37
View File
@@ -1,5 +1,3 @@
github.com/3andne/restls-client-go v0.1.6 h1:tRx/YilqW7iHpgmEL4E1D8dAsuB0tFF3uvncS+B6I08=
github.com/3andne/restls-client-go v0.1.6/go.mod h1:iEdTZNt9kzPIxjIGSMScUFSBrUH6bFRNg0BWlP4orEY=
github.com/RyuaNerin/go-krypto v1.3.0 h1:smavTzSMAx8iuVlGb4pEwl9MD2qicqMzuXR2QWp2/Pg=
github.com/RyuaNerin/go-krypto v1.3.0/go.mod h1:9R9TU936laAIqAmjcHo/LsaXYOZlymudOAxjaBf62UM=
github.com/RyuaNerin/testingutil v0.1.0 h1:IYT6JL57RV3U2ml3dLHZsVtPOP6yNK7WUVdzzlpNrss=
@@ -24,10 +22,10 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dlclark/regexp2 v1.11.5 h1:Q/sSnsKerHeCkc/jSTNq1oCm7KiVgUMZRDUoRu0JQZQ=
github.com/dlclark/regexp2 v1.11.5/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
github.com/ebitengine/purego v0.8.3 h1:K+0AjQp63JEZTEMZiwsI9g0+hAMNohwUOtY0RPGexmc=
github.com/ebitengine/purego v0.8.3/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ=
github.com/enfein/mieru/v3 v3.16.1 h1:CfIt1pQCCQbohkw+HBD2o8V9tnhZvB5yuXGGQIXTLOs=
github.com/enfein/mieru/v3 v3.16.1/go.mod h1:zJBUCsi5rxyvHM8fjFf+GLaEl4OEjjBXr1s5F6Qd3hM=
github.com/ebitengine/purego v0.8.4 h1:CF7LEKg5FFOsASUj0+QwaXf8Ht6TlFxg09+S9wz0omw=
github.com/ebitengine/purego v0.8.4/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ=
github.com/enfein/mieru/v3 v3.19.1 h1:19b9kgFC7oJXX9RLEO5Pi1gO6yek5cWlpK7IJVUoE8I=
github.com/enfein/mieru/v3 v3.19.1/go.mod h1:zJBUCsi5rxyvHM8fjFf+GLaEl4OEjjBXr1s5F6Qd3hM=
github.com/ericlagergren/aegis v0.0.0-20250325060835-cd0defd64358 h1:kXYqH/sL8dS/FdoFjr12ePjnLPorPo2FsnrHNuXSDyo=
github.com/ericlagergren/aegis v0.0.0-20250325060835-cd0defd64358/go.mod h1:hkIFzoiIPZYxdFOOLyDho59b7SrDfo+w3h+yWdlg45I=
github.com/ericlagergren/polyval v0.0.0-20220411101811-e25bc10ba391 h1:8j2RH289RJplhA6WfdaPqzg1MjH2K8wX5e0uhAxrw2g=
@@ -41,8 +39,8 @@ github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S
github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
github.com/gaukas/godicttls v0.0.4 h1:NlRaXb3J6hAnTmWdsEKb9bcSBD6BvcIjdGdeb0zfXbk=
github.com/gaukas/godicttls v0.0.4/go.mod h1:l6EenT4TLWgTdwslVb4sEMOCf7Bv0JAK67deKr9/NCI=
github.com/go-chi/chi/v5 v5.2.2 h1:CMwsvRVTbXVytCk1Wd72Zy1LAsAh9GxMmSNWLHCG618=
github.com/go-chi/chi/v5 v5.2.2/go.mod h1:L2yAIGWB3H+phAw1NxKwWM+7eUH/lU8pOMm5hHcoops=
github.com/go-chi/chi/v5 v5.2.3 h1:WQIt9uxdsAbgIYgid+BpYc+liqQZGMHRaUwp0JUcvdE=
github.com/go-chi/chi/v5 v5.2.3/go.mod h1:L2yAIGWB3H+phAw1NxKwWM+7eUH/lU8pOMm5hHcoops=
github.com/go-chi/render v1.0.3 h1:AsXqd2a1/INaIfUSKq3G5uA8weYx20FOsM7uSoCyyt4=
github.com/go-chi/render v1.0.3/go.mod h1:/gr3hVkmYR0YlEy3LxCuVRFzEu9Ruok+gFqbIofjao0=
github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ=
@@ -81,24 +79,24 @@ github.com/josharian/native v1.1.0 h1:uuaP0hAbW7Y4l0ZRQ6C9zfb7Mg1mbFKry/xzDAfmtL
github.com/josharian/native v1.1.0/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w=
github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA=
github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
github.com/klauspost/cpuid/v2 v2.2.9 h1:66ze0taIn2H33fBvCkXuv9BmCwDfafmiIVpKV9kKGuY=
github.com/klauspost/cpuid/v2 v2.2.9/go.mod h1:rqkxqrZ1EhYM9G+hXH7YdowN5R5RGN6NK4QwQ3WMXF8=
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ81pIr0yLvtUWk2if982qA3F3QD6H4=
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I=
github.com/lunixbochs/struc v0.0.0-20200707160740-784aaebc1d40 h1:EnfXoSqDfSNJv0VBNqY/88RNnhSGYkrHaO0mmFGbVsc=
github.com/lunixbochs/struc v0.0.0-20200707160740-784aaebc1d40/go.mod h1:vy1vK6wD6j7xX6O6hXe621WabdtNkou2h7uRtTfRMyg=
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
github.com/mdlayher/netlink v1.7.2 h1:/UtM3ofJap7Vl4QWCPDGXY8d3GIY2UGSDbK+QWmY8/g=
github.com/mdlayher/netlink v1.7.2/go.mod h1:xraEF7uJbxLhc5fpHL4cPe221LI2bdttWlU+ZGLfQSw=
github.com/mdlayher/socket v0.4.1 h1:eM9y2/jlbs1M615oshPQOHZzj6R6wMT7bX5NPiQvn2U=
github.com/mdlayher/socket v0.4.1/go.mod h1:cAqeGjoufqdxWkD7DkpyS+wcefOtmu5OQ8KuoJGIReA=
github.com/metacubex/amneziawg-go v0.0.0-20240922133038-fdf3a4d5a4ab h1:Chbw+/31UC14YFNr78pESt5Vowlc62zziw05JCUqoL4=
github.com/metacubex/amneziawg-go v0.0.0-20240922133038-fdf3a4d5a4ab/go.mod h1:xVKK8jC5Sd3hfh7WjmCq+HorehIbrBijaUWmcuKjPcI=
github.com/metacubex/amneziawg-go v0.0.0-20250820070344-732c0c9d418a h1:c1QSGpacSeQdBdWcEKZKGuWLcqIG2wxHEygAcXuDwS4=
github.com/metacubex/amneziawg-go v0.0.0-20250820070344-732c0c9d418a/go.mod h1:MsM/5czONyXMJ3PRr5DbQ4O/BxzAnJWOIcJdLzW6qHY=
github.com/metacubex/ascon v0.1.0 h1:6ZWxmXYszT1XXtwkf6nxfFhc/OTtQ9R3Vyj1jN32lGM=
github.com/metacubex/ascon v0.1.0/go.mod h1:eV5oim4cVPPdEL8/EYaTZ0iIKARH9pnhAK/fcT5Kacc=
github.com/metacubex/bart v0.20.5 h1:XkgLZ17QxfxkqKdGsojoM2Zu01mmHyyQSFzt2/calTM=
github.com/metacubex/bart v0.20.5/go.mod h1:DCcyfP4MC+Zy7sLK7XeGuMw+P5K9mIRsYOBgiE8icsI=
github.com/metacubex/bbolt v0.0.0-20250725135710-010dbbbb7a5b h1:j7dadXD8I2KTmMt8jg1JcaP1ANL3JEObJPdANKcSYPY=
github.com/metacubex/bbolt v0.0.0-20250725135710-010dbbbb7a5b/go.mod h1:+WmP0VJZDkDszvpa83HzfUp6QzARl/IKkMorH4+nODw=
github.com/metacubex/blake3 v0.1.0 h1:KGnjh/56REO7U+cgZA8dnBhxdP7jByrG7hTP+bu6cqY=
github.com/metacubex/blake3 v0.1.0/go.mod h1:CCkLdzFrqf7xmxCdhQFvJsRRV2mwOLDoSPg6vUTB9Uk=
github.com/metacubex/chacha v0.1.5 h1:fKWMb/5c7ZrY8Uoqi79PPFxl+qwR7X/q0OrsAubyX2M=
github.com/metacubex/chacha v0.1.5/go.mod h1:Djn9bPZxLTXbJFSeyo0/qzEzQI+gUSSzttuzZM75GH8=
github.com/metacubex/fswatch v0.1.1 h1:jqU7C/v+g0qc2RUFgmAOPoVvfl2BXXUXEumn6oQuxhU=
@@ -109,37 +107,39 @@ github.com/metacubex/gvisor v0.0.0-20250324165734-5857f47bd43b h1:RUh4OdVPz/jDrM
github.com/metacubex/gvisor v0.0.0-20250324165734-5857f47bd43b/go.mod h1:8LpS0IJW1VmWzUm3ylb0e2SK5QDm5lO/2qwWLZgRpBU=
github.com/metacubex/nftables v0.0.0-20250503052935-30a69ab87793 h1:1Qpuy+sU3DmyX9HwI+CrBT/oLNJngvBorR2RbajJcqo=
github.com/metacubex/nftables v0.0.0-20250503052935-30a69ab87793/go.mod h1:RjRNb4G52yAgfR+Oe/kp9G4PJJ97Fnj89eY1BFO3YyA=
github.com/metacubex/quic-go v0.53.1-0.20250628094454-fda5262d1d9c h1:ABQzmOaZddM3q0OYeoZEc0XF+KW+dUdPNvY/c5rsunI=
github.com/metacubex/quic-go v0.53.1-0.20250628094454-fda5262d1d9c/go.mod h1:eWlAK3zsKI0P8UhYpXlIsl3mtW4D6MpMNuYLIu8CKWI=
github.com/metacubex/quic-go v0.54.1-0.20250730114134-a1ae705fe295 h1:8JVlYuE8uSJAvmyCd4TjvDxs57xjb0WxEoaWafK5+qs=
github.com/metacubex/quic-go v0.54.1-0.20250730114134-a1ae705fe295/go.mod h1:1lktQFtCD17FZliVypbrDHwbsFSsmz2xz2TRXydvB5c=
github.com/metacubex/randv2 v0.2.0 h1:uP38uBvV2SxYfLj53kuvAjbND4RUDfFJjwr4UigMiLs=
github.com/metacubex/randv2 v0.2.0/go.mod h1:kFi2SzrQ5WuneuoLLCMkABtiBu6VRrMrWFqSPyj2cxY=
github.com/metacubex/restls-client-go v0.1.7 h1:eCwiXCTQb5WJu9IlgYvDBA1OgrINv58dEe7hcN5H15k=
github.com/metacubex/restls-client-go v0.1.7/go.mod h1:BN/U52vPw7j8VTSh2vleD/MnmVKCov84mS5VcjVHH4g=
github.com/metacubex/sing v0.5.2/go.mod h1:ypf0mjwlZm0sKdQSY+yQvmsbWa0hNPtkeqyRMGgoN+w=
github.com/metacubex/sing v0.5.4 h1:a4kAOZmF+OXosbzPEcrSc5QD35/ex+MNuZsrcuWskHk=
github.com/metacubex/sing v0.5.4/go.mod h1:ypf0mjwlZm0sKdQSY+yQvmsbWa0hNPtkeqyRMGgoN+w=
github.com/metacubex/sing-mux v0.3.2 h1:nJv52pyRivHcaZJKk2JgxpaVvj1GAXG81scSa9N7ncw=
github.com/metacubex/sing-mux v0.3.2/go.mod h1:3rt1soewn0O6j89GCLmwAQFsq257u0jf2zQSPhTL3Bw=
github.com/metacubex/sing v0.5.5 h1:m5U8iHvRAUxlme3FZlE/LPIGHjU8oMCUzXWGbQQAC1E=
github.com/metacubex/sing v0.5.5/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-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.11 h1:p2NGNOdF95e6XvdDKipLj1FRRqR8dnbfC/7pw2CCTlw=
github.com/metacubex/sing-shadowsocks v0.2.11/go.mod h1:bT1PCTV316zFnlToRMk5zt9HmIQYRBveiT71mplYPfc=
github.com/metacubex/sing-shadowsocks2 v0.2.5 h1:MnPn0hbcDkSJt6TlpI15XImHKK6IqaOwBUGPKyMnJnE=
github.com/metacubex/sing-shadowsocks2 v0.2.5/go.mod h1:Zyh+rAQRyevYfG/COCvDs1c/YMhGqCuknn7QrGmoQIw=
github.com/metacubex/sing-shadowsocks v0.2.12 h1:Wqzo8bYXrK5aWqxu/TjlTnYZzAKtKsaFQBdr6IHFaBE=
github.com/metacubex/sing-shadowsocks v0.2.12/go.mod h1:2e5EIaw0rxKrm1YTRmiMnDulwbGxH9hAFlrwQLQMQkU=
github.com/metacubex/sing-shadowsocks2 v0.2.6 h1:ZR1kYT0f0Vi64iQSS09OdhFfppiNkh7kjgRdMm0SB98=
github.com/metacubex/sing-shadowsocks2 v0.2.6/go.mod h1:vOEbfKC60txi0ca+yUlqEwOGc3Obl6cnSgx9Gf45KjE=
github.com/metacubex/sing-shadowtls v0.0.0-20250503063515-5d9f966d17a2 h1:gXU+MYPm7Wme3/OAY2FFzVq9d9GxPHOqu5AQfg/ddhI=
github.com/metacubex/sing-shadowtls v0.0.0-20250503063515-5d9f966d17a2/go.mod h1:mbfboaXauKJNIHJYxQRa+NJs4JU9NZfkA+I33dS2+9E=
github.com/metacubex/sing-tun v0.4.7-0.20250721020617-8e7c37ed3d97 h1:YYpc60UZE2G0pUeHbRw9erDrUDZrPQy8QzWFqA3kHsk=
github.com/metacubex/sing-tun v0.4.7-0.20250721020617-8e7c37ed3d97/go.mod h1:2YywXPWW8Z97kTH7RffOeykKzU+l0aiKlglWV1PAS64=
github.com/metacubex/sing-vmess v0.2.3 h1:QKLdIk5A2FcR3Y7m2/JO1XhfzgDA8tF4W9/ffsH9opo=
github.com/metacubex/sing-vmess v0.2.3/go.mod h1:21R5R1u90uUvBQF0owoooEu96/SAYYD56nDrwm6nFaM=
github.com/metacubex/sing-tun v0.4.7 h1:ZDY/W+1c7PeWWKeKRyUo18fySF/TWjB0i5ui81Ar778=
github.com/metacubex/sing-tun v0.4.7/go.mod h1:xHecZRwBnKWe6zG9amAK9cXf91lF6blgjBqm+VvOrmU=
github.com/metacubex/sing-vmess v0.2.4-0.20250822020810-4856053566f0 h1:WZepq4TOZa6WewB8tGAZrrL+bL2R2ivoBzuEgAeolWc=
github.com/metacubex/sing-vmess v0.2.4-0.20250822020810-4856053566f0/go.mod h1:21R5R1u90uUvBQF0owoooEu96/SAYYD56nDrwm6nFaM=
github.com/metacubex/sing-wireguard v0.0.0-20250503063753-2dc62acc626f h1:Sr/DYKYofKHKc4GF3qkRGNuj6XA6c0eqPgEDN+VAsYU=
github.com/metacubex/sing-wireguard v0.0.0-20250503063753-2dc62acc626f/go.mod h1:jpAkVLPnCpGSfNyVmj6Cq4YbuZsFepm/Dc+9BAOcR80=
github.com/metacubex/smux v0.0.0-20250503055512-501391591dee h1:lp6hJ+4wCLZu113awp7P6odM2okB5s60HUyF0FMqKmo=
github.com/metacubex/smux v0.0.0-20250503055512-501391591dee/go.mod h1:4bPD8HWx9jPJ9aE4uadgyN7D1/Wz3KmPy+vale8sKLE=
github.com/metacubex/tfo-go v0.0.0-20250516165257-e29c16ae41d4 h1:j1VRTiC9JLR4nUbSikx9OGdu/3AgFDqgcLj4GoqyQkc=
github.com/metacubex/tfo-go v0.0.0-20250516165257-e29c16ae41d4/go.mod h1:l9oLnLoEXyGZ5RVLsh7QCC5XsouTUyKk4F2nLm2DHLw=
github.com/metacubex/utls v1.8.0 h1:mSYi6FMnmc5riARl5UZDmWVy710z+P5b7xuGW0lV9ac=
github.com/metacubex/utls v1.8.0/go.mod h1:FdjYzVfCtgtna19hX0ER1Xsa5uJInwdQ4IcaaI98lEQ=
github.com/metacubex/wireguard-go v0.0.0-20240922131502-c182e7471181 h1:hJLQviGySBuaynlCwf/oYgIxbVbGRUIKZCxdya9YrbQ=
github.com/metacubex/wireguard-go v0.0.0-20240922131502-c182e7471181/go.mod h1:phewKljNYiTVT31Gcif8RiCKnTUOgVWFJjccqYM8s+Y=
github.com/metacubex/tfo-go v0.0.0-20250827083229-aa432b865617 h1:yN3mQ4cT9sPUciw/rO0Isc/8QlO86DB6g9SEMRgQ8Cw=
github.com/metacubex/tfo-go v0.0.0-20250827083229-aa432b865617/go.mod h1:l9oLnLoEXyGZ5RVLsh7QCC5XsouTUyKk4F2nLm2DHLw=
github.com/metacubex/utls v1.8.1-0.20250823120917-12f5ba126142 h1:csEbKOzRAxJXffOeZnnS3/kA/F55JiTbKv5jcYqCXms=
github.com/metacubex/utls v1.8.1-0.20250823120917-12f5ba126142/go.mod h1:67I3skhEY4Sya8f1YxELwWPoeQdXqZCrWNYLvq8gn2U=
github.com/metacubex/wireguard-go v0.0.0-20250820062549-a6cecdd7f57f h1:FGBPRb1zUabhPhDrlKEjQ9lgIwQ6cHL4x8M9lrERhbk=
github.com/metacubex/wireguard-go v0.0.0-20250820062549-a6cecdd7f57f/go.mod h1:oPGcV994OGJedmmxrcK9+ni7jUEMGhR+uVQAdaduIP4=
github.com/miekg/dns v1.1.63 h1:8M5aAw6OMZfFXTT7K5V0Eu5YiiL8l7nUAkyN6C9YwaY=
github.com/miekg/dns v1.1.63/go.mod h1:6NGHfjhpmr5lt3XPLuyfDJi5AXbNIPM9PY6H6sF1Nfs=
github.com/mroth/weightedrand/v2 v2.1.0 h1:o1ascnB1CIVzsqlfArQQjeMy1U0NcIbBO5rfd5E/OeU=
@@ -192,7 +192,7 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
github.com/stretchr/testify v1.11.0 h1:ib4sjIrwZKxE5u/Japgo/7SJV3PvgjGiRNAvTVGqQl8=
github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFAEVmqU=
github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI=
github.com/tklauser/numcpus v0.6.1 h1:ng9scYS7az0Bk4OZLvrNXNSAO2Pxr1XXRAPyjhIx+Fk=
@@ -272,5 +272,3 @@ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
lukechampine.com/blake3 v1.3.0 h1:sJ3XhFINmHSrYCgl958hscfIa3bw8x4DqMP3u1YvoYE=
lukechampine.com/blake3 v1.3.0/go.mod h1:0OFRp7fBtAylGVCO40o87sbupkyIGgbpv1+M1k1LM6k=
+6 -6
View File
@@ -6,8 +6,8 @@ require (
github.com/bahlo/generic-list-go v0.2.0
github.com/coreos/go-iptables v0.8.0
github.com/dlclark/regexp2 v1.11.5
github.com/enfein/mieru/v3 v3.19.0
github.com/go-chi/chi/v5 v5.2.2
github.com/enfein/mieru/v3 v3.19.1
github.com/go-chi/chi/v5 v5.2.3
github.com/go-chi/render v1.0.3
github.com/gobwas/ws v1.4.0
github.com/gofrs/uuid/v5 v5.3.2
@@ -30,11 +30,11 @@ require (
github.com/metacubex/sing-shadowsocks v0.2.12
github.com/metacubex/sing-shadowsocks2 v0.2.6
github.com/metacubex/sing-shadowtls v0.0.0-20250503063515-5d9f966d17a2
github.com/metacubex/sing-tun v0.4.8-0.20250826073243-05ab78f45ac4
github.com/metacubex/sing-tun v0.4.8-0.20250827085914-fc5681b9fc9f
github.com/metacubex/sing-vmess v0.2.4-0.20250822020810-4856053566f0
github.com/metacubex/sing-wireguard v0.0.0-20250503063753-2dc62acc626f
github.com/metacubex/smux v0.0.0-20250503055512-501391591dee
github.com/metacubex/tfo-go v0.0.0-20250516165257-e29c16ae41d4
github.com/metacubex/tfo-go v0.0.0-20250827083229-aa432b865617
github.com/metacubex/utls v1.8.1-0.20250823120917-12f5ba126142
github.com/metacubex/wireguard-go v0.0.0-20250820062549-a6cecdd7f57f
github.com/miekg/dns v1.1.63 // lastest version compatible with golang1.20
@@ -46,7 +46,7 @@ require (
github.com/samber/lo v1.51.0
github.com/shirou/gopsutil/v4 v4.25.1 // lastest version compatible with golang1.20
github.com/sirupsen/logrus v1.9.3
github.com/stretchr/testify v1.10.0
github.com/stretchr/testify v1.11.0
github.com/vmihailenco/msgpack/v5 v5.4.1
github.com/wk8/go-ordered-map/v2 v2.1.8
gitlab.com/go-extension/aes-ccm v0.0.0-20230221065045-e58665ef23c7
@@ -68,7 +68,7 @@ require (
github.com/andybalholm/brotli v1.0.6 // indirect
github.com/buger/jsonparser v1.1.1 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/ebitengine/purego v0.8.3 // indirect
github.com/ebitengine/purego v0.8.4 // indirect
github.com/ericlagergren/aegis v0.0.0-20250325060835-cd0defd64358 // indirect
github.com/ericlagergren/polyval v0.0.0-20220411101811-e25bc10ba391 // indirect
github.com/ericlagergren/siv v0.0.0-20220507050439-0b757b3aa5f1 // indirect
+12 -12
View File
@@ -23,10 +23,10 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dlclark/regexp2 v1.11.5 h1:Q/sSnsKerHeCkc/jSTNq1oCm7KiVgUMZRDUoRu0JQZQ=
github.com/dlclark/regexp2 v1.11.5/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
github.com/ebitengine/purego v0.8.3 h1:K+0AjQp63JEZTEMZiwsI9g0+hAMNohwUOtY0RPGexmc=
github.com/ebitengine/purego v0.8.3/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ=
github.com/enfein/mieru/v3 v3.19.0 h1:GXUTWoWmr8pTqGSTbh82VXfnCENJm6m5UN76c3Ynzfw=
github.com/enfein/mieru/v3 v3.19.0/go.mod h1:zJBUCsi5rxyvHM8fjFf+GLaEl4OEjjBXr1s5F6Qd3hM=
github.com/ebitengine/purego v0.8.4 h1:CF7LEKg5FFOsASUj0+QwaXf8Ht6TlFxg09+S9wz0omw=
github.com/ebitengine/purego v0.8.4/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ=
github.com/enfein/mieru/v3 v3.19.1 h1:19b9kgFC7oJXX9RLEO5Pi1gO6yek5cWlpK7IJVUoE8I=
github.com/enfein/mieru/v3 v3.19.1/go.mod h1:zJBUCsi5rxyvHM8fjFf+GLaEl4OEjjBXr1s5F6Qd3hM=
github.com/ericlagergren/aegis v0.0.0-20250325060835-cd0defd64358 h1:kXYqH/sL8dS/FdoFjr12ePjnLPorPo2FsnrHNuXSDyo=
github.com/ericlagergren/aegis v0.0.0-20250325060835-cd0defd64358/go.mod h1:hkIFzoiIPZYxdFOOLyDho59b7SrDfo+w3h+yWdlg45I=
github.com/ericlagergren/polyval v0.0.0-20220411101811-e25bc10ba391 h1:8j2RH289RJplhA6WfdaPqzg1MjH2K8wX5e0uhAxrw2g=
@@ -40,8 +40,8 @@ github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S
github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
github.com/gaukas/godicttls v0.0.4 h1:NlRaXb3J6hAnTmWdsEKb9bcSBD6BvcIjdGdeb0zfXbk=
github.com/gaukas/godicttls v0.0.4/go.mod h1:l6EenT4TLWgTdwslVb4sEMOCf7Bv0JAK67deKr9/NCI=
github.com/go-chi/chi/v5 v5.2.2 h1:CMwsvRVTbXVytCk1Wd72Zy1LAsAh9GxMmSNWLHCG618=
github.com/go-chi/chi/v5 v5.2.2/go.mod h1:L2yAIGWB3H+phAw1NxKwWM+7eUH/lU8pOMm5hHcoops=
github.com/go-chi/chi/v5 v5.2.3 h1:WQIt9uxdsAbgIYgid+BpYc+liqQZGMHRaUwp0JUcvdE=
github.com/go-chi/chi/v5 v5.2.3/go.mod h1:L2yAIGWB3H+phAw1NxKwWM+7eUH/lU8pOMm5hHcoops=
github.com/go-chi/render v1.0.3 h1:AsXqd2a1/INaIfUSKq3G5uA8weYx20FOsM7uSoCyyt4=
github.com/go-chi/render v1.0.3/go.mod h1:/gr3hVkmYR0YlEy3LxCuVRFzEu9Ruok+gFqbIofjao0=
github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ=
@@ -129,16 +129,16 @@ github.com/metacubex/sing-shadowsocks2 v0.2.6 h1:ZR1kYT0f0Vi64iQSS09OdhFfppiNkh7
github.com/metacubex/sing-shadowsocks2 v0.2.6/go.mod h1:vOEbfKC60txi0ca+yUlqEwOGc3Obl6cnSgx9Gf45KjE=
github.com/metacubex/sing-shadowtls v0.0.0-20250503063515-5d9f966d17a2 h1:gXU+MYPm7Wme3/OAY2FFzVq9d9GxPHOqu5AQfg/ddhI=
github.com/metacubex/sing-shadowtls v0.0.0-20250503063515-5d9f966d17a2/go.mod h1:mbfboaXauKJNIHJYxQRa+NJs4JU9NZfkA+I33dS2+9E=
github.com/metacubex/sing-tun v0.4.8-0.20250826073243-05ab78f45ac4 h1:GRfLW6QD1SfApCzi2SR8prAWVA//myGDq93YL4OE2T0=
github.com/metacubex/sing-tun v0.4.8-0.20250826073243-05ab78f45ac4/go.mod h1:FQ9zXA+kVhdzqgFqeJdi/AUhJgUgw+SUXqrR++GvbnM=
github.com/metacubex/sing-tun v0.4.8-0.20250827085914-fc5681b9fc9f h1:1MV/pFn2vjnyvH/0u6sJST0kmaoZXgbUytCCfuelhl8=
github.com/metacubex/sing-tun v0.4.8-0.20250827085914-fc5681b9fc9f/go.mod h1:FQ9zXA+kVhdzqgFqeJdi/AUhJgUgw+SUXqrR++GvbnM=
github.com/metacubex/sing-vmess v0.2.4-0.20250822020810-4856053566f0 h1:WZepq4TOZa6WewB8tGAZrrL+bL2R2ivoBzuEgAeolWc=
github.com/metacubex/sing-vmess v0.2.4-0.20250822020810-4856053566f0/go.mod h1:21R5R1u90uUvBQF0owoooEu96/SAYYD56nDrwm6nFaM=
github.com/metacubex/sing-wireguard v0.0.0-20250503063753-2dc62acc626f h1:Sr/DYKYofKHKc4GF3qkRGNuj6XA6c0eqPgEDN+VAsYU=
github.com/metacubex/sing-wireguard v0.0.0-20250503063753-2dc62acc626f/go.mod h1:jpAkVLPnCpGSfNyVmj6Cq4YbuZsFepm/Dc+9BAOcR80=
github.com/metacubex/smux v0.0.0-20250503055512-501391591dee h1:lp6hJ+4wCLZu113awp7P6odM2okB5s60HUyF0FMqKmo=
github.com/metacubex/smux v0.0.0-20250503055512-501391591dee/go.mod h1:4bPD8HWx9jPJ9aE4uadgyN7D1/Wz3KmPy+vale8sKLE=
github.com/metacubex/tfo-go v0.0.0-20250516165257-e29c16ae41d4 h1:j1VRTiC9JLR4nUbSikx9OGdu/3AgFDqgcLj4GoqyQkc=
github.com/metacubex/tfo-go v0.0.0-20250516165257-e29c16ae41d4/go.mod h1:l9oLnLoEXyGZ5RVLsh7QCC5XsouTUyKk4F2nLm2DHLw=
github.com/metacubex/tfo-go v0.0.0-20250827083229-aa432b865617 h1:yN3mQ4cT9sPUciw/rO0Isc/8QlO86DB6g9SEMRgQ8Cw=
github.com/metacubex/tfo-go v0.0.0-20250827083229-aa432b865617/go.mod h1:l9oLnLoEXyGZ5RVLsh7QCC5XsouTUyKk4F2nLm2DHLw=
github.com/metacubex/utls v1.8.1-0.20250823120917-12f5ba126142 h1:csEbKOzRAxJXffOeZnnS3/kA/F55JiTbKv5jcYqCXms=
github.com/metacubex/utls v1.8.1-0.20250823120917-12f5ba126142/go.mod h1:67I3skhEY4Sya8f1YxELwWPoeQdXqZCrWNYLvq8gn2U=
github.com/metacubex/wireguard-go v0.0.0-20250820062549-a6cecdd7f57f h1:FGBPRb1zUabhPhDrlKEjQ9lgIwQ6cHL4x8M9lrERhbk=
@@ -196,8 +196,8 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/stretchr/testify v1.11.0 h1:ib4sjIrwZKxE5u/Japgo/7SJV3PvgjGiRNAvTVGqQl8=
github.com/stretchr/testify v1.11.0/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFAEVmqU=
github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI=
github.com/tklauser/numcpus v0.6.1 h1:ng9scYS7az0Bk4OZLvrNXNSAO2Pxr1XXRAPyjhIx+Fk=
+2 -2
View File
@@ -1305,9 +1305,9 @@ dependencies = [
[[package]]
name = "camino"
version = "1.1.11"
version = "1.1.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5d07aa9a93b00c76f71bc35d598bed923f6d4f3a9ca5c24b7737ae1a292841c0"
checksum = "dd0b03af37dad7a14518b7691d81acb0f8222604ad3d1b02f6b4bed5188c0cd5"
dependencies = [
"serde",
]
@@ -59,9 +59,9 @@
"@iconify/json": "2.2.378",
"@monaco-editor/react": "4.7.0",
"@tanstack/react-query": "5.85.5",
"@tanstack/react-router": "1.131.27",
"@tanstack/react-router-devtools": "1.131.27",
"@tanstack/router-plugin": "1.131.27",
"@tanstack/react-router": "1.131.28",
"@tanstack/react-router-devtools": "1.131.28",
"@tanstack/router-plugin": "1.131.28",
"@tauri-apps/plugin-clipboard-manager": "2.3.0",
"@tauri-apps/plugin-dialog": "2.3.0",
"@tauri-apps/plugin-fs": "2.4.0",
@@ -71,7 +71,7 @@
"@tauri-apps/plugin-shell": "2.3.0",
"@tauri-apps/plugin-updater": "2.9.0",
"@types/react": "19.1.11",
"@types/react-dom": "19.1.7",
"@types/react-dom": "19.1.8",
"@types/validator": "13.15.2",
"@vitejs/plugin-legacy": "7.2.1",
"@vitejs/plugin-react": "5.0.1",
+2 -2
View File
@@ -2,7 +2,7 @@
"manifest_version": 1,
"latest": {
"mihomo": "v1.19.12",
"mihomo_alpha": "alpha-443200a",
"mihomo_alpha": "alpha-bf8d1e1",
"clash_rs": "v0.9.0",
"clash_premium": "2023-09-05-gdcc8d87",
"clash_rs_alpha": "0.9.0-alpha+sha.8791f7f"
@@ -69,5 +69,5 @@
"linux-armv7hf": "clash-armv7-unknown-linux-gnueabihf"
}
},
"updated_at": "2025-08-25T22:21:06.996Z"
"updated_at": "2025-08-26T22:20:55.772Z"
}
+169 -143
View File
@@ -250,7 +250,7 @@ importers:
version: 4.1.12
'@tanstack/router-zod-adapter':
specifier: 1.81.5
version: 1.81.5(@tanstack/react-router@1.131.27(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(zod@4.0.17)
version: 1.81.5(@tanstack/react-router@1.131.28(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(zod@4.0.17)
'@tauri-apps/api':
specifier: 2.6.0
version: 2.6.0
@@ -352,14 +352,14 @@ importers:
specifier: 5.85.5
version: 5.85.5(react@19.1.1)
'@tanstack/react-router':
specifier: 1.131.27
version: 1.131.27(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
specifier: 1.131.28
version: 1.131.28(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
'@tanstack/react-router-devtools':
specifier: 1.131.27
version: 1.131.27(@tanstack/react-router@1.131.27(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(@tanstack/router-core@1.131.27)(csstype@3.1.3)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(solid-js@1.9.5)(tiny-invariant@1.3.3)
specifier: 1.131.28
version: 1.131.28(@tanstack/react-router@1.131.28(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(@tanstack/router-core@1.131.28)(csstype@3.1.3)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(solid-js@1.9.5)(tiny-invariant@1.3.3)
'@tanstack/router-plugin':
specifier: 1.131.27
version: 1.131.27(@tanstack/react-router@1.131.27(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(vite@7.1.3(@types/node@22.18.0)(jiti@2.5.1)(less@4.2.0)(lightningcss@1.30.1)(sass-embedded@1.90.0)(sass@1.90.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.20.5)(yaml@2.8.1))
specifier: 1.131.28
version: 1.131.28(@tanstack/react-router@1.131.28(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(vite@7.1.3(@types/node@22.18.0)(jiti@2.5.1)(less@4.2.0)(lightningcss@1.30.1)(sass-embedded@1.90.0)(sass@1.90.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.20.5)(yaml@2.8.1))
'@tauri-apps/plugin-clipboard-manager':
specifier: 2.3.0
version: 2.3.0
@@ -388,8 +388,8 @@ importers:
specifier: 19.1.11
version: 19.1.11
'@types/react-dom':
specifier: 19.1.7
version: 19.1.7(@types/react@19.1.11)
specifier: 19.1.8
version: 19.1.8(@types/react@19.1.11)
'@types/validator':
specifier: 13.15.2
version: 13.15.2
@@ -473,10 +473,10 @@ importers:
version: 7.3.1(@emotion/react@11.14.0(@types/react@19.1.11)(react@19.1.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.1.11)(react@19.1.1))(@types/react@19.1.11)(react@19.1.1))(@types/react@19.1.11)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
'@radix-ui/react-portal':
specifier: 1.1.9
version: 1.1.9(@types/react-dom@19.1.7(@types/react@19.1.11))(@types/react@19.1.11)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
version: 1.1.9(@types/react-dom@19.1.8(@types/react@19.1.11))(@types/react@19.1.11)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
'@radix-ui/react-scroll-area':
specifier: 1.2.10
version: 1.2.10(@types/react-dom@19.1.7(@types/react@19.1.11))(@types/react@19.1.11)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
version: 1.2.10(@types/react-dom@19.1.8(@types/react@19.1.11))(@types/react@19.1.11)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
'@tauri-apps/api':
specifier: 2.6.0
version: 2.6.0
@@ -566,8 +566,8 @@ importers:
specifier: 11.0.2
version: 11.0.2
p-retry:
specifier: 6.2.1
version: 6.2.1
specifier: 7.0.0
version: 7.0.0
semver:
specifier: 7.7.2
version: 7.7.2
@@ -3021,16 +3021,16 @@ packages:
peerDependencies:
react: ^18 || ^19
'@tanstack/react-router-devtools@1.131.27':
resolution: {integrity: sha512-SHulN0a7hZvyl3fXi+VLHxdMKdsg1lhPOZeKd5xs6bu/x+N5FaXEA5bUPGB2sbiSYXw/XFcjUqR5dkw8T1dkXg==}
'@tanstack/react-router-devtools@1.131.28':
resolution: {integrity: sha512-2EOxuvc2k7vT14XVEGJRuqEZhQkZ7RnHwpw2aGY6m/7xprl2elNwKtLExTntirAxE6HDokg8sRAnqvySHf1OVA==}
engines: {node: '>=12'}
peerDependencies:
'@tanstack/react-router': ^1.131.27
'@tanstack/react-router': ^1.131.28
react: '>=18.0.0 || >=19.0.0'
react-dom: '>=18.0.0 || >=19.0.0'
'@tanstack/react-router@1.131.27':
resolution: {integrity: sha512-JLUsmlarNxMz7VDhFscZCqoc2quhocQZKhia/7YXWf8Jbc8rANk6lukK4ecYn92m/ytoHAAy77JeaB6n0HvqwQ==}
'@tanstack/react-router@1.131.28':
resolution: {integrity: sha512-vWExhrqHJuT9v+6/2DCQ4pVvPaYoLazMNw8WXiLNuzBXh1FuEoIGaW3jw3DEP0OJCmMiWtTi34NzQnakkQZlQg==}
engines: {node: '>=12'}
peerDependencies:
react: '>=18.0.0 || >=19.0.0'
@@ -3055,15 +3055,15 @@ packages:
react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
'@tanstack/router-core@1.131.27':
resolution: {integrity: sha512-NEBNxZ/LIBIh6kvQntr6bKq57tDe55zecyTtjAmzPkYFsMy1LXEpRm5H3BPiteBMRApAjuaq+bS1qA664hLH6Q==}
'@tanstack/router-core@1.131.28':
resolution: {integrity: sha512-f+vdfr3WKSS/BcqgI5s4vZg9xYb7NkvIolkaMELrbz3l+khkw1aTjx8wqCHRY4dqwIAxq+iZBZtMWXA7pztGJg==}
engines: {node: '>=12'}
'@tanstack/router-devtools-core@1.131.27':
resolution: {integrity: sha512-upoMv/uq1CQdrOyBO2h6CLXI1Ym7Rawoovt26fN1Wl+RMXqKGVpHAXYuKpugdFMFhFieccKVYcrj9NP4V5BIDw==}
'@tanstack/router-devtools-core@1.131.28':
resolution: {integrity: sha512-CPj8wv/00sfHm5tjUCJ44A5tWBYvui5PVstkNfEyNW/Cmo6aknMk4SHiWIa/khCbj5HGjVMWSBRn6XZixEdOxw==}
engines: {node: '>=12'}
peerDependencies:
'@tanstack/router-core': ^1.131.27
'@tanstack/router-core': ^1.131.28
csstype: ^3.0.10
solid-js: '>=1.9.5'
tiny-invariant: ^1.3.3
@@ -3071,16 +3071,16 @@ packages:
csstype:
optional: true
'@tanstack/router-generator@1.131.27':
resolution: {integrity: sha512-PXBIVl45q2bBq9g0DDXLBGeKjO9eExcZd2JotLjLdIJ0I/wdxPQOBJHLPZfnmbf3vispToedRvG3b1YDWjL48g==}
'@tanstack/router-generator@1.131.28':
resolution: {integrity: sha512-e/6+2bfKhdiAgbFh4X0fADcnS7jNr6HqmDQ8Dcx9zpIGzWnj3pi9HUfHi7kmgZvxtCv8286BdVJsC7PqgxFHJw==}
engines: {node: '>=12'}
'@tanstack/router-plugin@1.131.27':
resolution: {integrity: sha512-0V611ehOE8nfCFT2tvrLfQMroyoYW/virDXPaaFe38hdDxslmfCW2miJxngxz4+QqgK/M3sX71ElrZDvkP2Ixw==}
'@tanstack/router-plugin@1.131.28':
resolution: {integrity: sha512-7PxDjczsv90YQtphmjaakvHi8yF+d1mSs+ro8yIA/KrGD1+TaWvguAdFceDn/2ZGy5/tmCOVXQwuOg95HL8u6g==}
engines: {node: '>=12'}
peerDependencies:
'@rsbuild/core': '>=1.0.2'
'@tanstack/react-router': ^1.131.27
'@tanstack/react-router': ^1.131.28
vite: '>=5.0.0 || >=6.0.0'
vite-plugin-solid: ^2.11.2
webpack: '>=5.92.0'
@@ -3432,8 +3432,8 @@ packages:
'@types/prop-types@15.7.15':
resolution: {integrity: sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw==}
'@types/react-dom@19.1.7':
resolution: {integrity: sha512-i5ZzwYpqjmrKenzkoLM2Ibzt6mAsM7pxB6BCIouEVVmgiqaMj1TjaK7hnA36hbW5aZv20kx7Lw6hWzPWg0Rurw==}
'@types/react-dom@19.1.8':
resolution: {integrity: sha512-xG7xaBMJCpcK0RpN8jDbAACQo54ycO6h4dSSmgv8+fu6ZIAdANkx/WsawASUjVXYfy+J9AbUpRMNNEsXCDfDBQ==}
peerDependencies:
'@types/react': ^19.0.0
@@ -3448,9 +3448,6 @@ packages:
'@types/responselike@1.0.3':
resolution: {integrity: sha512-H/+L+UkTV33uf49PH5pCAUBVPNj2nDBXTN+qS1dOwyyg24l3CcicicCA7ca+HMvJBZcFgl5r8e+RR6elsb4Lyw==}
'@types/retry@0.12.2':
resolution: {integrity: sha512-XISRgDJ2Tc5q4TRqvgJtzsRkFYNJzZrhTdtMoGVBttwzzQJkPnS3WWTFc7kuDRoPtPakl+T+OfdEUjYJj7Jbow==}
'@types/semver@7.7.0':
resolution: {integrity: sha512-k107IF4+Xr7UHjwDc7Cfd6PRQfbdkiRabXGRjo07b4WyPahFBZCZ1sE+BNxYIJPPg73UkfOsVOLwqVc/6ETrIA==}
@@ -6790,9 +6787,9 @@ packages:
resolution: {integrity: sha512-wPrq66Llhl7/4AGC6I+cqxT07LhXvWL08LNXz1fENOw0Ap4sRZZ/gZpTTJ5jpurzzzfS2W/Ge9BY3LgLjCShcw==}
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
p-retry@6.2.1:
resolution: {integrity: sha512-hEt02O4hUct5wtwg4H4KcWgDdm+l1bOaEy/hWzd8xtXB9BqxTWBBhb+2ImAtH4Cv4rPjV76xN3Zumqk3k3AhhQ==}
engines: {node: '>=16.17'}
p-retry@7.0.0:
resolution: {integrity: sha512-3BgO9rjULJYyr0Y0pcsG7FZ+7JB/hfOODO8kx9ppumiO5jprUF92WK/Y7Q0xppZtq4VhTcPiVq7qWLQfIV5aKQ==}
engines: {node: '>=20'}
p-timeout@3.2.0:
resolution: {integrity: sha512-rhIwUycgwwKcP9yTOOFK/AKsAopjjCakVqLHePO3CC6Mir1Z99xT+R63jZxAT5lFZLa2inS5h+ZS2GvR99/FBg==}
@@ -7386,10 +7383,6 @@ packages:
resolution: {integrity: sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==}
engines: {node: '>=18'}
retry@0.13.1:
resolution: {integrity: sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==}
engines: {node: '>= 4'}
reusify@1.0.4:
resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==}
engines: {iojs: '>=1.0.0', node: '>=0.10.0'}
@@ -8829,11 +8822,11 @@ snapshots:
'@babel/helper-annotate-as-pure@7.25.9':
dependencies:
'@babel/types': 7.28.1
'@babel/types': 7.28.2
'@babel/helper-annotate-as-pure@7.27.3':
dependencies:
'@babel/types': 7.28.1
'@babel/types': 7.28.2
'@babel/helper-compilation-targets@7.26.5':
dependencies:
@@ -8859,7 +8852,7 @@ snapshots:
'@babel/helper-optimise-call-expression': 7.25.9
'@babel/helper-replace-supers': 7.25.9(@babel/core@7.26.10)
'@babel/helper-skip-transparent-expression-wrappers': 7.25.9
'@babel/traverse': 7.28.0
'@babel/traverse': 7.28.3
semver: 6.3.1
transitivePeerDependencies:
- supports-color
@@ -8872,7 +8865,20 @@ snapshots:
'@babel/helper-optimise-call-expression': 7.27.1
'@babel/helper-replace-supers': 7.27.1(@babel/core@7.28.0)
'@babel/helper-skip-transparent-expression-wrappers': 7.27.1
'@babel/traverse': 7.28.0
'@babel/traverse': 7.28.3
semver: 6.3.1
transitivePeerDependencies:
- supports-color
'@babel/helper-create-class-features-plugin@7.27.1(@babel/core@7.28.3)':
dependencies:
'@babel/core': 7.28.3
'@babel/helper-annotate-as-pure': 7.27.3
'@babel/helper-member-expression-to-functions': 7.27.1
'@babel/helper-optimise-call-expression': 7.27.1
'@babel/helper-replace-supers': 7.27.1(@babel/core@7.28.3)
'@babel/helper-skip-transparent-expression-wrappers': 7.27.1
'@babel/traverse': 7.28.3
semver: 6.3.1
transitivePeerDependencies:
- supports-color
@@ -8915,14 +8921,14 @@ snapshots:
'@babel/helper-member-expression-to-functions@7.25.9':
dependencies:
'@babel/traverse': 7.28.0
'@babel/types': 7.28.1
'@babel/traverse': 7.28.3
'@babel/types': 7.28.2
transitivePeerDependencies:
- supports-color
'@babel/helper-member-expression-to-functions@7.27.1':
dependencies:
'@babel/traverse': 7.28.0
'@babel/traverse': 7.28.3
'@babel/types': 7.28.2
transitivePeerDependencies:
- supports-color
@@ -8936,8 +8942,8 @@ snapshots:
'@babel/helper-module-imports@7.27.1':
dependencies:
'@babel/traverse': 7.28.0
'@babel/types': 7.28.1
'@babel/traverse': 7.28.3
'@babel/types': 7.28.2
transitivePeerDependencies:
- supports-color
@@ -8946,7 +8952,7 @@ snapshots:
'@babel/core': 7.26.10
'@babel/helper-module-imports': 7.25.9
'@babel/helper-validator-identifier': 7.27.1
'@babel/traverse': 7.28.0
'@babel/traverse': 7.28.3
transitivePeerDependencies:
- supports-color
@@ -8955,7 +8961,16 @@ snapshots:
'@babel/core': 7.28.0
'@babel/helper-module-imports': 7.27.1
'@babel/helper-validator-identifier': 7.27.1
'@babel/traverse': 7.28.0
'@babel/traverse': 7.28.3
transitivePeerDependencies:
- supports-color
'@babel/helper-module-transforms@7.28.3(@babel/core@7.28.0)':
dependencies:
'@babel/core': 7.28.0
'@babel/helper-module-imports': 7.27.1
'@babel/helper-validator-identifier': 7.27.1
'@babel/traverse': 7.28.3
transitivePeerDependencies:
- supports-color
@@ -8970,7 +8985,7 @@ snapshots:
'@babel/helper-optimise-call-expression@7.25.9':
dependencies:
'@babel/types': 7.28.1
'@babel/types': 7.28.2
'@babel/helper-optimise-call-expression@7.27.1':
dependencies:
@@ -8985,7 +9000,7 @@ snapshots:
'@babel/core': 7.28.0
'@babel/helper-annotate-as-pure': 7.27.3
'@babel/helper-wrap-function': 7.27.1
'@babel/traverse': 7.28.0
'@babel/traverse': 7.28.3
transitivePeerDependencies:
- supports-color
@@ -8994,7 +9009,7 @@ snapshots:
'@babel/core': 7.26.10
'@babel/helper-member-expression-to-functions': 7.25.9
'@babel/helper-optimise-call-expression': 7.25.9
'@babel/traverse': 7.28.0
'@babel/traverse': 7.28.3
transitivePeerDependencies:
- supports-color
@@ -9003,21 +9018,30 @@ snapshots:
'@babel/core': 7.28.0
'@babel/helper-member-expression-to-functions': 7.27.1
'@babel/helper-optimise-call-expression': 7.27.1
'@babel/traverse': 7.28.0
'@babel/traverse': 7.28.3
transitivePeerDependencies:
- supports-color
'@babel/helper-replace-supers@7.27.1(@babel/core@7.28.3)':
dependencies:
'@babel/core': 7.28.3
'@babel/helper-member-expression-to-functions': 7.27.1
'@babel/helper-optimise-call-expression': 7.27.1
'@babel/traverse': 7.28.3
transitivePeerDependencies:
- supports-color
'@babel/helper-skip-transparent-expression-wrappers@7.25.9':
dependencies:
'@babel/traverse': 7.28.0
'@babel/types': 7.28.1
'@babel/traverse': 7.28.3
'@babel/types': 7.28.2
transitivePeerDependencies:
- supports-color
'@babel/helper-skip-transparent-expression-wrappers@7.27.1':
dependencies:
'@babel/traverse': 7.28.0
'@babel/types': 7.28.1
'@babel/traverse': 7.28.3
'@babel/types': 7.28.2
transitivePeerDependencies:
- supports-color
@@ -9037,7 +9061,7 @@ snapshots:
'@babel/helper-wrap-function@7.27.1':
dependencies:
'@babel/template': 7.27.2
'@babel/traverse': 7.28.0
'@babel/traverse': 7.28.3
'@babel/types': 7.28.2
transitivePeerDependencies:
- supports-color
@@ -9045,12 +9069,12 @@ snapshots:
'@babel/helpers@7.27.0':
dependencies:
'@babel/template': 7.27.2
'@babel/types': 7.28.1
'@babel/types': 7.28.2
'@babel/helpers@7.27.6':
dependencies:
'@babel/template': 7.27.2
'@babel/types': 7.28.1
'@babel/types': 7.28.2
'@babel/helpers@7.28.3':
dependencies:
@@ -9073,7 +9097,7 @@ snapshots:
dependencies:
'@babel/core': 7.28.0
'@babel/helper-plugin-utils': 7.27.1
'@babel/traverse': 7.28.0
'@babel/traverse': 7.28.3
transitivePeerDependencies:
- supports-color
@@ -9100,7 +9124,7 @@ snapshots:
dependencies:
'@babel/core': 7.28.0
'@babel/helper-plugin-utils': 7.27.1
'@babel/traverse': 7.28.0
'@babel/traverse': 7.28.3
transitivePeerDependencies:
- supports-color
@@ -9126,14 +9150,14 @@ snapshots:
'@babel/core': 7.28.0
'@babel/helper-plugin-utils': 7.27.1
'@babel/plugin-syntax-jsx@7.27.1(@babel/core@7.28.0)':
'@babel/plugin-syntax-jsx@7.27.1(@babel/core@7.28.3)':
dependencies:
'@babel/core': 7.28.0
'@babel/core': 7.28.3
'@babel/helper-plugin-utils': 7.27.1
'@babel/plugin-syntax-typescript@7.27.1(@babel/core@7.28.0)':
'@babel/plugin-syntax-typescript@7.27.1(@babel/core@7.28.3)':
dependencies:
'@babel/core': 7.28.0
'@babel/core': 7.28.3
'@babel/helper-plugin-utils': 7.27.1
'@babel/plugin-syntax-unicode-sets-regex@7.18.6(@babel/core@7.28.0)':
@@ -9152,7 +9176,7 @@ snapshots:
'@babel/core': 7.28.0
'@babel/helper-plugin-utils': 7.27.1
'@babel/helper-remap-async-to-generator': 7.27.1(@babel/core@7.28.0)
'@babel/traverse': 7.28.0
'@babel/traverse': 7.28.3
transitivePeerDependencies:
- supports-color
@@ -9199,7 +9223,7 @@ snapshots:
'@babel/helper-globals': 7.28.0
'@babel/helper-plugin-utils': 7.27.1
'@babel/helper-replace-supers': 7.27.1(@babel/core@7.28.0)
'@babel/traverse': 7.28.0
'@babel/traverse': 7.28.3
transitivePeerDependencies:
- supports-color
@@ -9213,7 +9237,7 @@ snapshots:
dependencies:
'@babel/core': 7.28.0
'@babel/helper-plugin-utils': 7.27.1
'@babel/traverse': 7.28.0
'@babel/traverse': 7.28.3
transitivePeerDependencies:
- supports-color
@@ -9270,7 +9294,7 @@ snapshots:
'@babel/core': 7.28.0
'@babel/helper-compilation-targets': 7.27.2
'@babel/helper-plugin-utils': 7.27.1
'@babel/traverse': 7.28.0
'@babel/traverse': 7.28.3
transitivePeerDependencies:
- supports-color
@@ -9297,7 +9321,7 @@ snapshots:
'@babel/plugin-transform-modules-amd@7.27.1(@babel/core@7.28.0)':
dependencies:
'@babel/core': 7.28.0
'@babel/helper-module-transforms': 7.27.3(@babel/core@7.28.0)
'@babel/helper-module-transforms': 7.28.3(@babel/core@7.28.0)
'@babel/helper-plugin-utils': 7.27.1
transitivePeerDependencies:
- supports-color
@@ -9305,7 +9329,15 @@ snapshots:
'@babel/plugin-transform-modules-commonjs@7.27.1(@babel/core@7.28.0)':
dependencies:
'@babel/core': 7.28.0
'@babel/helper-module-transforms': 7.27.3(@babel/core@7.28.0)
'@babel/helper-module-transforms': 7.28.3(@babel/core@7.28.0)
'@babel/helper-plugin-utils': 7.27.1
transitivePeerDependencies:
- supports-color
'@babel/plugin-transform-modules-commonjs@7.27.1(@babel/core@7.28.3)':
dependencies:
'@babel/core': 7.28.3
'@babel/helper-module-transforms': 7.28.3(@babel/core@7.28.3)
'@babel/helper-plugin-utils': 7.27.1
transitivePeerDependencies:
- supports-color
@@ -9323,7 +9355,7 @@ snapshots:
'@babel/plugin-transform-modules-umd@7.27.1(@babel/core@7.28.0)':
dependencies:
'@babel/core': 7.28.0
'@babel/helper-module-transforms': 7.27.3(@babel/core@7.28.0)
'@babel/helper-module-transforms': 7.28.3(@babel/core@7.28.0)
'@babel/helper-plugin-utils': 7.27.1
transitivePeerDependencies:
- supports-color
@@ -9356,7 +9388,7 @@ snapshots:
'@babel/helper-plugin-utils': 7.27.1
'@babel/plugin-transform-destructuring': 7.28.0(@babel/core@7.28.0)
'@babel/plugin-transform-parameters': 7.27.7(@babel/core@7.28.0)
'@babel/traverse': 7.28.0
'@babel/traverse': 7.28.3
transitivePeerDependencies:
- supports-color
@@ -9462,14 +9494,14 @@ snapshots:
'@babel/core': 7.28.0
'@babel/helper-plugin-utils': 7.27.1
'@babel/plugin-transform-typescript@7.27.1(@babel/core@7.28.0)':
'@babel/plugin-transform-typescript@7.27.1(@babel/core@7.28.3)':
dependencies:
'@babel/core': 7.28.0
'@babel/core': 7.28.3
'@babel/helper-annotate-as-pure': 7.27.3
'@babel/helper-create-class-features-plugin': 7.27.1(@babel/core@7.28.0)
'@babel/helper-create-class-features-plugin': 7.27.1(@babel/core@7.28.3)
'@babel/helper-plugin-utils': 7.27.1
'@babel/helper-skip-transparent-expression-wrappers': 7.27.1
'@babel/plugin-syntax-typescript': 7.27.1(@babel/core@7.28.0)
'@babel/plugin-syntax-typescript': 7.27.1(@babel/core@7.28.3)
transitivePeerDependencies:
- supports-color
@@ -9576,17 +9608,17 @@ snapshots:
dependencies:
'@babel/core': 7.28.0
'@babel/helper-plugin-utils': 7.27.1
'@babel/types': 7.28.1
'@babel/types': 7.28.2
esutils: 2.0.3
'@babel/preset-typescript@7.27.1(@babel/core@7.28.0)':
'@babel/preset-typescript@7.27.1(@babel/core@7.28.3)':
dependencies:
'@babel/core': 7.28.0
'@babel/core': 7.28.3
'@babel/helper-plugin-utils': 7.27.1
'@babel/helper-validator-option': 7.27.1
'@babel/plugin-syntax-jsx': 7.27.1(@babel/core@7.28.0)
'@babel/plugin-transform-modules-commonjs': 7.27.1(@babel/core@7.28.0)
'@babel/plugin-transform-typescript': 7.27.1(@babel/core@7.28.0)
'@babel/plugin-syntax-jsx': 7.27.1(@babel/core@7.28.3)
'@babel/plugin-transform-modules-commonjs': 7.27.1(@babel/core@7.28.3)
'@babel/plugin-transform-typescript': 7.27.1(@babel/core@7.28.3)
transitivePeerDependencies:
- supports-color
@@ -9604,13 +9636,13 @@ snapshots:
dependencies:
'@babel/code-frame': 7.27.1
'@babel/parser': 7.28.0
'@babel/types': 7.28.1
'@babel/types': 7.28.2
'@babel/template@7.27.2':
dependencies:
'@babel/code-frame': 7.27.1
'@babel/parser': 7.28.0
'@babel/types': 7.28.1
'@babel/parser': 7.28.3
'@babel/types': 7.28.2
'@babel/traverse@7.23.2':
dependencies:
@@ -10804,17 +10836,17 @@ snapshots:
optionalDependencies:
'@types/react': 19.1.11
'@radix-ui/react-portal@1.1.9(@types/react-dom@19.1.7(@types/react@19.1.11))(@types/react@19.1.11)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)':
'@radix-ui/react-portal@1.1.9(@types/react-dom@19.1.8(@types/react@19.1.11))(@types/react@19.1.11)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)':
dependencies:
'@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.7(@types/react@19.1.11))(@types/react@19.1.11)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
'@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.8(@types/react@19.1.11))(@types/react@19.1.11)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
'@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.1.11)(react@19.1.1)
react: 19.1.1
react-dom: 19.1.1(react@19.1.1)
optionalDependencies:
'@types/react': 19.1.11
'@types/react-dom': 19.1.7(@types/react@19.1.11)
'@types/react-dom': 19.1.8(@types/react@19.1.11)
'@radix-ui/react-presence@1.1.5(@types/react-dom@19.1.7(@types/react@19.1.11))(@types/react@19.1.11)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)':
'@radix-ui/react-presence@1.1.5(@types/react-dom@19.1.8(@types/react@19.1.11))(@types/react@19.1.11)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)':
dependencies:
'@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.11)(react@19.1.1)
'@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.1.11)(react@19.1.1)
@@ -10822,33 +10854,33 @@ snapshots:
react-dom: 19.1.1(react@19.1.1)
optionalDependencies:
'@types/react': 19.1.11
'@types/react-dom': 19.1.7(@types/react@19.1.11)
'@types/react-dom': 19.1.8(@types/react@19.1.11)
'@radix-ui/react-primitive@2.1.3(@types/react-dom@19.1.7(@types/react@19.1.11))(@types/react@19.1.11)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)':
'@radix-ui/react-primitive@2.1.3(@types/react-dom@19.1.8(@types/react@19.1.11))(@types/react@19.1.11)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)':
dependencies:
'@radix-ui/react-slot': 1.2.3(@types/react@19.1.11)(react@19.1.1)
react: 19.1.1
react-dom: 19.1.1(react@19.1.1)
optionalDependencies:
'@types/react': 19.1.11
'@types/react-dom': 19.1.7(@types/react@19.1.11)
'@types/react-dom': 19.1.8(@types/react@19.1.11)
'@radix-ui/react-scroll-area@1.2.10(@types/react-dom@19.1.7(@types/react@19.1.11))(@types/react@19.1.11)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)':
'@radix-ui/react-scroll-area@1.2.10(@types/react-dom@19.1.8(@types/react@19.1.11))(@types/react@19.1.11)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)':
dependencies:
'@radix-ui/number': 1.1.1
'@radix-ui/primitive': 1.1.3
'@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.11)(react@19.1.1)
'@radix-ui/react-context': 1.1.2(@types/react@19.1.11)(react@19.1.1)
'@radix-ui/react-direction': 1.1.1(@types/react@19.1.11)(react@19.1.1)
'@radix-ui/react-presence': 1.1.5(@types/react-dom@19.1.7(@types/react@19.1.11))(@types/react@19.1.11)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
'@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.7(@types/react@19.1.11))(@types/react@19.1.11)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
'@radix-ui/react-presence': 1.1.5(@types/react-dom@19.1.8(@types/react@19.1.11))(@types/react@19.1.11)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
'@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.8(@types/react@19.1.11))(@types/react@19.1.11)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
'@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.1.11)(react@19.1.1)
'@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.1.11)(react@19.1.1)
react: 19.1.1
react-dom: 19.1.1(react@19.1.1)
optionalDependencies:
'@types/react': 19.1.11
'@types/react-dom': 19.1.7(@types/react@19.1.11)
'@types/react-dom': 19.1.8(@types/react@19.1.11)
'@radix-ui/react-slot@1.2.3(@types/react@19.1.11)(react@19.1.1)':
dependencies:
@@ -11248,10 +11280,10 @@ snapshots:
'@tanstack/query-core': 5.85.5
react: 19.1.1
'@tanstack/react-router-devtools@1.131.27(@tanstack/react-router@1.131.27(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(@tanstack/router-core@1.131.27)(csstype@3.1.3)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(solid-js@1.9.5)(tiny-invariant@1.3.3)':
'@tanstack/react-router-devtools@1.131.28(@tanstack/react-router@1.131.28(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(@tanstack/router-core@1.131.28)(csstype@3.1.3)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(solid-js@1.9.5)(tiny-invariant@1.3.3)':
dependencies:
'@tanstack/react-router': 1.131.27(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
'@tanstack/router-devtools-core': 1.131.27(@tanstack/router-core@1.131.27)(csstype@3.1.3)(solid-js@1.9.5)(tiny-invariant@1.3.3)
'@tanstack/react-router': 1.131.28(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
'@tanstack/router-devtools-core': 1.131.28(@tanstack/router-core@1.131.28)(csstype@3.1.3)(solid-js@1.9.5)(tiny-invariant@1.3.3)
react: 19.1.1
react-dom: 19.1.1(react@19.1.1)
transitivePeerDependencies:
@@ -11260,11 +11292,11 @@ snapshots:
- solid-js
- tiny-invariant
'@tanstack/react-router@1.131.27(react-dom@19.1.1(react@19.1.1))(react@19.1.1)':
'@tanstack/react-router@1.131.28(react-dom@19.1.1(react@19.1.1))(react@19.1.1)':
dependencies:
'@tanstack/history': 1.131.2
'@tanstack/react-store': 0.7.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
'@tanstack/router-core': 1.131.27
'@tanstack/router-core': 1.131.28
isbot: 5.1.28
react: 19.1.1
react-dom: 19.1.1(react@19.1.1)
@@ -11290,7 +11322,7 @@ snapshots:
react: 19.1.1
react-dom: 19.1.1(react@19.1.1)
'@tanstack/router-core@1.131.27':
'@tanstack/router-core@1.131.28':
dependencies:
'@tanstack/history': 1.131.2
'@tanstack/store': 0.7.0
@@ -11300,9 +11332,9 @@ snapshots:
tiny-invariant: 1.3.3
tiny-warning: 1.0.3
'@tanstack/router-devtools-core@1.131.27(@tanstack/router-core@1.131.27)(csstype@3.1.3)(solid-js@1.9.5)(tiny-invariant@1.3.3)':
'@tanstack/router-devtools-core@1.131.28(@tanstack/router-core@1.131.28)(csstype@3.1.3)(solid-js@1.9.5)(tiny-invariant@1.3.3)':
dependencies:
'@tanstack/router-core': 1.131.27
'@tanstack/router-core': 1.131.28
clsx: 2.1.1
goober: 2.1.16(csstype@3.1.3)
solid-js: 1.9.5
@@ -11310,9 +11342,9 @@ snapshots:
optionalDependencies:
csstype: 3.1.3
'@tanstack/router-generator@1.131.27':
'@tanstack/router-generator@1.131.28':
dependencies:
'@tanstack/router-core': 1.131.27
'@tanstack/router-core': 1.131.28
'@tanstack/router-utils': 1.131.2
'@tanstack/virtual-file-routes': 1.131.2
prettier: 3.6.2
@@ -11323,16 +11355,16 @@ snapshots:
transitivePeerDependencies:
- supports-color
'@tanstack/router-plugin@1.131.27(@tanstack/react-router@1.131.27(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(vite@7.1.3(@types/node@22.18.0)(jiti@2.5.1)(less@4.2.0)(lightningcss@1.30.1)(sass-embedded@1.90.0)(sass@1.90.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.20.5)(yaml@2.8.1))':
'@tanstack/router-plugin@1.131.28(@tanstack/react-router@1.131.28(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(vite@7.1.3(@types/node@22.18.0)(jiti@2.5.1)(less@4.2.0)(lightningcss@1.30.1)(sass-embedded@1.90.0)(sass@1.90.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.20.5)(yaml@2.8.1))':
dependencies:
'@babel/core': 7.28.0
'@babel/plugin-syntax-jsx': 7.27.1(@babel/core@7.28.0)
'@babel/plugin-syntax-typescript': 7.27.1(@babel/core@7.28.0)
'@babel/core': 7.28.3
'@babel/plugin-syntax-jsx': 7.27.1(@babel/core@7.28.3)
'@babel/plugin-syntax-typescript': 7.27.1(@babel/core@7.28.3)
'@babel/template': 7.27.2
'@babel/traverse': 7.28.0
'@babel/types': 7.28.1
'@tanstack/router-core': 1.131.27
'@tanstack/router-generator': 1.131.27
'@babel/traverse': 7.28.3
'@babel/types': 7.28.2
'@tanstack/router-core': 1.131.28
'@tanstack/router-generator': 1.131.28
'@tanstack/router-utils': 1.131.2
'@tanstack/virtual-file-routes': 1.131.2
babel-dead-code-elimination: 1.0.10
@@ -11340,25 +11372,25 @@ snapshots:
unplugin: 2.3.5
zod: 3.25.76
optionalDependencies:
'@tanstack/react-router': 1.131.27(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
'@tanstack/react-router': 1.131.28(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
vite: 7.1.3(@types/node@22.18.0)(jiti@2.5.1)(less@4.2.0)(lightningcss@1.30.1)(sass-embedded@1.90.0)(sass@1.90.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.20.5)(yaml@2.8.1)
transitivePeerDependencies:
- supports-color
'@tanstack/router-utils@1.131.2':
dependencies:
'@babel/core': 7.28.0
'@babel/generator': 7.28.0
'@babel/parser': 7.28.0
'@babel/preset-typescript': 7.27.1(@babel/core@7.28.0)
'@babel/core': 7.28.3
'@babel/generator': 7.28.3
'@babel/parser': 7.28.3
'@babel/preset-typescript': 7.27.1(@babel/core@7.28.3)
ansis: 4.1.0
diff: 8.0.2
transitivePeerDependencies:
- supports-color
'@tanstack/router-zod-adapter@1.81.5(@tanstack/react-router@1.131.27(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(zod@4.0.17)':
'@tanstack/router-zod-adapter@1.81.5(@tanstack/react-router@1.131.28(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(zod@4.0.17)':
dependencies:
'@tanstack/react-router': 1.131.27(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
'@tanstack/react-router': 1.131.28(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
zod: 4.0.17
'@tanstack/store@0.7.0': {}
@@ -11490,23 +11522,23 @@ snapshots:
'@types/babel__core@7.20.5':
dependencies:
'@babel/parser': 7.28.0
'@babel/types': 7.28.1
'@babel/types': 7.28.2
'@types/babel__generator': 7.6.8
'@types/babel__template': 7.4.4
'@types/babel__traverse': 7.20.6
'@types/babel__generator@7.6.8':
dependencies:
'@babel/types': 7.28.1
'@babel/types': 7.28.2
'@types/babel__template@7.4.4':
dependencies:
'@babel/parser': 7.28.0
'@babel/types': 7.28.1
'@babel/parser': 7.28.3
'@babel/types': 7.28.2
'@types/babel__traverse@7.20.6':
dependencies:
'@babel/types': 7.28.1
'@babel/types': 7.28.2
'@types/cacheable-request@6.0.3':
dependencies:
@@ -11707,7 +11739,7 @@ snapshots:
'@types/prop-types@15.7.15': {}
'@types/react-dom@19.1.7(@types/react@19.1.11)':
'@types/react-dom@19.1.8(@types/react@19.1.11)':
dependencies:
'@types/react': 19.1.11
@@ -11723,8 +11755,6 @@ snapshots:
dependencies:
'@types/node': 22.18.0
'@types/retry@0.12.2': {}
'@types/semver@7.7.0': {}
'@types/unist@2.0.10': {}
@@ -12011,7 +12041,7 @@ snapshots:
'@vue/compiler-core@3.5.13':
dependencies:
'@babel/parser': 7.28.0
'@babel/parser': 7.28.3
'@vue/shared': 3.5.13
entities: 4.5.0
estree-walker: 2.0.2
@@ -12300,10 +12330,10 @@ snapshots:
babel-dead-code-elimination@1.0.10:
dependencies:
'@babel/core': 7.28.0
'@babel/parser': 7.28.0
'@babel/traverse': 7.28.0
'@babel/types': 7.28.1
'@babel/core': 7.28.3
'@babel/parser': 7.28.3
'@babel/traverse': 7.28.3
'@babel/types': 7.28.2
transitivePeerDependencies:
- supports-color
@@ -15636,11 +15666,9 @@ snapshots:
dependencies:
p-limit: 4.0.0
p-retry@6.2.1:
p-retry@7.0.0:
dependencies:
'@types/retry': 0.12.2
is-network-error: 1.1.0
retry: 0.13.1
p-timeout@3.2.0:
dependencies:
@@ -16195,8 +16223,6 @@ snapshots:
onetime: 7.0.0
signal-exit: 4.1.0
retry@0.13.1: {}
reusify@1.0.4: {}
rfdc@1.4.1: {}
+1 -1
View File
@@ -8,7 +8,7 @@
"@types/semver": "7.7.0",
"figlet": "1.8.2",
"filesize": "11.0.2",
"p-retry": "6.2.1",
"p-retry": "7.0.0",
"semver": "7.7.2",
"zod": "4.0.17"
},
@@ -578,7 +578,7 @@ SVN-Revision: 35130
goto next_ht;
--- a/net/ipv6/ip6_offload.c
+++ b/net/ipv6/ip6_offload.c
@@ -269,7 +269,7 @@ INDIRECT_CALLABLE_SCOPE struct sk_buff *
@@ -271,7 +271,7 @@ INDIRECT_CALLABLE_SCOPE struct sk_buff *
continue;
iph2 = (struct ipv6hdr *)(p->data + off);
@@ -1248,7 +1248,7 @@ Signed-off-by: Jonathan Bell <jonathan@raspberrypi.com>
}
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -5757,7 +5757,7 @@ static void port_event(struct usb_hub *h
@@ -5786,7 +5786,7 @@ static void port_event(struct usb_hub *h
port_dev->over_current_count++;
port_over_current_notify(port_dev);
@@ -18589,7 +18589,7 @@ Signed-off-by: j-schambacher <joerg@hifiberry.com>
u32 xfer_resolution;
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -1434,7 +1434,15 @@ int snd_soc_runtime_set_dai_fmt(struct s
@@ -1437,7 +1437,15 @@ int snd_soc_runtime_set_dai_fmt(struct s
return 0;
for_each_rtd_codec_dais(rtd, i, codec_dai) {
@@ -1,31 +0,0 @@
From 6fd71667a133560b84946a5008e3c9375b5115b7 Mon Sep 17 00:00:00 2001
From: Dave Stevenson <dave.stevenson@raspberrypi.org>
Date: Wed, 31 Oct 2018 14:56:59 +0000
Subject: [PATCH] media: tc358743: Increase FIFO level to 374.
The existing fixed value of 16 worked for UYVY 720P60 over
2 lanes at 594MHz, or UYVY 1080P60 over 4 lanes. (RGB888
1080P60 needs 6 lanes at 594MHz).
It doesn't allow for lower resolutions to work as the FIFO
underflows.
374 is required for 1080P24-30 UYVY over 2 lanes @ 972Mbit/s, but
>374 means that the FIFO underflows on 1080P50 UYVY over 2 lanes
@ 972Mbit/s.
Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
---
drivers/media/i2c/tc358743.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
--- a/drivers/media/i2c/tc358743.c
+++ b/drivers/media/i2c/tc358743.c
@@ -1942,7 +1942,7 @@ static int tc358743_probe_of(struct tc35
state->pdata.ddc5v_delay = DDC5V_DELAY_100_MS;
state->pdata.enable_hdcp = false;
/* A FIFO level of 16 should be enough for 2-lane 720p60 at 594 MHz. */
- state->pdata.fifo_level = 16;
+ state->pdata.fifo_level = 374;
/*
* The PLL input clock is obtained by dividing refclk by pll_prd.
* It must be between 6 MHz and 40 MHz, lower frequency is better.
@@ -24,7 +24,7 @@ Signed-off-by: Jacko Dirks <jdirks.linuxdev@gmail.com>
--- a/drivers/media/i2c/tc358743.c
+++ b/drivers/media/i2c/tc358743.c
@@ -1962,6 +1962,7 @@ static int tc358743_probe_of(struct tc35
@@ -1980,6 +1980,7 @@ static int tc358743_probe_of(struct tc35
/*
* The CSI bps per lane must be between 62.5 Mbps and 1 Gbps.
* The default is 594 Mbps for 4-lane 1080p60 or 2-lane 720p60.
@@ -32,7 +32,7 @@ Signed-off-by: Jacko Dirks <jdirks.linuxdev@gmail.com>
*/
bps_pr_lane = 2 * endpoint.link_frequencies[0];
if (bps_pr_lane < 62500000U || bps_pr_lane > 1000000000U) {
@@ -1975,23 +1976,42 @@ static int tc358743_probe_of(struct tc35
@@ -1993,23 +1994,42 @@ static int tc358743_probe_of(struct tc35
state->pdata.refclk_hz * state->pdata.pll_prd;
/*
@@ -1,98 +0,0 @@
From 307615221ab3249fcfdd21b81a8aca138ed7a1ed Mon Sep 17 00:00:00 2001
From: Dave Stevenson <dave.stevenson@raspberrypi.org>
Date: Wed, 31 Oct 2018 14:57:34 +0000
Subject: [PATCH] media: tc358743: Check I2C succeeded during probe.
The probe for the TC358743 reads the CHIPID register from
the device and compares it to the expected value of 0.
If the I2C request fails then that also returns 0, so
the driver loads thinking that the device is there.
Generally I2C communications are reliable so there is
limited need to check the return value on every transfer,
therefore only amend the one read during probe to check
for I2C errors.
Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
---
drivers/media/i2c/tc358743.c | 27 +++++++++++++++++++++++----
1 file changed, 23 insertions(+), 4 deletions(-)
--- a/drivers/media/i2c/tc358743.c
+++ b/drivers/media/i2c/tc358743.c
@@ -110,7 +110,7 @@ static inline struct tc358743_state *to_
/* --------------- I2C --------------- */
-static void i2c_rd(struct v4l2_subdev *sd, u16 reg, u8 *values, u32 n)
+static int i2c_rd(struct v4l2_subdev *sd, u16 reg, u8 *values, u32 n)
{
struct tc358743_state *state = to_state(sd);
struct i2c_client *client = state->i2c_client;
@@ -136,6 +136,7 @@ static void i2c_rd(struct v4l2_subdev *s
v4l2_err(sd, "%s: reading register 0x%x from 0x%x failed: %d\n",
__func__, reg, client->addr, err);
}
+ return err != ARRAY_SIZE(msgs);
}
static void i2c_wr(struct v4l2_subdev *sd, u16 reg, u8 *values, u32 n)
@@ -192,15 +193,24 @@ static void i2c_wr(struct v4l2_subdev *s
}
}
-static noinline u32 i2c_rdreg(struct v4l2_subdev *sd, u16 reg, u32 n)
+static noinline u32 i2c_rdreg_err(struct v4l2_subdev *sd, u16 reg, u32 n,
+ int *err)
{
+ int error;
__le32 val = 0;
- i2c_rd(sd, reg, (u8 __force *)&val, n);
+ error = i2c_rd(sd, reg, (u8 __force *)&val, n);
+ if (err)
+ *err = error;
return le32_to_cpu(val);
}
+static inline u32 i2c_rdreg(struct v4l2_subdev *sd, u16 reg, u32 n)
+{
+ return i2c_rdreg_err(sd, reg, n, NULL);
+}
+
static noinline void i2c_wrreg(struct v4l2_subdev *sd, u16 reg, u32 val, u32 n)
{
__le32 raw = cpu_to_le32(val);
@@ -229,6 +239,13 @@ static u16 i2c_rd16(struct v4l2_subdev *
return i2c_rdreg(sd, reg, 2);
}
+static int i2c_rd16_err(struct v4l2_subdev *sd, u16 reg, u16 *value)
+{
+ int err;
+ *value = i2c_rdreg_err(sd, reg, 2, &err);
+ return err;
+}
+
static void i2c_wr16(struct v4l2_subdev *sd, u16 reg, u16 val)
{
i2c_wrreg(sd, reg, val, 2);
@@ -2050,6 +2067,7 @@ static int tc358743_probe(struct i2c_cli
struct tc358743_platform_data *pdata = client->dev.platform_data;
struct v4l2_subdev *sd;
u16 irq_mask = MASK_HDMI_MSK | MASK_CSI_MSK;
+ u16 chipid;
int err;
if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
@@ -2081,7 +2099,8 @@ static int tc358743_probe(struct i2c_cli
sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS;
/* i2c access */
- if ((i2c_rd16(sd, CHIPID) & MASK_CHIPID) != 0) {
+ if (i2c_rd16_err(sd, CHIPID, &chipid) ||
+ (chipid & MASK_CHIPID) != 0) {
v4l2_info(sd, "not a TC358743 on address 0x%x\n",
client->addr << 1);
return -ENODEV;
@@ -1,110 +0,0 @@
From 1745cb8447123a894db6c0b579259ec5d976808f Mon Sep 17 00:00:00 2001
From: Dave Stevenson <dave.stevenson@raspberrypi.org>
Date: Thu, 22 Nov 2018 17:31:06 +0000
Subject: [PATCH] media: tc358743: Return an appropriate colorspace from
tc358743_set_fmt
When calling tc358743_set_fmt, the code was calling tc358743_get_fmt
to choose a valid format. However that sets the colorspace
based on what was read back from the chip. When you set the format,
then the driver would choose and program the colorspace based
on the format code.
The result was that if you called try or set format for UYVY
when the current format was RGB3 then you would get told sRGB,
and try RGB3 when current was UYVY and you would get told
SMPTE170M.
The value programmed into the chip is determined by this driver,
therefore there is no need to read back the value. Return the
colorspace based on the format set/tried instead.
Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
media: i2c: tc358743: Only allow supported pixel fmts in set_fmt
Fix commit "media: tc358743: Return an appropriate colorspace from
tc358743_set_fmt" to ensure that the format passed in to set_fmt
is checked to be valid, and reset to the current format if not.
Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
---
drivers/media/i2c/tc358743.c | 44 ++++++++++++++----------------------
1 file changed, 17 insertions(+), 27 deletions(-)
--- a/drivers/media/i2c/tc358743.c
+++ b/drivers/media/i2c/tc358743.c
@@ -1677,12 +1677,23 @@ static int tc358743_enum_mbus_code(struc
return 0;
}
+static u32 tc358743_g_colorspace(u32 code)
+{
+ switch (code) {
+ case MEDIA_BUS_FMT_RGB888_1X24:
+ return V4L2_COLORSPACE_SRGB;
+ case MEDIA_BUS_FMT_UYVY8_1X16:
+ return V4L2_COLORSPACE_SMPTE170M;
+ default:
+ return 0;
+ }
+}
+
static int tc358743_get_fmt(struct v4l2_subdev *sd,
struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *format)
{
struct tc358743_state *state = to_state(sd);
- u8 vi_rep = i2c_rd8(sd, VI_REP);
if (format->pad != 0)
return -EINVAL;
@@ -1692,23 +1703,7 @@ static int tc358743_get_fmt(struct v4l2_
format->format.height = state->timings.bt.height;
format->format.field = V4L2_FIELD_NONE;
- switch (vi_rep & MASK_VOUT_COLOR_SEL) {
- case MASK_VOUT_COLOR_RGB_FULL:
- case MASK_VOUT_COLOR_RGB_LIMITED:
- format->format.colorspace = V4L2_COLORSPACE_SRGB;
- break;
- case MASK_VOUT_COLOR_601_YCBCR_LIMITED:
- case MASK_VOUT_COLOR_601_YCBCR_FULL:
- format->format.colorspace = V4L2_COLORSPACE_SMPTE170M;
- break;
- case MASK_VOUT_COLOR_709_YCBCR_FULL:
- case MASK_VOUT_COLOR_709_YCBCR_LIMITED:
- format->format.colorspace = V4L2_COLORSPACE_REC709;
- break;
- default:
- format->format.colorspace = 0;
- break;
- }
+ format->format.colorspace = tc358743_g_colorspace(format->format.code);
return 0;
}
@@ -1722,19 +1717,14 @@ static int tc358743_set_fmt(struct v4l2_
u32 code = format->format.code; /* is overwritten by get_fmt */
int ret = tc358743_get_fmt(sd, sd_state, format);
- format->format.code = code;
+ if (code == MEDIA_BUS_FMT_RGB888_1X24 ||
+ code == MEDIA_BUS_FMT_UYVY8_1X16)
+ format->format.code = code;
+ format->format.colorspace = tc358743_g_colorspace(format->format.code);
if (ret)
return ret;
- switch (code) {
- case MEDIA_BUS_FMT_RGB888_1X24:
- case MEDIA_BUS_FMT_UYVY8_1X16:
- break;
- default:
- return -EINVAL;
- }
-
if (format->which == V4L2_SUBDEV_FORMAT_TRY)
return 0;
@@ -14,7 +14,7 @@ Signed-off-by: Jonathan Bell <jonathan@raspberrypi.org>
--- a/drivers/usb/host/xhci.c
+++ b/drivers/usb/host/xhci.c
@@ -1517,6 +1517,109 @@ static int xhci_check_ep0_maxpacket(stru
@@ -1519,6 +1519,109 @@ static int xhci_check_ep0_maxpacket(stru
}
/*
@@ -124,7 +124,7 @@ Signed-off-by: Jonathan Bell <jonathan@raspberrypi.org>
* non-error returns are a promise to giveback() the urb later
* we drop ownership so next owner (or urb unlink) can get it
*/
@@ -5381,6 +5484,7 @@ static const struct hc_driver xhci_hc_dr
@@ -5383,6 +5486,7 @@ static const struct hc_driver xhci_hc_dr
.endpoint_reset = xhci_endpoint_reset,
.check_bandwidth = xhci_check_bandwidth,
.reset_bandwidth = xhci_reset_bandwidth,
@@ -19,7 +19,7 @@ Signed-off-by: Jonathan Bell <jonathan@raspberrypi.com>
--- a/drivers/usb/host/xhci.c
+++ b/drivers/usb/host/xhci.c
@@ -1606,7 +1606,7 @@ static void xhci_fixup_endpoint(struct u
@@ -1608,7 +1608,7 @@ static void xhci_fixup_endpoint(struct u
return;
}
ctrl_ctx->add_flags = xhci_get_endpoint_flag_from_index(ep_index);
@@ -32,7 +32,7 @@ Signed-off-by: Jonathan Bell <jonathan@raspberrypi.org>
#define USB_VENDOR_ID_BELKIN 0x050d
#define USB_DEVICE_ID_FLIP_KVM 0x3201
@@ -1460,6 +1463,9 @@
@@ -1463,6 +1466,9 @@
#define USB_VENDOR_ID_XIAOMI 0x2717
#define USB_DEVICE_ID_MI_SILENT_MOUSE 0x5014
@@ -26,7 +26,7 @@ Signed-off-by: Jonathan Bell <jonathan@raspberrypi.org>
return;
val = bcm_phy_read_shadow(phydev, BCM54XX_SHD_SCR3);
@@ -1444,7 +1445,7 @@ static struct phy_driver broadcom_driver
@@ -1461,7 +1462,7 @@ static struct phy_driver broadcom_driver
.link_change_notify = bcm54xx_link_change_notify,
}, {
.phy_id = PHY_ID_BCM54210E,
@@ -35,7 +35,7 @@ Signed-off-by: Jonathan Bell <jonathan@raspberrypi.org>
.name = "Broadcom BCM54210E",
/* PHY_GBIT_FEATURES */
.flags = PHY_ALWAYS_CALL_SUSPEND,
@@ -1462,6 +1463,13 @@ static struct phy_driver broadcom_driver
@@ -1479,6 +1480,13 @@ static struct phy_driver broadcom_driver
.set_wol = bcm54xx_phy_set_wol,
.led_brightness_set = bcm_phy_led_brightness_set,
}, {
@@ -49,7 +49,7 @@ Signed-off-by: Jonathan Bell <jonathan@raspberrypi.org>
.phy_id = PHY_ID_BCM5461,
.phy_id_mask = 0xfffffff0,
.name = "Broadcom BCM5461",
@@ -1728,7 +1736,8 @@ module_phy_driver(broadcom_drivers);
@@ -1745,7 +1753,8 @@ module_phy_driver(broadcom_drivers);
static const struct mdio_device_id __maybe_unused broadcom_tbl[] = {
{ PHY_ID_BCM5411, 0xfffffff0 },
{ PHY_ID_BCM5421, 0xfffffff0 },
@@ -95,7 +95,7 @@ Signed-off-by: Phil Elwell <phil@raspberrypi.com>
#include <video/mipi_display.h>
@@ -1131,6 +1133,7 @@ static struct fbtft_platform_data *fbtft
@@ -1132,6 +1134,7 @@ static struct fbtft_platform_data *fbtft
* @display: Display properties
* @sdev: SPI device
* @pdev: Platform device
@@ -103,7 +103,7 @@ Signed-off-by: Phil Elwell <phil@raspberrypi.com>
*
* Allocates, initializes and registers a framebuffer
*
@@ -1140,12 +1143,15 @@ static struct fbtft_platform_data *fbtft
@@ -1141,12 +1144,15 @@ static struct fbtft_platform_data *fbtft
*/
int fbtft_probe_common(struct fbtft_display *display,
struct spi_device *sdev,
@@ -120,7 +120,7 @@ Signed-off-by: Phil Elwell <phil@raspberrypi.com>
int ret;
if (sdev)
@@ -1158,6 +1164,14 @@ int fbtft_probe_common(struct fbtft_disp
@@ -1159,6 +1165,14 @@ int fbtft_probe_common(struct fbtft_disp
pdata = fbtft_properties_read(dev);
if (IS_ERR(pdata))
return PTR_ERR(pdata);
@@ -165,7 +165,7 @@ Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
if (IS_ERR(data->cdev_data[cdev_idx].cdev)) {
dev_err(dev, "Failed to register cooling device %s\n", emc2305_fan_name[idx]);
@@ -347,9 +410,11 @@ static void emc2305_unset_tz(struct devi
@@ -353,9 +416,11 @@ static void emc2305_unset_tz(struct devi
int i;
/* Unregister cooling device. */
@@ -180,7 +180,7 @@ Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
}
static umode_t
@@ -571,11 +636,18 @@ static int emc2305_probe(struct i2c_clie
@@ -577,11 +642,18 @@ static int emc2305_probe(struct i2c_clie
data->pwm_separate = pdata->pwm_separate;
for (i = 0; i < EMC2305_PWM_MAX; i++)
data->pwm_min[i] = pdata->pwm_min[i];
@@ -199,7 +199,7 @@ Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
}
data->hwmon_dev = devm_hwmon_device_register_with_info(dev, "emc2305", data,
@@ -596,6 +668,12 @@ static int emc2305_probe(struct i2c_clie
@@ -602,6 +674,12 @@ static int emc2305_probe(struct i2c_clie
return ret;
}
@@ -212,7 +212,7 @@ Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
return 0;
}
@@ -610,6 +688,7 @@ static void emc2305_remove(struct i2c_cl
@@ -616,6 +694,7 @@ static void emc2305_remove(struct i2c_cl
static struct i2c_driver emc2305_driver = {
.driver = {
.name = "emc2305",
@@ -16,7 +16,7 @@ Signed-off-by: Jonathan Lemon <jonathan.lemon@gmail.com>
--- a/drivers/net/phy/broadcom.c
+++ b/drivers/net/phy/broadcom.c
@@ -1478,8 +1478,14 @@ static struct phy_driver broadcom_driver
@@ -1495,8 +1495,14 @@ static struct phy_driver broadcom_driver
.phy_id_mask = 0xffffffff,
.name = "Broadcom BCM54213PE",
/* PHY_GBIT_FEATURES */
@@ -22,7 +22,7 @@ Signed-off-by: Phil Elwell <phil@raspberrypi.com>
#include <linux/of_irq.h>
#include <linux/platform_device.h>
#include <linux/scatterlist.h>
@@ -1347,8 +1346,8 @@ static int bcm2835_probe(struct platform
@@ -1348,8 +1347,8 @@ static int bcm2835_probe(struct platform
struct device *dev = &pdev->dev;
struct clk *clk;
struct bcm2835_host *host;
@@ -32,7 +32,7 @@ Signed-off-by: Phil Elwell <phil@raspberrypi.com>
int ret;
dev_dbg(dev, "%s\n", __func__);
@@ -1361,23 +1360,13 @@ static int bcm2835_probe(struct platform
@@ -1362,23 +1361,13 @@ static int bcm2835_probe(struct platform
host->pdev = pdev;
spin_lock_init(&host->lock);
@@ -22,7 +22,7 @@ Signed-off-by: Phil Elwell <phil@raspberrypi.com>
--- a/drivers/pps/pps.c
+++ b/drivers/pps/pps.c
@@ -249,12 +249,13 @@ static long pps_cdev_ioctl(struct file *
@@ -254,12 +254,13 @@ static long pps_cdev_ioctl(struct file *
static long pps_cdev_compat_ioctl(struct file *file,
unsigned int cmd, unsigned long arg)
{
@@ -38,7 +38,7 @@ Signed-off-by: Phil Elwell <phil@raspberrypi.com>
struct pps_fdata_compat compat;
struct pps_fdata fdata;
int err;
@@ -289,6 +290,7 @@ static long pps_cdev_compat_ioctl(struct
@@ -296,6 +297,7 @@ static long pps_cdev_compat_ioctl(struct
return copy_to_user(uarg, &compat,
sizeof(struct pps_fdata_compat)) ? -EFAULT : 0;
}
@@ -34,7 +34,7 @@ Signed-off-by: Jonathan Bell <jonathan@raspberrypi.com>
--- a/drivers/usb/host/xhci-mem.c
+++ b/drivers/usb/host/xhci-mem.c
@@ -1395,6 +1395,7 @@ int xhci_endpoint_init(struct xhci_hcd *
@@ -1397,6 +1397,7 @@ int xhci_endpoint_init(struct xhci_hcd *
unsigned int ep_index;
struct xhci_ep_ctx *ep_ctx;
struct xhci_ring *ep_ring;
@@ -42,7 +42,7 @@ Signed-off-by: Jonathan Bell <jonathan@raspberrypi.com>
unsigned int max_packet;
enum xhci_ring_type ring_type;
u32 max_esit_payload;
@@ -1404,6 +1405,8 @@ int xhci_endpoint_init(struct xhci_hcd *
@@ -1406,6 +1407,8 @@ int xhci_endpoint_init(struct xhci_hcd *
unsigned int mult;
unsigned int avg_trb_len;
unsigned int err_count = 0;
@@ -51,7 +51,7 @@ Signed-off-by: Jonathan Bell <jonathan@raspberrypi.com>
ep_index = xhci_get_endpoint_index(&ep->desc);
ep_ctx = xhci_get_ep_ctx(xhci, virt_dev->in_ctx, ep_index);
@@ -1439,9 +1442,35 @@ int xhci_endpoint_init(struct xhci_hcd *
@@ -1441,9 +1444,35 @@ int xhci_endpoint_init(struct xhci_hcd *
mult = xhci_get_endpoint_mult(udev, ep);
max_packet = usb_endpoint_maxp(&ep->desc);
@@ -75,7 +75,7 @@ Signed-off-by: Jonathan Bell <jonathan@raspberrypi.com>
if (pdev->vendor == PCI_VENDOR_ID_ASMEDIA &&
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
@@ -3656,6 +3656,48 @@ static int xhci_align_td(struct xhci_hcd
@@ -3659,6 +3659,48 @@ static int xhci_align_td(struct xhci_hcd
return 1;
}
@@ -124,7 +124,7 @@ Signed-off-by: Jonathan Bell <jonathan@raspberrypi.com>
/* This is very similar to what ehci-q.c qtd_fill() does */
int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
struct urb *urb, int slot_id, unsigned int ep_index)
@@ -3810,6 +3852,8 @@ int xhci_queue_bulk_tx(struct xhci_hcd *
@@ -3813,6 +3855,8 @@ int xhci_queue_bulk_tx(struct xhci_hcd *
}
check_trb_math(urb, enqd_len);
@@ -133,7 +133,7 @@ Signed-off-by: Jonathan Bell <jonathan@raspberrypi.com>
giveback_first_trb(xhci, slot_id, ep_index, urb->stream_id,
start_cycle, start_trb);
return 0;
@@ -3958,6 +4002,8 @@ int xhci_queue_ctrl_tx(struct xhci_hcd *
@@ -3961,6 +4005,8 @@ int xhci_queue_ctrl_tx(struct xhci_hcd *
/* Event on completion */
field | TRB_IOC | TRB_TYPE(TRB_STATUS) | ep_ring->cycle_state);
@@ -1,20 +0,0 @@
From c921a4d6cfed23d22f583dd18a25f61fdde3735a Mon Sep 17 00:00:00 2001
From: Phil Elwell <phil@raspberrypi.com>
Date: Thu, 27 May 2021 11:46:30 +0100
Subject: [PATCH] Allow RESET_BRCMSTB on ARCH_BCM2835
---
drivers/reset/Kconfig | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
--- a/drivers/reset/Kconfig
+++ b/drivers/reset/Kconfig
@@ -51,7 +51,7 @@ config RESET_BERLIN
config RESET_BRCMSTB
tristate "Broadcom STB reset controller"
- depends on ARCH_BRCMSTB || COMPILE_TEST
+ depends on ARCH_BRCMSTB || ARCH_BCM2835 || COMPILE_TEST
default ARCH_BRCMSTB
help
This enables the reset controller driver for Broadcom STB SoCs using
@@ -31,7 +31,7 @@ Signed-off-by: Jonathan Bell <jonathan@raspberrypi.com>
--- a/drivers/irqchip/Kconfig
+++ b/drivers/irqchip/Kconfig
@@ -109,6 +109,14 @@ config I8259
@@ -110,6 +110,14 @@ config I8259
bool
select IRQ_DOMAIN
@@ -36,9 +36,9 @@ Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
+ fb_info->node = i;
+ }
if (!fb_info->modelist.prev || !fb_info->modelist.next)
INIT_LIST_HEAD(&fb_info->modelist);
@@ -411,7 +415,6 @@ static int do_register_framebuffer(struc
if (i >= FB_MAX)
return -ENXIO;
@@ -414,7 +418,6 @@ static int do_register_framebuffer(struc
if (err < 0)
return err;
@@ -46,7 +46,7 @@ Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
refcount_set(&fb_info->count, 1);
mutex_init(&fb_info->lock);
mutex_init(&fb_info->mm_lock);
@@ -442,7 +445,7 @@ static int do_register_framebuffer(struc
@@ -445,7 +448,7 @@ static int do_register_framebuffer(struc
pm_vt_switch_required(fb_info->device, true);
num_registered_fb++;
@@ -55,7 +55,7 @@ Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
#ifdef CONFIG_GUMSTIX_AM200EPD
{
@@ -503,6 +506,12 @@ static void do_unregister_framebuffer(st
@@ -506,6 +509,12 @@ static void do_unregister_framebuffer(st
put_fb_info(fb_info);
}
@@ -16,7 +16,7 @@ Signed-off-by: Phil Elwell <phil@raspberrypi.com>
--- a/mm/vmscan.c
+++ b/mm/vmscan.c
@@ -4128,7 +4128,7 @@ bool lru_gen_look_around(struct page_vma
@@ -4136,7 +4136,7 @@ bool lru_gen_look_around(struct page_vma
if (!folio)
continue;
@@ -32,7 +32,7 @@ Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
drm_printf(p, "\tmode: " DRM_MODE_FMT "\n", DRM_MODE_ARG(&state->mode));
--- a/drivers/gpu/drm/drm_framebuffer.c
+++ b/drivers/gpu/drm/drm_framebuffer.c
@@ -975,7 +975,7 @@ static int atomic_remove_fb(struct drm_f
@@ -1002,7 +1002,7 @@ static int atomic_remove_fb(struct drm_f
struct drm_connector *conn __maybe_unused;
struct drm_connector_state *conn_state;
int i, ret;
@@ -18,7 +18,7 @@ Signed-off-by: Phil Elwell <phil@raspberrypi.com>
--- a/drivers/nvme/host/pci.c
+++ b/drivers/nvme/host/pci.c
@@ -2083,6 +2083,7 @@ static void nvme_free_host_mem(struct nv
@@ -2103,6 +2103,7 @@ static void nvme_free_host_mem(struct nv
dev->nr_host_mem_descs = 0;
}
@@ -26,7 +26,7 @@ Signed-off-by: Phil Elwell <phil@raspberrypi.com>
static int __nvme_alloc_host_mem(struct nvme_dev *dev, u64 preferred,
u32 chunk_size)
{
@@ -2151,9 +2152,11 @@ out:
@@ -2171,9 +2172,11 @@ out:
dev->host_mem_descs = NULL;
return -ENOMEM;
}
@@ -38,7 +38,7 @@ Signed-off-by: Phil Elwell <phil@raspberrypi.com>
u64 min_chunk = min_t(u64, preferred, PAGE_SIZE * MAX_ORDER_NR_PAGES);
u64 hmminds = max_t(u32, dev->ctrl.hmminds * 4096, PAGE_SIZE * 2);
u64 chunk_size;
@@ -2166,6 +2169,7 @@ static int nvme_alloc_host_mem(struct nv
@@ -2186,6 +2189,7 @@ static int nvme_alloc_host_mem(struct nv
nvme_free_host_mem(dev);
}
}
@@ -65,7 +65,7 @@ Signed-off-by: Phil Elwell <phil@raspberrypi.com>
}
static void bcm2835_reset(struct mmc_host *mmc)
@@ -595,6 +607,25 @@ static void bcm2835_finish_request(struc
@@ -596,6 +608,25 @@ static void bcm2835_finish_request(struc
mrq = host->mrq;
@@ -91,7 +91,7 @@ Signed-off-by: Phil Elwell <phil@raspberrypi.com>
host->mrq = NULL;
host->cmd = NULL;
host->data = NULL;
@@ -1091,8 +1122,13 @@ static void bcm2835_dma_complete_work(st
@@ -1092,8 +1123,13 @@ static void bcm2835_dma_complete_work(st
static void bcm2835_set_clock(struct bcm2835_host *host, unsigned int clock)
{
struct mmc_host *mmc = mmc_from_priv(host);
@@ -105,7 +105,7 @@ Signed-off-by: Phil Elwell <phil@raspberrypi.com>
/* The SDCDIV register has 11 bits, and holds (div - 2). But
* in data mode the max is 50MHz wihout a minimum, and only
* the bottom 3 bits are used. Since the switch over is
@@ -1114,38 +1150,78 @@ static void bcm2835_set_clock(struct bcm
@@ -1115,38 +1151,78 @@ static void bcm2835_set_clock(struct bcm
* clock divisor at all times.
*/
@@ -205,7 +205,7 @@ Signed-off-by: Phil Elwell <phil@raspberrypi.com>
}
static void bcm2835_request(struct mmc_host *mmc, struct mmc_request *mrq)
@@ -1175,6 +1251,9 @@ static void bcm2835_request(struct mmc_h
@@ -1176,6 +1252,9 @@ static void bcm2835_request(struct mmc_h
return;
}
@@ -215,7 +215,7 @@ Signed-off-by: Phil Elwell <phil@raspberrypi.com>
mutex_lock(&host->mutex);
WARN_ON(host->mrq);
@@ -1198,7 +1277,7 @@ static void bcm2835_request(struct mmc_h
@@ -1199,7 +1278,7 @@ static void bcm2835_request(struct mmc_h
return;
}
@@ -224,7 +224,7 @@ Signed-off-by: Phil Elwell <phil@raspberrypi.com>
bcm2835_prepare_dma(host, mrq->data);
host->use_sbc = !!mrq->sbc && host->mrq->data &&
@@ -1333,8 +1412,8 @@ static int bcm2835_add_host(struct bcm28
@@ -1334,8 +1413,8 @@ static int bcm2835_add_host(struct bcm28
}
pio_limit_string[0] = '\0';
@@ -235,7 +235,7 @@ Signed-off-by: Phil Elwell <phil@raspberrypi.com>
dev_info(dev, "loaded - DMA %s%s\n",
host->use_dma ? "enabled" : "disabled", pio_limit_string);
@@ -1344,10 +1423,13 @@ static int bcm2835_add_host(struct bcm28
@@ -1345,10 +1424,13 @@ static int bcm2835_add_host(struct bcm28
static int bcm2835_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
@@ -250,7 +250,7 @@ Signed-off-by: Phil Elwell <phil@raspberrypi.com>
int ret;
dev_dbg(dev, "%s\n", __func__);
@@ -1367,6 +1449,23 @@ static int bcm2835_probe(struct platform
@@ -1368,6 +1450,23 @@ static int bcm2835_probe(struct platform
}
host->phys_addr = iomem->start;
@@ -274,7 +274,7 @@ Signed-off-by: Phil Elwell <phil@raspberrypi.com>
host->dma_chan = NULL;
host->dma_desc = NULL;
@@ -1389,6 +1488,24 @@ static int bcm2835_probe(struct platform
@@ -1390,6 +1489,24 @@ static int bcm2835_probe(struct platform
goto err;
}
@@ -21,7 +21,7 @@ Signed-off-by: Stanimir Varbanov <svarbanov@suse.de>
--- a/drivers/irqchip/Kconfig
+++ b/drivers/irqchip/Kconfig
@@ -110,12 +110,20 @@ config I8259
@@ -111,12 +111,20 @@ config I8259
select IRQ_DOMAIN
config BCM2712_MIP

Some files were not shown because too many files have changed in this diff Show More