Along with their anti-spam Block Lists, Spamhaus also provide a DROP list, which is a list of stolen ‘hijacked’ netblocks and netblocks controlled entirely by criminals and professional spammers. As nothing good can come out of these ranges, it’s handy to block them outright at the firewall level, if that firewall happens to be TMG or ISA you can make use of the following script to keep the DROP list up-to-date.
The IP address conversion functions in this script are all courtesy of Chris Dent of www.indented.co.uk and were a godsend. To make use of this script you will need to create your Network object in ISA/TMG and update the network name in the following code to match $ipranges = $server.NetworkConfiguration.Networks.item("Spamhaus DROP List").IpRangeSet. You will also need to set $dropfile to match the location where you will be storing the downloaded DROP List, this needs to be retained so that updates can easily do a diff on the file without having to query ISA/TMG, which is much slower. Create a blank text file matching this filename & path before running the script for the first time.
<# Copyright (c) 2013, Adam Beardwood 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR 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. The views and conclusions contained in the software and documentation are those of the authors and should not be interpreted as representing official policies, either expressed or implied, of the FreeBSD Project. #> #Grab Spamhaus DROP List and update TMG network sets based on changes #IP Conversion Functions Courtesy of Chris Dent - http://www.indented.co.uk/index.php/2010/01/23/powershell-subnet-math/ #Adam Beardwood 26/03/2013 #v1.0 - Initial Release #v1.1 - Considerable improvements to error checking Function ConvertTo-DottedDecimalIP { <# .Synopsis Returns a dotted decimal IP address from either an unsigned 32-bit integer or a dotted binary string. .Description ConvertTo-DottedDecimalIP uses a regular expression match on the input string to convert to an IP address. .Parameter IPAddress A string representation of an IP address from either UInt32 or dotted binary. #> [CmdLetBinding()] Param( [Parameter(Mandatory = $True, Position = 0, ValueFromPipeline = $True)] [String]$IPAddress ) Process { Switch -RegEx ($IPAddress) { "([01]{8}\.){3}[01]{8}" { Return [String]::Join('.', $( $IPAddress.Split('.') | ForEach-Object { [Convert]::ToUInt32($_, 2) } )) } "\d" { $IPAddress = [UInt32]$IPAddress $DottedIP = $( For ($i = 3; $i -gt -1; $i--) { $Remainder = $IPAddress % [Math]::Pow(256, $i) ($IPAddress - $Remainder) / [Math]::Pow(256, $i) $IPAddress = $Remainder } ) Return [String]::Join('.', $DottedIP) } default { Write-Error "Cannot convert this format" } } } } Function ConvertTo-DecimalIP { <# .Synopsis Converts a Decimal IP address into a 32-bit unsigned integer. .Description ConvertTo-DecimalIP takes a decimal IP, uses a shift-like operation on each octet and returns a single UInt32 value. .Parameter IPAddress An IP Address to convert. #> [CmdLetBinding()] Param( [Parameter(Mandatory = $True, Position = 0, ValueFromPipeline = $True)] [Net.IPAddress]$IPAddress ) Process { $i = 3; $DecimalIP = 0; $IPAddress.GetAddressBytes() | ForEach-Object { $DecimalIP += $_ * [Math]::Pow(256, $i); $i-- } Return [UInt32]$DecimalIP } } Function Get-BroadcastAddress { <# .Synopsis Takes an IP address and subnet mask then calculates the broadcast address for the range. .Description Get-BroadcastAddress returns the broadcast address for a subnet by performing a bitwise AND operation against the decimal forms of the IP address and inverted subnet mask. Get-BroadcastAddress expects both the IP address and subnet mask in dotted decimal format. .Parameter IPAddress Any IP address within the network range. .Parameter SubnetMask The subnet mask for the network. #> [CmdLetBinding()] Param( [Parameter(Mandatory = $True, Position = 0, ValueFromPipeline = $True)] [Net.IPAddress]$IPAddress, [Parameter(Mandatory = $True, Position = 1)] [Alias("Mask")] [Net.IPAddress]$SubnetMask ) Process { Return ConvertTo-DottedDecimalIP $((ConvertTo-DecimalIP $IPAddress) -BOr ` ((-BNot (ConvertTo-DecimalIP $SubnetMask)) -BAnd [UInt32]::MaxValue)) } } #Create ISA COM Objects $root = new-object -comObject "FPC.Root" -strict #Get our array (well, there is only one in this case) $server = $root.Arrays | Select-Object -first 1 #Get IPRangeSet for the Spamhaus DROP List network $ipranges = $server.NetworkConfiguration.Networks.item("Spamhaus DROP List").IpRangeSet $banned = $server.NetworkConfiguration.Networks.item("Banned Hosts").IpRangeSet $dropfile = "c:\users\adam\desktop\drop.txt" #If local copy of DROP file is missing, remove all addresses and start clean if($(test-path $dropfile) -eq $false){ #$ipranges.removeall() #Download DROP List from webserver $source = "http://www.spamhaus.org/drop/drop.txt" $destination = $dropfile $wc = New-Object System.Net.WebClient $wc.DownloadFile($source, $destination) $drop = "" $difference = Compare-Object $drop $(gc $dropfile) }else{ $drop = gc $dropfile if($drop -eq $null){$drop = ";"} #Download DROP List from webserver $source = "http://www.spamhaus.org/drop/drop.txt" $destination = $dropfile $wc = New-Object System.Net.WebClient $wc.DownloadFile($source, $destination) $difference = Compare-Object $drop $(gc $dropfile) } if($difference -ne $null){ $difference foreach($diff in $difference){ if ($diff.inputobject.startswith(";")){ }else{ $ip = $($diff.inputobject.split(" ; ")[0]).split("/")[0] $cidr = $($diff.inputobject.split(" ; ")[0]).split("/")[1] $mask = ConvertTo-DottedDecimalIP ([Convert]::ToUInt32($(("1" * $cidr).PadRight(32, "0")), 2)) $bcast = Get-BroadcastAddress $ip $mask Switch ($diff.SideIndicator){ "=>" {if(!$ipranges.isipinset($ip)){$ipranges.add($ip,$bcast)}elseif($banned.isipinset($ip)){write-host "IP Address Range $ip - $bcast already in Banned Hosts" -fore red}else{write-host "IP Address Range $ip - $bcast already in DROP List" -fore red}} #Not in local "<=" {if($ipranges.isipinset($ip)){$ipranges.remove($ip,$bcast)}else{write-host "IP Address Range $ip - $bcast not present in Network Object" -fore yellow}} #Not in remote } } } }else{ write-host "No Changes Since Last Update" -fore green } $ipranges.save() write-host "Update Complete" -fore green |