I'm not a fulltime programmer so I don't think like a geek. I just made it work for my case. If it's usefull, please feel free to use it. I will be very happy if I know that it's intergrated into pfsense. I can sleep with a happy face :)
The three main files that I modified are: filter.inc, dyndns.class, and pfsense-utils.inc (see attached files). As always, diff is really useful to checkout the differences. It's not much coding, here are all of my codes & modifications:
//
/ File: /etc/inc/filter.inc /
/ At the end of the function filter_configure_sync add /
/ the new wan_monitor() function in /
//
/* reload filter sync /
function filter_configure_sync() {
…
/ sync carp entries to other firewalls */
update_filter_reload_status("Syncing CARP data");
carp_sync_client();
/* WAN monitoring */
wan_monitor();
update_filter_reload_status("Done");
return 0;
}
function wan_monitor() {
global $config;
$failure = 0;
update_filter_reload_status("Debug: WAN Monitoring");
foreach ($config['filter']['rule'] as $rule) {
if ($rule['gateway'] <> "") {
$rulegw = $rule['gateway'];
}
}
foreach($config['load_balancer']['lbpool'] as $lb) {
$poolname = $lb['name'];
$servers = $lb['servers'];
if ($poolname == $rulegw) {
if($lb['behaviour'] == "failover") {
$routeto = exec("cat /tmp/rules.debug | grep route-to | cut -d '(' -f2 | cut -d ')' -f1 | /usr/bin/sed -e 's/^ //g'");
list($int, $gateway) = split(" ", $routeto);
$default_route = exec("netstat -rn | grep default | awk '{print $2, $6}'");
list($default_gw, $default_int) = split(" ", $default_route);
if ($default_gw != $gateway && $gateway <> "" ) {
$wan1_gw = $config['interfaces']['wan']['gateway'];
list($int_name, $monIP) = split("|", $servers[0]);
/* Double check by ping to the host monitor IP 3 times */
for ($i = 1; $i <= 3; $i++) {
$pingstatus = exec("/sbin/ping -c 1 -t 2 -q -Q $monIP | grep 'packet loss' | cut -d ',' -f3 | /usr/bin/sed -e 's/^ //g' | cut -d '%' -f1");
if ($pingstatus == 100) {
$failure++;
}
sleep (5);
}
/* If total failure is 3 times, then switch the default route /
if ($failure == 3) {
$switchroute = 1;
}
/ Switch back to WAN1 if the host monitor IP is pingable /
/ and the default gateway is on WAN2 */
else if ($failure == 0 && $default_gw != $wan1_gw) {
$switchroute = 1;
}
else {
$switchroute = 0;
}
update_filter_reload_status("Debug: Switch Route = $switchroute");
update_filter_reload_status("Debug: Total Failure time = $failure");
}
else {
update_filter_reload_status("Debug: Do nothing. Same route");
}
if ($switchroute == 1) {
update_filter_reload_status("Debug: Changing the default gateway to $gateway");
exec("/sbin/route delete default");
exec("/sbin/route add default $gateway");
update_filter_reload_status("Debug: Sending email notification");
$hostname = exec("hostname");
$subject = "$hostname has switched the default gateway to $gateway";
$msg = "This is an automate email notification that the default gateway has switched over to ";
$msg .= "$gateway\n";
$to = "email@company.com";
exec("/usr/local/bin/php /root/my-scripts/phpmailer/smtp.php "$subject" "$msg" $to");
}
$is_carp_enable = get_carp_status();
if ($is_carp_enable == 1) {
foreach($config['virtualip']['vip'] as $carp) {
if ($carp['mode'] != "carp") continue;
$ipaddress = $carp['subnet'];
$carp_int = find_carp_interface($ipaddress);
$carp_status = get_carp_interface_status($carp_int);
update_filter_reload_status("Debug: $carp_status");
}
}
if ($carp_status == "MASTER") {
update_filter_reload_status("Debug: Updating with DynDNS");
exec("/etc/rc.dyndns.update");
}
update_filter_reload_status("Debug: End");
}
}
}
}
//
/ File: /etc/inc/dyndns.class /
/ Replace $wan_ip to use $this->_checkip() function to /
/ get the real WAN IP to use with Dyndns /
//
if(!$wan_ip)
$wan_ip = $this->_checkip();
function _checkip() {
//log_error("DynDns: Running _checkip() for real WAN IP");
exec("/usr/bin/netstat -rn | grep carp | awk '{print $1, $6}'", $getcarp);
list($gwip, $gwint) = split(" ", /usr/bin/netstat -rn | grep default | awk '{print $2, $6}');
$gwip = str_replace("\n", "", $gwip);
$gwint = str_replace("\n", "", $gwint);
if ($getcarp[0] <> "") {
foreach ($getcarp as $carpinfo) {
list($carpip, $carpname) = split(" ", $carpinfo);
$carp_int = $this->_getcarp_int($carpip);
if ($gwint == "$carp_int") {
$match = exec("echo $carpinfo | grep $carpname");
list($gwvip, $gwcarp) = split(" ", $match);
$ip = $gwvip;
}
}
}
else {
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, 'http://checkip.dyndns.com');
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
$data = curl_exec($ch);
curl_close($ch);
list($part1, $part2) = split(': ', $data, 2);
list($ip, $junk) = split('<', $part2);
}
return $ip;
}
/* End of function */
function _getcarp_int($carpip) {
global $config;
foreach($config['virtualip']['vip'] as $vip) {
if ($vip['subnet'] == "$carpip") {
$int_name = $vip['interface'];
$int = convert_friendly_interface_to_real_interface_name($int_name);
}
}
return $int;
}
/*
* Private Function (added 12 July 05) [beta]
* - Detect whether or not IP needs to be updated.
* | Written Specifically for pfSense (pfsense.com) may
* | work with other systems. pfSense base is FreeBSD.
*/
function _detectChange() {
global $config;
log_error("DynDns: _detectChange() starting.");
$currentTime = time();
$wan_ip = $this->_checkip();
$this->_dnsIP = $wan_ip;
$this->_dnsHost = $config['dyndns']['host'];
$previousIP = exec("/sbin/ping -c1 $this->_dnsHost | grep PING | cut -d '(' -f2 | cut -d ')' -f1");
log_error("DynDns: Previous DNS IP: {$previousIP}");
log_error("DynDns: Current WAN IP: {$wan_ip}");
if (file_exists($this->_cacheFile)) {
if(file_exists($this->_cacheFile))
$contents = file_get_contents($this->_cacheFile);
else
$contents = "";
list($cacheIP,$cacheTime) = split(':', $contents);
$this->_debug($cacheIP.'/'.$cacheTime);
$initial = false;
log_error("DynDns: Cached IP: {$cacheIP}");
} else {
conf_mount_rw();
$file = fopen($this->_cacheFile, 'w');
fwrite($file, '0.0.0.0:'.$currentTime);
fclose($file);
conf_mount_ro();
$cacheIP = '0.0.0.0';
$cacheTime = $currentTime;
$initial = true;
log_error("DynDns: No Cached IP found.");
}
/* use 2419200 for dyndns, dhs, easydns, noip, hn
* zoneedit, dyns, ods
*/
$time = '2160000';
$needs_updating = FALSE;
/* lets deterimine if the item needs updating /
if ($previousIP != $wan_ip) {
$needs_updating = TRUE;
log_error("DynDns: previousIP != wan_ip. Updating.");
}
if ($cacheIP != $wan_ip) {
$needs_updating = TRUE;
log_error("DynDns: cacheIP != wan_ip. Updating.");
}
$update_reason = "Cached IP: {$cacheIP} WAN IP: {$wan_ip} ";
if (($currentTime - $cacheTime) > $time ) {
$needs_updating = TRUE;
log_error("DynDns: More than 25 days. Updating.");
}
$update_reason .= "{$currentTime} - {$cacheTime} > {$time} ";
if ($initial == TRUE) {
$needs_updating = TRUE;
$update_reason .= "Inital update. ";
log_error("DynDns: Initial run. Updating.");
}
/ finally if we need updating then store the
* new cache value and return true
*/
if($needs_updating == TRUE) {
return TRUE;
} else {
return FALSE;
}
log_error("DynDns debug information: {$update_reason}");
}
filter.inc.txt
dyndns.class.txt
pfsense-utils.inc.txt