I'm parsing an LDAP record that has an IPv4 address as one attribute, and then a list of IPv4 subnets in <network>/<dotted quad netmask> format as another attribute. I need to be able to first verify that the single IP address is a member of one of the subnets in the list, and then get the netmask of that subnet. Net::Subnet will tell me if it's a member of one of the subnets, but I can't follow the flow well enough to modify it to give me the netmask of the subnet in question (I'm not sure if it's really clever or really poorly-written, but either way I've spent quite a bit of time staring at it and am now hopelessly stuck). I need to be able to run this on any given server, most of which I won't have access to and won't have Net::Subnet installed, so I'm trying to do this internally.

Here is the code I've got so far; it runs as-is and will tell me whether it finds a hit or not, but without being able to grab the netmask, it's not useful. I'm also open to other implementation suggestions, but at this point I'm really curious about how this is actually working (for example, WTF is "return !!0"???). All of the subs outside of main() are from Net::Subnet, but I pared them down to the minimum to get them to do what I needed.

(And to clarify, this is only a POC--the LDAP bits are represented here by $ip, @true, and @false. $ip is a member of @true, but not @false.)

#!/usr/bin/perl -w use strict; use Socket; sub subnet_matcher { @_ > 1 and goto &multi_matcher; my ($net, $mask) = split m[/], shift; return ipv4_matcher($net, $mask); } sub ipv4_matcher { my ($net, $mask) = @_; $net = inet_aton($net); $mask = inet_aton($mask); my $masked_net = $net & $mask; return sub { ((inet_aton(shift) // return !1) & $mask) eq $masked_ +net }; } sub multi_matcher { my @nets = map subnet_matcher($_), @_; return sub { $_->($_[0]) and return 1 for @nets; return !!0; } } sub main { my $ip = "65.181.207.232"; my @true = qw(10.96.2.0/255.255.254.0 10.123.50.0/255.255.255.0 72 +.24.196.0/255.255.255.0 72.24.137.192/255.255.255.192 10.122.50.0/255 +.255.255.0 65.181.207.128/255.255.255.128); my @false = qw(10.96.2.0/255.255.254.0 10.123.50.0/255.255.255.0 7 +2.24.196.0/255.255.255.0 72.24.137.192/255.255.255.192 10.122.50.0/25 +5.255.255.0); my $matcherTrue = subnet_matcher(@true); my $matcherFalse = subnet_matcher(@false); print "matcherTrue = " . ($matcherTrue->($ip) ? "yes\n" : "no\n"); print "matcherFalse = " . ($matcherFalse->($ip) ? "yes\n" : "no\n" +); } main;

In reply to finding netmask for "arbitrary" ip address by jasonl

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.