Inhalt

Ist diese IP Adresse Teil des Office 365 Adressbereiches?

Inhalt

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.

/ist-diese-ip-adresse-teil-des-office-365-adressbereiches/images/Test-IsO365IPAddress.gif

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"
    }
}