package com.intel.mtwilson.datatypes; import java.net.URI; import java.net.URISyntaxException; import com.fasterxml.jackson.annotation.JsonValue; //import org.codehaus.jackson.annotate.JsonValue; /** * Representation of an IP Address in either IPv4 or IPv6 format. * * Internally it uses the java.net.URI class to validate IPv4 and IPv6 * addresses but this may change in the future. * * The reason we are not using InetAddress as the underlying validator is that * it doesn't convert numeric IP address in String format to byte[] - given a String, it will * try to look it up as a hostname. Given a String which is an invalid IP address * (such as 127.0.0.w) it will delay while looking it up and then fail. * * What we need for this class is quick validation or fault identification of a String like "127.0.0.w" * and for that purpose the URI class is more convenient. * * Alternatives to using URI are to implement a regexp parser or simple string format parser. * * @since 0.5.1 * @author jbuhacoff */ public class IPAddress { private String address = null; public IPAddress() { } public IPAddress(String address) { setAddress(address); } public final void setAddress(String address) { if (isValid(address)) { this.address = address; } else { throw new IllegalArgumentException("Invalid IP address: " + address); } } /** * Returns the address so that you can easily concatenate to a string. * Example: assert new IPAddress("1.2.3.4").toString().equals("1.2.3.4"); * * @see java.lang.Object#toString() */ @JsonValue @Override public String toString() { return address; } // should deprecate? or still allow it? don't want to return new // Hostname(...) because then it's checked twice public static IPAddress parse(String input) { if (isValid(input)) { IPAddress h = new IPAddress(); h.address = input; return h; // new IPAddress(input); } throw new IllegalArgumentException("Invalid IP address: " + input); } /** * This method does NOT check the network for the existence of the given * address, it only checks its format for validity and, if an IPv4 or IPv6 * address is given, checks that it is within the allowed range. * * @param address to check for validity, such as 1.2.3.4 * @return true if the address appears to be a valid IPv4 or IPv6 address, * false if the address is null or otherwise invalid */ public static boolean isValid(String address) { try { /* * because URI format for host is hostname ; but problem is that * ipv4 is valid and [ipv6] is valid but [ipv4] is not valid and * ipv6 is not valid so we need to know in advance which it is or it * won't validate properly.. .which defeats the purpose of this * check... so we look for ":" to distinguish ipv4 from ipv6 * * When IP address is invalid such as "1b.2.3i.4" there will be an exception thrown */ if( address.contains(":") ) { // IPv6 format URI valid = new URI(String.format("//[%s]", address)); return valid.getHost() != null; } else { // IPv4 format URI valid = new URI(String.format("//%s", address)); // also make sure that there are only digits and dots // because URI also accepts valid hostnames, which are not addresses return valid.getHost() != null && address.matches("[\\d\\.]+"); } } catch (URISyntaxException e) { return false; } } @Override public int hashCode() { return address.hashCode(); } @Override public boolean equals(Object obj) { if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } final IPAddress other = (IPAddress) obj; if ((this.address == null) ? (other.address != null) : !this.address.equals(other.address)) { return false; } return true; } }