001: // Copyright (c) 1999-2004 Brian Wellington (bwelling@xbill.org)
002:
003: package org.xbill.DNS;
004:
005: import java.net.*;
006: import java.net.Inet6Address;
007: import java.util.*;
008:
009: /**
010: * Routines dealing with IP addresses. Includes functions similar to
011: * those in the java.net.InetAddress class.
012: *
013: * @author Brian Wellington
014: */
015:
016: public final class Address {
017:
018: public static final int IPv4 = 1;
019: public static final int IPv6 = 2;
020:
021: private Address() {
022: }
023:
024: private static byte[] parseV4(String s) {
025: int numDigits;
026: int currentOctet;
027: byte[] values = new byte[4];
028: int currentValue;
029: int length = s.length();
030:
031: currentOctet = 0;
032: currentValue = 0;
033: numDigits = 0;
034: for (int i = 0; i < length; i++) {
035: char c = s.charAt(i);
036: if (c >= '0' && c <= '9') {
037: /* Can't have more than 3 digits per octet. */
038: if (numDigits == 3)
039: return null;
040: /* Octets shouldn't start with 0, unless they are 0. */
041: if (numDigits > 0 && currentValue == 0)
042: return null;
043: numDigits++;
044: currentValue *= 10;
045: currentValue += (c - '0');
046: /* 255 is the maximum value for an octet. */
047: if (currentValue > 255)
048: return null;
049: } else if (c == '.') {
050: /* Can't have more than 3 dots. */
051: if (currentOctet == 3)
052: return null;
053: /* Two consecutive dots are bad. */
054: if (numDigits == 0)
055: return null;
056: values[currentOctet++] = (byte) currentValue;
057: currentValue = 0;
058: numDigits = 0;
059: } else
060: return null;
061: }
062: /* Must have 4 octets. */
063: if (currentOctet != 3)
064: return null;
065: /* The fourth octet can't be empty. */
066: if (numDigits == 0)
067: return null;
068: values[currentOctet] = (byte) currentValue;
069: return values;
070: }
071:
072: private static byte[] parseV6(String s) {
073: boolean parsev4 = false;
074: List l = new ArrayList();
075: int range = -1;
076: byte[] data = new byte[16];
077:
078: String[] tokens = s.split(":", -1);
079:
080: int first = 0;
081: int last = tokens.length - 1;
082:
083: if (tokens[0].length() == 0) {
084: // If the first two tokens are empty, it means the string
085: // started with ::, which is fine. If only the first is
086: // empty, the string started with :, which is bad.
087: if (last - first > 0 && tokens[1].length() == 0)
088: first++;
089: else
090: return null;
091: }
092:
093: if (tokens[last].length() == 0) {
094: // If the last two tokens are empty, it means the string
095: // ended with ::, which is fine. If only the last is
096: // empty, the string ended with :, which is bad.
097: if (last - first > 0 && tokens[last - 1].length() == 0)
098: last--;
099: else
100: return null;
101: }
102:
103: if (last - first + 1 > 8)
104: return null;
105:
106: int i, j;
107: for (i = first, j = 0; i <= last; i++) {
108: if (tokens[i].length() == 0) {
109: if (range >= 0)
110: return null;
111: range = j;
112: continue;
113: }
114:
115: if (tokens[i].indexOf('.') >= 0) {
116: parsev4 = true;
117: // An IPv4 address must be the last component
118: if (i < last)
119: return null;
120: // There can't have been more than 6 components.
121: if (i > 6)
122: return null;
123: byte[] v4addr = Address.toByteArray(tokens[i], IPv4);
124: if (v4addr == null)
125: return null;
126: for (int k = 0; k < 4; k++)
127: data[j++] = v4addr[k];
128: break;
129: }
130:
131: try {
132: for (int k = 0; k < tokens[i].length(); k++) {
133: char c = tokens[i].charAt(k);
134: if (Character.digit(c, 16) < 0)
135: return null;
136: }
137: int x = Integer.parseInt(tokens[i], 16);
138: if (x > 0xFFFF || x < 0)
139: return null;
140: data[j++] = (byte) (x >>> 8);
141: data[j++] = (byte) (x & 0xFF);
142: } catch (NumberFormatException e) {
143: return null;
144: }
145: }
146:
147: if (j < 16 && range < 0)
148: return null;
149:
150: if (range >= 0) {
151: int empty = 16 - j;
152: System.arraycopy(data, range, data, range + empty, j
153: - range);
154: for (i = range; i < range + empty; i++)
155: data[i] = 0;
156: }
157:
158: return data;
159: }
160:
161: /**
162: * Convert a string containing an IP address to an array of 4 or 16 integers.
163: * @param s The address, in text format.
164: * @param family The address family.
165: * @return The address
166: */
167: public static int[] toArray(String s, int family) {
168: byte[] byteArray = toByteArray(s, family);
169: if (byteArray == null)
170: return null;
171: int[] intArray = new int[byteArray.length];
172: for (int i = 0; i < byteArray.length; i++)
173: intArray[i] = byteArray[i] & 0xFF;
174: return intArray;
175: }
176:
177: /**
178: * Convert a string containing an IPv4 address to an array of 4 integers.
179: * @param s The address, in text format.
180: * @return The address
181: */
182: public static int[] toArray(String s) {
183: return toArray(s, IPv4);
184: }
185:
186: /**
187: * Convert a string containing an IP address to an array of 4 or 16 bytes.
188: * @param s The address, in text format.
189: * @param family The address family.
190: * @return The address
191: */
192: public static byte[] toByteArray(String s, int family) {
193: if (family == IPv4)
194: return parseV4(s);
195: else if (family == IPv6)
196: return parseV6(s);
197: else
198: throw new IllegalArgumentException("unknown address family");
199: }
200:
201: /**
202: * Determines if a string contains a valid IP address.
203: * @param s The string
204: * @return Whether the string contains a valid IP address
205: */
206: public static boolean isDottedQuad(String s) {
207: byte[] address = Address.toByteArray(s, IPv4);
208: return (address != null);
209: }
210:
211: /**
212: * Converts a byte array containing an IPv4 address into a dotted quad string.
213: * @param addr The array
214: * @return The string representation
215: */
216: public static String toDottedQuad(byte[] addr) {
217: return ((addr[0] & 0xFF) + "." + (addr[1] & 0xFF) + "."
218: + (addr[2] & 0xFF) + "." + (addr[3] & 0xFF));
219: }
220:
221: /**
222: * Converts an int array containing an IPv4 address into a dotted quad string.
223: * @param addr The array
224: * @return The string representation
225: */
226: public static String toDottedQuad(int[] addr) {
227: return (addr[0] + "." + addr[1] + "." + addr[2] + "." + addr[3]);
228: }
229:
230: private static Record[] lookupHostName(String name)
231: throws UnknownHostException {
232: try {
233: Record[] records = new Lookup(name).run();
234: if (records == null)
235: throw new UnknownHostException("unknown host");
236: return records;
237: } catch (TextParseException e) {
238: throw new UnknownHostException("invalid name");
239: }
240: }
241:
242: private static InetAddress addrFromRecord(String name, Record r)
243: throws UnknownHostException {
244: ARecord a = (ARecord) r;
245: return InetAddress.getByAddress(name, a.getAddress()
246: .getAddress());
247: }
248:
249: /**
250: * Determines the IP address of a host
251: * @param name The hostname to look up
252: * @return The first matching IP address
253: * @exception UnknownHostException The hostname does not have any addresses
254: */
255: public static InetAddress getByName(String name)
256: throws UnknownHostException {
257: try {
258: return getByAddress(name);
259: } catch (UnknownHostException e) {
260: Record[] records = lookupHostName(name);
261: return addrFromRecord(name, records[0]);
262: }
263: }
264:
265: /**
266: * Determines all IP address of a host
267: * @param name The hostname to look up
268: * @return All matching IP addresses
269: * @exception UnknownHostException The hostname does not have any addresses
270: */
271: public static InetAddress[] getAllByName(String name)
272: throws UnknownHostException {
273: try {
274: InetAddress addr = getByAddress(name);
275: return new InetAddress[] { addr };
276: } catch (UnknownHostException e) {
277: Record[] records = lookupHostName(name);
278: InetAddress[] addrs = new InetAddress[records.length];
279: for (int i = 0; i < records.length; i++)
280: addrs[i] = addrFromRecord(name, records[i]);
281: return addrs;
282: }
283: }
284:
285: /**
286: * Converts an address from its string representation to an IP address.
287: * The address can be either IPv4 or IPv6.
288: * @param addr The address, in string form
289: * @return The IP addresses
290: * @exception UnknownHostException The address is not a valid IP address.
291: */
292: public static InetAddress getByAddress(String addr)
293: throws UnknownHostException {
294: byte[] bytes;
295: bytes = toByteArray(addr, IPv4);
296: if (bytes != null)
297: return InetAddress.getByAddress(bytes);
298: bytes = toByteArray(addr, IPv6);
299: if (bytes != null)
300: return InetAddress.getByAddress(bytes);
301: throw new UnknownHostException("Invalid address: " + addr);
302: }
303:
304: /**
305: * Converts an address from its string representation to an IP address in
306: * a particular family.
307: * @param addr The address, in string form
308: * @param family The address family, either IPv4 or IPv6.
309: * @return The IP addresses
310: * @exception UnknownHostException The address is not a valid IP address in
311: * the specified address family.
312: */
313: public static InetAddress getByAddress(String addr, int family)
314: throws UnknownHostException {
315: if (family != IPv4 && family != IPv6)
316: throw new IllegalArgumentException("unknown address family");
317: byte[] bytes;
318: bytes = toByteArray(addr, family);
319: if (bytes != null)
320: return InetAddress.getByAddress(bytes);
321: throw new UnknownHostException("Invalid address: " + addr);
322: }
323:
324: /**
325: * Determines the hostname for an address
326: * @param addr The address to look up
327: * @return The associated host name
328: * @exception UnknownHostException There is no hostname for the address
329: */
330: public static String getHostName(InetAddress addr)
331: throws UnknownHostException {
332: Name name = ReverseMap.fromAddress(addr);
333: Record[] records = new Lookup(name, Type.PTR).run();
334: if (records == null)
335: throw new UnknownHostException("unknown address");
336: PTRRecord ptr = (PTRRecord) records[0];
337: return ptr.getTarget().toString();
338: }
339:
340: /**
341: * Returns the family of an InetAddress.
342: * @param address The supplied address.
343: * @return The family, either IPv4 or IPv6.
344: */
345: public static int familyOf(InetAddress address) {
346: if (address instanceof Inet4Address)
347: return IPv4;
348: if (address instanceof Inet6Address)
349: return IPv6;
350: throw new IllegalArgumentException("unknown address family");
351: }
352:
353: /**
354: * Returns the length of an address in a particular family.
355: * @param family The address family, either IPv4 or IPv6.
356: * @return The length of addresses in that family.
357: */
358: public static int addressLength(int family) {
359: if (family == IPv4)
360: return 4;
361: if (family == IPv6)
362: return 16;
363: throw new IllegalArgumentException("unknown address family");
364: }
365:
366: }
|