Import Remote IP Range into Exchange 2007 EDGE servers

We maintain an Exchange EDGE server on our perimeter as SMTP relay. Application servers can use this server to relay email out (to internal recipients or the Internet). To keep this server from being an open relay, we maintain a list of valid IP addresses that can relay through this server. To update the the relay, we run my script below to import the IPs. On our first attempt, we found that MS Edge 2007 - Receive Connectors have a limit on allowed RemoteIPRanges values. After approximately 1100 individual IPs, it would quit accepting any additional IP addresses. Unfortunately, we have over 1300 current application servers running currently.

Dealing with Receive Connector limits. This field accepts 3 different formats: straight IP, IP Range (0.0.0.0 - 0.0.0.1) and CIDR format (0.0.0.0/24). Since I am working from a list of allowed IP addresses, the first option is easy. CIDR format requires a bit of fiddling, as you want valid ranges and using defining a valid subnet mask is complicated. So, why not use ranges.

What my script does:

  1. Reads a text file of IP addresses and CIDR IPs.
  2. Breaks apart octets and sorts IP addresses (numerically not alphabetically)
  3. Parses IP addresses and consolidate's IP ranges with no skips
    • 10.0.0.1, 10.0.0.2, 10.0.0.3, 10.0.0.4 -> 10.0.0.1 - 10.0.0.4
  4. Updates local Receive Connector - RemoteIPRAnges value on local host.

Drawback is that if someone manually adds an IP directly to the server, it will be lost. Currently the script deletes any values already there.

Get-PSSnapin -registered | Add-PSSnapin -passThru
$ips = Get-Content c:\ip-addresses.txt

$broken = @()
$connIPRanges = @()

Function Add-OneIP($IPAddress) {
        $octets = $IPAddress.split(".")
        $Entry = new-Object -typename System.Object
        $Entry | add-Member -memberType noteProperty -name A -Value ([int]$octets[0])
        $Entry | add-Member -memberType noteProperty -name B -Value ([int]$octets[1])
        $Entry | add-Member -memberType noteProperty -name C -Value ([int]$octets[2])
        $Entry | add-Member -memberType noteProperty -name D -Value ([int]$octets[3])
        $Entry | add-Member -memberType noteProperty -name Subnet -Value $subnet
        $outstr = $octets[0] +"," +$octets[1] +"," +$octets[2] +"," +$octets[3]+ ","+$subnet | Out-File c:\ip.csv -Append
        return $entry
}


foreach ($ip in $ips) {
        if ($ip -match "/") {
                $Parts = $ip.Split("/")
                $ip = $parts[0]
                $subnet = $parts[1]
                $ipobj = Add-OneIP $IP
                $broken += $ipobj
        } elseif ($ip -match "-") {

                $Range = $ip.split("-")        
                $subnet = ""
                $StartIP = $range[0].trim().split(".")
                $EndIP = $range[1].trim().split(".")
                for ($a = [int]$StartIP[3]; $a -le $EndIP[3]; $a++) {                  
                        $IPString = [string] $StartIP[0] +"." + $StartIP[1] +"." + $StartIP[2] +"." + [string]$a                       
                        $ipobj = Add-OneIP $IPstring
                        $broken += $ipobj
                }
        } else {
                $subnet = ""
                $ipobj = Add-OneIP $IP
                $broken += $ipobj

        }      
}

$broken.count
$ipranges = $broken | Sort A, b, c, d
$last = $ipranges[0]
$null | out-file c:\ip-addresses2.txt

foreach ($ipr in $ipRanges) {
        if ($IpR.Subnet -ne "") {
                $ipstr = [string]$ipr.a+"."+[string]$ipr.b+"."+[string]$ipr.c+"."+[string]$ipr.d+"/"+$ipr.Subnet
                $ipstr | out-file c:\ip-addresses2.txt -append
                $ConnIPRanges += $ipstr
        } else {
                $value = ($ipr.a - $last.a)*1000 + ($ipr.b - $last.b)*100 + ($ipr.c - $last.c)*10 + ($ipr.d - $last.d)
               
                if ($value -eq 1) {
                        if ($Start -eq $null) {$start = $last}
                        $counter += 1
                } else {               
                        if (($start -ne $last) -and ($start -ne $null)) {
                                Write-Host $start.a $start.b $start.c $start.d - $last.a $last.b $last.c $last.d, "("$counter")"
                                $ipstr = [string]([string]$start.a+"."+[string]$start.b+"."+[string]$start.c+"."+[string]$start.d+"-"+[string]$last.a+"."+[string]$last.b+"."+[string]$last.c+"."+[string]$last.d)
                                $ipstr | out-file c:\ip-addresses2.txt -append
                                $ConnIPRanges += $ipstr
                        } else {
                                $ipstr = ([string]$last.a+"."+[string]$last.b+"."+[string]$last.c+"."+[string]$last.d)
                                $ipstr | out-file c:\ip-addresses2.txt -append
                                $ConnIPRanges += $ipstr
                                write-host $last.a $last.b $last.c $last.d
                        }
                        $counter = 0
                        $start = $null
                }
                $last = $ipr
        }
}

$conn = get-receiveconnector
$conn.remoteipranges.clear()
ForEach ($RIP in $connIPRanges) {
        $conn.remoteIPRanges.add($RIP) 
}      
$conn | Set-receiveconnector

Comments

Post new comment

The content of this field is kept private and will not be shown publicly.
  • Allowed HTML tags: <a> <blockquote> <center> <hr> <em> <strong> <cite> <code> <ul> <ol> <li> <dl> <dt> <dd> <img>
  • Lines and paragraphs break automatically.
  • Web page addresses and e-mail addresses turn into links automatically.
  • You can enable syntax highlighting of source code with the following tags: <code>, <blockcode>, <drupal6>, <html>, <java>, <javascript>, <php>, <posh>.

More information about formatting options

Type the characters you see in this picture. (verify using audio)
Type the characters you see in the picture above; if you can't read them, submit the form and a new image will be generated. Not case sensitive.