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

I have what I hope to be an easy question to answer but so far I have not found much in the way of enlightenment on the web. I'm working on code to traverse a routing table and run some checks on traffic I see. I need to do some bitwise & on IP addresses to match subnets. In C I would just run 161 & 255 and get 161 back. In Perl when I run 161 & 255 I get back 041 This is not unexpected, but I need to know if there is a way to get the C type of functionality in perl, is there some simple option that I'm unaware of? Thanks, G

Replies are listed 'Best First'.
Re: bitwise operators
by Anonymous Monk on Jan 19, 2005 at 15:36 UTC
    Make sure your arguments are numbers, not strings:
    print 161 & 255; # Prints 161 print "161" & "255"; # Prints 041
    You probably use variables, so you have to make sure Perl thinks they contain only numbers, and not strings. If you populate your variables by reading it from file, or by extracting it with a regex, Perl thinks the variables are strings. You can numify them by adding 0s:
    print +("161" + 0) & ("255" + 0); # Prints 161
      If only one of them is a number and the other a string, both will be treated as integers.
      $x = "161"; # a string print $x & 255; # the other one is a number...
      Result:
      161
      

      Assuming the "161" comes from user input and the 255 is hardcoded, there's no reason to have a problem.

        No, but that's a big if. This is 2005, and A-, B-, C- subnets are so 1980s. If I have a /23 subnet, I won't be using 255 exclusively.
        $ ifconfig | awk 'NR == 2 {print $4}' Mask:255.255.224.0
Re: bitwise operators
by holli (Abbot) on Jan 19, 2005 at 15:10 UTC
    c:\> perl -e "$e = 161 & 255; print $e" 161 c:\>
    perl 5.8.0, Windows XP

    Are sure about your numbers?

    holli, regexed monk
Re: bitwise operators
by Fletch (Bishop) on Jan 19, 2005 at 19:15 UTC

    Not your original question, but you might check out Net::Netmask which handles this stuff (including "is this IP in this mask?").

      use Socket; $net = "192.168.0.0"; $mask = "255.255.255.240"; $ip = "192.168.0.5"; print "$ip belongs to $net/$mask\n" if ((net2long($ip) & net2long($mas +k)) == net2long($net)); sub net2long { return unpack("N", inet_aton(shift)); }

      2005-01-20 Janitored by Arunbear - added code tags, as per Monastery guidelines

        And for CIDR notation use this :
        use Socket; $net = "192.168.0.0"; $mask = "28"; # /28 is 255.255.255.240 $ip = "192.168.0.5"; print "$ip belongs to $net/$mask\n" if ((net2long($ip) & ~((1 << (32 - + $mask)) - 1 )) == net2long($net)); sub net2long { return unpack("N", inet_aton(shift)); }

        2005-01-20 Janitored by Arunbear - added code tags, as per Monastery guidelines

Re: bitwise operators
by Anonymous Monk on Jan 20, 2005 at 17:35 UTC
    I do something similar to this quite often, and I like to pull the information out of a routing table dump and insert into a Net::Patricia instance.
    use Net::Patricia; my $pt = new Net::Patricia; while (<>) { if ( /((?:\d{1,3}\.){3}\d{1,3}\/\d{1,2})/ ) { $pt->add_string($1, 'Inside networks'); } } print "$host: Inside\n" if $pt->match_string($host);
    It saves the trouble of worrying about bitwise operations in string or numeric context and makes for a simple way to store and retrieve CIDR block information.