/// <summary> /// Connects with the specified pfSense server using the v2.0 protocol implementation and returns the backup file contents /// </summary> /// <param name="pfSenseServer">pfSense server details which identifies which pfSense server to connect to</param> /// <param name="cookieJar">Cookie container to use through the communication with pfSense</param> /// <param name="timeout">Timeout in milliseconds on how long requests to pfSense may take. Default = 60000 = 60 seconds.</param> /// <returns>PfSenseBackupFile instance containing the retrieved backup content from pfSense</returns> public PfSenseBackupFile Execute(PfSenseServerDetails pfSenseServer, CookieContainer cookieJar, int timeout = 60000) { Program.WriteOutput("Connecting using protocol version {0}", new object[] { pfSenseServer.Version }); // Create a session on the pfSense webserver HttpUtility.HttpCreateSession(pfSenseServer.ServerBaseUrl, cookieJar); Program.WriteOutput("Authenticating"); // Authenticate the session var authenticationResult = HttpUtility.AuthenticateViaUrlEncodedFormMethod(string.Concat(pfSenseServer.ServerBaseUrl, "index.php"), new Dictionary <string, string>(), new Dictionary <string, string> { { "usernamefld", System.Web.HttpUtility.UrlEncode(pfSenseServer.Username) }, { "passwordfld", System.Web.HttpUtility.UrlEncode(pfSenseServer.Password) }, { "login", "Login" } }, 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("Retrieving backup file"); var downloadArgs = new Dictionary <string, string> { { "donotbackuprrd", pfSenseServer.BackupStatisticsData ? "" : "on" }, { "nopackages", pfSenseServer.BackupPackageInfo ? "" : "on" }, { "Submit", "Download configuration" } }; string filename; var pfSenseBackupFile = new PfSenseBackupFile { FileContents = HttpUtility.DownloadBackupFile(string.Concat(pfSenseServer.ServerBaseUrl, "diag_backup.php"), new Dictionary <string, string>(), downloadArgs, cookieJar, out filename, timeout), FileName = filename }; return(pfSenseBackupFile); }
/// <summary> /// Connects with the specified pfSense server using the v1.2 protocol implementation and returns the backup file contents /// </summary> /// <param name="pfSenseServer">pfSense server details which identifies which pfSense server to connect to</param> /// <param name="cookieJar">Cookie container to use through the communication with pfSense</param> /// <param name="timeout">Timeout in milliseconds on how long requests to pfSense may take. Default = 60000 = 60 seconds.</param> /// <returns>PfSenseBackupFile instance containing the retrieved backup content from pfSense</returns> public PfSenseBackupFile Execute(PfSenseServerDetails pfSenseServer, CookieContainer cookieJar, int timeout = 60000) { Program.WriteOutput("Retrieving backup file"); var downloadArgs = new Dictionary <string, string> { { "nopackages", pfSenseServer.BackupPackageInfo ? "" : "on" }, { "Submit", "Download configuration" } }; string filename; var pfSenseBackupFile = new PfSenseBackupFile { FileContents = HttpUtility.DownloadBackupFile(string.Concat(pfSenseServer.ServerBaseUrl, "diag_backup.php"), downloadArgs, cookieJar, out filename, timeout), FileName = filename }; return(pfSenseBackupFile); }
/// <summary> /// Retrieves the backup file from pfSense /// </summary> private static void RetrieveBackupFile() { if (PfSenseServerDetails.UseHttps) { // Ignore all certificate related errors ServicePointManager.ServerCertificateValidationCallback += (sender, cert, chain, sslPolicyErrors) => true; // Also allow TLS 1.1 and TLS 1.2 to be used by the pfSense server. TLS 1.0 and SSLv3 are already allowed by default. ServicePointManager.SecurityProtocol |= SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12; } // Create a cookie container to hold the session cookies var cookieJar = new CookieContainer(); // Define the protocol implementation to use to communicate with pfSense Protocols.IPfSenseProtocol pfSenseProtocol = null; switch (PfSenseServerDetails.Version) { case "1.2": pfSenseProtocol = new Protocols.PfSenseVersion12(); break; case "2.0": pfSenseProtocol = new Protocols.PfSenseVersion20(); break; case "2.1": case "2.2": pfSenseProtocol = new Protocols.PfSenseVersion21(); break; case "2.3": pfSenseProtocol = new Protocols.PfSenseVersion23(); break; case "2.3.3": pfSenseProtocol = new Protocols.PfSenseVersion233(); break; case "opn1907": pfSenseProtocol = new Protocols.OPNSenseVersion197(); break; default: WriteOutput("Unsupported pfSense version provided ({0})", new object[] { PfSenseServerDetails.Version }); Environment.Exit(1); break; } // Execute the communication with pfSense through the protocol implementation Protocols.PfSenseBackupFile pfSenseBackupFile = null; try { pfSenseBackupFile = pfSenseProtocol.Execute(PfSenseServerDetails, cookieJar, PfSenseServerDetails.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 (pfSenseBackupFile == null || string.IsNullOrEmpty(pfSenseBackupFile.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 pfSense, unless otherwise specified using the -o parameter. string outputPath; 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 pfSense outputPath = Path.Combine(new FileInfo(System.Diagnostics.Process.GetCurrentProcess().MainModule.FileName).DirectoryName, pfSenseBackupFile.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 pfSense to store it in the by -o provided path outputPath = Path.Combine(OutputFileName, pfSenseBackupFile.FileName); } else { // Complete path including filename has been provided with the -o flag, use that to store the backup outputPath = OutputFileName; } } WriteOutput($"Saving backup file to {outputPath}"); // Store the backup contents in the file WriteBackupToFile(outputPath, pfSenseBackupFile.FileContents); // Check if we should look to remove old backups if (PfSenseServerDetails.BackupDaysToKeep.HasValue) { DeleteOldBackups(Directory.GetParent(outputPath).FullName, PfSenseServerDetails.BackupDaysToKeep.Value); } WriteOutput(); WriteOutput("DONE"); }
/// <summary> /// Connects with the specified pfSense server using the v2.1 and v2.2 implementation and returns the backup file contents /// </summary> /// <param name="pfSenseServer">pfSense server details which identifies which pfSense server to connect to</param> /// <param name="cookieJar">Cookie container to use through the communication with pfSense</param> /// <param name="timeout">Timeout in milliseconds on how long requests to pfSense may take. Default = 60000 = 60 seconds.</param> /// <returns>PfSenseBackupFile instance containing the retrieved backup content from pfSense</returns> public PfSenseBackupFile Execute(PfSenseServerDetails pfSenseServer, CookieContainer cookieJar, int timeout = 60000) { Program.WriteOutput("Connecting using protocol version {0}", new object[] { pfSenseServer.Version }); // Create a session on the pfSense webserver var loginPageContents = HttpUtility.HttpGetLoginPageContents(pfSenseServer.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['\"].+?name=['\"]_+?csrf_magic['\"] value=['\"](?<xsstoken>.*?)['\"].+?/>", RegexOptions.IgnoreCase); // Verify that the anti XSS token was found if (!xssToken.Success) { xssToken = Regex.Match(loginPageContents, "var.*?csrfMagicToken.*?=.*?\"(?<xsstoken>.*?)\""); } // Authenticate the session var authenticationResult = HttpUtility.AuthenticateViaUrlEncodedFormMethod(string.Concat(pfSenseServer.ServerBaseUrl, "index.php"), new Dictionary <string, string> { { "__csrf_magic", xssToken.Groups["xsstoken"].Value }, { "usernamefld", System.Web.HttpUtility.UrlEncode(pfSenseServer.Username) }, { "passwordfld", System.Web.HttpUtility.UrlEncode(pfSenseServer.Password) }, { "login", "Login" } }, 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("Retrieving backup file"); var downloadArgs = new Dictionary <string, string> { { "donotbackuprrd", pfSenseServer.BackupStatisticsData ? "" : "on" }, { "nopackages", pfSenseServer.BackupPackageInfo ? "" : "on" }, { "encrypt", pfSenseServer.EncryptBackup ? "on" : "" }, { "encrypt_password", pfSenseServer.EncryptionPassword }, { "encrypt_passconf", pfSenseServer.EncryptionPassword }, { "Submit", "Download configuration" } }; string filename; var pfSenseBackupFile = new PfSenseBackupFile { FileContents = HttpUtility.DownloadBackupFile(string.Concat(pfSenseServer.ServerBaseUrl, "diag_backup.php"), downloadArgs, cookieJar, out filename, timeout), FileName = filename }; return(pfSenseBackupFile); }
/// <summary> /// Connects with the specified OPNSense server using the 19.07 protocol implementation and returns the backup file contents /// </summary> /// <param name="pfSenseServer">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 PfSenseBackupFile Execute(PfSenseServerDetails pfSenseServer, CookieContainer cookieJar, int timeout = 60000) { Program.WriteOutput("Connecting using protocol version {0}", new object[] { pfSenseServer.Version }); // Create a session on the OPNSense webserver var loginPageContents = HttpUtility.HttpGetLoginPageContents(pfSenseServer.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, @"xhr.setRequestHeader\(""X-CSRFToken"", ""(.*)"" \);", RegexOptions.IgnoreCase); // Authenticate the session var authenticationResult = HttpUtility.AuthenticateViaUrlEncodedFormMethod(string.Concat(pfSenseServer.ServerBaseUrl, "index.php"), new Dictionary <string, string> { { "X-CSRFToken", xssToken.Groups[1].Value } }, new Dictionary <string, string> { { "usernamefld", System.Web.HttpUtility.UrlEncode(pfSenseServer.Username) }, { "passwordfld", System.Web.HttpUtility.UrlEncode(pfSenseServer.Password) }, { "login", "1" } }, cookieJar, timeout); // Verify if the username/password combination was valid by examining the server response if (authenticationResult.Contains("Wrong username or password")) { throw new ApplicationException("ERROR: Credentials incorrect"); } Program.WriteOutput("Requesting backup file"); // Get the backup page contents for the xsrf token var backupPageUrl = string.Concat(pfSenseServer.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, @"xhr.setRequestHeader\(""X-CSRFToken"", ""(.*)"" \);", RegexOptions.IgnoreCase); Program.WriteOutput("Retrieving backup file"); var downloadArgs = new Dictionary <string, string>(); downloadArgs.Add("download", "Download configuration"); if (!pfSenseServer.BackupStatisticsData) { downloadArgs.Add("donotbackuprrd", "on"); } if (pfSenseServer.EncryptBackup) { downloadArgs.Add("encrypt", "on"); downloadArgs.Add("encrypt_password", pfSenseServer.EncryptionPassword); downloadArgs.Add("encrypt_passconf", pfSenseServer.EncryptionPassword); } string filename; var pfSenseBackupFile = new PfSenseBackupFile { FileContents = HttpUtility.DownloadBackupFile(backupPageUrl, new Dictionary <string, string> { { "X-CSRFToken", xssToken.Groups[1].Value } }, downloadArgs, cookieJar, out filename, timeout, backupPageUrl), FileName = filename }; return(pfSenseBackupFile); }