NAME

NetAddr::IP::InetBase - IPv4 and IPv6 address parsing and formatting utilities

VERSION

version 4.080_07

SYNOPSIS

use NetAddr::IP::InetBase qw(fillIPv4 inet_any2n inet_aton inet_n2dx
    inet_ntoa ipv6_aton ipv6_n2x);

my $packed = inet_aton('192.0.2.1');
print length($packed), "\n";                      # 4
print inet_ntoa($packed), "\n";                   # 192.0.2.1
print ipv6_n2x(ipv6_aton('2001:db8::1')), "\n";   # 2001:db8:0:0:0:0:0:1
print inet_n2dx(inet_any2n('192.0.2.1')), "\n";   # 192.0.2.1
print fillIPv4('192.0.2'), "\n";                  # 192.0.0.2

NetAddr::IP::InetBase::lower();                   # case, see IMPORT TAGS
NetAddr::IP::InetBase::upper();

DESCRIPTION

The NetAddr::IP::InetBase module is the pure Perl layer that converts IPv4 and IPv6 addresses between binary and text. Everything here is pure Perl on every host. Both NetAddr::IP::Util and the XS build take these functions from it rather than reimplementing them. The function inet_ntop calls core Socket, which calls the platform C library. See "Core Socket".

A binary address here is called packed below, as opposed to text. It comes in two sizes. The IPv4 form, $V4_PACKED_BYTES bytes, is what inet_aton returns. The 16 byte form, $V6_PACKED_BYTES, is what ipv6_aton returns, and inet_any2n returns it for both families, with an IPv4 address in the low 32 bits.

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

Each d is decimal, 0 to 255, without a leading zero. No part of an IPv4 address takes one, in a tail or on its own, so ::ffff:192.0.2.010, 192.0.2.010 and 010.1 are not addresses: the C library's inet_aton reads 010 as octal 8, and a person reads it as decimal 10.

The whole string has to be the address. Surrounding whitespace, a trailing newline included, makes it text that is not one, and inet_aton returns undef for it without asking gethostbyname. The constructor, NetAddr::IP->new, strips surrounding whitespace before it reads an address.

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. A binary argument of the wrong length is an error, and each entry below says which functions croak on one.

A binary argument is measured in bytes, as the XS functions of NetAddr::IP::Util measure one. A string upgraded to UTF-8 is read as the bytes it holds. A string with a character above 0xFF cannot be read as bytes, and every function that croaks on a wrong length croaks on it, with Wide character in and the full name of the function that measures the argument.

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 undef

Short forms follow the BSD inet_aton convention, not RFC 791: 127.1 is 127.0.0.1 and 192.0.2 is 192.0.0.2. Its octal reading of a leading zero does not: 192.0.2.010 returns undef. A literal does not call gethostbyname. Other text does, and that function keeps one static buffer, so two threads resolving names at once can swap answers. Returns undef for an octet above 255, for text with whitespace, 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 undef

Returns undef if the text is not an address, including a bare number such as 10, which has no colon and is no dotted quad. An empty or undefined argument is read as ::, the all-zero address.

$netaddr = inet_pton($AF_family,$text_addr);

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_INET and AF_INET6.

NOTE: inet_pton reads the text itself rather than calling the platform inet_pton, so every host reads it alike. For IPv4, inet_pton(AF_INET, ...) takes only four decimal parts from 0 to 255, each without a leading zero, and nothing after them. It returns undef for a short form such as 127.1, for a host name, and for an undefined address. By contrast, inet_aton accepts the short form and the host name.

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.1

Croaks if the argument is not 4 bytes.

$ipv6text = ipv6_ntoa($ipv6naddr);

Convert a 128 bit binary IPv6 address to the compressed RFC 5952 s4 text representation.

input:    128 bit RDATA string
returns:  ipv6 text

Croaks if the argument is not 16 bytes.

This is inet_ntop(AF_INET6,$ipv6naddr). An address with an IPv4 address in the low 32 bits is printed by the platform inet_ntop. On glibc that is mixed notation, ::ffff:192.0.2.1. A different C library can print a different form. See the notes on inet_ntop below.

No method of NetAddr::IP or NetAddr::IP::Lite calls this function. Stringification goes through ipv6_n2x, which is pure Perl on every host.

$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:x

Note: this function does NOT compress adjacent
strings of 0:0:0:0 into the :: format
$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.d

Note: this function does NOT compress adjacent
strings of 0:0:0:0 into the :: format
$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

Note: this function does NOT compress adjacent
strings of 0:0:0:0 into the :: format

Croaks 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.ddd

Note: this function does NOT compress adjacent
strings of 0:0:0:0 into the :: format

Croaks if the argument is not 16 bytes.

$text_addr = inet_ntop($AF_family,$netaddr);

This function takes an 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.

For IPv4, inet_ntop(AF_INET, ...) is inet_ntoa. For IPv6, inet_ntop(AF_INET6, ...) is the platform inet_ntop. An address with an IPv4 address in the low 32 bits is printed in that library's form. On glibc:

address           text
::ffff:192.0.2.1  ::ffff:192.0.2.1
::ffff:0:0        ::ffff:0.0.0.0
::192.0.2.1       ::192.0.2.1

A different C library can print a different form. The difference is confined to the mapped prefix ::ffff:0:0/96 and the deprecated compatible prefix ::/96. Everything else agrees, including zero run compression, which of two equal runs is shortened, a single zero group, leading zeros and case.

$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

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.d

which 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, or isNewIPv4 or isAnyIPv4 when 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.d

which is the RFC 4291 s2.5.5.2 prefix ::ffff:0:0/96. Croaks if the argument is not 16 bytes.

$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.d

which 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.

Address family

$constant = AF_INET;

Returns the system value for AF_INET, taken from Socket.

$constant = AF_INET6;

Returns the value for AF_INET6, taken from Socket.

use NetAddr::IP::InetBase qw(AF_INET AF_INET6);
print AF_INET(), ' ', AF_INET6(), "\n";   # 2, then the platform value
$false = fake_AF_INET6;

Deprecated. Returns 0 on every host, because AF_INET6 always comes from Socket, and warns in the deprecated category. See "DEPRECATED".

Short IPv4 text

$ip_filled = fillIPv4($shortIP);

Expands a short IPv4 text address to the four part form, padding the missing octets with zeros. This follows the BSD inet_aton convention for padding and is not RFC 791. Unlike BSD, every part must fit in an octet, so 300 gives undef rather than 0.0.1.44.

input:    short or full IPv4 text
returns:  the four part form, or undef

print fillIPv4('192.0.2.1'), "\n";   # 192.0.2.1
print fillIPv4('192.0.2'),   "\n";   # 192.0.0.2
print fillIPv4('192.0'),     "\n";   # 192.0.0.0
print fillIPv4('10'),        "\n";   # 0.0.0.10

An argument that does not look like a short or full IPv4 address is returned unchanged, so a hostname passes straight through, and an octet out of range gives undef:

print fillIPv4('example.com'), "\n"; # example.com
print defined(fillIPv4('256.1.1.1')) ? 'defined' : 'undef', "\n";   # undef
print defined(fillIPv4('300'))       ? 'defined' : 'undef', "\n";   # undef

The argument is text, not a packed address. A packed string does not match, so it is returned unchanged too.

Case

NetAddr::IP::InetBase::lower();

Return IPv6 strings in lowercase. This is the default only when NetAddr::IP::InetBase is loaded on its own. The module NetAddr::IP::Util loads this one with the :upper tag, so a program that loads NetAddr::IP::Util, NetAddr::IP::Lite or NetAddr::IP gets uppercase output unless it calls lower() or imports :lower from NetAddr::IP::Lite, NetAddr::IP, or this module.

NetAddr::IP::InetBase::upper();

Return IPv6 strings in uppercase.

The case setting is one package-wide variable. Calling lower() or upper(), or importing :lower or :upper from this module, NetAddr::IP::Lite, or NetAddr::IP, changes the output for every user of these modules in the running program, not only the caller. The last call wins. Those tags are not accepted by NetAddr::IP::Util. Call its lower() or upper().

The default may be set to uppercase when the module is loaded by importing the tag :upper:

use NetAddr::IP::InetBase qw(:upper);

EXPORTS

Nothing is exported by default.

EXPORT_OK

inet_aton     inet_ntoa      ipv6_aton      ipv6_ntoa
ipv6_n2x      ipv6_n2d       inet_any2n     inet_n2dx
inet_n2ad     inet_pton      inet_ntop      packzeros
isIPv4        isNewIPv4      isAnyIPv4      AF_INET
AF_INET6      fake_AF_INET6  fillIPv4

IMPORT TAGS

:all

Every name in "EXPORT_OK".

:ipv4
inet_aton inet_ntoa fillIPv4
:ipv6
ipv6_aton ipv6_ntoa ipv6_n2x ipv6_n2d
inet_any2n inet_n2dx inet_n2ad
inet_pton inet_ntop packzeros
:lower and :upper

The case tags. If both are given, :upper wins, whichever order they are in. See "THE CASE POLICY".

DEPRECATED

Everything listed here is deprecated and will be removed in version 5.

fake_AF_INET6

Returned the AF_INET6 value this module guessed from the operating system's name on a perl whose Socket had none. Every supported perl's Socket has AF_INET6, so nothing is guessed and it returns 0. Call AF_INET6 for the value.

THE CASE POLICY

The case of IPv6 text output is one package global, not a setting per object or per module, so it applies to every user of the library in the process. Two consequences worth stating plainly.

This module defaults to lowercase:

use NetAddr::IP::InetBase qw(ipv6_aton ipv6_n2x);
my $bits128 = ipv6_aton('2001:db8::1');
print ipv6_n2x($bits128);          # 2001:db8:0:0:0:0:0:1

Importing :upper from this module switches it:

use NetAddr::IP::InetBase qw(:upper ipv6_aton ipv6_n2x);
my $bits128 = ipv6_aton('2001:db8::1');
print ipv6_n2x($bits128);          # 2001:DB8:0:0:0:0:0:1

Loading NetAddr::IP::Util does the same, because that module imports :upper from here as it loads. Passing :upper or :lower on a use NetAddr::IP::Util line dies. Both NetAddr::IP::Lite and NetAddr::IP accept the tags.

And once set, an unrelated package importing :lower changes it back for everyone:

use NetAddr::IP;
package Other;
use NetAddr::IP::Lite qw(:lower);
package main;
print NetAddr::IP->new('2001:db8::1')->addr, "\n";   # 2001:db8:0:0:0:0:0:1

Under ithreads each thread has its own copy of the setting. A thread starts with the case in force when it was created, and upper() or lower() in one thread does not change another.

Whether uppercase or lowercase should be the default, and whether the setting should be process-wide at all, is an open question: see GH#7.

Three functions ignore the setting entirely and are always lowercase: packzeros, which follows RFC 5952 s4.3, and ipv6_ntoa and inet_ntop, which follow the platform inet_ntop.

Core Socket

The constants AF_INET and AF_INET6 and the function inet_ntop come from core Socket. Socket6 is not used. The inet_pton here reads the text itself, because C libraries differ in the IPv4 text they accept.

For an IPv4 address, inet_ntop is inet_ntoa. For an IPv6 address, inet_ntop is the platform function, so an address with an IPv4 address in the low 32 bits follows that C library. On glibc the mapped form is ::ffff:192.0.2.1.

SEE ALSO

NetAddr::IP, NetAddr::IP::Lite, NetAddr::IP::Util

AUTHORS

  • Dean Hamstead <dean@fragfest.com.au>

  • Luis E. Muñoz <luismunoz@cpan.org>

  • Michael Robinton <michael@bizsystems.com>

COPYRIGHT AND LICENSE

This software is Copyright (c) 2026 by Dean Hamstead, Luis E. Muñoz, Michael Robinton.

This is free software, licensed under:

The MIT (X11) License

The full text of the license can be found in the LICENSE file included with this distribution.