Beefy Boxes and Bandwidth Generously Provided by pair Networks
XP is just a number
 
PerlMonks  

checking ip ranges

by arcnon (Monk)
on Mar 13, 2008 at 18:27 UTC ( [id://674042]=perlquestion: print w/replies, xml ) Need Help??

arcnon has asked for the wisdom of the Perl Monks concerning the following question:

can anyone see any flaws with my code? it works but is it solid?
#!/usr/bin/perl use strict; print cmp_ips('10.1.2.31','10.1.2.30','10.1.2.45')."\n"; print cmp_ips('10.1.2.255','9.1.2.30','11.1.2.45')."\n"; print cmp_ips('10.1.2.255','10.1.1.30','10.1.3.45')."\n"; print cmp_ips('10.1.2.255','10.1.2.30','10.1.2.45')."\n"; print cmp_ips('10.1.2.255','10.1.2.30','10.1.2.255')."\n"; print cmp_ips('10.1.2.30','10.1.2.30','10.1.2.255')."\n"; print cmp_ips('10.1.2.30','10.1.2.30','10.1.2.255')."\n"; sub cmp_ips{ my @r; my @t = quadify(shift); my @s = quadify(shift); my @e = quadify(shift); ($t[0] == $s[0] && $t[0] == $e[0]) ? $r[0] = 1 : $r[0] = 0; ($t[1] == $s[1] && $t[1] == $e[1]) ? $r[1] = 1 : $r[1] = 0; ($t[2] == $s[2] && $t[2] == $e[2]) ? $r[2] = 1 : $r[2] = 0; ($t[3] == $s[3] && $t[3] == $e[3]) ? $r[3] = 1 : $r[3] = 0; return 1 if $t[0]*$t[1]*$t[2]*$t[3] == 1; return 1 if ($r[0] == 0 && ($t[0] >= $s[0] && $t[0] <= $e[0]) ); return 1 if ($r[1] == 0 && ($t[1] >= $s[1] && $t[1] <= $e[1]) ); return 1 if ($r[2] == 0 && ($t[2] >= $s[2] && $t[2] <= $e[2]) ); return 1 if ($r[3] == 0 && ($t[3] >= $s[3] && $t[3] <= $e[3]) ); return 0; } sub quadify{ my $ip = shift; $ip =~ /^(\d+)\.(\d+)\.(\d+)\.(\d+)$/; return ($1,$2,$3,$4); }

Replies are listed 'Best First'.
Re: checking ip ranges
by Fletch (Bishop) on Mar 13, 2008 at 18:48 UTC

    You could just use Socket's inet_aton and an unpack "N" to turn your IPs into single numbers and compare those. Or just use Net::Netmask off CPAN which does all the grunt work for you.

    The cake is a lie.
    The cake is a lie.
    The cake is a lie.

    A reply falls below the community's threshold of quality. You may see it by logging in.
Re: checking ip ranges
by shmem (Chancellor) on Mar 13, 2008 at 19:18 UTC
    it works but is it solid?

    Probably not, since it happily accepts 345.456.567.789 as an argument. There are many modules on CPAN for that, e.g. Net::IP::Match.

    --shmem

    _($_=" "x(1<<5)."?\n".q·/)Oo.  G°\        /
                                  /\_¯/(q    /
    ----------------------------  \__(m.====·.(_("always off the crowd"))."·
    ");sub _{s./.($e="'Itrs `mnsgdq Gdbj O`qkdq")=~y/"-y/#-z/;$e.e && print}
    A reply falls below the community's threshold of quality. You may see it by logging in.
Re: checking ip ranges
by jwkrahn (Abbot) on Mar 13, 2008 at 20:21 UTC
    can anyone see any flaws with my code? it works but is it solid?

    You have a precedence problem in this code:

    ($t[0] == $s[0] && $t[0] == $e[0]) ? $r[0] = 1 : $r[0] = 0; ($t[1] == $s[1] && $t[1] == $e[1]) ? $r[1] = 1 : $r[1] = 0; ($t[2] == $s[2] && $t[2] == $e[2]) ? $r[2] = 1 : $r[2] = 0; ($t[3] == $s[3] && $t[3] == $e[3]) ? $r[3] = 1 : $r[3] = 0;

    The  = operator has higher precedence than the  ?: operator.    That should be written as:

    $r[0] = $t[0] == $s[0] && $t[0] == $e[0] ? 1 : 0; $r[1] = $t[1] == $s[1] && $t[1] == $e[1] ? 1 : 0; $r[2] = $t[2] == $s[2] && $t[2] == $e[2] ? 1 : 0; $r[3] = $t[3] == $s[3] && $t[3] == $e[3] ? 1 : 0;

    However it would be better to use the Socket module that is installed with Perl:

    use Socket; sub cmp_ips { my $t = inet_aton( $_[0] ) or do { warn "$_[0] is not a valid IP a +ddress.\n"; return 0 }; my $s = inet_aton( $_[1] ) or do { warn "$_[1] is not a valid IP a +ddress.\n"; return 0 }; my $e = inet_aton( $_[2] ) or do { warn "$_[2] is not a valid IP a +ddress.\n"; return 0 }; return 1 if $t eq $s && $t eq $e; return 1 if $t ge $s && $t le $e && ( $t ne $s || $t ne $e ); return 0; }
      not to get off topic but your saying
      ($t[0] == $s[0] && $t[0] == $e[0]) ? $r[0] = 1 : $r[0] = 0;
      isn't the same as
      if ($t[0] == $s[0] && $t[0] == $e[0]){ $r[0] = 1; } else{ $r[0] = 0; }
      right?

        No it isn't:

        $ perl -MO=Deparse,-p -e ' ($t[0] == $s[0] && $t[0] == $e[0]) ? $r[0] += 1 : $r[0] = 0; ' (((($t[0] == $s[0]) && ($t[0] == $e[0])) ? ($r[0] = 1) : $r[0]) = 0); -e syntax OK $ perl -MO=Deparse,-p -e ' $r[0] = ($t[0] == $s[0] && $t[0] == $e[0]) +? 1 : 0; ' ($r[0] = ((($t[0] == $s[0]) && ($t[0] == $e[0])) ? 1 : 0)); -e syntax OK

        Update: for example:

        $ perl -le' @test = ( [ 10, 12, 14 ], [ 12, 12, 14 ], [ 12, 14, 14 ], [ 12, 12, 12 + ], [ 14, 10, 14 ] ); for ( @test ) { ( $t, $s, $e ) = @$_; print "1: $t $s $e"; $r = undef; ($t == $s && $t == $e) ? $r = 1 : $r = 0; print "2: $t $s $e $r"; $r = undef; $r = ($t == $s && $t == $e) ? 1 : 0; print "3: $t $s $e $r\n"; } ' 1: 10 12 14 2: 10 12 14 0 3: 10 12 14 0 1: 12 12 14 2: 12 12 14 0 3: 12 12 14 0 1: 12 14 14 2: 12 14 14 0 3: 12 14 14 0 1: 12 12 12 2: 12 12 12 0 3: 12 12 12 1 1: 14 10 14 2: 14 10 14 0 3: 14 10 14 0
Re: checking ip ranges
by hipowls (Curate) on Mar 13, 2008 at 19:29 UTC

    I think you are testing that the first address is between the second and third. If so then this it the approach I'd use

    sub cmp_ips { my $ip = normalize(shift); my $lower = normalize(shift); my $upper = normalize(shift); return 1 if $lower le $ip && $ip le $upper; return 0; } sub normalize { return pack 'C*', split /\./, shift; }

      Edit: Nevermind, I had the argument order messed up in my head and said something very, very wrong.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://674042]
Approved by Erez
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others scrutinizing the Monastery: (4)
As of 2024-04-16 18:48 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found