using Step.CmsConnectManager.Events; using Step.CmsConnectManager.Exceptions; using System; using System.Collections.Generic; using System.Linq; using System.Net; using System.Text.RegularExpressions; using System.Threading.Tasks; using static Step.CmsConnectManager.CMSConnectConstants; namespace Step.CmsConnectManager { public class GatewayController { private SSHAdapter SSHAdapter; //--------------------------------------------------------------------------------------------------- #region Public_methods /// /// Simple constructor. /// Create an instance with this configuration: hostname: localhost, username: root, password: root. /// public GatewayController() { SSHAdapter = new SSHAdapter("localhost", "root", "root"); } /// /// Advanced constructor. /// Create an instance with the configuration passed by arguments /// /// Name (or IP-Address) of the gateway /// Username for Gateway Login /// Password for Gateway Login /// Thrown when one parameter is null public GatewayController(string hostname, string username, string password) { SSHAdapter = new SSHAdapter(hostname, username, password); } /// /// Write Proxy-Configuration on Gateway. /// See for generate the configuration. /// /// Configuration of the proxy. /// public void WriteGatewayProxyConfiguration(GatewayProxyConfiguration proxyConfiguration) { string Command = SSHAdapter.GenerateSshProxyCommand(proxyConfiguration); SSHAdapter.SendSSHCommand(Command); } /// /// Write Newtork-Configuration on Gateway. /// See for generate the configuration. /// /// Configuration of the network. /// public void WriteGatewayNetworkConfiguration(GatewayNetworkConfiguration networkConfiguration) { string NetworkCommand = SSHAdapter.GenerateSshNetworkCommand(networkConfiguration); string DnsIpCommand = SSHAdapter.GenerateSshDnsCommand(networkConfiguration); string DnsSuffixCommand = SSHAdapter.GenerateSshDnsSuffxCommand(networkConfiguration); SSHAdapter.SendSSHCommand(new List() { NetworkCommand, DnsIpCommand, DnsSuffixCommand }); } /// /// Read Newtork-Configuration saved on Gateway. /// /// See /// /// public GatewayNetworkConfiguration ReadGatewayNetworkConfiguration() { return ElaborateConfigFromSshNetworkCommand( SSHAdapter.SendSSHCommand(SSH_GET_NETWORK_COMMAND) ); } /// /// Read Proxy-Configuration saved on Gateway. /// /// See /// /// public GatewayProxyConfiguration ReadGatewayProxyConfiguration() { return ElaborateConfigFromSshProxyCommand( SSHAdapter.SendSSHCommand(SSH_GET_PROXY_COMMAND)); } /// /// Test connection to SCM/CMS Server, on Gateway. /// /// Seconds timeout for the request /// public GatewayConnectionStatus TestGatewayConnection(int timeout) { if (timeout < 0) throw new ArgumentOutOfRangeException("Timeout must be > 0"); return ElaborateTestConnectionCommand(SSHAdapter.SendSSHCommand(SSH_TEST_CONNECTION_COMMAND + timeout)); } /// /// Reboot asynchronously the Gateway. /// /// Serconds to delay before reboot /// Handler Callback when the operation is finished or an error occours. /// See /// public void RebootGatewayAsync(int delay, EventHandler handler) { if (delay < 0) throw new ArgumentOutOfRangeException("Delay must be > 0"); //Create the Action Action> action = (int del, EventHandler hand) => { GatewayRebootEventHandlerArgs ev = new GatewayRebootEventHandlerArgs(); try { SSHAdapter.SendSSHReboot(del); } catch (Exception e) { ev.ErrorStatus = true; ev.ErrorMessage = e.Message; } hand(this, ev); }; // Create a task and not start it. Task t = new Task (() => action(delay, handler)); t.Start(); } /// /// Reboot and wait a new session of the Gateway. /// /// Seconds to delay before reboot /// public void RebootGateway(int delay) { if (delay < 0) throw new ArgumentOutOfRangeException("Delay must be > 0"); // Send Command SSHAdapter.SendSSHReboot(delay); } #endregion //--------------------------------------------------------------------------------------------------- #region SSH_commands_preparations_sub_methods #endregion //--------------------------------------------------------------------------------------------------- #region elaborate_SSH_values_sub_methods private GatewayNetworkConfiguration ElaborateConfigFromSshNetworkCommand(List lines) { GatewayNetworkConfiguration configuration = new GatewayNetworkConfiguration(); foreach (string line in lines) { if (line.StartsWith(IP_ADDR_LABEL)) DecodeNetworkIPAddress(line.Remove(0, IP_ADDR_LABEL.Length).Trim(), ref configuration); else if (line.StartsWith(GATEWAY_LABEL)) DecodeNetworkDefGateway(line.Remove(0, GATEWAY_LABEL.Length).Trim(), ref configuration); else if (line.StartsWith(DNSIP_LABEL)) DecodeNetworkDnsIp(line.Remove(0, DNSIP_LABEL.Length).Trim(), ref configuration); else if (line.StartsWith(DNSPREFIX_LABEL)) DecodeNetworkDnsPrefix(line.Remove(0, DNSPREFIX_LABEL.Length).Trim(), ref configuration); } return configuration; } private GatewayProxyConfiguration ElaborateConfigFromSshProxyCommand(List lines) { GatewayProxyConfiguration configuration = new GatewayProxyConfiguration(); foreach (string line in lines) { if (line.StartsWith(PROXY_ADDR_LABEL)) DecodeProxyAddress(line.Remove(0, PROXY_ADDR_LABEL.Length).Trim(), ref configuration); else if (line.StartsWith(NO_PROXY_LABEL)) DecodeNoProxyUrls(line.Remove(0, NO_PROXY_LABEL.Length).Trim(), ref configuration); } return configuration; } private GatewayConnectionStatus ElaborateTestConnectionCommand(List lines) { GatewayConnectionStatus status = new GatewayConnectionStatus(); foreach (string line in lines) { if (!string.IsNullOrWhiteSpace(line)) DecodeConnectionStatus(line.Trim(), ref status); } return status; } #endregion //--------------------------------------------------------------------------------------------------- #region decode_SSH_values_sub_methods private void DecodeNetworkIPAddress(string stringValue, ref GatewayNetworkConfiguration configuration) { //Check if has DHCP if (stringValue == "DHCP") configuration.hasDhcp = true; else { configuration.hasDhcp = false; //Check if has / for netmask if (!stringValue.Contains('/')) throw new GatewayException("Internal Gateway Error during read (bad format): " + IP_ADDR_LABEL + stringValue); string [] tempAddr = stringValue.Split('/'); //Check if has lenght == 2 if (tempAddr.Length != 2) throw new GatewayException("Internal Gateway Error during read (bad format): " + IP_ADDR_LABEL + stringValue); //Set the IPAddress / Netmask IPAddress tempIp; if (!EvaluateIPV4(tempAddr[0], out tempIp)) throw new GatewayException("Internal Gateway Error during read (bad format): " + IP_ADDR_LABEL + stringValue); IPNetwork tempIpNetw; if (!IPNetwork.TryParse(stringValue, out tempIpNetw)) throw new GatewayException("Internal Gateway Error during read (bad format): " + IP_ADDR_LABEL + stringValue); configuration.ipAddress = tempIp; configuration.netMaskAddress = tempIpNetw.Netmask; } } private void DecodeNetworkDefGateway(string stringValue, ref GatewayNetworkConfiguration configuration) { //check if is defined if (stringValue == UNDEF_VALUE) configuration.defaultGatewayAddress = null; else { if (!EvaluateIPV4(stringValue, out IPAddress tempIp)) throw new GatewayException("Internal Gateway Error during read (bad format): " + GATEWAY_LABEL + stringValue); configuration.defaultGatewayAddress = tempIp; } } private void DecodeNetworkDnsIp(string stringValue, ref GatewayNetworkConfiguration configuration) { //check if is defined if (stringValue == UNDEF_VALUE) configuration.dnsAddresses = null; else { string[] tempStr = stringValue.Split(' '); if (tempStr.Length == 0) configuration.dnsAddresses = null; else { IPAddress tempIp; List tempDns = new List(); foreach (string str in tempStr) { if (string.IsNullOrEmpty(str)) continue; if (!EvaluateIPV4(str, out tempIp)) throw new GatewayException("Internal Gateway Error during read (bad format): " + DNSIP_LABEL + stringValue); tempDns.Add(tempIp); } configuration.dnsAddresses = tempDns; } } } private void DecodeNetworkDnsPrefix(string stringValue, ref GatewayNetworkConfiguration configuration) { // Check if is defined if (stringValue == UNDEF_VALUE) configuration.dnsPrefixes = null; else { string[] tempStr = stringValue.Split(' '); if (tempStr.Length == 0) configuration.dnsPrefixes = null; else configuration.dnsPrefixes = tempStr.Where(X=> !string.IsNullOrEmpty(X)).ToList(); } } private void DecodeProxyAddress(string stringValue, ref GatewayProxyConfiguration configuration) { // Check if is defined if (stringValue == UNDEF_VALUE) configuration.hasProxy = false; else { configuration.hasProxy = true; /* Must be one of these: * - Address:Port * - User:Password@Address:Port */ if (!stringValue.Contains("@")) { // Set username & password configuration.username = null; configuration.password = null; // Check if has : if (!stringValue.Contains(':')) throw new GatewayException("Internal Gateway Error during read (bad format): " + PROXY_ADDR_LABEL + stringValue); string[] tempAddr = stringValue.Split(':'); // Check if has lenght == 2 if (tempAddr.Length != 2) throw new GatewayException("Internal Gateway Error during read (bad format): " + PROXY_ADDR_LABEL + stringValue); // Set the address configuration.address = tempAddr[0]; // Set the port if (!uint.TryParse(tempAddr[1], out uint tempPort)) throw new GatewayException("Internal Gateway Error during read (bad format): " + PROXY_ADDR_LABEL + stringValue); configuration.port = tempPort; } else { string[] splitted = stringValue.Split('@'); //Check if has lenght == 2 if (splitted.Length != 2) throw new GatewayException("Internal Gateway Error during read (bad format): " + PROXY_ADDR_LABEL + stringValue); //Check if has : if (!splitted[0].Contains(':')) throw new GatewayException("Internal Gateway Error during read (bad format): " + PROXY_ADDR_LABEL + stringValue); if (!splitted[1].Contains(':')) throw new GatewayException("Internal Gateway Error during read (bad format): " + PROXY_ADDR_LABEL + stringValue); string[] tempLogin = splitted[0].Split(':'); string[] tempAddr = splitted[1].Split(':'); //Check if has lenght == 2 if (tempLogin.Length != 2) throw new GatewayException("Internal Gateway Error during read (bad format): " + PROXY_ADDR_LABEL + stringValue); if (tempAddr.Length != 2) throw new GatewayException("Internal Gateway Error during read (bad format): " + PROXY_ADDR_LABEL + stringValue); // Set the username configuration.username = tempLogin[0]; // Set the password configuration.password = tempLogin[1]; // Set the address configuration.address = tempAddr[0]; // Set the port if (!uint.TryParse(tempAddr[1], out uint tempPort)) throw new GatewayException("Internal Gateway Error during read (bad format): " + PROXY_ADDR_LABEL + stringValue); configuration.port = tempPort; } } } private void DecodeNoProxyUrls(string stringValue, ref GatewayProxyConfiguration configuration) { // Check if is defined if (stringValue == UNDEF_VALUE) configuration.noproxyAddresses = null; else { string[] tempStr = stringValue.Trim('"').Split(','); for (int i=0;i