diff --git a/.github/update.log b/.github/update.log index 68126a9444..659ecc6d50 100644 --- a/.github/update.log +++ b/.github/update.log @@ -1094,3 +1094,4 @@ Update On Fri Aug 15 20:40:48 CEST 2025 Update On Sat Aug 16 20:36:37 CEST 2025 Update On Sun Aug 17 20:39:03 CEST 2025 Update On Mon Aug 18 20:42:30 CEST 2025 +Update On Tue Aug 19 20:36:45 CEST 2025 diff --git a/clash-meta/adapter/outbound/mieru.go b/clash-meta/adapter/outbound/mieru.go index fca7ede4c8..8ef9cfd758 100644 --- a/clash-meta/adapter/outbound/mieru.go +++ b/clash-meta/adapter/outbound/mieru.go @@ -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 } diff --git a/clash-meta/docs/config.yaml b/clash-meta/docs/config.yaml index e4c5e7534a..445c61a388 100644 --- a/clash-meta/docs/config.yaml +++ b/clash-meta/docs/config.yaml @@ -933,6 +933,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 @@ -1475,6 +1477,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 diff --git a/clash-meta/go.mod b/clash-meta/go.mod index 1845c53242..2e19c8a24a 100644 --- a/clash-meta/go.mod +++ b/clash-meta/go.mod @@ -6,7 +6,7 @@ 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.16.1 + github.com/enfein/mieru/v3 v3.19.0 github.com/go-chi/chi/v5 v5.2.2 github.com/go-chi/render v1.0.3 github.com/gobwas/ws v1.4.0 @@ -31,7 +31,7 @@ require ( 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 - github.com/metacubex/sing-vmess v0.2.4-0.20250817075824-5e05f123ccdd + github.com/metacubex/sing-vmess v0.2.4-0.20250819151326-51d195aac5db 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 diff --git a/clash-meta/go.sum b/clash-meta/go.sum index 90fcddcc18..18cbabb0a0 100644 --- a/clash-meta/go.sum +++ b/clash-meta/go.sum @@ -25,8 +25,8 @@ github.com/dlclark/regexp2 v1.11.5 h1:Q/sSnsKerHeCkc/jSTNq1oCm7KiVgUMZRDUoRu0JQZ 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/enfein/mieru/v3 v3.19.0 h1:GXUTWoWmr8pTqGSTbh82VXfnCENJm6m5UN76c3Ynzfw= +github.com/enfein/mieru/v3 v3.19.0/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= @@ -131,8 +131,8 @@ github.com/metacubex/sing-shadowtls v0.0.0-20250503063515-5d9f966d17a2 h1:gXU+MY 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 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.20250817075824-5e05f123ccdd h1:VfD6UxKPAg7u9rPyxl18lQkpE9s8dZq0u2cPAgQShWs= -github.com/metacubex/sing-vmess v0.2.4-0.20250817075824-5e05f123ccdd/go.mod h1:21R5R1u90uUvBQF0owoooEu96/SAYYD56nDrwm6nFaM= +github.com/metacubex/sing-vmess v0.2.4-0.20250819151326-51d195aac5db h1:W7VKxR0r5IR+56Lblx2iyrEaykx0esdQwTQbkSrSaek= +github.com/metacubex/sing-vmess v0.2.4-0.20250819151326-51d195aac5db/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= diff --git a/clash-meta/listener/reality/reality.go b/clash-meta/listener/reality/reality.go index d91055f8ed..256dbcf6a9 100644 --- a/clash-meta/listener/reality/reality.go +++ b/clash-meta/listener/reality/reality.go @@ -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 +} diff --git a/clash-meta/listener/sing_vless/server.go b/clash-meta/listener/sing_vless/server.go index d386ef670b..7dfcd0102e 100644 --- a/clash-meta/listener/sing_vless/server.go +++ b/clash-meta/listener/sing_vless/server.go @@ -25,11 +25,12 @@ import ( "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 } @@ -37,7 +38,7 @@ 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 } @@ -45,7 +46,7 @@ func init() { }) vless.RegisterTLS(func(conn net.Conn) (loaded bool, netConn net.Conn, reflectType reflect.Type, reflectPointer unsafe.Pointer) { - tlsConn, loaded := common.Cast[*encryption.ClientConn](conn) + tlsConn, loaded := network.CastReader[*encryption.ClientConn](conn) if !loaded { return } @@ -53,7 +54,7 @@ func init() { }) vless.RegisterTLS(func(conn net.Conn) (loaded bool, netConn net.Conn, reflectType reflect.Type, reflectPointer unsafe.Pointer) { - tlsConn, loaded := common.Cast[*encryption.ServerConn](conn) + tlsConn, loaded := network.CastReader[*encryption.ServerConn](conn) if !loaded { return } diff --git a/clash-meta/transport/vless/encryption/client.go b/clash-meta/transport/vless/encryption/client.go index 9d24903886..ecf20692ea 100644 --- a/clash-meta/transport/vless/encryption/client.go +++ b/clash-meta/transport/vless/encryption/client.go @@ -69,8 +69,8 @@ func (i *ClientInstance) Init(nfsEKeyBytes []byte, xor uint32, minutes time.Dura if err != nil { return } - hash256 := sha3.Sum256(nfsEKeyBytes) - copy(i.hash11[:], hash256[:]) + hash32 := sha3.Sum256(nfsEKeyBytes) + copy(i.hash11[:], hash32[:]) if xor > 0 { xorKey := sha3.Sum256(nfsEKeyBytes) i.xorKey = xorKey[:] @@ -79,7 +79,7 @@ func (i *ClientInstance) Init(nfsEKeyBytes []byte, xor uint32, minutes time.Dura return } -func (i *ClientInstance) Handshake(conn net.Conn) (net.Conn, error) { +func (i *ClientInstance) Handshake(conn net.Conn) (*ClientConn, error) { if i.nfsEKey == nil { return nil, errors.New("uninitialized") } diff --git a/clash-meta/transport/vless/encryption/doc.go b/clash-meta/transport/vless/encryption/doc.go index 9ba7eb113d..6f0c8f7039 100644 --- a/clash-meta/transport/vless/encryption/doc.go +++ b/clash-meta/transport/vless/encryption/doc.go @@ -13,4 +13,5 @@ // 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 package encryption diff --git a/clash-meta/transport/vless/encryption/server.go b/clash-meta/transport/vless/encryption/server.go index 9c5c102e8c..ea72f2f5cf 100644 --- a/clash-meta/transport/vless/encryption/server.go +++ b/clash-meta/transport/vless/encryption/server.go @@ -54,8 +54,8 @@ func (i *ServerInstance) Init(nfsDKeySeed []byte, xor uint32, minutes time.Durat if err != nil { return } - hash256 := sha3.Sum256(i.nfsDKey.EncapsulationKey().Bytes()) - copy(i.hash11[:], hash256[:]) + hash32 := sha3.Sum256(i.nfsDKey.EncapsulationKey().Bytes()) + copy(i.hash11[:], hash32[:]) if xor > 0 { xorKey := sha3.Sum256(i.nfsDKey.EncapsulationKey().Bytes()) i.xorKey = xorKey[:] @@ -91,7 +91,7 @@ func (i *ServerInstance) Close() (err error) { return } -func (i *ServerInstance) Handshake(conn net.Conn) (net.Conn, error) { +func (i *ServerInstance) Handshake(conn net.Conn) (*ServerConn, error) { if i.nfsDKey == nil { return nil, errors.New("uninitialized") } diff --git a/clash-meta/transport/vless/encryption/xor.go b/clash-meta/transport/vless/encryption/xor.go index 69ff15780f..caad12bf07 100644 --- a/clash-meta/transport/vless/encryption/xor.go +++ b/clash-meta/transport/vless/encryption/xor.go @@ -49,6 +49,7 @@ func (c *XorConn) Write(b []byte) (int, error) { // whole one/two records l += 10 if t == 0 { c.out_after0 = true + c.out_header = make([]byte, 0, 5) // important } } c.ctr.XORKeyStream(b[:l], b[:l]) // caller MUST discard b @@ -77,7 +78,7 @@ func (c *XorConn) Write(b []byte) (int, error) { // whole one/two records break } _, c.out_skip, _ = DecodeHeader(append(c.out_header, p[:need]...)) - c.out_header = make([]byte, 0, 5) // DO NOT CHANGE + c.out_header = c.out_header[:0] c.ctr.XORKeyStream(p[:need], p[:need]) p = p[need:] } @@ -116,6 +117,7 @@ func (c *XorConn) Read(b []byte) (int, error) { // 5-bytes, data, 5-bytes... c.isHeader = false if t == 0 { c.in_after0 = true + c.in_header = make([]byte, 0, 5) // important } } } else { @@ -139,7 +141,7 @@ func (c *XorConn) Read(b []byte) (int, error) { // 5-bytes, data, 5-bytes... } c.peerCtr.XORKeyStream(p[:need], p[:need]) _, c.in_skip, _ = DecodeHeader(append(c.in_header, p[:need]...)) - c.in_header = make([]byte, 0, 5) // DO NOT CHANGE + c.in_header = c.in_header[:0] p = p[need:] } return n, err diff --git a/clash-nyanpasu/frontend/nyanpasu/package.json b/clash-nyanpasu/frontend/nyanpasu/package.json index 7482c2eb3b..b72ee2edb1 100644 --- a/clash-nyanpasu/frontend/nyanpasu/package.json +++ b/clash-nyanpasu/frontend/nyanpasu/package.json @@ -22,7 +22,7 @@ "@mui/x-date-pickers": "8.10.0", "@nyanpasu/interface": "workspace:^", "@nyanpasu/ui": "workspace:^", - "@tailwindcss/postcss": "4.1.11", + "@tailwindcss/postcss": "4.1.12", "@tanstack/router-zod-adapter": "1.81.5", "@tauri-apps/api": "2.6.0", "@types/json-schema": "7.0.15", @@ -56,12 +56,12 @@ "@csstools/normalize.css": "12.1.1", "@emotion/babel-plugin": "11.13.5", "@emotion/react": "11.14.0", - "@iconify/json": "2.2.375", + "@iconify/json": "2.2.376", "@monaco-editor/react": "4.7.0", "@tanstack/react-query": "5.84.2", - "@tanstack/react-router": "1.131.26", - "@tanstack/react-router-devtools": "1.131.26", - "@tanstack/router-plugin": "1.131.26", + "@tanstack/react-router": "1.131.27", + "@tanstack/react-router-devtools": "1.131.27", + "@tanstack/router-plugin": "1.131.27", "@tauri-apps/plugin-clipboard-manager": "2.3.0", "@tauri-apps/plugin-dialog": "2.3.0", "@tauri-apps/plugin-fs": "2.4.0", diff --git a/clash-nyanpasu/frontend/ui/package.json b/clash-nyanpasu/frontend/ui/package.json index 65bbea8dc4..194bc90045 100644 --- a/clash-nyanpasu/frontend/ui/package.json +++ b/clash-nyanpasu/frontend/ui/package.json @@ -29,7 +29,7 @@ "react-error-boundary": "6.0.0", "react-i18next": "15.6.1", "react-use": "17.6.0", - "tailwindcss": "4.1.11", + "tailwindcss": "4.1.12", "vite": "7.1.2", "vite-tsconfig-paths": "5.1.4" }, diff --git a/clash-nyanpasu/manifest/version.json b/clash-nyanpasu/manifest/version.json index 50e435325d..dbc6c6b0ce 100644 --- a/clash-nyanpasu/manifest/version.json +++ b/clash-nyanpasu/manifest/version.json @@ -2,10 +2,10 @@ "manifest_version": 1, "latest": { "mihomo": "v1.19.12", - "mihomo_alpha": "alpha-b481eca", - "clash_rs": "v0.8.2", + "mihomo_alpha": "alpha-4e20ed6", + "clash_rs": "v0.9.0", "clash_premium": "2023-09-05-gdcc8d87", - "clash_rs_alpha": "0.8.2-alpha+sha.3010e42" + "clash_rs_alpha": "0.9.0-alpha+sha.ac11887" }, "arch_template": { "mihomo": { @@ -69,5 +69,5 @@ "linux-armv7hf": "clash-armv7-unknown-linux-gnueabihf" } }, - "updated_at": "2025-08-17T22:21:09.107Z" + "updated_at": "2025-08-18T22:20:44.906Z" } diff --git a/clash-nyanpasu/package.json b/clash-nyanpasu/package.json index 8d3cb0813d..36ed6a72a3 100644 --- a/clash-nyanpasu/package.json +++ b/clash-nyanpasu/package.json @@ -104,7 +104,7 @@ "stylelint-declaration-block-no-ignored-properties": "2.8.0", "stylelint-order": "7.0.0", "stylelint-scss": "6.12.1", - "tailwindcss": "4.1.11", + "tailwindcss": "4.1.12", "tsx": "4.20.4", "typescript": "5.9.2", "typescript-eslint": "8.39.1" diff --git a/clash-nyanpasu/pnpm-lock.yaml b/clash-nyanpasu/pnpm-lock.yaml index 90934d73e8..b1b560bbc3 100644 --- a/clash-nyanpasu/pnpm-lock.yaml +++ b/clash-nyanpasu/pnpm-lock.yaml @@ -30,7 +30,7 @@ importers: version: 19.8.1 '@eslint/compat': specifier: 1.3.2 - version: 1.3.2(eslint@9.33.0(jiti@2.4.2)) + version: 1.3.2(eslint@9.33.0(jiti@2.5.1)) '@eslint/eslintrc': specifier: 3.3.1 version: 3.3.1 @@ -51,10 +51,10 @@ importers: version: 22.17.2 '@typescript-eslint/eslint-plugin': specifier: 8.39.1 - version: 8.39.1(@typescript-eslint/parser@8.39.1(eslint@9.33.0(jiti@2.4.2))(typescript@5.9.2))(eslint@9.33.0(jiti@2.4.2))(typescript@5.9.2) + version: 8.39.1(@typescript-eslint/parser@8.39.1(eslint@9.33.0(jiti@2.5.1))(typescript@5.9.2))(eslint@9.33.0(jiti@2.5.1))(typescript@5.9.2) '@typescript-eslint/parser': specifier: 8.39.1 - version: 8.39.1(eslint@9.33.0(jiti@2.4.2))(typescript@5.9.2) + version: 8.39.1(eslint@9.33.0(jiti@2.5.1))(typescript@5.9.2) autoprefixer: specifier: 10.4.21 version: 10.4.21(postcss@8.5.6) @@ -69,37 +69,37 @@ importers: version: 1.6.0(babel-plugin-macros@3.1.0) eslint: specifier: 9.33.0 - version: 9.33.0(jiti@2.4.2) + version: 9.33.0(jiti@2.5.1) eslint-config-prettier: specifier: 10.1.8 - version: 10.1.8(eslint@9.33.0(jiti@2.4.2)) + version: 10.1.8(eslint@9.33.0(jiti@2.5.1)) eslint-import-resolver-alias: specifier: 1.1.2 - version: 1.1.2(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.39.1(eslint@9.33.0(jiti@2.4.2))(typescript@5.9.2))(eslint@9.33.0(jiti@2.4.2))) + version: 1.1.2(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.39.1(eslint@9.33.0(jiti@2.5.1))(typescript@5.9.2))(eslint@9.33.0(jiti@2.5.1))) eslint-plugin-html: specifier: 8.1.3 version: 8.1.3 eslint-plugin-import: specifier: 2.32.0 - version: 2.32.0(@typescript-eslint/parser@8.39.1(eslint@9.33.0(jiti@2.4.2))(typescript@5.9.2))(eslint@9.33.0(jiti@2.4.2)) + version: 2.32.0(@typescript-eslint/parser@8.39.1(eslint@9.33.0(jiti@2.5.1))(typescript@5.9.2))(eslint@9.33.0(jiti@2.5.1)) eslint-plugin-n: specifier: 17.21.3 - version: 17.21.3(eslint@9.33.0(jiti@2.4.2))(typescript@5.9.2) + version: 17.21.3(eslint@9.33.0(jiti@2.5.1))(typescript@5.9.2) eslint-plugin-prettier: specifier: 5.5.4 - version: 5.5.4(eslint-config-prettier@10.1.8(eslint@9.33.0(jiti@2.4.2)))(eslint@9.33.0(jiti@2.4.2))(prettier@3.6.2) + version: 5.5.4(eslint-config-prettier@10.1.8(eslint@9.33.0(jiti@2.5.1)))(eslint@9.33.0(jiti@2.5.1))(prettier@3.6.2) eslint-plugin-promise: specifier: 7.2.1 - version: 7.2.1(eslint@9.33.0(jiti@2.4.2)) + version: 7.2.1(eslint@9.33.0(jiti@2.5.1)) eslint-plugin-react: specifier: 7.37.5 - version: 7.37.5(eslint@9.33.0(jiti@2.4.2)) + version: 7.37.5(eslint@9.33.0(jiti@2.5.1)) eslint-plugin-react-compiler: specifier: 19.1.0-rc.2 - version: 19.1.0-rc.2(eslint@9.33.0(jiti@2.4.2)) + version: 19.1.0-rc.2(eslint@9.33.0(jiti@2.5.1)) eslint-plugin-react-hooks: specifier: 5.2.0 - version: 5.2.0(eslint@9.33.0(jiti@2.4.2)) + version: 5.2.0(eslint@9.33.0(jiti@2.5.1)) globals: specifier: 16.3.0 version: 16.3.0 @@ -111,7 +111,7 @@ importers: version: 16.1.5 neostandard: specifier: 0.12.2 - version: 0.12.2(@typescript-eslint/utils@8.39.1(eslint@9.33.0(jiti@2.4.2))(typescript@5.9.2))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.39.1(eslint@9.33.0(jiti@2.4.2))(typescript@5.9.2))(eslint@9.33.0(jiti@2.4.2)))(eslint@9.33.0(jiti@2.4.2))(typescript@5.9.2) + version: 0.12.2(@typescript-eslint/utils@8.39.1(eslint@9.33.0(jiti@2.5.1))(typescript@5.9.2))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.39.1(eslint@9.33.0(jiti@2.5.1))(typescript@5.9.2))(eslint@9.33.0(jiti@2.5.1)))(eslint@9.33.0(jiti@2.5.1))(typescript@5.9.2) npm-run-all2: specifier: 8.0.4 version: 8.0.4 @@ -161,8 +161,8 @@ importers: specifier: 6.12.1 version: 6.12.1(stylelint@16.23.1(typescript@5.9.2)) tailwindcss: - specifier: 4.1.11 - version: 4.1.11 + specifier: 4.1.12 + version: 4.1.12 tsx: specifier: 4.20.4 version: 4.20.4 @@ -171,7 +171,7 @@ importers: version: 5.9.2 typescript-eslint: specifier: 8.39.1 - version: 8.39.1(eslint@9.33.0(jiti@2.4.2))(typescript@5.9.2) + version: 8.39.1(eslint@9.33.0(jiti@2.5.1))(typescript@5.9.2) frontend/interface: dependencies: @@ -246,11 +246,11 @@ importers: specifier: workspace:^ version: link:../ui '@tailwindcss/postcss': - specifier: 4.1.11 - version: 4.1.11 + specifier: 4.1.12 + version: 4.1.12 '@tanstack/router-zod-adapter': specifier: 1.81.5 - version: 1.81.5(@tanstack/react-router@1.131.26(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.27(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 @@ -343,8 +343,8 @@ importers: specifier: 11.14.0 version: 11.14.0(@types/react@19.1.10)(react@19.1.1) '@iconify/json': - specifier: 2.2.375 - version: 2.2.375 + specifier: 2.2.376 + version: 2.2.376 '@monaco-editor/react': specifier: 4.7.0 version: 4.7.0(monaco-editor@0.52.2)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) @@ -352,14 +352,14 @@ importers: specifier: 5.84.2 version: 5.84.2(react@19.1.1) '@tanstack/react-router': - specifier: 1.131.26 - version: 1.131.26(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + specifier: 1.131.27 + version: 1.131.27(react-dom@19.1.1(react@19.1.1))(react@19.1.1) '@tanstack/react-router-devtools': - specifier: 1.131.26 - version: 1.131.26(@tanstack/react-router@1.131.26(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(@tanstack/router-core@1.131.26)(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.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) '@tanstack/router-plugin': - specifier: 1.131.26 - version: 1.131.26(@tanstack/react-router@1.131.26(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(vite@7.1.2(@types/node@22.17.2)(jiti@2.4.2)(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.4)(yaml@2.8.1)) + 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.2(@types/node@22.17.2)(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.4)(yaml@2.8.1)) '@tauri-apps/plugin-clipboard-manager': specifier: 2.3.0 version: 2.3.0 @@ -395,13 +395,13 @@ importers: version: 13.15.2 '@vitejs/plugin-legacy': specifier: 7.2.1 - version: 7.2.1(terser@5.36.0)(vite@7.1.2(@types/node@22.17.2)(jiti@2.4.2)(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.4)(yaml@2.8.1)) + version: 7.2.1(terser@5.36.0)(vite@7.1.2(@types/node@22.17.2)(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.4)(yaml@2.8.1)) '@vitejs/plugin-react': specifier: 5.0.0 - version: 5.0.0(vite@7.1.2(@types/node@22.17.2)(jiti@2.4.2)(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.4)(yaml@2.8.1)) + version: 5.0.0(vite@7.1.2(@types/node@22.17.2)(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.4)(yaml@2.8.1)) '@vitejs/plugin-react-swc': specifier: 4.0.0 - version: 4.0.0(vite@7.1.2(@types/node@22.17.2)(jiti@2.4.2)(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.4)(yaml@2.8.1)) + version: 4.0.0(vite@7.1.2(@types/node@22.17.2)(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.4)(yaml@2.8.1)) change-case: specifier: 5.4.4 version: 5.4.4 @@ -440,19 +440,19 @@ importers: version: 13.15.15 vite: specifier: 7.1.2 - version: 7.1.2(@types/node@22.17.2)(jiti@2.4.2)(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.4)(yaml@2.8.1) + version: 7.1.2(@types/node@22.17.2)(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.4)(yaml@2.8.1) vite-plugin-html: specifier: 3.2.2 - version: 3.2.2(vite@7.1.2(@types/node@22.17.2)(jiti@2.4.2)(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.4)(yaml@2.8.1)) + version: 3.2.2(vite@7.1.2(@types/node@22.17.2)(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.4)(yaml@2.8.1)) vite-plugin-sass-dts: specifier: 1.3.31 - version: 1.3.31(postcss@8.5.6)(prettier@3.6.2)(sass-embedded@1.90.0)(vite@7.1.2(@types/node@22.17.2)(jiti@2.4.2)(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.4)(yaml@2.8.1)) + version: 1.3.31(postcss@8.5.6)(prettier@3.6.2)(sass-embedded@1.90.0)(vite@7.1.2(@types/node@22.17.2)(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.4)(yaml@2.8.1)) vite-plugin-svgr: specifier: 4.3.0 - version: 4.3.0(rollup@4.46.2)(typescript@5.9.2)(vite@7.1.2(@types/node@22.17.2)(jiti@2.4.2)(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.4)(yaml@2.8.1)) + version: 4.3.0(rollup@4.46.2)(typescript@5.9.2)(vite@7.1.2(@types/node@22.17.2)(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.4)(yaml@2.8.1)) vite-tsconfig-paths: specifier: 5.1.4 - version: 5.1.4(typescript@5.9.2)(vite@7.1.2(@types/node@22.17.2)(jiti@2.4.2)(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.4)(yaml@2.8.1)) + version: 5.1.4(typescript@5.9.2)(vite@7.1.2(@types/node@22.17.2)(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.4)(yaml@2.8.1)) zod: specifier: 4.0.17 version: 4.0.17 @@ -488,7 +488,7 @@ importers: version: 19.1.10 '@vitejs/plugin-react': specifier: 5.0.0 - version: 5.0.0(vite@7.1.2(@types/node@22.17.2)(jiti@2.4.2)(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.4)(yaml@2.8.1)) + version: 5.0.0(vite@7.1.2(@types/node@22.17.2)(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.4)(yaml@2.8.1)) ahooks: specifier: 3.9.3 version: 3.9.3(react-dom@19.1.1(react@19.1.1))(react@19.1.1) @@ -514,14 +514,14 @@ importers: specifier: 17.6.0 version: 17.6.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1) tailwindcss: - specifier: 4.1.11 - version: 4.1.11 + specifier: 4.1.12 + version: 4.1.12 vite: specifier: 7.1.2 - version: 7.1.2(@types/node@22.17.2)(jiti@2.4.2)(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.4)(yaml@2.8.1) + version: 7.1.2(@types/node@22.17.2)(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.4)(yaml@2.8.1) vite-tsconfig-paths: specifier: 5.1.4 - version: 5.1.4(typescript@5.9.2)(vite@7.1.2(@types/node@22.17.2)(jiti@2.4.2)(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.4)(yaml@2.8.1)) + version: 5.1.4(typescript@5.9.2)(vite@7.1.2(@types/node@22.17.2)(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.4)(yaml@2.8.1)) devDependencies: '@emotion/react': specifier: 11.14.0 @@ -546,7 +546,7 @@ importers: version: 5.2.0(typescript@5.9.2) vite-plugin-dts: specifier: 4.5.4 - version: 4.5.4(@types/node@22.17.2)(rollup@4.46.2)(typescript@5.9.2)(vite@7.1.2(@types/node@22.17.2)(jiti@2.4.2)(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.4)(yaml@2.8.1)) + version: 4.5.4(@types/node@22.17.2)(rollup@4.46.2)(typescript@5.9.2)(vite@7.1.2(@types/node@22.17.2)(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.4)(yaml@2.8.1)) scripts: dependencies: @@ -615,8 +615,8 @@ importers: specifier: 2.26.22 version: 2.26.22 undici: - specifier: 7.13.0 - version: 7.13.0 + specifier: 7.14.0 + version: 7.14.0 yargs: specifier: 18.0.0 version: 18.0.0 @@ -1759,8 +1759,8 @@ packages: prettier-plugin-ember-template-tag: optional: true - '@iconify/json@2.2.375': - resolution: {integrity: sha512-SexUHUFDGXWZbRIJKg63opwAA/qVquYYi3H4hOdyWwmzuEyjdfzpvkBwEA/BekJX+M3mBOxu6uRj+E89hJbFvw==} + '@iconify/json@2.2.376': + resolution: {integrity: sha512-2jQ+5zPV7Lva9iuFOvMkcq5XQyRx7xvLuodpDI+yjAxOnB2gpWa4caFz53tyPgCWU50Zd9/JSNZaCNYSTniSrg==} '@iconify/types@2.0.0': resolution: {integrity: sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg==} @@ -1779,6 +1779,9 @@ packages: '@jridgewell/gen-mapping@0.3.12': resolution: {integrity: sha512-OuLGC46TjB5BbN1dH8JULVVZY4WTdkF7tV9Ys6wLL1rubZnCMstOhNHueU5bLCrnRuDhKPDM4g6sw4Bel5Gzqg==} + '@jridgewell/remapping@2.3.5': + resolution: {integrity: sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==} + '@jridgewell/resolve-uri@3.1.2': resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} engines: {node: '>=6.0.0'} @@ -2841,65 +2844,65 @@ packages: resolution: {integrity: sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w==} engines: {node: '>=10'} - '@tailwindcss/node@4.1.11': - resolution: {integrity: sha512-yzhzuGRmv5QyU9qLNg4GTlYI6STedBWRE7NjxP45CsFYYq9taI0zJXZBMqIC/c8fViNLhmrbpSFS57EoxUmD6Q==} + '@tailwindcss/node@4.1.12': + resolution: {integrity: sha512-3hm9brwvQkZFe++SBt+oLjo4OLDtkvlE8q2WalaD/7QWaeM7KEJbAiY/LJZUaCs7Xa8aUu4xy3uoyX4q54UVdQ==} - '@tailwindcss/oxide-android-arm64@4.1.11': - resolution: {integrity: sha512-3IfFuATVRUMZZprEIx9OGDjG3Ou3jG4xQzNTvjDoKmU9JdmoCohQJ83MYd0GPnQIu89YoJqvMM0G3uqLRFtetg==} + '@tailwindcss/oxide-android-arm64@4.1.12': + resolution: {integrity: sha512-oNY5pq+1gc4T6QVTsZKwZaGpBb2N1H1fsc1GD4o7yinFySqIuRZ2E4NvGasWc6PhYJwGK2+5YT1f9Tp80zUQZQ==} engines: {node: '>= 10'} cpu: [arm64] os: [android] - '@tailwindcss/oxide-darwin-arm64@4.1.11': - resolution: {integrity: sha512-ESgStEOEsyg8J5YcMb1xl8WFOXfeBmrhAwGsFxxB2CxY9evy63+AtpbDLAyRkJnxLy2WsD1qF13E97uQyP1lfQ==} + '@tailwindcss/oxide-darwin-arm64@4.1.12': + resolution: {integrity: sha512-cq1qmq2HEtDV9HvZlTtrj671mCdGB93bVY6J29mwCyaMYCP/JaUBXxrQQQm7Qn33AXXASPUb2HFZlWiiHWFytw==} engines: {node: '>= 10'} cpu: [arm64] os: [darwin] - '@tailwindcss/oxide-darwin-x64@4.1.11': - resolution: {integrity: sha512-EgnK8kRchgmgzG6jE10UQNaH9Mwi2n+yw1jWmof9Vyg2lpKNX2ioe7CJdf9M5f8V9uaQxInenZkOxnTVL3fhAw==} + '@tailwindcss/oxide-darwin-x64@4.1.12': + resolution: {integrity: sha512-6UCsIeFUcBfpangqlXay9Ffty9XhFH1QuUFn0WV83W8lGdX8cD5/+2ONLluALJD5+yJ7k8mVtwy3zMZmzEfbLg==} engines: {node: '>= 10'} cpu: [x64] os: [darwin] - '@tailwindcss/oxide-freebsd-x64@4.1.11': - resolution: {integrity: sha512-xdqKtbpHs7pQhIKmqVpxStnY1skuNh4CtbcyOHeX1YBE0hArj2romsFGb6yUmzkq/6M24nkxDqU8GYrKrz+UcA==} + '@tailwindcss/oxide-freebsd-x64@4.1.12': + resolution: {integrity: sha512-JOH/f7j6+nYXIrHobRYCtoArJdMJh5zy5lr0FV0Qu47MID/vqJAY3r/OElPzx1C/wdT1uS7cPq+xdYYelny1ww==} engines: {node: '>= 10'} cpu: [x64] os: [freebsd] - '@tailwindcss/oxide-linux-arm-gnueabihf@4.1.11': - resolution: {integrity: sha512-ryHQK2eyDYYMwB5wZL46uoxz2zzDZsFBwfjssgB7pzytAeCCa6glsiJGjhTEddq/4OsIjsLNMAiMlHNYnkEEeg==} + '@tailwindcss/oxide-linux-arm-gnueabihf@4.1.12': + resolution: {integrity: sha512-v4Ghvi9AU1SYgGr3/j38PD8PEe6bRfTnNSUE3YCMIRrrNigCFtHZ2TCm8142X8fcSqHBZBceDx+JlFJEfNg5zQ==} engines: {node: '>= 10'} cpu: [arm] os: [linux] - '@tailwindcss/oxide-linux-arm64-gnu@4.1.11': - resolution: {integrity: sha512-mYwqheq4BXF83j/w75ewkPJmPZIqqP1nhoghS9D57CLjsh3Nfq0m4ftTotRYtGnZd3eCztgbSPJ9QhfC91gDZQ==} + '@tailwindcss/oxide-linux-arm64-gnu@4.1.12': + resolution: {integrity: sha512-YP5s1LmetL9UsvVAKusHSyPlzSRqYyRB0f+Kl/xcYQSPLEw/BvGfxzbH+ihUciePDjiXwHh+p+qbSP3SlJw+6g==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] - '@tailwindcss/oxide-linux-arm64-musl@4.1.11': - resolution: {integrity: sha512-m/NVRFNGlEHJrNVk3O6I9ggVuNjXHIPoD6bqay/pubtYC9QIdAMpS+cswZQPBLvVvEF6GtSNONbDkZrjWZXYNQ==} + '@tailwindcss/oxide-linux-arm64-musl@4.1.12': + resolution: {integrity: sha512-V8pAM3s8gsrXcCv6kCHSuwyb/gPsd863iT+v1PGXC4fSL/OJqsKhfK//v8P+w9ThKIoqNbEnsZqNy+WDnwQqCA==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] - '@tailwindcss/oxide-linux-x64-gnu@4.1.11': - resolution: {integrity: sha512-YW6sblI7xukSD2TdbbaeQVDysIm/UPJtObHJHKxDEcW2exAtY47j52f8jZXkqE1krdnkhCMGqP3dbniu1Te2Fg==} + '@tailwindcss/oxide-linux-x64-gnu@4.1.12': + resolution: {integrity: sha512-xYfqYLjvm2UQ3TZggTGrwxjYaLB62b1Wiysw/YE3Yqbh86sOMoTn0feF98PonP7LtjsWOWcXEbGqDL7zv0uW8Q==} engines: {node: '>= 10'} cpu: [x64] os: [linux] - '@tailwindcss/oxide-linux-x64-musl@4.1.11': - resolution: {integrity: sha512-e3C/RRhGunWYNC3aSF7exsQkdXzQ/M+aYuZHKnw4U7KQwTJotnWsGOIVih0s2qQzmEzOFIJ3+xt7iq67K/p56Q==} + '@tailwindcss/oxide-linux-x64-musl@4.1.12': + resolution: {integrity: sha512-ha0pHPamN+fWZY7GCzz5rKunlv9L5R8kdh+YNvP5awe3LtuXb5nRi/H27GeL2U+TdhDOptU7T6Is7mdwh5Ar3A==} engines: {node: '>= 10'} cpu: [x64] os: [linux] - '@tailwindcss/oxide-wasm32-wasi@4.1.11': - resolution: {integrity: sha512-Xo1+/GU0JEN/C/dvcammKHzeM6NqKovG+6921MR6oadee5XPBaKOumrJCXvopJ/Qb5TH7LX/UAywbqrP4lax0g==} + '@tailwindcss/oxide-wasm32-wasi@4.1.12': + resolution: {integrity: sha512-4tSyu3dW+ktzdEpuk6g49KdEangu3eCYoqPhWNsZgUhyegEda3M9rG0/j1GV/JjVVsj+lG7jWAyrTlLzd/WEBg==} engines: {node: '>=14.0.0'} cpu: [wasm32] bundledDependencies: @@ -2910,24 +2913,24 @@ packages: - '@emnapi/wasi-threads' - tslib - '@tailwindcss/oxide-win32-arm64-msvc@4.1.11': - resolution: {integrity: sha512-UgKYx5PwEKrac3GPNPf6HVMNhUIGuUh4wlDFR2jYYdkX6pL/rn73zTq/4pzUm8fOjAn5L8zDeHp9iXmUGOXZ+w==} + '@tailwindcss/oxide-win32-arm64-msvc@4.1.12': + resolution: {integrity: sha512-iGLyD/cVP724+FGtMWslhcFyg4xyYyM+5F4hGvKA7eifPkXHRAUDFaimu53fpNg9X8dfP75pXx/zFt/jlNF+lg==} engines: {node: '>= 10'} cpu: [arm64] os: [win32] - '@tailwindcss/oxide-win32-x64-msvc@4.1.11': - resolution: {integrity: sha512-YfHoggn1j0LK7wR82TOucWc5LDCguHnoS879idHekmmiR7g9HUtMw9MI0NHatS28u/Xlkfi9w5RJWgz2Dl+5Qg==} + '@tailwindcss/oxide-win32-x64-msvc@4.1.12': + resolution: {integrity: sha512-NKIh5rzw6CpEodv/++r0hGLlfgT/gFN+5WNdZtvh6wpU2BpGNgdjvj6H2oFc8nCM839QM1YOhjpgbAONUb4IxA==} engines: {node: '>= 10'} cpu: [x64] os: [win32] - '@tailwindcss/oxide@4.1.11': - resolution: {integrity: sha512-Q69XzrtAhuyfHo+5/HMgr1lAiPP/G40OMFAnws7xcFEYqcypZmdW8eGXaOUIeOl1dzPJBPENXgbjsOyhg2nkrg==} + '@tailwindcss/oxide@4.1.12': + resolution: {integrity: sha512-gM5EoKHW/ukmlEtphNwaGx45fGoEmP10v51t9unv55voWh6WrOL19hfuIdo2FjxIaZzw776/BUQg7Pck++cIVw==} engines: {node: '>= 10'} - '@tailwindcss/postcss@4.1.11': - resolution: {integrity: sha512-q/EAIIpF6WpLhKEuQSEVMZNMIY8KhWoAemZ9eylNAih9jxMGAYPPWBn3I9QL/2jZ+e7OEz/tZkX5HwbBR4HohA==} + '@tailwindcss/postcss@4.1.12': + resolution: {integrity: sha512-5PpLYhCAwf9SJEeIsSmCDLgyVfdBhdBpzX1OJ87anT9IVR0Z9pjM0FNixCAUAHGnMBGB8K99SwAheXrT0Kh6QQ==} '@tanstack/history@1.131.2': resolution: {integrity: sha512-cs1WKawpXIe+vSTeiZUuSBy8JFjEuDgdMKZFRLKwQysKo8y2q6Q1HvS74Yw+m5IhOW1nTZooa6rlgdfXcgFAaw==} @@ -2945,16 +2948,16 @@ packages: peerDependencies: react: ^18 || ^19 - '@tanstack/react-router-devtools@1.131.26': - resolution: {integrity: sha512-QdDF2t3ILZLqblBYDWQXpQ8QsHzo2ZJcWhaeQEdAkMZ0w0mlfKdZKOGigA21KvDbyTOgkfuQBj+DlkiQPqKYMA==} + '@tanstack/react-router-devtools@1.131.27': + resolution: {integrity: sha512-SHulN0a7hZvyl3fXi+VLHxdMKdsg1lhPOZeKd5xs6bu/x+N5FaXEA5bUPGB2sbiSYXw/XFcjUqR5dkw8T1dkXg==} engines: {node: '>=12'} peerDependencies: - '@tanstack/react-router': ^1.131.26 + '@tanstack/react-router': ^1.131.27 react: '>=18.0.0 || >=19.0.0' react-dom: '>=18.0.0 || >=19.0.0' - '@tanstack/react-router@1.131.26': - resolution: {integrity: sha512-bXfONifen0f3EBfHXTSSCQMT/svV+/te/ncgZSUdxrN/nE01GqGsBvD590wOQMV9CBw5iqFfxEM3kA5GM3RhXw==} + '@tanstack/react-router@1.131.27': + resolution: {integrity: sha512-JLUsmlarNxMz7VDhFscZCqoc2quhocQZKhia/7YXWf8Jbc8rANk6lukK4ecYn92m/ytoHAAy77JeaB6n0HvqwQ==} engines: {node: '>=12'} peerDependencies: react: '>=18.0.0 || >=19.0.0' @@ -2979,15 +2982,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.26': - resolution: {integrity: sha512-MED3i/vhHqBFfQZp309JduePtnJwG30KTM+swKgBWBwDoQHvYbtTWhJKPAm1EhkuFyIXuZo/mWTCwdzo/Te7pA==} + '@tanstack/router-core@1.131.27': + resolution: {integrity: sha512-NEBNxZ/LIBIh6kvQntr6bKq57tDe55zecyTtjAmzPkYFsMy1LXEpRm5H3BPiteBMRApAjuaq+bS1qA664hLH6Q==} engines: {node: '>=12'} - '@tanstack/router-devtools-core@1.131.26': - resolution: {integrity: sha512-TGHmRDQpYphuRbDH+jJp418vQuIydzITaUx7MiPk5U1ZZ+2O/GxcF/ycXmyYR0IHTpSky35I83X3bKTiv+thyw==} + '@tanstack/router-devtools-core@1.131.27': + resolution: {integrity: sha512-upoMv/uq1CQdrOyBO2h6CLXI1Ym7Rawoovt26fN1Wl+RMXqKGVpHAXYuKpugdFMFhFieccKVYcrj9NP4V5BIDw==} engines: {node: '>=12'} peerDependencies: - '@tanstack/router-core': ^1.131.26 + '@tanstack/router-core': ^1.131.27 csstype: ^3.0.10 solid-js: '>=1.9.5' tiny-invariant: ^1.3.3 @@ -2995,16 +2998,16 @@ packages: csstype: optional: true - '@tanstack/router-generator@1.131.26': - resolution: {integrity: sha512-FUeFIBp22XQ985Xuy+8YGSm/Spe9/ZJIZKJlgDokq09b3HTJTGydne8aXPUtemaOkiA50LOUMxrZV2dBtSbB9w==} + '@tanstack/router-generator@1.131.27': + resolution: {integrity: sha512-PXBIVl45q2bBq9g0DDXLBGeKjO9eExcZd2JotLjLdIJ0I/wdxPQOBJHLPZfnmbf3vispToedRvG3b1YDWjL48g==} engines: {node: '>=12'} - '@tanstack/router-plugin@1.131.26': - resolution: {integrity: sha512-fw4XxcoGHAdNIikfqyxDyF2Sxku99/LKB7BFopPW3EPnjBMul/XpglTzoe7FMKdoBjts4961rr54/QwimeYnug==} + '@tanstack/router-plugin@1.131.27': + resolution: {integrity: sha512-0V611ehOE8nfCFT2tvrLfQMroyoYW/virDXPaaFe38hdDxslmfCW2miJxngxz4+QqgK/M3sX71ElrZDvkP2Ixw==} engines: {node: '>=12'} peerDependencies: '@rsbuild/core': '>=1.0.2' - '@tanstack/react-router': ^1.131.26 + '@tanstack/react-router': ^1.131.27 vite: '>=5.0.0 || >=6.0.0' vite-plugin-solid: ^2.11.2 webpack: '>=5.92.0' @@ -4698,6 +4701,10 @@ packages: resolution: {integrity: sha512-ZSW3ma5GkcQBIpwZTSRAI8N71Uuwgs93IezB7mf7R60tC8ZbJideoDNKjHn2O9KIlx6rkGTTEk1xUCK2E1Y2Yg==} engines: {node: '>=10.13.0'} + enhanced-resolve@5.18.3: + resolution: {integrity: sha512-d4lC8xfavMeBjzGr2vECC3fsGXziXZQyJxD868h2M/mBI3PwAuODxAkLkq5HYuvrPYcUtiLzsTo8U3PgX3Ocww==} + engines: {node: '>=10.13.0'} + entities@2.2.0: resolution: {integrity: sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==} @@ -5909,6 +5916,10 @@ packages: resolution: {integrity: sha512-rg9zJN+G4n2nfJl5MW3BMygZX56zKPNVEYYqq7adpmMh4Jn2QNEwhvQlFy6jPVdcod7txZtKHWnyZiA3a0zP7A==} hasBin: true + jiti@2.5.1: + resolution: {integrity: sha512-twQoecYPiVA5K/h6SxtORw/Bs3ar+mLUtoPSc7iMXzQzK8d7eJ/R09wmTwAjiamETn1cXYPGfNnu7DMoHgu12w==} + hasBin: true + jju@1.4.0: resolution: {integrity: sha512-8wb9Yw966OSxApiCt0K3yNJL8pnNeIv+OEq2YMidz4FKP6nonSRoOXc80iXY4JaN2FC11B9qsNmDsm+ZOfMROA==} @@ -7918,8 +7929,8 @@ packages: tailwind-merge@3.3.1: resolution: {integrity: sha512-gBXpgUm/3rp1lMZZrM/w7D8GKqshif0zAymAhbCyIt8KMe+0v9DQ7cdYLR4FHH/cKpdTXb+A/tKKU3eolfsI+g==} - tailwindcss@4.1.11: - resolution: {integrity: sha512-2E9TBm6MDD/xKYe+dvJZAmg3yxIEDNRc0jwlNyDg/4Fil2QcSLjFKGVff0lAf1jjeaArlG/M75Ey/EYr/OJtBA==} + tailwindcss@4.1.12: + resolution: {integrity: sha512-DzFtxOi+7NsFf7DBtI3BJsynR+0Yp6etH+nRPTbpWnS2pZBaSksv/JGctNwSWzbFjp0vxSqknaUylseZqMDGrA==} tapable@2.2.1: resolution: {integrity: sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==} @@ -8129,8 +8140,8 @@ packages: resolution: {integrity: sha512-raqeBD6NQK4SkWhQzeYKd1KmIG6dllBOTt55Rmkt4HtI9mwdWtJljnrXjAFUBLTSN67HWrOIZ3EPF4kjUw80Bg==} engines: {node: '>=14.0'} - undici@7.13.0: - resolution: {integrity: sha512-l+zSMssRqrzDcb3fjMkjjLGmuiiK2pMIcV++mJaAc9vhjSGpvM7h43QgP+OAMb1GImHmbPyG2tBXeuyG5iY4gA==} + undici@7.14.0: + resolution: {integrity: sha512-Vqs8HTzjpQXZeXdpsfChQTlafcMQaaIwnGwLam1wudSSjlJeQ3bw1j+TLPePgrCnCpUXx7Ba5Pdpf5OBih62NQ==} engines: {node: '>=20.18.1'} unicode-canonical-property-names-ecmascript@2.0.1: @@ -9871,21 +9882,21 @@ snapshots: '@esbuild/win32-x64@0.25.0': optional: true - '@eslint-community/eslint-utils@4.4.1(eslint@9.33.0(jiti@2.4.2))': + '@eslint-community/eslint-utils@4.4.1(eslint@9.33.0(jiti@2.5.1))': dependencies: - eslint: 9.33.0(jiti@2.4.2) + eslint: 9.33.0(jiti@2.5.1) eslint-visitor-keys: 3.4.3 - '@eslint-community/eslint-utils@4.7.0(eslint@9.33.0(jiti@2.4.2))': + '@eslint-community/eslint-utils@4.7.0(eslint@9.33.0(jiti@2.5.1))': dependencies: - eslint: 9.33.0(jiti@2.4.2) + eslint: 9.33.0(jiti@2.5.1) eslint-visitor-keys: 3.4.3 '@eslint-community/regexpp@4.12.1': {} - '@eslint/compat@1.3.2(eslint@9.33.0(jiti@2.4.2))': + '@eslint/compat@1.3.2(eslint@9.33.0(jiti@2.5.1))': optionalDependencies: - eslint: 9.33.0(jiti@2.4.2) + eslint: 9.33.0(jiti@2.5.1) '@eslint/config-array@0.21.0': dependencies: @@ -9968,7 +9979,7 @@ snapshots: transitivePeerDependencies: - supports-color - '@iconify/json@2.2.375': + '@iconify/json@2.2.376': dependencies: '@iconify/types': 2.0.0 pathe: 1.1.2 @@ -10006,6 +10017,11 @@ snapshots: '@jridgewell/sourcemap-codec': 1.5.0 '@jridgewell/trace-mapping': 0.3.29 + '@jridgewell/remapping@2.3.5': + dependencies: + '@jridgewell/gen-mapping': 0.3.12 + '@jridgewell/trace-mapping': 0.3.29 + '@jridgewell/resolve-uri@3.1.2': {} '@jridgewell/source-map@0.3.6': @@ -10832,10 +10848,10 @@ snapshots: '@sindresorhus/is@4.6.0': {} - '@stylistic/eslint-plugin@2.11.0(eslint@9.33.0(jiti@2.4.2))(typescript@5.9.2)': + '@stylistic/eslint-plugin@2.11.0(eslint@9.33.0(jiti@2.5.1))(typescript@5.9.2)': dependencies: - '@typescript-eslint/utils': 8.38.0(eslint@9.33.0(jiti@2.4.2))(typescript@5.9.2) - eslint: 9.33.0(jiti@2.4.2) + '@typescript-eslint/utils': 8.38.0(eslint@9.33.0(jiti@2.5.1))(typescript@5.9.2) + eslint: 9.33.0(jiti@2.5.1) eslint-visitor-keys: 4.2.1 espree: 10.4.0 estraverse: 5.3.0 @@ -10970,77 +10986,77 @@ snapshots: dependencies: defer-to-connect: 2.0.1 - '@tailwindcss/node@4.1.11': + '@tailwindcss/node@4.1.12': dependencies: - '@ampproject/remapping': 2.3.0 - enhanced-resolve: 5.18.1 - jiti: 2.4.2 + '@jridgewell/remapping': 2.3.5 + enhanced-resolve: 5.18.3 + jiti: 2.5.1 lightningcss: 1.30.1 magic-string: 0.30.17 source-map-js: 1.2.1 - tailwindcss: 4.1.11 + tailwindcss: 4.1.12 - '@tailwindcss/oxide-android-arm64@4.1.11': + '@tailwindcss/oxide-android-arm64@4.1.12': optional: true - '@tailwindcss/oxide-darwin-arm64@4.1.11': + '@tailwindcss/oxide-darwin-arm64@4.1.12': optional: true - '@tailwindcss/oxide-darwin-x64@4.1.11': + '@tailwindcss/oxide-darwin-x64@4.1.12': optional: true - '@tailwindcss/oxide-freebsd-x64@4.1.11': + '@tailwindcss/oxide-freebsd-x64@4.1.12': optional: true - '@tailwindcss/oxide-linux-arm-gnueabihf@4.1.11': + '@tailwindcss/oxide-linux-arm-gnueabihf@4.1.12': optional: true - '@tailwindcss/oxide-linux-arm64-gnu@4.1.11': + '@tailwindcss/oxide-linux-arm64-gnu@4.1.12': optional: true - '@tailwindcss/oxide-linux-arm64-musl@4.1.11': + '@tailwindcss/oxide-linux-arm64-musl@4.1.12': optional: true - '@tailwindcss/oxide-linux-x64-gnu@4.1.11': + '@tailwindcss/oxide-linux-x64-gnu@4.1.12': optional: true - '@tailwindcss/oxide-linux-x64-musl@4.1.11': + '@tailwindcss/oxide-linux-x64-musl@4.1.12': optional: true - '@tailwindcss/oxide-wasm32-wasi@4.1.11': + '@tailwindcss/oxide-wasm32-wasi@4.1.12': optional: true - '@tailwindcss/oxide-win32-arm64-msvc@4.1.11': + '@tailwindcss/oxide-win32-arm64-msvc@4.1.12': optional: true - '@tailwindcss/oxide-win32-x64-msvc@4.1.11': + '@tailwindcss/oxide-win32-x64-msvc@4.1.12': optional: true - '@tailwindcss/oxide@4.1.11': + '@tailwindcss/oxide@4.1.12': dependencies: detect-libc: 2.0.4 tar: 7.4.3 optionalDependencies: - '@tailwindcss/oxide-android-arm64': 4.1.11 - '@tailwindcss/oxide-darwin-arm64': 4.1.11 - '@tailwindcss/oxide-darwin-x64': 4.1.11 - '@tailwindcss/oxide-freebsd-x64': 4.1.11 - '@tailwindcss/oxide-linux-arm-gnueabihf': 4.1.11 - '@tailwindcss/oxide-linux-arm64-gnu': 4.1.11 - '@tailwindcss/oxide-linux-arm64-musl': 4.1.11 - '@tailwindcss/oxide-linux-x64-gnu': 4.1.11 - '@tailwindcss/oxide-linux-x64-musl': 4.1.11 - '@tailwindcss/oxide-wasm32-wasi': 4.1.11 - '@tailwindcss/oxide-win32-arm64-msvc': 4.1.11 - '@tailwindcss/oxide-win32-x64-msvc': 4.1.11 + '@tailwindcss/oxide-android-arm64': 4.1.12 + '@tailwindcss/oxide-darwin-arm64': 4.1.12 + '@tailwindcss/oxide-darwin-x64': 4.1.12 + '@tailwindcss/oxide-freebsd-x64': 4.1.12 + '@tailwindcss/oxide-linux-arm-gnueabihf': 4.1.12 + '@tailwindcss/oxide-linux-arm64-gnu': 4.1.12 + '@tailwindcss/oxide-linux-arm64-musl': 4.1.12 + '@tailwindcss/oxide-linux-x64-gnu': 4.1.12 + '@tailwindcss/oxide-linux-x64-musl': 4.1.12 + '@tailwindcss/oxide-wasm32-wasi': 4.1.12 + '@tailwindcss/oxide-win32-arm64-msvc': 4.1.12 + '@tailwindcss/oxide-win32-x64-msvc': 4.1.12 - '@tailwindcss/postcss@4.1.11': + '@tailwindcss/postcss@4.1.12': dependencies: '@alloc/quick-lru': 5.2.0 - '@tailwindcss/node': 4.1.11 - '@tailwindcss/oxide': 4.1.11 + '@tailwindcss/node': 4.1.12 + '@tailwindcss/oxide': 4.1.12 postcss: 8.5.6 - tailwindcss: 4.1.11 + tailwindcss: 4.1.12 '@tanstack/history@1.131.2': {} @@ -11055,10 +11071,10 @@ snapshots: '@tanstack/query-core': 5.83.1 react: 19.1.1 - '@tanstack/react-router-devtools@1.131.26(@tanstack/react-router@1.131.26(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(@tanstack/router-core@1.131.26)(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.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)': dependencies: - '@tanstack/react-router': 1.131.26(react-dom@19.1.1(react@19.1.1))(react@19.1.1) - '@tanstack/router-devtools-core': 1.131.26(@tanstack/router-core@1.131.26)(csstype@3.1.3)(solid-js@1.9.5)(tiny-invariant@1.3.3) + '@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) react: 19.1.1 react-dom: 19.1.1(react@19.1.1) transitivePeerDependencies: @@ -11067,11 +11083,11 @@ snapshots: - solid-js - tiny-invariant - '@tanstack/react-router@1.131.26(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': + '@tanstack/react-router@1.131.27(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.26 + '@tanstack/router-core': 1.131.27 isbot: 5.1.28 react: 19.1.1 react-dom: 19.1.1(react@19.1.1) @@ -11097,7 +11113,7 @@ snapshots: react: 19.1.1 react-dom: 19.1.1(react@19.1.1) - '@tanstack/router-core@1.131.26': + '@tanstack/router-core@1.131.27': dependencies: '@tanstack/history': 1.131.2 '@tanstack/store': 0.7.0 @@ -11107,9 +11123,9 @@ snapshots: tiny-invariant: 1.3.3 tiny-warning: 1.0.3 - '@tanstack/router-devtools-core@1.131.26(@tanstack/router-core@1.131.26)(csstype@3.1.3)(solid-js@1.9.5)(tiny-invariant@1.3.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)': dependencies: - '@tanstack/router-core': 1.131.26 + '@tanstack/router-core': 1.131.27 clsx: 2.1.1 goober: 2.1.16(csstype@3.1.3) solid-js: 1.9.5 @@ -11117,9 +11133,9 @@ snapshots: optionalDependencies: csstype: 3.1.3 - '@tanstack/router-generator@1.131.26': + '@tanstack/router-generator@1.131.27': dependencies: - '@tanstack/router-core': 1.131.26 + '@tanstack/router-core': 1.131.27 '@tanstack/router-utils': 1.131.2 '@tanstack/virtual-file-routes': 1.131.2 prettier: 3.6.2 @@ -11130,7 +11146,7 @@ snapshots: transitivePeerDependencies: - supports-color - '@tanstack/router-plugin@1.131.26(@tanstack/react-router@1.131.26(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(vite@7.1.2(@types/node@22.17.2)(jiti@2.4.2)(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.4)(yaml@2.8.1))': + '@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.2(@types/node@22.17.2)(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.4)(yaml@2.8.1))': dependencies: '@babel/core': 7.28.0 '@babel/plugin-syntax-jsx': 7.27.1(@babel/core@7.28.0) @@ -11138,8 +11154,8 @@ snapshots: '@babel/template': 7.27.2 '@babel/traverse': 7.28.0 '@babel/types': 7.28.1 - '@tanstack/router-core': 1.131.26 - '@tanstack/router-generator': 1.131.26 + '@tanstack/router-core': 1.131.27 + '@tanstack/router-generator': 1.131.27 '@tanstack/router-utils': 1.131.2 '@tanstack/virtual-file-routes': 1.131.2 babel-dead-code-elimination: 1.0.10 @@ -11147,8 +11163,8 @@ snapshots: unplugin: 2.3.5 zod: 3.25.76 optionalDependencies: - '@tanstack/react-router': 1.131.26(react-dom@19.1.1(react@19.1.1))(react@19.1.1) - vite: 7.1.2(@types/node@22.17.2)(jiti@2.4.2)(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.4)(yaml@2.8.1) + '@tanstack/react-router': 1.131.27(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + vite: 7.1.2(@types/node@22.17.2)(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.4)(yaml@2.8.1) transitivePeerDependencies: - supports-color @@ -11163,9 +11179,9 @@ snapshots: transitivePeerDependencies: - supports-color - '@tanstack/router-zod-adapter@1.81.5(@tanstack/react-router@1.131.26(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.27(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(zod@4.0.17)': dependencies: - '@tanstack/react-router': 1.131.26(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@tanstack/react-router': 1.131.27(react-dom@19.1.1(react@19.1.1))(react@19.1.1) zod: 4.0.17 '@tanstack/store@0.7.0': {} @@ -11546,15 +11562,15 @@ snapshots: '@types/node': 22.17.2 optional: true - '@typescript-eslint/eslint-plugin@8.39.1(@typescript-eslint/parser@8.39.1(eslint@9.33.0(jiti@2.4.2))(typescript@5.9.2))(eslint@9.33.0(jiti@2.4.2))(typescript@5.9.2)': + '@typescript-eslint/eslint-plugin@8.39.1(@typescript-eslint/parser@8.39.1(eslint@9.33.0(jiti@2.5.1))(typescript@5.9.2))(eslint@9.33.0(jiti@2.5.1))(typescript@5.9.2)': dependencies: '@eslint-community/regexpp': 4.12.1 - '@typescript-eslint/parser': 8.39.1(eslint@9.33.0(jiti@2.4.2))(typescript@5.9.2) + '@typescript-eslint/parser': 8.39.1(eslint@9.33.0(jiti@2.5.1))(typescript@5.9.2) '@typescript-eslint/scope-manager': 8.39.1 - '@typescript-eslint/type-utils': 8.39.1(eslint@9.33.0(jiti@2.4.2))(typescript@5.9.2) - '@typescript-eslint/utils': 8.39.1(eslint@9.33.0(jiti@2.4.2))(typescript@5.9.2) + '@typescript-eslint/type-utils': 8.39.1(eslint@9.33.0(jiti@2.5.1))(typescript@5.9.2) + '@typescript-eslint/utils': 8.39.1(eslint@9.33.0(jiti@2.5.1))(typescript@5.9.2) '@typescript-eslint/visitor-keys': 8.39.1 - eslint: 9.33.0(jiti@2.4.2) + eslint: 9.33.0(jiti@2.5.1) graphemer: 1.4.0 ignore: 7.0.5 natural-compare: 1.4.0 @@ -11563,14 +11579,14 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@8.39.1(eslint@9.33.0(jiti@2.4.2))(typescript@5.9.2)': + '@typescript-eslint/parser@8.39.1(eslint@9.33.0(jiti@2.5.1))(typescript@5.9.2)': dependencies: '@typescript-eslint/scope-manager': 8.39.1 '@typescript-eslint/types': 8.39.1 '@typescript-eslint/typescript-estree': 8.39.1(typescript@5.9.2) '@typescript-eslint/visitor-keys': 8.39.1 debug: 4.4.1 - eslint: 9.33.0(jiti@2.4.2) + eslint: 9.33.0(jiti@2.5.1) typescript: 5.9.2 transitivePeerDependencies: - supports-color @@ -11615,13 +11631,13 @@ snapshots: dependencies: typescript: 5.9.2 - '@typescript-eslint/type-utils@8.39.1(eslint@9.33.0(jiti@2.4.2))(typescript@5.9.2)': + '@typescript-eslint/type-utils@8.39.1(eslint@9.33.0(jiti@2.5.1))(typescript@5.9.2)': dependencies: '@typescript-eslint/types': 8.39.1 '@typescript-eslint/typescript-estree': 8.39.1(typescript@5.9.2) - '@typescript-eslint/utils': 8.39.1(eslint@9.33.0(jiti@2.4.2))(typescript@5.9.2) + '@typescript-eslint/utils': 8.39.1(eslint@9.33.0(jiti@2.5.1))(typescript@5.9.2) debug: 4.4.1 - eslint: 9.33.0(jiti@2.4.2) + eslint: 9.33.0(jiti@2.5.1) ts-api-utils: 2.1.0(typescript@5.9.2) typescript: 5.9.2 transitivePeerDependencies: @@ -11667,24 +11683,24 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/utils@8.38.0(eslint@9.33.0(jiti@2.4.2))(typescript@5.9.2)': + '@typescript-eslint/utils@8.38.0(eslint@9.33.0(jiti@2.5.1))(typescript@5.9.2)': dependencies: - '@eslint-community/eslint-utils': 4.7.0(eslint@9.33.0(jiti@2.4.2)) + '@eslint-community/eslint-utils': 4.7.0(eslint@9.33.0(jiti@2.5.1)) '@typescript-eslint/scope-manager': 8.38.0 '@typescript-eslint/types': 8.38.0 '@typescript-eslint/typescript-estree': 8.38.0(typescript@5.9.2) - eslint: 9.33.0(jiti@2.4.2) + eslint: 9.33.0(jiti@2.5.1) typescript: 5.9.2 transitivePeerDependencies: - supports-color - '@typescript-eslint/utils@8.39.1(eslint@9.33.0(jiti@2.4.2))(typescript@5.9.2)': + '@typescript-eslint/utils@8.39.1(eslint@9.33.0(jiti@2.5.1))(typescript@5.9.2)': dependencies: - '@eslint-community/eslint-utils': 4.7.0(eslint@9.33.0(jiti@2.4.2)) + '@eslint-community/eslint-utils': 4.7.0(eslint@9.33.0(jiti@2.5.1)) '@typescript-eslint/scope-manager': 8.39.1 '@typescript-eslint/types': 8.39.1 '@typescript-eslint/typescript-estree': 8.39.1(typescript@5.9.2) - eslint: 9.33.0(jiti@2.4.2) + eslint: 9.33.0(jiti@2.5.1) typescript: 5.9.2 transitivePeerDependencies: - supports-color @@ -11760,7 +11776,7 @@ snapshots: '@unrs/resolver-binding-win32-x64-msvc@1.10.1': optional: true - '@vitejs/plugin-legacy@7.2.1(terser@5.36.0)(vite@7.1.2(@types/node@22.17.2)(jiti@2.4.2)(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.4)(yaml@2.8.1))': + '@vitejs/plugin-legacy@7.2.1(terser@5.36.0)(vite@7.1.2(@types/node@22.17.2)(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.4)(yaml@2.8.1))': dependencies: '@babel/core': 7.28.0 '@babel/plugin-transform-dynamic-import': 7.27.1(@babel/core@7.28.0) @@ -11775,19 +11791,19 @@ snapshots: regenerator-runtime: 0.14.1 systemjs: 6.15.1 terser: 5.36.0 - vite: 7.1.2(@types/node@22.17.2)(jiti@2.4.2)(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.4)(yaml@2.8.1) + vite: 7.1.2(@types/node@22.17.2)(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.4)(yaml@2.8.1) transitivePeerDependencies: - supports-color - '@vitejs/plugin-react-swc@4.0.0(vite@7.1.2(@types/node@22.17.2)(jiti@2.4.2)(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.4)(yaml@2.8.1))': + '@vitejs/plugin-react-swc@4.0.0(vite@7.1.2(@types/node@22.17.2)(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.4)(yaml@2.8.1))': dependencies: '@rolldown/pluginutils': 1.0.0-beta.30 '@swc/core': 1.13.3 - vite: 7.1.2(@types/node@22.17.2)(jiti@2.4.2)(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.4)(yaml@2.8.1) + vite: 7.1.2(@types/node@22.17.2)(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.4)(yaml@2.8.1) transitivePeerDependencies: - '@swc/helpers' - '@vitejs/plugin-react@5.0.0(vite@7.1.2(@types/node@22.17.2)(jiti@2.4.2)(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.4)(yaml@2.8.1))': + '@vitejs/plugin-react@5.0.0(vite@7.1.2(@types/node@22.17.2)(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.4)(yaml@2.8.1))': dependencies: '@babel/core': 7.28.0 '@babel/plugin-transform-react-jsx-self': 7.27.1(@babel/core@7.28.0) @@ -11795,7 +11811,7 @@ snapshots: '@rolldown/pluginutils': 1.0.0-beta.30 '@types/babel__core': 7.20.5 react-refresh: 0.17.0 - vite: 7.1.2(@types/node@22.17.2)(jiti@2.4.2)(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.4)(yaml@2.8.1) + vite: 7.1.2(@types/node@22.17.2)(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.4)(yaml@2.8.1) transitivePeerDependencies: - supports-color @@ -12961,6 +12977,11 @@ snapshots: graceful-fs: 4.2.11 tapable: 2.2.1 + enhanced-resolve@5.18.3: + dependencies: + graceful-fs: 4.2.11 + tapable: 2.2.1 + entities@2.2.0: {} entities@4.5.0: {} @@ -13265,14 +13286,14 @@ snapshots: escape-string-regexp@5.0.0: {} - eslint-compat-utils@0.5.1(eslint@9.33.0(jiti@2.4.2)): + eslint-compat-utils@0.5.1(eslint@9.33.0(jiti@2.5.1)): dependencies: - eslint: 9.33.0(jiti@2.4.2) + eslint: 9.33.0(jiti@2.5.1) semver: 7.7.2 - eslint-config-prettier@10.1.8(eslint@9.33.0(jiti@2.4.2)): + eslint-config-prettier@10.1.8(eslint@9.33.0(jiti@2.5.1)): dependencies: - eslint: 9.33.0(jiti@2.4.2) + eslint: 9.33.0(jiti@2.5.1) eslint-import-context@0.1.9(unrs-resolver@1.10.1): dependencies: @@ -13281,9 +13302,9 @@ snapshots: optionalDependencies: unrs-resolver: 1.10.1 - eslint-import-resolver-alias@1.1.2(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.39.1(eslint@9.33.0(jiti@2.4.2))(typescript@5.9.2))(eslint@9.33.0(jiti@2.4.2))): + eslint-import-resolver-alias@1.1.2(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.39.1(eslint@9.33.0(jiti@2.5.1))(typescript@5.9.2))(eslint@9.33.0(jiti@2.5.1))): dependencies: - eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.39.1(eslint@9.33.0(jiti@2.4.2))(typescript@5.9.2))(eslint@9.33.0(jiti@2.4.2)) + eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.39.1(eslint@9.33.0(jiti@2.5.1))(typescript@5.9.2))(eslint@9.33.0(jiti@2.5.1)) eslint-import-resolver-node@0.3.9: dependencies: @@ -13293,49 +13314,49 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-import-resolver-typescript@3.10.1(eslint-plugin-import-x@4.16.1(@typescript-eslint/utils@8.39.1(eslint@9.33.0(jiti@2.4.2))(typescript@5.9.2))(eslint-import-resolver-node@0.3.9)(eslint@9.33.0(jiti@2.4.2)))(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.39.1(eslint@9.33.0(jiti@2.4.2))(typescript@5.9.2))(eslint@9.33.0(jiti@2.4.2)))(eslint@9.33.0(jiti@2.4.2)): + eslint-import-resolver-typescript@3.10.1(eslint-plugin-import-x@4.16.1(@typescript-eslint/utils@8.39.1(eslint@9.33.0(jiti@2.5.1))(typescript@5.9.2))(eslint-import-resolver-node@0.3.9)(eslint@9.33.0(jiti@2.5.1)))(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.39.1(eslint@9.33.0(jiti@2.5.1))(typescript@5.9.2))(eslint@9.33.0(jiti@2.5.1)))(eslint@9.33.0(jiti@2.5.1)): dependencies: '@nolyfill/is-core-module': 1.0.39 debug: 4.4.1 - eslint: 9.33.0(jiti@2.4.2) + eslint: 9.33.0(jiti@2.5.1) get-tsconfig: 4.10.1 is-bun-module: 2.0.0 stable-hash: 0.0.5 tinyglobby: 0.2.14 unrs-resolver: 1.10.1 optionalDependencies: - eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.39.1(eslint@9.33.0(jiti@2.4.2))(typescript@5.9.2))(eslint@9.33.0(jiti@2.4.2)) - eslint-plugin-import-x: 4.16.1(@typescript-eslint/utils@8.39.1(eslint@9.33.0(jiti@2.4.2))(typescript@5.9.2))(eslint-import-resolver-node@0.3.9)(eslint@9.33.0(jiti@2.4.2)) + eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.39.1(eslint@9.33.0(jiti@2.5.1))(typescript@5.9.2))(eslint@9.33.0(jiti@2.5.1)) + eslint-plugin-import-x: 4.16.1(@typescript-eslint/utils@8.39.1(eslint@9.33.0(jiti@2.5.1))(typescript@5.9.2))(eslint-import-resolver-node@0.3.9)(eslint@9.33.0(jiti@2.5.1)) transitivePeerDependencies: - supports-color - eslint-module-utils@2.12.1(@typescript-eslint/parser@8.39.1(eslint@9.33.0(jiti@2.4.2))(typescript@5.9.2))(eslint-import-resolver-node@0.3.9)(eslint@9.33.0(jiti@2.4.2)): + eslint-module-utils@2.12.1(@typescript-eslint/parser@8.39.1(eslint@9.33.0(jiti@2.5.1))(typescript@5.9.2))(eslint-import-resolver-node@0.3.9)(eslint@9.33.0(jiti@2.5.1)): dependencies: debug: 3.2.7 optionalDependencies: - '@typescript-eslint/parser': 8.39.1(eslint@9.33.0(jiti@2.4.2))(typescript@5.9.2) - eslint: 9.33.0(jiti@2.4.2) + '@typescript-eslint/parser': 8.39.1(eslint@9.33.0(jiti@2.5.1))(typescript@5.9.2) + eslint: 9.33.0(jiti@2.5.1) eslint-import-resolver-node: 0.3.9 transitivePeerDependencies: - supports-color - eslint-plugin-es-x@7.8.0(eslint@9.33.0(jiti@2.4.2)): + eslint-plugin-es-x@7.8.0(eslint@9.33.0(jiti@2.5.1)): dependencies: - '@eslint-community/eslint-utils': 4.7.0(eslint@9.33.0(jiti@2.4.2)) + '@eslint-community/eslint-utils': 4.7.0(eslint@9.33.0(jiti@2.5.1)) '@eslint-community/regexpp': 4.12.1 - eslint: 9.33.0(jiti@2.4.2) - eslint-compat-utils: 0.5.1(eslint@9.33.0(jiti@2.4.2)) + eslint: 9.33.0(jiti@2.5.1) + eslint-compat-utils: 0.5.1(eslint@9.33.0(jiti@2.5.1)) eslint-plugin-html@8.1.3: dependencies: htmlparser2: 10.0.0 - eslint-plugin-import-x@4.16.1(@typescript-eslint/utils@8.39.1(eslint@9.33.0(jiti@2.4.2))(typescript@5.9.2))(eslint-import-resolver-node@0.3.9)(eslint@9.33.0(jiti@2.4.2)): + eslint-plugin-import-x@4.16.1(@typescript-eslint/utils@8.39.1(eslint@9.33.0(jiti@2.5.1))(typescript@5.9.2))(eslint-import-resolver-node@0.3.9)(eslint@9.33.0(jiti@2.5.1)): dependencies: '@typescript-eslint/types': 8.35.1 comment-parser: 1.4.1 debug: 4.4.1 - eslint: 9.33.0(jiti@2.4.2) + eslint: 9.33.0(jiti@2.5.1) eslint-import-context: 0.1.9(unrs-resolver@1.10.1) is-glob: 4.0.3 minimatch: 9.0.5 @@ -13343,12 +13364,12 @@ snapshots: stable-hash-x: 0.2.0 unrs-resolver: 1.10.1 optionalDependencies: - '@typescript-eslint/utils': 8.39.1(eslint@9.33.0(jiti@2.4.2))(typescript@5.9.2) + '@typescript-eslint/utils': 8.39.1(eslint@9.33.0(jiti@2.5.1))(typescript@5.9.2) eslint-import-resolver-node: 0.3.9 transitivePeerDependencies: - supports-color - eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.39.1(eslint@9.33.0(jiti@2.4.2))(typescript@5.9.2))(eslint@9.33.0(jiti@2.4.2)): + eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.39.1(eslint@9.33.0(jiti@2.5.1))(typescript@5.9.2))(eslint@9.33.0(jiti@2.5.1)): dependencies: '@rtsao/scc': 1.1.0 array-includes: 3.1.9 @@ -13357,9 +13378,9 @@ snapshots: array.prototype.flatmap: 1.3.3 debug: 3.2.7 doctrine: 2.1.0 - eslint: 9.33.0(jiti@2.4.2) + eslint: 9.33.0(jiti@2.5.1) eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.12.1(@typescript-eslint/parser@8.39.1(eslint@9.33.0(jiti@2.4.2))(typescript@5.9.2))(eslint-import-resolver-node@0.3.9)(eslint@9.33.0(jiti@2.4.2)) + eslint-module-utils: 2.12.1(@typescript-eslint/parser@8.39.1(eslint@9.33.0(jiti@2.5.1))(typescript@5.9.2))(eslint-import-resolver-node@0.3.9)(eslint@9.33.0(jiti@2.5.1)) hasown: 2.0.2 is-core-module: 2.16.1 is-glob: 4.0.3 @@ -13371,18 +13392,18 @@ snapshots: string.prototype.trimend: 1.0.9 tsconfig-paths: 3.15.0 optionalDependencies: - '@typescript-eslint/parser': 8.39.1(eslint@9.33.0(jiti@2.4.2))(typescript@5.9.2) + '@typescript-eslint/parser': 8.39.1(eslint@9.33.0(jiti@2.5.1))(typescript@5.9.2) transitivePeerDependencies: - eslint-import-resolver-typescript - eslint-import-resolver-webpack - supports-color - eslint-plugin-n@17.21.3(eslint@9.33.0(jiti@2.4.2))(typescript@5.9.2): + eslint-plugin-n@17.21.3(eslint@9.33.0(jiti@2.5.1))(typescript@5.9.2): dependencies: - '@eslint-community/eslint-utils': 4.7.0(eslint@9.33.0(jiti@2.4.2)) + '@eslint-community/eslint-utils': 4.7.0(eslint@9.33.0(jiti@2.5.1)) enhanced-resolve: 5.18.1 - eslint: 9.33.0(jiti@2.4.2) - eslint-plugin-es-x: 7.8.0(eslint@9.33.0(jiti@2.4.2)) + eslint: 9.33.0(jiti@2.5.1) + eslint-plugin-es-x: 7.8.0(eslint@9.33.0(jiti@2.5.1)) get-tsconfig: 4.10.1 globals: 15.15.0 globrex: 0.1.2 @@ -13392,37 +13413,37 @@ snapshots: transitivePeerDependencies: - typescript - eslint-plugin-prettier@5.5.4(eslint-config-prettier@10.1.8(eslint@9.33.0(jiti@2.4.2)))(eslint@9.33.0(jiti@2.4.2))(prettier@3.6.2): + eslint-plugin-prettier@5.5.4(eslint-config-prettier@10.1.8(eslint@9.33.0(jiti@2.5.1)))(eslint@9.33.0(jiti@2.5.1))(prettier@3.6.2): dependencies: - eslint: 9.33.0(jiti@2.4.2) + eslint: 9.33.0(jiti@2.5.1) prettier: 3.6.2 prettier-linter-helpers: 1.0.0 synckit: 0.11.8 optionalDependencies: - eslint-config-prettier: 10.1.8(eslint@9.33.0(jiti@2.4.2)) + eslint-config-prettier: 10.1.8(eslint@9.33.0(jiti@2.5.1)) - eslint-plugin-promise@7.2.1(eslint@9.33.0(jiti@2.4.2)): + eslint-plugin-promise@7.2.1(eslint@9.33.0(jiti@2.5.1)): dependencies: - '@eslint-community/eslint-utils': 4.4.1(eslint@9.33.0(jiti@2.4.2)) - eslint: 9.33.0(jiti@2.4.2) + '@eslint-community/eslint-utils': 4.4.1(eslint@9.33.0(jiti@2.5.1)) + eslint: 9.33.0(jiti@2.5.1) - eslint-plugin-react-compiler@19.1.0-rc.2(eslint@9.33.0(jiti@2.4.2)): + eslint-plugin-react-compiler@19.1.0-rc.2(eslint@9.33.0(jiti@2.5.1)): dependencies: '@babel/core': 7.26.10 '@babel/parser': 7.27.0 '@babel/plugin-proposal-private-methods': 7.18.6(@babel/core@7.26.10) - eslint: 9.33.0(jiti@2.4.2) + eslint: 9.33.0(jiti@2.5.1) hermes-parser: 0.25.1 zod: 3.24.4 zod-validation-error: 3.3.1(zod@3.24.4) transitivePeerDependencies: - supports-color - eslint-plugin-react-hooks@5.2.0(eslint@9.33.0(jiti@2.4.2)): + eslint-plugin-react-hooks@5.2.0(eslint@9.33.0(jiti@2.5.1)): dependencies: - eslint: 9.33.0(jiti@2.4.2) + eslint: 9.33.0(jiti@2.5.1) - eslint-plugin-react@7.37.5(eslint@9.33.0(jiti@2.4.2)): + eslint-plugin-react@7.37.5(eslint@9.33.0(jiti@2.5.1)): dependencies: array-includes: 3.1.8 array.prototype.findlast: 1.2.5 @@ -13430,7 +13451,7 @@ snapshots: array.prototype.tosorted: 1.1.4 doctrine: 2.1.0 es-iterator-helpers: 1.2.1 - eslint: 9.33.0(jiti@2.4.2) + eslint: 9.33.0(jiti@2.5.1) estraverse: 5.3.0 hasown: 2.0.2 jsx-ast-utils: 3.3.5 @@ -13455,9 +13476,9 @@ snapshots: eslint-visitor-keys@4.2.1: {} - eslint@9.33.0(jiti@2.4.2): + eslint@9.33.0(jiti@2.5.1): dependencies: - '@eslint-community/eslint-utils': 4.7.0(eslint@9.33.0(jiti@2.4.2)) + '@eslint-community/eslint-utils': 4.7.0(eslint@9.33.0(jiti@2.5.1)) '@eslint-community/regexpp': 4.12.1 '@eslint/config-array': 0.21.0 '@eslint/config-helpers': 0.3.1 @@ -13493,7 +13514,7 @@ snapshots: natural-compare: 1.4.0 optionator: 0.9.4 optionalDependencies: - jiti: 2.4.2 + jiti: 2.5.1 transitivePeerDependencies: - supports-color @@ -14481,6 +14502,8 @@ snapshots: jiti@2.4.2: {} + jiti@2.5.1: {} + jju@1.4.0: {} jotai@2.13.1(@babel/core@7.28.0)(@babel/template@7.27.2)(@types/react@19.1.10)(react@19.1.1): @@ -15168,20 +15191,20 @@ snapshots: sax: 1.3.0 optional: true - neostandard@0.12.2(@typescript-eslint/utils@8.39.1(eslint@9.33.0(jiti@2.4.2))(typescript@5.9.2))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.39.1(eslint@9.33.0(jiti@2.4.2))(typescript@5.9.2))(eslint@9.33.0(jiti@2.4.2)))(eslint@9.33.0(jiti@2.4.2))(typescript@5.9.2): + neostandard@0.12.2(@typescript-eslint/utils@8.39.1(eslint@9.33.0(jiti@2.5.1))(typescript@5.9.2))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.39.1(eslint@9.33.0(jiti@2.5.1))(typescript@5.9.2))(eslint@9.33.0(jiti@2.5.1)))(eslint@9.33.0(jiti@2.5.1))(typescript@5.9.2): dependencies: '@humanwhocodes/gitignore-to-minimatch': 1.0.2 - '@stylistic/eslint-plugin': 2.11.0(eslint@9.33.0(jiti@2.4.2))(typescript@5.9.2) - eslint: 9.33.0(jiti@2.4.2) - eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import-x@4.16.1(@typescript-eslint/utils@8.39.1(eslint@9.33.0(jiti@2.4.2))(typescript@5.9.2))(eslint-import-resolver-node@0.3.9)(eslint@9.33.0(jiti@2.4.2)))(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.39.1(eslint@9.33.0(jiti@2.4.2))(typescript@5.9.2))(eslint@9.33.0(jiti@2.4.2)))(eslint@9.33.0(jiti@2.4.2)) - eslint-plugin-import-x: 4.16.1(@typescript-eslint/utils@8.39.1(eslint@9.33.0(jiti@2.4.2))(typescript@5.9.2))(eslint-import-resolver-node@0.3.9)(eslint@9.33.0(jiti@2.4.2)) - eslint-plugin-n: 17.21.3(eslint@9.33.0(jiti@2.4.2))(typescript@5.9.2) - eslint-plugin-promise: 7.2.1(eslint@9.33.0(jiti@2.4.2)) - eslint-plugin-react: 7.37.5(eslint@9.33.0(jiti@2.4.2)) + '@stylistic/eslint-plugin': 2.11.0(eslint@9.33.0(jiti@2.5.1))(typescript@5.9.2) + eslint: 9.33.0(jiti@2.5.1) + eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import-x@4.16.1(@typescript-eslint/utils@8.39.1(eslint@9.33.0(jiti@2.5.1))(typescript@5.9.2))(eslint-import-resolver-node@0.3.9)(eslint@9.33.0(jiti@2.5.1)))(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.39.1(eslint@9.33.0(jiti@2.5.1))(typescript@5.9.2))(eslint@9.33.0(jiti@2.5.1)))(eslint@9.33.0(jiti@2.5.1)) + eslint-plugin-import-x: 4.16.1(@typescript-eslint/utils@8.39.1(eslint@9.33.0(jiti@2.5.1))(typescript@5.9.2))(eslint-import-resolver-node@0.3.9)(eslint@9.33.0(jiti@2.5.1)) + eslint-plugin-n: 17.21.3(eslint@9.33.0(jiti@2.5.1))(typescript@5.9.2) + eslint-plugin-promise: 7.2.1(eslint@9.33.0(jiti@2.5.1)) + eslint-plugin-react: 7.37.5(eslint@9.33.0(jiti@2.5.1)) find-up: 5.0.0 globals: 15.15.0 peowly: 1.3.2 - typescript-eslint: 8.39.1(eslint@9.33.0(jiti@2.4.2))(typescript@5.9.2) + typescript-eslint: 8.39.1(eslint@9.33.0(jiti@2.5.1))(typescript@5.9.2) transitivePeerDependencies: - '@typescript-eslint/utils' - eslint-import-resolver-node @@ -16679,7 +16702,7 @@ snapshots: tailwind-merge@3.3.1: {} - tailwindcss@4.1.11: {} + tailwindcss@4.1.12: {} tapable@2.2.1: {} @@ -16882,13 +16905,13 @@ snapshots: dependencies: is-typedarray: 1.0.0 - typescript-eslint@8.39.1(eslint@9.33.0(jiti@2.4.2))(typescript@5.9.2): + typescript-eslint@8.39.1(eslint@9.33.0(jiti@2.5.1))(typescript@5.9.2): dependencies: - '@typescript-eslint/eslint-plugin': 8.39.1(@typescript-eslint/parser@8.39.1(eslint@9.33.0(jiti@2.4.2))(typescript@5.9.2))(eslint@9.33.0(jiti@2.4.2))(typescript@5.9.2) - '@typescript-eslint/parser': 8.39.1(eslint@9.33.0(jiti@2.4.2))(typescript@5.9.2) + '@typescript-eslint/eslint-plugin': 8.39.1(@typescript-eslint/parser@8.39.1(eslint@9.33.0(jiti@2.5.1))(typescript@5.9.2))(eslint@9.33.0(jiti@2.5.1))(typescript@5.9.2) + '@typescript-eslint/parser': 8.39.1(eslint@9.33.0(jiti@2.5.1))(typescript@5.9.2) '@typescript-eslint/typescript-estree': 8.39.1(typescript@5.9.2) - '@typescript-eslint/utils': 8.39.1(eslint@9.33.0(jiti@2.4.2))(typescript@5.9.2) - eslint: 9.33.0(jiti@2.4.2) + '@typescript-eslint/utils': 8.39.1(eslint@9.33.0(jiti@2.5.1))(typescript@5.9.2) + eslint: 9.33.0(jiti@2.5.1) typescript: 5.9.2 transitivePeerDependencies: - supports-color @@ -16943,7 +16966,7 @@ snapshots: dependencies: '@fastify/busboy': 2.1.1 - undici@7.13.0: {} + undici@7.14.0: {} unicode-canonical-property-names-ecmascript@2.0.1: {} @@ -17165,7 +17188,7 @@ snapshots: - rollup - supports-color - vite-plugin-dts@4.5.4(@types/node@22.17.2)(rollup@4.46.2)(typescript@5.9.2)(vite@7.1.2(@types/node@22.17.2)(jiti@2.4.2)(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.4)(yaml@2.8.1)): + vite-plugin-dts@4.5.4(@types/node@22.17.2)(rollup@4.46.2)(typescript@5.9.2)(vite@7.1.2(@types/node@22.17.2)(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.4)(yaml@2.8.1)): dependencies: '@microsoft/api-extractor': 7.51.0(@types/node@22.17.2) '@rollup/pluginutils': 5.1.4(rollup@4.46.2) @@ -17178,13 +17201,13 @@ snapshots: magic-string: 0.30.17 typescript: 5.9.2 optionalDependencies: - vite: 7.1.2(@types/node@22.17.2)(jiti@2.4.2)(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.4)(yaml@2.8.1) + vite: 7.1.2(@types/node@22.17.2)(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.4)(yaml@2.8.1) transitivePeerDependencies: - '@types/node' - rollup - supports-color - vite-plugin-html@3.2.2(vite@7.1.2(@types/node@22.17.2)(jiti@2.4.2)(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.4)(yaml@2.8.1)): + vite-plugin-html@3.2.2(vite@7.1.2(@types/node@22.17.2)(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.4)(yaml@2.8.1)): dependencies: '@rollup/pluginutils': 4.2.1 colorette: 2.0.20 @@ -17198,39 +17221,39 @@ snapshots: html-minifier-terser: 6.1.0 node-html-parser: 5.4.2 pathe: 0.2.0 - vite: 7.1.2(@types/node@22.17.2)(jiti@2.4.2)(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.4)(yaml@2.8.1) + vite: 7.1.2(@types/node@22.17.2)(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.4)(yaml@2.8.1) - vite-plugin-sass-dts@1.3.31(postcss@8.5.6)(prettier@3.6.2)(sass-embedded@1.90.0)(vite@7.1.2(@types/node@22.17.2)(jiti@2.4.2)(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.4)(yaml@2.8.1)): + vite-plugin-sass-dts@1.3.31(postcss@8.5.6)(prettier@3.6.2)(sass-embedded@1.90.0)(vite@7.1.2(@types/node@22.17.2)(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.4)(yaml@2.8.1)): dependencies: postcss: 8.5.6 postcss-js: 4.0.1(postcss@8.5.6) prettier: 3.6.2 sass-embedded: 1.90.0 - vite: 7.1.2(@types/node@22.17.2)(jiti@2.4.2)(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.4)(yaml@2.8.1) + vite: 7.1.2(@types/node@22.17.2)(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.4)(yaml@2.8.1) - vite-plugin-svgr@4.3.0(rollup@4.46.2)(typescript@5.9.2)(vite@7.1.2(@types/node@22.17.2)(jiti@2.4.2)(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.4)(yaml@2.8.1)): + vite-plugin-svgr@4.3.0(rollup@4.46.2)(typescript@5.9.2)(vite@7.1.2(@types/node@22.17.2)(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.4)(yaml@2.8.1)): dependencies: '@rollup/pluginutils': 5.1.3(rollup@4.46.2) '@svgr/core': 8.1.0(typescript@5.9.2) '@svgr/plugin-jsx': 8.1.0(@svgr/core@8.1.0(typescript@5.9.2)) - vite: 7.1.2(@types/node@22.17.2)(jiti@2.4.2)(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.4)(yaml@2.8.1) + vite: 7.1.2(@types/node@22.17.2)(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.4)(yaml@2.8.1) transitivePeerDependencies: - rollup - supports-color - typescript - vite-tsconfig-paths@5.1.4(typescript@5.9.2)(vite@7.1.2(@types/node@22.17.2)(jiti@2.4.2)(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.4)(yaml@2.8.1)): + vite-tsconfig-paths@5.1.4(typescript@5.9.2)(vite@7.1.2(@types/node@22.17.2)(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.4)(yaml@2.8.1)): dependencies: debug: 4.3.7 globrex: 0.1.2 tsconfck: 3.0.3(typescript@5.9.2) optionalDependencies: - vite: 7.1.2(@types/node@22.17.2)(jiti@2.4.2)(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.4)(yaml@2.8.1) + vite: 7.1.2(@types/node@22.17.2)(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.4)(yaml@2.8.1) transitivePeerDependencies: - supports-color - typescript - vite@7.1.2(@types/node@22.17.2)(jiti@2.4.2)(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.4)(yaml@2.8.1): + vite@7.1.2(@types/node@22.17.2)(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.4)(yaml@2.8.1): dependencies: esbuild: 0.25.0 fdir: 6.4.6(picomatch@4.0.3) @@ -17241,7 +17264,7 @@ snapshots: optionalDependencies: '@types/node': 22.17.2 fsevents: 2.3.3 - jiti: 2.4.2 + jiti: 2.5.1 less: 4.2.0 lightningcss: 1.30.1 sass: 1.90.0 diff --git a/clash-nyanpasu/scripts/package.json b/clash-nyanpasu/scripts/package.json index 58ddc58c93..fa06419787 100644 --- a/clash-nyanpasu/scripts/package.json +++ b/clash-nyanpasu/scripts/package.json @@ -26,7 +26,7 @@ "picocolors": "1.1.1", "tar": "7.4.3", "telegram": "2.26.22", - "undici": "7.13.0", + "undici": "7.14.0", "yargs": "18.0.0" } } diff --git a/lede/target/linux/rockchip/armv8/base-files/etc/board.d/01_leds b/lede/target/linux/rockchip/armv8/base-files/etc/board.d/01_leds index a83b9625d5..c7cf300d14 100755 --- a/lede/target/linux/rockchip/armv8/base-files/etc/board.d/01_leds +++ b/lede/target/linux/rockchip/armv8/base-files/etc/board.d/01_leds @@ -13,6 +13,7 @@ friendlyarm,nanopi-r2c|\ friendlyarm,nanopi-r2c-plus|\ friendlyarm,nanopi-r2s|\ friendlyarm,nanopi-r2s-plus|\ +friendlyarm,nanopi-r3s|\ friendlyarm,nanopi-r4se|\ friendlyarm,nanopi-r4s|\ friendlyarm,nanopi-r6c|\ @@ -22,10 +23,6 @@ xunlong,orangepi-r1-plus-lts) ucidef_set_led_netdev "wan" "WAN" "green:wan" "eth0" ucidef_set_led_netdev "lan" "LAN" "green:lan" "eth1" ;; -friendlyarm,nanopi-r3s) - ucidef_set_led_netdev "wan" "WAN" "wan_led" "eth0" - ucidef_set_led_netdev "lan" "LAN" "lan_led" "eth1" - ;; friendlyarm,nanopi-r5c) ucidef_set_led_netdev "wan" "WAN" "green:wan" "eth1" ucidef_set_led_netdev "lan" "LAN" "green:lan" "eth0" @@ -43,7 +40,6 @@ friendlyarm,nanopi-r6s) ;; friendlyarm,nanopi-m5|\ friendlyarm,nanopi-r76s) - ucidef_set_led_default "power" "POWER" "red:power" "1" ucidef_set_led_netdev "wan" "WAN" "green:wan" "eth1" ucidef_set_led_netdev "lan" "LAN" "green:lan" "eth0" ;; @@ -65,6 +61,17 @@ radxa,e20c) ucidef_set_led_netdev "lan" "LAN" "green:lan" "eth0" ucidef_set_led_netdev "wan" "WAN" "green:wan" "eth1" ;; +radxa,e24c|\ +radxa,e54c) + ucidef_set_led_netdev "lan1" "LAN1" "green:lan1" "lan1" + ucidef_set_led_netdev "lan2" "LAN2" "green:lan2" "lan2" + ucidef_set_led_netdev "lan3" "LAN3" "green:lan3" "lan3" + ucidef_set_led_netdev "wan" "WAN" "green:wan" "wan" + ;; +radxa,e52c) + ucidef_set_led_netdev "lan" "LAN" "green:lan" "eth1" + ucidef_set_led_netdev "wan" "WAN" "green:wan" "eth0" + ;; widora,mangopi-m28c) ucidef_set_led_netdev "modem" "MODEM" "blue:modem" "usb0" ucidef_set_led_netdev "wifi" "WIFI" "yellow:wifi" "wlan0" diff --git a/lede/target/linux/rockchip/armv8/base-files/etc/board.d/02_network b/lede/target/linux/rockchip/armv8/base-files/etc/board.d/02_network index bbe65c220d..d17eabca3f 100755 --- a/lede/target/linux/rockchip/armv8/base-files/etc/board.d/02_network +++ b/lede/target/linux/rockchip/armv8/base-files/etc/board.d/02_network @@ -22,6 +22,7 @@ rockchip_setup_interfaces() friendlyarm,nanopi-r4se|\ friendlyarm,nanopi-r6c|\ hinlink,opc-h66k|\ + radxa,e52c|\ rocktech,mpc1903|\ seewo,srcm3588-io|\ sharevdi,h3399pc|\ @@ -69,6 +70,10 @@ rockchip_setup_interfaces() lyt,t68m) ucidef_set_interfaces_lan_wan 'lan2 lan3 lan4' 'lan1' ;; + radxa,e24c|\ + radxa,e54c) + ucidef_set_interfaces_lan_wan 'lan1 lan2 lan3' 'wan' + ;; *) ucidef_set_interface_lan 'eth0' ;; @@ -121,6 +126,7 @@ rockchip_setup_macs() friendlyarm,nanopi-r2c-plus|\ friendlyarm,nanopi-r2s|\ friendlyarm,nanopi-r2s-plus|\ + friendlyarm,nanopi-r76s|\ hinlink,opc-h28k|\ hinlink,opc-h66k|\ hinlink,opc-h68k|\ @@ -151,10 +157,6 @@ rockchip_setup_macs() wan_mac=$(macaddr_generate_from_mmc_cid mmcblk1) lan_mac=$(macaddr_add "$wan_mac" +1) ;; - friendlyarm,nanopi-r76s) - wan_mac=$(macaddr_generate_from_mmc_cid mmcblk2) - lan_mac=$(macaddr_add "$wan_mac" +1) - ;; xunlong,orangepi-r1-plus|\ xunlong,orangepi-r1-plus-lts) lan_mac=$(cat /sys/class/net/eth1/address) diff --git a/lede/target/linux/rockchip/armv8/base-files/etc/hotplug.d/net/40-net-smp-affinity b/lede/target/linux/rockchip/armv8/base-files/etc/hotplug.d/net/40-net-smp-affinity index 6ed5a87ab8..37e176b564 100644 --- a/lede/target/linux/rockchip/armv8/base-files/etc/hotplug.d/net/40-net-smp-affinity +++ b/lede/target/linux/rockchip/armv8/base-files/etc/hotplug.d/net/40-net-smp-affinity @@ -34,7 +34,6 @@ armsom,sige3|\ armsom,sige5|\ armsom,sige7|\ hinlink,opc-h28k|\ -radxa,e20c|\ widora,mangopi-m28k|\ widora,mangopi-m28k-pro) set_interface_core 4 "eth0" @@ -73,6 +72,13 @@ friendlyarm,nanopi-r6s) set_interface_core 20 "eth1" set_interface_core 40 "eth2" ;; +radxa,e20c|\ +radxa,e24c) + set_interface_core 2 "eth0" + ;; +radxa,e54c) + set_interface_core 20 "eth0" + ;; widora,mangopi-m28c) set_interface_core 4 "eth0" set_interface_core 8 "xhci-hcd:usb1" diff --git a/lede/target/linux/rockchip/files/arch/arm64/boot/dts/rockchip/rk3528-radxa-e20c.dts b/lede/target/linux/rockchip/files/arch/arm64/boot/dts/rockchip/rk3528-radxa-e20c.dts index 9d73227c2b..b0618c8fd3 100644 --- a/lede/target/linux/rockchip/files/arch/arm64/boot/dts/rockchip/rk3528-radxa-e20c.dts +++ b/lede/target/linux/rockchip/files/arch/arm64/boot/dts/rockchip/rk3528-radxa-e20c.dts @@ -2,10 +2,10 @@ // Copyright (c) 2024 AY /dts-v1/; + #include #include #include - #include "rk3528.dtsi" / { @@ -31,7 +31,7 @@ pinctrl-names = "default"; pinctrl-0 = <&user_key>; - key-user { + button-user { label = "user"; linux,code = ; gpios = <&gpio0 RK_PA0 GPIO_ACTIVE_LOW>; @@ -42,7 +42,7 @@ leds { compatible = "gpio-leds"; pinctrl-names = "default"; - pinctrl-0 = <&lan_led_en>, <&wan_led_en>, <&sys_led_en>; + pinctrl-0 = <&lan_led_g>, <&wan_led_g>, <&sys_led_g>; lan { label = "green:lan"; @@ -60,70 +60,7 @@ }; }; - vcc_1v8: vcc-1v8 { - compatible = "regulator-fixed"; - regulator-name = "vcc_1v8"; - regulator-always-on; - regulator-boot-on; - regulator-min-microvolt = <1800000>; - regulator-max-microvolt = <1800000>; - vin-supply = <&vcc_3v3>; - }; - - vcc_3v3: vcc-3v3 { - compatible = "regulator-fixed"; - regulator-name = "vcc_3v3"; - regulator-always-on; - regulator-boot-on; - regulator-min-microvolt = <3300000>; - regulator-max-microvolt = <3300000>; - vin-supply = <&vcc5v0_sys>; - }; - - vcc5v0_sys: vcc5v0-sys { - compatible = "regulator-fixed"; - regulator-name = "vcc5v0_sys"; - regulator-always-on; - regulator-boot-on; - regulator-min-microvolt = <5000000>; - regulator-max-microvolt = <5000000>; - }; - - vcc5v0_usb_host: vcc5v0-usb-host { - compatible = "regulator-fixed"; - enable-active-high; - gpio = <&gpio0 RK_PA1 GPIO_ACTIVE_HIGH>; - pinctrl-names = "default"; - pinctrl-0 = <&vcc5v0_usb_host_en>; - regulator-name = "vcc5v0_usb_host"; - regulator-min-microvolt = <5000000>; - regulator-max-microvolt = <5000000>; - vin-supply = <&vcc5v0_sys>; - }; - - vccio_sd: vccio-sd { - compatible = "regulator-gpio"; - gpios = <&gpio4 RK_PB6 GPIO_ACTIVE_HIGH>; - regulator-name = "vccio_sd"; - regulator-always-on; - regulator-boot-on; - regulator-min-microvolt = <1800000>; - regulator-max-microvolt = <3300000>; - states = <1800000 0x0>, <3300000 0x1>; - vin-supply = <&vcc5v0_sys>; - }; - - vcc_ddr: vcc-ddr { - compatible = "regulator-fixed"; - regulator-name = "vcc_ddr"; - regulator-always-on; - regulator-boot-on; - regulator-min-microvolt = <1200000>; - regulator-max-microvolt = <1200000>; - vin-supply = <&vcc5v0_sys>; - }; - - vdd_0v9: vdd-0v9 { + vdd_0v9: regulator-0v9-vdd { compatible = "regulator-fixed"; regulator-name = "vdd_0v9"; regulator-always-on; @@ -133,7 +70,70 @@ vin-supply = <&vcc5v0_sys>; }; - vdd_arm: vdd-arm { + vcc_ddr: regulator-1v1-vcc-ddr { + compatible = "regulator-fixed"; + regulator-name = "vcc_ddr"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <1100000>; + regulator-max-microvolt = <1100000>; + vin-supply = <&vcc5v0_sys>; + }; + + vcc_1v8: regulator-1v8-vcc { + compatible = "regulator-fixed"; + regulator-name = "vcc_1v8"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + vin-supply = <&vcc_3v3>; + }; + + vcc_3v3: regulator-3v3-vcc { + compatible = "regulator-fixed"; + regulator-name = "vcc_3v3"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + vin-supply = <&vcc5v0_sys>; + }; + + vcc5v0_sys: regulator-5v0-vcc-sys { + compatible = "regulator-fixed"; + regulator-name = "vcc5v0_sys"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + }; + + vcc5v0_usb20: regulator-5v0-vcc-usb20 { + compatible = "regulator-fixed"; + enable-active-high; + gpios = <&gpio0 RK_PA1 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; + pinctrl-0 = <&usb_host_en>; + regulator-name = "vcc5v0_usb20"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + vin-supply = <&vcc5v0_sys>; + }; + + vccio_sd: regulator-vccio-sd { + compatible = "regulator-gpio"; + gpios = <&gpio4 RK_PB6 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; + pinctrl-0 = <&sdmmc_vol_ctrl_h>; + regulator-name = "vccio_sd"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + states = <1800000 0x0>, <3300000 0x1>; + vin-supply = <&vcc5v0_sys>; + }; + + vdd_arm: regulator-vdd-arm { compatible = "pwm-regulator"; pwms = <&pwm1 0 5000 1>; pwm-supply = <&vcc5v0_sys>; @@ -145,7 +145,7 @@ regulator-settling-time-up-us = <250>; }; - vdd_logic: vdd-logic { + vdd_logic: regulator-vdd-logic { compatible = "pwm-regulator"; pwms = <&pwm2 0 5000 1>; pwm-supply = <&vcc5v0_sys>; @@ -205,19 +205,24 @@ &i2c1 { status = "okay"; - eeprom: eeprom@50 { - compatible = "atmel,24c16"; + eeprom@50 { + compatible = "belling,bl24c16a", "atmel,24c16"; #address-cells = <1>; #size-cells = <1>; reg = <0x50>; pagesize = <16>; read-only; + vcc-supply = <&vcc_3v3>; nvmem-layout { compatible = "fixed-layout"; #address-cells = <1>; #size-cells = <1>; + eth_mac0: macaddr@9e { + reg = <0x9e 0x06>; + }; + eth_mac1: macaddr@a4 { reg = <0xa4 0x06>; }; @@ -226,7 +231,7 @@ }; &mdio1 { - rgmii_phy: phy@1 { + rgmii_phy: ethernet-phy@1 { compatible = "ethernet-phy-ieee802.3-c22"; reg = <0x1>; }; @@ -259,21 +264,27 @@ }; leds { - lan_led_en: lan-led-en { + lan_led_g: lan-led-g { rockchip,pins = <4 RK_PB5 RK_FUNC_GPIO &pcfg_pull_none>; }; - wan_led_en: wan-led-en { + wan_led_g: wan-led-g { rockchip,pins = <4 RK_PC0 RK_FUNC_GPIO &pcfg_pull_none>; }; - sys_led_en: sys-led-en { + sys_led_g: sys-led-g { rockchip,pins = <4 RK_PC1 RK_FUNC_GPIO &pcfg_pull_none>; }; }; + sdmmc { + sdmmc_vol_ctrl_h: sdmmc-vol-ctrl-h { + rockchip,pins = <4 RK_PB6 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; + usb { - vcc5v0_usb_host_en: vcc5v0-usb-host-en { + usb_host_en: usb-host-en { rockchip,pins = <0 RK_PA1 RK_FUNC_GPIO &pcfg_pull_none>; }; }; @@ -332,7 +343,11 @@ }; &usb2phy0_host { - phy-supply = <&vcc5v0_usb_host>; + phy-supply = <&vcc5v0_usb20>; + status = "okay"; +}; + +&usb2phy0_otg { status = "okay"; }; @@ -343,3 +358,11 @@ &usb_host0_ohci { status = "okay"; }; + +&usb_host0_xhci { + dr_mode = "host"; + maximum-speed = "high-speed"; + phys = <&usb2phy0_otg>; + phy-names = "usb2-phy"; + status = "okay"; +}; diff --git a/lede/target/linux/rockchip/files/arch/arm64/boot/dts/rockchip/rk3528-radxa-e24c.dts b/lede/target/linux/rockchip/files/arch/arm64/boot/dts/rockchip/rk3528-radxa-e24c.dts new file mode 100644 index 0000000000..992260f748 --- /dev/null +++ b/lede/target/linux/rockchip/files/arch/arm64/boot/dts/rockchip/rk3528-radxa-e24c.dts @@ -0,0 +1,626 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) + +/dts-v1/; + +#include +#include +#include +#include "rk3528.dtsi" + +/ { + model = "Radxa E24C"; + compatible = "radxa,e24c", "rockchip,rk3528"; + + aliases { + ethernet0 = &gmac1; + mmc0 = &sdhci; + mmc1 = &sdmmc; + rtc0 = &hym8563; + + led-boot = &status_led; + led-failsafe = &status_led; + led-running = &status_led; + led-upgrade = &status_led; + }; + + chosen { + stdout-path = "serial0:1500000n8"; + }; + + gpio-keys { + compatible = "gpio-keys"; + pinctrl-names = "default"; + pinctrl-0 = <&gpio0_a0_user>; + + button-user { + label = "USER"; + linux,code = ; + gpios = <&gpio0 RK_PA0 GPIO_ACTIVE_LOW>; + wakeup-source; + }; + }; + + leds { + compatible = "gpio-leds"; + + status_led: led-0 { + label = "green:sys"; + gpios = <&gpio4 RK_PA1 GPIO_ACTIVE_LOW>; + pinctrl-names = "default"; + pinctrl-0 = <&sys_led_g>; + }; + + led-1 { + label = "green:wan"; + linux,default-trigger = "netdev"; + gpios = <&gpio4 RK_PA0 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; + pinctrl-0 = <&wan_led_g>; + }; + + led-2 { + label = "green:lan1"; + linux,default-trigger = "netdev"; + gpios = <&gpio1 RK_PB0 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; + pinctrl-0 = <&lan1_led_g>; + }; + + led-3 { + label = "green:lan2"; + linux,default-trigger = "netdev"; + gpios = <&gpio1 RK_PB1 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; + pinctrl-0 = <&lan2_led_g>; + }; + + led-4 { + label = "green:lan3"; + linux,default-trigger = "netdev"; + gpios = <&gpio1 RK_PB4 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; + pinctrl-0 = <&lan3_led_g>; + }; + }; + + vcc_12v: regulator-12v0-vcc { + compatible = "regulator-fixed"; + regulator-name = "vcc_12v"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <12000000>; + regulator-max-microvolt = <12000000>; + }; + + vcc3v3_mkey: regulator-3v3-vcc-mkey { + compatible = "regulator-fixed"; + enable-active-high; + gpios = <&gpio4 RK_PC6 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; + pinctrl-0 = <&mkey_pwr_en>; + regulator-name = "vcc3v3_mkey"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + vin-supply = <&vcc5v0_sys>; + }; + + vcc5v0_sys: regulator-5v0-vcc-sys { + compatible = "regulator-fixed"; + regulator-name = "vcc5v0_sys"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + vin-supply = <&vcc_12v>; + }; + + vcc5v0_usb20: regulator-5v0-vcc-usb20 { + compatible = "regulator-fixed"; + enable-active-high; + gpios = <&gpio1 RK_PA3 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; + pinctrl-0 = <&usb_host_en>; + regulator-name = "vcc5v0_usb20"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + vin-supply = <&vcc5v0_sys>; + }; + + avddh_3v3: regulator-avdd-3v3 { + compatible = "regulator-fixed"; + enable-active-high; + gpios = <&gpio1 RK_PC3 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; + pinctrl-0 = <&gpio_8367_en>; + regulator-name = "avddh_3v3"; + startup-delay-us = <10000>; + vin-supply = <&vcc5v0_sys>; + }; + + vccio_sd: regulator-vccio-sd { + compatible = "regulator-gpio"; + gpios = <&gpio4 RK_PB6 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; + pinctrl-0 = <&sdmmc_vol_ctrl_h>; + regulator-name = "vccio_sd"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + states = <1800000 0x0>, <3300000 0x1>; + vin-supply = <&vcc5v0_sys>; + }; +}; + +&combphy { + status = "okay"; +}; + +&cpu0 { + cpu-supply = <&vdd_arm>; +}; + +&cpu1 { + cpu-supply = <&vdd_arm>; +}; + +&cpu2 { + cpu-supply = <&vdd_arm>; +}; + +&cpu3 { + cpu-supply = <&vdd_arm>; +}; + +&gmac1 { + /delete-property/ snps,tso; + clock_in_out = "output"; + phy-mode = "rgmii-id"; + phy-supply = <&avddh_3v3>; + pinctrl-names = "default"; + pinctrl-0 = <&rgmii_miim + &rgmii_tx_bus2 + &rgmii_rx_bus2 + &rgmii_rgmii_clk + &rgmii_rgmii_bus>; + status = "okay"; + + fixed-link { + speed = <1000>; + full-duplex; + }; +}; + +&gpu { + mali-supply = <&vdd_logic>; + status = "okay"; +}; + +&i2c0 { + pinctrl-names = "default"; + pinctrl-0 = <&i2c0m0_xfer>; + status = "okay"; + + rk805: pmic@18 { + compatible = "rockchip,rk805"; + reg = <0x18>; + interrupt-parent = <&gpio4>; + interrupts = ; + #clock-cells = <1>; + gpio-controller; + #gpio-cells = <2>; + pinctrl-names = "default"; + pinctrl-0 = <&pmic_int>; + system-power-controller; + wakeup-source; + + vcc1-supply = <&vcc5v0_sys>; + vcc2-supply = <&vcc5v0_sys>; + vcc3-supply = <&vcc5v0_sys>; + vcc4-supply = <&vcc5v0_sys>; + vcc5-supply = <&vcc5v0_sys>; + vcc6-supply = <&vcc5v0_sys>; + + regulators { + vdd_arm: DCDC_REG1 { + regulator-name = "vdd_arm"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <712500>; + regulator-max-microvolt = <1450000>; + regulator-ramp-delay = <12500>; + + regulator-state-mem { + regulator-on-in-suspend; + }; + }; + + vdd_logic: DCDC_REG2 { + regulator-name = "vdd_logic"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <712500>; + regulator-max-microvolt = <1450000>; + regulator-ramp-delay = <12500>; + + regulator-state-mem { + regulator-on-in-suspend; + }; + }; + + vcc_ddr: DCDC_REG3 { + regulator-name = "vcc_ddr"; + regulator-always-on; + regulator-boot-on; + + regulator-state-mem { + regulator-on-in-suspend; + }; + }; + + vcc_3v3: DCDC_REG4 { + regulator-name = "vcc_3v3"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + + regulator-state-mem { + regulator-on-in-suspend; + regulator-suspend-microvolt = <3300000>; + }; + }; + + vcc_1v8: LDO_REG1 { + regulator-name = "vcc_1v8"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + + regulator-state-mem { + regulator-on-in-suspend; + regulator-suspend-microvolt = <1800000>; + }; + }; + + vcc1v8_emmc: LDO_REG2 { + regulator-name = "vcc1v8_emmc"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + + regulator-state-mem { + regulator-on-in-suspend; + regulator-suspend-microvolt = <1800000>; + }; + }; + + vdd_0v9_p: LDO_REG3 { + regulator-name = "vdd_0v9_p"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <900000>; + regulator-max-microvolt = <900000>; + + regulator-state-mem { + regulator-on-in-suspend; + regulator-suspend-microvolt = <900000>; + }; + }; + }; + }; +}; + +&i2c1 { + pinctrl-names = "default"; + pinctrl-0 = <&i2c1m0_xfer>; + status = "okay"; + + eeprom@50 { + compatible = "belling,bl24c16a", "atmel,24c16"; + #address-cells = <1>; + #size-cells = <1>; + reg = <0x50>; + pagesize = <16>; + read-only; + vcc-supply = <&vcc_3v3>; + + nvmem-layout { + compatible = "fixed-layout"; + #address-cells = <1>; + #size-cells = <1>; + + eth_mac0: macaddr@9e { + reg = <0x9e 0x06>; + }; + + eth_mac1: macaddr@a4 { + reg = <0xa4 0x06>; + }; + + eth_mac2: macaddr@aa { + reg = <0xaa 0x06>; + }; + + eth_mac3: macaddr@b0 { + reg = <0xb0 0x06>; + }; + }; + }; +}; + +&i2c5 { + pinctrl-names = "default"; + pinctrl-0 = <&i2c5m0_xfer>; + status = "okay"; + + hym8563: rtc@51 { + compatible = "haoyu,hym8563"; + reg = <0x51>; + #clock-cells = <0>; + interrupt-parent = <&gpio4>; + interrupts = ; + pinctrl-names = "default"; + pinctrl-0 = <&rtc_int_l>; + wakeup-source; + }; +}; + +&mdio1 { + ethernet-switch@29 { + compatible = "realtek,rtl8365mb"; + reg = <29>; + reset-gpios = <&gpio4 RK_PC2 GPIO_ACTIVE_LOW>; + pinctrl-names = "default"; + pinctrl-0 = <&gmac1_rstn_l>; + + switch_intc: interrupt-controller { + interrupt-parent = <&gpio1>; + interrupts = ; + interrupt-controller; + #address-cells = <0>; + #interrupt-cells = <1>; + }; + + mdio { + #address-cells = <1>; + #size-cells = <0>; + + phy0: ethernet-phy@0 { + reg = <0>; + interrupt-parent = <&switch_intc>; + interrupts = <0>; + }; + + phy1: ethernet-phy@1 { + reg = <1>; + interrupt-parent = <&switch_intc>; + interrupts = <1>; + }; + + phy2: ethernet-phy@2 { + reg = <2>; + interrupt-parent = <&switch_intc>; + interrupts = <2>; + }; + + phy3: ethernet-phy@3 { + reg = <3>; + interrupt-parent = <&switch_intc>; + interrupts = <3>; + }; + + phy4: ethernet-phy@4 { + reg = <4>; + interrupt-parent = <&switch_intc>; + interrupts = <4>; + }; + }; + + ethernet-ports { + #address-cells = <1>; + #size-cells = <0>; + + ethernet-port@0 { + reg = <0>; + label = "wan"; + phy-handle = <&phy0>; + nvmem-cells = <ð_mac0>; + nvmem-cell-names = "mac-address"; + }; + + ethernet-port@1 { + reg = <1>; + label = "lan1"; + phy-handle = <&phy1>; + nvmem-cells = <ð_mac1>; + nvmem-cell-names = "mac-address"; + }; + + ethernet-port@2 { + reg = <2>; + label = "lan2"; + phy-handle = <&phy2>; + nvmem-cells = <ð_mac2>; + nvmem-cell-names = "mac-address"; + }; + + ethernet-port@3 { + reg = <3>; + label = "lan3"; + phy-handle = <&phy3>; + nvmem-cells = <ð_mac3>; + nvmem-cell-names = "mac-address"; + }; + + ethernet-port@6 { + reg = <6>; + ethernet = <&gmac1>; + phy-mode = "rgmii-id"; + rx-internal-delay-ps = <2000>; + tx-internal-delay-ps = <2000>; + + fixed-link { + speed = <1000>; + full-duplex; + }; + }; + }; + }; +}; + +&pcie2x1 { + pinctrl-names = "default"; + pinctrl-0 = <&pciem1_pins>; + reset-gpios = <&gpio1 RK_PA2 GPIO_ACTIVE_HIGH>; + vpcie3v3-supply = <&vcc3v3_mkey>; + status = "okay"; +}; + +&pinctrl { + ethernet { + gmac1_rstn_l: gmac1-rstn-l { + rockchip,pins = <4 RK_PC2 RK_FUNC_GPIO &pcfg_pull_none>; + }; + + gpio_8367_en: gpio-8367-en { + rockchip,pins = <1 RK_PC3 RK_FUNC_GPIO &pcfg_pull_none>; + }; + + rtl8367rb_eint: rtl8367rb-eint { + rockchip,pins = <1 RK_PC2 RK_FUNC_GPIO &pcfg_pull_up>; + }; + }; + + gpio-keys { + gpio0_a0_user: gpio0-a0-user { + rockchip,pins = <0 RK_PA0 RK_FUNC_GPIO &pcfg_pull_up>; + }; + }; + + leds { + lan1_led_g: lan1-led-g { + rockchip,pins = <1 RK_PB0 RK_FUNC_GPIO &pcfg_pull_none>; + }; + + lan2_led_g: lan2-led-g { + rockchip,pins = <1 RK_PB1 RK_FUNC_GPIO &pcfg_pull_none>; + }; + + lan3_led_g: lan3-led-g { + rockchip,pins = <1 RK_PB4 RK_FUNC_GPIO &pcfg_pull_none>; + }; + + sys_led_g: sys-led-g { + rockchip,pins = <4 RK_PA1 RK_FUNC_GPIO &pcfg_pull_none>; + }; + + wan_led_g: wan-led-g { + rockchip,pins = <4 RK_PA0 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; + + pcie { + mkey_pwr_en: mkey-pwr-en { + rockchip,pins = <4 RK_PC6 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; + + pmic { + pmic_int: pmic-int { + rockchip,pins = <4 RK_PB2 RK_FUNC_GPIO &pcfg_pull_up>; + }; + }; + + rtc { + rtc_int_l: rtc-int-l { + rockchip,pins = <4 RK_PB0 RK_FUNC_GPIO &pcfg_pull_up>; + }; + }; + + sdmmc { + sdmmc_vol_ctrl_h: sdmmc-vol-ctrl-h { + rockchip,pins = <4 RK_PB6 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; + + usb { + usb_host_en: usb-host-en { + rockchip,pins = <1 RK_PA3 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; +}; + +&rng { + status = "okay"; +}; + +&sdhci { + bus-width = <8>; + cap-mmc-highspeed; + mmc-hs200-1_8v; + non-removable; + vmmc-supply = <&vcc_3v3>; + vqmmc-supply = <&vcc1v8_emmc>; + status = "okay"; +}; + +&sdmmc { + bus-width = <4>; + cap-mmc-highspeed; + cap-sd-highspeed; + disable-wp; + sd-uhs-sdr104; + vmmc-supply = <&vcc_3v3>; + vqmmc-supply = <&vccio_sd>; + status = "okay"; +}; + +&sfc { + pinctrl-names = "default"; + pinctrl-0 = <&fspi_csn0>, <&fspi_pins>; + status = "okay"; + + flash@0 { + compatible = "jedec,spi-nor"; + reg = <0>; + spi-max-frequency = <50000000>; + spi-rx-bus-width = <4>; + spi-tx-bus-width = <1>; + }; +}; + +&tsadc { + status = "okay"; +}; + +&uart0 { + pinctrl-names = "default"; + pinctrl-0 = <&uart0m0_xfer>; + status = "okay"; +}; + +&usb2phy { + status = "okay"; +}; + +&usb2phy0_host { + phy-supply = <&vcc5v0_usb20>; + status = "okay"; +}; + +&usb2phy0_otg { + status = "okay"; +}; + +&usb_host0_ehci { + status = "okay"; +}; + +&usb_host0_xhci { + dr_mode = "host"; + maximum-speed = "high-speed"; + phys = <&usb2phy0_otg>; + phy-names = "usb2-phy"; + status = "okay"; +}; diff --git a/lede/target/linux/rockchip/files/arch/arm64/boot/dts/rockchip/rk3582-radxa-e52c.dts b/lede/target/linux/rockchip/files/arch/arm64/boot/dts/rockchip/rk3582-radxa-e52c.dts new file mode 100644 index 0000000000..bed9ac3ebb --- /dev/null +++ b/lede/target/linux/rockchip/files/arch/arm64/boot/dts/rockchip/rk3582-radxa-e52c.dts @@ -0,0 +1,737 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Copyright (c) 2024 Radxa Computer (Shenzhen) Co., Ltd. + */ + +/dts-v1/; + +#include +#include +#include +#include +#include +#include "rk3588s.dtsi" + +/ { + model = "Radxa E52C"; + compatible = "radxa,e52c", "rockchip,rk3582", "rockchip,rk3588s"; + + aliases { + mmc0 = &sdhci; + mmc1 = &sdmmc; + + led-boot = &status_led; + led-failsafe = &status_led; + led-running = &status_led; + led-upgrade = &status_led; + }; + + chosen { + stdout-path = "serial2:1500000n8"; + }; + + keys-0 { + compatible = "adc-keys"; + io-channels = <&saradc 0>; + io-channel-names = "buttons"; + keyup-threshold-microvolt = <18000>; + poll-interval = <100>; + + button-0 { + label = "Maskrom"; + linux,code = ; + press-threshold-microvolt = <0>; + }; + }; + + keys-1 { + compatible = "gpio-keys"; + pinctrl-names = "default"; + pinctrl-0 = <&pwm15_ir_m1>; + + button-1 { + label = "User"; + linux,code = ; + gpios = <&gpio4 RK_PB3 GPIO_ACTIVE_LOW>; + wakeup-source; + }; + }; + + leds-0 { + compatible = "gpio-leds"; + pinctrl-names = "default"; + pinctrl-0 = <&power_led>; + + status_led: led-0 { + color = ; + default-state = "on"; + function = LED_FUNCTION_STATUS; + gpios = <&gpio3 RK_PC4 GPIO_ACTIVE_HIGH>; + }; + }; + + leds-1 { + compatible = "pwm-leds"; + + led-1 { + color = ; + function = LED_FUNCTION_LAN; + linux,default-trigger = "netdev"; + pwms = <&pwm14 0 1000000 PWM_POLARITY_INVERTED>; + max-brightness = <255>; + }; + + led-2 { + color = ; + function = LED_FUNCTION_WAN; + linux,default-trigger = "netdev"; + pwms = <&pwm11 0 1000000 PWM_POLARITY_INVERTED>; + max-brightness = <255>; + }; + }; + + vcc_1v1_nldo_s3: regulator-1v1-vcc-nldo-s3 { + compatible = "regulator-fixed"; + regulator-name = "vcc_1v1_nldo_s3"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <1100000>; + regulator-max-microvolt = <1100000>; + vin-supply = <&vcc_sysin>; + }; + + vcc_3v3_s0: regulator-3v3-vcc-s0 { + compatible = "regulator-fixed"; + regulator-name = "vcc_3v3_s0"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + vin-supply = <&vcc_3v3_s3>; + }; + + vcca: regulator-4v0-vcca { + compatible = "regulator-fixed"; + regulator-name = "vcca"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <4000000>; + regulator-max-microvolt = <4000000>; + vin-supply = <&vcc_sysin>; + }; + + vcc5v0_usb_otg0: regulator-5v0-vcc-usb-otg0 { + compatible = "regulator-fixed"; + enable-active-high; + gpio = <&gpio0 RK_PD4 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; + pinctrl-0 = <&usb_otg_pwren_h>; + regulator-name = "vcc5v0_usb_otg0"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + vin-supply = <&vcc_sysin>; + }; + + vcc_5v0: regulator-5v0-vcc { + compatible = "regulator-fixed"; + enable-active-high; + gpio = <&gpio4 RK_PA3 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; + pinctrl-0 = <&vcc_5v0_pwren_h>; + regulator-name = "vcc_5v0"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + vin-supply = <&vcc_sysin>; + }; + + vcc_sysin: regulator-5v0-vcc-sysin { + compatible = "regulator-fixed"; + regulator-name = "vcc_sysin"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + }; +}; + +&combphy0_ps { + status = "okay"; +}; + +&combphy2_psu { + status = "okay"; +}; + +/* + * In the Rockchip RK3582 SoC, some CPU cores end up disabled + * and unused because they're marked in the efuses as defective. + * The disabling in the DT is performed by the boot loader. + */ +&cpu_b0 { + cpu-supply = <&vdd_cpu_big0_s0>; +}; + +&cpu_b1 { + cpu-supply = <&vdd_cpu_big0_s0>; +}; + +&cpu_b2 { + cpu-supply = <&vdd_cpu_big1_s0>; +}; + +&cpu_b3 { + cpu-supply = <&vdd_cpu_big1_s0>; +}; + +&cpu_l0 { + cpu-supply = <&vdd_cpu_lit_s0>; +}; + +&cpu_l1 { + cpu-supply = <&vdd_cpu_lit_s0>; +}; + +&cpu_l2 { + cpu-supply = <&vdd_cpu_lit_s0>; +}; + +&cpu_l3 { + cpu-supply = <&vdd_cpu_lit_s0>; +}; + +&display_subsystem { + status = "disabled"; +}; + +&i2c0 { + pinctrl-names = "default"; + pinctrl-0 = <&i2c0m2_xfer>; + status = "okay"; + + vdd_cpu_big0_s0: regulator@42 { + compatible = "rockchip,rk8602"; + reg = <0x42>; + fcs,suspend-voltage-selector = <1>; + regulator-name = "vdd_cpu_big0_s0"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <550000>; + regulator-max-microvolt = <1050000>; + regulator-ramp-delay = <2300>; + vin-supply = <&vcc_sysin>; + + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vdd_cpu_big1_s0: regulator@43 { + compatible = "rockchip,rk8603", "rockchip,rk8602"; + reg = <0x43>; + fcs,suspend-voltage-selector = <1>; + regulator-name = "vdd_cpu_big1_s0"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <550000>; + regulator-max-microvolt = <1050000>; + regulator-ramp-delay = <2300>; + vin-supply = <&vcc_sysin>; + + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + eeprom@50 { + compatible = "belling,bl24c16a", "atmel,24c16"; + reg = <0x50>; + pagesize = <16>; + read-only; + vcc-supply = <&vcc_3v3_s3>; + }; +}; + +&i2c2 { + status = "okay"; + + vdd_npu_s0: regulator@42 { + compatible = "rockchip,rk8602"; + reg = <0x42>; + fcs,suspend-voltage-selector = <1>; + regulator-name = "vdd_npu_s0"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <550000>; + regulator-max-microvolt = <950000>; + regulator-ramp-delay = <2300>; + vin-supply = <&vcc_sysin>; + + regulator-state-mem { + regulator-off-in-suspend; + }; + }; +}; + +&i2c5 { + pinctrl-names = "default"; + pinctrl-0 = <&i2c5m2_xfer>; + status = "okay"; + + rtc@51 { + compatible = "haoyu,hym8563"; + reg = <0x51>; + #clock-cells = <0>; + clock-output-names = "rtcic_32kout"; + interrupt-parent = <&gpio0>; + interrupts = ; + pinctrl-names = "default"; + pinctrl-0 = <&rtc_int_l>; + wakeup-source; + }; +}; + +&pcie2x1l1 { + pinctrl-names = "default"; + pinctrl-0 = <&pcie20x1_1_perstn_m1>; + reset-gpios = <&gpio4 RK_PA2 GPIO_ACTIVE_HIGH>; + vpcie3v3-supply = <&vcc_3v3_s3>; + status = "okay"; +}; + +&pcie2x1l2 { + pinctrl-names = "default"; + pinctrl-0 = <&pcie20x1_2_perstn_m0>; + reset-gpios = <&gpio3 RK_PD1 GPIO_ACTIVE_HIGH>; + vpcie3v3-supply = <&vcc_3v3_s3>; + status = "okay"; +}; + +&pinctrl { + keys { + pwm15_ir_m1: pwm15-ir-m1 { + rockchip,pins = <4 RK_PB3 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; + + leds { + power_led: power-led { + rockchip,pins = <3 RK_PC4 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; + + pcie { + pcie20x1_1_perstn_m1: pcie-1 { + rockchip,pins = <4 RK_PA2 RK_FUNC_GPIO &pcfg_pull_none>; + }; + + pcie20x1_2_perstn_m0: pcie-2 { + rockchip,pins = <3 RK_PD1 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; + + regulators { + vcc_5v0_pwren_h: vcc-5v0-pwren-h { + rockchip,pins = <4 RK_PA3 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; + + rtc { + rtc_int_l: rtc-int-l { + rockchip,pins = <0 RK_PB0 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; + + usb { + usb_otg_pwren_h: usb-otg-pwren-h { + rockchip,pins = <0 RK_PD4 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; +}; + +&pwm11 { + pinctrl-names = "default"; + pinctrl-0 = <&pwm11m1_pins>; + status = "okay"; +}; + +&pwm14 { + pinctrl-names = "default"; + pinctrl-0 = <&pwm14m1_pins>; + status = "okay"; +}; + +&saradc { + vref-supply = <&vcca_1v8_s0>; + status = "okay"; +}; + +&sdhci { + bus-width = <8>; + cap-mmc-highspeed; + mmc-hs400-1_8v; + mmc-hs400-enhanced-strobe; + non-removable; + vmmc-supply = <&vcc_3v3_s0>; + vqmmc-supply = <&vcc_1v8_s3>; + status = "okay"; +}; + +&sdmmc { + bus-width = <4>; + cap-mmc-highspeed; + cap-sd-highspeed; + cd-gpios = <&gpio0 RK_PA4 GPIO_ACTIVE_LOW>; + disable-wp; + sd-uhs-sdr104; + vmmc-supply = <&vcc_3v3_s3>; + vqmmc-supply = <&vccio_sd_s0>; + status = "okay"; +}; + +&spi2 { + status = "okay"; + assigned-clocks = <&cru CLK_SPI2>; + assigned-clock-rates = <200000000>; + num-cs = <1>; + pinctrl-names = "default"; + pinctrl-0 = <&spi2m2_cs0 &spi2m2_pins>; + + pmic@0 { + compatible = "rockchip,rk806"; + reg = <0>; + gpio-controller; + #gpio-cells = <2>; + interrupt-parent = <&gpio0>; + interrupts = <7 IRQ_TYPE_LEVEL_LOW>; + pinctrl-names = "default"; + pinctrl-0 = <&pmic_pins>, <&rk806_dvs1_null>, + <&rk806_dvs2_null>, <&rk806_dvs3_null>; + spi-max-frequency = <1000000>; + system-power-controller; + + vcc1-supply = <&vcc_sysin>; + vcc2-supply = <&vcc_sysin>; + vcc3-supply = <&vcc_sysin>; + vcc4-supply = <&vcc_sysin>; + vcc5-supply = <&vcc_sysin>; + vcc6-supply = <&vcc_sysin>; + vcc7-supply = <&vcc_sysin>; + vcc8-supply = <&vcc_sysin>; + vcc9-supply = <&vcc_sysin>; + vcc10-supply = <&vcc_sysin>; + vcc11-supply = <&vcc_2v0_pldo_s3>; + vcc12-supply = <&vcc_sysin>; + vcc13-supply = <&vcc_1v1_nldo_s3>; + vcc14-supply = <&vcc_1v1_nldo_s3>; + vcca-supply = <&vcca>; + + rk806_dvs1_null: dvs1-null-pins { + pins = "gpio_pwrctrl1"; + function = "pin_fun0"; + }; + + rk806_dvs2_null: dvs2-null-pins { + pins = "gpio_pwrctrl2"; + function = "pin_fun0"; + }; + + rk806_dvs3_null: dvs3-null-pins { + pins = "gpio_pwrctrl3"; + function = "pin_fun0"; + }; + + regulators { + vdd_gpu_s0: dcdc-reg1 { + regulator-name = "vdd_gpu_s0"; + regulator-boot-on; + regulator-min-microvolt = <550000>; + regulator-max-microvolt = <950000>; + regulator-ramp-delay = <12500>; + regulator-enable-ramp-delay = <400>; + + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vdd_cpu_lit_s0: dcdc-reg2 { + regulator-name = "vdd_cpu_lit_s0"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <550000>; + regulator-max-microvolt = <950000>; + regulator-ramp-delay = <12500>; + + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vdd_logic_s0: dcdc-reg3 { + regulator-name = "vdd_logic_s0"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <675000>; + regulator-max-microvolt = <750000>; + regulator-ramp-delay = <12500>; + + regulator-state-mem { + regulator-on-in-suspend; + regulator-suspend-microvolt = <750000>; + }; + }; + + vdd_vdenc_s0: dcdc-reg4 { + regulator-name = "vdd_vdenc_s0"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <550000>; + regulator-max-microvolt = <950000>; + regulator-ramp-delay = <12500>; + + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vdd_ddr_s0: dcdc-reg5 { + regulator-name = "vdd_ddr_s0"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <675000>; + regulator-max-microvolt = <900000>; + regulator-ramp-delay = <12500>; + + regulator-state-mem { + regulator-off-in-suspend; + regulator-suspend-microvolt = <850000>; + }; + }; + + vdd2_ddr_s3: dcdc-reg6 { + regulator-name = "vdd2_ddr_s3"; + regulator-always-on; + regulator-boot-on; + + regulator-state-mem { + regulator-on-in-suspend; + }; + }; + + vcc_2v0_pldo_s3: dcdc-reg7 { + regulator-name = "vcc_2v0_pldo_s3"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <2000000>; + regulator-max-microvolt = <2000000>; + + regulator-state-mem { + regulator-on-in-suspend; + regulator-suspend-microvolt = <2000000>; + }; + }; + + vcc_3v3_s3: dcdc-reg8 { + regulator-name = "vcc_3v3_s3"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + + regulator-state-mem { + regulator-on-in-suspend; + regulator-suspend-microvolt = <3300000>; + }; + }; + + vddq_ddr_s0: dcdc-reg9 { + regulator-name = "vddq_ddr_s0"; + regulator-always-on; + regulator-boot-on; + + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vcc_1v8_s3: dcdc-reg10 { + regulator-name = "vcc_1v8_s3"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + + regulator-state-mem { + regulator-on-in-suspend; + regulator-suspend-microvolt = <1800000>; + }; + }; + + vcc_1v8_s0: pldo-reg1 { + regulator-name = "vcc_1v8_s0"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + + regulator-state-mem { + regulator-on-in-suspend; + regulator-suspend-microvolt = <1800000>; + }; + }; + + vcca_1v8_s0: pldo-reg2 { + regulator-name = "vcca_1v8_s0"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + + regulator-state-mem { + regulator-on-in-suspend; + regulator-suspend-microvolt = <1800000>; + }; + }; + + vdda_1v2_s0: pldo-reg3 { + regulator-name = "vdda_1v2_s0"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vcca_3v3_s0: pldo-reg4 { + regulator-name = "vcca_3v3_s0"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + + regulator-state-mem { + regulator-on-in-suspend; + regulator-suspend-microvolt = <3300000>; + }; + }; + + vccio_sd_s0: pldo-reg5 { + regulator-name = "vccio_sd_s0"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + pldo6_s3: pldo-reg6 { + regulator-name = "pldo6_s3"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + + regulator-state-mem { + regulator-on-in-suspend; + regulator-suspend-microvolt = <1800000>; + }; + }; + + vdd_0v75_s3: nldo-reg1 { + regulator-name = "vdd_0v75_s3"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <750000>; + regulator-max-microvolt = <750000>; + + regulator-state-mem { + regulator-on-in-suspend; + regulator-suspend-microvolt = <750000>; + }; + }; + + vdda_ddr_pll_s0: nldo-reg2 { + regulator-name = "vdda_ddr_pll_s0"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <850000>; + regulator-max-microvolt = <850000>; + + regulator-state-mem { + regulator-on-in-suspend; + regulator-suspend-microvolt = <850000>; + }; + }; + + vdda_0v75_s0: nldo-reg3 { + regulator-name = "vdda_0v75_s0"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <750000>; + regulator-max-microvolt = <750000>; + + regulator-state-mem { + regulator-on-in-suspend; + regulator-suspend-microvolt = <750000>; + }; + }; + + vdda_0v85_s0: nldo-reg4 { + regulator-name = "vdda_0v85_s0"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <850000>; + regulator-max-microvolt = <850000>; + + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vdd_0v75_s0: nldo-reg5 { + regulator-name = "vdd_0v75_s0"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <750000>; + regulator-max-microvolt = <750000>; + + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + }; + }; +}; + +&tsadc { + status = "okay"; +}; + +&u2phy0 { + status = "okay"; +}; + +&u2phy0_otg { + phy-supply = <&vcc5v0_usb_otg0>; + status = "okay"; +}; + +&uart2 { + pinctrl-0 = <&uart2m0_xfer>; + status = "okay"; +}; + +&usbdp_phy0 { + status = "okay"; +}; + +&usb_host0_xhci { + dr_mode = "host"; + status = "okay"; +}; diff --git a/lede/target/linux/rockchip/files/arch/arm64/boot/dts/rockchip/rk3582-radxa-e54c.dts b/lede/target/linux/rockchip/files/arch/arm64/boot/dts/rockchip/rk3582-radxa-e54c.dts new file mode 100644 index 0000000000..2a128052f6 --- /dev/null +++ b/lede/target/linux/rockchip/files/arch/arm64/boot/dts/rockchip/rk3582-radxa-e54c.dts @@ -0,0 +1,1025 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) + +/dts-v1/; + +#include +#include +#include +#include +#include +#include +#include "rk3588s.dtsi" + +/ { + model = "Radxa E54C"; + compatible = "radxa,e54c", "rockchip,rk3582", "rockchip,rk3588s"; + + aliases { + ethernet0 = &gmac1; + mmc0 = &sdhci; + mmc1 = &sdmmc; + + led-boot = &status_led; + led-failsafe = &status_led; + led-running = &status_led; + led-upgrade = &status_led; + }; + + chosen { + stdout-path = "serial2:1500000n8"; + }; + + keys-0 { + compatible = "adc-keys"; + io-channels = <&saradc 0>; + io-channel-names = "buttons"; + keyup-threshold-microvolt = <18000>; + poll-interval = <100>; + + button-0 { + label = "Maskrom"; + linux,code = ; + press-threshold-microvolt = <0>; + }; + }; + + keys-1 { + compatible = "gpio-keys"; + pinctrl-names = "default"; + pinctrl-0 = <&user_key>; + + button-1 { + label = "User"; + linux,code = ; + gpios = <&gpio0 RK_PB2 GPIO_ACTIVE_LOW>; + wakeup-source; + }; + }; + + leds { + compatible = "gpio-leds"; + + status_led: led-0 { + label = "green:sys"; + gpios = <&gpio0 RK_PC6 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; + pinctrl-0 = <&sys_led>; + }; + + led-1 { + label = "green:lan1"; + linux,default-trigger = "netdev"; + gpios = <&gpio0 RK_PD3 GPIO_ACTIVE_LOW>; + pinctrl-names = "default"; + pinctrl-0 = <&lan1_led>; + }; + + led-2 { + label = "green:lan2"; + linux,default-trigger = "netdev"; + gpios = <&gpio1 RK_PB6 GPIO_ACTIVE_LOW>; + pinctrl-names = "default"; + pinctrl-0 = <&lan2_led>; + }; + + led-3 { + label = "green:lan3"; + linux,default-trigger = "netdev"; + gpios = <&gpio1 RK_PB7 GPIO_ACTIVE_LOW>; + pinctrl-names = "default"; + pinctrl-0 = <&lan3_led>; + }; + + led-4 { + label = "green:wan"; + linux,default-trigger = "netdev"; + gpios = <&gpio3 RK_PC4 GPIO_ACTIVE_LOW>; + pinctrl-names = "default"; + pinctrl-0 = <&wan_led>; + }; + }; + + dc_12v: regulator-12v-dc { + compatible = "regulator-fixed"; + regulator-name = "dc_12v"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <12000000>; + regulator-max-microvolt = <12000000>; + }; + + vcc_1v1_nldo_s3: regulator-1v1-vcc-nldo-s3 { + compatible = "regulator-fixed"; + regulator-name = "vcc_1v1_nldo_s3"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <1100000>; + regulator-max-microvolt = <1100000>; + vin-supply = <&vcc_sysin>; + }; + + vcc3v3_pcie: regulator-3v3-pcie { + compatible = "regulator-fixed"; + regulator-name = "vcc3v3_pcie"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + vin-supply = <&vcc_sysin>; + }; + + vcc_3v3_s0: regulator-3v3-vcc-s0 { + compatible = "regulator-fixed"; + regulator-name = "vcc_3v3_s0"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + vin-supply = <&vcc_3v3_s3>; + }; + + vcca: regulator-5v0-vcca { + compatible = "regulator-fixed"; + regulator-name = "vcca"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + vin-supply = <&typec_vin>; + }; + + vcc5v_usb3: regulator-5v0-usb3 { + compatible = "regulator-fixed"; + enable-active-high; + gpios = <&gpio0 RK_PD4 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; + pinctrl-0 = <&usb_otg_pwren_h>; + regulator-name = "vcc5v_usb3"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + vin-supply = <&vcc_sysin>; + }; + + vcc5v_usb_hub: regulator-5v0-usb-hub { + compatible = "regulator-fixed"; + enable-active-high; + gpios = <&gpio4 RK_PB5 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; + pinctrl-0 = <&usb_host_pwren_h>; + regulator-name = "vcc5v_usb_hub"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + vin-supply = <&vcc_sysin>; + }; + + vbus_typec0: regulator-5v0-vbus-typec0 { + compatible = "regulator-fixed"; + enable-active-high; + gpios = <&gpio3 RK_PC0 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; + pinctrl-0 = <&typec5v_pwren_h>; + regulator-name = "vbus_typec0"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + vin-supply = <&vcc_sysin>; + }; + + vcc_5v0: regulator-5v0-vcc { + compatible = "regulator-fixed"; + regulator-name = "vcc_5v0"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + vin-supply = <&vcc_sysin>; + }; + + avddh_3v3: regulator-avdd-3v3 { + compatible = "regulator-fixed"; + enable-active-high; + gpios = <&gpio3 RK_PA6 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; + pinctrl-0 = <&rtl8367_en>; + regulator-name = "avddh_3v3"; + startup-delay-us = <10000>; + vin-supply = <&vcc_5v0>; + }; + + typec_vin: regulator-typec-vin { + compatible = "regulator-fixed"; + regulator-name = "typec_vin"; + regulator-always-on; + regulator-boot-on; + vin-supply = <&dc_12v>; + }; + + vcc_sysin: regulator-vcc-sysin { + compatible = "regulator-fixed"; + regulator-name = "vcc_sysin"; + regulator-always-on; + regulator-boot-on; + vin-supply = <&typec_vin>; + }; +}; + +&combphy0_ps { + status = "okay"; +}; + +&combphy2_psu { + status = "okay"; +}; + +/* + * In the Rockchip RK3582 SoC, some CPU cores end up disabled + * and unused because they're marked in the efuses as defective. + * The disabling in the DT is performed by the boot loader. + */ +&cpu_b0 { + cpu-supply = <&vdd_cpu_big0_s0>; +}; + +&cpu_b1 { + cpu-supply = <&vdd_cpu_big0_s0>; +}; + +&cpu_b2 { + cpu-supply = <&vdd_cpu_big1_s0>; +}; + +&cpu_b3 { + cpu-supply = <&vdd_cpu_big1_s0>; +}; + +&cpu_l0 { + cpu-supply = <&vdd_cpu_lit_s0>; +}; + +&cpu_l1 { + cpu-supply = <&vdd_cpu_lit_s0>; +}; + +&cpu_l2 { + cpu-supply = <&vdd_cpu_lit_s0>; +}; + +&cpu_l3 { + cpu-supply = <&vdd_cpu_lit_s0>; +}; + +&gmac1 { + /delete-property/ snps,tso; + clock_in_out = "output"; + phy-mode = "rgmii-id"; + phy-supply = <&avddh_3v3>; + pinctrl-names = "default"; + pinctrl-0 = <&gmac1_miim + &gmac1_tx_bus2 + &gmac1_rx_bus2 + &gmac1_rgmii_clk + &gmac1_rgmii_bus>; + snps,no-vlhash; + status = "okay"; + + fixed-link { + speed = <1000>; + full-duplex; + }; +}; + +&i2c0 { + pinctrl-names = "default"; + pinctrl-0 = <&i2c0m2_xfer>; + status = "okay"; + + vdd_cpu_big0_s0: regulator@42 { + compatible = "rockchip,rk8602"; + reg = <0x42>; + fcs,suspend-voltage-selector = <1>; + regulator-name = "vdd_cpu_big0_s0"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <550000>; + regulator-max-microvolt = <1050000>; + regulator-ramp-delay = <2300>; + vin-supply = <&vcc_sysin>; + + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vdd_cpu_big1_s0: regulator@43 { + compatible = "rockchip,rk8603", "rockchip,rk8602"; + reg = <0x43>; + fcs,suspend-voltage-selector = <1>; + regulator-name = "vdd_cpu_big1_s0"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <550000>; + regulator-max-microvolt = <1050000>; + regulator-ramp-delay = <2300>; + vin-supply = <&vcc_sysin>; + + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + eeprom@50 { + compatible = "belling,bl24c16a", "atmel,24c16"; + #address-cells = <1>; + #size-cells = <1>; + reg = <0x50>; + pagesize = <16>; + read-only; + vcc-supply = <&vcc_3v3_s3>; + + nvmem-layout { + compatible = "fixed-layout"; + #address-cells = <1>; + #size-cells = <1>; + + eth_mac0: macaddr@9e { + reg = <0x9e 0x06>; + }; + + eth_mac1: macaddr@a4 { + reg = <0xa4 0x06>; + }; + + eth_mac2: macaddr@aa { + reg = <0xaa 0x06>; + }; + + eth_mac3: macaddr@b0 { + reg = <0xb0 0x06>; + }; + }; + }; +}; + +&i2c2 { + status = "okay"; + + vdd_npu_s0: regulator@42 { + compatible = "rockchip,rk8602"; + reg = <0x42>; + fcs,suspend-voltage-selector = <1>; + regulator-name = "vdd_npu_s0"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <550000>; + regulator-max-microvolt = <950000>; + regulator-ramp-delay = <2300>; + vin-supply = <&vcc_sysin>; + + regulator-state-mem { + regulator-off-in-suspend; + }; + }; +}; + +&i2c4 { + pinctrl-names = "default"; + pinctrl-0 = <&i2c4m2_xfer>; + status = "okay"; + + usbc0: usb-typec@22 { + compatible = "fcs,fusb302"; + reg = <0x22>; + interrupt-parent = <&gpio1>; + interrupts = ; + pinctrl-names = "default"; + pinctrl-0 = <&cc_int_l>; + vbus-supply = <&vbus_typec0>; + }; + + hym8563: rtc@51 { + compatible = "haoyu,hym8563"; + reg = <0x51>; + #clock-cells = <0>; + clock-output-names = "rtcic_32kout"; + interrupt-parent = <&gpio0>; + interrupts = ; + pinctrl-names = "default"; + pinctrl-0 = <&rtc_int_l>; + wakeup-source; + }; +}; + +&i2s5_8ch { + status = "okay"; +}; + +&mdio1 { + ethernet-switch@29 { + compatible = "realtek,rtl8365mb"; + reg = <29>; + reset-gpios = <&gpio3 RK_PB7 GPIO_ACTIVE_LOW>; + pinctrl-names = "default"; + pinctrl-0 = <&gmac1_rstn_l>; + + switch_intc: interrupt-controller { + interrupt-parent = <&gpio3>; + interrupts = ; + interrupt-controller; + #address-cells = <0>; + #interrupt-cells = <1>; + }; + + mdio { + #address-cells = <1>; + #size-cells = <0>; + + phy0: ethernet-phy@0 { + reg = <0>; + interrupt-parent = <&switch_intc>; + interrupts = <0>; + }; + + phy1: ethernet-phy@1 { + reg = <1>; + interrupt-parent = <&switch_intc>; + interrupts = <1>; + }; + + phy2: ethernet-phy@2 { + reg = <2>; + interrupt-parent = <&switch_intc>; + interrupts = <2>; + }; + + phy3: ethernet-phy@3 { + reg = <3>; + interrupt-parent = <&switch_intc>; + interrupts = <3>; + }; + + phy4: ethernet-phy@4 { + reg = <4>; + interrupt-parent = <&switch_intc>; + interrupts = <4>; + }; + }; + + ethernet-ports { + #address-cells = <1>; + #size-cells = <0>; + + ethernet-port@0 { + reg = <0>; + label = "lan3"; + phy-handle = <&phy0>; + nvmem-cells = <ð_mac0>; + nvmem-cell-names = "mac-address"; + }; + + ethernet-port@1 { + reg = <1>; + label = "lan2"; + phy-handle = <&phy1>; + nvmem-cells = <ð_mac1>; + nvmem-cell-names = "mac-address"; + }; + + ethernet-port@2 { + reg = <2>; + label = "lan1"; + phy-handle = <&phy2>; + nvmem-cells = <ð_mac2>; + nvmem-cell-names = "mac-address"; + }; + + ethernet-port@3 { + reg = <3>; + label = "wan"; + phy-handle = <&phy3>; + nvmem-cells = <ð_mac3>; + nvmem-cell-names = "mac-address"; + }; + + ethernet-port@6 { + reg = <6>; + ethernet = <&gmac1>; + phy-mode = "rgmii-id"; + rx-internal-delay-ps = <2000>; + tx-internal-delay-ps = <2000>; + + fixed-link { + speed = <1000>; + full-duplex; + }; + }; + }; + }; +}; + +&pcie2x1l2 { + pinctrl-names = "default"; + pinctrl-0 = <&pcie20x1_2_perstn_m0>; + reset-gpios = <&gpio3 RK_PD1 GPIO_ACTIVE_HIGH>; + vpcie3v3-supply = <&vcc3v3_pcie>; + status = "okay"; +}; + +&pinctrl { + ethernet { + gmac1_rstn_l: gmac1-rstn-l { + rockchip,pins = <3 RK_PB7 RK_FUNC_GPIO &pcfg_pull_none>; + }; + + rtl8367_en: rtl8367-en { + rockchip,pins = <3 RK_PA6 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; + + keys { + user_key: user-key { + rockchip,pins = <0 RK_PB2 RK_FUNC_GPIO &pcfg_pull_up>; + }; + }; + + leds { + lan1_led: lan1-led { + rockchip,pins = <0 RK_PD3 RK_FUNC_GPIO &pcfg_pull_none>; + }; + + lan2_led: lan2-led { + rockchip,pins = <1 RK_PB6 RK_FUNC_GPIO &pcfg_pull_none>; + }; + + lan3_led: lan3-led { + rockchip,pins = <1 RK_PB7 RK_FUNC_GPIO &pcfg_pull_none>; + }; + + sys_led: sys-led { + rockchip,pins = <0 RK_PC6 RK_FUNC_GPIO &pcfg_pull_none>; + }; + + wan_led: wan-led { + rockchip,pins = <3 RK_PC4 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; + + pcie { + pcie20x1_2_perstn_m0: pcie-perstn { + rockchip,pins = <3 RK_PD1 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; + + rtc { + rtc_int_l: rtc-int-l { + rockchip,pins = <0 RK_PB0 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; + + typec { + cc_int_l: cc-int-l { + rockchip,pins = <1 RK_PA7 RK_FUNC_GPIO &pcfg_pull_up>; + }; + + typec5v_pwren_h: typec5v-pwren-h { + rockchip,pins = <3 RK_PC0 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; + + usb { + usb_host_pwren_h: usb-host-pwren-h { + rockchip,pins = <4 RK_PB5 RK_FUNC_GPIO &pcfg_pull_none>; + }; + + usb_otg_pwren_h: usb-otg-pwren-h { + rockchip,pins = <0 RK_PD4 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; +}; + +&saradc { + vref-supply = <&vcca_1v8_s0>; + status = "okay"; +}; + +&sdhci { + bus-width = <8>; + cap-mmc-highspeed; + mmc-hs400-1_8v; + mmc-hs400-enhanced-strobe; + non-removable; + vmmc-supply = <&vcc_3v3_s0>; + vqmmc-supply = <&vcc_1v8_s3>; + status = "okay"; +}; + +&sdmmc { + bus-width = <4>; + cap-mmc-highspeed; + cap-sd-highspeed; + cd-gpios = <&gpio0 RK_PA4 GPIO_ACTIVE_LOW>; + disable-wp; + sd-uhs-sdr104; + vmmc-supply = <&vcc_3v3_s3>; + vqmmc-supply = <&vccio_sd_s0>; + status = "okay"; +}; + +&sfc { + pinctrl-names = "default"; + pinctrl-0 = <&fspim0_pins>; + status = "okay"; + + flash@0 { + compatible = "jedec,spi-nor"; + reg = <0>; + spi-max-frequency = <104000000>; + spi-rx-bus-width = <4>; + spi-tx-bus-width = <1>; + vcc-supply = <&vcc_1v8_s3>; + }; +}; + +&spi2 { + status = "okay"; + assigned-clocks = <&cru CLK_SPI2>; + assigned-clock-rates = <200000000>; + num-cs = <1>; + pinctrl-names = "default"; + pinctrl-0 = <&spi2m2_cs0 &spi2m2_pins>; + + pmic@0 { + compatible = "rockchip,rk806"; + reg = <0>; + gpio-controller; + #gpio-cells = <2>; + interrupt-parent = <&gpio0>; + interrupts = <7 IRQ_TYPE_LEVEL_LOW>; + pinctrl-names = "default"; + pinctrl-0 = <&pmic_pins>, <&rk806_dvs1_null>, + <&rk806_dvs2_null>, <&rk806_dvs3_null>; + spi-max-frequency = <1000000>; + system-power-controller; + + vcc1-supply = <&vcc_sysin>; + vcc2-supply = <&vcc_sysin>; + vcc3-supply = <&vcc_sysin>; + vcc4-supply = <&vcc_sysin>; + vcc5-supply = <&vcc_sysin>; + vcc6-supply = <&vcc_sysin>; + vcc7-supply = <&vcc_sysin>; + vcc8-supply = <&vcc_sysin>; + vcc9-supply = <&vcc_sysin>; + vcc10-supply = <&vcc_sysin>; + vcc11-supply = <&vcc_2v0_pldo_s3>; + vcc12-supply = <&vcc_sysin>; + vcc13-supply = <&vcc_1v1_nldo_s3>; + vcc14-supply = <&vcc_1v1_nldo_s3>; + vcca-supply = <&vcca>; + + rk806_dvs1_null: dvs1-null-pins { + pins = "gpio_pwrctrl1"; + function = "pin_fun0"; + }; + + rk806_dvs2_null: dvs2-null-pins { + pins = "gpio_pwrctrl2"; + function = "pin_fun0"; + }; + + rk806_dvs3_null: dvs3-null-pins { + pins = "gpio_pwrctrl3"; + function = "pin_fun0"; + }; + + regulators { + vdd_gpu_s0: dcdc-reg1 { + regulator-name = "vdd_gpu_s0"; + regulator-boot-on; + regulator-min-microvolt = <550000>; + regulator-max-microvolt = <950000>; + regulator-ramp-delay = <12500>; + regulator-enable-ramp-delay = <400>; + + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vdd_cpu_lit_s0: dcdc-reg2 { + regulator-name = "vdd_cpu_lit_s0"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <550000>; + regulator-max-microvolt = <950000>; + regulator-ramp-delay = <12500>; + + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vdd_logic_s0: dcdc-reg3 { + regulator-name = "vdd_logic_s0"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <675000>; + regulator-max-microvolt = <750000>; + regulator-ramp-delay = <12500>; + + regulator-state-mem { + regulator-on-in-suspend; + regulator-suspend-microvolt = <750000>; + }; + }; + + vdd_vdenc_s0: dcdc-reg4 { + regulator-name = "vdd_vdenc_s0"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <550000>; + regulator-max-microvolt = <950000>; + regulator-ramp-delay = <12500>; + + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vdd_ddr_s0: dcdc-reg5 { + regulator-name = "vdd_ddr_s0"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <675000>; + regulator-max-microvolt = <900000>; + regulator-ramp-delay = <12500>; + + regulator-state-mem { + regulator-off-in-suspend; + regulator-suspend-microvolt = <850000>; + }; + }; + + vdd2_ddr_s3: dcdc-reg6 { + regulator-name = "vdd2_ddr_s3"; + regulator-always-on; + regulator-boot-on; + + regulator-state-mem { + regulator-on-in-suspend; + }; + }; + + vcc_2v0_pldo_s3: dcdc-reg7 { + regulator-name = "vcc_2v0_pldo_s3"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <2000000>; + regulator-max-microvolt = <2000000>; + + regulator-state-mem { + regulator-on-in-suspend; + regulator-suspend-microvolt = <2000000>; + }; + }; + + vcc_3v3_s3: dcdc-reg8 { + regulator-name = "vcc_3v3_s3"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + + regulator-state-mem { + regulator-on-in-suspend; + regulator-suspend-microvolt = <3300000>; + }; + }; + + vddq_ddr_s0: dcdc-reg9 { + regulator-name = "vddq_ddr_s0"; + regulator-always-on; + regulator-boot-on; + + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vcc_1v8_s3: dcdc-reg10 { + regulator-name = "vcc_1v8_s3"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + + regulator-state-mem { + regulator-on-in-suspend; + regulator-suspend-microvolt = <1800000>; + }; + }; + + vcc_1v8_s0: pldo-reg1 { + regulator-name = "vcc_1v8_s0"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + + regulator-state-mem { + regulator-on-in-suspend; + regulator-suspend-microvolt = <1800000>; + }; + }; + + vcca_1v8_s0: pldo-reg2 { + regulator-name = "vcca_1v8_s0"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + + regulator-state-mem { + regulator-on-in-suspend; + regulator-suspend-microvolt = <1800000>; + }; + }; + + vdda_1v2_s0: pldo-reg3 { + regulator-name = "vdda_1v2_s0"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vcca_3v3_s0: pldo-reg4 { + regulator-name = "vcca_3v3_s0"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + + regulator-state-mem { + regulator-on-in-suspend; + regulator-suspend-microvolt = <3300000>; + }; + }; + + vccio_sd_s0: pldo-reg5 { + regulator-name = "vccio_sd_s0"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + pldo6_s3: pldo-reg6 { + regulator-name = "pldo6_s3"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + + regulator-state-mem { + regulator-on-in-suspend; + regulator-suspend-microvolt = <1800000>; + }; + }; + + vdd_0v75_s3: nldo-reg1 { + regulator-name = "vdd_0v75_s3"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <750000>; + regulator-max-microvolt = <750000>; + + regulator-state-mem { + regulator-on-in-suspend; + regulator-suspend-microvolt = <750000>; + }; + }; + + vdda_ddr_pll_s0: nldo-reg2 { + regulator-name = "vdda_ddr_pll_s0"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <850000>; + regulator-max-microvolt = <850000>; + + regulator-state-mem { + regulator-on-in-suspend; + regulator-suspend-microvolt = <850000>; + }; + }; + + vdda_0v75_s0: nldo-reg3 { + regulator-name = "vdda_0v75_s0"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <750000>; + regulator-max-microvolt = <750000>; + + regulator-state-mem { + regulator-on-in-suspend; + regulator-suspend-microvolt = <750000>; + }; + }; + + vdda_0v85_s0: nldo-reg4 { + regulator-name = "vdda_0v85_s0"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <850000>; + regulator-max-microvolt = <850000>; + + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vdd_0v75_s0: nldo-reg5 { + regulator-name = "vdd_0v75_s0"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <750000>; + regulator-max-microvolt = <750000>; + + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + }; + }; +}; + +&tsadc { + status = "okay"; +}; + +&u2phy0 { + status = "okay"; +}; + +&u2phy0_otg { + status = "okay"; +}; + +&u2phy2 { + status = "okay"; +}; + +&u2phy2_host { + phy-supply = <&vcc5v_usb_hub>; + status = "okay"; +}; + +&u2phy3 { + status = "okay"; +}; + +&u2phy3_host { + phy-supply = <&vcc5v_usb3>; + status = "okay"; +}; + +&uart2 { + pinctrl-0 = <&uart2m0_xfer>; + status = "okay"; +}; + +&usbdp_phy0 { + mode-switch; + orientation-switch; + sbu1-dc-gpios = <&gpio1 RK_PA6 GPIO_ACTIVE_HIGH>; + sbu2-dc-gpios = <&gpio3 RK_PD5 GPIO_ACTIVE_HIGH>; + status = "okay"; +}; + +&usb_host0_ehci { + status = "okay"; +}; + +&usb_host0_xhci { + dr_mode = "host"; + usb-role-switch; + status = "okay"; +}; + +&usb_host1_ehci { + status = "okay"; +}; + +&usb_host1_ohci { + status = "okay"; +}; + +&usb_host2_xhci { + status = "okay"; +}; diff --git a/lede/target/linux/rockchip/image/armv8.mk b/lede/target/linux/rockchip/image/armv8.mk index 6d13db6ab5..cd51b102a2 100644 --- a/lede/target/linux/rockchip/image/armv8.mk +++ b/lede/target/linux/rockchip/image/armv8.mk @@ -425,6 +425,16 @@ define Device/radxa_e20c endef TARGET_DEVICES += radxa_e20c +define Device/radxa_e24c + DEVICE_VENDOR := Radxa + DEVICE_MODEL := E24C + DEVICE_DTS := rockchip/rk3528-radxa-e24c + UBOOT_DEVICE_NAME := radxa-e20c-rk3528 + IMAGE/sysupgrade.img.gz := boot-common | boot-script rk3528 | pine64-img | gzip | append-metadata + DEVICE_PACKAGES := kmod-gpio-button-hotplug kmod-dsa-rtl8365mb -urngd +endef +TARGET_DEVICES += radxa_e24c + define Device/radxa_e25 DEVICE_VENDOR := Radxa DEVICE_MODEL := E25 @@ -435,6 +445,26 @@ define Device/radxa_e25 endef TARGET_DEVICES += radxa_e25 +define Device/radxa_e52c + DEVICE_VENDOR := Radxa + DEVICE_MODEL := E52C + DEVICE_DTS := rockchip/rk3582-radxa-e52c + UBOOT_DEVICE_NAME := generic-rk3588 + IMAGE/sysupgrade.img.gz := boot-common | boot-script | pine64-img | gzip | append-metadata + DEVICE_PACKAGES := kmod-gpio-button-hotplug kmod-r8125-rss +endef +TARGET_DEVICES += radxa_e52c + +define Device/radxa_e54c + DEVICE_VENDOR := Radxa + DEVICE_MODEL := E54C + DEVICE_DTS := rockchip/rk3582-radxa-e54c + UBOOT_DEVICE_NAME := generic-rk3588 + IMAGE/sysupgrade.img.gz := boot-common | boot-script | pine64-img | gzip | append-metadata + DEVICE_PACKAGES := kmod-gpio-button-hotplug kmod-dsa-rtl8365mb +endef +TARGET_DEVICES += radxa_e54c + define Device/radxa_rock-3a DEVICE_VENDOR := Radxa DEVICE_MODEL := ROCK 3A diff --git a/mihomo/adapter/outbound/mieru.go b/mihomo/adapter/outbound/mieru.go index fca7ede4c8..8ef9cfd758 100644 --- a/mihomo/adapter/outbound/mieru.go +++ b/mihomo/adapter/outbound/mieru.go @@ -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 } diff --git a/mihomo/docs/config.yaml b/mihomo/docs/config.yaml index e4c5e7534a..445c61a388 100644 --- a/mihomo/docs/config.yaml +++ b/mihomo/docs/config.yaml @@ -933,6 +933,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 @@ -1475,6 +1477,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 diff --git a/mihomo/go.mod b/mihomo/go.mod index 1845c53242..2e19c8a24a 100644 --- a/mihomo/go.mod +++ b/mihomo/go.mod @@ -6,7 +6,7 @@ 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.16.1 + github.com/enfein/mieru/v3 v3.19.0 github.com/go-chi/chi/v5 v5.2.2 github.com/go-chi/render v1.0.3 github.com/gobwas/ws v1.4.0 @@ -31,7 +31,7 @@ require ( 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 - github.com/metacubex/sing-vmess v0.2.4-0.20250817075824-5e05f123ccdd + github.com/metacubex/sing-vmess v0.2.4-0.20250819151326-51d195aac5db 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 diff --git a/mihomo/go.sum b/mihomo/go.sum index 90fcddcc18..18cbabb0a0 100644 --- a/mihomo/go.sum +++ b/mihomo/go.sum @@ -25,8 +25,8 @@ github.com/dlclark/regexp2 v1.11.5 h1:Q/sSnsKerHeCkc/jSTNq1oCm7KiVgUMZRDUoRu0JQZ 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/enfein/mieru/v3 v3.19.0 h1:GXUTWoWmr8pTqGSTbh82VXfnCENJm6m5UN76c3Ynzfw= +github.com/enfein/mieru/v3 v3.19.0/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= @@ -131,8 +131,8 @@ github.com/metacubex/sing-shadowtls v0.0.0-20250503063515-5d9f966d17a2 h1:gXU+MY 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 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.20250817075824-5e05f123ccdd h1:VfD6UxKPAg7u9rPyxl18lQkpE9s8dZq0u2cPAgQShWs= -github.com/metacubex/sing-vmess v0.2.4-0.20250817075824-5e05f123ccdd/go.mod h1:21R5R1u90uUvBQF0owoooEu96/SAYYD56nDrwm6nFaM= +github.com/metacubex/sing-vmess v0.2.4-0.20250819151326-51d195aac5db h1:W7VKxR0r5IR+56Lblx2iyrEaykx0esdQwTQbkSrSaek= +github.com/metacubex/sing-vmess v0.2.4-0.20250819151326-51d195aac5db/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= diff --git a/mihomo/listener/reality/reality.go b/mihomo/listener/reality/reality.go index d91055f8ed..256dbcf6a9 100644 --- a/mihomo/listener/reality/reality.go +++ b/mihomo/listener/reality/reality.go @@ -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 +} diff --git a/mihomo/listener/sing_vless/server.go b/mihomo/listener/sing_vless/server.go index d386ef670b..7dfcd0102e 100644 --- a/mihomo/listener/sing_vless/server.go +++ b/mihomo/listener/sing_vless/server.go @@ -25,11 +25,12 @@ import ( "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 } @@ -37,7 +38,7 @@ 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 } @@ -45,7 +46,7 @@ func init() { }) vless.RegisterTLS(func(conn net.Conn) (loaded bool, netConn net.Conn, reflectType reflect.Type, reflectPointer unsafe.Pointer) { - tlsConn, loaded := common.Cast[*encryption.ClientConn](conn) + tlsConn, loaded := network.CastReader[*encryption.ClientConn](conn) if !loaded { return } @@ -53,7 +54,7 @@ func init() { }) vless.RegisterTLS(func(conn net.Conn) (loaded bool, netConn net.Conn, reflectType reflect.Type, reflectPointer unsafe.Pointer) { - tlsConn, loaded := common.Cast[*encryption.ServerConn](conn) + tlsConn, loaded := network.CastReader[*encryption.ServerConn](conn) if !loaded { return } diff --git a/mihomo/transport/vless/encryption/client.go b/mihomo/transport/vless/encryption/client.go index 9d24903886..ecf20692ea 100644 --- a/mihomo/transport/vless/encryption/client.go +++ b/mihomo/transport/vless/encryption/client.go @@ -69,8 +69,8 @@ func (i *ClientInstance) Init(nfsEKeyBytes []byte, xor uint32, minutes time.Dura if err != nil { return } - hash256 := sha3.Sum256(nfsEKeyBytes) - copy(i.hash11[:], hash256[:]) + hash32 := sha3.Sum256(nfsEKeyBytes) + copy(i.hash11[:], hash32[:]) if xor > 0 { xorKey := sha3.Sum256(nfsEKeyBytes) i.xorKey = xorKey[:] @@ -79,7 +79,7 @@ func (i *ClientInstance) Init(nfsEKeyBytes []byte, xor uint32, minutes time.Dura return } -func (i *ClientInstance) Handshake(conn net.Conn) (net.Conn, error) { +func (i *ClientInstance) Handshake(conn net.Conn) (*ClientConn, error) { if i.nfsEKey == nil { return nil, errors.New("uninitialized") } diff --git a/mihomo/transport/vless/encryption/doc.go b/mihomo/transport/vless/encryption/doc.go index 9ba7eb113d..6f0c8f7039 100644 --- a/mihomo/transport/vless/encryption/doc.go +++ b/mihomo/transport/vless/encryption/doc.go @@ -13,4 +13,5 @@ // 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 package encryption diff --git a/mihomo/transport/vless/encryption/server.go b/mihomo/transport/vless/encryption/server.go index 9c5c102e8c..ea72f2f5cf 100644 --- a/mihomo/transport/vless/encryption/server.go +++ b/mihomo/transport/vless/encryption/server.go @@ -54,8 +54,8 @@ func (i *ServerInstance) Init(nfsDKeySeed []byte, xor uint32, minutes time.Durat if err != nil { return } - hash256 := sha3.Sum256(i.nfsDKey.EncapsulationKey().Bytes()) - copy(i.hash11[:], hash256[:]) + hash32 := sha3.Sum256(i.nfsDKey.EncapsulationKey().Bytes()) + copy(i.hash11[:], hash32[:]) if xor > 0 { xorKey := sha3.Sum256(i.nfsDKey.EncapsulationKey().Bytes()) i.xorKey = xorKey[:] @@ -91,7 +91,7 @@ func (i *ServerInstance) Close() (err error) { return } -func (i *ServerInstance) Handshake(conn net.Conn) (net.Conn, error) { +func (i *ServerInstance) Handshake(conn net.Conn) (*ServerConn, error) { if i.nfsDKey == nil { return nil, errors.New("uninitialized") } diff --git a/mihomo/transport/vless/encryption/xor.go b/mihomo/transport/vless/encryption/xor.go index 69ff15780f..caad12bf07 100644 --- a/mihomo/transport/vless/encryption/xor.go +++ b/mihomo/transport/vless/encryption/xor.go @@ -49,6 +49,7 @@ func (c *XorConn) Write(b []byte) (int, error) { // whole one/two records l += 10 if t == 0 { c.out_after0 = true + c.out_header = make([]byte, 0, 5) // important } } c.ctr.XORKeyStream(b[:l], b[:l]) // caller MUST discard b @@ -77,7 +78,7 @@ func (c *XorConn) Write(b []byte) (int, error) { // whole one/two records break } _, c.out_skip, _ = DecodeHeader(append(c.out_header, p[:need]...)) - c.out_header = make([]byte, 0, 5) // DO NOT CHANGE + c.out_header = c.out_header[:0] c.ctr.XORKeyStream(p[:need], p[:need]) p = p[need:] } @@ -116,6 +117,7 @@ func (c *XorConn) Read(b []byte) (int, error) { // 5-bytes, data, 5-bytes... c.isHeader = false if t == 0 { c.in_after0 = true + c.in_header = make([]byte, 0, 5) // important } } } else { @@ -139,7 +141,7 @@ func (c *XorConn) Read(b []byte) (int, error) { // 5-bytes, data, 5-bytes... } c.peerCtr.XORKeyStream(p[:need], p[:need]) _, c.in_skip, _ = DecodeHeader(append(c.in_header, p[:need]...)) - c.in_header = make([]byte, 0, 5) // DO NOT CHANGE + c.in_header = c.in_header[:0] p = p[need:] } return n, err diff --git a/shadowsocks-rust/Cargo.lock b/shadowsocks-rust/Cargo.lock index 55379a695b..29aaf38d29 100644 --- a/shadowsocks-rust/Cargo.lock +++ b/shadowsocks-rust/Cargo.lock @@ -1510,13 +1510,14 @@ checksum = "9b112acc8b3adf4b107a8ec20977da0273a8c386765a3ec0229bd500a1443f9f" [[package]] name = "hyper" -version = "1.6.0" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc2b571658e38e0c01b1fdca3bbbe93c00d3d71693ff2770043f8c29bc7d6f80" +checksum = "eb3aa54a13a0dfe7fbe3a59e0c76093041720fdc77b110cc0fc260fafb4dc51e" dependencies = [ + "atomic-waker", "bytes", "futures-channel", - "futures-util", + "futures-core", "h2", "http", "http-body", @@ -1524,6 +1525,7 @@ dependencies = [ "httpdate", "itoa", "pin-project-lite", + "pin-utils", "smallvec", "tokio", "want", @@ -3231,9 +3233,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.142" +version = "1.0.143" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "030fedb782600dcbd6f02d479bf0d817ac3bb40d644745b769d6a96bc3afc5a7" +checksum = "d401abef1d108fbd9cbaebc3e46611f4b1021f714a0597a71f41ee463f5f4a5a" dependencies = [ "indexmap", "itoa", diff --git a/sing-box/.github/workflows/build.yml b/sing-box/.github/workflows/build.yml index 1964301456..25114dff51 100644 --- a/sing-box/.github/workflows/build.yml +++ b/sing-box/.github/workflows/build.yml @@ -149,7 +149,7 @@ jobs: TAGS='with_gvisor,with_quic,with_dhcp,with_wireguard,with_utls,with_acme,with_clash_api,with_tailscale' echo "BUILD_TAGS=${TAGS}" >> "${GITHUB_ENV}" - name: Build - if: matrix.os != 'darwin' && matrix.os != 'android' + if: matrix.os != 'android' run: | set -xeuo pipefail mkdir -p dist @@ -165,23 +165,6 @@ jobs: GOMIPS: ${{ matrix.gomips }} GOMIPS64: ${{ matrix.gomips }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - name: Build darwin - if: matrix.os == 'darwin' - run: | - set -xeuo pipefail - mkdir -p dist - go build -v -trimpath -o dist/sing-box -tags "${BUILD_TAGS}" \ - -ldflags '-s -buildid= -X github.com/sagernet/sing-box/constant.Version=${{ needs.calculate_version.outputs.version }} -checklinkname=0' \ - ./cmd/sing-box - env: - CGO_ENABLED: "0" - GOOS: ${{ matrix.os }} - GOARCH: ${{ matrix.arch }} - GO386: ${{ matrix.go386 }} - GOARM: ${{ matrix.goarm }} - GOMIPS: ${{ matrix.gomips }} - GOMIPS64: ${{ matrix.gomips }} - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - name: Build Android if: matrix.os == 'android' run: | diff --git a/sing-box/clients/android/version.properties b/sing-box/clients/android/version.properties index 646d608330..0df1610ec6 100644 --- a/sing-box/clients/android/version.properties +++ b/sing-box/clients/android/version.properties @@ -1,3 +1,3 @@ -VERSION_CODE=552 +VERSION_CODE=554 VERSION_NAME=1.12.2 GO_VERSION=go1.25.0 diff --git a/sing-box/cmd/internal/build_libbox/main.go b/sing-box/cmd/internal/build_libbox/main.go index 71df1ae402..0f4db85045 100644 --- a/sing-box/cmd/internal/build_libbox/main.go +++ b/sing-box/cmd/internal/build_libbox/main.go @@ -46,7 +46,7 @@ var ( sharedFlags []string debugFlags []string sharedTags []string - darwinTags []string + macOSTags []string memcTags []string notMemcTags []string debugTags []string @@ -59,11 +59,11 @@ func init() { if err != nil { currentTag = "unknown" } - sharedFlags = append(sharedFlags, "-ldflags", "-X github.com/sagernet/sing-box/constant.Version="+currentTag+" -s -w -buildid= -checklinkname=0") - debugFlags = append(debugFlags, "-ldflags", "-X github.com/sagernet/sing-box/constant.Version="+currentTag+"-s -w -buildid= -checklinkname=0") + sharedFlags = append(sharedFlags, "-ldflags", "-X github.com/sagernet/sing-box/constant.Version="+currentTag+" -s -w -buildid=") + debugFlags = append(debugFlags, "-ldflags", "-X github.com/sagernet/sing-box/constant.Version="+currentTag) sharedTags = append(sharedTags, "with_gvisor", "with_quic", "with_wireguard", "with_utls", "with_clash_api", "with_conntrack") - darwinTags = append(darwinTags, "with_dhcp") + macOSTags = append(macOSTags, "with_dhcp") memcTags = append(memcTags, "with_tailscale") notMemcTags = append(notMemcTags, "with_low_memory") debugTags = append(debugTags, "debug") @@ -106,17 +106,19 @@ func buildAndroid() { "-libname=box", } + if !debugEnabled { + sharedFlags[3] = sharedFlags[3] + " -checklinkname=0" + args = append(args, sharedFlags...) + } else { + debugFlags[1] = debugFlags[1] + " -checklinkname=0" + args = append(args, debugFlags...) + } + tags := append(sharedTags, memcTags...) if debugEnabled { tags = append(tags, debugTags...) } - if !debugEnabled { - args = append(args, sharedFlags...) - } else { - args = append(args, debugFlags...) - } - args = append(args, "-tags", strings.Join(tags, ",")) args = append(args, "./experimental/libbox") @@ -158,7 +160,9 @@ func buildApple() { "-tags-not-macos=with_low_memory", } if !withTailscale { - args = append(args, "-tags-macos="+strings.Join(memcTags, ",")) + args = append(args, "-tags-macos="+strings.Join(append(macOSTags, memcTags...), ",")) + } else { + args = append(args, "-tags-macos="+strings.Join(macOSTags, ",")) } if !debugEnabled { @@ -167,7 +171,7 @@ func buildApple() { args = append(args, debugFlags...) } - tags := append(sharedTags, darwinTags...) + tags := sharedTags if withTailscale { tags = append(tags, memcTags...) } diff --git a/sing-box/common/tls/reality_server.go b/sing-box/common/tls/reality_server.go index 2742024877..3a3ae99e7e 100644 --- a/sing-box/common/tls/reality_server.go +++ b/sing-box/common/tls/reality_server.go @@ -206,3 +206,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 +} diff --git a/sing-box/common/tls/utls_client.go b/sing-box/common/tls/utls_client.go index f897e65c8a..fceb15b821 100644 --- a/sing-box/common/tls/utls_client.go +++ b/sing-box/common/tls/utls_client.go @@ -106,6 +106,14 @@ func (c *utlsConnWrapper) Upstream() any { return c.UConn } +func (c *utlsConnWrapper) ReaderReplaceable() bool { + return true +} + +func (c *utlsConnWrapper) WriterReplaceable() bool { + return true +} + type utlsALPNWrapper struct { utlsConnWrapper nextProtocols []string diff --git a/sing-box/dns/router.go b/sing-box/dns/router.go index 36b7bf054f..e62f0ef511 100644 --- a/sing-box/dns/router.go +++ b/sing-box/dns/router.go @@ -293,12 +293,7 @@ func (r *Router) Exchange(ctx context.Context, message *mDNS.Msg, options adapte } else if errors.Is(err, ErrResponseRejected) { rejected = true r.logger.DebugContext(ctx, E.Cause(err, "response rejected for ", FormatQuestion(message.Question[0].String()))) - /*} else if responseCheck!= nil && errors.Is(err, RcodeError(mDNS.RcodeNameError)) { - rejected = true - r.logger.DebugContext(ctx, E.Cause(err, "response rejected for ", FormatQuestion(message.Question[0].String()))) - */ } else if len(message.Question) > 0 { - rejected = true r.logger.ErrorContext(ctx, E.Cause(err, "exchange failed for ", FormatQuestion(message.Question[0].String()))) } else { r.logger.ErrorContext(ctx, E.Cause(err, "exchange failed for ")) diff --git a/sing-box/dns/transport/dhcp/dhcp.go b/sing-box/dns/transport/dhcp/dhcp.go index 92dd1f8bc6..b4be198c7c 100644 --- a/sing-box/dns/transport/dhcp/dhcp.go +++ b/sing-box/dns/transport/dhcp/dhcp.go @@ -9,10 +9,8 @@ import ( "time" "github.com/sagernet/sing-box/adapter" - "github.com/sagernet/sing-box/common/dialer" C "github.com/sagernet/sing-box/constant" "github.com/sagernet/sing-box/dns" - "github.com/sagernet/sing-box/dns/transport" "github.com/sagernet/sing-box/log" "github.com/sagernet/sing-box/option" "github.com/sagernet/sing-tun" @@ -29,6 +27,7 @@ import ( "github.com/insomniacslk/dhcp/dhcpv4" mDNS "github.com/miekg/dns" + "golang.org/x/exp/slices" ) func RegisterTransport(registry *dns.TransportRegistry) { @@ -45,9 +44,12 @@ type Transport struct { networkManager adapter.NetworkManager interfaceName string interfaceCallback *list.Element[tun.DefaultInterfaceUpdateCallback] - transports []adapter.DNSTransport - updateAccess sync.Mutex + transportLock sync.RWMutex updatedAt time.Time + servers []M.Socksaddr + search []string + ndots int + attempts int } func NewTransport(ctx context.Context, logger log.ContextLogger, tag string, options option.DHCPDNSServerOptions) (adapter.DNSTransport, error) { @@ -62,16 +64,28 @@ func NewTransport(ctx context.Context, logger log.ContextLogger, tag string, opt logger: logger, networkManager: service.FromContext[adapter.NetworkManager](ctx), interfaceName: options.Interface, + ndots: 1, + attempts: 2, }, nil } +func NewRawTransport(transportAdapter dns.TransportAdapter, ctx context.Context, dialer N.Dialer, logger log.ContextLogger) *Transport { + return &Transport{ + TransportAdapter: transportAdapter, + ctx: ctx, + dialer: dialer, + logger: logger, + networkManager: service.FromContext[adapter.NetworkManager](ctx), + } +} + func (t *Transport) Start(stage adapter.StartStage) error { if stage != adapter.StartStateStart { return nil } - err := t.fetchServers() + _, err := t.Fetch() if err != nil { - return err + t.logger.Error(E.Cause(err, "fetch DNS servers")) } if t.interfaceName == "" { t.interfaceCallback = t.networkManager.InterfaceMonitor().RegisterCallback(t.interfaceUpdated) @@ -80,9 +94,6 @@ func (t *Transport) Start(stage adapter.StartStage) error { } func (t *Transport) Close() error { - for _, transport := range t.transports { - transport.Close() - } if t.interfaceCallback != nil { t.networkManager.InterfaceMonitor().UnregisterCallback(t.interfaceCallback) } @@ -90,23 +101,44 @@ func (t *Transport) Close() error { } func (t *Transport) Exchange(ctx context.Context, message *mDNS.Msg) (*mDNS.Msg, error) { - err := t.fetchServers() + servers, err := t.Fetch() if err != nil { return nil, err } - - if len(t.transports) == 0 { + if len(servers) == 0 { return nil, E.New("dhcp: empty DNS servers from response") } + return t.Exchange0(ctx, message, servers) +} - var response *mDNS.Msg - for _, transport := range t.transports { - response, err = transport.Exchange(ctx, message) - if err == nil { - return response, nil - } +func (t *Transport) Exchange0(ctx context.Context, message *mDNS.Msg, servers []M.Socksaddr) (*mDNS.Msg, error) { + question := message.Question[0] + domain := dns.FqdnToDomain(question.Name) + if len(servers) == 1 || !(message.Question[0].Qtype == mDNS.TypeA || message.Question[0].Qtype == mDNS.TypeAAAA) { + return t.exchangeSingleRequest(ctx, servers, message, domain) + } else { + return t.exchangeParallel(ctx, servers, message, domain) } - return nil, err +} + +func (t *Transport) Fetch() ([]M.Socksaddr, error) { + t.transportLock.RLock() + updatedAt := t.updatedAt + servers := t.servers + t.transportLock.RUnlock() + if time.Since(updatedAt) < C.DHCPTTL { + return servers, nil + } + t.transportLock.Lock() + defer t.transportLock.Unlock() + if time.Since(t.updatedAt) < C.DHCPTTL { + return t.servers, nil + } + err := t.updateServers() + if err != nil { + return nil, err + } + return t.servers, nil } func (t *Transport) fetchInterface() (*control.Interface, error) { @@ -124,18 +156,6 @@ func (t *Transport) fetchInterface() (*control.Interface, error) { } } -func (t *Transport) fetchServers() error { - if time.Since(t.updatedAt) < C.DHCPTTL { - return nil - } - t.updateAccess.Lock() - defer t.updateAccess.Unlock() - if time.Since(t.updatedAt) < C.DHCPTTL { - return nil - } - return t.updateServers() -} - func (t *Transport) updateServers() error { iface, err := t.fetchInterface() if err != nil { @@ -148,7 +168,7 @@ func (t *Transport) updateServers() error { cancel() if err != nil { return err - } else if len(t.transports) == 0 { + } else if len(t.servers) == 0 { return E.New("dhcp: empty DNS servers response") } else { t.updatedAt = time.Now() @@ -177,7 +197,11 @@ func (t *Transport) fetchServers0(ctx context.Context, iface *control.Interface) } defer packetConn.Close() - discovery, err := dhcpv4.NewDiscovery(iface.HardwareAddr, dhcpv4.WithBroadcast(true), dhcpv4.WithRequestedOptions(dhcpv4.OptionDomainNameServer)) + discovery, err := dhcpv4.NewDiscovery(iface.HardwareAddr, dhcpv4.WithBroadcast(true), dhcpv4.WithRequestedOptions( + dhcpv4.OptionDomainName, + dhcpv4.OptionDomainNameServer, + dhcpv4.OptionDNSDomainSearchList, + )) if err != nil { return err } @@ -223,31 +247,23 @@ func (t *Transport) fetchServersResponse(iface *control.Interface, packetConn ne continue } - dns := dhcpPacket.DNS() - if len(dns) == 0 { - return nil - } - return t.recreateServers(iface, common.Map(dns, func(it net.IP) M.Socksaddr { - return M.SocksaddrFrom(M.AddrFromIP(it), 53) - })) + return t.recreateServers(iface, dhcpPacket) } } -func (t *Transport) recreateServers(iface *control.Interface, serverAddrs []M.Socksaddr) error { - if len(serverAddrs) > 0 { - t.logger.Info("dhcp: updated DNS servers from ", iface.Name, ": [", strings.Join(common.Map(serverAddrs, M.Socksaddr.String), ","), "]") +func (t *Transport) recreateServers(iface *control.Interface, dhcpPacket *dhcpv4.DHCPv4) error { + searchList := dhcpPacket.DomainSearch() + if searchList != nil && len(searchList.Labels) > 0 { + t.search = searchList.Labels + } else if dhcpPacket.DomainName() != "" { + t.search = []string{dhcpPacket.DomainName()} } - serverDialer := common.Must1(dialer.NewDefault(t.ctx, option.DialerOptions{ - BindInterface: iface.Name, - UDPFragmentDefault: true, - })) - var transports []adapter.DNSTransport - for _, serverAddr := range serverAddrs { - transports = append(transports, transport.NewUDPRaw(t.logger, t.TransportAdapter, serverDialer, serverAddr)) + serverAddrs := common.Map(dhcpPacket.DNS(), func(it net.IP) M.Socksaddr { + return M.SocksaddrFrom(M.AddrFromIP(it), 53) + }) + if len(serverAddrs) > 0 && !slices.Equal(t.servers, serverAddrs) { + t.logger.Info("dhcp: updated DNS servers from ", iface.Name, ": [", strings.Join(common.Map(serverAddrs, M.Socksaddr.String), ","), "], search: [", strings.Join(t.search, ","), "]") } - for _, transport := range t.transports { - transport.Close() - } - t.transports = transports + t.servers = serverAddrs return nil } diff --git a/sing-box/dns/transport/dhcp/dhcp_shared.go b/sing-box/dns/transport/dhcp/dhcp_shared.go new file mode 100644 index 0000000000..e470b1da5d --- /dev/null +++ b/sing-box/dns/transport/dhcp/dhcp_shared.go @@ -0,0 +1,202 @@ +package dhcp + +import ( + "context" + "math/rand" + "strings" + "time" + + C "github.com/sagernet/sing-box/constant" + "github.com/sagernet/sing-box/dns" + "github.com/sagernet/sing/common/buf" + E "github.com/sagernet/sing/common/exceptions" + M "github.com/sagernet/sing/common/metadata" + N "github.com/sagernet/sing/common/network" + + mDNS "github.com/miekg/dns" +) + +const ( + // net.maxDNSPacketSize + maxDNSPacketSize = 1232 +) + +func (t *Transport) exchangeSingleRequest(ctx context.Context, servers []M.Socksaddr, message *mDNS.Msg, domain string) (*mDNS.Msg, error) { + var lastErr error + for _, fqdn := range t.nameList(domain) { + response, err := t.tryOneName(ctx, servers, fqdn, message) + if err != nil { + lastErr = err + continue + } + return response, nil + } + return nil, lastErr +} + +func (t *Transport) exchangeParallel(ctx context.Context, servers []M.Socksaddr, message *mDNS.Msg, domain string) (*mDNS.Msg, error) { + returned := make(chan struct{}) + defer close(returned) + type queryResult struct { + response *mDNS.Msg + err error + } + results := make(chan queryResult) + startRacer := func(ctx context.Context, fqdn string) { + response, err := t.tryOneName(ctx, servers, fqdn, message) + if err == nil { + if response.Rcode != mDNS.RcodeSuccess { + err = dns.RcodeError(response.Rcode) + } else if len(dns.MessageToAddresses(response)) == 0 { + err = E.New(fqdn, ": empty result") + } + } + select { + case results <- queryResult{response, err}: + case <-returned: + } + } + queryCtx, queryCancel := context.WithCancel(ctx) + defer queryCancel() + var nameCount int + for _, fqdn := range t.nameList(domain) { + nameCount++ + go startRacer(queryCtx, fqdn) + } + var errors []error + for { + select { + case <-ctx.Done(): + return nil, ctx.Err() + case result := <-results: + if result.err == nil { + return result.response, nil + } + errors = append(errors, result.err) + if len(errors) == nameCount { + return nil, E.Errors(errors...) + } + } + } +} + +func (t *Transport) tryOneName(ctx context.Context, servers []M.Socksaddr, fqdn string, message *mDNS.Msg) (*mDNS.Msg, error) { + sLen := len(servers) + var lastErr error + for i := 0; i < t.attempts; i++ { + for j := 0; j < sLen; j++ { + server := servers[j%sLen] + question := message.Question[0] + question.Name = fqdn + response, err := t.exchangeOne(ctx, server, question, C.DNSTimeout, false, true) + if err != nil { + lastErr = err + continue + } + return response, nil + } + } + return nil, E.Cause(lastErr, fqdn) +} + +func (t *Transport) exchangeOne(ctx context.Context, server M.Socksaddr, question mDNS.Question, timeout time.Duration, useTCP, ad bool) (*mDNS.Msg, error) { + if server.Port == 0 { + server.Port = 53 + } + var networks []string + if useTCP { + networks = []string{N.NetworkTCP} + } else { + networks = []string{N.NetworkUDP, N.NetworkTCP} + } + request := &mDNS.Msg{ + MsgHdr: mDNS.MsgHdr{ + Id: uint16(rand.Uint32()), + RecursionDesired: true, + AuthenticatedData: ad, + }, + Question: []mDNS.Question{question}, + Compress: true, + } + request.SetEdns0(maxDNSPacketSize, false) + buffer := buf.Get(buf.UDPBufferSize) + defer buf.Put(buffer) + for _, network := range networks { + ctx, cancel := context.WithDeadline(ctx, time.Now().Add(timeout)) + defer cancel() + conn, err := t.dialer.DialContext(ctx, network, server) + if err != nil { + return nil, err + } + defer conn.Close() + if deadline, loaded := ctx.Deadline(); loaded && !deadline.IsZero() { + conn.SetDeadline(deadline) + } + rawMessage, err := request.PackBuffer(buffer) + if err != nil { + return nil, E.Cause(err, "pack request") + } + _, err = conn.Write(rawMessage) + if err != nil { + return nil, E.Cause(err, "write request") + } + n, err := conn.Read(buffer) + if err != nil { + return nil, E.Cause(err, "read response") + } + var response mDNS.Msg + err = response.Unpack(buffer[:n]) + if err != nil { + return nil, E.Cause(err, "unpack response") + } + if response.Truncated && network == N.NetworkUDP { + continue + } + return &response, nil + } + panic("unexpected") +} + +func (t *Transport) nameList(name string) []string { + l := len(name) + rooted := l > 0 && name[l-1] == '.' + if l > 254 || l == 254 && !rooted { + return nil + } + + if rooted { + if avoidDNS(name) { + return nil + } + return []string{name} + } + + hasNdots := strings.Count(name, ".") >= t.ndots + name += "." + // l++ + + names := make([]string, 0, 1+len(t.search)) + if hasNdots && !avoidDNS(name) { + names = append(names, name) + } + for _, suffix := range t.search { + fqdn := name + suffix + if !avoidDNS(fqdn) && len(fqdn) <= 254 { + names = append(names, fqdn) + } + } + if !hasNdots && !avoidDNS(name) { + names = append(names, name) + } + return names +} + +func avoidDNS(name string) bool { + if name == "" { + return true + } + if name[len(name)-1] == '.' { + name = name[:len(name)-1] + } + return strings.HasSuffix(name, ".onion") +} diff --git a/sing-box/dns/transport/local/local.go b/sing-box/dns/transport/local/local.go index 74c9c7021e..28d49aed1c 100644 --- a/sing-box/dns/transport/local/local.go +++ b/sing-box/dns/transport/local/local.go @@ -1,9 +1,9 @@ +//go:build !darwin + package local import ( "context" - "math/rand" - "time" "github.com/sagernet/sing-box/adapter" C "github.com/sagernet/sing-box/constant" @@ -11,10 +11,8 @@ import ( "github.com/sagernet/sing-box/dns/transport/hosts" "github.com/sagernet/sing-box/log" "github.com/sagernet/sing-box/option" - "github.com/sagernet/sing/common/buf" E "github.com/sagernet/sing/common/exceptions" "github.com/sagernet/sing/common/logger" - M "github.com/sagernet/sing/common/metadata" N "github.com/sagernet/sing/common/network" mDNS "github.com/miekg/dns" @@ -37,9 +35,6 @@ type Transport struct { } func NewTransport(ctx context.Context, logger log.ContextLogger, tag string, options option.LocalDNSServerOptions) (adapter.DNSTransport, error) { - if C.IsDarwin && !options.PreferGo { - return NewResolvTransport(ctx, logger, tag) - } transportDialer, err := dns.NewLocalDialer(ctx, options) if err != nil { return nil, err @@ -94,147 +89,5 @@ func (t *Transport) Exchange(ctx context.Context, message *mDNS.Msg) (*mDNS.Msg, return dns.FixedResponse(message.Id, question, addresses, C.DefaultDNSTTL), nil } } - systemConfig := getSystemDNSConfig(t.ctx) - if systemConfig.singleRequest || !(message.Question[0].Qtype == mDNS.TypeA || message.Question[0].Qtype == mDNS.TypeAAAA) { - return t.exchangeSingleRequest(ctx, systemConfig, message, domain) - } else { - return t.exchangeParallel(ctx, systemConfig, message, domain) - } -} - -func (t *Transport) exchangeSingleRequest(ctx context.Context, systemConfig *dnsConfig, message *mDNS.Msg, domain string) (*mDNS.Msg, error) { - var lastErr error - for _, fqdn := range systemConfig.nameList(domain) { - response, err := t.tryOneName(ctx, systemConfig, fqdn, message) - if err != nil { - lastErr = err - continue - } - return response, nil - } - return nil, lastErr -} - -func (t *Transport) exchangeParallel(ctx context.Context, systemConfig *dnsConfig, message *mDNS.Msg, domain string) (*mDNS.Msg, error) { - returned := make(chan struct{}) - defer close(returned) - type queryResult struct { - response *mDNS.Msg - err error - } - results := make(chan queryResult) - startRacer := func(ctx context.Context, fqdn string) { - response, err := t.tryOneName(ctx, systemConfig, fqdn, message) - if err == nil { - if response.Rcode != mDNS.RcodeSuccess { - err = dns.RcodeError(response.Rcode) - } else if len(dns.MessageToAddresses(response)) == 0 { - err = E.New(fqdn, ": empty result") - } - } - select { - case results <- queryResult{response, err}: - case <-returned: - } - } - queryCtx, queryCancel := context.WithCancel(ctx) - defer queryCancel() - var nameCount int - for _, fqdn := range systemConfig.nameList(domain) { - nameCount++ - go startRacer(queryCtx, fqdn) - } - var errors []error - for { - select { - case <-ctx.Done(): - return nil, ctx.Err() - case result := <-results: - if result.err == nil { - return result.response, nil - } - errors = append(errors, result.err) - if len(errors) == nameCount { - return nil, E.Errors(errors...) - } - } - } -} - -func (t *Transport) tryOneName(ctx context.Context, config *dnsConfig, fqdn string, message *mDNS.Msg) (*mDNS.Msg, error) { - serverOffset := config.serverOffset() - sLen := uint32(len(config.servers)) - var lastErr error - for i := 0; i < config.attempts; i++ { - for j := uint32(0); j < sLen; j++ { - server := config.servers[(serverOffset+j)%sLen] - question := message.Question[0] - question.Name = fqdn - response, err := t.exchangeOne(ctx, M.ParseSocksaddr(server), question, config.timeout, config.useTCP, config.trustAD) - if err != nil { - lastErr = err - continue - } - return response, nil - } - } - return nil, E.Cause(lastErr, fqdn) -} - -func (t *Transport) exchangeOne(ctx context.Context, server M.Socksaddr, question mDNS.Question, timeout time.Duration, useTCP, ad bool) (*mDNS.Msg, error) { - if server.Port == 0 { - server.Port = 53 - } - var networks []string - if useTCP { - networks = []string{N.NetworkTCP} - } else { - networks = []string{N.NetworkUDP, N.NetworkTCP} - } - request := &mDNS.Msg{ - MsgHdr: mDNS.MsgHdr{ - Id: uint16(rand.Uint32()), - RecursionDesired: true, - AuthenticatedData: ad, - }, - Question: []mDNS.Question{question}, - Compress: true, - } - request.SetEdns0(maxDNSPacketSize, false) - buffer := buf.Get(buf.UDPBufferSize) - defer buf.Put(buffer) - for _, network := range networks { - ctx, cancel := context.WithDeadline(ctx, time.Now().Add(timeout)) - defer cancel() - conn, err := t.dialer.DialContext(ctx, network, server) - if err != nil { - return nil, err - } - defer conn.Close() - if deadline, loaded := ctx.Deadline(); loaded && !deadline.IsZero() { - conn.SetDeadline(deadline) - } - rawMessage, err := request.PackBuffer(buffer) - if err != nil { - return nil, E.Cause(err, "pack request") - } - _, err = conn.Write(rawMessage) - if err != nil { - return nil, E.Cause(err, "write request") - } - n, err := conn.Read(buffer) - if err != nil { - return nil, E.Cause(err, "read response") - } - var response mDNS.Msg - err = response.Unpack(buffer[:n]) - if err != nil { - return nil, E.Cause(err, "unpack response") - } - if response.Truncated && network == N.NetworkUDP { - continue - } - return &response, nil - } - panic("unexpected") + return t.exchange(ctx, message, domain) } diff --git a/sing-box/dns/transport/local/local_darwin.go b/sing-box/dns/transport/local/local_darwin.go new file mode 100644 index 0000000000..5a8b4113e8 --- /dev/null +++ b/sing-box/dns/transport/local/local_darwin.go @@ -0,0 +1,142 @@ +//go:build darwin + +package local + +import ( + "context" + "errors" + "net" + + mDNS "github.com/miekg/dns" + "github.com/sagernet/sing-box/adapter" + C "github.com/sagernet/sing-box/constant" + "github.com/sagernet/sing-box/dns" + "github.com/sagernet/sing-box/dns/transport/hosts" + "github.com/sagernet/sing-box/log" + "github.com/sagernet/sing-box/option" + "github.com/sagernet/sing/common" + E "github.com/sagernet/sing/common/exceptions" + "github.com/sagernet/sing/common/logger" + M "github.com/sagernet/sing/common/metadata" + N "github.com/sagernet/sing/common/network" + "github.com/sagernet/sing/service" +) + +func RegisterTransport(registry *dns.TransportRegistry) { + dns.RegisterTransport[option.LocalDNSServerOptions](registry, C.DNSTypeLocal, NewTransport) +} + +var _ adapter.DNSTransport = (*Transport)(nil) + +type Transport struct { + dns.TransportAdapter + ctx context.Context + logger logger.ContextLogger + hosts *hosts.File + dialer N.Dialer + preferGo bool + fallback bool + dhcpTransport dhcpTransport + resolver net.Resolver +} + +type dhcpTransport interface { + adapter.DNSTransport + Fetch() ([]M.Socksaddr, error) + Exchange0(ctx context.Context, message *mDNS.Msg, servers []M.Socksaddr) (*mDNS.Msg, error) +} + +func NewTransport(ctx context.Context, logger log.ContextLogger, tag string, options option.LocalDNSServerOptions) (adapter.DNSTransport, error) { + transportDialer, err := dns.NewLocalDialer(ctx, options) + if err != nil { + return nil, err + } + transportAdapter := dns.NewTransportAdapterWithLocalOptions(C.DNSTypeLocal, tag, options) + return &Transport{ + TransportAdapter: transportAdapter, + ctx: ctx, + logger: logger, + hosts: hosts.NewFile(hosts.DefaultPath), + dialer: transportDialer, + preferGo: options.PreferGo, + }, nil +} + +func (t *Transport) Start(stage adapter.StartStage) error { + if stage != adapter.StartStateStart { + return nil + } + inboundManager := service.FromContext[adapter.InboundManager](t.ctx) + for _, inbound := range inboundManager.Inbounds() { + if inbound.Type() == C.TypeTun { + t.fallback = true + break + } + } + if !C.IsIos { + if t.fallback { + t.dhcpTransport = newDHCPTransport(t.TransportAdapter, log.ContextWithOverrideLevel(t.ctx, log.LevelDebug), t.dialer, t.logger) + if t.dhcpTransport != nil { + err := t.dhcpTransport.Start(stage) + if err != nil { + return err + } + } + } + } + return nil +} + +func (t *Transport) Close() error { + return common.Close( + t.dhcpTransport, + ) +} + +func (t *Transport) Exchange(ctx context.Context, message *mDNS.Msg) (*mDNS.Msg, error) { + question := message.Question[0] + domain := dns.FqdnToDomain(question.Name) + if question.Qtype == mDNS.TypeA || question.Qtype == mDNS.TypeAAAA { + addresses := t.hosts.Lookup(domain) + if len(addresses) > 0 { + return dns.FixedResponse(message.Id, question, addresses, C.DefaultDNSTTL), nil + } + } + if !t.fallback { + return t.exchange(ctx, message, domain) + } + if !C.IsIos { + if t.dhcpTransport != nil { + dhcpTransports, _ := t.dhcpTransport.Fetch() + if len(dhcpTransports) > 0 { + return t.dhcpTransport.Exchange0(ctx, message, dhcpTransports) + } + } + } + if t.preferGo { + // Assuming the user knows what they are doing, we still execute the query which will fail. + return t.exchange(ctx, message, domain) + } + if question.Qtype == mDNS.TypeA || question.Qtype == mDNS.TypeAAAA { + var network string + if question.Qtype == mDNS.TypeA { + network = "ip4" + } else { + network = "ip6" + } + addresses, err := t.resolver.LookupNetIP(ctx, network, domain) + if err != nil { + var dnsError *net.DNSError + if errors.As(err, &dnsError) && dnsError.IsNotFound { + return nil, dns.RcodeRefused + } + return nil, err + } + return dns.FixedResponse(message.Id, question, addresses, C.DefaultDNSTTL), nil + } + if C.IsIos { + return nil, E.New("only A and AAAA queries are supported on iOS and tvOS when using NetworkExtension.") + } else { + return nil, E.New("only A and AAAA queries are supported on macOS when using NetworkExtension and DHCP unavailable.") + } +} diff --git a/sing-box/dns/transport/local/local_darwin_dhcp.go b/sing-box/dns/transport/local/local_darwin_dhcp.go new file mode 100644 index 0000000000..b228b76a48 --- /dev/null +++ b/sing-box/dns/transport/local/local_darwin_dhcp.go @@ -0,0 +1,16 @@ +//go:build darwin && with_dhcp + +package local + +import ( + "context" + + "github.com/sagernet/sing-box/dns" + "github.com/sagernet/sing-box/dns/transport/dhcp" + "github.com/sagernet/sing-box/log" + N "github.com/sagernet/sing/common/network" +) + +func newDHCPTransport(transportAdapter dns.TransportAdapter, ctx context.Context, dialer N.Dialer, logger log.ContextLogger) dhcpTransport { + return dhcp.NewRawTransport(transportAdapter, ctx, dialer, logger) +} diff --git a/sing-box/dns/transport/local/local_darwin_nodhcp.go b/sing-box/dns/transport/local/local_darwin_nodhcp.go new file mode 100644 index 0000000000..5ce84690a4 --- /dev/null +++ b/sing-box/dns/transport/local/local_darwin_nodhcp.go @@ -0,0 +1,15 @@ +//go:build darwin && !with_dhcp + +package local + +import ( + "context" + + "github.com/sagernet/sing-box/dns" + "github.com/sagernet/sing-box/log" + N "github.com/sagernet/sing/common/network" +) + +func newDHCPTransport(transportAdapter dns.TransportAdapter, ctx context.Context, dialer N.Dialer, logger log.ContextLogger) dhcpTransport { + return nil +} diff --git a/sing-box/dns/transport/local/local_resolv.go b/sing-box/dns/transport/local/local_resolv.go deleted file mode 100644 index cf7bcfbab8..0000000000 --- a/sing-box/dns/transport/local/local_resolv.go +++ /dev/null @@ -1,46 +0,0 @@ -//go:build darwin - -package local - -import ( - "context" - - "github.com/sagernet/sing-box/adapter" - C "github.com/sagernet/sing-box/constant" - "github.com/sagernet/sing-box/dns" - "github.com/sagernet/sing-box/log" - "github.com/sagernet/sing/common/logger" - - mDNS "github.com/miekg/dns" -) - -var _ adapter.DNSTransport = (*ResolvTransport)(nil) - -type ResolvTransport struct { - dns.TransportAdapter - ctx context.Context - logger logger.ContextLogger -} - -func NewResolvTransport(ctx context.Context, logger log.ContextLogger, tag string) (adapter.DNSTransport, error) { - return &ResolvTransport{ - TransportAdapter: dns.NewTransportAdapter(C.DNSTypeLocal, tag, nil), - ctx: ctx, - logger: logger, - }, nil -} - -func (t *ResolvTransport) Start(stage adapter.StartStage) error { - return nil -} - -func (t *ResolvTransport) Close() error { - return nil -} - -func (t *ResolvTransport) Exchange(ctx context.Context, message *mDNS.Msg) (*mDNS.Msg, error) { - question := message.Question[0] - return doBlockingWithCtx(ctx, func() (*mDNS.Msg, error) { - return cgoResSearch(question.Name, int(question.Qtype), int(question.Qclass)) - }) -} diff --git a/sing-box/dns/transport/local/local_resolv_linkname.go b/sing-box/dns/transport/local/local_resolv_linkname.go deleted file mode 100644 index 1495ae1d7b..0000000000 --- a/sing-box/dns/transport/local/local_resolv_linkname.go +++ /dev/null @@ -1,170 +0,0 @@ -// Copyright 2022 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build darwin - -package local - -import ( - "context" - "errors" - "runtime" - "syscall" - "unsafe" - _ "unsafe" - - E "github.com/sagernet/sing/common/exceptions" - - mDNS "github.com/miekg/dns" -) - -type ( - _C_char = byte - _C_int = int32 - _C_uchar = byte - _C_ushort = uint16 - _C_uint = uint32 - _C_ulong = uint64 - _C_struct___res_state = ResState - _C_struct_sockaddr = syscall.RawSockaddr -) - -func _C_free(p unsafe.Pointer) { runtime.KeepAlive(p) } - -func _C_malloc(n uintptr) unsafe.Pointer { - if n <= 0 { - n = 1 - } - return unsafe.Pointer(&make([]byte, n)[0]) -} - -const ( - MAXNS = 3 - MAXDNSRCH = 6 -) - -type ResState struct { - Retrans _C_int - Retry _C_int - Options _C_ulong - Nscount _C_int - Nsaddrlist [MAXNS]_C_struct_sockaddr - Id _C_ushort - Dnsrch [MAXDNSRCH + 1]*_C_char - Defname [256]_C_char - Pfcode _C_ulong - Ndots _C_uint - Nsort _C_uint - stub [128]byte -} - -//go:linkname ResNinit internal/syscall/unix.ResNinit -func ResNinit(state *_C_struct___res_state) error - -//go:linkname ResNsearch internal/syscall/unix.ResNsearch -func ResNsearch(state *_C_struct___res_state, dname *byte, class, typ int, ans *byte, anslen int) (int, error) - -//go:linkname ResNclose internal/syscall/unix.ResNclose -func ResNclose(state *_C_struct___res_state) - -//go:linkname GoString internal/syscall/unix.GoString -func GoString(p *byte) string - -// doBlockingWithCtx executes a blocking function in a separate goroutine when the provided -// context is cancellable. It is intended for use with calls that don't support context -// cancellation (cgo, syscalls). blocking func may still be running after this function finishes. -// For the duration of the execution of the blocking function, the thread is 'acquired' using [acquireThread], -// blocking might not be executed when the context gets canceled early. -func doBlockingWithCtx[T any](ctx context.Context, blocking func() (T, error)) (T, error) { - if err := acquireThread(ctx); err != nil { - var zero T - return zero, err - } - - if ctx.Done() == nil { - defer releaseThread() - return blocking() - } - - type result struct { - res T - err error - } - - res := make(chan result, 1) - go func() { - defer releaseThread() - var r result - r.res, r.err = blocking() - res <- r - }() - - select { - case r := <-res: - return r.res, r.err - case <-ctx.Done(): - var zero T - return zero, ctx.Err() - } -} - -//go:linkname acquireThread net.acquireThread -func acquireThread(ctx context.Context) error - -//go:linkname releaseThread net.releaseThread -func releaseThread() - -func cgoResSearch(hostname string, rtype, class int) (*mDNS.Msg, error) { - resStateSize := unsafe.Sizeof(_C_struct___res_state{}) - var state *_C_struct___res_state - if resStateSize > 0 { - mem := _C_malloc(resStateSize) - defer _C_free(mem) - memSlice := unsafe.Slice((*byte)(mem), resStateSize) - clear(memSlice) - state = (*_C_struct___res_state)(unsafe.Pointer(&memSlice[0])) - } - if err := ResNinit(state); err != nil { - return nil, errors.New("res_ninit failure: " + err.Error()) - } - defer ResNclose(state) - - bufSize := maxDNSPacketSize - buf := (*_C_uchar)(_C_malloc(uintptr(bufSize))) - defer _C_free(unsafe.Pointer(buf)) - - s, err := syscall.BytePtrFromString(hostname) - if err != nil { - return nil, err - } - - var size int - for { - size, _ = ResNsearch(state, s, class, rtype, buf, bufSize) - if size <= bufSize || size > 0xffff { - break - } - - // Allocate a bigger buffer to fit the entire msg. - _C_free(unsafe.Pointer(buf)) - bufSize = size - buf = (*_C_uchar)(_C_malloc(uintptr(bufSize))) - } - - var msg mDNS.Msg - if size == -1 { - // macOS's libresolv seems to directly return -1 for responses that are not success responses but are exchanged. - // However, we still need the response, so we fall back to parsing the entire buffer. - err = msg.Unpack(unsafe.Slice(buf, bufSize)) - if err != nil { - return nil, E.New("res_nsearch failure") - } - } else { - err = msg.Unpack(unsafe.Slice(buf, size)) - if err != nil { - return nil, err - } - } - return &msg, nil -} diff --git a/sing-box/dns/transport/local/local_resolv_stub.go b/sing-box/dns/transport/local/local_resolv_stub.go deleted file mode 100644 index 8486b87a31..0000000000 --- a/sing-box/dns/transport/local/local_resolv_stub.go +++ /dev/null @@ -1,15 +0,0 @@ -//go:build !darwin - -package local - -import ( - "context" - "os" - - "github.com/sagernet/sing-box/adapter" - "github.com/sagernet/sing-box/log" -) - -func NewResolvTransport(ctx context.Context, logger log.ContextLogger, tag string) (adapter.DNSTransport, error) { - return nil, os.ErrInvalid -} diff --git a/sing-box/dns/transport/local/local_shared.go b/sing-box/dns/transport/local/local_shared.go new file mode 100644 index 0000000000..9059b91f36 --- /dev/null +++ b/sing-box/dns/transport/local/local_shared.go @@ -0,0 +1,161 @@ +package local + +import ( + "context" + "math/rand" + "time" + + "github.com/sagernet/sing-box/dns" + "github.com/sagernet/sing/common/buf" + E "github.com/sagernet/sing/common/exceptions" + M "github.com/sagernet/sing/common/metadata" + N "github.com/sagernet/sing/common/network" + + mDNS "github.com/miekg/dns" +) + +func (t *Transport) exchange(ctx context.Context, message *mDNS.Msg, domain string) (*mDNS.Msg, error) { + systemConfig := getSystemDNSConfig(t.ctx) + if systemConfig.singleRequest || !(message.Question[0].Qtype == mDNS.TypeA || message.Question[0].Qtype == mDNS.TypeAAAA) { + return t.exchangeSingleRequest(ctx, systemConfig, message, domain) + } else { + return t.exchangeParallel(ctx, systemConfig, message, domain) + } +} + +func (t *Transport) exchangeSingleRequest(ctx context.Context, systemConfig *dnsConfig, message *mDNS.Msg, domain string) (*mDNS.Msg, error) { + var lastErr error + for _, fqdn := range systemConfig.nameList(domain) { + response, err := t.tryOneName(ctx, systemConfig, fqdn, message) + if err != nil { + lastErr = err + continue + } + return response, nil + } + return nil, lastErr +} + +func (t *Transport) exchangeParallel(ctx context.Context, systemConfig *dnsConfig, message *mDNS.Msg, domain string) (*mDNS.Msg, error) { + returned := make(chan struct{}) + defer close(returned) + type queryResult struct { + response *mDNS.Msg + err error + } + results := make(chan queryResult) + startRacer := func(ctx context.Context, fqdn string) { + response, err := t.tryOneName(ctx, systemConfig, fqdn, message) + if err == nil { + if response.Rcode != mDNS.RcodeSuccess { + err = dns.RcodeError(response.Rcode) + } else if len(dns.MessageToAddresses(response)) == 0 { + err = E.New(fqdn, ": empty result") + } + } + select { + case results <- queryResult{response, err}: + case <-returned: + } + } + queryCtx, queryCancel := context.WithCancel(ctx) + defer queryCancel() + var nameCount int + for _, fqdn := range systemConfig.nameList(domain) { + nameCount++ + go startRacer(queryCtx, fqdn) + } + var errors []error + for { + select { + case <-ctx.Done(): + return nil, ctx.Err() + case result := <-results: + if result.err == nil { + return result.response, nil + } + errors = append(errors, result.err) + if len(errors) == nameCount { + return nil, E.Errors(errors...) + } + } + } +} + +func (t *Transport) tryOneName(ctx context.Context, config *dnsConfig, fqdn string, message *mDNS.Msg) (*mDNS.Msg, error) { + serverOffset := config.serverOffset() + sLen := uint32(len(config.servers)) + var lastErr error + for i := 0; i < config.attempts; i++ { + for j := uint32(0); j < sLen; j++ { + server := config.servers[(serverOffset+j)%sLen] + question := message.Question[0] + question.Name = fqdn + response, err := t.exchangeOne(ctx, M.ParseSocksaddr(server), question, config.timeout, config.useTCP, config.trustAD) + if err != nil { + lastErr = err + continue + } + return response, nil + } + } + return nil, E.Cause(lastErr, fqdn) +} + +func (t *Transport) exchangeOne(ctx context.Context, server M.Socksaddr, question mDNS.Question, timeout time.Duration, useTCP, ad bool) (*mDNS.Msg, error) { + if server.Port == 0 { + server.Port = 53 + } + var networks []string + if useTCP { + networks = []string{N.NetworkTCP} + } else { + networks = []string{N.NetworkUDP, N.NetworkTCP} + } + request := &mDNS.Msg{ + MsgHdr: mDNS.MsgHdr{ + Id: uint16(rand.Uint32()), + RecursionDesired: true, + AuthenticatedData: ad, + }, + Question: []mDNS.Question{question}, + Compress: true, + } + request.SetEdns0(maxDNSPacketSize, false) + buffer := buf.Get(buf.UDPBufferSize) + defer buf.Put(buffer) + for _, network := range networks { + ctx, cancel := context.WithDeadline(ctx, time.Now().Add(timeout)) + defer cancel() + conn, err := t.dialer.DialContext(ctx, network, server) + if err != nil { + return nil, err + } + defer conn.Close() + if deadline, loaded := ctx.Deadline(); loaded && !deadline.IsZero() { + conn.SetDeadline(deadline) + } + rawMessage, err := request.PackBuffer(buffer) + if err != nil { + return nil, E.Cause(err, "pack request") + } + _, err = conn.Write(rawMessage) + if err != nil { + return nil, E.Cause(err, "write request") + } + n, err := conn.Read(buffer) + if err != nil { + return nil, E.Cause(err, "read response") + } + var response mDNS.Msg + err = response.Unpack(buffer[:n]) + if err != nil { + return nil, E.Cause(err, "unpack response") + } + if response.Truncated && network == N.NetworkUDP { + continue + } + return &response, nil + } + panic("unexpected") +} diff --git a/sing-box/dns/transport/local/resolv_darwin.go b/sing-box/dns/transport/local/resolv_darwin.go deleted file mode 100644 index 396e40deec..0000000000 --- a/sing-box/dns/transport/local/resolv_darwin.go +++ /dev/null @@ -1,72 +0,0 @@ -package local - -import ( - "context" - "net/netip" - "syscall" - "time" - "unsafe" - - E "github.com/sagernet/sing/common/exceptions" - - "github.com/miekg/dns" -) - -func dnsReadConfig(_ context.Context, _ string) *dnsConfig { - resStateSize := unsafe.Sizeof(_C_struct___res_state{}) - var state *_C_struct___res_state - if resStateSize > 0 { - mem := _C_malloc(resStateSize) - defer _C_free(mem) - memSlice := unsafe.Slice((*byte)(mem), resStateSize) - clear(memSlice) - state = (*_C_struct___res_state)(unsafe.Pointer(&memSlice[0])) - } - if err := ResNinit(state); err != nil { - return &dnsConfig{ - servers: defaultNS, - search: dnsDefaultSearch(), - ndots: 1, - timeout: 5 * time.Second, - attempts: 2, - err: E.Cause(err, "libresolv initialization failed"), - } - } - defer ResNclose(state) - conf := &dnsConfig{ - ndots: 1, - timeout: 5 * time.Second, - attempts: int(state.Retry), - } - for i := 0; i < int(state.Nscount); i++ { - addr := parseRawSockaddr(&state.Nsaddrlist[i]) - if addr.IsValid() { - conf.servers = append(conf.servers, addr.String()) - } - } - for i := 0; ; i++ { - search := state.Dnsrch[i] - if search == nil { - break - } - name := dns.Fqdn(GoString(search)) - if name == "" { - continue - } - conf.search = append(conf.search, name) - } - return conf -} - -func parseRawSockaddr(rawSockaddr *syscall.RawSockaddr) netip.Addr { - switch rawSockaddr.Family { - case syscall.AF_INET: - sa := (*syscall.RawSockaddrInet4)(unsafe.Pointer(rawSockaddr)) - return netip.AddrFrom4(sa.Addr) - case syscall.AF_INET6: - sa := (*syscall.RawSockaddrInet6)(unsafe.Pointer(rawSockaddr)) - return netip.AddrFrom16(sa.Addr) - default: - return netip.Addr{} - } -} diff --git a/sing-box/dns/transport/local/resolv_unix.go b/sing-box/dns/transport/local/resolv_unix.go index 99eb71e6e2..51512f65e6 100644 --- a/sing-box/dns/transport/local/resolv_unix.go +++ b/sing-box/dns/transport/local/resolv_unix.go @@ -1,4 +1,4 @@ -//go:build !windows && !darwin +//go:build !windows package local diff --git a/sing-box/docs/changelog.md b/sing-box/docs/changelog.md index 736aff6b10..79cf1c107b 100644 --- a/sing-box/docs/changelog.md +++ b/sing-box/docs/changelog.md @@ -2,6 +2,14 @@ icon: material/alert-decagram --- +#### 1.13.0-alpha.4 + +* Fixes and improvements + +#### 1.12.2 + +* Fixes and improvements + #### 1.13.0-alpha.3 * Improve `local` DNS server **1** diff --git a/sing-box/docs/configuration/dns/server/local.md b/sing-box/docs/configuration/dns/server/local.md index 361c6c5b1d..9556cb1d0d 100644 --- a/sing-box/docs/configuration/dns/server/local.md +++ b/sing-box/docs/configuration/dns/server/local.md @@ -43,16 +43,18 @@ When enabled, `local` DNS server will resolve DNS by dialing itself whenever pos Specifically, it disables following behaviors which was added as features in sing-box 1.13.0: -* On Apple platforms: Use `libresolv` for resolution, as it is the only one that works properly with NetworkExtension - that overrides DNS servers (DHCP is also possible but is not considered). -* On Linux: Resolve through `systemd-resolvd`'s DBus interface when available. +1. On Apple platforms: Attempt to resolve A/AAAA requests using `getaddrinfo` in NetworkExtension. +2. On Linux: Resolve through `systemd-resolvd`'s DBus interface when available. As a sole exception, it cannot disable the following behavior: -In the Android graphical client, the `local` DNS server will always resolve DNS through the platform interface, -as there is no other way to obtain upstream DNS servers. +1. In the Android graphical client, +`local` will always resolve DNS through the platform interface, +as there is no other way to obtain upstream DNS servers; +On devices running Android versions lower than 10, this interface can only resolve A/AAAA requests. -On devices running Android versions lower than 10, this interface can only resolve IP queries. +2. On macOS, `local` will try DHCP first in Network Extension, since DHCP respects DIal Fields, +it will not be disabled by `prefer_go`. ### Dial Fields diff --git a/sing-box/go.mod b/sing-box/go.mod index 36038a3928..452694c678 100644 --- a/sing-box/go.mod +++ b/sing-box/go.mod @@ -15,7 +15,7 @@ require ( github.com/libdns/alidns v1.0.5-libdns.v1.beta1 github.com/libdns/cloudflare v0.2.2-0.20250708034226-c574dccb31a6 github.com/logrusorgru/aurora v2.0.3+incompatible - github.com/metacubex/tfo-go v0.0.0-20241231083714-66613d49c422 + github.com/metacubex/tfo-go v0.0.0-20250516165257-e29c16ae41d4 github.com/metacubex/utls v1.8.0 github.com/mholt/acmez/v3 v3.1.2 github.com/miekg/dns v1.1.67 @@ -34,7 +34,7 @@ require ( github.com/sagernet/sing-shadowsocks2 v0.2.1 github.com/sagernet/sing-shadowtls v0.2.1-0.20250503051639-fcd445d33c11 github.com/sagernet/sing-tun v0.7.0-beta.1 - github.com/sagernet/sing-vmess v0.2.6 + github.com/sagernet/sing-vmess v0.2.7 github.com/sagernet/smux v1.5.34-mod.2 github.com/sagernet/tailscale v1.80.3-mod.5 github.com/sagernet/wireguard-go v0.0.1-beta.7 diff --git a/sing-box/go.sum b/sing-box/go.sum index db3cf46466..d0f21c8cc2 100644 --- a/sing-box/go.sum +++ b/sing-box/go.sum @@ -122,8 +122,8 @@ github.com/mdlayher/sdnotify v1.0.0 h1:Ma9XeLVN/l0qpyx1tNeMSeTjCPH6NtuD6/N9XdTlQ github.com/mdlayher/sdnotify v1.0.0/go.mod h1:HQUmpM4XgYkhDLtd+Uad8ZFK1T9D5+pNxnXQjCeJlGE= github.com/mdlayher/socket v0.5.1 h1:VZaqt6RkGkt2OE9l3GcC6nZkqD3xKeQLyfleW/uBcos= github.com/mdlayher/socket v0.5.1/go.mod h1:TjPLHI1UgwEv5J1B5q0zTZq12A/6H7nKmtTanQE37IQ= -github.com/metacubex/tfo-go v0.0.0-20241231083714-66613d49c422 h1:zGeQt3UyNydIVrMRB97AA5WsYEau/TyCnRtTf1yUmJY= -github.com/metacubex/tfo-go v0.0.0-20241231083714-66613d49c422/go.mod h1:l9oLnLoEXyGZ5RVLsh7QCC5XsouTUyKk4F2nLm2DHLw= +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/mholt/acmez/v3 v3.1.2 h1:auob8J/0FhmdClQicvJvuDavgd5ezwLBfKuYmynhYzc= @@ -181,8 +181,8 @@ github.com/sagernet/sing-shadowtls v0.2.1-0.20250503051639-fcd445d33c11 h1:tK+75 github.com/sagernet/sing-shadowtls v0.2.1-0.20250503051639-fcd445d33c11/go.mod h1:sWqKnGlMipCHaGsw1sTTlimyUpgzP4WP3pjhCsYt9oA= github.com/sagernet/sing-tun v0.7.0-beta.1 h1:mBIFXYAnGO5ey/HcCYanqnBx61E7yF8zTFGRZonGYmY= github.com/sagernet/sing-tun v0.7.0-beta.1/go.mod h1:AHJuRrLbNRJuivuFZ2VhXwDj4ViYp14szG5EkkKAqRQ= -github.com/sagernet/sing-vmess v0.2.6 h1:1c4dGzeGy0kpBXXrT1sgiMZtHhdJylIT8eWrGhJYZec= -github.com/sagernet/sing-vmess v0.2.6/go.mod h1:5aYoOtYksAyS0NXDm0qKeTYW1yoE1bJVcv+XLcVoyJs= +github.com/sagernet/sing-vmess v0.2.7 h1:2ee+9kO0xW5P4mfe6TYVWf9VtY8k1JhNysBqsiYj0sk= +github.com/sagernet/sing-vmess v0.2.7/go.mod h1:5aYoOtYksAyS0NXDm0qKeTYW1yoE1bJVcv+XLcVoyJs= github.com/sagernet/smux v1.5.34-mod.2 h1:gkmBjIjlJ2zQKpLigOkFur5kBKdV6bNRoFu2WkltRQ4= github.com/sagernet/smux v1.5.34-mod.2/go.mod h1:0KW0+R+ycvA2INW4gbsd7BNyg+HEfLIAxa5N02/28Zc= github.com/sagernet/tailscale v1.80.3-mod.5 h1:7V7z+p2C//TGtff20pPnDCt3qP6uFyY62peJoKF9z/A= diff --git a/sing-box/transport/wireguard/endpoint.go b/sing-box/transport/wireguard/endpoint.go index f4c37c0c2f..2adf783213 100644 --- a/sing-box/transport/wireguard/endpoint.go +++ b/sing-box/transport/wireguard/endpoint.go @@ -223,6 +223,9 @@ func (e *Endpoint) Close() error { } func (e *Endpoint) Lookup(address netip.Addr) *device.Peer { + if e.allowedIPs == nil { + return nil + } return e.allowedIPs.Lookup(address.AsSlice()) } diff --git a/small/.github/workflows/T2 build.yml b/small/.github/workflows/T2 build.yml index a1c98e126b..bf856435f0 100644 --- a/small/.github/workflows/T2 build.yml +++ b/small/.github/workflows/T2 build.yml @@ -29,7 +29,7 @@ jobs: env: ARCH: ${{ matrix.arch }}-${{ matrix.sdk }} FEEDNAME: packages_ci - PACKAGES: luci-app-fchomo luci-app-homeproxy luci-app-nikki luci-app-openclash luci-app-passwall luci-app-passwall2 luci-app-ssr-plus luci-app-bypass brook hysteria ipt2socks pdnsd-alt redsocks2 shadow-tls trojan tuic-client xray-plugin v2ray-core v2ray-geodata naiveproxy sing-box + PACKAGES: luci-app-fchomo luci-app-homeproxy luci-app-momo luci-app-nikki luci-app-openclash luci-app-passwall luci-app-passwall2 luci-app-ssr-plus luci-app-bypass brook hysteria ipt2socks pdnsd-alt redsocks2 shadow-tls trojan tuic-client xray-plugin v2ray-core v2ray-geodata naiveproxy sing-box NO_REFRESH_CHECK: true IGNORE_ERRORS: true diff --git a/small/.github/workflows/T9 build.yml b/small/.github/workflows/T9 build.yml index 16750e7067..9ab5b5f7b7 100644 --- a/small/.github/workflows/T9 build.yml +++ b/small/.github/workflows/T9 build.yml @@ -68,7 +68,7 @@ jobs: env: ARCH: ${{ matrix.arch }}-${{ matrix.sdk }} FEEDNAME: packages_ci - PACKAGES: luci-app-fchomo luci-app-homeproxy luci-app-nikki luci-app-openclash luci-app-passwall luci-app-passwall2 luci-app-ssr-plus luci-app-bypass brook hysteria ipt2socks pdnsd-alt redsocks2 shadow-tls trojan tuic-client xray-plugin v2ray-core v2ray-geodata naiveproxy sing-box + PACKAGES: luci-app-fchomo luci-app-homeproxy luci-app-momo luci-app-nikki luci-app-openclash luci-app-passwall luci-app-passwall2 luci-app-ssr-plus luci-app-bypass brook hysteria ipt2socks pdnsd-alt redsocks2 shadow-tls trojan tuic-client xray-plugin v2ray-core v2ray-geodata naiveproxy sing-box NO_REFRESH_CHECK: true IGNORE_ERRORS: true diff --git a/small/luci-app-nikki/Makefile b/small/luci-app-nikki/Makefile index 9e9f0b4329..64bf375d4f 100644 --- a/small/luci-app-nikki/Makefile +++ b/small/luci-app-nikki/Makefile @@ -1,6 +1,6 @@ include $(TOPDIR)/rules.mk -PKG_VERSION:=1.23.3 +PKG_VERSION:=1.24.0 LUCI_TITLE:=LuCI Support for nikki LUCI_DEPENDS:=+luci-base +nikki diff --git a/small/luci-app-nikki/htdocs/luci-static/resources/tools/nikki.js b/small/luci-app-nikki/htdocs/luci-static/resources/tools/nikki.js index 7e7caa7aa9..57d8e3926c 100644 --- a/small/luci-app-nikki/htdocs/luci-static/resources/tools/nikki.js +++ b/small/luci-app-nikki/htdocs/luci-static/resources/tools/nikki.js @@ -65,8 +65,6 @@ const appLogPath = `${logDir}/app.log`; const coreLogPath = `${logDir}/core.log`; const debugLogPath = `${logDir}/debug.log`; const nftDir = `${homeDir}/nftables`; -const reservedIPNFT = `${nftDir}/reserved_ip.nft`; -const reservedIP6NFT = `${nftDir}/reserved_ip6.nft`; return baseclass.extend({ homeDir: homeDir, @@ -80,8 +78,6 @@ return baseclass.extend({ appLogPath: appLogPath, coreLogPath: coreLogPath, debugLogPath: debugLogPath, - reservedIPNFT: reservedIPNFT, - reservedIP6NFT: reservedIP6NFT, status: async function () { return (await callRCList('nikki'))?.nikki?.running; diff --git a/small/luci-app-nikki/htdocs/luci-static/resources/view/nikki/editor.js b/small/luci-app-nikki/htdocs/luci-static/resources/view/nikki/editor.js index 37ff4ac869..674b3f2596 100644 --- a/small/luci-app-nikki/htdocs/luci-static/resources/view/nikki/editor.js +++ b/small/luci-app-nikki/htdocs/luci-static/resources/view/nikki/editor.js @@ -47,8 +47,6 @@ return view.extend({ o.value(nikki.mixinFilePath, _('File for Mixin')); o.value(nikki.runProfilePath, _('Profile for Startup')); - o.value(nikki.reservedIPNFT, _('File for Reserved IP')); - o.value(nikki.reservedIP6NFT, _('File for Reserved IP6')); o.write = function (section_id, formvalue) { return true; diff --git a/small/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js b/small/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js index 7004ab9ae2..e76d51fb90 100644 --- a/small/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js +++ b/small/luci-app-nikki/htdocs/luci-static/resources/view/nikki/mixin.js @@ -117,10 +117,9 @@ return view.extend({ o.value('https://github.com/MetaCubeX/Yacd-meta/archive/refs/heads/gh-pages.zip', 'YACD'); o.value('https://github.com/MetaCubeX/Razord-meta/archive/refs/heads/gh-pages.zip', 'Razord'); - o = s.taboption('external_control', form.Value, 'api_listen', '*' + ' ' + _('API Listen')); + o = s.taboption('external_control', form.Value, 'api_listen', _('API Listen')); o.datatype = 'ipaddrport(1)'; o.placeholder = _('Unmodified'); - o.rmempty = false; o = s.taboption('external_control', form.Value, 'api_secret', _('API Secret')); o.password = true; @@ -152,15 +151,13 @@ return view.extend({ o.datatype = 'port'; o.placeholder = _('Unmodified'); - o = s.taboption('inbound', form.Value, 'redir_port', '*' + ' ' + _('Redirect Port')); + o = s.taboption('inbound', form.Value, 'redir_port', _('Redirect Port')); o.datatype = 'port'; o.placeholder = _('Unmodified'); - o.rmempty = false; - o = s.taboption('inbound', form.Value, 'tproxy_port', '*' + ' ' + _('TPROXY Port')); + o = s.taboption('inbound', form.Value, 'tproxy_port', _('TPROXY Port')); o.datatype = 'port'; o.placeholder = _('Unmodified'); - o.rmempty = false; o = s.taboption('inbound', form.Flag, 'authentication', _('Overwrite Authentication')); o.rmempty = false; @@ -185,9 +182,14 @@ return view.extend({ s.tab('tun', _('TUN Config')); - o = s.taboption('tun', form.Value, 'tun_device', '*' + ' ' + _('Device Name')); + o = s.taboption('tun', form.ListValue, 'tun_enabled', _('Enable')); + o.optional = true; + o.placeholder = _('Unmodified'); + o.value('0', _('Disable')); + o.value('1', _('Enable')); + + o = s.taboption('tun', form.Value, 'tun_device', _('Device Name')); o.placeholder = _('Unmodified'); - o.rmempty = false; o = s.taboption('tun', form.ListValue, 'tun_stack', _('Stack')); o.optional = true; @@ -227,10 +229,15 @@ return view.extend({ s.tab('dns', _('DNS Config')); - o = s.taboption('dns', form.Value, 'dns_listen', '*' + ' ' + _('DNS Listen')); + o = s.taboption('dns', form.ListValue, 'dns_enabled', _('Enable')); + o.optional = true; + o.placeholder = _('Unmodified'); + o.value('0', _('Disable')); + o.value('1', _('Enable')); + + o = s.taboption('dns', form.Value, 'dns_listen', _('DNS Listen')); o.datatype = 'ipaddrport(1)'; o.placeholder = _('Unmodified'); - o.rmempty = false; o = s.taboption('dns', form.ListValue, 'dns_ipv6', 'IPv6'); o.optional = true; @@ -238,15 +245,15 @@ return view.extend({ o.value('0', _('Disable')); o.value('1', _('Enable')); - o = s.taboption('dns', form.ListValue, 'dns_mode', '*' + ' ' + _('DNS Mode')); + o = s.taboption('dns', form.ListValue, 'dns_mode', _('DNS Mode')); + o.optional = true; o.placeholder = _('Unmodified'); o.value('redir-host', 'Redir-Host'); o.value('fake-ip', 'Fake-IP'); - o = s.taboption('dns', form.Value, 'fake_ip_range', '*' + ' ' + _('Fake-IP Range')); + o = s.taboption('dns', form.Value, 'fake_ip_range', _('Fake-IP Range')); o.datatype = 'cidr4'; o.placeholder = _('Unmodified'); - o.rmempty = false; o = s.taboption('dns', form.Flag, 'fake_ip_filter', _('Overwrite Fake-IP Filter')); o.rmempty = false; diff --git a/small/luci-app-nikki/htdocs/luci-static/resources/view/nikki/proxy.js b/small/luci-app-nikki/htdocs/luci-static/resources/view/nikki/proxy.js index 4d2cd6717c..42a5a0a7e0 100644 --- a/small/luci-app-nikki/htdocs/luci-static/resources/view/nikki/proxy.js +++ b/small/luci-app-nikki/htdocs/luci-static/resources/view/nikki/proxy.js @@ -132,6 +132,7 @@ return view.extend({ so.rmempty = false; so = o.subsection.option(form.DynamicList, 'ip', 'IP'); + so.datatype = 'ip4addr'; for (const mac in hosts) { const host = hosts[mac]; @@ -142,6 +143,7 @@ return view.extend({ }; so = o.subsection.option(form.DynamicList, 'ip6', 'IP6'); + so.datatype = 'ip6addr'; for (const mac in hosts) { const host = hosts[mac]; @@ -152,6 +154,7 @@ return view.extend({ }; so = o.subsection.option(form.DynamicList, 'mac', 'MAC'); + so.datatype = 'macaddr'; for (const mac in hosts) { const host = hosts[mac]; diff --git a/small/momo/files/momo.init b/small/momo/files/momo.init index 4306aefa4f..1db00cf95b 100644 --- a/small/momo/files/momo.init +++ b/small/momo/files/momo.init @@ -60,9 +60,10 @@ start_service() { config_get dns_inbound_tag "core" "dns_inbound_tag" config_get fake_ip_dns_server_tag "core" "fake_ip_dns_server_tag" ## proxy config - local ipv4_dns_hijack ipv6_dns_hijack tcp_mode udp_mode - config_get ipv4_dns_hijack "proxy" "ipv4_dns_hijack" - config_get ipv6_dns_hijack "proxy" "ipv6_dns_hijack" + local proxy_enabled ipv4_dns_hijack ipv6_dns_hijack tcp_mode udp_mode + config_get_bool proxy_enabled "proxy" "enabled" 0 + config_get_bool ipv4_dns_hijack "proxy" "ipv4_dns_hijack" 0 + config_get_bool ipv6_dns_hijack "proxy" "ipv6_dns_hijack" 0 config_get tcp_mode "proxy" "tcp_mode" config_get udp_mode "proxy" "udp_mode" # get profile @@ -100,11 +101,12 @@ start_service() { return fi # check profile - if [ "$core_only" = 0 ]; then + if [ "$core_only" = 0 ] && [ "$proxy_enabled" = 1 ]; then log "Profile" "Checking..." if [ "$ipv4_dns_hijack" = 1 ] || [ "$ipv6_dns_hijack" = 1 ]; then local dns_port; dns_port=$(jsonfilter -q -i "$RUN_PROFILE_PATH" -e "@['inbounds'][*]" | jsonfilter -q -a -e "@[@['tag']='$dns_inbound_tag']" | jsonfilter -q -a -e "@[@['type']='direct']" | jsonfilter -q -e "@['listen_port']") if [ -z "$dns_port" ]; then + log "Profile" "Check failed." log "Profile" "DNS inbound not found, should be tagged with $dns_inbound_tag and define listen_port." log "App" "Exit." return @@ -113,6 +115,7 @@ start_service() { if [ "$tcp_mode" = "redirect" ]; then local redirect_port; redirect_port=$(jsonfilter -q -i "$RUN_PROFILE_PATH" -e "@['inbounds'][*]" | jsonfilter -q -a -e "@[@['tag']='$redirect_inbound_tag']" | jsonfilter -q -a -e "@[@['type']='redirect']" | jsonfilter -q -e "@['listen_port']") if [ -z "$redirect_port" ]; then + log "Profile" "Check failed." log "Profile" "Redirect inbound not found, should be tagged with $redirect_inbound_tag and define listen_port." log "App" "Exit." return @@ -121,6 +124,7 @@ start_service() { if [ "$tcp_mode" = "tproxy" ] || [ "$udp_mode" = "tproxy" ]; then local tproxy_port; tproxy_port=$(jsonfilter -q -i "$RUN_PROFILE_PATH" -e "@['inbounds'][*]" | jsonfilter -q -a -e "@[@['tag']='$tproxy_inbound_tag']" | jsonfilter -q -a -e "@[@['type']='tproxy']" | jsonfilter -q -e "@['listen_port']") if [ -z "$tproxy_port" ]; then + log "Profile" "Check failed." log "Profile" "TPROXY inbound not found, should be tagged with $tproxy_inbound_tag and define listen_port." log "App" "Exit." return @@ -129,6 +133,7 @@ start_service() { if [ "$tcp_mode" = "tun" ] || [ "$udp_mode" = "tun" ]; then local tun_device; tun_device=$(jsonfilter -q -i "$RUN_PROFILE_PATH" -e "@['inbounds'][*]" | jsonfilter -q -a -e "@[@['tag']='$tun_inbound_tag']" | jsonfilter -q -a -e "@[@['type']='tun']" | jsonfilter -q -e "@['interface_name']") if [ -z "$tun_device" ]; then + log "Profile" "Check failed." log "Profile" "TUN inbound not found, should be tagged with $tun_inbound_tag and define interface_name." log "App" "Exit." return diff --git a/small/momo/files/scripts/include.sh b/small/momo/files/scripts/include.sh index 25249a8daf..09973029dc 100644 --- a/small/momo/files/scripts/include.sh +++ b/small/momo/files/scripts/include.sh @@ -27,8 +27,6 @@ DEBUG_SH="$SH_DIR/debug.sh" ## firewall NFT_DIR="$HOME_DIR/firewall" -RESERVED_IP_NFT="$NFT_DIR/reserved_ip.nft" -RESERVED_IP6_NFT="$NFT_DIR/reserved_ip6.nft" GEOIP_CN_NFT="$NFT_DIR/geoip_cn.nft" GEOIP6_CN_NFT="$NFT_DIR/geoip6_cn.nft" @@ -66,8 +64,6 @@ get_paths() { json_add_string debug_sh "$DEBUG_SH" json_add_string nft_dir "$NFT_DIR" - json_add_string reserved_ip_nft "$RESERVED_IP_NFT" - json_add_string reserved_ip6_nft "$RESERVED_IP6_NFT" json_add_string geoip_cn_nft "$GEOIP_CN_NFT" json_add_string geoip6_cn_nft "$GEOIP6_CN_NFT" diff --git a/small/momo/files/ucode/hijack.ut b/small/momo/files/ucode/hijack.ut index d966cfb491..facd7c1c4f 100644 --- a/small/momo/files/ucode/hijack.ut +++ b/small/momo/files/ucode/hijack.ut @@ -462,19 +462,17 @@ table inet momo { ip daddr @china_ip counter return ip6 daddr @china_ip6 counter return meta nfproto ipv4 meta l4proto . th dport != @proxy_dport {% if (fake_ip_range): %} ip daddr != {{ fake_ip_range }} {% endif %} counter return - meta nfproto ipv6 meta l4proto . th dport != @proxy_dport {% if (fake_ip6_range ): %} ip6 daddr != {{ fake_ip6_range }} {% endif %} counter return + meta nfproto ipv6 meta l4proto . th dport != @proxy_dport {% if (fake_ip6_range): %} ip6 daddr != {{ fake_ip6_range }} {% endif %} counter return meta l4proto { tcp, udp } ip dscp @bypass_dscp {% if (fake_ip_range): %} ip daddr != {{ fake_ip_range }} {% endif %} counter return - meta l4proto { tcp, udp } ip6 dscp @bypass_dscp {% if (fake_ip6_range ): %} ip6 daddr != {{ fake_ip6_range }} {% endif %} counter return + meta l4proto { tcp, udp } ip6 dscp @bypass_dscp {% if (fake_ip6_range): %} ip6 daddr != {{ fake_ip6_range }} {% endif %} counter return meta nfproto @proxy_nfproto jump router_redirect {% endif %} {% if (fake_ip_ping_hijack): %} - {% if (fake_ip_range ): %} + {% if (fake_ip_range): %} icmp type echo-request ip daddr {{ fake_ip_range }} counter redirect - {% endif %} - {% if (fake_ip6_range ): %} + {% if (fake_ip6_range): %} icmpv6 type echo-request ip6 daddr {{ fake_ip6_range }} counter redirect - {% endif %} {% endif %} } @@ -493,9 +491,9 @@ table inet momo { ip daddr @china_ip counter return ip6 daddr @china_ip6 counter return meta nfproto ipv4 meta l4proto . th dport != @proxy_dport {% if (fake_ip_range): %} ip daddr != {{ fake_ip_range }} {% endif %} counter return - meta nfproto ipv6 meta l4proto . th dport != @proxy_dport {% if (fake_ip6_range ): %} ip6 daddr != {{ fake_ip6_range }} {% endif %} counter return + meta nfproto ipv6 meta l4proto . th dport != @proxy_dport {% if (fake_ip6_range): %} ip6 daddr != {{ fake_ip6_range }} {% endif %} counter return meta l4proto { tcp, udp } ip dscp @bypass_dscp {% if (fake_ip_range): %} ip daddr != {{ fake_ip_range }} {% endif %} counter return - meta l4proto { tcp, udp } ip6 dscp @bypass_dscp {% if (fake_ip6_range ): %} ip6 daddr != {{ fake_ip6_range }} {% endif %} counter return + meta l4proto { tcp, udp } ip6 dscp @bypass_dscp {% if (fake_ip6_range): %} ip6 daddr != {{ fake_ip6_range }} {% endif %} counter return {% if (length(dns_hijack_nfproto) > 0): %} meta nfproto @dns_hijack_nfproto meta l4proto { tcp, udp } th dport 53 counter return {% endif %} @@ -536,19 +534,17 @@ table inet momo { ip daddr @china_ip counter return ip6 daddr @china_ip6 counter return meta nfproto ipv4 meta l4proto . th dport != @proxy_dport {% if (fake_ip_range): %} ip daddr != {{ fake_ip_range }} {% endif %} counter return - meta nfproto ipv6 meta l4proto . th dport != @proxy_dport {% if (fake_ip6_range ): %} ip6 daddr != {{ fake_ip6_range }} {% endif %} counter return + meta nfproto ipv6 meta l4proto . th dport != @proxy_dport {% if (fake_ip6_range): %} ip6 daddr != {{ fake_ip6_range }} {% endif %} counter return meta l4proto { tcp, udp } ip dscp @bypass_dscp {% if (fake_ip_range): %} ip daddr != {{ fake_ip_range }} {% endif %} counter return - meta l4proto { tcp, udp } ip6 dscp @bypass_dscp {% if (fake_ip6_range ): %} ip6 daddr != {{ fake_ip6_range }} {% endif %} counter return + meta l4proto { tcp, udp } ip6 dscp @bypass_dscp {% if (fake_ip6_range): %} ip6 daddr != {{ fake_ip6_range }} {% endif %} counter return iifname @lan_inbound_device meta nfproto @proxy_nfproto jump lan_redirect {% endif %} {% if (fake_ip_ping_hijack): %} - {% if (fake_ip_range ): %} + {% if (fake_ip_range): %} icmp type echo-request ip daddr {{ fake_ip_range }} counter redirect - {% endif %} - {% if (fake_ip6_range ): %} + {% if (fake_ip6_range): %} icmpv6 type echo-request ip6 daddr {{ fake_ip6_range }} counter redirect - {% endif %} {% endif %} } @@ -562,9 +558,9 @@ table inet momo { ip daddr @china_ip counter return ip6 daddr @china_ip6 counter return meta nfproto ipv4 meta l4proto . th dport != @proxy_dport {% if (fake_ip_range): %} ip daddr != {{ fake_ip_range }} {% endif %} counter return - meta nfproto ipv6 meta l4proto . th dport != @proxy_dport {% if (fake_ip6_range ): %} ip6 daddr != {{ fake_ip6_range }} {% endif %} counter return + meta nfproto ipv6 meta l4proto . th dport != @proxy_dport {% if (fake_ip6_range): %} ip6 daddr != {{ fake_ip6_range }} {% endif %} counter return meta l4proto { tcp, udp } ip dscp @bypass_dscp {% if (fake_ip_range): %} ip daddr != {{ fake_ip_range }} {% endif %} counter return - meta l4proto { tcp, udp } ip6 dscp @bypass_dscp {% if (fake_ip6_range ): %} ip6 daddr != {{ fake_ip6_range }} {% endif %} counter return + meta l4proto { tcp, udp } ip6 dscp @bypass_dscp {% if (fake_ip6_range): %} ip6 daddr != {{ fake_ip6_range }} {% endif %} counter return {% if (length(dns_hijack_nfproto) > 0): %} meta nfproto @dns_hijack_nfproto meta l4proto { tcp, udp } th dport 53 counter return {% endif %} diff --git a/small/nikki/Makefile b/small/nikki/Makefile index f8510f8155..88ff81716f 100644 --- a/small/nikki/Makefile +++ b/small/nikki/Makefile @@ -2,7 +2,7 @@ include $(TOPDIR)/rules.mk PKG_NAME:=nikki PKG_VERSION:=2025.07.27 -PKG_RELEASE:=1 +PKG_RELEASE:=2 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION) @@ -43,8 +43,6 @@ endef define Package/nikki/conffiles /etc/config/nikki /etc/nikki/mixin.yaml -/etc/nikki/nftables/reserved_ip.nft -/etc/nikki/nftables/reserved_ip6.nft endef define Package/nikki/install @@ -71,8 +69,6 @@ define Package/nikki/install $(INSTALL_BIN) $(CURDIR)/files/scripts/firewall_include.sh $(1)/etc/nikki/scripts/firewall_include.sh $(INSTALL_BIN) $(CURDIR)/files/scripts/debug.sh $(1)/etc/nikki/scripts/debug.sh - $(INSTALL_BIN) $(CURDIR)/files/nftables/reserved_ip.nft $(1)/etc/nikki/nftables/reserved_ip.nft - $(INSTALL_BIN) $(CURDIR)/files/nftables/reserved_ip6.nft $(1)/etc/nikki/nftables/reserved_ip6.nft $(INSTALL_BIN) $(CURDIR)/files/nftables/geoip_cn.nft $(1)/etc/nikki/nftables/geoip_cn.nft $(INSTALL_BIN) $(CURDIR)/files/nftables/geoip6_cn.nft $(1)/etc/nikki/nftables/geoip6_cn.nft diff --git a/small/nikki/files/nftables/reserved_ip.nft b/small/nikki/files/nftables/reserved_ip.nft deleted file mode 100644 index 012938f26a..0000000000 --- a/small/nikki/files/nftables/reserved_ip.nft +++ /dev/null @@ -1,19 +0,0 @@ -#!/usr/sbin/nft -f - -table inet nikki { - set reserved_ip { - type ipv4_addr - flags interval - elements = { - 0.0.0.0/8, - 10.0.0.0/8, - 127.0.0.0/8, - 100.64.0.0/10, - 169.254.0.0/16, - 172.16.0.0/12, - 192.168.0.0/16, - 224.0.0.0/4, - 240.0.0.0/4 - } - } -} diff --git a/small/nikki/files/nftables/reserved_ip6.nft b/small/nikki/files/nftables/reserved_ip6.nft deleted file mode 100644 index 0fb07156e0..0000000000 --- a/small/nikki/files/nftables/reserved_ip6.nft +++ /dev/null @@ -1,23 +0,0 @@ -#!/usr/sbin/nft -f - -table inet nikki { - set reserved_ip6 { - type ipv6_addr - flags interval - elements = { - ::/128, - ::1/128, - ::ffff:0:0/96, - 100::/64, - 64:ff9b::/96, - 2001::/32, - 2001:10::/28, - 2001:20::/28, - 2001:db8::/32, - 2002::/16, - fc00::/7, - fe80::/10, - ff00::/8 - } - } -} diff --git a/small/nikki/files/nikki.conf b/small/nikki/files/nikki.conf index 3ac304dd5a..7e71b121db 100644 --- a/small/nikki/files/nikki.conf +++ b/small/nikki/files/nikki.conf @@ -11,24 +11,11 @@ config config 'config' option 'fast_reload' '0' option 'core_only' '0' -config proxy 'proxy' - option 'enabled' '1' - option 'tcp_mode' 'redirect' - option 'udp_mode' 'tun' - option 'ipv4_dns_hijack' '1' - option 'ipv6_dns_hijack' '1' - option 'ipv4_proxy' '1' - option 'ipv6_proxy' '1' - option 'fake_ip_ping_hijack' '1' - option 'router_proxy' '1' - option 'lan_proxy' '1' - list 'lan_inbound_interface' 'lan' - list 'bypass_dscp' '4' - option 'bypass_china_mainland_ip' '0' - option 'proxy_tcp_dport' '0-65535' - option 'proxy_udp_dport' '0-65535' - option 'tun_timeout' '30' - option 'tun_interval' '1' +config env 'env' + option 'disable_loopback_detector' '0' + option 'disable_quic_go_gso' '0' + option 'disable_quic_go_ecn' '0' + option 'skip_system_ipv6_check' '0' config subscription 'subscription' option 'name' 'default' @@ -74,56 +61,6 @@ config mixin 'mixin' option 'rule_provider' '0' option 'mixin_file_content' '0' -config env 'env' - option 'disable_loopback_detector' '0' - option 'disable_quic_go_gso' '0' - option 'disable_quic_go_ecn' '0' - option 'skip_system_ipv6_check' '0' - -config router_access_control - option 'enabled' '1' - list 'user' 'dnsmasq' - list 'user' 'ftp' - list 'user' 'logd' - list 'user' 'nobody' - list 'user' 'ntp' - list 'user' 'ubus' - list 'group' 'dnsmasq' - list 'group' 'ftp' - list 'group' 'logd' - list 'group' 'nogroup' - list 'group' 'ntp' - list 'group' 'ubus' - list 'cgroup' 'services/adguardhome' - list 'cgroup' 'services/aria2' - list 'cgroup' 'services/dnsmasq' - list 'cgroup' 'services/netbird' - list 'cgroup' 'services/qbittorrent' - list 'cgroup' 'services/sysntpd' - list 'cgroup' 'services/tailscale' - list 'cgroup' 'services/zerotier' - option 'proxy' '0' - -config router_access_control - option 'enabled' '1' - option 'dns' '1' - option 'proxy' '1' - -config lan_access_control - option 'enabled' '1' - option 'dns' '1' - option 'proxy' '1' - -config routing 'routing' - option 'tproxy_fw_mark' '0x80' - option 'tun_fw_mark' '0x81' - option 'tproxy_rule_pref' '1024' - option 'tun_rule_pref' '1025' - option 'tproxy_route_table' '80' - option 'tun_route_table' '81' - option 'cgroup_id' '0x12061206' - option 'cgroup_name' 'nikki' - config authentication option 'enabled' '1' option 'username' 'nikki' @@ -192,6 +129,91 @@ config sniff list 'port' '8443' option 'overwrite_destination' '1' +config proxy 'proxy' + option 'enabled' '1' + option 'tcp_mode' 'redirect' + option 'udp_mode' 'tun' + option 'ipv4_dns_hijack' '1' + option 'ipv6_dns_hijack' '1' + option 'ipv4_proxy' '1' + option 'ipv6_proxy' '1' + option 'fake_ip_ping_hijack' '1' + option 'router_proxy' '1' + option 'lan_proxy' '1' + list 'lan_inbound_interface' 'lan' + list 'reserved_ip' '0.0.0.0/8' + list 'reserved_ip' '10.0.0.0/8' + list 'reserved_ip' '127.0.0.0/8' + list 'reserved_ip' '100.64.0.0/10' + list 'reserved_ip' '169.254.0.0/16' + list 'reserved_ip' '172.16.0.0/12' + list 'reserved_ip' '192.168.0.0/16' + list 'reserved_ip' '224.0.0.0/4' + list 'reserved_ip' '240.0.0.0/4' + list 'reserved_ip6' '::/128' + list 'reserved_ip6' '::1/128' + list 'reserved_ip6' '::ffff:0:0/96' + list 'reserved_ip6' '100::/64' + list 'reserved_ip6' '64:ff9b::/96' + list 'reserved_ip6' '2001::/32' + list 'reserved_ip6' '2001:10::/28' + list 'reserved_ip6' '2001:20::/28' + list 'reserved_ip6' '2001:db8::/32' + list 'reserved_ip6' '2002::/16' + list 'reserved_ip6' 'fc00::/7' + list 'reserved_ip6' 'fe80::/10' + list 'reserved_ip6' 'ff00::/8' + list 'bypass_dscp' '4' + option 'bypass_china_mainland_ip' '0' + option 'proxy_tcp_dport' '0-65535' + option 'proxy_udp_dport' '0-65535' + option 'tun_timeout' '30' + option 'tun_interval' '1' + +config router_access_control + option 'enabled' '1' + list 'user' 'dnsmasq' + list 'user' 'ftp' + list 'user' 'logd' + list 'user' 'nobody' + list 'user' 'ntp' + list 'user' 'ubus' + list 'group' 'dnsmasq' + list 'group' 'ftp' + list 'group' 'logd' + list 'group' 'nogroup' + list 'group' 'ntp' + list 'group' 'ubus' + list 'cgroup' 'services/adguardhome' + list 'cgroup' 'services/aria2' + list 'cgroup' 'services/dnsmasq' + list 'cgroup' 'services/netbird' + list 'cgroup' 'services/qbittorrent' + list 'cgroup' 'services/sysntpd' + list 'cgroup' 'services/tailscale' + list 'cgroup' 'services/zerotier' + option 'proxy' '0' + +config router_access_control + option 'enabled' '1' + option 'dns' '1' + option 'proxy' '1' + +config lan_access_control + option 'enabled' '1' + option 'dns' '1' + option 'proxy' '1' + +config routing 'routing' + option 'tproxy_fw_mark' '0x80' + option 'tun_fw_mark' '0x81' + option 'tproxy_rule_pref' '1024' + option 'tun_rule_pref' '1025' + option 'tproxy_route_table' '80' + option 'tun_route_table' '81' + option 'cgroup_id' '0x12061206' + option 'cgroup_name' 'nikki' + config editor 'editor' config log 'log' diff --git a/small/nikki/files/nikki.init b/small/nikki/files/nikki.init index 1cb213e9d0..4a6554ca64 100644 --- a/small/nikki/files/nikki.init +++ b/small/nikki/files/nikki.init @@ -52,6 +52,13 @@ start_service() { config_get_bool test_profile "config" "test_profile" 0 config_get_bool fast_reload "config" "fast_reload" 0 config_get_bool core_only "config" "core_only" 0 + ## environment variable + local safe_paths disable_loopback_detector disable_quic_go_gso disable_quic_go_ecn skip_system_ipv6_check + config_get safe_paths "env" "safe_paths" + config_get_bool disable_loopback_detector "env" "disable_loopback_detector" 0 + config_get_bool disable_quic_go_gso "env" "disable_quic_go_gso" 0 + config_get_bool disable_quic_go_ecn "env" "disable_quic_go_ecn" 0 + config_get_bool skip_system_ipv6_check "env" "skip_system_ipv6_check" 0 ## mixin config ### overwrite local overwrite_authentication overwrite_tun_dns_hijack overwrite_fake_ip_filter overwrite_hosts overwrite_dns_nameserver overwrite_dns_nameserver_policy overwrite_sniffer_sniff overwrite_sniffer_force_domain_name overwrite_sniffer_ignore_domain_name @@ -67,13 +74,13 @@ start_service() { ### mixin file content local mixin_file_content config_get_bool mixin_file_content "mixin" "mixin_file_content" 0 - ## environment variable - local safe_paths disable_loopback_detector disable_quic_go_gso disable_quic_go_ecn skip_system_ipv6_check - config_get safe_paths "env" "safe_paths" - config_get_bool disable_loopback_detector "env" "disable_loopback_detector" 0 - config_get_bool disable_quic_go_gso "env" "disable_quic_go_gso" 0 - config_get_bool disable_quic_go_ecn "env" "disable_quic_go_ecn" 0 - config_get_bool skip_system_ipv6_check "env" "skip_system_ipv6_check" 0 + ## proxy config + local proxy_enabled ipv4_dns_hijack ipv6_dns_hijack tcp_mode udp_mode + config_get_bool proxy_enabled "proxy" "enabled" 0 + config_get_bool ipv4_dns_hijack "proxy" "ipv4_dns_hijack" 0 + config_get_bool ipv6_dns_hijack "proxy" "ipv6_dns_hijack" 0 + config_get tcp_mode "proxy" "tcp_mode" + config_get udp_mode "proxy" "udp_mode" # get profile local profile_type; profile_type=$(echo "$profile" | cut -d ':' -f 1) local profile_id; profile_id=$(echo "$profile" | cut -d ':' -f 2) @@ -144,6 +151,43 @@ start_service() { ucode -S "$MIXIN_UC" | yq -M -p json -o yaml | yq -M -i ea '... comments="" | . as $item ireduce ({}; . * $item ) | .proxies = .nikki-proxies + .proxies | del(.nikki-proxies) | .rules = .nikki-rules + .rules | del(.nikki-rules)' "$RUN_PROFILE_PATH" "$MIXIN_FILE_PATH" - fi fi + # check profile + if [ "$core_only" = 0 ] && [ "$proxy_enabled" = 1 ]; then + log "Profile" "Checking..." + if [ "$ipv4_dns_hijack" = 1 ] || [ "$ipv6_dns_hijack" = 1 ]; then + if (! yq -M -e 'has("dns") and (.dns | .enable) and (.dns | has("listen"))' "$RUN_PROFILE_PATH"); then + log "Profile" "Check failed." + log "Profile" "DNS should be enabled and listen should be defined." + log "App" "Exit." + return + fi + fi + if [ "$tcp_mode" = "redirect" ]; then + if (! yq -M -e 'has("redir-port")' "$RUN_PROFILE_PATH"); then + log "Profile" "Check failed." + log "Profile" "Redirect Port should be defined." + log "App" "Exit." + return + fi + fi + if [ "$tcp_mode" = "tproxy" ] || [ "$udp_mode" = "tproxy" ]; then + if (! yq -M -e 'has("tproxy-port")' "$RUN_PROFILE_PATH"); then + log "Profile" "Check failed." + log "Profile" "TPROXY Port should be defined." + log "App" "Exit." + return + fi + fi + if [ "$tcp_mode" = "tun" ] || [ "$udp_mode" = "tun" ]; then + if (! yq -M -e 'has("tun") and (.tun | .enable) and (.tun | has("device"))' "$RUN_PROFILE_PATH"); then + log "Profile" "Check failed." + log "Profile" "TUN should be enabled and device should be defined." + log "App" "Exit." + return + fi + fi + log "Profile" "Check passed." + fi # test profile if [ "$test_profile" = 1 ]; then log "Profile" "Testing..." @@ -204,10 +248,6 @@ service_started() { ## app config local core_only config_get_bool core_only "config" "core_only" 0 - ## mixin - ### tun - local tun_device - config_get tun_device "mixin" "tun_device" "nikki" ## proxy config ### general local tcp_mode udp_mode ipv4_proxy ipv6_proxy tun_timeout tun_interval @@ -236,6 +276,7 @@ service_started() { if [ "$tcp_mode" = "tun" ] || [ "$udp_mode" = "tun" ]; then tun_enable=1 fi + local tun_device; tun_device=$(yq -M '.tun.device' "$RUN_PROFILE_PATH") if [ "$core_only" = 0 ]; then # proxy log "Proxy" "Enabled." @@ -243,11 +284,9 @@ service_started() { if [ "$tun_enable" = 1 ]; then log "Proxy" "Waiting for tun device online within $tun_timeout seconds..." while [ "$tun_timeout" -gt 0 ]; do - if (ip link show dev "$tun_device" > /dev/null 2>&1); then - if [ "$(ip -json addr show dev "$tun_device" | tun_device="$tun_device" yq -M '.[] | select(.ifname = strenv(tun_device)) | .addr_info | length')" -gt 0 ]; then - log "Proxy" "TUN device is online." - break - fi + if (ip -j link show dev "$tun_device" | jsonfilter -q -e "@[@['flags'][@='UP']]" > /dev/null 2>&1); then + log "Proxy" "TUN device is online." + break fi tun_timeout=$((tun_timeout - tun_interval)) sleep "$tun_interval" @@ -354,11 +393,11 @@ cleanup() { # delete hijack nft delete table inet nikki > /dev/null 2>&1 local handles handle - handles=$(nft --json list table inet fw4 | yq -M '.nftables[] | select(has("rule")) | .rule | select(.chain == "input" and .comment == "nikki") | .handle') + handles=$(nft --json list table inet fw4 | jsonfilter -q -e "@['nftables'][*]['rule']" | jsonfilter -q -a -e "@[@['chain']='input']" | jsonfilter -q -a -e "@[@['comment']='nikki']" | jsonfilter -q -a -e "@[*]['handle']") for handle in $handles; do nft delete rule inet fw4 input handle "$handle" done - handles=$(nft --json list table inet fw4 | yq -M '.nftables[] | select(has("rule")) | .rule | select(.chain == "forward" and .comment == "nikki") | .handle') + handles=$(nft --json list table inet fw4 | jsonfilter -q -e "@['nftables'][*]['rule']" | jsonfilter -q -a -e "@[@['chain']='forward']" | jsonfilter -q -a -e "@[@['comment']='nikki']" | jsonfilter -q -a -e "@[*]['handle']") for handle in $handles; do nft delete rule inet fw4 forward handle "$handle" done diff --git a/small/nikki/files/scripts/debug.sh b/small/nikki/files/scripts/debug.sh index aaecb74777..2bcfebe6bf 100644 --- a/small/nikki/files/scripts/debug.sh +++ b/small/nikki/files/scripts/debug.sh @@ -49,8 +49,8 @@ const config = uci.get_all("nikki"); const result = {}; for (let section_id in config) { - const section = config[section_id]; - const section_type = section[".type"]; + const section = config[section_id]; + const section_type = section[".type"]; if (result[section_type] == null) { result[section_type] = []; } diff --git a/small/nikki/files/scripts/firewall_include.sh b/small/nikki/files/scripts/firewall_include.sh index f270f0e425..2a237de4b9 100644 --- a/small/nikki/files/scripts/firewall_include.sh +++ b/small/nikki/files/scripts/firewall_include.sh @@ -9,10 +9,10 @@ config_get_bool core_only "config" "core_only" 0 config_get_bool proxy_enabled "proxy" "enabled" 0 config_get tcp_mode "proxy" "tcp_mode" config_get udp_mode "proxy" "udp_mode" -config_get tun_device "mixin" "tun_device" if [ "$enabled" = 1 ] && [ "$core_only" = 0 ] && [ "$proxy_enabled" = 1 ]; then if [ "$tcp_mode" = "tun" ] || [ "$udp_mode" = "tun" ]; then + tun_device=$(yq -M '.tun.device' "$RUN_PROFILE_PATH") nft insert rule inet fw4 input iifname "$tun_device" counter accept comment "nikki" nft insert rule inet fw4 forward oifname "$tun_device" counter accept comment "nikki" nft insert rule inet fw4 forward iifname "$tun_device" counter accept comment "nikki" diff --git a/small/nikki/files/scripts/include.sh b/small/nikki/files/scripts/include.sh index 918c139026..bff99a376b 100644 --- a/small/nikki/files/scripts/include.sh +++ b/small/nikki/files/scripts/include.sh @@ -36,8 +36,6 @@ FIREWALL_INCLUDE_SH="$SH_DIR/firewall_include.sh" # nftables NFT_DIR="$HOME_DIR/nftables" -RESERVED_IP_NFT="$NFT_DIR/reserved_ip.nft" -RESERVED_IP6_NFT="$NFT_DIR/reserved_ip6.nft" GEOIP_CN_NFT="$NFT_DIR/geoip_cn.nft" GEOIP6_CN_NFT="$NFT_DIR/geoip6_cn.nft" diff --git a/small/nikki/files/uci-defaults/migrate.sh b/small/nikki/files/uci-defaults/migrate.sh index f17dff2c2f..afa3e3b162 100644 --- a/small/nikki/files/uci-defaults/migrate.sh +++ b/small/nikki/files/uci-defaults/migrate.sh @@ -156,6 +156,35 @@ uci show nikki | grep -o -E 'nikki.@lan_access_control\[[[:digit:]]+\]=lan_acces [ -z "$lan_access_control_dns" ] && uci set "$lan_access_control.dns=$lan_access_control_proxy" done +# since v1.24.0 +proxy_reserved_ip=$(uci -q get nikki.proxy.reserved_ip); [ -z "$proxy_reserved_ip" ] && { + uci add_list nikki.proxy.reserved_ip=0.0.0.0/8 + uci add_list nikki.proxy.reserved_ip=10.0.0.0/8 + uci add_list nikki.proxy.reserved_ip=127.0.0.0/8 + uci add_list nikki.proxy.reserved_ip=100.64.0.0/10 + uci add_list nikki.proxy.reserved_ip=169.254.0.0/16 + uci add_list nikki.proxy.reserved_ip=172.16.0.0/12 + uci add_list nikki.proxy.reserved_ip=192.168.0.0/16 + uci add_list nikki.proxy.reserved_ip=224.0.0.0/4 + uci add_list nikki.proxy.reserved_ip=240.0.0.0/4 +} + +proxy_reserved_ip6=$(uci -q get nikki.proxy.reserved_ip6); [ -z "$proxy_reserved_ip6" ] && { + uci add_list nikki.proxy.reserved_ip6=::/128 + uci add_list nikki.proxy.reserved_ip6=::1/128 + uci add_list nikki.proxy.reserved_ip6=::ffff:0:0/96 + uci add_list nikki.proxy.reserved_ip6=100::/64 + uci add_list nikki.proxy.reserved_ip6=64:ff9b::/96 + uci add_list nikki.proxy.reserved_ip6=2001::/32 + uci add_list nikki.proxy.reserved_ip6=2001:10::/28 + uci add_list nikki.proxy.reserved_ip6=2001:20::/28 + uci add_list nikki.proxy.reserved_ip6=2001:db8::/32 + uci add_list nikki.proxy.reserved_ip6=2002::/16 + uci add_list nikki.proxy.reserved_ip6=fc00::/7 + uci add_list nikki.proxy.reserved_ip6=fe80::/10 + uci add_list nikki.proxy.reserved_ip6=ff00::/8 +} + # commit uci commit nikki diff --git a/small/nikki/files/ucode/hijack.ut b/small/nikki/files/ucode/hijack.ut index dd3744378c..15c1487064 100644 --- a/small/nikki/files/ucode/hijack.ut +++ b/small/nikki/files/ucode/hijack.ut @@ -5,7 +5,7 @@ import { cursor } from 'uci'; import { connect } from 'ubus'; - import { uci_bool, uci_array, get_cgroups_version, get_users, get_groups, get_cgroups } from '/etc/nikki/ucode/include.uc'; + import { uci_bool, uci_array, get_cgroups_version, get_users, get_groups, get_cgroups, load_profile } from '/etc/nikki/ucode/include.uc'; const cgroups_version = get_cgroups_version(); @@ -16,16 +16,18 @@ const uci = cursor(); const ubus = connect(); - uci.load('nikki'); + const profile = load_profile(); - const redir_port = uci.get('nikki', 'mixin', 'redir_port'); - const tproxy_port = uci.get('nikki', 'mixin', 'tproxy_port'); + const redir_port = profile['redir-port']; + const tproxy_port = profile['tproxy-port']; - const dns_listen = uci.get('nikki', 'mixin', 'dns_listen'); + const dns_listen = profile['dns']['listen']; const dns_port = substr(dns_listen, rindex(dns_listen, ':') + 1); - const fake_ip_range = uci.get('nikki', 'mixin', 'fake_ip_range'); + const fake_ip_range = profile['dns']['fake-ip-range']; - const tun_device = uci.get('nikki', 'mixin', 'tun_device'); + const tun_device = profile['tun']['device']; + + uci.load('nikki'); const tcp_mode = uci.get('nikki', 'proxy', 'tcp_mode'); const udp_mode = uci.get('nikki', 'proxy', 'udp_mode'); @@ -68,6 +70,8 @@ push(lan_access_control, access_control); }); + const reserved_ip = uci_array(uci.get('momo', 'proxy', 'reserved_ip')); + const reserved_ip6 = uci_array(uci.get('momo', 'proxy', 'reserved_ip6')); const bypass_dscp = uci_array(uci.get('nikki', 'proxy', 'bypass_dscp')); const bypass_china_mainland_ip = uci_bool(uci.get('nikki', 'proxy', 'bypass_china_mainland_ip')); const proxy_tcp_dport = split((uci.get('nikki', 'proxy', 'proxy_tcp_dport') ?? '0-65535'), ' '); @@ -128,12 +132,22 @@ table inet nikki { type ipv4_addr flags interval auto-merge + {% if (length(reserved_ip) > 0): %} + elements = { + {{ join(', ', reserved_ip) }} + } + {% endif %} } set reserved_ip6 { type ipv6_addr flags interval auto-merge + {% if (length(reserved_ip6) > 0): %} + elements = { + {{ join(', ', reserved_ip6) }} + } + {% endif %} } set lan_inbound_device { @@ -180,6 +194,7 @@ table inet nikki { } {% if (router_proxy): %} + {% if (length(dns_hijack_nfproto) > 0): %} chain router_dns_hijack { {% for (let access_control in router_access_control): %} {% if (access_control['enabled']): %} @@ -205,7 +220,9 @@ table inet nikki { {% endif %} {% endfor %} } + {% endif %} + {% if (tcp_mode == 'redirect'): %} chain router_redirect { {% for (let access_control in router_access_control): %} {% if (access_control['enabled']): %} @@ -231,7 +248,9 @@ table inet nikki { {% endif %} {% endfor %} } + {% endif %} + {% if (tcp_mode == 'tproxy' || udp_mode == 'tproxy'): %} chain router_tproxy { {% for (let access_control in router_access_control): %} {% if (access_control['enabled']): %} @@ -257,7 +276,9 @@ table inet nikki { {% endif %} {% endfor %} } + {% endif %} + {% if (tcp_mode == 'tun' || udp_mode == 'tun'): %} chain router_tun { {% for (let access_control in router_access_control): %} {% if (access_control['enabled']): %} @@ -284,8 +305,10 @@ table inet nikki { {% endfor %} } {% endif %} + {% endif %} {% if (lan_proxy): %} + {% if (length(dns_hijack_nfproto) > 0): %} chain lan_dns_hijack { {% for (let access_control in lan_access_control): %} {% if (access_control['enabled']): %} @@ -309,7 +332,9 @@ table inet nikki { {% endif %} {% endfor %} } + {% endif %} + {% if (tcp_mode == 'redirect'): %} chain lan_redirect { {% for (let access_control in lan_access_control): %} {% if (access_control['enabled']): %} @@ -333,7 +358,9 @@ table inet nikki { {% endif %} {% endfor %} } + {% endif %} + {% if (tcp_mode == 'tproxy' || udp_mode == 'tproxy'): %} chain lan_tproxy { {% for (let access_control in lan_access_control): %} {% if (access_control['enabled']): %} @@ -357,7 +384,9 @@ table inet nikki { {% endif %} {% endfor %} } + {% endif %} + {% if (tcp_mode == 'tun' || udp_mode == 'tun'): %} chain lan_tun { {% for (let access_control in lan_access_control): %} {% if (access_control['enabled']): %} @@ -382,6 +411,7 @@ table inet nikki { {% endfor %} } {% endif %} + {% endif %} {% if (router_proxy): %} chain nat_output { @@ -399,14 +429,16 @@ table inet nikki { ip6 daddr @reserved_ip6 counter return ip daddr @china_ip counter return ip6 daddr @china_ip6 counter return - meta nfproto ipv4 meta l4proto . th dport != @proxy_dport ip daddr != {{ fake_ip_range }} counter return + meta nfproto ipv4 meta l4proto . th dport != @proxy_dport {% if (fake_ip_range): %} ip daddr != {{ fake_ip_range }} {% endif %} counter return meta nfproto ipv6 meta l4proto . th dport != @proxy_dport counter return - meta l4proto { tcp, udp } ip dscp @bypass_dscp ip daddr != {{ fake_ip_range }} counter return + meta l4proto { tcp, udp } ip dscp @bypass_dscp {% if (fake_ip_range): %} ip daddr != {{ fake_ip_range }} {% endif %} counter return meta l4proto { tcp, udp } ip6 dscp @bypass_dscp counter return meta nfproto @proxy_nfproto jump router_redirect {% endif %} {% if (fake_ip_ping_hijack): %} - ip protocol icmp icmp type echo-request ip daddr {{ fake_ip_range }} counter redirect + {% if (fake_ip_range ): %} + icmp type echo-request ip daddr {{ fake_ip_range }} counter redirect + {% endif %} {% endif %} } @@ -423,9 +455,9 @@ table inet nikki { ip6 daddr @reserved_ip6 counter return ip daddr @china_ip counter return ip6 daddr @china_ip6 counter return - meta nfproto ipv4 meta l4proto . th dport != @proxy_dport ip daddr != {{ fake_ip_range }} counter return + meta nfproto ipv4 meta l4proto . th dport != @proxy_dport {% if (fake_ip_range): %} ip daddr != {{ fake_ip_range }} {% endif %} counter return meta nfproto ipv6 meta l4proto . th dport != @proxy_dport counter return - meta l4proto { tcp, udp } ip dscp @bypass_dscp ip daddr != {{ fake_ip_range }} counter return + meta l4proto { tcp, udp } ip dscp @bypass_dscp {% if (fake_ip_range): %} ip daddr != {{ fake_ip_range }} {% endif %} counter return meta l4proto { tcp, udp } ip6 dscp @bypass_dscp counter return meta nfproto @dns_hijack_nfproto meta l4proto { tcp, udp } th dport 53 counter return {% if (tcp_mode == 'tproxy'): %} @@ -462,14 +494,16 @@ table inet nikki { ip6 daddr @reserved_ip6 counter return ip daddr @china_ip counter return ip6 daddr @china_ip6 counter return - meta nfproto ipv4 meta l4proto . th dport != @proxy_dport ip daddr != {{ fake_ip_range }} counter return + meta nfproto ipv4 meta l4proto . th dport != @proxy_dport {% if (fake_ip_range): %} ip daddr != {{ fake_ip_range }} {% endif %} counter return meta nfproto ipv6 meta l4proto . th dport != @proxy_dport counter return - meta l4proto { tcp, udp } ip dscp @bypass_dscp ip daddr != {{ fake_ip_range }} counter return + meta l4proto { tcp, udp } ip dscp @bypass_dscp {% if (fake_ip_range): %} ip daddr != {{ fake_ip_range }} {% endif %} counter return meta l4proto { tcp, udp } ip6 dscp @bypass_dscp counter return iifname @lan_inbound_device meta nfproto @proxy_nfproto jump lan_redirect {% endif %} {% if (fake_ip_ping_hijack): %} - ip protocol icmp icmp type echo-request ip daddr {{ fake_ip_range }} counter redirect + {% if (fake_ip_range): %} + icmp type echo-request ip daddr {{ fake_ip_range }} counter redirect + {% endif %} {% endif %} } @@ -481,9 +515,9 @@ table inet nikki { ip6 daddr @reserved_ip6 counter return ip daddr @china_ip counter return ip6 daddr @china_ip6 counter return - meta nfproto ipv4 meta l4proto . th dport != @proxy_dport ip daddr != {{ fake_ip_range }} counter return + meta nfproto ipv4 meta l4proto . th dport != @proxy_dport {% if (fake_ip_range): %} ip daddr != {{ fake_ip_range }} {% endif %} counter return meta nfproto ipv6 meta l4proto . th dport != @proxy_dport counter return - meta l4proto { tcp, udp } ip dscp @bypass_dscp ip daddr != {{ fake_ip_range }} counter return + meta l4proto { tcp, udp } ip dscp @bypass_dscp {% if (fake_ip_range): %} ip daddr != {{ fake_ip_range }} {% endif %} counter return meta l4proto { tcp, udp } ip6 dscp @bypass_dscp counter return meta nfproto @dns_hijack_nfproto meta l4proto { tcp, udp } th dport 53 counter return {% if (tcp_mode == 'tproxy'): %} @@ -500,9 +534,6 @@ table inet nikki { {% endif %} } -include "/etc/nikki/nftables/reserved_ip.nft" -include "/etc/nikki/nftables/reserved_ip6.nft" - {% if (bypass_china_mainland_ip): %} include "/etc/nikki/nftables/geoip_cn.nft" include "/etc/nikki/nftables/geoip6_cn.nft" diff --git a/small/nikki/files/ucode/include.uc b/small/nikki/files/ucode/include.uc index a6411f2e45..97f824f12f 100644 --- a/small/nikki/files/ucode/include.uc +++ b/small/nikki/files/ucode/include.uc @@ -74,4 +74,14 @@ export function get_cgroups() { } } return result; +}; + +export function load_profile() { + let result = {}; + const process = popen('yq -M -p yaml -o json /etc/nikki/run/config.yaml'); + if (process) { + result = json(process); + process.close(); + } + return result; }; \ No newline at end of file diff --git a/small/nikki/files/ucode/mixin.uc b/small/nikki/files/ucode/mixin.uc index e71657338a..9d17cf57f7 100644 --- a/small/nikki/files/ucode/mixin.uc +++ b/small/nikki/files/ucode/mixin.uc @@ -51,26 +51,24 @@ if (uci_bool(uci.get('nikki', 'mixin', 'authentication'))) { } config['tun'] = {}; -if (uci.get('nikki', 'proxy', 'tcp_mode') == 'tun' || uci.get('nikki', 'proxy', 'udp_mode') == 'tun') { - config['tun']['enable'] = true; +config['tun']['enable'] = uci_bool(uci.get('nikki', 'mixin', 'tun_enabled')); +config['tun']['device'] = uci.get('nikki', 'mixin', 'tun_device'); +config['tun']['stack'] = uci.get('nikki', 'mixin', 'tun_stack'); +config['tun']['mtu'] = uci_int(uci.get('nikki', 'mixin', 'tun_mtu')); +config['tun']['gso'] = uci_bool(uci.get('nikki', 'mixin', 'tun_gso')); +config['tun']['gso-max-size'] = uci_int(uci.get('nikki', 'mixin', 'tun_gso_max_size')); +config['tun']['endpoint-independent-nat'] = uci_bool(uci.get('nikki', 'mixin', 'tun_endpoint_independent_nat')); +if (uci_bool(uci.get('nikki', 'mixin', 'tun_dns_hijack'))) { + config['tun']['dns-hijack'] = uci_array(uci.get('nikki', 'mixin', 'tun_dns_hijacks')); +} +if (uci_bool(uci.get('nikki', 'proxy', 'enabled'))) { config['tun']['auto-route'] = false; config['tun']['auto-redirect'] = false; config['tun']['auto-detect-interface'] = false; - config['tun']['device'] = uci.get('nikki', 'mixin', 'tun_device'); - config['tun']['stack'] = uci.get('nikki', 'mixin', 'tun_stack'); - config['tun']['mtu'] = uci_int(uci.get('nikki', 'mixin', 'tun_mtu')); - config['tun']['gso'] = uci_bool(uci.get('nikki', 'mixin', 'tun_gso')); - config['tun']['gso-max-size'] = uci_int(uci.get('nikki', 'mixin', 'tun_gso_max_size')); - config['tun']['endpoint-independent-nat'] = uci_bool(uci.get('nikki', 'mixin', 'tun_endpoint_independent_nat')); - if (uci_bool(uci.get('nikki', 'mixin', 'tun_dns_hijack'))) { - config['tun']['dns-hijack'] = uci_array(uci.get('nikki', 'mixin', 'tun_dns_hijacks')); - } -} else { - config['tun']['enable'] = false; } config['dns'] = {}; -config['dns']['enable'] = true; +config['dns']['enable'] = uci_bool(uci.get('nikki', 'mixin', 'dns_enabled')); config['dns']['listen'] = uci.get('nikki', 'mixin', 'dns_listen'); config['dns']['ipv6'] = uci_bool(uci.get('nikki', 'mixin', 'dns_ipv6')); config['dns']['enhanced-mode'] = uci.get('nikki', 'mixin', 'dns_mode'); @@ -182,7 +180,7 @@ if (uci_bool(uci.get('nikki', 'mixin', 'rule'))) { } const geoip_format = uci.get('nikki', 'mixin', 'geoip_format'); -config['geodata-mode'] = geoip_format == null ? null : geoip_format == 'dat'; +config['geodata-mode'] = geoip_format == null ? null : geoip_format == 'dat'; config['geodata-loader'] = uci.get('nikki', 'mixin', 'geodata_loader'); config['geox-url'] = {}; config['geox-url']['geosite'] = uci.get('nikki', 'mixin', 'geosite_url'); diff --git a/small/v2ray-geodata/Makefile b/small/v2ray-geodata/Makefile index b456a2701f..32ac757e6e 100644 --- a/small/v2ray-geodata/Makefile +++ b/small/v2ray-geodata/Makefile @@ -21,13 +21,13 @@ define Download/geoip HASH:=54761d8691a5756fdb08d2cd4d0a9c889dbaab786e1cf758592e09fb00377f53 endef -GEOSITE_VER:=20250814002625 +GEOSITE_VER:=20250819114505 GEOSITE_FILE:=dlc.dat.$(GEOSITE_VER) define Download/geosite URL:=https://github.com/v2fly/domain-list-community/releases/download/$(GEOSITE_VER)/ URL_FILE:=dlc.dat FILE:=$(GEOSITE_FILE) - HASH:=01dae2a9c31b5c74ba7e54d8d51e0060688ed22da493eaf09f6eeeec89db395e + HASH:=0388dba07e0567e5f35e728f595be0e6ee8b98dcddacd15745499ddcf58cbfa8 endef GEOSITE_IRAN_VER:=202508180044 diff --git a/v2rayn/package-rhel.sh b/v2rayn/package-rhel.sh index 2bfe1ad221..e852d17487 100644 --- a/v2rayn/package-rhel.sh +++ b/v2rayn/package-rhel.sh @@ -1,16 +1,16 @@ #!/usr/bin/env bash set -euo pipefail -# ===== Require Red Hat Enterprise Linux / Rocky Linux / AlmaLinux / CentOS Stream ======= +# ===== Require Red Hat Enterprise Linux/RockyLinux/AlmaLinux/CentOS OR Ubuntu/Debian ==== if [[ -r /etc/os-release ]]; then . /etc/os-release case "$ID" in - rhel|rocky|almalinux|centos) + rhel|rocky|almalinux|centos|ubuntu|debian) echo "[OK] Detected supported system: $NAME $VERSION_ID" ;; *) echo "[ERROR] Unsupported system: $NAME ($ID)." - echo "This script only supports Red Hat Enterprise Linux / Rocky Linux / AlmaLinux / CentOS Stream." + echo "This script only supports Red Hat Enterprise Linux/RockyLinux/AlmaLinux/CentOS or Ubuntu/Debian." exit 1 ;; esac @@ -24,8 +24,10 @@ VERSION_ARG="${1:-}" # Pass version number like 7.13.8, or leave empty WITH_CORE="both" # Default: bundle both xray+sing-box AUTOSTART=0 # 1 = enable system-wide autostart (/etc/xdg/autostart) FORCE_NETCORE=0 # --netcore => skip archive bundle, use separate downloads +ARCH_OVERRIDE="" # --arch x64|arm64|all (optional compile target) +BUILD_FROM="" # --buildfrom 1|2|3 to select channel non-interactively -# If the first argument starts with --, don’t treat it as version number +# If the first argument starts with --, do not treat it as a version number if [[ "${VERSION_ARG:-}" == --* ]]; then VERSION_ARG="" fi @@ -37,28 +39,109 @@ while [[ $# -gt 0 ]]; do case "$1" in --with-core) WITH_CORE="${2:-both}"; shift 2;; --autostart) AUTOSTART=1; shift;; - --xray-ver) XRAY_VER="${2:-}"; shift 2;; # Specify xray version (optional) - --singbox-ver) SING_VER="${2:-}"; shift 2;; # Specify sing-box version (optional) - --netcore) FORCE_NETCORE=1; shift;; # NEW: force old mode (no bundle zip) + --xray-ver) XRAY_VER="${2:-}"; shift 2;; + --singbox-ver) SING_VER="${2:-}"; shift 2;; + --netcore) FORCE_NETCORE=1; shift;; + --arch) ARCH_OVERRIDE="${2:-}"; shift 2;; + --buildfrom) BUILD_FROM="${2:-}"; shift 2;; *) if [[ -z "${VERSION_ARG:-}" ]]; then VERSION_ARG="$1"; fi shift;; esac done -# ===== Environment check =============================================================== -arch="$(uname -m)" -[[ "$arch" == "aarch64" || "$arch" == "x86_64" ]] || { echo "Only supports aarch64 / x86_64"; exit 1; } +# Conflict: version number AND --buildfrom cannot be used together +if [[ -n "${VERSION_ARG:-}" && -n "${BUILD_FROM:-}" ]]; then + echo "[ERROR] You cannot specify both an explicit version and --buildfrom at the same time." + echo " Provide either a version (e.g. 7.14.0) OR --buildfrom 1|2|3." + exit 1 +fi + +# ===== Environment check + Dependencies ======================================== +host_arch="$(uname -m)" +[[ "$host_arch" == "aarch64" || "$host_arch" == "x86_64" ]] || { echo "Only supports aarch64 / x86_64"; exit 1; } + +install_ok=0 +case "$ID" in + # ------------------------------ RHEL family (UNCHANGED) ------------------------------ + rhel|rocky|almalinux|centos) + if command -v dnf >/dev/null 2>&1; then + sudo dnf -y install dotnet-sdk-8.0 rpm-build rpmdevtools curl unzip tar rsync || \ + sudo dnf -y install dotnet-sdk rpm-build rpmdevtools curl unzip tar rsync + install_ok=1 + elif command -v yum >/dev/null 2>&1; then + sudo yum -y install dotnet-sdk-8.0 rpm-build rpmdevtools curl unzip tar rsync || \ + sudo yum -y install dotnet-sdk rpm-build rpmdevtools curl unzip tar rsync + install_ok=1 + fi + ;; + # ------------------------------ Ubuntu ---------------------------------------------- + ubuntu) + sudo apt-get update + # Ensure 'universe' (Ubuntu) to get 'rpm' + if ! apt-cache policy | grep -q '^500 .*ubuntu.com/ubuntu.* universe'; then + sudo apt-get -y install software-properties-common || true + sudo add-apt-repository -y universe || true + sudo apt-get update + fi + # Base tools + rpm (provides rpmbuild) + sudo apt-get -y install curl unzip tar rsync rpm || true + # Cross-arch binutils so strip matches target arch + objdump for brp scripts + sudo apt-get -y install binutils binutils-x86-64-linux-gnu binutils-aarch64-linux-gnu || true + # rpmbuild presence check + if ! command -v rpmbuild >/dev/null 2>&1; then + echo "[ERROR] 'rpmbuild' not found after installing 'rpm'." + echo " Please ensure the 'rpm' package is available from your repos (universe on Ubuntu)." + exit 1 + fi + # .NET SDK 8 (best effort via apt) + if ! command -v dotnet >/dev/null 2>&1; then + sudo apt-get -y install dotnet-sdk-8.0 || true + sudo apt-get -y install dotnet-sdk-8 || true + sudo apt-get -y install dotnet-sdk || true + fi + install_ok=1 + ;; + # ------------------------------ Debian (KEEP, with local dotnet install) ------------ + debian) + sudo apt-get update + # Base tools + rpm (provides rpmbuild on Debian) + objdump/strip + sudo apt-get -y install curl unzip tar rsync rpm binutils || true + # rpmbuild presence check + if ! command -v rpmbuild >/dev/null 2>&1; then + echo "[ERROR] 'rpmbuild' not found after installing 'rpm'." + echo " Please ensure 'rpm' is available from Debian repos." + exit 1 + fi + # Try apt for dotnet; fallback to official installer into $HOME/.dotnet + if ! command -v dotnet >/dev/null 2>&1; then + echo "[INFO] 'dotnet' not found. Installing .NET 8 SDK locally to \$HOME/.dotnet ..." + tmp="$(mktemp -d)"; trap '[[ -n "${tmp:-}" ]] && rm -rf "$tmp"' RETURN + curl -fsSL https://dot.net/v1/dotnet-install.sh -o "$tmp/dotnet-install.sh" + bash "$tmp/dotnet-install.sh" --channel 8.0 --install-dir "$HOME/.dotnet" + export PATH="$HOME/.dotnet:$HOME/.dotnet/tools:$PATH" + export DOTNET_ROOT="$HOME/.dotnet" + if ! command -v dotnet >/dev/null 2>&1; then + echo "[ERROR] dotnet installation failed." + exit 1 + fi + fi + install_ok=1 + ;; +esac + +if [[ "$install_ok" -ne 1 ]]; then + echo "[WARN] Could not auto-install dependencies for '$ID'. Make sure these are available:" + echo " dotnet-sdk 8.x, curl, unzip, tar, rsync, rpm, rpmdevtools, rpm-build (on RPM-based distros)" +fi -# Dependencies (packaging shouldn’t be run as root, but this line needs sudo) -sudo dnf -y install dotnet-sdk-8.0 rpm-build rpmdevtools curl unzip tar || sudo dnf -y install dotnet-sdk command -v curl >/dev/null # Root directory = the script's location SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)" cd "$SCRIPT_DIR" -# Git submodules (tolerant) +# Git submodules (best effort) if [[ -f .gitmodules ]]; then git submodule sync --recursive || true git submodule update --init --recursive || true @@ -72,25 +155,36 @@ fi [[ -f "$PROJECT" ]] || { echo "v2rayN.Desktop.csproj not found"; exit 1; } # ===== Resolve GUI version & auto checkout ============================================ -# Rules: -# - If VERSION_ARG provided: try to checkout that tag (vX.Y.Z or X.Y.Z). If not found, ask which channel (Latest vs Pre-release), -# default to Latest, then fetch the chosen channel's latest tag and checkout. -# - If VERSION_ARG not provided: ask the channel first (default Latest), then checkout to that tag. -# - If not a git repo, warn and continue without switching (keep current branch). -VERSION="" # final GUI version string without 'v' prefix +VERSION="" choose_channel() { - # Print menu to stderr first, then read from stdin; only echo the chosen token to stdout. + # If --buildfrom provided, map it directly and skip interaction. + if [[ -n "${BUILD_FROM:-}" ]]; then + case "$BUILD_FROM" in + 1) echo "latest"; return 0;; + 2) echo "prerelease"; return 0;; + 3) echo "keep"; return 0;; + *) echo "[ERROR] Invalid --buildfrom value: ${BUILD_FROM}. Use 1|2|3." >&2; exit 1;; + esac + fi + + # Print menu to stderr and read from /dev/tty so stdout only carries the token. local ch="latest" sel="" if [[ -t 0 ]]; then - >&2 echo "[?] Choose v2rayN release channel:" - >&2 echo " 1) Latest (stable) [default]" - >&2 echo " 2) Pre-release (preview)" - read -r -p "Enter 1 or 2 (default 1): " sel - case "${sel:-}" in - 2) ch="prerelease" ;; - *) ch="latest" ;; - esac + echo "[?] Choose v2rayN release channel:" >&2 + echo " 1) Latest (stable) [default]" >&2 + echo " 2) Pre-release (preview)" >&2 + echo " 3) Keep current (do nothing)" >&2 + printf "Enter 1, 2 or 3 [default 1]: " >&2 + if read -r sel /dev/null 2>&1; then + tag="$(printf '%s' "$json" \ + | jq -r '[.[] | select(.prerelease==true)][0].tag_name' 2>/dev/null \ + | sed 's/^v//')" || true + fi + + # 2) Fallback to sed/grep only + if [[ -z "${tag:-}" || "${tag:-}" == "null" ]]; then + tag="$(printf '%s' "$json" \ + | tr '\n' ' ' \ + | sed 's/},[[:space:]]*{/\n/g' \ + | grep -m1 -E '"prerelease"[[:space:]]*:[[:space:]]*true' \ + | grep -Eo '"tag_name"[[:space:]]*:[[:space:]]*"v?[^"]+"' \ + | head -n1 \ + | sed -E 's/.*"tag_name"[[:space:]]*:[[:space:]]*"v?([^"]+)".*/\1/')" || true + fi + + [[ -n "${tag:-}" && "${tag:-}" != "null" ]] || return 1 + printf '%s\n' "$tag" } git_try_checkout() { # Try a series of refs and checkout when found. - # Args: version-like string (may contain leading 'v') local want="$1" ref="" if git rev-parse --git-dir >/dev/null 2>&1; then git fetch --tags --force --prune --depth=1 || true @@ -147,10 +259,51 @@ if git rev-parse --git-dir >/dev/null 2>&1; then else echo "[WARN] Tag '${VERSION_ARG}' not found." ch="$(choose_channel)" + if [[ "$ch" == "keep" ]]; then + echo "[*] Keep current repository state (no checkout)." + if git describe --tags --abbrev=0 >/dev/null 2>&1; then + VERSION="$(git describe --tags --abbrev=0)" + else + VERSION="0.0.0+git" + fi + VERSION="${VERSION#v}" + else + echo "[*] Resolving ${ch} tag from GitHub releases..." + tag="" + if [[ "$ch" == "prerelease" ]]; then + tag="$(get_latest_tag_prerelease || true)" + if [[ -z "$tag" ]]; then + echo "[WARN] Failed to resolve prerelease tag, falling back to latest." + tag="$(get_latest_tag_latest || true)" + fi + else + tag="$(get_latest_tag_latest || true)" + fi + [[ -n "$tag" ]] || { echo "[ERROR] Failed to resolve latest tag for channel '${ch}'."; exit 1; } + echo "[*] Latest tag for '${ch}': ${tag}" + git_try_checkout "$tag" || { echo "[ERROR] Failed to checkout '${tag}'."; exit 1; } + VERSION="${tag#v}" + fi + fi + else + ch="$(choose_channel)" + if [[ "$ch" == "keep" ]]; then + echo "[*] Keep current repository state (no checkout)." + if git describe --tags --abbrev=0 >/dev/null 2>&1; then + VERSION="$(git describe --tags --abbrev=0)" + else + VERSION="0.0.0+git" + fi + VERSION="${VERSION#v}" + else echo "[*] Resolving ${ch} tag from GitHub releases..." tag="" if [[ "$ch" == "prerelease" ]]; then tag="$(get_latest_tag_prerelease || true)" + if [[ -z "$tag" ]]; then + echo "[WARN] Failed to resolve prerelease tag, falling back to latest." + tag="$(get_latest_tag_latest || true)" + fi else tag="$(get_latest_tag_latest || true)" fi @@ -159,20 +312,6 @@ if git rev-parse --git-dir >/dev/null 2>&1; then git_try_checkout "$tag" || { echo "[ERROR] Failed to checkout '${tag}'."; exit 1; } VERSION="${tag#v}" fi - else - # No explicit GUI version passed: ask channel first - ch="$(choose_channel)" - echo "[*] Resolving ${ch} tag from GitHub releases..." - tag="" - if [[ "$ch" == "prerelease" ]]; then - tag="$(get_latest_tag_prerelease || true)" - else - tag="$(get_latest_tag_latest || true)" - fi - [[ -n "$tag" ]] || { echo "[ERROR] Failed to resolve latest tag for channel '${ch}'."; exit 1; } - echo "[*] Latest tag for '${ch}': ${tag}" - git_try_checkout "$tag" || { echo "[ERROR] Failed to checkout '${tag}'."; exit 1; } - VERSION="${tag#v}" fi else echo "[WARN] Current directory is not a git repo; cannot checkout version. Proceeding on current tree." @@ -188,45 +327,30 @@ else fi echo "[*] GUI version resolved as: ${VERSION}" -# ===== .NET publish (non-single file, self-contained) =========================================== -dotnet clean "$PROJECT" -c Release -rm -rf "$(dirname "$PROJECT")/bin/Release/net8.0" || true - -dotnet restore "$PROJECT" -dotnet publish "$PROJECT" \ - -c Release -r "$( [[ "$arch" == "aarch64" ]] && echo linux-arm64 || echo linux-x64 )" \ - -p:PublishSingleFile=false \ - -p:SelfContained=true \ - -p:IncludeNativeLibrariesForSelfExtract=true - -RID_DIR="$( [[ "$arch" == "aarch64" ]] && echo linux-arm64 || echo linux-x64 )" -PUBDIR="$(dirname "$PROJECT")/bin/Release/net8.0/${RID_DIR}/publish" -[[ -d "$PUBDIR" ]] - -# ===== Download Core(Optional) ======================================================== +# ===== Helpers for core/rules download (use RID_DIR for arch sync) ===================== download_xray() { + # Download Xray core and install to outdir/xray local outdir="$1" ver="${XRAY_VER:-}" url tmp zipname="xray.zip" mkdir -p "$outdir" if [[ -z "$ver" ]]; then - # Latest version ver="$(curl -fsSL https://api.github.com/repos/XTLS/Xray-core/releases/latest \ | grep -Eo '"tag_name":\s*"v[^"]+"' | sed -E 's/.*"v([^"]+)".*/\1/' | head -n1)" || true fi [[ -n "$ver" ]] || { echo "[xray] Failed to get version"; return 1; } - - if [[ "$arch" == "aarch64" ]]; then + if [[ "$RID_DIR" == "linux-arm64" ]]; then url="https://github.com/XTLS/Xray-core/releases/download/v${ver}/Xray-linux-arm64-v8a.zip" else url="https://github.com/XTLS/Xray-core/releases/download/v${ver}/Xray-linux-64.zip" fi echo "[+] Download xray: $url" - tmp="$(mktemp -d)"; trap 'rm -rf "$tmp"' RETURN + tmp="$(mktemp -d)"; trap '[[ -n "${tmp:-}" ]] && rm -rf "$tmp"' RETURN curl -fL "$url" -o "$tmp/$zipname" unzip -q "$tmp/$zipname" -d "$tmp" install -Dm755 "$tmp/xray" "$outdir/xray" } download_singbox() { + # Download sing-box core and install to outdir/sing-box local outdir="$1" ver="${SING_VER:-}" url tmp tarname="singbox.tar.gz" bin mkdir -p "$outdir" if [[ -z "$ver" ]]; then @@ -234,14 +358,13 @@ download_singbox() { | grep -Eo '"tag_name":\s*"v[^"]+"' | sed -E 's/.*"v([^"]+)".*/\1/' | head -n1)" || true fi [[ -n "$ver" ]] || { echo "[sing-box] Failed to get version"; return 1; } - - if [[ "$arch" == "aarch64" ]]; then + if [[ "$RID_DIR" == "linux-arm64" ]]; then url="https://github.com/SagerNet/sing-box/releases/download/v${ver}/sing-box-${ver}-linux-arm64.tar.gz" else url="https://github.com/SagerNet/sing-box/releases/download/v${ver}/sing-box-${ver}-linux-amd64.tar.gz" fi echo "[+] Download sing-box: $url" - tmp="$(mktemp -d)"; trap 'rm -rf "$tmp"' RETURN + tmp="$(mktemp -d)"; trap '[[ -n "${tmp:-}" ]] && rm -rf "$tmp"' RETURN curl -fL "$url" -o "$tmp/$tarname" tar -C "$tmp" -xzf "$tmp/$tarname" bin="$(find "$tmp" -type f -name 'sing-box' | head -n1 || true)" @@ -249,18 +372,32 @@ download_singbox() { install -Dm755 "$bin" "$outdir/sing-box" } -# === Geo rule download (ZIP-LIKE LAYOUT for netcore mode) ===================== -# Make netcore output match the ZIP bundle structure: -# - All geo databases at outroot/bin/ (geosite.dat, geoip.dat, Country.mmdb, geoip-only-cn-private.dat, geoip.metadb) -# - All *.srs rule-sets at outroot/bin/srss/ -# (Binaries stay under outroot/bin/xray and outroot/bin/sing_box as before.) +# Move geo files to a unified path: outroot/bin/xray/ +unify_geo_layout() { + local outroot="$1" + mkdir -p "$outroot/bin/xray" + local srcs=( \ + "$outroot/bin/geosite.dat" \ + "$outroot/bin/geoip.dat" \ + "$outroot/bin/geoip-only-cn-private.dat" \ + "$outroot/bin/Country.mmdb" \ + "$outroot/bin/geoip.metadb" \ + ) + for s in "${srcs[@]}"; do + if [[ -f "$s" ]]; then + mv -f "$s" "$outroot/bin/xray/$(basename "$s")" + fi + done +} + +# Download geo/rule assets; then unify to bin/xray/ download_geo_assets() { local outroot="$1" local bin_dir="$outroot/bin" local srss_dir="$bin_dir/srss" mkdir -p "$bin_dir" "$srss_dir" - echo "[+] Download Xray Geo (geosite/geoip/...) to ${bin_dir}" + echo "[+] Download Xray Geo to ${bin_dir}" curl -fsSL -o "$bin_dir/geosite.dat" \ "https://github.com/Loyalsoldier/V2ray-rules-dat/releases/latest/download/geosite.dat" curl -fsSL -o "$bin_dir/geoip.dat" \ @@ -270,7 +407,7 @@ download_geo_assets() { curl -fsSL -o "$bin_dir/Country.mmdb" \ "https://raw.githubusercontent.com/Loyalsoldier/geoip/release/Country.mmdb" - echo "[+] Download sing-box rule DB & rule-sets to ZIP-like paths" + echo "[+] Download sing-box rule DB & rule-sets" curl -fsSL -o "$bin_dir/geoip.metadb" \ "https://github.com/MetaCubeX/meta-rules-dat/releases/latest/download/geoip.metadb" || true @@ -280,20 +417,22 @@ download_geo_assets() { curl -fsSL -o "$srss_dir/$f" \ "https://raw.githubusercontent.com/2dust/sing-box-rules/rule-set-geoip/$f" || true done - for f in \ geosite-cn.srs geosite-gfw.srs geosite-greatfire.srs \ geosite-geolocation-cn.srs geosite-category-ads-all.srs geosite-private.srs; do curl -fsSL -o "$srss_dir/$f" \ "https://raw.githubusercontent.com/2dust/sing-box-rules/rule-set-geosite/$f" || true done + + # Unify to bin/xray/ + unify_geo_layout "$outroot" } -# === NEW: Prefer the all-in-one v2rayN bundle zip first ======================= +# Prefer the prebuilt v2rayN core bundle; then unify geo layout download_v2rayn_bundle() { local outroot="$1" local url="" - if [[ "$arch" == "aarch64" ]]; then + if [[ "$RID_DIR" == "linux-arm64" ]]; then url="https://raw.githubusercontent.com/2dust/v2rayN-core-bin/refs/heads/master/v2rayN-linux-arm64.zip" else url="https://raw.githubusercontent.com/2dust/v2rayN-core-bin/refs/heads/master/v2rayN-linux-64.zip" @@ -304,7 +443,6 @@ download_v2rayn_bundle() { curl -fL "$url" -o "$zipname" || { echo "[!] Bundle download failed"; return 1; } unzip -q "$zipname" -d "$tmp" || { echo "[!] Bundle unzip failed"; return 1; } - # Normalize layout: copy 'bin/' if present; otherwise copy all if [[ -d "$tmp/bin" ]]; then mkdir -p "$outroot/bin" rsync -a "$tmp/bin/" "$outroot/bin/" @@ -312,7 +450,6 @@ download_v2rayn_bundle() { rsync -a "$tmp/" "$outroot/" fi - # --- CLEANUPS (keep bundle-only adjustments) ------------------------------- rm -f "$outroot/v2rayn.zip" 2>/dev/null || true find "$outroot" -type d -name "mihomo" -prune -exec rm -rf {} + 2>/dev/null || true @@ -323,37 +460,100 @@ download_v2rayn_bundle() { rsync -a "$nested_dir/bin/" "$outroot/bin/" rm -rf "$nested_dir" fi - # --------------------------------------------------------------------------- + + # Unify to bin/xray/ + unify_geo_layout "$outroot" echo "[+] Bundle extracted to $outroot" } -# ===== Copy publish files to RPM build root ================================================== -rpmdev-setuptree -TOPDIR="${HOME}/rpmbuild" -SPECDIR="${TOPDIR}/SPECS" -SOURCEDIR="${TOPDIR}/SOURCES" +# ===== Build results collection for --arch all ======================================== +BUILT_RPMS=() # Will collect absolute paths of built RPMs +BUILT_ALL=0 # Flag to know if we should print the final summary -PKGROOT="v2rayN-publish" -WORKDIR="$(mktemp -d)" -trap 'rm -rf "$WORKDIR"' EXIT +# ===== Build (single-arch) function ==================================================== +build_for_arch() { + # $1: target short arch: x64 | arm64 + local short="$1" + local rid rpm_target archdir + case "$short" in + x64) rid="linux-x64"; rpm_target="x86_64"; archdir="x86_64" ;; + arm64) rid="linux-arm64"; rpm_target="aarch64"; archdir="aarch64" ;; + *) echo "[ERROR] Unknown arch '$short' (use x64|arm64)"; return 1;; + esac -mkdir -p "$WORKDIR/$PKGROOT" -cp -a "$PUBDIR/." "$WORKDIR/$PKGROOT/" + echo "[*] Building for target: $short (RID=$rid, RPM --target $rpm_target)" -# icon(Optional) -ICON_CANDIDATE="$(dirname "$PROJECT")/../v2rayN.Desktop/v2rayN.png" -[[ -f "$ICON_CANDIDATE" ]] && cp "$ICON_CANDIDATE" "$WORKDIR/$PKGROOT/v2rayn.png" || true + # .NET publish (self-contained) for this RID + dotnet clean "$PROJECT" -c Release + rm -rf "$(dirname "$PROJECT")/bin/Release/net8.0" || true -# bin directory structure -mkdir -p "$WORKDIR/$PKGROOT/bin/xray" "$WORKDIR/$PKGROOT/bin/sing_box" + dotnet restore "$PROJECT" + dotnet publish "$PROJECT" \ + -c Release -r "$rid" \ + -p:PublishSingleFile=false \ + -p:SelfContained=true \ + -p:IncludeNativeLibrariesForSelfExtract=true -# ====== NEW decision: prefer bundle zip unless --netcore, else fall back ====== -if [[ "$FORCE_NETCORE" -eq 0 ]]; then - if download_v2rayn_bundle "$WORKDIR/$PKGROOT"; then - echo "[*] Using v2rayN bundle archive." + # Per-arch variables (scoped) + local RID_DIR="$rid" + local PUBDIR + PUBDIR="$(dirname "$PROJECT")/bin/Release/net8.0/${RID_DIR}/publish" + [[ -d "$PUBDIR" ]] + + # Make RID_DIR visible to download helpers (they read this var) + export RID_DIR + + # Per-arch working area + local PKGROOT="v2rayN-publish" + local WORKDIR + WORKDIR="$(mktemp -d)" + trap '[[ -n "${WORKDIR:-}" ]] && rm -rf "$WORKDIR"' RETURN + + # rpmbuild topdir selection + local TOPDIR SPECDIR SOURCEDIR USE_TOPDIR_DEFINE + if [[ "$ID" =~ ^(rhel|rocky|almalinux|centos)$ ]]; then + rpmdev-setuptree + TOPDIR="${HOME}/rpmbuild" + SPECDIR="${TOPDIR}/SPECS" + SOURCEDIR="${TOPDIR}/SOURCES" + USE_TOPDIR_DEFINE=0 else - echo "[*] Bundle failed, fallback to separate core + rules." + TOPDIR="${WORKDIR}/rpmbuild" + SPECDIR="${TOPDIR}/SPECS}" + SOURCEDIR="${TOPDIR}/SOURCES" + mkdir -p "${SPECDIR}" "${SOURCEDIR}" "${TOPDIR}/BUILD" "${TOPDIR}/RPMS" "${TOPDIR}/SRPMS" + USE_TOPDIR_DEFINE=1 + fi + + # Stage publish content + mkdir -p "$WORKDIR/$PKGROOT" + cp -a "$PUBDIR/." "$WORKDIR/$PKGROOT/" + + # Optional icon + local ICON_CANDIDATE + ICON_CANDIDATE="$(dirname "$PROJECT")/../v2rayN.Desktop/v2rayN.png" + [[ -f "$ICON_CANDIDATE" ]] && cp "$ICON_CANDIDATE" "$WORKDIR/$PKGROOT/v2rayn.png" || true + + # Prepare bin structure + mkdir -p "$WORKDIR/$PKGROOT/bin/xray" "$WORKDIR/$PKGROOT/bin/sing_box" + + # Bundle / cores per-arch + if [[ "$FORCE_NETCORE" -eq 0 ]]; then + if download_v2rayn_bundle "$WORKDIR/$PKGROOT"; then + echo "[*] Using v2rayN bundle archive." + else + echo "[*] Bundle failed, fallback to separate core + rules." + if [[ "$WITH_CORE" == "xray" || "$WITH_CORE" == "both" ]]; then + download_xray "$WORKDIR/$PKGROOT/bin/xray" || echo "[!] xray download failed (skipped)" + fi + if [[ "$WITH_CORE" == "sing-box" || "$WITH_CORE" == "both" ]]; then + download_singbox "$WORKDIR/$PKGROOT/bin/sing_box" || echo "[!] sing-box download failed (skipped)" + fi + download_geo_assets "$WORKDIR/$PKGROOT" || echo "[!] Geo rules download failed (skipped)" + fi + else + echo "[*] --netcore specified: use separate core + rules." if [[ "$WITH_CORE" == "xray" || "$WITH_CORE" == "both" ]]; then download_xray "$WORKDIR/$PKGROOT/bin/xray" || echo "[!] xray download failed (skipped)" fi @@ -362,22 +562,15 @@ if [[ "$FORCE_NETCORE" -eq 0 ]]; then fi download_geo_assets "$WORKDIR/$PKGROOT" || echo "[!] Geo rules download failed (skipped)" fi -else - echo "[*] --netcore specified: use separate core + rules." - if [[ "$WITH_CORE" == "xray" || "$WITH_CORE" == "both" ]]; then - download_xray "$WORKDIR/$PKGROOT/bin/xray" || echo "[!] xray download failed (skipped)" - fi - if [[ "$WITH_CORE" == "sing-box" || "$WITH_CORE" == "both" ]]; then - download_singbox "$WORKDIR/$PKGROOT/bin/sing_box" || echo "[!] sing-box download failed (skipped)" - fi - download_geo_assets "$WORKDIR/$PKGROOT" || echo "[!] Geo rules download failed (skipped)" -fi -tar -C "$WORKDIR" -czf "$SOURCEDIR/$PKGROOT.tar.gz" "$PKGROOT" + # Tarball + mkdir -p "$SOURCEDIR" + tar -C "$WORKDIR" -czf "$SOURCEDIR/$PKGROOT.tar.gz" "$PKGROOT" -# ===== Generate SPEC (heredoc with placeholders) =================================== -SPECFILE="$SPECDIR/v2rayN.spec" -cat > "$SPECFILE" <<'SPEC' + # SPEC + local SPECFILE="$SPECDIR/v2rayN.spec" + mkdir -p "$SPECDIR" + cat > "$SPECFILE" <<'SPEC' %global debug_package %{nil} %undefine _debuginfo_subpackages %undefine _debugsource_packages @@ -413,14 +606,14 @@ Geo files for Xray are placed at /opt/v2rayN/bin/xray; launcher will symlink the install -dm0755 %{buildroot}/opt/v2rayN cp -a * %{buildroot}/opt/v2rayN/ -# Launcher (prioritize ELF first, then fall back to DLL; also create Geo symlinks for the user) +# Launcher (prefer native ELF first, then DLL fallback; also create Geo symlinks for the user) install -dm0755 %{buildroot}%{_bindir} cat > %{buildroot}%{_bindir}/v2rayn << 'EOF' #!/usr/bin/bash set -euo pipefail DIR="/opt/v2rayN" -# --- SYMLINK GEO into user's XDG dir (new) --- +# --- Symlink GEO files into user's XDG dir (first-run convenience) --- XDG_DATA_HOME="${XDG_DATA_HOME:-$HOME/.local/share}" USR_GEO_DIR="$XDG_DATA_HOME/v2rayN/bin" SYS_XRAY_DIR="$DIR/bin/xray" @@ -432,10 +625,10 @@ for f in geosite.dat geoip.dat geoip-only-cn-private.dat Country.mmdb; do done # --- end GEO --- -# Prefer native ELF(apphost) +# Prefer native apphost if [[ -x "$DIR/v2rayN" ]]; then exec "$DIR/v2rayN" "$@"; fi -# DLL fallback (for framework-dependent publish) +# DLL fallback for dll in v2rayN.Desktop.dll v2rayN.dll; do if [[ -f "$DIR/$dll" ]]; then exec /usr/bin/dotnet "$DIR/$dll" "$@"; fi done @@ -446,7 +639,7 @@ exit 1 EOF chmod 0755 %{buildroot}%{_bindir}/v2rayn -# Desktop File +# Desktop file install -dm0755 %{buildroot}%{_datadir}/applications cat > %{buildroot}%{_datadir}/applications/v2rayn.desktop << 'EOF' [Desktop Entry] @@ -459,7 +652,7 @@ Terminal=false Categories=Network; EOF -# icon +# Icon if [ -f "%{_builddir}/__PKGROOT__/v2rayn.png" ]; then install -dm0755 %{buildroot}%{_datadir}/icons/hicolor/256x256/apps install -m0644 %{_builddir}/__PKGROOT__/v2rayn.png %{buildroot}%{_datadir}/icons/hicolor/256x256/apps/v2rayn.png @@ -480,32 +673,120 @@ fi %{_datadir}/icons/hicolor/256x256/apps/v2rayn.png SPEC -# Optional: system-wide autostart (append block, keep original logic unchanged) -if [[ "$AUTOSTART" -eq 1 ]]; then -cat >> "$SPECFILE" <<'SPEC' -# System-wide autostart entry -%install -install -dm0755 %{buildroot}/etc/xdg/autostart -cat > %{buildroot}/etc/xdg/autostart/v2rayn.desktop << 'EOF' -[Desktop Entry] -Type=Application -Name=v2rayN (Autostart) -Exec=v2rayn -X-GNOME-Autostart-enabled=true -NoDisplay=false -EOF + # Autostart injection (inside %install) and %files entry + if [[ "$AUTOSTART" -eq 1 ]]; then + awk ' + BEGIN{ins=0} + /^%post$/ && !ins { + print "# --- Autostart (.desktop) ---" + print "install -dm0755 %{buildroot}/etc/xdg/autostart" + print "cat > %{buildroot}/etc/xdg/autostart/v2rayn.desktop << '\''EOF'\''" + print "[Desktop Entry]" + print "Type=Application" + print "Name=v2rayN (Autostart)" + print "Exec=v2rayn" + print "X-GNOME-Autostart-enabled=true" + print "NoDisplay=false" + print "EOF" + ins=1 + } + {print} + ' "$SPECFILE" > "${SPECFILE}.tmp" && mv "${SPECFILE}.tmp" "$SPECFILE" -%files -%config(noreplace) /etc/xdg/autostart/v2rayn.desktop -SPEC + awk ' + BEGIN{infiles=0; done=0} + /^%files$/ {infiles=1} + infiles && done==0 && $0 ~ /%{_datadir}\/icons\/hicolor\/256x256\/apps\/v2rayn\.png/ { + print + print "%config(noreplace) /etc/xdg/autostart/v2rayn.desktop" + done=1 + next + } + {print} + ' "$SPECFILE" > "${SPECFILE}.tmp" && mv "${SPECFILE}.tmp" "$SPECFILE" + fi + + # Replace placeholders + sed -i "s/__VERSION__/${VERSION}/g" "$SPECFILE" + sed -i "s/__PKGROOT__/${PKGROOT}/g" "$SPECFILE" + + # ----- Select proper 'strip' per target arch on Ubuntu only (cross-binutils) ----- + # NOTE: We define only __strip to point to the target-arch strip. + # DO NOT override __brp_strip (it must stay the brp script path). + local STRIP_ARGS=() + if [[ "$ID" == "ubuntu" ]]; then + local STRIP_BIN="" + if [[ "$short" == "x64" ]]; then + STRIP_BIN="/usr/bin/x86_64-linux-gnu-strip" + else + STRIP_BIN="/usr/bin/aarch64-linux-gnu-strip" + fi + if [[ -x "$STRIP_BIN" ]]; then + STRIP_ARGS=( --define "__strip $STRIP_BIN" ) + fi + fi + + # Build RPM for this arch (force rpm --target to match compile arch) + if [[ "$USE_TOPDIR_DEFINE" -eq 1 ]]; then + rpmbuild -ba "$SPECFILE" --define "_topdir $TOPDIR" --target "$rpm_target" "${STRIP_ARGS[@]}" + else + rpmbuild -ba "$SPECFILE" --target "$rpm_target" "${STRIP_ARGS[@]}" + fi + + # Copy temporary rpmbuild to ~/rpmbuild on Debian/Ubuntu path + if [[ "$USE_TOPDIR_DEFINE" -eq 1 ]]; then + mkdir -p "$HOME/rpmbuild" + rsync -a "$TOPDIR"/ "$HOME/rpmbuild"/ + TOPDIR="$HOME/rpmbuild" + fi + + echo "Build done for $short. RPM at:" + local f + for f in "${TOPDIR}/RPMS/${archdir}/v2rayN-${VERSION}-1"*.rpm; do + [[ -e "$f" ]] || continue + echo " $f" + BUILT_RPMS+=("$f") + done +} + +# ===== Arch selection and build orchestration ========================================= +case "${ARCH_OVERRIDE:-}" in + "") + # No --arch: use host architecture + if [[ "$host_arch" == "aarch64" ]]; then + build_for_arch arm64 + else + build_for_arch x64 + fi + ;; + x64|amd64) + build_for_arch x64 + ;; + arm64|aarch64) + build_for_arch arm64 + ;; + all) + BUILT_ALL=1 + # Build x64 and arm64 separately; each package contains its own arch-only binaries. + build_for_arch x64 + build_for_arch arm64 + ;; + *) + echo "[ERROR] Unknown --arch '${ARCH_OVERRIDE}'. Use x64|arm64|all." + exit 1 + ;; +esac + +# ===== Final summary if building both arches ========================================== +if [[ "$BUILT_ALL" -eq 1 ]]; then + echo "" + echo "================ Build Summary (both architectures) ================" + if [[ "${#BUILT_RPMS[@]}" -gt 0 ]]; then + for rp in "${BUILT_RPMS[@]}"; do + echo "$rp" + done + else + echo "[WARN] No RPMs detected in summary (check build logs above)." + fi + echo "===================================================================" fi - -# Injecting version/package root placeholders -sed -i "s/__VERSION__/${VERSION}/g" "$SPECFILE" -sed -i "s/__PKGROOT__/${PKGROOT}/g" "$SPECFILE" - -# ===== Build RPM ================================================================ -rpmbuild -ba "$SPECFILE" - -echo "Build done. RPM at:" -ls -1 "${TOPDIR}/RPMS/$( [[ "$arch" == "aarch64" ]] && echo aarch64 || echo x86_64 )/v2rayN-${VERSION}-1"*.rpm diff --git a/v2rayn/v2rayN/Directory.Build.props b/v2rayn/v2rayN/Directory.Build.props index c7d69e206d..d4baa20711 100644 --- a/v2rayn/v2rayN/Directory.Build.props +++ b/v2rayn/v2rayN/Directory.Build.props @@ -1,7 +1,7 @@ - 7.14.1 + 7.14.2 diff --git a/v2rayn/v2rayN/Directory.Packages.props b/v2rayn/v2rayN/Directory.Packages.props index e923397d1c..ab71be955c 100644 --- a/v2rayn/v2rayN/Directory.Packages.props +++ b/v2rayn/v2rayN/Directory.Packages.props @@ -5,10 +5,10 @@ false - - - - + + + + @@ -20,7 +20,7 @@ - + diff --git a/v2rayn/v2rayN/ServiceLib/Services/CoreConfig/Singbox/CoreConfigSingboxService.cs b/v2rayn/v2rayN/ServiceLib/Services/CoreConfig/Singbox/CoreConfigSingboxService.cs index 7ee82af10e..4e24d8e2eb 100644 --- a/v2rayn/v2rayN/ServiceLib/Services/CoreConfig/Singbox/CoreConfigSingboxService.cs +++ b/v2rayn/v2rayN/ServiceLib/Services/CoreConfig/Singbox/CoreConfigSingboxService.cs @@ -64,7 +64,7 @@ public partial class CoreConfigSingboxService(Config config) await GenRouting(singboxConfig); - await GenDns(singboxConfig); + await GenDns(node, singboxConfig); await GenExperimental(singboxConfig); @@ -421,7 +421,7 @@ public partial class CoreConfigSingboxService(Config config) } await GenOutboundsList(proxyProfiles, singboxConfig); - await GenDns(singboxConfig); + await GenDns(null, singboxConfig); await ConvertGeo2Ruleset(singboxConfig); ret.Success = true; diff --git a/v2rayn/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxDnsService.cs b/v2rayn/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxDnsService.cs index ef22d926f8..15f2c43b65 100644 --- a/v2rayn/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxDnsService.cs +++ b/v2rayn/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxDnsService.cs @@ -2,14 +2,14 @@ namespace ServiceLib.Services.CoreConfig; public partial class CoreConfigSingboxService { - private async Task GenDns(SingboxConfig singboxConfig) + private async Task GenDns(ProfileItem? node, SingboxConfig singboxConfig) { try { var item = await AppManager.Instance.GetDNSItem(ECoreType.sing_box); if (item != null && item.Enabled == true) { - return await GenDnsCompatible(singboxConfig); + return await GenDnsCompatible(node, singboxConfig); } var simpleDNSItem = _config.SimpleDNSItem; @@ -19,6 +19,7 @@ public partial class CoreConfigSingboxService singboxConfig.dns ??= new Dns4Sbox(); singboxConfig.dns.independent_cache = true; + // final dns var routing = await ConfigHandler.GetDefaultRouting(_config); var useDirectDns = false; if (routing != null) @@ -32,6 +33,17 @@ public partial class CoreConfigSingboxService lastRule.Ip?.Contains("0.0.0.0/0") == true); } singboxConfig.dns.final = useDirectDns ? Global.SingboxDirectDNSTag : Global.SingboxRemoteDNSTag; + + // Tun2SocksAddress + if (node != null && Utils.IsDomain(node.Address)) + { + singboxConfig.dns.rules ??= new List(); + singboxConfig.dns.rules.Insert(0, new Rule4Sbox + { + server = Global.SingboxOutboundResolverTag, + domain = [node.Address], + }); + } } catch (Exception ex) { @@ -67,26 +79,27 @@ public partial class CoreConfigSingboxService { hostsDns.predefined = Global.PredefinedHosts; } - var userHostsMap = simpleDNSItem.Hosts? - .Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries) - .Where(line => !string.IsNullOrWhiteSpace(line)) - .Where(line => line.Contains(' ')) - .ToDictionary( - line => - { - var parts = line.Trim().Split(new[] { ' ', '\t' }, StringSplitOptions.RemoveEmptyEntries); - return parts[0]; - }, - line => - { - var parts = line.Trim().Split(new[] { ' ', '\t' }, StringSplitOptions.RemoveEmptyEntries); - var values = parts.Skip(1).ToList(); - return values; - } - ); - if (userHostsMap != null) + if (!simpleDNSItem.Hosts.IsNullOrEmpty()) { + var userHostsMap = simpleDNSItem.Hosts? + .Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries) + .Where(line => !string.IsNullOrWhiteSpace(line)) + .Where(line => line.Contains(' ')) + .ToDictionary( + line => + { + var parts = line.Trim().Split(new[] { ' ', '\t' }, StringSplitOptions.RemoveEmptyEntries); + return parts[0]; + }, + line => + { + var parts = line.Trim().Split(new[] { ' ', '\t' }, StringSplitOptions.RemoveEmptyEntries); + var values = parts.Skip(1).ToList(); + return values; + } + ) ?? new Dictionary>(); + foreach (var kvp in userHostsMap) { hostsDns.predefined[kvp.Key] = kvp.Value; @@ -100,11 +113,11 @@ public partial class CoreConfigSingboxService { foreach (var host in systemHosts) { - if (userHostsMap[host.Key] != null) + if (hostsDns.predefined[host.Key] != null) { continue; } - userHostsMap[host.Key] = new List { host.Value }; + hostsDns.predefined[host.Key] = new List { host.Value }; } } } @@ -289,7 +302,7 @@ public partial class CoreConfigSingboxService return 0; } - private async Task GenDnsCompatible(SingboxConfig singboxConfig) + private async Task GenDnsCompatible(ProfileItem? node, SingboxConfig singboxConfig) { try { @@ -319,6 +332,17 @@ public partial class CoreConfigSingboxService { await GenDnsDomainsLegacyCompatible(singboxConfig, item); } + + // Tun2SocksAddress + if (node != null && Utils.IsDomain(node.Address)) + { + singboxConfig.dns.rules ??= new List(); + singboxConfig.dns.rules.Insert(0, new Rule4Sbox + { + server = Global.SingboxFinalResolverTag, + domain = [node.Address], + }); + } } catch (Exception ex) { diff --git a/v2rayn/v2rayN/ServiceLib/Services/UpdateService.cs b/v2rayn/v2rayN/ServiceLib/Services/UpdateService.cs index e87522e232..95d51d4b50 100644 --- a/v2rayn/v2rayN/ServiceLib/Services/UpdateService.cs +++ b/v2rayn/v2rayN/ServiceLib/Services/UpdateService.cs @@ -434,7 +434,7 @@ public class UpdateService var fileName = $"{type}-{srsName}.srs"; var targetPath = Path.Combine(Utils.GetBinPath("srss"), fileName); - var url = string.Format(srsUrl, type, $"{type}-{srsName}"); + var url = string.Format(srsUrl, type, $"{type}-{srsName}", srsName); await DownloadGeoFile(url, fileName, targetPath, updateFunc); } diff --git a/xray-core/.github/ISSUE_TEMPLATE/bug_report.yml b/xray-core/.github/ISSUE_TEMPLATE/bug_report.yml index 32f58b1905..3a5c04f86d 100644 --- a/xray-core/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/xray-core/.github/ISSUE_TEMPLATE/bug_report.yml @@ -7,6 +7,8 @@ body: description: |- Please check all of the following options to prove that you have read and understood the requirements, otherwise this issue will be closed. options: + - label: I have read all the comments in the issue template and ensured that this issue meet the requirements. + required: true - label: I confirm that I have read the documentation, understand the meaning of all the configuration items I wrote, and did not pile up seemingly useful options or default values. required: true - label: I provided the complete config and logs, rather than just providing the truncated parts based on my own judgment. @@ -38,6 +40,8 @@ body: ### For config Please provide the configuration files that can reproduce the problem, including the server and client. Don't just paste a big exported config file here. Eliminate useless inbound/outbound, rules, options, this can help determine the problem, if you really want to get help. + After removing parts that do not affect reproduction, provide the actual running **complete** file. + meaning of complete: This config can be directly used to start the core, **not a truncated part of the config**. For fields like keys, use newly generated valid parameters that have not been actually used to fill in. ### For logs Please set the log level to debug and dnsLog to true first. @@ -46,42 +50,29 @@ body: Provide the log of Xray-core, not the log output by the panel or other things. ### Finally - After removing parts that do not affect reproduction, provide the actual running **complete** file, do not only provide inbound or outbound or a few lines of logs based on your own judgment. - Put the content between the preset ```
``` ```
``` in the text box. - If the problem is very clear that only related to one end (such as core startup failure/crash after correctly writing the config according to the documents), N/A can be filled in for unnecessary areas below. + The specific content to be filled in each of the following text boxes needs to be placed between ```
``` and ```
```, like this + ``` +

+        (config)
+        
+ ``` - type: textarea attributes: label: Client config - value: |- -

-
-        
validations: required: true - type: textarea attributes: label: Server config - value: |- -

-
-        
validations: required: true - type: textarea attributes: label: Client log - value: |- -

-
-        
validations: required: true - type: textarea attributes: label: Server log - value: |- -

-
-        
validations: required: true \ No newline at end of file diff --git a/xray-core/.github/ISSUE_TEMPLATE/bug_report_zh.yml b/xray-core/.github/ISSUE_TEMPLATE/bug_report_zh.yml index 201f847e22..939f663cc4 100644 --- a/xray-core/.github/ISSUE_TEMPLATE/bug_report_zh.yml +++ b/xray-core/.github/ISSUE_TEMPLATE/bug_report_zh.yml @@ -7,6 +7,8 @@ body: description: |- 请勾选以下所有选项以证明您已经阅读并理解了以下要求,否则该 issue 将被关闭。 options: + - label: 我读完了 issue 模板中的所有注释,确保填写符合要求。 + required: true - label: 我保证阅读了文档,了解所有我编写的配置文件项的含义,而不是大量堆砌看似有用的选项或默认值。 required: true - label: 我提供了完整的配置文件和日志,而不是出于自己的判断只给出截取的部分。 @@ -38,6 +40,8 @@ body: ### 对于配置文件 请提供可以重现问题的配置文件,包括服务端和客户端。 不要直接在这里黏贴一大段导出的 config 文件。去掉无用的出入站、规则、选项,这可以帮助确定问题,如果你真的想得到帮助。 + 在去掉不影响复现的部分后,提供实际运行的**完整**文件。 + 完整的含义:可以直接使用这个配置启动核心,**不是截取的部分配置**。对于密钥等参数使用重新生成未实际使用的有效参数填充。 ### 对于日志 请先将日志等级设置为 debug, dnsLog 设置为true. @@ -46,42 +50,29 @@ body: 提供 Xray-core 的日志,而不是面板或者别的东西输出的日志。 ### 最后 - 在去掉不影响复现的部分后,提供实际运行的**完整**文件,不要出于自己的判断只提供入站出站或者几行日志。 - 把内容放在文本框预置的 ```
``` 和 ```
``` 中间。 - 如果问题十分明确只出现在某一端(如按文档正确编写配置后核心启动失败/崩溃),可以在下面不需要的项目填入N/A. + 把下面的每格具体内容需要放在 ```
``` 和 ```
``` 中间,如 + ``` +

+        (config)
+        
+ ``` - type: textarea attributes: label: 客户端配置 - value: |- -

-
-        
validations: required: true - type: textarea attributes: label: 服务端配置 - value: |- -

-
-        
validations: required: true - type: textarea attributes: label: 客户端日志 - value: |- -

-
-        
validations: required: true - type: textarea attributes: label: 服务端日志 - value: |- -

-
-        
validations: required: true diff --git a/xray-core/.gitignore b/xray-core/.gitignore index ac744f79a3..f1eca8175d 100644 --- a/xray-core/.gitignore +++ b/xray-core/.gitignore @@ -11,21 +11,23 @@ # Output of the go coverage tool, specifically when used with LiteIDE *.out -# Dependency directories (remove the comment below to include it) -# vendor/ - # macOS specific files -*.DS_Store +.DS_Store -# IDE specific files +# IDE/editor specific files .idea/ .vscode/ +*.swp +*.swo -# Archive files +# Archives and compressed files *.zip *.tar.gz +*.tar +*.gz +*.bz2 -# Binaries +# Go build binaries xray xray_softfloat mockgen @@ -36,11 +38,31 @@ errorgen *.dat # Build assets -/build_assets +/build_assets/ # Output from dlv test **/debug.* -# Certificates +# Certificates and keys *.crt *.key + +# Dependency directories (uncomment if needed) +# vendor/ + +# Logs +*.log + +# Coverage reports +coverage.* + +# Node modules (in case of frontend assets) +node_modules/ + +# System files +Thumbs.db +ehthumbs.db + +# Other common ignores +*.bak +*.tmp diff --git a/xray-core/app/proxyman/inbound/worker.go b/xray-core/app/proxyman/inbound/worker.go index 44eba272b6..40c8bc157e 100644 --- a/xray-core/app/proxyman/inbound/worker.go +++ b/xray-core/app/proxyman/inbound/worker.go @@ -322,10 +322,18 @@ func (w *udpWorker) callback(b *buf.Buffer, source net.Destination, originalDest outbounds[0].Target = originalDest } ctx = session.ContextWithOutbounds(ctx, outbounds) + local := net.DestinationFromAddr(w.hub.Addr()) + if local.Address == net.AnyIP || local.Address == net.AnyIPv6 { + if source.Address.Family().IsIPv4() { + local.Address = net.AnyIP + } else if source.Address.Family().IsIPv6() { + local.Address = net.AnyIPv6 + } + } ctx = session.ContextWithInbound(ctx, &session.Inbound{ Source: source, - Local: net.DestinationFromAddr(w.hub.Addr()), // Due to some limitations, in UDP connections, localIP is always equal to listen interface IP + Local: local, // Due to some limitations, in UDP connections, localIP is always equal to listen interface IP Gateway: net.UDPDestination(w.address, w.port), Tag: w.tag, }) diff --git a/xray-core/app/proxyman/outbound/handler.go b/xray-core/app/proxyman/outbound/handler.go index c902160865..d0e670c501 100644 --- a/xray-core/app/proxyman/outbound/handler.go +++ b/xray-core/app/proxyman/outbound/handler.go @@ -4,12 +4,13 @@ import ( "context" "crypto/rand" goerrors "errors" - "github.com/xtls/xray-core/common/dice" "io" "math/big" gonet "net" "os" + "github.com/xtls/xray-core/common/dice" + "github.com/xtls/xray-core/app/proxyman" "github.com/xtls/xray-core/common" "github.com/xtls/xray-core/common/buf" @@ -180,7 +181,11 @@ func (h *Handler) Dispatch(ctx context.Context, link *transport.Link) { ob := outbounds[len(outbounds)-1] content := session.ContentFromContext(ctx) if h.senderSettings != nil && h.senderSettings.TargetStrategy.HasStrategy() && ob.Target.Address.Family().IsDomain() && (content == nil || !content.SkipDNSResolve) { - ips, err := internet.LookupForIP(ob.Target.Address.Domain(), h.senderSettings.TargetStrategy, nil) + strategy := h.senderSettings.TargetStrategy + if ob.Target.Network == net.Network_UDP && ob.OriginalTarget.Address != nil { + strategy = strategy.GetDynamicStrategy(ob.OriginalTarget.Address.Family()) + } + ips, err := internet.LookupForIP(ob.Target.Address.Domain(), strategy, nil) if err != nil { errors.LogInfoInner(ctx, err, "failed to resolve ip for target ", ob.Target.Address.Domain()) if h.senderSettings.TargetStrategy.ForceIP() { @@ -251,14 +256,6 @@ out: common.Interrupt(link.Reader) } -// Address implements internet.Dialer. -func (h *Handler) Address() net.Address { - if h.senderSettings == nil || h.senderSettings.Via == nil { - return nil - } - return h.senderSettings.Via.AsAddress() -} - func (h *Handler) DestIpAddress() net.IP { return internet.DestIpAddress() } @@ -293,41 +290,16 @@ func (h *Handler) Dial(ctx context.Context, dest net.Destination) (stat.Connecti return h.getStatCouterConnection(conn), nil } - errors.LogWarning(ctx, "failed to get outbound handler with tag: ", tag) + errors.LogError(ctx, "failed to get outbound handler with tag: ", tag) + return nil, errors.New("failed to get outbound handler with tag: " + tag) } if h.senderSettings.Via != nil { - outbounds := session.OutboundsFromContext(ctx) ob := outbounds[len(outbounds)-1] - var domain string - addr := h.senderSettings.Via.AsAddress() - domain = h.senderSettings.Via.GetDomain() - switch { - case h.senderSettings.ViaCidr != "": - ob.Gateway = ParseRandomIP(addr, h.senderSettings.ViaCidr) - - case domain == "origin": - if inbound := session.InboundFromContext(ctx); inbound != nil { - if inbound.Local.IsValid() && inbound.Local.Address.Family().IsIP() { - ob.Gateway = inbound.Local.Address - errors.LogDebug(ctx, "use inbound local ip as sendthrough: ", inbound.Local.Address.String()) - } - } - case domain == "srcip": - if inbound := session.InboundFromContext(ctx); inbound != nil { - if inbound.Source.IsValid() && inbound.Source.Address.Family().IsIP() { - ob.Gateway = inbound.Source.Address - errors.LogDebug(ctx, "use inbound source ip as sendthrough: ", inbound.Source.Address.String()) - } - } - //case addr.Family().IsDomain(): - default: - ob.Gateway = addr - - } - + h.SetOutboundGateway(ctx, ob) } + } if conn, err := h.getUoTConnection(ctx, dest); err != os.ErrInvalid { @@ -342,6 +314,38 @@ func (h *Handler) Dial(ctx context.Context, dest net.Destination) (stat.Connecti return conn, err } +func (h *Handler) SetOutboundGateway(ctx context.Context, ob *session.Outbound) { + if ob.Gateway == nil && h.senderSettings != nil && h.senderSettings.Via != nil && !h.senderSettings.ProxySettings.HasTag() && (h.streamSettings.SocketSettings == nil || len(h.streamSettings.SocketSettings.DialerProxy) == 0) { + var domain string + addr := h.senderSettings.Via.AsAddress() + domain = h.senderSettings.Via.GetDomain() + switch { + case h.senderSettings.ViaCidr != "": + ob.Gateway = ParseRandomIP(addr, h.senderSettings.ViaCidr) + + case domain == "origin": + if inbound := session.InboundFromContext(ctx); inbound != nil { + if inbound.Local.IsValid() && inbound.Local.Address.Family().IsIP() { + ob.Gateway = inbound.Local.Address + errors.LogDebug(ctx, "use inbound local ip as sendthrough: ", inbound.Local.Address.String()) + } + } + case domain == "srcip": + if inbound := session.InboundFromContext(ctx); inbound != nil { + if inbound.Source.IsValid() && inbound.Source.Address.Family().IsIP() { + ob.Gateway = inbound.Source.Address + errors.LogDebug(ctx, "use inbound source ip as sendthrough: ", inbound.Source.Address.String()) + } + } + //case addr.Family().IsDomain(): + default: + ob.Gateway = addr + + } + + } +} + func (h *Handler) getStatCouterConnection(conn stat.Connection) stat.Connection { if h.uplinkCounter != nil || h.downlinkCounter != nil { return &stat.CounterConnection{ diff --git a/xray-core/infra/conf/freedom.go b/xray-core/infra/conf/freedom.go index e38f8569af..65930a2e8a 100644 --- a/xray-core/infra/conf/freedom.go +++ b/xray-core/infra/conf/freedom.go @@ -11,6 +11,7 @@ import ( "github.com/xtls/xray-core/common/protocol" "github.com/xtls/xray-core/proxy/freedom" "google.golang.org/protobuf/proto" + "github.com/xtls/xray-core/transport/internet" ) type FreedomConfig struct { @@ -47,27 +48,27 @@ func (c *FreedomConfig) Build() (proto.Message, error) { } switch strings.ToLower(targetStrategy) { case "asis", "": - config.DomainStrategy = freedom.Config_AS_IS + config.DomainStrategy = internet.DomainStrategy_AS_IS case "useip": - config.DomainStrategy = freedom.Config_USE_IP + config.DomainStrategy = internet.DomainStrategy_USE_IP case "useipv4": - config.DomainStrategy = freedom.Config_USE_IP4 + config.DomainStrategy = internet.DomainStrategy_USE_IP4 case "useipv6": - config.DomainStrategy = freedom.Config_USE_IP6 + config.DomainStrategy = internet.DomainStrategy_USE_IP6 case "useipv4v6": - config.DomainStrategy = freedom.Config_USE_IP46 + config.DomainStrategy = internet.DomainStrategy_USE_IP46 case "useipv6v4": - config.DomainStrategy = freedom.Config_USE_IP64 + config.DomainStrategy = internet.DomainStrategy_USE_IP64 case "forceip": - config.DomainStrategy = freedom.Config_FORCE_IP + config.DomainStrategy = internet.DomainStrategy_FORCE_IP case "forceipv4": - config.DomainStrategy = freedom.Config_FORCE_IP4 + config.DomainStrategy = internet.DomainStrategy_FORCE_IP4 case "forceipv6": - config.DomainStrategy = freedom.Config_FORCE_IP6 + config.DomainStrategy = internet.DomainStrategy_FORCE_IP6 case "forceipv4v6": - config.DomainStrategy = freedom.Config_FORCE_IP46 + config.DomainStrategy = internet.DomainStrategy_FORCE_IP46 case "forceipv6v4": - config.DomainStrategy = freedom.Config_FORCE_IP64 + config.DomainStrategy = internet.DomainStrategy_FORCE_IP64 default: return nil, errors.New("unsupported domain strategy: ", targetStrategy) } diff --git a/xray-core/infra/conf/freedom_test.go b/xray-core/infra/conf/freedom_test.go index 3d9d142aa5..55a8324398 100644 --- a/xray-core/infra/conf/freedom_test.go +++ b/xray-core/infra/conf/freedom_test.go @@ -7,6 +7,7 @@ import ( "github.com/xtls/xray-core/common/protocol" . "github.com/xtls/xray-core/infra/conf" "github.com/xtls/xray-core/proxy/freedom" + "github.com/xtls/xray-core/transport/internet" ) func TestFreedomConfig(t *testing.T) { @@ -23,7 +24,7 @@ func TestFreedomConfig(t *testing.T) { }`, Parser: loadJSON(creator), Output: &freedom.Config{ - DomainStrategy: freedom.Config_AS_IS, + DomainStrategy: internet.DomainStrategy_AS_IS, DestinationOverride: &freedom.DestinationOverride{ Server: &protocol.ServerEndpoint{ Address: &net.IPOrDomain{ diff --git a/xray-core/proxy/freedom/config.go b/xray-core/proxy/freedom/config.go index 2e67244b93..38bd04faa3 100644 --- a/xray-core/proxy/freedom/config.go +++ b/xray-core/proxy/freedom/config.go @@ -1,44 +1 @@ package freedom - -var strategy = [][]byte{ - // name strategy, prefer, fallback - {0, 0, 0}, // AsIs none, /, / - {1, 0, 0}, // UseIP use, both, none - {1, 4, 0}, // UseIPv4 use, 4, none - {1, 6, 0}, // UseIPv6 use, 6, none - {1, 4, 6}, // UseIPv4v6 use, 4, 6 - {1, 6, 4}, // UseIPv6v4 use, 6, 4 - {2, 0, 0}, // ForceIP force, both, none - {2, 4, 0}, // ForceIPv4 force, 4, none - {2, 6, 0}, // ForceIPv6 force, 6, none - {2, 4, 6}, // ForceIPv4v6 force, 4, 6 - {2, 6, 4}, // ForceIPv6v4 force, 6, 4 -} - -func (c *Config) hasStrategy() bool { - return strategy[c.DomainStrategy][0] != 0 -} - -func (c *Config) forceIP() bool { - return strategy[c.DomainStrategy][0] == 2 -} - -func (c *Config) preferIP4() bool { - return strategy[c.DomainStrategy][1] == 4 || strategy[c.DomainStrategy][1] == 0 -} - -func (c *Config) preferIP6() bool { - return strategy[c.DomainStrategy][1] == 6 || strategy[c.DomainStrategy][1] == 0 -} - -func (c *Config) hasFallback() bool { - return strategy[c.DomainStrategy][2] != 0 -} - -func (c *Config) fallbackIP4() bool { - return strategy[c.DomainStrategy][2] == 4 -} - -func (c *Config) fallbackIP6() bool { - return strategy[c.DomainStrategy][2] == 6 -} diff --git a/xray-core/proxy/freedom/config.pb.go b/xray-core/proxy/freedom/config.pb.go index 96855aecaa..92d52ab548 100644 --- a/xray-core/proxy/freedom/config.pb.go +++ b/xray-core/proxy/freedom/config.pb.go @@ -8,6 +8,7 @@ package freedom import ( protocol "github.com/xtls/xray-core/common/protocol" + internet "github.com/xtls/xray-core/transport/internet" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" reflect "reflect" @@ -21,79 +22,6 @@ const ( _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) ) -type Config_DomainStrategy int32 - -const ( - Config_AS_IS Config_DomainStrategy = 0 - Config_USE_IP Config_DomainStrategy = 1 - Config_USE_IP4 Config_DomainStrategy = 2 - Config_USE_IP6 Config_DomainStrategy = 3 - Config_USE_IP46 Config_DomainStrategy = 4 - Config_USE_IP64 Config_DomainStrategy = 5 - Config_FORCE_IP Config_DomainStrategy = 6 - Config_FORCE_IP4 Config_DomainStrategy = 7 - Config_FORCE_IP6 Config_DomainStrategy = 8 - Config_FORCE_IP46 Config_DomainStrategy = 9 - Config_FORCE_IP64 Config_DomainStrategy = 10 -) - -// Enum value maps for Config_DomainStrategy. -var ( - Config_DomainStrategy_name = map[int32]string{ - 0: "AS_IS", - 1: "USE_IP", - 2: "USE_IP4", - 3: "USE_IP6", - 4: "USE_IP46", - 5: "USE_IP64", - 6: "FORCE_IP", - 7: "FORCE_IP4", - 8: "FORCE_IP6", - 9: "FORCE_IP46", - 10: "FORCE_IP64", - } - Config_DomainStrategy_value = map[string]int32{ - "AS_IS": 0, - "USE_IP": 1, - "USE_IP4": 2, - "USE_IP6": 3, - "USE_IP46": 4, - "USE_IP64": 5, - "FORCE_IP": 6, - "FORCE_IP4": 7, - "FORCE_IP6": 8, - "FORCE_IP46": 9, - "FORCE_IP64": 10, - } -) - -func (x Config_DomainStrategy) Enum() *Config_DomainStrategy { - p := new(Config_DomainStrategy) - *p = x - return p -} - -func (x Config_DomainStrategy) String() string { - return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) -} - -func (Config_DomainStrategy) Descriptor() protoreflect.EnumDescriptor { - return file_proxy_freedom_config_proto_enumTypes[0].Descriptor() -} - -func (Config_DomainStrategy) Type() protoreflect.EnumType { - return &file_proxy_freedom_config_proto_enumTypes[0] -} - -func (x Config_DomainStrategy) Number() protoreflect.EnumNumber { - return protoreflect.EnumNumber(x) -} - -// Deprecated: Use Config_DomainStrategy.Descriptor instead. -func (Config_DomainStrategy) EnumDescriptor() ([]byte, []int) { - return file_proxy_freedom_config_proto_rawDescGZIP(), []int{3, 0} -} - type DestinationOverride struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -330,12 +258,12 @@ type Config struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - DomainStrategy Config_DomainStrategy `protobuf:"varint,1,opt,name=domain_strategy,json=domainStrategy,proto3,enum=xray.proxy.freedom.Config_DomainStrategy" json:"domain_strategy,omitempty"` - DestinationOverride *DestinationOverride `protobuf:"bytes,3,opt,name=destination_override,json=destinationOverride,proto3" json:"destination_override,omitempty"` - UserLevel uint32 `protobuf:"varint,4,opt,name=user_level,json=userLevel,proto3" json:"user_level,omitempty"` - Fragment *Fragment `protobuf:"bytes,5,opt,name=fragment,proto3" json:"fragment,omitempty"` - ProxyProtocol uint32 `protobuf:"varint,6,opt,name=proxy_protocol,json=proxyProtocol,proto3" json:"proxy_protocol,omitempty"` - Noises []*Noise `protobuf:"bytes,7,rep,name=noises,proto3" json:"noises,omitempty"` + DomainStrategy internet.DomainStrategy `protobuf:"varint,1,opt,name=domain_strategy,json=domainStrategy,proto3,enum=xray.transport.internet.DomainStrategy" json:"domain_strategy,omitempty"` + DestinationOverride *DestinationOverride `protobuf:"bytes,3,opt,name=destination_override,json=destinationOverride,proto3" json:"destination_override,omitempty"` + UserLevel uint32 `protobuf:"varint,4,opt,name=user_level,json=userLevel,proto3" json:"user_level,omitempty"` + Fragment *Fragment `protobuf:"bytes,5,opt,name=fragment,proto3" json:"fragment,omitempty"` + ProxyProtocol uint32 `protobuf:"varint,6,opt,name=proxy_protocol,json=proxyProtocol,proto3" json:"proxy_protocol,omitempty"` + Noises []*Noise `protobuf:"bytes,7,rep,name=noises,proto3" json:"noises,omitempty"` } func (x *Config) Reset() { @@ -368,11 +296,11 @@ func (*Config) Descriptor() ([]byte, []int) { return file_proxy_freedom_config_proto_rawDescGZIP(), []int{3} } -func (x *Config) GetDomainStrategy() Config_DomainStrategy { +func (x *Config) GetDomainStrategy() internet.DomainStrategy { if x != nil { return x.DomainStrategy } - return Config_AS_IS + return internet.DomainStrategy(0) } func (x *Config) GetDestinationOverride() *DestinationOverride { @@ -418,81 +346,72 @@ var file_proxy_freedom_config_proto_rawDesc = []byte{ 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x66, 0x72, 0x65, 0x65, 0x64, 0x6f, 0x6d, 0x1a, 0x21, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x5f, 0x73, 0x70, 0x65, 0x63, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x22, 0x53, 0x0a, 0x13, 0x44, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x4f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x12, 0x3c, 0x0a, 0x06, 0x73, 0x65, - 0x72, 0x76, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x78, 0x72, 0x61, - 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, - 0x6c, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x45, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, - 0x52, 0x06, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x22, 0x98, 0x02, 0x0a, 0x08, 0x46, 0x72, 0x61, - 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x21, 0x0a, 0x0c, 0x70, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x73, - 0x5f, 0x66, 0x72, 0x6f, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b, 0x70, 0x61, 0x63, - 0x6b, 0x65, 0x74, 0x73, 0x46, 0x72, 0x6f, 0x6d, 0x12, 0x1d, 0x0a, 0x0a, 0x70, 0x61, 0x63, 0x6b, - 0x65, 0x74, 0x73, 0x5f, 0x74, 0x6f, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x70, 0x61, - 0x63, 0x6b, 0x65, 0x74, 0x73, 0x54, 0x6f, 0x12, 0x1d, 0x0a, 0x0a, 0x6c, 0x65, 0x6e, 0x67, 0x74, - 0x68, 0x5f, 0x6d, 0x69, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x6c, 0x65, 0x6e, - 0x67, 0x74, 0x68, 0x4d, 0x69, 0x6e, 0x12, 0x1d, 0x0a, 0x0a, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, - 0x5f, 0x6d, 0x61, 0x78, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x6c, 0x65, 0x6e, 0x67, - 0x74, 0x68, 0x4d, 0x61, 0x78, 0x12, 0x21, 0x0a, 0x0c, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, - 0x6c, 0x5f, 0x6d, 0x69, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b, 0x69, 0x6e, 0x74, - 0x65, 0x72, 0x76, 0x61, 0x6c, 0x4d, 0x69, 0x6e, 0x12, 0x21, 0x0a, 0x0c, 0x69, 0x6e, 0x74, 0x65, - 0x72, 0x76, 0x61, 0x6c, 0x5f, 0x6d, 0x61, 0x78, 0x18, 0x06, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b, - 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x4d, 0x61, 0x78, 0x12, 0x22, 0x0a, 0x0d, 0x6d, - 0x61, 0x78, 0x5f, 0x73, 0x70, 0x6c, 0x69, 0x74, 0x5f, 0x6d, 0x69, 0x6e, 0x18, 0x07, 0x20, 0x01, - 0x28, 0x04, 0x52, 0x0b, 0x6d, 0x61, 0x78, 0x53, 0x70, 0x6c, 0x69, 0x74, 0x4d, 0x69, 0x6e, 0x12, - 0x22, 0x0a, 0x0d, 0x6d, 0x61, 0x78, 0x5f, 0x73, 0x70, 0x6c, 0x69, 0x74, 0x5f, 0x6d, 0x61, 0x78, - 0x18, 0x08, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b, 0x6d, 0x61, 0x78, 0x53, 0x70, 0x6c, 0x69, 0x74, - 0x4d, 0x61, 0x78, 0x22, 0xb2, 0x01, 0x0a, 0x05, 0x4e, 0x6f, 0x69, 0x73, 0x65, 0x12, 0x1d, 0x0a, - 0x0a, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x5f, 0x6d, 0x69, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x04, 0x52, 0x09, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x4d, 0x69, 0x6e, 0x12, 0x1d, 0x0a, 0x0a, - 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x5f, 0x6d, 0x61, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, - 0x52, 0x09, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x4d, 0x61, 0x78, 0x12, 0x1b, 0x0a, 0x09, 0x64, - 0x65, 0x6c, 0x61, 0x79, 0x5f, 0x6d, 0x69, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, - 0x64, 0x65, 0x6c, 0x61, 0x79, 0x4d, 0x69, 0x6e, 0x12, 0x1b, 0x0a, 0x09, 0x64, 0x65, 0x6c, 0x61, - 0x79, 0x5f, 0x6d, 0x61, 0x78, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x64, 0x65, 0x6c, - 0x61, 0x79, 0x4d, 0x61, 0x78, 0x12, 0x16, 0x0a, 0x06, 0x70, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x18, - 0x05, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x70, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x12, 0x19, 0x0a, - 0x08, 0x61, 0x70, 0x70, 0x6c, 0x79, 0x5f, 0x74, 0x6f, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x07, 0x61, 0x70, 0x70, 0x6c, 0x79, 0x54, 0x6f, 0x22, 0x97, 0x04, 0x0a, 0x06, 0x43, 0x6f, 0x6e, - 0x66, 0x69, 0x67, 0x12, 0x52, 0x0a, 0x0f, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x5f, 0x73, 0x74, - 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x29, 0x2e, 0x78, - 0x72, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x66, 0x72, 0x65, 0x65, 0x64, 0x6f, - 0x6d, 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x53, - 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x52, 0x0e, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x53, - 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x12, 0x5a, 0x0a, 0x14, 0x64, 0x65, 0x73, 0x74, 0x69, - 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x18, - 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, - 0x78, 0x79, 0x2e, 0x66, 0x72, 0x65, 0x65, 0x64, 0x6f, 0x6d, 0x2e, 0x44, 0x65, 0x73, 0x74, 0x69, - 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x52, 0x13, - 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4f, 0x76, 0x65, 0x72, 0x72, - 0x69, 0x64, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x6c, 0x65, 0x76, 0x65, - 0x6c, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x09, 0x75, 0x73, 0x65, 0x72, 0x4c, 0x65, 0x76, - 0x65, 0x6c, 0x12, 0x38, 0x0a, 0x08, 0x66, 0x72, 0x61, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x18, 0x05, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x78, - 0x79, 0x2e, 0x66, 0x72, 0x65, 0x65, 0x64, 0x6f, 0x6d, 0x2e, 0x46, 0x72, 0x61, 0x67, 0x6d, 0x65, - 0x6e, 0x74, 0x52, 0x08, 0x66, 0x72, 0x61, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x25, 0x0a, 0x0e, - 0x70, 0x72, 0x6f, 0x78, 0x79, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x18, 0x06, - 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0d, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x50, 0x72, 0x6f, 0x74, 0x6f, - 0x63, 0x6f, 0x6c, 0x12, 0x31, 0x0a, 0x06, 0x6e, 0x6f, 0x69, 0x73, 0x65, 0x73, 0x18, 0x07, 0x20, - 0x03, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, - 0x2e, 0x66, 0x72, 0x65, 0x65, 0x64, 0x6f, 0x6d, 0x2e, 0x4e, 0x6f, 0x69, 0x73, 0x65, 0x52, 0x06, - 0x6e, 0x6f, 0x69, 0x73, 0x65, 0x73, 0x22, 0xa9, 0x01, 0x0a, 0x0e, 0x44, 0x6f, 0x6d, 0x61, 0x69, - 0x6e, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x12, 0x09, 0x0a, 0x05, 0x41, 0x53, 0x5f, - 0x49, 0x53, 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x55, 0x53, 0x45, 0x5f, 0x49, 0x50, 0x10, 0x01, - 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x53, 0x45, 0x5f, 0x49, 0x50, 0x34, 0x10, 0x02, 0x12, 0x0b, 0x0a, - 0x07, 0x55, 0x53, 0x45, 0x5f, 0x49, 0x50, 0x36, 0x10, 0x03, 0x12, 0x0c, 0x0a, 0x08, 0x55, 0x53, - 0x45, 0x5f, 0x49, 0x50, 0x34, 0x36, 0x10, 0x04, 0x12, 0x0c, 0x0a, 0x08, 0x55, 0x53, 0x45, 0x5f, - 0x49, 0x50, 0x36, 0x34, 0x10, 0x05, 0x12, 0x0c, 0x0a, 0x08, 0x46, 0x4f, 0x52, 0x43, 0x45, 0x5f, - 0x49, 0x50, 0x10, 0x06, 0x12, 0x0d, 0x0a, 0x09, 0x46, 0x4f, 0x52, 0x43, 0x45, 0x5f, 0x49, 0x50, - 0x34, 0x10, 0x07, 0x12, 0x0d, 0x0a, 0x09, 0x46, 0x4f, 0x52, 0x43, 0x45, 0x5f, 0x49, 0x50, 0x36, - 0x10, 0x08, 0x12, 0x0e, 0x0a, 0x0a, 0x46, 0x4f, 0x52, 0x43, 0x45, 0x5f, 0x49, 0x50, 0x34, 0x36, - 0x10, 0x09, 0x12, 0x0e, 0x0a, 0x0a, 0x46, 0x4f, 0x52, 0x43, 0x45, 0x5f, 0x49, 0x50, 0x36, 0x34, - 0x10, 0x0a, 0x42, 0x58, 0x0a, 0x16, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x70, - 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x66, 0x72, 0x65, 0x65, 0x64, 0x6f, 0x6d, 0x50, 0x01, 0x5a, 0x27, - 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x78, 0x74, 0x6c, 0x73, 0x2f, - 0x78, 0x72, 0x61, 0x79, 0x2d, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2f, - 0x66, 0x72, 0x65, 0x65, 0x64, 0x6f, 0x6d, 0xaa, 0x02, 0x12, 0x58, 0x72, 0x61, 0x79, 0x2e, 0x50, - 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x46, 0x72, 0x65, 0x65, 0x64, 0x6f, 0x6d, 0x62, 0x06, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x33, + 0x6f, 0x74, 0x6f, 0x1a, 0x1f, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x69, + 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x53, 0x0a, 0x13, 0x44, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x4f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x12, 0x3c, 0x0a, 0x06, 0x73, + 0x65, 0x72, 0x76, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x78, 0x72, + 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, + 0x6f, 0x6c, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x45, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, + 0x74, 0x52, 0x06, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x22, 0x98, 0x02, 0x0a, 0x08, 0x46, 0x72, + 0x61, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x21, 0x0a, 0x0c, 0x70, 0x61, 0x63, 0x6b, 0x65, 0x74, + 0x73, 0x5f, 0x66, 0x72, 0x6f, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b, 0x70, 0x61, + 0x63, 0x6b, 0x65, 0x74, 0x73, 0x46, 0x72, 0x6f, 0x6d, 0x12, 0x1d, 0x0a, 0x0a, 0x70, 0x61, 0x63, + 0x6b, 0x65, 0x74, 0x73, 0x5f, 0x74, 0x6f, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x70, + 0x61, 0x63, 0x6b, 0x65, 0x74, 0x73, 0x54, 0x6f, 0x12, 0x1d, 0x0a, 0x0a, 0x6c, 0x65, 0x6e, 0x67, + 0x74, 0x68, 0x5f, 0x6d, 0x69, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x6c, 0x65, + 0x6e, 0x67, 0x74, 0x68, 0x4d, 0x69, 0x6e, 0x12, 0x1d, 0x0a, 0x0a, 0x6c, 0x65, 0x6e, 0x67, 0x74, + 0x68, 0x5f, 0x6d, 0x61, 0x78, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x6c, 0x65, 0x6e, + 0x67, 0x74, 0x68, 0x4d, 0x61, 0x78, 0x12, 0x21, 0x0a, 0x0c, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, + 0x61, 0x6c, 0x5f, 0x6d, 0x69, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b, 0x69, 0x6e, + 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x4d, 0x69, 0x6e, 0x12, 0x21, 0x0a, 0x0c, 0x69, 0x6e, 0x74, + 0x65, 0x72, 0x76, 0x61, 0x6c, 0x5f, 0x6d, 0x61, 0x78, 0x18, 0x06, 0x20, 0x01, 0x28, 0x04, 0x52, + 0x0b, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x4d, 0x61, 0x78, 0x12, 0x22, 0x0a, 0x0d, + 0x6d, 0x61, 0x78, 0x5f, 0x73, 0x70, 0x6c, 0x69, 0x74, 0x5f, 0x6d, 0x69, 0x6e, 0x18, 0x07, 0x20, + 0x01, 0x28, 0x04, 0x52, 0x0b, 0x6d, 0x61, 0x78, 0x53, 0x70, 0x6c, 0x69, 0x74, 0x4d, 0x69, 0x6e, + 0x12, 0x22, 0x0a, 0x0d, 0x6d, 0x61, 0x78, 0x5f, 0x73, 0x70, 0x6c, 0x69, 0x74, 0x5f, 0x6d, 0x61, + 0x78, 0x18, 0x08, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b, 0x6d, 0x61, 0x78, 0x53, 0x70, 0x6c, 0x69, + 0x74, 0x4d, 0x61, 0x78, 0x22, 0xb2, 0x01, 0x0a, 0x05, 0x4e, 0x6f, 0x69, 0x73, 0x65, 0x12, 0x1d, + 0x0a, 0x0a, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x5f, 0x6d, 0x69, 0x6e, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x04, 0x52, 0x09, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x4d, 0x69, 0x6e, 0x12, 0x1d, 0x0a, + 0x0a, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x5f, 0x6d, 0x61, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x04, 0x52, 0x09, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x4d, 0x61, 0x78, 0x12, 0x1b, 0x0a, 0x09, + 0x64, 0x65, 0x6c, 0x61, 0x79, 0x5f, 0x6d, 0x69, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, + 0x08, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x4d, 0x69, 0x6e, 0x12, 0x1b, 0x0a, 0x09, 0x64, 0x65, 0x6c, + 0x61, 0x79, 0x5f, 0x6d, 0x61, 0x78, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x64, 0x65, + 0x6c, 0x61, 0x79, 0x4d, 0x61, 0x78, 0x12, 0x16, 0x0a, 0x06, 0x70, 0x61, 0x63, 0x6b, 0x65, 0x74, + 0x18, 0x05, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x70, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x12, 0x19, + 0x0a, 0x08, 0x61, 0x70, 0x70, 0x6c, 0x79, 0x5f, 0x74, 0x6f, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x07, 0x61, 0x70, 0x70, 0x6c, 0x79, 0x54, 0x6f, 0x22, 0xe9, 0x02, 0x0a, 0x06, 0x43, 0x6f, + 0x6e, 0x66, 0x69, 0x67, 0x12, 0x50, 0x0a, 0x0f, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x5f, 0x73, + 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x27, 0x2e, + 0x78, 0x72, 0x61, 0x79, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, + 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x53, 0x74, + 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x52, 0x0e, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x53, 0x74, + 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x12, 0x5a, 0x0a, 0x14, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x78, + 0x79, 0x2e, 0x66, 0x72, 0x65, 0x65, 0x64, 0x6f, 0x6d, 0x2e, 0x44, 0x65, 0x73, 0x74, 0x69, 0x6e, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x52, 0x13, 0x64, + 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4f, 0x76, 0x65, 0x72, 0x72, 0x69, + 0x64, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x6c, 0x65, 0x76, 0x65, 0x6c, + 0x18, 0x04, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x09, 0x75, 0x73, 0x65, 0x72, 0x4c, 0x65, 0x76, 0x65, + 0x6c, 0x12, 0x38, 0x0a, 0x08, 0x66, 0x72, 0x61, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x18, 0x05, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, + 0x2e, 0x66, 0x72, 0x65, 0x65, 0x64, 0x6f, 0x6d, 0x2e, 0x46, 0x72, 0x61, 0x67, 0x6d, 0x65, 0x6e, + 0x74, 0x52, 0x08, 0x66, 0x72, 0x61, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x25, 0x0a, 0x0e, 0x70, + 0x72, 0x6f, 0x78, 0x79, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x18, 0x06, 0x20, + 0x01, 0x28, 0x0d, 0x52, 0x0d, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, + 0x6f, 0x6c, 0x12, 0x31, 0x0a, 0x06, 0x6e, 0x6f, 0x69, 0x73, 0x65, 0x73, 0x18, 0x07, 0x20, 0x03, + 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, + 0x66, 0x72, 0x65, 0x65, 0x64, 0x6f, 0x6d, 0x2e, 0x4e, 0x6f, 0x69, 0x73, 0x65, 0x52, 0x06, 0x6e, + 0x6f, 0x69, 0x73, 0x65, 0x73, 0x42, 0x58, 0x0a, 0x16, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x72, 0x61, + 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x66, 0x72, 0x65, 0x65, 0x64, 0x6f, 0x6d, 0x50, + 0x01, 0x5a, 0x27, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x78, 0x74, + 0x6c, 0x73, 0x2f, 0x78, 0x72, 0x61, 0x79, 0x2d, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x70, 0x72, 0x6f, + 0x78, 0x79, 0x2f, 0x66, 0x72, 0x65, 0x65, 0x64, 0x6f, 0x6d, 0xaa, 0x02, 0x12, 0x58, 0x72, 0x61, + 0x79, 0x2e, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x46, 0x72, 0x65, 0x65, 0x64, 0x6f, 0x6d, 0x62, + 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -507,22 +426,21 @@ func file_proxy_freedom_config_proto_rawDescGZIP() []byte { return file_proxy_freedom_config_proto_rawDescData } -var file_proxy_freedom_config_proto_enumTypes = make([]protoimpl.EnumInfo, 1) var file_proxy_freedom_config_proto_msgTypes = make([]protoimpl.MessageInfo, 4) var file_proxy_freedom_config_proto_goTypes = []any{ - (Config_DomainStrategy)(0), // 0: xray.proxy.freedom.Config.DomainStrategy - (*DestinationOverride)(nil), // 1: xray.proxy.freedom.DestinationOverride - (*Fragment)(nil), // 2: xray.proxy.freedom.Fragment - (*Noise)(nil), // 3: xray.proxy.freedom.Noise - (*Config)(nil), // 4: xray.proxy.freedom.Config - (*protocol.ServerEndpoint)(nil), // 5: xray.common.protocol.ServerEndpoint + (*DestinationOverride)(nil), // 0: xray.proxy.freedom.DestinationOverride + (*Fragment)(nil), // 1: xray.proxy.freedom.Fragment + (*Noise)(nil), // 2: xray.proxy.freedom.Noise + (*Config)(nil), // 3: xray.proxy.freedom.Config + (*protocol.ServerEndpoint)(nil), // 4: xray.common.protocol.ServerEndpoint + (internet.DomainStrategy)(0), // 5: xray.transport.internet.DomainStrategy } var file_proxy_freedom_config_proto_depIdxs = []int32{ - 5, // 0: xray.proxy.freedom.DestinationOverride.server:type_name -> xray.common.protocol.ServerEndpoint - 0, // 1: xray.proxy.freedom.Config.domain_strategy:type_name -> xray.proxy.freedom.Config.DomainStrategy - 1, // 2: xray.proxy.freedom.Config.destination_override:type_name -> xray.proxy.freedom.DestinationOverride - 2, // 3: xray.proxy.freedom.Config.fragment:type_name -> xray.proxy.freedom.Fragment - 3, // 4: xray.proxy.freedom.Config.noises:type_name -> xray.proxy.freedom.Noise + 4, // 0: xray.proxy.freedom.DestinationOverride.server:type_name -> xray.common.protocol.ServerEndpoint + 5, // 1: xray.proxy.freedom.Config.domain_strategy:type_name -> xray.transport.internet.DomainStrategy + 0, // 2: xray.proxy.freedom.Config.destination_override:type_name -> xray.proxy.freedom.DestinationOverride + 1, // 3: xray.proxy.freedom.Config.fragment:type_name -> xray.proxy.freedom.Fragment + 2, // 4: xray.proxy.freedom.Config.noises:type_name -> xray.proxy.freedom.Noise 5, // [5:5] is the sub-list for method output_type 5, // [5:5] is the sub-list for method input_type 5, // [5:5] is the sub-list for extension type_name @@ -540,14 +458,13 @@ func file_proxy_freedom_config_proto_init() { File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_proxy_freedom_config_proto_rawDesc, - NumEnums: 1, + NumEnums: 0, NumMessages: 4, NumExtensions: 0, NumServices: 0, }, GoTypes: file_proxy_freedom_config_proto_goTypes, DependencyIndexes: file_proxy_freedom_config_proto_depIdxs, - EnumInfos: file_proxy_freedom_config_proto_enumTypes, MessageInfos: file_proxy_freedom_config_proto_msgTypes, }.Build() File_proxy_freedom_config_proto = out.File diff --git a/xray-core/proxy/freedom/config.proto b/xray-core/proxy/freedom/config.proto index 3a59e44d58..fd0547d80b 100644 --- a/xray-core/proxy/freedom/config.proto +++ b/xray-core/proxy/freedom/config.proto @@ -7,6 +7,7 @@ option java_package = "com.xray.proxy.freedom"; option java_multiple_files = true; import "common/protocol/server_spec.proto"; +import "transport/internet/config.proto"; message DestinationOverride { xray.common.protocol.ServerEndpoint server = 1; @@ -32,20 +33,7 @@ message Noise { } message Config { - enum DomainStrategy { - AS_IS = 0; - USE_IP = 1; - USE_IP4 = 2; - USE_IP6 = 3; - USE_IP46 = 4; - USE_IP64 = 5; - FORCE_IP = 6; - FORCE_IP4 = 7; - FORCE_IP6 = 8; - FORCE_IP46 = 9; - FORCE_IP64 = 10; - } - DomainStrategy domain_strategy = 1; + xray.transport.internet.DomainStrategy domain_strategy = 1; DestinationOverride destination_override = 3; uint32 user_level = 4; Fragment fragment = 5; diff --git a/xray-core/proxy/freedom/freedom.go b/xray-core/proxy/freedom/freedom.go index 99b24fef77..0e9937e3c7 100644 --- a/xray-core/proxy/freedom/freedom.go +++ b/xray-core/proxy/freedom/freedom.go @@ -20,7 +20,6 @@ import ( "github.com/xtls/xray-core/common/task" "github.com/xtls/xray-core/common/utils" "github.com/xtls/xray-core/core" - "github.com/xtls/xray-core/features/dns" "github.com/xtls/xray-core/features/policy" "github.com/xtls/xray-core/features/stats" "github.com/xtls/xray-core/proxy" @@ -35,8 +34,8 @@ var useSplice bool func init() { common.Must(common.RegisterConfig((*Config)(nil), func(ctx context.Context, config interface{}) (interface{}, error) { h := new(Handler) - if err := core.RequireFeatures(ctx, func(pm policy.Manager, d dns.Client) error { - return h.Init(config.(*Config), pm, d) + if err := core.RequireFeatures(ctx, func(pm policy.Manager) error { + return h.Init(config.(*Config), pm) }); err != nil { return nil, err } @@ -53,16 +52,13 @@ func init() { // Handler handles Freedom connections. type Handler struct { policyManager policy.Manager - dns dns.Client config *Config } // Init initializes the Handler with necessary parameters. -func (h *Handler) Init(config *Config, pm policy.Manager, d dns.Client) error { +func (h *Handler) Init(config *Config, pm policy.Manager) error { h.config = config h.policyManager = pm - h.dns = d - return nil } @@ -71,28 +67,6 @@ func (h *Handler) policy() policy.Session { return p } -func (h *Handler) resolveIP(ctx context.Context, domain string, localAddr net.Address) net.Address { - ips, _, err := h.dns.LookupIP(domain, dns.IPOption{ - IPv4Enable: (localAddr == nil || localAddr.Family().IsIPv4()) && h.config.preferIP4(), - IPv6Enable: (localAddr == nil || localAddr.Family().IsIPv6()) && h.config.preferIP6(), - }) - { // Resolve fallback - if (len(ips) == 0 || err != nil) && h.config.hasFallback() && localAddr == nil { - ips, _, err = h.dns.LookupIP(domain, dns.IPOption{ - IPv4Enable: h.config.fallbackIP4(), - IPv6Enable: h.config.fallbackIP6(), - }) - } - } - if err != nil { - errors.LogInfoInner(ctx, err, "failed to get IP address for domain ", domain) - } - if len(ips) == 0 { - return nil - } - return net.IPAddress(ips[dice.Roll(len(ips))]) -} - func isValidAddress(addr *net.IPOrDomain) bool { if addr == nil { return false @@ -114,6 +88,12 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte inbound := session.InboundFromContext(ctx) destination := ob.Target + origTargetAddr := ob.OriginalTarget.Address + if origTargetAddr == nil { + origTargetAddr = ob.Target.Address + } + dialer.SetOutboundGateway(ctx, ob) + outGateway := ob.Gateway UDPOverride := net.UDPDestination(nil, 0) if h.config.DestinationOverride != nil { server := h.config.DestinationOverride.Server @@ -133,17 +113,24 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte var conn stat.Connection err := retry.ExponentialBackoff(5, 100).On(func() error { dialDest := destination - if h.config.hasStrategy() && dialDest.Address.Family().IsDomain() { - ip := h.resolveIP(ctx, dialDest.Address.Domain(), dialer.Address()) - if ip != nil { + if h.config.DomainStrategy.HasStrategy() && dialDest.Address.Family().IsDomain() { + strategy := h.config.DomainStrategy + if destination.Network == net.Network_UDP && origTargetAddr != nil && outGateway == nil { + strategy = strategy.GetDynamicStrategy(origTargetAddr.Family()) + } + ips, err := internet.LookupForIP(dialDest.Address.Domain(), strategy, outGateway) + if err != nil { + errors.LogInfoInner(ctx, err, "failed to get IP address for domain ", dialDest.Address.Domain()) + if h.config.DomainStrategy.ForceIP() { + return err + } + } else { dialDest = net.Destination{ Network: dialDest.Network, - Address: ip, + Address: net.IPAddress(ips[dice.Roll(len(ips))]), Port: dialDest.Port, } errors.LogInfo(ctx, "dialing to ", dialDest) - } else if h.config.forceIP() { - return dns.ErrEmptyResponse } } @@ -203,7 +190,7 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte writer = buf.NewWriter(conn) } } else { - writer = NewPacketWriter(conn, h, ctx, UDPOverride, destination) + writer = NewPacketWriter(conn, h, UDPOverride, destination) if h.config.Noises != nil { errors.LogDebug(ctx, "NOISE", h.config.Noises) writer = &NoisePacketWriter{ @@ -339,7 +326,7 @@ func (r *PacketReader) ReadMultiBuffer() (buf.MultiBuffer, error) { } // DialDest means the dial target used in the dialer when creating conn -func NewPacketWriter(conn net.Conn, h *Handler, ctx context.Context, UDPOverride net.Destination, DialDest net.Destination) buf.Writer { +func NewPacketWriter(conn net.Conn, h *Handler, UDPOverride net.Destination, DialDest net.Destination) buf.Writer { iConn := conn statConn, ok := iConn.(*stat.CounterConnection) if ok { @@ -360,9 +347,9 @@ func NewPacketWriter(conn net.Conn, h *Handler, ctx context.Context, UDPOverride PacketConnWrapper: c, Counter: counter, Handler: h, - Context: ctx, UDPOverride: UDPOverride, - resolvedUDPAddr: resolvedUDPAddr, + ResolvedUDPAddr: resolvedUDPAddr, + LocalAddr: net.DestinationFromAddr(conn.LocalAddr()).Address, } } @@ -373,14 +360,14 @@ type PacketWriter struct { *internet.PacketConnWrapper stats.Counter *Handler - context.Context UDPOverride net.Destination // Dest of udp packets might be a domain, we will resolve them to IP // But resolver will return a random one if the domain has many IPs // Resulting in these packets being sent to many different IPs randomly // So, cache and keep the resolve result - resolvedUDPAddr *utils.TypedSyncMap[string, net.Address] + ResolvedUDPAddr *utils.TypedSyncMap[string, net.Address] + LocalAddr net.Address } func (w *PacketWriter) WriteMultiBuffer(mb buf.MultiBuffer) error { @@ -400,20 +387,22 @@ func (w *PacketWriter) WriteMultiBuffer(mb buf.MultiBuffer) error { b.UDP.Port = w.UDPOverride.Port } if b.UDP.Address.Family().IsDomain() { - if ip, ok := w.resolvedUDPAddr.Load(b.UDP.Address.Domain()); ok { + if ip, ok := w.ResolvedUDPAddr.Load(b.UDP.Address.Domain()); ok { b.UDP.Address = ip } else { ShouldUseSystemResolver := true - if w.Handler.config.hasStrategy() { - ip = w.Handler.resolveIP(w.Context, b.UDP.Address.Domain(), nil) - if ip != nil { + if w.Handler.config.DomainStrategy.HasStrategy() { + ips, err := internet.LookupForIP(b.UDP.Address.Domain(), w.Handler.config.DomainStrategy, w.LocalAddr) + if err != nil { + // drop packet if resolve failed when forceIP + if w.Handler.config.DomainStrategy.ForceIP() { + b.Release() + continue + } + } else { + ip = net.IPAddress(ips[dice.Roll(len(ips))]) ShouldUseSystemResolver = false } - // drop packet if resolve failed when forceIP - if ip == nil && w.Handler.config.forceIP() { - b.Release() - continue - } } if ShouldUseSystemResolver { udpAddr, err := net.ResolveUDPAddr("udp", b.UDP.NetAddr()) @@ -425,7 +414,7 @@ func (w *PacketWriter) WriteMultiBuffer(mb buf.MultiBuffer) error { } } if ip != nil { - b.UDP.Address, _ = w.resolvedUDPAddr.LoadOrStore(b.UDP.Address.Domain(), ip) + b.UDP.Address, _ = w.ResolvedUDPAddr.LoadOrStore(b.UDP.Address.Domain(), ip) } } } @@ -496,7 +485,10 @@ func (w *NoisePacketWriter) WriteMultiBuffer(mb buf.MultiBuffer) error { if err != nil { return err } - w.Writer.WriteMultiBuffer(buf.MultiBuffer{buf.FromBytes(noise)}) + err = w.Writer.WriteMultiBuffer(buf.MultiBuffer{buf.FromBytes(noise)}) + if err != nil { + return err + } if n.DelayMin != 0 || n.DelayMax != 0 { time.Sleep(time.Duration(crypto.RandBetween(int64(n.DelayMin), int64(n.DelayMax))) * time.Millisecond) diff --git a/xray-core/testing/scenarios/dns_test.go b/xray-core/testing/scenarios/dns_test.go index 1c6d8277a1..4de2fe7e3d 100644 --- a/xray-core/testing/scenarios/dns_test.go +++ b/xray-core/testing/scenarios/dns_test.go @@ -16,6 +16,7 @@ import ( "github.com/xtls/xray-core/proxy/freedom" "github.com/xtls/xray-core/proxy/socks" "github.com/xtls/xray-core/testing/servers/tcp" + "github.com/xtls/xray-core/transport/internet" xproxy "golang.org/x/net/proxy" ) @@ -83,7 +84,7 @@ func TestResolveIP(t *testing.T) { { Tag: "direct", ProxySettings: serial.ToTypedMessage(&freedom.Config{ - DomainStrategy: freedom.Config_USE_IP, + DomainStrategy: internet.DomainStrategy_USE_IP, }), }, }, diff --git a/xray-core/transport/internet/config.go b/xray-core/transport/internet/config.go index 6978eaceb5..bd6dfac4fe 100644 --- a/xray-core/transport/internet/config.go +++ b/xray-core/transport/internet/config.go @@ -2,6 +2,7 @@ package internet import ( "github.com/xtls/xray-core/common/errors" + "github.com/xtls/xray-core/common/net" "github.com/xtls/xray-core/common/serial" ) @@ -127,3 +128,25 @@ func (s DomainStrategy) FallbackIP4() bool { func (s DomainStrategy) FallbackIP6() bool { return strategy[s][2] == 6 } + +func (s DomainStrategy) GetDynamicStrategy(addrFamily net.AddressFamily) DomainStrategy { + if addrFamily.IsDomain(){ + return s + } + switch s { + case DomainStrategy_USE_IP: + if addrFamily.IsIPv4() { + return DomainStrategy_USE_IP46 + } else if addrFamily.IsIPv6() { + return DomainStrategy_USE_IP64 + } + case DomainStrategy_FORCE_IP: + if addrFamily.IsIPv4() { + return DomainStrategy_FORCE_IP46 + } else if addrFamily.IsIPv6() { + return DomainStrategy_FORCE_IP64 + } + default: + } + return s +} diff --git a/xray-core/transport/internet/dialer.go b/xray-core/transport/internet/dialer.go index a53498abaa..4ac478ecdb 100644 --- a/xray-core/transport/internet/dialer.go +++ b/xray-core/transport/internet/dialer.go @@ -24,11 +24,11 @@ type Dialer interface { // Dial dials a system connection to the given destination. Dial(ctx context.Context, destination net.Destination) (stat.Connection, error) - // Address returns the address used by this Dialer. Maybe nil if not known. - Address() net.Address - // DestIpAddress returns the ip of proxy server. It is useful in case of Android client, which prepare an IP before proxy connection is established DestIpAddress() net.IP + + // SetOutboundGateway set outbound gateway + SetOutboundGateway(ctx context.Context, ob *session.Outbound) } // dialFunc is an interface to dial network connection to a specific destination. @@ -91,8 +91,8 @@ func LookupForIP(domain string, strategy DomainStrategy, localAddr net.Address) } ips, _, err := dnsClient.LookupIP(domain, dns.IPOption{ - IPv4Enable: (localAddr == nil || localAddr.Family().IsIPv4()) && strategy.PreferIP4(), - IPv6Enable: (localAddr == nil || localAddr.Family().IsIPv6()) && strategy.PreferIP6(), + IPv4Enable: (localAddr == nil && strategy.PreferIP4()) || (localAddr != nil && localAddr.Family().IsIPv4() && (strategy.PreferIP4() || strategy.FallbackIP4())), + IPv6Enable: (localAddr == nil && strategy.PreferIP6()) || (localAddr != nil && localAddr.Family().IsIPv6() && (strategy.PreferIP6() || strategy.FallbackIP6())), }) { // Resolve fallback if (len(ips) == 0 || err != nil) && strategy.HasFallback() && localAddr == nil { @@ -109,13 +109,6 @@ func LookupForIP(domain string, strategy DomainStrategy, localAddr net.Address) return ips, err } -func canLookupIP(dst net.Destination, sockopt *SocketConfig) bool { - if dst.Address.Family().IsIP() { - return false - } - return sockopt.DomainStrategy.HasStrategy() -} - func redirect(ctx context.Context, dst net.Destination, obt string, h outbound.Handler) net.Conn { errors.LogInfo(ctx, "redirecting request "+dst.String()+" to "+obt) outbounds := session.OutboundsFromContext(ctx) @@ -235,9 +228,15 @@ func checkAddressPortStrategy(ctx context.Context, dest net.Destination, sockopt func DialSystem(ctx context.Context, dest net.Destination, sockopt *SocketConfig) (net.Conn, error) { var src net.Address outbounds := session.OutboundsFromContext(ctx) + var outboundName string + var origTargetAddr net.Address if len(outbounds) > 0 { ob := outbounds[len(outbounds)-1] - src = ob.Gateway + if sockopt == nil || len(sockopt.DialerProxy) == 0 { + src = ob.Gateway + } + outboundName = ob.Name + origTargetAddr = ob.OriginalTarget.Address } if sockopt == nil { return effectiveSystemDialer.Dial(ctx, src, dest, sockopt) @@ -248,8 +247,12 @@ func DialSystem(ctx context.Context, dest net.Destination, sockopt *SocketConfig dest = *newDest } - if canLookupIP(dest, sockopt) { - ips, err := LookupForIP(dest.Address.String(), sockopt.DomainStrategy, src) + if sockopt.DomainStrategy.HasStrategy() && dest.Address.Family().IsDomain() { + finalStrategy := sockopt.DomainStrategy + if outboundName == "freedom" && dest.Network == net.Network_UDP && origTargetAddr != nil && src == nil { + finalStrategy = finalStrategy.GetDynamicStrategy(origTargetAddr.Family()) + } + ips, err := LookupForIP(dest.Address.Domain(), finalStrategy, src) if err != nil { errors.LogErrorInner(ctx, err, "failed to resolve ip") if sockopt.DomainStrategy.ForceIP() { diff --git a/yt-dlp/yt_dlp/extractor/vimeo.py b/yt-dlp/yt_dlp/extractor/vimeo.py index b22bea5204..ce3f441be7 100644 --- a/yt-dlp/yt_dlp/extractor/vimeo.py +++ b/yt-dlp/yt_dlp/extractor/vimeo.py @@ -28,7 +28,6 @@ from ..utils import ( qualities, smuggle_url, str_or_none, - traverse_obj, try_call, try_get, unified_timestamp, @@ -39,6 +38,7 @@ from ..utils import ( urlhandle_detect_ext, urljoin, ) +from ..utils.traversal import require, traverse_obj class VimeoBaseInfoExtractor(InfoExtractor): @@ -117,13 +117,13 @@ class VimeoBaseInfoExtractor(InfoExtractor): def _jwt_is_expired(self, token): return jwt_decode_hs256(token)['exp'] - time.time() < 120 - def _fetch_viewer_info(self, display_id=None, fatal=True): + def _fetch_viewer_info(self, display_id=None): if self._viewer_info and not self._jwt_is_expired(self._viewer_info['jwt']): return self._viewer_info self._viewer_info = self._download_json( 'https://vimeo.com/_next/viewer', display_id, 'Downloading web token info', - 'Failed to download web token info', fatal=fatal, headers={'Accept': 'application/json'}) + 'Failed to download web token info', headers={'Accept': 'application/json'}) return self._viewer_info @@ -502,6 +502,43 @@ class VimeoBaseInfoExtractor(InfoExtractor): 'quality': 1, } + @staticmethod + def _get_embed_params(is_embed, referer): + return { + 'is_embed': 'true' if is_embed else 'false', + 'referrer': urllib.parse.urlparse(referer).hostname if referer and is_embed else '', + } + + def _get_album_data_and_hashed_pass(self, album_id, is_embed, referer): + viewer = self._fetch_viewer_info(album_id) + jwt = viewer['jwt'] + album = self._download_json( + 'https://api.vimeo.com/albums/' + album_id, + album_id, headers={'Authorization': 'jwt ' + jwt, 'Accept': 'application/json'}, + query={**self._get_embed_params(is_embed, referer), 'fields': 'description,name,privacy'}) + hashed_pass = None + if traverse_obj(album, ('privacy', 'view')) == 'password': + password = self.get_param('videopassword') + if not password: + raise ExtractorError( + 'This album is protected by a password, use the --video-password option', + expected=True) + try: + hashed_pass = self._download_json( + f'https://vimeo.com/showcase/{album_id}/auth', + album_id, 'Verifying the password', data=urlencode_postdata({ + 'password': password, + 'token': viewer['xsrft'], + }), headers={ + 'X-Requested-With': 'XMLHttpRequest', + })['hashed_pass'] + except ExtractorError as e: + if isinstance(e.cause, HTTPError) and e.cause.status == 401: + raise ExtractorError('Wrong password', expected=True) + raise + + return album, hashed_pass + class VimeoIE(VimeoBaseInfoExtractor): """Information extractor for vimeo.com.""" @@ -1188,42 +1225,6 @@ class VimeoIE(VimeoBaseInfoExtractor): info[k + '_count'] = int_or_none(try_get(connections, lambda x: x[k + 's']['total'])) return info - def _try_album_password(self, url): - album_id = self._search_regex( - r'vimeo\.com/(?:album|showcase)/([^/]+)', url, 'album id', default=None) - if not album_id: - return - viewer = self._fetch_viewer_info(album_id, fatal=False) - if not viewer: - webpage = self._download_webpage(url, album_id) - viewer = self._parse_json(self._search_regex( - r'bootstrap_data\s*=\s*({.+?})', - webpage, 'bootstrap data'), album_id)['viewer'] - jwt = viewer['jwt'] - album = self._download_json( - 'https://api.vimeo.com/albums/' + album_id, - album_id, headers={'Authorization': 'jwt ' + jwt, 'Accept': 'application/json'}, - query={'fields': 'description,name,privacy'}) - if try_get(album, lambda x: x['privacy']['view']) == 'password': - password = self.get_param('videopassword') - if not password: - raise ExtractorError( - 'This album is protected by a password, use the --video-password option', - expected=True) - try: - self._download_json( - f'https://vimeo.com/showcase/{album_id}/auth', - album_id, 'Verifying the password', data=urlencode_postdata({ - 'password': password, - 'token': viewer['xsrft'], - }), headers={ - 'X-Requested-With': 'XMLHttpRequest', - }) - except ExtractorError as e: - if isinstance(e.cause, HTTPError) and e.cause.status == 401: - raise ExtractorError('Wrong password', expected=True) - raise - def _real_extract(self, url): url, data, headers = self._unsmuggle_headers(url) if 'Referer' not in headers: @@ -1238,8 +1239,14 @@ class VimeoIE(VimeoBaseInfoExtractor): if any(p in url for p in ('play_redirect_hls', 'moogaloop.swf')): url = 'https://vimeo.com/' + video_id - self._try_album_password(url) - is_secure = urllib.parse.urlparse(url).scheme == 'https' + album_id = self._search_regex( + r'vimeo\.com/(?:album|showcase)/([0-9]+)/', url, 'album id', default=None) + if album_id: + # Detect password-protected showcase video => POST album password => set cookies + self._get_album_data_and_hashed_pass(album_id, False, None) + + parsed_url = urllib.parse.urlparse(url) + is_secure = parsed_url.scheme == 'https' try: # Retrieve video webpage to extract further information webpage, urlh = self._download_webpage_handle( @@ -1265,7 +1272,7 @@ class VimeoIE(VimeoBaseInfoExtractor): f'{self._downloader._format_err("compromising your security/cookies", "light red")}, ' f'try replacing "https:" with "http:" in the input URL. {dcip_msg}.', expected=True) - if '://player.vimeo.com/video/' in url: + if parsed_url.hostname == 'player.vimeo.com': config = self._search_json( r'\b(?:playerC|c)onfig\s*=', webpage, 'info section', video_id) if config.get('view') == 4: @@ -1293,7 +1300,7 @@ class VimeoIE(VimeoBaseInfoExtractor): config_url = None channel_id = self._search_regex( - r'vimeo\.com/channels/([^/]+)', url, 'channel id', default=None) + r'vimeo\.com/channels/([^/?#]+)', url, 'channel id', default=None) if channel_id: config_url = self._extract_config_url(webpage, default=None) video_description = clean_html(get_element_by_class('description', webpage)) @@ -1531,7 +1538,7 @@ class VimeoUserIE(VimeoChannelIE): # XXX: Do not subclass from concrete IE class VimeoAlbumIE(VimeoBaseInfoExtractor): IE_NAME = 'vimeo:album' - _VALID_URL = r'https://vimeo\.com/(?:album|showcase)/(?P\d+)(?:$|[?#]|/(?!video))' + _VALID_URL = r'https://vimeo\.com/(?:album|showcase)/(?P[^/?#]+)(?:$|[?#]|(?P/embed))' _TITLE_RE = r'