From 6a2a003e988142e7b5d2338199ca542a4dceba0f Mon Sep 17 00:00:00 2001 From: ProxySU Date: Sun, 16 Aug 2020 12:58:37 +0800 Subject: [PATCH] =?UTF-8?q?Trojan-go=E6=9B=B4=E6=96=B0=E5=AE=89=E8=A3=85?= =?UTF-8?q?=E8=84=9A=E6=9C=AC=E5=92=8C=E9=85=8D=E7=BD=AE=E6=96=87=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ProxySU/MainWindow.xaml.cs | 2725 ++++++++--------- ProxySU/TemplateConfiguration.xaml | 14 +- ProxySU/TemplateConfiguration.xaml.cs | 17 +- ProxySU/TrojanGoTemplateWindow.xaml | 4 +- ProxySU/TrojanTemplateWindow.xaml | 4 +- ProxySU/bin/Beta/Beta.zip | Bin 494654 -> 495108 bytes .../WebSocketTLSWeb_server_config.caddyfile | 28 +- TemplateConfg/trojan-go_all_config.json | 101 +- TemplateConfg/trojan_caddy_config.caddyfile | 8 +- TemplateConfg/trojan_client_config.json | 4 +- TemplateConfg/trojan_server_config.json | 12 +- 11 files changed, 1419 insertions(+), 1498 deletions(-) diff --git a/ProxySU/MainWindow.xaml.cs b/ProxySU/MainWindow.xaml.cs index 12659df..084672c 100644 --- a/ProxySU/MainWindow.xaml.cs +++ b/ProxySU/MainWindow.xaml.cs @@ -72,224 +72,6 @@ namespace ProxySU TextBoxNaiveUser3in1.Text = RandomUserName(); TextBoxNaivePassword3in1.Text= RandomUUID(); - } - //远程主机连接信息 - private ConnectionInfo GenerateConnectionInfo() - { - ConnectionInfo connectionInfo; - - #region 检测输入的内空是否有错,并读取内容 - if (string.IsNullOrEmpty(TextBoxHost.Text) == true || string.IsNullOrEmpty(TextBoxPort.Text) == true || string.IsNullOrEmpty(TextBoxUserName.Text) == true) - { - MessageBox.Show("主机地址、主机端口、用户名为必填项,不能为空"); - - return connectionInfo = null; - } - string sshHostName = TextBoxHost.Text.ToString(); - int sshPort = int.Parse(TextBoxPort.Text); - string sshUser = TextBoxUserName.Text.ToString(); - if (RadioButtonPasswordLogin.IsChecked == true && string.IsNullOrEmpty(PasswordBoxHostPassword.Password) == true) - { - MessageBox.Show("登录密码为必填项,不能为空"); - return connectionInfo = null; - } - string sshPassword = PasswordBoxHostPassword.Password.ToString(); - if (RadioButtonCertLogin.IsChecked == true && string.IsNullOrEmpty(TextBoxCertFilePath.Text) == true) - { - MessageBox.Show("密钥文件为必填项,不能为空"); - return connectionInfo = null; - } - string sshPrivateKey = TextBoxCertFilePath.Text.ToString(); - ProxyTypes proxyTypes = new ProxyTypes();//默认为None - - //proxyTypes = ProxyTypes.Socks5; - if (RadioButtonHttp.IsChecked == true) - { - proxyTypes = ProxyTypes.Http; - } - else if (RadioButtonSocks4.IsChecked == true) - { - proxyTypes = ProxyTypes.Socks4; - } - else if (RadioButtonSocks5.IsChecked == true) - { - proxyTypes = ProxyTypes.Socks5; - } - else - { - proxyTypes = ProxyTypes.None; - } - - //MessageBox.Show(proxyTypes.ToString()); - if (RadioButtonNoProxy.IsChecked == false && (string.IsNullOrEmpty(TextBoxProxyHost.Text) == true || string.IsNullOrEmpty(TextBoxProxyPort.Text) == true)) - { - MessageBox.Show("如果选择了代理,则代理地址与端口不能为空"); - return connectionInfo = null; - } - string sshProxyHost = TextBoxProxyHost.Text.ToString(); - int sshProxyPort = int.Parse(TextBoxProxyPort.Text.ToString()); - if (RadioButtonNoProxy.IsChecked==false && RadiobuttonProxyYesLogin.IsChecked == true && (string.IsNullOrEmpty(TextBoxProxyUserName.Text) == true || string.IsNullOrEmpty(PasswordBoxProxyPassword.Password) == true)) - { - MessageBox.Show("如果代理需要登录,则代理登录的用户名与密码不能为空"); - return connectionInfo = null; - } - string sshProxyUser = TextBoxProxyUserName.Text.ToString(); - string sshProxyPassword = PasswordBoxProxyPassword.Password.ToString(); - - #endregion - - - //var connectionInfo = new PasswordConnectionInfo(sshHostName, sshPort, sshUser, sshPassword); - - connectionInfo = new ConnectionInfo( - sshHostName, - sshPort, - sshUser, - proxyTypes, - sshProxyHost, - sshProxyPort, - sshProxyUser, - sshProxyPassword, - new PasswordAuthenticationMethod(sshUser, sshPassword) - //new PrivateKeyAuthenticationMethod(sshUser, new PrivateKeyFile(sshPrivateKey)) - ); - - if (RadioButtonCertLogin.IsChecked == true) - { - connectionInfo = new ConnectionInfo( - sshHostName, - sshPort, - sshUser, - proxyTypes, - sshProxyHost, - sshProxyPort, - sshProxyUser, - sshProxyPassword, - //new PasswordAuthenticationMethod(sshUser, sshPassword) - new PrivateKeyAuthenticationMethod(sshUser, new PrivateKeyFile(sshPrivateKey)) - ); - - } - return connectionInfo; - } - - //开始布署安装V2ray - private void Button_Login_Click(object sender, RoutedEventArgs e) - - { - ConnectionInfo connectionInfo = GenerateConnectionInfo(); - if(connectionInfo==null) - { - MessageBox.Show("远程主机连接信息有误,请检查"); - return; - } - - //读取模板配置 - - string serverConfig=""; //服务端配置文件 - string clientConfig = ""; //生成的客户端配置文件 - string upLoadPath = "/usr/local/etc/v2ray/config.json"; //服务端文件位置 - //生成客户端配置时,连接的服务主机的IP或者域名 - if (String.IsNullOrEmpty(ReceiveConfigurationParameters[4])==true) - { - ReceiveConfigurationParameters[4] = TextBoxHost.Text.ToString(); - testDomain = false; - } - //选择模板 - if (String.IsNullOrEmpty(ReceiveConfigurationParameters[0]) == true) - { - MessageBox.Show("请先选择配置模板!"); - return; - } - else if (String.Equals(ReceiveConfigurationParameters[0], "TCP")) - { - testDomain = false; - serverConfig = "TemplateConfg\\tcp_server_config.json"; - clientConfig = "TemplateConfg\\tcp_client_config.json"; - } - else if (String.Equals(ReceiveConfigurationParameters[0], "TCPhttp")) - { - testDomain = false; - serverConfig = "TemplateConfg\\tcp_http_server_config.json"; - clientConfig = "TemplateConfg\\tcp_http_client_config.json"; - } - else if (String.Equals(ReceiveConfigurationParameters[0], "tcpTLS")) - { - testDomain = true; - serverConfig = "TemplateConfg\\tcp_TLS_server_config.json"; - clientConfig = "TemplateConfg\\tcp_TLS_client_config.json"; - } - else if (String.Equals(ReceiveConfigurationParameters[0], "tcpTLSselfSigned")) - { - testDomain = false; - serverConfig = "TemplateConfg\\tcpTLSselfSigned_server_config.json"; - clientConfig = "TemplateConfg\\tcpTLSselfSigned_client_config.json"; - } - else if (String.Equals(ReceiveConfigurationParameters[0], "webSocket")) - { - testDomain = false; - serverConfig = "TemplateConfg\\webSocket_server_config.json"; - clientConfig = "TemplateConfg\\webSocket_client_config.json"; - } - else if (String.Equals(ReceiveConfigurationParameters[0], "WebSocketTLS")) - { - testDomain = true; - serverConfig = "TemplateConfg\\WebSocket_TLS_server_config.json"; - clientConfig = "TemplateConfg\\WebSocket_TLS_client_config.json"; - } - else if (String.Equals(ReceiveConfigurationParameters[0], "WebSocketTLSselfSigned")) - { - testDomain = false; - serverConfig = "TemplateConfg\\WebSocketTLS_selfSigned_server_config.json"; - clientConfig = "TemplateConfg\\WebSocketTLS_selfSigned_client_config.json"; - } - else if (String.Equals(ReceiveConfigurationParameters[0], "WebSocketTLS2Web")) - { - testDomain = true; - serverConfig = "TemplateConfg\\WebSocketTLSWeb_server_config.json"; - clientConfig = "TemplateConfg\\WebSocketTLSWeb_client_config.json"; - } - else if (String.Equals(ReceiveConfigurationParameters[0], "Http2")) - { - testDomain = true; - serverConfig = "TemplateConfg\\http2_server_config.json"; - clientConfig = "TemplateConfg\\http2_client_config.json"; - } - else if (String.Equals(ReceiveConfigurationParameters[0], "http2Web")) - { - testDomain = true; - serverConfig = "TemplateConfg\\Http2Web_server_config.json"; - clientConfig = "TemplateConfg\\Http2Web_client_config.json"; - } - else if (String.Equals(ReceiveConfigurationParameters[0], "http2selfSigned")) - { - testDomain = false; - serverConfig = "TemplateConfg\\Http2selfSigned_server_config.json"; - clientConfig = "TemplateConfg\\Http2selfSigned_client_config.json"; - } - //else if (String.Equals(ReceiveConfigurationParameters[0], "MkcpNone")|| String.Equals(ReceiveConfigurationParameters[0], "mKCP2SRTP")||String.Equals(ReceiveConfigurationParameters[0], "mKCPuTP")|| String.Equals(ReceiveConfigurationParameters[0], "mKCP2WechatVideo")|| String.Equals(ReceiveConfigurationParameters[0], "mKCP2DTLS")|| String.Equals(ReceiveConfigurationParameters[0], "mKCP2WireGuard")) - else if (ReceiveConfigurationParameters[0].Contains("mKCP")) - { - testDomain = false; - serverConfig = "TemplateConfg\\mkcp_server_config.json"; - clientConfig = "TemplateConfg\\mkcp_client_config.json"; - } - - // else if (String.Equals(ReceiveConfigurationParameters[0], "QuicNone") || String.Equals(ReceiveConfigurationParameters[0], "QuicSRTP") || String.Equals(ReceiveConfigurationParameters[0], "Quic2uTP") || String.Equals(ReceiveConfigurationParameters[0], "QuicWechatVideo") || String.Equals(ReceiveConfigurationParameters[0], "QuicDTLS") || String.Equals(ReceiveConfigurationParameters[0], "QuicWireGuard")) - else if (ReceiveConfigurationParameters[0].Contains("Quic")) - { - testDomain = false; - serverConfig = "TemplateConfg\\quic_server_config.json"; - clientConfig = "TemplateConfg\\quic_client_config.json"; - } - - //Thread thread - Thread thread = new Thread(() => StartSetUpV2ray(connectionInfo, TextBlockSetUpProcessing, ProgressBarSetUpProcessing, serverConfig, clientConfig, upLoadPath)); - thread.SetApartmentState(ApartmentState.STA); - thread.Start(); - // Task task = new Task(() => StartSetUpRemoteHost(connectionInfo, TextBlockSetUpProcessing, ProgressBarSetUpProcessing, serverConfig, clientConfig, upLoadPath)); - //task.Start(); - } #region 端口数字防错代码,密钥选择代码 @@ -297,7 +79,7 @@ namespace ProxySU { Application.Current.Shutdown(); } - // private static readonly Regex _regex = new Regex("[^0-9]+"); + // private static readonly Regex _regex = new Regex("[^0-9]+"); private void TextBoxPort_PreviewTextInput(object sender, TextCompositionEventArgs e) { Regex regex = new Regex("[^0-9]+"); @@ -438,6 +220,236 @@ namespace ProxySU } #endregion + //远程主机连接信息 + private ConnectionInfo GenerateConnectionInfo() + { + ConnectionInfo connectionInfo; + + #region 检测输入的内空是否有错,并读取内容 + if (string.IsNullOrEmpty(TextBoxHost.Text) == true || string.IsNullOrEmpty(TextBoxPort.Text) == true || string.IsNullOrEmpty(TextBoxUserName.Text) == true) + { + MessageBox.Show("主机地址、主机端口、用户名为必填项,不能为空"); + + return connectionInfo = null; + } + string sshHostName = TextBoxHost.Text.ToString(); + int sshPort = int.Parse(TextBoxPort.Text); + string sshUser = TextBoxUserName.Text.ToString(); + if (RadioButtonPasswordLogin.IsChecked == true && string.IsNullOrEmpty(PasswordBoxHostPassword.Password) == true) + { + MessageBox.Show("登录密码为必填项,不能为空"); + return connectionInfo = null; + } + string sshPassword = PasswordBoxHostPassword.Password.ToString(); + if (RadioButtonCertLogin.IsChecked == true && string.IsNullOrEmpty(TextBoxCertFilePath.Text) == true) + { + MessageBox.Show("密钥文件为必填项,不能为空"); + return connectionInfo = null; + } + string sshPrivateKey = TextBoxCertFilePath.Text.ToString(); + ProxyTypes proxyTypes = new ProxyTypes();//默认为None + + //proxyTypes = ProxyTypes.Socks5; + if (RadioButtonHttp.IsChecked == true) + { + proxyTypes = ProxyTypes.Http; + } + else if (RadioButtonSocks4.IsChecked == true) + { + proxyTypes = ProxyTypes.Socks4; + } + else if (RadioButtonSocks5.IsChecked == true) + { + proxyTypes = ProxyTypes.Socks5; + } + else + { + proxyTypes = ProxyTypes.None; + } + + //MessageBox.Show(proxyTypes.ToString()); + if (RadioButtonNoProxy.IsChecked == false && (string.IsNullOrEmpty(TextBoxProxyHost.Text) == true || string.IsNullOrEmpty(TextBoxProxyPort.Text) == true)) + { + MessageBox.Show("如果选择了代理,则代理地址与端口不能为空"); + return connectionInfo = null; + } + string sshProxyHost = TextBoxProxyHost.Text.ToString(); + int sshProxyPort = int.Parse(TextBoxProxyPort.Text.ToString()); + if (RadioButtonNoProxy.IsChecked==false && RadiobuttonProxyYesLogin.IsChecked == true && (string.IsNullOrEmpty(TextBoxProxyUserName.Text) == true || string.IsNullOrEmpty(PasswordBoxProxyPassword.Password) == true)) + { + MessageBox.Show("如果代理需要登录,则代理登录的用户名与密码不能为空"); + return connectionInfo = null; + } + string sshProxyUser = TextBoxProxyUserName.Text.ToString(); + string sshProxyPassword = PasswordBoxProxyPassword.Password.ToString(); + + #endregion + + + //var connectionInfo = new PasswordConnectionInfo(sshHostName, sshPort, sshUser, sshPassword); + + connectionInfo = new ConnectionInfo( + sshHostName, + sshPort, + sshUser, + proxyTypes, + sshProxyHost, + sshProxyPort, + sshProxyUser, + sshProxyPassword, + new PasswordAuthenticationMethod(sshUser, sshPassword) + //new PrivateKeyAuthenticationMethod(sshUser, new PrivateKeyFile(sshPrivateKey)) + ); + + if (RadioButtonCertLogin.IsChecked == true) + { + connectionInfo = new ConnectionInfo( + sshHostName, + sshPort, + sshUser, + proxyTypes, + sshProxyHost, + sshProxyPort, + sshProxyUser, + sshProxyPassword, + //new PasswordAuthenticationMethod(sshUser, sshPassword) + new PrivateKeyAuthenticationMethod(sshUser, new PrivateKeyFile(sshPrivateKey)) + ); + + } + return connectionInfo; + } + + //打开v2ray模板设置窗口 + private void ButtonTemplateConfiguration_Click(object sender, RoutedEventArgs e) + { + //清空初始化模板参数 + for (int i = 0; i != ReceiveConfigurationParameters.Length; i++) + + { + ReceiveConfigurationParameters[i] = ""; + } + WindowTemplateConfiguration windowTemplateConfiguration = new WindowTemplateConfiguration(); + windowTemplateConfiguration.ShowDialog(); + } + //传送V2Ray模板参数,启动V2Ray安装进程 + private void Button_Login_Click(object sender, RoutedEventArgs e) + + { + ConnectionInfo connectionInfo = GenerateConnectionInfo(); + if(connectionInfo==null) + { + MessageBox.Show("远程主机连接信息有误,请检查"); + return; + } + + //读取模板配置 + + string serverConfig=""; //服务端配置文件 + string clientConfig = ""; //生成的客户端配置文件 + string upLoadPath = "/usr/local/etc/v2ray/config.json"; //服务端文件位置 + //生成客户端配置时,连接的服务主机的IP或者域名 + if (String.IsNullOrEmpty(ReceiveConfigurationParameters[4])==true) + { + ReceiveConfigurationParameters[4] = TextBoxHost.Text.ToString(); + testDomain = false; + } + //选择模板 + if (String.IsNullOrEmpty(ReceiveConfigurationParameters[0]) == true) + { + MessageBox.Show("请先选择配置模板!"); + return; + } + else if (String.Equals(ReceiveConfigurationParameters[0], "TCP")) + { + testDomain = false; + serverConfig = "TemplateConfg\\tcp_server_config.json"; + clientConfig = "TemplateConfg\\tcp_client_config.json"; + } + else if (String.Equals(ReceiveConfigurationParameters[0], "TCPhttp")) + { + testDomain = false; + serverConfig = "TemplateConfg\\tcp_http_server_config.json"; + clientConfig = "TemplateConfg\\tcp_http_client_config.json"; + } + else if (String.Equals(ReceiveConfigurationParameters[0], "tcpTLS")) + { + testDomain = true; + serverConfig = "TemplateConfg\\tcp_TLS_server_config.json"; + clientConfig = "TemplateConfg\\tcp_TLS_client_config.json"; + } + else if (String.Equals(ReceiveConfigurationParameters[0], "tcpTLSselfSigned")) + { + testDomain = false; + serverConfig = "TemplateConfg\\tcpTLSselfSigned_server_config.json"; + clientConfig = "TemplateConfg\\tcpTLSselfSigned_client_config.json"; + } + else if (String.Equals(ReceiveConfigurationParameters[0], "webSocket")) + { + testDomain = false; + serverConfig = "TemplateConfg\\webSocket_server_config.json"; + clientConfig = "TemplateConfg\\webSocket_client_config.json"; + } + else if (String.Equals(ReceiveConfigurationParameters[0], "WebSocketTLS")) + { + testDomain = true; + serverConfig = "TemplateConfg\\WebSocket_TLS_server_config.json"; + clientConfig = "TemplateConfg\\WebSocket_TLS_client_config.json"; + } + else if (String.Equals(ReceiveConfigurationParameters[0], "WebSocketTLSselfSigned")) + { + testDomain = false; + serverConfig = "TemplateConfg\\WebSocketTLS_selfSigned_server_config.json"; + clientConfig = "TemplateConfg\\WebSocketTLS_selfSigned_client_config.json"; + } + else if (String.Equals(ReceiveConfigurationParameters[0], "WebSocketTLS2Web")) + { + testDomain = true; + serverConfig = "TemplateConfg\\WebSocketTLSWeb_server_config.json"; + clientConfig = "TemplateConfg\\WebSocketTLSWeb_client_config.json"; + } + else if (String.Equals(ReceiveConfigurationParameters[0], "Http2")) + { + testDomain = true; + serverConfig = "TemplateConfg\\http2_server_config.json"; + clientConfig = "TemplateConfg\\http2_client_config.json"; + } + else if (String.Equals(ReceiveConfigurationParameters[0], "http2Web")) + { + testDomain = true; + serverConfig = "TemplateConfg\\Http2Web_server_config.json"; + clientConfig = "TemplateConfg\\Http2Web_client_config.json"; + } + else if (String.Equals(ReceiveConfigurationParameters[0], "http2selfSigned")) + { + testDomain = false; + serverConfig = "TemplateConfg\\Http2selfSigned_server_config.json"; + clientConfig = "TemplateConfg\\Http2selfSigned_client_config.json"; + } + //else if (String.Equals(ReceiveConfigurationParameters[0], "MkcpNone")|| String.Equals(ReceiveConfigurationParameters[0], "mKCP2SRTP")||String.Equals(ReceiveConfigurationParameters[0], "mKCPuTP")|| String.Equals(ReceiveConfigurationParameters[0], "mKCP2WechatVideo")|| String.Equals(ReceiveConfigurationParameters[0], "mKCP2DTLS")|| String.Equals(ReceiveConfigurationParameters[0], "mKCP2WireGuard")) + else if (ReceiveConfigurationParameters[0].Contains("mKCP")) + { + testDomain = false; + serverConfig = "TemplateConfg\\mkcp_server_config.json"; + clientConfig = "TemplateConfg\\mkcp_client_config.json"; + } + + // else if (String.Equals(ReceiveConfigurationParameters[0], "QuicNone") || String.Equals(ReceiveConfigurationParameters[0], "QuicSRTP") || String.Equals(ReceiveConfigurationParameters[0], "Quic2uTP") || String.Equals(ReceiveConfigurationParameters[0], "QuicWechatVideo") || String.Equals(ReceiveConfigurationParameters[0], "QuicDTLS") || String.Equals(ReceiveConfigurationParameters[0], "QuicWireGuard")) + else if (ReceiveConfigurationParameters[0].Contains("Quic")) + { + testDomain = false; + serverConfig = "TemplateConfg\\quic_server_config.json"; + clientConfig = "TemplateConfg\\quic_client_config.json"; + } + + //Thread thread + Thread thread = new Thread(() => StartSetUpV2ray(connectionInfo, TextBlockSetUpProcessing, ProgressBarSetUpProcessing, serverConfig, clientConfig, upLoadPath)); + thread.SetApartmentState(ApartmentState.STA); + thread.Start(); + // Task task = new Task(() => StartSetUpRemoteHost(connectionInfo, TextBlockSetUpProcessing, ProgressBarSetUpProcessing, serverConfig, clientConfig, upLoadPath)); + //task.Start(); + + } //登录远程主机布署V2ray程序 private void StartSetUpV2ray(ConnectionInfo connectionInfo,TextBlock textBlockName, ProgressBar progressBar, string serverConfig,string clientConfig,string upLoadPath) { @@ -741,29 +753,29 @@ namespace ProxySU //设置uuid serverJson["inbounds"][0]["settings"]["clients"][0]["id"] = ReceiveConfigurationParameters[2]; //除WebSocketTLSWeb/http2Web模式外设置监听端口 - if (ReceiveConfigurationParameters[0].Contains("WebSocketTLS2Web") == false && ReceiveConfigurationParameters[0].Contains("http2Web") == false) + if (String.Equals(ReceiveConfigurationParameters[0], "WebSocketTLS2Web") == false && String.Equals(ReceiveConfigurationParameters[0], "http2Web") == false) { serverJson["inbounds"][0]["port"] = int.Parse(ReceiveConfigurationParameters[1]); } - //TLS自签证书/WebSocketTLS(自签证书)/http2Web/http2自签证书模式下,使用v2ctl 生成自签证书 - if (ReceiveConfigurationParameters[0].Contains("WebSocketTLSselfSigned") == true || ReceiveConfigurationParameters[0].Contains("tcpTLSselfSigned") == true || ReceiveConfigurationParameters[0].Contains("http2Web") == true || ReceiveConfigurationParameters[0].Contains("http2selfSigned") == true) + //TLS自签证书/WebSocketTLS(自签证书)/http2自签证书模式下,使用v2ctl 生成自签证书 + if (String.Equals(ReceiveConfigurationParameters[0], "WebSocketTLSselfSigned") == true || String.Equals(ReceiveConfigurationParameters[0], "tcpTLSselfSigned") == true || String.Equals(ReceiveConfigurationParameters[0], "http2selfSigned") == true) { string selfSignedCa = client.RunCommand("/usr/local/bin/v2ctl cert --ca").Result; JObject selfSignedCaJObject = JObject.Parse(selfSignedCa); serverJson["inbounds"][0]["streamSettings"]["tlsSettings"]["certificates"][0] = selfSignedCaJObject; } //如果是WebSocketTLSWeb/WebSocketTLS/WebSocketTLS(自签证书)模式,则设置路径 - if (ReceiveConfigurationParameters[0].Contains("WebSocketTLS") == true || ReceiveConfigurationParameters[0].Contains("WebSocketTLSselfSigned") == true || ReceiveConfigurationParameters[0].Contains("WebSocketTLS2Web") == true) + if (String.Equals(ReceiveConfigurationParameters[0], "WebSocketTLS") == true || String.Equals(ReceiveConfigurationParameters[0], "WebSocketTLSselfSigned") == true || String.Equals(ReceiveConfigurationParameters[0], "WebSocketTLS2Web") == true) { serverJson["inbounds"][0]["streamSettings"]["wsSettings"]["path"] = ReceiveConfigurationParameters[3]; } - //如果是Http2模式下,设置路径 - if (ReceiveConfigurationParameters[0].Contains("Http2") == true || ReceiveConfigurationParameters[0].Contains("http2Web") == true || ReceiveConfigurationParameters[0].Contains("http2selfSigned") == true) + //如果是Http2/http2Web/http2自签模式下,设置路径 + if (String.Equals(ReceiveConfigurationParameters[0], "Http2") == true || String.Equals(ReceiveConfigurationParameters[0], "http2Web") == true || String.Equals(ReceiveConfigurationParameters[0], "http2selfSigned") == true) { serverJson["inbounds"][0]["streamSettings"]["httpSettings"]["path"] = ReceiveConfigurationParameters[3]; } //如果是Http2Web模式下,设置host - if (ReceiveConfigurationParameters[0].Contains("http2Web") == true) + if (String.Equals(ReceiveConfigurationParameters[0], "http2Web") == true) { // serverJson["inbounds"][0]["streamSettings"]["httpSettings"]["path"] = ReceiveConfigurationParameters[3]; serverJson["inbounds"][0]["streamSettings"]["httpSettings"]["host"][0] = ReceiveConfigurationParameters[4]; @@ -834,11 +846,12 @@ namespace ProxySU textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); Thread.Sleep(1000); - + //安装Caddy //为假则表示系统有相应的组件。 if (getApt == false) { client.RunCommand(@"echo ""deb [trusted=yes] https://apt.fury.io/caddy/ /"" | tee -a /etc/apt/sources.list.d/caddy-fury.list"); + client.RunCommand("apt install -y apt-transport-https"); client.RunCommand("apt -qq update"); client.RunCommand("apt -y -qq install caddy"); } @@ -878,6 +891,19 @@ namespace ProxySU Thread.Sleep(1000); client.RunCommand("systemctl enable caddy"); } + //在Caddy 2还未推出2.2.0的正式版之前,先用测试版替代 + if (String.Equals(ReceiveConfigurationParameters[0], "http2Web")) + { + currentStatus = "正在为Http2Web模式升级Caddy v2.2.0测试版!"; + textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); + Thread.Sleep(1000); + + client.RunCommand(@"curl -o /tmp/caddy.zip https://raw.githubusercontent.com/proxysu/Resources/master/Caddy2/caddy.zip"); + client.RunCommand(@"unzip /tmp/caddy.zip"); + client.RunCommand(@"chmod +x caddy"); + client.RunCommand(@"systemctl stop caddy;rm -f /usr/bin/caddy"); + client.RunCommand(@"cp /root/caddy /usr/bin/"); + } currentStatus = "上传Caddy配置文件......"; textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); Thread.Sleep(1000); @@ -1001,23 +1027,26 @@ namespace ProxySU using (StreamReader reader = File.OpenText(clientConfig)) { JObject clientJson = (JObject)JToken.ReadFrom(new JsonTextReader(reader)); - + //设置客户端的地址/端口/id clientJson["outbounds"][0]["settings"]["vnext"][0]["address"] = ReceiveConfigurationParameters[4]; clientJson["outbounds"][0]["settings"]["vnext"][0]["port"] = int.Parse(ReceiveConfigurationParameters[1]); clientJson["outbounds"][0]["settings"]["vnext"][0]["users"][0]["id"] = ReceiveConfigurationParameters[2]; - if (clientConfig.Contains("WebSocket")==true) + //设置WebSocket系统模式下的path + if (String.Equals(ReceiveConfigurationParameters[0], "WebSocketTLS") == true || String.Equals(ReceiveConfigurationParameters[0], "WebSocketTLSselfSigned") == true || String.Equals(ReceiveConfigurationParameters[0], "WebSocketTLS2Web") == true) { clientJson["outbounds"][0]["streamSettings"]["wsSettings"]["path"] = ReceiveConfigurationParameters[3]; } - if (clientConfig.Contains("http2") == true|| clientConfig.Contains("Http2") == true) + //设置http2模式下的path + if (String.Equals(ReceiveConfigurationParameters[0], "Http2") == true|| String.Equals(ReceiveConfigurationParameters[0], "http2Web") == true || String.Equals(ReceiveConfigurationParameters[0], "http2selfSigned") == true) { clientJson["outbounds"][0]["streamSettings"]["httpSettings"]["path"] = ReceiveConfigurationParameters[3]; } - if (clientConfig.Contains("Http2Web") == true) + //设置http2web模式下的host + if (String.Equals(ReceiveConfigurationParameters[0], "http2Web") == true) { clientJson["outbounds"][0]["streamSettings"]["httpSettings"]["host"][0] = ReceiveConfigurationParameters[4]; } - if (clientConfig.Contains("mkcp")==true) + if (ReceiveConfigurationParameters[0].Contains("mKCP") ==true) { clientJson["outbounds"][0]["streamSettings"]["kcpSettings"]["header"]["type"] = ReceiveConfigurationParameters[5]; if (String.IsNullOrEmpty(ReceiveConfigurationParameters[6]) == false) @@ -1025,7 +1054,7 @@ namespace ProxySU clientJson["outbounds"][0]["streamSettings"]["kcpSettings"]["seed"] = ReceiveConfigurationParameters[6]; } } - if (clientConfig.Contains("quic") == true) + if (ReceiveConfigurationParameters[0].Contains("Quic") == true) { clientJson["outbounds"][0]["streamSettings"]["quicSettings"]["header"]["type"] = ReceiveConfigurationParameters[5]; clientJson["outbounds"][0]["streamSettings"]["quicSettings"]["key"] = ReceiveConfigurationParameters[6]; @@ -1089,7 +1118,224 @@ namespace ProxySU #endregion } - + + //检测升级远程主机端的V2Ray版本 + private void ButtonUpdateV2ray_Click(object sender, RoutedEventArgs e) + { + ConnectionInfo connectionInfo = GenerateConnectionInfo(); + if (connectionInfo == null) + { + MessageBox.Show("远程主机连接信息有误,请检查"); + return; + } + + Thread thread = new Thread(() => UpdateV2ray(connectionInfo, TextBlockSetUpProcessing, ProgressBarSetUpProcessing)); + thread.SetApartmentState(ApartmentState.STA); + thread.Start(); + } + //升级V2ray主程序 + private void UpdateV2ray(ConnectionInfo connectionInfo, TextBlock textBlockName, ProgressBar progressBar) + { + string currentStatus = "正在登录远程主机......"; + Action updateAction = new Action(UpdateTextBlock); + textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); + + try + { + #region 主机指纹,暂未启用 + //byte[] expectedFingerPrint = new byte[] { + // 0x66, 0x31, 0xaf, 0x00, 0x54, 0xb9, 0x87, 0x31, + // 0xff, 0x58, 0x1c, 0x31, 0xb1, 0xa2, 0x4c, 0x6b + // }; + #endregion + using (var client = new SshClient(connectionInfo)) + + { + #region ssh登录验证主机指纹代码块,暂未启用 + // client.HostKeyReceived += (sender, e) => + // { + // if (expectedFingerPrint.Length == e.FingerPrint.Length) + // { + // for (var i = 0; i < expectedFingerPrint.Length; i++) + // { + // if (expectedFingerPrint[i] != e.FingerPrint[i]) + // { + // e.CanTrust = false; + // break; + // } + // } + // } + // else + // { + // e.CanTrust = false; + // } + // }; + #endregion + + client.Connect(); + if (client.IsConnected == true) + { + currentStatus = "主机登录成功"; + textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); + Thread.Sleep(1000); + } + //检测是否运行在root权限下 + string testRootAuthority = client.RunCommand(@"id -u").Result; + if (testRootAuthority.Equals("0\n") == false) + { + MessageBox.Show("请使用具有root权限的账户登录主机!!"); + client.Disconnect(); + return; + } + //检测远程主机V2ray版本 + currentStatus = "检测远程主机V2ray版本......"; + textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); + Thread.Sleep(1000); + //检测是否安装V2Ray + string resultCmdTestV2rayInstalled = client.RunCommand(@"find / -name v2ray").Result; + + if (resultCmdTestV2rayInstalled.Contains("/usr/bin/v2ray") == false && resultCmdTestV2rayInstalled.Contains("/usr/local/bin/v2ray") == false) + { + MessageBoxResult messageBoxResult = MessageBox.Show("远程主机未安装V2ray!"); + + currentStatus = "未安装V2ray,退出"; + textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); + Thread.Sleep(1000); + client.Disconnect(); + return; + + } + else if (resultCmdTestV2rayInstalled.Contains("/usr/bin/v2ray") == true) + { + client.RunCommand("curl -o /tmp/go.sh https://raw.githubusercontent.com/proxysu/shellscript/master/v2ray/go.sh"); + client.RunCommand("bash /tmp/go.sh --remove"); + string installResult = client.RunCommand("find / -name v2ray").Result.ToString(); + + if (!installResult.Contains("/usr/bin/v2ray")) + { + currentStatus = "删除旧版本,OK"; + textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); + Thread.Sleep(1000); + } + currentStatus = "安装新版本。。。。。。"; + textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); + Thread.Sleep(1000); + + client.RunCommand("curl -o /tmp/go.sh https://raw.githubusercontent.com/v2fly/fhs-install-v2ray/master/install-release.sh"); + client.RunCommand("bash /tmp/go.sh -f"); + installResult = client.RunCommand("find / -name v2ray").Result.ToString(); + + if (!installResult.Contains("/usr/local/bin/v2ray")) + { + MessageBox.Show("安装V2ray失败(官方脚本运行出错!"); + + currentStatus = "安装V2ray失败(官方脚本运行出错!"; + textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); + client.Disconnect(); + return; + } + client.RunCommand(@"mv /etc/v2ray/config.json /usr/local/etc/v2ray/"); + client.RunCommand(@"systemctl restart v2ray"); + currentStatus = "已更新到最新版本。"; + textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); + Thread.Sleep(1000); + } + string sshcmd; + sshcmd = @"/usr/local/bin/v2ray -version | head -n 1 | cut -d "" "" -f2"; + + string v2rayCurrentVersion = client.RunCommand(sshcmd).Result;//不含字母v + + sshcmd = @"curl -H ""Accept: application/json"" -H ""User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:74.0) Gecko/20100101 Firefox/74.0"" -s ""https://api.github.com/repos/v2fly/v2ray-core/releases/latest"" --connect-timeout 10| grep 'tag_name' | cut -d\"" -f4"; + + string v2rayNewVersion = client.RunCommand(sshcmd).Result;//包含字母v + + if (v2rayNewVersion.Contains(v2rayCurrentVersion) == false) + { + MessageBoxResult messageBoxResult = MessageBox.Show($"远程主机当前版本为:v{v2rayCurrentVersion}\n最新版本为:{v2rayNewVersion}\n是否升级为最新版本?", "", MessageBoxButton.YesNo, MessageBoxImage.Question); + if (messageBoxResult == MessageBoxResult.Yes) + { + currentStatus = "正在升级V2ray到最新版本......"; + textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); + Thread.Sleep(1000); + client.RunCommand(@"bash <(curl -L -s https://raw.githubusercontent.com/v2fly/fhs-install-v2ray/master/install-release.sh)"); + sshcmd = @"/usr/local/bin/v2ray -version | head -n 1 | cut -d "" "" -f2"; + + v2rayCurrentVersion = client.RunCommand(sshcmd).Result;//不含字母v + if (v2rayNewVersion.Contains(v2rayCurrentVersion) == true) + { + MessageBox.Show($"升级成功!!\n当前版本为:v{v2rayCurrentVersion}\n最新版本为:{v2rayNewVersion}"); + currentStatus = "升级成功!当前已是最新版本!"; + textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); + Thread.Sleep(1000); + } + else + { + MessageBox.Show("升级失败,原因未知,请向开发者提问,以寻求支持!"); + currentStatus = "升级失败!"; + textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); + Thread.Sleep(1000); + } + } + else + { + currentStatus = "升级取消,退出"; + textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); + Thread.Sleep(1000); + client.Disconnect(); + return; + } + } + else + { + MessageBox.Show($"远程主机当前已是最新版本:{v2rayNewVersion}\n无需升级!"); + currentStatus = "已是最新版本,无需升级,退出"; + textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); + Thread.Sleep(1000); + } + + client.Disconnect(); + return; + } + } + catch (Exception ex1)//例外处理 + #region 例外处理 + { + //MessageBox.Show(ex1.Message); + if (ex1.Message.Contains("连接尝试失败") == true) + { + MessageBox.Show($"{ex1.Message}\n请检查主机地址及端口是否正确,如果通过代理,请检查代理是否正常工作"); + } + + else if (ex1.Message.Contains("denied (password)") == true) + { + MessageBox.Show($"{ex1.Message}\n密码错误或用户名错误"); + } + else if (ex1.Message.Contains("Invalid private key file") == true) + { + MessageBox.Show($"{ex1.Message}\n所选密钥文件错误或者格式不对"); + } + else if (ex1.Message.Contains("denied (publickey)") == true) + { + MessageBox.Show($"{ex1.Message}\n使用密钥登录,密钥文件错误或用户名错误"); + } + else if (ex1.Message.Contains("目标计算机积极拒绝") == true) + { + MessageBox.Show($"{ex1.Message}\n主机地址错误,如果使用了代理,也可能是连接代理的端口错误"); + } + else + { + MessageBox.Show("发生错误"); + MessageBox.Show(ex1.Message); + } + currentStatus = "主机登录失败"; + textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); + + } + #endregion + + } + + //上传配置文件 private void UploadConfig(ConnectionInfo connectionInfo,string uploadConfig,string upLoadPath) { @@ -1115,7 +1361,6 @@ namespace ProxySU return; } } - //下载配置文件 private void DownloadConfig(ConnectionInfo connectionInfo, string downloadConfig,string downloadPath) { @@ -1136,7 +1381,8 @@ namespace ProxySU catch (Exception ex2) { MessageBox.Show("sftp" + ex2.ToString()); - MessageBox.Show("sftp出现未知错误"); + MessageBox.Show("sftp出现未知错误,下载文件失败,请重试!"); + return; } } @@ -1228,18 +1474,7 @@ namespace ProxySU } - //打开v2ray模板设置窗口 - private void ButtonTemplateConfiguration_Click(object sender, RoutedEventArgs e) - { - //清空初始化模板参数 - for (int i = 0; i != ReceiveConfigurationParameters.Length; i++) - - { - ReceiveConfigurationParameters[i] = ""; - } - WindowTemplateConfiguration windowTemplateConfiguration = new WindowTemplateConfiguration(); - windowTemplateConfiguration.ShowDialog(); - } + //打开系统工具中的校对时间窗口 private void ButtonProofreadTime_Click(object sender, RoutedEventArgs e) { @@ -1313,6 +1548,7 @@ namespace ProxySU MessageBox.Show(ex.Message); } } + //private void ButtonGuideConfiguration_Click(object sender, RoutedEventArgs e) //{ // MessageBox.Show("尚未完善,敬请期待"); @@ -1323,6 +1559,7 @@ namespace ProxySU // MessageBox.Show("尚未完善,敬请期待"); //} + #region 资源工具标签页控制 private void ButtonWebBrowserBack_Click(object sender, RoutedEventArgs e) { try @@ -1358,7 +1595,7 @@ namespace ProxySU MessageBox.Show(ex.Message); } } - + #endregion //打开Trojan参数设置界面 private void ButtonTrojanTemplate_Click(object sender, RoutedEventArgs e) @@ -1371,8 +1608,7 @@ namespace ProxySU TrojanTemplateWindow windowTrojanTemplateConfiguration = new TrojanTemplateWindow(); windowTrojanTemplateConfiguration.ShowDialog(); } - - //Trojan一键安装 + //Trojan参数传递 private void ButtonTrojanSetUp_Click(object sender, RoutedEventArgs e) { ConnectionInfo connectionInfo = GenerateConnectionInfo(); @@ -1402,7 +1638,6 @@ namespace ProxySU thread.SetApartmentState(ApartmentState.STA); thread.Start(); } - //登录远程主机布署Trojan程序 private void StartSetUpTrojan(ConnectionInfo connectionInfo, TextBlock textBlockName, ProgressBar progressBar, string serverConfig, string clientConfig, string upLoadPath) { @@ -1458,12 +1693,25 @@ namespace ProxySU client.Disconnect(); return; } + //检测远程主机系统环境是否符合要求 + currentStatus = "检测系统是否符合安装要求......"; + textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); + Thread.Sleep(1000); + + string resultCmd = client.RunCommand("uname -m").Result; + + if (resultCmd.Contains("x86_64") == false) + { + MessageBox.Show($"请在x86_64系统中安装Trojan"); + currentStatus = "系统不符合要求,安装失败!!"; + textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); + Thread.Sleep(1000); + } //检测是否安装有Trojan currentStatus = "检测系统是否已经安装Trojan......"; textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); Thread.Sleep(1000); - //string cmdTestTrojanInstalled = @"find / -name trojan"; string resultCmdTestTrojanInstalled = client.RunCommand(@"find / -name trojan").Result; if (resultCmdTestTrojanInstalled.Contains("/usr/local/bin/trojan") == true) @@ -1479,36 +1727,18 @@ namespace ProxySU } } - //检测远程主机系统环境是否符合要求 - currentStatus = "检测系统是否符合安装要求......"; - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - Thread.Sleep(1000); - - string resultCmd = client.RunCommand("uname -m").Result; - //var result = client.RunCommand("cat /root/test.ver"); - //string[] linuxKernelVerStr = resultCmd.Split('-'); - - //bool detectResult = DetectKernelVersion(linuxKernelVerStr[0]); - - if (resultCmd.Contains("x86_64") == false) - { - MessageBox.Show($"请在x86_64系统中安装Trojan"); - currentStatus = "系统不符合要求,安装失败!!"; - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - Thread.Sleep(1000); - } - //检测系统是否支持yum 或 apt或zypper,且支持Systemd //如果不存在组件,则命令结果为空,string.IsNullOrEmpty值为真, bool getApt = String.IsNullOrEmpty(client.RunCommand("command -v apt").Result); + bool getDnf = String.IsNullOrEmpty(client.RunCommand("command -v dnf").Result); bool getYum = String.IsNullOrEmpty(client.RunCommand("command -v yum").Result); bool getZypper = String.IsNullOrEmpty(client.RunCommand("command -v zypper").Result); bool getSystemd = String.IsNullOrEmpty(client.RunCommand("command -v systemctl").Result); bool getGetenforce = String.IsNullOrEmpty(client.RunCommand("command -v getenforce").Result); - //没有安装apt,也没有安装yum,也没有安装zypper,或者没有安装systemd的,不满足安装条件 - //也就是apt ,yum, zypper必须安装其中之一,且必须安装Systemd的系统才能安装。 - if ((getApt && getYum && getZypper) || getSystemd) + //没有安装apt,也没有安装dnf\yum,也没有安装zypper,或者没有安装systemd的,不满足安装条件 + //也就是apt ,dnf\yum, zypper必须安装其中之一,且必须安装Systemd的系统才能安装。 + if ((getApt && getDnf && getYum && getZypper) || getSystemd) { MessageBox.Show($"系统缺乏必要的安装组件如:apt-get||yum||zypper||Syetemd,主机系统推荐使用:CentOS 7/8,Debian 8/9/10,Ubuntu 16.04及以上版本"); currentStatus = "系统环境不满足要求,安装失败!!"; @@ -1530,129 +1760,123 @@ namespace ProxySU } } + //在相应系统内安装curl(如果没有安装curl) + if (string.IsNullOrEmpty(client.RunCommand("command -v curl").Result) == true) + { + //为假则表示系统有相应的组件。 + if (getApt == false) + { + client.RunCommand("apt -qq update"); + client.RunCommand("apt -y -qq install curl"); + } + else if (getDnf == false) + { + client.RunCommand("dnf -q makecache"); + client.RunCommand("dnf -y -q install curl"); + } + else if (getYum == false) + { + client.RunCommand("yum -q makecache"); + client.RunCommand("yum -y -q install curl"); + } + //else if (getZypper == false) + //{ + // client.RunCommand("zypper ref"); + // client.RunCommand("zypper -y install curl"); + //} + } + //检测域名是否解析正确 + currentStatus = "正在检测域名是否解析到当前VPS的IP上......"; + textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); + Thread.Sleep(1000); + string nativeIp = client.RunCommand("curl -4 ip.sb").Result.ToString(); + string testDomainCmd = "ping " + ReceiveConfigurationParameters[4] + " -c 1 | grep -oE -m1 \"([0-9]{1,3}\\.){3}[0-9]{1,3}\""; + string resultTestDomainCmd = client.RunCommand(testDomainCmd).Result.ToString(); + if (String.Equals(nativeIp, resultTestDomainCmd) == true) + { + currentStatus = "解析正确!"; + textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); + Thread.Sleep(1000); + } + else + { + currentStatus = "域名未能正确解析到当前VPS的IP上!安装失败!"; + textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); + Thread.Sleep(1000); + MessageBox.Show("域名未能正确解析到当前VPS的IP上,请检查!若解析设置正确,请等待生效后再重试安装。如果域名使用了CDN,请先关闭!"); + client.Disconnect(); + return; + } - //如果使用如果是WebSocket + TLS + Web/http2/Http2Web/tcp_TLS/WebSocket_TLS模式,需要检测域名解析是否正确 - //if (serverConfig.Contains("trojan_server") == true) - //{ - currentStatus = "正在检测域名是否解析到当前VPS的IP上......"; + //检测是否安装lsof + if (string.IsNullOrEmpty(client.RunCommand("command -v lsof").Result) == true) + { + //为假则表示系统有相应的组件。 + if (getApt == false) + { + client.RunCommand("apt-get -qq update"); + client.RunCommand("apt-get -y -qq install lsof"); + } + else if (getDnf == false) + { + client.RunCommand("dnf -q makecache"); + client.RunCommand("dnf -y -q install lsof"); + } + else if (getYum == false) + { + client.RunCommand("yum -q makecache"); + client.RunCommand("yum -y -q install lsof"); + } + //else if (getZypper == false) + //{ + // client.RunCommand("zypper ref"); + // client.RunCommand("zypper -y install lsof"); + //} + } + currentStatus = "正在检测端口占用情况......"; textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); Thread.Sleep(1000); - //在相应系统内安装curl(如果没有安装curl) - if (string.IsNullOrEmpty(client.RunCommand("command -v curl").Result) == true) + if (String.IsNullOrEmpty(client.RunCommand(@"lsof -n -P -i :80 | grep LISTEN").Result) == false || String.IsNullOrEmpty(client.RunCommand(@"lsof -n -P -i :443 | grep LISTEN").Result) == false) + { + MessageBoxResult dialogResult = MessageBox.Show("80/443端口之一,或全部被占用,将强制停止占用80/443端口的程序?", "Stop application", MessageBoxButton.YesNo); + if (dialogResult == MessageBoxResult.No) { - //为假则表示系统有相应的组件。 - if (getApt == false) - { - client.RunCommand("apt-get -qq update"); - client.RunCommand("apt-get -y -qq install curl"); - } - if (getYum == false) - { - client.RunCommand("yum -q makecache"); - client.RunCommand("yum -y -q install curl"); - } - if (getZypper == false) - { - client.RunCommand("zypper ref"); - client.RunCommand("zypper -y install curl"); - } - } - - string nativeIp = client.RunCommand("curl -4 ip.sb").Result.ToString(); - //MessageBox.Show(nativeIp); - string testDomainCmd = "ping " + ReceiveConfigurationParameters[4] + " -c 1 | grep -oE -m1 \"([0-9]{1,3}\\.){3}[0-9]{1,3}\""; - //MessageBox.Show(testDomainCmd); - string resultTestDomainCmd = client.RunCommand(testDomainCmd).Result.ToString(); - //MessageBox.Show(resultTestDomainCmd); - if (String.Equals(nativeIp, resultTestDomainCmd) == true) - { - currentStatus = "解析正确!"; + currentStatus = "端口被占用,安装失败......"; textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); Thread.Sleep(1000); - } - else - { - currentStatus = "域名未能正确解析到当前VPS的IP上!安装失败!"; - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - Thread.Sleep(1000); - MessageBox.Show("域名未能正确解析到当前VPS的IP上,请检查!若解析设置正确,请等待生效后再重试安装。如果域名使用了CDN,请先关闭!"); client.Disconnect(); return; } - //} - //if (serverConfig.Contains("trojan_server") == true) - //{ - //检测是否安装lsof - if (string.IsNullOrEmpty(client.RunCommand("command -v lsof").Result) == true) - { - //为假则表示系统有相应的组件。 - if (getApt == false) - { - client.RunCommand("apt-get -qq update"); - client.RunCommand("apt-get -y -qq install lsof"); - } - if (getYum == false) - { - client.RunCommand("yum -q makecache"); - client.RunCommand("yum -y -q install lsof"); - } - if (getZypper == false) - { - client.RunCommand("zypper ref"); - client.RunCommand("zypper -y install lsof"); - } - } - currentStatus = "正在检测端口占用情况......"; + currentStatus = "正在释放80/443端口......"; textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); Thread.Sleep(1000); - //MessageBox.Show(@"lsof -n -P -i :80 | grep LISTEN"); - //MessageBox.Show(client.RunCommand(@"lsof -n -P -i :80 | grep LISTEN").Result); - if (String.IsNullOrEmpty(client.RunCommand(@"lsof -n -P -i :80 | grep LISTEN").Result) == false || String.IsNullOrEmpty(client.RunCommand(@"lsof -n -P -i :443 | grep LISTEN").Result) == false) + + string cmdTestPort = @"lsof -n -P -i :443 | grep LISTEN"; + string cmdResult = client.RunCommand(cmdTestPort).Result; + + if (String.IsNullOrEmpty(cmdResult) == false) { - MessageBoxResult dialogResult = MessageBox.Show("80/443端口之一,或全部被占用,将强制停止占用80/443端口的程序?", "Stop application", MessageBoxButton.YesNo); - if (dialogResult == MessageBoxResult.No) - { - currentStatus = "端口被占用,安装失败......"; - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - Thread.Sleep(1000); - client.Disconnect(); - return; - } - - currentStatus = "正在释放80/443端口......"; - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - Thread.Sleep(1000); - - string cmdTestPort = @"lsof -n -P -i :443 | grep LISTEN"; - string cmdResult = client.RunCommand(cmdTestPort).Result; - //MessageBox.Show(cmdTestPort); - if (String.IsNullOrEmpty(cmdResult) == false) - { - //MessageBox.Show(cmdResult); - string[] cmdResultArry443 = cmdResult.Split(' '); - //MessageBox.Show(cmdResultArry443[3]); - client.RunCommand($"systemctl stop {cmdResultArry443[0]}"); - client.RunCommand($"systemctl disable {cmdResultArry443[0]}"); - client.RunCommand($"kill -9 {cmdResultArry443[3]}"); - } - - cmdTestPort = @"lsof -n -P -i :80 | grep LISTEN"; - cmdResult = client.RunCommand(cmdTestPort).Result; - if (String.IsNullOrEmpty(cmdResult) == false) - { - string[] cmdResultArry80 = cmdResult.Split(' '); - client.RunCommand($"systemctl stop {cmdResultArry80[0]}"); - client.RunCommand($"systemctl disable {cmdResultArry80[0]}"); - client.RunCommand($"kill -9 {cmdResultArry80[3]}"); - } - currentStatus = "80/443端口释放完毕!"; - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - Thread.Sleep(1000); - + string[] cmdResultArry443 = cmdResult.Split(' '); + client.RunCommand($"systemctl stop {cmdResultArry443[0]}"); + client.RunCommand($"systemctl disable {cmdResultArry443[0]}"); + client.RunCommand($"kill -9 {cmdResultArry443[3]}"); } - // } + + cmdTestPort = @"lsof -n -P -i :80 | grep LISTEN"; + cmdResult = client.RunCommand(cmdTestPort).Result; + if (String.IsNullOrEmpty(cmdResult) == false) + { + string[] cmdResultArry80 = cmdResult.Split(' '); + client.RunCommand($"systemctl stop {cmdResultArry80[0]}"); + client.RunCommand($"systemctl disable {cmdResultArry80[0]}"); + client.RunCommand($"kill -9 {cmdResultArry80[3]}"); + } + currentStatus = "80/443端口释放完毕!"; + textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); + Thread.Sleep(1000); + } currentStatus = "符合安装要求,布署中......"; textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); Thread.Sleep(1000); @@ -1664,16 +1888,21 @@ namespace ProxySU client.RunCommand("apt-get -qq update"); client.RunCommand("apt-get -y -qq install xz-utils"); } - if (getYum == false) + else if (getDnf == false) + { + //client.RunCommand("yum -q makecache"); + client.RunCommand("dnf -y -q install xz-utils"); + } + else if (getYum == false) { client.RunCommand("yum -q makecache"); client.RunCommand("yum -y -q install xz-utils"); } - if (getZypper == false) - { - client.RunCommand("zypper ref"); - client.RunCommand("zypper -y install xz-utils"); - } + //else if (getZypper == false) + //{ + // client.RunCommand("zypper ref"); + // client.RunCommand("zypper -y install xz-utils"); + //} //下载官方安装脚本安装 @@ -1750,112 +1979,148 @@ namespace ProxySU } } - + currentStatus = "使用Trojan+TLS+Web模式,正在安装acme.sh......"; + textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); + Thread.Sleep(1000); - //if (serverConfig.Contains("trojan_server") == true) + if (getApt == false) + { + //client.RunCommand("apt-get -qq update"); + client.RunCommand("apt-get -y -qq install socat"); + } + else if (getDnf == false) + { + //client.RunCommand("yum -q makecache"); + client.RunCommand("dnf -y -q install socat"); + } + else if (getYum == false) + { + //client.RunCommand("yum -q makecache"); + client.RunCommand("yum -y -q install socat"); + } + //else if (getZypper == false) //{ - currentStatus = "使用Trojan+TLS+Web模式,正在安装acme.sh......"; - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - Thread.Sleep(1000); + // // client.RunCommand("zypper ref"); + // client.RunCommand("zypper -y install socat"); + //} + client.RunCommand("curl https://raw.githubusercontent.com/acmesh-official/acme.sh/master/acme.sh | INSTALLONLINE=1 sh"); + client.RunCommand("cd ~/.acme.sh/"); + client.RunCommand("alias acme.sh=~/.acme.sh/acme.sh"); - if (getApt == false) - { - //client.RunCommand("apt-get -qq update"); - client.RunCommand("apt-get -y -qq install socat"); - } - if (getYum == false) - { - //client.RunCommand("yum -q makecache"); - client.RunCommand("yum -y -q install socat"); - } - if (getZypper == false) - { - // client.RunCommand("zypper ref"); - client.RunCommand("zypper -y install socat"); - } - client.RunCommand("curl https://raw.githubusercontent.com/acmesh-official/acme.sh/master/acme.sh | INSTALLONLINE=1 sh"); - client.RunCommand("cd ~/.acme.sh/"); - client.RunCommand("alias acme.sh=~/.acme.sh/acme.sh"); - - currentStatus = "申请域名证书......"; - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - Thread.Sleep(1000); + currentStatus = "申请域名证书......"; + textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); + Thread.Sleep(1000); //client.RunCommand("mkdir -p /etc/v2ray/ssl"); - client.RunCommand($"/root/.acme.sh/acme.sh --issue --standalone -d {ReceiveConfigurationParameters[4]}"); + client.RunCommand($"/root/.acme.sh/acme.sh --issue --standalone -d {ReceiveConfigurationParameters[4]}"); - currentStatus = "安装证书到Trojan......"; - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - Thread.Sleep(1000); - client.RunCommand($"/root/.acme.sh/acme.sh --installcert -d {ReceiveConfigurationParameters[4]} --certpath /usr/local/etc/trojan/trojan_ssl.crt --keypath /usr/local/etc/trojan/trojan_ssl.key --capath /usr/local/etc/trojan/trojan_ssl.crt --reloadcmd \"systemctl restart trojan\""); - //} + currentStatus = "安装证书到Trojan......"; + textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); + Thread.Sleep(1000); + client.RunCommand($"/root/.acme.sh/acme.sh --installcert -d {ReceiveConfigurationParameters[4]} --certpath /usr/local/etc/trojan/trojan_ssl.crt --keypath /usr/local/etc/trojan/trojan_ssl.key --capath /usr/local/etc/trojan/trojan_ssl.crt --reloadcmd \"systemctl restart trojan\""); currentStatus = "正在启动Trojan......"; textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); Thread.Sleep(1000); - //启动V2ray服务 + client.RunCommand("systemctl restart trojan"); currentStatus = "Trojan启动成功!"; textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); Thread.Sleep(1000); + currentStatus = "正在安装Caddy"; + textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); + Thread.Sleep(1000); + + //client.RunCommand("curl https://getcaddy.com -o getcaddy"); + //client.RunCommand("bash getcaddy personal hook.service"); + //client.RunCommand("mkdir -p /etc/caddy"); + //client.RunCommand("mkdir -p /var/www"); + //安装Caddy - //if (serverConfig.Contains("trojan_server") == true) + //为假则表示系统有相应的组件。 + if (getApt == false) + { + client.RunCommand(@"echo ""deb [trusted=yes] https://apt.fury.io/caddy/ /"" | tee -a /etc/apt/sources.list.d/caddy-fury.list"); + client.RunCommand("apt install -y apt-transport-https"); + client.RunCommand("apt -qq update"); + client.RunCommand("apt -y -qq install caddy"); + } + else if (getDnf == false) + { + client.RunCommand(@"dnf install 'dnf-command(copr)' -y"); + client.RunCommand(@"dnf copr enable @caddy/caddy -y"); + //client.RunCommand("dnf -q makecache"); + client.RunCommand("dnf -y -q install caddy"); + } + else if (getYum == false) + { + client.RunCommand(@"yum install yum-plugin-copr -y"); + client.RunCommand(@"yum copr enable @caddy/caddy -y"); + //client.RunCommand("yum -q makecache"); + client.RunCommand("yum -y -q install caddy"); + } + //else if (getZypper == false) //{ - currentStatus = "正在安装Caddy"; + // client.RunCommand("zypper ref"); + // client.RunCommand("zypper -y install curl"); + //} + installResult = client.RunCommand("find / -name caddy").Result.ToString(); + + if (!installResult.Contains("/usr/bin/caddy")) + { + MessageBox.Show("安装Caddy失败!"); + currentStatus = "安装Caddy失败!"; + textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); + client.Disconnect(); + return; + } + else + { + currentStatus = "Caddy安装成功!"; textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); Thread.Sleep(1000); + client.RunCommand("systemctl enable caddy"); + } - client.RunCommand("curl https://getcaddy.com -o getcaddy"); - client.RunCommand("bash getcaddy personal hook.service"); - client.RunCommand("mkdir -p /etc/caddy"); - client.RunCommand("mkdir -p /var/www"); + currentStatus = "上传Caddy配置文件......"; + textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); + Thread.Sleep(1000); + string caddyConfig = "TemplateConfg\\trojan_caddy_config.caddyfile"; + upLoadPath = "/etc/caddy/Caddyfile"; + client.RunCommand("mv /etc/caddy/Caddyfile /etc/caddy/Caddyfile.bak"); + UploadConfig(connectionInfo, caddyConfig, upLoadPath); - currentStatus = "上传Caddy配置文件......"; - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - Thread.Sleep(1000); + ////设置Caddyfile文件中的tls 邮箱 - string caddyConfig = "TemplateConfg\\trojan_caddy_config.caddyfile"; - //if (serverConfig.Contains("trojan_server") == true) - //{ - // caddyConfig = "TemplateConfg\\trojan_caddy_config.caddyfile"; - //} - - upLoadPath = "/etc/caddy/Caddyfile"; - UploadConfig(connectionInfo, caddyConfig, upLoadPath); - - //设置Caddyfile文件中的tls 邮箱 - - string email = $"user@{ReceiveConfigurationParameters[4]}"; - string sshCmd; - //设置域名 - sshCmd = $"sed -i 's/##domain##/{ReceiveConfigurationParameters[4]}:80/' {upLoadPath}"; + //string email = $"user@{ReceiveConfigurationParameters[4]}"; + //string sshCmd; + //设置域名 + string sshCmd = $"sed -i 's/##domain##/{ReceiveConfigurationParameters[4]}:80/' {upLoadPath}"; + client.RunCommand(sshCmd); + //设置伪装网站 + if (String.IsNullOrEmpty(ReceiveConfigurationParameters[7]) == false) + { + sshCmd = $"sed -i 's/##sites##/proxy \\/ {ReceiveConfigurationParameters[7]}/' {upLoadPath}"; //MessageBox.Show(sshCmd); client.RunCommand(sshCmd); - //设置伪装网站 - if (String.IsNullOrEmpty(ReceiveConfigurationParameters[7]) == false) - { - sshCmd = $"sed -i 's/##sites##/proxy \\/ {ReceiveConfigurationParameters[7]}/' {upLoadPath}"; - //MessageBox.Show(sshCmd); - client.RunCommand(sshCmd); - } - Thread.Sleep(2000); + } + // Thread.Sleep(2000); //安装Caddy服务 - sshCmd = $"caddy -service install -agree -conf /etc/caddy/Caddyfile -email {email}"; + //sshCmd = $"caddy -service install -agree -conf /etc/caddy/Caddyfile -email {email}"; //MessageBox.Show(sshCmd); - client.RunCommand(sshCmd); + //client.RunCommand(sshCmd); //启动Caddy服务 - client.RunCommand("caddy -service restart"); + client.RunCommand("systemctl restart caddy"); //} //测试BBR条件,若满足提示是否启用 var result = client.RunCommand("uname -r"); - //var result = client.RunCommand("cat /root/test.ver"); string[] linuxKernelVerStr = result.Result.Split('-'); bool detectResult = DetectKernelVersionBBR(linuxKernelVerStr[0]); @@ -1942,6 +2207,198 @@ namespace ProxySU #endregion } + //检测升级远程主机Trojan版本 + private void ButtonUpdateTrojan_Click(object sender, RoutedEventArgs e) + { + ConnectionInfo connectionInfo = GenerateConnectionInfo(); + if (connectionInfo == null) + { + MessageBox.Show("远程主机连接信息有误,请检查"); + return; + } + + Thread thread = new Thread(() => UpdateTojan(connectionInfo, TextBlockSetUpProcessing, ProgressBarSetUpProcessing)); + thread.SetApartmentState(ApartmentState.STA); + thread.Start(); + } + //升级Trojan主程序 + private void UpdateTojan(ConnectionInfo connectionInfo, TextBlock textBlockName, ProgressBar progressBar) + { + string currentStatus = "正在登录远程主机......"; + Action updateAction = new Action(UpdateTextBlock); + textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); + + try + { + #region 主机指纹,暂未启用 + //byte[] expectedFingerPrint = new byte[] { + // 0x66, 0x31, 0xaf, 0x00, 0x54, 0xb9, 0x87, 0x31, + // 0xff, 0x58, 0x1c, 0x31, 0xb1, 0xa2, 0x4c, 0x6b + // }; + #endregion + using (var client = new SshClient(connectionInfo)) + + { + #region ssh登录验证主机指纹代码块,暂未启用 + // client.HostKeyReceived += (sender, e) => + // { + // if (expectedFingerPrint.Length == e.FingerPrint.Length) + // { + // for (var i = 0; i < expectedFingerPrint.Length; i++) + // { + // if (expectedFingerPrint[i] != e.FingerPrint[i]) + // { + // e.CanTrust = false; + // break; + // } + // } + // } + // else + // { + // e.CanTrust = false; + // } + // }; + #endregion + + client.Connect(); + if (client.IsConnected == true) + { + currentStatus = "主机登录成功"; + textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); + Thread.Sleep(1000); + } + //检测是否运行在root权限下 + string testRootAuthority = client.RunCommand(@"id -u").Result; + if (testRootAuthority.Equals("0\n") == false) + { + MessageBox.Show("请使用具有root权限的账户登录主机!!"); + client.Disconnect(); + return; + } + //检测远程主机V2ray版本 + currentStatus = "检测远程主机Trojan版本......"; + textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); + Thread.Sleep(1000); + + string cmdTestTrojanInstalled = @"find / -name trojan"; + string resultCmdTestTrojanInstalled = client.RunCommand(cmdTestTrojanInstalled).Result; + + if (resultCmdTestTrojanInstalled.Contains("/usr/local/bin/trojan") == false) + { + MessageBoxResult messageBoxResult = MessageBox.Show("远程主机未安装Trojan!"); + + currentStatus = "未安装Trojan,退出"; + textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); + Thread.Sleep(1000); + client.Disconnect(); + return; + + } + //string sshcmd; + string sshcmd = @"echo ""$(/usr/local/bin/trojan -v 2>&1)"" | head -n 1 | cut -d "" "" -f4"; + string trojanCurrentVersion = client.RunCommand(sshcmd).Result;//不含字母v + + sshcmd = @"curl -fsSL https://api.github.com/repos/trojan-gfw/trojan/releases/latest | grep tag_name | sed -E 's/.*""v(.*)"".*/\1/'"; + + string trojanNewVersion = client.RunCommand(sshcmd).Result;//不包含字母v + + if (trojanNewVersion.Equals(trojanCurrentVersion) == false) + { + MessageBoxResult messageBoxResult = MessageBox.Show($"远程主机当前版本为:v{trojanCurrentVersion}\n最新版本为:{trojanNewVersion}\n是否升级为最新版本?", "", MessageBoxButton.YesNo, MessageBoxImage.Question); + if (messageBoxResult == MessageBoxResult.Yes) + { + currentStatus = "正在升级Trojan到最新版本......"; + textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); + Thread.Sleep(1000); + + //备份配置文件 + sshcmd = @"mv /usr/local/etc/trojan/config.json /usr/local/etc/trojan/config.json.bak"; + client.RunCommand(sshcmd); + //升级Trojan主程序 + client.RunCommand("curl -o /tmp/trojan-quickstart.sh https://raw.githubusercontent.com/trojan-gfw/trojan-quickstart/master/trojan-quickstart.sh"); + client.RunCommand("yes | bash /tmp/trojan-quickstart.sh"); + sshcmd = @"echo ""$(/usr/local/bin/trojan -v 2>&1)"" | head -n 1 | cut -d "" "" -f4"; + + trojanCurrentVersion = client.RunCommand(sshcmd).Result;//不含字母v + if (trojanNewVersion.Equals(trojanCurrentVersion) == true) + { + //恢复原来的配置文件备份 + sshcmd = @"rm -f /usr/local/etc/trojan/config.json"; + client.RunCommand(sshcmd); + sshcmd = @"mv /usr/local/etc/trojan/config.json.bak /usr/local/etc/trojan/config.json"; + client.RunCommand(sshcmd); + MessageBox.Show($"升级成功!!\n当前版本为:v{trojanCurrentVersion}\n最新版本为:{trojanNewVersion}"); + currentStatus = "升级成功!当前已是最新版本!"; + textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); + Thread.Sleep(1000); + } + else + { + MessageBox.Show("升级失败,原因未知,请向开发者提问,以寻求支持!"); + currentStatus = "升级失败!"; + textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); + Thread.Sleep(1000); + } + } + + else + { + currentStatus = "升级取消,退出"; + textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); + Thread.Sleep(1000); + client.Disconnect(); + return; + } + } + else + { + MessageBox.Show($"远程主机当前已是最新版本:{trojanNewVersion}\n无需升级!"); + currentStatus = "已是最新版本,无需升级,退出"; + textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); + Thread.Sleep(1000); + } + + client.Disconnect(); + return; + } + } + catch (Exception ex1)//例外处理 + #region 例外处理 + { + //MessageBox.Show(ex1.Message); + if (ex1.Message.Contains("连接尝试失败") == true) + { + MessageBox.Show($"{ex1.Message}\n请检查主机地址及端口是否正确,如果通过代理,请检查代理是否正常工作"); + } + + else if (ex1.Message.Contains("denied (password)") == true) + { + MessageBox.Show($"{ex1.Message}\n密码错误或用户名错误"); + } + else if (ex1.Message.Contains("Invalid private key file") == true) + { + MessageBox.Show($"{ex1.Message}\n所选密钥文件错误或者格式不对"); + } + else if (ex1.Message.Contains("denied (publickey)") == true) + { + MessageBox.Show($"{ex1.Message}\n使用密钥登录,密钥文件错误或用户名错误"); + } + else if (ex1.Message.Contains("目标计算机积极拒绝") == true) + { + MessageBox.Show($"{ex1.Message}\n主机地址错误,如果使用了代理,也可能是连接代理的端口错误"); + } + else + { + MessageBox.Show("发生错误"); + MessageBox.Show(ex1.Message); + } + currentStatus = "主机登录失败"; + textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); + + } + #endregion + + } //打开设置TrojanGo参数窗口 @@ -1955,6 +2412,7 @@ namespace ProxySU TrojanGoTemplateWindow windowTrojanGoTemplateConfiguration = new TrojanGoTemplateWindow(); windowTrojanGoTemplateConfiguration.ShowDialog(); } + //传递TrojanGo参数 private void ButtonTrojanGoSetUp_Click(object sender, RoutedEventArgs e) { ConnectionInfo connectionInfo = GenerateConnectionInfo(); @@ -1967,23 +2425,7 @@ namespace ProxySU string clientConfig = "TemplateConfg\\trojan-go_all_config.json"; //生成的客户端配置文件 string upLoadPath = "/etc/trojan-go/config.json"; //服务端文件位置 - //if (String.IsNullOrEmpty(ReceiveConfigurationParameters[0]) == false) - //if(ReceiveConfigurationParameters[0].Contains("TrojanGo")==true) - //{ - // serverConfig = "TemplateConfg\\trojan-go_all_config.json"; - // clientConfig = "TemplateConfg\\trojan-go_all_config.json"; - //} - //else if (String.Equals(ReceiveConfigurationParameters[0], "TrojanGoTLS2Web")) - //{ - // serverConfig = "TemplateConfg\\trojan-go_all_config.json"; - // clientConfig = "TemplateConfg\\trojan-go_all_config.json"; - //} - //else if (String.Equals(ReceiveConfigurationParameters[0], "TrojanGoWebSocketTLS2Web")) - //{ - // serverConfig = "TemplateConfg\\trojan-go_all_config.json"; - // clientConfig = "TemplateConfg\\trojan-go_all_config.json"; - //} - //else + if (String.IsNullOrEmpty(ReceiveConfigurationParameters[0]) == true) { MessageBox.Show("未选择配置模板或模板选择错误!"); @@ -1993,13 +2435,8 @@ namespace ProxySU { MessageBox.Show("空域名,请检查相关参数设置!"); return; - //ReceiveConfigurationParameters[4] = TextBoxHost.Text.ToString(); } - //else - //{ - // MessageBox.Show("空域名,请检查相关参数设置!"); - // return; - //} + Thread thread = new Thread(() => StartSetUpTrojanGo(connectionInfo, TextBlockSetUpProcessing, ProgressBarSetUpProcessing, serverConfig, clientConfig, upLoadPath)); thread.SetApartmentState(ApartmentState.STA); thread.Start(); @@ -2067,7 +2504,7 @@ namespace ProxySU //string cmdTestTrojanInstalled = @"find / -name trojan"; string resultCmdTestTrojanInstalled = client.RunCommand(@"find / -name trojan-go").Result; - if (resultCmdTestTrojanInstalled.Contains("/usr/bin/trojan-go/trojan-go") == true) + if (resultCmdTestTrojanInstalled.Contains("/usr/local/bin/trojan-go") == true) { MessageBoxResult messageBoxResult = MessageBox.Show("远程主机已安装Trojan,是否强制重新安装?", "", MessageBoxButton.YesNo, MessageBoxImage.Question); if (messageBoxResult == MessageBoxResult.No) @@ -2085,30 +2522,18 @@ namespace ProxySU textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); Thread.Sleep(1000); - //string resultCmd = client.RunCommand("uname -m").Result; - //var result = client.RunCommand("cat /root/test.ver"); - //string[] linuxKernelVerStr = resultCmd.Split('-'); - - //bool detectResult = DetectKernelVersion(linuxKernelVerStr[0]); - - //if (resultCmd.Contains("x86_64") == false) - //{ - // MessageBox.Show($"请在x86_64系统中安装Trojan"); - // currentStatus = "系统不符合要求,安装失败!!"; - // textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - // Thread.Sleep(1000); - //} //检测系统是否支持yum 或 apt-get或zypper,且支持Systemd //如果不存在组件,则命令结果为空,string.IsNullOrEmpty值为真, - bool getApt = String.IsNullOrEmpty(client.RunCommand("command -v apt-get").Result); + bool getApt = String.IsNullOrEmpty(client.RunCommand("command -v apt").Result); + bool getDnf = String.IsNullOrEmpty(client.RunCommand("command -v dnf").Result); bool getYum = String.IsNullOrEmpty(client.RunCommand("command -v yum").Result); bool getZypper = String.IsNullOrEmpty(client.RunCommand("command -v zypper").Result); bool getSystemd = String.IsNullOrEmpty(client.RunCommand("command -v systemctl").Result); bool getGetenforce = String.IsNullOrEmpty(client.RunCommand("command -v getenforce").Result); - //没有安装apt-get,也没有安装yum,也没有安装zypper,或者没有安装systemd的,不满足安装条件 - //也就是apt-get ,yum, zypper必须安装其中之一,且必须安装Systemd的系统才能安装。 + //没有安装apt,也没有安装dnf\yum,也没有安装zypper,或者没有安装systemd的,不满足安装条件 + //也就是apt ,dnf\yum, zypper必须安装其中之一,且必须安装Systemd的系统才能安装。 if ((getApt && getYum && getZypper) || getSystemd) { MessageBox.Show($"系统缺乏必要的安装组件如:apt-get||yum||zypper||Syetemd,主机系统推荐使用:CentOS 7/8,Debian 8/9/10,Ubuntu 16.04及以上版本"); @@ -2133,128 +2558,8 @@ namespace ProxySU } //检测域名解析是否正确 - //if (serverConfig.Contains("trojan_server") == true) - //{ - currentStatus = "正在检测域名是否解析到当前VPS的IP上......"; - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - Thread.Sleep(1000); - //在相应系统内安装curl(如果没有安装curl) - if (string.IsNullOrEmpty(client.RunCommand("command -v curl").Result) == true) - { - //为假则表示系统有相应的组件。 - if (getApt == false) - { - client.RunCommand("apt-get -qq update"); - client.RunCommand("apt-get -y -qq install curl"); - } - if (getYum == false) - { - client.RunCommand("yum -q makecache"); - client.RunCommand("yum -y -q install curl"); - } - if (getZypper == false) - { - client.RunCommand("zypper ref"); - client.RunCommand("zypper -y install curl"); - } - } - - string nativeIp = client.RunCommand("curl -4 ip.sb").Result.ToString(); - //MessageBox.Show(nativeIp); - string testDomainCmd = "ping " + ReceiveConfigurationParameters[4] + " -c 1 | grep -oE -m1 \"([0-9]{1,3}\\.){3}[0-9]{1,3}\""; - //MessageBox.Show(testDomainCmd); - string resultTestDomainCmd = client.RunCommand(testDomainCmd).Result.ToString(); - //MessageBox.Show(resultTestDomainCmd); - if (String.Equals(nativeIp, resultTestDomainCmd) == true) - { - currentStatus = "解析正确!"; - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - Thread.Sleep(1000); - } - else - { - currentStatus = "域名未能正确解析到当前VPS的IP上!安装失败!"; - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - Thread.Sleep(1000); - MessageBox.Show("域名未能正确解析到当前VPS的IP上,请检查!若解析设置正确,请等待生效后再重试安装。如果域名使用了CDN,请先关闭!"); - client.Disconnect(); - return; - } - - //} - //if (serverConfig.Contains("trojan_server") == true) - //{ - //检测是否安装lsof - if (string.IsNullOrEmpty(client.RunCommand("command -v lsof").Result) == true) - { - //为假则表示系统有相应的组件。 - if (getApt == false) - { - client.RunCommand("apt-get -qq update"); - client.RunCommand("apt-get -y -qq install lsof"); - } - if (getYum == false) - { - client.RunCommand("yum -q makecache"); - client.RunCommand("yum -y -q install lsof"); - } - if (getZypper == false) - { - client.RunCommand("zypper ref"); - client.RunCommand("zypper -y install lsof"); - } - } - currentStatus = "正在检测端口占用情况......"; - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - Thread.Sleep(1000); - //MessageBox.Show(@"lsof -n -P -i :80 | grep LISTEN"); - //MessageBox.Show(client.RunCommand(@"lsof -n -P -i :80 | grep LISTEN").Result); - if (String.IsNullOrEmpty(client.RunCommand(@"lsof -n -P -i :80 | grep LISTEN").Result) == false || String.IsNullOrEmpty(client.RunCommand(@"lsof -n -P -i :443 | grep LISTEN").Result) == false) - { - MessageBoxResult dialogResult = MessageBox.Show("80/443端口之一,或全部被占用,将强制停止占用80/443端口的程序?", "Stop application", MessageBoxButton.YesNo); - if (dialogResult == MessageBoxResult.No) - { - currentStatus = "端口被占用,安装失败......"; - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - Thread.Sleep(1000); - client.Disconnect(); - return; - } - - currentStatus = "正在释放80/443端口......"; - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - Thread.Sleep(1000); - - string cmdTestPort = @"lsof -n -P -i :443 | grep LISTEN"; - string cmdResult = client.RunCommand(cmdTestPort).Result; - //MessageBox.Show(cmdTestPort); - if (String.IsNullOrEmpty(cmdResult) == false) - { - //MessageBox.Show(cmdResult); - string[] cmdResultArry443 = cmdResult.Split(' '); - //MessageBox.Show(cmdResultArry443[3]); - client.RunCommand($"systemctl stop {cmdResultArry443[0]}"); - client.RunCommand($"systemctl disable {cmdResultArry443[0]}"); - client.RunCommand($"kill -9 {cmdResultArry443[3]}"); - } - - cmdTestPort = @"lsof -n -P -i :80 | grep LISTEN"; - cmdResult = client.RunCommand(cmdTestPort).Result; - if (String.IsNullOrEmpty(cmdResult) == false) - { - string[] cmdResultArry80 = cmdResult.Split(' '); - client.RunCommand($"systemctl stop {cmdResultArry80[0]}"); - client.RunCommand($"systemctl disable {cmdResultArry80[0]}"); - client.RunCommand($"kill -9 {cmdResultArry80[3]}"); - } - currentStatus = "80/443端口释放完毕!"; - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - Thread.Sleep(1000); - - } - //} - currentStatus = "符合安装要求,布署中......"; + currentStatus = "正在检测域名是否解析到当前VPS的IP上......"; textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); Thread.Sleep(1000); @@ -2267,31 +2572,129 @@ namespace ProxySU client.RunCommand("apt-get -qq update"); client.RunCommand("apt-get -y -qq install curl"); } - if (getYum == false) + else if (getDnf == false) + { + client.RunCommand("dnf -q makecache"); + client.RunCommand("dnf -y -q install curl"); + } + else if (getYum == false) { client.RunCommand("yum -q makecache"); client.RunCommand("yum -y -q install curl"); } - if (getZypper == false) + else if (getZypper == false) { client.RunCommand("zypper ref"); client.RunCommand("zypper -y install curl"); } } + string nativeIp = client.RunCommand("curl -4 ip.sb").Result.ToString(); + string testDomainCmd = "ping " + ReceiveConfigurationParameters[4] + " -c 1 | grep -oE -m1 \"([0-9]{1,3}\\.){3}[0-9]{1,3}\""; + string resultTestDomainCmd = client.RunCommand(testDomainCmd).Result.ToString(); - //下载官方安装脚本安装 + if (String.Equals(nativeIp, resultTestDomainCmd) == true) + { + currentStatus = "解析正确!"; + textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); + Thread.Sleep(1000); + } + else + { + currentStatus = "域名未能正确解析到当前VPS的IP上!安装失败!"; + textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); + Thread.Sleep(1000); + MessageBox.Show("域名未能正确解析到当前VPS的IP上,请检查!若解析设置正确,请等待生效后再重试安装。如果域名使用了CDN,请先关闭!"); + client.Disconnect(); + return; + } + + //检测是否安装lsof + if (string.IsNullOrEmpty(client.RunCommand("command -v lsof").Result) == true) + { + //为假则表示系统有相应的组件。 + if (getApt == false) + { + client.RunCommand("apt -qq update"); + client.RunCommand("apt -y -qq install lsof"); + } + else if (getDnf == false) + { + client.RunCommand("dnf -q makecache"); + client.RunCommand("dnf -y -q install lsof"); + } + else if (getYum == false) + { + client.RunCommand("yum -q makecache"); + client.RunCommand("yum -y -q install lsof"); + } + else if (getZypper == false) + { + client.RunCommand("zypper ref"); + client.RunCommand("zypper -y install lsof"); + } + } + currentStatus = "正在检测端口占用情况......"; + textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); + Thread.Sleep(1000); + //MessageBox.Show(@"lsof -n -P -i :80 | grep LISTEN"); + //MessageBox.Show(client.RunCommand(@"lsof -n -P -i :80 | grep LISTEN").Result); + if (String.IsNullOrEmpty(client.RunCommand(@"lsof -n -P -i :80 | grep LISTEN").Result) == false || String.IsNullOrEmpty(client.RunCommand(@"lsof -n -P -i :443 | grep LISTEN").Result) == false) + { + MessageBoxResult dialogResult = MessageBox.Show("80/443端口之一,或全部被占用,将强制停止占用80/443端口的程序?", "Stop application", MessageBoxButton.YesNo); + if (dialogResult == MessageBoxResult.No) + { + currentStatus = "端口被占用,安装失败......"; + textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); + Thread.Sleep(1000); + client.Disconnect(); + return; + } + + currentStatus = "正在释放80/443端口......"; + textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); + Thread.Sleep(1000); + + string cmdTestPort = @"lsof -n -P -i :443 | grep LISTEN"; + string cmdResult = client.RunCommand(cmdTestPort).Result; + + if (String.IsNullOrEmpty(cmdResult) == false) + { + string[] cmdResultArry443 = cmdResult.Split(' '); + client.RunCommand($"systemctl stop {cmdResultArry443[0]}"); + client.RunCommand($"systemctl disable {cmdResultArry443[0]}"); + client.RunCommand($"kill -9 {cmdResultArry443[3]}"); + } + + cmdTestPort = @"lsof -n -P -i :80 | grep LISTEN"; + cmdResult = client.RunCommand(cmdTestPort).Result; + if (String.IsNullOrEmpty(cmdResult) == false) + { + string[] cmdResultArry80 = cmdResult.Split(' '); + client.RunCommand($"systemctl stop {cmdResultArry80[0]}"); + client.RunCommand($"systemctl disable {cmdResultArry80[0]}"); + client.RunCommand($"kill -9 {cmdResultArry80[3]}"); + } + currentStatus = "80/443端口释放完毕!"; + textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); + Thread.Sleep(1000); + } + currentStatus = "符合安装要求,布署中......"; + textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); + Thread.Sleep(1000); + + //下载安装脚本安装 client.RunCommand("curl -o /tmp/trojan-go.sh https://raw.githubusercontent.com/proxysu/shellscript/master/trojan-go.sh"); client.RunCommand("bash /tmp/trojan-go.sh -f"); string installResult = client.RunCommand("find / -name trojan-go").Result.ToString(); - if (!installResult.Contains("/usr/bin/trojan-go/trojan-go")) + if (!installResult.Contains("/usr/local/bin/trojan-go")) { - MessageBox.Show("安装Trojan失败(官方脚本运行出错!"); + MessageBox.Show("安装Trojan失败(安装脚本运行出错!"); - currentStatus = "安装Trojan失败(官方脚本运行出错!"; + currentStatus = "安装Trojan失败(安装脚本运行出错!"; textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); client.Disconnect(); return; @@ -2315,11 +2718,11 @@ namespace ProxySU //设置密码 serverJson["password"][0] = ReceiveConfigurationParameters[2]; //设置证书 - serverJson["ssl"]["cert"] = "/etc/trojan-go/trojan-go.crt"; - serverJson["ssl"]["key"] = "/etc/trojan-go/trojan-go.key"; - serverJson["ssl"]["sni"] = ReceiveConfigurationParameters[4]; + serverJson["ssl"]["cert"] = "/usr/local/etc/trojan-go/trojan-go.crt"; + serverJson["ssl"]["key"] = "/usr/local/etc/trojan-go/trojan-go.key"; + //serverJson["ssl"]["sni"] = ReceiveConfigurationParameters[4]; - if (ReceiveConfigurationParameters[0].Contains("WebSocket")) + if (String.Equals(ReceiveConfigurationParameters[0], "TrojanGoWebSocketTLS2Web")) { serverJson["websocket"]["enabled"] = true; serverJson["websocket"]["path"] = ReceiveConfigurationParameters[3]; @@ -2330,7 +2733,7 @@ namespace ProxySU sw.Write(serverJson.ToString()); } } - upLoadPath = "/etc/trojan-go/config.json"; + upLoadPath = "/usr/local/etc/trojan-go/config.json"; UploadConfig(connectionInfo, @"config.json", upLoadPath); File.Delete(@"config.json"); @@ -2339,134 +2742,147 @@ namespace ProxySU string openFireWallPort = ReceiveConfigurationParameters[1]; if (String.IsNullOrEmpty(client.RunCommand("command -v firewall-cmd").Result) == false) { - //if (String.Equals(openFireWallPort, "443")) - //{ - client.RunCommand("firewall-cmd --zone=public --add-port=80/tcp --permanent"); - client.RunCommand("firewall-cmd --zone=public --add-port=443/tcp --permanent"); - client.RunCommand("firewall-cmd --reload"); - //} - //else - //{ - // client.RunCommand($"firewall-cmd --zone=public --add-port={openFireWallPort}/tcp --permanent"); - // client.RunCommand($"firewall-cmd --zone=public --add-port={openFireWallPort}/udp --permanent"); - // client.RunCommand("firewall-cmd --reload"); - //} + client.RunCommand("firewall-cmd --zone=public --add-port=80/tcp --permanent"); + client.RunCommand("firewall-cmd --zone=public --add-port=443/tcp --permanent"); + client.RunCommand("firewall-cmd --reload"); + } if (String.IsNullOrEmpty(client.RunCommand("command -v ufw").Result) == false) { - //if (String.Equals(openFireWallPort, "443")) - //{ - client.RunCommand("ufw allow 80"); - client.RunCommand("ufw allow 443"); - client.RunCommand("yes | ufw reload"); - //} - //else - //{ - // client.RunCommand($"ufw allow {openFireWallPort}/tcp"); - // client.RunCommand($"ufw allow {openFireWallPort}/udp"); - // client.RunCommand("yes | ufw reload"); - //} + client.RunCommand("ufw allow 80"); + client.RunCommand("ufw allow 443"); + client.RunCommand("yes | ufw reload"); + } - //if (serverConfig.Contains("trojan_server") == true) - //{ - currentStatus = "正在安装acme.sh......"; - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - Thread.Sleep(1000); + currentStatus = "正在安装acme.sh......"; + textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); + Thread.Sleep(1000); - if (getApt == false) - { - //client.RunCommand("apt-get -qq update"); - client.RunCommand("apt-get -y -qq install socat"); - } - if (getYum == false) - { - //client.RunCommand("yum -q makecache"); - client.RunCommand("yum -y -q install socat"); - } - if (getZypper == false) - { - // client.RunCommand("zypper ref"); - client.RunCommand("zypper -y install socat"); - } - client.RunCommand("curl https://raw.githubusercontent.com/acmesh-official/acme.sh/master/acme.sh | INSTALLONLINE=1 sh"); - client.RunCommand("cd ~/.acme.sh/"); - client.RunCommand("alias acme.sh=~/.acme.sh/acme.sh"); + if (getApt == false) + { + //client.RunCommand("apt-get -qq update"); + client.RunCommand("apt-get -y -qq install socat"); + } + else if (getDnf == false) + { + //client.RunCommand("yum -q makecache"); + client.RunCommand("dnf -y -q install socat"); + } + else if (getYum == false) + { + //client.RunCommand("yum -q makecache"); + client.RunCommand("yum -y -q install socat"); + } + else if (getZypper == false) + { + // client.RunCommand("zypper ref"); + client.RunCommand("zypper -y install socat"); + } + client.RunCommand("curl https://raw.githubusercontent.com/acmesh-official/acme.sh/master/acme.sh | INSTALLONLINE=1 sh"); + client.RunCommand("cd ~/.acme.sh/"); + client.RunCommand("alias acme.sh=~/.acme.sh/acme.sh"); - currentStatus = "申请域名证书......"; - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - Thread.Sleep(1000); + currentStatus = "申请域名证书......"; + textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); + Thread.Sleep(1000); - //client.RunCommand("mkdir -p /etc/v2ray/ssl"); - client.RunCommand($"/root/.acme.sh/acme.sh --issue --standalone -d {ReceiveConfigurationParameters[4]}"); + //client.RunCommand("mkdir -p /etc/v2ray/ssl"); + client.RunCommand($"/root/.acme.sh/acme.sh --issue --standalone -d {ReceiveConfigurationParameters[4]}"); - currentStatus = "安装证书到Trojan-Go......"; - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - Thread.Sleep(1000); - client.RunCommand($"/root/.acme.sh/acme.sh --installcert -d {ReceiveConfigurationParameters[4]} --certpath /etc/trojan-go/trojan-go.crt --keypath /etc/trojan-go/trojan-go.key --capath /etc/trojan-go/trojan-go.crt --reloadcmd \"systemctl restart trojan-go\""); - //} - - + currentStatus = "安装证书到Trojan-Go......"; + textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); + Thread.Sleep(1000); + client.RunCommand($"/root/.acme.sh/acme.sh --installcert -d {ReceiveConfigurationParameters[4]} --certpath /usr/local/etc/trojan-go/trojan-go.crt --keypath /usr/local/etc/trojan-go/trojan-go.key --capath /usr/local/etc/trojan-go/trojan-go.crt --reloadcmd \"systemctl restart trojan-go\""); //安装Caddy - //if (serverConfig.Contains("trojan_server") == true) + currentStatus = "正在安装Caddy"; + textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); + Thread.Sleep(1000); + + //安装Caddy + //为假则表示系统有相应的组件。 + if (getApt == false) + { + client.RunCommand(@"echo ""deb [trusted=yes] https://apt.fury.io/caddy/ /"" | tee -a /etc/apt/sources.list.d/caddy-fury.list"); + client.RunCommand("apt install -y apt-transport-https"); + client.RunCommand("apt -qq update"); + client.RunCommand("apt -y -qq install caddy"); + } + else if (getDnf == false) + { + client.RunCommand(@"dnf install 'dnf-command(copr)' -y"); + client.RunCommand(@"dnf copr enable @caddy/caddy -y"); + //client.RunCommand("dnf -q makecache"); + client.RunCommand("dnf -y -q install caddy"); + } + else if (getYum == false) + { + client.RunCommand(@"yum install yum-plugin-copr -y"); + client.RunCommand(@"yum copr enable @caddy/caddy -y"); + //client.RunCommand("yum -q makecache"); + client.RunCommand("yum -y -q install caddy"); + } + //else if (getZypper == false) //{ - currentStatus = "正在安装Caddy"; - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - Thread.Sleep(1000); - - client.RunCommand("curl https://getcaddy.com -o getcaddy"); - client.RunCommand("bash getcaddy personal hook.service"); - client.RunCommand("mkdir -p /etc/caddy"); - client.RunCommand("mkdir -p /var/www"); - - - currentStatus = "上传Caddy配置文件......"; - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - Thread.Sleep(1000); - - string caddyConfig = ""; - //if (serverConfig.Contains("trojan_server") == true) - //{ - caddyConfig = "TemplateConfg\\trojan_caddy_config.caddyfile"; - //} - - upLoadPath = "/etc/caddy/Caddyfile"; - UploadConfig(connectionInfo, caddyConfig, upLoadPath); - - //设置Caddyfile文件中的tls 邮箱 - - string email = $"user@{ReceiveConfigurationParameters[4]}"; - string sshCmd; - //设置域名 - sshCmd = $"sed -i 's/##domain##/{ReceiveConfigurationParameters[4]}:80/' {upLoadPath}"; - //MessageBox.Show(sshCmd); - client.RunCommand(sshCmd); - //设置伪装网站 - if (String.IsNullOrEmpty(ReceiveConfigurationParameters[7]) == false) - { - sshCmd = $"sed -i 's/##sites##/proxy \\/ {ReceiveConfigurationParameters[7]}/' {upLoadPath}"; - //MessageBox.Show(sshCmd); - client.RunCommand(sshCmd); - } - Thread.Sleep(2000); - - //安装Caddy服务 - sshCmd = $"caddy -service install -agree -conf /etc/caddy/Caddyfile -email {email}"; - //MessageBox.Show(sshCmd); - client.RunCommand(sshCmd); - //启动Caddy服务 - currentStatus = "正在启动Caddy......"; - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - Thread.Sleep(1000); - //启动V2ray服务 - client.RunCommand("caddy -service restart"); - - currentStatus = "Caddy启动成功!"; - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - Thread.Sleep(1000); - + // client.RunCommand("zypper ref"); + // client.RunCommand("zypper -y install curl"); //} + installResult = client.RunCommand("find / -name caddy").Result.ToString(); + + if (!installResult.Contains("/usr/bin/caddy")) + { + MessageBox.Show("安装Caddy失败!"); + + currentStatus = "安装Caddy失败!"; + textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); + client.Disconnect(); + return; + } + + currentStatus = "Caddy安装成功!"; + textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); + Thread.Sleep(1000); + client.RunCommand("systemctl enable caddy"); + + + //currentStatus = "上传Caddy配置文件......"; + //textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); + //Thread.Sleep(1000); + + //string caddyConfig = "TemplateConfg\\trojan_caddy_config.caddyfile"; + + //upLoadPath = "/etc/caddy/Caddyfile"; + //UploadConfig(connectionInfo, caddyConfig, upLoadPath); + + //设置Caddyfile文件中的tls 邮箱 + + //string email = $"user@{ReceiveConfigurationParameters[4]}"; + //设置域名 + //string sshCmd = $"sed -i 's/##domain##/{ReceiveConfigurationParameters[4]}:80/' {upLoadPath}"; + //MessageBox.Show(sshCmd); + //client.RunCommand(sshCmd); + //设置伪装网站 + //if (String.IsNullOrEmpty(ReceiveConfigurationParameters[7]) == false) + //{ + // sshCmd = $"sed -i 's/##sites##/proxy \\/ {ReceiveConfigurationParameters[7]}/' {upLoadPath}"; + // client.RunCommand(sshCmd); + //} + //Thread.Sleep(2000); + + //安装Caddy服务 + //sshCmd = $"caddy -service install -agree -conf /etc/caddy/Caddyfile -email {email}"; + //client.RunCommand(sshCmd); + //启动Caddy服务 + currentStatus = "正在启动Caddy......"; + textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); + Thread.Sleep(1000); + //启动Caddy服务 + client.RunCommand("systemctl restart caddy"); + + currentStatus = "Caddy启动成功!"; + textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); + Thread.Sleep(1000); currentStatus = "正在启动Trojan-Go......"; textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); @@ -2474,7 +2890,7 @@ namespace ProxySU //启动V2ray服务 client.RunCommand("systemctl restart trojan-go"); - currentStatus = "Trojan启动成功!"; + currentStatus = "Trojan-go启动成功!"; textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); Thread.Sleep(1000); @@ -2510,9 +2926,10 @@ namespace ProxySU clientJson["local_port"] = 1080; clientJson["remote_addr"] = ReceiveConfigurationParameters[4]; clientJson["remote_port"] = 443; + //设置密码 clientJson["password"][0] = ReceiveConfigurationParameters[2]; - - if (ReceiveConfigurationParameters[0].Contains("WebSocket")) + //如果是WebSocket协议则设置路径 + if (String.Equals(ReceiveConfigurationParameters[0], "TrojanGoWebSocketTLS2Web")) { clientJson["websocket"]["enabled"] = true; clientJson["websocket"]["path"] = ReceiveConfigurationParameters[3]; @@ -2574,6 +2991,199 @@ namespace ProxySU } #endregion + } + //检测升级Trojan-Go版本 + private void ButtonUpdateTrojanGo_Click(object sender, RoutedEventArgs e) + { + ConnectionInfo connectionInfo = GenerateConnectionInfo(); + if (connectionInfo == null) + { + MessageBox.Show("远程主机连接信息有误,请检查"); + return; + } + + Thread thread = new Thread(() => UpdateTojanGo(connectionInfo, TextBlockSetUpProcessing, ProgressBarSetUpProcessing)); + thread.SetApartmentState(ApartmentState.STA); + thread.Start(); + } + //升级Trojan-go主程序 + private void UpdateTojanGo(ConnectionInfo connectionInfo, TextBlock textBlockName, ProgressBar progressBar) + { + string currentStatus = "正在登录远程主机......"; + Action updateAction = new Action(UpdateTextBlock); + textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); + + try + { + #region 主机指纹,暂未启用 + //byte[] expectedFingerPrint = new byte[] { + // 0x66, 0x31, 0xaf, 0x00, 0x54, 0xb9, 0x87, 0x31, + // 0xff, 0x58, 0x1c, 0x31, 0xb1, 0xa2, 0x4c, 0x6b + // }; + #endregion + using (var client = new SshClient(connectionInfo)) + + { + #region ssh登录验证主机指纹代码块,暂未启用 + // client.HostKeyReceived += (sender, e) => + // { + // if (expectedFingerPrint.Length == e.FingerPrint.Length) + // { + // for (var i = 0; i < expectedFingerPrint.Length; i++) + // { + // if (expectedFingerPrint[i] != e.FingerPrint[i]) + // { + // e.CanTrust = false; + // break; + // } + // } + // } + // else + // { + // e.CanTrust = false; + // } + // }; + #endregion + + client.Connect(); + if (client.IsConnected == true) + { + currentStatus = "主机登录成功"; + textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); + Thread.Sleep(1000); + } + //检测是否运行在root权限下 + string testRootAuthority = client.RunCommand(@"id -u").Result; + if (testRootAuthority.Equals("0\n") == false) + { + MessageBox.Show("请使用具有root权限的账户登录主机!!"); + client.Disconnect(); + return; + } + //检测当前安装的版本 + currentStatus = "检测远程主机Trojan-Go版本......"; + textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); + Thread.Sleep(1000); + + string cmdTestTrojanInstalled = @"find / -name trojan-go"; + string resultCmdTestTrojanInstalled = client.RunCommand(cmdTestTrojanInstalled).Result; + + if (resultCmdTestTrojanInstalled.Contains("/usr/local/bin/trojan-go") == false) + { + MessageBoxResult messageBoxResult = MessageBox.Show("远程主机未安装Trojan-Go!"); + + currentStatus = "未安装Trojan-Go,退出"; + textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); + Thread.Sleep(1000); + client.Disconnect(); + return; + + } + //获取当前安装的版本 + string sshcmd = @"echo ""$(/usr/local/bin/trojan-go -version)"" | head -n 1 | cut -d "" "" -f2"; + string trojanCurrentVersion = client.RunCommand(sshcmd).Result;//含字母v + //获取最新版本 + sshcmd = @"curl -s https://api.github.com/repos/p4gefau1t/trojan-go/tags | grep 'name' | cut -d\"" -f4 | head -1"; + string trojanNewVersion = client.RunCommand(sshcmd).Result;//含字母v + + if (trojanNewVersion.Equals(trojanCurrentVersion) == false) + { + MessageBoxResult messageBoxResult = MessageBox.Show($"远程主机当前版本为:v{trojanCurrentVersion}\n最新版本为:{trojanNewVersion}\n是否升级为最新版本?", "", MessageBoxButton.YesNo, MessageBoxImage.Question); + if (messageBoxResult == MessageBoxResult.Yes) + { + currentStatus = "正在升级Trojan-Go到最新版本......"; + textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); + Thread.Sleep(1000); + + //备份配置文件 + //sshcmd = @"mv /usr/local/etc/trojan/config.json /usr/local/etc/trojan/config.json.bak"; + //client.RunCommand(sshcmd); + //升级Trojan-Go主程序 + client.RunCommand("curl -o /tmp/trojan-go.sh https://raw.githubusercontent.com/proxysu/shellscript/master/trojan-go.sh"); + client.RunCommand("bash /tmp/trojan-go.sh -f"); + //获取升级后的版本 + sshcmd = @"echo ""$(/usr/local/bin/trojan-go -version)"" | head -n 1 | cut -d "" "" -f2"; + trojanCurrentVersion = client.RunCommand(sshcmd).Result;//含字母v + if (trojanNewVersion.Equals(trojanCurrentVersion) == true) + { + //恢复原来的配置文件备份 + //sshcmd = @"rm -f /usr/local/etc/trojan/config.json"; + //client.RunCommand(sshcmd); + //sshcmd = @"mv /usr/local/etc/trojan/config.json.bak /usr/local/etc/trojan/config.json"; + //client.RunCommand(sshcmd); + MessageBox.Show($"升级成功!!\n当前版本为:v{trojanCurrentVersion}\n最新版本为:{trojanNewVersion}"); + currentStatus = "升级成功!当前已是最新版本!"; + textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); + Thread.Sleep(1000); + } + else + { + MessageBox.Show("升级失败,原因未知,请向开发者提问,以寻求支持!"); + currentStatus = "升级失败!"; + textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); + Thread.Sleep(1000); + client.Disconnect(); + return; + } + } + + else + { + currentStatus = "升级取消,退出"; + textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); + Thread.Sleep(1000); + client.Disconnect(); + return; + } + } + else + { + MessageBox.Show($"远程主机当前已是最新版本:{trojanNewVersion}\n无需升级!"); + currentStatus = "已是最新版本,无需升级,退出"; + textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); + Thread.Sleep(1000); + } + + client.Disconnect(); + return; + } + } + catch (Exception ex1)//例外处理 + #region 例外处理 + { + //MessageBox.Show(ex1.Message); + if (ex1.Message.Contains("连接尝试失败") == true) + { + MessageBox.Show($"{ex1.Message}\n请检查主机地址及端口是否正确,如果通过代理,请检查代理是否正常工作"); + } + + else if (ex1.Message.Contains("denied (password)") == true) + { + MessageBox.Show($"{ex1.Message}\n密码错误或用户名错误"); + } + else if (ex1.Message.Contains("Invalid private key file") == true) + { + MessageBox.Show($"{ex1.Message}\n所选密钥文件错误或者格式不对"); + } + else if (ex1.Message.Contains("denied (publickey)") == true) + { + MessageBox.Show($"{ex1.Message}\n使用密钥登录,密钥文件错误或用户名错误"); + } + else if (ex1.Message.Contains("目标计算机积极拒绝") == true) + { + MessageBox.Show($"{ex1.Message}\n主机地址错误,如果使用了代理,也可能是连接代理的端口错误"); + } + else + { + MessageBox.Show("发生错误"); + MessageBox.Show(ex1.Message); + } + currentStatus = "主机登录失败"; + textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); + + } + #endregion + } //更新NaiveProxy的密码 @@ -2582,7 +3192,6 @@ namespace ProxySU Guid uuid = Guid.NewGuid(); TextBoxNaivePassword.Text = uuid.ToString(); } - //生成随机UUID private string RandomUUID() { @@ -3139,7 +3748,6 @@ namespace ProxySU thread.SetApartmentState(ApartmentState.STA); thread.Start(); } - //启用BBR的主要进程 private void StartTestAndEnableBBR(ConnectionInfo connectionInfo, TextBlock textBlockName, ProgressBar progressBar) { @@ -3329,620 +3937,7 @@ namespace ProxySU return false; } - //检测升级远程主机端的V2Ray版本 - private void ButtonUpdateV2ray_Click(object sender, RoutedEventArgs e) - { - ConnectionInfo connectionInfo = GenerateConnectionInfo(); - if (connectionInfo == null) - { - MessageBox.Show("远程主机连接信息有误,请检查"); - return; - } - - Thread thread = new Thread(() => UpdateV2ray(connectionInfo, TextBlockSetUpProcessing, ProgressBarSetUpProcessing)); - thread.SetApartmentState(ApartmentState.STA); - thread.Start(); - } - //升级V2ray主程序 - private void UpdateV2ray(ConnectionInfo connectionInfo, TextBlock textBlockName, ProgressBar progressBar) - { - string currentStatus = "正在登录远程主机......"; - Action updateAction = new Action(UpdateTextBlock); - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - - try - { - #region 主机指纹,暂未启用 - //byte[] expectedFingerPrint = new byte[] { - // 0x66, 0x31, 0xaf, 0x00, 0x54, 0xb9, 0x87, 0x31, - // 0xff, 0x58, 0x1c, 0x31, 0xb1, 0xa2, 0x4c, 0x6b - // }; - #endregion - using (var client = new SshClient(connectionInfo)) - - { - #region ssh登录验证主机指纹代码块,暂未启用 - // client.HostKeyReceived += (sender, e) => - // { - // if (expectedFingerPrint.Length == e.FingerPrint.Length) - // { - // for (var i = 0; i < expectedFingerPrint.Length; i++) - // { - // if (expectedFingerPrint[i] != e.FingerPrint[i]) - // { - // e.CanTrust = false; - // break; - // } - // } - // } - // else - // { - // e.CanTrust = false; - // } - // }; - #endregion - - client.Connect(); - if (client.IsConnected == true) - { - currentStatus = "主机登录成功"; - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - Thread.Sleep(1000); - } - //检测是否运行在root权限下 - string testRootAuthority = client.RunCommand(@"id -u").Result; - if (testRootAuthority.Equals("0\n") == false) - { - MessageBox.Show("请使用具有root权限的账户登录主机!!"); - client.Disconnect(); - return; - } - //检测远程主机V2ray版本 - currentStatus = "检测远程主机V2ray版本......"; - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - Thread.Sleep(1000); - - //string cmdTestV2rayInstalled = @"find / -name v2ray"; - //MessageBox.Show(cmdTestV2rayInstalled); - string resultCmdTestV2rayInstalled = client.RunCommand(@"find / -name v2ray").Result; - //client.Disconnect(); - //MessageBox.Show(resultCmdTestV2rayInstalled); - if (resultCmdTestV2rayInstalled.Contains("/usr/bin/v2ray") == false && resultCmdTestV2rayInstalled.Contains("/usr/local/bin/v2ray") == false) - { - MessageBoxResult messageBoxResult = MessageBox.Show("远程主机未安装V2ray!"); - - currentStatus = "未安装V2ray,退出"; - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - Thread.Sleep(1000); - client.Disconnect(); - return; - - } - if (resultCmdTestV2rayInstalled.Contains("/usr/bin/v2ray") == true) - { - client.RunCommand("curl -o /tmp/go.sh https://raw.githubusercontent.com/proxysu/shellscript/master/v2ray/go.sh"); - client.RunCommand("bash /tmp/go.sh --remove"); - string installResult = client.RunCommand("find / -name v2ray").Result.ToString(); - - if (!installResult.Contains("/usr/bin/v2ray")) - { - currentStatus = "删除旧版本,OK"; - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - Thread.Sleep(1000); - } - currentStatus = "安装新版本。。。。。。"; - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - Thread.Sleep(1000); - - client.RunCommand("curl -o /tmp/go.sh https://raw.githubusercontent.com/v2fly/fhs-install-v2ray/master/install-release.sh"); - client.RunCommand("bash /tmp/go.sh -f"); - installResult = client.RunCommand("find / -name v2ray").Result.ToString(); - - if (!installResult.Contains("/usr/local/bin/v2ray")) - { - MessageBox.Show("安装V2ray失败(官方脚本运行出错!"); - - currentStatus = "安装V2ray失败(官方脚本运行出错!"; - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - client.Disconnect(); - return; - } - client.RunCommand(@"mv /etc/v2ray/config.json /usr/local/etc/v2ray/"); - client.RunCommand(@"systemctl restart v2ray"); - currentStatus = "已更新到最新版本。"; - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - Thread.Sleep(1000); - } - string sshcmd; - sshcmd = @"/usr/local/bin/v2ray -version | head -n 1 | cut -d "" "" -f2"; - //MessageBox.Show(sshcmd); - string v2rayCurrentVersion = client.RunCommand(sshcmd).Result;//不含字母v - //MessageBox.Show(v2rayCurrentVersion); - - sshcmd = @"curl -H ""Accept: application/json"" -H ""User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:74.0) Gecko/20100101 Firefox/74.0"" -s ""https://api.github.com/repos/v2ray/v2ray-core/releases/latest"" --connect-timeout 10| grep 'tag_name' | cut -d\"" -f4"; - //MessageBox.Show(sshcmd); - //client.RunCommand($"echo {sshcmd} >cmd.txt"); - string v2rayNewVersion = client.RunCommand(sshcmd).Result;//包含字母v - //MessageBox.Show(v2rayNewVersion); - if (v2rayNewVersion.Contains(v2rayCurrentVersion)==false) - { - MessageBoxResult messageBoxResult = MessageBox.Show($"远程主机当前版本为:v{v2rayCurrentVersion}\n最新版本为:{v2rayNewVersion}\n是否升级为最新版本?", "", MessageBoxButton.YesNo, MessageBoxImage.Question); - if (messageBoxResult == MessageBoxResult.Yes) - { - currentStatus = "正在升级V2ray到最新版本......"; - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - Thread.Sleep(1000); - client.RunCommand(@"bash <(curl -L -s https://raw.githubusercontent.com/v2fly/fhs-install-v2ray/master/install-release.sh)"); - sshcmd = @"/usr/local/bin/v2ray -version | head -n 1 | cut -d "" "" -f2"; - //MessageBox.Show(sshcmd); - v2rayCurrentVersion = client.RunCommand(sshcmd).Result;//不含字母v - if (v2rayNewVersion.Contains(v2rayCurrentVersion) == true) - { - MessageBox.Show($"升级成功!!\n当前版本为:v{v2rayCurrentVersion}\n最新版本为:{v2rayNewVersion}"); - currentStatus = "升级成功!当前已是最新版本!"; - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - Thread.Sleep(1000); - } - else - { - MessageBox.Show("升级失败,原因未知,请向开发者提问,以寻求支持!"); - currentStatus = "升级失败!"; - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - Thread.Sleep(1000); - } - } - else - { - currentStatus = "升级取消,退出"; - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - Thread.Sleep(1000); - client.Disconnect(); - return; - } - } - else - { - MessageBox.Show($"远程主机当前已是最新版本:{v2rayNewVersion}\n无需升级!"); - currentStatus = "已是最新版本,无需升级,退出"; - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - Thread.Sleep(1000); - } - - client.Disconnect(); - return; - } - } - catch (Exception ex1)//例外处理 - #region 例外处理 - { - //MessageBox.Show(ex1.Message); - if (ex1.Message.Contains("连接尝试失败") == true) - { - MessageBox.Show($"{ex1.Message}\n请检查主机地址及端口是否正确,如果通过代理,请检查代理是否正常工作"); - } - - else if (ex1.Message.Contains("denied (password)") == true) - { - MessageBox.Show($"{ex1.Message}\n密码错误或用户名错误"); - } - else if (ex1.Message.Contains("Invalid private key file") == true) - { - MessageBox.Show($"{ex1.Message}\n所选密钥文件错误或者格式不对"); - } - else if (ex1.Message.Contains("denied (publickey)") == true) - { - MessageBox.Show($"{ex1.Message}\n使用密钥登录,密钥文件错误或用户名错误"); - } - else if (ex1.Message.Contains("目标计算机积极拒绝") == true) - { - MessageBox.Show($"{ex1.Message}\n主机地址错误,如果使用了代理,也可能是连接代理的端口错误"); - } - else - { - MessageBox.Show("发生错误"); - MessageBox.Show(ex1.Message); - } - currentStatus = "主机登录失败"; - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - - } - #endregion - - } - //检测升级远程主机Trojan版本 - private void ButtonUpdateTrojan_Click(object sender, RoutedEventArgs e) - { - ConnectionInfo connectionInfo = GenerateConnectionInfo(); - if (connectionInfo == null) - { - MessageBox.Show("远程主机连接信息有误,请检查"); - return; - } - - Thread thread = new Thread(() => UpdateTojan(connectionInfo, TextBlockSetUpProcessing, ProgressBarSetUpProcessing)); - thread.SetApartmentState(ApartmentState.STA); - thread.Start(); - } - //升级Trojan主程序 - private void UpdateTojan(ConnectionInfo connectionInfo, TextBlock textBlockName, ProgressBar progressBar) - { - string currentStatus = "正在登录远程主机......"; - Action updateAction = new Action(UpdateTextBlock); - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - - try - { - #region 主机指纹,暂未启用 - //byte[] expectedFingerPrint = new byte[] { - // 0x66, 0x31, 0xaf, 0x00, 0x54, 0xb9, 0x87, 0x31, - // 0xff, 0x58, 0x1c, 0x31, 0xb1, 0xa2, 0x4c, 0x6b - // }; - #endregion - using (var client = new SshClient(connectionInfo)) - - { - #region ssh登录验证主机指纹代码块,暂未启用 - // client.HostKeyReceived += (sender, e) => - // { - // if (expectedFingerPrint.Length == e.FingerPrint.Length) - // { - // for (var i = 0; i < expectedFingerPrint.Length; i++) - // { - // if (expectedFingerPrint[i] != e.FingerPrint[i]) - // { - // e.CanTrust = false; - // break; - // } - // } - // } - // else - // { - // e.CanTrust = false; - // } - // }; - #endregion - - client.Connect(); - if (client.IsConnected == true) - { - currentStatus = "主机登录成功"; - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - Thread.Sleep(1000); - } - //检测是否运行在root权限下 - string testRootAuthority = client.RunCommand(@"id -u").Result; - if (testRootAuthority.Equals("0\n") == false) - { - MessageBox.Show("请使用具有root权限的账户登录主机!!"); - client.Disconnect(); - return; - } - //检测远程主机V2ray版本 - currentStatus = "检测远程主机Trojan版本......"; - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - Thread.Sleep(1000); - - string cmdTestTrojanInstalled = @"find / -name trojan"; - //MessageBox.Show(cmdTestV2rayInstalled); - string resultCmdTestTrojanInstalled = client.RunCommand(cmdTestTrojanInstalled).Result; - //client.Disconnect(); - //MessageBox.Show(resultCmdTestV2rayInstalled); - if (resultCmdTestTrojanInstalled.Contains("/usr/local/bin/trojan") == false) - { - MessageBoxResult messageBoxResult = MessageBox.Show("远程主机未安装Trojan!"); - - currentStatus = "未安装Trojan,退出"; - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - Thread.Sleep(1000); - client.Disconnect(); - return; - - } - string sshcmd; - sshcmd = @"echo ""$(/usr/local/bin/trojan -v 2>&1)"" | head -n 1 | cut -d "" "" -f4"; - //MessageBox.Show(sshcmd); - string trojanCurrentVersion = client.RunCommand(sshcmd).Result;//不含字母v - //MessageBox.Show(v2rayCurrentVersion); - - sshcmd = @"curl -fsSL https://api.github.com/repos/trojan-gfw/trojan/releases/latest | grep tag_name | sed -E 's/.*""v(.*)"".*/\1/'"; - //MessageBox.Show(sshcmd); - - string trojanNewVersion = client.RunCommand(sshcmd).Result;//不包含字母v - //MessageBox.Show(v2rayNewVersion); - if (trojanNewVersion.Equals(trojanCurrentVersion) == false) - { - MessageBoxResult messageBoxResult = MessageBox.Show($"远程主机当前版本为:v{trojanCurrentVersion}\n最新版本为:{trojanNewVersion}\n是否升级为最新版本?", "", MessageBoxButton.YesNo, MessageBoxImage.Question); - if (messageBoxResult == MessageBoxResult.Yes) - { - currentStatus = "正在升级Trojan到最新版本......"; - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - Thread.Sleep(1000); - - //备份配置文件 - sshcmd = @"mv /usr/local/etc/trojan/config.json /usr/local/etc/trojan/config.json.bak"; - client.RunCommand(sshcmd); - //升级Trojan主程序 - client.RunCommand("curl -o /tmp/trojan-quickstart.sh https://raw.githubusercontent.com/trojan-gfw/trojan-quickstart/master/trojan-quickstart.sh"); - client.RunCommand("yes | bash /tmp/trojan-quickstart.sh"); - sshcmd = @"echo ""$(/usr/local/bin/trojan -v 2>&1)"" | head -n 1 | cut -d "" "" -f4"; - //MessageBox.Show(sshcmd); - trojanCurrentVersion = client.RunCommand(sshcmd).Result;//不含字母v - if (trojanNewVersion.Equals(trojanCurrentVersion) == true) - { - //恢复原来的配置文件备份 - sshcmd = @"rm -f /usr/local/etc/trojan/config.json"; - client.RunCommand(sshcmd); - sshcmd = @"mv /usr/local/etc/trojan/config.json.bak /usr/local/etc/trojan/config.json"; - client.RunCommand(sshcmd); - MessageBox.Show($"升级成功!!\n当前版本为:v{trojanCurrentVersion}\n最新版本为:{trojanNewVersion}"); - currentStatus = "升级成功!当前已是最新版本!"; - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - Thread.Sleep(1000); - } - else - { - MessageBox.Show("升级失败,原因未知,请向开发者提问,以寻求支持!"); - currentStatus = "升级失败!"; - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - Thread.Sleep(1000); - } - } - - else - { - currentStatus = "升级取消,退出"; - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - Thread.Sleep(1000); - client.Disconnect(); - return; - } - } - else - { - MessageBox.Show($"远程主机当前已是最新版本:{trojanNewVersion}\n无需升级!"); - currentStatus = "已是最新版本,无需升级,退出"; - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - Thread.Sleep(1000); - } - - client.Disconnect(); - return; - } - } - catch (Exception ex1)//例外处理 - #region 例外处理 - { - //MessageBox.Show(ex1.Message); - if (ex1.Message.Contains("连接尝试失败") == true) - { - MessageBox.Show($"{ex1.Message}\n请检查主机地址及端口是否正确,如果通过代理,请检查代理是否正常工作"); - } - - else if (ex1.Message.Contains("denied (password)") == true) - { - MessageBox.Show($"{ex1.Message}\n密码错误或用户名错误"); - } - else if (ex1.Message.Contains("Invalid private key file") == true) - { - MessageBox.Show($"{ex1.Message}\n所选密钥文件错误或者格式不对"); - } - else if (ex1.Message.Contains("denied (publickey)") == true) - { - MessageBox.Show($"{ex1.Message}\n使用密钥登录,密钥文件错误或用户名错误"); - } - else if (ex1.Message.Contains("目标计算机积极拒绝") == true) - { - MessageBox.Show($"{ex1.Message}\n主机地址错误,如果使用了代理,也可能是连接代理的端口错误"); - } - else - { - MessageBox.Show("发生错误"); - MessageBox.Show(ex1.Message); - } - currentStatus = "主机登录失败"; - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - - } - #endregion - - } - //检测升级Trojan-Go版本 - private void ButtonUpdateTrojanGo_Click(object sender, RoutedEventArgs e) - { - ConnectionInfo connectionInfo = GenerateConnectionInfo(); - if (connectionInfo == null) - { - MessageBox.Show("远程主机连接信息有误,请检查"); - return; - } - - Thread thread = new Thread(() => UpdateTojanGo(connectionInfo, TextBlockSetUpProcessing, ProgressBarSetUpProcessing)); - thread.SetApartmentState(ApartmentState.STA); - thread.Start(); - } - //升级Trojan主程序 - private void UpdateTojanGo(ConnectionInfo connectionInfo, TextBlock textBlockName, ProgressBar progressBar) - { - string currentStatus = "正在登录远程主机......"; - Action updateAction = new Action(UpdateTextBlock); - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - - try - { - #region 主机指纹,暂未启用 - //byte[] expectedFingerPrint = new byte[] { - // 0x66, 0x31, 0xaf, 0x00, 0x54, 0xb9, 0x87, 0x31, - // 0xff, 0x58, 0x1c, 0x31, 0xb1, 0xa2, 0x4c, 0x6b - // }; - #endregion - using (var client = new SshClient(connectionInfo)) - - { - #region ssh登录验证主机指纹代码块,暂未启用 - // client.HostKeyReceived += (sender, e) => - // { - // if (expectedFingerPrint.Length == e.FingerPrint.Length) - // { - // for (var i = 0; i < expectedFingerPrint.Length; i++) - // { - // if (expectedFingerPrint[i] != e.FingerPrint[i]) - // { - // e.CanTrust = false; - // break; - // } - // } - // } - // else - // { - // e.CanTrust = false; - // } - // }; - #endregion - - client.Connect(); - if (client.IsConnected == true) - { - currentStatus = "主机登录成功"; - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - Thread.Sleep(1000); - } - //检测是否运行在root权限下 - string testRootAuthority = client.RunCommand(@"id -u").Result; - if (testRootAuthority.Equals("0\n") == false) - { - MessageBox.Show("请使用具有root权限的账户登录主机!!"); - client.Disconnect(); - return; - } - //检测远程主机V2ray版本 - currentStatus = "检测远程主机Trojan-Go版本......"; - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - Thread.Sleep(1000); - - string cmdTestTrojanInstalled = @"find / -name trojan-go"; - //MessageBox.Show(cmdTestV2rayInstalled); - string resultCmdTestTrojanInstalled = client.RunCommand(cmdTestTrojanInstalled).Result; - //client.Disconnect(); - //MessageBox.Show(resultCmdTestV2rayInstalled); - if (resultCmdTestTrojanInstalled.Contains("/usr/bin/trojan-go/trojan-go") == false) - { - MessageBoxResult messageBoxResult = MessageBox.Show("远程主机未安装Trojan-Go!"); - - currentStatus = "未安装Trojan-Go,退出"; - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - Thread.Sleep(1000); - client.Disconnect(); - return; - - } - string sshcmd; - sshcmd = @"echo ""$(/usr/bin/trojan-go/trojan-go -version)"" | head -n 1 | cut -d "" "" -f2"; - //MessageBox.Show(sshcmd); - string trojanCurrentVersion = client.RunCommand(sshcmd).Result;//含字母v - //MessageBox.Show(v2rayCurrentVersion); - - sshcmd = @"curl -s https://api.github.com/repos/p4gefau1t/trojan-go/tags | grep 'name' | cut -d\"" -f4 | head -1"; - //MessageBox.Show(sshcmd); - - string trojanNewVersion = client.RunCommand(sshcmd).Result;//含字母v - //MessageBox.Show(v2rayNewVersion); - if (trojanNewVersion.Equals(trojanCurrentVersion) == false) - { - MessageBoxResult messageBoxResult = MessageBox.Show($"远程主机当前版本为:v{trojanCurrentVersion}\n最新版本为:{trojanNewVersion}\n是否升级为最新版本?", "", MessageBoxButton.YesNo, MessageBoxImage.Question); - if (messageBoxResult == MessageBoxResult.Yes) - { - currentStatus = "正在升级Trojan-Go到最新版本......"; - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - Thread.Sleep(1000); - - //备份配置文件 - //sshcmd = @"mv /usr/local/etc/trojan/config.json /usr/local/etc/trojan/config.json.bak"; - //client.RunCommand(sshcmd); - //升级Trojan-Go主程序 - client.RunCommand("curl -o /tmp/trojan-go.sh https://raw.githubusercontent.com/proxysu/shellscript/master/trojan-go.sh"); - client.RunCommand("bash /tmp/trojan-go.sh -f"); - sshcmd = @"curl -s https://api.github.com/repos/p4gefau1t/trojan-go/tags | grep 'name' | cut -d\"" -f4 | head -1"; - //MessageBox.Show(sshcmd); - trojanCurrentVersion = client.RunCommand(sshcmd).Result;//含字母v - if (trojanNewVersion.Equals(trojanCurrentVersion) == true) - { - //恢复原来的配置文件备份 - //sshcmd = @"rm -f /usr/local/etc/trojan/config.json"; - //client.RunCommand(sshcmd); - //sshcmd = @"mv /usr/local/etc/trojan/config.json.bak /usr/local/etc/trojan/config.json"; - //client.RunCommand(sshcmd); - MessageBox.Show($"升级成功!!\n当前版本为:v{trojanCurrentVersion}\n最新版本为:{trojanNewVersion}"); - currentStatus = "升级成功!当前已是最新版本!"; - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - Thread.Sleep(1000); - } - else - { - MessageBox.Show("升级失败,原因未知,请向开发者提问,以寻求支持!"); - currentStatus = "升级失败!"; - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - Thread.Sleep(1000); - } - } - - else - { - currentStatus = "升级取消,退出"; - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - Thread.Sleep(1000); - client.Disconnect(); - return; - } - } - else - { - MessageBox.Show($"远程主机当前已是最新版本:{trojanNewVersion}\n无需升级!"); - currentStatus = "已是最新版本,无需升级,退出"; - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - Thread.Sleep(1000); - } - - client.Disconnect(); - return; - } - } - catch (Exception ex1)//例外处理 - #region 例外处理 - { - //MessageBox.Show(ex1.Message); - if (ex1.Message.Contains("连接尝试失败") == true) - { - MessageBox.Show($"{ex1.Message}\n请检查主机地址及端口是否正确,如果通过代理,请检查代理是否正常工作"); - } - - else if (ex1.Message.Contains("denied (password)") == true) - { - MessageBox.Show($"{ex1.Message}\n密码错误或用户名错误"); - } - else if (ex1.Message.Contains("Invalid private key file") == true) - { - MessageBox.Show($"{ex1.Message}\n所选密钥文件错误或者格式不对"); - } - else if (ex1.Message.Contains("denied (publickey)") == true) - { - MessageBox.Show($"{ex1.Message}\n使用密钥登录,密钥文件错误或用户名错误"); - } - else if (ex1.Message.Contains("目标计算机积极拒绝") == true) - { - MessageBox.Show($"{ex1.Message}\n主机地址错误,如果使用了代理,也可能是连接代理的端口错误"); - } - else - { - MessageBox.Show("发生错误"); - MessageBox.Show(ex1.Message); - } - currentStatus = "主机登录失败"; - textBlockName.Dispatcher.BeginInvoke(updateAction, textBlockName, progressBar, currentStatus); - - } - #endregion - - } + //生成三合一的v2ray路径 private void ButtonV2rayPath3in1_Click(object sender, RoutedEventArgs e) diff --git a/ProxySU/TemplateConfiguration.xaml b/ProxySU/TemplateConfiguration.xaml index 05d9287..15f47c1 100644 --- a/ProxySU/TemplateConfiguration.xaml +++ b/ProxySU/TemplateConfiguration.xaml @@ -61,7 +61,9 @@ - + + + @@ -118,7 +120,7 @@ - + @@ -146,7 +148,7 @@ - + @@ -257,7 +259,7 @@ - + @@ -265,8 +267,8 @@ - - + + diff --git a/ProxySU/TemplateConfiguration.xaml.cs b/ProxySU/TemplateConfiguration.xaml.cs index 303e819..e82df60 100644 --- a/ProxySU/TemplateConfiguration.xaml.cs +++ b/ProxySU/TemplateConfiguration.xaml.cs @@ -171,7 +171,7 @@ namespace ProxySU } //http2+TLS+Web模式被选中 - else if (RadioButtonHTTP2Web.IsChecked == true) + else if (RadioButtonHTTP2Web.IsChecked == true || RadioButtonHTTP2WebHot.IsChecked == true) { if (string.IsNullOrEmpty(TextBoxDomain.Text.ToString()) == true) { @@ -352,6 +352,7 @@ namespace ProxySU TextBlockQuicUUID.Visibility = Visibility.Collapsed; TextBoxQuicUUID.Visibility = Visibility.Collapsed; ButtonQuicUUID.Visibility = Visibility.Collapsed; + TextBlockMkcpUUID.Visibility = Visibility.Collapsed; //隐藏Path TextBlockPath.Visibility = Visibility.Collapsed; TextBoxPath.Visibility = Visibility.Collapsed; @@ -392,6 +393,7 @@ namespace ProxySU TextBlockQuicUUID.Visibility = Visibility.Collapsed; TextBoxQuicUUID.Visibility = Visibility.Collapsed; ButtonQuicUUID.Visibility = Visibility.Collapsed; + TextBlockMkcpUUID.Visibility = Visibility.Collapsed; //隐藏伪装网站 TextBlockMaskSites.Visibility = Visibility.Collapsed; TextBoxMaskSites.Visibility = Visibility.Collapsed; @@ -417,6 +419,7 @@ namespace ProxySU TextBlockQuicUUID.Visibility = Visibility.Collapsed; TextBoxQuicUUID.Visibility = Visibility.Collapsed; ButtonQuicUUID.Visibility = Visibility.Collapsed; + TextBlockMkcpUUID.Visibility = Visibility.Collapsed; //隐藏伪装网站 TextBlockMaskSites.Visibility = Visibility.Collapsed; TextBoxMaskSites.Visibility = Visibility.Collapsed; @@ -442,6 +445,7 @@ namespace ProxySU TextBlockQuicUUID.Visibility = Visibility.Collapsed; TextBoxQuicUUID.Visibility = Visibility.Collapsed; ButtonQuicUUID.Visibility = Visibility.Collapsed; + TextBlockMkcpUUID.Visibility = Visibility.Collapsed; //隐藏伪装网站 TextBlockMaskSites.Visibility = Visibility.Collapsed; TextBoxMaskSites.Visibility = Visibility.Collapsed; @@ -470,9 +474,13 @@ namespace ProxySU TextBlockQuicUUID.Visibility = Visibility.Collapsed; TextBoxQuicUUID.Visibility = Visibility.Collapsed; ButtonQuicUUID.Visibility = Visibility.Collapsed; + TextBlockMkcpUUID.Visibility = Visibility.Collapsed; //显示伪装网站 - TextBlockMaskSites.Visibility = Visibility.Visible; - TextBoxMaskSites.Visibility = Visibility.Visible; + //TextBlockMaskSites.Visibility = Visibility.Visible; + //TextBoxMaskSites.Visibility = Visibility.Visible; + //隐藏伪装网站 + TextBlockMaskSites.Visibility = Visibility.Collapsed; + TextBoxMaskSites.Visibility = Visibility.Collapsed; Guid uuid = Guid.NewGuid(); TextBoxNewUUID.Text = uuid.ToString(); @@ -499,6 +507,7 @@ namespace ProxySU TextBlockQuicUUID.Visibility = Visibility.Collapsed; TextBoxQuicUUID.Visibility = Visibility.Collapsed; ButtonQuicUUID.Visibility = Visibility.Collapsed; + TextBlockMkcpUUID.Visibility = Visibility.Collapsed; //隐藏伪装网站 TextBlockMaskSites.Visibility = Visibility.Collapsed; TextBoxMaskSites.Visibility = Visibility.Collapsed; @@ -527,6 +536,7 @@ namespace ProxySU TextBlockQuicUUID.Visibility = Visibility.Collapsed; TextBoxQuicUUID.Visibility = Visibility.Collapsed; ButtonQuicUUID.Visibility = Visibility.Collapsed; + TextBlockMkcpUUID.Visibility = Visibility.Collapsed; //隐藏伪装网站 TextBlockMaskSites.Visibility = Visibility.Collapsed; TextBoxMaskSites.Visibility = Visibility.Collapsed; @@ -542,6 +552,7 @@ namespace ProxySU TextBlockQuicUUID.Visibility = Visibility.Visible; TextBoxQuicUUID.Visibility = Visibility.Visible; ButtonQuicUUID.Visibility = Visibility.Visible; + TextBlockMkcpUUID.Visibility = Visibility.Visible; //隐藏Path TextBlockPath.Visibility = Visibility.Collapsed; TextBoxPath.Visibility = Visibility.Collapsed; diff --git a/ProxySU/TrojanGoTemplateWindow.xaml b/ProxySU/TrojanGoTemplateWindow.xaml index c7f5667..15c45d0 100644 --- a/ProxySU/TrojanGoTemplateWindow.xaml +++ b/ProxySU/TrojanGoTemplateWindow.xaml @@ -93,8 +93,8 @@ - - + + diff --git a/ProxySU/TrojanTemplateWindow.xaml b/ProxySU/TrojanTemplateWindow.xaml index 0d05b5d..e7d9807 100644 --- a/ProxySU/TrojanTemplateWindow.xaml +++ b/ProxySU/TrojanTemplateWindow.xaml @@ -83,8 +83,8 @@ - - + + diff --git a/ProxySU/bin/Beta/Beta.zip b/ProxySU/bin/Beta/Beta.zip index 8891babe8070283667becb17ae00879f4e500bc5..622bdd10fdeda4ce654436b504ea1c31507ef172 100644 GIT binary patch delta 48178 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

v0*S>r2;X<2`QyrzIs)=16{Sc1d1I+5WQq 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 Ge*1qxeZhAC delta 47735 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