A pure C implementation providing features similar to Python's ipaddress module for command-line IP address manipulation and querying.
ipaddr [OPTIONS] <address> [command [arguments...]]...Commands can be chained: operations that output addresses can feed into subsequent operations.
make
sudo make install # installs to /usr/local/bin by defaultThe tool accepts three input formats:
- Address:
192.168.1.1or2001:db8::1 - CIDR/Network:
192.168.1.0/24or2001:db8::/32 - Interface Address:
192.168.1.30/28(address with prefix length, may have non-zero host bits)
Addresses are parsed using getaddrinfo(AI_NUMERICHOST) and normalized through getnameinfo(NI_NUMERICHOST), ensuring proper handling of IPv6 zone IDs and address normalization.
The prefix length can be specified in two ways:
- Decimal prefix length:
/24,/64 - Netmask notation:
/255.255.255.0,/ffff:ffff:ffff:ffff::
Internally, all netmasks are converted to prefix lengths. Netmasks must represent valid CIDR prefixes (contiguous 1-bits followed by 0-bits).
-M: Print prefix lengths as netmasks instead of/Nnotation
Prints the normalized address after getaddrinfo→getnameinfo roundtrip.
ipaddr 192.168.001.1
# Output: 192.168.1.1
ipaddr 2001:0db8:0000:0000:0000:0000:0000:0001
# Output: 2001:db8::1 (normalized by getnameinfo)
ipaddr fe80::1%eth0
# Output: fe80::1%eth0Note: getnameinfo() may preserve embedded IPv4 syntax for IPv4-mapped/compatible addresses (e.g., ::ffff:192.168.1.1) rather than converting to pure hexadecimal form.
Prints IP version (4 or 6).
ipaddr 192.168.1.1 version
# Output: 4
ipaddr ::1 version
# Output: 6Prints hex bytes of the address (no separators).
ipaddr 127.0.0.1 packed
# Output: 7f000001
ipaddr ::1 packed
# Output: 00000000000000000000000000000001Prints the address as a decimal integer (32-bit for IPv4, 128-bit for IPv6).
ipaddr 192.168.1.1 to-int
# Output: 3232235777
ipaddr ::1 to-int
# Output: 1Prints the prefix length. Returns 32 for IPv4 addresses or 128 for IPv6 addresses without explicit prefix.
ipaddr 192.168.1.0/24 prefix-length
# Output: 24
ipaddr 192.168.1.1 prefix-length
# Output: 32Prints the netmask in address form.
ipaddr 192.168.1.0/24 netmask
# Output: 255.255.255.0
ipaddr 2001:db8::/32 netmask
# Output: ffff:ffff::Prints the hostmask (inverse of netmask) in address form.
ipaddr 192.168.1.0/24 hostmask
# Output: 0.0.0.255
ipaddr 2001:db8::/32 hostmask
# Output: ::ffff:ffff:ffff:ffff:ffff:ffffPrints only the address part, discarding prefix length if present.
ipaddr 192.168.1.30/28 address
# Output: 192.168.1.30Prints the network address (zeroes host bits) with prefix length.
ipaddr 192.168.1.30/28 network
# Output: 192.168.1.16/28
ipaddr 192.168.1.1 network
# Output: 192.168.1.1/32Prints the broadcast address for a network. Cannot be used with plain addresses (without prefix length).
ipaddr 192.168.1.16/28 broadcast
# Output: 192.168.1.31
ipaddr 2001:db8::/64 broadcast
# Output: 2001:db8::ffff:ffff:ffff:ffffPrints the zone ID including the % prefix. Empty for IPv4.
ipaddr fe80::1%eth0 zone-id
# Output: %eth0
ipaddr 192.168.1.1 zone-id
# Output: (empty)Prints the numeric scope ID. Returns 0 for IPv4.
ipaddr fe80::1%2 scope-id
# Output: 2
ipaddr 192.168.1.1 scope-id
# Output: 0Extracts the last 32 bits and prints them in IPv4 notation. For IPv4 addresses, returns normalized form.
ipaddr ::ffff:0102:0304 ipv4
# Output: 1.2.3.4
ipaddr 192.168.1.1 ipv4
# Output: 192.168.1.1Extracts the embedded IPv4 address from a 6to4 address (2002::/16). Returns error if not a valid 6to4 address.
ipaddr 2002:c000:0201::1 6to4
# Output: 192.0.2.1Extracts the Teredo server or client IPv4 address from a Teredo address (2001::/32).
ipaddr 2001:0000:4136:e378:8000:63bf:3fff:fdd2 teredo server
# Output: 65.54.227.120
ipaddr 2001:0000:4136:e378:8000:63bf:3fff:fdd2 teredo client
# Output: 192.0.2.45Returns exit code 0 (true) or 1 (false).
ipaddr <address> is-multicast
ipaddr <address> is-private
ipaddr <address> is-global
ipaddr <address> is-unspecified
ipaddr <address> is-reserved
ipaddr <address> is-loopback
ipaddr <address> is-link-localExamples:
ipaddr ::1 is-loopback
# Exit code: 0 (true)
ipaddr 192.168.1.1 is-private
# Exit code: 0 (true)
ipaddr 8.8.8.8 is-global
# Exit code: 0 (true)Note: is-private covers RFC 1918 addresses, IPv6 ULAs (fc00::/7), and deprecated site-local addresses (fec0::/10).
Prints the number of addresses in the network. Returns 1 for plain addresses.
ipaddr 192.168.1.0/24 num-addresses
# Output: 256
ipaddr 2001:db8::/64 num-addresses
# Output: 18446744073709551616Returns the Nth address in the network. Supports negative indexing.
ipaddr 192.168.1.16/28 host 0
# Output: 192.168.1.16
ipaddr 192.168.1.16/28 host 1
# Output: 192.168.1.17
ipaddr 192.168.1.16/28 host -1
# Output: 192.168.1.31
ipaddr 192.168.1.16/28 host -2
# Output: 192.168.1.30Note: host 0 is equivalent to network, and host -1 is equivalent to broadcast.
Returns the host portion of an interface address as a decimal integer.
ipaddr 192.168.1.35/28 host-index
# Output: 3
ipaddr 192.168.1.16/28 host-index
# Output: 0Returns the Nth subnet with the given prefix length. Supports negative indexing.
<prefixlen> can be:
- Absolute:
28,64 - Relative (prefixed with
+):+4,+8
ipaddr 192.168.1.0/24 subnet 28 0
# Output: 192.168.1.0/28
ipaddr 192.168.1.0/24 subnet 28 3
# Output: 192.168.1.48/28
ipaddr 192.168.1.0/24 subnet +5 -2
# Equivalent to: ipaddr 192.168.1.0/24 subnet 29 -2
# Output: 192.168.1.192/29For interface addresses, preserves the host portion:
ipaddr 192.168.1.1/24 subnet 28 2
# Output: 192.168.1.33/28Returns the supernet with the given prefix length.
<prefixlen> can be:
- Absolute:
16,48 - Relative (prefixed with
-):-8,-16
ipaddr 192.168.1.0/24 super 16
# Output: 192.168.0.0/16
ipaddr 192.168.1.0/24 super -8
# Equivalent to: ipaddr 192.168.1.0/24 super 16
# Output: 192.168.0.0/16Returns exit code 0 (true) or 1 (false).
Tests if the left operand is contained within the right network.
ipaddr 192.168.1.1/24 in 192.168.0.0/16
# Exit code: 0 (true)
ipaddr 192.168.1.1/16 in 192.168.1.0/24
# Exit code: 1 (false)For interface addresses, only the network portion is compared (host bits ignored).
Equivalent to <address/network> in <left-operand>.
ipaddr 192.168.0.0/16 contains 192.168.1.1/24
# Exit code: 0 (true)Tests if two networks overlap (either contains the other).
ipaddr 192.168.1.0/24 overlaps 192.168.1.128/25
# Exit code: 0 (true)
ipaddr 192.168.1.0/24 overlaps 192.168.2.0/24
# Exit code: 1 (false)Compares two addresses/networks. Networks are compared by network address first, then prefix length, then host bits (for interface addresses).
ipaddr <addr1> eq <addr2> # Equal
ipaddr <addr1> ne <addr2> # Not equal
ipaddr <addr1> lt <addr2> # Less than
ipaddr <addr1> le <addr2> # Less than or equal
ipaddr <addr1> gt <addr2> # Greater than
ipaddr <addr1> ge <addr2> # Greater than or equalReturns exit code 0 (true) or 1 (false).
- Address parsing: Uses
getaddrinfo(AI_NUMERICHOST)for AF-independent parsing - Internal storage: Uses
struct sockaddr_storageto preserve address family and IPv6 scope ID - Address printing: Uses
getnameinfo(NI_NUMERICHOST)for normalized output - Netmask handling: Netmasks are validated (must be contiguous 1-bits) and converted to prefix length
- CIDR flag: Each address structure tracks whether it's a plain address or CIDR/interface address
By default, prefix lengths are printed as /N. Use -M to force netmask notation:
ipaddr -M 192.168.1.0/24
# Output: 192.168.1.0/255.255.255.0Zone IDs (scope IDs) are preserved through the parsing pipeline and included in output where present. They depend on the local system's network interface configuration.
Commands requiring enumeration (host, subnet, num-addresses) need 128-bit integer arithmetic for IPv6. These operations use appropriate integer types and algorithms to handle the full IPv6 address space.
Operations that output addresses/networks can be chained together, allowing the output of one operation to become the input for the next. This enables complex transformations in a single command.
ipaddr <address> <operation1> [args...] <operation2> [args...] <operation3> [args...]The following operations output addresses/networks and can be chained:
- Default (normalization)
addressnetworkbroadcasthost <index>subnet <prefixlen> <index>super <prefixlen>ipv46to4teredo server|client
Operations that output non-address data (numbers, booleans) terminate the chain:
version,packed,to-intprefix-length,netmask,hostmaskzone-id,scope-idnum-addresses,host-indexis-*(classification tests)in,contains,overlapseq,ne,lt,le,gt,ge
# Get the 19th host in the 2nd /20 subnet of 192.168.0.0/16
ipaddr 192.168.0.0/16 subnet 20 1 host 19
# Output: 192.168.16.19
# Get broadcast of the 5th /24 subnet of 10.0.0.0/16
ipaddr 10.0.0.0/16 subnet 24 4 broadcast
# Output: 10.0.4.255
# Get network address of a specific subnet
ipaddr 192.168.0.0/16 subnet 24 10 network
# Output: 192.168.10.0/24# Go to supernet, then get a different subnet
ipaddr 192.168.5.0/24 super 16 subnet 24 50
# Output: 192.168.50.0/24
# Navigate through network hierarchy
ipaddr 10.1.2.3/24 network super 16 subnet 20 3 host 100
# Output: 10.1.48.100# Extract IPv4 from 6to4, then get network info
ipaddr 2002:c000:0201::1 6to4 to-int
# Output: 3221226241
# Get the broadcast of extracted IPv4 (if it were /24)
ipaddr ::ffff:192.168.1.1 ipv4 network
# Output: 192.168.1.1/32 (plain address becomes /32)# Get last host in the last subnet
ipaddr 10.0.0.0/16 subnet 24 -1 host -1
# Output: 10.0.255.255
# Get the first host (after network address) in a subnet
ipaddr 172.16.0.0/12 subnet 24 0 host 1
# Output: 172.16.0.1
# Navigate to a specific subnet and get its supernet
ipaddr 192.168.0.0/16 subnet 28 100 super 24
# Output: 192.168.6.0/24# Subnet an interface address (preserves host portion)
ipaddr 192.168.1.1/16 subnet 24 5 host 50
# Output: 192.168.5.50
# This works because:
# 1. 192.168.1.1/16 subnet 24 5 -> 192.168.5.1/24 (host .1 preserved)
# 2. 192.168.5.1/24 host 50 -> 192.168.5.50# Get Teredo client address and convert to integer
ipaddr 2001:0000:4136:e378:8000:63bf:3fff:fdd2 teredo client to-int
# Output: 3221225997
# Get broadcast address and convert to packed form
ipaddr 10.0.0.0/24 broadcast packed
# Output: 0a0000ff# Check if two subnets overlap
ipaddr 10.0.0.0/16 subnet 24 5 in 10.0.0.0/20
# Exit code: 0 (true)
# Compare derived addresses
ipaddr 192.168.0.0/16 subnet 24 10 host 5 lt 192.168.10.10
# Exit code: 0 (true, 192.168.10.5 < 192.168.10.10)# Allocate DHCP pool: get addresses 10-254 in the first subnet
for i in {10..254}; do
ipaddr 10.0.0.0/16 subnet 24 0 host $i
done
# Find the gateway (first host) in each of 8 subnets
for i in {0..7}; do
ipaddr 172.16.0.0/16 subnet 24 $i host 1
done
# Get the last usable address in a subnet (broadcast - 1)
ipaddr 192.168.1.0/24 host -2
# Output: 192.168.1.2540: Success (or true for boolean tests)1: Failure (or false for boolean tests)2: Invalid arguments or usage error
# Normalize addresses
ipaddr 192.168.001.001
# 192.168.1.1
# Extract network
ipaddr 192.168.1.35/24 network
# 192.168.1.0/24
# List first 5 hosts
for i in {0..4}; do ipaddr 10.0.0.0/24 host $i; done
# 10.0.0.0
# 10.0.0.1
# 10.0.0.2
# 10.0.0.3
# 10.0.0.4
# Check if address is private
if ipaddr 192.168.1.1 is-private; then
echo "Private address"
fi
# Subnet calculation
ipaddr 10.0.0.0/8 subnet 16 256
# 10.1.0.0/16
# Extract IPv4 from IPv4-mapped IPv6
ipaddr ::ffff:192.168.1.1 ipv4
# 192.168.1.1
# Compare addresses
ipaddr 192.168.1.1 lt 192.168.1.2
# Exit code: 0 (true)- RFC 4291 (IPv6 Addressing Architecture)
- RFC 4193 (Unique Local IPv6 Unicast Addresses)
- RFC 3056 (Connection of IPv6 Domains via IPv4 Clouds - 6to4)
- RFC 4380 (Teredo: Tunneling IPv6 over UDP through NATs)
- Python
ipaddressmodule documentation