NAME
NetAddr::IP::Util - Native C and pure perl implementations of IPv4 and IPv6 address utilities
VERSION
version 4.080_04
SYNOPSIS
use NetAddr::IP::Util qw(
inet_aton inet_ntoa ipv6_aton ipv6_ntoa ipv6_n2x ipv6_n2d
inet_any2n inet_n2dx inet_n2ad inet_pton inet_ntop inet_4map6
packzeros ipv4to6 mask4to6 ipanyto6 maskanyto6 ipv6to4
hasbits isIPv4 isNewIPv4 isAnyIPv4
shiftleft addconst add128 sub128 notcontiguous
bin2bcd bcd2bin mode
AF_INET AF_INET6 naip_gethostbyname
);
# text to packed, and back
$netaddr = inet_aton('192.0.2.1'); # 4 bytes
$dotquad = inet_ntoa($netaddr); # '192.0.2.1'
$ipv6naddr = ipv6_aton('2001:db8::1'); # 16 bytes
$ipv6_text = ipv6_ntoa($ipv6naddr); # '2001:db8::1'
$bits128 = inet_any2n('192.0.2.1'); # 0:0:0:0:0:0:C000:201
$hex_text = ipv6_n2x($ipv6naddr); # '2001:DB8:0:0:0:0:0:1'
$dec_text = ipv6_n2d($ipv6naddr); # '2001:DB8:0:0:0:0:0.0.0.1'
$hex_text = packzeros('0:0:0:0:0:ffff:c000:201');
# '::ffff:c000:201'
# the family tests
$rv = hasbits($bits128); # true if any bit is set
$rv = isIPv4($bits128); # ::d.d.d.d, deprecated
$rv = isNewIPv4($bits128); # ::ffff:d.d.d.d
$rv = isAnyIPv4($bits128); # either of the above
# widening and narrowing
$ipv6naddr = ipv4to6($netaddr); # 0:0:0:0:0:0:C000:201
$ipv6naddr = inet_4map6($netaddr); # 0:0:0:0:0:FFFF:C000:201
$netaddr = ipv6to4($ipv6naddr); # low 32 bits
# 128 bit arithmetic, carry in scalar context
$signed_32bit = 1;
$bits1281 = ipv6_aton('2001:db8::2');
$bits1282 = ipv6_aton('2001:db8::1');
$mask128 = ipv6_aton('ffff:ffff:ffff:ffff:ffff:ffff:ffff:ff00');
$carry = addconst($bits128, $signed_32bit);
($carry, $bits128) = addconst($bits128, $signed_32bit);
$carry = sub128($bits1281, $bits1282);
($spurious, $cidr) = notcontiguous($mask128);
$modetext = mode; # 'CC XS' or 'Pure Perl'
DESCRIPTION
NetAddr::IP::Util converts IPv4 and IPv6 addresses to and from 128 bit binary strings, and does arithmetic on those strings. A 128 bit string here means 16 bytes, whatever the family: an IPv4 address is carried in the low 32 bits with the rest zero. That is what lets one set of functions take either family.
use NetAddr::IP::Util qw(inet_any2n ipv6_n2x);
my $v4 = inet_any2n('192.0.2.1');
my $v6 = inet_any2n('2001:db8::1');
print length($v4), "\n"; # 16, not 4
print ipv6_n2x($v4), "\n"; # 0:0:0:0:0:0:C000:201
The strings behave like vec strings under the bit operators:
and &
or |
xor ^
~ complement
so masks and tests are written as arithmetic on them, which is what the family tests below and netbroad in "EXAMPLES" do.
The functions come in two implementations, XS and pure Perl, and mode() reports which one is loaded:
print mode(); # 'CC XS' or 'Pure Perl'
Text that is not an address is not an error. Four functions, inet_aton, ipv6_aton, inet_any2n and inet_pton, return undef for it, and inet_4map6 returns undef for an argument it cannot map. A binary argument of the wrong length is an error. Most functions that take one croak, on both implementations, with a message that names the function and gives both lengths in bits:
Bad arg length for NetAddr::IP::Util::hasbits, length is 40, should be 128
Each entry below says what its function does with a bad argument.
The IPv6 functions accept every text form in RFC 4291 s2.2:
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
::ffff:d.d.d.d
and produce text following RFC 5952 s4. Which case they produce depends on the process-wide setting described under NetAddr::IP::InetBase, except for ipv6_ntoa, inet_ntop and packzeros, which are always lowercase.
FUNCTIONS
Text to binary
- $netaddr = inet_aton($dotquad);
-
Convert a dot-quad IP address into an IPv4 packed network address.
input: IP address i.e. 192.0.2.1 returns: packed network address, or undefShort forms follow the BSD
inet_atonconvention, not RFC 791:127.1is 127.0.0.1 and192.0.2is 192.0.0.2. Other text goes togethostbyname, so a host name is resolved. Returns undef for an octet above 255 and for text that does not resolve. - $bits128 = ipv6_aton($ipv6_text);
-
Takes an IPv6 address in any of the RFC 4291 s2.2 text forms and returns a 128 bit binary RDATA string. Returns undef if the text is not a valid address.
input: ipv6 text returns: 128 bit RDATA string, or undef - $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 RFC 4291 s2.2 address returns: 128 bit IPv6 string, or undefReturns undef if the text is not an address. An empty or undefined argument is read as
::, the all-zero address. - $netaddr = inet_pton($AF_family,$hex_text);
-
This function takes an IP address in IPv4 or IPv6 text format and converts it into binary format. The type of IP address conversion is controlled by the FAMILY argument.
Returns undef for text that is not an address of that family, and croaks on a family other than
AF_INETandAF_INET6.NOTE: inet_pton, inet_ntop and AF_INET6 come from the Socket6 library if it is present on this host. The two sources differ on IPv4 text: without Socket6,
inet_pton(AF_INET, ...)isinet_atonand also takes short forms such as127.1and host names, which Socket6 rejects.
Binary to text
- $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. 192.0.2.1Croaks if the argument is not 4 bytes.
- $ipv6_text = ipv6_ntoa($ipv6naddr);
-
Convert a 128 bit binary IPv6 address to the compressed RFC 5952 s4 text representation, which is lowercase whatever the case setting.
input: 128 bit RDATA string returns: ipv6 textCroaks if the argument is not 16 bytes.
NOTE: for an address with an IPv4 address in the low 32 bits the output depends on whether Socket6 is installed. See the entry for
inet_ntop. - $hex_text = ipv6_n2x($bits128);
-
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:xCroaks if the argument is not 16 bytes.
- $dec_text = ipv6_n2d($bits128);
-
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.dCroaks if the argument is not 16 bytes.
- $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:xCroaks if the argument is not 16 bytes.
- $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.dddCroaks if the argument is not 16 bytes.
- $hex_text = inet_ntop($AF_family,$netaddr);
-
This function takes and IP address in binary format and converts it into text format. The type of IP address conversion is controlled by the FAMILY argument.
NOTE: inet_ntop ALWAYS returns lowercase characters.
- $hex_text = packzeros($hex_text);
-
Shortens an eight-group IPv6 hex address by substituting :: for the longest run of zero groups, per RFC 5952 s4.2.1. Where two runs are equally long the first is shortened, s4.2.3, and a run of one zero group is never shortened at all, s4.2.2. The result is always lowercase, RFC 5952 s4.3, whatever the case setting.
print packzeros('0:0:0:0:0:ffff:c000:201'); # ::ffff:c000:201 print packzeros('2001:db8:0:1:1:1:1:1'); # 2001:db8:0:1:1:1:1:1 print packzeros('2001:db8:0:0:1:0:0:1'); # 2001:db8::1:0:0:1 print packzeros('2001:db8:0:1:1:0:0:1'); # 2001:db8:0:1:1::1 print packzeros('2001:0DB8:0:1:2:3:4:5'); # 2001:db8:0:1:2:3:4:5 print packzeros('2001:0:0:1:0:0:0:1'); # 2001:0:0:1::1
Case
- NetAddr::IP::Util::lower();
-
Return IPv6 strings in lowercase.
- NetAddr::IP::Util::upper();
-
Return IPv6 strings in uppercase. This is the default.
Family tests
- $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.
i.e. the address must be of the form - ::d.d.d.dwhich is the RFC 4291 s2.5.5.1 IPv4-compatible prefix
::/96, deprecated by that RFC.Croaks if the argument is not 16 bytes. The message names
isIPv4, orisNewIPv4orisAnyIPv4when the argument came in through one of them. - $rv = isNewIPv4($bits128);
-
This function returns true if the 128 bit string is an IPv4-mapped address, of the form
::ffff:d.d.d.dwhich is the RFC 4291 s2.5.5.2 prefix
::ffff:0:0/96. - $rv = isAnyIPv4($bits128);
-
This function returns true if the 128 bit string has an IPv4 address in the low 32 bits, of either form
::d.d.d.d or ::ffff:d.d.d.dwhich is the union of the RFC 4291 s2.5.5.1 compatible prefix and the s2.5.5.2 mapped prefix. Croaks if the argument is not 16 bytes.
- $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 presentCroaks if the argument is not 16 bytes.
Widening and narrowing
- $ipv6naddr = ipv4to6($netaddr);
-
Convert an ipv4 network address into an IPv6 network address.
input: 32 bit network address returns: 128 bit network addressCroaks if the argument is not 4 bytes.
- $ipv6naddr = mask4to6($netaddr);
-
Convert an ipv4 network address/mask into an ipv6 network mask.
input: 32 bit network/mask address returns: 128 bit network/mask addressNOTE: returns the high 96 bits as one's
Croaks if the argument is not 4 bytes.
- $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 addressCroaks if the argument is neither 4 nor 16 bytes.
- $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 maskCroaks if the argument is neither 4 nor 16 bytes.
- $netaddr = ipv6to4($ipv6naddr);
-
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 addressCroaks if the argument is not 16 bytes.
- $ipv6naddr = inet_4map6($netaddr or $ipv6naddr);
-
Return an IPv4-mapped IPv6 address: the first 80 bits zero, the next 16 bits one, and the low 32 bits the IPv4 address. RFC 4291 s2.5.5.2.
input: 4 byte packed IPv4 or 16 byte packed IPv6 already in one of the two IPv4-embedded spaces returns: 16 byte packed IPv6 or undef my $mapped = inet_4map6(inet_aton('192.0.2.1')); print ipv6_n2x($mapped); # 0:0:0:0:0:FFFF:C000:201An IPv6 input must already be in one of the two IPv4-embedded spaces. i.e.
::ffff:d.d.d.d or ::d.d.d.d
Arithmetic
- $bitsXn = shiftleft($bits128,$n);
-
Shift a 128 bit string left by
$nbits. Bits shifted past the top are discarded.input: 128 bit string, number of shifts [optional] returns: 128 bit string, shifted left by nWith no
$n, or with$nof 0, the input is returned unchanged, on both the XS and the pure Perl build:my $bits128 = ipv6_aton('ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff'); print ipv6_n2x(shiftleft($bits128)); # FFFF:...:FFFF unchanged print ipv6_n2x(shiftleft($bits128, 8)); # FFFF:...:FF00, top 8 gone$nabove$MAX_SHIFTLEFTof 128 croaks. - 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 numberCroaks if the argument is not 16 bytes.
Decimal strings
- $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 variableCroaks if the string is empty, is longer than 40 digits, holds a character other than 0 to 9, or is a number too large for 128 bits.
Resolver
- ($name,$aliases,$addrtype,$length,@addrs)=naip_gethostbyname(NAME);
-
Replacement for Perl's gethostbyname if Socket6 is available
In ARRAY context, returns a list of five elements, the hostname or NAME, a space separated list of C_NAMES, AF family, length of the address structure, and an array of one or more netaddr's
In SCALAR context, returns the first netaddr.
This function ALWAYS returns an IPv6 address, even on IPv4 only systems. IPv4 answers are mapped into IPv6 space in the RFC 4291 s2.5.5.2 form:
::FFFF:d.d.d.dso an answer for 127.0.0.1 is
0:0:0:0:0:FFFF:7F00:1.This is NOT the expected result from Perl's gethostbyname2. It is instead equivalent to:
On an IPv4 only system: $ipv6naddr = inet_4map6 scalar ( gethostbyname( name )); On a system with Socket6 and a working gethostbyname2: $ipv6naddr = gethostbyname2( name, AF_INET6 ); and if that fails, the IPv4 conversion above.For a gethostbyname2 emulator that behave like Socket6, see: Net::DNS::Dig
- $trueif = havegethostbyname2();
-
This function returns TRUE if Socket6 has a functioning gethostbyname2, otherwise it returns FALSE. See the comments above about the behavior of naip_gethostbyname.
Address family
- $constant = AF_INET;
-
Returns the system value for AF_INET, taken from Socket.
- $constant = AF_INET6;
-
Returns the value for AF_INET6. It comes from Socket6 when Socket6 is installed. Without Socket6 it is a value guessed from the name of the operating system, which is 10 on Linux.
use NetAddr::IP::Util qw(AF_INET AF_INET6); print AF_INET(), ' ', AF_INET6(), "\n"; # 2 10 on Linux
Build mode
- $modetext = mode;
-
Returns the operating mode of this module.
input: none returns: "Pure Perl" or "CC XS"
EXAMPLES
The examples below show the functions in use, and the results are comments.
Convert any text address and mask into a 128 bit vector, extending a 32 bit mask over the IPv6 side:
use NetAddr::IP::Util qw(ipv6_aton inet_any2n hasbits ipv6_n2x);
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);
my $bits = 128; # default
unless (hasbits($mask & $notiv4)) {
$mask |= $notiv4;
$bits = 32;
}
return ($vecip, $mask, $bits);
}
my ($addr, $mask, $bits) = text2vec('192.0.2.9', '255.255.255.0');
print ipv6_n2x($addr), "\n"; # 0:0:0:0:0:0:C000:209
print ipv6_n2x($mask), "\n"; # FFFF:...:FF00, all 128 bits
print "$bits\n"; # 32
my ($a6, $m6, $b6) = text2vec('2001:db8::1', 'ffff:ffff:ffff:ffff::');
print "$b6\n"; # 128
The same thing keyed off isIPv4 instead of hasbits, which is a little faster and needs no mask constant:
my $bits = 128;
if (isIPv4($mask)) {
$mask |= $notiv4;
$bits = 32;
}
Network and broadcast addresses from a vector. Note the $bcast name, which was $broadcast in the original and never declared:
use NetAddr::IP ();
use NetAddr::IP::Util qw(ipv6_n2d);
sub netbroad {
my ($nip) = @_;
my $notmask = ~ $nip->{mask};
my $bcast = $nip->{addr} | $notmask;
my $network = $nip->{addr} & $nip->{mask};
return ($network, $bcast);
}
my $nip = NetAddr::IP->new('192.0.2.9/24');
print ipv6_n2d((netbroad($nip))[0]), "\n"; # 0:0:0:0:0:0:192.0.2.0
print ipv6_n2d((netbroad($nip))[1]), "\n"; # 0:0:0:0:0:0:192.0.2.255
Whether one address falls inside a net, using sub128, whose carry is NOT borrow:
use NetAddr::IP::Util qw(sub128);
sub within {
my ($nip, $net) = @_;
my $addr = $nip->{addr};
my ($nw, $bc) = netbroad($net);
return (sub128($addr, $nw) && sub128($bc, $addr)) ? 1 : 0;
}
my $other = NetAddr::IP->new('198.51.100.1/24');
print within($nip, $nip), "\n"; # 1
print within($other, $nip), "\n"; # 0
addconst stores the carry in scalar context and ($carry, $result) in list context, so wrapping a net at a boundary means taking the second element:
use NetAddr::IP::Util qw(addconst);
use NetAddr::IP ();
my $ip = NetAddr::IP->new('192.0.2.127/26');
my $nextnet = 64; # one /26 step
my $before = $ip->copy; # a new object, same address
$ip++;
if ($ip < $before) { # host part wrapped
(undef, $ip->{addr}) = addconst($ip->{addr}, $nextnet);
}
print "$ip\n"; # 192.0.2.128/26
The test hands both objects to the overloaded <, which compares the addresses as 128 bit numbers. Comparing their string forms instead gives wrong answers, because text order is not address order. As text, 192.0.2.10 sorts before 192.0.2.9, and the wrap from 192.0.2.11 back to 192.0.2.8 sorts after. Stepping a /30 from 192.0.2.8 passes both points:
my $ip = NetAddr::IP->new('192.0.2.8/30');
for my $step (0 .. 3) {
my $before = $ip->copy;
$ip++;
printf "step %d: %-16s wrapped: %d\n", $step, "$ip",
($ip < $before ? 1 : 0);
}
# step 0: 192.0.2.9/30 wrapped: 0
# step 1: 192.0.2.10/30 wrapped: 0
# step 2: 192.0.2.11/30 wrapped: 0
# step 3: 192.0.2.8/30 wrapped: 1
EXPORTS
Nothing is exported by default. Use explicit import tags:
use NetAddr::IP::Util qw(:all);
use NetAddr::IP::Util qw(:math);
The tags are:
:all-
Everything in "EXPORT_OK".
:inet-
Nineteen names: the text and binary conversions, the widening helpers and the resolver. The family tests are in
:math.inet_aton inet_ntoa ipv6_aton ipv6_ntoa ipv6_n2x ipv6_n2d inet_any2n inet_n2dx inet_n2ad inet_pton inet_ntop inet_4map6 ipv4to6 mask4to6 ipanyto6 maskanyto6 ipv6to4 packzeros naip_gethostbyname :ipv4-
Two names:
inet_aton inet_ntoa :ipv6-
Seventeen names. This is
:inetwithoutinet_atonandinet_ntoa:ipv6_aton ipv6_ntoa ipv6_n2x ipv6_n2d inet_any2n inet_n2dx inet_n2ad inet_pton inet_ntop inet_4map6 ipv4to6 mask4to6 ipanyto6 maskanyto6 ipv6to4 packzeros naip_gethostbyname :math-
Eleven names:
hasbits isIPv4 isNewIPv4 isAnyIPv4 addconst add128 sub128 notcontiguous bin2bcd bcd2bin shiftleft
EXPORT_OK
The functions this module can export. The first group is the documented API; the last five are helpers for the test suite, exported so that UtilPP and the XS build can be compared against each other, and not stable API.
inet_aton inet_ntoa ipv6_aton ipv6_ntoa
ipv6_n2x ipv6_n2d inet_any2n inet_n2dx
inet_n2ad inet_pton inet_ntop inet_4map6
hasbits isIPv4 isNewIPv4 isAnyIPv4
shiftleft addconst add128 sub128
notcontiguous bin2bcd bcd2bin mode
ipv4to6 mask4to6 ipanyto6 maskanyto6
ipv6to4 packzeros naip_gethostbyname
havegethostbyname2
AF_INET AF_INET6
Test helpers, not API:
bin2bcdn bcdn2txt bcdn2bin simple_pack
comp128
bin2bcd returns text digits and simple_pack turns text digits into a packed string, padding to $MAX_BCD_DIGITS first. bcdn2txt is the inverse of the packing and bcdn2bin turns it back to 128 bits. comp128 exists because Perl's ~ is faster than calling into the XS routine for a one's complement, so it is published only for testing.
IMPORT TAGS THAT CHANGE BEHAVIOUR
Two tags change what the module does rather than which names it exports.
:noSock6-
Forces
naip_gethostbynameto report that Socket6 is unavailable, so the resolver fallback can be tested on a host that has it. Test hook, not API. :upperand:lower-
These are in NetAddr::IP::InetBase, and see the note there: the case setting is one package global, so importing either affects every user of the module in the process.
:upperwins if both are given, whichever order they are in.
SEE ALSO
NetAddr::IP, NetAddr::IP::Lite, NetAddr::IP::InetBase
AUTHORS
Dean Hamstead <dean@fragfest.com.au>
Luis E. Muñoz <luismunoz@cpan.org>
Michael Robinton <miker@cpan.org>
COPYRIGHT AND LICENSE
This software is Copyright (c) 2026 by Dean Hamstead.
This is free software, licensed under:
The GNU General Public License, Version 2, June 1991
ADDITIONAL LICENSE
This file is also available to redistribute it and/or modify it under the terms of the "Artistic License" which comes with this distribution, in the file named "Artistic".