. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. All advertising materials mentioning features or use of this software must display the following acknowledgment: "This product includes software developed by the pfSense Project for use in the pfSense® software distribution. (http://www.pfsense.org/). 4. The names "pfSense" and "pfSense Project" must not be used to endorse or promote products derived from this software without prior written permission. For written permission, please contact coreteam@pfsense.org. 5. Products derived from this software may not be called "pfSense" nor may "pfSense" appear in their names without prior written permission of the Electric Sheep Fencing, LLC. 6. Redistributions of any form whatsoever must retain the following acknowledgment: "This product includes software developed by the pfSense Project for use in the pfSense software distribution (http://www.pfsense.org/). THIS SOFTWARE IS PROVIDED BY THE pfSense PROJECT ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE pfSense PROJECT OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ require_once("ipsec.inc"); require_once("filter.inc"); function vpn_update_daemon_loglevel($category, $level) { global $ipsec_log_cats, $ipsec_log_sevs; 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}"); } } 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 */ function vpn_ipsec_convert_to_modp($index) { $conversion = ""; switch ($index) { case '1': $conversion = "modp768"; break; case '2': $conversion = "modp1024"; break; case '5': $conversion = "modp1536"; break; case '14': $conversion = "modp2048"; break; case '15': $conversion = "modp3072"; break; case '16': $conversion = "modp4096"; break; case '17': $conversion = "modp6144"; break; case '18': $conversion = "modp8192"; break; case '19': $conversion = "ecp256"; break; case '20': $conversion = "ecp384"; break; case '21': $conversion = "ecp521"; break; case '22': $conversion = "modp1024s160"; break; case '23': $conversion = "modp2048s224"; break; case '24': $conversion = "modp2048s256"; break; case '28': $conversion = "ecp256bp"; break; case '29': $conversion = "ecp384bp"; break; case '30': $conversion = "ecp512bp"; break; } return $conversion; } function vpn_ipsec_configure($restart = false) { global $config, $g, $sa, $sn, $p1_ealgos, $p2_ealgos, $ipsec_idhandling; $ipsecstartlock = lock('ipsec', LOCK_EX); /* 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 (!ipsec_enabled()) { /* try to stop charon */ mwexec("/usr/local/sbin/ipsec stop"); /* Stop dynamic monitoring */ killbypid("{$g['varrun_path']}/filterdns-ipsec.pid"); /* wait for process to die */ sleep(2); /* IPSEC is off, shutdown enc interface.*/ mwexec("/sbin/ifconfig enc0 down"); unlock($ipsecstartlock); return 0; } $a_phase1 = $config['ipsec']['phase1']; $a_phase2 = $config['ipsec']['phase2']; $a_client = $config['ipsec']['client']; $certpath = "{$g['varetc_path']}/ipsec/ipsec.d/certs"; $capath = "{$g['varetc_path']}/ipsec/ipsec.d/cacerts"; $keypath = "{$g['varetc_path']}/ipsec/ipsec.d/private"; $crlpath = "{$g['varetc_path']}/ipsec/ipsec.d/crls"; mwexec("/sbin/ifconfig enc0 up"); if (php_uname('m') != "amd64") { set_single_sysctl("net.inet.ipsec.directdispatch", "0"); } /* needed for config files */ if (!is_dir("{$g['varetc_path']}/ipsec")) { mkdir("{$g['varetc_path']}/ipsec"); } 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); } if (!is_dir($keypath)) { mkdir($keypath); } if (!is_dir($crlpath)) { mkdir($crlpath); } if (!is_dir($certpath)) { mkdir($certpath); } if (!is_dir("{$g['varetc_path']}/ipsec/ipsec.d/aacerts")) { mkdir("{$g['varetc_path']}/ipsec/ipsec.d/aacerts"); } if (!is_dir("{$g['varetc_path']}/ipsec/ipsec.d/acerts")) { mkdir("{$g['varetc_path']}/ipsec/ipsec.d/acerts"); } if (!is_dir("{$g['varetc_path']}/ipsec/ipsec.d/ocspcerts")) { mkdir("{$g['varetc_path']}/ipsec/ipsec.d/ocspcerts"); } if (!is_dir("{$g['varetc_path']}/ipsec/ipsec.d/reqs")) { 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... "); } /* resolve all local, peer addresses and setup pings */ $ipmap = array(); $rgmap = array(); $filterdns_list = array(); $aggressive_mode_psk = false; unset($iflist); $ifacesuse = array(); $mobile_ipsec_auth = ""; if (is_array($a_phase1) && count($a_phase1)) { $ipsecpinghosts = ""; /* step through each phase1 entry */ foreach ($a_phase1 as $ph1ent) { if (isset($ph1ent['disabled'])) { continue; } if (substr($ph1ent['interface'], 0, 4) == "_vip") { $vpninterface = get_configured_vip_interface($ph1ent['interface']); $ifacesuse[] = get_real_interface($vpninterface); } else { $vpninterface = get_failover_interface($ph1ent['interface']); if (substr($vpninterface, 0, 4) == "_vip") { $vpninterface = get_configured_vip_interface($vpninterface); $ifacesuse[] = get_real_interface($vpninterface); } elseif (!empty($vpninterface)) { $ifacesuse[] = $vpninterface; } } if ($ph1ent['mode'] == "aggressive" && ($ph1ent['authentication_method'] == "pre_shared_key" || $ph1ent['authentication_method'] == "xauth_psk_server")) { $aggressive_mode_psk = true; } $ikeid = $ph1ent['ikeid']; $ep = ipsec_get_phase1_src($ph1ent); if (!is_ipaddr($ep)) { log_error(sprintf(gettext("IPsec ERROR: Could not find phase 1 source for connection %s. Omitting from configuration file."), $ph1ent['descr'])); continue; } if (!in_array($ep, $ipmap)) { $ipmap[] = $ep; } /* see if this tunnel has a hostname for the remote-gateway. If so, try to resolve it now and add it to the list for filterdns */ if (isset ($ph1ent['mobile'])) { $mobile_ipsec_auth = $ph1ent['authentication_method']; continue; } $rg = $ph1ent['remote-gateway']; if (!is_ipaddr($rg)) { $filterdns_list[] = "{$rg}"; add_hostname_to_watch($rg); if (!platform_booting()) { $rg = resolve_retry($rg); } if (!is_ipaddr($rg)) { continue; } } if (array_search($rg, $rgmap)) { log_error(sprintf(gettext("The remote gateway %s already exists on another phase 1 entry"), $rg)); continue; } $rgmap[$ph1ent['remote-gateway']] = $rg; if (is_array($a_phase2)) { /* step through each phase2 entry */ foreach ($a_phase2 as $ph2ent) { if (isset($ph2ent['disabled'])) { continue; } if ($ikeid != $ph2ent['ikeid']) { continue; } /* add an ipsec pinghosts entry */ if ($ph2ent['pinghost']) { if (!is_array($iflist)) { $iflist = get_configured_interface_list(); } $srcip = null; $local_subnet = ipsec_idinfo_to_cidr($ph2ent['localid'], true, $ph2ent['mode']); if (is_ipaddrv6($ph2ent['pinghost'])) { foreach ($iflist as $ifent => $ifname) { $interface_ip = get_interface_ipv6($ifent); if (!is_ipaddrv6($interface_ip)) { continue; } if (ip_in_subnet($interface_ip, $local_subnet)) { $srcip = $interface_ip; break; } } } else { foreach ($iflist as $ifent => $ifname) { $interface_ip = get_interface_ip($ifent); if (!is_ipaddrv4($interface_ip)) { continue; } if ($local_subnet == "0.0.0.0/0" || ip_in_subnet($interface_ip, $local_subnet)) { $srcip = $interface_ip; break; } } } /* if no valid src IP was found in configured interfaces, try the vips */ if (is_null($srcip)) { $viplist = get_configured_vip_list(); foreach ($viplist as $vip => $address) { if (ip_in_subnet($address, $local_subnet)) { $srcip = $address; break; } } } $dstip = $ph2ent['pinghost']; if (is_ipaddrv6($dstip)) { $family = "inet6"; } else { $family = "inet"; } if (is_ipaddr($srcip)) { $ipsecpinghosts[] = "{$srcip}|{$dstip}|3|||||{$family}|\n"; $ipsecpinghostsactive = true; } } } } } @file_put_contents("{$g['vardb_path']}/ipsecpinghosts", $ipsecpinghosts); unset($ipsecpinghosts); } unset($iflist); $accept_unencrypted = ""; if (isset($config['ipsec']['acceptunencryptedmainmode'])) { $accept_unencrypted = "accept_unencrypted_mainmode_messages = yes"; } $stronconf = ''; if (file_exists("{$g['varetc_path']}/ipsec/strongswan.conf")) { $stronconf = file_get_contents("{$g['varetc_path']}/ipsec/strongswan.conf"); } $i_dont_care_about_security_and_use_aggressive_mode_psk = ""; if ($aggressive_mode_psk) { log_error("WARNING: Setting i_dont_care_about_security_and_use_aggressive_mode_psk option because a phase 1 is configured using aggressive mode with pre-shared keys. This is not a secure configuration."); if (!empty($stronconf) && strpos($stronconf, 'i_dont_care_about_security_and_use_aggressive_mode_psk') === FALSE) { $restart = true; } $i_dont_care_about_security_and_use_aggressive_mode_psk = "i_dont_care_about_security_and_use_aggressive_mode_psk=yes"; } $unity_enabled = isset($config['ipsec']['unityplugin']) ? 'yes' : 'no'; $makebeforebreak = ''; if (isset($config['ipsec']['makebeforebreak'])) { $makebeforebreak = 'make_before_break = yes'; } if (isset($config['ipsec']['enableinterfacesuse'])) { if (!empty($ifacesuse)) { $ifacesuse = 'interfaces_use = ' . implode(',', array_unique($ifacesuse)); } else { $ifacesuse = ''; } } else { $ifacesuse = ''; } unset($stronconf); $strongswanlog = ""; $ipsecloglevels = vpn_logging_cfgtxt(); if (is_array($ipsecloglevels)) { foreach ($ipsecloglevels as $loglevel) { $strongswanlog .= "\t\t\t" . $loglevel . "\n"; } } $strongswan = << 0) { $strongswan .= ","; } if ($authcfg == "system") { $authcfg = "Local Database"; } $strongswan .= $authcfg; $firstsed = 1; } $strongswan .= "\n"; $strongswan .= "\t\t}\n"; } } $strongswan .= "\n\t}\n}\n"; @file_put_contents("{$g['varetc_path']}/ipsec/strongswan.conf", $strongswan); unset($strongswan); /* write out CRL files */ if (is_array($config['crl']) && count($config['crl'])) { foreach ($config['crl'] as $crl) { if (!isset($crl['text'])) { log_error(sprintf(gettext("Warning: Missing CRL data for %s"), $crl['descr'])); continue; } $fpath = "{$crlpath}/{$crl['refid']}.crl"; if (!@file_put_contents($fpath, base64_decode($crl['text']))) { log_error(sprintf(gettext("Error: Cannot write IPsec CRL file for %s"), $crl['descr'])); continue; } } } $pskconf = ""; $vpncas = array(); if (is_array($a_phase1) && count($a_phase1)) { foreach ($a_phase1 as $ph1ent) { if (isset($ph1ent['disabled'])) { continue; } if (strstr($ph1ent['authentication_method'], 'rsa') || in_array($ph1ent['authentication_method'], array('eap-mschapv2', 'eap-tls', 'eap-radius'))) { $certline = ''; $ikeid = $ph1ent['ikeid']; $cert = lookup_cert($ph1ent['certref']); if (!$cert) { log_error(sprintf(gettext("Error: Invalid phase1 certificate reference for %s"), $ph1ent['name'])); 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"; if (!file_put_contents($ph1keyfile, base64_decode($cert['prv']))) { log_error(sprintf(gettext("Error: Cannot write phase1 key file for %s"), $ph1ent['name'])); continue; } @chmod($ph1keyfile, 0600); $ph1certfile = "{$certpath}/cert-{$ikeid}.crt"; if (!file_put_contents($ph1certfile, base64_decode($cert['crt']))) { log_error(sprintf(gettext("Error: Cannot write phase1 certificate file for %s"), $ph1ent['name'])); @unlink($ph1keyfile); continue; } @chmod($ph1certfile, 0600); /* XXX" Traffic selectors? */ $pskconf .= " : RSA {$ph1keyfile}\n"; } else { list ($myid_type, $myid_data) = ipsec_find_id($ph1ent, 'local'); list ($peerid_type, $peerid_data) = ipsec_find_id($ph1ent, 'peer', $rgmap); $myid = trim($myid_data); if (empty($peerid_data)) { continue; } if ($myid_type == 'fqdn' && !empty($myid)) { $myid = "@{$myid}"; } $myid = isset($ph1ent['mobile']) ? trim($myid_data) : "%any"; $peerid = ($peerid_data != 'allusers') ? trim($peerid_data) : ''; if ($peerid_type == 'fqdn' && !empty($peerid)) { $peerid = "@{$peerid}"; } if (!empty($ph1ent['pre-shared-key'])) { $pskconf .= "{$myid} {$peerid} : PSK 0s" . base64_encode(trim($ph1ent['pre-shared-key'])) . "\n"; if (isset($ph1ent['mobile'])) { $pskconf .= " : PSK 0s" . base64_encode(trim($ph1ent['pre-shared-key'])) . "\n"; } } } /* 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; } } /* Add user PSKs */ if (is_array($config['system']) && is_array($config['system']['user'])) { foreach ($config['system']['user'] as $user) { if (!empty($user['ipsecpsk'])) { $pskconf .= "{$myid} {$user['name']} : PSK 0s" . base64_encode($user['ipsecpsk']) . "\n"; } } unset($user); } /* add PSKs for mobile clients */ if (is_array($ipseccfg['mobilekey'])) { foreach ($ipseccfg['mobilekey'] as $key) { if ($key['ident'] == "allusers") { $key['ident'] = '%any'; } if ($key['ident'] == "any") { $key['ident'] = '%any'; } if (empty($key['type'])) { $key['type'] = 'PSK'; } $pskconf .= "{$myid} {$key['ident']} : {$key['type']} 0s" . base64_encode($key['pre-shared-key']) . "\n"; } unset($key); } @file_put_contents("{$g['varetc_path']}/ipsec/ipsec.secrets", $pskconf); chmod("{$g['varetc_path']}/ipsec/ipsec.secrets", 0600); unset($pskconf); $uniqueids = 'yes'; if (!empty($config['ipsec']['uniqueids'])) { if (array_key_exists($config['ipsec']['uniqueids'], $ipsec_idhandling)) { $uniqueids = $config['ipsec']['uniqueids']; } } $natfilterrules = false; /* begin ipsec.conf */ $ipsecconf = ""; $enablecompression = false; if (is_array($a_phase1) && count($a_phase1)) { $ipsecconf .= "# This file is automatically generated. Do not edit\n"; $ipsecconf .= "config setup\n\tuniqueids = {$uniqueids}\n"; if (isset($config['ipsec']['strictcrlpolicy'])) { $ipsecconf .= "\tstrictcrlpolicy = yes \n"; } if (!isset($config['ipsec']['noshuntlaninterfaces'])) { if ($config['interfaces']['lan']) { $lanip = get_interface_ip("lan"); if (!empty($lanip) && is_ipaddrv4($lanip)) { $lansn = get_interface_subnet("lan"); $lansa = gen_subnet($lanip, $lansn); $ipsecconf .= <<= $key_lo; $keylen -= $key_step) { if (!empty($ph2ent['hash-algorithm-option']) && is_array($ph2ent['hash-algorithm-option'])) { foreach ($ph2ent['hash-algorithm-option'] as $halgo) { $halgo = str_replace('hmac_', '', $halgo); $tmpealgo = "{$ealg_id}{$keylen}-{$halgo}"; $modp = vpn_ipsec_convert_to_modp($ph2ent['pfsgroup']); if (!empty($modp)) { $tmpealgo .= "-{$modp}"; } $ealgoESPsp2arr[] = $tmpealgo; } } else { $tmpealgo = "{$ealg_id}{$keylen}"; $modp = vpn_ipsec_convert_to_modp($ph2ent['pfsgroup']); if (!empty($modp)) { $tmpealgo .= "-{$modp}"; } $ealgoESPsp2arr[] = $tmpealgo; } } } } else { if (!empty($ph2ent['hash-algorithm-option']) && is_array($ph2ent['hash-algorithm-option'])) { foreach ($ph2ent['hash-algorithm-option'] as $halgo) { $halgo = str_replace('hmac_', '', $halgo); $tmpealgo = "{$ealg_id}{$ealg_kl}-{$halgo}"; $modp = vpn_ipsec_convert_to_modp($ph2ent['pfsgroup']); if (!empty($modp)) { $tmpealgo .= "-{$modp}"; } $ealgoESPsp2arr[] = $tmpealgo; } } else { $tmpealgo = "{$ealg_id}{$ealg_kl}"; $modp = vpn_ipsec_convert_to_modp($ph2ent['pfsgroup']); if (!empty($modp)) { $tmpealgo .= "-{$modp}"; } $ealgoESPsp2arr[] = $tmpealgo; } } } } } else if ($ph2ent['protocol'] == 'ah') { if (!empty($ph2ent['hash-algorithm-option']) && is_array($ph2ent['hash-algorithm-option'])) { $modp = vpn_ipsec_convert_to_modp($ph2ent['pfsgroup']); foreach ($ph2ent['hash-algorithm-option'] as $tmpAHalgo) { $tmpAHalgo = str_replace('hmac_', '', $tmpAHalgo); if (!empty($modp)) { $tmpAHalgo = "-{$modp}"; } $ealgoAHsp2arr[] = $tmpAHalgo; } } } $reqids[] = $ph2ent['reqid']; if (!empty($ph2ent['lifetime'])) { if ($ipseclifetime == 0 || intval($ipseclifetime) > intval($ph2ent['lifetime'])) { $ipseclifetime = intval($ph2ent['lifetime']); } } } } $ipsecconnect =<< 0) { $ipsecconnect .= "\tlifetime = {$ipseclifetime}s\n"; } if (!empty($rightsourceip)) { $ipsecconnect .= "{$rightsourceip}"; } if (!empty($ealgosp1)) { $ipsecconnect .= "\t{$ealgosp1}\n"; } if (!empty($ealgoAHsp2arr)) { $ipsecconnect .= "\tah = " . join(',', $ealgoAHsp2arr) . "!\n"; } if (!empty($ealgoESPsp2arr)) { $ipsecconnect .= "\tesp = " . join(',', $ealgoESPsp2arr) . "!\n"; } if (!empty($authentication)) { $ipsecconnect .= "\t{$authentication}\n"; } if (!empty($peerid_spec)) { $ipsecconnect .= "\trightid = {$peerid_spec}\n"; } if ($keyexchange == 'ikev1') { $ipsecconnect .= "\taggressive = {$aggressive}\n"; } if (!isset($ph1ent['mobile']) && ($keyexchange == 'ikev1' || isset($ph1ent['splitconn']))) { if (!empty($rightsubnet_spec)) { $ipsecfin = ''; foreach ($rightsubnet_spec as $idx => $rsubnet) { $ipsecfin .= "\nconn con{$ph1ent['ikeid']}00{$idx}\n"; //if (!empty($reqids[$idx])) { // $ipsecfin .= "\treqid = " . $reqids[$idx] . "\n"; //} $ipsecfin .= $ipsecconnect; $ipsecfin .= "\trightsubnet = {$rsubnet}\n"; $ipsecfin .= "\tleftsubnet = " . $leftsubnet_spec[$idx] . "\n"; } } else { log_error(sprintf(gettext("No phase2 specifications for tunnel with REQID = %s"), $ikeid)); } } else { $ipsecfin = "\nconn con{$ph1ent['ikeid']}\n"; //if (!empty($reqids[$idx])) { // $ipsecfin .= "\treqid = " . $reqids[0] . "\n"; //} $ipsecfin .= $ipsecconnect; if (!isset($ph1ent['mobile']) && !empty($rightsubnet_spec)) { $tempsubnets = array(); foreach ($rightsubnet_spec as $rightsubnet) { $tempsubnets[$rightsubnet] = $rightsubnet; } $ipsecfin .= "\trightsubnet = " . join(",", $tempsubnets) . "\n"; unset($tempsubnets, $rightsubnet); } if (!empty($leftsubnet_spec)) { $tempsubnets = array(); foreach ($leftsubnet_spec as $leftsubnet) { $tempsubnets[$leftsubnet] = $leftsubnet; } $ipsecfin .= "\tleftsubnet = " . join(",", $tempsubnets) . "\n"; unset($tempsubnets, $leftsubnet); } } $ipsecconf .= $ipsecfin; unset($ipsecfin); } } @file_put_contents("{$g['varetc_path']}/ipsec/ipsec.conf", $ipsecconf); unset($ipsecconf); /* end ipsec.conf */ if ($enablecompression === true) { set_single_sysctl('net.inet.ipcomp.ipcomp_enable', 1); } else { set_single_sysctl('net.inet.ipcomp.ipcomp_enable', 0); } /* manage process */ if ($restart === true) { mwexec("/usr/local/sbin/ipsec restart", false); } else { if (isvalidpid("{$g['varrun_path']}/starter.charon.pid")) { /* Update configuration changes */ /* Read secrets */ mwexec("/usr/local/sbin/ipsec rereadall", false); mwexec("/usr/local/sbin/ipsec reload", false); } else { mwexec("/usr/local/sbin/ipsec start", false); } } // 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(); } /* start filterdns, if necessary */ if (count($filterdns_list) > 0) { $interval = 60; if (!empty($ipseccfg['dns-interval']) && is_numeric($ipseccfg['dns-interval'])) { $interval = $ipseccfg['dns-interval']; } $hostnames = ""; array_unique($filterdns_list); foreach ($filterdns_list as $hostname) { $hostnames .= "cmd {$hostname} '/usr/local/sbin/pfSctl -c \"service reload ipsecdns\"'\n"; } file_put_contents("{$g['varetc_path']}/ipsec/filterdns-ipsec.hosts", $hostnames); unset($hostnames); if (isvalidpid("{$g['varrun_path']}/filterdns-ipsec.pid")) { sigkillbypid("{$g['varrun_path']}/filterdns-ipsec.pid", "HUP"); } else { mwexec("/usr/local/sbin/filterdns -p {$g['varrun_path']}/filterdns-ipsec.pid -i {$interval} -c {$g['varetc_path']}/ipsec/filterdns-ipsec.hosts -d 1"); } } else { killbypid("{$g['varrun_path']}/filterdns-ipsec.pid"); @unlink("{$g['varrun_path']}/filterdns-ipsec.pid"); } if (platform_booting()) { echo "done\n"; } unlock($ipsecstartlock); return count($filterdns_list); } /* * Forcefully restart IPsec * This is required for when dynamic interfaces reload * For all other occasions the normal vpn_ipsec_configure() * will gracefully reload the settings without restarting */ function vpn_ipsec_force_reload($interface = "") { global $g, $config; if (!ipsec_enabled()) { return; } $ipseccfg = $config['ipsec']; if (!empty($interface) && is_array($ipseccfg['phase1'])) { $found = false; foreach ($ipseccfg['phase1'] as $ipsec) { if (!isset($ipsec['disabled']) && ($ipsec['interface'] == $interface)) { $found = true; break; } } if (!$found) { log_error(sprintf(gettext("Ignoring IPsec reload since there are no tunnels on interface %s"), $interface)); return; } } /* If we get this far then we need to take action. */ log_error(gettext("Forcefully reloading IPsec")); vpn_ipsec_configure(); } /* master setup for vpn (mpd) */ function vpn_setup() { /* start pppoe server */ vpn_pppoes_configure(); /* setup l2tp */ vpn_l2tp_configure(); } function vpn_netgraph_support() { $iflist = get_configured_interface_list(); foreach ($iflist as $iface) { $realif = get_real_interface($iface); /* Get support for netgraph(4) from the nic */ $ifinfo = pfSense_get_interface_addresses($realif); if (!empty($ifinfo) && in_array($ifinfo['iftype'], array("ether", "vlan", "bridge"))) { pfSense_ngctl_attach(".", $realif); } } } function vpn_pppoes_configure() { global $config; if (is_array($config['pppoes']['pppoe'])) { foreach ($config['pppoes']['pppoe'] as $pppoe) { vpn_pppoe_configure($pppoe); } } } function vpn_pppoe_configure(&$pppoecfg) { global $config, $g; $syscfg = $config['system']; /* create directory if it does not exist */ if (!is_dir("{$g['varetc_path']}/pppoe{$pppoecfg['pppoeid']}-vpn")) { mkdir("{$g['varetc_path']}/pppoe{$pppoecfg['pppoeid']}-vpn"); } if (platform_booting()) { if (!$pppoecfg['mode'] || ($pppoecfg['mode'] == "off")) { return 0; } echo gettext("Configuring PPPoE Server service... "); } else { /* kill mpd */ killbypid("{$g['varrun_path']}/pppoe{$pppoecfg['pppoeid']}-vpn.pid"); /* wait for process to die */ sleep(2); } switch ($pppoecfg['mode']) { case 'server': $pppoe_interface = get_real_interface($pppoecfg['interface']); if ($pppoecfg['paporchap'] == "chap") { $paporchap = "set link enable chap"; } else { $paporchap = "set link enable pap"; } /* write mpd.conf */ $fd = fopen("{$g['varetc_path']}/pppoe{$pppoecfg['pppoeid']}-vpn/mpd.conf", "w"); if (!$fd) { printf(gettext("Error: cannot open mpd.conf in vpn_pppoe_configure().") . "\n"); return 1; } $mpdconf = "\n\n"; $mpdconf .= "poes:\n"; for ($i = 0; $i < $pppoecfg['n_pppoe_units']; $i++) { $mpdconf .= " load poes{$pppoecfg['pppoeid']}{$i}\n"; } for ($i = 0; $i < $pppoecfg['n_pppoe_units']; $i++) { $clientip = ip_after($pppoecfg['remoteip'], $i); if (isset($pppoecfg['radius']['radiusissueips']) && isset($pppoecfg['radius']['server']['enable'])) { $issue_ip_type = "set ipcp ranges {$pppoecfg['localip']}/32 0.0.0.0/0"; } else { $issue_ip_type = "set ipcp ranges {$pppoecfg['localip']}/32 {$clientip}/32"; } $mpdconf .=<< 0)) { $pppoemaxlogins = $pppoecfg['n_pppoe_maxlogin']; } else { $pppoemaxlogins = 1; } $mpdconf .=<<