diff --git a/.github/update.log b/.github/update.log index 553351a37e..97b5c5a28b 100644 --- a/.github/update.log +++ b/.github/update.log @@ -733,3 +733,4 @@ Update On Sat Aug 10 20:30:21 CEST 2024 Update On Sun Aug 11 20:32:52 CEST 2024 Update On Mon Aug 12 20:34:23 CEST 2024 Update On Tue Aug 13 20:34:16 CEST 2024 +Update On Wed Aug 14 20:33:18 CEST 2024 diff --git a/bbdown/.gitignore b/bbdown/.gitignore index 1ee53850b8..9107fd7151 100644 --- a/bbdown/.gitignore +++ b/bbdown/.gitignore @@ -16,6 +16,12 @@ # Mono auto generated files mono_crash.* +# Rider +.idea + +# macOS shit +.DS_Store + # Build results [Dd]ebug/ [Dd]ebugPublic/ diff --git a/bbdown/BBDown/BBDown.csproj b/bbdown/BBDown/BBDown.csproj index 35b8129562..14d887cf2e 100644 --- a/bbdown/BBDown/BBDown.csproj +++ b/bbdown/BBDown/BBDown.csproj @@ -4,7 +4,7 @@ Exe net8.0 MIT - 1.6.2 + 1.6.3 BBDown是一个免费且便捷高效的哔哩哔哩下载/解析软件. https://github.com/nilaoda/BBDown diff --git a/bbdown/BBDown/BBDownUtil.cs b/bbdown/BBDown/BBDownUtil.cs index 66cc882d53..5500ae8307 100644 --- a/bbdown/BBDown/BBDownUtil.cs +++ b/bbdown/BBDown/BBDownUtil.cs @@ -84,12 +84,12 @@ namespace BBDown string epId = await GetEpIdByBangumiSSIdAsync(SsRegex().Match(input).Groups[1].Value); avid = $"ep:{epId}"; } - else if (input.Contains("/medialist/") && input.Contains("business_id=") && input.Contains("business=space_collection")) //列表类型是合集 + else if (input.Contains("/medialist/") && input.Contains("business_id=") && input.Contains("business=space_collection")) // 列表类型是合集 { string bizId = GetQueryString("business_id", input); avid = $"listBizId:{bizId}"; } - else if (input.Contains("/medialist/") && input.Contains("business_id=") && input.Contains("business=space_series")) //列表类型是系列 + else if (input.Contains("/medialist/") && input.Contains("business_id=") && input.Contains("business=space_series")) // 列表类型是系列 { string bizId = GetQueryString("business_id", input); avid = $"seriesBizId:{bizId}"; @@ -145,10 +145,23 @@ namespace BBDown { avid = GetAidByBV(input[3..]); } - else if (input.ToLower().StartsWith("av")) //av + else if (input.ToLower().StartsWith("av")) // av { avid = input.ToLower()[2..]; } + else if (input.StartsWith("cheese/")) // ^cheese/(ep|ss)\d+ 格式 + { + string epId = ""; + if (input.Contains("/ep")) + { + epId = EpRegex().Match(input).Groups[1].Value; + } + else if (input.Contains("/ss")) + { + epId = await GetEpidBySSIdAsync(SsRegex().Match(input).Groups[1].Value); + } + avid = $"cheese:{epId}"; + } else if (input.StartsWith("ep")) { string epId = input[2..]; diff --git a/bbdown/BBDown/Program.cs b/bbdown/BBDown/Program.cs index ef980b14a0..d14661d6f6 100644 --- a/bbdown/BBDown/Program.cs +++ b/bbdown/BBDown/Program.cs @@ -226,14 +226,15 @@ namespace BBDown public static async Task<(string fetchedAid, VInfo vInfo, string apiType)> GetVideoInfoAsync(MyOption myOption, string aidOri, string input) { - //加载认证信息 + Log("检测账号登录..."); + + // 加载认证信息 LoadCredentials(myOption); // 检测是否登录了账号 bool is_login = await CheckLogin(Config.COOKIE); if (!myOption.UseIntlApi && !myOption.UseTvApi && Config.AREA == "") { - Log("检测账号登录..."); if (!is_login) { LogWarn("你尚未登录B站账号, 解析可能受到限制"); @@ -251,7 +252,33 @@ namespace BBDown Log("获取视频信息..."); IFetcher fetcher = FetcherFactory.CreateFetcher(aidOri, myOption.UseIntlApi); - var vInfo = await fetcher.FetchAsync(aidOri); + VInfo? vInfo = null; + + // 只输入 EP/SS 时优先按番剧查找,如果找不到则尝试按课程查找 + try + { + vInfo = await fetcher.FetchAsync(aidOri); + } + catch (KeyNotFoundException e) + { + if (e.Message != "Arg_KeyNotFound") throw; // 错误消息不符合预期,抛出异常 + if (aidOri.StartsWith("cheese:")) throw; // 已经按课程查找过,不再重复尝试 + + LogWarn("未找到此 EP/SS 对应番剧信息, 正在尝试按课程查找。"); + + aidOri = aidOri.Replace("ep", "cheese"); + Log("新的 aid: " + aidOri); + + if (string.IsNullOrEmpty(aidOri)) + { + throw new Exception("输入有误"); + } + + Log("获取视频信息..."); + fetcher = FetcherFactory.CreateFetcher(aidOri, myOption.UseIntlApi); + vInfo = await fetcher.FetchAsync(aidOri); + } + string title = vInfo.Title; long pubTime = vInfo.PubTime; LogColor("视频标题: " + title); diff --git a/clash-meta/.github/patch_go122/48042aa09c2f878c4faa576948b07fe625c4707a.diff b/clash-meta/.github/patch_go122/48042aa09c2f878c4faa576948b07fe625c4707a.diff deleted file mode 100644 index 2c68233358..0000000000 --- a/clash-meta/.github/patch_go122/48042aa09c2f878c4faa576948b07fe625c4707a.diff +++ /dev/null @@ -1,54 +0,0 @@ -diff --git a/src/syscall/exec_windows.go b/src/syscall/exec_windows.go -index 06e684c7116b4..b311a5c74684b 100644 ---- a/src/syscall/exec_windows.go -+++ b/src/syscall/exec_windows.go -@@ -319,17 +319,6 @@ func StartProcess(argv0 string, argv []string, attr *ProcAttr) (pid int, handle - } - } - -- var maj, min, build uint32 -- rtlGetNtVersionNumbers(&maj, &min, &build) -- isWin7 := maj < 6 || (maj == 6 && min <= 1) -- // NT kernel handles are divisible by 4, with the bottom 3 bits left as -- // a tag. The fully set tag correlates with the types of handles we're -- // concerned about here. Except, the kernel will interpret some -- // special handle values, like -1, -2, and so forth, so kernelbase.dll -- // checks to see that those bottom three bits are checked, but that top -- // bit is not checked. -- isLegacyWin7ConsoleHandle := func(handle Handle) bool { return isWin7 && handle&0x10000003 == 3 } -- - p, _ := GetCurrentProcess() - parentProcess := p - if sys.ParentProcess != 0 { -@@ -338,15 +327,7 @@ func StartProcess(argv0 string, argv []string, attr *ProcAttr) (pid int, handle - fd := make([]Handle, len(attr.Files)) - for i := range attr.Files { - if attr.Files[i] > 0 { -- destinationProcessHandle := parentProcess -- -- // On Windows 7, console handles aren't real handles, and can only be duplicated -- // into the current process, not a parent one, which amounts to the same thing. -- if parentProcess != p && isLegacyWin7ConsoleHandle(Handle(attr.Files[i])) { -- destinationProcessHandle = p -- } -- -- err := DuplicateHandle(p, Handle(attr.Files[i]), destinationProcessHandle, &fd[i], 0, true, DUPLICATE_SAME_ACCESS) -+ err := DuplicateHandle(p, Handle(attr.Files[i]), parentProcess, &fd[i], 0, true, DUPLICATE_SAME_ACCESS) - if err != nil { - return 0, 0, err - } -@@ -377,14 +358,6 @@ func StartProcess(argv0 string, argv []string, attr *ProcAttr) (pid int, handle - - fd = append(fd, sys.AdditionalInheritedHandles...) - -- // On Windows 7, console handles aren't real handles, so don't pass them -- // through to PROC_THREAD_ATTRIBUTE_HANDLE_LIST. -- for i := range fd { -- if isLegacyWin7ConsoleHandle(fd[i]) { -- fd[i] = 0 -- } -- } -- - // The presence of a NULL handle in the list is enough to cause PROC_THREAD_ATTRIBUTE_HANDLE_LIST - // to treat the entire list as empty, so remove NULL handles. - j := 0 \ No newline at end of file diff --git a/clash-meta/.github/patch_go122/693def151adff1af707d82d28f55dba81ceb08e1.diff b/clash-meta/.github/patch_go122/693def151adff1af707d82d28f55dba81ceb08e1.diff deleted file mode 100644 index ca41ec317e..0000000000 --- a/clash-meta/.github/patch_go122/693def151adff1af707d82d28f55dba81ceb08e1.diff +++ /dev/null @@ -1,158 +0,0 @@ -diff --git a/src/crypto/rand/rand.go b/src/crypto/rand/rand.go -index 62738e2cb1a7d..d0dcc7cc71fc0 100644 ---- a/src/crypto/rand/rand.go -+++ b/src/crypto/rand/rand.go -@@ -15,7 +15,7 @@ import "io" - // available, /dev/urandom otherwise. - // On OpenBSD and macOS, Reader uses getentropy(2). - // On other Unix-like systems, Reader reads from /dev/urandom. --// On Windows systems, Reader uses the RtlGenRandom API. -+// On Windows systems, Reader uses the ProcessPrng API. - // On JS/Wasm, Reader uses the Web Crypto API. - // On WASIP1/Wasm, Reader uses random_get from wasi_snapshot_preview1. - var Reader io.Reader -diff --git a/src/crypto/rand/rand_windows.go b/src/crypto/rand/rand_windows.go -index 6c0655c72b692..7380f1f0f1e6e 100644 ---- a/src/crypto/rand/rand_windows.go -+++ b/src/crypto/rand/rand_windows.go -@@ -15,11 +15,8 @@ func init() { Reader = &rngReader{} } - - type rngReader struct{} - --func (r *rngReader) Read(b []byte) (n int, err error) { -- // RtlGenRandom only returns 1<<32-1 bytes at a time. We only read at -- // most 1<<31-1 bytes at a time so that this works the same on 32-bit -- // and 64-bit systems. -- if err := batched(windows.RtlGenRandom, 1<<31-1)(b); err != nil { -+func (r *rngReader) Read(b []byte) (int, error) { -+ if err := windows.ProcessPrng(b); err != nil { - return 0, err - } - return len(b), nil -diff --git a/src/internal/syscall/windows/syscall_windows.go b/src/internal/syscall/windows/syscall_windows.go -index ab4ad2ec64108..5854ca60b5cef 100644 ---- a/src/internal/syscall/windows/syscall_windows.go -+++ b/src/internal/syscall/windows/syscall_windows.go -@@ -373,7 +373,7 @@ func ErrorLoadingGetTempPath2() error { - //sys DestroyEnvironmentBlock(block *uint16) (err error) = userenv.DestroyEnvironmentBlock - //sys CreateEvent(eventAttrs *SecurityAttributes, manualReset uint32, initialState uint32, name *uint16) (handle syscall.Handle, err error) = kernel32.CreateEventW - --//sys RtlGenRandom(buf []byte) (err error) = advapi32.SystemFunction036 -+//sys ProcessPrng(buf []byte) (err error) = bcryptprimitives.ProcessPrng - - type FILE_ID_BOTH_DIR_INFO struct { - NextEntryOffset uint32 -diff --git a/src/internal/syscall/windows/zsyscall_windows.go b/src/internal/syscall/windows/zsyscall_windows.go -index e3f6d8d2a2208..5a587ad4f146c 100644 ---- a/src/internal/syscall/windows/zsyscall_windows.go -+++ b/src/internal/syscall/windows/zsyscall_windows.go -@@ -37,13 +37,14 @@ func errnoErr(e syscall.Errno) error { - } - - var ( -- modadvapi32 = syscall.NewLazyDLL(sysdll.Add("advapi32.dll")) -- modiphlpapi = syscall.NewLazyDLL(sysdll.Add("iphlpapi.dll")) -- modkernel32 = syscall.NewLazyDLL(sysdll.Add("kernel32.dll")) -- modnetapi32 = syscall.NewLazyDLL(sysdll.Add("netapi32.dll")) -- modpsapi = syscall.NewLazyDLL(sysdll.Add("psapi.dll")) -- moduserenv = syscall.NewLazyDLL(sysdll.Add("userenv.dll")) -- modws2_32 = syscall.NewLazyDLL(sysdll.Add("ws2_32.dll")) -+ modadvapi32 = syscall.NewLazyDLL(sysdll.Add("advapi32.dll")) -+ modbcryptprimitives = syscall.NewLazyDLL(sysdll.Add("bcryptprimitives.dll")) -+ modiphlpapi = syscall.NewLazyDLL(sysdll.Add("iphlpapi.dll")) -+ modkernel32 = syscall.NewLazyDLL(sysdll.Add("kernel32.dll")) -+ modnetapi32 = syscall.NewLazyDLL(sysdll.Add("netapi32.dll")) -+ modpsapi = syscall.NewLazyDLL(sysdll.Add("psapi.dll")) -+ moduserenv = syscall.NewLazyDLL(sysdll.Add("userenv.dll")) -+ modws2_32 = syscall.NewLazyDLL(sysdll.Add("ws2_32.dll")) - - procAdjustTokenPrivileges = modadvapi32.NewProc("AdjustTokenPrivileges") - procDuplicateTokenEx = modadvapi32.NewProc("DuplicateTokenEx") -@@ -55,7 +56,7 @@ var ( - procQueryServiceStatus = modadvapi32.NewProc("QueryServiceStatus") - procRevertToSelf = modadvapi32.NewProc("RevertToSelf") - procSetTokenInformation = modadvapi32.NewProc("SetTokenInformation") -- procSystemFunction036 = modadvapi32.NewProc("SystemFunction036") -+ procProcessPrng = modbcryptprimitives.NewProc("ProcessPrng") - procGetAdaptersAddresses = modiphlpapi.NewProc("GetAdaptersAddresses") - procCreateEventW = modkernel32.NewProc("CreateEventW") - procGetACP = modkernel32.NewProc("GetACP") -@@ -179,12 +180,12 @@ func SetTokenInformation(tokenHandle syscall.Token, tokenInformationClass uint32 - return - } - --func RtlGenRandom(buf []byte) (err error) { -+func ProcessPrng(buf []byte) (err error) { - var _p0 *byte - if len(buf) > 0 { - _p0 = &buf[0] - } -- r1, _, e1 := syscall.Syscall(procSystemFunction036.Addr(), 2, uintptr(unsafe.Pointer(_p0)), uintptr(len(buf)), 0) -+ r1, _, e1 := syscall.Syscall(procProcessPrng.Addr(), 2, uintptr(unsafe.Pointer(_p0)), uintptr(len(buf)), 0) - if r1 == 0 { - err = errnoErr(e1) - } -diff --git a/src/runtime/os_windows.go b/src/runtime/os_windows.go -index 8ca8d7790909e..3772a864b2ff4 100644 ---- a/src/runtime/os_windows.go -+++ b/src/runtime/os_windows.go -@@ -127,15 +127,8 @@ var ( - _WriteFile, - _ stdFunction - -- // Use RtlGenRandom to generate cryptographically random data. -- // This approach has been recommended by Microsoft (see issue -- // 15589 for details). -- // The RtlGenRandom is not listed in advapi32.dll, instead -- // RtlGenRandom function can be found by searching for SystemFunction036. -- // Also some versions of Mingw cannot link to SystemFunction036 -- // when building executable as Cgo. So load SystemFunction036 -- // manually during runtime startup. -- _RtlGenRandom stdFunction -+ // Use ProcessPrng to generate cryptographically random data. -+ _ProcessPrng stdFunction - - // Load ntdll.dll manually during startup, otherwise Mingw - // links wrong printf function to cgo executable (see issue -@@ -151,11 +144,11 @@ var ( - ) - - var ( -- advapi32dll = [...]uint16{'a', 'd', 'v', 'a', 'p', 'i', '3', '2', '.', 'd', 'l', 'l', 0} -- ntdlldll = [...]uint16{'n', 't', 'd', 'l', 'l', '.', 'd', 'l', 'l', 0} -- powrprofdll = [...]uint16{'p', 'o', 'w', 'r', 'p', 'r', 'o', 'f', '.', 'd', 'l', 'l', 0} -- winmmdll = [...]uint16{'w', 'i', 'n', 'm', 'm', '.', 'd', 'l', 'l', 0} -- ws2_32dll = [...]uint16{'w', 's', '2', '_', '3', '2', '.', 'd', 'l', 'l', 0} -+ bcryptprimitivesdll = [...]uint16{'b', 'c', 'r', 'y', 'p', 't', 'p', 'r', 'i', 'm', 'i', 't', 'i', 'v', 'e', 's', '.', 'd', 'l', 'l', 0} -+ ntdlldll = [...]uint16{'n', 't', 'd', 'l', 'l', '.', 'd', 'l', 'l', 0} -+ powrprofdll = [...]uint16{'p', 'o', 'w', 'r', 'p', 'r', 'o', 'f', '.', 'd', 'l', 'l', 0} -+ winmmdll = [...]uint16{'w', 'i', 'n', 'm', 'm', '.', 'd', 'l', 'l', 0} -+ ws2_32dll = [...]uint16{'w', 's', '2', '_', '3', '2', '.', 'd', 'l', 'l', 0} - ) - - // Function to be called by windows CreateThread -@@ -251,11 +244,11 @@ func windowsLoadSystemLib(name []uint16) uintptr { - } - - func loadOptionalSyscalls() { -- a32 := windowsLoadSystemLib(advapi32dll[:]) -- if a32 == 0 { -- throw("advapi32.dll not found") -+ bcryptPrimitives := windowsLoadSystemLib(bcryptprimitivesdll[:]) -+ if bcryptPrimitives == 0 { -+ throw("bcryptprimitives.dll not found") - } -- _RtlGenRandom = windowsFindfunc(a32, []byte("SystemFunction036\000")) -+ _ProcessPrng = windowsFindfunc(bcryptPrimitives, []byte("ProcessPrng\000")) - - n32 := windowsLoadSystemLib(ntdlldll[:]) - if n32 == 0 { -@@ -531,7 +524,7 @@ func osinit() { - //go:nosplit - func readRandom(r []byte) int { - n := 0 -- if stdcall2(_RtlGenRandom, uintptr(unsafe.Pointer(&r[0])), uintptr(len(r)))&0xff != 0 { -+ if stdcall2(_ProcessPrng, uintptr(unsafe.Pointer(&r[0])), uintptr(len(r)))&0xff != 0 { - n = len(r) - } - return n \ No newline at end of file diff --git a/clash-meta/.github/patch_go122/7c1157f9544922e96945196b47b95664b1e39108.diff b/clash-meta/.github/patch_go122/7c1157f9544922e96945196b47b95664b1e39108.diff deleted file mode 100644 index c1fc5f6d2d..0000000000 --- a/clash-meta/.github/patch_go122/7c1157f9544922e96945196b47b95664b1e39108.diff +++ /dev/null @@ -1,162 +0,0 @@ -diff --git a/src/net/hook_windows.go b/src/net/hook_windows.go -index ab8656cbbf343..28c49cc6de7e7 100644 ---- a/src/net/hook_windows.go -+++ b/src/net/hook_windows.go -@@ -14,7 +14,6 @@ var ( - testHookDialChannel = func() { time.Sleep(time.Millisecond) } // see golang.org/issue/5349 - - // Placeholders for socket system calls. -- socketFunc func(int, int, int) (syscall.Handle, error) = syscall.Socket - wsaSocketFunc func(int32, int32, int32, *syscall.WSAProtocolInfo, uint32, uint32) (syscall.Handle, error) = windows.WSASocket - connectFunc func(syscall.Handle, syscall.Sockaddr) error = syscall.Connect - listenFunc func(syscall.Handle, int) error = syscall.Listen -diff --git a/src/net/internal/socktest/main_test.go b/src/net/internal/socktest/main_test.go -index 0197feb3f199a..967ce6795aedb 100644 ---- a/src/net/internal/socktest/main_test.go -+++ b/src/net/internal/socktest/main_test.go -@@ -2,7 +2,7 @@ - // Use of this source code is governed by a BSD-style - // license that can be found in the LICENSE file. - --//go:build !js && !plan9 && !wasip1 -+//go:build !js && !plan9 && !wasip1 && !windows - - package socktest_test - -diff --git a/src/net/internal/socktest/main_windows_test.go b/src/net/internal/socktest/main_windows_test.go -deleted file mode 100644 -index df1cb97784b51..0000000000000 ---- a/src/net/internal/socktest/main_windows_test.go -+++ /dev/null -@@ -1,22 +0,0 @@ --// Copyright 2015 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. -- --package socktest_test -- --import "syscall" -- --var ( -- socketFunc func(int, int, int) (syscall.Handle, error) -- closeFunc func(syscall.Handle) error --) -- --func installTestHooks() { -- socketFunc = sw.Socket -- closeFunc = sw.Closesocket --} -- --func uninstallTestHooks() { -- socketFunc = syscall.Socket -- closeFunc = syscall.Closesocket --} -diff --git a/src/net/internal/socktest/sys_windows.go b/src/net/internal/socktest/sys_windows.go -index 8c1c862f33c9b..1c42e5c7f34b7 100644 ---- a/src/net/internal/socktest/sys_windows.go -+++ b/src/net/internal/socktest/sys_windows.go -@@ -9,38 +9,6 @@ import ( - "syscall" - ) - --// Socket wraps syscall.Socket. --func (sw *Switch) Socket(family, sotype, proto int) (s syscall.Handle, err error) { -- sw.once.Do(sw.init) -- -- so := &Status{Cookie: cookie(family, sotype, proto)} -- sw.fmu.RLock() -- f, _ := sw.fltab[FilterSocket] -- sw.fmu.RUnlock() -- -- af, err := f.apply(so) -- if err != nil { -- return syscall.InvalidHandle, err -- } -- s, so.Err = syscall.Socket(family, sotype, proto) -- if err = af.apply(so); err != nil { -- if so.Err == nil { -- syscall.Closesocket(s) -- } -- return syscall.InvalidHandle, err -- } -- -- sw.smu.Lock() -- defer sw.smu.Unlock() -- if so.Err != nil { -- sw.stats.getLocked(so.Cookie).OpenFailed++ -- return syscall.InvalidHandle, so.Err -- } -- nso := sw.addLocked(s, family, sotype, proto) -- sw.stats.getLocked(nso.Cookie).Opened++ -- return s, nil --} -- - // WSASocket wraps [syscall.WSASocket]. - func (sw *Switch) WSASocket(family, sotype, proto int32, protinfo *syscall.WSAProtocolInfo, group uint32, flags uint32) (s syscall.Handle, err error) { - sw.once.Do(sw.init) -diff --git a/src/net/main_windows_test.go b/src/net/main_windows_test.go -index 07f21b72eb1fc..bc024c0bbd82d 100644 ---- a/src/net/main_windows_test.go -+++ b/src/net/main_windows_test.go -@@ -8,7 +8,6 @@ import "internal/poll" - - var ( - // Placeholders for saving original socket system calls. -- origSocket = socketFunc - origWSASocket = wsaSocketFunc - origClosesocket = poll.CloseFunc - origConnect = connectFunc -@@ -18,7 +17,6 @@ var ( - ) - - func installTestHooks() { -- socketFunc = sw.Socket - wsaSocketFunc = sw.WSASocket - poll.CloseFunc = sw.Closesocket - connectFunc = sw.Connect -@@ -28,7 +26,6 @@ func installTestHooks() { - } - - func uninstallTestHooks() { -- socketFunc = origSocket - wsaSocketFunc = origWSASocket - poll.CloseFunc = origClosesocket - connectFunc = origConnect -diff --git a/src/net/sock_windows.go b/src/net/sock_windows.go -index fa11c7af2e727..5540135a2c43e 100644 ---- a/src/net/sock_windows.go -+++ b/src/net/sock_windows.go -@@ -19,21 +19,6 @@ func maxListenerBacklog() int { - func sysSocket(family, sotype, proto int) (syscall.Handle, error) { - s, err := wsaSocketFunc(int32(family), int32(sotype), int32(proto), - nil, 0, windows.WSA_FLAG_OVERLAPPED|windows.WSA_FLAG_NO_HANDLE_INHERIT) -- if err == nil { -- return s, nil -- } -- // WSA_FLAG_NO_HANDLE_INHERIT flag is not supported on some -- // old versions of Windows, see -- // https://msdn.microsoft.com/en-us/library/windows/desktop/ms742212(v=vs.85).aspx -- // for details. Just use syscall.Socket, if windows.WSASocket failed. -- -- // See ../syscall/exec_unix.go for description of ForkLock. -- syscall.ForkLock.RLock() -- s, err = socketFunc(family, sotype, proto) -- if err == nil { -- syscall.CloseOnExec(s) -- } -- syscall.ForkLock.RUnlock() - if err != nil { - return syscall.InvalidHandle, os.NewSyscallError("socket", err) - } -diff --git a/src/syscall/exec_windows.go b/src/syscall/exec_windows.go -index 0a93bc0a80d4e..06e684c7116b4 100644 ---- a/src/syscall/exec_windows.go -+++ b/src/syscall/exec_windows.go -@@ -14,6 +14,7 @@ import ( - "unsafe" - ) - -+// ForkLock is not used on Windows. - var ForkLock sync.RWMutex - - // EscapeArg rewrites command line argument s as prescribed \ No newline at end of file diff --git a/clash-meta/.github/workflows/build.yml b/clash-meta/.github/workflows/build.yml index cd5202e12e..fb3eb621a4 100644 --- a/clash-meta/.github/workflows/build.yml +++ b/clash-meta/.github/workflows/build.yml @@ -67,6 +67,12 @@ jobs: - { goos: android, goarch: arm, ndk: armv7a-linux-androideabi34, output: armv7 } - { goos: android, goarch: arm64, ndk: aarch64-linux-android34, output: arm64-v8 } + # Go 1.22 with special patch can work on Windows 7 + # https://github.com/MetaCubeX/go/commits/release-branch.go1.22/ + - { goos: windows, goarch: '386', output: '386-go122', goversion: '1.22' } + - { goos: windows, goarch: amd64, goamd64: v1, output: amd64-compatible-go122, goversion: '1.22' } + - { goos: windows, goarch: amd64, goamd64: v3, output: amd64-go122, goversion: '1.22' } + # Go 1.21 can revert commit `9e4385` to work on Windows 7 # https://github.com/golang/go/issues/64622#issuecomment-1847475161 # (OR we can just use golang1.21.4 which unneeded any patch) @@ -79,6 +85,11 @@ jobs: - { goos: windows, goarch: amd64, goamd64: v1, output: amd64-compatible-go120, goversion: '1.20' } - { goos: windows, goarch: amd64, goamd64: v3, output: amd64-go120, goversion: '1.20' } + # Go 1.22 is the last release that will run on macOS 10.15 Catalina. Go 1.23 will require macOS 11 Big Sur or later. + - { goos: darwin, goarch: arm64, output: arm64-go122, goversion: '1.22' } + - { goos: darwin, goarch: amd64, goamd64: v1, output: amd64-compatible-go122, goversion: '1.22' } + - { goos: darwin, goarch: amd64, goamd64: v3, output: amd64-go122, goversion: '1.22' } + # Go 1.20 is the last release that will run on macOS 10.13 High Sierra or 10.14 Mojave. Go 1.21 will require macOS 10.15 Catalina or later. - { goos: darwin, goarch: arm64, output: arm64-go120, goversion: '1.20' } - { goos: darwin, goarch: amd64, goamd64: v1, output: amd64-compatible-go120, goversion: '1.20' } @@ -96,7 +107,7 @@ jobs: if: ${{ matrix.jobs.goversion == '' && matrix.jobs.goarch != 'loong64' }} uses: actions/setup-go@v5 with: - go-version: '1.22' + go-version: '1.23' - name: Set up Go if: ${{ matrix.jobs.goversion != '' && matrix.jobs.goarch != 'loong64' }} @@ -119,19 +130,40 @@ jobs: echo "/usr/local/go/bin" >> $GITHUB_PATH # modify from https://github.com/restic/restic/issues/4636#issuecomment-1896455557 - # this patch file only works on golang1.22.x - # that means after golang1.23 release it must be changed + # this patch file only works on golang1.23.x + # that means after golang1.24 release it must be changed + # see: https://github.com/MetaCubeX/go/commits/release-branch.go1.23/ # revert: # 693def151adff1af707d82d28f55dba81ceb08e1: "crypto/rand,runtime: switch RtlGenRandom for ProcessPrng" # 7c1157f9544922e96945196b47b95664b1e39108: "net: remove sysSocket fallback for Windows 7" # 48042aa09c2f878c4faa576948b07fe625c4707a: "syscall: remove Windows 7 console handle workaround" - - name: Revert Golang1.22 commit for Windows7/8 + # a17d959debdb04cd550016a3501dd09d50cd62e7: "runtime: always use LoadLibraryEx to load system libraries" + - name: Revert Golang1.23 commit for Windows7/8 if: ${{ matrix.jobs.goos == 'windows' && matrix.jobs.goversion == '' }} run: | cd $(go env GOROOT) - patch --verbose -R -p 1 < $GITHUB_WORKSPACE/.github/patch_go122/693def151adff1af707d82d28f55dba81ceb08e1.diff - patch --verbose -R -p 1 < $GITHUB_WORKSPACE/.github/patch_go122/7c1157f9544922e96945196b47b95664b1e39108.diff - patch --verbose -R -p 1 < $GITHUB_WORKSPACE/.github/patch_go122/48042aa09c2f878c4faa576948b07fe625c4707a.diff + curl https://github.com/MetaCubeX/go/commit/9ac42137ef6730e8b7daca016ece831297a1d75b.diff | patch --verbose -p 1 + curl https://github.com/MetaCubeX/go/commit/21290de8a4c91408de7c2b5b68757b1e90af49dd.diff | patch --verbose -p 1 + curl https://github.com/MetaCubeX/go/commit/6a31d3fa8e47ddabc10bd97bff10d9a85f4cfb76.diff | patch --verbose -p 1 + curl https://github.com/MetaCubeX/go/commit/69e2eed6dd0f6d815ebf15797761c13f31213dd6.diff | patch --verbose -p 1 + + # modify from https://github.com/restic/restic/issues/4636#issuecomment-1896455557 + # this patch file only works on golang1.22.x + # that means after golang1.23 release it must be changed + # see: https://github.com/MetaCubeX/go/commits/release-branch.go1.22/ + # revert: + # 693def151adff1af707d82d28f55dba81ceb08e1: "crypto/rand,runtime: switch RtlGenRandom for ProcessPrng" + # 7c1157f9544922e96945196b47b95664b1e39108: "net: remove sysSocket fallback for Windows 7" + # 48042aa09c2f878c4faa576948b07fe625c4707a: "syscall: remove Windows 7 console handle workaround" + # a17d959debdb04cd550016a3501dd09d50cd62e7: "runtime: always use LoadLibraryEx to load system libraries" + - name: Revert Golang1.22 commit for Windows7/8 + if: ${{ matrix.jobs.goos == 'windows' && matrix.jobs.goversion == '1.22' }} + run: | + cd $(go env GOROOT) + curl https://github.com/MetaCubeX/go/commit/9779155f18b6556a034f7bb79fb7fb2aad1e26a9.diff | patch --verbose -p 1 + curl https://github.com/MetaCubeX/go/commit/ef0606261340e608017860b423ffae5c1ce78239.diff | patch --verbose -p 1 + curl https://github.com/MetaCubeX/go/commit/7f83badcb925a7e743188041cb6e561fc9b5b642.diff | patch --verbose -p 1 + curl https://github.com/MetaCubeX/go/commit/83ff9782e024cb328b690cbf0da4e7848a327f4f.diff | patch --verbose -p 1 # modify from https://github.com/restic/restic/issues/4636#issuecomment-1896455557 - name: Revert Golang1.21 commit for Windows7/8 diff --git a/clash-meta/common/net/tcp_keepalive.go b/clash-meta/common/net/tcp_keepalive.go new file mode 100644 index 0000000000..047a1c05eb --- /dev/null +++ b/clash-meta/common/net/tcp_keepalive.go @@ -0,0 +1,23 @@ +package net + +import ( + "net" + "runtime" + "time" +) + +var ( + KeepAliveIdle = 0 * time.Second + KeepAliveInterval = 0 * time.Second + DisableKeepAlive = false +) + +func TCPKeepAlive(c net.Conn) { + if tcp, ok := c.(*net.TCPConn); ok { + if runtime.GOOS == "android" || DisableKeepAlive { + _ = tcp.SetKeepAlive(false) + } else { + tcpKeepAlive(tcp) + } + } +} diff --git a/clash-meta/common/net/tcp_keepalive_go122.go b/clash-meta/common/net/tcp_keepalive_go122.go new file mode 100644 index 0000000000..1287316868 --- /dev/null +++ b/clash-meta/common/net/tcp_keepalive_go122.go @@ -0,0 +1,10 @@ +//go:build !go1.23 + +package net + +import "net" + +func tcpKeepAlive(tcp *net.TCPConn) { + _ = tcp.SetKeepAlive(true) + _ = tcp.SetKeepAlivePeriod(KeepAliveInterval) +} diff --git a/clash-meta/common/net/tcp_keepalive_go123.go b/clash-meta/common/net/tcp_keepalive_go123.go new file mode 100644 index 0000000000..2dd4754bbe --- /dev/null +++ b/clash-meta/common/net/tcp_keepalive_go123.go @@ -0,0 +1,19 @@ +//go:build go1.23 + +package net + +import "net" + +func tcpKeepAlive(tcp *net.TCPConn) { + config := net.KeepAliveConfig{ + Enable: true, + Idle: KeepAliveIdle, + Interval: KeepAliveInterval, + } + if !SupportTCPKeepAliveCount() { + // it's recommended to set both Idle and Interval to non-negative values in conjunction with a -1 + // for Count on those old Windows if you intend to customize the TCP keep-alive settings. + config.Count = -1 + } + _ = tcp.SetKeepAliveConfig(config) +} diff --git a/clash-meta/common/net/tcp_keepalive_go123_unix.go b/clash-meta/common/net/tcp_keepalive_go123_unix.go new file mode 100644 index 0000000000..0ead7ca472 --- /dev/null +++ b/clash-meta/common/net/tcp_keepalive_go123_unix.go @@ -0,0 +1,15 @@ +//go:build go1.23 && unix + +package net + +func SupportTCPKeepAliveIdle() bool { + return true +} + +func SupportTCPKeepAliveInterval() bool { + return true +} + +func SupportTCPKeepAliveCount() bool { + return true +} diff --git a/clash-meta/common/net/tcp_keepalive_go123_windows.go b/clash-meta/common/net/tcp_keepalive_go123_windows.go new file mode 100644 index 0000000000..8f1e61f959 --- /dev/null +++ b/clash-meta/common/net/tcp_keepalive_go123_windows.go @@ -0,0 +1,63 @@ +//go:build go1.23 && windows + +// copy and modify from golang1.23's internal/syscall/windows/version_windows.go + +package net + +import ( + "errors" + "sync" + "syscall" + + "github.com/metacubex/mihomo/constant/features" + + "golang.org/x/sys/windows" +) + +var ( + supportTCPKeepAliveIdle bool + supportTCPKeepAliveInterval bool + supportTCPKeepAliveCount bool +) + +var initTCPKeepAlive = sync.OnceFunc(func() { + s, err := windows.WSASocket(syscall.AF_INET, syscall.SOCK_STREAM, syscall.IPPROTO_TCP, nil, 0, windows.WSA_FLAG_NO_HANDLE_INHERIT) + if err != nil { + // Fallback to checking the Windows version. + major, build := features.WindowsMajorVersion, features.WindowsBuildNumber + supportTCPKeepAliveIdle = major >= 10 && build >= 16299 + supportTCPKeepAliveInterval = major >= 10 && build >= 16299 + supportTCPKeepAliveCount = major >= 10 && build >= 15063 + return + } + defer windows.Closesocket(s) + var optSupported = func(opt int) bool { + err := windows.SetsockoptInt(s, syscall.IPPROTO_TCP, opt, 1) + return !errors.Is(err, syscall.WSAENOPROTOOPT) + } + supportTCPKeepAliveIdle = optSupported(windows.TCP_KEEPIDLE) + supportTCPKeepAliveInterval = optSupported(windows.TCP_KEEPINTVL) + supportTCPKeepAliveCount = optSupported(windows.TCP_KEEPCNT) +}) + +// SupportTCPKeepAliveIdle indicates whether TCP_KEEPIDLE is supported. +// The minimal requirement is Windows 10.0.16299. +func SupportTCPKeepAliveIdle() bool { + initTCPKeepAlive() + return supportTCPKeepAliveIdle +} + +// SupportTCPKeepAliveInterval indicates whether TCP_KEEPINTVL is supported. +// The minimal requirement is Windows 10.0.16299. +func SupportTCPKeepAliveInterval() bool { + initTCPKeepAlive() + return supportTCPKeepAliveInterval +} + +// SupportTCPKeepAliveCount indicates whether TCP_KEEPCNT is supported. +// supports TCP_KEEPCNT. +// The minimal requirement is Windows 10.0.15063. +func SupportTCPKeepAliveCount() bool { + initTCPKeepAlive() + return supportTCPKeepAliveCount +} diff --git a/clash-meta/common/net/tcpip.go b/clash-meta/common/net/tcpip.go index 0499e54c17..a84e7e4c4f 100644 --- a/clash-meta/common/net/tcpip.go +++ b/clash-meta/common/net/tcpip.go @@ -4,11 +4,8 @@ import ( "fmt" "net" "strings" - "time" ) -var KeepAliveInterval = 15 * time.Second - func SplitNetworkType(s string) (string, string, error) { var ( shecme string @@ -47,10 +44,3 @@ func SplitHostPort(s string) (host, port string, hasPort bool, err error) { host, port, err = net.SplitHostPort(temp) return } - -func TCPKeepAlive(c net.Conn) { - if tcp, ok := c.(*net.TCPConn); ok { - _ = tcp.SetKeepAlive(true) - _ = tcp.SetKeepAlivePeriod(KeepAliveInterval) - } -} diff --git a/clash-meta/component/dialer/dialer.go b/clash-meta/component/dialer/dialer.go index ba95c31b81..2a39508f3f 100644 --- a/clash-meta/component/dialer/dialer.go +++ b/clash-meta/component/dialer/dialer.go @@ -13,7 +13,6 @@ import ( "time" "github.com/metacubex/mihomo/component/resolver" - "github.com/metacubex/mihomo/constant/features" "github.com/metacubex/mihomo/log" ) @@ -79,29 +78,29 @@ func DialContext(ctx context.Context, network, address string, options ...Option } func ListenPacket(ctx context.Context, network, address string, rAddrPort netip.AddrPort, options ...Option) (net.PacketConn, error) { - if features.CMFA && DefaultSocketHook != nil { - return listenPacketHooked(ctx, network, address) - } - cfg := applyOptions(options...) lc := &net.ListenConfig{} - if cfg.interfaceName != "" { - bind := bindIfaceToListenConfig - if cfg.fallbackBind { - bind = fallbackBindIfaceToListenConfig - } - addr, err := bind(cfg.interfaceName, lc, network, address, rAddrPort) - if err != nil { - return nil, err - } - address = addr - } if cfg.addrReuse { addrReuseToListenConfig(lc) } - if cfg.routingMark != 0 { - bindMarkToListenConfig(cfg.routingMark, lc, network, address) + if DefaultSocketHook != nil { // ignore interfaceName, routingMark when DefaultSocketHook not null (in CFMA) + socketHookToListenConfig(lc) + } else { + if cfg.interfaceName != "" { + bind := bindIfaceToListenConfig + if cfg.fallbackBind { + bind = fallbackBindIfaceToListenConfig + } + addr, err := bind(cfg.interfaceName, lc, network, address, rAddrPort) + if err != nil { + return nil, err + } + address = addr + } + if cfg.routingMark != 0 { + bindMarkToListenConfig(cfg.routingMark, lc, network, address) + } } return lc.ListenPacket(ctx, network, address) @@ -149,25 +148,26 @@ func dialContext(ctx context.Context, network string, destination netip.Addr, po setMultiPathTCP(dialer) } - if features.CMFA && DefaultSocketHook != nil { // ignore interfaceName, routingMark and tfo in CMFA - return dialContextHooked(ctx, dialer, network, address) + if DefaultSocketHook != nil { // ignore interfaceName, routingMark and tfo when DefaultSocketHook not null (in CFMA) + socketHookToToDialer(dialer) + } else { + if opt.interfaceName != "" { + bind := bindIfaceToDialer + if opt.fallbackBind { + bind = fallbackBindIfaceToDialer + } + if err := bind(opt.interfaceName, dialer, network, destination); err != nil { + return nil, err + } + } + if opt.routingMark != 0 { + bindMarkToDialer(opt.routingMark, dialer, network, destination) + } + if opt.tfo && !DisableTFO { + return dialTFO(ctx, *dialer, network, address) + } } - if opt.interfaceName != "" { - bind := bindIfaceToDialer - if opt.fallbackBind { - bind = fallbackBindIfaceToDialer - } - if err := bind(opt.interfaceName, dialer, network, destination); err != nil { - return nil, err - } - } - if opt.routingMark != 0 { - bindMarkToDialer(opt.routingMark, dialer, network, destination) - } - if opt.tfo && !DisableTFO { - return dialTFO(ctx, *dialer, network, address) - } return dialer.DialContext(ctx, network, address) } diff --git a/clash-meta/component/dialer/patch_android.go b/clash-meta/component/dialer/patch_android.go deleted file mode 100644 index 079b9772ab..0000000000 --- a/clash-meta/component/dialer/patch_android.go +++ /dev/null @@ -1,38 +0,0 @@ -//go:build android && cmfa - -package dialer - -import ( - "context" - "net" - "syscall" -) - -type SocketControl func(network, address string, conn syscall.RawConn) error - -var DefaultSocketHook SocketControl - -func dialContextHooked(ctx context.Context, dialer *net.Dialer, network string, address string) (net.Conn, error) { - addControlToDialer(dialer, func(ctx context.Context, network, address string, c syscall.RawConn) error { - return DefaultSocketHook(network, address, c) - }) - - conn, err := dialer.DialContext(ctx, network, address) - if err != nil { - return nil, err - } - - if t, ok := conn.(*net.TCPConn); ok { - t.SetKeepAlive(false) - } - - return conn, nil -} - -func listenPacketHooked(ctx context.Context, network, address string) (net.PacketConn, error) { - lc := &net.ListenConfig{ - Control: DefaultSocketHook, - } - - return lc.ListenPacket(ctx, network, address) -} diff --git a/clash-meta/component/dialer/patch_common.go b/clash-meta/component/dialer/patch_common.go deleted file mode 100644 index 2c96fe60b7..0000000000 --- a/clash-meta/component/dialer/patch_common.go +++ /dev/null @@ -1,21 +0,0 @@ -//go:build !(android && cmfa) - -package dialer - -import ( - "context" - "net" - "syscall" -) - -type SocketControl func(network, address string, conn syscall.RawConn) error - -var DefaultSocketHook SocketControl - -func dialContextHooked(ctx context.Context, dialer *net.Dialer, network string, address string) (net.Conn, error) { - return nil, nil -} - -func listenPacketHooked(ctx context.Context, network, address string) (net.PacketConn, error) { - return nil, nil -} diff --git a/clash-meta/component/dialer/socket_hook.go b/clash-meta/component/dialer/socket_hook.go new file mode 100644 index 0000000000..7a2ea43215 --- /dev/null +++ b/clash-meta/component/dialer/socket_hook.go @@ -0,0 +1,27 @@ +package dialer + +import ( + "context" + "net" + "syscall" +) + +// SocketControl +// never change type traits because it's used in CFMA +type SocketControl func(network, address string, conn syscall.RawConn) error + +// DefaultSocketHook +// never change type traits because it's used in CFMA +var DefaultSocketHook SocketControl + +func socketHookToToDialer(dialer *net.Dialer) { + addControlToDialer(dialer, func(ctx context.Context, network, address string, c syscall.RawConn) error { + return DefaultSocketHook(network, address, c) + }) +} + +func socketHookToListenConfig(lc *net.ListenConfig) { + addControlToListenConfig(lc, func(ctx context.Context, network, address string, c syscall.RawConn) error { + return DefaultSocketHook(network, address, c) + }) +} diff --git a/clash-meta/component/fakeip/pool.go b/clash-meta/component/fakeip/pool.go index 2b06fc0bdf..8096a868af 100644 --- a/clash-meta/component/fakeip/pool.go +++ b/clash-meta/component/fakeip/pool.go @@ -8,7 +8,7 @@ import ( "github.com/metacubex/mihomo/common/nnip" "github.com/metacubex/mihomo/component/profile/cachefile" - "github.com/metacubex/mihomo/component/trie" + C "github.com/metacubex/mihomo/constant" ) const ( @@ -35,7 +35,7 @@ type Pool struct { offset netip.Addr cycle bool mux sync.Mutex - host *trie.DomainTrie[struct{}] + host []C.Rule ipnet netip.Prefix store store } @@ -66,10 +66,12 @@ func (p *Pool) LookBack(ip netip.Addr) (string, bool) { // ShouldSkipped return if domain should be skipped func (p *Pool) ShouldSkipped(domain string) bool { - if p.host == nil { - return false + for _, rule := range p.host { + if match, _ := rule.Match(&C.Metadata{Host: domain}); match { + return true + } } - return p.host.Search(domain) != nil + return false } // Exist returns if given ip exists in fake-ip pool @@ -154,7 +156,7 @@ func (p *Pool) restoreState() { type Options struct { IPNet netip.Prefix - Host *trie.DomainTrie[struct{}] + Host []C.Rule // Size sets the maximum number of entries in memory // and does not work if Persistence is true diff --git a/clash-meta/component/fakeip/pool_test.go b/clash-meta/component/fakeip/pool_test.go index cc50fcf7b5..9c05a32778 100644 --- a/clash-meta/component/fakeip/pool_test.go +++ b/clash-meta/component/fakeip/pool_test.go @@ -9,6 +9,8 @@ import ( "github.com/metacubex/mihomo/component/profile/cachefile" "github.com/metacubex/mihomo/component/trie" + C "github.com/metacubex/mihomo/constant" + RP "github.com/metacubex/mihomo/rules/provider" "github.com/sagernet/bbolt" "github.com/stretchr/testify/assert" @@ -154,7 +156,7 @@ func TestPool_Skip(t *testing.T) { pools, tempfile, err := createPools(Options{ IPNet: ipnet, Size: 10, - Host: tree, + Host: []C.Rule{RP.NewDomainSet(tree.NewDomainSet(), "")}, }) assert.Nil(t, err) defer os.Remove(tempfile) diff --git a/clash-meta/component/sniffer/dispatcher.go b/clash-meta/component/sniffer/dispatcher.go index 4438638dad..c96f5a4b03 100644 --- a/clash-meta/component/sniffer/dispatcher.go +++ b/clash-meta/component/sniffer/dispatcher.go @@ -9,7 +9,6 @@ import ( "github.com/metacubex/mihomo/common/lru" N "github.com/metacubex/mihomo/common/net" - "github.com/metacubex/mihomo/component/trie" C "github.com/metacubex/mihomo/constant" "github.com/metacubex/mihomo/constant/sniffer" "github.com/metacubex/mihomo/log" @@ -26,17 +25,26 @@ var Dispatcher *SnifferDispatcher type SnifferDispatcher struct { enable bool sniffers map[sniffer.Sniffer]SnifferConfig - forceDomain *trie.DomainSet - skipSNI *trie.DomainSet + forceDomain []C.Rule + skipDomain []C.Rule skipList *lru.LruCache[string, uint8] forceDnsMapping bool parsePureIp bool } func (sd *SnifferDispatcher) shouldOverride(metadata *C.Metadata) bool { - return (metadata.Host == "" && sd.parsePureIp) || - sd.forceDomain.Has(metadata.Host) || - (metadata.DNSMode == C.DNSMapping && sd.forceDnsMapping) + if metadata.Host == "" && sd.parsePureIp { + return true + } + if metadata.DNSMode == C.DNSMapping && sd.forceDnsMapping { + return true + } + for _, rule := range sd.forceDomain { + if ok, _ := rule.Match(&C.Metadata{Host: metadata.Host}); ok { + return true + } + } + return false } func (sd *SnifferDispatcher) UDPSniff(packet C.PacketAdapter) bool { @@ -94,9 +102,11 @@ func (sd *SnifferDispatcher) TCPSniff(conn *N.BufferedConn, metadata *C.Metadata log.Debugln("[Sniffer] All sniffing sniff failed with from [%s:%d] to [%s:%d]", metadata.SrcIP, metadata.SrcPort, metadata.String(), metadata.DstPort) return false } else { - if sd.skipSNI.Has(host) { - log.Debugln("[Sniffer] Skip sni[%s]", host) - return false + for _, rule := range sd.skipDomain { + if ok, _ := rule.Match(&C.Metadata{Host: host}); ok { + log.Debugln("[Sniffer] Skip sni[%s]", host) + return false + } } sd.skipList.Delete(dst) @@ -187,12 +197,12 @@ func NewCloseSnifferDispatcher() (*SnifferDispatcher, error) { } func NewSnifferDispatcher(snifferConfig map[sniffer.Type]SnifferConfig, - forceDomain *trie.DomainSet, skipSNI *trie.DomainSet, + forceDomain []C.Rule, skipDomain []C.Rule, forceDnsMapping bool, parsePureIp bool) (*SnifferDispatcher, error) { dispatcher := SnifferDispatcher{ enable: true, forceDomain: forceDomain, - skipSNI: skipSNI, + skipDomain: skipDomain, skipList: lru.New(lru.WithSize[string, uint8](128), lru.WithAge[string, uint8](600)), forceDnsMapping: forceDnsMapping, parsePureIp: parsePureIp, diff --git a/clash-meta/component/trie/domain.go b/clash-meta/component/trie/domain.go index db30402ede..6d3e37f70a 100644 --- a/clash-meta/component/trie/domain.go +++ b/clash-meta/component/trie/domain.go @@ -134,6 +134,13 @@ func (t *DomainTrie[T]) Foreach(fn func(domain string, data T) bool) { } } +func (t *DomainTrie[T]) IsEmpty() bool { + if t == nil { + return true + } + return t.root.isEmpty() +} + func recursion[T any](items []string, node *Node[T], fn func(domain string, data T) bool) bool { for key, data := range node.getChildren() { newItems := append([]string{key}, items...) diff --git a/clash-meta/config/config.go b/clash-meta/config/config.go index 5f2b68453d..74ffdd038c 100644 --- a/clash-meta/config/config.go +++ b/clash-meta/config/config.go @@ -38,6 +38,7 @@ import ( LC "github.com/metacubex/mihomo/listener/config" "github.com/metacubex/mihomo/log" R "github.com/metacubex/mihomo/rules" + RC "github.com/metacubex/mihomo/rules/common" RP "github.com/metacubex/mihomo/rules/provider" T "github.com/metacubex/mihomo/tunnel" @@ -163,8 +164,8 @@ type IPTables struct { type Sniffer struct { Enable bool Sniffers map[snifferTypes.Type]SNIFF.SnifferConfig - ForceDomain *trie.DomainSet - SkipDomain *trie.DomainSet + ForceDomain []C.Rule + SkipDomain []C.Rule ForceDnsMapping bool ParsePureIp bool } @@ -338,7 +339,9 @@ type RawConfig struct { FindProcessMode P.FindProcessMode `yaml:"find-process-mode" json:"find-process-mode"` GlobalClientFingerprint string `yaml:"global-client-fingerprint"` GlobalUA string `yaml:"global-ua"` + KeepAliveIdle int `yaml:"keep-alive-idle"` KeepAliveInterval int `yaml:"keep-alive-interval"` + DisableKeepAlive bool `yaml:"disable-keep-alive"` Sniffer RawSniffer `yaml:"sniffer" json:"sniffer"` ProxyProvider map[string]map[string]any `yaml:"proxy-providers"` @@ -624,7 +627,7 @@ func ParseRawConfig(rawCfg *RawConfig) (*Config, error) { } } - config.Sniffer, err = parseSniffer(rawCfg.Sniffer) + config.Sniffer, err = parseSniffer(rawCfg.Sniffer, rules, ruleProviders) if err != nil { return nil, err } @@ -649,9 +652,14 @@ func parseGeneral(cfg *RawConfig) (*General, error) { C.ASNUrl = cfg.GeoXUrl.ASN C.GeodataMode = cfg.GeodataMode C.UA = cfg.GlobalUA + + if cfg.KeepAliveIdle != 0 { + N.KeepAliveIdle = time.Duration(cfg.KeepAliveIdle) * time.Second + } if cfg.KeepAliveInterval != 0 { N.KeepAliveInterval = time.Duration(cfg.KeepAliveInterval) * time.Second } + N.DisableKeepAlive = cfg.DisableKeepAlive updater.ExternalUIPath = cfg.ExternalUI // checkout externalUI exist @@ -1400,27 +1408,21 @@ func parseDNS(rawCfg *RawConfig, hosts *trie.DomainTrie[resolver.HostValue], rul return nil, err } - var host *trie.DomainTrie[struct{}] - // fake ip skip host filter - if len(cfg.FakeIPFilter) != 0 { - host = trie.New[struct{}]() - for _, domain := range cfg.FakeIPFilter { - _ = host.Insert(domain, struct{}{}) - } - host.Optimize() - } - + var fakeIPTrie *trie.DomainTrie[struct{}] if len(dnsCfg.Fallback) != 0 { - if host == nil { - host = trie.New[struct{}]() - } + fakeIPTrie = trie.New[struct{}]() for _, fb := range dnsCfg.Fallback { if net.ParseIP(fb.Addr) != nil { continue } - _ = host.Insert(fb.Addr, struct{}{}) + _ = fakeIPTrie.Insert(fb.Addr, struct{}{}) } - host.Optimize() + } + + // fake ip skip host filter + host, err := parseDomain(cfg.FakeIPFilter, fakeIPTrie, rules, ruleProviders) + if err != nil { + return nil, err } pool, err := fakeip.New(fakeip.Options{ @@ -1547,7 +1549,7 @@ func parseTuicServer(rawTuic RawTuicServer, general *General) error { return nil } -func parseSniffer(snifferRaw RawSniffer) (*Sniffer, error) { +func parseSniffer(snifferRaw RawSniffer, rules []C.Rule, ruleProviders map[string]providerTypes.RuleProvider) (*Sniffer, error) { sniffer := &Sniffer{ Enable: snifferRaw.Enable, ForceDnsMapping: snifferRaw.ForceDnsMapping, @@ -1610,23 +1612,83 @@ func parseSniffer(snifferRaw RawSniffer) (*Sniffer, error) { sniffer.Sniffers = loadSniffer - forceDomainTrie := trie.New[struct{}]() - for _, domain := range snifferRaw.ForceDomain { - err := forceDomainTrie.Insert(domain, struct{}{}) - if err != nil { - return nil, fmt.Errorf("error domian[%s] in force-domain, error:%v", domain, err) - } + forceDomain, err := parseDomain(snifferRaw.ForceDomain, nil, rules, ruleProviders) + if err != nil { + return nil, fmt.Errorf("error in force-domain, error:%w", err) } - sniffer.ForceDomain = forceDomainTrie.NewDomainSet() + sniffer.ForceDomain = forceDomain - skipDomainTrie := trie.New[struct{}]() - for _, domain := range snifferRaw.SkipDomain { - err := skipDomainTrie.Insert(domain, struct{}{}) - if err != nil { - return nil, fmt.Errorf("error domian[%s] in force-domain, error:%v", domain, err) - } + skipDomain, err := parseDomain(snifferRaw.SkipDomain, nil, rules, ruleProviders) + if err != nil { + return nil, fmt.Errorf("error in skip-domain, error:%w", err) } - sniffer.SkipDomain = skipDomainTrie.NewDomainSet() + sniffer.SkipDomain = skipDomain return sniffer, nil } + +func parseDomain(domains []string, domainTrie *trie.DomainTrie[struct{}], rules []C.Rule, ruleProviders map[string]providerTypes.RuleProvider) (domainRules []C.Rule, err error) { + var rule C.Rule + for _, domain := range domains { + domainLower := strings.ToLower(domain) + if strings.Contains(domainLower, "geosite:") { + subkeys := strings.Split(domain, ":") + subkeys = subkeys[1:] + subkeys = strings.Split(subkeys[0], ",") + for _, country := range subkeys { + found := false + for _, rule = range rules { + if rule.RuleType() == C.GEOSITE { + if strings.EqualFold(country, rule.Payload()) { + found = true + domainRules = append(domainRules, rule) + } + } + } + if !found { + rule, err = RC.NewGEOSITE(country, "") + if err != nil { + return nil, err + } + domainRules = append(domainRules, rule) + } + } + } else if strings.Contains(domainLower, "rule-set:") { + subkeys := strings.Split(domain, ":") + subkeys = subkeys[1:] + subkeys = strings.Split(subkeys[0], ",") + for _, domainSetName := range subkeys { + if rp, ok := ruleProviders[domainSetName]; !ok { + return nil, fmt.Errorf("not found rule-set: %s", domainSetName) + } else { + switch rp.Behavior() { + case providerTypes.IPCIDR: + return nil, fmt.Errorf("rule provider type error, except domain,actual %s", rp.Behavior()) + case providerTypes.Classical: + log.Warnln("%s provider is %s, only matching it contain domain rule", rp.Name(), rp.Behavior()) + default: + } + } + rule, err = RP.NewRuleSet(domainSetName, "", true) + if err != nil { + return nil, err + } + + domainRules = append(domainRules, rule) + } + } else { + if domainTrie == nil { + domainTrie = trie.New[struct{}]() + } + err = domainTrie.Insert(domain, struct{}{}) + if err != nil { + return nil, err + } + } + } + if !domainTrie.IsEmpty() { + rule = RP.NewDomainSet(domainTrie.NewDomainSet(), "") + domainRules = append(domainRules, rule) + } + return +} diff --git a/clash-meta/constant/rule.go b/clash-meta/constant/rule.go index a91ee6cb07..f9f987e672 100644 --- a/clash-meta/constant/rule.go +++ b/clash-meta/constant/rule.go @@ -27,6 +27,7 @@ const ( ProcessNameRegex ProcessPathRegex RuleSet + DomainSet Network Uid SubRules @@ -90,6 +91,8 @@ func (rt RuleType) String() string { return "Match" case RuleSet: return "RuleSet" + case DomainSet: + return "DomainSet" case Network: return "Network" case DSCP: diff --git a/clash-meta/docs/config.yaml b/clash-meta/docs/config.yaml index d7c686d01f..8db06b6d7d 100644 --- a/clash-meta/docs/config.yaml +++ b/clash-meta/docs/config.yaml @@ -82,7 +82,9 @@ external-doh-server: /dns-query global-client-fingerprint: chrome # TCP keep alive interval -keep-alive-interval: 15 +# disable-keep-alive: false #目前在android端强制为true +# keep-alive-idle: 15 +# keep-alive-interval: 15 # routing-mark:6666 # 配置 fwmark 仅用于 Linux experimental: @@ -241,6 +243,16 @@ dns: fake-ip-range: 198.18.0.1/16 # fake-ip 池设置 + # 配置不使用 fake-ip 的域名 + fake-ip-filter: + - '*.lan' + - localhost.ptlogin2.qq.com + # fakeip-filter 为 rule-providers 中的名为 fakeip-filter 规则订阅, + # 且 behavior 必须为 domain/classical,当为 classical 时仅会生效域名类规则 + - rule-set:fakeip-filter + # fakeip-filter 为 geosite 中名为 fakeip-filter 的分类(需要自行保证该分类存在) + - geosite:fakeip-filter + # use-hosts: true # 查询 hosts # 配置后面的nameserver、fallback和nameserver-policy向dns服务器的连接过程是否遵守遵守rules规则 @@ -250,11 +262,6 @@ dns: # 此外,这三者配置中的dns服务器如果出现域名会采用default-nameserver配置项解析,也请确保正确配置default-nameserver respect-rules: false - # 配置不使用 fake-ip 的域名 - # fake-ip-filter: - # - '*.lan' - # - localhost.ptlogin2.qq.com - # DNS 主要域名配置 # 支持 UDP,TCP,DoT,DoH,DoQ # 这部分为主要 DNS 配置,影响所有直连,确保使用对大陆解析精准的 DNS diff --git a/clash-meta/listener/http/server.go b/clash-meta/listener/http/server.go index 77e10f0841..f61dd03609 100644 --- a/clash-meta/listener/http/server.go +++ b/clash-meta/listener/http/server.go @@ -4,9 +4,9 @@ import ( "net" "github.com/metacubex/mihomo/adapter/inbound" + N "github.com/metacubex/mihomo/common/net" "github.com/metacubex/mihomo/component/auth" C "github.com/metacubex/mihomo/constant" - "github.com/metacubex/mihomo/constant/features" authStore "github.com/metacubex/mihomo/listener/auth" ) @@ -74,11 +74,7 @@ func NewWithAuthenticator(addr string, tunnel C.Tunnel, authenticator auth.Authe } continue } - if features.CMFA { - if t, ok := conn.(*net.TCPConn); ok { - t.SetKeepAlive(false) - } - } + N.TCPKeepAlive(conn) if isDefault { // only apply on default listener if !inbound.IsRemoteAddrDisAllowed(conn.RemoteAddr()) { _ = conn.Close() diff --git a/clash-meta/rules/provider/domain_set.go b/clash-meta/rules/provider/domain_set.go new file mode 100644 index 0000000000..372b438ea8 --- /dev/null +++ b/clash-meta/rules/provider/domain_set.go @@ -0,0 +1,43 @@ +package provider + +import ( + "github.com/metacubex/mihomo/component/trie" + C "github.com/metacubex/mihomo/constant" +) + +type DomainSet struct { + *domainStrategy + adapter string +} + +func (d *DomainSet) ProviderNames() []string { + return nil +} + +func (d *DomainSet) RuleType() C.RuleType { + return C.DomainSet +} + +func (d *DomainSet) Match(metadata *C.Metadata) (bool, string) { + if d.domainSet == nil { + return false, "" + } + return d.domainSet.Has(metadata.RuleHost()), d.adapter +} + +func (d *DomainSet) Adapter() string { + return d.adapter +} + +func (d *DomainSet) Payload() string { + return "" +} + +func NewDomainSet(domainSet *trie.DomainSet, adapter string) *DomainSet { + return &DomainSet{ + domainStrategy: &domainStrategy{domainSet: domainSet}, + adapter: adapter, + } +} + +var _ C.Rule = (*DomainSet)(nil) diff --git a/clash-nyanpasu/backend/Cargo.lock b/clash-nyanpasu/backend/Cargo.lock index ca703b8f7b..09d5278234 100644 --- a/clash-nyanpasu/backend/Cargo.lock +++ b/clash-nyanpasu/backend/Cargo.lock @@ -774,7 +774,7 @@ dependencies = [ "bitflags 2.6.0", "boa_interner", "boa_macros", - "indexmap 2.3.0", + "indexmap 2.4.0", "num-bigint", "rustc-hash 2.0.0", ] @@ -800,7 +800,7 @@ dependencies = [ "fast-float", "hashbrown 0.14.5", "icu_normalizer", - "indexmap 2.3.0", + "indexmap 2.4.0", "intrusive-collections", "itertools 0.13.0", "num-bigint", @@ -846,7 +846,7 @@ dependencies = [ "boa_gc", "boa_macros", "hashbrown 0.14.5", - "indexmap 2.3.0", + "indexmap 2.4.0", "once_cell", "phf 0.11.2", "rustc-hash 2.0.0", @@ -1265,7 +1265,7 @@ dependencies = [ "hex", "humansize", "image 0.25.2", - "indexmap 2.3.0", + "indexmap 2.4.0", "log 0.4.22", "md-5", "mime", @@ -1667,12 +1667,12 @@ dependencies = [ [[package]] name = "ctrlc" -version = "3.4.4" +version = "3.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "672465ae37dc1bc6380a6547a8883d5dd397b0f1faaad4f265726cc7042a5345" +checksum = "90eeab0aa92f3f9b4e87f258c72b139c207d251f9cbc1080a0086b86a8870dd3" dependencies = [ - "nix 0.28.0", - "windows-sys 0.52.0", + "nix 0.29.0", + "windows-sys 0.59.0", ] [[package]] @@ -2911,7 +2911,7 @@ dependencies = [ "futures-sink", "futures-util", "http 0.2.12", - "indexmap 2.3.0", + "indexmap 2.4.0", "slab", "tokio", "tokio-util", @@ -2930,7 +2930,7 @@ dependencies = [ "futures-core", "futures-sink", "http 1.1.0", - "indexmap 2.3.0", + "indexmap 2.4.0", "slab", "tokio", "tokio-util", @@ -3481,9 +3481,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.3.0" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de3fc2e30ba82dd1b3911c8de1ffc143c74a914a14e99514d7637e3099df5ea0" +checksum = "93ead53efc7ea8ed3cfb0c79fc8023fbb782a5432b52830b6518941cebe6505c" dependencies = [ "equivalent", "hashbrown 0.14.5", @@ -5252,7 +5252,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4c5cc86750666a3ed20bdaf5ca2a0344f9c67674cae0515bec2da16fbaa47db" dependencies = [ "fixedbitset", - "indexmap 2.3.0", + "indexmap 2.4.0", ] [[package]] @@ -5455,7 +5455,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42cf17e9a1800f5f396bc67d193dc9411b59012a5876445ef450d449881e1016" dependencies = [ "base64 0.22.1", - "indexmap 2.3.0", + "indexmap 2.4.0", "quick-xml 0.32.0", "serde", "time", @@ -6450,7 +6450,7 @@ version = "1.0.124" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "66ad62847a56b3dba58cc891acd13884b9c61138d330c0d7b6181713d4fce38d" dependencies = [ - "indexmap 2.3.0", + "indexmap 2.4.0", "itoa 1.0.11", "memchr", "ryu", @@ -6509,7 +6509,7 @@ dependencies = [ "chrono", "hex", "indexmap 1.9.3", - "indexmap 2.3.0", + "indexmap 2.4.0", "serde", "serde_derive", "serde_json", @@ -6535,7 +6535,7 @@ version = "0.9.34+deprecated" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47" dependencies = [ - "indexmap 2.3.0", + "indexmap 2.4.0", "itoa 1.0.11", "ryu", "serde", @@ -6548,7 +6548,7 @@ version = "0.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "48e76bab63c3fd98d27c17f9cbce177f64a91f5e69ac04cafe04e1bb25d1dc3c" dependencies = [ - "indexmap 2.3.0", + "indexmap 2.4.0", "itoa 1.0.11", "libyml", "log 0.4.22", @@ -7790,7 +7790,7 @@ version = "0.19.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" dependencies = [ - "indexmap 2.3.0", + "indexmap 2.4.0", "serde", "serde_spanned", "toml_datetime", @@ -7803,7 +7803,7 @@ version = "0.21.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a8534fd7f78b5405e860340ad6575217ce99f38d4d5c8f2442cb5ecb50090e1" dependencies = [ - "indexmap 2.3.0", + "indexmap 2.4.0", "toml_datetime", "winnow 0.5.40", ] @@ -7814,7 +7814,7 @@ version = "0.22.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "583c44c02ad26b0c3f3066fe629275e50627026c51ac2e595cca4c230ce1ce1d" dependencies = [ - "indexmap 2.3.0", + "indexmap 2.4.0", "serde", "serde_spanned", "toml_datetime", @@ -9643,7 +9643,7 @@ dependencies = [ "displaydoc", "flate2", "hmac", - "indexmap 2.3.0", + "indexmap 2.4.0", "lzma-rs", "memchr", "pbkdf2", diff --git a/clash-nyanpasu/frontend/nyanpasu/package.json b/clash-nyanpasu/frontend/nyanpasu/package.json index 54e63fafe2..08cade995e 100644 --- a/clash-nyanpasu/frontend/nyanpasu/package.json +++ b/clash-nyanpasu/frontend/nyanpasu/package.json @@ -24,7 +24,6 @@ "@tauri-apps/api": "1.6.0", "ahooks": "3.8.1", "allotment": "1.20.2", - "axios": "1.7.3", "country-code-emoji": "2.3.0", "dayjs": "1.11.12", "framer-motion": "12.0.0-alpha.0", @@ -48,7 +47,7 @@ "devDependencies": { "@emotion/babel-plugin": "11.12.0", "@emotion/react": "11.13.0", - "@iconify/json": "2.2.236", + "@iconify/json": "2.2.237", "@types/react": "18.3.3", "@types/react-dom": "18.3.0", "@vitejs/plugin-react": "4.3.1", diff --git a/clash-nyanpasu/manifest/version.json b/clash-nyanpasu/manifest/version.json index f5c6e063a8..c2378752f9 100644 --- a/clash-nyanpasu/manifest/version.json +++ b/clash-nyanpasu/manifest/version.json @@ -2,7 +2,7 @@ "manifest_version": 1, "latest": { "mihomo": "v1.18.7", - "mihomo_alpha": "alpha-c17d7c0", + "mihomo_alpha": "alpha-50d0cd3", "clash_rs": "v0.2.0", "clash_premium": "2023-09-05-gdcc8d87" }, @@ -36,5 +36,5 @@ "darwin-x64": "clash-darwin-amd64-n{}.gz" } }, - "updated_at": "2024-08-12T22:20:24.265Z" + "updated_at": "2024-08-13T22:20:21.347Z" } diff --git a/clash-nyanpasu/package.json b/clash-nyanpasu/package.json index e19b0694b4..14fe205f95 100644 --- a/clash-nyanpasu/package.json +++ b/clash-nyanpasu/package.json @@ -94,7 +94,7 @@ "stylelint-declaration-block-no-ignored-properties": "2.8.0", "stylelint-order": "6.0.4", "stylelint-scss": "6.5.0", - "tailwindcss": "3.4.9", + "tailwindcss": "3.4.10", "tsx": "4.17.0", "typescript": "5.5.4" }, diff --git a/clash-nyanpasu/pnpm-lock.yaml b/clash-nyanpasu/pnpm-lock.yaml index be1e61d29a..b241133d17 100644 --- a/clash-nyanpasu/pnpm-lock.yaml +++ b/clash-nyanpasu/pnpm-lock.yaml @@ -152,8 +152,8 @@ importers: specifier: 6.5.0 version: 6.5.0(stylelint@16.8.1(typescript@5.5.4)) tailwindcss: - specifier: 3.4.9 - version: 3.4.9 + specifier: 3.4.10 + version: 3.4.10 tsx: specifier: 4.17.0 version: 4.17.0 @@ -230,9 +230,6 @@ importers: allotment: specifier: 1.20.2 version: 1.20.2(react-dom@19.0.0-rc-e948a5ac-20240807(react@19.0.0-rc-e948a5ac-20240807))(react@19.0.0-rc-e948a5ac-20240807) - axios: - specifier: 1.7.3 - version: 1.7.3 country-code-emoji: specifier: 2.3.0 version: 2.3.0 @@ -298,8 +295,8 @@ importers: specifier: 11.13.0 version: 11.13.0(react@19.0.0-rc-e948a5ac-20240807)(types-react@19.0.0-rc.1) '@iconify/json': - specifier: 2.2.236 - version: 2.2.236 + specifier: 2.2.237 + version: 2.2.237 '@types/react': specifier: npm:types-react@rc version: types-react@19.0.0-rc.1 @@ -1359,8 +1356,8 @@ packages: '@vue/compiler-sfc': optional: true - '@iconify/json@2.2.236': - resolution: {integrity: sha512-eiIOW9RfIMlrJl77+VfM4FM+bF46zQNxanNe8MADgXxNCeFR8LW70bC2u6El5Cqf/gx/n0EmqA5kXQ8J+BHjsg==} + '@iconify/json@2.2.237': + resolution: {integrity: sha512-lMK5I9JX90L2LR18Lz6C5XrivxxAGejdJvFQI7TQkj03WcaxRJlciPbQb6z4nX+DS1T6k591ZQ2/hyRVbjqrgA==} '@iconify/types@2.0.0': resolution: {integrity: sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg==} @@ -2677,9 +2674,6 @@ packages: async-mutex@0.3.2: resolution: {integrity: sha512-HuTK7E7MT7jZEh1P9GtRW9+aTWiDWWi9InbZ5hjxrnRa39KS4BW04+xLBhYNS2aXhHUIKZSw3gj4Pn1pj+qGAA==} - asynckit@0.4.0: - resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} - autoprefixer@10.4.20: resolution: {integrity: sha512-XY25y5xSv/wEoqzDyXXME4AFfkZI0P23z6Fs3YgymDnKJkCGOnkL0iTxCa85UTqaSgfcqyf3UA6+c7wUvx/16g==} engines: {node: ^10 || ^12 || >=14} @@ -2695,9 +2689,6 @@ packages: resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==} engines: {node: '>= 0.4'} - axios@1.7.3: - resolution: {integrity: sha512-Ar7ND9pU99eJ9GpoGQKhKf58GpUOgnzuaB7ueNQ5BMi0p+LZ5oaEnfF999fAArcTIBwXTCHAmGcHOZJaWPq9Nw==} - babel-plugin-macros@3.1.0: resolution: {integrity: sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==} engines: {node: '>=10', npm: '>=6'} @@ -2927,10 +2918,6 @@ packages: colorize-template@1.0.0: resolution: {integrity: sha512-beJ9v9RjpbYZ8OdwJgIRZD3YUkZPXmi1MK+yX0J24UupKVHa9yk0jiARgt2i6MBX6AKjYA0SNsBn65bUPuVQiw==} - combined-stream@1.0.8: - resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} - engines: {node: '>= 0.8'} - comma-separated-tokens@2.0.3: resolution: {integrity: sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==} @@ -3303,10 +3290,6 @@ packages: delaunator@5.0.1: resolution: {integrity: sha512-8nvh+XBe96aCESrGOqMp/84b13H9cdKbG5P2ejQCh4d4sK9RL4371qou9drQjMhvnPmhWl5hnmqbEE0fXr9Xnw==} - delayed-stream@1.0.0: - resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} - engines: {node: '>=0.4.0'} - deprecation@2.3.1: resolution: {integrity: sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ==} @@ -3780,15 +3763,6 @@ packages: flatted@3.3.1: resolution: {integrity: sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==} - follow-redirects@1.15.6: - resolution: {integrity: sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==} - engines: {node: '>=4.0'} - peerDependencies: - debug: '*' - peerDependenciesMeta: - debug: - optional: true - for-each@0.3.3: resolution: {integrity: sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==} @@ -3796,10 +3770,6 @@ packages: resolution: {integrity: sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==} engines: {node: '>=14'} - form-data@4.0.0: - resolution: {integrity: sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==} - engines: {node: '>= 6'} - formdata-polyfill@4.0.10: resolution: {integrity: sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==} engines: {node: '>=12.20.0'} @@ -4755,14 +4725,6 @@ packages: resolution: {integrity: sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q==} engines: {node: '>=8.6'} - mime-db@1.52.0: - resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} - engines: {node: '>= 0.6'} - - mime-types@2.1.35: - resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} - engines: {node: '>= 0.6'} - mime@1.6.0: resolution: {integrity: sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==} engines: {node: '>=4'} @@ -5395,9 +5357,6 @@ packages: property-information@6.5.0: resolution: {integrity: sha512-PgTgs/BlvHxOu8QuEN7wi5A0OmXaBcHpmCSTehcs6Uuu9IkDIEo13Hy7n898RHfrQ49vKCoGeWZSaAK01nwVig==} - proxy-from-env@1.1.0: - resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==} - prr@1.0.1: resolution: {integrity: sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw==} @@ -6020,8 +5979,8 @@ packages: engines: {node: '>=8.9.0'} hasBin: true - tailwindcss@3.4.9: - resolution: {integrity: sha512-1SEOvRr6sSdV5IDf9iC+NU4dhwdqzF4zKKq3sAbasUWHEM6lsMhX+eNN5gkPx1BvLFEnZQEUFbXnGj8Qlp83Pg==} + tailwindcss@3.4.10: + resolution: {integrity: sha512-KWZkVPm7yJRhdu4SRSl9d4AK2wM3a50UsvgHZO7xY77NQr2V+fIrEuoDGQcbvswWvFGbS2f6e+jC/6WJm1Dl0w==} engines: {node: '>=14.0.0'} hasBin: true @@ -7408,7 +7367,7 @@ snapshots: transitivePeerDependencies: - supports-color - '@iconify/json@2.2.236': + '@iconify/json@2.2.237': dependencies: '@iconify/types': 2.0.0 pathe: 1.1.2 @@ -8760,8 +8719,6 @@ snapshots: dependencies: tslib: 2.6.2 - asynckit@0.4.0: {} - autoprefixer@10.4.20(postcss@8.4.41): dependencies: browserslist: 4.23.3 @@ -8786,14 +8743,6 @@ snapshots: dependencies: possible-typed-array-names: 1.0.0 - axios@1.7.3: - dependencies: - follow-redirects: 1.15.6 - form-data: 4.0.0 - proxy-from-env: 1.1.0 - transitivePeerDependencies: - - debug - babel-plugin-macros@3.1.0: dependencies: '@babel/runtime': 7.24.8 @@ -9016,10 +8965,6 @@ snapshots: colorize-template@1.0.0: {} - combined-stream@1.0.8: - dependencies: - delayed-stream: 1.0.0 - comma-separated-tokens@2.0.3: {} commander@12.1.0: {} @@ -9391,8 +9336,6 @@ snapshots: dependencies: robust-predicates: 3.0.2 - delayed-stream@1.0.0: {} - deprecation@2.3.1: {} dequal@2.0.3: {} @@ -10089,8 +10032,6 @@ snapshots: flatted@3.3.1: {} - follow-redirects@1.15.6: {} - for-each@0.3.3: dependencies: is-callable: 1.2.7 @@ -10100,12 +10041,6 @@ snapshots: cross-spawn: 7.0.3 signal-exit: 4.1.0 - form-data@4.0.0: - dependencies: - asynckit: 0.4.0 - combined-stream: 1.0.8 - mime-types: 2.1.35 - formdata-polyfill@4.0.10: dependencies: fetch-blob: 3.2.0 @@ -11179,12 +11114,6 @@ snapshots: braces: 3.0.3 picomatch: 2.3.1 - mime-db@1.52.0: {} - - mime-types@2.1.35: - dependencies: - mime-db: 1.52.0 - mime@1.6.0: optional: true @@ -11723,8 +11652,6 @@ snapshots: property-information@6.5.0: {} - proxy-from-env@1.1.0: {} - prr@1.0.1: optional: true @@ -12465,7 +12392,7 @@ snapshots: reduce-css-calc: 2.1.8 resolve: 1.22.8 - tailwindcss@3.4.9: + tailwindcss@3.4.10: dependencies: '@alloc/quick-lru': 5.2.0 arg: 5.0.2 diff --git a/glider/Dockerfile b/glider/Dockerfile index 73794eacbc..953f5d2409 100644 --- a/glider/Dockerfile +++ b/glider/Dockerfile @@ -1,5 +1,5 @@ # Build Stage -FROM golang:1.20-alpine AS build-env +FROM golang:1.23-alpine AS build-env ADD . /src RUN apk --no-cache add git \ && cd /src && go build -v -ldflags "-s -w" diff --git a/glider/go.mod b/glider/go.mod index de899b82e3..47bf0e60b5 100644 --- a/glider/go.mod +++ b/glider/go.mod @@ -1,36 +1,29 @@ module github.com/nadoo/glider -go 1.20 +go 1.23 require ( github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da github.com/dgryski/go-camellia v0.0.0-20191119043421-69a8a13fb23d github.com/dgryski/go-idea v0.0.0-20170306091226-d2fb45a411fb github.com/dgryski/go-rc2 v0.0.0-20150621095337-8a9021637152 - github.com/insomniacslk/dhcp v0.0.0-20240710054256-ddd8a41251c9 + github.com/insomniacslk/dhcp v0.0.0-20240812123929-b105c29bd1b5 github.com/nadoo/conflag v0.3.1 github.com/nadoo/ipset v0.5.0 github.com/xtaci/kcp-go/v5 v5.6.12 - golang.org/x/crypto v0.25.0 - golang.org/x/sys v0.23.0 + golang.org/x/crypto v0.26.0 + golang.org/x/sys v0.24.0 ) require ( github.com/ebfe/rc2 v0.0.0-20131011165748-24b9757f5521 // indirect - github.com/josharian/native v1.1.0 // indirect github.com/klauspost/cpuid/v2 v2.2.8 // indirect github.com/klauspost/reedsolomon v1.12.3 // indirect github.com/pierrec/lz4/v4 v4.1.21 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/templexxx/cpu v0.1.1 // indirect - github.com/templexxx/xorsimd v0.4.2 // indirect + github.com/templexxx/xorsimd v0.4.3 // indirect github.com/tjfoc/gmsm v1.4.1 // indirect github.com/u-root/uio v0.0.0-20240224005618-d2acac8f3701 // indirect - golang.org/x/net v0.27.0 // indirect -) - -replace ( - // Go1.20 - github.com/u-root/uio => github.com/u-root/uio v0.0.0-20240207222400-ab2ff1dfd969 - github.com/xtaci/kcp-go/v5 => github.com/xtaci/kcp-go/v5 v5.6.1 + golang.org/x/net v0.28.0 // indirect ) diff --git a/glider/go.sum b/glider/go.sum index c0546fa5f1..ab4f0898dd 100644 --- a/glider/go.sum +++ b/glider/go.sum @@ -33,26 +33,22 @@ github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5a github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/insomniacslk/dhcp v0.0.0-20240710054256-ddd8a41251c9 h1:LZJWucZz7ztCqY6Jsu7N9g124iJ2kt/O62j3+UchZFg= -github.com/insomniacslk/dhcp v0.0.0-20240710054256-ddd8a41251c9/go.mod h1:KclMyHxX06VrVr0DJmeFSUb1ankt7xTfoOA35pCkoic= -github.com/josharian/native v1.0.1-0.20221213033349-c1e37c09b531/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w= +github.com/insomniacslk/dhcp v0.0.0-20240812123929-b105c29bd1b5 h1:GkMacU5ftc+IEg1449N3UEy2XLDz58W4fkrRu2fibb8= +github.com/insomniacslk/dhcp v0.0.0-20240812123929-b105c29bd1b5/go.mod h1:KclMyHxX06VrVr0DJmeFSUb1ankt7xTfoOA35pCkoic= github.com/josharian/native v1.1.0 h1:uuaP0hAbW7Y4l0ZRQ6C9zfb7Mg1mbFKry/xzDAfmtLA= github.com/josharian/native v1.1.0/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w= -github.com/klauspost/cpuid v1.2.4/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= -github.com/klauspost/cpuid v1.3.1/go.mod h1:bYW4mA6ZgKPob1/Dlai2LviZJO7KGI3uoWLd42rAQw4= github.com/klauspost/cpuid/v2 v2.2.8 h1:+StwCXwm9PdpiEkPyzBXIy+M9KUb4ODm0Zarf1kS5BM= github.com/klauspost/cpuid/v2 v2.2.8/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= -github.com/klauspost/reedsolomon v1.9.9/go.mod h1:O7yFFHiQwDR6b2t63KPUpccPtNdp5ADgh1gg4fd12wo= github.com/klauspost/reedsolomon v1.12.3 h1:tzUznbfc3OFwJaTebv/QdhnFf2Xvb7gZ24XaHLBPmdc= github.com/klauspost/reedsolomon v1.12.3/go.mod h1:3K5rXwABAvzGeR01r6pWZieUALXO/Tq7bFKGIb4m4WI= github.com/mdlayher/packet v1.1.2 h1:3Up1NG6LZrsgDVn6X4L9Ge/iyRyxFEFD9o6Pr3Q1nQY= +github.com/mdlayher/packet v1.1.2/go.mod h1:GEu1+n9sG5VtiRE4SydOmX5GTwyyYlteZiFU+x0kew4= github.com/mdlayher/socket v0.4.1 h1:eM9y2/jlbs1M615oshPQOHZzj6R6wMT7bX5NPiQvn2U= -github.com/mmcloughlin/avo v0.0.0-20200803215136-443f81d77104/go.mod h1:wqKykBG2QzQDJEzvRkcS8x6MiSJkF52hXZsXcjaB3ls= +github.com/mdlayher/socket v0.4.1/go.mod h1:cAqeGjoufqdxWkD7DkpyS+wcefOtmu5OQ8KuoJGIReA= github.com/nadoo/conflag v0.3.1 h1:4pHkLIz8PUsfg6ajNYRRSY3bt6m2LPsu6KOzn5uIXQw= github.com/nadoo/conflag v0.3.1/go.mod h1:dzFfDUpXdr2uS2oV+udpy5N2vfNOu/bFzjhX1WI52co= github.com/nadoo/ipset v0.5.0 h1:5GJUAuZ7ITQQQGne5J96AmFjRtI8Avlbk6CabzYWVUc= github.com/nadoo/ipset v0.5.0/go.mod h1:rYF5DQLRGGoQ8ZSWeK+6eX5amAuPqwFkWjhQlEITGJQ= -github.com/pierrec/lz4/v4 v4.1.14/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= github.com/pierrec/lz4/v4 v4.1.21 h1:yOVMLb6qSIDP67pl/5F7RepeKYu/VmTyEXvuMI5d9mQ= github.com/pierrec/lz4/v4 v4.1.21/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= @@ -60,73 +56,52 @@ github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/templexxx/cpu v0.0.1/go.mod h1:w7Tb+7qgcAlIyX4NhLuDKt78AHA5SzPmq0Wj6HiEnnk= -github.com/templexxx/cpu v0.0.7/go.mod h1:w7Tb+7qgcAlIyX4NhLuDKt78AHA5SzPmq0Wj6HiEnnk= -github.com/templexxx/cpu v0.1.0/go.mod h1:w7Tb+7qgcAlIyX4NhLuDKt78AHA5SzPmq0Wj6HiEnnk= github.com/templexxx/cpu v0.1.1 h1:isxHaxBXpYFWnk2DReuKkigaZyrjs2+9ypIdGP4h+HI= github.com/templexxx/cpu v0.1.1/go.mod h1:w7Tb+7qgcAlIyX4NhLuDKt78AHA5SzPmq0Wj6HiEnnk= -github.com/templexxx/xorsimd v0.4.1/go.mod h1:W+ffZz8jJMH2SXwuKu9WhygqBMbFnp14G2fqEr8qaNo= -github.com/templexxx/xorsimd v0.4.2 h1:ocZZ+Nvu65LGHmCLZ7OoCtg8Fx8jnHKK37SjvngUoVI= -github.com/templexxx/xorsimd v0.4.2/go.mod h1:HgwaPoDREdi6OnULpSfxhzaiiSUY4Fi3JPn1wpt28NI= -github.com/tjfoc/gmsm v1.3.2/go.mod h1:HaUcFuY0auTiaHB9MHFGCPx5IaLhTUd2atbCFBQXn9w= +github.com/templexxx/xorsimd v0.4.3 h1:9AQTFHd7Bhk3dIT7Al2XeBX5DWOvsUPZCuhyAtNbHjU= +github.com/templexxx/xorsimd v0.4.3/go.mod h1:oZQcD6RFDisW2Am58dSAGwwL6rHjbzrlu25VDqfWkQg= github.com/tjfoc/gmsm v1.4.1 h1:aMe1GlZb+0bLjn+cKTPEvvn9oUEBlJitaZiiBwsbgho= github.com/tjfoc/gmsm v1.4.1/go.mod h1:j4INPkHWMrhJb38G+J6W4Tw0AbuN8Thu3PbdVYhVcTE= -github.com/u-root/uio v0.0.0-20240207222400-ab2ff1dfd969 h1:4+l/zS5QI+CxIMvb02kWu7J4xMbg6nkebX64Y/X6fG8= -github.com/u-root/uio v0.0.0-20240207222400-ab2ff1dfd969/go.mod h1:eLL9Nub3yfAho7qB0MzZizFhTU2QkLeoVsWdHtDW264= -github.com/xtaci/kcp-go/v5 v5.6.1 h1:Pwn0aoeNSPF9dTS7IgiPXn0HEtaIlVb6y5UKWPsx8bI= -github.com/xtaci/kcp-go/v5 v5.6.1/go.mod h1:W3kVPyNYwZ06p79dNwFWQOVFrdcBpDBsdyvK8moQrYo= +github.com/u-root/uio v0.0.0-20240224005618-d2acac8f3701 h1:pyC9PaHYZFgEKFdlp3G8RaCKgVpHZnecvArXvPXcFkM= +github.com/u-root/uio v0.0.0-20240224005618-d2acac8f3701/go.mod h1:P3a5rG4X7tI17Nn3aOIAYr5HbIMukwXG0urG0WuL8OA= +github.com/xtaci/kcp-go/v5 v5.6.12 h1:49PY4MbRz5CmwNzdZpREgqdAbP4QVQvCmJwjl9gpOeY= +github.com/xtaci/kcp-go/v5 v5.6.12/go.mod h1:GSs9Z62r41kTb4CxKaRKr6ED+j7I0sUvj7Koql/RN6c= github.com/xtaci/lossyconn v0.0.0-20190602105132-8df528c0c9ae h1:J0GxkO96kL4WF+AIT3M4mfUVinOCPgf2uUWYFUzN0sM= github.com/xtaci/lossyconn v0.0.0-20190602105132-8df528c0c9ae/go.mod h1:gXtu8J62kEgmN++bm9BVICuT/e8yiLI2KFobd/TRFsE= -github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -golang.org/x/arch v0.0.0-20190909030613-46d78d1859ac/go.mod h1:flIaEI6LNU6xOCD5PaJvn9wGP0agmIOqjrtsKGRguv4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20191219195013-becbf705a915/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201012173705-84dcc777aaee/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.25.0 h1:ypSNr+bnYL2YhwoMt2zPxHFmbAN1KZs/njMG3hxUp30= -golang.org/x/crypto v0.25.0/go.mod h1:T+wALwcMOSE0kXgUAnPAHqTLW+XHgcELELW8VaDgm/M= +golang.org/x/crypto v0.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw= +golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.27.0 h1:5K3Njcw06/l2y9vpGCSdcxWOYHOUk3dVNGDXN+FvAys= -golang.org/x/net v0.27.0/go.mod h1:dDi0PyhWNoiUOrAS8uXv/vnScO4wnHQO4mj9fn/RytE= +golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE= +golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E= +golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200808120158-1030fc2bf1d9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20220622161953-175b2fd9d664/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.23.0 h1:YfKFowiIMvtgl1UERQoTPPToxltDeZfbj4H7dVUCwmM= -golang.org/x/sys v0.23.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/term v0.22.0 h1:BbsgPEJULsl2fV/AT3v15Mjva5yXKQDyKf+TbDz7QJk= +golang.org/x/sys v0.24.0 h1:Twjiwq9dn6R1fQcyiK+wQyHWfaz/BJB+YIpzU/Cv3Xg= +golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/term v0.23.0 h1:F6D4vR+EHoL9/sWAWgAR1H2DcHr4PareCbAaCo1RpuU= +golang.org/x/term v0.23.0/go.mod h1:DgV24QBUrK6jhZXl+20l6UWznPlwAHm1Q1mGHtydmSk= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -134,13 +109,7 @@ golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGm golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20200425043458-8463f397d07c/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200808161706-5bf02b21f123/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= @@ -155,9 +124,7 @@ google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQ google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0 h1:hjy8E9ON/egN1tAYqKb61G10WtihqetD4sz2H+8nIeA= +gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= diff --git a/glider/main.go b/glider/main.go index c4cc65b223..21862ae669 100644 --- a/glider/main.go +++ b/glider/main.go @@ -17,7 +17,7 @@ import ( ) var ( - version = "0.16.4" + version = "0.17.0" config = parseConfig() ) diff --git a/lede/package/firmware/armbian-firmware/Makefile b/lede/package/firmware/armbian-firmware/Makefile new file mode 100644 index 0000000000..186c18d06b --- /dev/null +++ b/lede/package/firmware/armbian-firmware/Makefile @@ -0,0 +1,134 @@ +include $(TOPDIR)/rules.mk + +PKG_NAME:=armbian-firmware +PKG_RELEASE:=1 + +PKG_SOURCE_PROTO:=git +PKG_SOURCE_DATE:=2024-06-26 +PKG_SOURCE_URL:=https://github.com/armbian/firmware.git +PKG_SOURCE_VERSION:=7f2e18ecac75d50acb843395ad07a0f2b9a12a50 +PKG_MIRROR_HASH:=9967883add1587fb178e3b1a9aecec8e03b67f3554af63b294b771f67b88c934 + +include $(INCLUDE_DIR)/package.mk + +RSTRIP:=: +STRIP:=: + +define Package/armbian-firmware-default + SECTION:=firmware + CATEGORY:=Firmware + URL:=https://github.com/armbian/firmware + TITLE:=$(1) + DEPENDS:=$(2) +endef + +define Build/Compile +endef + +Package/brcmfmac-firmware-4356-sdio = $(call Package/armbian-firmware-default,Broadcom BCM4356 FullMac SDIO firmware) +define Package/brcmfmac-firmware-4356-sdio/install + $(INSTALL_DIR) $(1)/lib/firmware/brcm + $(INSTALL_DATA) \ + $(PKG_BUILD_DIR)/brcm/BCM4356A2.hcd \ + $(1)/lib/firmware/brcm/ + $(INSTALL_DATA) \ + $(PKG_BUILD_DIR)/brcm/brcmfmac4356-sdio.bin \ + $(1)/lib/firmware/brcm/ + $(INSTALL_DATA) \ + $(PKG_BUILD_DIR)/brcm/brcmfmac4356-sdio.clm_blob \ + $(1)/lib/firmware/brcm/ +endef +$(eval $(call BuildPackage,brcmfmac-firmware-4356-sdio)) + +Package/brcmfmac-firmware-43456-sdio = $(call Package/armbian-firmware-default,Broadcom BCM43456 FullMac SDIO firmware) +define Package/brcmfmac-firmware-43456-sdio/install + $(INSTALL_DIR) $(1)/lib/firmware/brcm + $(INSTALL_DATA) \ + $(PKG_BUILD_DIR)/brcm/brcmfmac43456-sdio.bin \ + $(1)/lib/firmware/brcm/ + $(INSTALL_DATA) \ + $(PKG_BUILD_DIR)/brcm/brcmfmac43456-sdio.clm_blob \ + $(1)/lib/firmware/brcm/ +endef +$(eval $(call BuildPackage,brcmfmac-firmware-43456-sdio)) + +Package/brcmfmac-firmware-43752-pcie = $(call Package/armbian-firmware-default,Broadcom BCM43752 FullMac PCIe firmware) +define Package/brcmfmac-firmware-43752-pcie/install + $(INSTALL_DIR) $(1)/lib/firmware/brcm + $(INSTALL_DATA) \ + $(PKG_BUILD_DIR)/brcm/BCM4362A2.hcd \ + $(1)/lib/firmware/brcm/ + $(INSTALL_DATA) \ + $(PKG_BUILD_DIR)/brcm/brcmfmac43752-pcie.bin \ + $(1)/lib/firmware/brcm/ + $(INSTALL_DATA) \ + $(PKG_BUILD_DIR)/brcm/brcmfmac43752-pcie.clm_blob \ + $(1)/lib/firmware/brcm/ +endef +$(eval $(call BuildPackage,brcmfmac-firmware-43752-pcie)) + +Package/brcmfmac-firmware-43752-sdio = $(call Package/armbian-firmware-default,Broadcom BCM43752 FullMac SDIO firmware) +define Package/brcmfmac-firmware-43752-sdio/install + $(INSTALL_DIR) $(1)/lib/firmware/brcm + $(INSTALL_DATA) \ + $(PKG_BUILD_DIR)/brcm/BCM4362A2.hcd \ + $(1)/lib/firmware/brcm/ + $(INSTALL_DATA) \ + $(PKG_BUILD_DIR)/brcm/brcmfmac43752-sdio.bin \ + $(1)/lib/firmware/brcm/ + $(INSTALL_DATA) \ + $(PKG_BUILD_DIR)/brcm/brcmfmac43752-sdio.clm_blob \ + $(1)/lib/firmware/brcm/ +endef +$(eval $(call BuildPackage,brcmfmac-firmware-43752-sdio)) + +Package/brcmfmac-nvram-4356-sdio = $(call Package/armbian-firmware-default,Broadcom BCM4356 SDIO NVRAM firmware) +define Package/brcmfmac-nvram-4356-sdio/install + $(INSTALL_DIR) $(1)/lib/firmware/brcm + $(INSTALL_DATA) \ + $(PKG_BUILD_DIR)/brcm/brcmfmac4356-sdio.txt \ + $(1)/lib/firmware/brcm/ + $(LN) \ + brcmfmac4356-sdio.txt \ + $(1)/lib/firmware/brcm/brcmfmac4356-sdio.friendlyarm,nanopc-t4.txt +endef +$(eval $(call BuildPackage,brcmfmac-nvram-4356-sdio)) + +Package/brcmfmac-nvram-43456-sdio = $(call Package/armbian-firmware-default,Broadcom BCM43456 SDIO NVRAM firmware) +define Package/brcmfmac-nvram-43456-sdio/install + $(INSTALL_DIR) $(1)/lib/firmware/brcm + $(INSTALL_DATA) \ + $(PKG_BUILD_DIR)/brcm/brcmfmac43456-sdio.txt \ + $(1)/lib/firmware/brcm/ + $(LN) \ + brcmfmac43456-sdio.txt \ + $(1)/lib/firmware/brcm/brcmfmac43456-sdio.radxa,rockpi4a.txt +endef +$(eval $(call BuildPackage,brcmfmac-nvram-43456-sdio)) + +Package/brcmfmac-nvram-43752-pcie = $(call Package/armbian-firmware-default,Broadcom BCM43752 PCIe NVRAM firmware) +define Package/brcmfmac-nvram-43752-pcie/install + $(INSTALL_DIR) $(1)/lib/firmware/brcm + $(INSTALL_DATA) \ + $(PKG_BUILD_DIR)/brcm/brcmfmac43752-pcie.txt \ + $(1)/lib/firmware/brcm/ + $(LN) \ + brcmfmac43752-pcie.txt \ + $(1)/lib/firmware/brcm/brcmfmac43752-pcie.armsom,sige7.txt +endef +$(eval $(call BuildPackage,brcmfmac-nvram-43752-pcie)) + +Package/brcmfmac-nvram-43752-sdio = $(call Package/armbian-firmware-default,Broadcom BCM43752 SDIO NVRAM firmware) +define Package/brcmfmac-nvram-43752-sdio/install + $(INSTALL_DIR) $(1)/lib/firmware/brcm + $(INSTALL_DATA) \ + $(PKG_BUILD_DIR)/brcm/brcmfmac43752-sdio.txt \ + $(1)/lib/firmware/brcm/ + $(LN) \ + brcmfmac43752-sdio.txt \ + $(1)/lib/firmware/brcm/brcmfmac43752-sdio.armsom,sige1-v1.txt + $(LN) \ + brcmfmac43752-sdio.txt \ + $(1)/lib/firmware/brcm/brcmfmac43752-sdio.firefly,rk3568-roc-pc.txt +endef +$(eval $(call BuildPackage,brcmfmac-nvram-43752-sdio)) diff --git a/lede/target/linux/rockchip/image/rk35xx.mk b/lede/target/linux/rockchip/image/rk35xx.mk index 35016188e1..dfd568f204 100644 --- a/lede/target/linux/rockchip/image/rk35xx.mk +++ b/lede/target/linux/rockchip/image/rk35xx.mk @@ -35,6 +35,30 @@ $(call Device/rk3588) endef TARGET_DEVICES += armsom_sige7 +define Device/friendlyarm_nanopi-r6c +$(call Device/rk3588) + DEVICE_VENDOR := FriendlyARM + DEVICE_MODEL := NanoPi R6C + DEVICE_PACKAGES := kmod-r8125 kmod-nvme kmod-thermal +endef +TARGET_DEVICES += friendlyarm_nanopi-r6c + +define Device/friendlyarm_nanopi-r6s +$(call Device/rk3588) + DEVICE_VENDOR := FriendlyARM + DEVICE_MODEL := NanoPi R6S + DEVICE_PACKAGES := kmod-r8125 kmod-nvme kmod-thermal +endef +TARGET_DEVICES += friendlyarm_nanopi-r6s + +define Device/friendlyarm_nanopi-r6t +$(call Device/rk3588) + DEVICE_VENDOR := FriendlyARM + DEVICE_MODEL := NanoPC T6 + DEVICE_PACKAGES := kmod-r8125 kmod-nvme kmod-thermal +endef +TARGET_DEVICES += friendlyarm_nanopi-r6t + define Device/mangopi_m28k $(call Device/rk3528) DEVICE_VENDOR := MangoPi @@ -53,3 +77,12 @@ $(call Device/rk3528) DEVICE_PACKAGES := kmod-r8168 kmod-r8125 kmod-thermal endef TARGET_DEVICES += radxa_e20c + +define Device/radxa_rock-5c +$(call Device/rk3588) + DEVICE_VENDOR := Radxa + DEVICE_MODEL := ROCK 5C / 5C Lite + DEVICE_DTS := rk3588-rock-5c + DEVICE_PACKAGES := kmod-r8125 kmod-nvme kmod-thermal +endef +TARGET_DEVICES += radxa_rock-5c diff --git a/mihomo/.github/patch_go122/48042aa09c2f878c4faa576948b07fe625c4707a.diff b/mihomo/.github/patch_go122/48042aa09c2f878c4faa576948b07fe625c4707a.diff deleted file mode 100644 index 2c68233358..0000000000 --- a/mihomo/.github/patch_go122/48042aa09c2f878c4faa576948b07fe625c4707a.diff +++ /dev/null @@ -1,54 +0,0 @@ -diff --git a/src/syscall/exec_windows.go b/src/syscall/exec_windows.go -index 06e684c7116b4..b311a5c74684b 100644 ---- a/src/syscall/exec_windows.go -+++ b/src/syscall/exec_windows.go -@@ -319,17 +319,6 @@ func StartProcess(argv0 string, argv []string, attr *ProcAttr) (pid int, handle - } - } - -- var maj, min, build uint32 -- rtlGetNtVersionNumbers(&maj, &min, &build) -- isWin7 := maj < 6 || (maj == 6 && min <= 1) -- // NT kernel handles are divisible by 4, with the bottom 3 bits left as -- // a tag. The fully set tag correlates with the types of handles we're -- // concerned about here. Except, the kernel will interpret some -- // special handle values, like -1, -2, and so forth, so kernelbase.dll -- // checks to see that those bottom three bits are checked, but that top -- // bit is not checked. -- isLegacyWin7ConsoleHandle := func(handle Handle) bool { return isWin7 && handle&0x10000003 == 3 } -- - p, _ := GetCurrentProcess() - parentProcess := p - if sys.ParentProcess != 0 { -@@ -338,15 +327,7 @@ func StartProcess(argv0 string, argv []string, attr *ProcAttr) (pid int, handle - fd := make([]Handle, len(attr.Files)) - for i := range attr.Files { - if attr.Files[i] > 0 { -- destinationProcessHandle := parentProcess -- -- // On Windows 7, console handles aren't real handles, and can only be duplicated -- // into the current process, not a parent one, which amounts to the same thing. -- if parentProcess != p && isLegacyWin7ConsoleHandle(Handle(attr.Files[i])) { -- destinationProcessHandle = p -- } -- -- err := DuplicateHandle(p, Handle(attr.Files[i]), destinationProcessHandle, &fd[i], 0, true, DUPLICATE_SAME_ACCESS) -+ err := DuplicateHandle(p, Handle(attr.Files[i]), parentProcess, &fd[i], 0, true, DUPLICATE_SAME_ACCESS) - if err != nil { - return 0, 0, err - } -@@ -377,14 +358,6 @@ func StartProcess(argv0 string, argv []string, attr *ProcAttr) (pid int, handle - - fd = append(fd, sys.AdditionalInheritedHandles...) - -- // On Windows 7, console handles aren't real handles, so don't pass them -- // through to PROC_THREAD_ATTRIBUTE_HANDLE_LIST. -- for i := range fd { -- if isLegacyWin7ConsoleHandle(fd[i]) { -- fd[i] = 0 -- } -- } -- - // The presence of a NULL handle in the list is enough to cause PROC_THREAD_ATTRIBUTE_HANDLE_LIST - // to treat the entire list as empty, so remove NULL handles. - j := 0 \ No newline at end of file diff --git a/mihomo/.github/patch_go122/693def151adff1af707d82d28f55dba81ceb08e1.diff b/mihomo/.github/patch_go122/693def151adff1af707d82d28f55dba81ceb08e1.diff deleted file mode 100644 index ca41ec317e..0000000000 --- a/mihomo/.github/patch_go122/693def151adff1af707d82d28f55dba81ceb08e1.diff +++ /dev/null @@ -1,158 +0,0 @@ -diff --git a/src/crypto/rand/rand.go b/src/crypto/rand/rand.go -index 62738e2cb1a7d..d0dcc7cc71fc0 100644 ---- a/src/crypto/rand/rand.go -+++ b/src/crypto/rand/rand.go -@@ -15,7 +15,7 @@ import "io" - // available, /dev/urandom otherwise. - // On OpenBSD and macOS, Reader uses getentropy(2). - // On other Unix-like systems, Reader reads from /dev/urandom. --// On Windows systems, Reader uses the RtlGenRandom API. -+// On Windows systems, Reader uses the ProcessPrng API. - // On JS/Wasm, Reader uses the Web Crypto API. - // On WASIP1/Wasm, Reader uses random_get from wasi_snapshot_preview1. - var Reader io.Reader -diff --git a/src/crypto/rand/rand_windows.go b/src/crypto/rand/rand_windows.go -index 6c0655c72b692..7380f1f0f1e6e 100644 ---- a/src/crypto/rand/rand_windows.go -+++ b/src/crypto/rand/rand_windows.go -@@ -15,11 +15,8 @@ func init() { Reader = &rngReader{} } - - type rngReader struct{} - --func (r *rngReader) Read(b []byte) (n int, err error) { -- // RtlGenRandom only returns 1<<32-1 bytes at a time. We only read at -- // most 1<<31-1 bytes at a time so that this works the same on 32-bit -- // and 64-bit systems. -- if err := batched(windows.RtlGenRandom, 1<<31-1)(b); err != nil { -+func (r *rngReader) Read(b []byte) (int, error) { -+ if err := windows.ProcessPrng(b); err != nil { - return 0, err - } - return len(b), nil -diff --git a/src/internal/syscall/windows/syscall_windows.go b/src/internal/syscall/windows/syscall_windows.go -index ab4ad2ec64108..5854ca60b5cef 100644 ---- a/src/internal/syscall/windows/syscall_windows.go -+++ b/src/internal/syscall/windows/syscall_windows.go -@@ -373,7 +373,7 @@ func ErrorLoadingGetTempPath2() error { - //sys DestroyEnvironmentBlock(block *uint16) (err error) = userenv.DestroyEnvironmentBlock - //sys CreateEvent(eventAttrs *SecurityAttributes, manualReset uint32, initialState uint32, name *uint16) (handle syscall.Handle, err error) = kernel32.CreateEventW - --//sys RtlGenRandom(buf []byte) (err error) = advapi32.SystemFunction036 -+//sys ProcessPrng(buf []byte) (err error) = bcryptprimitives.ProcessPrng - - type FILE_ID_BOTH_DIR_INFO struct { - NextEntryOffset uint32 -diff --git a/src/internal/syscall/windows/zsyscall_windows.go b/src/internal/syscall/windows/zsyscall_windows.go -index e3f6d8d2a2208..5a587ad4f146c 100644 ---- a/src/internal/syscall/windows/zsyscall_windows.go -+++ b/src/internal/syscall/windows/zsyscall_windows.go -@@ -37,13 +37,14 @@ func errnoErr(e syscall.Errno) error { - } - - var ( -- modadvapi32 = syscall.NewLazyDLL(sysdll.Add("advapi32.dll")) -- modiphlpapi = syscall.NewLazyDLL(sysdll.Add("iphlpapi.dll")) -- modkernel32 = syscall.NewLazyDLL(sysdll.Add("kernel32.dll")) -- modnetapi32 = syscall.NewLazyDLL(sysdll.Add("netapi32.dll")) -- modpsapi = syscall.NewLazyDLL(sysdll.Add("psapi.dll")) -- moduserenv = syscall.NewLazyDLL(sysdll.Add("userenv.dll")) -- modws2_32 = syscall.NewLazyDLL(sysdll.Add("ws2_32.dll")) -+ modadvapi32 = syscall.NewLazyDLL(sysdll.Add("advapi32.dll")) -+ modbcryptprimitives = syscall.NewLazyDLL(sysdll.Add("bcryptprimitives.dll")) -+ modiphlpapi = syscall.NewLazyDLL(sysdll.Add("iphlpapi.dll")) -+ modkernel32 = syscall.NewLazyDLL(sysdll.Add("kernel32.dll")) -+ modnetapi32 = syscall.NewLazyDLL(sysdll.Add("netapi32.dll")) -+ modpsapi = syscall.NewLazyDLL(sysdll.Add("psapi.dll")) -+ moduserenv = syscall.NewLazyDLL(sysdll.Add("userenv.dll")) -+ modws2_32 = syscall.NewLazyDLL(sysdll.Add("ws2_32.dll")) - - procAdjustTokenPrivileges = modadvapi32.NewProc("AdjustTokenPrivileges") - procDuplicateTokenEx = modadvapi32.NewProc("DuplicateTokenEx") -@@ -55,7 +56,7 @@ var ( - procQueryServiceStatus = modadvapi32.NewProc("QueryServiceStatus") - procRevertToSelf = modadvapi32.NewProc("RevertToSelf") - procSetTokenInformation = modadvapi32.NewProc("SetTokenInformation") -- procSystemFunction036 = modadvapi32.NewProc("SystemFunction036") -+ procProcessPrng = modbcryptprimitives.NewProc("ProcessPrng") - procGetAdaptersAddresses = modiphlpapi.NewProc("GetAdaptersAddresses") - procCreateEventW = modkernel32.NewProc("CreateEventW") - procGetACP = modkernel32.NewProc("GetACP") -@@ -179,12 +180,12 @@ func SetTokenInformation(tokenHandle syscall.Token, tokenInformationClass uint32 - return - } - --func RtlGenRandom(buf []byte) (err error) { -+func ProcessPrng(buf []byte) (err error) { - var _p0 *byte - if len(buf) > 0 { - _p0 = &buf[0] - } -- r1, _, e1 := syscall.Syscall(procSystemFunction036.Addr(), 2, uintptr(unsafe.Pointer(_p0)), uintptr(len(buf)), 0) -+ r1, _, e1 := syscall.Syscall(procProcessPrng.Addr(), 2, uintptr(unsafe.Pointer(_p0)), uintptr(len(buf)), 0) - if r1 == 0 { - err = errnoErr(e1) - } -diff --git a/src/runtime/os_windows.go b/src/runtime/os_windows.go -index 8ca8d7790909e..3772a864b2ff4 100644 ---- a/src/runtime/os_windows.go -+++ b/src/runtime/os_windows.go -@@ -127,15 +127,8 @@ var ( - _WriteFile, - _ stdFunction - -- // Use RtlGenRandom to generate cryptographically random data. -- // This approach has been recommended by Microsoft (see issue -- // 15589 for details). -- // The RtlGenRandom is not listed in advapi32.dll, instead -- // RtlGenRandom function can be found by searching for SystemFunction036. -- // Also some versions of Mingw cannot link to SystemFunction036 -- // when building executable as Cgo. So load SystemFunction036 -- // manually during runtime startup. -- _RtlGenRandom stdFunction -+ // Use ProcessPrng to generate cryptographically random data. -+ _ProcessPrng stdFunction - - // Load ntdll.dll manually during startup, otherwise Mingw - // links wrong printf function to cgo executable (see issue -@@ -151,11 +144,11 @@ var ( - ) - - var ( -- advapi32dll = [...]uint16{'a', 'd', 'v', 'a', 'p', 'i', '3', '2', '.', 'd', 'l', 'l', 0} -- ntdlldll = [...]uint16{'n', 't', 'd', 'l', 'l', '.', 'd', 'l', 'l', 0} -- powrprofdll = [...]uint16{'p', 'o', 'w', 'r', 'p', 'r', 'o', 'f', '.', 'd', 'l', 'l', 0} -- winmmdll = [...]uint16{'w', 'i', 'n', 'm', 'm', '.', 'd', 'l', 'l', 0} -- ws2_32dll = [...]uint16{'w', 's', '2', '_', '3', '2', '.', 'd', 'l', 'l', 0} -+ bcryptprimitivesdll = [...]uint16{'b', 'c', 'r', 'y', 'p', 't', 'p', 'r', 'i', 'm', 'i', 't', 'i', 'v', 'e', 's', '.', 'd', 'l', 'l', 0} -+ ntdlldll = [...]uint16{'n', 't', 'd', 'l', 'l', '.', 'd', 'l', 'l', 0} -+ powrprofdll = [...]uint16{'p', 'o', 'w', 'r', 'p', 'r', 'o', 'f', '.', 'd', 'l', 'l', 0} -+ winmmdll = [...]uint16{'w', 'i', 'n', 'm', 'm', '.', 'd', 'l', 'l', 0} -+ ws2_32dll = [...]uint16{'w', 's', '2', '_', '3', '2', '.', 'd', 'l', 'l', 0} - ) - - // Function to be called by windows CreateThread -@@ -251,11 +244,11 @@ func windowsLoadSystemLib(name []uint16) uintptr { - } - - func loadOptionalSyscalls() { -- a32 := windowsLoadSystemLib(advapi32dll[:]) -- if a32 == 0 { -- throw("advapi32.dll not found") -+ bcryptPrimitives := windowsLoadSystemLib(bcryptprimitivesdll[:]) -+ if bcryptPrimitives == 0 { -+ throw("bcryptprimitives.dll not found") - } -- _RtlGenRandom = windowsFindfunc(a32, []byte("SystemFunction036\000")) -+ _ProcessPrng = windowsFindfunc(bcryptPrimitives, []byte("ProcessPrng\000")) - - n32 := windowsLoadSystemLib(ntdlldll[:]) - if n32 == 0 { -@@ -531,7 +524,7 @@ func osinit() { - //go:nosplit - func readRandom(r []byte) int { - n := 0 -- if stdcall2(_RtlGenRandom, uintptr(unsafe.Pointer(&r[0])), uintptr(len(r)))&0xff != 0 { -+ if stdcall2(_ProcessPrng, uintptr(unsafe.Pointer(&r[0])), uintptr(len(r)))&0xff != 0 { - n = len(r) - } - return n \ No newline at end of file diff --git a/mihomo/.github/patch_go122/7c1157f9544922e96945196b47b95664b1e39108.diff b/mihomo/.github/patch_go122/7c1157f9544922e96945196b47b95664b1e39108.diff deleted file mode 100644 index c1fc5f6d2d..0000000000 --- a/mihomo/.github/patch_go122/7c1157f9544922e96945196b47b95664b1e39108.diff +++ /dev/null @@ -1,162 +0,0 @@ -diff --git a/src/net/hook_windows.go b/src/net/hook_windows.go -index ab8656cbbf343..28c49cc6de7e7 100644 ---- a/src/net/hook_windows.go -+++ b/src/net/hook_windows.go -@@ -14,7 +14,6 @@ var ( - testHookDialChannel = func() { time.Sleep(time.Millisecond) } // see golang.org/issue/5349 - - // Placeholders for socket system calls. -- socketFunc func(int, int, int) (syscall.Handle, error) = syscall.Socket - wsaSocketFunc func(int32, int32, int32, *syscall.WSAProtocolInfo, uint32, uint32) (syscall.Handle, error) = windows.WSASocket - connectFunc func(syscall.Handle, syscall.Sockaddr) error = syscall.Connect - listenFunc func(syscall.Handle, int) error = syscall.Listen -diff --git a/src/net/internal/socktest/main_test.go b/src/net/internal/socktest/main_test.go -index 0197feb3f199a..967ce6795aedb 100644 ---- a/src/net/internal/socktest/main_test.go -+++ b/src/net/internal/socktest/main_test.go -@@ -2,7 +2,7 @@ - // Use of this source code is governed by a BSD-style - // license that can be found in the LICENSE file. - --//go:build !js && !plan9 && !wasip1 -+//go:build !js && !plan9 && !wasip1 && !windows - - package socktest_test - -diff --git a/src/net/internal/socktest/main_windows_test.go b/src/net/internal/socktest/main_windows_test.go -deleted file mode 100644 -index df1cb97784b51..0000000000000 ---- a/src/net/internal/socktest/main_windows_test.go -+++ /dev/null -@@ -1,22 +0,0 @@ --// Copyright 2015 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. -- --package socktest_test -- --import "syscall" -- --var ( -- socketFunc func(int, int, int) (syscall.Handle, error) -- closeFunc func(syscall.Handle) error --) -- --func installTestHooks() { -- socketFunc = sw.Socket -- closeFunc = sw.Closesocket --} -- --func uninstallTestHooks() { -- socketFunc = syscall.Socket -- closeFunc = syscall.Closesocket --} -diff --git a/src/net/internal/socktest/sys_windows.go b/src/net/internal/socktest/sys_windows.go -index 8c1c862f33c9b..1c42e5c7f34b7 100644 ---- a/src/net/internal/socktest/sys_windows.go -+++ b/src/net/internal/socktest/sys_windows.go -@@ -9,38 +9,6 @@ import ( - "syscall" - ) - --// Socket wraps syscall.Socket. --func (sw *Switch) Socket(family, sotype, proto int) (s syscall.Handle, err error) { -- sw.once.Do(sw.init) -- -- so := &Status{Cookie: cookie(family, sotype, proto)} -- sw.fmu.RLock() -- f, _ := sw.fltab[FilterSocket] -- sw.fmu.RUnlock() -- -- af, err := f.apply(so) -- if err != nil { -- return syscall.InvalidHandle, err -- } -- s, so.Err = syscall.Socket(family, sotype, proto) -- if err = af.apply(so); err != nil { -- if so.Err == nil { -- syscall.Closesocket(s) -- } -- return syscall.InvalidHandle, err -- } -- -- sw.smu.Lock() -- defer sw.smu.Unlock() -- if so.Err != nil { -- sw.stats.getLocked(so.Cookie).OpenFailed++ -- return syscall.InvalidHandle, so.Err -- } -- nso := sw.addLocked(s, family, sotype, proto) -- sw.stats.getLocked(nso.Cookie).Opened++ -- return s, nil --} -- - // WSASocket wraps [syscall.WSASocket]. - func (sw *Switch) WSASocket(family, sotype, proto int32, protinfo *syscall.WSAProtocolInfo, group uint32, flags uint32) (s syscall.Handle, err error) { - sw.once.Do(sw.init) -diff --git a/src/net/main_windows_test.go b/src/net/main_windows_test.go -index 07f21b72eb1fc..bc024c0bbd82d 100644 ---- a/src/net/main_windows_test.go -+++ b/src/net/main_windows_test.go -@@ -8,7 +8,6 @@ import "internal/poll" - - var ( - // Placeholders for saving original socket system calls. -- origSocket = socketFunc - origWSASocket = wsaSocketFunc - origClosesocket = poll.CloseFunc - origConnect = connectFunc -@@ -18,7 +17,6 @@ var ( - ) - - func installTestHooks() { -- socketFunc = sw.Socket - wsaSocketFunc = sw.WSASocket - poll.CloseFunc = sw.Closesocket - connectFunc = sw.Connect -@@ -28,7 +26,6 @@ func installTestHooks() { - } - - func uninstallTestHooks() { -- socketFunc = origSocket - wsaSocketFunc = origWSASocket - poll.CloseFunc = origClosesocket - connectFunc = origConnect -diff --git a/src/net/sock_windows.go b/src/net/sock_windows.go -index fa11c7af2e727..5540135a2c43e 100644 ---- a/src/net/sock_windows.go -+++ b/src/net/sock_windows.go -@@ -19,21 +19,6 @@ func maxListenerBacklog() int { - func sysSocket(family, sotype, proto int) (syscall.Handle, error) { - s, err := wsaSocketFunc(int32(family), int32(sotype), int32(proto), - nil, 0, windows.WSA_FLAG_OVERLAPPED|windows.WSA_FLAG_NO_HANDLE_INHERIT) -- if err == nil { -- return s, nil -- } -- // WSA_FLAG_NO_HANDLE_INHERIT flag is not supported on some -- // old versions of Windows, see -- // https://msdn.microsoft.com/en-us/library/windows/desktop/ms742212(v=vs.85).aspx -- // for details. Just use syscall.Socket, if windows.WSASocket failed. -- -- // See ../syscall/exec_unix.go for description of ForkLock. -- syscall.ForkLock.RLock() -- s, err = socketFunc(family, sotype, proto) -- if err == nil { -- syscall.CloseOnExec(s) -- } -- syscall.ForkLock.RUnlock() - if err != nil { - return syscall.InvalidHandle, os.NewSyscallError("socket", err) - } -diff --git a/src/syscall/exec_windows.go b/src/syscall/exec_windows.go -index 0a93bc0a80d4e..06e684c7116b4 100644 ---- a/src/syscall/exec_windows.go -+++ b/src/syscall/exec_windows.go -@@ -14,6 +14,7 @@ import ( - "unsafe" - ) - -+// ForkLock is not used on Windows. - var ForkLock sync.RWMutex - - // EscapeArg rewrites command line argument s as prescribed \ No newline at end of file diff --git a/mihomo/.github/workflows/build.yml b/mihomo/.github/workflows/build.yml index cd5202e12e..fb3eb621a4 100644 --- a/mihomo/.github/workflows/build.yml +++ b/mihomo/.github/workflows/build.yml @@ -67,6 +67,12 @@ jobs: - { goos: android, goarch: arm, ndk: armv7a-linux-androideabi34, output: armv7 } - { goos: android, goarch: arm64, ndk: aarch64-linux-android34, output: arm64-v8 } + # Go 1.22 with special patch can work on Windows 7 + # https://github.com/MetaCubeX/go/commits/release-branch.go1.22/ + - { goos: windows, goarch: '386', output: '386-go122', goversion: '1.22' } + - { goos: windows, goarch: amd64, goamd64: v1, output: amd64-compatible-go122, goversion: '1.22' } + - { goos: windows, goarch: amd64, goamd64: v3, output: amd64-go122, goversion: '1.22' } + # Go 1.21 can revert commit `9e4385` to work on Windows 7 # https://github.com/golang/go/issues/64622#issuecomment-1847475161 # (OR we can just use golang1.21.4 which unneeded any patch) @@ -79,6 +85,11 @@ jobs: - { goos: windows, goarch: amd64, goamd64: v1, output: amd64-compatible-go120, goversion: '1.20' } - { goos: windows, goarch: amd64, goamd64: v3, output: amd64-go120, goversion: '1.20' } + # Go 1.22 is the last release that will run on macOS 10.15 Catalina. Go 1.23 will require macOS 11 Big Sur or later. + - { goos: darwin, goarch: arm64, output: arm64-go122, goversion: '1.22' } + - { goos: darwin, goarch: amd64, goamd64: v1, output: amd64-compatible-go122, goversion: '1.22' } + - { goos: darwin, goarch: amd64, goamd64: v3, output: amd64-go122, goversion: '1.22' } + # Go 1.20 is the last release that will run on macOS 10.13 High Sierra or 10.14 Mojave. Go 1.21 will require macOS 10.15 Catalina or later. - { goos: darwin, goarch: arm64, output: arm64-go120, goversion: '1.20' } - { goos: darwin, goarch: amd64, goamd64: v1, output: amd64-compatible-go120, goversion: '1.20' } @@ -96,7 +107,7 @@ jobs: if: ${{ matrix.jobs.goversion == '' && matrix.jobs.goarch != 'loong64' }} uses: actions/setup-go@v5 with: - go-version: '1.22' + go-version: '1.23' - name: Set up Go if: ${{ matrix.jobs.goversion != '' && matrix.jobs.goarch != 'loong64' }} @@ -119,19 +130,40 @@ jobs: echo "/usr/local/go/bin" >> $GITHUB_PATH # modify from https://github.com/restic/restic/issues/4636#issuecomment-1896455557 - # this patch file only works on golang1.22.x - # that means after golang1.23 release it must be changed + # this patch file only works on golang1.23.x + # that means after golang1.24 release it must be changed + # see: https://github.com/MetaCubeX/go/commits/release-branch.go1.23/ # revert: # 693def151adff1af707d82d28f55dba81ceb08e1: "crypto/rand,runtime: switch RtlGenRandom for ProcessPrng" # 7c1157f9544922e96945196b47b95664b1e39108: "net: remove sysSocket fallback for Windows 7" # 48042aa09c2f878c4faa576948b07fe625c4707a: "syscall: remove Windows 7 console handle workaround" - - name: Revert Golang1.22 commit for Windows7/8 + # a17d959debdb04cd550016a3501dd09d50cd62e7: "runtime: always use LoadLibraryEx to load system libraries" + - name: Revert Golang1.23 commit for Windows7/8 if: ${{ matrix.jobs.goos == 'windows' && matrix.jobs.goversion == '' }} run: | cd $(go env GOROOT) - patch --verbose -R -p 1 < $GITHUB_WORKSPACE/.github/patch_go122/693def151adff1af707d82d28f55dba81ceb08e1.diff - patch --verbose -R -p 1 < $GITHUB_WORKSPACE/.github/patch_go122/7c1157f9544922e96945196b47b95664b1e39108.diff - patch --verbose -R -p 1 < $GITHUB_WORKSPACE/.github/patch_go122/48042aa09c2f878c4faa576948b07fe625c4707a.diff + curl https://github.com/MetaCubeX/go/commit/9ac42137ef6730e8b7daca016ece831297a1d75b.diff | patch --verbose -p 1 + curl https://github.com/MetaCubeX/go/commit/21290de8a4c91408de7c2b5b68757b1e90af49dd.diff | patch --verbose -p 1 + curl https://github.com/MetaCubeX/go/commit/6a31d3fa8e47ddabc10bd97bff10d9a85f4cfb76.diff | patch --verbose -p 1 + curl https://github.com/MetaCubeX/go/commit/69e2eed6dd0f6d815ebf15797761c13f31213dd6.diff | patch --verbose -p 1 + + # modify from https://github.com/restic/restic/issues/4636#issuecomment-1896455557 + # this patch file only works on golang1.22.x + # that means after golang1.23 release it must be changed + # see: https://github.com/MetaCubeX/go/commits/release-branch.go1.22/ + # revert: + # 693def151adff1af707d82d28f55dba81ceb08e1: "crypto/rand,runtime: switch RtlGenRandom for ProcessPrng" + # 7c1157f9544922e96945196b47b95664b1e39108: "net: remove sysSocket fallback for Windows 7" + # 48042aa09c2f878c4faa576948b07fe625c4707a: "syscall: remove Windows 7 console handle workaround" + # a17d959debdb04cd550016a3501dd09d50cd62e7: "runtime: always use LoadLibraryEx to load system libraries" + - name: Revert Golang1.22 commit for Windows7/8 + if: ${{ matrix.jobs.goos == 'windows' && matrix.jobs.goversion == '1.22' }} + run: | + cd $(go env GOROOT) + curl https://github.com/MetaCubeX/go/commit/9779155f18b6556a034f7bb79fb7fb2aad1e26a9.diff | patch --verbose -p 1 + curl https://github.com/MetaCubeX/go/commit/ef0606261340e608017860b423ffae5c1ce78239.diff | patch --verbose -p 1 + curl https://github.com/MetaCubeX/go/commit/7f83badcb925a7e743188041cb6e561fc9b5b642.diff | patch --verbose -p 1 + curl https://github.com/MetaCubeX/go/commit/83ff9782e024cb328b690cbf0da4e7848a327f4f.diff | patch --verbose -p 1 # modify from https://github.com/restic/restic/issues/4636#issuecomment-1896455557 - name: Revert Golang1.21 commit for Windows7/8 diff --git a/mihomo/common/net/tcp_keepalive.go b/mihomo/common/net/tcp_keepalive.go new file mode 100644 index 0000000000..047a1c05eb --- /dev/null +++ b/mihomo/common/net/tcp_keepalive.go @@ -0,0 +1,23 @@ +package net + +import ( + "net" + "runtime" + "time" +) + +var ( + KeepAliveIdle = 0 * time.Second + KeepAliveInterval = 0 * time.Second + DisableKeepAlive = false +) + +func TCPKeepAlive(c net.Conn) { + if tcp, ok := c.(*net.TCPConn); ok { + if runtime.GOOS == "android" || DisableKeepAlive { + _ = tcp.SetKeepAlive(false) + } else { + tcpKeepAlive(tcp) + } + } +} diff --git a/mihomo/common/net/tcp_keepalive_go122.go b/mihomo/common/net/tcp_keepalive_go122.go new file mode 100644 index 0000000000..1287316868 --- /dev/null +++ b/mihomo/common/net/tcp_keepalive_go122.go @@ -0,0 +1,10 @@ +//go:build !go1.23 + +package net + +import "net" + +func tcpKeepAlive(tcp *net.TCPConn) { + _ = tcp.SetKeepAlive(true) + _ = tcp.SetKeepAlivePeriod(KeepAliveInterval) +} diff --git a/mihomo/common/net/tcp_keepalive_go123.go b/mihomo/common/net/tcp_keepalive_go123.go new file mode 100644 index 0000000000..2dd4754bbe --- /dev/null +++ b/mihomo/common/net/tcp_keepalive_go123.go @@ -0,0 +1,19 @@ +//go:build go1.23 + +package net + +import "net" + +func tcpKeepAlive(tcp *net.TCPConn) { + config := net.KeepAliveConfig{ + Enable: true, + Idle: KeepAliveIdle, + Interval: KeepAliveInterval, + } + if !SupportTCPKeepAliveCount() { + // it's recommended to set both Idle and Interval to non-negative values in conjunction with a -1 + // for Count on those old Windows if you intend to customize the TCP keep-alive settings. + config.Count = -1 + } + _ = tcp.SetKeepAliveConfig(config) +} diff --git a/mihomo/common/net/tcp_keepalive_go123_unix.go b/mihomo/common/net/tcp_keepalive_go123_unix.go new file mode 100644 index 0000000000..0ead7ca472 --- /dev/null +++ b/mihomo/common/net/tcp_keepalive_go123_unix.go @@ -0,0 +1,15 @@ +//go:build go1.23 && unix + +package net + +func SupportTCPKeepAliveIdle() bool { + return true +} + +func SupportTCPKeepAliveInterval() bool { + return true +} + +func SupportTCPKeepAliveCount() bool { + return true +} diff --git a/mihomo/common/net/tcp_keepalive_go123_windows.go b/mihomo/common/net/tcp_keepalive_go123_windows.go new file mode 100644 index 0000000000..8f1e61f959 --- /dev/null +++ b/mihomo/common/net/tcp_keepalive_go123_windows.go @@ -0,0 +1,63 @@ +//go:build go1.23 && windows + +// copy and modify from golang1.23's internal/syscall/windows/version_windows.go + +package net + +import ( + "errors" + "sync" + "syscall" + + "github.com/metacubex/mihomo/constant/features" + + "golang.org/x/sys/windows" +) + +var ( + supportTCPKeepAliveIdle bool + supportTCPKeepAliveInterval bool + supportTCPKeepAliveCount bool +) + +var initTCPKeepAlive = sync.OnceFunc(func() { + s, err := windows.WSASocket(syscall.AF_INET, syscall.SOCK_STREAM, syscall.IPPROTO_TCP, nil, 0, windows.WSA_FLAG_NO_HANDLE_INHERIT) + if err != nil { + // Fallback to checking the Windows version. + major, build := features.WindowsMajorVersion, features.WindowsBuildNumber + supportTCPKeepAliveIdle = major >= 10 && build >= 16299 + supportTCPKeepAliveInterval = major >= 10 && build >= 16299 + supportTCPKeepAliveCount = major >= 10 && build >= 15063 + return + } + defer windows.Closesocket(s) + var optSupported = func(opt int) bool { + err := windows.SetsockoptInt(s, syscall.IPPROTO_TCP, opt, 1) + return !errors.Is(err, syscall.WSAENOPROTOOPT) + } + supportTCPKeepAliveIdle = optSupported(windows.TCP_KEEPIDLE) + supportTCPKeepAliveInterval = optSupported(windows.TCP_KEEPINTVL) + supportTCPKeepAliveCount = optSupported(windows.TCP_KEEPCNT) +}) + +// SupportTCPKeepAliveIdle indicates whether TCP_KEEPIDLE is supported. +// The minimal requirement is Windows 10.0.16299. +func SupportTCPKeepAliveIdle() bool { + initTCPKeepAlive() + return supportTCPKeepAliveIdle +} + +// SupportTCPKeepAliveInterval indicates whether TCP_KEEPINTVL is supported. +// The minimal requirement is Windows 10.0.16299. +func SupportTCPKeepAliveInterval() bool { + initTCPKeepAlive() + return supportTCPKeepAliveInterval +} + +// SupportTCPKeepAliveCount indicates whether TCP_KEEPCNT is supported. +// supports TCP_KEEPCNT. +// The minimal requirement is Windows 10.0.15063. +func SupportTCPKeepAliveCount() bool { + initTCPKeepAlive() + return supportTCPKeepAliveCount +} diff --git a/mihomo/common/net/tcpip.go b/mihomo/common/net/tcpip.go index 0499e54c17..a84e7e4c4f 100644 --- a/mihomo/common/net/tcpip.go +++ b/mihomo/common/net/tcpip.go @@ -4,11 +4,8 @@ import ( "fmt" "net" "strings" - "time" ) -var KeepAliveInterval = 15 * time.Second - func SplitNetworkType(s string) (string, string, error) { var ( shecme string @@ -47,10 +44,3 @@ func SplitHostPort(s string) (host, port string, hasPort bool, err error) { host, port, err = net.SplitHostPort(temp) return } - -func TCPKeepAlive(c net.Conn) { - if tcp, ok := c.(*net.TCPConn); ok { - _ = tcp.SetKeepAlive(true) - _ = tcp.SetKeepAlivePeriod(KeepAliveInterval) - } -} diff --git a/mihomo/component/dialer/dialer.go b/mihomo/component/dialer/dialer.go index ba95c31b81..2a39508f3f 100644 --- a/mihomo/component/dialer/dialer.go +++ b/mihomo/component/dialer/dialer.go @@ -13,7 +13,6 @@ import ( "time" "github.com/metacubex/mihomo/component/resolver" - "github.com/metacubex/mihomo/constant/features" "github.com/metacubex/mihomo/log" ) @@ -79,29 +78,29 @@ func DialContext(ctx context.Context, network, address string, options ...Option } func ListenPacket(ctx context.Context, network, address string, rAddrPort netip.AddrPort, options ...Option) (net.PacketConn, error) { - if features.CMFA && DefaultSocketHook != nil { - return listenPacketHooked(ctx, network, address) - } - cfg := applyOptions(options...) lc := &net.ListenConfig{} - if cfg.interfaceName != "" { - bind := bindIfaceToListenConfig - if cfg.fallbackBind { - bind = fallbackBindIfaceToListenConfig - } - addr, err := bind(cfg.interfaceName, lc, network, address, rAddrPort) - if err != nil { - return nil, err - } - address = addr - } if cfg.addrReuse { addrReuseToListenConfig(lc) } - if cfg.routingMark != 0 { - bindMarkToListenConfig(cfg.routingMark, lc, network, address) + if DefaultSocketHook != nil { // ignore interfaceName, routingMark when DefaultSocketHook not null (in CFMA) + socketHookToListenConfig(lc) + } else { + if cfg.interfaceName != "" { + bind := bindIfaceToListenConfig + if cfg.fallbackBind { + bind = fallbackBindIfaceToListenConfig + } + addr, err := bind(cfg.interfaceName, lc, network, address, rAddrPort) + if err != nil { + return nil, err + } + address = addr + } + if cfg.routingMark != 0 { + bindMarkToListenConfig(cfg.routingMark, lc, network, address) + } } return lc.ListenPacket(ctx, network, address) @@ -149,25 +148,26 @@ func dialContext(ctx context.Context, network string, destination netip.Addr, po setMultiPathTCP(dialer) } - if features.CMFA && DefaultSocketHook != nil { // ignore interfaceName, routingMark and tfo in CMFA - return dialContextHooked(ctx, dialer, network, address) + if DefaultSocketHook != nil { // ignore interfaceName, routingMark and tfo when DefaultSocketHook not null (in CFMA) + socketHookToToDialer(dialer) + } else { + if opt.interfaceName != "" { + bind := bindIfaceToDialer + if opt.fallbackBind { + bind = fallbackBindIfaceToDialer + } + if err := bind(opt.interfaceName, dialer, network, destination); err != nil { + return nil, err + } + } + if opt.routingMark != 0 { + bindMarkToDialer(opt.routingMark, dialer, network, destination) + } + if opt.tfo && !DisableTFO { + return dialTFO(ctx, *dialer, network, address) + } } - if opt.interfaceName != "" { - bind := bindIfaceToDialer - if opt.fallbackBind { - bind = fallbackBindIfaceToDialer - } - if err := bind(opt.interfaceName, dialer, network, destination); err != nil { - return nil, err - } - } - if opt.routingMark != 0 { - bindMarkToDialer(opt.routingMark, dialer, network, destination) - } - if opt.tfo && !DisableTFO { - return dialTFO(ctx, *dialer, network, address) - } return dialer.DialContext(ctx, network, address) } diff --git a/mihomo/component/dialer/patch_android.go b/mihomo/component/dialer/patch_android.go deleted file mode 100644 index 079b9772ab..0000000000 --- a/mihomo/component/dialer/patch_android.go +++ /dev/null @@ -1,38 +0,0 @@ -//go:build android && cmfa - -package dialer - -import ( - "context" - "net" - "syscall" -) - -type SocketControl func(network, address string, conn syscall.RawConn) error - -var DefaultSocketHook SocketControl - -func dialContextHooked(ctx context.Context, dialer *net.Dialer, network string, address string) (net.Conn, error) { - addControlToDialer(dialer, func(ctx context.Context, network, address string, c syscall.RawConn) error { - return DefaultSocketHook(network, address, c) - }) - - conn, err := dialer.DialContext(ctx, network, address) - if err != nil { - return nil, err - } - - if t, ok := conn.(*net.TCPConn); ok { - t.SetKeepAlive(false) - } - - return conn, nil -} - -func listenPacketHooked(ctx context.Context, network, address string) (net.PacketConn, error) { - lc := &net.ListenConfig{ - Control: DefaultSocketHook, - } - - return lc.ListenPacket(ctx, network, address) -} diff --git a/mihomo/component/dialer/patch_common.go b/mihomo/component/dialer/patch_common.go deleted file mode 100644 index 2c96fe60b7..0000000000 --- a/mihomo/component/dialer/patch_common.go +++ /dev/null @@ -1,21 +0,0 @@ -//go:build !(android && cmfa) - -package dialer - -import ( - "context" - "net" - "syscall" -) - -type SocketControl func(network, address string, conn syscall.RawConn) error - -var DefaultSocketHook SocketControl - -func dialContextHooked(ctx context.Context, dialer *net.Dialer, network string, address string) (net.Conn, error) { - return nil, nil -} - -func listenPacketHooked(ctx context.Context, network, address string) (net.PacketConn, error) { - return nil, nil -} diff --git a/mihomo/component/dialer/socket_hook.go b/mihomo/component/dialer/socket_hook.go new file mode 100644 index 0000000000..7a2ea43215 --- /dev/null +++ b/mihomo/component/dialer/socket_hook.go @@ -0,0 +1,27 @@ +package dialer + +import ( + "context" + "net" + "syscall" +) + +// SocketControl +// never change type traits because it's used in CFMA +type SocketControl func(network, address string, conn syscall.RawConn) error + +// DefaultSocketHook +// never change type traits because it's used in CFMA +var DefaultSocketHook SocketControl + +func socketHookToToDialer(dialer *net.Dialer) { + addControlToDialer(dialer, func(ctx context.Context, network, address string, c syscall.RawConn) error { + return DefaultSocketHook(network, address, c) + }) +} + +func socketHookToListenConfig(lc *net.ListenConfig) { + addControlToListenConfig(lc, func(ctx context.Context, network, address string, c syscall.RawConn) error { + return DefaultSocketHook(network, address, c) + }) +} diff --git a/mihomo/component/fakeip/pool.go b/mihomo/component/fakeip/pool.go index 2b06fc0bdf..8096a868af 100644 --- a/mihomo/component/fakeip/pool.go +++ b/mihomo/component/fakeip/pool.go @@ -8,7 +8,7 @@ import ( "github.com/metacubex/mihomo/common/nnip" "github.com/metacubex/mihomo/component/profile/cachefile" - "github.com/metacubex/mihomo/component/trie" + C "github.com/metacubex/mihomo/constant" ) const ( @@ -35,7 +35,7 @@ type Pool struct { offset netip.Addr cycle bool mux sync.Mutex - host *trie.DomainTrie[struct{}] + host []C.Rule ipnet netip.Prefix store store } @@ -66,10 +66,12 @@ func (p *Pool) LookBack(ip netip.Addr) (string, bool) { // ShouldSkipped return if domain should be skipped func (p *Pool) ShouldSkipped(domain string) bool { - if p.host == nil { - return false + for _, rule := range p.host { + if match, _ := rule.Match(&C.Metadata{Host: domain}); match { + return true + } } - return p.host.Search(domain) != nil + return false } // Exist returns if given ip exists in fake-ip pool @@ -154,7 +156,7 @@ func (p *Pool) restoreState() { type Options struct { IPNet netip.Prefix - Host *trie.DomainTrie[struct{}] + Host []C.Rule // Size sets the maximum number of entries in memory // and does not work if Persistence is true diff --git a/mihomo/component/fakeip/pool_test.go b/mihomo/component/fakeip/pool_test.go index cc50fcf7b5..9c05a32778 100644 --- a/mihomo/component/fakeip/pool_test.go +++ b/mihomo/component/fakeip/pool_test.go @@ -9,6 +9,8 @@ import ( "github.com/metacubex/mihomo/component/profile/cachefile" "github.com/metacubex/mihomo/component/trie" + C "github.com/metacubex/mihomo/constant" + RP "github.com/metacubex/mihomo/rules/provider" "github.com/sagernet/bbolt" "github.com/stretchr/testify/assert" @@ -154,7 +156,7 @@ func TestPool_Skip(t *testing.T) { pools, tempfile, err := createPools(Options{ IPNet: ipnet, Size: 10, - Host: tree, + Host: []C.Rule{RP.NewDomainSet(tree.NewDomainSet(), "")}, }) assert.Nil(t, err) defer os.Remove(tempfile) diff --git a/mihomo/component/sniffer/dispatcher.go b/mihomo/component/sniffer/dispatcher.go index 4438638dad..c96f5a4b03 100644 --- a/mihomo/component/sniffer/dispatcher.go +++ b/mihomo/component/sniffer/dispatcher.go @@ -9,7 +9,6 @@ import ( "github.com/metacubex/mihomo/common/lru" N "github.com/metacubex/mihomo/common/net" - "github.com/metacubex/mihomo/component/trie" C "github.com/metacubex/mihomo/constant" "github.com/metacubex/mihomo/constant/sniffer" "github.com/metacubex/mihomo/log" @@ -26,17 +25,26 @@ var Dispatcher *SnifferDispatcher type SnifferDispatcher struct { enable bool sniffers map[sniffer.Sniffer]SnifferConfig - forceDomain *trie.DomainSet - skipSNI *trie.DomainSet + forceDomain []C.Rule + skipDomain []C.Rule skipList *lru.LruCache[string, uint8] forceDnsMapping bool parsePureIp bool } func (sd *SnifferDispatcher) shouldOverride(metadata *C.Metadata) bool { - return (metadata.Host == "" && sd.parsePureIp) || - sd.forceDomain.Has(metadata.Host) || - (metadata.DNSMode == C.DNSMapping && sd.forceDnsMapping) + if metadata.Host == "" && sd.parsePureIp { + return true + } + if metadata.DNSMode == C.DNSMapping && sd.forceDnsMapping { + return true + } + for _, rule := range sd.forceDomain { + if ok, _ := rule.Match(&C.Metadata{Host: metadata.Host}); ok { + return true + } + } + return false } func (sd *SnifferDispatcher) UDPSniff(packet C.PacketAdapter) bool { @@ -94,9 +102,11 @@ func (sd *SnifferDispatcher) TCPSniff(conn *N.BufferedConn, metadata *C.Metadata log.Debugln("[Sniffer] All sniffing sniff failed with from [%s:%d] to [%s:%d]", metadata.SrcIP, metadata.SrcPort, metadata.String(), metadata.DstPort) return false } else { - if sd.skipSNI.Has(host) { - log.Debugln("[Sniffer] Skip sni[%s]", host) - return false + for _, rule := range sd.skipDomain { + if ok, _ := rule.Match(&C.Metadata{Host: host}); ok { + log.Debugln("[Sniffer] Skip sni[%s]", host) + return false + } } sd.skipList.Delete(dst) @@ -187,12 +197,12 @@ func NewCloseSnifferDispatcher() (*SnifferDispatcher, error) { } func NewSnifferDispatcher(snifferConfig map[sniffer.Type]SnifferConfig, - forceDomain *trie.DomainSet, skipSNI *trie.DomainSet, + forceDomain []C.Rule, skipDomain []C.Rule, forceDnsMapping bool, parsePureIp bool) (*SnifferDispatcher, error) { dispatcher := SnifferDispatcher{ enable: true, forceDomain: forceDomain, - skipSNI: skipSNI, + skipDomain: skipDomain, skipList: lru.New(lru.WithSize[string, uint8](128), lru.WithAge[string, uint8](600)), forceDnsMapping: forceDnsMapping, parsePureIp: parsePureIp, diff --git a/mihomo/component/trie/domain.go b/mihomo/component/trie/domain.go index db30402ede..6d3e37f70a 100644 --- a/mihomo/component/trie/domain.go +++ b/mihomo/component/trie/domain.go @@ -134,6 +134,13 @@ func (t *DomainTrie[T]) Foreach(fn func(domain string, data T) bool) { } } +func (t *DomainTrie[T]) IsEmpty() bool { + if t == nil { + return true + } + return t.root.isEmpty() +} + func recursion[T any](items []string, node *Node[T], fn func(domain string, data T) bool) bool { for key, data := range node.getChildren() { newItems := append([]string{key}, items...) diff --git a/mihomo/config/config.go b/mihomo/config/config.go index 5f2b68453d..74ffdd038c 100644 --- a/mihomo/config/config.go +++ b/mihomo/config/config.go @@ -38,6 +38,7 @@ import ( LC "github.com/metacubex/mihomo/listener/config" "github.com/metacubex/mihomo/log" R "github.com/metacubex/mihomo/rules" + RC "github.com/metacubex/mihomo/rules/common" RP "github.com/metacubex/mihomo/rules/provider" T "github.com/metacubex/mihomo/tunnel" @@ -163,8 +164,8 @@ type IPTables struct { type Sniffer struct { Enable bool Sniffers map[snifferTypes.Type]SNIFF.SnifferConfig - ForceDomain *trie.DomainSet - SkipDomain *trie.DomainSet + ForceDomain []C.Rule + SkipDomain []C.Rule ForceDnsMapping bool ParsePureIp bool } @@ -338,7 +339,9 @@ type RawConfig struct { FindProcessMode P.FindProcessMode `yaml:"find-process-mode" json:"find-process-mode"` GlobalClientFingerprint string `yaml:"global-client-fingerprint"` GlobalUA string `yaml:"global-ua"` + KeepAliveIdle int `yaml:"keep-alive-idle"` KeepAliveInterval int `yaml:"keep-alive-interval"` + DisableKeepAlive bool `yaml:"disable-keep-alive"` Sniffer RawSniffer `yaml:"sniffer" json:"sniffer"` ProxyProvider map[string]map[string]any `yaml:"proxy-providers"` @@ -624,7 +627,7 @@ func ParseRawConfig(rawCfg *RawConfig) (*Config, error) { } } - config.Sniffer, err = parseSniffer(rawCfg.Sniffer) + config.Sniffer, err = parseSniffer(rawCfg.Sniffer, rules, ruleProviders) if err != nil { return nil, err } @@ -649,9 +652,14 @@ func parseGeneral(cfg *RawConfig) (*General, error) { C.ASNUrl = cfg.GeoXUrl.ASN C.GeodataMode = cfg.GeodataMode C.UA = cfg.GlobalUA + + if cfg.KeepAliveIdle != 0 { + N.KeepAliveIdle = time.Duration(cfg.KeepAliveIdle) * time.Second + } if cfg.KeepAliveInterval != 0 { N.KeepAliveInterval = time.Duration(cfg.KeepAliveInterval) * time.Second } + N.DisableKeepAlive = cfg.DisableKeepAlive updater.ExternalUIPath = cfg.ExternalUI // checkout externalUI exist @@ -1400,27 +1408,21 @@ func parseDNS(rawCfg *RawConfig, hosts *trie.DomainTrie[resolver.HostValue], rul return nil, err } - var host *trie.DomainTrie[struct{}] - // fake ip skip host filter - if len(cfg.FakeIPFilter) != 0 { - host = trie.New[struct{}]() - for _, domain := range cfg.FakeIPFilter { - _ = host.Insert(domain, struct{}{}) - } - host.Optimize() - } - + var fakeIPTrie *trie.DomainTrie[struct{}] if len(dnsCfg.Fallback) != 0 { - if host == nil { - host = trie.New[struct{}]() - } + fakeIPTrie = trie.New[struct{}]() for _, fb := range dnsCfg.Fallback { if net.ParseIP(fb.Addr) != nil { continue } - _ = host.Insert(fb.Addr, struct{}{}) + _ = fakeIPTrie.Insert(fb.Addr, struct{}{}) } - host.Optimize() + } + + // fake ip skip host filter + host, err := parseDomain(cfg.FakeIPFilter, fakeIPTrie, rules, ruleProviders) + if err != nil { + return nil, err } pool, err := fakeip.New(fakeip.Options{ @@ -1547,7 +1549,7 @@ func parseTuicServer(rawTuic RawTuicServer, general *General) error { return nil } -func parseSniffer(snifferRaw RawSniffer) (*Sniffer, error) { +func parseSniffer(snifferRaw RawSniffer, rules []C.Rule, ruleProviders map[string]providerTypes.RuleProvider) (*Sniffer, error) { sniffer := &Sniffer{ Enable: snifferRaw.Enable, ForceDnsMapping: snifferRaw.ForceDnsMapping, @@ -1610,23 +1612,83 @@ func parseSniffer(snifferRaw RawSniffer) (*Sniffer, error) { sniffer.Sniffers = loadSniffer - forceDomainTrie := trie.New[struct{}]() - for _, domain := range snifferRaw.ForceDomain { - err := forceDomainTrie.Insert(domain, struct{}{}) - if err != nil { - return nil, fmt.Errorf("error domian[%s] in force-domain, error:%v", domain, err) - } + forceDomain, err := parseDomain(snifferRaw.ForceDomain, nil, rules, ruleProviders) + if err != nil { + return nil, fmt.Errorf("error in force-domain, error:%w", err) } - sniffer.ForceDomain = forceDomainTrie.NewDomainSet() + sniffer.ForceDomain = forceDomain - skipDomainTrie := trie.New[struct{}]() - for _, domain := range snifferRaw.SkipDomain { - err := skipDomainTrie.Insert(domain, struct{}{}) - if err != nil { - return nil, fmt.Errorf("error domian[%s] in force-domain, error:%v", domain, err) - } + skipDomain, err := parseDomain(snifferRaw.SkipDomain, nil, rules, ruleProviders) + if err != nil { + return nil, fmt.Errorf("error in skip-domain, error:%w", err) } - sniffer.SkipDomain = skipDomainTrie.NewDomainSet() + sniffer.SkipDomain = skipDomain return sniffer, nil } + +func parseDomain(domains []string, domainTrie *trie.DomainTrie[struct{}], rules []C.Rule, ruleProviders map[string]providerTypes.RuleProvider) (domainRules []C.Rule, err error) { + var rule C.Rule + for _, domain := range domains { + domainLower := strings.ToLower(domain) + if strings.Contains(domainLower, "geosite:") { + subkeys := strings.Split(domain, ":") + subkeys = subkeys[1:] + subkeys = strings.Split(subkeys[0], ",") + for _, country := range subkeys { + found := false + for _, rule = range rules { + if rule.RuleType() == C.GEOSITE { + if strings.EqualFold(country, rule.Payload()) { + found = true + domainRules = append(domainRules, rule) + } + } + } + if !found { + rule, err = RC.NewGEOSITE(country, "") + if err != nil { + return nil, err + } + domainRules = append(domainRules, rule) + } + } + } else if strings.Contains(domainLower, "rule-set:") { + subkeys := strings.Split(domain, ":") + subkeys = subkeys[1:] + subkeys = strings.Split(subkeys[0], ",") + for _, domainSetName := range subkeys { + if rp, ok := ruleProviders[domainSetName]; !ok { + return nil, fmt.Errorf("not found rule-set: %s", domainSetName) + } else { + switch rp.Behavior() { + case providerTypes.IPCIDR: + return nil, fmt.Errorf("rule provider type error, except domain,actual %s", rp.Behavior()) + case providerTypes.Classical: + log.Warnln("%s provider is %s, only matching it contain domain rule", rp.Name(), rp.Behavior()) + default: + } + } + rule, err = RP.NewRuleSet(domainSetName, "", true) + if err != nil { + return nil, err + } + + domainRules = append(domainRules, rule) + } + } else { + if domainTrie == nil { + domainTrie = trie.New[struct{}]() + } + err = domainTrie.Insert(domain, struct{}{}) + if err != nil { + return nil, err + } + } + } + if !domainTrie.IsEmpty() { + rule = RP.NewDomainSet(domainTrie.NewDomainSet(), "") + domainRules = append(domainRules, rule) + } + return +} diff --git a/mihomo/constant/rule.go b/mihomo/constant/rule.go index a91ee6cb07..f9f987e672 100644 --- a/mihomo/constant/rule.go +++ b/mihomo/constant/rule.go @@ -27,6 +27,7 @@ const ( ProcessNameRegex ProcessPathRegex RuleSet + DomainSet Network Uid SubRules @@ -90,6 +91,8 @@ func (rt RuleType) String() string { return "Match" case RuleSet: return "RuleSet" + case DomainSet: + return "DomainSet" case Network: return "Network" case DSCP: diff --git a/mihomo/docs/config.yaml b/mihomo/docs/config.yaml index d7c686d01f..8db06b6d7d 100644 --- a/mihomo/docs/config.yaml +++ b/mihomo/docs/config.yaml @@ -82,7 +82,9 @@ external-doh-server: /dns-query global-client-fingerprint: chrome # TCP keep alive interval -keep-alive-interval: 15 +# disable-keep-alive: false #目前在android端强制为true +# keep-alive-idle: 15 +# keep-alive-interval: 15 # routing-mark:6666 # 配置 fwmark 仅用于 Linux experimental: @@ -241,6 +243,16 @@ dns: fake-ip-range: 198.18.0.1/16 # fake-ip 池设置 + # 配置不使用 fake-ip 的域名 + fake-ip-filter: + - '*.lan' + - localhost.ptlogin2.qq.com + # fakeip-filter 为 rule-providers 中的名为 fakeip-filter 规则订阅, + # 且 behavior 必须为 domain/classical,当为 classical 时仅会生效域名类规则 + - rule-set:fakeip-filter + # fakeip-filter 为 geosite 中名为 fakeip-filter 的分类(需要自行保证该分类存在) + - geosite:fakeip-filter + # use-hosts: true # 查询 hosts # 配置后面的nameserver、fallback和nameserver-policy向dns服务器的连接过程是否遵守遵守rules规则 @@ -250,11 +262,6 @@ dns: # 此外,这三者配置中的dns服务器如果出现域名会采用default-nameserver配置项解析,也请确保正确配置default-nameserver respect-rules: false - # 配置不使用 fake-ip 的域名 - # fake-ip-filter: - # - '*.lan' - # - localhost.ptlogin2.qq.com - # DNS 主要域名配置 # 支持 UDP,TCP,DoT,DoH,DoQ # 这部分为主要 DNS 配置,影响所有直连,确保使用对大陆解析精准的 DNS diff --git a/mihomo/listener/http/server.go b/mihomo/listener/http/server.go index 77e10f0841..f61dd03609 100644 --- a/mihomo/listener/http/server.go +++ b/mihomo/listener/http/server.go @@ -4,9 +4,9 @@ import ( "net" "github.com/metacubex/mihomo/adapter/inbound" + N "github.com/metacubex/mihomo/common/net" "github.com/metacubex/mihomo/component/auth" C "github.com/metacubex/mihomo/constant" - "github.com/metacubex/mihomo/constant/features" authStore "github.com/metacubex/mihomo/listener/auth" ) @@ -74,11 +74,7 @@ func NewWithAuthenticator(addr string, tunnel C.Tunnel, authenticator auth.Authe } continue } - if features.CMFA { - if t, ok := conn.(*net.TCPConn); ok { - t.SetKeepAlive(false) - } - } + N.TCPKeepAlive(conn) if isDefault { // only apply on default listener if !inbound.IsRemoteAddrDisAllowed(conn.RemoteAddr()) { _ = conn.Close() diff --git a/mihomo/rules/provider/domain_set.go b/mihomo/rules/provider/domain_set.go new file mode 100644 index 0000000000..372b438ea8 --- /dev/null +++ b/mihomo/rules/provider/domain_set.go @@ -0,0 +1,43 @@ +package provider + +import ( + "github.com/metacubex/mihomo/component/trie" + C "github.com/metacubex/mihomo/constant" +) + +type DomainSet struct { + *domainStrategy + adapter string +} + +func (d *DomainSet) ProviderNames() []string { + return nil +} + +func (d *DomainSet) RuleType() C.RuleType { + return C.DomainSet +} + +func (d *DomainSet) Match(metadata *C.Metadata) (bool, string) { + if d.domainSet == nil { + return false, "" + } + return d.domainSet.Has(metadata.RuleHost()), d.adapter +} + +func (d *DomainSet) Adapter() string { + return d.adapter +} + +func (d *DomainSet) Payload() string { + return "" +} + +func NewDomainSet(domainSet *trie.DomainSet, adapter string) *DomainSet { + return &DomainSet{ + domainStrategy: &domainStrategy{domainSet: domainSet}, + adapter: adapter, + } +} + +var _ C.Rule = (*DomainSet)(nil) diff --git a/openwrt-packages/alist/files/alist.init b/openwrt-packages/alist/files/alist.init index a1703bb2b0..157aa47924 100755 --- a/openwrt-packages/alist/files/alist.init +++ b/openwrt-packages/alist/files/alist.init @@ -188,7 +188,7 @@ start_service() { json_dump > $data_dir/config.json - procd_open_instance + procd_open_instance alist procd_set_param command $PROG procd_append_param command server --data $data_dir procd_set_param stdout 0 @@ -196,7 +196,13 @@ start_service() { procd_set_param respawn procd_set_param limits core="unlimited" procd_set_param limits nofile="200000 200000" - procd_close_instance + procd_close_instance alist +} + +reload_service() { + stop + sleep 3 + start } service_triggers() { diff --git a/openwrt-packages/luci-app-alist/htdocs/luci-static/resources/view/alist/basic.js b/openwrt-packages/luci-app-alist/htdocs/luci-static/resources/view/alist/basic.js index 23c2416b1b..bb40c41c71 100644 --- a/openwrt-packages/luci-app-alist/htdocs/luci-static/resources/view/alist/basic.js +++ b/openwrt-packages/luci-app-alist/htdocs/luci-static/resources/view/alist/basic.js @@ -17,18 +17,18 @@ function getServiceStatus() { return L.resolveDefault(callServiceList('alist'), {}).then(function (res) { var isRunning = false; try { - isRunning = res['alist']['instances']['instance1']['running']; + isRunning = res['alist']['instances']['alist']['running']; } catch (e) { } return isRunning; }); } -function renderStatus(isRunning, webport) { +function renderStatus(isRunning, protocol, webport) { var spanTemp = '%s %s'; var renderHTML; if (isRunning) { - var button = String.format('', - _('Open Web Interface'), window.location.hostname, webport); + var button = String.format('', + _('Open Web Interface'), protocol, window.location.hostname, webport); renderHTML = spanTemp.format('green', 'Alist', _('RUNNING')) + button; } else { renderHTML = spanTemp.format('red', 'Alist', _('NOT RUNNING')); @@ -64,6 +64,13 @@ return view.extend({ render: function (data) { var m, s, o; var webport = uci.get(data[0], '@alist[0]', 'port') || '5244'; + var ssl = uci.get(data[0], '@alist[0]', 'ssl') || '0'; + var protocol; + if (ssl === '0') { + protocol = 'http:'; + } else if (ssl === '1') { + protocol = 'https:'; + } m = new form.Map('alist', _('Alist'), _('A file list program that supports multiple storage.') + @@ -79,7 +86,7 @@ return view.extend({ poll.add(function () { return L.resolveDefault(getServiceStatus()).then(function (res) { var view = document.getElementById('service_status'); - view.innerHTML = renderStatus(res, webport); + view.innerHTML = renderStatus(res, protocol, webport); }); }); @@ -88,7 +95,7 @@ return view.extend({ ]); } - s = m.section(form.TypedSection); + s = m.section(form.NamedSection, '@alist[0]', 'alist'); o = s.option(form.Flag, 'enabled', _('Enabled')); o.default = o.disabled; @@ -108,10 +115,12 @@ return view.extend({ o = s.option(form.Value, 'ssl_cert', _('SSL cert'), _('SSL certificate file path')); + o.rmempty = false; o.depends('ssl', '1'); o = s.option(form.Value, 'ssl_key', _('SSL key'), _('SSL key file path')); + o.rmempty = false; o.depends('ssl', '1'); o = s.option(form.Flag, 'mysql', _('Enable Database')); diff --git a/openwrt-packages/luci-app-alist/po/zh_Hans/alist.po b/openwrt-packages/luci-app-alist/po/zh_Hans/alist.po index ec63260c61..c01cf1bab0 100644 --- a/openwrt-packages/luci-app-alist/po/zh_Hans/alist.po +++ b/openwrt-packages/luci-app-alist/po/zh_Hans/alist.po @@ -73,10 +73,10 @@ msgstr "随机生成一个新密码。" msgid "Username:" msgstr "用户名:" -msgstr "New Password:" +msgid "New Password:" msgstr "新密码:" -msgstr "New password has been copied to clipboard." +msgid "New password has been copied to clipboard." msgstr "新密码已复制到剪贴板。" msgid "Login Validity Period (hours)" diff --git a/openwrt-packages/luci-app-wechatpush/root/usr/share/serverchan/serverchan b/openwrt-packages/luci-app-wechatpush/root/usr/share/serverchan/serverchan index 157f211e0f..5a19c62f03 100755 --- a/openwrt-packages/luci-app-wechatpush/root/usr/share/serverchan/serverchan +++ b/openwrt-packages/luci-app-wechatpush/root/usr/share/serverchan/serverchan @@ -678,9 +678,9 @@ function rand_geturl(){ echo `curl -k -s -w "%{http_code}" -m 5 ${url_str} -A "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36 Edg/112.0.1722.58" -o /dev/null` } local check=`getcheck` - while [ -z "$check" ] || [[ $check -ne 200 && $check -ne 301 && $check -ne 302 ]]; do + while [ -z "$check" ] || [[ $check -ne 200 && $check -ne 202 && $check -ne 301 && $check -ne 302 ]]; do local check=`getcheck` - if [ ! -z "$check" ] && [[ $check -eq 200 || $check -eq 301 || $check -eq 302 ]]; then + if [ ! -z "$check" ] && [[ $check -eq 200 || $check -eq 202 || $check -eq 301 || $check -eq 302 ]]; then [ ! -z "$network_enable" ] && [ "$network_enable" -eq "404" ] && echo "`date "+%Y-%m-%d %H:%M:%S"` 【网络状态】网络恢复正常.." >> ${logfile} local network_enable="200" else diff --git a/pingtunnel/Dockerfile b/pingtunnel/Dockerfile index b14358cb94..cce8c7aa1c 100644 --- a/pingtunnel/Dockerfile +++ b/pingtunnel/Dockerfile @@ -5,7 +5,8 @@ WORKDIR /app COPY go.* ./ RUN go mod download COPY . ./ -RUN go build -v -o pingtunnel +RUN go mod tidy +RUN cd cmd && go build -v -o pingtunnel && mv pingtunnel ../ FROM debian COPY --from=build-env /app/pingtunnel . diff --git a/shadowsocks-rust/crates/shadowsocks-service/src/server/server.rs b/shadowsocks-rust/crates/shadowsocks-service/src/server/server.rs index 2bd0d03371..ae9102bdf8 100644 --- a/shadowsocks-rust/crates/shadowsocks-service/src/server/server.rs +++ b/shadowsocks-rust/crates/shadowsocks-service/src/server/server.rs @@ -2,12 +2,15 @@ use std::{ collections::HashMap, + future::Future, io::{self, ErrorKind}, + pin::Pin, sync::Arc, + task::{Context, Poll}, time::Duration, }; -use futures::{stream::FuturesUnordered, FutureExt, StreamExt}; +use futures::{future, ready}; use log::{error, trace}; use shadowsocks::{ config::{ManagerAddr, ServerConfig}, @@ -16,7 +19,7 @@ use shadowsocks::{ plugin::{Plugin, PluginMode}, ManagerClient, }; -use tokio::time; +use tokio::{task::JoinHandle, time}; use crate::{acl::AccessControl, config::SecurityConfig, net::FlowStat}; @@ -159,6 +162,27 @@ impl ServerBuilder { } } +struct ServerHandle(JoinHandle>); + +impl Drop for ServerHandle { + #[inline] + fn drop(&mut self) { + self.0.abort(); + } +} + +impl Future for ServerHandle { + type Output = io::Result<()>; + + #[inline] + fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + match ready!(Pin::new(&mut self.0).poll(cx)) { + Ok(res) => res.into(), + Err(err) => Err(io::Error::new(ErrorKind::Other, err)).into(), + } + } +} + /// Shadowsocks Server instance pub struct Server { context: Arc, @@ -187,36 +211,33 @@ impl Server { /// Start serving pub async fn run(self) -> io::Result<()> { - let vfut = FuturesUnordered::new(); + let mut vfut = Vec::new(); if let Some(plugin) = self.plugin { - vfut.push( - async move { - match plugin.join().await { - Ok(status) => { - error!("plugin exited with status: {}", status); - Ok(()) - } - Err(err) => { - error!("plugin exited with error: {}", err); - Err(err) - } + vfut.push(ServerHandle(tokio::spawn(async move { + match plugin.join().await { + Ok(status) => { + error!("plugin exited with status: {}", status); + Ok(()) + } + Err(err) => { + error!("plugin exited with error: {}", err); + Err(err) } } - .boxed(), - ); + }))); } if let Some(tcp_server) = self.tcp_server { - vfut.push(tcp_server.run().boxed()); + vfut.push(ServerHandle(tokio::spawn(tcp_server.run()))); } if let Some(udp_server) = self.udp_server { - vfut.push(udp_server.run().boxed()) + vfut.push(ServerHandle(tokio::spawn(udp_server.run()))); } if let Some(manager_addr) = self.manager_addr { - let manager_fut = async move { + vfut.push(ServerHandle(tokio::spawn(async move { loop { match ManagerClient::connect( self.context.context_ref(), @@ -251,13 +272,10 @@ impl Server { // Report every 10 seconds time::sleep(Duration::from_secs(10)).await; } - } - .boxed(); - vfut.push(manager_fut); + }))); } - let (res, _) = vfut.into_future().await; - if let Some(Err(err)) = res { + if let (Err(err), ..) = future::select_all(vfut).await { error!("servers exited with error: {}", err); } diff --git a/small/v2ray-geodata/Makefile b/small/v2ray-geodata/Makefile index 05c67a1f17..5f9549403b 100644 --- a/small/v2ray-geodata/Makefile +++ b/small/v2ray-geodata/Makefile @@ -21,13 +21,13 @@ define Download/geoip HASH:=0080f836cd88744fc37a8ec13f36e189814d8f95d8072c557bdab04f700f51e8 endef -GEOSITE_VER:=20240810010807 +GEOSITE_VER:=20240814034058 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:=f9e7fab895dc57e2c40d0e12a774dc45a3dc83f43eab5185757bb3f9e5b08010 + HASH:=cdb9e804886774f683f80c4f2819df8eebf67fd40f48406ac368286ae360ac0a endef GEOSITE_IRAN_VER:=202408120030 diff --git a/v2rayng/V2rayNG/app/src/main/kotlin/com/v2ray/ang/AngApplication.kt b/v2rayng/V2rayNG/app/src/main/kotlin/com/v2ray/ang/AngApplication.kt index 6416d201df..516fe1ed4f 100644 --- a/v2rayng/V2rayNG/app/src/main/kotlin/com/v2ray/ang/AngApplication.kt +++ b/v2rayng/V2rayNG/app/src/main/kotlin/com/v2ray/ang/AngApplication.kt @@ -17,9 +17,6 @@ class AngApplication : MultiDexApplication(), Configuration.Provider { application = this } - //var firstRun = false - // private set - override fun onCreate() { super.onCreate() diff --git a/v2rayng/V2rayNG/app/src/main/kotlin/com/v2ray/ang/ui/MainActivity.kt b/v2rayng/V2rayNG/app/src/main/kotlin/com/v2ray/ang/ui/MainActivity.kt index 023d2b7260..23fa921299 100644 --- a/v2rayng/V2rayNG/app/src/main/kotlin/com/v2ray/ang/ui/MainActivity.kt +++ b/v2rayng/V2rayNG/app/src/main/kotlin/com/v2ray/ang/ui/MainActivity.kt @@ -18,6 +18,7 @@ import androidx.activity.result.contract.ActivityResultContracts import androidx.activity.viewModels import androidx.appcompat.app.ActionBarDrawerToggle import androidx.appcompat.app.AlertDialog +import androidx.appcompat.widget.SearchView import androidx.core.content.ContextCompat import androidx.core.view.GravityCompat import androidx.core.view.isVisible @@ -27,7 +28,6 @@ import androidx.recyclerview.widget.LinearLayoutManager import com.google.android.material.navigation.NavigationView import com.google.android.material.tabs.TabLayout import com.tbruyelle.rxpermissions3.RxPermissions -import com.tencent.mmkv.MMKV import com.v2ray.ang.AppConfig import com.v2ray.ang.R import com.v2ray.ang.databinding.ActivityMainBinding @@ -54,8 +54,6 @@ class MainActivity : BaseActivity(), NavigationView.OnNavigationItemSelectedList } private val adapter by lazy { MainRecyclerAdapter(this) } - private val mainStorage by lazy { MMKV.mmkvWithID(MmkvManager.ID_MAIN, MMKV.MULTI_PROCESS_MODE) } - private val settingsStorage by lazy { MMKV.mmkvWithID(MmkvManager.ID_SETTING, MMKV.MULTI_PROCESS_MODE) } private val requestVpnPermission = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { if (it.resultCode == RESULT_OK) { startV2Ray() @@ -90,7 +88,7 @@ class MainActivity : BaseActivity(), NavigationView.OnNavigationItemSelectedList binding.fab.setOnClickListener { if (mainViewModel.isRunning.value == true) { Utils.stopVService(this) - } else if ((settingsStorage?.decodeString(AppConfig.PREF_MODE) ?: "VPN") == "VPN") { + } else if ((MmkvManager.settingsStorage?.decodeString(AppConfig.PREF_MODE) ?: "VPN") == "VPN") { val intent = VpnService.prepare(this) if (intent == null) { startV2Ray() @@ -120,14 +118,14 @@ class MainActivity : BaseActivity(), NavigationView.OnNavigationItemSelectedList val toggle = ActionBarDrawerToggle( - this, binding.drawerLayout, binding.toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close) + this, binding.drawerLayout, binding.toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close + ) binding.drawerLayout.addDrawerListener(toggle) toggle.syncState() binding.navView.setNavigationItemSelectedListener(this) initGroupTab() setupViewModel() - mainViewModel.copyAssets(assets) if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { RxPermissions(this) @@ -174,6 +172,7 @@ class MainActivity : BaseActivity(), NavigationView.OnNavigationItemSelectedList } } mainViewModel.startListenBroadcast() + mainViewModel.copyAssets(assets) } private fun initGroupTab() { @@ -201,7 +200,7 @@ class MainActivity : BaseActivity(), NavigationView.OnNavigationItemSelectedList fun startV2Ray() { if (isNetworkConnected) { - if (mainStorage?.decodeString(MmkvManager.KEY_SELECTED_SERVER).isNullOrEmpty()) { + if (MmkvManager.mainStorage?.decodeString(MmkvManager.KEY_SELECTED_SERVER).isNullOrEmpty()) { return } V2RayServiceManager.startV2Ray(this) @@ -215,10 +214,10 @@ class MainActivity : BaseActivity(), NavigationView.OnNavigationItemSelectedList Utils.stopVService(this) } Observable.timer(500, TimeUnit.MILLISECONDS) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe { - startV2Ray() - } + .observeOn(AndroidSchedulers.mainThread()) + .subscribe { + startV2Ray() + } } public override fun onResume() { @@ -232,7 +231,25 @@ class MainActivity : BaseActivity(), NavigationView.OnNavigationItemSelectedList override fun onCreateOptionsMenu(menu: Menu): Boolean { menuInflater.inflate(R.menu.menu_main, menu) - return true + + val searchItem = menu.findItem(R.id.search_view) + if (searchItem != null) { + val searchView = searchItem.actionView as SearchView + searchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener { + override fun onQueryTextSubmit(query: String?): Boolean { + mainViewModel.filterConfig(query.orEmpty()) + return false + } + + override fun onQueryTextChange(newText: String?): Boolean = false + }) + + searchView.setOnCloseListener { + mainViewModel.filterConfig("") + false + } + } + return super.onCreateOptionsMenu(menu) } override fun onOptionsItemSelected(item: MenuItem) = when (item.itemId) { @@ -240,46 +257,57 @@ class MainActivity : BaseActivity(), NavigationView.OnNavigationItemSelectedList importQRcode(true) true } + R.id.import_clipboard -> { importClipboard() true } + R.id.import_manually_vmess -> { importManually(EConfigType.VMESS.value) true } + R.id.import_manually_vless -> { importManually(EConfigType.VLESS.value) true } + R.id.import_manually_ss -> { importManually(EConfigType.SHADOWSOCKS.value) true } + R.id.import_manually_socks -> { importManually(EConfigType.SOCKS.value) true } + R.id.import_manually_trojan -> { importManually(EConfigType.TROJAN.value) true } + R.id.import_manually_wireguard -> { importManually(EConfigType.WIREGUARD.value) true } + R.id.import_config_custom_clipboard -> { importConfigCustomClipboard() true } + R.id.import_config_custom_local -> { importConfigCustomLocal() true } + R.id.import_config_custom_url -> { importConfigCustomUrlClipboard() true } + R.id.import_config_custom_url_scan -> { importQRcode(false) true @@ -291,11 +319,18 @@ class MainActivity : BaseActivity(), NavigationView.OnNavigationItemSelectedList } R.id.export_all -> { - if (AngConfigManager.shareNonCustomConfigsToClipboard(this, mainViewModel.serverList) == 0) { - toast(R.string.toast_success) - } else { - toast(R.string.toast_failure) + binding.pbWaiting.show() + lifecycleScope.launch(Dispatchers.IO) { + val ret = mainViewModel.exportAllServer() + launch(Dispatchers.Main) { + if (ret == 0) + toast(R.string.toast_success) + else + toast(R.string.toast_failure) + binding.pbWaiting.hide() + } } + true } @@ -315,49 +350,79 @@ class MainActivity : BaseActivity(), NavigationView.OnNavigationItemSelectedList } R.id.del_all_config -> { - AlertDialog.Builder(this).setMessage(R.string.del_config_comfirm) - .setPositiveButton(android.R.string.ok) { _, _ -> - MmkvManager.removeAllServer() - mainViewModel.reloadServerList() - } - .setNegativeButton(android.R.string.no) {_, _ -> - //do noting - } - .show() - true - } - R.id.del_duplicate_config-> { AlertDialog.Builder(this).setMessage(R.string.del_config_comfirm) .setPositiveButton(android.R.string.ok) { _, _ -> - mainViewModel.removeDuplicateServer() + binding.pbWaiting.show() + lifecycleScope.launch(Dispatchers.IO) { + mainViewModel.removeAllServer() + launch(Dispatchers.Main) { + mainViewModel.reloadServerList() + binding.pbWaiting.hide() + } + } } - .setNegativeButton(android.R.string.no) {_, _ -> + .setNegativeButton(android.R.string.no) { _, _ -> //do noting } .show() true } + + R.id.del_duplicate_config -> { + AlertDialog.Builder(this).setMessage(R.string.del_config_comfirm) + .setPositiveButton(android.R.string.ok) { _, _ -> + binding.pbWaiting.show() + lifecycleScope.launch(Dispatchers.IO) { + val ret = mainViewModel.removeDuplicateServer() + launch(Dispatchers.Main) { + mainViewModel.reloadServerList() + toast(getString(R.string.title_del_duplicate_config_count, ret)) + binding.pbWaiting.hide() + } + } + } + .setNegativeButton(android.R.string.no) { _, _ -> + //do noting + } + .show() + true + } + R.id.del_invalid_config -> { AlertDialog.Builder(this).setMessage(R.string.del_config_comfirm) .setPositiveButton(android.R.string.ok) { _, _ -> - MmkvManager.removeInvalidServer() - mainViewModel.reloadServerList() + binding.pbWaiting.show() + lifecycleScope.launch(Dispatchers.IO) { + mainViewModel.removeInvalidServer() + launch(Dispatchers.Main) { + mainViewModel.reloadServerList() + binding.pbWaiting.hide() + } + } } - .setNegativeButton(android.R.string.no) {_, _ -> + .setNegativeButton(android.R.string.no) { _, _ -> //do noting } .show() true } + R.id.sort_by_test_results -> { - MmkvManager.sortByTestResults() - mainViewModel.reloadServerList() + binding.pbWaiting.show() + lifecycleScope.launch(Dispatchers.IO) { + mainViewModel.sortByTestResults() + launch(Dispatchers.Main) { + mainViewModel.reloadServerList() + binding.pbWaiting.hide() + } + } true } + else -> super.onOptionsItemSelected(item) } - private fun importManually(createConfigType : Int) { + private fun importManually(createConfigType: Int) { startActivity( Intent() .putExtra("createConfigType", createConfigType) @@ -376,16 +441,16 @@ class MainActivity : BaseActivity(), NavigationView.OnNavigationItemSelectedList // .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP), requestCode) // } catch (e: Exception) { RxPermissions(this) - .request(Manifest.permission.CAMERA) - .subscribe { - if (it) - if (forConfig) - scanQRCodeForConfig.launch(Intent(this, ScannerActivity::class.java)) - else - scanQRCodeForUrlToCustomConfig.launch(Intent(this, ScannerActivity::class.java)) + .request(Manifest.permission.CAMERA) + .subscribe { + if (it) + if (forConfig) + scanQRCodeForConfig.launch(Intent(this, ScannerActivity::class.java)) else - toast(R.string.toast_permission_denied) - } + scanQRCodeForUrlToCustomConfig.launch(Intent(this, ScannerActivity::class.java)) + else + toast(R.string.toast_permission_denied) + } // } return true } @@ -439,7 +504,7 @@ class MainActivity : BaseActivity(), NavigationView.OnNavigationItemSelectedList //dialog.dismiss() binding.pbWaiting.hide() } - } + } } private fun importConfigCustomClipboard() @@ -516,7 +581,7 @@ class MainActivity : BaseActivity(), NavigationView.OnNavigationItemSelectedList /** * import config from sub */ - private fun importConfigViaSub() : Boolean { + private fun importConfigViaSub(): Boolean { // val dialog = AlertDialog.Builder(this) // .setView(LayoutProgressBinding.inflate(layoutInflater).root) // .setCancelable(false) @@ -524,7 +589,7 @@ class MainActivity : BaseActivity(), NavigationView.OnNavigationItemSelectedList binding.pbWaiting.show() lifecycleScope.launch(Dispatchers.IO) { - val count = AngConfigManager.updateConfigViaSubAll() + val count = mainViewModel.updateConfigViaSubAll() delay(500L) launch(Dispatchers.Main) { if (count > 0) { @@ -572,19 +637,19 @@ class MainActivity : BaseActivity(), NavigationView.OnNavigationItemSelectedList Manifest.permission.READ_EXTERNAL_STORAGE } RxPermissions(this) - .request(permission) - .subscribe { - if (it) { - try { - contentResolver.openInputStream(uri).use { input -> - importCustomizeConfig(input?.bufferedReader()?.readText()) - } - } catch (e: Exception) { - e.printStackTrace() + .request(permission) + .subscribe { + if (it) { + try { + contentResolver.openInputStream(uri).use { input -> + importCustomizeConfig(input?.bufferedReader()?.readText()) } - } else - toast(R.string.toast_permission_denied) - } + } catch (e: Exception) { + e.printStackTrace() + } + } else + toast(R.string.toast_permission_denied) + } } /** @@ -632,27 +697,33 @@ class MainActivity : BaseActivity(), NavigationView.OnNavigationItemSelectedList } - override fun onNavigationItemSelected(item: MenuItem): Boolean { // Handle navigation view item clicks here. when (item.itemId) { R.id.sub_setting -> { - requestSubSettingActivity.launch(Intent(this,SubSettingActivity::class.java)) + requestSubSettingActivity.launch(Intent(this, SubSettingActivity::class.java)) } + R.id.settings -> { - startActivity(Intent(this, SettingsActivity::class.java) - .putExtra("isRunning", mainViewModel.isRunning.value == true)) + startActivity( + Intent(this, SettingsActivity::class.java) + .putExtra("isRunning", mainViewModel.isRunning.value == true) + ) } + R.id.user_asset_setting -> { startActivity(Intent(this, UserAssetActivity::class.java)) } + R.id.promotion -> { Utils.openUri(this, "${Utils.decode(AppConfig.PromotionUrl)}?t=${System.currentTimeMillis()}") } + R.id.logcat -> { startActivity(Intent(this, LogcatActivity::class.java)) } - R.id.about-> { + + R.id.about -> { startActivity(Intent(this, AboutActivity::class.java)) } } diff --git a/v2rayng/V2rayNG/app/src/main/kotlin/com/v2ray/ang/ui/MainRecyclerAdapter.kt b/v2rayng/V2rayNG/app/src/main/kotlin/com/v2ray/ang/ui/MainRecyclerAdapter.kt index cc9a062f3f..b1e8911259 100644 --- a/v2rayng/V2rayNG/app/src/main/kotlin/com/v2ray/ang/ui/MainRecyclerAdapter.kt +++ b/v2rayng/V2rayNG/app/src/main/kotlin/com/v2ray/ang/ui/MainRecyclerAdapter.kt @@ -10,7 +10,6 @@ import androidx.appcompat.app.AlertDialog import androidx.core.content.ContextCompat import androidx.recyclerview.widget.RecyclerView import com.google.gson.Gson -import com.tencent.mmkv.MMKV import com.v2ray.ang.AngApplication.Companion.application import com.v2ray.ang.AppConfig import com.v2ray.ang.R @@ -38,9 +37,6 @@ class MainRecyclerAdapter(val activity: MainActivity) : RecyclerView.Adapter by lazy { mActivity.resources.getStringArray(R.array.share_method) } @@ -71,13 +67,13 @@ class MainRecyclerAdapter(val activity: MainActivity) : RecyclerView.Adapter { holder.itemMainBinding.tvType.text = profile.configType.name } + else -> { holder.itemMainBinding.tvType.text = profile.configType.name.lowercase() } @@ -114,6 +112,7 @@ class MainRecyclerAdapter(val activity: MainActivity) : RecyclerView.Adapter { if (AngConfigManager.share2Clipboard(mActivity, guid) == 0) { mActivity.toast(R.string.toast_success) @@ -121,6 +120,7 @@ class MainRecyclerAdapter(val activity: MainActivity) : RecyclerView.Adapter shareFullContent(guid) else -> mActivity.toast("else") } @@ -132,7 +132,7 @@ class MainRecyclerAdapter(val activity: MainActivity) : RecyclerView.Adapter removeServer(guid, position) } - .setNegativeButton(android.R.string.no) {_, _ -> + .setNegativeButton(android.R.string.no) { _, _ -> //do noting } .show() @@ -159,9 +159,9 @@ class MainRecyclerAdapter(val activity: MainActivity) : RecyclerView.Adapter MainViewHolder(ItemRecyclerMainBinding.inflate(LayoutInflater.from(parent.context), parent, false)) + else -> FooterViewHolder(ItemRecyclerFooterBinding.inflate(LayoutInflater.from(parent.context), parent, false)) } @@ -231,14 +232,14 @@ class MainRecyclerAdapter(val activity: MainActivity) : RecyclerView.Adapter - MmkvManager.removeSubscription(editSubId) - finish() + lifecycleScope.launch(Dispatchers.IO) { + MmkvManager.removeSubscription(editSubId) + launch(Dispatchers.Main) { + finish() + } + } } .setNegativeButton(android.R.string.no) {_, _ -> // do nothing diff --git a/v2rayng/V2rayNG/app/src/main/kotlin/com/v2ray/ang/ui/UrlSchemeActivity.kt b/v2rayng/V2rayNG/app/src/main/kotlin/com/v2ray/ang/ui/UrlSchemeActivity.kt index c7b71e5980..83cc4a76ac 100644 --- a/v2rayng/V2rayNG/app/src/main/kotlin/com/v2ray/ang/ui/UrlSchemeActivity.kt +++ b/v2rayng/V2rayNG/app/src/main/kotlin/com/v2ray/ang/ui/UrlSchemeActivity.kt @@ -22,7 +22,7 @@ class UrlSchemeActivity : BaseActivity() { if (action == Intent.ACTION_SEND) { if ("text/plain" == type) { intent.getStringExtra(Intent.EXTRA_TEXT)?.let { - parseUri(it) + parseUri(it, null) } } } else if (action == Intent.ACTION_VIEW) { @@ -30,13 +30,13 @@ class UrlSchemeActivity : BaseActivity() { "install-config" -> { val uri: Uri? = intent.data val shareUrl = uri?.getQueryParameter("url") ?: "" - parseUri(shareUrl) + parseUri(shareUrl, uri?.fragment) } "install-sub" -> { val uri: Uri? = intent.data val shareUrl = uri?.getQueryParameter("url") ?: "" - parseUri(shareUrl) + parseUri(shareUrl, uri?.fragment) } else -> { @@ -53,15 +53,19 @@ class UrlSchemeActivity : BaseActivity() { } } - private fun parseUri(uriString: String?) { + private fun parseUri(uriString: String?, fragment: String?) { if (uriString.isNullOrEmpty()) { return } Log.d("UrlScheme", uriString) - val decodedUrl = URLDecoder.decode(uriString, "UTF-8") + var decodedUrl = URLDecoder.decode(uriString, "UTF-8") val uri = Uri.parse(decodedUrl) if (uri != null) { + if (uri.fragment.isNullOrEmpty() && !fragment.isNullOrEmpty()) { + decodedUrl += "#${fragment}" + } + Log.d("UrlScheme-decodedUrl", decodedUrl) val (count, countSub) = AngConfigManager.importBatchConfig(decodedUrl, "", false) if (count + countSub > 0) { toast(R.string.import_subscription_success) diff --git a/v2rayng/V2rayNG/app/src/main/kotlin/com/v2ray/ang/util/AngConfigManager.kt b/v2rayng/V2rayNG/app/src/main/kotlin/com/v2ray/ang/util/AngConfigManager.kt index 0b60190a38..60317225c6 100644 --- a/v2rayng/V2rayNG/app/src/main/kotlin/com/v2ray/ang/util/AngConfigManager.kt +++ b/v2rayng/V2rayNG/app/src/main/kotlin/com/v2ray/ang/util/AngConfigManager.kt @@ -535,7 +535,7 @@ object AngConfigManager { return count } - private fun updateConfigViaSub(it: Pair): Int { + fun updateConfigViaSub(it: Pair): Int { try { if (TextUtils.isEmpty(it.first) || TextUtils.isEmpty(it.second.remarks) diff --git a/v2rayng/V2rayNG/app/src/main/kotlin/com/v2ray/ang/util/MmkvManager.kt b/v2rayng/V2rayNG/app/src/main/kotlin/com/v2ray/ang/util/MmkvManager.kt index b81c56fa0b..c04bdfc36a 100644 --- a/v2rayng/V2rayNG/app/src/main/kotlin/com/v2ray/ang/util/MmkvManager.kt +++ b/v2rayng/V2rayNG/app/src/main/kotlin/com/v2ray/ang/util/MmkvManager.kt @@ -21,12 +21,14 @@ object MmkvManager { const val KEY_SELECTED_SERVER = "SELECTED_SERVER" const val KEY_ANG_CONFIGS = "ANG_CONFIGS" - private val mainStorage by lazy { MMKV.mmkvWithID(ID_MAIN, MMKV.MULTI_PROCESS_MODE) } + val mainStorage by lazy { MMKV.mmkvWithID(ID_MAIN, MMKV.MULTI_PROCESS_MODE) } + val settingsStorage by lazy { MMKV.mmkvWithID(ID_SETTING, MMKV.MULTI_PROCESS_MODE) } private val serverStorage by lazy { MMKV.mmkvWithID(ID_SERVER_CONFIG, MMKV.MULTI_PROCESS_MODE) } private val profileStorage by lazy { MMKV.mmkvWithID(ID_PROFILE_CONFIG, MMKV.MULTI_PROCESS_MODE) } private val serverAffStorage by lazy { MMKV.mmkvWithID(ID_SERVER_AFF, MMKV.MULTI_PROCESS_MODE) } - private val subStorage by lazy { MMKV.mmkvWithID(ID_SUB, MMKV.MULTI_PROCESS_MODE) } + val subStorage by lazy { MMKV.mmkvWithID(ID_SUB, MMKV.MULTI_PROCESS_MODE) } private val assetStorage by lazy { MMKV.mmkvWithID(ID_ASSET, MMKV.MULTI_PROCESS_MODE) } + val serverRawStorage by lazy { MMKV.mmkvWithID(ID_SERVER_RAW, MMKV.MULTI_PROCESS_MODE) } fun decodeServerList(): MutableList { val json = mainStorage?.decodeString(KEY_ANG_CONFIGS) @@ -147,7 +149,7 @@ object MmkvManager { } val uri = URI(Utils.fixIllegalUrl(url)) val subItem = SubscriptionItem() - subItem.remarks = Utils.urlDecode(uri.fragment ?: "import sub") + subItem.remarks = uri.fragment ?: "import sub" subItem.url = url subStorage?.encode(Utils.getUuid(), Gson().toJson(subItem)) return 1 @@ -191,11 +193,19 @@ object MmkvManager { serverAffStorage?.clearAll() } - fun removeInvalidServer() { - serverAffStorage?.allKeys()?.forEach { key -> - decodeServerAffiliationInfo(key)?.let { aff -> + fun removeInvalidServer(guid: String) { + if (guid.isNotEmpty()) { + decodeServerAffiliationInfo(guid)?.let { aff -> if (aff.testDelayMillis < 0L) { - removeServer(key) + removeServer(guid) + } + } + } else { + serverAffStorage?.allKeys()?.forEach { key -> + decodeServerAffiliationInfo(key)?.let { aff -> + if (aff.testDelayMillis < 0L) { + removeServer(key) + } } } } diff --git a/v2rayng/V2rayNG/app/src/main/kotlin/com/v2ray/ang/viewmodel/MainViewModel.kt b/v2rayng/V2rayNG/app/src/main/kotlin/com/v2ray/ang/viewmodel/MainViewModel.kt index d0d4e589de..98700451fa 100644 --- a/v2rayng/V2rayNG/app/src/main/kotlin/com/v2ray/ang/viewmodel/MainViewModel.kt +++ b/v2rayng/V2rayNG/app/src/main/kotlin/com/v2ray/ang/viewmodel/MainViewModel.kt @@ -12,7 +12,6 @@ import androidx.lifecycle.AndroidViewModel import androidx.lifecycle.MutableLiveData import androidx.lifecycle.viewModelScope import com.google.gson.Gson -import com.tencent.mmkv.MMKV import com.v2ray.ang.AngApplication import com.v2ray.ang.AppConfig import com.v2ray.ang.AppConfig.ANG_PACKAGE @@ -21,11 +20,15 @@ import com.v2ray.ang.dto.EConfigType import com.v2ray.ang.dto.ProfileItem import com.v2ray.ang.dto.ServerConfig import com.v2ray.ang.dto.ServersCache +import com.v2ray.ang.dto.SubscriptionItem import com.v2ray.ang.dto.V2rayConfig import com.v2ray.ang.extension.toast +import com.v2ray.ang.util.AngConfigManager +import com.v2ray.ang.util.AngConfigManager.updateConfigViaSub import com.v2ray.ang.util.MessageUtil import com.v2ray.ang.util.MmkvManager import com.v2ray.ang.util.MmkvManager.KEY_ANG_CONFIGS +import com.v2ray.ang.util.MmkvManager.subStorage import com.v2ray.ang.util.SpeedtestUtil import com.v2ray.ang.util.Utils import com.v2ray.ang.util.V2rayConfigUtil @@ -39,34 +42,15 @@ import java.io.FileOutputStream import java.util.Collections class MainViewModel(application: Application) : AndroidViewModel(application) { - private val mainStorage by lazy { - MMKV.mmkvWithID( - MmkvManager.ID_MAIN, - MMKV.MULTI_PROCESS_MODE - ) - } - private val serverRawStorage by lazy { - MMKV.mmkvWithID( - MmkvManager.ID_SERVER_RAW, - MMKV.MULTI_PROCESS_MODE - ) - } - private val settingsStorage by lazy { - MMKV.mmkvWithID( - MmkvManager.ID_SETTING, - MMKV.MULTI_PROCESS_MODE - ) - } + private var serverList = MmkvManager.decodeServerList() + var subscriptionId: String = MmkvManager.settingsStorage.decodeString(AppConfig.CACHE_SUBSCRIPTION_ID, "") ?: "" - var serverList = MmkvManager.decodeServerList() - var subscriptionId: String = settingsStorage.decodeString(AppConfig.CACHE_SUBSCRIPTION_ID, "")?:"" - //var keywordFilter: String = settingsStorage.decodeString(AppConfig.CACHE_KEYWORD_FILTER, "")?:"" - private set + //var keywordFilter: String = MmkvManager.settingsStorage.decodeString(AppConfig.CACHE_KEYWORD_FILTER, "")?:"" + private var keywordFilter = "" val serversCache = mutableListOf() val isRunning by lazy { MutableLiveData() } val updateListAction by lazy { MutableLiveData() } val updateTestResultAction by lazy { MutableLiveData() } - private val tcpingTestScope by lazy { CoroutineScope(Dispatchers.IO) } fun startListenBroadcast() { @@ -120,7 +104,7 @@ class MainViewModel(application: Application) : AndroidViewModel(application) { config.fullConfig = Gson().fromJson(server, V2rayConfig::class.java) config.remarks = config.fullConfig?.remarks ?: System.currentTimeMillis().toString() val key = MmkvManager.encodeServerConfig("", config) - serverRawStorage?.encode(key, server) + MmkvManager.serverRawStorage?.encode(key, server) serverList.add(0, key) val profile = ProfileItem( configType = config.configType, @@ -141,7 +125,7 @@ class MainViewModel(application: Application) : AndroidViewModel(application) { fun swapServer(fromPosition: Int, toPosition: Int) { Collections.swap(serverList, fromPosition, toPosition) Collections.swap(serversCache, fromPosition, toPosition) - mainStorage?.encode(KEY_ANG_CONFIGS, Gson().toJson(serverList)) + MmkvManager.mainStorage?.encode(KEY_ANG_CONFIGS, Gson().toJson(serverList)) } @Synchronized @@ -165,11 +149,41 @@ class MainViewModel(application: Application) : AndroidViewModel(application) { continue } -// if (keywordFilter.isEmpty() || config.remarks.contains(keywordFilter)) { - serversCache.add(ServersCache(guid, profile)) + if (keywordFilter.isEmpty() || profile.remarks.contains(keywordFilter)) { + serversCache.add(ServersCache(guid, profile)) + } } } + fun updateConfigViaSubAll(): Int { + if (subscriptionId.isNullOrEmpty()) { + return AngConfigManager.updateConfigViaSubAll() + } else { + val json = subStorage?.decodeString(subscriptionId) + if (!json.isNullOrBlank()) { + return updateConfigViaSub(Pair(subscriptionId, Gson().fromJson(json, SubscriptionItem::class.java))) + } else { + return 0 + } + } + } + + fun exportAllServer(): Int { + val serverListCopy = + if (subscriptionId.isNullOrEmpty()) { + serverList + } else { + serversCache.map { it.guid }.toList() + } + + val ret = AngConfigManager.shareNonCustomConfigsToClipboard( + getApplication(), + serverListCopy + ) + return ret + } + + fun testAllTcping() { tcpingTestScope.coroutineContext[Job]?.cancelChildren() SpeedtestUtil.closeAllTcpSockets() @@ -223,12 +237,12 @@ class MainViewModel(application: Application) : AndroidViewModel(application) { fun subscriptionIdChanged(id: String) { if (subscriptionId != id) { subscriptionId = id - settingsStorage.encode(AppConfig.CACHE_SUBSCRIPTION_ID, subscriptionId) + MmkvManager.settingsStorage.encode(AppConfig.CACHE_SUBSCRIPTION_ID, subscriptionId) reloadServerList() } } - fun getSubscriptions(context: Context) : Pair?, MutableList?> { + fun getSubscriptions(context: Context): Pair?, MutableList?> { val subscriptions = MmkvManager.decodeSubscriptions() if (subscriptionId.isNotEmpty() && !subscriptions.map { it.first }.contains(subscriptionId) @@ -254,36 +268,59 @@ class MainViewModel(application: Application) : AndroidViewModel(application) { return -1 } - fun removeDuplicateServer() { - viewModelScope.launch(Dispatchers.Default) { - val deleteServer = mutableListOf() - serversCache.forEachIndexed { index, it -> - val outbound = MmkvManager.decodeServerConfig(it.guid)?.getProxyOutbound() - serversCache.forEachIndexed { index2, it2 -> - if (index2 > index) { - val outbound2 = MmkvManager.decodeServerConfig(it2.guid)?.getProxyOutbound() - if (outbound == outbound2 && !deleteServer.contains(it2.guid)) { - deleteServer.add(it2.guid) - } + fun removeDuplicateServer(): Int { + val serversCacheCopy = mutableListOf>() + for (it in serversCache) { + val config = MmkvManager.decodeServerConfig(it.guid) ?: continue + serversCacheCopy.add(Pair(it.guid, config)) + } + + val deleteServer = mutableListOf() + serversCacheCopy.forEachIndexed { index, it -> + val outbound = it.second.getProxyOutbound() + serversCacheCopy.forEachIndexed { index2, it2 -> + if (index2 > index) { + val outbound2 = it2.second.getProxyOutbound() + if (outbound == outbound2 && !deleteServer.contains(it2.first)) { + deleteServer.add(it2.first) } } } - for (it in deleteServer) { - MmkvManager.removeServer(it) - } - launch(Dispatchers.Main) { - reloadServerList() - getApplication().toast( - getApplication().getString( - R.string.title_del_duplicate_config_count, - deleteServer.count() - ) - ) - } + } + for (it in deleteServer) { + MmkvManager.removeServer(it) + } + return deleteServer.count() + } + + fun removeAllServer() { + if (subscriptionId.isNullOrEmpty()) { + MmkvManager.removeAllServer() + } else { + val serversCopy = serversCache.toList() + for (item in serversCopy) { + MmkvManager.removeServer(item.guid) + } } } + fun removeInvalidServer() { + if (subscriptionId.isNullOrEmpty()) { + MmkvManager.removeInvalidServer("") + } else { + val serversCopy = serversCache.toList() + for (item in serversCopy) { + MmkvManager.removeInvalidServer(item.guid) + } + } + } + + fun sortByTestResults() { + MmkvManager.sortByTestResults() + } + + fun copyAssets(assets: AssetManager) { val extFolder = Utils.userAssetPath(getApplication()) viewModelScope.launch(Dispatchers.Default) { @@ -310,6 +347,12 @@ class MainViewModel(application: Application) : AndroidViewModel(application) { } } + fun filterConfig(keyword: String) { + keywordFilter = keyword + MmkvManager.settingsStorage.encode(AppConfig.CACHE_KEYWORD_FILTER, keywordFilter) + reloadServerList() + } + private val mMsgReceiver = object : BroadcastReceiver() { override fun onReceive(ctx: Context?, intent: Intent?) { when (intent?.getIntExtra("key", 0)) { @@ -347,4 +390,4 @@ class MainViewModel(application: Application) : AndroidViewModel(application) { } } } -} +} \ No newline at end of file diff --git a/v2rayng/V2rayNG/app/src/main/res/menu/menu_main.xml b/v2rayng/V2rayNG/app/src/main/res/menu/menu_main.xml index 0db2486925..8edaf8a102 100644 --- a/v2rayng/V2rayNG/app/src/main/res/menu/menu_main.xml +++ b/v2rayng/V2rayNG/app/src/main/res/menu/menu_main.xml @@ -1,6 +1,12 @@ + ; + using _SmartPtr = __pointer_of_or_t<_Smart, _Pointer>; if constexpr (is_pointer_v<_Smart>) { - std::apply([&](auto&&... __args) { __s_ = _Smart(static_cast<_SP>(__p_), std::forward<_Args>(__args)...); }, + std::apply([&](auto&&... __args) { __s_ = _Smart(static_cast<_SmartPtr>(__p_), std::forward<_Args>(__args)...); }, std::move(__a_)); } else if constexpr (__resettable_smart_pointer_with_args<_Smart, _Pointer, _Args...>) { - std::apply([&](auto&&... __args) { __s_.reset(static_cast<_SP>(__p_), std::forward<_Args>(__args)...); }, + std::apply([&](auto&&... __args) { __s_.reset(static_cast<_SmartPtr>(__p_), std::forward<_Args>(__args)...); }, std::move(__a_)); } else { - static_assert(is_constructible_v<_Smart, _SP, _Args...>, + static_assert(is_constructible_v<_Smart, _SmartPtr, _Args...>, "The smart pointer must be constructible from arguments of types _Smart, _Pointer, _Args..."); - std::apply([&](auto&&... __args) { __s_ = _Smart(static_cast<_SP>(__p_), std::forward<_Args>(__args)...); }, + std::apply([&](auto&&... __args) { __s_ = _Smart(static_cast<_SmartPtr>(__p_), std::forward<_Args>(__args)...); }, std::move(__a_)); } } diff --git a/yass/third_party/libc++/trunk/include/__memory/out_ptr.h b/yass/third_party/libc++/trunk/include/__memory/out_ptr.h index 95aa2029c9..fd99110790 100644 --- a/yass/third_party/libc++/trunk/include/__memory/out_ptr.h +++ b/yass/third_party/libc++/trunk/include/__memory/out_ptr.h @@ -58,14 +58,14 @@ public: return; } - using _SP = __pointer_of_or_t<_Smart, _Pointer>; + using _SmartPtr = __pointer_of_or_t<_Smart, _Pointer>; if constexpr (__resettable_smart_pointer_with_args<_Smart, _Pointer, _Args...>) { - std::apply([&](auto&&... __args) { __s_.reset(static_cast<_SP>(__p_), std::forward<_Args>(__args)...); }, + std::apply([&](auto&&... __args) { __s_.reset(static_cast<_SmartPtr>(__p_), std::forward<_Args>(__args)...); }, std::move(__a_)); } else { - static_assert(is_constructible_v<_Smart, _SP, _Args...>, + static_assert(is_constructible_v<_Smart, _SmartPtr, _Args...>, "The smart pointer must be constructible from arguments of types _Smart, _Pointer, _Args..."); - std::apply([&](auto&&... __args) { __s_ = _Smart(static_cast<_SP>(__p_), std::forward<_Args>(__args)...); }, + std::apply([&](auto&&... __args) { __s_ = _Smart(static_cast<_SmartPtr>(__p_), std::forward<_Args>(__args)...); }, std::move(__a_)); } } diff --git a/yass/third_party/libc++/trunk/test/libcxx/gdb/gdb_pretty_printer_test.sh.cpp b/yass/third_party/libc++/trunk/test/libcxx/gdb/gdb_pretty_printer_test.sh.cpp index 4c2b483914..2c8534977f 100644 --- a/yass/third_party/libc++/trunk/test/libcxx/gdb/gdb_pretty_printer_test.sh.cpp +++ b/yass/third_party/libc++/trunk/test/libcxx/gdb/gdb_pretty_printer_test.sh.cpp @@ -20,6 +20,9 @@ // support gdb anymore, favoring lldb instead. // UNSUPPORTED: android +// This test doesn't work as such on Windows. +// UNSUPPORTED: windows + // RUN: %{cxx} %{flags} %s -o %t.exe %{compile_flags} -g %{link_flags} // Ensure locale-independence for unicode tests. // RUN: env LANG=en_US.UTF-8 %{gdb} -nx -batch -iex "set autoload off" -ex "source %S/../../../utils/gdb/libcxx/printers.py" -ex "python register_libcxx_printer_loader()" -ex "source %S/gdb_pretty_printer_test.py" %t.exe diff --git a/yass/third_party/libc++/trunk/test/libcxx/system_reserved_names.gen.py b/yass/third_party/libc++/trunk/test/libcxx/system_reserved_names.gen.py index 0d935a18ad..956a8d1abe 100644 --- a/yass/third_party/libc++/trunk/test/libcxx/system_reserved_names.gen.py +++ b/yass/third_party/libc++/trunk/test/libcxx/system_reserved_names.gen.py @@ -17,7 +17,8 @@ sys.path.append(sys.argv[1]) from libcxx.header_information import lit_header_restrictions, public_headers for header in public_headers: - print(f"""\ + print( + f"""\ //--- {header}.compile.pass.cpp {lit_header_restrictions.get(header, '')} @@ -162,6 +163,18 @@ for header in public_headers: #define erase SYSTEM_RESERVED_NAME #define refresh SYSTEM_RESERVED_NAME +// Dinkumware libc ctype.h uses these definitions +#define _XA SYSTEM_RESERVED_NAME +#define _XS SYSTEM_RESERVED_NAME +#define _BB SYSTEM_RESERVED_NAME +#define _CN SYSTEM_RESERVED_NAME +#define _DI SYSTEM_RESERVED_NAME +#define _LO SYSTEM_RESERVED_NAME +#define _PU SYSTEM_RESERVED_NAME +#define _SP SYSTEM_RESERVED_NAME +#define _UP SYSTEM_RESERVED_NAME +#define _XD SYSTEM_RESERVED_NAME + #include <{header}> // Make sure we don't swallow the definition of the macros we push/pop @@ -172,4 +185,5 @@ static_assert(__builtin_strcmp(STRINGIFY(max), STRINGIFY(SYSTEM_RESERVED_NAME)) static_assert(__builtin_strcmp(STRINGIFY(move), STRINGIFY(SYSTEM_RESERVED_NAME)) == 0, ""); static_assert(__builtin_strcmp(STRINGIFY(erase), STRINGIFY(SYSTEM_RESERVED_NAME)) == 0, ""); static_assert(__builtin_strcmp(STRINGIFY(refresh), STRINGIFY(SYSTEM_RESERVED_NAME)) == 0, ""); -""") +""" + ) diff --git a/yass/third_party/libc++/trunk/test/support/count_new.h b/yass/third_party/libc++/trunk/test/support/count_new.h index 0a95e05b72..2298c4fd63 100644 --- a/yass/third_party/libc++/trunk/test/support/count_new.h +++ b/yass/third_party/libc++/trunk/test/support/count_new.h @@ -455,7 +455,7 @@ void operator delete[](void* p, std::nothrow_t const&) TEST_NOEXCEPT { # define USE_ALIGNED_ALLOC # endif -inline void* alocate_aligned_impl(std::size_t size, std::align_val_t align) { +inline void* allocate_aligned_impl(std::size_t size, std::align_val_t align) { const std::size_t alignment = static_cast(align); void* ret = nullptr; # ifdef USE_ALIGNED_ALLOC @@ -479,7 +479,7 @@ inline void free_aligned_impl(void* ptr, std::align_val_t) { // operator new(size_t, align_val_t[, nothrow_t]) and operator delete(size_t, align_val_t[, nothrow_t]) void* operator new(std::size_t s, std::align_val_t av) TEST_THROW_SPEC(std::bad_alloc) { getGlobalMemCounter()->alignedNewCalled(s, static_cast(av)); - void* p = alocate_aligned_impl(s, av); + void* p = allocate_aligned_impl(s, av); if (p == nullptr) detail::throw_bad_alloc_helper(); return p; @@ -495,7 +495,7 @@ void* operator new(std::size_t s, std::align_val_t av, std::nothrow_t const&) TE return nullptr; } # endif - return alocate_aligned_impl(s, av); + return allocate_aligned_impl(s, av); } void operator delete(void* p, std::align_val_t av) TEST_NOEXCEPT { @@ -511,7 +511,7 @@ void operator delete(void* p, std::align_val_t av, std::nothrow_t const&) TEST_N // operator new[](size_t, align_val_t[, nothrow_t]) and operator delete[](size_t, align_val_t[, nothrow_t]) void* operator new[](std::size_t s, std::align_val_t av) TEST_THROW_SPEC(std::bad_alloc) { getGlobalMemCounter()->alignedNewArrayCalled(s, static_cast(av)); - void* p = alocate_aligned_impl(s, av); + void* p = allocate_aligned_impl(s, av); if (p == nullptr) detail::throw_bad_alloc_helper(); return p; @@ -527,7 +527,7 @@ void* operator new[](std::size_t s, std::align_val_t av, std::nothrow_t const&) return nullptr; } # endif - return alocate_aligned_impl(s, av); + return allocate_aligned_impl(s, av); } void operator delete[](void* p, std::align_val_t av) TEST_NOEXCEPT { diff --git a/yass/third_party/libc++/trunk/utils/synchronize_csv_status_files.py b/yass/third_party/libc++/trunk/utils/synchronize_csv_status_files.py new file mode 100755 index 0000000000..b44b02f530 --- /dev/null +++ b/yass/third_party/libc++/trunk/utils/synchronize_csv_status_files.py @@ -0,0 +1,236 @@ +#!/usr/bin/env python3 +# ===----------------------------------------------------------------------===## +# +# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +# See https://llvm.org/LICENSE.txt for license information. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +# +# ===----------------------------------------------------------------------===## + +from typing import List, Dict, Tuple, Optional +import csv +import itertools +import json +import os +import pathlib +import re +import subprocess + +# Number of the 'Libc++ Standards Conformance' project on Github +LIBCXX_CONFORMANCE_PROJECT = '31' + +class PaperInfo: + paper_number: str + """ + Identifier for the paper or the LWG issue. This must be something like 'PnnnnRx', 'Nxxxxx' or 'LWGxxxxx'. + """ + + paper_name: str + """ + Plain text string representing the name of the paper. + """ + + meeting: Optional[str] + """ + Plain text string representing the meeting at which the paper/issue was voted. + """ + + status: Optional[str] + """ + Status of the paper/issue. This must be '|Complete|', '|Nothing To Do|', '|In Progress|', + '|Partial|' or 'Resolved by '. + """ + + first_released_version: Optional[str] + """ + First version of LLVM in which this paper/issue was resolved. + """ + + labels: Optional[List[str]] + """ + List of labels to associate to the issue in the status-tracking table. Supported labels are + 'format', 'ranges', 'spaceship', 'flat_containers', 'concurrency TS' and 'DR'. + """ + + original: Optional[object] + """ + Object from which this PaperInfo originated. This is used to track the CSV row or Github issue that + was used to generate this PaperInfo and is useful for error reporting purposes. + """ + + def __init__(self, paper_number: str, paper_name: str, + meeting: Optional[str] = None, + status: Optional[str] = None, + first_released_version: Optional[str] = None, + labels: Optional[List[str]] = None, + original: Optional[object] = None): + self.paper_number = paper_number + self.paper_name = paper_name + self.meeting = meeting + self.status = status + self.first_released_version = first_released_version + self.labels = labels + self.original = original + + def for_printing(self) -> Tuple[str, str, str, str, str, str]: + return ( + f'`{self.paper_number} `__', + self.paper_name, + self.meeting if self.meeting is not None else '', + self.status if self.status is not None else '', + self.first_released_version if self.first_released_version is not None else '', + ' '.join(f'|{label}|' for label in self.labels) if self.labels is not None else '', + ) + + def __repr__(self) -> str: + return repr(self.original) if self.original is not None else repr(self.for_printing()) + + def is_implemented(self) -> bool: + if self.status is None: + return False + if re.search(r'(in progress|partial)', self.status.lower()): + return False + return True + + @staticmethod + def from_csv_row(row: Tuple[str, str, str, str, str, str]):# -> PaperInfo: + """ + Given a row from one of our status-tracking CSV files, create a PaperInfo object representing that row. + """ + # Extract the paper number from the first column + match = re.search(r"((P[0-9R]+)|(LWG[0-9]+)|(N[0-9]+))\s+", row[0]) + if match is None: + raise RuntimeError(f"Can't parse paper/issue number out of row: {row}") + + return PaperInfo( + paper_number=match.group(1), + paper_name=row[1], + meeting=row[2] or None, + status=row[3] or None, + first_released_version=row[4] or None, + labels=[l.strip('|') for l in row[5].split(' ') if l] or None, + original=row, + ) + + @staticmethod + def from_github_issue(issue: Dict):# -> PaperInfo: + """ + Create a PaperInfo object from the Github issue information obtained from querying a Github Project. + """ + # Extract the paper number from the issue title + match = re.search(r"((P[0-9R]+)|(LWG[0-9]+)|(N[0-9]+)):", issue['title']) + if match is None: + raise RuntimeError(f"Issue doesn't have a title that we know how to parse: {issue}") + paper = match.group(1) + + # Figure out the status of the paper according to the Github project information. + # + # Sadly, we can't make a finer-grained distiction about *how* the issue + # was closed (such as Nothing To Do or similar). + status = '|Complete|' if 'status' in issue and issue['status'] == 'Done' else None + + # Handle labels + valid_labels = ('format', 'ranges', 'spaceship', 'flat_containers', 'concurrency TS', 'DR') + labels = [label for label in issue['labels'] if label in valid_labels] + + return PaperInfo( + paper_number=paper, + paper_name=issue['title'], + meeting=issue.get('meeting Voted', None), + status=status, + first_released_version=None, # TODO + labels=labels if labels else None, + original=issue, + ) + +def load_csv(file: pathlib.Path) -> List[Tuple]: + rows = [] + with open(file, newline='') as f: + reader = csv.reader(f, delimiter=',') + for row in reader: + rows.append(row) + return rows + +def write_csv(output: pathlib.Path, rows: List[Tuple]): + with open(output, 'w', newline='') as f: + writer = csv.writer(f, quoting=csv.QUOTE_ALL, lineterminator='\n') + for row in rows: + writer.writerow(row) + +def sync_csv(rows: List[Tuple], from_github: List[PaperInfo]) -> List[Tuple]: + """ + Given a list of CSV rows representing an existing status file and a list of PaperInfos representing + up-to-date (but potentially incomplete) tracking information from Github, this function returns the + new CSV rows synchronized with the up-to-date information. + + Note that this only tracks changes from 'not implemented' issues to 'implemented'. If an up-to-date + PaperInfo reports that a paper is not implemented but the existing CSV rows report it as implemented, + it is an error (i.e. the result is not a CSV row where the paper is *not* implemented). + """ + results = [rows[0]] # Start with the header + for row in rows[1:]: # Skip the header + # If the row contains empty entries, this is a "separator row" between meetings. + # Preserve it as-is. + if row[0] == "": + results.append(row) + continue + + paper = PaperInfo.from_csv_row(row) + + # If the row is already implemented, basically keep it unchanged but also validate that we're not + # out-of-sync with any still-open Github issue tracking the same paper. + if paper.is_implemented(): + dangling = [gh for gh in from_github if gh.paper_number == paper.paper_number and not gh.is_implemented()] + if dangling: + raise RuntimeError(f"We found the following open tracking issues for a row which is already marked as implemented:\nrow: {row}\ntracking issues: {dangling}") + results.append(paper.for_printing()) + else: + # Find any Github issues tracking this paper + tracking = [gh for gh in from_github if paper.paper_number == gh.paper_number] + + # If there is no tracking issue for that row in the CSV, this is an error since we're + # missing a Github issue. + if not tracking: + raise RuntimeError(f"Can't find any Github issue for CSV row which isn't marked as done yet: {row}") + + # If there's more than one tracking issue, something is weird too. + if len(tracking) > 1: + raise RuntimeError(f"Found a row with more than one tracking issue: {row}\ntracked by: {tracking}") + + # If the issue is closed, synchronize the row based on the Github issue. Otherwise, use the + # existing CSV row as-is. + results.append(tracking[0].for_printing() if tracking[0].is_implemented() else row) + + return results + +CSV_FILES_TO_SYNC = [ + 'Cxx14Issues.csv', + 'Cxx17Issues.csv', + 'Cxx17Papers.csv', + 'Cxx20Issues.csv', + 'Cxx20Papers.csv', + # TODO: The Github issues are not created yet. + # 'Cxx23Issues.csv', + # 'Cxx23Papers.csv', + # 'Cxx2cIssues.csv', + # 'Cxx2cPapers.csv', +] + +def main(): + libcxx_root = pathlib.Path(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) + + # Extract the list of PaperInfos from issues we're tracking on Github. + print("Loading all issues from Github") + gh_command_line = ['gh', 'project', 'item-list', LIBCXX_CONFORMANCE_PROJECT, '--owner', 'llvm', '--format', 'json', '--limit', '9999999'] + project_info = json.loads(subprocess.check_output(gh_command_line)) + from_github = [PaperInfo.from_github_issue(i) for i in project_info['items']] + + for filename in CSV_FILES_TO_SYNC: + print(f"Synchronizing {filename} with Github issues") + file = libcxx_root / 'docs' / 'Status' / filename + csv = load_csv(file) + synced = sync_csv(csv, from_github) + write_csv(file, synced) + +if __name__ == '__main__': + main() diff --git a/yt-dlp/yt_dlp/extractor/patreon.py b/yt-dlp/yt_dlp/extractor/patreon.py index 7d6e8439c6..4489d533a6 100644 --- a/yt-dlp/yt_dlp/extractor/patreon.py +++ b/yt-dlp/yt_dlp/extractor/patreon.py @@ -420,7 +420,7 @@ class PatreonIE(PatreonBaseIE): class PatreonCampaignIE(PatreonBaseIE): - _VALID_URL = r'https?://(?:www\.)?patreon\.com/(?!rss)(?:(?:m/(?P\d+))|(?P[-\w]+))' + _VALID_URL = r'https?://(?:www\.)?patreon\.com/(?!rss)(?:(?:m|api/campaigns)/(?P\d+)|(?P[-\w]+))' _TESTS = [{ 'url': 'https://www.patreon.com/dissonancepod/', 'info_dict': { @@ -442,25 +442,44 @@ class PatreonCampaignIE(PatreonBaseIE): 'url': 'https://www.patreon.com/m/4767637/posts', 'info_dict': { 'title': 'Not Just Bikes', - 'channel_follower_count': int, 'id': '4767637', 'channel_id': '4767637', 'channel_url': 'https://www.patreon.com/notjustbikes', - 'description': 'md5:595c6e7dca76ae615b1d38c298a287a1', + 'description': 'md5:9f4b70051216c4d5c58afe580ffc8d0f', 'age_limit': 0, 'channel': 'Not Just Bikes', 'uploader_url': 'https://www.patreon.com/notjustbikes', - 'uploader': 'Not Just Bikes', + 'uploader': 'Jason', 'uploader_id': '37306634', 'thumbnail': r're:^https?://.*$', }, 'playlist_mincount': 71, + }, { + 'url': 'https://www.patreon.com/api/campaigns/4243769/posts', + 'info_dict': { + 'title': 'Second Thought', + 'channel_follower_count': int, + 'id': '4243769', + 'channel_id': '4243769', + 'channel_url': 'https://www.patreon.com/secondthought', + 'description': 'md5:69c89a3aba43efdb76e85eb023e8de8b', + 'age_limit': 0, + 'channel': 'Second Thought', + 'uploader_url': 'https://www.patreon.com/secondthought', + 'uploader': 'JT Chapman', + 'uploader_id': '32718287', + 'thumbnail': r're:^https?://.*$', + }, + 'playlist_mincount': 201, }, { 'url': 'https://www.patreon.com/dissonancepod/posts', 'only_matching': True, }, { 'url': 'https://www.patreon.com/m/5932659', 'only_matching': True, + }, { + 'url': 'https://www.patreon.com/api/campaigns/4243769', + 'only_matching': True, }] @classmethod