summaryrefslogtreecommitdiffstats
path: root/src/etc/inc/vpn.inc
diff options
context:
space:
mode:
Diffstat (limited to 'src/etc/inc/vpn.inc')
-rw-r--r--src/etc/inc/vpn.inc282
1 files changed, 204 insertions, 78 deletions
diff --git a/src/etc/inc/vpn.inc b/src/etc/inc/vpn.inc
index e277da5..50f0b01 100644
--- a/src/etc/inc/vpn.inc
+++ b/src/etc/inc/vpn.inc
@@ -1,5 +1,4 @@
<?php
-
/*
vpn.inc
Copyright (C) 2004 Scott Ullrich
@@ -33,32 +32,36 @@
POSSIBILITY OF SUCH DAMAGE.
*/
-/*
- pfSense_BUILDER_BINARIES: /sbin/ifconfig
- pfSense_BUILDER_BINARIES: /usr/local/sbin/ipsec /usr/local/libexec/ipsec/charon /usr/local/libexec/ipsec/starter
- pfSense_BUILDER_BINARIES: /usr/local/sbin/filterdns /usr/local/sbin/mpd4
- pfSense_MODULE: vpn
-*/
-
require_once("ipsec.inc");
require_once("filter.inc");
-function vpn_ipsec_configure_loglevels($forconfig = false) {
- global $config, $ipsec_loglevels;
+function vpn_update_daemon_loglevel($category, $level) {
+ global $ipsec_log_cats, $ipsec_log_sevs;
- $cfgtext = array();
- foreach ($ipsec_loglevels as $lkey => $ldescr) {
- if (!isset($config['ipsec']["ipsec_{$lkey}"]) && !$forconfig) {
- mwexec("/usr/local/sbin/ipsec stroke loglevel {$lkey} -- -1", false);
- } else if (is_numeric($config['ipsec']["ipsec_{$lkey}"]) &&
- intval($config['ipsec']["ipsec_{$lkey}"]) >= 0 && intval($config['ipsec']["ipsec_{$lkey}"]) <= 5) {
- $forconfig ? $cfgtext[] = "${lkey} " . (intval($config['ipsec']["ipsec_{$lkey}"]) - 1) :
- mwexec("/usr/local/sbin/ipsec stroke loglevel {$lkey} " . (intval($config['ipsec']["ipsec_{$lkey}"]) - 1) , false);
+ if (in_array($category, array_keys($ipsec_log_cats), true) && in_array(intval($level), array_keys($ipsec_log_sevs), true)) {
+
+ /* if you're setting to -1, need to add "--" to args */
+ $argterm = "";
+ if ($level == "-1") {
+ $argterm = "--";
}
+
+ mwexec("/usr/local/sbin/ipsec stroke loglevel {$category} {$argterm} {$level}");
}
- if ($forconfig) {
- return implode(',', $cfgtext);
+}
+
+function vpn_logging_cfgtxt() {
+ global $config, $ipsec_log_cats, $ipsec_log_sevs;
+
+ $cfgtext = array();
+ foreach (array_keys($ipsec_log_cats) as $cat) {
+ if (is_numeric($config['ipsec']['logging'][$cat]) &&
+ in_array(intval($config['ipsec']['logging'][$cat]), array_keys($ipsec_log_sevs), true)) {
+ $cfgtext[] = "${cat} = {$config['ipsec']['logging'][$cat]}";
+ }
}
+
+ return $cfgtext;
}
/* include all configuration functions */
@@ -128,13 +131,14 @@ function vpn_ipsec_configure($restart = false) {
/* get the automatic ping_hosts.sh ready */
unlink_if_exists("{$g['vardb_path']}/ipsecpinghosts");
touch("{$g['vardb_path']}/ipsecpinghosts");
+ $ipsecpinghostsactive = false;
/* service may have been enabled, disabled, or otherwise changed in a way requiring rule updates */
filter_configure();
$syscfg = $config['system'];
$ipseccfg = $config['ipsec'];
- if (!isset($ipseccfg['enable'])) {
+ if (!ipsec_enabled()) {
/* try to stop charon */
mwexec("/usr/local/sbin/ipsec stop");
/* Stop dynamic monitoring */
@@ -143,9 +147,8 @@ function vpn_ipsec_configure($restart = false) {
/* wait for process to die */
sleep(2);
- /* disallow IPSEC, it is off */
+ /* IPSEC is off, shutdown enc interface.*/
mwexec("/sbin/ifconfig enc0 down");
- set_single_sysctl("net.inet.ip.ipsec_in_use", "0");
return 0;
}
@@ -160,7 +163,6 @@ function vpn_ipsec_configure($restart = false) {
$crlpath = "{$g['varetc_path']}/ipsec/ipsec.d/crls";
mwexec("/sbin/ifconfig enc0 up");
- set_single_sysctl("net.inet.ip.ipsec_in_use", "1");
if (php_uname('m') != "amd64") {
set_single_sysctl("net.inet.ipsec.directdispatch", "0");
}
@@ -172,6 +174,11 @@ function vpn_ipsec_configure($restart = false) {
if (!is_dir("{$g['varetc_path']}/ipsec/ipsec.d")) {
mkdir("{$g['varetc_path']}/ipsec/ipsec.d");
}
+ // delete these paths first to ensure old CAs, certs and CRLs aren't left behind. redmine #5238
+ rmdir_recursive($capath);
+ rmdir_recursive($keypath);
+ rmdir_recursive($crlpath);
+ rmdir_recursive($certpath);
if (!is_dir($capath)) {
mkdir($capath);
}
@@ -197,14 +204,49 @@ function vpn_ipsec_configure($restart = false) {
mkdir("{$g['varetc_path']}/ipsec/ipsec.d/reqs");
}
+ if (!file_exists("/usr/local/etc/ipsec.d") ||
+ !is_link("/usr/local/etc/ipsec.d")) {
+ conf_mount_rw();
+ if (file_exists("/usr/local/etc/ipsec.d")) {
+ rmdir_recursive("/usr/local/etc/ipsec.d");
+ }
+ @symlink("{$g['varetc_path']}/ipsec/ipsec.d",
+ "/usr/local/etc/ipsec.d");
+ conf_mount_ro();
+ }
+ if (!file_exists("{$g['varetc_path']}/etc/strongswan.d") ||
+ !is_link("{$g['varetc_path']}/etc/strongswan.d")) {
+ conf_mount_rw();
+ if (is_link("{$g['varetc_path']}/etc/strongswan.d")) {
+ @unlink("{$g['varetc_path']}/etc/strongswan.d");
+ } else {
+ rmdir_recursive("{$g['varetc_path']}/etc/strongswan.d");
+ }
+ @symlink("/usr/local/etc/strongswan.d",
+ "{$g['varetc_path']}/ipsec/strongswan.d");
+ conf_mount_ro();
+ }
+ if (!file_exists("/usr/local/etc/strongswan.conf") ||
+ !is_link("/usr/local/etc/strongswan.conf")) {
+ conf_mount_rw();
+ @unlink("/usr/local/etc/strongswan.conf");
+ @symlink("{$g['varetc_path']}/ipsec/strongswan.conf",
+ "/usr/local/etc/strongswan.conf");
+ conf_mount_ro();
+ }
+ if (!file_exists("/usr/local/etc/ipsec.conf") ||
+ !is_link("/usr/local/etc/ipsec.conf")) {
+ conf_mount_rw();
+ @unlink("/usr/local/etc/ipsec.conf");
+ @symlink("{$g['varetc_path']}/ipsec/ipsec.conf",
+ "/usr/local/etc/ipsec.conf");
+ conf_mount_ro();
+ }
if (platform_booting()) {
echo gettext("Configuring IPsec VPN... ");
}
- /* fastforwarding is not compatible with ipsec tunnels */
- set_single_sysctl("net.inet.ip.fastforwarding", "0");
-
/* resolve all local, peer addresses and setup pings */
$ipmap = array();
$rgmap = array();
@@ -213,6 +255,7 @@ function vpn_ipsec_configure($restart = false) {
$aggressive_mode_psk = false;
unset($iflist);
$ifacesuse = array();
+ $mobile_ipsec_auth = "";
if (is_array($a_phase1) && count($a_phase1)) {
$ipsecpinghosts = "";
@@ -256,6 +299,7 @@ function vpn_ipsec_configure($restart = false) {
try to resolve it now and add it to the list for filterdns */
if (isset ($ph1ent['mobile'])) {
+ $mobile_ipsec_auth = $ph1ent['authentication_method'];
continue;
}
@@ -336,6 +380,7 @@ function vpn_ipsec_configure($restart = false) {
}
if (is_ipaddr($srcip)) {
$ipsecpinghosts[] = "{$srcip}|{$dstip}|3|||||{$family}|\n";
+ $ipsecpinghostsactive = true;
}
}
}
@@ -396,11 +441,19 @@ function vpn_ipsec_configure($restart = false) {
unset($stronconf);
+ $strongswanlog = "";
+ $ipsecloglevels = vpn_logging_cfgtxt();
+ if (is_array($ipsecloglevels)) {
+ foreach ($ipsecloglevels as $loglevel) {
+ $strongswanlog .= "\t\t" . $loglevel . "\n";
+ }
+ }
$strongswan = <<<EOD
# Automatically generated config file - DO NOT MODIFY. Changes will be overwritten.
starter {
-load_warning = no
+ load_warning = no
+ config_file = {$g['varetc_path']}/ipsec/ipsec.conf
}
charon {
@@ -416,53 +469,61 @@ cisco_unity = {$unity_enabled}
{$ifacesuse}
{$makebeforebreak}
-# And two loggers using syslog. The subsections define the facility to log
-# to, currently one of: daemon, auth.
syslog {
identifier = charon
- # default level to the LOG_DAEMON facility
+ # log everything under daemon since it ends up in the same place regardless with our syslog.conf
daemon {
ike_name = yes
+{$strongswanlog}
}
- # very minimalistic IKE auditing logs to LOG_AUTHPRIV
+ # disable logging under auth so logs aren't duplicated
auth {
default = -1
- ike = 1
- ike_name = yes
}
}
+ plugins {
+ stroke {
+ secrets_file = {$g['varetc_path']}/ipsec/ipsec.secrets
+ }
+
EOD;
- $strongswan .= "\tplugins {\n";
+ /* Find RADIUS servers designated for Mobile IPsec user auth */
+ $radius_server_txt = "";
+ $user_sources = explode(',', $config['ipsec']['client']['user_source']);
+ foreach ($user_sources as $user_source) {
+ $auth_server = auth_get_authserver($user_source);
+ $nice_user_source = strtolower(preg_replace('/\s+/', '_', $user_source));
+ if ($auth_server && $auth_server['type'] === 'radius') {
+ $radius_server_txt .= <<<EOD
+ {$nice_user_source} {
+ address = {$auth_server['host']}
+ secret = "{$auth_server['radius_secret']}"
+ auth_port = {$auth_server['radius_auth_port']}
+ acct_port = {$auth_server['radius_acct_port']}
+ }
+
+EOD;
+ }
+ }
- $a_servers = auth_get_authserver_list();
- foreach ($a_servers as $id => $pconfig) {
- if ($id == $config['ipsec']['client']['user_source'] && $pconfig['type'] == "radius") {
- $strongswan .= <<<EOD
+ /* write an eap-radius config section if appropriate */
+ if (strlen($radius_server_txt) && ($mobile_ipsec_auth === "eap-radius")) {
+ $strongswan .= <<<EOD
eap-radius {
class_group = yes
eap_start = no
servers {
- primary {
- address = {$pconfig['host']}
- secret = {$pconfig['radius_secret']}
- auth_port = {$pconfig['radius_auth_port']}
- acct_port = {$pconfig['radius_acct_port']}
- }
+{$radius_server_txt}
}
}
EOD;
- break;
- }
}
if (is_array($a_client) && isset($a_client['enable'])) {
$strongswan .= "\t\tattr {\n";
- if ($a_client['pool_address'] && $a_client['pool_netbits']) {
- $strongswan .= "\t\t\tsubnet = {$a_client['pool_address']}/{$a_client['pool_netbits']}\n";
- }
$cfgservers = array();
if (!empty($a_client['dns_server1'])) {
@@ -514,6 +575,7 @@ EOD;
}
if (!empty($net_list)) {
+ $strongswan .= "\t\t\tsubnet = {$net_list}\n";
$strongswan .= "\t\t\tsplit-include = {$net_list}\n";
unset($net_list);
}
@@ -570,28 +632,6 @@ EOD;
@file_put_contents("{$g['varetc_path']}/ipsec/strongswan.conf", $strongswan);
unset($strongswan);
- /* generate CA certificates files */
- if (is_array($config['ca']) && count($config['ca'])) {
- foreach ($config['ca'] as $ca) {
- if (!isset($ca['crt'])) {
- log_error(sprintf(gettext("Error: Invalid certificate info for %s"), $ca['descr']));
- continue;
- }
- $cert = base64_decode($ca['crt']);
- $x509cert = openssl_x509_parse(openssl_x509_read($cert));
- if (!is_array($x509cert) || !isset($x509cert['hash'])) {
- log_error(sprintf(gettext("Error: Invalid certificate hash info for %s"), $ca['descr']));
- continue;
- }
- $fname = "{$capath}/{$x509cert['hash']}.0.crt";
- if (!@file_put_contents($fname, $cert)) {
- log_error(sprintf(gettext("Error: Cannot write IPsec CA file for %s"), $ca['descr']));
- continue;
- }
- unset($cert);
- }
- }
-
/* write out CRL files */
if (is_array($config['crl']) && count($config['crl'])) {
foreach ($config['crl'] as $crl) {
@@ -609,6 +649,7 @@ EOD;
$pskconf = "";
+ $vpncas = array();
if (is_array($a_phase1) && count($a_phase1)) {
foreach ($a_phase1 as $ph1ent) {
@@ -628,6 +669,16 @@ EOD;
continue;
}
+ /* add signing CA cert chain of server cert
+ * to the list of CAs to write
+ */
+ $cachain = ca_chain_array($cert);
+ if ($cachain && is_array($cachain)) {
+ foreach ($cachain as $cacrt) {
+ $vpncas[$cacrt['refid']] = $cacrt;
+ }
+ }
+
@chmod($certpath, 0600);
$ph1keyfile = "{$keypath}/cert-{$ikeid}.key";
@@ -676,6 +727,41 @@ EOD;
}
}
}
+
+ /* if the client authenticates with a cert add the
+ * client cert CA chain to the list of CAs to write
+ */
+ if (in_array($ph1ent['authentication_method'],
+ array('rsasig', 'eap-tls', 'xauth_rsa_server'))) {
+
+ if (!empty($ph1ent['caref']) && !array_key_exists($ph1ent['caref'], $vpncas)) {
+ $thisca = lookup_ca($ph1ent['caref']);
+ $vpncas[$ph1ent['caref']] = $thisca;
+
+ /* follow chain up to root */
+ $cachain = ca_chain_array($thisca);
+ if ($cachain and is_array($cachain)) {
+ foreach ($cachain as $cacrt) {
+ $vpncas[$cacrt['refid']] = $cacrt;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /* write the required CAs */
+ foreach ($vpncas as $carefid => $cadata) {
+ $cacrt = base64_decode($cadata['crt']);
+ $cacrtattrs = openssl_x509_parse($cacrt);
+ if (!is_array($cacrtattrs) || !isset($cacrtattrs['hash'])) {
+ log_error(sprintf(gettext("Error: Invalid certificate hash info for %s"), $cadata['descr']));
+ continue;
+ }
+ $cafilename = "{$capath}/{$cacrtattrs['hash']}.0.crt";
+ if (!@file_put_contents($cafilename, $cacrt)) {
+ log_error(sprintf(gettext("Error: Cannot write IPsec CA file for %s"), $cadata['descr']));
+ continue;
}
}
@@ -724,7 +810,6 @@ EOD;
$ipsecconf .= "# This file is automatically generated. Do not edit\n";
$ipsecconf .= "config setup\n\tuniqueids = {$uniqueids}\n";
- $ipsecconf .= "\tcharondebug=\"" . vpn_ipsec_configure_loglevels(true) . "\"\n";
if (isset($config['ipsec']['strictcrlpolicy'])) {
$ipsecconf .= "\tstrictcrlpolicy = yes \n";
@@ -942,6 +1027,21 @@ EOD;
}
}
+ if (!empty($ph1ent['caref'])) {
+ $ca = lookup_ca($ph1ent['caref']);
+ if ($ca) {
+ $casubarr = cert_get_subject_array($ca['crt']);
+ $casub = "";
+ foreach ($casubarr as $casubfield) {
+ if (empty($casub)) {
+ $casub = "/";
+ }
+ $casub .= "{$casubfield['a']}={$casubfield['v']}/";
+ }
+
+ }
+ }
+
$authentication = "";
switch ($ph1ent['authentication_method']) {
case 'eap-mschapv2':
@@ -950,6 +1050,7 @@ EOD;
$authentication .= "leftauth=pubkey\n\trightauth=eap-mschapv2";
if (!empty($ph1ent['certref'])) {
$authentication .= "\n\tleftcert={$certpath}/cert-{$ph1ent['ikeid']}.crt";
+ $authentication .= "\n\tleftsendcert=always";
}
}
break;
@@ -959,13 +1060,18 @@ EOD;
$authentication .= "leftauth=pubkey\n\trightauth=eap-tls";
if (!empty($ph1ent['certref'])) {
$authentication .= "\n\tleftcert={$certpath}/cert-{$ph1ent['ikeid']}.crt";
+ $authentication .= "\n\tleftsendcert=always";
}
} else {
$authentication = "leftauth=eap-tls\n\trightauth=eap-tls";
if (!empty($ph1ent['certref'])) {
$authentication .= "\n\tleftcert={$certpath}/cert-{$ph1ent['ikeid']}.crt";
+ $authentication .= "\n\tleftsendcert=always";
}
}
+ if (isset($casub)) {
+ $authentication .= "\n\trightca=\"$casub\"";
+ }
break;
case 'eap-radius':
if (isset($ph1ent['mobile'])) {
@@ -973,11 +1079,13 @@ EOD;
$authentication .= "leftauth=pubkey\n\trightauth=eap-radius";
if (!empty($ph1ent['certref'])) {
$authentication .= "\n\tleftcert={$certpath}/cert-{$ph1ent['ikeid']}.crt";
+ $authentication .= "\n\tleftsendcert=always";
}
} else {
$authentication = "leftauth=eap-radius\n\trightauth=eap-radius";
if (!empty($ph1ent['certref'])) {
$authentication .= "\n\tleftcert={$certpath}/cert-{$ph1ent['ikeid']}.crt";
+ $authentication .= "\n\tleftsendcert=always";
}
}
break;
@@ -987,6 +1095,9 @@ EOD;
if (!empty($ph1ent['certref'])) {
$authentication .= "\n\tleftcert={$certpath}/cert-{$ph1ent['ikeid']}.crt";
}
+ if (isset($casub)) {
+ $authentication .= "\n\trightca=\"$casub\"";
+ }
break;
case 'xauth_psk_server':
$authentication = "leftauth = psk\n\trightauth = psk";
@@ -1000,6 +1111,9 @@ EOD;
if (!empty($ph1ent['certref'])) {
$authentication .= "\n\tleftcert={$certpath}/cert-{$ph1ent['ikeid']}.crt";
}
+ if (isset($casub)) {
+ $authentication .= "\n\trightca=\"$casub\"";
+ }
break;
case 'hybrid_rsa_server':
$authentication = "leftauth = pubkey\n\trightauth = xauth-generic";
@@ -1102,7 +1216,8 @@ EOD;
$tunneltype = "type = transport";
if ((($ph1ent['authentication_method'] == "xauth_psk_server") ||
- ($ph1ent['authentication_method'] == "pre_shared_key")) && isset($ph1ent['mobile'])) {
+ ($ph1ent['authentication_method'] == "pre_shared_key")) &&
+ isset($ph1ent['mobile'])) {
$left_spec = "%any";
} else {
$tmpsubnet = ipsec_get_phase1_src($ph1ent);
@@ -1318,6 +1433,11 @@ EOD;
}
}
+ // run ping_hosts.sh once if it's enabled to avoid wait for minicron
+ if ($ipsecpinghostsactive == true) {
+ mwexec_bg("/usr/local/bin/ping_hosts.sh");
+ }
+
if ($natfilterrules == true) {
filter_configure();
}
@@ -1677,10 +1797,16 @@ function vpn_l2tp_configure() {
$l2tp_listen="set l2tp self $ipaddr";
}
- if ($l2tpcfg['paporchap'] == "chap") {
- $paporchap = "set link enable chap";
- } else {
- $paporchap = "set link enable pap";
+ switch ($l2tpcfg['paporchap']) {
+ case 'chap':
+ $paporchap = "set link enable chap";
+ break;
+ case 'chap-msv2':
+ $paporchap = "set link enable chap-msv2";
+ break;
+ default:
+ $paporchap = "set link enable pap";
+ break;
}
/* write mpd.conf */
OpenPOWER on IntegriCloud