diff --git a/.gitignore b/.gitignore index 61dbe0cb..5bc7e4ef 100644 --- a/.gitignore +++ b/.gitignore @@ -5,5 +5,6 @@ obj node_modules /public/* /x64/* +linker.share.win TestResults \ No newline at end of file diff --git a/src/linker.ics/Program.cs b/src/linker.ics/Program.cs index 4a990d3b..e26ac87c 100644 --- a/src/linker.ics/Program.cs +++ b/src/linker.ics/Program.cs @@ -26,6 +26,7 @@ namespace linker.ics { try { + publicCon.EnableSharing(tagSHARINGCONNECTIONTYPE.ICSSHARINGTYPE_PUBLIC); } catch (Exception ex) diff --git a/src/linker.install.win/dist/linker简易安装程序.exe b/src/linker.install.win/dist/linker简易安装程序.exe deleted file mode 100644 index b09e547a..00000000 Binary files a/src/linker.install.win/dist/linker简易安装程序.exe and /dev/null differ diff --git a/src/linker.install.win/img/linker.ico b/src/linker.install.win/img/linker.ico deleted file mode 100644 index 9caec54b..00000000 Binary files a/src/linker.install.win/img/linker.ico and /dev/null differ diff --git a/src/linker.install.win/img/logo.png b/src/linker.install.win/img/logo.png deleted file mode 100644 index 6f42c567..00000000 Binary files a/src/linker.install.win/img/logo.png and /dev/null differ diff --git a/src/linker.install.win/logo.png b/src/linker.install.win/logo.png deleted file mode 100644 index 6f42c567..00000000 Binary files a/src/linker.install.win/logo.png and /dev/null differ diff --git a/src/linker.install.win/main1.0.py b/src/linker.install.win/main1.0.py deleted file mode 100644 index def073df..00000000 --- a/src/linker.install.win/main1.0.py +++ /dev/null @@ -1,199 +0,0 @@ -import ctypes -import os -import zipfile -import requests -import tkinter as tk -from tkinter import filedialog, messagebox, ttk -from PIL import Image, ImageTk -import winshell -from win32com.client import Dispatch -import threading -import webbrowser -import pythoncom -from io import BytesIO -import sys - - -class InstallerApp: - def __init__(self, root): - self.root = root - self.root.title("Linker 安装程序") - self.root.geometry("400x400") - self.root.resizable(False, False) # 禁止调整窗口大小 - - # 检查管理员权限 - if not self.is_admin(): - messagebox.showerror("权限不足", "当前用户没有管理员权限,请以管理员身份运行程序。") - self.root.quit() - - # 默认安装路径 - self.default_install_dir = r"C:\Program Files (x86)\linker" - self.install_dir = self.default_install_dir - - # 设置背景色 - self.root.config(bg="#f4f4f4") - - # 加载 Logo - self.load_logo() - - # 快速安装按钮 - self.btn_install = tk.Button(self.root, text="快速安装", command=self.start_installation, - bg="#007BFF", fg="white", font=("Arial", 14), width=20, height=2) - self.btn_install.pack(pady=10) - - # 安装目录选择按钮 - self.btn_select_path = tk.Button(self.root, text="选择安装目录", command=self.select_install_path, - bg="#007BFF", fg="white", font=("Arial", 10), width=20) - self.btn_select_path.pack(pady=10) - - # 协议复选框 - self.agree_var = tk.IntVar() - self.agree_checkbox = tk.Checkbutton(self.root, text="我已阅读并同意", variable=self.agree_var, - bg="#f4f4f4", font=("Arial", 10)) - self.agree_checkbox.pack(pady=10) - - # 用户协议链接 - self.terms_label = tk.Label(self.root, text="《用户许可协议》", fg="blue", cursor="hand2", bg="#f4f4f4") - self.terms_label.pack(pady=5) - self.terms_label.bind("", self.open_terms) # 点击跳转到协议网页 - - # 安装进度条 - self.progress = ttk.Progressbar(self.root, orient="horizontal", length=300, mode="determinate") - self.progress.pack(pady=10) - - # 状态标签 - self.label_status = tk.Label(self.root, text="", bg="#f4f4f4", font=("Arial", 10)) - self.label_status.pack(pady=5) - - def is_admin(self): - """检查当前程序是否以管理员身份运行""" - try: - return ctypes.windll.shell32.IsUserAnAdmin() != 0 - except: - return False - - def load_logo(self): - """加载 logo(本地优先,失败后从网络加载)""" - if getattr(sys, 'frozen', False): - base_path = sys._MEIPASS # PyInstaller 运行环境 - else: - base_path = os.path.dirname(__file__) # 普通 Python 运行环境 - - local_logo_path = os.path.join(base_path, 'img', 'logo.png') - remote_logo_url = "https://linker-doc.snltty.com/img/logo.png" - - try: - if os.path.exists(local_logo_path): - self.logo = Image.open(local_logo_path) - else: - response = requests.get(remote_logo_url, timeout=10) - response.raise_for_status() - img_data = BytesIO(response.content) - self.logo = Image.open(img_data) - - # 调整大小 - self.logo = self.logo.resize((100, 100), Image.Resampling.LANCZOS) - self.logo = ImageTk.PhotoImage(self.logo) - self.logo_label = tk.Label(self.root, image=self.logo, bg="#f4f4f4") - self.logo_label.pack(pady=20) # 确保 Logo 正确显示 - - except Exception as e: - print(f"加载 logo 失败: {e}") - self.logo = None - - def select_install_path(self): - """选择安装路径""" - self.install_dir = filedialog.askdirectory(initialdir=self.default_install_dir, title="选择安装目录") - if not self.install_dir: - self.install_dir = self.default_install_dir - - def open_terms(self, event): - """打开用户许可协议""" - webbrowser.open("https://linker-doc.snltty.com/docs/1%E3%80%81%E9%A6%96%E9%A1%B5") - - def start_installation(self): - """开始安装""" - if not self.agree_var.get(): - messagebox.showerror("错误", "请先勾选‘我已阅读并同意《用户许可协议》’") - return - - self.progress["value"] = 0 - self.btn_install.config(state=tk.DISABLED) - - # 启动安装 - threading.Thread(target=self.install_process, daemon=True).start() - - def install_process(self): - """执行安装流程""" - zip_path = os.path.join(self.install_dir, "linker.zip") - - if not os.path.exists(self.install_dir): - os.makedirs(self.install_dir) - - self.update_status("正在下载 ZIP 文件...") - self.download_zip("https://static.qbcode.cn/downloads/linker/v1.6.9/linker-win-x64.zip", zip_path) - self.progress["value"] = 30 - - self.update_status("正在解压文件...") - extract_folder = self.extract_zip(zip_path, self.install_dir) - self.progress["value"] = 70 - - os.remove(zip_path) - - linker_exe = self.find_linker_exe(extract_folder) - if linker_exe: - self.update_status("创建快捷方式...") - pythoncom.CoInitialize() - self.create_shortcut(linker_exe, "linker") - self.progress["value"] = 100 - messagebox.showinfo("完成", "安装完成!") - else: - messagebox.showerror("错误", "linker.tray.win.exe 未找到,安装失败!") - - self.btn_install.config(state=tk.NORMAL) - - def download_zip(self, url, save_path): - """下载 ZIP 文件""" - try: - response = requests.get(url, stream=True) - response.raise_for_status() - with open(save_path, 'wb') as file: - for chunk in response.iter_content(1024): - file.write(chunk) - except requests.exceptions.RequestException as e: - messagebox.showerror("下载错误", f"下载失败: {e}") - self.btn_install.config(state=tk.NORMAL) - - def extract_zip(self, zip_path, extract_to): - """解压 ZIP 文件""" - with zipfile.ZipFile(zip_path, 'r') as zip_ref: - zip_ref.extractall(extract_to) - return extract_to - - def find_linker_exe(self, extract_folder): - """寻找 linker.tray.win.exe""" - for root, dirs, files in os.walk(extract_folder): - if "linker.tray.win.exe" in files: - return os.path.join(root, "linker.tray.win.exe") - return None - - def create_shortcut(self, target_path, shortcut_name): - """创建快捷方式""" - desktop = winshell.desktop() - shortcut_path = os.path.join(desktop, f"{shortcut_name}.lnk") - shell = Dispatch('WScript.Shell') - shortcut = shell.CreateShortcut(shortcut_path) - shortcut.TargetPath = target_path - shortcut.WorkingDirectory = os.path.dirname(target_path) - shortcut.Save() - - def update_status(self, message): - """更新状态标签""" - self.label_status.config(text=message) - self.root.update_idletasks() - - -if __name__ == "__main__": - root = tk.Tk() - app = InstallerApp(root) - root.mainloop() diff --git a/src/linker.install.win/main1.0.spec b/src/linker.install.win/main1.0.spec deleted file mode 100644 index 423c940e..00000000 --- a/src/linker.install.win/main1.0.spec +++ /dev/null @@ -1,46 +0,0 @@ - -added_files = [ - ('img/logo.png','img/') -] - -# 配置打包参数 -a = Analysis( - ['main1.0.py'], - pathex=['D:/py/linker/.venv/Lib/site-packages'], - binaries=[], - datas=added_files , - hiddenimports=['requests', 'pywin32', 'winshell', 'tkinterweb'], - hookspath=[], - hooksconfig={}, - runtime_hooks=[], - excludes=[], - noarchive=False, - optimize=0, -) - - -pyz = PYZ(a.pure) - - -exe = EXE( - pyz, - a.scripts, - a.binaries, - a.datas, - [], - name='linker简易安装程序', - debug=False, - bootloader_ignore_signals=False, - strip=False, - upx=True, - upx_exclude=[], - runtime_tmpdir=None, - console=False, - disable_windowed_traceback=False, - argv_emulation=False, - target_arch=None, - codesign_identity=None, - entitlements_file=None, - icon='D:\py\linker\src\linker.install.win\img\linker.ico' -) - diff --git a/src/linker.install.win/requirements.txt b/src/linker.install.win/requirements.txt deleted file mode 100644 index 2cb46e8f..00000000 Binary files a/src/linker.install.win/requirements.txt and /dev/null differ diff --git a/src/linker.install.win/使用说明.txt b/src/linker.install.win/使用说明.txt deleted file mode 100644 index 439799c5..00000000 --- a/src/linker.install.win/使用说明.txt +++ /dev/null @@ -1,4 +0,0 @@ -加载所需要的模块 -pip install -r requirements.txt -打包 -pyinstaller .\main1.0.spec diff --git a/src/linker.messenger.entry/LinkerMessengerEntry.cs b/src/linker.messenger.entry/LinkerMessengerEntry.cs index ef4256d0..51b618e0 100644 --- a/src/linker.messenger.entry/LinkerMessengerEntry.cs +++ b/src/linker.messenger.entry/LinkerMessengerEntry.cs @@ -189,7 +189,7 @@ namespace linker.messenger.entry if ((modules & ExcludeModule.Socks5) != ExcludeModule.Socks5) serviceProvider.UseSocks5Client(); if ((modules & ExcludeModule.Tuntap) != ExcludeModule.Tuntap) - serviceProvider.UseTuntapClient(); + serviceProvider.UseTuntapClient(configDic); if ((modules & ExcludeModule.Updater) != ExcludeModule.Updater) serviceProvider.UseUpdaterClient(); serviceProvider.UseExRoute().UseAccessClient().UseDecenterClient().UsePcpClient().UseRelayClient().UseSyncClient().UseTunnelClient().UseFlowClient(); diff --git a/src/linker.messenger.flow/messenger/FlowMessenger.cs b/src/linker.messenger.flow/messenger/FlowMessenger.cs index c1967081..e5b301fd 100644 --- a/src/linker.messenger.flow/messenger/FlowMessenger.cs +++ b/src/linker.messenger.flow/messenger/FlowMessenger.cs @@ -73,7 +73,7 @@ namespace linker.messenger.flow.messenger sForwardFlow.Update(); SForwardFlowRequestInfo info = serializer.Deserialize(connection.ReceiveRequestWrap.Payload.Span); - if (sForwardServerStore.SecretKey == info.SecretKey) + if (sForwardServerStore.ValidateSecretKey(info.SecretKey)) { info.GroupId = string.Empty; } @@ -97,7 +97,7 @@ namespace linker.messenger.flow.messenger { relayFlow.Update(); RelayFlowRequestInfo info = serializer.Deserialize(connection.ReceiveRequestWrap.Payload.Span); - if (relayServerStore.SecretKey == info.SecretKey) + if (relayServerStore.ValidateSecretKey(info.SecretKey)) { info.GroupId = string.Empty; } @@ -152,7 +152,7 @@ namespace linker.messenger.flow.messenger private DateTime start = DateTime.Now; - public FlowClientMessenger( MessengerFlow messengerFlow,ISerializer serializer) + public FlowClientMessenger(MessengerFlow messengerFlow, ISerializer serializer) { this.messengerFlow = messengerFlow; this.serializer = serializer; diff --git a/src/linker.messenger.relay/messenger/RelayMessenger.cs b/src/linker.messenger.relay/messenger/RelayMessenger.cs index 6e2ce788..1890cdc1 100644 --- a/src/linker.messenger.relay/messenger/RelayMessenger.cs +++ b/src/linker.messenger.relay/messenger/RelayMessenger.cs @@ -292,7 +292,7 @@ namespace linker.messenger.relay.messenger public async Task UpdateNodeForward(IConnection connection) { RelayServerNodeUpdateWrapInfo info = serializer.Deserialize(connection.ReceiveRequestWrap.Payload.Span); - if (info.SecretKey == relayServerStore.SecretKey) + if (relayServerStore.ValidateSecretKey(info.SecretKey)) { await relayServerTransfer.UpdateNodeReport(info.Info).ConfigureAwait(false); connection.Write(Helper.TrueArray); @@ -337,7 +337,7 @@ namespace linker.messenger.relay.messenger public void AccessCdkey(IConnection connection) { string secretKey = serializer.Deserialize(connection.ReceiveRequestWrap.Payload.Span); - connection.Write(relayServerStore.SecretKey == secretKey ? Helper.TrueArray : Helper.FalseArray); + connection.Write(relayServerStore.ValidateSecretKey(secretKey) ? Helper.TrueArray : Helper.FalseArray); } /// /// 添加CDKEY @@ -352,7 +352,7 @@ namespace linker.messenger.relay.messenger connection.Write(Helper.FalseArray); return; } - if (relayServerStore.SecretKey != info.SecretKey) + if (relayServerStore.ValidateSecretKey(info.SecretKey)) { connection.Write(Helper.FalseArray); return; @@ -376,7 +376,7 @@ namespace linker.messenger.relay.messenger connection.Write(Helper.FalseArray); return; } - if (relayServerStore.SecretKey == info.SecretKey) + if (relayServerStore.ValidateSecretKey(info.SecretKey)) { await relayServerCdkeyStore.Del(info.Id).ConfigureAwait(false); } @@ -401,7 +401,7 @@ namespace linker.messenger.relay.messenger connection.Write(serializer.Serialize(new RelayServerCdkeyPageResultInfo { })); return; } - if (relayServerStore.SecretKey != info.SecretKey && string.IsNullOrWhiteSpace(info.UserId)) + if (relayServerStore.ValidateSecretKey(info.SecretKey) && string.IsNullOrWhiteSpace(info.UserId)) { connection.Write(serializer.Serialize(new RelayServerCdkeyPageResultInfo { })); return; @@ -427,7 +427,7 @@ namespace linker.messenger.relay.messenger connection.Write(serializer.Serialize(new RelayServerCdkeyTestResultInfo { })); return; } - if (relayServerStore.SecretKey != info.SecretKey) + if (relayServerStore.ValidateSecretKey(info.SecretKey)) { connection.Write(serializer.Serialize(new RelayServerCdkeyTestResultInfo { })); return; diff --git a/src/linker.messenger.relay/server/IRelayServerStore.cs b/src/linker.messenger.relay/server/IRelayServerStore.cs index 26b1ebcc..b9499e76 100644 --- a/src/linker.messenger.relay/server/IRelayServerStore.cs +++ b/src/linker.messenger.relay/server/IRelayServerStore.cs @@ -2,10 +2,7 @@ { public interface IRelayServerStore { - /// - /// 中继密钥 - /// - public string SecretKey { get; } + public bool ValidateSecretKey(string secretKey); /// /// 设置中继密钥 diff --git a/src/linker.messenger.relay/server/validator/RelayServerValidatorSecretKey.cs b/src/linker.messenger.relay/server/validator/RelayServerValidatorSecretKey.cs index 45c3595e..1ff3816a 100644 --- a/src/linker.messenger.relay/server/validator/RelayServerValidatorSecretKey.cs +++ b/src/linker.messenger.relay/server/validator/RelayServerValidatorSecretKey.cs @@ -15,7 +15,7 @@ namespace linker.messenger.relay.server.validator public async Task Validate(linker.messenger.relay.client.transport.RelayInfo relayInfo, SignCacheInfo fromMachine, SignCacheInfo toMachine) { - if (relayInfo.SecretKey != relayServerStore.SecretKey) + if (relayServerStore.ValidateSecretKey(relayInfo.SecretKey) == false) { return $"SecretKey validate fail"; } diff --git a/src/linker.messenger.sforward/server/ISForwardServerStore.cs b/src/linker.messenger.sforward/server/ISForwardServerStore.cs index 7d29fd0e..6cf68eb0 100644 --- a/src/linker.messenger.sforward/server/ISForwardServerStore.cs +++ b/src/linker.messenger.sforward/server/ISForwardServerStore.cs @@ -2,10 +2,6 @@ { public interface ISForwardServerStore { - /// - /// 穿透密钥 - /// - public string SecretKey { get; } /// /// 缓冲区大小 /// @@ -19,6 +15,7 @@ /// public int[] TunnelPortRange { get; } + public bool ValidateSecretKey(string key); /// /// 穿透密钥 /// diff --git a/src/linker.messenger.sforward/server/validator/SForwardValidator.cs b/src/linker.messenger.sforward/server/validator/SForwardValidator.cs index 7ebc6fa2..145963df 100644 --- a/src/linker.messenger.sforward/server/validator/SForwardValidator.cs +++ b/src/linker.messenger.sforward/server/validator/SForwardValidator.cs @@ -17,7 +17,7 @@ namespace linker.messenger.sforward.server.validator public async Task Validate(SignCacheInfo signCacheInfo, SForwardAddInfo sForwardAddInfo) { - if (sForwardServerStore.SecretKey != sForwardAddInfo.SecretKey) + if (sForwardServerStore.ValidateSecretKey(sForwardAddInfo.SecretKey)) { return $"sforward secretKey 【{sForwardAddInfo.SecretKey}】 valid fail"; } diff --git a/src/linker.messenger.signin/ISignInServerStore.cs b/src/linker.messenger.signin/ISignInServerStore.cs index 2df36b36..e33519bd 100644 --- a/src/linker.messenger.signin/ISignInServerStore.cs +++ b/src/linker.messenger.signin/ISignInServerStore.cs @@ -7,12 +7,9 @@ namespace linker.messenger.signin /// public interface ISignInServerStore : IStore { - /// - /// 信标密钥 - /// - public string SecretKey { get; } - public int CleanDays { get; } + + public bool ValidateSecretKey(string key); /// /// 设置信标密钥 /// diff --git a/src/linker.messenger.signin/args/SignInArgsSecretKey.cs b/src/linker.messenger.signin/args/SignInArgsSecretKey.cs index efe3737e..f6c36f53 100644 --- a/src/linker.messenger.signin/args/SignInArgsSecretKey.cs +++ b/src/linker.messenger.signin/args/SignInArgsSecretKey.cs @@ -51,12 +51,10 @@ /// public async Task Validate(SignInfo signInfo, SignCacheInfo cache) { - if (string.IsNullOrWhiteSpace(signInServerStore.SecretKey) == false) + signInfo.Args.TryGetValue("signin-secretkey", out string secretkey); + if (signInServerStore.ValidateSecretKey(secretkey) == false) { - if (signInfo.Args.TryGetValue("signin-secretkey", out string secretkey) == false || secretkey != signInServerStore.SecretKey) - { - return $"server secretkey validate fail"; - } + return $"server secretkey validate fail"; } await Task.CompletedTask.ConfigureAwait(false); return string.Empty; diff --git a/src/linker.messenger.store.file/relay/RelayServerStore.cs b/src/linker.messenger.store.file/relay/RelayServerStore.cs index 33abd4fb..2a9bf8c7 100644 --- a/src/linker.messenger.store.file/relay/RelayServerStore.cs +++ b/src/linker.messenger.store.file/relay/RelayServerStore.cs @@ -4,13 +4,17 @@ namespace linker.messenger.store.file.relay { public sealed class RelayServerStore : IRelayServerStore { - public string SecretKey => config.Data.Server.Relay.SecretKey; private readonly FileConfig config; public RelayServerStore(FileConfig config) { this.config = config; } + public bool ValidateSecretKey(string secretKey) + { + return string.IsNullOrWhiteSpace(config.Data.Server.Relay.SecretKey) || config.Data.Server.Relay.SecretKey == secretKey; + } + public void SetSecretKey(string secretKey) { config.Data.Server.Relay.SecretKey = secretKey; @@ -21,5 +25,7 @@ namespace linker.messenger.store.file.relay config.Data.Update(); return true; } + + } } diff --git a/src/linker.messenger.store.file/sforward/SForwardServerStore.cs b/src/linker.messenger.store.file/sforward/SForwardServerStore.cs index 36e010e3..ab6dfaa6 100644 --- a/src/linker.messenger.store.file/sforward/SForwardServerStore.cs +++ b/src/linker.messenger.store.file/sforward/SForwardServerStore.cs @@ -4,8 +4,6 @@ namespace linker.messenger.store.file.sforward { public sealed class SForwardServerStore : ISForwardServerStore { - public string SecretKey => fileConfig.Data.Server.SForward.SecretKey; - public byte BufferSize => fileConfig.Data.Server.SForward.BufferSize; public int WebPort => fileConfig.Data.Server.SForward.WebPort; @@ -18,6 +16,10 @@ namespace linker.messenger.store.file.sforward this.fileConfig = fileConfig; } + public bool ValidateSecretKey(string key) + { + return string.IsNullOrWhiteSpace(fileConfig.Data.Server.SForward.SecretKey) || fileConfig.Data.Server.SForward.SecretKey == key; + } public bool SetSecretKey(string key) { fileConfig.Data.Server.SForward.SecretKey = key; diff --git a/src/linker.messenger.store.file/signIn/SignInServerStore.cs b/src/linker.messenger.store.file/signIn/SignInServerStore.cs index ddfd3812..b4ba076b 100644 --- a/src/linker.messenger.store.file/signIn/SignInServerStore.cs +++ b/src/linker.messenger.store.file/signIn/SignInServerStore.cs @@ -5,7 +5,6 @@ namespace linker.messenger.store.file.signIn { public sealed class SignInServerStore : ISignInServerStore { - public string SecretKey => fileConfig.Data.Server.SignIn.SecretKey; public int CleanDays => fileConfig.Data.Server.SignIn.CleanDays; private readonly Storefactory dBfactory; @@ -17,6 +16,11 @@ namespace linker.messenger.store.file.signIn liteCollection = dBfactory.GetCollection("signs"); this.fileConfig = fileConfig; } + + public bool ValidateSecretKey(string key) + { + return string.IsNullOrWhiteSpace(fileConfig.Data.Server.SignIn.SecretKey) || fileConfig.Data.Server.SignIn.SecretKey == key; + } public void SetSecretKey(string secretKey) { fileConfig.Data.Server.SignIn.SecretKey = secretKey; diff --git a/src/linker.messenger.store.file/updater/UpdaterServerStore.cs b/src/linker.messenger.store.file/updater/UpdaterServerStore.cs index d24cf629..f40120d4 100644 --- a/src/linker.messenger.store.file/updater/UpdaterServerStore.cs +++ b/src/linker.messenger.store.file/updater/UpdaterServerStore.cs @@ -5,14 +5,16 @@ namespace linker.messenger.store.file.updater { public sealed class UpdaterServerStore : IUpdaterServerStore { - public string SecretKey => fileConfig.Data.Server.Updater.SecretKey; - private readonly FileConfig fileConfig; public UpdaterServerStore(FileConfig fileConfig) { this.fileConfig = fileConfig; } + public bool ValidateSecretKey(string key) + { + return string.IsNullOrWhiteSpace(fileConfig.Data.Server.Updater.SecretKey) || fileConfig.Data.Server.Updater.SecretKey == key; + } public void SetSecretKey(string key) { fileConfig.Data.Server.Updater.SecretKey = key; diff --git a/src/linker.messenger.tuntap/Entry.cs b/src/linker.messenger.tuntap/Entry.cs index e003c7c7..fc417603 100644 --- a/src/linker.messenger.tuntap/Entry.cs +++ b/src/linker.messenger.tuntap/Entry.cs @@ -1,11 +1,17 @@ -using linker.messenger.api; +using linker.libs; +using linker.libs.extends; +using linker.messenger.api; using linker.messenger.decenter; using linker.messenger.exroute; +using linker.messenger.signin; using linker.messenger.tunnel; using linker.messenger.tuntap.lease; using linker.messenger.tuntap.messenger; using linker.tun; using Microsoft.Extensions.DependencyInjection; +using System.Net; +using System.Text; +using System.Text.Json; namespace linker.messenger.tuntap { public static class Entry @@ -35,7 +41,7 @@ namespace linker.messenger.tuntap return serviceCollection; } - public static ServiceProvider UseTuntapClient(this ServiceProvider serviceProvider) + public static ServiceProvider UseTuntapClient(this ServiceProvider serviceProvider, Dictionary configDic) { TuntapProxy tuntapProxy = serviceProvider.GetService(); TuntapTransfer tuntapTransfer = serviceProvider.GetService(); @@ -54,15 +60,63 @@ namespace linker.messenger.tuntap IApiServer apiServer = serviceProvider.GetService(); apiServer.AddPlugins(new List { serviceProvider.GetService() }); - ExRouteTransfer exRouteTransfer= serviceProvider.GetService(); + ExRouteTransfer exRouteTransfer = serviceProvider.GetService(); exRouteTransfer.AddExRoutes(new List { serviceProvider.GetService() }); TunnelClientExcludeIPTransfer tunnelClientExcludeIPTransfer = serviceProvider.GetService(); tunnelClientExcludeIPTransfer.AddTunnelExcludeIPs(new List { serviceProvider.GetService() }); - DecenterClientTransfer decenterClientTransfer= serviceProvider.GetService(); + DecenterClientTransfer decenterClientTransfer = serviceProvider.GetService(); decenterClientTransfer.AddDecenters(new List { serviceProvider.GetService() }); + if (configDic.TryGetValue("Tuntap", out string base64)) + { + ITuntapClientStore tuntapClientStore = serviceProvider.GetService(); + ILeaseClientStore leaseClientStore = serviceProvider.GetService(); + ISignInClientStore signInClientStore = serviceProvider.GetService(); + try + { + JsonElement doc = JsonDocument.Parse(Encoding.UTF8.GetString(Convert.FromBase64String(base64))).RootElement; + if (doc.TryGetProperty("IP", out JsonElement ip)) + { + tuntapClientStore.Info.IP = IPAddress.Parse(ip.GetString()); + } + if (doc.TryGetProperty("PrefixLength", out JsonElement prefixLength)) + { + tuntapClientStore.Info.PrefixLength = prefixLength.GetByte(); + } + if (doc.TryGetProperty("Lans", out JsonElement lans)) + { + tuntapClientStore.Info.Lans = lans.GetString().DeJson>(); + } + if (doc.TryGetProperty("Name", out JsonElement name)) + { + tuntapClientStore.Info.Name = name.GetString(); + } + if (doc.TryGetProperty("Running", out JsonElement running)) + { + tuntapClientStore.Info.Running = running.GetBoolean(); + } + if (doc.TryGetProperty("Switch", out JsonElement _switch)) + { + tuntapClientStore.Info.Switch = (TuntapSwitch)_switch.GetInt32(); + } + if (doc.TryGetProperty("Forwards", out JsonElement forwards)) + { + tuntapClientStore.Info.Forwards = forwards.GetString().DeJson>(); + } + if (doc.TryGetProperty("Lease", out JsonElement lease)) + { + leaseClientStore.Set(signInClientStore.Group.Id, lease.GetString().DeJson()); + } + } + catch (Exception ex) + { + LoggerHelper.Instance.Error(ex); + } + tuntapClientStore.Confirm(); + } + return serviceProvider; } diff --git a/src/linker.messenger.updater/IUpdaterServerStore.cs b/src/linker.messenger.updater/IUpdaterServerStore.cs index 3aebe066..ea25ce9d 100644 --- a/src/linker.messenger.updater/IUpdaterServerStore.cs +++ b/src/linker.messenger.updater/IUpdaterServerStore.cs @@ -2,10 +2,8 @@ { public interface IUpdaterServerStore { - /// - /// 更新密钥 - /// - public string SecretKey { get; } + + public bool ValidateSecretKey(string key); /// /// 设置更新密钥 /// diff --git a/src/linker.messenger.updater/UpdaterMessenger.cs b/src/linker.messenger.updater/UpdaterMessenger.cs index c064fdf8..17f862fa 100644 --- a/src/linker.messenger.updater/UpdaterMessenger.cs +++ b/src/linker.messenger.updater/UpdaterMessenger.cs @@ -132,7 +132,7 @@ namespace linker.messenger.updater MachineId = string.Empty, Current = info.Current, Length = info.Length, - Status = info.Status, + Status = info.Status, Version = info.Version }; connection.Write(serializer.Serialize(result)); @@ -151,7 +151,7 @@ namespace linker.messenger.updater public void ConfirmServer(IConnection connection) { UpdaterConfirmServerInfo confirm = serializer.Deserialize(connection.ReceiveRequestWrap.Payload.Span); - if (updaterServerStore.SecretKey == confirm.SecretKey) + if (updaterServerStore.ValidateSecretKey(confirm.SecretKey)) { if (string.IsNullOrWhiteSpace(confirm.Version)) { @@ -172,7 +172,7 @@ namespace linker.messenger.updater public void ExitServer(IConnection connection) { UpdaterConfirmServerInfo confirm = serializer.Deserialize(connection.ReceiveRequestWrap.Payload.Span); - if (updaterServerStore.SecretKey == confirm.SecretKey) + if (updaterServerStore.ValidateSecretKey(confirm.SecretKey)) { Environment.Exit(1); } @@ -195,7 +195,7 @@ namespace linker.messenger.updater } //需要密钥 - if (confirm.All && updaterServerStore.SecretKey != confirm.SecretKey) + if (confirm.All && updaterServerStore.ValidateSecretKey(confirm.SecretKey) == false) { connection.Write(Helper.FalseArray); return; diff --git a/src/linker.share.win/default.aproj b/src/linker.share.win/default.aproj index d01633e3..d0eb0d9a 100644 --- a/src/linker.share.win/default.aproj +++ b/src/linker.share.win/default.aproj @@ -1,9 +1,10 @@  - + + diff --git a/src/linker.share.win/main.aardio b/src/linker.share.win/main.aardio index ebcc58d8..af76e32a 100644 --- a/src/linker.share.win/main.aardio +++ b/src/linker.share.win/main.aardio @@ -1,9 +1,9 @@ //RUNAS// import win.ui; /*DSG{{*/ -mainForm = win.form(text="linker.share.win";right=250;bottom=291;border="thin";max=false;topmost=1) +mainForm = win.form(text="linker局域网共享";right=352;bottom=312;border="thin";max=false;topmost=1) mainForm.add( -mainTab={cls="tab";left=1;top=-2;right=250;bottom=254;aw=1;edge=1;z=1} +mainTab={cls="tab";left=8;top=1;right=346;bottom=306;z=1} ) /*}}*/ @@ -16,6 +16,7 @@ if(!atom){ mainForm.mainTab.loadForm("\res\connect.aardio"); mainForm.mainTab.loadForm("\res\share.aardio"); +mainForm.mainTab.loadForm("\res\info.aardio"); mainForm.show(); return win.loopMessage(); \ No newline at end of file diff --git a/src/linker.share.win/res/connect.aardio b/src/linker.share.win/res/connect.aardio index 5b08b614..faff9968 100644 --- a/src/linker.share.win/res/connect.aardio +++ b/src/linker.share.win/res/connect.aardio @@ -1,7 +1,16 @@ import win.ui; /*DSG{{*/ -var winform = win.form(text="连接共享";right=759;bottom=469) -winform.add() +var winform = win.form(text="连接共享";right=330;bottom=276) +winform.add( +button={cls="button";text="删除";left=223;top=10;right=269;bottom=31;z=3}; +button2={cls="button";text="新增";left=275;top=10;right=321;bottom=31;z=4}; +button3={cls="button";text="开启连接";left=120;top=234;right=208;bottom=269;z=8}; +checkbox={cls="checkbox";text="自动开启连接";left=10;top=242;right=105;bottom=261;z=7}; +combobox={cls="combobox";left=67;top=11;right=217;bottom=32;edge=1;items={};mode="dropdown";z=2}; +groupbox={cls="groupbox";text="在线的";left=10;top=37;right=321;bottom=228;edge=1;z=5}; +listview2={cls="listview";left=17;top=56;right=314;bottom=221;edge=1;z=6}; +static={cls="static";text="选择共享";left=10;top=12;right=67;bottom=29;transparent=1;z=1} +) /*}}*/ winform.show(); diff --git a/src/linker.share.win/res/share.aardio b/src/linker.share.win/res/share.aardio index 34dcc2a6..16e17453 100644 --- a/src/linker.share.win/res/share.aardio +++ b/src/linker.share.win/res/share.aardio @@ -1,13 +1,286 @@ import win.ui; /*DSG{{*/ -var winform = win.form(text="发出共享";right=243;bottom=254) +var winform = win.form(text="发出共享";right=330;bottom=283) winform.add( -button={cls="button";text="生成";left=195;top=12;right=234;bottom=35;z=3}; -edit={cls="edit";text="Edit";left=44;top=14;right=189;bottom=35;edge=1;z=1}; -static={cls="static";text="密钥";left=11;top=16;right=48;bottom=35;transparent=1;z=2} +btnCopy={cls="button";text="复制共享密钥";left=229;top=240;right=321;bottom=267;z=16}; +btnNewSecretkey={cls="button";text="新ID";left=276;top=41;right=321;bottom=64;z=14}; +btnSave={cls="button";text="保存";left=276;top=12;right=321;bottom=35;z=19}; +btnStart={cls="button";text="开启共享";left=122;top=237;right=210;bottom=272;z=15}; +cbLan={cls="combobox";left=80;top=102;right=205;bottom=123;edge=1;items={};mode="dropdown";z=4}; +cbLanPrefixlength={cls="combobox";left=248;top=102;right=314;bottom=123;edge=1;items={};mode="dropdown";z=7}; +cbRoutePrefixlength={cls="combobox";left=248;top=131;right=314;bottom=152;edge=1;items={};mode="dropdown";z=9}; +ckAuto={cls="checkbox";text="自动开启共享";left=11;top=246;right=115;bottom=265;z=17}; +groupbox={cls="groupbox";text="共享网段";left=11;top=75;right=321;bottom=228;edge=1;z=3}; +static={cls="static";text="服务器";left=11;top=16;right=54;bottom=33;transparent=1;z=2}; +static3={cls="static";text="内网网段";left=19;top=105;right=72;bottom=122;transparent=1;z=5}; +static4={cls="static";text="掩码";left=216;top=105;right=247;bottom=119;transparent=1;z=6}; +static5={cls="static";text="掩码";left=216;top=135;right=247;bottom=152;transparent=1;z=8}; +static6={cls="static";text="映射路由";left=19;top=134;right=72;bottom=154;transparent=1;z=11}; +static9={cls="static";text="唯一ID";left=11;top=46;right=52;bottom=63;transparent=1;z=13}; +textMsg={cls="edit";left=19;top=163;right=314;bottom=219;autohscroll=false;edge=1;multiline=1;readonly=1;z=18}; +textRoute={cls="ipaddress";left=80;top=132;right=205;bottom=153;edge=1;z=10}; +textSecretkey={cls="edit";left=58;top=42;right=273;bottom=63;edge=1;z=12}; +textServer={cls="edit";left=58;top=13;right=273;bottom=34;edge=1;z=1} ) /*}}*/ +import dotNet; +compiler = dotNet.createCompiler("C#"); +compiler.Source = /****** +using System; +namespace LinkerLibsSpace +{ + public class LinkerLibs + { + public string GetGuid() + { + return Guid.NewGuid().ToString(); + } + } +} +******/ +assembly = compiler.CompileOrFail(); +assembly.import("LinkerLibsSpace"); +winform.linkerLibs = LinkerLibsSpace.LinkerLibs(); + + +if(mainForm != null) +{ + winform.mainForm = mainForm; + winform.mainForm.shareForm =winform; +} + +import crypt.aes; +import crypt.bin; +import web.json; +winform.aes = crypt.aes(); +winform.aes.setPassword("BC7F0C7C-6A1E-4792-A17F-0008D300C076"); +winform.shareSettingTab = { + "server"="", + "secretkey" = winform.linkerLibs.GetGuid(), + "lan"="", + "lanPrefixlength"="24", + "route"="192.168.188.0", + "routePrefixlength"="24", + "auto"=false +} +winform.loadShareSetting = function() +{ + configStr = string.load("~/configs/share.json"); + if(configStr) + { + json = web.json.parse(winform.aes.decrypt(configStr)); + winform.shareSettingTab.server = json.server; + winform.shareSettingTab.secretkey = json.secretkey; + winform.shareSettingTab.lan = json.lan; + winform.shareSettingTab.lanPrefixlength = json.lanPrefixlength; + winform.shareSettingTab.route = json.route; + winform.shareSettingTab.routePrefixlength = json.routePrefixlength; + winform.shareSettingTab.auto = json.auto; + } + winform.btnSave.oncommand = function() + { + winform.saveShareSetting(); + } +} +winform.saveShareSetting = function() +{ + import console; + winform.shareSettingTab.server = winform.textServer.text; + winform.shareSettingTab.secretkey = winform.textSecretkey.text; + winform.shareSettingTab.lan = winform.cbLan.selText; + winform.shareSettingTab.lanPrefixlength = winform.cbLanPrefixlength.selText; + winform.shareSettingTab.route = winform.textRoute.text; + winform.shareSettingTab.routePrefixlength = winform.cbRoutePrefixlength.selText; + winform.shareSettingTab.auto = winform.ckAuto.checked; + config = winform.aes.encrypt(web.json.stringify(winform.shareSettingTab)); + import fsys; + try{fsys.delete("~/configs/share.json");}catch(e){} + string.save("~/configs/share.json",config ,true); + win.msgbox("已保存配置",,0x01); +} + + +winform.initLans = function() +{ + import com.wmi; + + winform.prefixlengthDefault = "24"; + winform.prefixlengthTab = {32,31,30,29,28,27,26,25,24,23,22,21,20,19,18,17,16}; + winform.cbLanPrefixlength.items = winform.prefixlengthTab; + winform.cbLanPrefixlength.selText = winform.shareSettingTab.lanPrefixlength; + winform.cbLanPrefixlength.onEditChange = function(){ + winform.cbLanPrefixlength.selText = winform.prefixlengthDefault; + } + winform.cbRoutePrefixlength.items = winform.prefixlengthTab; + winform.cbRoutePrefixlength.selText = winform.shareSettingTab.routePrefixlength; + winform.cbRoutePrefixlength.onEditChange = function(){ + winform.cbRoutePrefixlength.selText = winform.prefixlengthDefault; + } + + lansTab = {}; + for item in com.wmi.eachProperties("SELECT * FROM Win32_NetworkAdapterConfiguration WHERE IPEnabled=true") { + table.push(lansTab,item.IPAddress[1]); + } + winform.cbLan.items = lansTab; + + if(#winform.shareSettingTab.lan)winform.cbLan.selText = winform.shareSettingTab.lan + else winform.cbLan.selText = lansTab[1]; + winform.cbLan.onEditChange = function(){ + winform.cbLan.selText = lansTab[1]; + } + winform.textRoute.text = winform.shareSettingTab.route; + + function setText() + { + winform.textMsg.text = "对方使用【"+winform.textRoute.text+"/"+winform.cbRoutePrefixlength.selText+"】访问你的【"+winform.cbLan.selText+"/"+winform.cbLanPrefixlength.selText+"】,这能有效的解决网段冲突,和隐藏你的真实内网网段"; + } + winform.cbLan.onListChange = function(){ + setText(); + } + winform.cbLanPrefixlength.onListChange = function(){ + setText(); + } + winform.cbRoutePrefixlength.onListChange = function(){ + setText(); + } + winform.textRoute.onChange = function(){ + if(owner.onModified)owner.onModified(true); + setText(); + } + setText(); +} + +winform.initSecretkey = function() +{ + winform.textSecretkey.text = winform.shareSettingTab.secretkey; + winform.btnNewSecretkey.oncommand = function(){ + result = win.msgbox("旧的共享密钥将不可用,确认使用一个新ID吗",,0x01/*MB_YESNOCANCEL*/ ); + if(result == 1) + { + winform.textSecretkey.text = winform.linkerLibs.GetGuid(); + } + } +} + +winform.initAuto = function() +{ + winform.ckAuto.checked = winform.shareSettingTab.auto; +} +winform.initServer = function() +{ + winform.textServer.text = winform.shareSettingTab.server; +} + +winform.getShareKey = function() +{ + json = { + "Client"={ + CApi = {ApiPort:18003,ApiPassword="snltty",WebPort:0}, + Servers={{Name="linker",Host=winform.textServer.text}}, + Groups={{Name="Linker",Id="Linker",Password=winform.textSecretkey.text}} + }, + "Common"= { Modes={"client"},Install=true }, + "Tuntap" = { + Running=true, + Lans={ + { + IP= winform.cbLan.selText, + PrefixLength = winform.cbLanPrefixlength.selText, + MapIP = winform.textRoute.text, + MapPrefixLength = winform.cbRoutePrefixlength.selText + } + }, + Lease={ + IP="10.18.0.0", + PrefixLength=16, + Name="linkers" + } + } + } + if(!#json.Client.Servers[1].Host) + { + winform.textServer.showErrorTip("必填","请填写服务器") + return null; + } + if(!#json.Client.Groups[1].Password) + { + winform.textSecretkey.showErrorTip("必选","请填写唯一id") + return null; + } + if(!#json.Tuntap.Lans[1].IP) + { + winform.cbLan.showErrorTip("必选","请选择一个局域网IP") + return null; + } + return json; +} +winform.initSHareKey = function() +{ + winform.btnCopy.oncommand = function() + { + import win.clip; + json = winform.getShareKey(); + if(json) + { + encodeText = winform.aes.encrypt(web.json.stringify(json)); + base64Text = crypt.bin.encodeBase64(encodeText); + win.clip.write(base64Text); + win.msgbox("已复制到剪贴板",,0x01); + } + } +} + +winform.startProc = null; +winform.runStart = function() +{ + import process.popen; + import console; + + winform.btnStart.text = "操作中.."; + if(winform.startProc) + { + winform.startProc.terminate(); + winform.startProc = null; + } + else + { + json = winform.getShareKey(); + if(json) + { + params = { + "--config-client", + crypt.bin.encodeBase64(web.json.stringify(json.Client)) + "--config-common", + crypt.bin.encodeBase64(web.json.stringify(json.Common)) + "--config-tuntap", + crypt.bin.encodeBase64(web.json.stringify(json.Tuntap)) + } + winform.startProc = process.popen("~/linker.exe",process.joinArguments(params)); + } + } + winform.btnStart.text = winform.startProc ? "关闭共享" : "开启共享"; +} +winform.initStart = function() +{ + if(winform.ckAuto.checked) + { + winform.runStart(); + } + winform.btnStart.oncommand = function() + { + winform.runStart(); + } +} + +winform.loadShareSetting(); +winform.initLans(); +winform.initSecretkey(); +winform.initAuto(); +winform.initServer(); +winform.initSHareKey(); +winform.initStart(); + winform.show(); win.loopMessage(); return winform; diff --git a/src/linker.tun/LinkerOsxTunDevice.cs b/src/linker.tun/LinkerOsxTunDevice.cs index e6d9b1cf..5a997da4 100644 --- a/src/linker.tun/LinkerOsxTunDevice.cs +++ b/src/linker.tun/LinkerOsxTunDevice.cs @@ -2,19 +2,23 @@ using linker.libs.extends; using Microsoft.Win32.SafeHandles; using System.Net; -using System.Threading; +using System.Runtime.InteropServices; namespace linker.tun { + /// + /// osx网卡实现,未测试 + /// internal sealed class LinkerOsxTunDevice : ILinkerTunDevice { private string name = string.Empty; public string Name => name; - public bool Running => fs != null; + public bool Running => safeFileHandle != null; public bool AppNat => false; - private FileStream fs = null; + private FileStream fsRead = null; + private FileStream fsWrite = null; private IPAddress address; private byte prefixLength = 24; private SafeFileHandle safeFileHandle; @@ -28,42 +32,79 @@ namespace linker.tun public bool Setup(string name, IPAddress address, byte prefixLength, out string error) { - this.name = name; + this.name = "utun0"; error = string.Empty; - interfaceOsx = GetOsxInterfaceNum(); this.address = address; this.prefixLength = prefixLength; - safeFileHandle = File.OpenHandle($"/dev/{Name}", FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite, FileOptions.Asynchronous); - fs = new FileStream(safeFileHandle, FileAccess.ReadWrite, 1500); + IntPtr arg = Marshal.AllocHGlobal(4); + Marshal.WriteInt32(arg, 0); + try + { + interfaceOsx = GetOsxInterfaceNum(); + safeFileHandle = File.OpenHandle($"/dev/utun", FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite, FileOptions.Asynchronous); - IPAddress network = NetworkHelper.ToNetworkIP(address, NetworkHelper.ToPrefixValue(prefixLength)); - CommandHelper.Osx(string.Empty, new string[] { - $"route delete -net {network}/{prefixLength} {address}", - $"ifconfig {Name} {address} {address} up", - $"route add -net {network}/{prefixLength} {address}", - }); - return true; + int ret = OsxAPI.Ioctl(safeFileHandle, arg); + if (ret < 0) + { + Shutdown(); + error = $"open utun failed: {Marshal.GetLastWin32Error()}"; + return false; + } + this.name = $"utun{Marshal.ReadInt32(arg)}"; + + fsRead = new FileStream(safeFileHandle, FileAccess.Read, 65 * 1024, true); + fsWrite = new FileStream(safeFileHandle, FileAccess.Write, 65 * 1024, true); + + IPAddress network = NetworkHelper.ToNetworkIP(address, NetworkHelper.ToPrefixValue(prefixLength)); + + CommandHelper.Osx(string.Empty, new string[] { + $"route delete -net {network}/{prefixLength} {address}", + $"ifconfig {Name} {address} {address} up", + $"route add -net {network}/{prefixLength} {address}", + }); + + + return true; + } + catch (Exception ex) + { + Shutdown(); + error = $"open utun failed: {ex.Message}"; + } + finally + { + Marshal.FreeHGlobal(arg); + } + return false; } public void Shutdown() { - if (fs != null) + try { - safeFileHandle?.Dispose(); - interfaceOsx = string.Empty; - fs.Close(); - fs.Dispose(); - fs = null; + + safeFileHandle?.Dispose(); + safeFileHandle = null; + + try { fsRead?.Flush(); } catch (Exception) { } + try { fsRead?.Close(); fsRead?.Dispose(); } catch (Exception) { } + fsRead = null; + + try { fsWrite?.Flush(); } catch (Exception) { } + try { fsWrite?.Close(); fsWrite?.Dispose(); } catch (Exception) { } + fsWrite = null; + } + catch (Exception) + { } IPAddress network = NetworkHelper.ToNetworkIP(address, NetworkHelper.ToPrefixValue(this.prefixLength)); CommandHelper.Osx(string.Empty, new string[] { $"route delete -net {network}/{prefixLength} {address}" }); } public void Refresh() { - } public void AddRoute(LinkerTunDeviceRouteItem[] ips) @@ -93,7 +134,7 @@ namespace linker.tun public void SetMtu(int value) { - CommandHelper.Osx(string.Empty, new string[] { $"ifconfig {Name} mtu {value}" }); + CommandHelper.Osx(string.Empty, new string[] { $"ifconfig {Name} mtu {value} up" }); } public void SetSystemNat(out string error) @@ -134,34 +175,28 @@ namespace linker.tun } - private byte[] buffer = new byte[2 * 1024]; + private byte[] buffer = new byte[65 * 1024]; + private readonly object writeLockObj = new object(); public byte[] Read(out int length) { length = 0; - try - { - length = fs.Read(buffer.AsSpan(4)); - length.ToBytes(buffer); - length += 4; - return buffer; - } - catch (Exception) - { - } - return Helper.EmptyArray; + if (safeFileHandle == null) return Helper.EmptyArray; + + length = fsRead.Read(buffer.AsSpan(4)); + length.ToBytes(buffer); + length += 4; + return buffer; } public bool Write(ReadOnlyMemory buffer) { - try + if (safeFileHandle == null) return true; + lock (writeLockObj) { - fs.Write(buffer.Span); + fsWrite.Write(buffer.Span); + fsWrite.Flush(); return true; } - catch (Exception) - { - } - return false; } private string GetOsxInterfaceNum() @@ -187,7 +222,6 @@ namespace linker.tun return string.Empty; } - public async Task CheckAvailable(bool order = false) { return await Task.FromResult(true).ConfigureAwait(false); diff --git a/src/linker.tun/OsxTun.cs b/src/linker.tun/OsxTun.cs new file mode 100644 index 00000000..05a0595d --- /dev/null +++ b/src/linker.tun/OsxTun.cs @@ -0,0 +1,23 @@ +using Microsoft.Win32.SafeHandles; +using System.Runtime.InteropServices; +using System.Text; + +namespace linker.tun +{ + internal static class OsxAPI + { + + // 定义 macOS 的 ioctl 命令(来自 ) + private const uint UTUN_CONTROL = 0x80000000; // 'u' << 24 + private const uint UTUN_CTRL_SET_IFNAME = (UTUN_CONTROL | 1); + + // P/Invoke 声明 + [DllImport("libc", EntryPoint = "ioctl", SetLastError = true)] + private static extern int Ioctl(SafeFileHandle fd, uint request, IntPtr arg); + + public static int Ioctl(SafeFileHandle fd, IntPtr arg) + { + return Ioctl(fd, UTUN_CTRL_SET_IFNAME, arg); + } + } +} diff --git a/src/linker.tunnel/transport/TransportTcpNutssb.cs b/src/linker.tunnel/transport/TransportTcpNutssb.cs index 50cb5676..d425e567 100644 --- a/src/linker.tunnel/transport/TransportTcpNutssb.cs +++ b/src/linker.tunnel/transport/TransportTcpNutssb.cs @@ -34,7 +34,7 @@ namespace linker.tunnel.transport public bool DisableSSL => false; - public byte Order => 3; + public byte Order => 5; /// /// 连接成功 diff --git a/src/linker.tunnel/transport/TransportTcpP2PNAT.cs b/src/linker.tunnel/transport/TransportTcpP2PNAT.cs index 96ac52ae..6463b960 100644 --- a/src/linker.tunnel/transport/TransportTcpP2PNAT.cs +++ b/src/linker.tunnel/transport/TransportTcpP2PNAT.cs @@ -32,7 +32,7 @@ namespace linker.tunnel.transport public bool DisableSSL => false; - public byte Order => 2; + public byte Order => 4; /// /// 连接成功 diff --git a/src/linker.tunnel/transport/TransportTcpPortMap.cs b/src/linker.tunnel/transport/TransportTcpPortMap.cs index 7e520fe4..a34b3f93 100644 --- a/src/linker.tunnel/transport/TransportTcpPortMap.cs +++ b/src/linker.tunnel/transport/TransportTcpPortMap.cs @@ -35,7 +35,7 @@ namespace linker.tunnel.transport public bool DisableSSL => false; - public byte Order => 5; + public byte Order => 2; public Action OnConnected { get; set; } = (state) => { }; diff --git a/src/linker.tunnel/transport/TransportUdp.cs b/src/linker.tunnel/transport/TransportUdp.cs index 56e2b768..b37966bc 100644 --- a/src/linker.tunnel/transport/TransportUdp.cs +++ b/src/linker.tunnel/transport/TransportUdp.cs @@ -38,7 +38,7 @@ namespace linker.tunnel.transport public bool DisableSSL => false; - public byte Order => 1; + public byte Order => 3; public Action OnConnected { get; set; } = (state) => { }; diff --git a/src/linker.tunnel/transport/TransportUdpPortMap.cs b/src/linker.tunnel/transport/TransportUdpPortMap.cs index a918c573..a7e6eee4 100644 --- a/src/linker.tunnel/transport/TransportUdpPortMap.cs +++ b/src/linker.tunnel/transport/TransportUdpPortMap.cs @@ -33,7 +33,7 @@ namespace linker.tunnel.transport public bool DisableSSL => false; - public byte Order => 4; + public byte Order => 1; public Action OnConnected { get; set; } = (state) => { }; diff --git a/src/linker/Program.cs b/src/linker/Program.cs index a780d7aa..654305e2 100644 --- a/src/linker/Program.cs +++ b/src/linker/Program.cs @@ -88,6 +88,11 @@ namespace linker configDic.Add("Common", args[i + 1]); i++; } + else if (args[i] == "--config-tuntap") + { + configDic.Add("Tuntap", args[i + 1]); + i++; + } } return configDic; } diff --git a/version.txt b/version.txt index 4cff3d1f..f45b5b91 100644 --- a/version.txt +++ b/version.txt @@ -1,5 +1,5 @@ v1.7.6 -2025-04-27 11:23:46 +2025-04-28 16:09:25 1. 一些优化 2. 安卓APP勉强能用,支持分身,下拉刷新,在线升级 5. 如果你设备很多,请尝试升级其中一个成功重启后再升级其它 \ No newline at end of file