• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 1999-2004 Brian Wellington (bwelling@xbill.org)
2 
3 package org.xbill.DNS;
4 
5 import java.net.*;
6 import java.net.Inet6Address;
7 
8 /**
9  * Routines dealing with IP addresses.  Includes functions similar to
10  * those in the java.net.InetAddress class.
11  *
12  * @author Brian Wellington
13  */
14 
15 public final class Address {
16 
17 public static final int IPv4 = 1;
18 public static final int IPv6 = 2;
19 
20 private
Address()21 Address() {}
22 
23 private static byte []
parseV4(String s)24 parseV4(String s) {
25 	int numDigits;
26 	int currentOctet;
27 	byte [] values = new byte[4];
28 	int currentValue;
29 	int length = s.length();
30 
31 	currentOctet = 0;
32 	currentValue = 0;
33 	numDigits = 0;
34 	for (int i = 0; i < length; i++) {
35 		char c = s.charAt(i);
36 		if (c >= '0' && c <= '9') {
37 			/* Can't have more than 3 digits per octet. */
38 			if (numDigits == 3)
39 				return null;
40 			/* Octets shouldn't start with 0, unless they are 0. */
41 			if (numDigits > 0 && currentValue == 0)
42 				return null;
43 			numDigits++;
44 			currentValue *= 10;
45 			currentValue += (c - '0');
46 			/* 255 is the maximum value for an octet. */
47 			if (currentValue > 255)
48 				return null;
49 		} else if (c == '.') {
50 			/* Can't have more than 3 dots. */
51 			if (currentOctet == 3)
52 				return null;
53 			/* Two consecutive dots are bad. */
54 			if (numDigits == 0)
55 				return null;
56 			values[currentOctet++] = (byte) currentValue;
57 			currentValue = 0;
58 			numDigits = 0;
59 		} else
60 			return null;
61 	}
62 	/* Must have 4 octets. */
63 	if (currentOctet != 3)
64 		return null;
65 	/* The fourth octet can't be empty. */
66 	if (numDigits == 0)
67 		return null;
68 	values[currentOctet] = (byte) currentValue;
69 	return values;
70 }
71 
72 private static byte []
parseV6(String s)73 parseV6(String s) {
74 	int range = -1;
75 	byte [] data = new byte[16];
76 
77 	String [] tokens = s.split(":", -1);
78 
79 	int first = 0;
80 	int last = tokens.length - 1;
81 
82 	if (tokens[0].length() == 0) {
83 		// If the first two tokens are empty, it means the string
84 		// started with ::, which is fine.  If only the first is
85 		// empty, the string started with :, which is bad.
86 		if (last - first > 0 && tokens[1].length() == 0)
87 			first++;
88 		else
89 			return null;
90 	}
91 
92 	if (tokens[last].length() == 0) {
93 		// If the last two tokens are empty, it means the string
94 		// ended with ::, which is fine.  If only the last is
95 		// empty, the string ended with :, which is bad.
96 		if (last - first > 0 && tokens[last - 1].length() == 0)
97 			last--;
98 		else
99 			return null;
100 	}
101 
102 	if (last - first + 1 > 8)
103 		return null;
104 
105 	int i, j;
106 	for (i = first, j = 0; i <= last; i++) {
107 		if (tokens[i].length() == 0) {
108 			if (range >= 0)
109 				return null;
110 			range = j;
111 			continue;
112 		}
113 
114 		if (tokens[i].indexOf('.') >= 0) {
115 			// An IPv4 address must be the last component
116 			if (i < last)
117 				return null;
118 			// There can't have been more than 6 components.
119 			if (i > 6)
120 				return null;
121 			byte [] v4addr = Address.toByteArray(tokens[i], IPv4);
122 			if (v4addr == null)
123 				return null;
124 			for (int k = 0; k < 4; k++)
125 				data[j++] = v4addr[k];
126 			break;
127 		}
128 
129 		try {
130 			for (int k = 0; k < tokens[i].length(); k++) {
131 				char c = tokens[i].charAt(k);
132 				if (Character.digit(c, 16) < 0)
133 					return null;
134 			}
135 			int x = Integer.parseInt(tokens[i], 16);
136 			if (x > 0xFFFF || x < 0)
137 				return null;
138 			data[j++] = (byte)(x >>> 8);
139 			data[j++] = (byte)(x & 0xFF);
140 		}
141 		catch (NumberFormatException e) {
142 			return null;
143 		}
144 	}
145 
146 	if (j < 16 && range < 0)
147 		return null;
148 
149 	if (range >= 0) {
150 		int empty = 16 - j;
151 		System.arraycopy(data, range, data, range + empty, j - range);
152 		for (i = range; i < range + empty; i++)
153 			data[i] = 0;
154 	}
155 
156 	return data;
157 }
158 
159 /**
160  * Convert a string containing an IP address to an array of 4 or 16 integers.
161  * @param s The address, in text format.
162  * @param family The address family.
163  * @return The address
164  */
165 public static int []
toArray(String s, int family)166 toArray(String s, int family) {
167 	byte [] byteArray = toByteArray(s, family);
168 	if (byteArray == null)
169 		return null;
170 	int [] intArray = new int[byteArray.length];
171 	for (int i = 0; i < byteArray.length; i++)
172 		intArray[i] = byteArray[i] & 0xFF;
173 	return intArray;
174 }
175 
176 /**
177  * Convert a string containing an IPv4 address to an array of 4 integers.
178  * @param s The address, in text format.
179  * @return The address
180  */
181 public static int []
toArray(String s)182 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 toByteArray(String s, int family) {
194 	if (family == IPv4)
195 		return parseV4(s);
196 	else if (family == IPv6)
197 		return parseV6(s);
198 	else
199 		throw new IllegalArgumentException("unknown address family");
200 }
201 
202 /**
203  * Determines if a string contains a valid IP address.
204  * @param s The string
205  * @return Whether the string contains a valid IP address
206  */
207 public static boolean
isDottedQuad(String s)208 isDottedQuad(String s) {
209 	byte [] address = Address.toByteArray(s, IPv4);
210 	return (address != null);
211 }
212 
213 /**
214  * Converts a byte array containing an IPv4 address into a dotted quad string.
215  * @param addr The array
216  * @return The string representation
217  */
218 public static String
toDottedQuad(byte [] addr)219 toDottedQuad(byte [] addr) {
220 	return ((addr[0] & 0xFF) + "." + (addr[1] & 0xFF) + "." +
221 		(addr[2] & 0xFF) + "." + (addr[3] & 0xFF));
222 }
223 
224 /**
225  * Converts an int array containing an IPv4 address into a dotted quad string.
226  * @param addr The array
227  * @return The string representation
228  */
229 public static String
toDottedQuad(int [] addr)230 toDottedQuad(int [] addr) {
231 	return (addr[0] + "." + addr[1] + "." + addr[2] + "." + addr[3]);
232 }
233 
234 private static Record []
lookupHostName(String name)235 lookupHostName(String name) throws UnknownHostException {
236 	try {
237 		Record [] records = new Lookup(name).run();
238 		if (records == null)
239 			throw new UnknownHostException("unknown host");
240 		return records;
241 	}
242 	catch (TextParseException e) {
243 		throw new UnknownHostException("invalid name");
244 	}
245 }
246 
247 private static InetAddress
addrFromRecord(String name, Record r)248 addrFromRecord(String name, Record r) throws UnknownHostException {
249 	ARecord a = (ARecord) r;
250 	return InetAddress.getByAddress(name, a.getAddress().getAddress());
251 }
252 
253 /**
254  * Determines the IP address of a host
255  * @param name The hostname to look up
256  * @return The first matching IP address
257  * @exception UnknownHostException The hostname does not have any addresses
258  */
259 public static InetAddress
getByName(String name)260 getByName(String name) throws UnknownHostException {
261 	try {
262 		return getByAddress(name);
263 	} catch (UnknownHostException e) {
264 		Record [] records = lookupHostName(name);
265 		return addrFromRecord(name, records[0]);
266 	}
267 }
268 
269 /**
270  * Determines all IP address of a host
271  * @param name The hostname to look up
272  * @return All matching IP addresses
273  * @exception UnknownHostException The hostname does not have any addresses
274  */
275 public static InetAddress []
getAllByName(String name)276 getAllByName(String name) throws UnknownHostException {
277 	try {
278 		InetAddress addr = getByAddress(name);
279 		return new InetAddress[] {addr};
280 	} catch (UnknownHostException e) {
281 		Record [] records = lookupHostName(name);
282 		InetAddress [] addrs = new InetAddress[records.length];
283 		for (int i = 0; i < records.length; i++)
284 			addrs[i] = addrFromRecord(name, records[i]);
285 		return addrs;
286 	}
287 }
288 
289 /**
290  * Converts an address from its string representation to an IP address.
291  * The address can be either IPv4 or IPv6.
292  * @param addr The address, in string form
293  * @return The IP addresses
294  * @exception UnknownHostException The address is not a valid IP address.
295  */
296 public static InetAddress
getByAddress(String addr)297 getByAddress(String addr) throws UnknownHostException {
298 	byte [] bytes;
299 	bytes = toByteArray(addr, IPv4);
300 	if (bytes != null)
301 		return InetAddress.getByAddress(addr, bytes);
302 	bytes = toByteArray(addr, IPv6);
303 	if (bytes != null)
304 		return InetAddress.getByAddress(addr, bytes);
305 	throw new UnknownHostException("Invalid address: " + addr);
306 }
307 
308 /**
309  * Converts an address from its string representation to an IP address in
310  * a particular family.
311  * @param addr The address, in string form
312  * @param family The address family, either IPv4 or IPv6.
313  * @return The IP addresses
314  * @exception UnknownHostException The address is not a valid IP address in
315  * the specified address family.
316  */
317 public static InetAddress
getByAddress(String addr, int family)318 getByAddress(String addr, int family) throws UnknownHostException {
319 	if (family != IPv4 && family != IPv6)
320 		throw new IllegalArgumentException("unknown address family");
321 	byte [] bytes;
322 	bytes = toByteArray(addr, family);
323 	if (bytes != null)
324 		return InetAddress.getByAddress(addr, bytes);
325 	throw new UnknownHostException("Invalid address: " + addr);
326 }
327 
328 /**
329  * Determines the hostname for an address
330  * @param addr The address to look up
331  * @return The associated host name
332  * @exception UnknownHostException There is no hostname for the address
333  */
334 public static String
getHostName(InetAddress addr)335 getHostName(InetAddress addr) throws UnknownHostException {
336 	Name name = ReverseMap.fromAddress(addr);
337 	Record [] records = new Lookup(name, Type.PTR).run();
338 	if (records == null)
339 		throw new UnknownHostException("unknown address");
340 	PTRRecord ptr = (PTRRecord) records[0];
341 	return ptr.getTarget().toString();
342 }
343 
344 /**
345  * Returns the family of an InetAddress.
346  * @param address The supplied address.
347  * @return The family, either IPv4 or IPv6.
348  */
349 public static int
familyOf(InetAddress address)350 familyOf(InetAddress address) {
351 	if (address instanceof Inet4Address)
352 		return IPv4;
353 	if (address instanceof Inet6Address)
354 		return IPv6;
355 	throw new IllegalArgumentException("unknown address family");
356 }
357 
358 /**
359  * Returns the length of an address in a particular family.
360  * @param family The address family, either IPv4 or IPv6.
361  * @return The length of addresses in that family.
362  */
363 public static int
addressLength(int family)364 addressLength(int family) {
365 	if (family == IPv4)
366 		return 4;
367 	if (family == IPv6)
368 		return 16;
369 	throw new IllegalArgumentException("unknown address family");
370 }
371 
372 /**
373  * Truncates an address to the specified number of bits.  For example,
374  * truncating the address 10.1.2.3 to 8 bits would yield 10.0.0.0.
375  * @param address The source address
376  * @param maskLength The number of bits to truncate the address to.
377  */
378 public static InetAddress
truncate(InetAddress address, int maskLength)379 truncate(InetAddress address, int maskLength)
380 {
381 	int family = familyOf(address);
382 	int maxMaskLength = addressLength(family) * 8;
383 	if (maskLength < 0 || maskLength > maxMaskLength)
384 		throw new IllegalArgumentException("invalid mask length");
385 	if (maskLength == maxMaskLength)
386 		return address;
387 	byte [] bytes = address.getAddress();
388 	for (int i = maskLength / 8 + 1; i < bytes.length; i++)
389 		bytes[i] = 0;
390 	int maskBits = maskLength % 8;
391 	int bitmask = 0;
392 	for (int i = 0; i < maskBits; i++)
393 		bitmask |= (1 << (7 - i));
394 	bytes[maskLength / 8] &= bitmask;
395 	try {
396 		return InetAddress.getByAddress(bytes);
397 	} catch (UnknownHostException e) {
398 		throw new IllegalArgumentException("invalid address");
399 	}
400 }
401 
402 }
403