diff options
Diffstat (limited to 'src/org/xbill/DNS/Address.java')
-rw-r--r-- | src/org/xbill/DNS/Address.java | 402 |
1 files changed, 402 insertions, 0 deletions
diff --git a/src/org/xbill/DNS/Address.java b/src/org/xbill/DNS/Address.java new file mode 100644 index 0000000..799185b --- /dev/null +++ b/src/org/xbill/DNS/Address.java @@ -0,0 +1,402 @@ +// Copyright (c) 1999-2004 Brian Wellington (bwelling@xbill.org) + +package org.xbill.DNS; + +import java.net.*; +import java.net.Inet6Address; + +/** + * Routines dealing with IP addresses. Includes functions similar to + * those in the java.net.InetAddress class. + * + * @author Brian Wellington + */ + +public final class Address { + +public static final int IPv4 = 1; +public static final int IPv6 = 2; + +private +Address() {} + +private static byte [] +parseV4(String s) { + int numDigits; + int currentOctet; + byte [] values = new byte[4]; + int currentValue; + int length = s.length(); + + currentOctet = 0; + currentValue = 0; + numDigits = 0; + for (int i = 0; i < length; i++) { + char c = s.charAt(i); + if (c >= '0' && c <= '9') { + /* Can't have more than 3 digits per octet. */ + if (numDigits == 3) + return null; + /* Octets shouldn't start with 0, unless they are 0. */ + if (numDigits > 0 && currentValue == 0) + return null; + numDigits++; + currentValue *= 10; + currentValue += (c - '0'); + /* 255 is the maximum value for an octet. */ + if (currentValue > 255) + return null; + } else if (c == '.') { + /* Can't have more than 3 dots. */ + if (currentOctet == 3) + return null; + /* Two consecutive dots are bad. */ + if (numDigits == 0) + return null; + values[currentOctet++] = (byte) currentValue; + currentValue = 0; + numDigits = 0; + } else + return null; + } + /* Must have 4 octets. */ + if (currentOctet != 3) + return null; + /* The fourth octet can't be empty. */ + if (numDigits == 0) + return null; + values[currentOctet] = (byte) currentValue; + return values; +} + +private static byte [] +parseV6(String s) { + int range = -1; + byte [] data = new byte[16]; + + String [] tokens = s.split(":", -1); + + int first = 0; + int last = tokens.length - 1; + + if (tokens[0].length() == 0) { + // If the first two tokens are empty, it means the string + // started with ::, which is fine. If only the first is + // empty, the string started with :, which is bad. + if (last - first > 0 && tokens[1].length() == 0) + first++; + else + return null; + } + + if (tokens[last].length() == 0) { + // If the last two tokens are empty, it means the string + // ended with ::, which is fine. If only the last is + // empty, the string ended with :, which is bad. + if (last - first > 0 && tokens[last - 1].length() == 0) + last--; + else + return null; + } + + if (last - first + 1 > 8) + return null; + + int i, j; + for (i = first, j = 0; i <= last; i++) { + if (tokens[i].length() == 0) { + if (range >= 0) + return null; + range = j; + continue; + } + + if (tokens[i].indexOf('.') >= 0) { + // An IPv4 address must be the last component + if (i < last) + return null; + // There can't have been more than 6 components. + if (i > 6) + return null; + byte [] v4addr = Address.toByteArray(tokens[i], IPv4); + if (v4addr == null) + return null; + for (int k = 0; k < 4; k++) + data[j++] = v4addr[k]; + break; + } + + try { + for (int k = 0; k < tokens[i].length(); k++) { + char c = tokens[i].charAt(k); + if (Character.digit(c, 16) < 0) + return null; + } + int x = Integer.parseInt(tokens[i], 16); + if (x > 0xFFFF || x < 0) + return null; + data[j++] = (byte)(x >>> 8); + data[j++] = (byte)(x & 0xFF); + } + catch (NumberFormatException e) { + return null; + } + } + + if (j < 16 && range < 0) + return null; + + if (range >= 0) { + int empty = 16 - j; + System.arraycopy(data, range, data, range + empty, j - range); + for (i = range; i < range + empty; i++) + data[i] = 0; + } + + return data; +} + +/** + * Convert a string containing an IP address to an array of 4 or 16 integers. + * @param s The address, in text format. + * @param family The address family. + * @return The address + */ +public static int [] +toArray(String s, int family) { + byte [] byteArray = toByteArray(s, family); + if (byteArray == null) + return null; + int [] intArray = new int[byteArray.length]; + for (int i = 0; i < byteArray.length; i++) + intArray[i] = byteArray[i] & 0xFF; + return intArray; +} + +/** + * Convert a string containing an IPv4 address to an array of 4 integers. + * @param s The address, in text format. + * @return The address + */ +public static int [] +toArray(String s) { + return toArray(s, IPv4); +} + +/** + * Convert a string containing an IP address to an array of 4 or 16 bytes. + * @param s The address, in text format. + * @param family The address family. + * @return The address + */ +public static byte [] +toByteArray(String s, int family) { + if (family == IPv4) + return parseV4(s); + else if (family == IPv6) + return parseV6(s); + else + throw new IllegalArgumentException("unknown address family"); +} + +/** + * Determines if a string contains a valid IP address. + * @param s The string + * @return Whether the string contains a valid IP address + */ +public static boolean +isDottedQuad(String s) { + byte [] address = Address.toByteArray(s, IPv4); + return (address != null); +} + +/** + * Converts a byte array containing an IPv4 address into a dotted quad string. + * @param addr The array + * @return The string representation + */ +public static String +toDottedQuad(byte [] addr) { + return ((addr[0] & 0xFF) + "." + (addr[1] & 0xFF) + "." + + (addr[2] & 0xFF) + "." + (addr[3] & 0xFF)); +} + +/** + * Converts an int array containing an IPv4 address into a dotted quad string. + * @param addr The array + * @return The string representation + */ +public static String +toDottedQuad(int [] addr) { + return (addr[0] + "." + addr[1] + "." + addr[2] + "." + addr[3]); +} + +private static Record [] +lookupHostName(String name) throws UnknownHostException { + try { + Record [] records = new Lookup(name).run(); + if (records == null) + throw new UnknownHostException("unknown host"); + return records; + } + catch (TextParseException e) { + throw new UnknownHostException("invalid name"); + } +} + +private static InetAddress +addrFromRecord(String name, Record r) throws UnknownHostException { + ARecord a = (ARecord) r; + return InetAddress.getByAddress(name, a.getAddress().getAddress()); +} + +/** + * Determines the IP address of a host + * @param name The hostname to look up + * @return The first matching IP address + * @exception UnknownHostException The hostname does not have any addresses + */ +public static InetAddress +getByName(String name) throws UnknownHostException { + try { + return getByAddress(name); + } catch (UnknownHostException e) { + Record [] records = lookupHostName(name); + return addrFromRecord(name, records[0]); + } +} + +/** + * Determines all IP address of a host + * @param name The hostname to look up + * @return All matching IP addresses + * @exception UnknownHostException The hostname does not have any addresses + */ +public static InetAddress [] +getAllByName(String name) throws UnknownHostException { + try { + InetAddress addr = getByAddress(name); + return new InetAddress[] {addr}; + } catch (UnknownHostException e) { + Record [] records = lookupHostName(name); + InetAddress [] addrs = new InetAddress[records.length]; + for (int i = 0; i < records.length; i++) + addrs[i] = addrFromRecord(name, records[i]); + return addrs; + } +} + +/** + * Converts an address from its string representation to an IP address. + * The address can be either IPv4 or IPv6. + * @param addr The address, in string form + * @return The IP addresses + * @exception UnknownHostException The address is not a valid IP address. + */ +public static InetAddress +getByAddress(String addr) throws UnknownHostException { + byte [] bytes; + bytes = toByteArray(addr, IPv4); + if (bytes != null) + return InetAddress.getByAddress(addr, bytes); + bytes = toByteArray(addr, IPv6); + if (bytes != null) + return InetAddress.getByAddress(addr, bytes); + throw new UnknownHostException("Invalid address: " + addr); +} + +/** + * Converts an address from its string representation to an IP address in + * a particular family. + * @param addr The address, in string form + * @param family The address family, either IPv4 or IPv6. + * @return The IP addresses + * @exception UnknownHostException The address is not a valid IP address in + * the specified address family. + */ +public static InetAddress +getByAddress(String addr, int family) throws UnknownHostException { + if (family != IPv4 && family != IPv6) + throw new IllegalArgumentException("unknown address family"); + byte [] bytes; + bytes = toByteArray(addr, family); + if (bytes != null) + return InetAddress.getByAddress(addr, bytes); + throw new UnknownHostException("Invalid address: " + addr); +} + +/** + * Determines the hostname for an address + * @param addr The address to look up + * @return The associated host name + * @exception UnknownHostException There is no hostname for the address + */ +public static String +getHostName(InetAddress addr) throws UnknownHostException { + Name name = ReverseMap.fromAddress(addr); + Record [] records = new Lookup(name, Type.PTR).run(); + if (records == null) + throw new UnknownHostException("unknown address"); + PTRRecord ptr = (PTRRecord) records[0]; + return ptr.getTarget().toString(); +} + +/** + * Returns the family of an InetAddress. + * @param address The supplied address. + * @return The family, either IPv4 or IPv6. + */ +public static int +familyOf(InetAddress address) { + if (address instanceof Inet4Address) + return IPv4; + if (address instanceof Inet6Address) + return IPv6; + throw new IllegalArgumentException("unknown address family"); +} + +/** + * Returns the length of an address in a particular family. + * @param family The address family, either IPv4 or IPv6. + * @return The length of addresses in that family. + */ +public static int +addressLength(int family) { + if (family == IPv4) + return 4; + if (family == IPv6) + return 16; + throw new IllegalArgumentException("unknown address family"); +} + +/** + * Truncates an address to the specified number of bits. For example, + * truncating the address 10.1.2.3 to 8 bits would yield 10.0.0.0. + * @param address The source address + * @param maskLength The number of bits to truncate the address to. + */ +public static InetAddress +truncate(InetAddress address, int maskLength) +{ + int family = familyOf(address); + int maxMaskLength = addressLength(family) * 8; + if (maskLength < 0 || maskLength > maxMaskLength) + throw new IllegalArgumentException("invalid mask length"); + if (maskLength == maxMaskLength) + return address; + byte [] bytes = address.getAddress(); + for (int i = maskLength / 8 + 1; i < bytes.length; i++) + bytes[i] = 0; + int maskBits = maskLength % 8; + int bitmask = 0; + for (int i = 0; i < maskBits; i++) + bitmask |= (1 << (7 - i)); + bytes[maskLength / 8] &= bitmask; + try { + return InetAddress.getByAddress(bytes); + } catch (UnknownHostException e) { + throw new IllegalArgumentException("invalid address"); + } +} + +} |