Dynamic IPSEC remote gateway addresses on TMG and ISA

 If you've worked with Microsoft ISA and now Forefront TMG 2010 IPSEC VPNs, you will know that dynamic end point addresses are not supported. This would be a great feature to have, especially since home and small office connections are less expensive or only available with dynamic (DHCP) addressing. Luckily, services that support DDNS (Dynamic DNS) such as DynDns.org are available to allow locations with a changing IP address to have a consistent DNS address. This is even supported on a number of SOHO router/Firewall platforms. I came across a need to connect a number of branch offices and home offices via IPSEC to a main location. The main reason was to support the VoIP phones that we had without tunneling or other protocols that not all the phones supported. We tried PPTP site-to-site tunnels, but those were problematic due to inconsistent NAT support on the different platforms. We found that IPSEC was the only good option to go with on our TMG servers, so we found a remote/branch/home office router that fit the bill for supporting IPSEC tunnels, being inexpensive and supporting all the typical NAT and firewall functions needed for normal internet connectivity.

 

The router we chose was a Cisco/Linksys RVS4400, and I believe most of the 4000 line is very similar. This overall process should actually work for any device that supports IPSEC tunnels (ESP tunnel mode on the device itself, not just IPSEC VPN pass-thru). As I mentioned, the VPN head-end is TMG 2010, operating on a static IP address. If you have TMG/ISA operating on a dynamic address, there are some good directions here, but I'm focusing on the remote DDNS locations, as I could not find a script anywhere that addressed that issue...

 

The script basically does the following:

  1. Looks up the DNS record specified and returns the IP address
  2. Gets the current remote IP address associated with the specified VPN connection (Name)
  3. Check to see if the IP addresses match
  4. If they don't match, change the IPSEC's stored address for the remote site to the new IP address
  5. It appears that IPSEC automatically detects the changes and reconnects the VPN
  6. Write results to log file
  7. Write to the event log if there is a change

I simply named this to a .ps1 file and put it in a folder called "c:\scripts" (folder required) and scheduled via task scheduler to run every 15 minutes and viola, we have a dynamically addressed IPSEC VPN connection to a location that is on DHCP.

 

Code:

$startstring="Start script run at:  "
$startendtime=date
$startannounce=$startstring+$startendtime

#enter the name of your VPN, must be an exact match
$varRemoteName = "vpnNameinTMG"

#enter the DNS name of your remote site
$comp = "DNSnameOfRemoteSite.dyndns.org"

#enter your DNS server
$ns = "8.8.8.8" 

#end input global variables


# ==========================================
# FORWARD DNS RESOLUTON WITH NSLOOKUP
# This function calls nslookup (which is a standard microsoft tool)
# and fetches from the output string just the IP address.
# You can specify a Name Server to use.
# Please note the $Comp can be an array, in which case you should
# run into it with foreach().
# ==========================================
Function forward_dns
{
$cmd = "nslookup " + $args[0] + " " + $ns
$result = Invoke-Expression ($cmd)
trap
{
$global:controlladns = $true
$global:solved_ip = "No record found"
continue
}
$global:controlladns = $false
$global:solved_ip = $result.SyncRoot[4]
if (-not $global:controlladns)
{
$leng = $global:solved_ip.Length -10
$global:solved_ip =
$global:solved_ip.substring(10,$leng)
}
}
forward_dns $comp
echo "Host: $comp - IP : $global:solved_ip - NS: $ns"
# ==========================================

#function to write event to Windows event log
function writeEventlogEntry([string]$eventChangeMade)
{
$evt=new-object System.Diagnostics.EventLog("Application")
$evt.Source="IPSEC VPN Remote Endpoint Change"
$infoevent=[System.Diagnostics.EventLogEntryType]::Warning
$1stpart="IPSEC VPN Remote Endpoint Change: "
$2ndpart=" , see log for more details at C:\scripts"
$eventStringfull=$1stpart+$varRemoteName+$eventChangeMade+$2ndpart
$evt.WriteEntry($eventStringfull,$infoevent,1111)
}
# ==========================================

Start-Transcript -Append -Force -Path 'C:\scripts\VPN-remote-IP-changes.log'
$startannounce
" "
#begin main program

$root = New-Object -comObject "FPC.Root" -strict
$server = $root.Arrays | Select-Object -first 1
$newRemoteIP = $solved_ip
$ipSecSite2SiteNetwork = $server.NetworkConfiguration.Networks | Where-Object { $_.NetworkConnectionType -eq 4 } | where-object {$_.Name -eq $varRemoteName}
$remoteIP = $ipSecSite2SiteNetwork.VpnConfiguration.IPSecSettings.RemoteServerAddress
$remoteName = $ipSecSite2SiteNetwork.Name

Write-Output ""
Write-Output "Found Network Named:"
Write-Output $remoteName
Write-Output ""
Write-Output "Remote IP address is currently:"
Write-Output $remoteIP
Write-Output ""
Write-Output "IP adress should be:"
Write-Output $newRemoteIP
Write-Output ""

#Makes changes as needed
If ($remoteIP -ne $newRemoteIP){$ipSecSite2SiteNetwork.VpnConfiguration.IPSecSettings.RemoteServerAddress = $newRemoteIP; $ipSecSite2SiteNetwork.VpnConfiguration.IPSecSettings.Save() ; Write-Output "Remote IP changed from: " $remoteIP " To: " $newRemoteIP " for VPN Named: " $remoteName ; writeEventlogEntry $newRemoteIP}
else{Write-Output "Remote IP is correct for IPSEC VPN named:" $remoteName}

#end main program
" "

stop-transcript


#exit default if no changes made
exit