-
Notifications
You must be signed in to change notification settings - Fork 64
Code Examples 1: Creating, Parsing, Extracting Address Subnet Info
- Parse IP Address or Subnet String
- Parse IP Address String with Prefix Length as Subnet or IP Address
- Check if String is an IP Address or Host Name
- Parse Socket Address
- Convert to/from byte[], int, BigInteger or InetAddress
- Get Prefix Length, Network Mask, Network Address, Version, Subnet Size and Segments from CIDR Address or Subnet
- Check if Multicast
- Control Parsing of IP Addresses with Fewer Segments than Standard
Parses representations of IPv6 and IPv4 addresses and subnets. For a list of supported formats, see javadoc for IPAddressString or the docs and docs examples
You can either validate using exceptions:
try {
IPAddressString str = new IPAddressString("::1");
IPAddress addr = str.toAddress();
// use address
} catch(AddressStringException e) {
// e.getMessage has validation error
}
... or avoid exceptions, instead checking for null:
IPAddressString str = new IPAddressString("a:b:c:d:e-f:f:1.2-3.3.4/64");
IPAddress addr = str.getAddress();
if(addr != null) {
// use address
}
Starting with address or subnet strings, use exceptions to handle formats:
try {
val ipv6AddressStr = IPAddressString("a:b:c:d::a:b/64")
val ipv6Addr = ipv6AddressStr.toAddress()
// use address
} catch(e: AddressStringException) {
// e.message has validation error
}
...or use nullable types and safe calls to handle invalid or unexpected formats:
val ipv6v4Str = "a:b:c:d:e:f:1.2.3.4/112"
val ipv6v4AddressStr = IPAddressString(ipv6v4Str)
val ipAddr: IPAddress? = ipv6v4AddressStr.address
Comparing to the analogous code with the Go library...
Starting with address or subnet strings, use errors to handle invalid formats:
ipv6AddrStr := ipaddr.NewIPAddressString("a:b:c:d::a:b/64")
if ipAddr, err := ipv6AddrStr.ToAddress(); err != nil {
// err.Error() has validation error
} else {
// use the address
}
...or avoid errors, checking for nil:
str := ipaddr.NewIPAddressString("a:b:c:d:e-f:f:1.2-3.3.4/64")
addr := str.GetAddress()
if addr != nil {
// use address
}
In the IPAddress library, an IPAddress instance can be either an address or a subnet, which differs from most other libraries, which typically use separate types. Using a single type simplifies code.
By default, CIDR IP addresses with a host of zero (or IPAddress ranges whose boundaries have hosts of zero) are treated as subnets, while CIDR IP addresses with non-zero hosts are treated as single addresses. The bits beyond the prefix (as determined by the prefix length) form the host. For example:
parse("1.2.0.0/16"); // this is a subnet of 65536 addresses, the 0.0 host makes it a network
parse("1.2.3.4/16"); // this is a single address, since the host is 3.4
static void parse(String addressStr) {
IPAddress addr = new IPAddressString(addressStr).getAddress();
System.out.println("count of "+ addressStr + " is " + addr.getCount());
}
Output:
count of 1.2.0.0/16 is 65536
count of 1.2.3.4/16 is 1
This convention follows the same convention in common usage by network engineers.
With this convention, the address 1.2.0.0/16, with a zero host, often called the network address, is the entire network of addresses with the same 16-bit prefix 1.2. Meanwhile, the address 1.2.3.4/16, with a non-zero host, is the single address 1.2.3.4 in that same network. Sometimes it is called an interface address.
The same convention applies to IPv6.
If you wish to see the network and host bits, use toBinaryString()
.
Use getLower()
parseAddress("1.2.0.0/16");
parseAddress("1.2.3.4/16");
static void parseAddress(String addressStr) {
IPAddress addr = new IPAddressString(addressStr).getAddress().getLower();
System.out.println("count of "+ addr + " is " + addr.getCount());
}
Output:
count of 1.2.0.0/16 is 1
count of 1.2.3.4/16 is 1
Or use toZeroHost()
parseAddressHost("1.2.0.0/16");
parseAddressHost("1.2.3.4/16");
static void parseAddressHost(String addressStr) {
IPAddress addr = new IPAddressString(addressStr).getAddress();
if(addr.isSinglePrefixBlock()) {
addr = addr.toZeroHost();
System.out.print("zero host ");
}
System.out.println("count of "+ addr + " is " + addr.getCount());
}
Output:
zero host count of 1.2.0.0/16 is 1
count of 1.2.3.4/16 is 1
Or parse separately from the prefix length:
parseHostAddress("1.2.0.0/16");
parseHostAddress("1.2.3.4/16");
static void parseHostAddress(String addressStr) {
IPAddressString addrStr = new IPAddressString(addressStr);
IPAddress addr = addrStr.getHostAddress(); // ignores prefix length
addr = addr.setPrefixLength(addrStr.getNetworkPrefixLength(), false, false);
System.out.println("count of "+ addr + " is " + addr.getCount());
}
Output:
count of 1.2.0.0/16 is 1
count of 1.2.3.4/16 is 1
Use toPrefixBlock()
parseSubnet("1.2.0.0/16");
parseSubnet("1.2.3.4/16");
static void parseSubnet(String str) {
IPAddress addr = new IPAddressString(str).getAddress().toPrefixBlock();
System.out.println("count of "+ addr + " is " + addr.getCount());
}
Output:
count of 1.2.0.0/16 is 65536
count of 1.2.0.0/16 is 65536
The code above works the same way for IPv6 address strings with prefix lengths.
Unlike java.net.InetAddress.getByName(), parsing an invalid address or host will not trigger a DNS lookup.
check("1.2.3.4");
check("1.2.a.4");
check("::1");
check("[::1]");
check("1.2.?.4");
static void check(String hostStr) {
HostName host = new HostName(hostStr);
try {
host.validate();
if(host.isAddress()) {
System.out.println("address: " + host.asAddress());
} else {
System.out.println("host name: " + host);
}
} catch(HostNameException e) {
System.out.println(e.getMessage());
}
}
Output:
address: 1.2.3.4
host name: 1.2.a.4
address: ::1
address: ::1
1.2.?.4 Host error: invalid character at index 4
A socket address, or TCP address, consists of address and port, or possibly a host name and port. Use HostName to parse.
String hostName = "[a:b:c:d:e:f:a:b]:8080";
String hostName2 = "1.2.3.4:8080";
String hostName3 = "a.com:8080";
try {
HostName host = new HostName(hostName);
host.validate(); // to throw parse exception, rather than check for null
InetSocketAddress address = host.asInetSocketAddress();
HostName host2 = new HostName(hostName2);
host2.validate();
InetSocketAddress address2 = host2.asInetSocketAddress();
HostName host3 = new HostName(hostName3);
host3.validate();
InetSocketAddress address3 = host3.asInetSocketAddress();
// use socket addresses
} catch (HostNameException e) {
String msg = e.getMessage();
// handle improperly formatted host name or address string
}
IPAddress loopback = new IPAddressString("::1").getAddress();
byte bytes[] = loopback.getBytes();
System.out.println(Arrays.toString(bytes));
IPAddressGenerator generator = new IPAddressGenerator();
IPAddress backAgain = generator.from(bytes);
System.out.println(backAgain);
Output:
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]
::1
IPAddress loopback = new IPAddressString("::1").getAddress();
InetAddress inetAddress = loopback.toInetAddress();
System.out.println(inetAddress);
IPAddressGenerator generator = new IPAddressGenerator();
IPAddress andBackAgain = generator.from(inetAddress);
System.out.println(andBackAgain);
Output:
/0:0:0:0:0:0:0:1
::1
IPAddress loopbackv6 = new IPAddressString("::1").getAddress();
BigInteger bigVal = loopbackv6.getValue();
System.out.println(bigVal);
IPv6Address backAgainv6 = new IPv6Address(bigVal);
System.out.println(backAgainv6);
Output:
1
::1
IPv4Address loopbackv4 = new IPAddressString("127.0.0.1").
getAddress().toIPv4();
int val = loopbackv4.intValue();
System.out.println(val);
IPv4Address backAgainv4 = new IPv4Address(val);
System.out.println(backAgainv4);
Output:
2130706433
127.0.0.1
IPAddress loopback = new IPAddressString("::1").getAddress();
BigInteger value = loopback.getValue();
System.out.println(value);
IPAddress andAgain = loopback.isIPv4() ?
new IPv4Address(value.intValue()) : new IPv6Address(value);
System.out.println(andAgain);
Output:
1
::1
static byte[] extendArray(byte bytes[], int len) {
if(bytes.length < len) {
byte newBytes[] = new byte[len];
System.arraycopy(bytes, 0, newBytes,
newBytes.length - bytes.length, bytes.length);
return newBytes;
}
return bytes;
}
IPAddress loopback = new IPAddressString("::1").getAddress();
BigInteger value = loopback.getValue();
System.out.println(value);
byte bigIntBytes[] = extendArray(value.toByteArray(), loopback.getByteCount());
IPAddressGenerator generator = new IPAddressGenerator();
IPAddress andAgain = generator.from(bigIntBytes); // keys on byte length for version
System.out.println(andAgain);
Output:
1
::1
Get Prefix Length, Network Mask, Network Address, Version, Subnet Size and Segments from CIDR Address or Subnet
The code is entirely polymorphic. Note the addresses are subnets since hosts are zero.
cidr("192.168.10.0/24");
cidr("2001:db8:abcd:0012::/64");
static void cidr(String str) {
IPAddressString addrString = new IPAddressString(str);
IPAddress addr = addrString.getAddress();
IPVersion version = addrString.getIPVersion();
IPAddressSegment[] segments = addr.getSegments();
int bitLength = addr.getBitCount();
BigInteger size = addr.getCount();
Integer prefixLen = addr.getNetworkPrefixLength();
IPAddress mask = addr.getNetworkMask();
IPAddress maskNoPrefix = mask.withoutPrefixLength();
// three different ways to get the network address
IPAddress networkAddr = addr.mask(mask);
IPAddress networkAddrAnotherWay = addr.getLower().withoutPrefixLength();
IPAddress networkAddrOneMoreWay = addr.toZeroHost().withoutPrefixLength();
PrintStream out = System.out;
out.println(version + " address: " + addr);
out.println("prefix length: " + prefixLen);
out.println("bit length: " + bitLength);
out.println("segments: " + Arrays.asList(segments));
out.println("size: " + size);
out.println("mask with prefix: " + mask);
out.println("mask: " + maskNoPrefix);
out.println("network address: " + networkAddr + "\n");
}
Output:
IPv4 address: 192.168.10.0/24
prefix length: 24
bit length: 32
segments: [192, 168, 10, 0-255]
size: 256
mask with prefix: 255.255.255.0/24
mask: 255.255.255.0
network address: 192.168.10.0
IPv6 address: 2001:db8:abcd:12::/64
prefix length: 64
bit length: 128
segments: [0x2001, 0xdb8, 0xabcd, 0x12, 0x0-0xffff, 0x0-0xffff, 0x0-0xffff, 0x0-0xffff]
size: 18446744073709551616
mask with prefix: ffff:ffff:ffff:ffff::/64
mask: ffff:ffff:ffff:ffff::
network address: 2001:db8:abcd:12::
static void isMulticast(String addressStr) {
IPAddressString addrString = new IPAddressString(addressStr);
IPAddress addr = addrString.getAddress();
boolean result = addr.isMulticast();
System.out.println(addr + " is multicast " + result);
}
isMulticast("224.0.0.0/4");
isMulticast("ff00::/64");
isMulticast("224-239.0.0.1-5");
isMulticast("1.0.0.0/4");
isMulticast("fe::/64");
Output:
224.0.0.0/4 is multicast true
ff00::/64 is multicast true
224-239.0.0.1-5 is multicast true
1.0.0.0/4 is multicast false
fe::/64 is multicast false
If you type 23.23.43 into the address bar of some browsers, you will see it is interpreted as 23.23.0.43. If you do the same with http://2222, you will see it interpreted as the IPv4 address 0.0.8.174. Those strings are IPv4 string formats originally introduced by the inet_aton utility in BSD Unix. Those formats have persisted with inet_aton in the various Unix and Linux flavours, while spreading elsewhere into browsers and other software.
If you wish, you can treat such addresses as invalid, using validation parameters. You can either do it on a case-by-case basis or make it the default behaviour.
IP address strings:
IPAddressStringParameters strParams = new IPAddressStringParameters.Builder().
allow_inet_aton(false).toParams();
String str = "23.23.43";
// do not allow it this time
IPAddressString addrStr = new IPAddressString(str, strParams);
check(addrStr);
// otherwise allowed, since the default validation options are permissive
addrStr = new IPAddressString(str);
check(addrStr);
// or make it default behaviour using fixed params with your own class
class MyStringClass extends IPAddressString {
MyStringClass(String name) {
super(name, strParams);
}
}
addrStr = new MyStringClass(str);
check(addrStr);
static void check(HostIdentifierString addrStr) {
try {
System.out.println("address: " + addrStr.toAddress());
} catch (HostIdentifierException | IOException e) {
System.out.println(e.getMessage());
}
}
Output:
23.23.43 IP Address error: options do not allow IPv4 address with less than four segments
address: 23.23.0.43
23.23.43 IP Address error: options do not allow IPv4 address with less than four segments
Host names:
HostNameParameters hostParams = new HostNameParameters.Builder().
getAddressOptionsBuilder().allow_inet_aton(false).getParentBuilder().toParams();
String str = "23.23.43";
// do not allow it this time
HostName hostName = new HostName(str, hostParams);
check(hostName);
// otherwise allowed
hostName = new HostName(str);
check(hostName);
// or make it default behaviour using fixed params with your own class
class MyHostNameClass extends HostName {
MyHostNameClass(String name) {
super(name, hostParams);
}
}
hostName = new MyHostNameClass(str);
check(hostName);
Output:
23.23.43 Host error: invalid host
address: 23.23.0.43
23.23.43 Host error: invalid host
You can also be more specific, using allow_inet_aton_joined_segments, allow_inet_aton_hex, allow_inet_aton_octal, or allowSingleSegment.
The allowSingleSegment parameter also applies to IPv6, for which 32 hex characters or 20 base 85 chars can be parsed an an IPv6 address.
IPAddressStringParameters strParams = new IPAddressStringParameters.Builder().
allowSingleSegment(false).toParams();
String str = "aaaabbbbccccddddeeeeffffaaaabbbb";
// do not allow it this time
IPAddressString addrStr = new IPAddressString(str, strParams);
check(addrStr);
// otherwise allowed
addrStr = new IPAddressString(str);
check(addrStr);
Output:
aaaabbbbccccddddeeeeffffaaaabbbb IP Address error: validation options do not allow you to specify a non-segmented single value
address: aaaa:bbbb:cccc:dddd:eeee:ffff:aaaa:bbbb