Update On Thu May 15 20:37:50 CEST 2025

This commit is contained in:
github-action[bot]
2025-05-15 20:37:50 +02:00
parent 40de315c68
commit 3800404536
54 changed files with 600 additions and 384 deletions
+1
View File
@@ -999,3 +999,4 @@ Update On Sun May 11 20:34:28 CEST 2025
Update On Mon May 12 20:36:32 CEST 2025
Update On Tue May 13 20:37:30 CEST 2025
Update On Wed May 14 20:34:49 CEST 2025
Update On Thu May 15 20:37:42 CEST 2025
+3
View File
@@ -13,11 +13,14 @@ import (
type RealityOptions struct {
PublicKey string `proxy:"public-key"`
ShortID string `proxy:"short-id"`
SupportX25519MLKEM768 bool `proxy:"support-x25519mlkem768"`
}
func (o RealityOptions) Parse() (*tlsC.RealityConfig, error) {
if o.PublicKey != "" {
config := new(tlsC.RealityConfig)
config.SupportX25519MLKEM768 = o.SupportX25519MLKEM768
const x25519ScalarSize = 32
publicKey, err := base64.RawURLEncoding.DecodeString(o.PublicKey)
+24 -24
View File
@@ -35,6 +35,8 @@ const RealityMaxShortIDLen = 8
type RealityConfig struct {
PublicKey *ecdh.PublicKey
ShortID [RealityMaxShortIDLen]byte
SupportX25519MLKEM768 bool
}
func GetRealityConn(ctx context.Context, conn net.Conn, fingerprint UClientHelloID, tlsConfig *tls.Config, realityConfig *RealityConfig) (net.Conn, error) {
@@ -48,38 +50,36 @@ func GetRealityConn(ctx context.Context, conn net.Conn, fingerprint UClientHello
SessionTicketsDisabled: true,
VerifyPeerCertificate: verifier.VerifyPeerCertificate,
}
clientID := utls.ClientHelloID{
Client: fingerprint.Client,
Version: fingerprint.Version,
Seed: fingerprint.Seed,
}
uConn := utls.UClient(conn, uConfig, clientID)
uConn := utls.UClient(conn, uConfig, fingerprint)
verifier.UConn = uConn
err := uConn.BuildHandshakeState()
if err != nil {
return nil, err
}
// ------for X25519MLKEM768 does not work properly with reality-------
// Iterate over extensions and check
for _, extension := range uConn.Extensions {
if ce, ok := extension.(*utls.SupportedCurvesExtension); ok {
ce.Curves = slices.DeleteFunc(ce.Curves, func(curveID utls.CurveID) bool {
return curveID == utls.X25519MLKEM768
})
if !realityConfig.SupportX25519MLKEM768 {
// ------for X25519MLKEM768 does not work properly with the old reality server-------
// Iterate over extensions and check
for _, extension := range uConn.Extensions {
if ce, ok := extension.(*utls.SupportedCurvesExtension); ok {
ce.Curves = slices.DeleteFunc(ce.Curves, func(curveID utls.CurveID) bool {
return curveID == utls.X25519MLKEM768
})
}
if ks, ok := extension.(*utls.KeyShareExtension); ok {
ks.KeyShares = slices.DeleteFunc(ks.KeyShares, func(share utls.KeyShare) bool {
return share.Group == utls.X25519MLKEM768
})
}
}
if ks, ok := extension.(*utls.KeyShareExtension); ok {
ks.KeyShares = slices.DeleteFunc(ks.KeyShares, func(share utls.KeyShare) bool {
return share.Group == utls.X25519MLKEM768
})
// Rebuild the client hello
err = uConn.BuildHandshakeState()
if err != nil {
return nil, err
}
// --------------------------------------------------------------------
}
// Rebuild the client hello
err = uConn.BuildHandshakeState()
if err != nil {
return nil, err
}
// --------------------------------------------------------------------
hello := uConn.HandshakeState.Hello
rawSessionID := hello.Raw[39 : 39+32] // the location of session ID
@@ -144,7 +144,7 @@ func GetRealityConn(ctx context.Context, conn net.Conn, fingerprint UClientHello
log.Debugln("REALITY Authentication: %v, AEAD: %T", verifier.verified, aeadCipher)
if !verifier.verified {
go realityClientFallback(uConn, uConfig.ServerName, clientID)
go realityClientFallback(uConn, uConfig.ServerName, fingerprint)
return nil, errors.New("REALITY authentication failed")
}
+1 -1
View File
@@ -36,7 +36,7 @@ require (
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-20250503140532-decbcfccbfdf
github.com/metacubex/utls v1.7.0-alpha.3
github.com/metacubex/utls v1.7.3
github.com/metacubex/wireguard-go v0.0.0-20240922131502-c182e7471181
github.com/miekg/dns v1.1.63 // lastest version compatible with golang1.20
github.com/mroth/weightedrand/v2 v2.1.0
+2 -2
View File
@@ -138,8 +138,8 @@ github.com/metacubex/smux v0.0.0-20250503055512-501391591dee h1:lp6hJ+4wCLZu113a
github.com/metacubex/smux v0.0.0-20250503055512-501391591dee/go.mod h1:4bPD8HWx9jPJ9aE4uadgyN7D1/Wz3KmPy+vale8sKLE=
github.com/metacubex/tfo-go v0.0.0-20250503140532-decbcfccbfdf h1:LwID1wz4tzypidd412dd4dC1H0m1TgRCQ/XvRvMJDFM=
github.com/metacubex/tfo-go v0.0.0-20250503140532-decbcfccbfdf/go.mod h1:l9oLnLoEXyGZ5RVLsh7QCC5XsouTUyKk4F2nLm2DHLw=
github.com/metacubex/utls v1.7.0-alpha.3 h1:cp1cEMUnoifiWrGHRzo+nCwPRveN9yPD8QaRFmfcYxA=
github.com/metacubex/utls v1.7.0-alpha.3/go.mod h1:oknYT0qTOwE4hjPmZOEpzVdefnW7bAdGLvZcqmk4TLU=
github.com/metacubex/utls v1.7.3 h1:yDcMEWojFh+t8rU9X0HPcZDPAoFze/rIIyssqivzj8A=
github.com/metacubex/utls v1.7.3/go.mod h1:oknYT0qTOwE4hjPmZOEpzVdefnW7bAdGLvZcqmk4TLU=
github.com/metacubex/wireguard-go v0.0.0-20240922131502-c182e7471181 h1:hJLQviGySBuaynlCwf/oYgIxbVbGRUIKZCxdya9YrbQ=
github.com/metacubex/wireguard-go v0.0.0-20240922131502-c182e7471181/go.mod h1:phewKljNYiTVT31Gcif8RiCKnTUOgVWFJjccqYM8s+Y=
github.com/miekg/dns v1.1.63 h1:8M5aAw6OMZfFXTT7K5V0Eu5YiiL8l7nUAkyN6C9YwaY=
+3 -3
View File
@@ -31,7 +31,7 @@ func (l *LogLevel) UnmarshalYAML(unmarshal func(any) error) error {
unmarshal(&tp)
level, exist := LogLevelMapping[strings.ToLower(tp)]
if !exist {
return errors.New("invalid mode")
return errors.New("invalid log-level")
}
*l = level
return nil
@@ -43,7 +43,7 @@ func (l *LogLevel) UnmarshalJSON(data []byte) error {
json.Unmarshal(data, &tp)
level, exist := LogLevelMapping[strings.ToLower(tp)]
if !exist {
return errors.New("invalid mode")
return errors.New("invalid log-level")
}
*l = level
return nil
@@ -53,7 +53,7 @@ func (l *LogLevel) UnmarshalJSON(data []byte) error {
func (l *LogLevel) UnmarshalText(data []byte) error {
level, exist := LogLevelMapping[strings.ToLower(string(data))]
if !exist {
return errors.New("invalid mode")
return errors.New("invalid log-level")
}
*l = level
return nil
@@ -30,8 +30,8 @@
"country-code-emoji": "2.3.0",
"country-emoji": "1.5.6",
"dayjs": "1.11.13",
"framer-motion": "12.10.5",
"i18next": "25.1.2",
"framer-motion": "12.11.3",
"i18next": "25.1.3",
"jotai": "2.12.4",
"json-schema": "0.4.0",
"material-react-table": "3.2.1",
+2 -2
View File
@@ -23,7 +23,7 @@
"@vitejs/plugin-react": "4.4.1",
"ahooks": "3.8.4",
"d3": "7.9.0",
"framer-motion": "12.10.5",
"framer-motion": "12.11.3",
"react": "19.1.0",
"react-dom": "19.1.0",
"react-error-boundary": "6.0.0",
@@ -41,6 +41,6 @@
"sass-embedded": "1.88.0",
"tailwind-merge": "3.3.0",
"typescript-plugin-css-modules": "5.1.0",
"vite-plugin-dts": "4.5.3"
"vite-plugin-dts": "4.5.4"
}
}
+1 -1
View File
@@ -81,7 +81,7 @@
"eslint-plugin-prettier": "5.4.0",
"eslint-plugin-promise": "7.2.1",
"eslint-plugin-react": "7.37.5",
"eslint-plugin-react-compiler": "19.1.0-rc.1",
"eslint-plugin-react-compiler": "19.1.0-rc.2",
"eslint-plugin-react-hooks": "5.2.0",
"globals": "16.1.0",
"knip": "5.55.1",
+32 -32
View File
@@ -91,8 +91,8 @@ importers:
specifier: 7.37.5
version: 7.37.5(eslint@9.26.0(jiti@2.4.2))
eslint-plugin-react-compiler:
specifier: 19.1.0-rc.1
version: 19.1.0-rc.1(eslint@9.26.0(jiti@2.4.2))
specifier: 19.1.0-rc.2
version: 19.1.0-rc.2(eslint@9.26.0(jiti@2.4.2))
eslint-plugin-react-hooks:
specifier: 5.2.0
version: 5.2.0(eslint@9.26.0(jiti@2.4.2))
@@ -266,11 +266,11 @@ importers:
specifier: 1.11.13
version: 1.11.13
framer-motion:
specifier: 12.10.5
version: 12.10.5(@emotion/is-prop-valid@1.3.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
specifier: 12.11.3
version: 12.11.3(@emotion/is-prop-valid@1.3.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
i18next:
specifier: 25.1.2
version: 25.1.2(typescript@5.8.3)
specifier: 25.1.3
version: 25.1.3(typescript@5.8.3)
jotai:
specifier: 2.12.4
version: 2.12.4(@types/react@19.1.4)(react@19.1.0)
@@ -303,7 +303,7 @@ importers:
version: 7.6.0(9b960f55d242927c500fd44155e8e7af)
react-i18next:
specifier: 15.5.1
version: 15.5.1(i18next@25.1.2(typescript@5.8.3))(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(typescript@5.8.3)
version: 15.5.1(i18next@25.1.3(typescript@5.8.3))(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(typescript@5.8.3)
react-markdown:
specifier: 10.1.0
version: 10.1.0(@types/react@19.1.4)(react@19.1.0)
@@ -486,8 +486,8 @@ importers:
specifier: 7.9.0
version: 7.9.0
framer-motion:
specifier: 12.10.5
version: 12.10.5(@emotion/is-prop-valid@1.3.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
specifier: 12.11.3
version: 12.11.3(@emotion/is-prop-valid@1.3.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
react:
specifier: 19.1.0
version: 19.1.0
@@ -499,7 +499,7 @@ importers:
version: 6.0.0(react@19.1.0)
react-i18next:
specifier: 15.5.1
version: 15.5.1(i18next@25.1.2(typescript@5.8.3))(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(typescript@5.8.3)
version: 15.5.1(i18next@25.1.3(typescript@5.8.3))(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(typescript@5.8.3)
react-use:
specifier: 17.6.0
version: 17.6.0(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
@@ -535,8 +535,8 @@ importers:
specifier: 5.1.0
version: 5.1.0(typescript@5.8.3)
vite-plugin-dts:
specifier: 4.5.3
version: 4.5.3(@types/node@22.15.18)(rollup@4.40.0)(typescript@5.8.3)(vite@6.3.5(@types/node@22.15.18)(jiti@2.4.2)(less@4.2.0)(lightningcss@1.29.2)(sass-embedded@1.88.0)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.4)(yaml@2.7.0))
specifier: 4.5.4
version: 4.5.4(@types/node@22.15.18)(rollup@4.40.0)(typescript@5.8.3)(vite@6.3.5(@types/node@22.15.18)(jiti@2.4.2)(less@4.2.0)(lightningcss@1.29.2)(sass-embedded@1.88.0)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.4)(yaml@2.7.0))
scripts:
dependencies:
@@ -4634,8 +4634,8 @@ packages:
peerDependencies:
eslint: ^7.0.0 || ^8.0.0 || ^9.0.0
eslint-plugin-react-compiler@19.1.0-rc.1:
resolution: {integrity: sha512-3umw5eqZXapBl7aQGmvcjheKhUbsElb9jTETxRZg371e1LG4EPs/zCHt2JzP+wNcdaZWzjU/R730zPUJblY2zw==}
eslint-plugin-react-compiler@19.1.0-rc.2:
resolution: {integrity: sha512-oKalwDGcD+RX9mf3NEO4zOoUMeLvjSvcbbEOpquzmzqEEM2MQdp7/FY/Hx9NzmUwFzH1W9SKTz5fihfMldpEYw==}
engines: {node: ^14.17.0 || ^16.0.0 || >= 18.0.0}
peerDependencies:
eslint: '>=7'
@@ -4889,8 +4889,8 @@ packages:
fraction.js@4.3.7:
resolution: {integrity: sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==}
framer-motion@12.10.5:
resolution: {integrity: sha512-p6VF1YkwWvNDFzg5IQ5lqPx11Td4TQ6LqDnshV7sWj0Nrp4dwz2/aEzmgh9WA9ridcTIJ625Fr0oiuhgqIoFwQ==}
framer-motion@12.11.3:
resolution: {integrity: sha512-ksUtDFBZtrbQFt4bEMFrFgo7camhmXcLeuylKQxEYSd9czkZ4tZmFROxWczWeu51WqC2m91ifpvgGCBLd0uviQ==}
peerDependencies:
'@emotion/is-prop-valid': '*'
react: ^18.0.0 || ^19.0.0
@@ -5218,8 +5218,8 @@ packages:
hyphenate-style-name@1.1.0:
resolution: {integrity: sha512-WDC/ui2VVRrz3jOVi+XtjqkDjiVjTtFaAGiW37k6b+ohyQ5wYDOGkvCZa8+H0nx3gyvv0+BST9xuOgIyGQ00gw==}
i18next@25.1.2:
resolution: {integrity: sha512-SP63m8LzdjkrAjruH7SCI3ndPSgjt4/wX7ouUUOzCW/eY+HzlIo19IQSfYA9X3qRiRP1SYtaTsg/Oz/PGsfD8w==}
i18next@25.1.3:
resolution: {integrity: sha512-VY1iKox3YWPRTNMHFdgk5TV+Jq6rNKexLCLpPmP5oXXJ5Kl7yDBi3ycZ5fyEKZ1tNBW5gOqD4WV0XqE7rl3JUg==}
peerDependencies:
typescript: ^5
peerDependenciesMeta:
@@ -6205,8 +6205,8 @@ packages:
peerDependencies:
monaco-editor: '>=0.36'
motion-dom@12.10.5:
resolution: {integrity: sha512-F7XKmhxXEH/y3aWWf0N2w69wNSN+6PcJ1seqR1WolClmXpPhj+xwzs9j5CpsMFzeHR1D7irl3JcWMToPRwX6Hg==}
motion-dom@12.11.2:
resolution: {integrity: sha512-wZ396XNNTI9GOkyrr80wFSbZc1JbIHSHTbLdririSbkEgahWWKmsHzsxyxqBBvuBU/iaQWVu1YCjdpXYNfo2yQ==}
motion-utils@12.9.4:
resolution: {integrity: sha512-BW3I65zeM76CMsfh3kHid9ansEJk9Qvl+K5cu4DVHKGsI52n76OJ4z2CUJUV+Mn3uEP9k1JJA3tClG0ggSrRcg==}
@@ -8122,8 +8122,8 @@ packages:
engines: {node: ^18.19.0 || >=20.6.0}
hasBin: true
vite-plugin-dts@4.5.3:
resolution: {integrity: sha512-P64VnD00dR+e8S26ESoFELqc17+w7pKkwlBpgXteOljFyT0zDwD8hH4zXp49M/kciy//7ZbVXIwQCekBJjfWzA==}
vite-plugin-dts@4.5.4:
resolution: {integrity: sha512-d4sOM8M/8z7vRXHHq/ebbblfaxENjogAAekcfcDCCwAyvGqnPrc7f4NZbvItS+g4WTgerW0xDwSz5qz11JT3vg==}
peerDependencies:
typescript: '*'
vite: '*'
@@ -10373,7 +10373,7 @@ snapshots:
'@rollup/pluginutils@5.1.4(rollup@4.40.0)':
dependencies:
'@types/estree': 1.0.6
'@types/estree': 1.0.7
estree-walker: 2.0.2
picomatch: 4.0.2
optionalDependencies:
@@ -12894,7 +12894,7 @@ snapshots:
'@eslint-community/eslint-utils': 4.4.1(eslint@9.26.0(jiti@2.4.2))
eslint: 9.26.0(jiti@2.4.2)
eslint-plugin-react-compiler@19.1.0-rc.1(eslint@9.26.0(jiti@2.4.2)):
eslint-plugin-react-compiler@19.1.0-rc.2(eslint@9.26.0(jiti@2.4.2)):
dependencies:
'@babel/core': 7.26.10
'@babel/parser': 7.27.0
@@ -13254,9 +13254,9 @@ snapshots:
fraction.js@4.3.7: {}
framer-motion@12.10.5(@emotion/is-prop-valid@1.3.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0):
framer-motion@12.11.3(@emotion/is-prop-valid@1.3.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0):
dependencies:
motion-dom: 12.10.5
motion-dom: 12.11.2
motion-utils: 12.9.4
tslib: 2.8.1
optionalDependencies:
@@ -13663,7 +13663,7 @@ snapshots:
hyphenate-style-name@1.1.0: {}
i18next@25.1.2(typescript@5.8.3):
i18next@25.1.3(typescript@5.8.3):
dependencies:
'@babel/runtime': 7.27.1
optionalDependencies:
@@ -14693,7 +14693,7 @@ snapshots:
vscode-uri: 3.0.8
yaml: 2.7.0
motion-dom@12.10.5:
motion-dom@12.11.2:
dependencies:
motion-utils: 12.9.4
@@ -15314,11 +15314,11 @@ snapshots:
dependencies:
react: 19.1.0
react-i18next@15.5.1(i18next@25.1.2(typescript@5.8.3))(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(typescript@5.8.3):
react-i18next@15.5.1(i18next@25.1.3(typescript@5.8.3))(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(typescript@5.8.3):
dependencies:
'@babel/runtime': 7.26.10
html-parse-stringify: 3.0.1
i18next: 25.1.2(typescript@5.8.3)
i18next: 25.1.3(typescript@5.8.3)
react: 19.1.0
optionalDependencies:
react-dom: 19.1.0(react@19.1.0)
@@ -16729,7 +16729,7 @@ snapshots:
- rollup
- supports-color
vite-plugin-dts@4.5.3(@types/node@22.15.18)(rollup@4.40.0)(typescript@5.8.3)(vite@6.3.5(@types/node@22.15.18)(jiti@2.4.2)(less@4.2.0)(lightningcss@1.29.2)(sass-embedded@1.88.0)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.4)(yaml@2.7.0)):
vite-plugin-dts@4.5.4(@types/node@22.15.18)(rollup@4.40.0)(typescript@5.8.3)(vite@6.3.5(@types/node@22.15.18)(jiti@2.4.2)(less@4.2.0)(lightningcss@1.29.2)(sass-embedded@1.88.0)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.4)(yaml@2.7.0)):
dependencies:
'@microsoft/api-extractor': 7.51.0(@types/node@22.15.18)
'@rollup/pluginutils': 5.1.4(rollup@4.40.0)
@@ -16738,7 +16738,7 @@ snapshots:
compare-versions: 6.1.1
debug: 4.4.0
kolorist: 1.8.0
local-pkg: 1.0.0
local-pkg: 1.1.1
magic-string: 0.30.17
typescript: 5.8.3
optionalDependencies:
+2 -2
View File
@@ -8,7 +8,7 @@ use tokio::task::spawn_blocking;
/// get the system proxy
#[tauri::command]
pub async fn get_sys_proxy() -> CmdResult<Mapping> {
let current = spawn_blocking(move || Sysproxy::get_system_proxy())
let current = spawn_blocking(Sysproxy::get_system_proxy)
.await
.map_err(|e| format!("Failed to spawn blocking task for sysproxy: {}", e))?
.map_err(|e| format!("Failed to get system proxy: {}", e))?;
@@ -27,7 +27,7 @@ pub async fn get_sys_proxy() -> CmdResult<Mapping> {
/// get the system proxy
#[tauri::command]
pub async fn get_auto_proxy() -> CmdResult<Mapping> {
let current = spawn_blocking(move || Autoproxy::get_auto_proxy())
let current = spawn_blocking(Autoproxy::get_auto_proxy)
.await
.map_err(|e| format!("Failed to spawn blocking task for autoproxy: {}", e))?
.map_err(|e| format!("Failed to get auto proxy: {}", e))?;
@@ -46,7 +46,7 @@ impl IClashTemp {
map.insert("mixed-port".into(), 7897.into());
map.insert("socks-port".into(), 7898.into());
map.insert("port".into(), 7899.into());
map.insert("log-level".into(), "warn".into());
map.insert("log-level".into(), "warning".into());
map.insert("allow-lan".into(), false.into());
map.insert("ipv6".into(), true.into());
map.insert("mode".into(), "rule".into());
@@ -259,11 +259,11 @@ impl PrfItem {
// 选择代理类型
let proxy_type = if self_proxy {
ProxyType::SelfProxy
ProxyType::Localhost
} else if with_proxy {
ProxyType::SystemProxy
ProxyType::System
} else {
ProxyType::NoProxy
ProxyType::None
};
// 使用网络管理器发送请求
+2 -1
View File
@@ -128,9 +128,10 @@ impl WebDavClient {
.build()?;
// 尝试检查目录是否存在,如果不存在尝试创建,但创建失败不报错
if let Err(_) = client
if client
.list(dirs::BACKUP_DIR, reqwest_dav::Depth::Number(0))
.await
.is_err()
{
let _ = client.mkcol(dirs::BACKUP_DIR).await;
}
+5 -5
View File
@@ -89,7 +89,7 @@ impl NotificationSystem {
let system_guard = handle.notification_system.read();
let is_emergency = system_guard
.as_ref()
.and_then(|sys| Some(*sys.emergency_mode.read()))
.map(|sys| *sys.emergency_mode.read())
.unwrap_or(false);
if is_emergency {
@@ -110,7 +110,7 @@ impl NotificationSystem {
&window,
"verge://refresh-clash-config",
"yes",
&handle,
handle,
);
}
FrontendEvent::RefreshVerge => {
@@ -118,7 +118,7 @@ impl NotificationSystem {
&window,
"verge://refresh-verge-config",
"yes",
&handle,
handle,
);
}
FrontendEvent::NoticeMessage {
@@ -129,7 +129,7 @@ impl NotificationSystem {
&window,
"verge://notice-message",
(status.clone(), message.clone()),
&handle,
handle,
);
}
}
@@ -273,7 +273,7 @@ impl Default for Handle {
impl Handle {
pub fn global() -> &'static Handle {
static HANDLE: OnceCell<Handle> = OnceCell::new();
HANDLE.get_or_init(|| Handle::default())
HANDLE.get_or_init(Handle::default)
}
pub fn init(&self, app_handle: &AppHandle) {
@@ -538,7 +538,7 @@ pub async fn check_ipc_service_status() -> Result<JsonResponse> {
json_response.msg,
json_response.data.is_some()
);
return Ok(json_response);
Ok(json_response)
} else {
// 尝试直接解析
match serde_json::from_value::<JsonResponse>(data.clone()) {
@@ -551,7 +551,7 @@ pub async fn check_ipc_service_status() -> Result<JsonResponse> {
json_response.code,
json_response.msg
);
return Ok(json_response);
Ok(json_response)
}
Err(e) => {
logging!(
+1 -5
View File
@@ -385,10 +385,7 @@ impl Timer {
}
};
let profile = match items
.iter()
.find(|item| item.uid.as_ref().map(|u| u.as_str()) == Some(uid))
{
let profile = match items.iter().find(|item| item.uid.as_deref() == Some(uid)) {
Some(p) => p,
None => {
logging!(warn, Type::Timer, "找不到对应的配置,uid={}", uid);
@@ -441,7 +438,6 @@ impl Timer {
}
/// Async task with better error handling and logging
async fn async_task(uid: String) {
let task_start = std::time::Instant::now();
logging!(info, Type::Timer, "Running timer task for profile: {}", uid);
@@ -442,7 +442,7 @@ impl Tray {
traffic_result = stream.next() => {
match traffic_result {
Some(Ok(traffic)) => {
if let Ok(speedrate_result) = tokio::time::timeout(
if let Ok(Some(rate)) = tokio::time::timeout(
std::time::Duration::from_millis(50),
async {
let guard = speed_rate.try_lock();
@@ -457,12 +457,10 @@ impl Tray {
}
}
).await {
if let Some(rate) = speedrate_result {
let _ = tokio::time::timeout(
std::time::Duration::from_millis(100),
async { let _ = Tray::global().update_icon(Some(rate)); }
).await;
}
let _ = tokio::time::timeout(
std::time::Duration::from_millis(100),
async { let _ = Tray::global().update_icon(Some(rate)); }
).await;
}
},
Some(Err(e)) => {
@@ -271,7 +271,7 @@ impl Traffic {
// 设置流超时控制
let traffic_stream = ws_stream
.take_while(|msg| {
let continue_stream = matches!(msg, Ok(_));
let continue_stream = msg.is_ok();
async move { continue_stream }.boxed()
})
.filter_map(|msg| async move {
+2 -2
View File
@@ -98,9 +98,9 @@ pub async fn test_delay(url: String) -> anyhow::Result<u32> {
// 如果是TUN模式,不使用代理,否则使用自身代理
let proxy_type = if !tun_mode {
ProxyType::SelfProxy
ProxyType::Localhost
} else {
ProxyType::NoProxy
ProxyType::None
};
let user_agent = Some("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36 Edg/120.0.0.0".to_string());
@@ -1,4 +1,4 @@
use std::fmt::{self, write};
use std::fmt;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Type {
@@ -274,10 +274,10 @@ impl NetworkManager {
}
match proxy_type {
ProxyType::NoProxy => {
ProxyType::None => {
builder = builder.no_proxy();
}
ProxyType::SelfProxy => {
ProxyType::Localhost => {
let port = Config::verge()
.latest()
.verge_mixed_port
@@ -295,7 +295,7 @@ impl NetworkManager {
builder = builder.proxy(proxy);
}
}
ProxyType::SystemProxy => {
ProxyType::System => {
use sysproxy::Sysproxy;
if let Ok(p @ Sysproxy { enable: true, .. }) = Sysproxy::get_system_proxy() {
@@ -420,7 +420,7 @@ impl NetworkManager {
/// 代理类型
#[derive(Debug, Clone, Copy)]
pub enum ProxyType {
NoProxy,
SelfProxy,
SystemProxy,
None,
Localhost,
System,
}
@@ -29,7 +29,7 @@ const getLanguagePackMap = (key: string) =>
* custom theme
*/
export const useCustomTheme = () => {
const appWindow: WebviewWindow = getCurrentWebviewWindow();
const appWindow: WebviewWindow = useMemo(() => getCurrentWebviewWindow(), []);
const { verge } = useVerge();
const { i18n } = useTranslation();
const { theme_mode, theme_setting } = verge ?? {};
@@ -37,45 +37,71 @@ export const useCustomTheme = () => {
const setMode = useSetThemeMode();
useEffect(() => {
const themeModeSetting = ["light", "dark", "system"].includes(theme_mode!)
? theme_mode!
: "light";
if (theme_mode === "light" || theme_mode === "dark") {
setMode(theme_mode);
}
}, [theme_mode, setMode]);
if (themeModeSetting !== "system") {
setMode(themeModeSetting as 'light' | 'dark');
useEffect(() => {
if (theme_mode !== "system") {
return;
}
appWindow.theme().then((systemTheme: 'light' | 'dark' | null) => {
if (systemTheme) {
setMode(systemTheme);
let isMounted = true;
const timerId = setTimeout(() => {
if (!isMounted) return;
appWindow.theme().then((systemTheme) => {
if (isMounted && systemTheme) {
setMode(systemTheme);
}
}).catch(err => {
console.error("Failed to get initial system theme:", err);
});
}, 0);
const unlistenPromise = appWindow.onThemeChanged(({ payload }) => {
if (isMounted) {
setMode(payload);
}
});
const unlisten = appWindow.onThemeChanged(({ payload }: { payload: 'light' | 'dark' }) => {
setMode(payload);
});
return () => {
unlisten.then((fn: () => void) => fn());
isMounted = false;
clearTimeout(timerId);
unlistenPromise.then((unlistenFn) => {
if (typeof unlistenFn === 'function') {
unlistenFn();
}
}).catch(err => {
console.error("Failed to unlisten from theme changes:", err);
});
};
}, [theme_mode, setMode, i18n, theme_setting, appWindow]);
}, [theme_mode, appWindow, setMode]);
useEffect(() => {
if (mode) {
appWindow.setTheme(mode as TauriOsTheme).catch((err: any) => {
console.error("Failed to set window theme:", err);
if (theme_mode === undefined) {
return;
}
if (theme_mode === "system") {
appWindow.setTheme(null).catch((err) => {
console.error("Failed to set window theme to follow system (setTheme(null)):", err);
});
} else if (mode) {
appWindow.setTheme(mode as TauriOsTheme).catch((err) => {
console.error(`Failed to set window theme to ${mode}:`, err);
});
}
}, [mode, appWindow]);
}, [mode, appWindow, theme_mode]);
const theme = useMemo(() => {
const setting = theme_setting || {};
const dt = mode === "light" ? defaultTheme : defaultDarkTheme;
let theme: MuiTheme;
let muiTheme: MuiTheme;
try {
theme = createTheme(
muiTheme = createTheme(
{
breakpoints: {
values: { xs: 0, sm: 650, md: 900, lg: 1200, xl: 1536 },
@@ -98,7 +124,6 @@ export const useCustomTheme = () => {
},
shadows: Array(25).fill("none") as Shadows,
typography: {
// todo
fontFamily: setting.font_family
? `${setting.font_family}, ${dt.font_family}`
: dt.font_family,
@@ -106,9 +131,9 @@ export const useCustomTheme = () => {
},
getLanguagePackMap(i18n.language),
);
} catch {
// fix #294
theme = createTheme({
} catch (e) {
console.error("Error creating MUI theme, falling back to defaults:", e);
muiTheme = createTheme({
breakpoints: {
values: { xs: 0, sm: 650, md: 900, lg: 1200, xl: 1536 },
},
@@ -126,38 +151,36 @@ export const useCustomTheme = () => {
});
}
// css
const backgroundColor = mode === "light" ? "#ECECEC" : "#2e303d";
const selectColor = mode === "light" ? "#f5f5f5" : "#d5d5d5";
const scrollColor = mode === "light" ? "#90939980" : "#3E3E3Eee";
const dividerColor =
mode === "light" ? "rgba(0, 0, 0, 0.06)" : "rgba(255, 255, 255, 0.06)";
const rootEle = document.documentElement;
rootEle.style.setProperty("--divider-color", dividerColor);
rootEle.style.setProperty("--background-color", backgroundColor);
rootEle.style.setProperty("--selection-color", selectColor);
rootEle.style.setProperty("--scroller-color", scrollColor);
rootEle.style.setProperty("--primary-main", theme.palette.primary.main);
rootEle.style.setProperty(
"--background-color-alpha",
alpha(theme.palette.primary.main, 0.1),
);
if (rootEle) {
const backgroundColor = mode === "light" ? "#ECECEC" : "#2e303d";
const selectColor = mode === "light" ? "#f5f5f5" : "#d5d5d5";
const scrollColor = mode === "light" ? "#90939980" : "#3E3E3Eee";
const dividerColor =
mode === "light" ? "rgba(0, 0, 0, 0.06)" : "rgba(255, 255, 255, 0.06)";
rootEle.style.setProperty("--divider-color", dividerColor);
rootEle.style.setProperty("--background-color", backgroundColor);
rootEle.style.setProperty("--selection-color", selectColor);
rootEle.style.setProperty("--scroller-color", scrollColor);
rootEle.style.setProperty("--primary-main", muiTheme.palette.primary.main);
rootEle.style.setProperty(
"--background-color-alpha",
alpha(muiTheme.palette.primary.main, 0.1),
);
}
// inject css
let style = document.querySelector("style#verge-theme");
if (!style) {
style = document.createElement("style");
style.id = "verge-theme";
document.head.appendChild(style!);
let styleElement = document.querySelector("style#verge-theme");
if (!styleElement) {
styleElement = document.createElement("style");
styleElement.id = "verge-theme";
document.head.appendChild(styleElement!);
}
if (style) {
style.innerHTML = setting.css_injection || "";
if (styleElement) {
styleElement.innerHTML = setting.css_injection || "";
}
// update svg icon
const { palette } = theme;
const { palette } = muiTheme;
setTimeout(() => {
const dom = document.querySelector("#Gradient2");
if (dom) {
@@ -169,7 +192,7 @@ export const useCustomTheme = () => {
}
}, 0);
return theme;
return muiTheme;
}, [mode, theme_setting, i18n.language]);
return { theme };
@@ -201,7 +201,6 @@ const SettingClash = ({ onError }: Props) => {
}
>
<GuardState
// clash premium 2022.08.26 值为warn
value={logLevel === "warn" ? "warning" : (logLevel ?? "info")}
onCatch={onError}
onFormat={(e: any) => e.target.value}
@@ -1,41 +0,0 @@
#
# Copyright (C) 2022 OpenWrt.org
#
# This is free software, licensed under the GNU General Public License v2.
# See /LICENSE for more information.
#
include $(TOPDIR)/rules.mk
PKG_NAME:=ivpu-firmware
PKG_VERSION:=1.10.1
PKG_RELEASE:=1
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
PKG_SOURCE_URL_FILE:=v$(PKG_VERSION).tar.gz
PKG_SOURCE_URL:=https://github.com/intel/linux-npu-driver/archive/refs/tags
PKG_HASH:=a756de38cde7bd5a0402854d08429d271a33784835b80db3be672ade80570900
PKG_BUILD_DIR:=$(BUILD_DIR)/linux-npu-driver-$(PKG_VERSION)
include $(INCLUDE_DIR)/package.mk
define Package/ivpu-firmware
SECTION:=firmware
CATEGORY:=Firmware
TITLE:=Intel VPU firmware
URL:=$(PKG_SOURCE_URL)
DEPENDS:=
endef
define Build/Compile
true
endef
define Package/ivpu-firmware/install
$(INSTALL_DIR) $(1)/lib/firmware/intel/vpu
$(INSTALL_DATA) \
$(PKG_BUILD_DIR)/firmware/bin/*.bin \
$(1)/lib/firmware/intel/vpu
endef
$(eval $(call BuildPackage,ivpu-firmware))
@@ -279,3 +279,15 @@ define Package/i915-firmware-gsc/install
done
endef
$(eval $(call BuildPackage,i915-firmware-gsc))
Package/ivpu-firmware = $(call Package/firmware-default,Intel VPU firmware)
define Package/ivpu-firmware/install
$(INSTALL_DIR) $(1)/lib/firmware/intel/vpu
$(INSTALL_DATA) $(PKG_BUILD_DIR)/intel/vpu/*.bin $(1)/lib/firmware/intel/vpu
for t in `cd $(1)/lib/firmware/intel/vpu && ls vpu_*.bin | cut -d. -f1 | cut -d_ -f2 | sort | uniq`; do \
source=`cd $(1)/lib/firmware && ls intel/vpu/vpu_$$$${t}_v*.bin | sort | tail -n1`; \
target=$(1)/lib/firmware/vpu_$$$${t}.bin; \
if [ -n "$$$$source" ]; then ln -sf $$$$source $$$$target; fi \
done
endef
$(eval $(call BuildPackage,ivpu-firmware))
+51 -1
View File
@@ -362,6 +362,38 @@ endef
$(eval $(call KernelPackage,drm-exec))
define KernelPackage/drm-dma-helper
SUBMENU:=$(VIDEO_MENU)
HIDDEN:=1
TITLE:=GEM DMA helper functions
DEPENDS:=@DISPLAY_SUPPORT +kmod-drm-kms-helper
KCONFIG:=CONFIG_DRM_GEM_DMA_HELPER
FILES:=$(LINUX_DIR)/drivers/gpu/drm/drm_dma_helper.ko
AUTOLOAD:=$(call AutoProbe,drm_dma_helper)
endef
define KernelPackage/drm-dma-helper/description
GEM DMA helper functions.
endef
$(eval $(call KernelPackage,drm-dma-helper))
define KernelPackage/drm-mipi-dbi
SUBMENU:=$(VIDEO_MENU)
HIDDEN:=1
TITLE:=MIPI DBI helpers
DEPENDS:=@DISPLAY_SUPPORT +kmod-backlight +kmod-drm-kms-helper
KCONFIG:=CONFIG_DRM_MIPI_DBI
FILES:=$(LINUX_DIR)/drivers/gpu/drm/drm_mipi_dbi.ko
AUTOLOAD:=$(call AutoProbe,drm_mipi_dbi)
endef
define KernelPackage/drm-mipi-dbi/description
MIPI Display Bus Interface (DBI) LCD controller support.
endef
$(eval $(call KernelPackage,drm-mipi-dbi))
define KernelPackage/drm-ttm
SUBMENU:=$(VIDEO_MENU)
TITLE:=GPU memory management subsystem
@@ -514,7 +546,7 @@ $(eval $(call KernelPackage,drm-i915))
define KernelPackage/drm-ivpu
SUBMENU:=$(VIDEO_MENU)
TITLE:=Intel VPU DRM support
DEPENDS:=@TARGET_x86 +ivpu-firmware
DEPENDS:=@TARGET_x86_64 +ivpu-firmware
KCONFIG:=CONFIG_DRM_ACCEL_IVPU \
CONFIG_DRM_ACCEL_HABANALABS=n \
CONFIG_DRM_ACCEL_QAIC=n \
@@ -637,6 +669,24 @@ endef
$(eval $(call KernelPackage,drm-panfrost))
define KernelPackage/drm-panel-mipi-dbi
SUBMENU:=$(VIDEO_MENU)
TITLE:=Generic MIPI DBI LCD panel
DEPENDS:=+kmod-drm-mipi-dbi +kmod-drm-dma-helper
KCONFIG:=CONFIG_DRM_PANEL_MIPI_DBI \
CONFIG_DRM_FBDEV_EMULATION=y \
CONFIG_DRM_FBDEV_OVERALLOC=100
FILES:= \
$(LINUX_DIR)/drivers/gpu/drm/tiny/panel-mipi-dbi.ko
AUTOLOAD:=$(call AutoProbe,panel-mipi-dbi)
endef
define KernelPackage/drm-panel-mipi-dbi/description
Generic driver for MIPI Alliance Display Bus Interface
endef
$(eval $(call KernelPackage,drm-panel-mipi-dbi))
define KernelPackage/drm-radeon
SUBMENU:=$(VIDEO_MENU)
TITLE:=Radeon DRM support
+3
View File
@@ -13,11 +13,14 @@ import (
type RealityOptions struct {
PublicKey string `proxy:"public-key"`
ShortID string `proxy:"short-id"`
SupportX25519MLKEM768 bool `proxy:"support-x25519mlkem768"`
}
func (o RealityOptions) Parse() (*tlsC.RealityConfig, error) {
if o.PublicKey != "" {
config := new(tlsC.RealityConfig)
config.SupportX25519MLKEM768 = o.SupportX25519MLKEM768
const x25519ScalarSize = 32
publicKey, err := base64.RawURLEncoding.DecodeString(o.PublicKey)
+24 -24
View File
@@ -35,6 +35,8 @@ const RealityMaxShortIDLen = 8
type RealityConfig struct {
PublicKey *ecdh.PublicKey
ShortID [RealityMaxShortIDLen]byte
SupportX25519MLKEM768 bool
}
func GetRealityConn(ctx context.Context, conn net.Conn, fingerprint UClientHelloID, tlsConfig *tls.Config, realityConfig *RealityConfig) (net.Conn, error) {
@@ -48,38 +50,36 @@ func GetRealityConn(ctx context.Context, conn net.Conn, fingerprint UClientHello
SessionTicketsDisabled: true,
VerifyPeerCertificate: verifier.VerifyPeerCertificate,
}
clientID := utls.ClientHelloID{
Client: fingerprint.Client,
Version: fingerprint.Version,
Seed: fingerprint.Seed,
}
uConn := utls.UClient(conn, uConfig, clientID)
uConn := utls.UClient(conn, uConfig, fingerprint)
verifier.UConn = uConn
err := uConn.BuildHandshakeState()
if err != nil {
return nil, err
}
// ------for X25519MLKEM768 does not work properly with reality-------
// Iterate over extensions and check
for _, extension := range uConn.Extensions {
if ce, ok := extension.(*utls.SupportedCurvesExtension); ok {
ce.Curves = slices.DeleteFunc(ce.Curves, func(curveID utls.CurveID) bool {
return curveID == utls.X25519MLKEM768
})
if !realityConfig.SupportX25519MLKEM768 {
// ------for X25519MLKEM768 does not work properly with the old reality server-------
// Iterate over extensions and check
for _, extension := range uConn.Extensions {
if ce, ok := extension.(*utls.SupportedCurvesExtension); ok {
ce.Curves = slices.DeleteFunc(ce.Curves, func(curveID utls.CurveID) bool {
return curveID == utls.X25519MLKEM768
})
}
if ks, ok := extension.(*utls.KeyShareExtension); ok {
ks.KeyShares = slices.DeleteFunc(ks.KeyShares, func(share utls.KeyShare) bool {
return share.Group == utls.X25519MLKEM768
})
}
}
if ks, ok := extension.(*utls.KeyShareExtension); ok {
ks.KeyShares = slices.DeleteFunc(ks.KeyShares, func(share utls.KeyShare) bool {
return share.Group == utls.X25519MLKEM768
})
// Rebuild the client hello
err = uConn.BuildHandshakeState()
if err != nil {
return nil, err
}
// --------------------------------------------------------------------
}
// Rebuild the client hello
err = uConn.BuildHandshakeState()
if err != nil {
return nil, err
}
// --------------------------------------------------------------------
hello := uConn.HandshakeState.Hello
rawSessionID := hello.Raw[39 : 39+32] // the location of session ID
@@ -144,7 +144,7 @@ func GetRealityConn(ctx context.Context, conn net.Conn, fingerprint UClientHello
log.Debugln("REALITY Authentication: %v, AEAD: %T", verifier.verified, aeadCipher)
if !verifier.verified {
go realityClientFallback(uConn, uConfig.ServerName, clientID)
go realityClientFallback(uConn, uConfig.ServerName, fingerprint)
return nil, errors.New("REALITY authentication failed")
}
+1 -1
View File
@@ -36,7 +36,7 @@ require (
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-20250503140532-decbcfccbfdf
github.com/metacubex/utls v1.7.0-alpha.3
github.com/metacubex/utls v1.7.3
github.com/metacubex/wireguard-go v0.0.0-20240922131502-c182e7471181
github.com/miekg/dns v1.1.63 // lastest version compatible with golang1.20
github.com/mroth/weightedrand/v2 v2.1.0
+2 -2
View File
@@ -138,8 +138,8 @@ github.com/metacubex/smux v0.0.0-20250503055512-501391591dee h1:lp6hJ+4wCLZu113a
github.com/metacubex/smux v0.0.0-20250503055512-501391591dee/go.mod h1:4bPD8HWx9jPJ9aE4uadgyN7D1/Wz3KmPy+vale8sKLE=
github.com/metacubex/tfo-go v0.0.0-20250503140532-decbcfccbfdf h1:LwID1wz4tzypidd412dd4dC1H0m1TgRCQ/XvRvMJDFM=
github.com/metacubex/tfo-go v0.0.0-20250503140532-decbcfccbfdf/go.mod h1:l9oLnLoEXyGZ5RVLsh7QCC5XsouTUyKk4F2nLm2DHLw=
github.com/metacubex/utls v1.7.0-alpha.3 h1:cp1cEMUnoifiWrGHRzo+nCwPRveN9yPD8QaRFmfcYxA=
github.com/metacubex/utls v1.7.0-alpha.3/go.mod h1:oknYT0qTOwE4hjPmZOEpzVdefnW7bAdGLvZcqmk4TLU=
github.com/metacubex/utls v1.7.3 h1:yDcMEWojFh+t8rU9X0HPcZDPAoFze/rIIyssqivzj8A=
github.com/metacubex/utls v1.7.3/go.mod h1:oknYT0qTOwE4hjPmZOEpzVdefnW7bAdGLvZcqmk4TLU=
github.com/metacubex/wireguard-go v0.0.0-20240922131502-c182e7471181 h1:hJLQviGySBuaynlCwf/oYgIxbVbGRUIKZCxdya9YrbQ=
github.com/metacubex/wireguard-go v0.0.0-20240922131502-c182e7471181/go.mod h1:phewKljNYiTVT31Gcif8RiCKnTUOgVWFJjccqYM8s+Y=
github.com/miekg/dns v1.1.63 h1:8M5aAw6OMZfFXTT7K5V0Eu5YiiL8l7nUAkyN6C9YwaY=
+3 -3
View File
@@ -31,7 +31,7 @@ func (l *LogLevel) UnmarshalYAML(unmarshal func(any) error) error {
unmarshal(&tp)
level, exist := LogLevelMapping[strings.ToLower(tp)]
if !exist {
return errors.New("invalid mode")
return errors.New("invalid log-level")
}
*l = level
return nil
@@ -43,7 +43,7 @@ func (l *LogLevel) UnmarshalJSON(data []byte) error {
json.Unmarshal(data, &tp)
level, exist := LogLevelMapping[strings.ToLower(tp)]
if !exist {
return errors.New("invalid mode")
return errors.New("invalid log-level")
}
*l = level
return nil
@@ -53,7 +53,7 @@ func (l *LogLevel) UnmarshalJSON(data []byte) error {
func (l *LogLevel) UnmarshalText(data []byte) error {
level, exist := LogLevelMapping[strings.ToLower(string(data))]
if !exist {
return errors.New("invalid mode")
return errors.New("invalid log-level")
}
*l = level
return nil
+2 -2
View File
@@ -7,8 +7,8 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=luci-app-ddns-go
PKG_VERSION:=1.5.2
PKG_RELEASE:=20250514
PKG_VERSION:=1.5.3
PKG_RELEASE:=20250515
PKG_MAINTAINER:=sirpdboy <herboy2008@gmail.com>
PKG_CONFIG_DEPENDS:=
@@ -7,17 +7,33 @@
'require form';
'require poll';
function checkProcess() {
return fs.exec('/bin/pidof', ['ddns-go']).then(function(res) {
return {
running: res.code === 0,
pid: res.code === 0 ? res.stdout.trim() : null
};
}).catch(function() {
return { running: false, pid: null };
});
}
async function checkProcess() {
// 先尝试用 pidof
try {
const pidofRes = await fs.exec('/bin/pidof', ['ddns-go']);
if (pidofRes.code === 0) {
return {
running: true,
pid: pidofRes.stdout.trim()
};
}
} catch (err) {
// pidof 失败,继续尝试 ps
}
// 回退到 ps
try {
const psRes = await fs.exec('/bin/ps', ['-C', 'ddns-go', '-o', 'pid=']);
const pid = psRes.stdout.trim();
return {
running: pid !== '',
pid: pid || null
};
} catch (err) {
return { running: false, pid: null };
}
}
function renderStatus(isRunning, listen_port, noweb) {
var statusText = isRunning ? _('RUNNING') : _('NOT RUNNING');
var color = isRunning ? 'green' : 'red';
@@ -52,8 +68,8 @@ return view.extend({
render: function(data) {
var m, s, o;
var listen_port = (uci.get(data[0], 'basic', 'port') || '[::]:9876').split(':').slice(-1)[0];
var noweb = uci.get(data[0], 'basic', 'noweb') || '0';
var listen_port = (uci.get('ddns-go', 'config', 'port') || '[::]:9876').split(':').slice(-1)[0];
var noweb = uci.get('ddns-go', 'config', 'noweb') || '0';
m = new form.Map('ddns-go', _('DDNS-GO'),
_('DDNS-GO automatically obtains your public IPv4 or IPv6 address and resolves it to the corresponding domain name service.'));
@@ -63,7 +79,7 @@ return view.extend({
s.anonymous = true;
s.render = function() {
var statusView = E('p', { id: 'control_status' },
'<span class="spinning"></span> ' + _('Checking status...'));
'<span class="spinning"></span> ' + _('Checking status...'));
var pollInterval = poll.add(function() {
return checkProcess()
@@ -122,6 +138,7 @@ return view.extend({
o = s.option(form.Flag, 'noweb', _('Do not start web services'));
o.default = '0';
o.rmempty = false;
o = s.option(form.Value, 'delay', _('Delayed Start (seconds)'));
o.default = '60';
@@ -9,58 +9,71 @@
'require poll';
return view.extend({
//handleSaveApply: null,
//handleSave: null,
//handleReset: null,
load: function() {
return uci.load('ddns-go');
},
checkRunning: function() {
return fs.exec('/bin/pidof', ['ddns-go']).then(function(pidRes) {
if (pidRes.code === 0) return { isRunning: true };
return fs.exec('/bin/ash', ['-c', 'ps | grep -q "[d]dns-go"']).then(function(grepRes) {
return { isRunning: grepRes.code === 0 };
});
});
},
render: function() {
return fs.exec('/bin/pidof', ['ddns-go']).then(function(res) {
var isRunning = res.code === 0;
var port = uci.get('ddns-go', 'basic', 'port') || '[::]:9876';
var noweb = uci.get('ddns-go', 'basic', 'noweb') || '0';
var self = this;
return this.checkRunning().then(function(checkResult) {
var isRunning = checkResult.isRunning;
var port = uci.get('ddns-go', 'config', 'port') || '[::]:9876';
var noweb = uci.get('ddns-go', 'config', 'noweb') ;
port = port.split(':').pop();
var container = E('div');
var status = E('div', { style: 'text-align: center; padding: 2em;' }, [
E('img', {
src: 'data:image/svg+xml;base64,PHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgd2lkdGg9IjEwMjQiIGhlaWdodD0iMTAyNCIgdmlld0JveD0iMCAwIDEwMjQgMTAyNCI+PHBhdGggZmlsbD0iI2RmMDAwMCIgZD0iTTk0Mi40MjEgMjM0LjYyNGw4MC44MTEtODAuODExLTE1My4wNDUtMTUzLjA0NS04MC44MTEgODAuODExYy03OS45NTctNTEuNjI3LTE3NS4xNDctODEuNTc5LTI3Ny4zNzYtODEuNTc5LTI4Mi43NTIgMC01MTIgMjI5LjI0OC01MTIgNTEyIDAgMTAyLjIyOSAyOS45NTIgMTk3LjQxOSA4MS41NzkgMjc3LjM3NmwtODAuODExIDgwLjgxMSAxNTMuMDQ1IDE1My4wNDUgODAuODExLTgwLjgxMWM3OS45NTcgNTEuNjI3IDE3NS4xNDcgODEuNTc5IDI3Ny4zNzYgODEuNTc5IDI4Mi43NTIgMCA1MTItMjI5LjI0OCA1MTItNTEyIDAtMTAyLjIyOS0yOS45NTItMTk3LjQxOS04MS41NzktMjc3LjM3NnpNMTk0Ljk0NCA1MTJjMC0xNzUuMTA0IDE0MS45NTItMzE3LjA1NiAzMTcuMDU2LTMxNy4wNTYgNDggMCA5My40ODMgMTAuNjY3IDEzNC4yMjkgMjkuNzgxbC00MjEuNTQ3IDQyMS41NDdjLTE5LjA3Mi00MC43ODktMjkuNzM5LTg2LjI3Mi0yOS43MzktMTM0LjI3MnpNNTEyIDgyOS4wNTZjLTQ4IDAtOTMuNDgzLTEwLjY2Ny0xMzQuMjI5LTI5Ljc4MWw0MjEuNTQ3LTQyMS41NDdjMTkuMDcyIDQwLjc4OSAyOS43ODEgODYuMjcyIDI5Ljc4MSAxMzQuMjI5LTAuMDQzIDE3NS4xNDctMTQxLjk5NSAzMTcuMDk5LTMxNy4wOTkgMzE3LjA5OXoiLz48L3N2Zz4=',
style: 'width: 100px; height: 100px; margin-bottom: 1em;'
}),
E('h2', {}, _('DDNS-GO Service Not Running')),
E('p', {}, _('Please enable the DDNS-GO service'))
]);
if (isRunning && noweb !== '1') {
console.log('Debug: isRunning=' + isRunning + ', noweb=' + noweb + ', port=' + port);
if (!isRunning || noweb === '1') {
if (!isRunning) {
var message = _('DDNS-GO Service Not Running');
}
if (noweb === '1') {
var message = _('DDNS-GO Web Interface Disabled');
}
container.appendChild(E('div', {
style: 'text-align: center; padding: 2em;'
}, [
E('img', {
src: 'data:image/svg+xml;base64,PHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgd2lkdGg9IjEwMjQiIGhlaWdodD0iMTAyNCIgdmlld0JveD0iMCAwIDEwMjQgMTAyNCI+PHBhdGggZmlsbD0iI2RmMDAwMCIgZD0iTTk0Mi40MjEgMjM0LjYyNGw4MC44MTEtODAuODExLTE1My4wNDUtMTUzLjA0NS04MC44MTEgODAuODExYy03OS45NTctNTEuNjI3LTE3NS4xNDctODEuNTc5LTI3Ny4zNzYtODEuNTc5LTI4Mi43NTIgMC01MTIgMjI5LjI0OC01MTIgNTEyIDAgMTAyLjIyOSAyOS45NTIgMTk3LjQxOSA4MS41NzkgMjc3LjM3NmwtODAuODExIDgwLjgxMSAxNTMuMDQ1IDE1My4wNDUgODAuODExLTgwLjgxMWM3OS45NTcgNTEuNjI3IDE3NS4xNDcgODEuNTc5IDI3Ny4zNzYgODEuNTc5IDI4Mi43NTIgMCA1MTItMjI5LjI0OCA1MTItNTEyIDAtMTAyLjIyOS0yOS45NTItMTk3LjQxOS04MS41NzktMjc3LjM3NnpNMTk0Ljk0NCA1MTJjMC0xNzUuMTA0IDE0MS45NTItMzE3LjA1NiAzMTcuMDU2LTMxNy4wNTYgNDggMCA5My40ODMgMTAuNjY3IDEzNC4yMjkgMjkuNzgxbC00MjEuNTQ3IDQyMS41NDdjLTE5LjA3Mi00MC43ODktMjkuNzM5LTg2LjI3Mi0yOS43MzktMTM0LjI3MnpNNTEyIDgyOS4wNTZjLTQ4IDAtOTMuNDgzLTEwLjY2Ny0xMzQuMjI5LTI5Ljc4MWw0MjEuNTQ3LTQyMS41NDdjMTkuMDcyIDQwLjc4OSAyOS43ODEgODYuMjcyIDI5Ljc4MSAxMzQuMjI5LTAuMDQzIDE3NS4xNDctMTQxLjk5NSAzMTcuMDk5LTMxNy4wOTkgMzE3LjA5OXoiLz48L3N2Zz4=',
style: 'width: 100px; height: 100px; margin-bottom: 1em;'
}),
E('h2', {}, message)
]));
} else {
var iframe = E('iframe', {
src: window.location.origin + ':' + port,
style: 'width: 100%; min-height: 100vh; border: none; border-radius: 3px;'
src: window.location.protocol + '//' + window.location.hostname + ':' + port,
style: 'width: 100%; min-height: 100vh; border: none;'
});
container.appendChild(iframe);
} else
{
container.appendChild(status);
}
}
// Add polling to refresh status
poll.add(function() {
return fs.exec('/bin/pidof', ['ddns-go']).then(function(res) {
var newIsRunning = res.code === 0;
if (newIsRunning !== isRunning) {
return self.checkRunning().then(function(checkResult) {
var newStatus = checkResult.isRunning;
if (newStatus !== isRunning) {
window.location.reload();
}
});
}, 5);
poll.start();
return container;
}).catch(function(err) {
return E('div', { class: 'error' }, _('Error checking DDNS-Go status: ') + err.message);
});
}
},
handleSaveApply: null,
handleSave: null,
handleReset: null
});
@@ -43,8 +43,8 @@ msgstr "运行中"
msgid "DDNS-GO Service Not Running"
msgstr "DDNS-GO服务未启用"
msgid "Please enable the DDNS-GO service"
msgstr "请将DDNS-GO服务用"
msgid "DDNS-GO Web Interface Disabled"
msgstr "DDNS-GO WEB服务用"
msgid "Open Web Interface"
msgstr "打开Web界面"
+4 -4
View File
@@ -11,13 +11,13 @@ LUCI_DEPENDS:=+curl +opkg +luci-base +tar +libuci-lua +mount-utils +luci-lib-tas
LUCI_EXTRA_DEPENDS:=luci-lib-taskd (>=1.0.19)
LUCI_PKGARCH:=all
PKG_VERSION:=0.1.27-4
PKG_VERSION:=0.1.28-2
# PKG_RELEASE MUST be empty for luci.mk
PKG_RELEASE:=
ISTORE_UI_VERSION:=0.1.27
ISTORE_UI_RELEASE:=2
PKG_HASH:=7fb8e9983dd33b14c43de3caf6a6121df0727e0adac6c666354e0d8a0cffa0b8
ISTORE_UI_VERSION:=0.1.28
ISTORE_UI_RELEASE:=1
PKG_HASH:=c45d7552a4c52fdd2f5a2a9bbc94d14a66c5af187ef8a117a3e08b6a9a4b7dbf
PKG_SOURCE_URL_FILE:=v$(ISTORE_UI_VERSION)-$(ISTORE_UI_RELEASE).tar.gz
PKG_SOURCE:=istore-ui-$(PKG_SOURCE_URL_FILE)
@@ -2,6 +2,7 @@ module("luci.controller.store", package.seeall)
local myopkg = "is-opkg"
local is_backup = "/usr/libexec/istore/backup"
local is_overlay_backup = "/usr/libexec/istore/overlay-backup"
local page_index = {"admin", "store", "pages"}
function index()
@@ -44,16 +45,18 @@ function index()
store_api(action, false)
end
-- backup
-- istore backup
if nixio.fs.access("/usr/libexec/istore/backup") then
entry({"admin", "store", "get_support_backup_features"}, call("get_support_backup_features"))
entry({"admin", "store", "light_backup"}, post("light_backup"))
entry({"admin", "store", "get_light_backup_file"}, call("get_light_backup_file"))
entry({"admin", "store", "local_backup"}, post("local_backup"))
entry({"admin", "store", "light_restore"}, post("light_restore"))
entry({"admin", "store", "local_restore"}, post("local_restore"))
entry({"admin", "store", "get_backup_app_list_file_path"}, call("get_backup_app_list_file_path"))
entry({"admin", "store", "get_backup_app_list"}, call("get_backup_app_list"))
end
if nixio.fs.access("/usr/libexec/istore/backup") or nixio.fs.access("/usr/libexec/istore/overlay-backup") then
entry({"admin", "store", "local_backup"}, post("local_backup"))
entry({"admin", "store", "local_restore"}, post("local_restore"))
entry({"admin", "store", "get_available_backup_file_list"}, call("get_available_backup_file_list"))
entry({"admin", "store", "set_local_backup_dir_path"}, post("set_local_backup_dir_path"))
entry({"admin", "store", "get_local_backup_dir_path"}, call("get_local_backup_dir_path"))
@@ -160,6 +163,9 @@ function store_index()
if fs.access("/usr/libexec/istore/backup") then
features[#features+1] = "backup"
end
if luci.sys.call(is_overlay_backup .. " supports_overlay_backup >/dev/null 2>&1") == 0 then
features[#features+1] = "overlay"
end
if luci.sys.call("which docker >/dev/null 2>&1") == 0 then
features[#features+1] = "docker"
end
@@ -682,18 +688,27 @@ function local_backup()
local code, out, err, ret
local error_ret
local path = luci.http.formvalue("path")
local type = luci.http.formvalue("type") or "istore"
if path ~= "" then
-- judge path
local fs = require "nixio.fs"
fs.mkdirr(path)
code,out,err = is_exec("findmnt -T " .. path .. " -o TARGET|sed -n 2p")
if out:gsub("[\r\n]", "") == "/" or out:gsub("[\r\n]", "") == "/tmp" then
local mp = out:gsub("[\r\n]", "")
if mp == "/" or mp == "/tmp" then
-- error
error_ret = {code = 500, stderr = "Path Error,Can not be / or tmp."}
luci.http.prepare_content("application/json")
luci.http.write_json(error_ret)
luci.http.write_json(error_ret)
elseif type == "overlay" and ( mp == "/overlay" or mp == "/ext_overlay" ) then
-- error
error_ret = {code = 500, stderr = "Path Error,Can not be /overlay or /ext_overlay."}
luci.http.prepare_content("application/json")
luci.http.write_json(error_ret)
else
-- update local backup path
update_local_backup_path(path)
code,out,err = _action(is_backup, "backup", path)
code,out,err = _action(type == "overlay" and is_overlay_backup or is_backup, "backup", path)
ret = {
code = code,
stdout = out,
@@ -761,9 +776,10 @@ end
-- post local_restore
function local_restore()
local path = luci.http.formvalue("path")
local type = luci.http.formvalue("type") or "istore"
local code, out, err, ret
if path ~= "" then
code,out,err = _action(is_backup, "restore", path)
code,out,err = _action(type == "overlay" and is_overlay_backup or is_backup, "restore", path)
ret = {
code = code,
stdout = out,
@@ -821,12 +837,13 @@ function get_available_backup_file_list()
local error_ret = {code = 500, msg = "Unknown"}
local success_ret = {code = 200,msg = "Unknown"}
local path = luci.http.formvalue("path")
local type = luci.http.formvalue("type") or "istore"
local r,o,e
if path ~= "" then
-- update local backup path
update_local_backup_path(path)
r,o,e = is_exec(is_backup .. " get_available_backup_file_list " .. luci.util.shellquote(path))
r,o,e = is_exec((type == "overlay" and is_overlay_backup or is_backup) .. " get_available_backup_file_list " .. luci.util.shellquote(path))
if r ~= 0 then
error_ret.msg = e
luci.http.prepare_content("application/json")
@@ -170,7 +170,7 @@ backup() {
ipk_build ${pkg_name} $BACKUP_PATH/backup_istore_$date
done
# 5. create tar.gz file,and remove fir
# 5. create tar.gz file,and remove dir
cd $BACKUP_PATH
echo "write backup file to $BACKUP_PATH/backup_istore_$date.backup.tar.gz"
tar -czf $BACKUP_PATH/backup_istore_$date.backup.tar.gz backup_istore_$date
@@ -246,10 +246,10 @@ get_backup_app_list() {
}
get_available_backup_file_list() {
local backup_file
if [ -n "$1" ]; then
for backup_file in `ls $1/*.backup.tar.gz`; do
filename=${backup_file##*/}
echo "${filename}"
for backup_file in `cd $1 && ls backup_istore_*.backup.tar.gz`; do
echo "${backup_file}"
done
else
echo "input backup path is null"
@@ -0,0 +1,177 @@
#!/bin/sh
TMP_SELF_COPY=/var/run/cloned-overlay-backup
action=${1}
shift
has_overlay() {
[ -d "/overlay/upper" ] || return 1
[ "overlay" = "$(/bin/mount | awk '($3 ~ /^\/$/) && ($5 !~ /rootfs/) { print $5 }')" ] || return 1
return 0
}
has_ext_overlay() {
[ -d "/ext_overlay/upper" ] || return 1
grep '^overlayfs:/overlay / ' /proc/mounts | grep -Fq 'upperdir=/ext_overlay/upper' || return 1
return 0
}
backup() {
if ! has_overlay; then
echo "only supports squashfs firmware"
exit 1
fi
if [ -z "$1" ]; then
echo "input backup path is null"
exit 1
fi
local BACKUP_PATH="$1"
if echo "$BACKUP_PATH" | grep -q -e '^/overlay/upper' -e '^/ext_overlay/upper' ; then
echo "can not backup to /overlay/upper, /ext_overlay/upper"
exit 1
fi
if [ ! -d "${BACKUP_PATH}" ] && ! mkdir -p "${BACKUP_PATH}" ; then
echo "backup path does not exist and can not be create"
exit 1
fi
local realpath="$(cd "${BACKUP_PATH}"; pwd -P)"
if [ -z "$realpath" ]; then
echo "cannot get absolute path of ${BACKUP_PATH}"
exit 1
fi
local mountpoint=$(findmnt -T $realpath -o TARGET | sed -n 2p)
# while read -r; do
# if [[ "x$realpath" == "x$REPLY" || "x${realpath#$REPLY/}" != "x$realpath" ]]; then
# mountpoint="$REPLY"
# break
# fi
# done < <(
# cat /proc/mounts | grep -v '^overlay ' | awk 'NR>1 {print $2}' | grep -v '^/$' | \
# sort -u | \
# while read -r; do printf "%b\n" "$REPLY" ; done | \
# awk '{print length, $0}' | sort -nr | cut -d' ' -f2-
# )
if [ "/" = "$mountpoint" ]; then
echo "can not backup to /"
exit 1
else
echo "found mount point $mountpoint"
fi
local tar_extra_args=
if has_ext_overlay; then
tar_extra_args="$tar_extra_args ext_overlay/upper"
fi
local hostname=$(cat /proc/sys/kernel/hostname)
local fwver=$(. /etc/openwrt_release; echo $DISTRIB_ID-$DISTRIB_RELEASE)
local date=$(date +%Y-%m%d-%H%M)
local backup_name="backup_overlay_${hostname}_${fwver}_${date}.overlay.tar.gz"
local backup_full_path="$BACKUP_PATH/$backup_name"
echo "writing backup to $backup_full_path"
if tar -C / -cz overlay/upper $tar_extra_args > "$backup_full_path" ; then
sync "$BACKUP_PATH"
echo "backup success"
return 0
else
rm -f "$backup_full_path"
echo "backup failed"
exit 1
fi
}
restore() {
if ! has_overlay; then
echo "only supports squashfs firmware"
exit 1
fi
if [ -z "$1" ]; then
echo "input backup path is null"
exit 1
fi
local BACKUP_PATH_FILE="$1"
if [ ! -f "${BACKUP_PATH_FILE}" ]; then
echo "invalid backup file, can not restore"
exit 1
fi
local tar_extra_args=
if has_ext_overlay; then
tar_extra_args="$tar_extra_args ext_overlay/upper"
fi
sync /
echo "restoring from ${BACKUP_PATH_FILE}"
if tar -C / -xz overlay/upper $tar_extra_args < "${BACKUP_PATH_FILE}" ; then
sync /overlay /ext_overlay
echo "restore success"
echo "schedule to restart after 5 seconds!"
/etc/init.d/tasks task_add reboot 'reboot -d 5'
return 0
else
echo "restore failed"
exit 1
fi
}
supports_overlay_backup() {
has_overlay || return 1
echo "overlay"
has_ext_overlay && echo "ext_overlay"
return 0
}
get_backup_file_list() {
local backup_file
if [ -n "$1" ]; then
for backup_file in `cd $1 && ls backup_overlay_*.overlay.tar.gz`; do
echo "${backup_file}"
done
else
echo "input backup path is null"
exit 1
fi
}
usage() {
echo "usage: overlay-backup sub-command [arguments...]"
echo "where sub-command is one of:"
echo " backup [dir] Backup all installed package(s) to [directory]"
echo " restore [dir] Restore package(s) by [directory]"
echo " supports_overlay_backup check system supports overlay backup"
echo " get_backup_file_list [dir] get local available backup file list in [dir]"
}
case $action in
"supports_overlay_backup")
supports_overlay_backup
;;
"backup")
backup "$@"
;;
"restore")
if [ "$0" = "$TMP_SELF_COPY" ]; then
restore "$@"
else
echo "copy self $0 to $TMP_SELF_COPY when restore"
cp -af "$0" "$TMP_SELF_COPY"
exec "$TMP_SELF_COPY" restore "$@"
fi
;;
"get_available_backup_file_list")
get_backup_file_list "$@"
;;
*)
usage
;;
esac
+1 -1
View File
@@ -6,7 +6,7 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=luci-app-passwall
PKG_VERSION:=25.5.15
PKG_VERSION:=25.5.16
PKG_RELEASE:=1
PKG_CONFIG_DEPENDS:= \
@@ -459,6 +459,9 @@ function gen_outbound(flag, node, tag, proxy_table)
if node.protocol == "anytls" then
protocol_table = {
password = (node.password and node.password ~= "") and node.password or "",
idle_session_check_interval = "30s",
idle_session_timeout = "30s",
min_idle_session = 5,
tls = tls
}
end
@@ -1023,7 +1026,7 @@ function gen_config(var)
end
if is_new_ut_node then
local ut_node = uci:get_all(appname, ut_node_id)
local outbound = gen_outbound(flag, ut_node, ut_node_tag)
local outbound = gen_outbound(flag, ut_node, ut_node_tag, { run_socks_instance = not no_run })
if outbound then
outbound.tag = outbound.tag .. ":" .. ut_node.remarks
table.insert(outbounds, outbound)
@@ -1439,7 +1442,7 @@ function gen_config(var)
sys.call(string.format("mkdir -p %s && touch %s/%s", api.TMP_IFACE_PATH, api.TMP_IFACE_PATH, node.iface))
end
else
local outbound = gen_outbound(flag, node)
local outbound = gen_outbound(flag, node, nil, { run_socks_instance = not no_run })
if outbound then
outbound.tag = outbound.tag .. ":" .. node.remarks
COMMON.default_outbound_tag, last_insert_outbound = set_outbound_detour(node, outbound, outbounds)
+1 -1
View File
@@ -6,7 +6,7 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=luci-app-passwall
PKG_VERSION:=25.5.8
PKG_VERSION:=25.5.15
PKG_RELEASE:=1
PKG_CONFIG_DEPENDS:= \
@@ -84,6 +84,7 @@ function gen_outbound(flag, node, tag, proxy_table)
local run_socks_instance = true
if proxy_table ~= nil and type(proxy_table) == "table" then
proxy_tag = proxy_table.tag or nil
run_socks_instance = proxy_table.run_socks_instance
end
if node.type ~= "sing-box" then
@@ -458,6 +459,9 @@ function gen_outbound(flag, node, tag, proxy_table)
if node.protocol == "anytls" then
protocol_table = {
password = (node.password and node.password ~= "") and node.password or "",
idle_session_check_interval = "30s",
idle_session_timeout = "30s",
min_idle_session = 5,
tls = tls
}
end
@@ -62,6 +62,7 @@ function gen_outbound(flag, node, tag, proxy_table)
proxy_tag = proxy_table.tag or nil
fragment = proxy_table.fragment or nil
noise = proxy_table.noise or nil
run_socks_instance = proxy_table.run_socks_instance
end
if node.type ~= "Xray" then
@@ -735,7 +736,7 @@ function gen_config(var)
end
if is_new_blc_node then
local blc_node = uci:get_all(appname, blc_node_id)
local outbound = gen_outbound(flag, blc_node, blc_node_tag, { fragment = xray_settings.fragment == "1" or nil, noise = xray_settings.noise == "1" or nil })
local outbound = gen_outbound(flag, blc_node, blc_node_tag, { fragment = xray_settings.fragment == "1" or nil, noise = xray_settings.noise == "1" or nil, run_socks_instance = not no_run })
if outbound then
outbound.tag = outbound.tag .. ":" .. blc_node.remarks
table.insert(outbounds, outbound)
@@ -761,7 +762,7 @@ function gen_config(var)
if is_new_node then
local fallback_node = uci:get_all(appname, fallback_node_id)
if fallback_node.protocol ~= "_balancing" then
local outbound = gen_outbound(flag, fallback_node, fallback_node_id, { fragment = xray_settings.fragment == "1" or nil, noise = xray_settings.noise == "1" or nil })
local outbound = gen_outbound(flag, fallback_node, fallback_node_id, { fragment = xray_settings.fragment == "1" or nil, noise = xray_settings.noise == "1" or nil, run_socks_instance = not no_run })
if outbound then
outbound.tag = outbound.tag .. ":" .. fallback_node.remarks
table.insert(outbounds, outbound)
@@ -1140,7 +1141,7 @@ function gen_config(var)
sys.call(string.format("mkdir -p %s && touch %s/%s", api.TMP_IFACE_PATH, api.TMP_IFACE_PATH, node.iface))
end
else
local outbound = gen_outbound(flag, node, nil, { fragment = xray_settings.fragment == "1" or nil, noise = xray_settings.fragment == "1" or nil })
local outbound = gen_outbound(flag, node, nil, { fragment = xray_settings.fragment == "1" or nil, noise = xray_settings.fragment == "1" or nil, run_socks_instance = not no_run })
if outbound then
outbound.tag = outbound.tag .. ":" .. node.remarks
COMMON.default_outbound_tag, last_insert_outbound = set_outbound_detour(node, outbound, outbounds)
@@ -30,15 +30,21 @@ reload_dnsmasq_pids() {
while true; do
if [ -s "$LEASE_FILE" ]; then
awk 'NF >= 4 {print $3" "$4}' "$LEASE_FILE" | sort > "$TMP_FILE"
if [ -f "$TMP_FILE" ]; then
if [ ! -f "$HOSTS_FILE" ] || [ "$(md5sum "$TMP_FILE" | awk '{print $1}')" != "$(md5sum "$HOSTS_FILE" | awk '{print $1}')" ]; then
if [ -f "$LEASE_FILE" ]; then
awk 'NF >= 4 && $4 != "*" {print $3" "$4}' "$LEASE_FILE" | sort > "$TMP_FILE"
if [ -s "$TMP_FILE" ]; then
if [ ! -f "$HOSTS_FILE" ] || ! cmp -s "$TMP_FILE" "$HOSTS_FILE"; then
mv "$TMP_FILE" "$HOSTS_FILE"
reload_dnsmasq_pids
else
rm -rf "$TMP_FILE"
rm -f "$TMP_FILE"
fi
else
if [ -s "$HOSTS_FILE" ]; then
: > "$HOSTS_FILE"
reload_dnsmasq_pids
fi
rm -f "$TMP_FILE"
fi
fi
@@ -95,40 +95,11 @@ url_test_node() {
[ "${chn_list}" = "proxy" ] && probeUrl="www.baidu.com"
result=$(${_curl} --max-time 5 -o /dev/null -I -skL -x ${curlx} ${curl_arg}${probeUrl})
pgrep -af "url_test_${node_id}" | awk '! /test\.sh/{print $1}' | xargs kill -9 >/dev/null 2>&1
rm -rf "/tmp/etc/${CONFIG}/url_test_${node_id}"*.json
rm -rf /tmp/etc/${CONFIG}/*url_test_${node_id}*.json
}
echo $result
}
test_node() {
local node_id=$1
local _type=$(echo $(config_n_get ${node_id} type) | tr 'A-Z' 'a-z')
[ -n "${_type}" ] && {
if [ "${_type}" == "socks" ]; then
local _address=$(config_n_get ${node_id} address)
local _port=$(config_n_get ${node_id} port)
[ -n "${_address}" ] && [ -n "${_port}" ] && {
local curlx="socks5h://${_address}:${_port}"
local _username=$(config_n_get ${node_id} username)
local _password=$(config_n_get ${node_id} password)
[ -n "${_username}" ] && [ -n "${_password}" ] && curlx="socks5h://${_username}:${_password}@${_address}:${_port}"
}
else
local _tmp_port=$(/usr/share/${CONFIG}/app.sh get_new_port 61080 tcp)
/usr/share/${CONFIG}/app.sh run_socks flag="test_node_${node_id}" node=${node_id} bind=127.0.0.1 socks_port=${_tmp_port} config_file=test_node_${node_id}.json
local curlx="socks5h://127.0.0.1:${_tmp_port}"
fi
sleep 1s
_proxy_status=$(test_url "https://www.google.com/generate_204" ${retry_num} ${connect_timeout} "-x $curlx")
pgrep -af "test_node_${node_id}" | awk '! /test\.sh/{print $1}' | xargs kill -9 >/dev/null 2>&1
rm -rf "/tmp/etc/${CONFIG}/test_node_${node_id}.json"
if [ "${_proxy_status}" -eq 200 ]; then
return 0
fi
}
return 1
}
arg1=$1
shift
case $arg1 in
@@ -1417,6 +1417,6 @@
<value>صادر کردن سرور</value>
</data>
<data name="TbSettingsIPAPIUrl" xml:space="preserve">
<value>Current connection info test URL</value>
<value>URL آزمایش اطلاعات اتصال فعلی</value>
</data>
</root>
</root>
-4
View File
@@ -9,10 +9,6 @@ A V2Ray client for Android, support [Xray core](https://github.com/XTLS/Xray-cor
[![GitHub Releases](https://img.shields.io/github/downloads/2dust/v2rayNG/latest/total?logo=github)](https://github.com/2dust/v2rayNG/releases)
[![Chat on Telegram](https://img.shields.io/badge/Chat%20on-Telegram-brightgreen.svg)](https://t.me/v2rayn)
<a href="https://play.google.com/store/apps/details?id=com.v2ray.ang">
<img alt="Get it on Google Play" src="https://play.google.com/intl/en_us/badges/images/generic/en_badge_web_generic.png" width="165" height="64" />
</a>
### Telegram Channel
[github_2dust](https://t.me/github_2dust)
+2 -16
View File
@@ -96,7 +96,6 @@ type DefaultDispatcher struct {
router routing.Router
policy policy.Manager
stats stats.Manager
dns dns.Client
fdns dns.FakeDNSEngine
}
@@ -107,7 +106,7 @@ func init() {
core.OptionalFeatures(ctx, func(fdns dns.FakeDNSEngine) {
d.fdns = fdns
})
return d.Init(config.(*Config), om, router, pm, sm, dc)
return d.Init(config.(*Config), om, router, pm, sm)
}); err != nil {
return nil, err
}
@@ -116,12 +115,11 @@ func init() {
}
// Init initializes DefaultDispatcher.
func (d *DefaultDispatcher) Init(config *Config, om outbound.Manager, router routing.Router, pm policy.Manager, sm stats.Manager, dns dns.Client) error {
func (d *DefaultDispatcher) Init(config *Config, om outbound.Manager, router routing.Router, pm policy.Manager, sm stats.Manager) error {
d.ohm = om
d.router = router
d.policy = pm
d.stats = sm
d.dns = dns
return nil
}
@@ -407,18 +405,6 @@ func sniffer(ctx context.Context, cReader *cachedReader, metadataOnly bool, netw
func (d *DefaultDispatcher) routedDispatch(ctx context.Context, link *transport.Link, destination net.Destination) {
outbounds := session.OutboundsFromContext(ctx)
ob := outbounds[len(outbounds)-1]
if hosts, ok := d.dns.(dns.HostsLookup); ok && destination.Address.Family().IsDomain() {
proxied := hosts.LookupHosts(ob.Target.String())
if proxied != nil {
ro := ob.RouteTarget == destination
destination.Address = *proxied
if ro {
ob.RouteTarget = destination
} else {
ob.Target = destination
}
}
}
var handler outbound.Handler
-16
View File
@@ -243,22 +243,6 @@ func (s *DNS) LookupIP(domain string, option dns.IPOption) ([]net.IP, uint32, er
return nil, 0, dns.ErrEmptyResponse
}
// LookupHosts implements dns.HostsLookup.
func (s *DNS) LookupHosts(domain string) *net.Address {
domain = strings.TrimSuffix(domain, ".")
if domain == "" {
return nil
}
// Normalize the FQDN form query
addrs := s.hosts.Lookup(domain, *s.ipOption)
if len(addrs) > 0 {
errors.LogInfo(s.ctx, "domain replaced: ", domain, " -> ", addrs[0].String())
return &addrs[0]
}
return nil
}
func (s *DNS) sortClients(domain string) []*Client {
clients := make([]*Client, 0, len(s.clients))
clientUsed := make([]bool, len(s.clients))
-4
View File
@@ -24,10 +24,6 @@ type Client interface {
LookupIP(domain string, option IPOption) ([]net.IP, uint32, error)
}
type HostsLookup interface {
LookupHosts(domain string) *net.Address
}
// ClientType returns the type of Client interface. Can be used for implementing common.HasType.
//
// xray:api:beta
+2 -2
View File
@@ -13,7 +13,7 @@ require (
github.com/pelletier/go-toml v1.9.5
github.com/pires/go-proxyproto v0.8.1
github.com/quic-go/quic-go v0.51.0
github.com/refraction-networking/utls v1.7.2
github.com/refraction-networking/utls v1.7.3
github.com/sagernet/sing v0.5.1
github.com/sagernet/sing-shadowsocks v0.2.7
github.com/seiflotfy/cuckoofilter v0.0.0-20240715131351-a2f2c23f1771
@@ -27,7 +27,7 @@ require (
golang.org/x/sync v0.14.0
golang.org/x/sys v0.33.0
golang.zx2c4.com/wireguard v0.0.0-20231211153847-12269c276173
google.golang.org/grpc v1.72.0
google.golang.org/grpc v1.72.1
google.golang.org/protobuf v1.36.6
gvisor.dev/gvisor v0.0.0-20250428193742-2d800c3129d5
h12.io/socks v1.0.3
+4 -4
View File
@@ -56,8 +56,8 @@ github.com/quic-go/qpack v0.5.1 h1:giqksBPnT/HDtZ6VhtFKgoLOWmlyo9Ei6u9PqzIMbhI=
github.com/quic-go/qpack v0.5.1/go.mod h1:+PC4XFrEskIVkcLzpEkbLqq1uCoxPhQuvK5rH1ZgaEg=
github.com/quic-go/quic-go v0.51.0 h1:K8exxe9zXxeRKxaXxi/GpUqYiTrtdiWP8bo1KFya6Wc=
github.com/quic-go/quic-go v0.51.0/go.mod h1:MFlGGpcpJqRAfmYi6NC2cptDPSxRWTOGNuP4wqrWmzQ=
github.com/refraction-networking/utls v1.7.2 h1:XOgYzit7lAKaa7kzAO5BJR9l4X/H200eVUD4s8SF8/s=
github.com/refraction-networking/utls v1.7.2/go.mod h1:TUhh27RHMGtQvjQq+RyO11P6ZNQNBb3N0v7wsEjKAIQ=
github.com/refraction-networking/utls v1.7.3 h1:L0WRhHY7Oq1T0zkdzVZMR6zWZv+sXbHB9zcuvsAEqCo=
github.com/refraction-networking/utls v1.7.3/go.mod h1:TUhh27RHMGtQvjQq+RyO11P6ZNQNBb3N0v7wsEjKAIQ=
github.com/riobard/go-bloom v0.0.0-20200614022211-cdc8013cb5b3 h1:f/FNXud6gA3MNr8meMVVGxhp+QBTqY91tM8HjEuMjGg=
github.com/riobard/go-bloom v0.0.0-20200614022211-cdc8013cb5b3/go.mod h1:HgjTstvQsPGkxUsCd2KWxErBblirPizecHcpD3ffK+s=
github.com/sagernet/sing v0.5.1 h1:mhL/MZVq0TjuvHcpYcFtmSD1BFOxZ/+8ofbNZcg1k1Y=
@@ -143,8 +143,8 @@ golang.zx2c4.com/wireguard v0.0.0-20231211153847-12269c276173 h1:/jFs0duh4rdb8uI
golang.zx2c4.com/wireguard v0.0.0-20231211153847-12269c276173/go.mod h1:tkCQ4FQXmpAgYVh++1cq16/dH4QJtmvpRv19DWGAHSA=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250218202821-56aae31c358a h1:51aaUVRocpvUOSQKM6Q7VuoaktNIaMCLuhZB6DKksq4=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250218202821-56aae31c358a/go.mod h1:uRxBH1mhmO8PGhU89cMcHaXKZqO+OfakD8QQO0oYwlQ=
google.golang.org/grpc v1.72.0 h1:S7UkcVa60b5AAQTaO6ZKamFp1zMZSU0fGDK2WZLbBnM=
google.golang.org/grpc v1.72.0/go.mod h1:wH5Aktxcg25y1I3w7H69nHfXdOG3UiadoBtjh3izSDM=
google.golang.org/grpc v1.72.1 h1:HR03wO6eyZ7lknl75XlxABNVLLFc2PAb6mHlYh756mA=
google.golang.org/grpc v1.72.1/go.mod h1:wH5Aktxcg25y1I3w7H69nHfXdOG3UiadoBtjh3izSDM=
google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY=
google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=