Ist diese IP Adresse Teil des Office 365 Adressbereiches?
Bei der Analyse von Firewall Logs in Office 365 Projekten kommt es immer wieder zu der Fragestellung: Ist diese geblockte IP Adresse Teil des Office 365 Adressbereichs?
Dank PowerShell und der von Microsoft veröffentlichten Information im JSON Format ist die Antwort nur ein paar Zeilen Code entfernt.
Damit ihr das Rad nicht neu erfinden müsst teile ich hier mein Skript “Test-IsO365IpAddress.ps1”. Dem Skript wird einfach die fragliche IP Adresse und optional der TCP/UDP Port übergeben. Es lädt die aktuelle Liste der Adressbereiche von Microsoft und prüft ob die IP Adresse Teil eines der dort enthaltenen IP Netze ist. Ist dies der Fall werden alle Service die dieses Netz nutzen ausgegeben.
Wurde ein Port mit angegeben wird dies bei der Ausgabe der Service berücksichtigt.
Neben dem Service Namen (z.B. “Exchange Online”) wird auch die Kategorie (Optimize, Allow oder Default), die benötigten Ports, das Subnetz und die etwas veraltete Eingruppierung “Required” ausgegeben.
Mit diesen Daten ausgestattet sollte der Besuch beim Firewall Team erfolgreich sein.
Vielen Dank auch Luben Kirov dessen Netzwerkfunktionen ich für die schnelle Analyse der IP Netze nutzen durfte und Siva Padisetty dessen Funktion checkSubnet ich als Insperation für meine Implementierung genutzt habe.
Test-IsO365IpAddress.ps1
[CmdletBinding()]
param (
# IP Address to check against Office 365 Range
[Parameter(Mandatory = $true,
ValueFromPipeline = $true,
Position = 0)]
$IPAddress,
# Port to check
[Parameter(Mandatory = $false,
Position = 1)]
$Port
)
Begin {
#region Functions
# http://www.gi-architects.co.uk/2016/02/powershell-check-if-ip-or-subnet-matchesfits/
# Please note i took inspiration form www.padisetty.com
# The function will check ip to ip, ip to subnet, subnet to ip or subnet to subnet belong to each other and return true or false and the direction of the check
#////////////////////////////////////////////////////////////////////////
function checkSubnet ([string]$addr1, [string]$addr2) {
# Separate the network address and lenght
$network1, [int]$subnetlen1 = $addr1.Split('/')
$network2, [int]$subnetlen2 = $addr2.Split('/')
#Convert network address to binary
[uint32] $unetwork1 = NetworkToBinary $network1
[uint32] $unetwork2 = NetworkToBinary $network2
#Check if subnet length exists and is less then 32(/32 is host, single ip so no calculation needed) if so convert to binary
if ($subnetlen1 -lt 32) {
[uint32] $mask1 = SubToBinary $subnetlen1
}
if ($subnetlen2 -lt 32) {
[uint32] $mask2 = SubToBinary $subnetlen2
}
#Compare the results
if ($mask1 -and $mask2) {
# If both inputs are subnets check which is smaller and check if it belongs in the larger one
if ($mask1 -lt $mask2) {
return CheckSubnetToNetwork $unetwork1 $mask1 $unetwork2
} else {
return CheckNetworkToSubnet $unetwork2 $mask2 $unetwork1
}
} ElseIf ($mask1) {
# If second input is address and first input is subnet check if it belongs
return CheckSubnetToNetwork $unetwork1 $mask1 $unetwork2
} ElseIf ($mask2) {
# If first input is address and second input is subnet check if it belongs
return CheckNetworkToSubnet $unetwork2 $mask2 $unetwork1
} Else {
# If both inputs are ip check if they match
CheckNetworkToNetwork $unetwork1 $unetwork2
}
}
function CheckNetworkToSubnet ([uint32]$un2, [uint32]$ma2, [uint32]$un1) {
$ReturnArray = "" | Select-Object -Property Condition, Direction
if ($un2 -eq ($ma2 -band $un1)) {
$ReturnArray.Condition = $True
$ReturnArray.Direction = "Addr1ToAddr2"
return $ReturnArray
} else {
$ReturnArray.Condition = $False
$ReturnArray.Direction = "Addr1ToAddr2"
return $ReturnArray
}
}
function CheckSubnetToNetwork ([uint32]$un1, [uint32]$ma1, [uint32]$un2) {
$ReturnArray = "" | Select-Object -Property Condition, Direction
if ($un1 -eq ($ma1 -band $un2)) {
$ReturnArray.Condition = $True
$ReturnArray.Direction = "Addr2ToAddr1"
return $ReturnArray
} else {
$ReturnArray.Condition = $False
$ReturnArray.Direction = "Addr2ToAddr1"
return $ReturnArray
}
}
function CheckNetworkToNetwork ([uint32]$un1, [uint32]$un2) {
$ReturnArray = "" | Select-Object -Property Condition, Direction
if ($un1 -eq $un2) {
$ReturnArray.Condition = $True
$ReturnArray.Direction = "Addr1ToAddr2"
return $ReturnArray
} else {
$ReturnArray.Condition = $False
$ReturnArray.Direction = "Addr1ToAddr2"
return $ReturnArray
}
}
function SubToBinary ([int]$sub) {
return ((-bnot [uint32]0) -shl (32 - $sub))
}
function NetworkToBinary ($network) {
$a = [uint32[]]$network.split('.')
return ($a[0] -shl 24) + ($a[1] -shl 16) + ($a[2] -shl 8) + $a[3]
}
#////////////////////////////////////////////////////////////////////////
#endregion
# Generate GUID to query
$GUID = [guid]::NewGuid()
# Retreive
$Office365IPRanges = Invoke-RestMethod -Method Get -UseBasicParsing -Uri "https://endpoints.office.com/endpoints/worldwide?clientrequestid=$GUID&NoIPv6"
$IPAddressInSubnet = $false
$AllIPAddresses = $Office365IPRanges.ips | Select-Object -Unique
}
Process {
foreach ($Subnet in $AllIPAddresses) {
if ( (checkSubnet $IPAddress $Subnet).Condition ) {
Write-Verbose "$IPAddress is part of $Subnet"
$IPAddressInSubnet = $true
break
}
}
if ($IPAddressInSubnet) {
$MatchingServices = $Office365IPRanges | Where-Object { $Subnet -in $_.ips } | Add-Member -NotePropertyName "Subnet" -NotePropertyValue $Subnet -PassThru | Select-Object serviceAreaDisplayName, category, subnet, tcpPorts, required, @{e={"$IPAddress"};n="IPAddress"}
}
if ( $PSBoundParameters.ContainsKey('Port')) {
$MatchingServices = $MatchingServices | Where-Object { $_.tcpPorts -match $port -or $_.udpPorts -match $port }
}
# Output result
if ($MatchingServices) {
$MatchingServices
} else {
Write-Host -ForegroundColor Yellow "Did not find $IPAddress"
}
}