mirror of
https://github.com/pfsense/pfsense.git
synced 2025-10-26 11:38:35 +00:00
- Add proper support for using hostnames for the remote IPsec gateway.
- Make IPsec reloading granular, this resolves the long standing issue that a IPsec reload will cause all tunnels to drop. - Change IPsec edit screen description for remote gateway that a IP address or hostname is allowed here. We already accepted hostnames before. - Add /etc/rc.newipsecdns, when a hostname changes IP we invoke this script to remove the old tunnel and setup the new one.
This commit is contained in:
parent
e07ff7c0a5
commit
bf92bc791d
@ -1434,7 +1434,7 @@ function find_interface_ip($interface, $flush = false) {
|
||||
}
|
||||
|
||||
function guess_interface_from_ip($ipaddress) {
|
||||
$ret = exec_command("/usr/bin/netstat -rn | /usr/bin/awk '/^{$ipaddress}/ {print \$6}'");
|
||||
$ret = exec_command("/usr/bin/netstat -rn | /usr/bin/awk '/^{$ipaddress}/ {print $6}'");
|
||||
if(empty($ret)) {
|
||||
return false;
|
||||
}
|
||||
@ -3740,4 +3740,97 @@ function safe_write_file($file, $content, $force_binary) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Write out all the found IP addresses to a file
|
||||
* so we can compare it on change */
|
||||
function add_hostname_to_watch($hostname) {
|
||||
if(!is_dir("/var/db/dnscache")) {
|
||||
mkdir("/var/db/dnscache");
|
||||
}
|
||||
if((is_fqdn($hostname)) && (!is_ipaddr($hostname))) {
|
||||
$domrecords = array();
|
||||
$domips = array();
|
||||
exec("host -t A $hostname", $domrecords, $rethost);
|
||||
if($rethost == 0) {
|
||||
foreach($domrecords as $domr) {
|
||||
$doml = explode(" ", $domr);
|
||||
$domip = $doml[3];
|
||||
/* fill array with domain ip addresses */
|
||||
if(is_ipaddr($domip)) {
|
||||
$domips[] = $domip;
|
||||
}
|
||||
}
|
||||
}
|
||||
sort($domips);
|
||||
$contents = "";
|
||||
if(! empty($domips)) {
|
||||
foreach($domips as $ip) {
|
||||
$contents .= "$ip\n";
|
||||
}
|
||||
}
|
||||
file_put_contents("/var/db/dnscache/$hostname", $contents);
|
||||
}
|
||||
}
|
||||
|
||||
/* Compare the current hostname DNS to the DNS cache we made
|
||||
* if it has changed we return the old records
|
||||
* if no change we return true */
|
||||
function compare_hostname_to_dnscache($hostname) {
|
||||
if(!is_dir("/var/db/dnscache")) {
|
||||
mkdir("/var/db/dnscache");
|
||||
}
|
||||
$hostname = trim($hostname);
|
||||
if(is_readable("/var/db/dnscache/{$hostname}")) {
|
||||
$oldcontents = file_get_contents("/var/db/dnscache/{$hostname}");
|
||||
} else {
|
||||
$oldcontents = "";
|
||||
}
|
||||
if((is_fqdn($hostname)) && (!is_ipaddr($hostname))) {
|
||||
$domrecords = array();
|
||||
$domips = array();
|
||||
exec("host -t A $hostname", $domrecords, $rethost);
|
||||
if($rethost == 0) {
|
||||
foreach($domrecords as $domr) {
|
||||
$doml = explode(" ", $domr);
|
||||
$domip = $doml[3];
|
||||
/* fill array with domain ip addresses */
|
||||
if(is_ipaddr($domip)) {
|
||||
$domips[] = $domip;
|
||||
}
|
||||
}
|
||||
}
|
||||
sort($domips);
|
||||
$contents = "";
|
||||
if(! empty($domips)) {
|
||||
foreach($domips as $ip) {
|
||||
$contents .= "$ip\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(trim($oldcontents) != trim($contents)) {
|
||||
log_error("DNSCACHE: Found old IP {$oldcontents} and new IP {$contents}");
|
||||
return ($oldcontents);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function is_fqdn($fqdn) {
|
||||
$hostname = false;
|
||||
if(preg_match("/[-A-Z0-9\.]+\.[-A-Z0-9\.]+/i", $fqdn)) {
|
||||
$hostname = true;
|
||||
}
|
||||
if(preg_match("/\.\./", $fqdn)) {
|
||||
$hostname = false;
|
||||
}
|
||||
if(preg_match("/^\./i", $fqdn)) {
|
||||
$hostname = false;
|
||||
}
|
||||
if(preg_match("/\//i", $fqdn)) {
|
||||
$hostname = false;
|
||||
}
|
||||
return($hostname);
|
||||
}
|
||||
|
||||
|
||||
?>
|
||||
|
||||
@ -566,4 +566,24 @@ function mac_format($clientmac) {
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
function resolve_retry($hostname, $retries = 5) {
|
||||
|
||||
if (is_ipaddr($hostname))
|
||||
return $hostname;
|
||||
|
||||
for ($i = 0; $i < $retries; $i++) {
|
||||
$ip = gethostbyname($hostname);
|
||||
|
||||
if ($ip && $ip != $hostname) {
|
||||
/* success */
|
||||
return $ip;
|
||||
}
|
||||
|
||||
sleep(1);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
?>
|
||||
|
||||
300
etc/inc/vpn.inc
300
etc/inc/vpn.inc
@ -104,19 +104,6 @@ function vpn_ipsec_configure($ipchg = false) {
|
||||
unlink_if_exists("/var/db/ipsecpinghosts");
|
||||
touch("/var/db/ipsecpinghosts");
|
||||
|
||||
if($g['booting'] == true) {
|
||||
/* determine if we should load the via padlock module */
|
||||
$dmesg_boot = `cat /var/log/dmesg.boot | grep CPU`;
|
||||
if(stristr($dmesg_boot, "ACE") == true) {
|
||||
//echo "Enabling [VIA Padlock] ...";
|
||||
//mwexec("/sbin/kldload padlock");
|
||||
//mwexec("/sbin/sysctl net.inet.ipsec.crypto_support=1");
|
||||
//mwexec("/usr/local/sbin/setkey -F");
|
||||
//mwexec("/usr/local/sbin/setkey -FP");
|
||||
//echo " done.\n";
|
||||
}
|
||||
}
|
||||
|
||||
if(isset($config['ipsec']['preferredoldsa'])) {
|
||||
mwexec("/sbin/sysctl net.key.preferred_oldsa=0");
|
||||
} else {
|
||||
@ -143,6 +130,8 @@ function vpn_ipsec_configure($ipchg = false) {
|
||||
|
||||
/* kill racoon */
|
||||
mwexec("/usr/bin/killall racoon", true);
|
||||
killbypid("{$g['varrun_path']}/dnswatch-ipsec.pid");
|
||||
|
||||
|
||||
/* wait for process to die */
|
||||
sleep(2);
|
||||
@ -164,7 +153,7 @@ function vpn_ipsec_configure($ipchg = false) {
|
||||
if (isset($ipseccfg['enable'])) {
|
||||
|
||||
/* fastforwarding is not compatible with ipsec tunnels */
|
||||
system("/sbin/sysctl net.inet.ip.fastforwarding=0 >/dev/null 2>&1");
|
||||
mwexec("/sbin/sysctl net.inet.ip.fastforwarding=0");
|
||||
|
||||
if (!$curwanip) {
|
||||
/* IP address not configured yet, exit */
|
||||
@ -180,6 +169,9 @@ function vpn_ipsec_configure($ipchg = false) {
|
||||
if ((is_array($ipseccfg['tunnel']) && count($ipseccfg['tunnel'])) ||
|
||||
isset($ipseccfg['mobileclients']['enable'])) {
|
||||
|
||||
$dnswatch_list = array();
|
||||
$rgmap = array();
|
||||
|
||||
if (is_array($ipseccfg['tunnel']) && count($ipseccfg['tunnel'])) {
|
||||
|
||||
/* generate spd.conf */
|
||||
@ -200,30 +192,47 @@ function vpn_ipsec_configure($ipchg = false) {
|
||||
continue;
|
||||
|
||||
$ep = vpn_endpoint_determine($tunnel, $curwanip);
|
||||
/* see if this tunnel has a hostname for the remote-gateway, and if so,
|
||||
* try to resolve it now and add it to the list for dnswatch */
|
||||
if (!is_ipaddr($tunnel['remote-gateway'])) {
|
||||
$dnswatch_list[] = $tunnel['remote-gateway'];
|
||||
$rgip = resolve_retry($tunnel['remote-gateway']);
|
||||
add_hostname_to_watch($tunnel['remote-gateway']);
|
||||
if (!$rgip) {
|
||||
log_error("Could not deterimine VPN endpoint for {$tunnel['descr']}");
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
$rgip = $tunnel['remote-gateway'];
|
||||
}
|
||||
$rgmap[$tunnel['remote-gateway']] = $rgip;
|
||||
if (!$ep) {
|
||||
log_error("Could not deterimine VPN endpoint for {$tunnel['descr']}");
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
vpn_localnet_determine($tunnel['local-subnet'], $sa, $sn);
|
||||
|
||||
if(is_domain($tunnel['remote-gateway'])) {
|
||||
$tmp = gethostbyname($tunnel['remote-gateway']);
|
||||
if($tmp)
|
||||
if($tmp) {
|
||||
$tunnel['remote-gateway'] = $tmp;
|
||||
}
|
||||
}
|
||||
|
||||
/* add entry to host pinger */
|
||||
if ($tunnel['pinghost']) {
|
||||
$pfd = fopen("/var/db/ipsecpinghosts", "a");
|
||||
$iflist = array("lan" => "lan", "wan" => "wan");
|
||||
for ($i = 1; isset($config['interfaces']['opt' . $i]); $i++)
|
||||
$iflist['opt' . $i] = "opt{$i}";
|
||||
foreach ($iflist as $ifent => $ifname) {
|
||||
$interface_ip = find_interface_ip($config['interfaces'][$ifname]['if']);
|
||||
if (ip_in_subnet($interface_ip, $sa . "/" . $sn))
|
||||
$srcip = find_interface_ip($config['interfaces'][$ifname]['if']);
|
||||
}
|
||||
for ($i = 1; isset($config['interfaces']['opt' . $i]); $i++)
|
||||
$iflist['opt' . $i] = "opt{$i}";
|
||||
|
||||
foreach ($iflist as $ifent => $ifname) {
|
||||
$interface_ip = find_interface_ip($config['interfaces'][$ifname]['if']);
|
||||
if (ip_in_subnet($interface_ip, $sa . "/" . $sn))
|
||||
$srcip = find_interface_ip($config['interfaces'][$ifname]['if']);
|
||||
}
|
||||
$dstip = $tunnel['pinghost'];
|
||||
fwrite($pfd, "$srcip|$dstip|3\n");
|
||||
fclose($pfd);
|
||||
@ -287,7 +296,10 @@ function vpn_ipsec_configure($ipchg = false) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
$racoonconf = "";
|
||||
$racoonconf = "# This file is automatically generated. Do not edit\n";
|
||||
$racoonconf .= "listen {\n";
|
||||
$racoonconf .= " adminsock \"/var/run/racoon.sock\" \"root\" \"wheel\" 0660;\n";
|
||||
$racoonconf .= "}\n";
|
||||
|
||||
$racoonconf .= "path pre_shared_key \"{$g['varetc_path']}/psk.txt\";\n\n";
|
||||
$racoonconf .= "path certificate \"{$g['varetc_path']}\";\n\n";
|
||||
@ -322,6 +334,10 @@ function vpn_ipsec_configure($ipchg = false) {
|
||||
if (isset($tunnel['disabled']))
|
||||
continue;
|
||||
|
||||
$rgip = $rgmap[$tunnel['remote-gateway']];
|
||||
if (!$rgip)
|
||||
continue;
|
||||
|
||||
$ep = vpn_endpoint_determine($tunnel, $curwanip);
|
||||
if (!$ep)
|
||||
continue;
|
||||
@ -411,11 +427,11 @@ EOD;
|
||||
}
|
||||
}
|
||||
$racoonconf .= <<<EOD
|
||||
remote {$tunnel['remote-gateway']} \{
|
||||
remote {$rgmap[$tunnel['remote-gateway']]} \{
|
||||
exchange_mode {$tunnel['p1']['mode']};
|
||||
my_identifier {$myidentt}{$myident};
|
||||
{$certline}
|
||||
peers_identifier address {$tunnel['remote-gateway']};
|
||||
peers_identifier address {$rgmap[$tunnel['remote-gateway']]};
|
||||
initial_contact on;
|
||||
#dpd_delay 120; # DPD poll every 120 seconds
|
||||
ike_frag on;
|
||||
@ -585,7 +601,12 @@ EOD;
|
||||
foreach ($ipseccfg['tunnel'] as $tunnel) {
|
||||
if (isset($tunnel['disabled']))
|
||||
continue;
|
||||
$pskconf .= "{$tunnel['remote-gateway']} {$tunnel['p1']['pre-shared-key']}\n";
|
||||
|
||||
$rgip = $rgmap[$tunnel['remote-gateway']];
|
||||
if (!$rgip)
|
||||
continue;
|
||||
|
||||
$pskconf .= "{$rgip} {$tunnel['p1']['pre-shared-key']}\n";
|
||||
}
|
||||
}
|
||||
|
||||
@ -601,31 +622,41 @@ EOD;
|
||||
chmod("{$g['varetc_path']}/psk.txt", 0600);
|
||||
|
||||
if(is_process_running("racoon")) {
|
||||
/* flush SPD entries */
|
||||
mwexec("/usr/local/sbin/setkey -FP");
|
||||
log_error("IPSEC: Send a reload signal to the IPsec process");
|
||||
sleep("0.1");
|
||||
mwexec("/usr/local/sbin/setkey -F");
|
||||
/* load SPD */
|
||||
sleep("0.1");
|
||||
mwexec("/usr/local/sbin/setkey -f {$g['varetc_path']}/spd.conf");
|
||||
/* We are already online, reload */
|
||||
sleep("0.1");
|
||||
mwexec("/usr/bin/killall -HUP racoon", true);
|
||||
mwexec("/usr/local/sbin/racoonctl -s /var/run/racoon.sock reload-config", false);
|
||||
// mwexec("/usr/bin/killall -HUP racoon", false);
|
||||
} else {
|
||||
/* flush SA + SPD entries */
|
||||
mwexec("/usr/local/sbin/setkey -FP");
|
||||
mwexec("/usr/local/sbin/setkey -FP", false);
|
||||
sleep("0.1");
|
||||
mwexec("/usr/local/sbin/setkey -F");
|
||||
mwexec("/usr/local/sbin/setkey -F", false);
|
||||
sleep("0.1");
|
||||
/* start racoon */
|
||||
mwexec("/usr/local/sbin/racoon -f {$g['varetc_path']}/racoon.conf");
|
||||
mwexec("/usr/local/sbin/racoon -f {$g['varetc_path']}/racoon.conf", false);
|
||||
sleep("0.1");
|
||||
/* load SPD */
|
||||
mwexec("/usr/local/sbin/setkey -f {$g['varetc_path']}/spd.conf");
|
||||
mwexec("/usr/local/sbin/setkey -f {$g['varetc_path']}/spd.conf", false);
|
||||
/* We are already online, reload */
|
||||
sleep("0.1");
|
||||
mwexec("/usr/bin/killall -HUP racoon", true);
|
||||
mwexec("/usr/bin/killall -HUP racoon", false);
|
||||
}
|
||||
|
||||
/* start dnswatch, if necessary */
|
||||
if (count($dnswatch_list) > 0) {
|
||||
$interval = 60;
|
||||
if ($ipseccfg['dns-interval'])
|
||||
$interval = $ipseccfg['dns-interval'];
|
||||
|
||||
$hostnames = "";
|
||||
foreach ($dnswatch_list as $dns)
|
||||
$hostnames .= " " . escapeshellarg($dns);
|
||||
killbypid("{$g['varrun_path']}/dnswatch-ipsec.pid");
|
||||
mwexec("/usr/local/sbin/dnswatch {$g['varrun_path']}/dnswatch-ipsec.pid $interval " .
|
||||
escapeshellarg("/etc/rc.newipsecdns") . $hostnames, false);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -1086,9 +1117,6 @@ function vpn_ipsec_force_reload() {
|
||||
|
||||
$ipseccfg = $config['ipsec'];
|
||||
|
||||
/* kill any ipsec communications regardless when we are invoked */
|
||||
mwexec("/sbin/ifconfig enc0 down");
|
||||
|
||||
/* kill racoon */
|
||||
mwexec("/usr/bin/killall racoon", true);
|
||||
|
||||
@ -1109,4 +1137,190 @@ function vpn_ipsec_force_reload() {
|
||||
|
||||
}
|
||||
|
||||
/* Walk the tunnels for hostname endpoints. If the hostnames
|
||||
* resolve to a different IP now compared to the DNS cache
|
||||
* we reload the policies if the endpoint has changed */
|
||||
function vpn_ipsec_refresh_policies() {
|
||||
global $config;
|
||||
global $g;
|
||||
|
||||
$ipseccfg = $config['ipsec'];
|
||||
|
||||
if (! isset($ipseccfg['enable'])) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Walk the Ipsec tunnel array */
|
||||
if (is_array($ipseccfg['tunnel']) && count($ipseccfg['tunnel'])) {
|
||||
foreach ($ipseccfg['tunnel'] as $tunnel) {
|
||||
if (isset($tunnel['disabled'])) {
|
||||
continue;
|
||||
}
|
||||
if (is_ipaddr($tunnel['remote-gateway'])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!is_ipaddr($tunnel['remote-gateway'])) {
|
||||
$dnscache = compare_hostname_to_dnscache($tunnel['remote-gateway']);
|
||||
$dnscache = trim($dnscache);
|
||||
/* we should have the old IP addresses in the dnscache now */
|
||||
if($dnscache <> "") {
|
||||
$oldtunnel = $tunnel;
|
||||
$oldtunnel['remote-gateway'] = trim($dnscache);
|
||||
reload_tunnel_spd_policy ($tunnel, $oldtunnel);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* process all generated spd.conf files from tmp which are left behind
|
||||
* behind by either changes of dynamic tunnels or manual edits
|
||||
* scandir() is only available in PHP5 */
|
||||
$tmpfiles = array();
|
||||
$dh = opendir($g['tmp_path']);
|
||||
while (false !== ($filename = readdir($dh))) {
|
||||
$tmpfiles[] = $filename;
|
||||
}
|
||||
sort($tmpfiles);
|
||||
foreach($tmpfiles as $tmpfile) {
|
||||
if(preg_match("/^spd.conf./", $tmpfile)) {
|
||||
$ret = mwexec("/usr/local/sbin/setkey -f {$g['tmp_path']}/{$tmpfile} 2>&1", false);
|
||||
if($ret == 0) {
|
||||
unlink("{$g['tmp_path']}/{$tmpfile}");
|
||||
} else {
|
||||
rename("{$g['tmp_path']}/{$tmpfile}", ("{$g['tmp_path']}/failed.{$tmpfile}"));
|
||||
}
|
||||
unlink("{$g['tmp_path']}/{$tmpfile}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function reload_tunnel_spd_policy($tunnel, $oldtunnel) {
|
||||
global $config;
|
||||
global $g;
|
||||
|
||||
/* if we are not passed a old tunnel array we create one */
|
||||
if(empty($oldtunnel)) {
|
||||
$oldtunnel = $tunnel;
|
||||
}
|
||||
|
||||
$curwanip = get_current_wan_address();
|
||||
$sad_arr = return_ipsec_sad_array();
|
||||
|
||||
$ep = vpn_endpoint_determine($tunnel, $curwanip);
|
||||
vpn_localnet_determine($tunnel['local-subnet'], $sa, $sn);
|
||||
|
||||
/* make sure we pass the oldtunnel array with a IP for the remote gw */
|
||||
$oldgw = trim($oldtunnel['remote-gateway']);
|
||||
$oldep = vpn_endpoint_determine($oldtunnel, $curwanip);
|
||||
vpn_localnet_determine($oldtunnel['local-subnet'], $oldsa, $oldsn);
|
||||
|
||||
/* see if this tunnel has a hostname for the remote-gateway, and if so,
|
||||
* try to resolve it now and add it to the list for dnswatch */
|
||||
if (!is_ipaddr($tunnel['remote-gateway'])) {
|
||||
$rgip = resolve_retry($tunnel['remote-gateway']);
|
||||
add_hostname_to_watch($tunnel['remote-gateway']);
|
||||
if (!$rgip) {
|
||||
log_error("Could not determine VPN endpoint for {$tunnel['descr']}");
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
$rgip = $tunnel['remote-gateway'];
|
||||
}
|
||||
if (!$ep) {
|
||||
log_error("Could not determine VPN endpoint for {$tunnel['descr']}");
|
||||
return false;
|
||||
}
|
||||
|
||||
$spdconf = "";
|
||||
|
||||
/* Delete old SPD policies if there are changes between the old and new */
|
||||
if(($tunnel != $oldtunnel) && (is_ipaddr($oldgw))) {
|
||||
$spdconf .= "spddelete {$oldsa}/{$oldsn} " .
|
||||
"{$oldtunnel['remote-subnet']} any -P out ipsec " .
|
||||
"{$oldtunnel['p2']['protocol']}/tunnel/{$oldep}-" .
|
||||
"{$oldgw}/unique;\n";
|
||||
$spdconf .= "spddelete {$oldtunnel['remote-subnet']} " .
|
||||
"{$oldsa}/{$oldsn} any -P in ipsec " .
|
||||
"{$oldtunnel['p2']['protocol']}/tunnel/{$oldgw}-" .
|
||||
"{$oldep}/unique;\n";
|
||||
|
||||
/* zap any existing SA entries */
|
||||
foreach($sad_arr as $sad) {
|
||||
if(($sad['dst'] == $oldep) && ($sad['src'] == $oldgw)) {
|
||||
$spdconf .= "delete {$oldep} {$oldgw} {$tunnel['p2']['protocol']} 0x{$sad['spi']};\n";
|
||||
}
|
||||
if(($sad['src'] == $oldep) && ($sad['dst'] == $oldgw)) {
|
||||
$spdconf .= "delete {$oldgw} {$oldep} {$tunnel['p2']['protocol']} 0x{$sad['spi']};\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Create new SPD entries for the new configuration */
|
||||
/* zap any existing SA entries beforehand */
|
||||
foreach($sad_arr as $sad) {
|
||||
if(($sad['dst'] == $ep) && ($sad['src'] == $rgip)) {
|
||||
$spdconf .= "delete {$ep} {$rgip} {$tunnel['p2']['protocol']} 0x{$sad['spi']};\n";
|
||||
}
|
||||
if(($sad['src'] == $ep) && ($sad['dst'] == $rgip)) {
|
||||
$spdconf .= "delete {$rgip} {$ep} {$tunnel['p2']['protocol']} 0x{$sad['spi']};\n";
|
||||
}
|
||||
}
|
||||
/* add new SPD policies to replace them */
|
||||
$spdconf .= "spdadd {$sa}/{$sn} " .
|
||||
"{$tunnel['remote-subnet']} any -P out ipsec " .
|
||||
"{$tunnel['p2']['protocol']}/tunnel/{$ep}-" .
|
||||
"{$rgip}/unique;\n";
|
||||
$spdconf .= "spdadd {$tunnel['remote-subnet']} " .
|
||||
"{$sa}/{$sn} any -P in ipsec " .
|
||||
"{$tunnel['p2']['protocol']}/tunnel/{$rgip}-" .
|
||||
"{$ep}/unique;\n";
|
||||
|
||||
log_error("IPSEC: Tunnel '{$tunnel['descr']}' has changed IP from '{$oldgw}' to '{$rgip}', reloading policy");
|
||||
|
||||
$now = time();
|
||||
$spdfile = tempnam("{$g['tmp_path']}", "spd.conf.reload.{$now}.");
|
||||
/* generate temporary spd.conf */
|
||||
file_put_contents($spdfile, $spdconf);
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Dump SAD database to array */
|
||||
function return_ipsec_sad_array() {
|
||||
/* query SAD */
|
||||
$fd = @popen("/usr/local/sbin/setkey -D", "r");
|
||||
$sad = array();
|
||||
if ($fd) {
|
||||
while (!feof($fd)) {
|
||||
$line = chop(fgets($fd));
|
||||
if (!$line)
|
||||
continue;
|
||||
if ($line == "No SAD entries.")
|
||||
break;
|
||||
if ($line[0] != "\t") {
|
||||
if (is_array($cursa))
|
||||
$sad[] = $cursa;
|
||||
$cursa = array();
|
||||
list($cursa['src'],$cursa['dst']) = explode(" ", $line);
|
||||
$i = 0;
|
||||
} else {
|
||||
$linea = explode(" ", trim($line));
|
||||
if ($i == 1) {
|
||||
$cursa['proto'] = $linea[0];
|
||||
$cursa['spi'] = substr($linea[2], strpos($linea[2], "x")+1, -1);
|
||||
} else if ($i == 2) {
|
||||
$cursa['ealgo'] = $linea[1];
|
||||
} else if ($i == 3) {
|
||||
$cursa['aalgo'] = $linea[1];
|
||||
}
|
||||
}
|
||||
$i++;
|
||||
}
|
||||
if (is_array($cursa) && count($cursa))
|
||||
$sad[] = $cursa;
|
||||
pclose($fd);
|
||||
}
|
||||
return($sad);
|
||||
}
|
||||
|
||||
?>
|
||||
|
||||
52
etc/rc.newipsecdns
Executable file
52
etc/rc.newipsecdns
Executable file
@ -0,0 +1,52 @@
|
||||
#!/usr/local/bin/php -f
|
||||
<?php
|
||||
/*
|
||||
$Id$
|
||||
part of m0n0wall (http://m0n0.ch/wall)
|
||||
|
||||
Copyright (C) 2007 Manuel Kasper <mk@neon1.net>.
|
||||
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.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS 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
|
||||
AUTHOR 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.
|
||||
*/
|
||||
|
||||
/* parse the configuration and include all functions used below */
|
||||
require_once("config.inc");
|
||||
require_once("functions.inc");
|
||||
|
||||
/* make sure to wait until the boot scripts have finished */
|
||||
while (file_exists("{$g['varrun_path']}/booting")) {
|
||||
sleep(1);
|
||||
}
|
||||
|
||||
log_error("IPSEC: One or more IPSEC tunnel endpoints has changed IP. Refreshing.");
|
||||
/* We will walk the list of hostnames found in the ipsec tunnel
|
||||
* configuration. Since we are already triggered by dnswatch
|
||||
* that a hostname has changed we can proceed to compare the
|
||||
* new IP address with the old address from the DNS cache.
|
||||
*/
|
||||
vpn_ipsec_refresh_policies();
|
||||
|
||||
vpn_ipsec_configure();
|
||||
|
||||
?>
|
||||
|
||||
@ -34,6 +34,50 @@ $pgtitle = "Status: IPsec";
|
||||
|
||||
require("guiconfig.inc");
|
||||
include("head.inc");
|
||||
|
||||
function get_ipsec_tunnel_src($tunnel) {
|
||||
global $g, $config, $sad;
|
||||
$if = "WAN";
|
||||
if ($tunnel['interface']) {
|
||||
$if = $tunnel['interface'];
|
||||
$realinterface = convert_friendly_interface_to_real_interface_name($if);
|
||||
$interfaceip = find_interface_ip($realinterface);
|
||||
}
|
||||
return $interfaceip;
|
||||
}
|
||||
|
||||
function output_ipsec_tunnel_status($tunnel) {
|
||||
global $g, $config, $sad;
|
||||
$if = "WAN";
|
||||
$interfaceip = get_ipsec_tunnel_src($tunnel);
|
||||
$foundsrc = false;
|
||||
$founddst = false;
|
||||
if(!is_ipaddr($tunnel['remote-gateway']))
|
||||
$tunnel['remote-gateway'] = resolve_retry($tunnel['remote-gateway']);
|
||||
|
||||
foreach($sad as $sa) {
|
||||
if($sa['src'] == $interfaceip)
|
||||
$foundsrc = true;
|
||||
if($sa['dst'] == $tunnel['remote-gateway'])
|
||||
$founddst = true;
|
||||
}
|
||||
if($foundsrc && $founddst) {
|
||||
/* tunnel is up */
|
||||
$iconfn = "pass";
|
||||
} else {
|
||||
/* tunnel is down */
|
||||
$iconfn = "reject";
|
||||
}
|
||||
echo "<img src ='/themes/{$g['theme']}/images/icons/icon_{$iconfn}.gif'>";
|
||||
}
|
||||
|
||||
/* query SAD */
|
||||
$sad = return_ipsec_sad_array();
|
||||
|
||||
if (!is_array($config['ipsec']['tunnel'])) {
|
||||
$config['ipsec']['tunnel'] = array();
|
||||
}
|
||||
|
||||
?>
|
||||
|
||||
<body link="#0000CC" vlink="#0000CC" alink="#0000CC" onload="<?= $jsevents["body"]["onload"] ?>">
|
||||
@ -54,47 +98,6 @@ include("head.inc");
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<?php
|
||||
|
||||
/* query SAD */
|
||||
$fd = @popen("/usr/local/sbin/setkey -D", "r");
|
||||
$sad = array();
|
||||
if ($fd) {
|
||||
while (!feof($fd)) {
|
||||
$line = chop(fgets($fd));
|
||||
if (!$line)
|
||||
continue;
|
||||
if ($line == "No SAD entries.")
|
||||
break;
|
||||
if ($line[0] != "\t") {
|
||||
if (is_array($cursa))
|
||||
$sad[] = $cursa;
|
||||
$cursa = array();
|
||||
list($cursa['src'],$cursa['dst']) = explode(" ", $line);
|
||||
$i = 0;
|
||||
} else {
|
||||
$linea = explode(" ", trim($line));
|
||||
if ($i == 1) {
|
||||
$cursa['proto'] = $linea[0];
|
||||
$cursa['spi'] = substr($linea[2], strpos($linea[2], "x")+1, -1);
|
||||
} else if ($i == 2) {
|
||||
$cursa['ealgo'] = $linea[1];
|
||||
} else if ($i == 3) {
|
||||
$cursa['aalgo'] = $linea[1];
|
||||
}
|
||||
}
|
||||
$i++;
|
||||
}
|
||||
if (is_array($cursa) && count($cursa))
|
||||
$sad[] = $cursa;
|
||||
pclose($fd);
|
||||
}
|
||||
|
||||
if (!is_array($config['ipsec']['tunnel'])) {
|
||||
$config['ipsec']['tunnel'] = array();
|
||||
}
|
||||
|
||||
?>
|
||||
<div id="mainarea">
|
||||
<table class="tabcont" width="100%" border="0" cellpadding="6" cellspacing="0">
|
||||
<?php if (count($sad)): ?>
|
||||
@ -162,40 +165,3 @@ foreach ($config['ipsec']['tunnel'] as $ipsec) {
|
||||
<?php include("fend.inc"); ?>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
<?php
|
||||
|
||||
function get_ipsec_tunnel_src($tunnel) {
|
||||
global $g, $config, $sad;
|
||||
$if = "WAN";
|
||||
if ($tunnel['interface']) {
|
||||
$if = $tunnel['interface'];
|
||||
$realinterface = convert_friendly_interface_to_real_interface_name($if);
|
||||
$interfaceip = find_interface_ip($realinterface);
|
||||
}
|
||||
return $interfaceip;
|
||||
}
|
||||
|
||||
function output_ipsec_tunnel_status($tunnel) {
|
||||
global $g, $config, $sad;
|
||||
$if = "WAN";
|
||||
$interfaceip = get_ipsec_tunnel_src($tunnel);
|
||||
$foundsrc = false;
|
||||
$founddst = false;
|
||||
foreach($sad as $sa) {
|
||||
if($sa['src'] == $interfaceip)
|
||||
$foundsrc = true;
|
||||
if($sa['dst'] == $tunnel['remote-gateway'])
|
||||
$founddst = true;
|
||||
}
|
||||
if($foundsrc && $founddst) {
|
||||
/* tunnel is up */
|
||||
$iconfn = "pass";
|
||||
} else {
|
||||
/* tunnel is down */
|
||||
$iconfn = "reject";
|
||||
}
|
||||
echo "<img src ='/themes/{$g['theme']}/images/icons/icon_{$iconfn}.gif'>";
|
||||
}
|
||||
|
||||
?>
|
||||
|
||||
@ -66,38 +66,8 @@ if ($_GET['act'] == "del") {
|
||||
}
|
||||
|
||||
/* query SAD */
|
||||
$fd = @popen("/usr/local/sbin/setkey -D", "r");
|
||||
$sad = array();
|
||||
if ($fd) {
|
||||
while (!feof($fd)) {
|
||||
$line = chop(fgets($fd));
|
||||
if (!$line)
|
||||
continue;
|
||||
if ($line == "No SAD entries.")
|
||||
break;
|
||||
if ($line[0] != "\t") {
|
||||
if (is_array($cursa))
|
||||
$sad[] = $cursa;
|
||||
$cursa = array();
|
||||
list($cursa['src'],$cursa['dst']) = explode(" ", $line);
|
||||
$i = 0;
|
||||
} else {
|
||||
$linea = explode(" ", trim($line));
|
||||
if ($i == 1) {
|
||||
$cursa['proto'] = $linea[0];
|
||||
$cursa['spi'] = substr($linea[2], strpos($linea[2], "x")+1, -1);
|
||||
} else if ($i == 2) {
|
||||
$cursa['ealgo'] = $linea[1];
|
||||
} else if ($i == 3) {
|
||||
$cursa['aalgo'] = $linea[1];
|
||||
}
|
||||
}
|
||||
$i++;
|
||||
}
|
||||
if (is_array($cursa) && count($cursa))
|
||||
$sad[] = $cursa;
|
||||
pclose($fd);
|
||||
}
|
||||
$sad = return_ipsec_sad_array();
|
||||
|
||||
?>
|
||||
<div id="mainarea">
|
||||
<table class="tabcont" width="100%" border="0" cellpadding="6" cellspacing="0">
|
||||
|
||||
@ -40,6 +40,9 @@ $search = array();
|
||||
$replace = array();
|
||||
if(is_array($config['ipsec']['tunnel']))
|
||||
foreach($config['ipsec']['tunnel'] as $tunnel) {
|
||||
if(!is_ipaddr($tunnel['remote-gateway']))
|
||||
$tunnel['remote-gateway'] = resolve_retry($tunnel['remote-gateway']);
|
||||
|
||||
$gateway = "{$tunnel['remote-gateway']}";
|
||||
$search[] = "/(racoon: )([A-Z:].*?)({$gateway}\[[0-9].+\]|{$gateway})(.*)/i";
|
||||
$replace[] = "$1<strong>[{$tunnel['descr']}]</strong>: $2$3$4";
|
||||
|
||||
@ -43,7 +43,10 @@ if ($_POST) {
|
||||
|
||||
if ($_POST['apply']) {
|
||||
$retval = 0;
|
||||
$retval = vpn_ipsec_refresh_policies();
|
||||
$retval = vpn_ipsec_configure();
|
||||
/* reload the filter in the background */
|
||||
filter_configure();
|
||||
$savemsg = get_std_save_message($retval);
|
||||
if ($retval == 0) {
|
||||
if (file_exists($d_ipsecconfdirty_path))
|
||||
@ -59,6 +62,7 @@ if ($_POST) {
|
||||
|
||||
$retval = 0;
|
||||
config_lock();
|
||||
$retval = vpn_ipsec_refresh_policies();
|
||||
$retval = vpn_ipsec_configure();
|
||||
config_unlock();
|
||||
/* reload the filter in the background */
|
||||
@ -76,9 +80,11 @@ if ($_GET['act'] == "del") {
|
||||
if ($a_ipsec[$_GET['id']]) {
|
||||
/* remove static route if interface is not WAN */
|
||||
if($a_ipsec[$_GET['id']]['interface'] <> "wan") {
|
||||
mwexec("/sbin/route delete -host {$$a_ipsec[$_GET['id']]['remote-gateway']}");
|
||||
$oldgw = resolve_retry($a_ipsec[$_GET['id']]['remote-gateway']);
|
||||
mwexec("/sbin/route delete -host {$oldgw}");
|
||||
}
|
||||
unset($a_ipsec[$_GET['id']]);
|
||||
vpn_ipsec_configure();
|
||||
filter_configure();
|
||||
write_config();
|
||||
header("Location: vpn_ipsec.php");
|
||||
@ -99,7 +105,8 @@ include("head.inc");
|
||||
<?php if ($savemsg) print_info_box($savemsg); ?>
|
||||
<?php if (file_exists($d_ipsecconfdirty_path)): ?><p>
|
||||
<?php if ($pconfig['enable'])
|
||||
print_info_box_np("The IPsec tunnel configuration has been changed.<br>You must apply the changes in order for them to take effect.");?><br>
|
||||
print_info_box_np("The IPsec tunnel configuration has been changed.<br>You must apply the changes
|
||||
in order for them to take effect.");?><br>
|
||||
<?php endif; ?>
|
||||
<table width="100%" border="0" cellpadding="0" cellspacing="0">
|
||||
<tr><td class="tabnavtbl">
|
||||
|
||||
@ -46,6 +46,7 @@ if (isset($_GET['dup'])) {
|
||||
}
|
||||
|
||||
if (isset($id) && $a_ipsec[$id]) {
|
||||
$oldipsecent = $a_ipsec[$id];
|
||||
$pconfig['disabled'] = isset($a_ipsec[$id]['disabled']);
|
||||
$pconfig['auto'] = isset($a_ipsec[$id]['auto']);
|
||||
|
||||
@ -61,6 +62,7 @@ if (isset($id) && $a_ipsec[$id]) {
|
||||
|
||||
list($pconfig['remotenet'],$pconfig['remotebits']) = explode("/", $a_ipsec[$id]['remote-subnet']);
|
||||
$pconfig['remotegw'] = $a_ipsec[$id]['remote-gateway'];
|
||||
|
||||
$pconfig['p1mode'] = $a_ipsec[$id]['p1']['mode'];
|
||||
|
||||
if (isset($a_ipsec[$id]['p1']['myident']['myaddress']))
|
||||
@ -209,13 +211,24 @@ if ($_POST) {
|
||||
$ipsecent['interface'] = $pconfig['interface'];
|
||||
pconfig_to_address($ipsecent['local-subnet'], $_POST['localnet'], $_POST['localnetmask']);
|
||||
$ipsecent['remote-subnet'] = $_POST['remotenet'] . "/" . $_POST['remotebits'];
|
||||
/* if the remote gateway changed and the interface is not WAN then remove route */
|
||||
/* the vpn_ipsec_configure() handles adding the route */
|
||||
if($_POST['interface'] <> "wan") {
|
||||
if($ipsecent['remote-gateway'] <> $_POST['remotegw']) {
|
||||
|
||||
/* if the old endpoint is different from the new one we make sure to purge
|
||||
* the old policy and add a new one. If the old endpoint IP is empty we
|
||||
* only add new SPD entries. */
|
||||
if(!is_ipaddr($oldipsecent['remote-gateway'])) {
|
||||
$oldipsecent['remote-gateway'] = resolve_retry($oldipsecent['remote-gateway']);
|
||||
}
|
||||
if($ipsecent['remote-gateway'] <> $_POST['remotegw']) {
|
||||
if(!is_ipaddr($ipsecent['remote-gateway'])) {
|
||||
$ipsecent['remote-gateway'] = resolve_retry($ipsecent['remote-gateway']);
|
||||
}
|
||||
/* if the remote gateway changed and the interface is not WAN then remove route */
|
||||
/* the vpn_ipsec_configure() handles adding the route */
|
||||
if($_POST['interface'] <> "wan") {
|
||||
mwexec("/sbin/route delete -host {$ipsecent['remote-gateway']}");
|
||||
}
|
||||
}
|
||||
|
||||
$ipsecent['remote-gateway'] = $_POST['remotegw'];
|
||||
$ipsecent['p1']['mode'] = $_POST['p1mode'];
|
||||
|
||||
@ -261,6 +274,7 @@ if ($_POST) {
|
||||
$a_ipsec[] = $ipsecent;
|
||||
|
||||
write_config();
|
||||
reload_tunnel_spd_policy($ipsecent, $oldipsecent);
|
||||
touch($d_ipsecconfdirty_path);
|
||||
|
||||
header("Location: vpn_ipsec.php");
|
||||
@ -401,7 +415,7 @@ function methodsel_change() {
|
||||
<td width="78%" class="vtable">
|
||||
<?=$mandfldhtml;?><input name="remotegw" type="text" class="formfld" id="remotegw" size="20" value="<?=$pconfig['remotegw'];?>">
|
||||
<br>
|
||||
Enter the public IP address of the remote gateway</td>
|
||||
Enter the public IP address or hostname of the remote gateway</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="22%" valign="top" class="vncell">Description</td>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user