While I think there are better methods of doing this (a horse that will be beaten long after it is turning to dust), within the criteria given the following method would work, given here as a small test script (debug code left in place). (Reading the IP information into a similar structure is left as an exercise to the reader.) The central trick is converting the IP in question, the network address, and netmask to unsigned numbers, then performing a binary AND of the IP and netmask and the network address and netmask, and see if the results match.

Actually, after testing the code at the bottom of this post, I realized there was a quicker way-build a hash of the results of AND on the network address and netmask, then loop through the IPs and netmasks and look for a match.

#!perl use strict; use warnings; use Data::Dumper; $Data::Dumper::Deepcopy = 1; $Data::Dumper::Sortkeys = 1; $| = 1; srand(); my $_DEBUG = 0; my %known = ( q{192.168.0.0} => { network => q{192.168.0.0}, mask => q{24}, }, q{192.168.42.128} => { network => q{192.168.42.128}, mask => q{255.255.255.128}, }, q{192.168.127.0} => { network => q{192.168.127.0}, mask => q{255.255.255.0}, }, ); my @test = ( q{192.168.0.1}, q{192.168.42.25}, q{192.168.42.192}, q{192.168.127.0}, q{192.168.127.10}, q{192.168.127.255}, ); my %seen; foreach my $k ( keys %known ) { my $n = str2n( $known{$k}{network} ); my $m; if ( $known{$k}{mask} !~ m/\./ ) { $m = 0xFFFFFFFF << ( 32 - $known{$k}{mask} ); } else { $m = str2n( $known{$k}{mask} ); } $seen{$m}{ $n & $m } = $k; } TESTING: foreach my $ip (@test) { my $i = str2n($ip); foreach my $m ( sort { $b <=> $a } keys %seen ) { my $result = $i & $m; if ( defined( $seen{$m}{ $i & $m } ) ) { my $k = $seen{$m}{$result}; print sprintf qq{%s in %s / %s\n}, $ip, $known{$k}{network}, $known{$k}{mask}; next TESTING; } } print sprintf qq{%s not in provided ranges\n}, $ip; } print Data::Dumper->Dump( [ \@test, \%known, \%seen, ], [qw( *test *known *seen )] ), qq{\n} if ($_DEBUG); sub str2n { print sprintf( qq{\t\t%d %s\n\t\t%d %s\n\t\t%d %d\n}, __LINE__, $_[0], __LINE__, join( q{ }, split /\D/, $_[0] ), __LINE__, unpack( q{N}, pack( q{C4}, split /\D/, $_[0] ), ) ) if ($_DEBUG); return unpack( q{N}, pack( q{C4}, split /\D/, $_[0] ) ); } # Output: # # $ perl test-20140305-01.pl # 192.168.0.1 in 192.168.0.0 / 24 # 192.168.42.25 not in provided ranges # 192.168.42.192 in 192.168.42.128 / 255.255.255.128 # 192.168.127.0 in 192.168.127.0 / 255.255.255.0 # 192.168.127.10 in 192.168.127.0 / 255.255.255.0 # 192.168.127.255 in 192.168.127.0 / 255.255.255.0 #

Original code:

#!perl use strict; use warnings; use Data::Dumper; $| = 1; srand(); my $_DEBUG = 0; my %known = ( 192.168.0.0 => { network => q{192.168.0.0}, mask => q{24}, }, 192.168.42.128 => { network => q{192.168.42.128}, mask => q{255.255.255.128}, }, 192.168.127.0 => { network => q{192.168.127.0}, mask => q{255.255.255.0}, }, ); my @test = ( q{192.168.0.1}, q{192.168.42.25}, q{192.168.42.192}, q{192.168.127.0}, q{192.168.127.10}, q{192.168.127.255}, ); TESTING: foreach my $ip (@test) { my $i = str2n($ip); print sprintf( qq{%d %s: %d (0x%8x)\n}, __LINE__, $ip, $i, $i, ) if ($_DEBUG); foreach my $k ( keys %known ) { print sprintf( qq{\t%d %s / %s\n}, __LINE__, $known{$k}{network}, $known{$k}{mask}, ) if ($_DEBUG); my ( $m, $n, ); $n = str2n( $known{$k}{network} ); if ( $known{$k}{mask} !~ m/\./ ) { $m = 0xFFFFFFFF << ( 32 - $known{$k}{mask} ); } else { $m = str2n( $known{$k}{mask} ); } print sprintf( qq{\t%d %d / %d\n}, __LINE__, $n, $m, ) if ($_DEBUG); my $n_m = $n & $m; my $i_m = $i & $m; print sprintf( qq{\tTest range: %d / %d\n} . qq{\tnet & mask: %d\n} . qq{ip & mask: %d\nResults: %d\n}, $n, $m, $n_m, $i_m, $i_m == $n_m ) if ($_DEBUG); if ( $n_m == $i_m ) { print $ip, q{ in }, $known{$k}{network}, q{/}, $known{$k}{mask}, qq{\n}; next TESTING; } } print $ip, qq{ not in provided ranges\n}; } sub str2n { print sprintf( qq{\t\t%d %s\n\t\t%d %s\n\t\t%d %d\n}, __LINE__, $_[0], __LINE__, join( q{ }, split /\D/, $_[0] ), __LINE__, unpack( q{N}, pack( q{C4}, split /\D/, $_[0] ), ) ) if ($_DEBUG); return unpack( q{N}, pack( q{C4}, split /\D/, $_[0] ) ); } # Output: # # $ perl test-20140305-00.pl # 192.168.0.1 in 192.168.0.0/24 # 192.168.42.25 not in provided ranges # 192.168.42.192 in 192.168.42.128/255.255.255.128 # 192.168.127.0 in 192.168.127.0/255.255.255.0 # 192.168.127.10 in 192.168.127.0/255.255.255.0 # 192.168.127.255 in 192.168.127.0/255.255.255.0 #

Hope that helps.

Update: 2014-03-05
Updated code to remove $flag variable.


In reply to Re: finding if an ip is in a subnet by atcroft
in thread finding if an ip is in a subnet by AltGrendel

Title:
Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post, it's "PerlMonks-approved HTML":



  • Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
  • Titles consisting of a single word are discouraged, and in most cases are disallowed outright.
  • Read Where should I post X? if you're not absolutely sure you're posting in the right place.
  • Please read these before you post! —
  • Posts may use any of the Perl Monks Approved HTML tags:
    a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, details, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, summary, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
  • You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
            For:     Use:
    & &amp;
    < &lt;
    > &gt;
    [ &#91;
    ] &#93;
  • Link using PerlMonks shortcuts! What shortcuts can I use for linking?
  • See Writeup Formatting Tips and other pages linked from there for more info.