/// <summary> /// Connects with the specified opnSense server using the v17.1 protocol implementation and returns the backup file contents /// </summary> /// <param name="opnSenseServer">opnSense server details which identifies which opnSense server to connect to</param> /// <param name="cookieJar">Cookie container to use through the communication with opnSense</param> /// <param name="timeout">Timeout in milliseconds on how long requests to opnSense may take. Default = 60000 = 60 seconds.</param> /// <returns>OpnSenseBackupFile instance containing the retrieved backup content from opnSense</returns> public OpnSenseBackupFile Execute(OpnSenseServerDetails opnSenseServer, CookieContainer cookieJar, int timeout = 60000) { Program.WriteOutput("Connecting using protocol version {0}", new object[] { opnSenseServer.Version }); // Create a session on the opnSense webserver var loginPageContents = HttpUtility.HttpGetLoginPageContents(opnSenseServer.ServerBaseUrl, cookieJar, timeout); // Check if a response was returned from the login page request if (string.IsNullOrEmpty(loginPageContents)) { throw new ApplicationException("Unable to retrieve login page contents"); } Program.WriteOutput("Authenticating"); // Use a regular expression to fetch the anti cross site scriping token from the HTML var xssToken = Regex.Match(loginPageContents, "<input.+?type=['\"]hidden['\"].+?id=['\"]_+?opnsense_csrf['\"].+?name=['\"](?<xsstokenname>.*?)['\"].+?value=['\"](?<xsstokenvalue>.*?)['\"].+?/>", RegexOptions.IgnoreCase); // Verify that the anti XSS token was found if (!xssToken.Success) { throw new ApplicationException("Unable to retrieve Cross Site Request Forgery token from login page"); } // Authenticate the session var authenticationResult = HttpUtility.AuthenticateViaUrlEncodedFormMethod(string.Concat(opnSenseServer.ServerBaseUrl, "index.php"), new Dictionary <string, string> { { xssToken.Groups["xsstokenname"].Value, xssToken.Groups["xsstokenvalue"].Value }, { "usernamefld", System.Web.HttpUtility.UrlEncode(opnSenseServer.Username) }, { "passwordfld", System.Web.HttpUtility.UrlEncode(opnSenseServer.Password) }, { "login", "1" } }, cookieJar, timeout); // Verify if the username/password combination was valid by examining the server response if (authenticationResult.Contains("Username or Password incorrect")) { throw new ApplicationException("ERROR: Credentials incorrect"); } Program.WriteOutput("Requesting backup file"); // Get the backup page contents for the xsrf token var backupPageUrl = string.Concat(opnSenseServer.ServerBaseUrl, "diag_backup.php"); var backupPageContents = HttpUtility.HttpGetLoginPageContents(backupPageUrl, cookieJar, timeout); // Check if a response was returned from the login page request if (string.IsNullOrEmpty(backupPageContents)) { throw new ApplicationException("Unable to retrieve backup page contents"); } // Use a regular expression to fetch the anti cross site scriping token from the HTML xssToken = Regex.Match(backupPageContents, "<input.+?type=['\"]hidden['\"].+?id=['\"]_+?opnsense_csrf['\"].+?name=['\"](?<xsstokenname>.*?)['\"].+?value=['\"](?<xsstokenvalue>.*?)['\"].+?/>", RegexOptions.IgnoreCase); // Verify that the anti XSS token was found if (!xssToken.Success) { throw new ApplicationException("Unable to retrieve Cross Site Request Forgery token from backup page"); } Program.WriteOutput("Retrieving backup file"); var downloadArgs = new Dictionary <string, string> { { xssToken.Groups["xsstokenname"].Value, xssToken.Groups["xsstokenvalue"].Value }, { "donotbackuprrd", opnSenseServer.BackupStatisticsData ? "" : "on" }, { "encrypt", opnSenseServer.EncryptBackup ? "on" : "" }, { "encrypt_password", opnSenseServer.EncryptionPassword }, { "encrypt_passconf", opnSenseServer.EncryptionPassword }, { "download", "Download configuration" }, { "restorearea", "" }, { "rebootafterrestore", "on" }, { "decrypt_password", "" }, { "decrypt_passconf", "" } }; string filename; var opnSenseBackupFile = new OpnSenseBackupFile { FileContents = HttpUtility.DownloadBackupFile(backupPageUrl, downloadArgs, cookieJar, out filename, timeout, backupPageUrl), FileName = filename }; return(opnSenseBackupFile); }
/// <summary> /// Retrieves the backup file from opnSense /// </summary> private static void RetrieveBackupFile() { if (OpnSenseServerDetails.UseHttps) { // Ignore all certificate related errors ServicePointManager.ServerCertificateValidationCallback += (sender, cert, chain, sslPolicyErrors) => true; } // Create a cookie container to hold the session cookies var cookieJar = new CookieContainer(); // Define the protocol implementation to use to communicate with opnSense Protocols.IOpnSenseProtocol opnSenseProtocol = null; switch (OpnSenseServerDetails.Version) { case "17.1": opnSenseProtocol = new Protocols.OpnSenseVersion171(); break; default: WriteOutput("Unsupported opnSense version provided ({0})", new object[] { OpnSenseServerDetails.Version }); Environment.Exit(1); break; } // Execute the communication with opnSense through the protocol implementation Protocols.OpnSenseBackupFile opnSenseBackupFile = null; try { opnSenseBackupFile = opnSenseProtocol.Execute(OpnSenseServerDetails, cookieJar, OpnSenseServerDetails.RequestTimeOut.GetValueOrDefault(60000)); } catch (Exception e) { WriteOutput("Error: {0}", new object[] { e.Message }); Environment.Exit(1); } // Verify that the backup file returned contains content if (opnSenseBackupFile == null || string.IsNullOrEmpty(opnSenseBackupFile.FileContents)) { WriteOutput("No valid backup contents returned"); Environment.Exit(1); } // Define the full path to the file to store the backup in. By default this will be in the same directory as this application runs from using the filename provided by opnSense, unless otherwise specified using the -o parameter. string outputDirectory; if (string.IsNullOrEmpty(OutputFileName)) { // -o flag has not been provided, store the file in the same directory as this tool runs using the same filename as provided by opnSense outputDirectory = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), opnSenseBackupFile.FileName); } else { // -o flag has been provided, check if just a path was provided or a path including filename if (Directory.Exists(OutputFileName)) { // Path was provided, use the filename as provided by opnSense to store it in the by -o provided path outputDirectory = Path.Combine(OutputFileName, opnSenseBackupFile.FileName); } else { // Complete path including filename has been provided with the -o flag, use that to store the backup outputDirectory = OutputFileName; } } WriteOutput(string.Concat("Saving backup file to ", outputDirectory)); // Store the backup contents in the file WriteBackupToFile(outputDirectory, opnSenseBackupFile.FileContents); WriteOutput(); WriteOutput("DONE"); }