diff --git a/pfSense-pkg-API/files/etc/inc/api/endpoints/APIServicesOpenVPNServer.inc b/pfSense-pkg-API/files/etc/inc/api/endpoints/APIServicesOpenVPNServer.inc
new file mode 100644
index 000000000..c82299ec8
--- /dev/null
+++ b/pfSense-pkg-API/files/etc/inc/api/endpoints/APIServicesOpenVPNServer.inc
@@ -0,0 +1,38 @@
+url = "/api/v1/services/openvpn/server";
+ }
+
+ protected function get() {
+ return (new APIServicesOpenVPNServerRead())->call();
+ }
+
+ protected function post() {
+ return (new APIServicesOpenVPNServerCreate())->call();
+ }
+
+ protected function put() {
+ return (new APIServicesOpenVPNServerUpdate())->call();
+ }
+
+ protected function delete() {
+ return (new APIServicesOpenVPNServerDelete())->call();
+ }
+}
diff --git a/pfSense-pkg-API/files/etc/inc/api/framework/APIResponse.inc b/pfSense-pkg-API/files/etc/inc/api/framework/APIResponse.inc
index 01895e57a..1c3d09a0b 100644
--- a/pfSense-pkg-API/files/etc/inc/api/framework/APIResponse.inc
+++ b/pfSense-pkg-API/files/etc/inc/api/framework/APIResponse.inc
@@ -1229,6 +1229,300 @@ function get($id, $data=[], $all=false) {
"return" => $id,
"message" => "Please check the system_logs, the WOL command did not complete successfully"
],
+ 2104 => [
+ "status" => "bad request",
+ "code" => 400,
+ "return" => $id,
+ "message" => "Unknown OpenVPN Server Mode"
+ ],
+ 2105 => [
+ "status" => "bad request",
+ "code" => 400,
+ "return" => $id,
+ "message" => "Unknown OpenVPN Server Protocol"
+ ],
+ 2106 => [
+ "status" => "bad request",
+ "code" => 400,
+ "return" => $id,
+ "message" => "Unknown OpenVPN Server Device mode"
+ ],
+ 2107 => [
+ "status" => "bad request",
+ "code" => 400,
+ "return" => $id,
+ "message" => "Unknown OpenVPN Server Interface"
+ ],
+ 2108 => [
+ "status" => "server error",
+ "code" => 500,
+ "return" => $id,
+ "message" => "Invalid or taken OpenVPN Server Local port (allowed range 1-65535)"
+ ],
+ 2109 => [
+ "status" => "bad request",
+ "code" => 400,
+ "return" => $id,
+ "message" => "Unknown OpenVPN Server TLS Key Usage Mode"
+ ],
+ 2110 => [
+ "status" => "bad request",
+ "code" => 400,
+ "return" => $id,
+ "message" => "Unknown OpenVPN Server TLS keydir direction"
+ ],
+ 2111 => [
+ "status" => "bad request",
+ "code" => 400,
+ "return" => $id,
+ "message" => "Unknown OpenVPN Server TLS DH Parameter Length"
+ ],
+ 2112 => [
+ "status" => "bad request",
+ "code" => 400,
+ "return" => $id,
+ "message" => "Unknown OpenVPN Server ECDH Curve"
+ ],
+ 2113 => [
+ "status" => "bad request",
+ "code" => 400,
+ "return" => $id,
+ "message" => "Unknown OpenVPN Server Certificate Depth"
+ ],
+ 2114 => [
+ "status" => "bad request",
+ "code" => 400,
+ "return" => $id,
+ "message" => "Unknown OpenVPN Server Fallback Data Encryption Algorithm"
+ ],
+ 2115 => [
+ "status" => "bad request",
+ "code" => 400,
+ "return" => $id,
+ "message" => "Unknown OpenVPN Server Auth Digest Algorithm"
+ ],
+ 2116 => [
+ "status" => "bad request",
+ "code" => 400,
+ "return" => $id,
+ "message" => "Unknown OpenVPN Server Hardware Crypto Engine"
+ ],
+ 2117 => [
+ "status" => "bad request",
+ "code" => 400,
+ "return" => $id,
+ "message" => "Unknown or already in use OpenVPN Server Tunnel Network"
+ ],
+ 2118 => [
+ "status" => "bad request",
+ "code" => 400,
+ "return" => $id,
+ "message" => "Unknown OpenVPN Server Remote network(s)"
+ ],
+ 2119 => [
+ "status" => "bad request",
+ "code" => 400,
+ "return" => $id,
+ "message" => "Unknown OpenVPN Server Local network(s)"
+ ],
+ 2120 => [
+ "status" => "bad request",
+ "code" => 400,
+ "return" => $id,
+ "message" => "Unknown OpenVPN Server Allow Compression"
+ ],
+ 2121 => [
+ "status" => "bad request",
+ "code" => 400,
+ "return" => $id,
+ "message" => "Unknown OpenVPN Server Compression"
+ ],
+ 2122 => [
+ "status" => "bad request",
+ "code" => 400,
+ "return" => $id,
+ "message" => "Unknown OpenVPN Server Topology"
+ ],
+ 2123 => [
+ "status" => "bad request",
+ "code" => 400,
+ "return" => $id,
+ "message" => "Unknown OpenVPN Server Ping Method"
+ ],
+ 2124 => [
+ "status" => "bad request",
+ "code" => 400,
+ "return" => $id,
+ "message" => "Unknown OpenVPN Server Keepalive Interval"
+ ],
+ 2125 => [
+ "status" => "bad request",
+ "code" => 400,
+ "return" => $id,
+ "message" => "Unknown OpenVPN Server Keepalive Timeout"
+ ],
+ 2126 => [
+ "status" => "bad request",
+ "code" => 400,
+ "return" => $id,
+ "message" => "Unknown OpenVPN Server Ping Seconds"
+ ],
+ 2127 => [
+ "status" => "bad request",
+ "code" => 400,
+ "return" => $id,
+ "message" => "Unknown OpenVPN Server Ping restart or exit seconds"
+ ],
+ 2128 => [
+ "status" => "bad request",
+ "code" => 400,
+ "return" => $id,
+ "message" => "Unknown OpenVPN Server Ping restart or exit"
+ ],
+ 2129 => [
+ "status" => "bad request",
+ "code" => 400,
+ "return" => $id,
+ "message" => "Unknown OpenVPN Server Exit Notify"
+ ],
+ 2130 => [
+ "status" => "bad request",
+ "code" => 400,
+ "return" => $id,
+ "message" => "Unknown OpenVPN Server Send/Receive Buffer"
+ ],
+ 2131 => [
+ "status" => "bad request",
+ "code" => 400,
+ "return" => $id,
+ "message" => "Unknown OpenVPN Server Gateway Creation"
+ ],
+ 2132 => [
+ "status" => "bad request",
+ "code" => 400,
+ "return" => $id,
+ "message" => "Unknown OpenVPN Server Verbosity Level"
+ ],
+ 2133 => [
+ "status" => "bad request",
+ "code" => 400,
+ "return" => $id,
+ "message" => "Unknown OpenVPN Server Concurrent Connections"
+ ],
+ 2134 => [
+ "status" => "bad request",
+ "code" => 400,
+ "return" => $id,
+ "message" => "Unknown OpenVPN Server Inactive Time"
+ ],
+ 2135 => [
+ "status" => "bad request",
+ "code" => 400,
+ "return" => $id,
+ "message" => "Missing OpenVPN Server Certificate"
+ ],
+ 2136 => [
+ "status" => "bad request",
+ "code" => 400,
+ "return" => $id,
+ "message" => "Missing OpenVPN Server Certificate Authority"
+ ],
+ 2137 => [
+ "status" => "bad request",
+ "code" => 400,
+ "return" => $id,
+ "message" => "Unknown OpenVPN Server Peer Certificate Revocation List"
+ ],
+ 2138 => [
+ "status" => "bad request",
+ "code" => 400,
+ "return" => $id,
+ "message" => "Unknown OpenVPN Server Data Encryption Algorithms"
+ ],
+ 2139 => [
+ "status" => "Not found",
+ "code" => 404,
+ "return" => $id,
+ "message" => "Unknown OpenVPN Server 'vpnid'"
+ ],
+ 2140 => [
+ "status" => "bad request",
+ "code" => 400,
+ "return" => $id,
+ "message" => "Missing OpenVPN Server 'vpnid'. This parameter is needed to identify the server to modify/delete."
+ ],
+ 2141 => [
+ "status" => "bad request",
+ "code" => 400,
+ "return" => $id,
+ "message" => "Missing OpenVPN Server 'shared_key'. This parameter is needed for server mode 'p2p_shared_key'"
+ ],
+ 2142 => [
+ "status" => "bad request",
+ "code" => 400,
+ "return" => $id,
+ "message" => "Unknown OpenVPN Server Certificate Authority"
+ ],
+ 2143 => [
+ "status" => "bad request",
+ "code" => 400,
+ "return" => $id,
+ "message" => "Unknown OpenVPN Server Certificate"
+ ],
+ 2144 => [
+ "status" => "bad request",
+ "code" => 400,
+ "return" => $id,
+ "message" => "OpenVPN Server No Certificate Authority found"
+ ],
+ 2145 => [
+ "status" => "bad request",
+ "code" => 400,
+ "return" => $id,
+ "message" => "OpenVPN Server No Server Certificate found"
+ ],
+ 2146 => [
+ "status" => "bad request",
+ "code" => 400,
+ "return" => $id,
+ "message" => "Unknown OpenVPN Server Bridge Interface"
+ ],
+ 2147 => [
+ "status" => "bad request",
+ "code" => 400,
+ "return" => $id,
+ "message" => "Unknown OpenVPN Server Bridge Route Gateway requires a valid Bridge Interface"
+ ],
+ 2148 => [
+ "status" => "bad request",
+ "code" => 400,
+ "return" => $id,
+ "message" => "Unknown OpenVPN Server Bridge DHCP Start and End must both be empty, or defined, or The Server Bridge DHCP range is invalid (start higher than end)."
+ ],
+ 2149 => [
+ "status" => "bad request",
+ "code" => 400,
+ "return" => $id,
+ "message" => "OpenVPN Server The field 'NTP Server' must contain a valid IP address."
+ ],
+ 2150 => [
+ "status" => "bad request",
+ "code" => 400,
+ "return" => $id,
+ "message" => "OpenVPN Server The field 'DNS Server' must contain a valid IP address."
+ ],
+ 2151 => [
+ "status" => "bad request",
+ "code" => 400,
+ "return" => $id,
+ "message" => "OpenVPN Server The field 'WINS Server' must contain a valid IP address."
+ ],
+ 2152 => [
+ "status" => "bad request",
+ "code" => 400,
+ "return" => $id,
+ "message" => "OpenVPN Server cannot delete an OpenVPN instance while the interface is assigned. Remove the interface assignment first."
+ ],
2999 => [
"status" => "bad request",
"code" => 400,
diff --git a/pfSense-pkg-API/files/etc/inc/api/models/APIServicesOpenVPNServerCreate.inc b/pfSense-pkg-API/files/etc/inc/api/models/APIServicesOpenVPNServerCreate.inc
new file mode 100644
index 000000000..7ca43e678
--- /dev/null
+++ b/pfSense-pkg-API/files/etc/inc/api/models/APIServicesOpenVPNServerCreate.inc
@@ -0,0 +1,1400 @@
+privileges = ["page-all", "page-openvpn-server"];
+ $this->change_note = "Added OpenVPN server via API";
+ }
+
+ public function action() {
+ # Initialize expected configuration arrays
+ $this->__init_config();
+
+ # Add our Server to the configuration and resync OpenVPN to use new server
+ $this->config['openvpn']['openvpn-server'][] = $this->validated_data;
+ $this->write_config();
+ openvpn_resync('server', $this->validated_data);
+ return APIResponse\get(0, $this->validated_data);
+ }
+
+ private function __validate_vpnid() {
+ # Get next vpnid
+ $this->validated_data["vpnid"] = (string) openvpn_vpnid_next();
+ }
+
+ private function __validate_mode() {
+ # Local variables
+ $key_types = ["p2p_tls", "p2p_shared_key", "server_tls", "server_user", "server_tls_user"];
+
+ # Validate Server mode
+ if (isset($this->initial_data["mode"])) {
+ if (in_array($this->initial_data["mode"], $key_types)) {
+ $this->validated_data["mode"] = $this->initial_data["mode"];
+ } else {
+ $this->errors[] = APIResponse\get(2104);
+ }
+ # Assume default if none was specified
+ } else {
+ $this->validated_data["mode"] = "p2p_tls";
+ }
+ }
+
+ private function __validate_authmode() {
+ # Validate Backend for authentication
+ if (isset($this->initial_data["authmode"])) {
+ $this->validated_data["authmode"] = $this->initial_data["authmode"];
+ # Assume default if none was specified
+ } else {
+ $this->validated_data["authmode"] = "Local Database";
+ }
+ }
+
+ private function __validate_protocol() {
+ # Local variables
+ $key_types = ["UDP4", "UDP6", "TCP4", "TCP6", "UDP", "TCP"];
+
+ # Validate Protocol
+ if (isset($this->initial_data["protocol"])) {
+ if (in_array(strtoupper($this->initial_data["protocol"]), $key_types)) {
+ $this->validated_data["protocol"] = strtoupper($this->initial_data["protocol"]);
+ } else {
+ $this->errors[] = APIResponse\get(2105);
+ }
+ # Assume default if none was specified
+ } else {
+ $this->validated_data["protocol"] = "UDP4";
+ }
+ }
+
+ private function __validate_dev_mode() {
+ # Local variables
+ $key_types = ["tun", "tap"];
+
+ # Validate Device mode
+ if (isset($this->initial_data["dev_mode"])) {
+ if (in_array($this->initial_data["dev_mode"], $key_types)) {
+ $this->validated_data["dev_mode"] = $this->initial_data["dev_mode"];
+ } else {
+ $this->errors[] = APIResponse\get(2106);
+ }
+ # Assume default if none was specified
+ } else {
+ $this->validated_data["dev_mode"] = "tun";
+ }
+ }
+
+ private function __validate_interface() {
+ if (($this->validated_data["protocol"] === "UDP") or ($this->validated_data["protocol"] === "TCP")) {
+ $this->validated_data["interface"] = "wan";
+ $this->validated_data["ipaddr"] = "";
+ } elseif (isset($this->initial_data["interface"])) {
+ # Local variables
+ $match = false;
+ $interface = $this->initial_data["interface"];
+
+ // Validate Interface
+ if (!empty(APITools\get_pfsense_if_id($interface))) {
+ if (isset($this->config["interfaces"][APITools\get_pfsense_if_id($interface)]["enable"])) {
+ $this->validated_data["interface"] = APITools\get_pfsense_if_id($interface);
+ $this->validated_data["ipaddr"] = "";
+ $match = true;
+ }
+ }
+
+ // Validate Virtual Interface
+ if (!$match) {
+ foreach ($this->config["virtualip"]["vip"] as $vip) {
+ if (($vip["mode"] === "ipalias") or ($vip["mode"] === "carp") ) {
+ if (strtolower($this->initial_data["interface"]) === strtolower($vip["descr"])) {
+ $this->validated_data["interface"] = "_vip" . $vip["uniqid"];
+ $this->validated_data["ipaddr"] = $vip["subnet"];
+ $match = true;
+ break;
+ } elseif ((filter_var($vip["subnet"], FILTER_VALIDATE_IP)) and ($this->initial_data["interface"] === $vip["subnet"])) {
+ $this->validated_data["interface"] = "_vip" . $vip["uniqid"];
+ $this->validated_data["ipaddr"] = $vip["subnet"];
+ $match = true;
+ break;
+ } elseif (strtolower($this->initial_data["interface"]) === $vip["uniqid"]) {
+ $this->validated_data["interface"] = "_vip" . $vip["uniqid"];
+ $this->validated_data["ipaddr"] = $vip["subnet"];
+ $match = true;
+ break;
+ }
+ }
+ }
+ }
+
+ // Validate Gateway Group Interface
+ if (!$match) {
+ foreach ($this->config["gateways"]["gateway_group"] as $gateway_group) {
+ if (strtolower($this->initial_data["interface"]) === strtolower($gateway_group['name'])) {
+ $this->validated_data["interface"] = $gateway_group['name'];
+ $this->validated_data["ipaddr"] = "";
+ $match = true;
+ break;
+ }
+ }
+ }
+
+ if (!$match) {
+ $this->errors[] = APIResponse\get(2107);
+ }
+ # Assume default if none was specified
+ } else {
+ $this->validated_data["interface"] = "wan";
+ $this->validated_data["ipaddr"] = "";
+ }
+ }
+
+ private function __validate_local_port() {
+ # Only create local_port if no errors were found
+ if ((empty($this->errors)) and (isset($this->initial_data["local_port"]))) {
+ if (!openvpn_validate_port($this->initial_data["local_port"], "local_port", 1)) {
+ if (openvpn_port_used($this->validated_data["protocol"], $this->validated_data["interface"], $this->initial_data["local_port"], 0) == 0) {
+ $this->validated_data["local_port"] = $this->initial_data["local_port"];
+ } else {
+ $this->errors[] = APIResponse\get(2108);
+ }
+ } else {
+ $this->errors[] = APIResponse\get(2108);
+ }
+ # Assume default if none was specified
+ } else {
+ $this->validated_data["local_port"] = (string) openvpn_port_next($this->validated_data["protocol"], $this->validated_data["interface"]);
+ }
+ }
+
+ private function __validate_description() {
+ # Check for our optional `descr` payload value
+ if (isset($this->initial_data['description'])) {
+ $this->validated_data["description"] = $this->initial_data['description'];
+ }
+ # Assume default if none was specified
+ else {
+ $this->validated_data["description"] = "";
+ }
+ }
+
+ private function __validate_custom_options() {
+ # Check for our optional `Custom options` payload value
+ if (isset($this->initial_data['custom_options'])) {
+ $this->validated_data["custom_options"] = $this->initial_data['custom_options'];
+ # Assume default if none was specified
+ } else {
+ $this->validated_data["custom_options"] = "";
+ }
+ }
+
+ private function __validate_tls() {
+ # Check for our optional `TLS` payload value
+ if (isset($this->initial_data["tls"])) {
+ # Auto generate TLS key if empty
+ if ($this->initial_data["tls"] == "" or $this->initial_data["tls"] == "true") {
+ $this->validated_data["tls"] = base64_encode(openvpn_create_key());
+ } else {
+ $this->validated_data["tls"] = base64_encode($this->initial_data["tls"]);
+ }
+ }
+ }
+
+ private function __validate_tls_type() {
+ # Local variables
+ $key_types = ["auth", "crypt"];
+
+ # Validate TLS type if TLS set
+ if (($this->initial_data["tls"] !== "") and (isset($this->validated_data['tls']))) {
+ if (isset($this->initial_data["tls_type"])) {
+ if (in_array($this->initial_data["tls_type"], $key_types)) {
+ $this->validated_data["tls_type"] = $this->initial_data["tls_type"];
+ } else {
+ $this->errors[] = APIResponse\get(2109);
+ }
+ # Assume default if none was specified
+ } else {
+ $this->validated_data["tls_type"] = "auth";
+ }
+ }
+ }
+
+ private function __validate_tls_keydir() {
+ # Local variables
+ $key_types = ["default", "direction-0", "direction-1", "both-directions"];
+
+ # Validate keydir direction if TLS set
+ if (($this->initial_data["tls"] !== "") and (isset($this->validated_data['tls']))) {
+ if (isset($this->initial_data["tlsauth_keydir"])) {
+ if (in_array($this->initial_data["tlsauth_keydir"], $key_types)) {
+ switch ($this->initial_data["tlsauth_keydir"]) {
+ case "default":
+ $this->validated_data["tlsauth_keydir"] = "default";
+ break;
+ case "direction-0":
+ $this->validated_data["tlsauth_keydir"] = "0";
+ break;
+ case "direction-1":
+ $this->validated_data["tlsauth_keydir"] = "1";
+ break;
+ case "both-directions":
+ $this->validated_data["tlsauth_keydir"] = "2";
+ break;
+ }
+ } else {
+ $this->errors[] = APIResponse\get(2110);
+ }
+ # Assume default if none was specified
+ } else {
+ $this->validated_data["tlsauth_keydir"] = "default";
+ }
+ }
+ }
+
+ private function __validate_shared_key() {
+ # Check for our optional `Shared key` payload value
+ if (isset($this->initial_data["shared_key"])) {
+ # Auto generate Shared key if empty
+ if ($this->initial_data["shared_key"] === "") {
+ $this->validated_data["shared_key"] = base64_encode(openvpn_create_key());
+ # Assume default if none was specified
+ } else {
+ $this->validated_data["shared_key"] = base64_encode($this->initial_data["shared_key"]);
+ }
+ } else {
+ $this->errors[] = APIResponse\get(2141);
+ }
+ }
+
+ private function __validate_caref() {
+ if (!empty($this->config["ca"])) {
+ if (isset($this->initial_data["caref"])) {
+ foreach ($this->config["ca"] as $ca) {
+ if ($this->initial_data["caref"] === $ca["refid"]) {
+ $this->validated_data["caref"] = $ca["refid"];
+ break;
+ }
+ }
+
+ if (empty($this->validated_data["caref"])) {
+ $this->errors[] = APIResponse\get(2142);
+ }
+ } else {
+ $this->errors[] = APIResponse\get(2136);
+ }
+ } else {
+ $this->errors[] = APIResponse\get(2144);
+ }
+ }
+
+ private function __validate_crlref() {
+ if (isset($this->initial_data["crlref"])) {
+ foreach ($this->config["crl"] as $crl) {
+ if (($this->validated_data["caref"] === $crl["caref"]) and ($this->initial_data["crlref"] === $crl["refid"])) {
+ $this->validated_data["crlref"] = $this->initial_data["refid"];
+ break;
+ }
+ }
+
+ if ($this->initial_data["crlref"] === "none") {
+ $this->validated_data["crlref"] = "";
+ }
+
+ if (empty($this->validated_data["crlref"])) {
+ $this->errors[] = APIResponse\get(2137);
+ }
+
+ } else {
+ $this->validated_data["crlref"] = "";
+ }
+ }
+
+ private function __validate_ocspcheck() {
+ # Check for our optional `OCSP` payload value
+ if ($this->initial_data["ocspcheck"] === true) {
+ $this->validated_data["ocspcheck"] = "yes";
+ }
+ }
+
+ private function __validate_ocspurl() {
+ # Check for our optional `OCSP URL` payload value
+ if ($this->validated_data["ocspcheck"] === "yes") {
+ if (isset($this->initial_data["ocspurl"])) {
+ $this->validated_data["ocspurl"] = $this->initial_data["ocspurl"];
+ } else {
+ $this->validated_data["ocspurl"] = "";
+ }
+ # Assume default if none was specified
+ } else {
+ $this->validated_data["ocspurl"] = "";
+ }
+ }
+
+ private function __validate_certref() {
+ if (!empty($this->config["cert"])) {
+ if (isset($this->initial_data["certref"])) {
+ foreach ($this->config["cert"] as $cert) {
+ if ($this->initial_data["certref"] === $cert["refid"]) {
+ $this->validated_data["certref"] = $cert["refid"];
+ break;
+ }
+ }
+ } else {
+ $this->errors[] = APIResponse\get(2135);
+ }
+
+ if (empty($this->validated_data["certref"])) {
+ $this->errors[] = APIResponse\get(2143);
+ }
+ } else {
+ $this->errors[] = APIResponse\get(2145);
+ }
+ }
+
+ private function __validate_dh_length() {
+ # Local variables
+ $key_types = ["1024", "2048", "3072", "4096", "6144", "7680", "8192", "15360", "16384", "ECDH Only"];
+
+ # Validate DH Parameter Length
+ if (isset($this->initial_data["dh_length"])) {
+ if (in_array($this->initial_data["dh_length"], $key_types)) {
+ if ($this->initial_data["dh_length"] === "ECDH Only") {
+ $this->validated_data["dh_length"] = "none";
+ } else {
+ $this->validated_data["dh_length"] = $this->initial_data["dh_length"];
+ }
+ } else {
+ $this->errors[] = APIResponse\get(2111);
+ }
+ # Assume default if none was specified
+ } else {
+ $this->validated_data["dh_length"] = "2048";
+ }
+ }
+
+ private function __validate_ecdh_curve() {
+ # Local variables
+ $key_types = ["none", "prime256v1", "secp384r1", "secp521r1"];
+
+ # Validate ECDH Curve
+ if (isset($this->initial_data["ecdh_curve"])) {
+ if (in_array($this->initial_data["ecdh_curve"], $key_types)) {
+ $this->validated_data["ecdh_curve"] = $this->initial_data["ecdh_curve"];
+ } else {
+ $this->errors[] = APIResponse\get(2112);
+ }
+ # Assume default if none was specified
+ } else {
+ $this->validated_data["ecdh_curve"] = "none";
+ }
+ }
+
+ private function __validate_cert_depth() {
+ # Local variables
+ $key_types = ["none", "one", "two", "three", "four", "five"];
+
+ # Validate Certificate Depth
+ if (isset($this->initial_data["cert_depth"])) {
+ if (in_array($this->initial_data["cert_depth"], $key_types)) {
+ switch ($this->initial_data["cert_depth"]) {
+ case "none":
+ $this->validated_data["cert_depth"] = "";
+ break;
+ case "one":
+ $this->validated_data["cert_depth"] = "1";
+ break;
+ case "two":
+ $this->validated_data["cert_depth"] = "2";
+ break;
+ case "three":
+ $this->validated_data["cert_depth"] = "3";
+ break;
+ case "four":
+ $this->validated_data["cert_depth"] = "4";
+ break;
+ case "five":
+ $this->validated_data["cert_depth"] = "5";
+ break;
+ }
+ } else {
+ $this->errors[] = APIResponse\get(2113);
+ }
+ # Assume default if none was specified
+ } else {
+ $this->validated_data["cert_depth"] = "1";
+ }
+ }
+
+ private function __validate_strick_user_cn() {
+ if ($this->initial_data['strictusercn'] === true) {
+ $this->validated_data["strictusercn"] = "yes";
+ # Assume default if none was specified
+ } else {
+ $this->validated_data["strictusercn"] = "";
+ }
+ }
+
+ private function __validate_ncp_enable() {
+ if ($this->initial_data["data_encryption_negotiation"] === false) {
+ $this->validated_data["ncp_enable"] = "disabled";
+ } else {
+ $this->validated_data["ncp_enable"] = "enabled";
+ }
+ }
+
+ private function __validate_data_ciphers() {
+ if (isset($this->initial_data["data_ciphers"])) {
+ $data_ciphers = explode(',', $this->initial_data['data_ciphers']);
+ $counter = 1;
+ foreach ($data_ciphers as $cipher) {
+ if (!array_key_exists($cipher, openvpn_get_cipherlist())) {
+ $this->errors[] = APIResponse\get(2138);
+ } elseif ($counter > 19) {
+ break;
+ } else {
+ $counter += 1;
+ }
+ }
+ $this->validated_data['data_ciphers'] = $this->initial_data['data_ciphers'];
+ } else {
+ $this->validated_data["data_ciphers"] = "AES-256-GCM,AES-128-GCM,CHACHA20-POLY1305";
+ }
+ }
+
+ private function __validate_data_ciphers_fallback() {
+ # Validate Fallback Data Encryption Algorithm
+ if (isset($this->initial_data["data_ciphers_fallback"])) {
+ if (array_key_exists($this->initial_data["data_ciphers_fallback"], openvpn_get_cipherlist())) {
+ $this->validated_data["data_ciphers_fallback"] = $this->initial_data["data_ciphers_fallback"];
+ } else {
+ $this->errors[] = APIResponse\get(2114);
+ }
+ # Assume default if none was specified
+ } else {
+ $this->validated_data["data_ciphers_fallback"] = "AES-256-CBC";
+ }
+ }
+
+ private function __validate_digest() {
+ # Local variables
+ $key_types = ["SHA256", "BLAKE2b512", "BLAKE2b256", "MD4", "MD5", "MD5-SHA1", "MDC2", "RIPEMD160", "SHA1", "SHA224", "SHA256", "SHA3-224", "SHA3-256", "SHA3-384", "SHA3-512", "SHA384", "SHA512", "SHA512-224", "SHA512-256", "SHAKE128", "SHAKE256", "SM3", "whirlpool", "none"];
+
+ # Validate Auth digest algorithm
+ if (isset($this->initial_data["digest"])) {
+ if (in_array($this->initial_data["digest"], $key_types)) {
+ $this->validated_data["digest"] = $this->initial_data["digest"];
+ } else {
+ $this->errors[] = APIResponse\get(2115);
+ }
+ # Assume default if none was specified
+ } else {
+ $this->validated_data["digest"] = "SHA256";
+ }
+ }
+
+ private function __validate_engine() {
+ # Validate Hardware Crypto
+ if (isset($this->initial_data["engine"])) {
+ if (array_key_exists($this->initial_data["engine"], openvpn_get_engines())) {
+ $this->validated_data["engine"] = $this->initial_data["engine"];
+ } else {
+ $this->errors[] = APIResponse\get(2116);
+ }
+ # Assume default if none was specified
+ } else {
+ $this->validated_data["engine"] = "none";
+ }
+ }
+
+ private function __validate_tunnel_network() {
+ # Validate Tunnel Network
+ if (isset($this->initial_data['tunnel_network'])) {
+ if (!openvpn_validate_cidr($this->initial_data['tunnel_network'], "", false, "ipv4")) {
+ if (!openvpn_is_tunnel_network_in_use($this->initial_data['tunnel_network'])) {
+ $this->validated_data["tunnel_network"] = $this->initial_data['tunnel_network'];
+ } else {
+ $this->errors[] = APIResponse\get(2117);
+ }
+ } else {
+ $this->errors[] = APIResponse\get(2117);
+ }
+ # Assume default if none was specified
+ } else {
+ $this->validated_data["tunnel_network"] = "";
+ }
+ }
+
+ private function __validate_tunnel_networkv6() {
+ # Validate Tunnel Network v6
+ if (isset($this->initial_data['tunnel_networkv6'])) {
+ if (!openvpn_validate_cidr($this->initial_data['tunnel_networkv6'], "", false, "ipv6")) {
+ if (!openvpn_is_tunnel_network_in_use($this->initial_data['tunnel_networkv6'])) {
+ $this->validated_data["tunnel_networkv6"] = $this->initial_data['tunnel_networkv6'];
+ } else {
+ $this->errors[] = APIResponse\get(2117);
+ }
+ } else {
+ $this->errors[] = APIResponse\get(2117);
+ }
+ # Assume default if none was specified
+ } else {
+ $this->validated_data["tunnel_networkv6"] = "";
+ }
+ }
+
+ private function __validate_serverbridge_dhcp() {
+ if ($this->validated_data['dev_mode'] === 'tap') {
+ if ($this->initial_data['serverbridge_dhcp'] === true) {
+ $this->validated_data['serverbridge_dhcp'] = 'yes';
+ } else {
+ $this->validated_data['serverbridge_dhcp'] = "";
+ }
+ } else {
+ $this->validated_data['serverbridge_dhcp'] = "";
+ }
+ }
+
+ private function __validate_serverbridge_interface() {
+ $key_types = ["wan", "lan", "none"];
+ $match = false;
+
+ if (($this->validated_data['serverbridge_dhcp'] === 'yes') and (isset($this->initial_data['serverbridge_interface']))) {
+ // Validate Virtual Interface
+ foreach ($this->config["virtualip"]["vip"] as $vip) {
+ if (strtolower($this->initial_data["serverbridge_interface"]) === strtolower($vip["descr"])) {
+ $this->validated_data["interface"] = "_vip" . $vip["uniqid"] . "|" . $vip["subnet"];
+ $match = true;
+ break;
+ } elseif ((filter_var($vip["subnet"], FILTER_VALIDATE_IP)) and ($this->initial_data["serverbridge_interface"] === $vip["subnet"])) {
+ $this->validated_data["interface"] = "_vip" . $vip["uniqid"] . "|" . $vip["subnet"];
+ $match = true;
+ break;
+ } elseif (strtolower($this->initial_data["serverbridge_interface"]) === strtolower($vip["uniqid"])) {
+ $this->validated_data["interface"] = "_vip" . $vip["uniqid"] . "|" . $vip["subnet"];
+ $match = true;
+ break;
+ }
+ }
+
+ if (in_array(strtolower($this->initial_data['serverbridge_interface']), $key_types)) {
+ $this->validated_data["serverbridge_interface"] = strtolower($this->initial_data['serverbridge_interface']);
+ $match = true;
+ }
+
+ if (!$match) {
+ $this->errors[] = APIResponse\get(2146);
+ }
+
+ } else {
+ $this->validated_data["serverbridge_interface"] = "none";
+ }
+ }
+
+ private function __validate_serverbridge_routegateway() {
+ if ($this->validated_data['serverbridge_dhcp'] === 'yes') {
+ if ($this->initial_data['serverbridge_routegateway'] === true) {
+ if ($this->validated_data["serverbridge_interface"] !== "none") {
+ $this->validated_data["serverbridge_routegateway"] = "yes";
+ } else {
+ $this->errors[] = APIResponse\get(2147);
+ }
+ } else {
+ $this->validated_data["serverbridge_routegateway"] = "";
+ }
+ } else {
+ $this->validated_data["serverbridge_routegateway"] = "";
+ }
+ }
+
+ private function __validate_serverbridge_dhcp_start() {
+ if ($this->validated_data['serverbridge_dhcp'] === 'yes') {
+ if ((isset($this->initial_data['serverbridge_dhcp_start'])) and (is_ipaddrv4($this->initial_data['serverbridge_dhcp_start'])) and (isset($this->initial_data['serverbridge_dhcp_end']))) {
+ $this->validated_data["serverbridge_dhcp_start"] = $this->initial_data['serverbridge_dhcp_start'];
+ } else {
+ $this->errors[] = APIResponse\get(2148);
+ }
+ } else {
+ $this->validated_data["serverbridge_dhcp_start"] = "";
+ }
+ }
+
+ private function __validate_serverbridge_dhcp_end() {
+ if ($this->validated_data['serverbridge_dhcp'] === 'yes') {
+ if ((isset($this->initial_data['serverbridge_dhcp_end'])) and (is_ipaddrv4($this->initial_data['serverbridge_dhcp_end'])) and (isset($this->initial_data['serverbridge_dhcp_start']))) {
+ $this->validated_data["serverbridge_dhcp_end"] = $this->initial_data['serverbridge_dhcp_end'];
+ } else {
+ $this->errors[] = APIResponse\get(2148);
+ }
+ } else {
+ $this->validated_data["serverbridge_dhcp_end"] = "";
+ }
+ }
+
+ private function __validate_remote_network() {
+ # Check for our optional `Remote Network` payload value
+ if (isset($this->initial_data['remote_network'])) {
+ if (!openvpn_validate_cidr($this->initial_data['remote_network'], "", true, "ipv4")) {
+ $this->validated_data["remote_network"] = $this->initial_data['remote_network'];
+ } else {
+ $this->errors[] = APIResponse\get(2118);
+ }
+ # Assume default if none was specified
+ } else {
+ $this->validated_data["remote_network"] = "";
+ }
+ }
+
+ private function __validate_remote_networkv6() {
+ # Check for our optional `Remote Network v6` payload value
+ if (isset($this->initial_data['remote_networkv6'])) {
+ if (!openvpn_validate_cidr($this->initial_data['remote_networkv6'], "", true, "ipv6")) {
+ $this->validated_data["remote_networkv6"] = $this->initial_data['remote_networkv6'];
+ } else {
+ $this->errors[] = APIResponse\get(2118);
+ }
+ # Assume default if none was specified
+ } else {
+ $this->validated_data["remote_networkv6"] = "";
+ }
+ }
+
+ private function __validate_redirect_gateway() {
+ if ($this->initial_data['redirect_gateway'] === true) {
+ $this->validated_data["gwredir"] = "yes";
+ # Assume default if none was specified
+ } else {
+ $this->validated_data["gwredir"] = "";
+ }
+ }
+
+ private function __validate_redirect_gateway6() {
+ if ($this->initial_data['redirect_gateway6'] === true) {
+ $this->validated_data["gwredir6"] = "yes";
+ # Assume default if none was specified
+ } else {
+ $this->validated_data["gwredir6"] = "";
+ }
+ }
+
+ private function __validate_local_network() {
+ if ($this->validated_data['gwredir'] === "") {
+ if (isset($this->initial_data['local_network'])) {
+ if (!openvpn_validate_cidr($this->initial_data['local_network'], "", true, "ipv4")) {
+ $this->validated_data["local_network"] = $this->initial_data['local_network'];
+ } else {
+ $this->errors[] = APIResponse\get(2119);
+ }
+ # Assume default if none was specified
+ } else {
+ $this->validated_data["local_network"] = "";
+ }
+ # Assume default if none was specified
+ } else {
+ $this->validated_data["local_network"] = "";
+ }
+ }
+
+ private function __validate_local_networkv6() {
+ if ($this->validated_data['gwredir6'] === "") {
+ if (isset($this->initial_data['local_networkv6'])) {
+ if (!openvpn_validate_cidr($this->initial_data['local_networkv6'], "", true, "ipv6")) {
+ $this->validated_data["local_networkv6"] = $this->initial_data['local_networkv6'];
+ } else {
+ $this->errors[] = APIResponse\get(2119);
+ }
+ # Assume default if none was specified
+ } else {
+ $this->validated_data["local_networkv6"] = "";
+ }
+ # Assume default if none was specified
+ } else {
+ $this->validated_data["local_networkv6"] = "";
+ }
+ }
+
+ private function __validate_concurrent_connections() {
+ if (isset($this->initial_data['concurrent_connections'])) {
+ if (is_numericint($this->initial_data['concurrent_connections']) and (int) $this->initial_data['concurrent_connections'] > 0) {
+ $this->validated_data["maxclients"] = $this->initial_data['concurrent_connections'];
+ } else {
+ $this->errors[] = APIResponse\get(2133);
+ }
+ # Assume default if none was specified
+ } else {
+ $this->validated_data["maxclients"] = "";
+ }
+ }
+
+ private function __validate_allow_compression() {
+ # Local variables
+ $key_types = ["asym", "no", "yes"];
+
+ # Validate Allow Compression
+ if (isset($this->initial_data["allow_compression"])) {
+ if (in_array($this->initial_data["allow_compression"], $key_types)) {
+ $this->validated_data["allow_compression"] = $this->initial_data["allow_compression"];
+ } else {
+ $this->errors[] = APIResponse\get(2120);
+ }
+ # Assume default if none was specified
+ } else {
+ $this->validated_data["allow_compression"] = "no";
+ }
+ }
+
+ private function __validate_compression() {
+ # Local variables
+ $key_types = ["none", "stub", "stub-v2", "lz4", "lz4-v2", "lzo", "noadapt", "adaptive", "yes", "no"];
+
+ if (($this->validated_data["allow_compression"] === "yes") or ($this->validated_data["allow_compression"] === "asym")) {
+ # Validate Compression
+ if (isset($this->initial_data["compression"])) {
+ if (in_array($this->initial_data["compression"], $key_types)) {
+ $this->validated_data["compression"] = $this->initial_data["compression"];
+ } else {
+ $this->errors[] = APIResponse\get(2121);
+ }
+ # Assume default if none was specified
+ } else {
+ $this->validated_data["compression"] = "";
+ }
+ # Assume default if none was specified
+ } else {
+ $this->validated_data["compression"] = "";
+ }
+ }
+
+ private function __validate_compression_push() {
+ if ($this->initial_data['compression_push'] === true) {
+ $this->validated_data["compression_push"] = "yes";
+ # Assume default if none was specified
+ } else {
+ $this->validated_data["compression_push"] = "";
+ }
+ }
+
+ private function __validate_type_of_service() {
+ if ($this->initial_data['passtos'] === true) {
+ $this->validated_data["passtos"] = "yes";
+ # Assume default if none was specified
+ } else {
+ $this->validated_data["passtos"] = "";
+ }
+ }
+
+ private function __validate_inter_client_communication() {
+ if ($this->initial_data['client2client'] === true) {
+ $this->validated_data["client2client"] = "yes";
+ # Assume default if none was specified
+ } else {
+ $this->validated_data["client2client"] = "";
+ }
+ }
+
+ private function __validate_duplicate_connection() {
+ if ($this->initial_data['duplicate_cn'] === true) {
+ $this->validated_data["duplicate_cn"] = "";
+ }
+ }
+
+ private function __validate_dynamic_ip() {
+ if ($this->initial_data['dynamic_ip'] === true) {
+ $this->validated_data["dynamic_ip"] = "yes";
+ }
+ # Assume default if none was specified
+ else {
+ $this->validated_data["dynamic_ip"] = "";
+ }
+ }
+
+ private function __validate_topology() {
+ # Local variables
+ $key_types = ["subnet", "net30"];
+
+ if ($this->validated_data["dev_mode"] === "tap") {
+ $this->validated_data["topology"] = "subnet";
+ } elseif (isset($this->initial_data["topology"])) {
+ if (in_array($this->initial_data["topology"], $key_types)) {
+ $this->validated_data["topology"] = $this->initial_data["topology"];
+ } else {
+ $this->errors[] = APIResponse\get(2122);
+ }
+ # Assume default if none was specified
+ } else {
+ $this->validated_data["topology"] = "subnet";
+ }
+ }
+
+ private function __validate_dns_domain() {
+ if (isset($this->initial_data['dns_domain'])) {
+ $this->validated_data["dns_domain"] = $this->initial_data['dns_domain'];
+ }
+ else {
+ $this->validated_data["dns_domain"] = "";
+ }
+ }
+
+ private function __validate_dns_servers() {
+ if (isset($this->initial_data['dns_servers'])) {
+ $dns_servers = explode(',', $this->initial_data['dns_servers']);
+ $counter = 1;
+ foreach ($dns_servers as $server) {
+ if ($counter > 4) {
+ break;
+ } elseif (is_ipaddrv4(str_replace(" ", "", $server))) {
+ $this->validated_data["dns_server" . $counter] = str_replace(" ", "", $server);
+ $counter += 1;
+ } else {
+ $this->errors[] = APIResponse\get(2150);
+ }
+ }
+ }
+ }
+
+ private function __validate_push_blockout_side_dns() {
+ if ($this->initial_data['push_blockoutsidedns'] === true) {
+ $this->validated_data["push_blockoutsidedns"] = "yes";
+ }
+ }
+
+ private function __validate_inactive_seconds() {
+ if (isset($this->initial_data['inactive_seconds'])) {
+ if (is_numericint($this->initial_data['inactive_seconds']) and ((int) $this->initial_data['inactive_seconds']) >= 0) {
+ $this->validated_data["inactive_seconds"] = $this->initial_data['inactive_seconds'];
+ # Assume default if none was specified
+ } else {
+ $this->errors[] = APIResponse\get(2134);
+ }
+ # Assume default if none was specified
+ } else {
+ $this->validated_data["inactive_seconds"] = "300";
+ }
+ }
+
+ private function __validate_ping_method() {
+ # Local variables
+ $key_types = ["keepalive", "ping"];
+
+ # Validate Ping method
+ if (isset($this->initial_data["ping_method"])) {
+ if (in_array($this->initial_data["ping_method"], $key_types)) {
+ $this->validated_data["ping_method"] = $this->initial_data["ping_method"];
+ } else {
+ $this->errors[] = APIResponse\get(2123);
+ }
+ # Assume default if none was specified
+ } else {
+ $this->validated_data["ping_method"] = "keepalive";
+ }
+ }
+
+ private function __validate_keepalive_interval() {
+ if ($this->validated_data["ping_method"] === "keepalive") {
+ if (isset($this->initial_data['keepalive_interval'])) {
+ if (is_numericint($this->initial_data['keepalive_interval']) and ((int) $this->initial_data['keepalive_interval'] >= 0)) {
+ $this->validated_data["keepalive_interval"] = $this->initial_data['keepalive_interval'];
+ } else {
+ $this->errors[] = APIResponse\get(2124);
+ }
+ # Assume default if none was specified
+ } else {
+ $this->validated_data["keepalive_interval"] = "10";
+ }
+ # Assume default if none was specified
+ } else {
+ $this->validated_data["keepalive_interval"] = "10";
+ }
+ }
+
+ private function __validate_keepalive_timeout() {
+ if ($this->validated_data["ping_method"] === "keepalive") {
+ if (isset($this->initial_data['keepalive_timeout'])) {
+ if (is_numericint($this->initial_data['keepalive_timeout']) and ((int) $this->initial_data['keepalive_timeout'] >= 0)) {
+ $this->validated_data["keepalive_timeout"] = $this->initial_data['keepalive_timeout'];
+ } else {
+ $this->errors[] = APIResponse\get(2125);
+ }
+ # Assume default if none was specified
+ } else {
+ $this->validated_data["keepalive_timeout"] = "60";
+ }
+ # Assume default if none was specified
+ } else {
+ $this->validated_data["keepalive_timeout"] = "60";
+ }
+ }
+
+ private function __validate_ping_seconds() {
+ if ($this->validated_data["ping_method"] === "ping") {
+ if (isset($this->initial_data['ping_seconds'])) {
+ if (is_numericint($this->initial_data['ping_seconds']) and ((int) $this->initial_data['ping_seconds'] >= 0)) {
+ $this->validated_data["ping_seconds"] = $this->initial_data['ping_seconds'];
+ } else {
+ $this->errors[] = APIResponse\get(2126);
+ }
+ # Assume default if none was specified
+ } else {
+ $this->validated_data["ping_seconds"] = "10";
+ }
+ # Assume default if none was specified
+ } else {
+ $this->validated_data["ping_seconds"] = "10";
+ }
+ }
+
+ private function __validate_ping_action_seconds() {
+ if ($this->validated_data["ping_method"] === "ping") {
+ if (isset($this->initial_data['ping_action_seconds'])) {
+ if (is_numericint($this->initial_data['ping_action_seconds']) and ((int) $this->initial_data['ping_action_seconds'] >= 0)) {
+ $this->validated_data["ping_action_seconds"] = $this->initial_data['ping_action_seconds'];
+ } else {
+ $this->errors[] = APIResponse\get(2127);
+ }
+ # Assume default if none was specified
+ } else {
+ $this->validated_data["ping_action_seconds"] = "60";
+ }
+ # Assume default if none was specified
+ } else {
+ $this->validated_data["ping_action_seconds"] = "60";
+ }
+ }
+
+ private function __validate_ping_push() {
+ if ($this->validated_data["ping_method"] === "ping") {
+ if ($this->initial_data['ping_push'] === true) {
+ $this->validated_data["ping_push"] = "yes";
+ # Assume default if none was specified
+ } else {
+ $this->validated_data["ping_push"] = "";
+ }
+ # Assume default if none was specified
+ } else {
+ $this->validated_data["ping_push"] = "";
+ }
+ }
+
+ private function __validate_ping_action_push() {
+ if ($this->validated_data["ping_method"] === "ping") {
+ if ($this->initial_data['ping_action_push'] === true) {
+ $this->validated_data["ping_action_push"] = "yes";
+ }
+ # Assume default if none was specified
+ else {
+ $this->validated_data["ping_action_push"] = "";
+ }
+ # Assume default if none was specified
+ } else {
+ $this->validated_data["ping_action_push"] = "";
+ }
+ }
+
+ private function __validate_ping_action() {
+ # Local variables
+ $key_types = ["ping_exit", "ping_restart"];
+
+ # Validate Ping restart or exit
+ if (($this->validated_data["ping_method"] === "ping") and (isset($this->initial_data["ping_action"]))) {
+ if (in_array($this->initial_data["ping_action"], $key_types)) {
+ $this->validated_data["ping_action"] = $this->initial_data["ping_action"];
+ }
+ else {
+ $this->errors[] = APIResponse\get(2128);
+ }
+ # Assume default if none was specified
+ } else {
+ $this->validated_data["ping_action"] = "ping_restart";
+ }
+ }
+
+ private function __validate_username_as_cn() {
+ if ($this->initial_data['username_as_common_name'] === true) {
+ $this->validated_data["username_as_common_name"] = "enabled";
+ } else {
+ $this->validated_data["username_as_common_name"] = "disabled";
+ }
+ }
+
+ private function __validate_udp_fast_io() {
+ if ($this->initial_data['udp_fast_io'] === true) {
+ $this->validated_data["udp_fast_io"] = "yes";
+ }
+ }
+
+ private function __validate_exit_notify() {
+ # Local variables
+ $key_types = ["once", "twice", "none", ""];
+
+ # Validate Exit Notify
+ if (isset($this->initial_data["exit_notify"])) {
+ if (in_array($this->initial_data["exit_notify"], $key_types)) {
+ switch ($this->initial_data["exit_notify"]) {
+ case "none":
+ $this->validated_data["exit_notify"] = "none";
+ break;
+ case "":
+ $this->validated_data["exit_notify"] = "none";
+ break;
+ case "once":
+ $this->validated_data["exit_notify"] = "1";
+ break;
+ case "twice":
+ $this->validated_data["exit_notify"] = "2";
+ break;
+ }
+ } else {
+ $this->errors[] = APIResponse\get(2129);
+ }
+ # Assume default if none was specified
+ } else {
+ $this->validated_data["exit_notify"] = "1";
+ }
+ }
+
+ private function __validate_snd_rcv_buf() {
+ # Local variables
+ $key_types = ["64KiB", "128KiB", "256KiB", "512KiB", "1MiB", "2MiB", "default"];
+
+ # Validate Send/Receive Buffer
+ if (isset($this->initial_data["sndrcvbuf"])) {
+ if (in_array($this->initial_data["sndrcvbuf"], $key_types)) {
+ switch ($this->initial_data["sndrcvbuf"]) {
+ case "64KiB":
+ $this->validated_data["sndrcvbuf"] = "65536";
+ break;
+ case "128KiB":
+ $this->validated_data["sndrcvbuf"] = "131072";
+ break;
+ case "256KiB":
+ $this->validated_data["sndrcvbuf"] = "262144";
+ break;
+ case "512KiB":
+ $this->validated_data["sndrcvbuf"] = "524288";
+ break;
+ case "1MiB":
+ $this->validated_data["sndrcvbuf"] = "1048576";
+ break;
+ case "2MiB":
+ $this->validated_data["sndrcvbuf"] = "2097152";
+ break;
+ case "default":
+ $this->validated_data["sndrcvbuf"] = "";
+ break;
+ }
+ } else {
+ $this->errors[] = APIResponse\get(2130);
+ }
+ } else {
+ $this->validated_data["sndrcvbuf"] = "";
+ }
+ }
+
+ private function __validate_push_register_dns() {
+ if ($this->initial_data['push_register_dns'] === true) {
+ $this->validated_data["push_register_dns"] = "yes";
+ }
+ }
+
+ private function __validate_ntp_servers() {
+ if (isset($this->initial_data['ntp_servers'])) {
+ $ntp_servers = explode(',', $this->initial_data['ntp_servers']);
+ $counter = 1;
+ foreach ($ntp_servers as $server) {
+ if ($counter > 2) {
+ break;
+ } elseif (is_ipaddrv4(str_replace(" ", "", $server))) {
+ $this->validated_data["ntp_server" . $counter] = str_replace(" ", "", $server);
+ $counter += 1;
+ } else {
+ $this->errors[] = APIResponse\get(2149);
+ }
+ }
+ }
+ }
+
+ private function __validate_netbios_enable() {
+ if ($this->initial_data['netbios_enable'] === true) {
+ $this->validated_data["netbios_enable"] = "yes";
+ # Assume default if none was specified
+ } else {
+ $this->validated_data["netbios_enable"] = "";
+ }
+ }
+
+ private function __validate_netbios_ntype() {
+ if (isset($this->initial_data['netbios_node_type'])) {
+ if ($this->initial_data['netbios_node_type'] == 'b') {
+ $this->validated_data["netbios_ntype"] = "1";
+ } else if ($this->initial_data['netbios_node_type'] == 'p') {
+ $this->validated_data["netbios_ntype"] = "2";
+ } else if ($this->initial_data['netbios_node_type'] == 'm') {
+ $this->validated_data["netbios_ntype"] = "3";
+ } else if ($this->initial_data['netbios_node_type'] == 'h') {
+ $this->validated_data["netbios_ntype"] = "4";
+ } else {
+ $this->errors[] = APIResponse\get(2076);
+ }
+ } else {
+ if (isset($this->initial_data['netbios_enable'])) {
+ $this->validated_data["netbios_ntype"] = "1";
+ } else {
+ $this->validated_data["netbios_ntype"] = "0";
+ }
+ }
+ }
+
+ private function __validate_netbios_scope() {
+ if (isset($this->initial_data['netbios_scope'])) {
+ $this->validated_data["netbios_scope"] = $this->initial_data['netbios_scope'];
+ } else {
+ $this->validated_data["netbios_scope"] = "";
+ }
+ }
+
+ private function __validate_create_gw() {
+ # Local variables
+ $key_types = ["both", "v4only", "v6only"];
+
+ # Validate Gateway creation
+ if (isset($this->initial_data["create_gw"])) {
+ if (in_array(strtolower($this->initial_data["create_gw"]), $key_types)) {
+ switch ($this->initial_data["create_gw"]) {
+ case "both":
+ $this->validated_data["create_gw"] = strtolower($this->initial_data["create_gw"]);
+ break;
+ case "v4only":
+ $this->validated_data["create_gw"] = strtolower($this->initial_data["create_gw"]);
+ break;
+ case "v6only":
+ $this->validated_data["create_gw"] = strtolower($this->initial_data["create_gw"]);
+ break;
+ }
+ } else {
+ $this->errors[] = APIResponse\get(2131);
+ }
+ # Assume default if none was specified
+ } else {
+ $this->validated_data["create_gw"] = "both";
+ }
+ }
+
+ private function __validate_verbosity_level() {
+ if (isset($this->initial_data['verbosity_level'])) {
+ if (is_numericint($this->initial_data['verbosity_level']) and ((int) $this->initial_data['verbosity_level'] >= 2) and ((int) $this->initial_data['verbosity_level'] < 13)) {
+ $this->validated_data["verbosity_level"] = $this->initial_data["verbosity_level"];
+ } elseif ($this->initial_data['verbosity_level'] == "none") {
+ $this->validated_data["verbosity_level"] = "0";
+ } elseif ($this->initial_data['verbosity_level'] == "default") {
+ $this->validated_data["verbosity_level"] = "1";
+ } else {
+ $this->errors[] = APIResponse\get(2132);
+ }
+ # Assume default if none was specified
+ } else {
+ $this->validated_data["verbosity_level"] = "1";
+ }
+ }
+
+ private function __validate_wins_servers() {
+ if (isset($this->initial_data['wins_servers'])) {
+ $win_servers = explode(',', $this->initial_data['wins_servers']);
+ $counter = 1;
+ foreach ($win_servers as $server) {
+ if ($counter > 2) {
+ break;
+ } elseif (is_ipaddrv4(str_replace(" ", "", $server))) {
+ $this->validated_data["wins_server" . $counter] = str_replace(" ", "", $server);
+ $counter += 1;
+ } else {
+ $this->errors[] = APIResponse\get(2151);
+ }
+ }
+ }
+ }
+
+ // TODO: Validate nbdd servers is not yet available
+ private function __validate_nbdd_server() {
+ if (isset($this->initial_data['wins_servers']) and ($this->validated_data["netbios_enable"] = "yes")) {
+ $this->validated_data["nbdd_server1"] = "";
+ }
+ }
+
+ private function __validate_disabled() {
+ # Check for our optional `disabled` payload value
+ if ($this->initial_data["disable"] === true) {
+ $this->validated_data["disable"] = "";
+ }
+ }
+
+ public function validate_payload() {
+ # Run each validation method
+ $this->__validate_vpnid();
+ $this->__validate_mode();
+ $this->__validate_description();
+ $this->__validate_disabled();
+ $this->__validate_dev_mode();
+ $this->__validate_protocol();
+ $this->__validate_interface();
+ $this->__validate_local_port();
+ $this->__validate_ncp_enable();
+ $this->__validate_data_ciphers();
+ $this->__validate_data_ciphers_fallback();
+ $this->__validate_engine();
+ $this->__validate_digest();
+ $this->__validate_tunnel_network();
+ $this->__validate_tunnel_networkv6();
+ $this->__validate_concurrent_connections();
+ $this->__validate_allow_compression();
+ $this->__validate_compression();
+ $this->__validate_type_of_service();
+ $this->__validate_ping_method();
+ $this->__validate_keepalive_interval();
+ $this->__validate_keepalive_timeout();
+ $this->__validate_ping_seconds();
+ $this->__validate_ping_action_seconds();
+ $this->__validate_ping_push();
+ $this->__validate_ping_action_push();
+ $this->__validate_ping_action();
+ $this->__validate_custom_options();
+ $this->__validate_udp_fast_io();
+ $this->__validate_snd_rcv_buf();
+ $this->__validate_create_gw();
+ $this->__validate_verbosity_level();
+
+ # Run each validation method for ["p2p_shared_key"]
+ if ($this->validated_data["mode"] === "p2p_shared_key") {
+ $this->__validate_shared_key();
+
+ $this->validated_data["gwredir"] = "";
+ $this->validated_data["gwredir6"] = "";
+ $this->validated_data["local_network"] = "";
+ $this->validated_data["local_networkv6"] = "";
+ $this->validated_data["compression_push"] = "";
+ $this->validated_data["client2client"] = "";
+ $this->validated_data["topology"] = "subnet";
+ $this->validated_data["dynamic_ip"] = "";
+ $this->validated_data["exit_notify"] = "1";
+ $this->validated_data["inactive_seconds"] = "300";
+ }
+
+ # Run each validation method for ["p2p_tls", "server_tls", "server_user", "server_tls_user"]
+ if ($this->validated_data["mode"] !== "p2p_shared_key") {
+ $this->__validate_tls();
+ $this->__validate_tls_type();
+ $this->__validate_tls_keydir();
+ $this->__validate_caref();
+ $this->__validate_crlref();
+ $this->__validate_ocspcheck();
+ $this->__validate_ocspurl();
+ $this->__validate_certref();
+ $this->__validate_dh_length();
+ $this->__validate_ecdh_curve();
+ $this->__validate_cert_depth();
+ $this->__validate_redirect_gateway();
+ $this->__validate_redirect_gateway6();
+ $this->__validate_local_network();
+ $this->__validate_local_networkv6();
+ $this->__validate_compression_push();
+ $this->__validate_inter_client_communication();
+ $this->__validate_duplicate_connection();
+ $this->__validate_dynamic_ip();
+ $this->__validate_topology();
+ $this->__validate_inactive_seconds();
+ $this->__validate_exit_notify();
+ }
+
+ # Run each validation method for ["p2p_tls", "p2p_shared_key"]
+ if (($this->validated_data["mode"] === "p2p_tls") or ($this->validated_data["mode"] === "p2p_shared_key")) {
+ $this->__validate_remote_network();
+ $this->__validate_remote_networkv6();
+
+ $this->validated_data["serverbridge_dhcp"] = "";
+ $this->validated_data["serverbridge_interface"] = "none";
+ $this->validated_data["serverbridge_routegateway"] = "";
+ $this->validated_data["serverbridge_dhcp_start"] = "";
+ $this->validated_data["serverbridge_dhcp_end"] = "";
+ $this->validated_data["netbios_enable"] = "";
+ $this->validated_data["netbios_ntype"] = "0";
+ $this->validated_data["netbios_scope"] = "";
+ }
+
+ # Run each validation method for ["server_tls", "server_user", "server_tls_user"]
+ if (($this->validated_data["mode"] !== "p2p_tls") and ($this->validated_data["mode"] !== "p2p_shared_key")) {
+ $this->__validate_dns_domain();
+ $this->__validate_dns_servers();
+ $this->__validate_push_blockout_side_dns();
+ $this->__validate_push_register_dns();
+ $this->__validate_ntp_servers();
+ $this->__validate_netbios_enable();
+ $this->__validate_netbios_ntype();
+ $this->__validate_netbios_scope();
+ $this->__validate_wins_servers();
+ $this->__validate_nbdd_server();
+ $this->__validate_serverbridge_dhcp();
+ $this->__validate_serverbridge_interface();
+ $this->__validate_serverbridge_routegateway();
+ $this->__validate_serverbridge_dhcp_start();
+ $this->__validate_serverbridge_dhcp_end();
+
+ $this->validated_data["remote_network"] = "";
+ $this->validated_data["remote_networkv6"] = "";
+ }
+
+ # Run each validation method for ["p2p_tls", "p2p_shared_key", "server_tls"]
+ if (($this->validate_data["mode"] !== "server_user") and ($this->validated_data["mode"] !== "server_tls_user")) {
+ $this->validated_data["username_as_common_name"] = "disabled";
+ }
+
+ # Run each validation method for ["server_user", "server_tls_user"]
+ if (($this->validate_data["mode"] === "server_user") or ($this->validated_data["mode"] === "server_tls_user")) {
+ $this->__validate_authmode();
+ $this->__validate_username_as_cn();
+
+ }
+
+ # Run each validation method for ["p2p_tls"]
+ if ($this->validated_data["mode"] === "p2p_tls") {
+ }
+
+ # Run each validation method for ["server_tls"]
+ if ($this->validated_data["mode"] === "server_tls") {
+ }
+
+ # Run each validation method for ["server_user"]
+ if ($this->validate_data["mode"] === "server_user") {
+ }
+
+ # Run each validation method for ["server_tls_user"]
+ if ($this->validated_data["mode"] === "server_tls_user") {
+ $this->__validate_strick_user_cn();
+ }
+ }
+
+ private function __init_config() {
+ # Ensure the OpenVPN configuration array exists
+ if (empty($this->config["openvpn"])) {
+ $this->config["openvpn"] = [];
+ }
+
+ # Ensure the OpenVPN server configuration array exists
+ if (empty($this->config['openvpn']['openvpn-server'])) {
+ $this->config['openvpn']['openvpn-server'] = [];
+ }
+ }
+}
diff --git a/pfSense-pkg-API/files/etc/inc/api/models/APIServicesOpenVPNServerDelete.inc b/pfSense-pkg-API/files/etc/inc/api/models/APIServicesOpenVPNServerDelete.inc
new file mode 100644
index 000000000..b5a4aa70b
--- /dev/null
+++ b/pfSense-pkg-API/files/etc/inc/api/models/APIServicesOpenVPNServerDelete.inc
@@ -0,0 +1,67 @@
+privileges = ["page-all", "page-openvpn-server"];
+ $this->change_note = "Deleted OpenVPN server via API";
+ }
+
+ public function action() {
+ # Remove user from backend and remove from config
+ openvpn_delete("server",$this->config["openvpn"]["openvpn-server"][$this->id]);
+ unset($this->config["openvpn"]["openvpn-server"][$this->id]);
+ $this->write_config();
+ return APIResponse\get(0, $this->validated_data);
+ }
+
+ private function __validate_vpnid() {
+ if (isset($this->initial_data['vpnid'])) {
+ $counter = 0;
+ foreach ($this->config["openvpn"]["openvpn-server"] as $server) {
+ if ((string) $this->initial_data['vpnid'] === (string) $server["vpnid"]) {
+ $this->id = $counter;
+ $this->validated_data['vpnid'] = (string) $this->initial_data['vpnid'];
+ break;
+ }
+ $counter += 1;
+ }
+
+ if (empty($this->validated_data["vpnid"])) {
+ $this->errors[] = APIResponse\get(2139);
+ }
+ } else {
+ $this->errors[] = APIResponse\get(2140);
+ }
+ }
+
+ public function __validate_ovpns() {
+ foreach ($this->config["interfaces"] as $interface) {
+ if (isset($interface["if"]) and ($interface["if"] == "ovpns" . $this->validated_data['vpnid'])) {
+ $this->errors[] = APIResponse\get(2152);
+ }
+ }
+ }
+
+ public function validate_payload() {
+ $this->__validate_vpnid();
+ $this->__validate_ovpns();
+ }
+}
diff --git a/pfSense-pkg-API/files/etc/inc/api/models/APIServicesOpenVPNServerRead.inc b/pfSense-pkg-API/files/etc/inc/api/models/APIServicesOpenVPNServerRead.inc
new file mode 100644
index 000000000..2f3b33267
--- /dev/null
+++ b/pfSense-pkg-API/files/etc/inc/api/models/APIServicesOpenVPNServerRead.inc
@@ -0,0 +1,29 @@
+privileges = ["page-all", "page-openvpn-server"];
+ }
+
+ public function action() {
+ return APIResponse\get(0, $this->config["openvpn"]["openvpn-server"]);
+ }
+}
\ No newline at end of file
diff --git a/pfSense-pkg-API/files/etc/inc/api/models/APIServicesOpenVPNServerUpdate.inc b/pfSense-pkg-API/files/etc/inc/api/models/APIServicesOpenVPNServerUpdate.inc
new file mode 100644
index 000000000..06e6de50f
--- /dev/null
+++ b/pfSense-pkg-API/files/etc/inc/api/models/APIServicesOpenVPNServerUpdate.inc
@@ -0,0 +1,1370 @@
+privileges = ["page-all", "page-openvpn-server"];
+ $this->change_note = "Modified OpenVPN server via API";
+ }
+
+ public function action() {
+ # Initialize expected configuration arrays
+ $this->__init_config();
+
+ # Update server to the new configuration and resync OpenVPN to use new server
+ $this->config['openvpn']['openvpn-server'][$this->id] = $this->validated_data;
+ $this->write_config();
+
+ openvpn_delete('server', $this->original_server);
+ openvpn_resync('server', $this->validated_data);
+ return APIResponse\get(0, $this->validated_data);
+ }
+
+ private function __validate_vpnid() {
+ if (isset($this->initial_data['vpnid'])) {
+ foreach ($this->config["openvpn"]["openvpn-server"] as $i => $server) {
+ if ((string) $this->initial_data['vpnid'] === (string) $server['vpnid']) {
+ $this->id = $i;
+ $this->validated_data = $this->config['openvpn']['openvpn-server'][$this->id];
+ $this->original_server = $this->config['openvpn']['openvpn-server'][$this->id];
+ break;
+ }
+ }
+ if (empty($this->validated_data["vpnid"])) {
+ $this->errors[] = APIResponse\get(2139);
+ }
+ } else {
+ $this->errors[] = APIResponse\get(2140);
+ }
+ }
+
+ private function __validate_mode() {
+ # Local variables
+ $key_types = ["p2p_tls", "p2p_shared_key", "server_tls", "server_user", "server_tls_user"];
+
+ # Validate Server mode
+ if (isset($this->initial_data["mode"])) {
+ if (in_array($this->initial_data["mode"], $key_types)) {
+ $this->validated_data["mode"] = $this->initial_data["mode"];
+ } else {
+ $this->errors[] = APIResponse\get(2104);
+ }
+ }
+ }
+
+ private function __validate_authmode() {
+ # Validate Backend for authentication
+ if (isset($this->initial_data["authmode"])) {
+ $this->validated_data["authmode"] = $this->initial_data["authmode"];
+ }
+ }
+
+ private function __validate_protocol() {
+ # Local variables
+ $key_types = ["UDP4", "UDP6", "TCP4", "TCP6", "UDP", "TCP"];
+
+ # Validate Protocol
+ if (isset($this->initial_data["protocol"])) {
+ if (in_array(strtoupper($this->initial_data["protocol"]), $key_types)) {
+ $this->validated_data["protocol"] = strtoupper($this->initial_data["protocol"]);
+ } else {
+ $this->errors[] = APIResponse\get(2105);
+ }
+ }
+ }
+
+ private function __validate_dev_mode() {
+ # Local variables
+ $key_types = ["tun", "tap"];
+
+ # Validate Device mode
+ if (isset($this->initial_data["dev_mode"])) {
+ if (in_array($this->initial_data["dev_mode"], $key_types)) {
+ $this->validated_data["dev_mode"] = $this->initial_data["dev_mode"];
+ } else {
+ $this->errors[] = APIResponse\get(2106);
+ }
+ }
+ }
+
+ private function __validate_interface() {
+ if (($this->validated_data["protocol"] === "UDP") or ($this->validated_data["protocol"] === "TCP")) {
+ $this->validated_data["interface"] = "wan";
+ $this->validated_data["ipaddr"] = "";
+ } elseif (isset($this->initial_data["interface"])) {
+ # Local variables
+ $match = false;
+ $interface = $this->initial_data["interface"];
+
+ // Validate Interface
+ if (!empty(APITools\get_pfsense_if_id($interface))) {
+ if (isset($this->config["interfaces"][APITools\get_pfsense_if_id($interface)]["enable"])) {
+ $this->validated_data["interface"] = APITools\get_pfsense_if_id($interface);
+ $this->validated_data["ipaddr"] = "";
+ $match = true;
+ }
+ }
+
+ // Validate Virtual Interface
+ if (!$match) {
+ foreach ($this->config["virtualip"]["vip"] as $vip) {
+ if (($vip["mode"] === "ipalias") or ($vip["mode"] === "carp") ) {
+ if (strtolower($this->initial_data["interface"]) === strtolower($vip["descr"])) {
+ $this->validated_data["interface"] = "_vip" . $vip["uniqid"];
+ $this->validated_data["ipaddr"] = $vip["subnet"];
+ $match = true;
+ break;
+ } elseif ((filter_var($vip["subnet"], FILTER_VALIDATE_IP)) and ($this->initial_data["interface"] === $vip["subnet"])) {
+ $this->validated_data["interface"] = "_vip" . $vip["uniqid"];
+ $this->validated_data["ipaddr"] = $vip["subnet"];
+ $match = true;
+ break;
+ } elseif (strtolower($this->initial_data["interface"]) === $vip["uniqid"]) {
+ $this->validated_data["interface"] = "_vip" . $vip["uniqid"];
+ $this->validated_data["ipaddr"] = $vip["subnet"];
+ $match = true;
+ break;
+ }
+ }
+ }
+ }
+
+ // Validate Gateway Group Interface
+ if (!$match) {
+ foreach ($this->config["gateways"]["gateway_group"] as $gateway_group) {
+ if (strtolower($this->initial_data["interface"]) === strtolower($gateway_group['name'])) {
+ $this->validated_data["interface"] = $gateway_group['name'];
+ $this->validated_data["ipaddr"] = "";
+ $match = true;
+ break;
+ }
+ }
+ }
+
+ if (!$match) {
+ $this->errors[] = APIResponse\get(2107);
+ }
+ }
+ }
+
+ private function __validate_local_port() {
+ # Only create local_port if no errors were found
+ if (isset($this->initial_data["local_port"])) {
+ if (!openvpn_validate_port($this->initial_data["local_port"], "local_port", 1)) {
+ if (openvpn_port_used($this->validated_data["protocol"], $this->validated_data["interface"], $this->initial_data["local_port"], 0) == 0) {
+ $this->validated_data["local_port"] = $this->initial_data["local_port"];
+ } else {
+ $this->errors[] = APIResponse\get(2108);
+ }
+ } else {
+ $this->errors[] = APIResponse\get(2108);
+ }
+ }
+ }
+
+ private function __validate_description() {
+ # Check for our optional `descr` payload value
+ if (isset($this->initial_data['description'])) {
+ $this->validated_data["description"] = $this->initial_data['description'];
+ }
+ }
+
+ private function __validate_custom_options() {
+ # Check for our optional `Custom options` payload value
+ if (isset($this->initial_data['custom_options'])) {
+ $this->validated_data["custom_options"] = $this->initial_data['custom_options'];
+ }
+ }
+
+ private function __validate_tls() {
+ # Check for our optional `TLS` payload value
+ if (isset($this->initial_data["tls"])) {
+ # Auto generate TLS key if empty
+ if ($this->initial_data["tls"] == "" or $this->initial_data["tls"] == "true") {
+ $this->validated_data["tls"] = base64_encode(openvpn_create_key());
+ } else {
+ $this->validated_data["tls"] = base64_encode($this->initial_data["tls"]);
+ }
+
+ # Disable TLS if fasle
+ if ($this->initial_data["tls"] == "false") {
+ unset($this->validated_data["tls"]);
+ }
+ }
+ }
+
+ private function __validate_tls_type() {
+ # Local variables
+ $key_types = ["auth", "crypt"];
+
+ # Validate TLS type if TLS set
+ if (isset($this->validated_data["tls"])) {
+ if (isset($this->initial_data["tls_type"])) {
+ if (in_array($this->initial_data["tls_type"], $key_types)) {
+ $this->validated_data["tls_type"] = $this->initial_data["tls_type"];
+ } else {
+ $this->errors[] = APIResponse\get(2109);
+ }
+ }
+ } else {
+ unset($this->validated_data["tls_type"]);
+ }
+ }
+
+ private function __validate_tls_keydir() {
+ # Local variables
+ $key_types = ["default", "direction-0", "direction-1", "both-directions"];
+
+ # Validate keydir direction if TLS set
+ if (isset($this->validated_data["tls"])) {
+ if (isset($this->initial_data["tlsauth_keydir"])) {
+ if (in_array($this->initial_data["tlsauth_keydir"], $key_types)) {
+ switch ($this->initial_data["tlsauth_keydir"]) {
+ case "default":
+ $this->validated_data["tlsauth_keydir"] = "default";
+ break;
+ case "direction-0":
+ $this->validated_data["tlsauth_keydir"] = "0";
+ break;
+ case "direction-1":
+ $this->validated_data["tlsauth_keydir"] = "1";
+ break;
+ case "both-directions":
+ $this->validated_data["tlsauth_keydir"] = "2";
+ break;
+ }
+ } else {
+ $this->errors[] = APIResponse\get(2110);
+ }
+ }
+ } else {
+ unset($this->validated_data["tlsauth_keydir"]);
+ }
+ }
+
+ private function __validate_shared_key() {
+ # Check for our optional `Shared key` payload value
+ if (isset($this->initial_data["shared_key"])) {
+ # Auto generate Shared key if empty
+ if ($this->initial_data["shared_key"] === "") {
+ $this->validated_data["shared_key"] = base64_encode(openvpn_create_key());
+ # Assume default if none was specified
+ } else {
+ $this->validated_data["shared_key"] = base64_encode($this->initial_data["shared_key"]);
+ }
+ }
+ }
+
+ private function __validate_caref() {
+ if (isset($this->initial_data["caref"])) {
+ foreach ($this->config["ca"] as $ca) {
+ if ($this->initial_data["caref"] === $ca["refid"]) {
+ $this->validated_data["caref"] = $ca["refid"];
+ break;
+ }
+ }
+
+ if ($this->validated_data["caref"] !== $this->initial_data["caref"]) {
+ $this->errors[] = APIResponse\get(2142);
+ }
+ }
+ }
+
+ private function __validate_crlref() {
+ if (isset($this->initial_data["crlref"])) {
+ if ($this->initial_data["crlref"] === "none") {
+ $this->validated_data["crlref"] = "";
+ } else {
+ foreach ($this->config["crl"] as $crl) {
+ if (($this->validated_data["caref"] === $crl["caref"]) and ($this->initial_data["crlref"] === $crl["refid"])) {
+ $this->validated_data["crlref"] = $this->initial_data["refid"];
+ break;
+ }
+
+ if ((empty($this->validated_data["crlref"])) or ($this->validated_data["crlref"] !== $this->initial_data["crlref"])) {
+ $this->errors[] = APIResponse\get(2137);
+ }
+ }
+ }
+ }
+ }
+
+ private function __validate_ocspcheck() {
+ # Check for our optional `OCSP` payload value
+ if (($this->initial_data["ocspcheck"] === true) and (empty($this->validated_data["ocspcheck"]))) {
+ $this->validated_data["ocspcheck"] = "yes";
+ } elseif (($this->initial_data["ocspcheck"] === false) and (!empty($this->validated_data["ocspcheck"]))) {
+ unset($this->validated_data["ocspcheck"]);
+ }
+ }
+
+ private function __validate_ocspurl() {
+ # Check for our optional `OCSP URL` payload value
+ if ($this->validated_data["ocspcheck"] === "yes") {
+ if (isset($this->initial_data["ocspurl"])) {
+ $this->validated_data["ocspurl"] = $this->initial_data["ocspurl"];
+ }
+ } elseif (empty($this->validated_data["ocspcheck"])) {
+ unset($this->validated_data["ocspurl"]);
+ }
+ }
+
+ private function __validate_certref() {
+ if (isset($this->initial_data["certref"])) {
+ foreach ($this->config["cert"] as $cert) {
+ if ($this->initial_data["certref"] === $cert["refid"]) {
+ $this->validated_data["certref"] = $cert["refid"];
+ break;
+ }
+ }
+
+ if ($this->validated_data["certref"] !== $this->initial_data["certref"]) {
+ $this->errors[] = APIResponse\get(2143);
+ }
+ }
+ }
+
+ private function __validate_dh_length() {
+ # Local variables
+ $key_types = ["1024", "2048", "3072", "4096", "6144", "7680", "8192", "15360", "16384", "ECDH Only"];
+
+ # Validate DH Parameter Length
+ if (isset($this->initial_data["dh_length"])) {
+ if (in_array($this->initial_data["dh_length"], $key_types)) {
+ if ($this->initial_data["dh_length"] === "ECDH Only") {
+ $this->validated_data["dh_length"] = "none";
+ } else {
+ $this->validated_data["dh_length"] = $this->initial_data["dh_length"];
+ }
+ } else {
+ $this->errors[] = APIResponse\get(2111);
+ }
+ }
+ }
+
+ private function __validate_ecdh_curve() {
+ # Local variables
+ $key_types = ["none", "prime256v1", "secp384r1", "secp521r1"];
+
+ # Validate ECDH Curve
+ if (isset($this->initial_data["ecdh_curve"])) {
+ if (in_array($this->initial_data["ecdh_curve"], $key_types)) {
+ $this->validated_data["ecdh_curve"] = $this->initial_data["ecdh_curve"];
+ } else {
+ $this->errors[] = APIResponse\get(2112);
+ }
+ }
+ }
+
+ private function __validate_cert_depth() {
+ # Local variables
+ $key_types = ["none", "one", "two", "three", "four", "five"];
+
+ # Validate Certificate Depth
+ if (isset($this->initial_data["cert_depth"])) {
+ if (in_array($this->initial_data["cert_depth"], $key_types)) {
+ switch ($this->initial_data["cert_depth"]) {
+ case "none":
+ $this->validated_data["cert_depth"] = "";
+ break;
+ case "one":
+ $this->validated_data["cert_depth"] = "1";
+ break;
+ case "two":
+ $this->validated_data["cert_depth"] = "2";
+ break;
+ case "three":
+ $this->validated_data["cert_depth"] = "3";
+ break;
+ case "four":
+ $this->validated_data["cert_depth"] = "4";
+ break;
+ case "five":
+ $this->validated_data["cert_depth"] = "5";
+ break;
+ }
+ } else {
+ $this->errors[] = APIResponse\get(2113);
+ }
+ }
+ }
+
+ private function __validate_strick_user_cn() {
+ if (($this->initial_data['strictusercn'] === true) and ($this->validated_data["strictusercn"] === "")) {
+ $this->validated_data["strictusercn"] = "yes";
+ } elseif (($this->initial_data['strictusercn'] === false) and ($this->validated_data["strictusercn"] === "yes")) {
+ $this->validated_data["strictusercn"] = "";
+ }
+ }
+
+ private function __validate_ncp_enable() {
+ if (($this->initial_data["data_encryption_negotiation"] === false) and ($this->validated_data["ncp_enable"] === "enabled")) {
+ $this->validated_data["ncp_enable"] = "disabled";
+ } elseif (($this->initial_data["data_encryption_negotiation"] === true) and ($this->validated_data["ncp_enable"] === "disabled")) {
+ $this->validated_data["ncp_enable"] = "enabled";
+ }
+ }
+
+ private function __validate_data_ciphers() {
+ if (isset($this->initial_data["data_ciphers"])) {
+ $data_ciphers = explode(',', $this->initial_data['data_ciphers']);
+ $counter = 1;
+ foreach ($data_ciphers as $cipher) {
+ if (!array_key_exists($cipher, openvpn_get_cipherlist())) {
+ $this->errors[] = APIResponse\get(2138);
+ } elseif ($counter > 19) {
+ break;
+ } else {
+ $counter += 1;
+ }
+ }
+ $this->validated_data["data_ciphers"] = $this->initial_data['data_ciphers'];
+ }
+ }
+
+ private function __validate_data_ciphers_fallback() {
+ # Validate Fallback Data Encryption Algorithm
+ if (isset($this->initial_data["data_ciphers_fallback"])) {
+ if (array_key_exists($this->initial_data["data_ciphers_fallback"], openvpn_get_cipherlist())) {
+ $this->validated_data["data_ciphers_fallback"] = $this->initial_data["data_ciphers_fallback"];
+ } else {
+ $this->errors[] = APIResponse\get(2114);
+ }
+ }
+ }
+
+ private function __validate_digest() {
+ # Local variables
+ $key_types = ["SHA256", "BLAKE2b512", "BLAKE2b256", "MD4", "MD5", "MD5-SHA1", "MDC2", "RIPEMD160", "SHA1", "SHA224", "SHA256", "SHA3-224", "SHA3-256", "SHA3-384", "SHA3-512", "SHA384", "SHA512", "SHA512-224", "SHA512-256", "SHAKE128", "SHAKE256", "SM3", "whirlpool", "none"];
+
+ # Validate Auth digest algorithm
+ if (isset($this->initial_data["digest"])) {
+ if (in_array($this->initial_data["digest"], $key_types)) {
+ $this->validated_data["digest"] = $this->initial_data["digest"];
+ } else {
+ $this->errors[] = APIResponse\get(2115);
+ }
+ }
+ }
+
+ private function __validate_engine() {
+ # Validate Hardware Crypto
+ if (isset($this->initial_data["engine"])) {
+ if (array_key_exists($this->initial_data["engine"], openvpn_get_engines())) {
+ $this->validated_data["engine"] = $this->initial_data["engine"];
+ } else {
+ $this->errors[] = APIResponse\get(2116);
+ }
+ }
+ }
+
+ private function __validate_tunnel_network() {
+ # Validate Tunnel Network
+ if (isset($this->initial_data['tunnel_network'])) {
+ if (!openvpn_validate_cidr($this->initial_data['tunnel_network'], "", false, "ipv4")) {
+ if (!openvpn_is_tunnel_network_in_use($this->initial_data['tunnel_network'])) {
+ $this->validated_data["tunnel_network"] = $this->initial_data['tunnel_network'];
+ } else {
+ $this->errors[] = APIResponse\get(2117);
+ }
+ } else {
+ $this->errors[] = APIResponse\get(2117);
+ }
+ }
+ }
+
+ private function __validate_tunnel_networkv6() {
+ # Validate Tunnel Network v6
+ if (isset($this->initial_data['tunnel_networkv6'])) {
+ if (!openvpn_validate_cidr($this->initial_data['tunnel_networkv6'], "", false, "ipv6")) {
+ if (!openvpn_is_tunnel_network_in_use($this->initial_data['tunnel_networkv6'])) {
+ $this->validated_data["tunnel_networkv6"] = $this->initial_data['tunnel_networkv6'];
+ } else {
+ $this->errors[] = APIResponse\get(2117);
+ }
+ } else {
+ $this->errors[] = APIResponse\get(2117);
+ }
+ }
+ }
+
+ private function __validate_serverbridge_dhcp() {
+ if (($this->validated_data['dev_mode'] === 'tap') and (isset($this->initial_data["serverbridge_dhcp"]))) {
+ if ($this->initial_data['serverbridge_dhcp'] === true) {
+ $this->validated_data['serverbridge_dhcp'] = 'yes';
+ } else {
+ $this->validated_data['serverbridge_dhcp'] = "";
+ }
+ }
+ }
+
+ private function __validate_serverbridge_interface() {
+ $key_types = ["wan", "lan", "none"];
+ $match = false;
+
+ if (($this->validated_data['serverbridge_dhcp'] === 'yes') and (isset($this->initial_data['serverbridge_interface']))) {
+ // Validate Virtual Interface
+ foreach ($this->config["virtualip"]["vip"] as $vip) {
+ if (strtolower($this->initial_data["serverbridge_interface"]) === strtolower($vip["descr"])) {
+ $this->validated_data["interface"] = "_vip" . $vip["uniqid"] . "|" . $vip["subnet"];
+ $match = true;
+ break;
+ } elseif ((filter_var($vip["subnet"], FILTER_VALIDATE_IP)) and ($this->initial_data["serverbridge_interface"] === $vip["subnet"])) {
+ $this->validated_data["interface"] = "_vip" . $vip["uniqid"] . "|" . $vip["subnet"];
+ $match = true;
+ break;
+ } elseif (strtolower($this->initial_data["serverbridge_interface"]) === strtolower($vip["uniqid"])) {
+ $this->validated_data["interface"] = "_vip" . $vip["uniqid"] . "|" . $vip["subnet"];
+ $match = true;
+ break;
+ }
+ }
+
+ if (in_array(strtolower($this->initial_data['serverbridge_interface']), $key_types)) {
+ $this->validated_data["serverbridge_interface"] = strtolower($this->initial_data['serverbridge_interface']);
+ $match = true;
+ }
+
+ if (!$match) {
+ $this->errors[] = APIResponse\get(2146);
+ }
+ }
+ }
+
+ private function __validate_serverbridge_routegateway() {
+ if (($this->validated_data['serverbridge_dhcp'] === 'yes') and (isset($this->initial_data['serverbridge_routegateway']))) {
+ if ($this->initial_data['serverbridge_routegateway'] === true) {
+ if ($this->validated_data["serverbridge_interface"] !== "none") {
+ $this->validated_data["serverbridge_routegateway"] = "yes";
+ } else {
+ $this->errors[] = APIResponse\get(2142);
+ }
+ } else {
+ $this->validated_data["serverbridge_routegateway"] = "";
+ }
+ }
+ }
+
+ private function __validate_serverbridge_dhcp_start() {
+ if (($this->validated_data['serverbridge_dhcp'] === 'yes') and (isset($this->initial_data['serverbridge_dhcp_start']))) {
+ if ((isset($this->initial_data['serverbridge_dhcp_start'])) and (is_ipaddrv4($this->initial_data['serverbridge_dhcp_start'])) and (isset($this->initial_data['serverbridge_dhcp_end']))) {
+ $this->validated_data["serverbridge_dhcp_start"] = $this->initial_data['serverbridge_dhcp_start'];
+ } else {
+ $this->errors[] = APIResponse\get(2148);
+ }
+ }
+ }
+
+ private function __validate_serverbridge_dhcp_end() {
+ if (($this->validated_data['serverbridge_dhcp'] === 'yes') and (isset($this->initial_data['serverbridge_dhcp_end']))) {
+ if ((isset($this->initial_data['serverbridge_dhcp_end'])) and (is_ipaddrv4($this->initial_data['serverbridge_dhcp_end'])) and (isset($this->initial_data['serverbridge_dhcp_start']))) {
+ $this->validated_data["serverbridge_dhcp_end"] = $this->initial_data['serverbridge_dhcp_end'];
+ } else {
+ $this->errors[] = APIResponse\get(2148);
+ }
+ }
+ }
+
+ private function __validate_remote_network() {
+ # Check for our optional `Remote Network` payload value
+ if (isset($this->initial_data['remote_network'])) {
+ if (!openvpn_validate_cidr($this->initial_data['remote_network'], "", true, "ipv4")) {
+ $this->validated_data["remote_network"] = $this->initial_data['remote_network'];
+ } else {
+ $this->errors[] = APIResponse\get(2118);
+ }
+ }
+ }
+
+ private function __validate_remote_networkv6() {
+ # Check for our optional `Remote Network v6` payload value
+ if (isset($this->initial_data['remote_networkv6'])) {
+ if (!openvpn_validate_cidr($this->initial_data['remote_networkv6'], "", true, "ipv6") === false) {
+ $this->validated_data["remote_networkv6"] = $this->initial_data['remote_networkv6'];
+ } else {
+ $this->errors[] = APIResponse\get(2118);
+ }
+ }
+ }
+
+ private function __validate_redirect_gateway() {
+ if (isset($this->initial_data['redirect_gateway'])) {
+ if (($this->initial_data['redirect_gateway'] === true) and ($this->validated_data["gwredir"] === "")) {
+ $this->validated_data["gwredir"] = "yes";
+ } elseif (($this->initial_data['redirect_gateway'] === false) and ($this->validated_data["gwredir"] === "yes")) {
+ $this->validated_data["gwredir"] = "";
+ }
+ }
+ }
+
+ private function __validate_redirect_gateway6() {
+ if (isset($this->initial_data['redirect_gateway6'])) {
+ if (($this->initial_data['redirect_gateway6'] === true) and ($this->validated_data["gwredir6"] === "")) {
+ $this->validated_data["gwredir6"] = "yes";
+ } elseif (($this->initial_data['redirect_gateway6'] === false) and ($this->validated_data["gwredir6"] === "yes")) {
+ $this->validated_data["gwredir6"] = "";
+ }
+ }
+ }
+
+ private function __validate_local_network() {
+ if ($this->validated_data['gwredir'] === "") {
+ if (isset($this->initial_data['local_network'])) {
+ if (!openvpn_validate_cidr($this->initial_data['local_network'], "", true, "ipv4")) {
+ $this->validated_data["local_network"] = $this->initial_data['local_network'];
+ } else {
+ $this->errors[] = APIResponse\get(2119);
+ }
+ }
+ } else {
+ $this->validated_data["local_network"] = "";
+ }
+ }
+
+ private function __validate_local_networkv6() {
+ if ($this->validated_data['gwredir6'] === "") {
+ if (isset($this->initial_data['local_networkv6'])) {
+ if (!openvpn_validate_cidr($this->initial_data['local_networkv6'], "", true, "ipv6")) {
+ $this->validated_data["local_networkv6"] = $this->initial_data['local_networkv6'];
+ } else {
+ $this->errors[] = APIResponse\get(2119);
+ }
+ }
+ } else {
+ $this->validated_data["local_networkv6"] = "";
+ }
+ }
+
+ private function __validate_concurrent_connections() {
+ if (isset($this->initial_data['concurrent_connections'])) {
+ if (is_numericint($this->initial_data['concurrent_connections']) and (int) $this->initial_data['concurrent_connections'] > 0) {
+ $this->validated_data["maxclients"] = $this->initial_data['concurrent_connections'];
+ } else {
+ $this->errors[] = APIResponse\get(2133);
+ }
+ }
+ }
+
+ private function __validate_allow_compression() {
+ # Local variables
+ $key_types = ["asym", "no", "yes"];
+
+ # Validate Allow Compression
+ if (isset($this->initial_data["allow_compression"])) {
+ if (in_array($this->initial_data["allow_compression"], $key_types)) {
+ $this->validated_data["allow_compression"] = $this->initial_data["allow_compression"];
+ } else {
+ $this->errors[] = APIResponse\get(2120);
+ }
+ }
+ }
+
+ private function __validate_compression() {
+ # Local variables
+ $key_types = ["none", "stub", "stub-v2", "lz4", "lz4-v2", "lzo", "noadapt", "adaptive", "yes", "no"];
+
+ if (($this->validated_data["allow_compression"] === "yes") or ($this->validated_data["allow_compression"] === "asym")) {
+ # Validate Compression
+ if (isset($this->initial_data["compression"])) {
+ if (in_array($this->initial_data["compression"], $key_types)) {
+ $this->validated_data["compression"] = $this->initial_data["compression"];
+ } else {
+ $this->errors[] = APIResponse\get(2121);
+ }
+ }
+ # Assume default if none was specified
+ } else {
+ $this->validated_data["compression"] = "";
+ }
+ }
+
+ private function __validate_compression_push() {
+ if (($this->initial_data['compression_push'] === true) and ($this->validated_data["compression_push"] === "")) {
+ $this->validated_data["compression_push"] = "yes";
+ # Assume default if none was specified
+ } elseif (($this->initial_data['compression_push'] === false) and ($this->validated_data["compression_push"] === "yes")) {
+ $this->validated_data["compression_push"] = "";
+ }
+ }
+
+ private function __validate_type_of_service() {
+ if (($this->initial_data['passtos'] === true) and ($this->validated_data["passtos"] === "")) {
+ $this->validated_data["passtos"] = "yes";
+ } elseif (($this->initial_data['passtos'] === false) and ($this->validated_data["passtos"] === "yes")) {
+ $this->validated_data["passtos"] = "";
+ }
+ }
+
+ private function __validate_inter_client_communication() {
+ if (($this->initial_data['client2client'] === true) and ($this->validated_data["client2client"] === "")) {
+ $this->validated_data["client2client"] = "yes";
+ # Assume default if none was specified
+ } elseif (($this->initial_data['client2client'] === false) and ($this->validated_data["client2client"] === "yes")) {
+ $this->validated_data["client2client"] = "";
+ }
+ }
+
+ private function __validate_duplicate_connection() {
+ if (($this->initial_data['duplicate_cn'] === true) and (empty($this->validated_data["duplicate_cn"]))) {
+ $this->validated_data["duplicate_cn"] = "";
+ } elseif (($this->initial_data['duplicate_cn'] === false) and (!empty($this->validated_data["duplicate_cn"]))) {
+ unset($this->validated_data["duplicate_cn"]);
+ }
+ }
+
+ private function __validate_dynamic_ip() {
+ if (($this->initial_data['dynamic_ip'] === true) and ($this->validated_data["dynamic_ip"] === "")) {
+ $this->validated_data["dynamic_ip"] = "yes";
+ } elseif (($this->initial_data['dynamic_ip'] === false) and ($this->validated_data["dynamic_ip"] === "yes")) {
+ $this->validated_data["dynamic_ip"] = "";
+ }
+ }
+
+ // TODO: Add validation for "topology"
+ private function __validate_topology() {
+ # Local variables
+ $key_types = ["subnet", "net30"];
+
+ # Validate Topology
+ if ($this->validated_data["dev_mode"] === "tap") {
+ $this->validated_data["topology"] = "subnet";
+ } elseif (isset($this->initial_data["topology"])) {
+ if (in_array($this->initial_data["topology"], $key_types)) {
+ $this->validated_data["topology"] = $this->initial_data["topology"];
+ } else {
+ $this->errors[] = APIResponse\get(2122);
+ }
+ }
+ }
+
+ private function __validate_dns_domain() {
+ if (isset($this->initial_data['dns_domain'])) {
+ $this->validated_data["dns_domain"] = $this->initial_data['dns_domain'];
+ }
+ }
+
+ private function __validate_dns_servers() {
+ if (isset($this->initial_data['dns_servers'])) {
+ $dns_servers = explode(',', $this->initial_data['dns_servers']);
+ $counter = 1;
+ foreach ($dns_servers as $server) {
+ if ($counter > 4) {
+ break;
+ } elseif (is_ipaddrv4(str_replace(" ", "", $server))) {
+ $this->validated_data["dns_server" . $counter] = str_replace(" ", "", $server);
+ $counter += 1;
+ }
+ }
+ }
+ }
+
+ private function __validate_push_blockout_side_dns() {
+ if (($this->initial_data['push_blockoutsidedns'] === true) and (empty($this->validated_data["push_blockoutsidedns"]))) {
+ $this->validated_data["push_blockoutsidedns"] = "yes";
+ } elseif (($this->initial_data['push_blockoutsidedns'] === false) and (!empty($this->validated_data["push_blockoutsidedns"]))) {
+ unset($this->validated_data["push_blockoutsidedns"]);
+ }
+ }
+
+ private function __validate_inactive_seconds() {
+ if (isset($this->initial_data['inactive_seconds'])) {
+ if (is_numericint($this->initial_data['inactive_seconds']) and ((int) $this->initial_data['inactive_seconds']) >= 0) {
+ $this->validated_data["inactive_seconds"] = $this->initial_data['inactive_seconds'];
+ # Assume default if none was specified
+ } else {
+ $this->errors[] = APIResponse\get(2134);
+ }
+ }
+ }
+
+ private function __validate_ping_method() {
+ # Local variables
+ $key_types = ["keepalive", "ping"];
+
+ # Validate Ping method
+ if (isset($this->initial_data["ping_method"])) {
+ if (in_array($this->initial_data["ping_method"], $key_types)) {
+ $this->validated_data["ping_method"] = $this->initial_data["ping_method"];
+ } else {
+ $this->errors[] = APIResponse\get(2123);
+ }
+ }
+ }
+
+ private function __validate_keepalive_interval() {
+ if ($this->validated_data["ping_method"] === "keepalive") {
+ if (isset($this->initial_data['keepalive_interval'])) {
+ if (is_numericint($this->initial_data['keepalive_interval']) and ((int) $this->initial_data['keepalive_interval'] >= 0)) {
+ $this->validated_data["keepalive_interval"] = $this->initial_data['keepalive_interval'];
+ } else {
+ $this->errors[] = APIResponse\get(2124);
+ }
+ }
+ # Assume default if none was specified
+ } else {
+ $this->validated_data["keepalive_interval"] = "10";
+ }
+ }
+
+ private function __validate_keepalive_timeout() {
+ if ($this->validated_data["ping_method"] === "keepalive") {
+ if (isset($this->initial_data['keepalive_timeout'])) {
+ if (is_numericint($this->initial_data['keepalive_timeout']) and ((int) $this->initial_data['keepalive_timeout'] >= 0)) {
+ $this->validated_data["keepalive_timeout"] = $this->initial_data['keepalive_timeout'];
+ } else {
+ $this->errors[] = APIResponse\get(2125);
+ }
+ }
+ # Assume default if none was specified
+ } else {
+ $this->validated_data["keepalive_timeout"] = "60";
+ }
+ }
+
+ private function __validate_ping_seconds() {
+ if ($this->validated_data["ping_method"] === "ping") {
+ if (isset($this->initial_data['ping_seconds'])) {
+ if (is_numericint($this->initial_data['ping_seconds']) and ((int) $this->initial_data['ping_seconds'] >= 0)) {
+ $this->validated_data["ping_seconds"] = $this->initial_data['ping_seconds'];
+ } else {
+ $this->errors[] = APIResponse\get(2126);
+ }
+ }
+ # Assume default if none was specified
+ } else {
+ $this->validated_data["ping_seconds"] = "10";
+ }
+ }
+
+ private function __validate_ping_action_seconds() {
+ if ($this->validated_data["ping_method"] === "ping") {
+ if (isset($this->initial_data['ping_action_seconds'])) {
+ if (is_numericint($this->initial_data['ping_action_seconds']) and ((int) $this->initial_data['ping_action_seconds'] >= 0)) {
+ $this->validated_data["ping_action_seconds"] = $this->initial_data['ping_action_seconds'];
+ } else {
+ $this->errors[] = APIResponse\get(2127);
+ }
+ }
+ # Assume default if none was specified
+ } else {
+ $this->validated_data["ping_action_seconds"] = "60";
+ }
+ }
+
+ private function __validate_ping_push() {
+ if ($this->validated_data["ping_method"] === "ping") {
+ if (($this->initial_data['ping_push'] === true) and ($this->validated_data["ping_push"] === "")) {
+ $this->validated_data["ping_push"] = "yes";
+ } elseif (($this->initial_data['ping_push'] === false) and ($this->validated_data["ping_push"] === "yes")) {
+ $this->validated_data["ping_push"] = "";
+ }
+ # Assume default if none was specified
+ } else {
+ $this->validated_data["ping_push"] = "";
+ }
+ }
+
+ private function __validate_ping_action_push() {
+ if ($this->validated_data["ping_method"] === "ping") {
+ if (($this->initial_data['ping_action_push'] === true) and ($this->validated_data["ping_action_push"] === "")) {
+ $this->validated_data["ping_action_push"] = "yes";
+ } elseif (($this->initial_data['ping_action_push'] === false) and ($this->validated_data["ping_action_push"] === "yes")) {
+ $this->validated_data["ping_action_push"] = "";
+ }
+ # Assume default if none was specified
+ } else {
+ $this->validated_data["ping_action_push"] = "";
+ }
+ }
+
+ private function __validate_ping_action() {
+ # Local variables
+ $key_types = ["ping_exit", "ping_restart"];
+
+ # Validate Ping restart or exit
+ if ($this->validated_data["ping_method"] === "ping") {
+ if (isset($this->initial_data["ping_action"])) {
+ if (in_array($this->initial_data["ping_action"], $key_types)) {
+ $this->validated_data["ping_action"] = $this->initial_data["ping_action"];
+ }
+ else {
+ $this->errors[] = APIResponse\get(2128);
+ }
+ }
+ # Assume default if none was specified
+ } else {
+ $this->validated_data["ping_action"] = "ping_restart";
+ }
+ }
+
+ private function __validate_username_as_cn() {
+ if (($this->initial_data['username_as_common_name'] === true) and ($this->validated_data["username_as_common_name"] === "disabled")) {
+ $this->validated_data["username_as_common_name"] = "enabled";
+ } elseif (($this->initial_data['username_as_common_name'] === false) and ($this->validated_data["username_as_common_name"] === "enabled")) {
+ $this->validated_data["username_as_common_name"] = "disabled";
+ }
+ }
+
+ private function __validate_udp_fast_io() {
+ if (($this->initial_data['udp_fast_io'] === true) and (empty($this->validated_data["udp_fast_io"]))) {
+ $this->validated_data["udp_fast_io"] = "yes";
+ } elseif (($this->initial_data['udp_fast_io'] === false) and (!empty($this->validated_data["udp_fast_io"]))) {
+ unset($this->validated_data["udp_fast_io"]);
+ }
+ }
+
+ private function __validate_exit_notify() {
+ # Local variables
+ $key_types = ["once", "twice", "none", ""];
+
+ # Validate Exit Notify
+ if (isset($this->initial_data["exit_notify"])) {
+ if (in_array($this->initial_data["exit_notify"], $key_types)) {
+ switch ($this->initial_data["exit_notify"]) {
+ case "none":
+ $this->validated_data["exit_notify"] = "none";
+ break;
+ case "":
+ $this->validated_data["exit_notify"] = "none";
+ break;
+ case "once":
+ $this->validated_data["exit_notify"] = "1";
+ break;
+ case "twice":
+ $this->validated_data["exit_notify"] = "2";
+ break;
+ }
+ } else {
+ $this->errors[] = APIResponse\get(2129);
+ }
+ }
+ }
+
+ private function __validate_snd_rcv_buf() {
+ # Local variables
+ $key_types = ["64KiB", "128KiB", "256KiB", "512KiB", "1MiB", "2MiB", "default"];
+
+ # Validate Send/Receive Buffer
+ if (isset($this->initial_data["sndrcvbuf"])) {
+ if (in_array($this->initial_data["sndrcvbuf"], $key_types)) {
+ switch ($this->initial_data["sndrcvbuf"]) {
+ case "64KiB":
+ $this->validated_data["sndrcvbuf"] = "65536";
+ break;
+ case "128KiB":
+ $this->validated_data["sndrcvbuf"] = "131072";
+ break;
+ case "256KiB":
+ $this->validated_data["sndrcvbuf"] = "262144";
+ break;
+ case "512KiB":
+ $this->validated_data["sndrcvbuf"] = "524288";
+ break;
+ case "1MiB":
+ $this->validated_data["sndrcvbuf"] = "1048576";
+ break;
+ case "2MiB":
+ $this->validated_data["sndrcvbuf"] = "2097152";
+ break;
+ case "default":
+ $this->validated_data["sndrcvbuf"] = "";
+ break;
+ }
+ } else {
+ $this->errors[] = APIResponse\get(2130);
+ }
+ }
+ }
+
+ private function __validate_push_register_dns() {
+ if (($this->initial_data['push_register_dns'] === true) and (empty($this->validated_data["push_register_dns"]))) {
+ $this->validated_data["push_register_dns"] = "yes";
+ } elseif (($this->initial_data['push_register_dns'] === false) and (!empty($this->validated_data["push_register_dns"]))) {
+ unset($this->validated_data["push_register_dns"]);
+ }
+ }
+
+ private function __validate_ntp_servers() {
+ if (isset($this->initial_data['ntp_servers'])) {
+ $ntp_servers = explode(',', $this->initial_data['ntp_servers']);
+ $counter = 1;
+ foreach ($ntp_servers as $server) {
+ if ($counter > 2) {
+ break;
+ } elseif (is_ipaddrv4(str_replace(" ", "", $server))) {
+ $this->validated_data["ntp_server" . $counter] = str_replace(" ", "", $server);
+ $counter += 1;
+ } else {
+ $this->errors[] = APIResponse\get(2149);
+ }
+ }
+ }
+ }
+
+ private function __validate_netbios_enable() {
+ if (($this->initial_data['netbios_enable'] === true) and ($this->validated_data["netbios_enable"] === "")) {
+ $this->validated_data["netbios_enable"] = "yes";
+ } elseif (($this->initial_data['netbios_enable'] === false) and ($this->validated_data["netbios_enable"] === "yes")) {
+ $this->validated_data["netbios_enable"] = "";
+ }
+ }
+
+ private function __validate_netbios_ntype() {
+ if (isset($this->initial_data['netbios_node_type'])) {
+ if ($this->initial_data['netbios_node_type'] == 'b') {
+ $this->validated_data["netbios_ntype"] = "1";
+ } else if ($this->initial_data['netbios_node_type'] == 'p') {
+ $this->validated_data["netbios_ntype"] = "2";
+ } else if ($this->initial_data['netbios_node_type'] == 'm') {
+ $this->validated_data["netbios_ntype"] = "3";
+ } else if ($this->initial_data['netbios_node_type'] == 'h') {
+ $this->validated_data["netbios_ntype"] = "4";
+ } else {
+ $this->errors[] = APIResponse\get(2076);
+ }
+ }
+ }
+
+ private function __validate_netbios_scope() {
+ if (isset($this->initial_data['netbios_scope'])) {
+ $this->validated_data["netbios_scope"] = $this->initial_data['netbios_scope'];
+ }
+ }
+
+ private function __validate_create_gw() {
+ # Local variables
+ $key_types = ["both", "v4only", "v6only"];
+
+ # Validate Gateway creation
+ if (isset($this->initial_data["create_gw"])) {
+ if (in_array(strtolower($this->initial_data["create_gw"]), $key_types)) {
+ switch ($this->initial_data["create_gw"]) {
+ case "both":
+ $this->validated_data["create_gw"] = strtolower($this->initial_data["create_gw"]);
+ break;
+ case "v4only":
+ $this->validated_data["create_gw"] = strtolower($this->initial_data["create_gw"]);
+ break;
+ case "v6only":
+ $this->validated_data["create_gw"] = strtolower($this->initial_data["create_gw"]);
+ break;
+ }
+ } else {
+ $this->errors[] = APIResponse\get(2131);
+ }
+ }
+ }
+
+ private function __validate_verbosity_level() {
+ if (isset($this->initial_data['verbosity_level'])) {
+ if (is_numericint($this->initial_data['verbosity_level']) and ((int) $this->initial_data['verbosity_level'] >= 2) and ((int) $this->initial_data['verbosity_level'] < 13)) {
+ $this->validated_data["verbosity_level"] = $this->initial_data["verbosity_level"];
+ } elseif ($this->initial_data['verbosity_level'] == "none") {
+ $this->validated_data["verbosity_level"] = "0";
+ } elseif ($this->initial_data['verbosity_level'] == "default") {
+ $this->validated_data["verbosity_level"] = "1";
+ } else {
+ $this->errors[] = APIResponse\get(2132);
+ }
+ }
+ }
+
+ private function __validate_wins_servers() {
+ if (isset($this->initial_data['wins_servers'])) {
+ $win_servers = explode(',', $this->initial_data['wins_servers']);
+ $counter = 1;
+ foreach ($win_servers as $server) {
+ if ($counter > 2) {
+ break;
+ } elseif (is_ipaddrv4(str_replace(" ", "", $server))) {
+ $this->validated_data["wins_server" . $counter] = str_replace(" ", "", $server);
+ $counter += 1;
+ } else {
+ $this->errors[] = APIResponse\get(2151);
+ }
+ }
+ }
+ }
+
+ // TODO: Validate nbdd servers is not yet available
+ private function __validate_nbdd_server() {
+ if (isset($this->validated_data['wins_servers' . '1']) and ($this->validated_data["netbios_enable"] = "yes")) {
+ $this->validated_data["nbdd_server1"] = "";
+ } else {
+ unset($this->validated_data["nbdd_server1"]);
+ }
+ }
+
+ private function __validate_disabled() {
+ # Check for our optional `disabled` payload value
+ if (($this->initial_data["disable"] === true) and (empty($this->validated_data["disable"]))) {
+ $this->validated_data["disable"] = "";
+ } elseif (($this->initial_data["disable"] === false) and (!empty($this->validated_data["disable"]))) {
+ unset($this->validated_data["disable"]);
+ }
+ }
+
+ public function validate_payload() {
+ # Run each validation method
+ $this->__validate_description();
+ $this->__validate_disabled();
+ $this->__validate_vpnid();
+ $this->__validate_mode();
+ $this->__validate_dev_mode();
+ $this->__validate_protocol();
+ $this->__validate_interface();
+ $this->__validate_local_port();
+ $this->__validate_ncp_enable();
+ $this->__validate_data_ciphers();
+ $this->__validate_data_ciphers_fallback();
+ $this->__validate_engine();
+ $this->__validate_digest();
+ $this->__validate_tunnel_network();
+ $this->__validate_tunnel_networkv6();
+ $this->__validate_concurrent_connections();
+ $this->__validate_allow_compression();
+ $this->__validate_compression();
+ $this->__validate_type_of_service();
+ $this->__validate_ping_method();
+ $this->__validate_keepalive_interval();
+ $this->__validate_keepalive_timeout();
+ $this->__validate_ping_seconds();
+ $this->__validate_ping_action_seconds();
+ $this->__validate_ping_push();
+ $this->__validate_ping_action_push();
+ $this->__validate_ping_action();
+ $this->__validate_custom_options();
+ $this->__validate_udp_fast_io();
+ $this->__validate_snd_rcv_buf();
+ $this->__validate_create_gw();
+ $this->__validate_verbosity_level();
+
+ # Run each validation method for ["p2p_tls", "server_tls", "server_user", "server_tls_user"]
+ if ($this->validated_data["mode"] !== "p2p_shared_key") {
+ $this->__validate_tls();
+ $this->__validate_tls_type();
+ $this->__validate_tls_keydir();
+ $this->__validate_caref();
+ $this->__validate_crlref();
+ $this->__validate_ocspcheck();
+ $this->__validate_ocspurl();
+ $this->__validate_certref();
+ $this->__validate_dh_length();
+ $this->__validate_ecdh_curve();
+ $this->__validate_cert_depth();
+ $this->__validate_redirect_gateway();
+ $this->__validate_redirect_gateway6();
+ $this->__validate_local_network();
+ $this->__validate_local_networkv6();
+ $this->__validate_compression_push();
+ $this->__validate_inter_client_communication();
+ $this->__validate_duplicate_connection();
+ $this->__validate_dynamic_ip();
+ $this->__validate_topology();
+ $this->__validate_inactive_seconds();
+ $this->__validate_exit_notify();
+
+ if (isset($this->validated_data["shared_key"])) {
+ unset($this->validated_data["shared_key"]);
+ }
+ }
+
+ # Run each validation method for ["p2p_tls", "p2p_shared_key"]
+ if (($this->validated_data["mode"] === "p2p_tls") or ($this->validated_data["mode"] === "p2p_shared_key")) {
+ $this->__validate_remote_network();
+ $this->__validate_remote_networkv6();
+
+ $this->validated_data["serverbridge_dhcp"] = "";
+ $this->validated_data["serverbridge_interface"] = "none";
+ $this->validated_data["serverbridge_routegateway"] = "";
+ $this->validated_data["serverbridge_dhcp_start"] = "";
+ $this->validated_data["serverbridge_dhcp_end"] = "";
+ $this->validated_data["netbios_enable"] = "";
+ $this->validated_data["netbios_ntype"] = "0";
+ $this->validated_data["netbios_scope"] = "";
+
+ if (isset($this->validated_data["dns_domain"])) {
+ unset($this->validated_data["dns_domain"]);
+ }
+
+ for ($i=1; $i < 5; $i++) {
+ if (isset($this->validated_data["dns_server" . $i])) {
+ unset($this->validated_data["dns_server" . $i]);
+ }
+ }
+
+ for ($i=1; $i < 3; $i++) {
+ if (isset($this->validated_data["ntp_server" . $i])) {
+ unset($this->validated_data["ntp_server" . $i]);
+ }
+ }
+
+ for ($i=1; $i < 3; $i++) {
+ if (isset($this->validated_data["wins_server" . $i])) {
+ unset($this->validated_data["wins_server" . $i]);
+ }
+ }
+
+ if (isset($this->validated_data["push_blockoutsidedns"])) {
+ unset($this->validated_data["push_blockoutsidedns"]);
+ }
+
+ if (isset($this->validated_data["push_register_dns"])) {
+ unset($this->validated_data["push_register_dns"]);
+ }
+ }
+
+ # Run each validation method for ["server_tls", "server_user", "server_tls_user"]
+ if (($this->validated_data["mode"] !== "p2p_tls") and ($this->validated_data["mode"] !== "p2p_shared_key")) {
+ $this->__validate_dns_domain();
+ $this->__validate_dns_servers();
+ $this->__validate_push_blockout_side_dns();
+ $this->__validate_push_register_dns();
+ $this->__validate_ntp_servers();
+ $this->__validate_netbios_enable();
+ $this->__validate_netbios_ntype();
+ $this->__validate_netbios_scope();
+ $this->__validate_wins_servers();
+ $this->__validate_nbdd_server();
+ $this->__validate_serverbridge_dhcp();
+ $this->__validate_serverbridge_interface();
+ $this->__validate_serverbridge_routegateway();
+ $this->__validate_serverbridge_dhcp_start();
+ $this->__validate_serverbridge_dhcp_end();
+
+ $this->validated_data["remote_network"] = "";
+ $this->validated_data["remote_networkv6"] = "";
+ }
+
+ # Run each validation method for ["p2p_tls", "p2p_shared_key", "server_tls"]
+ if (($this->validate_data["mode"] !== "server_user") and ($this->validated_data["mode"] !== "server_tls_user")) {
+ $this->validated_data["username_as_common_name"] = "disabled";
+
+ if (isset($this->validated_data["authmode"])) {
+ unset($this->validated_data["authmode"]);
+ }
+ }
+
+ # Run each validation method for ["server_user", "server_tls_user"]
+ if (($this->validate_data["mode"] === "server_user") or ($this->validated_data["mode"] === "server_tls_user")) {
+ $this->__validate_authmode();
+ $this->__validate_username_as_cn();
+ }
+
+ if ($this->validated_data['mode'] !== 'server_tls_user') {
+ unset($this->validated_data["strictusercn"]);
+ }
+
+ # Run each validation method for ["p2p_tls"]
+ if ($this->validated_data["mode"] === "p2p_tls") {
+ }
+
+ # Run each validation method for ["p2p_shared_key"]
+ if ($this->validated_data["mode"] === "p2p_shared_key") {
+ $this->__validate_shared_key();
+
+ $this->validated_data["gwredir"] = "";
+ $this->validated_data["gwredir6"] = "";
+ $this->validated_data["local_network"] = "";
+ $this->validated_data["local_networkv6"] = "";
+ $this->validated_data["compression_push"] = "";
+ $this->validated_data["client2client"] = "";
+ $this->validated_data["topology"] = "subnet";
+ $this->validated_data["dynamic_ip"] = "";
+ $this->validated_data["exit_notify"] = "1";
+ $this->validated_data["inactive_seconds"] = "300";
+
+ if (isset($this->validated_data["tls"])) {
+ unset($this->validated_data["tls"]);
+ }
+
+ if (isset($this->validated_data["tls_type"])) {
+ unset($this->validated_data["tls_type"]);
+ }
+
+ if (isset($this->validated_data["tlsauth_keydir"])) {
+ unset($this->validated_data["tlsauth_keydir"]);
+ }
+
+ if (isset($this->validated_data["caref"])) {
+ unset($this->validated_data["caref"]);
+ }
+
+ if (isset($this->validated_data["certref"])) {
+ unset($this->validated_data["certref"]);
+ }
+
+ if (isset($this->validated_data["crlref"])) {
+ unset($this->validated_data["crlref"]);
+ }
+
+ if (isset($this->validated_data["cert_depth"])) {
+ unset($this->validated_data["cert_depth"]);
+ }
+
+ if (isset($this->validated_data["ocspcheck"])) {
+ unset($this->validated_data["ocspcheck"]);
+ }
+
+ if (isset($this->validated_data["ocspurl"])) {
+ unset($this->validated_data["ocspurl"]);
+ }
+
+ if (isset($this->validated_data["dh_length"])) {
+ unset($this->validated_data["dh_length"]);
+ }
+
+ if (isset($this->validated_data["ecdh_curve"])) {
+ unset($this->validated_data["ecdh_curve"]);
+ }
+
+ if (isset($this->validated_data["duplicate_cn"])) {
+ unset($this->validated_data["duplicate_cn"]);
+ }
+ }
+
+ # Run each validation method for ["server_tls"]
+ if ($this->validated_data["mode"] === "server_tls") {
+ }
+
+ # Run each validation method for ["server_user"]
+ if ($this->validate_data["mode"] === "server_user") {
+ }
+
+ # Run each validation method for ["server_tls_user"]
+ if ($this->validated_data["mode"] === "server_tls_user") {
+ $this->__validate_strick_user_cn();
+ }
+ }
+
+ private function __init_config() {
+ # Ensure the OpenVPN configuration array exists
+ if (empty($this->config["openvpn"])) {
+ $this->config["openvpn"] = [];
+ }
+
+ # Ensure the OpenVPN server configuration array exists
+ if (empty($this->config['openvpn']['openvpn-server'])) {
+ $this->config['openvpn']['openvpn-server'] = [];
+ }
+ }
+}
diff --git a/pfSense-pkg-API/files/usr/local/www/api/documentation/openapi.yml b/pfSense-pkg-API/files/usr/local/www/api/documentation/openapi.yml
index 9ca90087b..cf0785a09 100644
--- a/pfSense-pkg-API/files/usr/local/www/api/documentation/openapi.yml
+++ b/pfSense-pkg-API/files/usr/local/www/api/documentation/openapi.yml
@@ -6535,6 +6535,1515 @@ paths:
summary: Add NTP (ntpd) time server
tags:
- Services > NTPD > Time Server
+ /api/v1/services/openvpn/server:
+ delete:
+ description: 'Delete OpenVPN Server instance.
+
+ _Requires at least one of the following privileges:_ [`page-all`, `page-openvpn-server`]'
+ parameters:
+ - description: This id indicates the id of the server you want to delete.
+ This id is static and not an index of an entry in the config array.
+ Best to first get all servers and get the id of the one you want to
+ delete before calling this endpoint.
+ in: query
+ name: vpnid
+ required: true
+ schema:
+ oneOf:
+ - type: integer
+ - type: string
+ requestBody:
+ content:
+ application/json:
+ schema:
+ properties:
+ vpnid:
+ description: This id indicates the id of the server you want to delete.
+ This id is static and not an index of an entry in the config array.
+ Best to first get all servers and get the id of the one you want to
+ delete before calling this endpoint.
+ oneOf:
+ - type: integer
+ - type: string
+ example: "1"
+ required:
+ - vpnid
+ type: object
+ responses:
+ 200:
+ $ref: '#/components/responses/Success'
+ 401:
+ $ref: '#/components/responses/AuthenticationFailed'
+ summary: Delete OpenVPN Server
+ tags:
+ - Services > OpenVPN > Server
+ get:
+ description: 'Read All OpenVPN Server instances.
+
+ _Requires at least one of the following privileges:_ [`page-all`, `page-openvpn-server`]'
+ responses:
+ 200:
+ $ref: '#/components/responses/Success'
+ 401:
+ $ref: '#/components/responses/AuthenticationFailed'
+ summary: Read OpenVPN Server
+ tags:
+ - Services > OpenVPN > Server
+ post:
+ description: 'Create OpenVPN Server instance.
+
+ _Requires at least one of the following privileges:_ [`page-all`, `page-openvpn-server`]'
+ requestBody:
+ content:
+ application/json:
+ schema:
+ properties:
+ mode:
+ default: 'p2p_tls'
+ description: The role for the server, which specifies how peers connect to a
+ server instance. Changing this also affects which options the
+ GUI displays on the rest of the page.
+ enum:
+ - p2p_tls
+ - p2p_shared_key
+ - server_tls
+ - server_user
+ - server_tls_user
+ type: string
+ protocol:
+ default: 'udp4'
+ description: The IP protocol clients will use to connect to this VPN.
+ enum:
+ - udp4
+ - udp6
+ - tcp4
+ - tcp6
+ - udp
+ - tcp
+ type: string
+ authmode:
+ default: 'Local Database'
+ description: One or more authentication servers to use when checking user credentials.
+ This can be the Local Database (user manager) or it can be a RADIUS or LDAP server
+ configured in the user manager.
+
+ Selecting multiple entries will use each one in turn. If authentication against an entry fails,
+ the VPN will try the next server. It will continue this process until it has tried
+ all selected entries.
+
+ This field is only present when using a Server Mode (`server_user` or `server_tls_user`)
+ which requires user authentication.
+ type: string
+ dev_mode:
+ default: 'tun'
+ description: OpenVPN can run in one of two device modes.
+ enum:
+ - tun
+ - tap
+ type: string
+ interface:
+ default: 'wan'
+ description: 'Selects the interface, VIP, or failover group that the OpenVPN instance will use
+ when communicating with peers.
+ This also controls which interface the traffic from the instance will exit.
+ Interface can be provided as Interface ID (e.g. `wan`, `lan`, `opt1`, etc.),
+ Interface physical name (e.g. `igb0`, `vtnet`, etc.) or Interface descriptive
+ name (e.g. `MY_LAN`, `MY_WAN`, etc.).
+ VIP can be provided as description, subnet or uniqid.
+ Failover group can be provided as group name.
+
+ _Note: If you are using a failover group, the failover group must be configured to use the same_.'
+ type: string
+ local_port:
+ description: The port number upon which OpenVPN will listen for incoming connections from peers.
+ Firewall rules must allow traffic to this port and this port must be specified in the client configuration.
+
+ The port for each server must be unique for each interface when using a standard
+ UDP or TCP Protocol choice and must be globally unique if using a multihome Protocol.
+
+ Omitting this will default to next available port.
+ type: integer
+ example: 1194
+ description:
+ description: Enter a description for this VPN instance, for reference.
+ type: string
+ example: 'My VPN'
+ custom_options:
+ description: Custom options may be added in using the Custom option box separated by a semicolon (;)
+ and the firewall will pass the custom directives to OpenVPN.
+ type: string
+ example: 'push "route 10.0.0.0 255.255.255.0";'
+ tls:
+ default: ''
+ description: TLS, or Transport Layer Security, can provide session
+ authentication and encryption to ensure the validity of peers and to protect the control channel.
+ Paste the TLS key. This is not necessary for mode `p2p_shared_key`.
+ Options are `""` or `true` for automatic TLS key generation, `false` to disable TLS
+ or a raw TLS key as a string.
+ Omitting disable TLS configuration.
+ type: string
+ example: '-----BEGIN OpenVPN Static key V1-----
+ db8701afd882d746be67f084bae68470
+ 54a99ef3b61864cfe1864c6c02584335
+ fe706df150250bf7e294b8c35911817c
+ 133c8d9b505573ebeb65259bc54c70ae
+ 88cc3163fd11a20f73d2c6fb3eea7cc2
+ fdaefcde510486adc0acbb9481b3aef4
+ 930db91806469218b2a4f92e71787cf4
+ 635f5b3f773fefc28d492738d2648673
+ 8fa9b23d41e5999f58c3f0004a59ecda
+ 119162e598764d9c8f6b99e7054f3ea4
+ fdb4461913d2e3273a8a0db29332406a
+ 237bcfccca2315445ef809eaa933fa30
+ a9a7510d2d167033edfd3580a824f3e1
+ 1af57da6eee89e6318ec29c67da8a19d
+ 7c9d74c7afac6ee0f813a0278a6261d7
+ a28e7bdbf1743527346bda359bc92fc9
+ -----END OpenVPN Static key V1-----'
+ tls_type:
+ default: 'auth'
+ description: Enter TLS Key Usage Mode. This is not necessary for mode `p2p_shared_key`.
+ enum:
+ - auth
+ - crypt
+ type: string
+ tlsauth_keydir:
+ default: 'default'
+ description: The direction in which this VPN endpoint uses the TLS key.
+ The TLS Key Direction must be set to complementary values on the server and clients.
+ The default behavior uses 0 on server instances and 1 on client instances.
+
+ Enter TLS keydir direction. This is not necessary for mode `p2p_shared_key`.
+ enum:
+ - default
+ - direction-0
+ - direction-1
+ - both-directions
+ type: string
+ shared_key:
+ default: ''
+ description: Enter Shared Key. This is only mandatory for mode `p2p_shared_key`.
+ Options are `""` for automatic shared key generation and a raw shared key.
+ type: string
+ example: '-----BEGIN OpenVPN Static key V1-----
+ db8701afd882d746be67f084bae68470
+ 54a99ef3b61864cfe1864c6c02584335
+ fe706df150250bf7e294b8c35911817c
+ 133c8d9b505573ebeb65259bc54c70ae
+ 88cc3163fd11a20f73d2c6fb3eea7cc2
+ fdaefcde510486adc0acbb9481b3aef4
+ 930db91806469218b2a4f92e71787cf4
+ 635f5b3f773fefc28d492738d2648673
+ 8fa9b23d41e5999f58c3f0004a59ecda
+ 119162e598764d9c8f6b99e7054f3ea4
+ fdb4461913d2e3273a8a0db29332406a
+ 237bcfccca2315445ef809eaa933fa30
+ a9a7510d2d167033edfd3580a824f3e1
+ 1af57da6eee89e6318ec29c67da8a19d
+ 7c9d74c7afac6ee0f813a0278a6261d7
+ a28e7bdbf1743527346bda359bc92fc9
+ -----END OpenVPN Static key V1-----'
+ caref:
+ description: Specify the unique reference ID of the certificate signing authority.
+ type: string
+ example: 61c7fbce3a351
+ crlref:
+ default: 'none'
+ description: This optional field is for the Certificate Revocation List (CRL)
+ this tunnel will use to check the validity of peer certificates.
+
+ A CRL is a list of certificates signed by a CA which are no longer valid.
+ This could be due to a certificate being compromised or lost, such as from
+ a stolen laptop, spyware infection, etc.
+
+ Specify the unique reference ID of the certificate.
+ type: string
+ example: 61c467cd2fd4f
+ certref:
+ description: The certificate used by the VPN instance to identify itself to peers.
+ This certificate must contain appropriate properties marking it as a server
+ certificate and not a user or client certificate.
+
+ Specify the unique reference ID of the certificate revocation list.
+ type: string
+ example: 61c4121240420
+ ocspcheck:
+ default: false
+ description: When set, OpenVPN will attempt to confirm client certificate validity
+ using Online Certificate Status Protocol (OCSP) against the site listed in the OCSP URL field.
+ type: boolean
+ ocspurl:
+ default: ''
+ description: Enter OCSP URL. This is only necessary for `ocspcheck`.
+ type: string
+ format: uri
+ dh_length:
+ default: '2048'
+ description: The Diffie-Hellman (DH) key exchange parameters are used for establishing a
+ secure communications channel. They may be regenerated at any time, and they are not
+ specific to an OpenVPN instance. When importing an existing OpenVPN configuration
+ these parameters do not need to be copied from the previous server nor does it require
+ generating new parameters. The length of the desired DH parameters may be chosen from
+ the drop-down box, either 1024, 2048, or 4096. There is an additional choice for
+ ECDH Only which disables traditional DH parameters and uses only ECDH.
+ enum:
+ - 1024
+ - 2048
+ - 3072
+ - 4096
+ - 6144
+ - 7680
+ - 8192
+ - 15360
+ - 16384
+ - 'ECDH Only'
+ type: string
+ ecdh_curve:
+ default: 'none'
+ description: Configures a specific elliptic curve to use for Elliptic Curve Diffie-Hellman
+ key exchanges. This is only for use with ECDH TLS encryption.
+ enum:
+ - none
+ - prime256v1
+ - secp384r1
+ - secp521r1
+ type: string
+ cert_depth:
+ default: 'one'
+ description: This option limits the valid length of a certificate chain. The default value
+ limits a chain to One (Client+Server). With that value, if an unauthorized intermediate
+ CA signs a certificate, certificates signed by the rogue intermediate would fail validation.
+ In cases when the certificate stricture requires chaining with intermediates,
+ raise this limit to accommodate the longest allowed chain.
+ enum:
+ - none
+ - one
+ - two
+ - three
+ - four
+ - five
+ type: string
+ strictusercn:
+ default: false
+ description: Controls whether the firewall will enforce a strict match between the username
+ supplied by the user and the Common Name of their user certificate when the firewall
+ authenticates a user. When enabled, authentication fails if the two values do not match.
+
+ This prevents users from using their own credentials with the certificate from a different
+ user and vice versa.
+
+ This is only necessary for mode `server_tls_user`.
+ Omitting will disable.
+ type: boolean
+ ncp_enable:
+ default: false
+ description: Enable Data Encryption Negotiation.
+ Disabling this feature is deprecated.
+ Omitting will enable.
+ type: boolean
+ data_ciphers:
+ default: 'AES-256-GCM,AES-128-GCM,CHACHA20-POLY1305'
+ description: These options define the cryptographic ciphers OpenVPN will use for this VPN.
+ Enter comma sepereted data encryption algorithms
+ (e.g. `AES-256-GCM,AES-128-GCM,CHACHA20-POLY1305`).
+ Data encryption algorithms will be truncated to 19.
+ type: string
+ data_ciphers_fallback:
+ default: 'AES-256-CBC'
+ description: Enter fallback data encryption algorithm.
+ type: string
+ digest:
+ default: 'SHA256'
+ description: Selects the message digest algorithm OpenVPN uses for HMAC authentication of
+ incoming packets. This is used for the data channel and if also for the control channel
+ when the tunnel uses a TLS key. The GUI default of SHA256 is a good balance of security and speed.
+
+ When using AEAD ciphers such as AES-GCM, OpenVPN ignores this value for the data channel
+ since AEAD ciphers already perform authentication. Even with an AEAD cipher, OpenVPN still
+ uses this algorithm to authenticate the control channel when the tunnel uses a TLS key.
+ enum:
+ - BLAKE2b512
+ - BLAKE2b256
+ - MD4
+ - MD5
+ - MD5-SHA1
+ - MDC2
+ - RIPEMD160
+ - SHA1
+ - SHA224
+ - SHA256
+ - SHA3-224
+ - SHA3-256
+ - SHA3-384
+ - SHA3-512
+ - SHA384
+ - SHA512
+ - SHA512-224
+ - SHA512-256
+ - SHAKE128
+ - SHAKE256
+ - SM3
+ - whirlpool
+ - none
+ type: string
+ engine:
+ default: 'none'
+ description: If available, this option controls which hardware cryptographic accelerator
+ will be used by OpenVPN. When left unspecified, OpenVPN will choose automatically based
+ on what is available in the operating system to accelerate ciphers OpenVPN wants to use.
+
+ Some hardware acceleration, such as AES-NI, happens automatically in OpenVPN via OpenSSL
+ and cannot be enabled or disabled by this option.
+
+ Enter Hardware crypto. Options are `none` and any enabled
+ hardware crypto.
+ type: string
+ tunnel_network:
+ default: ''
+ description: 'Virtual IPv4 network used for private communications
+ between this client and the server expressed using CIDR (e.g.
+ 10.0.8.5/24).
+
+ With subnet topology, enter the client IP address and the subnet
+ mask must match the IPv4 Tunnel Network on the server.
+
+ With net30 topology, the first network address of the /30 is assumed
+ to be the server address and the second network address will be
+ assigned to the client.'
+ type: string
+ tunnel_networkv6:
+ default: ''
+ description: 'Virtual IPv6 network used for private communications
+ between this client and the server expressed using prefix (e.g.
+ 2001:db9:1:1::100/64).
+
+ Enter the client IPv6 address and prefix. The prefix must match
+ the IPv6 Tunnel Network prefix on the server.'
+ type: string
+ local_network:
+ default: ''
+ description: 'IPv4 server-side networks that will be accessible
+ from this particular client. Expressed as a comma-separated list
+ of one or more CIDR networks.
+
+ NOTE: Networks do not need to be specified here if they have already
+ been defined on the main server configuration.'
+ type: string
+ local_networkv6:
+ default: ''
+ description: 'IPv6 server-side networks that will be accessible
+ from this particular client. Expressed as a comma-separated list
+ of one or more IP/PREFIX networks.
+
+ NOTE: Networks do not need to be specified here if they have already
+ been defined on the main server configuration.'
+ type: string
+ remote_network:
+ default: ''
+ description: 'IPv4 client-side networks that will be routed to this
+ client specifically using iroute, so that a site-to-site VPN can
+ be established. Expressed as a comma-separated list of one or
+ more CIDR ranges. May be left blank if there are no client-side
+ networks to be routed.
+
+ NOTE: Remember to add these subnets to the IPv4 Remote Networks
+ list on the corresponding OpenVPN server settings.'
+ type: string
+ remote_networkv6:
+ default: ''
+ description: 'IPv6 client-side networks that will be routed to this
+ client specifically using iroute, so that a site-to-site VPN can
+ be established. Expressed as a comma-separated list of one or
+ more IP/PREFIX networks. May be left blank if there are no client-side
+ networks to be routed.
+
+ NOTE: Remember to add these subnets to the IPv6 Remote Networks
+ list on the corresponding OpenVPN server settings.'
+ type: string
+ redirect_gateway:
+ default: false
+ description: When a Redirect IPv4 Gateway option is selected the server
+ pushes a message to clients instructing them to forward all traffic for
+ that address family, including Internet traffic, over the VPN tunnel.
+ type: boolean
+ redirect_gateway6:
+ default: false
+ description: When a Redirect IPv6 Gateway option is selected the server
+ pushes a message to clients instructing them to forward all traffic for
+ that address family, including Internet traffic, over the VPN tunnel.
+ type: boolean
+ serverbridge_dhcp:
+ default: ""
+ description: When using `tap` mode for a remote access SSL/TLS VPN,
+ (`server_tls`, `server_user`, `server_tls_user`), additional options
+ to control bridging behavior in OpenVPN and client address assignment.
+
+ When selected, OpenVPN passes through DHCP to the bridged.
+ In the most common scenario, this is LAN.
+
+ Using this method connecting clients receive IP addresses from the
+ same DHCP pool used by clients on the LAN.
+ type: string
+ format: ipv4
+ serverbridge_interface:
+ default: "none"
+ description: This setting indicates to OpenVPN which interface will be used for the bridge.
+ In most cases this is LAN.
+ This option controls which existing IP address and subnet mask are used by OpenVPN for the bridge.
+ Setting this to none will cause the Server Bridge DHCP (`serverbridge_dhcp_start`, `serverbridge_dhcp_end`) settings below to be ignored.
+ enum:
+ - wan
+ - lan
+ - none
+ type: string
+ serverbridge_routegateway:
+ description: Makes OpenVPN push the Bridge Interface IPv4 address to connecting
+ clients as a route gateway.
+
+ When the IPv4 Tunnel Network in OpenVPN is empty for a bridged VPN,
+ connecting clients cannot automatically determine a server-side gateway for
+ use with routes pushed to clients by the server.
+ type: boolean
+ example: true
+ serverbridge_dhcp_start:
+ default: ""
+ description: Defines a DHCP range from which OpenVPN can assign addresses to clients.
+ If these settings are left blank, OpenVPN passes DHCP through to the bridge interface
+ and it ignores the interface setting above.
+
+ When set, this range should be within the same subnet as the Bridge Interface
+ (`serverbridge_interface`) but it should not overlap an existing in-use portion
+ of the subnet, such as the current DHCP pool.
+
+ This allows a range of IP addresses to be set aside for use only by OpenVPN clients so they may be contained within a portion of the internal network rather than consuming IP addresses from the existing DHCP pool.
+ type: string
+ format: ipv4
+ serverbridge_dhcp_end:
+ default: ""
+ description: Defines a DHCP range from which OpenVPN can assign addresses to clients.
+ If these settings are left blank, OpenVPN passes DHCP through to the bridge interface
+ and it ignores the interface setting above.
+
+ When set, this range should be within the same subnet as the Bridge Interface
+ (`serverbridge_interface`) but it should not overlap an existing in-use portion
+ of the subnet, such as the current DHCP pool.
+
+ This allows a range of IP addresses to be set aside for use only by OpenVPN clients so they may be contained within a portion of the internal network rather than consuming IP addresses from the existing DHCP pool.
+ type: string
+ format: ipv4
+ concurrent_connections:
+ description: Specifies the number of clients that may be simultaneously
+ connected to this OpenVPN server instance at any given time.
+ type: integer
+ example: '10'
+ allow_compression:
+ default: 'no'
+ description: Controls whether or not compression is allowed on the VPN, and how it is handled.
+ enum:
+ - asym
+ - no
+ - yes
+ type: string
+ compression:
+ default: 'none'
+ description: Compression to be used with this VPN instance. This is only
+ necessary for `allow_compression` set to `yes` or `asym`.
+ Compression can potentially dangerous and insecure. Deprecated.
+ Compress tunnel packets using the LZO algorithm.
+ enum:
+ - none
+ - stub
+ - stub-v2
+ - lz4
+ - lz4-v2
+ - lzo
+ - noadapt
+ - adaptive
+ - yes
+ - no
+ type: string
+ compression_push:
+ default: false
+ description: Push the selected Compression setting to connecting clients.
+ This is only necessary for `allow_compression` set to `yes` or `asym`.
+ type: boolean
+ passtos:
+ default: false
+ description: When this option is enabled OpenVPN sets the Type-of-Service (TOS)
+ IP header value of tunnel packets to match the encapsulated packet value.
+ This may cause important traffic to be handled faster over the tunnel by
+ intermediate hops at the cost of minor information disclosure.
+ type: boolean
+ client2client:
+ default: false
+ description: This option controls whether or not connected clients are able to
+ communicate with one another. To allow this behavior, check the option.
+ When unchecked, clients can only send traffic to the server or destinations
+ beyond the server such as routed networks or the Internet.
+ type: boolean
+ duplicate_cn:
+ default: false
+ description: Controls whether or not OpenVPN will allow multiple connections
+ from the same user to work simultaneously.
+ This is only necessary for mode `p2p_shared_key`.
+ type: boolean
+ dynamic_ip:
+ default: false
+ description: For clients on Internet connections where the IP address changes frequently,
+ or mobile users who commonly move between different Internet connections,
+ check this option for more stable connectivity. Where the client IP address
+ is static or rarely changes, not using this option offers a small security improvement.
+ type: boolean
+ topology:
+ default: 'subnet'
+ description: Sets the method OpenVPN uses to allocate addresses for clients in a
+ client/server setup on tun device mode VPNs. The Topology option is relevant
+ only when supplying a virtual adapter IP address to clients using tun mode on IPv4.
+ Some clients may require this even for IPv6, such as OpenVPN Connect, though in
+ reality IPv6 always runs with a subnet topology even when IPv4 uses net30.
+ OpenVPN instances using tap mode always use subnet topology as well.
+ enum:
+ - subnet
+ - net30
+ type: string
+ dns_domain:
+ default: ''
+ description: Configures a default domain name which clients will append to DNS requests.
+ This can be helpful to ensure name resolution works properly for hosts on the local
+ network where DNS name resolution is used.
+ type: string
+ example: example.com
+ dns_servers:
+ default: ''
+ description: Comma-separated list of no more than 4 DNS server IP
+ addresses (i.e. 8.8.8.8). Any more than the first four are ignored.
+ This list is provided to the clent.
+ type: string
+ example: "8.8.8.8, 8.8.4.4, 8.8.3.3, 8.8.2.2"
+ push_blockoutsidedns:
+ default: false
+ description: Make Windows 10 Clients Block access to DNS servers except
+ across OpenVPN while connected, forcing clients to use only VPN DNS servers.
+ type: boolean
+ push_register_dns:
+ default: false
+ description: Run "net stop dnscache", "net start dnscache",
+ "ipconfig /flushdns" and "ipconfig /registerdns" on connection initiation.
+ type: boolean
+ inactive_seconds:
+ default: 300
+ description: The amount of time, in seconds, which a client can be inactive before
+ OpenVPN disconnects it for inactivity. OpenVPN bases activity on the last incoming
+ or outgoing data channel packet, not control channel packets.
+
+ `0` disables this feature.
+ type: integer
+ ping_method:
+ default: 'keepalive'
+ description: The Ping Method controls OpenVPN monitoring of peers through the
+ control channel and how it deals with unresponsive peers.
+ enum:
+ - keepalive
+ - ping
+ type: string
+ keepalive_interval:
+ default: 10
+ description: Enter keepalive interval.
+ type: integer
+ keepalive_timeout:
+ default: 60
+ description: Enter keepalive timeout.
+ type: integer
+ ping_seconds:
+ default: 10
+ description: Enter ping seconds. This is only necessary for `ping` method.
+ type: integer
+ ping_action_seconds:
+ default: 60
+ description: Enter ping action seconds. This is only necessary for `ping` method.
+ type: integer
+ ping_push:
+ default: false
+ description: Push ping to VPN client. This is only necessary for `ping` method.
+ type: boolean
+ ping_action_push:
+ default: false
+ description: Push ping-restart/ping-exit to VPN client.
+ This is only necessary for `ping` method.
+ type: boolean
+ ping_action:
+ default: 'ping_restart'
+ description: Exit or restart OpenVPN after timeout from remote.
+ This is only necessary for `ping` method.
+ enum:
+ - ping_restart
+ - ping_exit
+ type: string
+ username_as_common_name:
+ default: false
+ description: Controls whether or not OpenVPN will use the username given by the
+ client in place of the certificate common name (CN) for purposes such as determining
+ Client Specific Overrides. This is only relevant when user authentication is enabled.
+ This is typically the best practice, but not a requirement.
+
+ This is only necessary for mode `server_user` or `server_tls_user`.
+ type: boolean
+ udp_fast_io:
+ default: false
+ description: Controls whether or not OpenVPN will use fast I/O operations with UDP writes
+ to its tun or tap device. This behavior optimizes the packet write event loop,
+ improving CPU efficiency by 5% to 10%. Experimental.
+ type: boolean
+ exit_notify:
+ default: 'none'
+ description: Controls whether or not OpenVPN will send an explicit exit notification to
+ connected UDP clients or peers when restarting or shutting down. This notification
+ allows peers to immediately disconnect rather than wait for a timeout.
+ This is only relevant to UDP modes as TCP natively supports closing connections.
+ enum:
+ - once
+ - twice
+ - none
+ - ''
+ type: string
+ sndrcvbuf:
+ default: 'default'
+ description: Configures a Send and Receive Buffer size for OpenVPN.
+ The default buffer size can be too small in many cases, depending on hardware
+ and network uplink speeds. Finding the best buffer size can take experimentation.
+ To test the best value for a site, start at 512KiB and test higher and lower
+ values until testing results in peak performance.
+ enum:
+ - 64KiB
+ - 128KiB
+ - 256KiB
+ - 512KiB
+ - 1MiB
+ - 2MiB
+ - default
+ - none
+ type: string
+ ntp_servers:
+ default: ''
+ description: Comma-separated list of no more than 2 NTP server IP
+ addresses. Any more than the first two are ignored.
+ type: string
+ example: "192.168.56.101, 192.168.56.102"
+ netbios_enable:
+ default: false
+ description: Enable NetBIOS over TCP/IP. If this option is not set,
+ all NetBIOS-over-TCP/IP options (including WINS) will be disabled.
+ type: boolean
+ netbios_node_type:
+ description: 'Possible options: b (broadcasts), p (point-to-point
+ name queries to a WINS server), m (broadcast then query name server),
+ and h (query name server, then broadcast). This parameter takes
+ a single letter either b, p, m, or h. Any other string will result
+ in this option being set to none.'
+ enum:
+ - b
+ - p
+ - m
+ - h
+ type: string
+ example: b
+ netbios_scope:
+ description: NetBIOS Scope ID provides an extended naming service
+ for NetBIOS over TCP/IP. The NetBIOS scope ID isolates NetBIOS
+ traffic on a single network to only those nodes with the same
+ NetBIOS scope ID.
+ type: string
+ example: '5'
+ create_gw:
+ default: 'both'
+ description: If you assign a virtual interface to this OpenVPN server,
+ this setting controls which gateway types will be created.
+ enum:
+ - v4only
+ - v6only
+ - both
+ type: string
+ verbosity_level:
+ default: '3'
+ description: Configures the amount of detail OpenVPN will log for this instance,
+ which is useful for troubleshooting problems. Higher numbers will result in
+ higher amounts of detail in the log.
+ During normal operation the default selection is ideal.
+ Level `3` is recommended for a good summary of what's happening without
+ being swamped by output. Maximum level `11`.
+ The `default` setting is equivalent to level `1`.
+ enum:
+ - 0
+ - 1
+ - 2
+ - 3
+ - 4
+ - 5
+ - 6
+ - 7
+ - 8
+ - 9
+ - 10
+ - 11
+ - 'default'
+ type: string
+ wins_servers:
+ default: ''
+ description: Comma-separated list of no more than 2 WINS server
+ IP addresses. Any more than the first two are ignored.
+ type: string
+ example: "192.168.56.103, 192.168.56.104"
+ disable:
+ default: false
+ description: Disable this override without removing it.
+ type: boolean
+ type: object
+ responses:
+ 200:
+ $ref: '#/components/responses/Success'
+ 401:
+ $ref: '#/components/responses/AuthenticationFailed'
+ summary: Create OpenVPN Server
+ tags:
+ - Services > OpenVPN > Server
+ put:
+ description: 'Update OpenVPN Server instance.
+
+ _Requires at least one of the following privileges:_ [`page-all`, `page-openvpn-server`]'
+ parameters:
+ - description: This id indicates the id of the server you want to delete.
+ This id is static and not an index of an entry in the config array.
+ Best to first get all servers and get the id of the one you want to
+ delete before calling this endpoint.
+ in: query
+ name: vpnid
+ required: true
+ schema:
+ oneOf:
+ - type: integer
+ - type: string
+ requestBody:
+ content:
+ application/json:
+ schema:
+ properties:
+ vpnid:
+ description: This id indicates the id of the server you want to delete.
+ This id is static and not an index of an entry in the config array.
+ Best to first get all servers and get the id of the one you want to
+ delete before calling this endpoint.
+ type: string
+ example: '1'
+ mode:
+ default: 'p2p_tls'
+ description: The role for the server, which specifies how peers connect to a
+ server instance. Changing this also affects which options the
+ GUI displays on the rest of the page.
+ enum:
+ - p2p_tls
+ - p2p_shared_key
+ - server_tls
+ - server_user
+ - server_tls_user
+ type: string
+ protocol:
+ default: 'udp4'
+ description: The IP protocol clients will use to connect to this VPN.
+ enum:
+ - udp4
+ - udp6
+ - tcp4
+ - tcp6
+ - udp
+ - tcp
+ type: string
+ authmode:
+ default: 'Local Database'
+ description: One or more authentication servers to use when checking user credentials.
+ This can be the Local Database (user manager) or it can be a RADIUS or LDAP server
+ configured in the user manager.
+
+ Selecting multiple entries will use each one in turn. If authentication against an entry fails,
+ the VPN will try the next server. It will continue this process until it has tried
+ all selected entries.
+
+ This field is only present when using a Server Mode (`server_user` or `server_tls_user`)
+ which requires user authentication.
+ type: string
+ dev_mode:
+ default: 'tun'
+ description: OpenVPN can run in one of two device modes.
+ enum:
+ - tun
+ - tap
+ type: string
+ interface:
+ default: 'wan'
+ description: 'Selects the interface, VIP, or failover group that the OpenVPN instance will use
+ when communicating with peers.
+ This also controls which interface the traffic from the instance will exit.
+ Interface can be provided as Interface ID (e.g. `wan`, `lan`, `opt1`, etc.),
+ Interface physical name (e.g. `igb0`, `vtnet`, etc.) or Interface descriptive
+ name (e.g. `MY_LAN`, `MY_WAN`, etc.).
+ VIP can be provided as description, subnet or uniqid.
+ Failover group can be provided as group name.
+
+ _Note: If you are using a failover group, the failover group must be configured to use the same_.'
+ type: string
+ local_port:
+ description: The port number upon which OpenVPN will listen for incoming connections from peers.
+ Firewall rules must allow traffic to this port and this port must be specified in the client configuration.
+
+ The port for each server must be unique for each interface when using a standard
+ UDP or TCP Protocol choice and must be globally unique if using a multihome Protocol.
+
+ Omitting this will default to next available port.
+ type: integer
+ example: 1194
+ description:
+ description: Enter a description for this VPN instance, for reference.
+ type: string
+ example: 'My VPN'
+ custom_options:
+ description: Custom options may be added in using the Custom option box separated by a semicolon (;)
+ and the firewall will pass the custom directives to OpenVPN.
+ type: string
+ example: 'push "route 10.0.0.0 255.255.255.0";'
+ tls:
+ default: ''
+ description: TLS, or Transport Layer Security, can provide session
+ authentication and encryption to ensure the validity of peers and to protect the control channel.
+ Paste the TLS key. This is not necessary for mode `p2p_shared_key`.
+ Options are `""` or `true` for automatic TLS key generation, `false` to disable TLS
+ or a raw TLS key as a string.
+ Omitting disable TLS configuration.
+ type: string
+ example: '-----BEGIN OpenVPN Static key V1-----
+ db8701afd882d746be67f084bae68470
+ 54a99ef3b61864cfe1864c6c02584335
+ fe706df150250bf7e294b8c35911817c
+ 133c8d9b505573ebeb65259bc54c70ae
+ 88cc3163fd11a20f73d2c6fb3eea7cc2
+ fdaefcde510486adc0acbb9481b3aef4
+ 930db91806469218b2a4f92e71787cf4
+ 635f5b3f773fefc28d492738d2648673
+ 8fa9b23d41e5999f58c3f0004a59ecda
+ 119162e598764d9c8f6b99e7054f3ea4
+ fdb4461913d2e3273a8a0db29332406a
+ 237bcfccca2315445ef809eaa933fa30
+ a9a7510d2d167033edfd3580a824f3e1
+ 1af57da6eee89e6318ec29c67da8a19d
+ 7c9d74c7afac6ee0f813a0278a6261d7
+ a28e7bdbf1743527346bda359bc92fc9
+ -----END OpenVPN Static key V1-----'
+ tls_type:
+ default: 'auth'
+ description: Enter TLS Key Usage Mode. This is not necessary for mode `p2p_shared_key`.
+ enum:
+ - auth
+ - crypt
+ type: string
+ tlsauth_keydir:
+ default: 'default'
+ description: The direction in which this VPN endpoint uses the TLS key.
+ The TLS Key Direction must be set to complementary values on the server and clients.
+ The default behavior uses 0 on server instances and 1 on client instances.
+
+ Enter TLS keydir direction. This is not necessary for mode `p2p_shared_key`.
+ enum:
+ - default
+ - direction-0
+ - direction-1
+ - both-directions
+ type: string
+ shared_key:
+ default: ''
+ description: Enter Shared Key. This is only mandatory for mode `p2p_shared_key`.
+ Options are `""` for automatic shared key generation and a raw shared key.
+ type: string
+ example: '-----BEGIN OpenVPN Static key V1-----
+ db8701afd882d746be67f084bae68470
+ 54a99ef3b61864cfe1864c6c02584335
+ fe706df150250bf7e294b8c35911817c
+ 133c8d9b505573ebeb65259bc54c70ae
+ 88cc3163fd11a20f73d2c6fb3eea7cc2
+ fdaefcde510486adc0acbb9481b3aef4
+ 930db91806469218b2a4f92e71787cf4
+ 635f5b3f773fefc28d492738d2648673
+ 8fa9b23d41e5999f58c3f0004a59ecda
+ 119162e598764d9c8f6b99e7054f3ea4
+ fdb4461913d2e3273a8a0db29332406a
+ 237bcfccca2315445ef809eaa933fa30
+ a9a7510d2d167033edfd3580a824f3e1
+ 1af57da6eee89e6318ec29c67da8a19d
+ 7c9d74c7afac6ee0f813a0278a6261d7
+ a28e7bdbf1743527346bda359bc92fc9
+ -----END OpenVPN Static key V1-----'
+ caref:
+ description: Specify the unique reference ID of the certificate signing authority.
+ type: string
+ example: 61c7fbce3a351
+ crlref:
+ default: 'none'
+ description: This optional field is for the Certificate Revocation List (CRL)
+ this tunnel will use to check the validity of peer certificates.
+
+ A CRL is a list of certificates signed by a CA which are no longer valid.
+ This could be due to a certificate being compromised or lost, such as from
+ a stolen laptop, spyware infection, etc.
+
+ Specify the unique reference ID of the certificate.
+ type: string
+ example: 61c467cd2fd4f
+ certref:
+ description: The certificate used by the VPN instance to identify itself to peers.
+ This certificate must contain appropriate properties marking it as a server
+ certificate and not a user or client certificate.
+
+ Specify the unique reference ID of the certificate revocation list.
+ type: string
+ example: 61c4121240420
+ ocspcheck:
+ default: false
+ description: When set, OpenVPN will attempt to confirm client certificate validity
+ using Online Certificate Status Protocol (OCSP) against the site listed in the OCSP URL field.
+ type: boolean
+ ocspurl:
+ default: ''
+ description: Enter OCSP URL. This is only necessary for `ocspcheck`.
+ type: string
+ format: uri
+ dh_length:
+ default: '2048'
+ description: The Diffie-Hellman (DH) key exchange parameters are used for establishing a
+ secure communications channel. They may be regenerated at any time, and they are not
+ specific to an OpenVPN instance. When importing an existing OpenVPN configuration
+ these parameters do not need to be copied from the previous server nor does it require
+ generating new parameters. The length of the desired DH parameters may be chosen from
+ the drop-down box, either 1024, 2048, or 4096. There is an additional choice for
+ ECDH Only which disables traditional DH parameters and uses only ECDH.
+ enum:
+ - 1024
+ - 2048
+ - 3072
+ - 4096
+ - 6144
+ - 7680
+ - 8192
+ - 15360
+ - 16384
+ - 'ECDH Only'
+ type: string
+ ecdh_curve:
+ default: 'none'
+ description: Configures a specific elliptic curve to use for Elliptic Curve Diffie-Hellman
+ key exchanges. This is only for use with ECDH TLS encryption.
+ enum:
+ - none
+ - prime256v1
+ - secp384r1
+ - secp521r1
+ type: string
+ cert_depth:
+ default: 'one'
+ description: This option limits the valid length of a certificate chain. The default value
+ limits a chain to One (Client+Server). With that value, if an unauthorized intermediate
+ CA signs a certificate, certificates signed by the rogue intermediate would fail validation.
+ In cases when the certificate stricture requires chaining with intermediates,
+ raise this limit to accommodate the longest allowed chain.
+ enum:
+ - none
+ - one
+ - two
+ - three
+ - four
+ - five
+ type: string
+ strictusercn:
+ default: false
+ description: Controls whether the firewall will enforce a strict match between the username
+ supplied by the user and the Common Name of their user certificate when the firewall
+ authenticates a user. When enabled, authentication fails if the two values do not match.
+
+ This prevents users from using their own credentials with the certificate from a different
+ user and vice versa.
+
+ This is only necessary for mode `server_tls_user`.
+ Omitting will disable.
+ type: boolean
+ ncp_enable:
+ default: false
+ description: Enable Data Encryption Negotiation.
+ Disabling this feature is deprecated.
+ Omitting will enable.
+ type: boolean
+ data_ciphers:
+ default: 'AES-256-GCM,AES-128-GCM,CHACHA20-POLY1305'
+ description: These options define the cryptographic ciphers OpenVPN will use for this VPN.
+ Enter comma sepereted data encryption algorithms
+ (e.g. `AES-256-GCM,AES-128-GCM,CHACHA20-POLY1305`).
+ Data encryption algorithms will be truncated to 19.
+ type: string
+ data_ciphers_fallback:
+ default: 'AES-256-CBC'
+ description: Enter fallback data encryption algorithm.
+ type: string
+ digest:
+ default: 'SHA256'
+ description: Selects the message digest algorithm OpenVPN uses for HMAC authentication of
+ incoming packets. This is used for the data channel and if also for the control channel
+ when the tunnel uses a TLS key. The GUI default of SHA256 is a good balance of security and speed.
+
+ When using AEAD ciphers such as AES-GCM, OpenVPN ignores this value for the data channel
+ since AEAD ciphers already perform authentication. Even with an AEAD cipher, OpenVPN still
+ uses this algorithm to authenticate the control channel when the tunnel uses a TLS key.
+ enum:
+ - BLAKE2b512
+ - BLAKE2b256
+ - MD4
+ - MD5
+ - MD5-SHA1
+ - MDC2
+ - RIPEMD160
+ - SHA1
+ - SHA224
+ - SHA256
+ - SHA3-224
+ - SHA3-256
+ - SHA3-384
+ - SHA3-512
+ - SHA384
+ - SHA512
+ - SHA512-224
+ - SHA512-256
+ - SHAKE128
+ - SHAKE256
+ - SM3
+ - whirlpool
+ - none
+ type: string
+ engine:
+ default: 'none'
+ description: If available, this option controls which hardware cryptographic accelerator
+ will be used by OpenVPN. When left unspecified, OpenVPN will choose automatically based
+ on what is available in the operating system to accelerate ciphers OpenVPN wants to use.
+
+ Some hardware acceleration, such as AES-NI, happens automatically in OpenVPN via OpenSSL
+ and cannot be enabled or disabled by this option.
+
+ Enter Hardware crypto. Options are `none` and any enabled
+ hardware crypto.
+ type: string
+ tunnel_network:
+ default: ''
+ description: 'Virtual IPv4 network used for private communications
+ between this client and the server expressed using CIDR (e.g.
+ 10.0.8.5/24).
+
+ With subnet topology, enter the client IP address and the subnet
+ mask must match the IPv4 Tunnel Network on the server.
+
+ With net30 topology, the first network address of the /30 is assumed
+ to be the server address and the second network address will be
+ assigned to the client.'
+ type: string
+ tunnel_networkv6:
+ default: ''
+ description: 'Virtual IPv6 network used for private communications
+ between this client and the server expressed using prefix (e.g.
+ 2001:db9:1:1::100/64).
+
+ Enter the client IPv6 address and prefix. The prefix must match
+ the IPv6 Tunnel Network prefix on the server.'
+ type: string
+ local_network:
+ default: ''
+ description: 'IPv4 server-side networks that will be accessible
+ from this particular client. Expressed as a comma-separated list
+ of one or more CIDR networks.
+
+ NOTE: Networks do not need to be specified here if they have already
+ been defined on the main server configuration.'
+ type: string
+ local_networkv6:
+ default: ''
+ description: 'IPv6 server-side networks that will be accessible
+ from this particular client. Expressed as a comma-separated list
+ of one or more IP/PREFIX networks.
+
+ NOTE: Networks do not need to be specified here if they have already
+ been defined on the main server configuration.'
+ type: string
+ remote_network:
+ default: ''
+ description: 'IPv4 client-side networks that will be routed to this
+ client specifically using iroute, so that a site-to-site VPN can
+ be established. Expressed as a comma-separated list of one or
+ more CIDR ranges. May be left blank if there are no client-side
+ networks to be routed.
+
+ NOTE: Remember to add these subnets to the IPv4 Remote Networks
+ list on the corresponding OpenVPN server settings.'
+ type: string
+ remote_networkv6:
+ default: ''
+ description: 'IPv6 client-side networks that will be routed to this
+ client specifically using iroute, so that a site-to-site VPN can
+ be established. Expressed as a comma-separated list of one or
+ more IP/PREFIX networks. May be left blank if there are no client-side
+ networks to be routed.
+
+ NOTE: Remember to add these subnets to the IPv6 Remote Networks
+ list on the corresponding OpenVPN server settings.'
+ type: string
+ redirect_gateway:
+ default: false
+ description: When a Redirect IPv4 Gateway option is selected the server
+ pushes a message to clients instructing them to forward all traffic for
+ that address family, including Internet traffic, over the VPN tunnel.
+ type: boolean
+ redirect_gateway6:
+ default: false
+ description: When a Redirect IPv6 Gateway option is selected the server
+ pushes a message to clients instructing them to forward all traffic for
+ that address family, including Internet traffic, over the VPN tunnel.
+ type: boolean
+ serverbridge_dhcp:
+ default: ""
+ description: When using `tap` mode for a remote access SSL/TLS VPN,
+ (`server_tls`, `server_user`, `server_tls_user`), additional options
+ to control bridging behavior in OpenVPN and client address assignment.
+
+ When selected, OpenVPN passes through DHCP to the bridged.
+ In the most common scenario, this is LAN.
+
+ Using this method connecting clients receive IP addresses from the
+ same DHCP pool used by clients on the LAN.
+ type: string
+ format: ipv4
+ serverbridge_interface:
+ default: "none"
+ description: This setting indicates to OpenVPN which interface will be used for the bridge.
+ In most cases this is LAN.
+ This option controls which existing IP address and subnet mask are used by OpenVPN for the bridge.
+ Setting this to none will cause the Server Bridge DHCP (`serverbridge_dhcp_start`, `serverbridge_dhcp_end`) settings below to be ignored.
+ enum:
+ - wan
+ - lan
+ - none
+ type: string
+ serverbridge_routegateway:
+ description: Makes OpenVPN push the Bridge Interface IPv4 address to connecting
+ clients as a route gateway.
+
+ When the IPv4 Tunnel Network in OpenVPN is empty for a bridged VPN,
+ connecting clients cannot automatically determine a server-side gateway for
+ use with routes pushed to clients by the server.
+ type: boolean
+ example: true
+ serverbridge_dhcp_start:
+ default: ""
+ description: Defines a DHCP range from which OpenVPN can assign addresses to clients.
+ If these settings are left blank, OpenVPN passes DHCP through to the bridge interface
+ and it ignores the interface setting above.
+
+ When set, this range should be within the same subnet as the Bridge Interface
+ (`serverbridge_interface`) but it should not overlap an existing in-use portion
+ of the subnet, such as the current DHCP pool.
+
+ This allows a range of IP addresses to be set aside for use only by OpenVPN clients so they may be contained within a portion of the internal network rather than consuming IP addresses from the existing DHCP pool.
+ type: string
+ format: ipv4
+ serverbridge_dhcp_end:
+ default: ""
+ description: Defines a DHCP range from which OpenVPN can assign addresses to clients.
+ If these settings are left blank, OpenVPN passes DHCP through to the bridge interface
+ and it ignores the interface setting above.
+
+ When set, this range should be within the same subnet as the Bridge Interface
+ (`serverbridge_interface`) but it should not overlap an existing in-use portion
+ of the subnet, such as the current DHCP pool.
+
+ This allows a range of IP addresses to be set aside for use only by OpenVPN clients so they may be contained within a portion of the internal network rather than consuming IP addresses from the existing DHCP pool.
+ type: string
+ format: ipv4
+ concurrent_connections:
+ description: Specifies the number of clients that may be simultaneously
+ connected to this OpenVPN server instance at any given time.
+ type: integer
+ example: '10'
+ allow_compression:
+ default: 'no'
+ description: Controls whether or not compression is allowed on the VPN, and how it is handled.
+ enum:
+ - asym
+ - no
+ - yes
+ type: string
+ compression:
+ default: 'none'
+ description: Compression to be used with this VPN instance. This is only
+ necessary for `allow_compression` set to `yes` or `asym`.
+ Compression can potentially dangerous and insecure. Deprecated.
+ Compress tunnel packets using the LZO algorithm.
+ enum:
+ - none
+ - stub
+ - stub-v2
+ - lz4
+ - lz4-v2
+ - lzo
+ - noadapt
+ - adaptive
+ - yes
+ - no
+ type: string
+ compression_push:
+ default: false
+ description: Push the selected Compression setting to connecting clients.
+ This is only necessary for `allow_compression` set to `yes` or `asym`.
+ type: boolean
+ passtos:
+ default: false
+ description: When this option is enabled OpenVPN sets the Type-of-Service (TOS)
+ IP header value of tunnel packets to match the encapsulated packet value.
+ This may cause important traffic to be handled faster over the tunnel by
+ intermediate hops at the cost of minor information disclosure.
+ type: boolean
+ client2client:
+ default: false
+ description: This option controls whether or not connected clients are able to
+ communicate with one another. To allow this behavior, check the option.
+ When unchecked, clients can only send traffic to the server or destinations
+ beyond the server such as routed networks or the Internet.
+ type: boolean
+ duplicate_cn:
+ default: false
+ description: Controls whether or not OpenVPN will allow multiple connections
+ from the same user to work simultaneously.
+ This is only necessary for mode `p2p_shared_key`.
+ type: boolean
+ dynamic_ip:
+ default: false
+ description: For clients on Internet connections where the IP address changes frequently,
+ or mobile users who commonly move between different Internet connections,
+ check this option for more stable connectivity. Where the client IP address
+ is static or rarely changes, not using this option offers a small security improvement.
+ type: boolean
+ topology:
+ default: 'subnet'
+ description: Sets the method OpenVPN uses to allocate addresses for clients in a
+ client/server setup on tun device mode VPNs. The Topology option is relevant
+ only when supplying a virtual adapter IP address to clients using tun mode on IPv4.
+ Some clients may require this even for IPv6, such as OpenVPN Connect, though in
+ reality IPv6 always runs with a subnet topology even when IPv4 uses net30.
+ OpenVPN instances using tap mode always use subnet topology as well.
+ enum:
+ - subnet
+ - net30
+ type: string
+ dns_domain:
+ default: ''
+ description: Configures a default domain name which clients will append to DNS requests.
+ This can be helpful to ensure name resolution works properly for hosts on the local
+ network where DNS name resolution is used.
+ type: string
+ example: example.com
+ dns_servers:
+ default: ''
+ description: Comma-separated list of no more than 4 DNS server IP
+ addresses (i.e. 8.8.8.8). Any more than the first four are ignored.
+ This list is provided to the clent.
+ type: string
+ example: "8.8.8.8, 8.8.4.4, 8.8.3.3, 8.8.2.2"
+ push_blockoutsidedns:
+ default: false
+ description: Make Windows 10 Clients Block access to DNS servers except
+ across OpenVPN while connected, forcing clients to use only VPN DNS servers.
+ type: boolean
+ push_register_dns:
+ default: false
+ description: Run "net stop dnscache", "net start dnscache",
+ "ipconfig /flushdns" and "ipconfig /registerdns" on connection initiation.
+ type: boolean
+ inactive_seconds:
+ default: 300
+ description: The amount of time, in seconds, which a client can be inactive before
+ OpenVPN disconnects it for inactivity. OpenVPN bases activity on the last incoming
+ or outgoing data channel packet, not control channel packets.
+
+ `0` disables this feature.
+ type: integer
+ ping_method:
+ default: 'keepalive'
+ description: The Ping Method controls OpenVPN monitoring of peers through the
+ control channel and how it deals with unresponsive peers.
+ enum:
+ - keepalive
+ - ping
+ type: string
+ keepalive_interval:
+ default: 10
+ description: Enter keepalive interval.
+ type: integer
+ keepalive_timeout:
+ default: 60
+ description: Enter keepalive timeout.
+ type: integer
+ ping_seconds:
+ default: 10
+ description: Enter ping seconds. This is only necessary for `ping` method.
+ type: integer
+ ping_action_seconds:
+ default: 60
+ description: Enter ping action seconds. This is only necessary for `ping` method.
+ type: integer
+ ping_push:
+ default: false
+ description: Push ping to VPN client. This is only necessary for `ping` method.
+ type: boolean
+ ping_action_push:
+ default: false
+ description: Push ping-restart/ping-exit to VPN client.
+ This is only necessary for `ping` method.
+ type: boolean
+ ping_action:
+ default: 'ping_restart'
+ description: Exit or restart OpenVPN after timeout from remote.
+ This is only necessary for `ping` method.
+ enum:
+ - ping_restart
+ - ping_exit
+ type: string
+ username_as_common_name:
+ default: false
+ description: Controls whether or not OpenVPN will use the username given by the
+ client in place of the certificate common name (CN) for purposes such as determining
+ Client Specific Overrides. This is only relevant when user authentication is enabled.
+ This is typically the best practice, but not a requirement.
+
+ This is only necessary for mode `server_user` or `server_tls_user`.
+ type: boolean
+ udp_fast_io:
+ default: false
+ description: Controls whether or not OpenVPN will use fast I/O operations with UDP writes
+ to its tun or tap device. This behavior optimizes the packet write event loop,
+ improving CPU efficiency by 5% to 10%. Experimental.
+ type: boolean
+ exit_notify:
+ default: 'none'
+ description: Controls whether or not OpenVPN will send an explicit exit notification to
+ connected UDP clients or peers when restarting or shutting down. This notification
+ allows peers to immediately disconnect rather than wait for a timeout.
+ This is only relevant to UDP modes as TCP natively supports closing connections.
+ enum:
+ - once
+ - twice
+ - none
+ - ''
+ type: string
+ sndrcvbuf:
+ default: 'default'
+ description: Configures a Send and Receive Buffer size for OpenVPN.
+ The default buffer size can be too small in many cases, depending on hardware
+ and network uplink speeds. Finding the best buffer size can take experimentation.
+ To test the best value for a site, start at 512KiB and test higher and lower
+ values until testing results in peak performance.
+ enum:
+ - 64KiB
+ - 128KiB
+ - 256KiB
+ - 512KiB
+ - 1MiB
+ - 2MiB
+ - default
+ - none
+ type: string
+ ntp_servers:
+ default: ''
+ description: Comma-separated list of no more than 2 NTP server IP
+ addresses. Any more than the first two are ignored.
+ type: string
+ example: "192.168.56.101, 192.168.56.102"
+ netbios_enable:
+ default: false
+ description: Enable NetBIOS over TCP/IP. If this option is not set,
+ all NetBIOS-over-TCP/IP options (including WINS) will be disabled.
+ type: boolean
+ netbios_node_type:
+ description: 'Possible options: b (broadcasts), p (point-to-point
+ name queries to a WINS server), m (broadcast then query name server),
+ and h (query name server, then broadcast). This parameter takes
+ a single letter either b, p, m, or h. Any other string will result
+ in this option being set to none.'
+ enum:
+ - b
+ - p
+ - m
+ - h
+ type: string
+ example: b
+ netbios_scope:
+ description: NetBIOS Scope ID provides an extended naming service
+ for NetBIOS over TCP/IP. The NetBIOS scope ID isolates NetBIOS
+ traffic on a single network to only those nodes with the same
+ NetBIOS scope ID.
+ type: string
+ example: '5'
+ create_gw:
+ default: 'both'
+ description: If you assign a virtual interface to this OpenVPN server,
+ this setting controls which gateway types will be created.
+ enum:
+ - v4only
+ - v6only
+ - both
+ type: string
+ verbosity_level:
+ default: '3'
+ description: Configures the amount of detail OpenVPN will log for this instance,
+ which is useful for troubleshooting problems. Higher numbers will result in
+ higher amounts of detail in the log.
+ During normal operation the default selection is ideal.
+ Level `3` is recommended for a good summary of what's happening without
+ being swamped by output. Maximum level `11`.
+ The `default` setting is equivalent to level `1`.
+ enum:
+ - 0
+ - 1
+ - 2
+ - 3
+ - 4
+ - 5
+ - 6
+ - 7
+ - 8
+ - 9
+ - 10
+ - 11
+ - 'default'
+ type: string
+ wins_servers:
+ default: ''
+ description: Comma-separated list of no more than 2 WINS server
+ IP addresses. Any more than the first two are ignored.
+ type: string
+ example: "192.168.56.103, 192.168.56.104"
+ disable:
+ default: false
+ description: Disable this override without removing it.
+ type: boolean
+ required:
+ - vpnid
+ type: object
+ responses:
+ 200:
+ $ref: '#/components/responses/Success'
+ 401:
+ $ref: '#/components/responses/AuthenticationFailed'
+ summary: Update OpenVPN Server
+ tags:
+ - Services > OpenVPN > Server
/api/v1/services/openvpn/csc:
delete:
parameters:
@@ -9764,4 +11273,3 @@ tags:
- name: Services > DDNS
- name: Services > WOL
- name: Diagnostics > Command Prompt
-
diff --git a/tests/test_api_v1_services_openvpn_server.py b/tests/test_api_v1_services_openvpn_server.py
new file mode 100644
index 000000000..914034911
--- /dev/null
+++ b/tests/test_api_v1_services_openvpn_server.py
@@ -0,0 +1,611 @@
+from operator import truediv
+import e2e_test_framework
+import base64
+
+class APIE2ETestOpenVPNServer(e2e_test_framework.APIE2ETest):
+ uri = "/api/v1/services/openvpn/server"
+ tls_key_text = "-----BEGIN OpenVPN Static key V1----- \
+db8701afd882d746be67f084bae68470 \
+54a99ef3b61864cfe1864c6c02584335 \
+fe706df150250bf7e294b8c35911817c \
+133c8d9b505573ebeb65259bc54c70ae \
+88cc3163fd11a20f73d2c6fb3eea7cc2 \
+fdaefcde510486adc0acbb9481b3aef4 \
+930db91806469218b2a4f92e71787cf4 \
+635f5b3f773fefc28d492738d2648673 \
+8fa9b23d41e5999f58c3f0004a59ecda \
+119162e598764d9c8f6b99e7054f3ea4 \
+fdb4461913d2e3273a8a0db29332406a \
+237bcfccca2315445ef809eaa933fa30 \
+a9a7510d2d167033edfd3580a824f3e1 \
+1af57da6eee89e6318ec29c67da8a19d \
+7c9d74c7afac6ee0f813a0278a6261d7 \
+a28e7bdbf1743527346bda359bc92fc9 \
+-----END OpenVPN Static key V1----- \
+"
+ get_tests = [{"name": "Read all OpenVPN Server instances"}]
+ post_tests = [
+ {
+ "name": "OpenVPN Server No Certificate Authority found",
+ "status": 400,
+ "return": 2144,
+ "payload": {}
+ },
+ {
+ "name": "Create RSA internal CA",
+ "uri": "/api/v1/system/ca",
+ "no_caref": True, # Prevents the overriden post_post() method from auto-adding the created CA ref ID
+ "payload": {
+ "method": "internal",
+ "descr": "INTERNAL_CA_TEST",
+ "trust": True,
+ "keytype": "RSA",
+ "keylen": 2048,
+ "digest_alg": "sha256",
+ "dn_commonname": "internal-ca-e2e-test.example.com"
+ },
+ },
+ {
+ "name": "OpenVPN Server No Server Certificate found",
+ "status": 400,
+ "return": 2145,
+ "payload": {}
+ },
+ {
+ "name": "Create internal certificate with RSA key",
+ "uri": "/api/v1/system/certificate",
+ "no_certref": True, # Prevents the overriden post_post() method from auto-adding the created Certificate ref ID
+ "payload": {
+ "method": "internal",
+ "descr": "INTERNAL_CERT_RSA",
+ "keytype": "RSA",
+ "keylen": 2048,
+ "digest_alg": "sha256",
+ "lifetime": 3650,
+ "dn_commonname": "internal-cert-e2e-test.example.com",
+ "dn_country": "US",
+ "dn_city": "Salt Lake City",
+ "dn_state": "Utah",
+ "dn_organization": "Test Company",
+ "dn_organizationalunit": "IT",
+ "type": "server"
+ }
+ },
+ {
+ "name": "Create OpenVPN Server",
+ "status": 200,
+ "return": 0,
+ "payload": {
+ "protocol": "udp4",
+ "description": "TEST_Create_OpenVPN_SERVER",
+ "tls": "",
+ "tls_type": "crypt",
+ "tlsauth_keydir": "both-directions",
+ "ecdh_curve": "prime256v1",
+ "ncp_enable": True,
+ "data_ciphers": "AES-128-GCM,CHACHA20-POLY1305",
+ "data_ciphers_fallback": "AES-256-CBC",
+ "digest": "SHA512",
+ "dh_length": "4096",
+ "tunnel_network": "1.2.3.4/24",
+ "concurrent_connections": 15,
+ "custom_options": 'push "route 10.0.0.0 255.255.255.0";'
+ }
+ },
+ {
+ "name": "Create Interface (ovpns1)",
+ "uri": "/api/v1/interface",
+ "no_caref": True, # Prevents the overriden post_post() method from auto-adding the created CA ref ID
+ "no_certref": True, # Prevents the overriden post_post() method from auto-adding the created Certificate ref ID
+ # "resp_time": 30,
+ "payload": {
+ "if": "ovpns1",
+ "descr": "TEST_INTERFACE_OVPNS1",
+ }
+ },
+ {
+ "name": "Unknown OpenVPN Server Mode",
+ "status": 400,
+ "return": 2104,
+ "payload": {
+ "mode": "INVALID_MODE"
+ }
+ },
+ {
+ "name": "Unknown OpenVPN Server Protocol",
+ "status": 400,
+ "return": 2105,
+ "payload": {
+ "protocol": "INVALID_PROTOCOL"
+ }
+ },
+ {
+ "name": "Unknown OpenVPN Server Device mode",
+ "status": 400,
+ "return": 2106,
+ "payload": {
+ "dev_mode": "INVALID_DEV_MODE"
+ }
+ },
+ {
+ "name": "Unknown OpenVPN Server Interface",
+ "status": 400,
+ "return": 2107,
+ "payload": {
+ "interface": "INVALID_INTERFACE"
+ }
+ },
+ {
+ "name": "Invalid or taken OpenVPN Server Local port (allowed range 1-65535)",
+ "status": 500,
+ "return": 2108,
+ "payload": {
+ "local_port": "99999"
+ }
+ },
+ {
+ "name": "Unknown OpenVPN Server TLS Key Usage Mode",
+ "status": 400,
+ "return": 2109,
+ "payload": {
+ "tls": tls_key_text,
+ "tls_type": "INVALID_TLS_TYPE"
+ }
+ },
+ {
+ "name": "Unknown OpenVPN Server TLS keydir direction",
+ "status": 400,
+ "return": 2110,
+ "payload": {
+ "tls": tls_key_text,
+ "tlsauth_keydir": "INVALID_TLS_KEYDIR"
+ }
+ },
+ {
+ "name": "Unknown OpenVPN Server TLS DH Parameter Length",
+ "status": 400,
+ "return": 2111,
+ "payload": {
+ "dh_length": "INVALID_DH_LENGTH"
+ }
+ },
+ {
+ "name": "Unknown OpenVPN Server ECDH Curve",
+ "status": 400,
+ "return": 2112,
+ "payload": {
+ "ecdh_curve": "INVALID_ECDH_CURVE"
+ }
+ },
+ {
+ "name": "Unknown OpenVPN Server Certificate Depth",
+ "status": 400,
+ "return": 2113,
+ "payload": {
+ "cert_depth": "INVALID_CERT_DEPTH"
+ }
+ },
+ {
+ "name": "Unknown OpenVPN Server Fallback Data Encryption Algorithm",
+ "status": 400,
+ "return": 2114,
+ "payload": {
+ "data_ciphers_fallback": "INVALID_DATA_CIPHERS_FALLBACK"
+ }
+ },
+ {
+ "name": "Unknown OpenVPN Server Auth Digest Algorithm",
+ "status": 400,
+ "return": 2115,
+ "payload": {
+ "digest": "INVALID_DIGEST"
+ }
+ },
+ {
+ "name": "Unknown OpenVPN Server Hardware Crypto Engine",
+ "status": 400,
+ "return": 2116,
+ "payload": {
+ "engine": "INVALID_ENGINE"
+ }
+ },
+ {
+ "name": "Unknown or already in use OpenVPN Server Tunnel Network",
+ "status": 400,
+ "return": 2117,
+ "payload": {
+ "tunnel_network": "INVALID_TUNNEL_NETWORK"
+ }
+ },
+ {
+ "name": "Unknown OpenVPN Server Remote network(s)",
+ "status": 400,
+ "return": 2118,
+ "payload": {
+ "remote_network": "INVALID_REMOTE_NETWORK"
+ }
+ },
+ {
+ "name": "Unknown OpenVPN Server Local network(s)",
+ "status": 400,
+ "return": 2119,
+ "payload": {
+ "local_network": "INVALID_LOCAL_NETWORK"
+ }
+ },
+ {
+ "name": "Unknown OpenVPN Server Allow Compression",
+ "status": 400,
+ "return": 2120,
+ "payload": {
+ "allow_compression": "INVALID_ALLOW_COMPRESSION"
+ }
+ },
+ {
+ "name": "Unknown OpenVPN Server Compression",
+ "status": 400,
+ "return": 2121,
+ "payload": {
+ "allow_compression": "yes",
+ "compression": "INVALID_COMPRESSION"
+ }
+ },
+ {
+ "name": "Unknown OpenVPN Server Topology",
+ "status": 400,
+ "return": 2122,
+ "payload": {
+ "dev_mode": "tun",
+ "topology": "INVALID_TOPOLOGY"
+ }
+ },
+ {
+ "name": "Unknown OpenVPN Server Ping Method",
+ "status": 400,
+ "return": 2123,
+ "payload": {
+ "ping_method": "INVALID_PING_METHOD"
+ }
+ },
+ {
+ "name": "Unknown OpenVPN Server Keepalive Interval",
+ "status": 400,
+ "return": 2124,
+ "payload": {
+ "ping_method": "keepalive",
+ "keepalive_interval": "INVALID_KEEPALIVE_INTERVAL"
+ }
+ },
+ {
+ "name": "Unknown OpenVPN Server Keepalive Timeout",
+ "status": 400,
+ "return": 2125,
+ "payload": {
+ "ping_method": "keepalive",
+ "keepalive_timeout": "INVALID_KEEPALIVE_TIMEOUT"
+ }
+ },
+ {
+ "name": "Unknown OpenVPN Server Ping Seconds",
+ "status": 400,
+ "return": 2126,
+ "payload": {
+ "ping_method": "ping",
+ "ping_seconds": "INVALID_PING_SECONDS"
+ }
+ },
+ {
+ "name": "Unknown OpenVPN Server Ping restart or exit seconds",
+ "status": 400,
+ "return": 2127,
+ "payload": {
+ "ping_method": "ping",
+ "ping_action_seconds": "INVALID_PING_ACTION_SECONDS"
+ }
+ },
+ {
+ "name": "Unknown OpenVPN Server Ping restart or exit",
+ "status": 400,
+ "return": 2128,
+ "payload": {
+ "ping_method": "ping",
+ "ping_action": "INVALID_PING_ACTION"
+ }
+ },
+ {
+ "name": "Unknown OpenVPN Server Exit Notify",
+ "status": 400,
+ "return": 2129,
+ "payload": {
+ "exit_notify": "INVALID_EXIT_NOTIFY"
+ }
+ },
+ {
+ "name": "Unknown OpenVPN Server Send/Receive Buffer",
+ "status": 400,
+ "return": 2130,
+ "payload": {
+ "sndrcvbuf": "INVALID_SNDRCVBUF"
+ }
+ },
+ {
+ "name": "Unknown OpenVPN Server Gateway Creation",
+ "status": 400,
+ "return": 2131,
+ "payload": {
+ "create_gw": "INVALID_CREATE_GW"
+ }
+ },
+ {
+ "name": "Unknown OpenVPN Server Verbosity Level",
+ "status": 400,
+ "return": 2132,
+ "payload": {
+ "verbosity_level": "INVALID_VERBOSITY_LEVEL"
+ }
+ },
+ {
+ "name": "Unknown OpenVPN Server Concurrent Connections",
+ "status": 400,
+ "return": 2133,
+ "payload": {
+ "concurrent_connections": "INVALID_CONCURRENT_CONNECTIONS"
+ }
+ },
+ {
+ "name": "Unknown OpenVPN Server Inactive Time",
+ "status": 400,
+ "return": 2134,
+ "payload": {
+ "inactive_seconds": "INVALID_INACTIVE_SECONDS"
+ }
+ },
+ {
+ "name": "Missing OpenVPN Server Certificate",
+ "status": 400,
+ "return": 2135,
+ "no_certref": True, # Prevents the overriden post_post() method from auto-adding the created Certificate ref ID
+ "payload": {}
+ },
+ {
+ "name": "Missing OpenVPN Server Certificate Authority",
+ "status": 400,
+ "return": 2136,
+ "no_caref": True, # Prevents the overriden post_post() method from auto-adding the created CA ref ID
+ "payload": {}
+ },
+ {
+ "name": "Unknown OpenVPN Server Peer Certificate Revocation List",
+ "status": 400,
+ "return": 2137,
+ "payload": {
+ "crlref": "INVALID_CRLREF"
+ }
+ },
+ {
+ "name": "Unknown OpenVPN Server Data Encryption Algorithms",
+ "status": 400,
+ "return": 2138,
+ "payload": {
+ "data_ciphers": "INVALID_DATA_ENCRYP_ALGO"
+ }
+ },
+ {
+ "name": "Missing OpenVPN Server 'shared_key'. This parameter is needed for server mode 'p2p_shared_key'",
+ "status": 400,
+ "return": 2141,
+ "no_certref": True, # Prevents the overriden post_post() method from auto-adding the created Certificate ref ID
+ "no_caref": True, # Prevents the overriden post_post() method from auto-adding the created CA ref ID
+ "payload": {
+ "mode": "p2p_shared_key"
+ }
+ },
+ {
+ "name": "Unknown OpenVPN Server Certificate Authority",
+ "status": 400,
+ "return": 2142,
+ "no_caref": True, # Prevents the overriden post_post() method from auto-adding the created CA ref ID
+ "payload": {
+ "caref": "INVALID_CA_REF",
+ }
+ },
+ {
+ "name": "Unknown OpenVPN Server Certificate",
+ "status": 400,
+ "return": 2143,
+ "no_certref": True, # Prevents the overriden post_post() method from auto-adding the created Certificate ref ID
+ "payload": {
+ "certref": "INVALID_CERT_REF",
+ }
+ },
+ {
+ "name": "Unknown OpenVPN Server Bridge Interface",
+ "status": 400,
+ "return": 2146,
+ "payload": {
+ "mode": "server_tls",
+ "dev_mode": "tap",
+ "serverbridge_dhcp": True,
+ "serverbridge_interface": "INVALID_BRIDGE_INTERFACE"
+ }
+ },
+ {
+ "name": "Unknown OpenVPN Server Bridge Route Gateway requires a valid Bridge Interface",
+ "status": 400,
+ "return": 2147,
+ "payload": {
+ "mode": "server_tls",
+ "dev_mode": "tap",
+ "serverbridge_dhcp": True,
+ "serverbridge_routegateway": True,
+ "serverbridge_interface": "none"
+ }
+ },
+ {
+ "name": "Unknown OpenVPN Server Bridge DHCP Start and End must both be empty, or defined, or The Server Bridge DHCP range is invalid (start higher than end).",
+ "status": 400,
+ "return": 2148,
+ "payload": {
+ "mode": "server_tls",
+ "dev_mode": "tap",
+ "serverbridge_dhcp": True,
+ "serverbridge_dhcp_start": "INVALID_DHCP_START"
+ }
+ },
+ {
+ "name": "OpenVPN Server The field 'NTP Server' must contain a valid IP address.",
+ "status": 400,
+ "return": 2149,
+ "payload": {
+ "mode": "server_tls",
+ "ntp_servers": "INVALID_NTP_SERVER"
+ }
+ },
+ {
+ "name": "OpenVPN Server The field 'DNS Server' must contain a valid IP address.",
+ "status": 400,
+ "return": 2150,
+ "payload": {
+ "mode": "server_tls",
+ "dns_servers": "INVALID_DNS_SERVER"
+ }
+ },
+ {
+ "name": "OpenVPN Server The field 'WINS Server' must contain a valid IP address.",
+ "status": 400,
+ "return": 2151,
+ "payload": {
+ "mode": "server_tls",
+ "wins_servers": "INVALID_WINS_SERVER"
+ }
+ },
+ ]
+ put_tests = [
+ {
+ "name": "OpenVPN Server Update 1",
+ "status": 200,
+ "return": 0,
+ "no_certref": True, # Prevents the overriden post_post() method from auto-adding the created Certificate ref ID
+ "no_caref": True, # Prevents the overriden post_post() method from auto-adding the created CA ref ID
+ "payload": {
+ "description": "TEST_Update_OpenVPN_SERVER_1",
+ "mode": "p2p_shared_key",
+ "shared_key": ""
+ }
+ },
+ {
+ "name": "OpenVPN Server Update 2",
+ "status": 200,
+ "return": 0,
+ "payload": {
+ "description": "TEST_Update_OpenVPN_SERVER_2",
+ "mode": "server_tls_user",
+ "tls": "false",
+ "dev_mode": "tap",
+ "local_network": "4.3.2.1/24",
+ "compression_push": True,
+ "client2client": True,
+ "dynamic_ip": True,
+ "exit_notify": "twice",
+ "netbios_enable": True,
+ "netbios_ntype": "m",
+ "wins_servers": "10.0.0.10,10.0.0.20",
+ "serverbridge_dhcp": True,
+ "strictusercn": True,
+ "username_as_common_name": True,
+ }
+ }
+ ]
+ delete_tests = [
+ {
+ "name": "OpenVPN Server cannot delete an OpenVPN instance while the interface is assigned. Remove the interface assignment first.",
+ "status": 400,
+ "return": 2152,
+ "payload": {}
+ },
+ {
+ "name": "Delete Interface (ovpns1)",
+ "uri": "/api/v1/interface",
+ "status": 200,
+ "return": 0,
+ "payload": {}
+ },
+ {
+ "name": "Delete OpenVPN Server Instance",
+ "status": 200,
+ "return": 0,
+ "payload": {},
+ "resp_time": 10
+ }, # vpnid gets populated by post_post() method
+ {
+ "name": "Delete Certificate",
+ "uri": "/api/v1/system/certificate",
+ "status": 200,
+ "return": 0,
+ "payload": {"descr": "INTERNAL_CERT_RSA"}
+ },
+ {
+ "name": "Delete CA certificate",
+ "uri": "/api/v1/system/ca",
+ "status": 200,
+ "return": 0,
+ "payload": {"descr": "INTERNAL_CA_TEST"}
+ },
+ {
+ "name": "Unknown OpenVPN Server 'vpnid'",
+ "status": 404,
+ "return": 2139,
+ "payload": {
+ "vpnid": "INVALID_VPNID"
+ }
+ },
+ {
+ "name": "Missing OpenVPN Server 'vpnid'. This parameter is needed to identify the server to modify/delete",
+ "status": 400,
+ "return": 2140,
+ "payload": {}
+ },
+ ]
+
+ # Override our PRE/POST methods
+ def post_post(self):
+ if len(self.post_responses) == 2:
+ # Variables
+ counter = 0
+ for test in self.post_tests:
+ # Assign the required refid created in the POST request to the POST/PUT payloads
+ if "payload" in test.keys() and "no_caref" not in test.keys():
+ self.post_tests[counter]["payload"]["caref"] = self.post_responses[1]["data"]["refid"]
+ self.put_tests[1]["payload"]["caref"] = self.post_responses[1]["data"]["refid"]
+ # self.put_tests[1]["payload"]["caref"] = self.post_responses[1]["data"]["refid"]
+ counter = counter + 1
+
+ if len(self.post_responses) == 4:
+ # Variables
+ counter = 0
+ for test in self.post_tests:
+ # Assign the required refid created in the POST request to the POST/PUT payloads
+ if "payload" in test.keys() and "no_certref" not in test.keys():
+ self.post_tests[counter]["payload"]["certref"] = self.post_responses[3]["data"]["refid"]
+ self.put_tests[1]["payload"]["certref"] = self.post_responses[3]["data"]["refid"]
+ counter = counter + 1
+
+ if len(self.post_responses) == 5:
+ # Variables
+ # counter = 0
+ for test in self.post_tests:
+ # Assign the required vpnid created in the POST request to the DELETE/PUT payloads
+ self.delete_tests[0]["payload"]["vpnid"] = self.post_responses[4]["data"]["vpnid"]
+ self.delete_tests[2]["payload"]["vpnid"] = self.post_responses[4]["data"]["vpnid"]
+ self.put_tests[0]["payload"]["vpnid"] = self.post_responses[4]["data"]["vpnid"]
+ self.put_tests[1]["payload"]["vpnid"] = self.post_responses[4]["data"]["vpnid"]
+ # counter = counter + 1
+
+ if len(self.post_responses) == 6:
+ # Variables
+ # counter = 0
+ for test in self.post_tests:
+ # Assign the required vpnid created in the POST request to the DELETE payloads
+ self.delete_tests[1]["payload"]["if"] = self.post_responses[5]["data"]["if"]
+
+APIE2ETestOpenVPNServer()
\ No newline at end of file