diff --git a/src/opnsense/mvc/app/controllers/OPNsense/OpenVPN/forms/dialogInstance.xml b/src/opnsense/mvc/app/controllers/OPNsense/OpenVPN/forms/dialogInstance.xml index c8d8942ed..95041a723 100644 --- a/src/opnsense/mvc/app/controllers/OPNsense/OpenVPN/forms/dialogInstance.xml +++ b/src/opnsense/mvc/app/controllers/OPNsense/OpenVPN/forms/dialogInstance.xml @@ -107,6 +107,22 @@ The server itself will take the next base address (+1) of the given network for use as the server-side endpoint of the local TUN/TAP interface + + instance.bridge_gateway + + text + + + This directive will set up an OpenVPN server which will allocate addresses to clients out of the given network pool. + + + + instance.bridge_pool + + text + + Specify an ip range which should be used to offer IPv4 addresses to the client. + instance.topology diff --git a/src/opnsense/mvc/app/models/OPNsense/OpenVPN/OpenVPN.php b/src/opnsense/mvc/app/models/OPNsense/OpenVPN/OpenVPN.php index 03eb062f6..e1c2920f3 100644 --- a/src/opnsense/mvc/app/models/OPNsense/OpenVPN/OpenVPN.php +++ b/src/opnsense/mvc/app/models/OPNsense/OpenVPN/OpenVPN.php @@ -72,36 +72,60 @@ class OpenVPN extends BaseModel )); } } elseif ($instance->role == 'server') { - if ( - $instance->dev_type == 'tun' && - empty((string)$instance->server) && - empty((string)$instance->server_ipv6) - ) { - $messages->appendMessage( - new Message(gettext('At least one IPv4 or IPv6 tunnel network is required.'), $key . '.server') - ); - $messages->appendMessage( - new Message(gettext('At least one IPv4 or IPv6 tunnel network is required.'), $key . '.server_ipv6') - ); - } - if (!empty((string)$instance->server) && strpos((string)$instance->server, '/') !== false) { - if ( - explode('/', (string)$instance->server)[1] > 29 && !( - (string)$instance->dev_type == 'tun' && (string)$instance->topology == 'p2p' - ) - ) { - /* tun + p2p is the exceptions here */ - $msg = gettext( - 'Server directive must define a subnet of /29 or lower unless topology equals p2p.' + if ($instance->dev_type == 'tun') { + if (empty((string)$instance->server) && empty((string)$instance->server_ipv6)) { + $messages->appendMessage( + new Message(gettext('At least one IPv4 or IPv6 tunnel network is required.'), $key . '.server') ); - $messages->appendMessage(new Message($msg, $key . '.server')); + $messages->appendMessage( + new Message(gettext('At least one IPv4 or IPv6 tunnel network is required.'), $key . '.server_ipv6') + ); + } + if (!empty((string)$instance->server) && strpos((string)$instance->server, '/') !== false) { + if ( + explode('/', (string)$instance->server)[1] > 29 && !( + (string)$instance->dev_type == 'tun' && (string)$instance->topology == 'p2p' + ) + ) { + /* tun + p2p is the exceptions here */ + $msg = gettext( + 'Server directive must define a subnet of /29 or lower unless topology equals p2p.' + ); + $messages->appendMessage(new Message($msg, $key . '.server')); + } + } + } elseif ($instance->dev_type == 'tap') { + if (!(empty((string)$instance->bridge_gateway) xor ((string)$instance->bridge_pool))) { + $messages->appendMessage(new Message( + gettext('When specifying a bridge gateway, a pool should also be provided.'), + $key . ".bridge_gateway" + )); + } elseif (!empty((string)$instance->bridge_pool)) { + $parts = array_map('trim', explode('-', (string)$instance->bridge_pool)); + if (count($parts) != 2 || !Util::isIpv4Address($parts[0]) || !Util::isIpv4Address($parts[1])) { + $messages->appendMessage(new Message( + gettext('Invalid range provided.'), + $key . ".bridge_pool" + )); + } else { + $ip = (string)$instance->bridge_gateway; + if (!Util::isIPInCIDR($parts[0], $ip) || !Util::isIPInCIDR($parts[1], $ip)) { + $messages->appendMessage(new Message( + gettext('Range does not match specified subnet.'), + $key . ".bridge_pool" + )); + } + } + } } if ((string)$instance->verify_client_cert != 'none') { - $messages->appendMessage(new Message( - gettext('To validate a certificate one has to be provided.'), - $key . ".verify_client_cert" - )); + if (empty((string)$instance->cert)) { + $messages->appendMessage(new Message( + gettext('To validate a certificate one has to be provided.'), + $key . ".verify_client_cert" + )); + } } elseif (empty((string)$instance->authmode)) { $messages->appendMessage(new Message( gettext( @@ -463,6 +487,7 @@ class OpenVPN extends BaseModel //$options['user'] = 'openvpn'; //$options['group'] = 'openvpn'; } else { + // server only settings $event_script = '/usr/local/opnsense/scripts/openvpn/ovpn_event.py'; $options['dev'] = "ovpns{$node->vpnid}"; $options['ping-timer-rem'] = null; @@ -494,8 +519,17 @@ class OpenVPN extends BaseModel $options['server'] = $parts[0] . " " . $mask; } } elseif ((string)$node->dev_type == 'tap') { - $options['mode'] = 'server'; - $options['tls-server'] = null; + if (!empty((string)$node->bridge_gateway)) { + $parts = explode('/', (string)$node->bridge_gateway); + $options['server-bridge'] = sprintf( + "%s %s %s", + $parts[0], + Util::CIDRToMask($parts[1]), + str_replace('-', ' ', (string)$node->bridge_pool) + ); + } else { + $options['server-bridge'] = ''; + } } if (!empty((string)$node->server_ipv6)) { $options['server-ipv6'] = (string)$node->server_ipv6; @@ -503,24 +537,17 @@ class OpenVPN extends BaseModel if (!empty((string)$node->username_as_common_name)) { $options['username-as-common-name'] = null; } - // server only settings - if ( - !empty((string)$node->server) || - !empty((string)$node->server_ipv6) || - (string)$node->dev_type == 'tap' - ){ - $options['client-config-dir'] = "/var/etc/openvpn-csc/{$node->vpnid}"; - // hook event handlers - if (!empty((string)$node->authmode)) { - $options['auth-user-pass-verify'] = "\"{$event_script} --defer '{$node_uuid}'\" via-env"; - $options['learn-address'] = "\"{$event_script} '{$node->vpnid}'\""; - } else { - // client specific profiles are being deployed using the connect event when no auth is used - $options['client-connect'] = "\"{$event_script} '{$node_uuid}'\""; - } - $options['client-disconnect'] = "\"{$event_script} '{$node_uuid}'\""; - $options['tls-verify'] = "\"{$event_script} '{$node_uuid}'\""; + $options['client-config-dir'] = "/var/etc/openvpn-csc/{$node->vpnid}"; + // hook event handlers + if (!empty((string)$node->authmode)) { + $options['auth-user-pass-verify'] = "\"{$event_script} --defer '{$node_uuid}'\" via-env"; + $options['learn-address'] = "\"{$event_script} '{$node->vpnid}'\""; + } else { + // client specific profiles are being deployed using the connect event when no auth is used + $options['client-connect'] = "\"{$event_script} '{$node_uuid}'\""; } + $options['client-disconnect'] = "\"{$event_script} '{$node_uuid}'\""; + $options['tls-verify'] = "\"{$event_script} '{$node_uuid}'\""; if (!empty((string)$node->maxclients)) { $options['max-clients'] = (string)$node->maxclients; diff --git a/src/opnsense/mvc/app/models/OPNsense/OpenVPN/OpenVPN.xml b/src/opnsense/mvc/app/models/OPNsense/OpenVPN/OpenVPN.xml index 9f688062c..33aac799c 100644 --- a/src/opnsense/mvc/app/models/OPNsense/OpenVPN/OpenVPN.xml +++ b/src/opnsense/mvc/app/models/OPNsense/OpenVPN/OpenVPN.xml @@ -161,6 +161,10 @@ N + + N + + , Y