The London Perl and Raku Workshop takes place on 26th Oct 2024. If your company depends on Perl, please consider sponsoring and/or attending.

NAME

NetAddr::IP::Util -- IPv4/6 and 128 bit number utilities

SYNOPSIS

  use NetAddr::IP::Util qw(
        inet_aton
        inet_ntoa
        ipv6_aton
        ipv6_n2x
        ipv6_n2d
        inet_any2n
        hasbits
        isIPv4
        inet_n2dx
        inet_n2ad
        ipv4to6
        mask4to6
        ipanyto6
        maskanyto6
        ipv6to4
        shiftleft
        addconst
        add128
        sub128
        notcontiguous
        bin2bcd
        bcd2bin
        mode
  );

  use NetAddr::IP::Util qw(:all :inet :ipv4 :ipv6 :math)

  :inet   =>    inet_aton, inet_ntoa, ipv6_aton,
                ipv6_n2x, ipv6_n2d, inet_any2n, 
                inet_n2dx, inet_n2ad, ipv4to6,
                mask4to6, ipanyto6, maskanyto6,
                ipv6to4

  :ipv4   =>    inet_aton, inet_ntoa

  :ipv6   =>    ipv6_aton, ipv6_n2x, ipv6_n2d,
                inet_any2n, inet_n2dx, inet_n2ad
                ipv4to6, mask4to6, ipanyto6,
                maskanyto6, ipv6to4

  :math   =>    hasbits, isIPv4, addconst,
                add128, sub128, notcontiguous,
                bin2bcd, bcd2bin, shiftleft

  $dotquad = inet_ntoa($netaddr);
  $netaddr = inet_aton($dotquad);
  $ipv6naddr = ipv6_aton($ipv6_text);
  $hex_text = ipv6_n2x($ipv6naddr);
  $dec_text = ipv6_n2d($ipv6naddr);
  $ipv6naddr = inet_any2n($dotquad or $ipv6_text);
  $rv = hasbits($bits128);
  $rv = isIPv4($bits128);
  $dotquad or $hex_text = inet_n2dx($ipv6naddr);
  $dotquad or $dec_text = inet_n2ad($ipv6naddr);
  $ipv6naddr = ipv4to6($netaddr);
  $ipv6naddr = mask4to6($netaddr);
  $ipv6naddr = ipanyto6($netaddr);
  $ipv6naddr = maskanyto6($netaddr);
  $netaddr = ipv6to4($pv6naddr);
  $bitsX2 = shiftleft($bits128,$n);
  $carry = addconst($ipv6naddr,$signed_32con);
  ($carry,$ipv6naddr)=addconst($ipv6naddr,$signed_32con);
  $carry = add128($ipv6naddr1,$ipv6naddr2);
  ($carry,$ipv6naddr)=add128($ipv6naddr1,$ipv6naddr2);
  $carry = sub128($ipv6naddr1,$ipv6naddr2);
  ($carry,$ipv6naddr)=sub128($ipv6naddr1,$ipv6naddr2);
  ($spurious,$cidr) = notcontiguous($mask128);
  $bcdtext = bin2bcd($bits128);
  $bits128 = bcd2bin($bcdtxt);
  $modetext = mode;

INSTALLATION

Un-tar the distribution in an appropriate directory and type:

        perl Makefile.PL
        make
        make test
        make install

NetAddr::IP::Util installs by default with its primary functions compiled using Perl's XS extensions to build a 'C' library. If you do not have a 'C' complier available or would like the slower Pure Perl version for some other reason, then type:

        perl Makefile.PL -noxs
        make
        make test
        make install

DESCRIPTION

NetAddr::IP::Util provides a suite of tools for manipulating and converting IPv4 and IPv6 addresses into 128 bit string context and back to text. The strings can be manipulated with Perl's logical operators:

        and     &
        or      |
        xor     ^

in the same manner as 'vec' strings.

The IPv6 functions support all rfc1884 formats.

  i.e.  x:x:x:x:x:x:x:x:x
        x:x:x:x:x:x:x:d.d.d.d
        ::x:x:x
        ::x:d.d.d.d
  and so on...
  • $dotquad = inet_ntoa($netaddr);

    Convert a packed IPv4 network address to a dot-quad IP address.

      input:        packed network address
      returns:      IP address i.e. 10.4.12.123
  • $netaddr = inet_aton($dotquad);

    Convert a dot-quad IP address into an IPv4 packed network address.

      input:        IP address i.e. 192.5.16.32
      returns:      packed network address
  • $ipv6addr = ipv6_aton($ipv6_text);

    Takes an IPv6 address of the form described in rfc1884 and returns a 128 bit binary RDATA string.

      input:        ipv6 text
      returns:      128 bit RDATA string
  • $hex_text = ipv6_n2x($ipv6addr);

    Takes an IPv6 RDATA string and returns an 8 segment IPv6 hex address

      input:        128 bit RDATA string
      returns:      x:x:x:x:x:x:x:x
  • $dec_text = ipv6_n2d($ipv6addr);

    Takes an IPv6 RDATA string and returns a mixed hex - decimal IPv6 address with the 6 uppermost chunks in hex and the lower 32 bits in dot-quad representation.

      input:        128 bit RDATA string
      returns:      x:x:x:x:x:x:d.d.d.d
  • $ipv6naddr = inet_any2n($dotquad or $ipv6_text);

    This function converts a text IPv4 or IPv6 address in text format in any standard notation into a 128 bit IPv6 string address. It prefixes any dot-quad address (if found) with '::' and passes it to ipv6_aton.

      input:        dot-quad or rfc1844 address
      returns:      128 bit IPv6 string
  • $rv = hasbits($bits128);

    This function returns true if there are one's present in the 128 bit string and false if all the bits are zero.

      i.e.  if (hasbits($bits128)) {
              &do_something;
            }
    
      or    if (hasbits($bits128 & $mask128) {
              &do_something;
            }

    This allows the implementation of logical functions of the form of:

            if ($bits128 & $mask128) {
                ...
    
      input:        128 bit IPv6 string
      returns:      true if any bits are present
  • $rv = isIPv4($bits128);

    This function returns true if there are no on bits present in the IPv6 portion of the 128 bit string and false otherwise.

  • $dotquad or $hex_text = inet_n2dx($ipv6naddr);

    This function does the right thing and returns the text for either a dot-quad IPv4 or a hex notation IPv6 address.

      input:        128 bit IPv6 string
      returns:      ddd.ddd.ddd.ddd
                or  x:x:x:x:x:x:x:x
  • $dotquad or $dec_text = inet_n2ad($ipv6naddr);

    This function does the right thing and returns the text for either a dot-quad IPv4 or a hex::decimal notation IPv6 address.

      input:        128 bit IPv6 string
      returns:      ddd.ddd.ddd.ddd
                or  x:x:x:x:x:x:ddd.ddd.ddd.dd
  • $ipv6naddr = ipv4to6($netaddr);

    Convert an ipv4 network address into an ipv6 network address.

      input:        32 bit network address
      returns:      128 bit network address
  • $ipv6naddr = mask4to6($netaddr);

    Convert an ipv4 netowrk address into an ipv6 network mask.

      input:        32 bit network/mask address
      returns:      128 bit network/mask address

    NOTE: returns the high 96 bits as one's

  • $ipv6naddr = ipanyto6($netaddr);

    Similar to ipv4to6 except that this function takes either an IPv4 or IPv6 input and always returns a 128 bit IPv6 network address.

      input:        32 or 128 bit network address
      returns:      128 bit network address
  • $ipv6naddr = maskanyto6($netaddr);

    Similar to mask4to6 except that this function takes either an IPv4 or IPv6 netmask and always returns a 128 bit IPv6 netmask.

      input:        32 or 128 bit network mask
      returns:      128 bit network mask
  • $netaddr = ipv6to4($pv6naddr);

    Truncate the upper 96 bits of a 128 bit address and return the lower 32 bits. Returns an IPv4 address as returned by inet_aton.

      input:        128 bit network address
      returns:      32 bit inet_aton network address
  • $bitsXn = shiftleft($bits128,$n);

      input:        128 bit string variable,
                    number of shifts [optional]
      returns:      bits X n shifts
    
      NOTE: a single shift is performed 
            if $n is not specified
  • addconst($ipv6naddr,$signed_32con);

    Add a signed constant to a 128 bit string variable.

      input:        128 bit IPv6 string,
                    signed 32 bit integer
      returns:  scalar      carry
                array       (carry, result)
  • add128($ipv6naddr1,$ipv6naddr2);

    Add two 128 bit string variables.

      input:        128 bit string var1,
                    128 bit string var2
      returns:  scalar      carry
                array       (carry, result)
  • sub128($ipv6naddr1,$ipv6naddr2);

    Subtract two 128 bit string variables.

      input:        128 bit string var1,
                    128 bit string var2
      returns:  scalar      carry
                array       (carry, result)
        

    Note: The carry from this operation is the result of adding the one's complement of ARG2 +1 to the ARG1. It is logically NOT borrow.

            i.e.    if ARG1 >= ARG2 then carry = 1
            or      if ARG1  < ARG2 then carry = 0
  • ($spurious,$cidr) = notcontiguous($mask128);

    This function counts the bit positions remaining in the mask when the rightmost '0's are removed.

            input:  128 bit netmask
            returns true if there are spurious
                        zero bits remaining in the
                        mask, false if the mask is
                        contiguous one's,
                    128 bit cidr number
  • $bcdtext = bin2bcd($bits128);

    Convert a 128 bit binary string into binary coded decimal text digits.

      input:        128 bit string variable
      returns:      string of bcd text digits
  • $bits128 = bcd2bin($bcdtxt);

    Convert a bcd text string to 128 bit string variable

      input:        string of bcd text digits
      returns:      128 bit string variable
  • $modetext = mode;

    Returns the operating mode of this module.

            input:          none
            returns:        "Pure Perl"
                       or   "CC XS"

EXAMPLES

  # convert any textual IP address into a 128 bit vector
  #
  sub text2vec {
    my($anyIP,$anyMask) = @_;

  # not IPv4 bit mask
    my $notiv4 = ipv6_aton('FFFF:FFFF:FFFF:FFFF:FFFF:FFFF::');

    my $vecip   = inet_any2n($anyIP);
    my $mask    = inet_any2n($anyMask);

  # extend mask bits for IPv4
    my $bits = 128;     # default
    unless (hasbits($mask & $notiv4)) {
      $mask |= $notiv4;
      $bits = 32;
    }
    return ($vecip, $mask, $bits);
  }

  ... alternate implementation, a little faster

  sub text2vec {
    my($anyIP,$anyMask) = @_;

  # not IPv4 bit mask
    my $notiv4 = ipv6_aton('FFFF:FFFF:FFFF:FFFF:FFFF:FFFF::');

    my $vecip   = inet_any2n($anyIP);
    my $mask    = inet_any2n($anyMask);

  # extend mask bits for IPv4
    my $bits = 128;     # default
    if (isIPv4($mask)) {
      $mask |= $notiv4;
      $bits = 32;
    }
    return ($vecip, $mask, $bits);
  }


  ... elsewhere
    $nip = {
        addr    => $vecip,
        mask    => $mask,
        bits    => $bits,
    };

  # return network and broadcast addresses from IP and Mask
  #
  sub netbroad {
    my($nip) = shift;
    my $notmask = ~ $nip->{mask};
    my $bcast   = $nip->{addr} | $notmask;
    my $network = $nip->{addr} & $nip->{mask};
    return ($network, $broadcast);
  }

  # check if address is within a network
  #
  sub within {
    my($nip,$net) = @_;
    my $addr = $nip->{addr}
    my($nw,$bc) = netbroad($net);
  # arg1 >= arg2, sub128 returns true
    return (sub128($addr,$nw) && sub128($bc,$addr))
        ? 1 : 0;
  }

  # add a constant, wrapping at netblock boundries
  # to subtract the constant, negate it before calling 
  # 'addwrap' since 'addconst' will extend the sign bits
  #
  sub addwrap {
    my($nip,$const) = @_;
    my $mask    = $nip->{addr};
    my $bits    = $nip->{bits};
    my $notmask = ~ $mask;
    my $hibits  = $addr & $mask;
    my $addr = addconst($addr,$const);
    my $wraponly = $addr & $notmask;
    my $newip = {
        addr    => $hibits | $wraponly,
        mask    => $mask,
        bits    => $bits,
    };
    # bless $newip as appropriate
    return $newip;
  }     
    

EXPORT_OK

        inet_aton
        inet_ntoa
        ipv6_aton
        ipv6_n2x
        ipv6_n2d
        inet_any2n
        hasbits
        isIPv4
        inet_n2dx
        inet_n2ad
        ipv4to6
        mask4to6
        ipanyto6
        maskanyto6
        ipv6to4
        shiftleft
        addconst
        add128
        sub128
        notcontiguous
        bin2bcd
        bcd2bin
        mode

AUTHOR

Michael Robinton <michael@bizsystems.com>

ACKNOWLEDGEMENTS

The following functions are used in whole or in part as include files to Util.xs. The copyright is include in the file.

  file:              function:

  miniSocket.inc  inet_aton, inet_ntoa

inet_aton, inet_ntoa are from the perl-5.8.0 release by Larry Wall, copyright 1989-2002. inet_aton, inet_ntoa code is current through perl-5.9.3 release. Thank you Larry for making PERL possible for all of us.

COPYRIGHT

Copyright 2003 - 2006, Michael Robinton <michael@bizsystems.com>

This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License (except as noted otherwise in individuals sub modules) published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.

AUTHOR

Michael Robinton <michael@bizsystems.com>