Map list of IPs to list of subnets (cidr)

46 Views Asked by At

I have list over 3k IPs which I need to map to correct subnets (cidr). I already created basic PS script but in some cases IP is map to two or more subnets, what is incorrect.

Looks like it is working only for subnets with mask /24 and when I have lower mask then it is mapping two subnets as in example below

abc         10.41.92.45     

Map too

10.41.92.0/29   sub1
10.41.92.40/29  sub2

Anyone could help with below

$SimpleSitelist = @(Import-csv -path C:\Users\ip\subnet.csv  )

#Site,CIDR
#Site1,192.168.1.0/24
#Site2,192.168.2.0/24
 
$SimpleHostList = @(Import-Csv -path C:\Users\ip.csv )

#hostname,ipaddress
#host1, 192.168.2.45
#host2, 192.168.1.45

foreach ($SingleHost in $SimpleHostList){
    $first, $second, $thrid, $4th = $SingleHost.IPAddress.split('.')
    $Sitetest = "{0}.{1}.{2}" -f $first, $second, $thrid
    [pscustomobject]@{
        Hostname  = $SingleHost.Hostname
        IPAddress = $SingleHost.IPAddress
        Site      = ($SimpleSitelist | where CIDR -match $Sitetest).Site
        Subnet      = ($SimpleSitelist | where CIDR -match $Sitetest).CIDR
        }
    }

example of data

abc;10.41.92.45
xyz;10.188.2.48
abc1;10.248.232.5
aabb;151.156.179.145
         
sub1;10.41.92.0/29
sub2;10.41.92.40/29
sub3;10.188.2.0/24
sub4;10.248.232.0/21    
sub5;151.156.179.0/24

Thanks for support

1

There are 1 best solutions below

1
mclayton On

So apparently dotnet core has a System.Net.IPNetwork struct that makes this a lot easier than having to twiddle bits inside a Uint32.

We can set up your sample data like this:

$sites = @"
sub1;10.41.92.0/29
sub2;10.41.92.40/29
sub3;10.188.2.0/24
sub4;10.248.232.0/21    
sub5;151.156.179.0/24
"@ | convertfrom-csv -header @( "Name", "CIDR" ) -delimiter ";";

$hosts = @"
bc;10.41.92.45
xyz;10.188.2.48
abc1;10.248.232.5
aabb;151.156.179.145
"@ | convertfrom-csv -header @("Hostname", "IPAddress") -delimiter ";";

Then parse the CIDR ranges into IPNetwork structs:

# parse the cidr range text string for each site
$networks = $sites | foreach-object {
    $parts = $_.CIDR.Split("/");
    $network = new-object System.Net.IPNetwork(
        [System.Net.IPAddress]::Parse($parts[0]),
        [int]::Parse($parts[1])
    );
    [pscustomobject] @{
        "Site"    = $_
        "Network" = $network
    }
}

And finally check each host for membership of networks:

$membership = foreach( $hostinfo in $hosts )
{
    $hostIpAddress = [System.Net.IPAddress]::Parse($hostinfo.IPAddress);
    $hostNetworks  = $networks | where-object { $_.Network.Contains($hostIpAddress) };
    [pscustomobject]@{
         "Hostname"  = $hostinfo.Hostname
         "IPAddress" = $hostinfo.IPAddress
         "Site"      = $hostNetworks.Site
         "Subnet"    = $hostNetworks.Site.CIDR
    }            
}

$membership

which outputs:

Hostname IPAddress       Site                                Subnet
-------- ---------       ----                                ------
bc       10.41.92.45     @{Name=sub2; CIDR=10.41.92.40/29}   10.41.92.40/29
xyz      10.188.2.48     @{Name=sub3; CIDR=10.188.2.0/24}    10.188.2.0/24
abc1     10.248.232.5    @{Name=sub4; CIDR=10.248.232.0/21 } 10.248.232.0/21
aabb     151.156.179.145 @{Name=sub5; CIDR=151.156.179.0/24} 151.156.179.0/24

Credit to this answer for pointing the way...

https://stackoverflow.com/a/63161497/3156906