aboutsummaryrefslogtreecommitdiff
path: root/src/org/xbill/DNS/Address.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/org/xbill/DNS/Address.java')
-rw-r--r--src/org/xbill/DNS/Address.java402
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");
+ }
+}
+
+}