1. /*
  2. * @(#)InetAddress.java 1.68 01/11/29
  3. *
  4. * Copyright 2002 Sun Microsystems, Inc. All rights reserved.
  5. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
  6. */
  7. package java.net;
  8. import java.util.HashMap;
  9. import java.util.Random;
  10. import java.security.AccessController;
  11. import sun.security.action.*;
  12. import sun.net.InetAddressCachePolicy;
  13. /**
  14. * This class represents an Internet Protocol (IP) address.
  15. * <p>
  16. * Applications should use the methods <code>getLocalHost</code>,
  17. * <code>getByName</code>, or <code>getAllByName</code> to
  18. * create a new <code>InetAddress</code> instance.
  19. *
  20. * @author Chris Warth
  21. * @version 1.66, 05/16/00
  22. * @see java.net.InetAddress#getAllByName(java.lang.String)
  23. * @see java.net.InetAddress#getByName(java.lang.String)
  24. * @see java.net.InetAddress#getLocalHost()
  25. * @since JDK1.0
  26. */
  27. public final
  28. class InetAddress implements java.io.Serializable {
  29. /**
  30. * @serial
  31. */
  32. String hostName;
  33. /*
  34. * Currently we only deal effectively with 32-bit addresses.
  35. * However this field can be expanded to be a byte array
  36. * or a 64-bit quantity without too much effort.
  37. *
  38. * @serial
  39. */
  40. int address;
  41. /**
  42. * @serial
  43. */
  44. int family;
  45. /** use serialVersionUID from JDK 1.0.2 for interoperability */
  46. private static final long serialVersionUID = 3286316764910316507L;
  47. /*
  48. * Load net library into runtime, and perform initializations.
  49. */
  50. static {
  51. AccessController.doPrivileged(new LoadLibraryAction("net"));
  52. init();
  53. }
  54. /**
  55. * Constructor for the Socket.accept() method.
  56. * This creates an empty InetAddress, which is filled in by
  57. * the accept() method. This InetAddress, however, is not
  58. * put in the address cache, since it is not created by name.
  59. */
  60. InetAddress() {
  61. family = impl.getInetFamily();
  62. }
  63. /**
  64. * Creates an InetAddress with the specified host name and IP address.
  65. * @param hostName the specified host name
  66. * @param addr the specified IP address. The address is expected in
  67. * network byte order.
  68. * @exception UnknownHostException If the address is unknown.
  69. */
  70. InetAddress(String hostName, byte addr[]) {
  71. this.hostName = hostName;
  72. this.family = impl.getInetFamily();
  73. /*
  74. * We must be careful here to maintain the network byte
  75. * order of the address. As it comes in, the most
  76. * significant byte of the address is in addr[0]. It
  77. * actually doesn't matter what order they end up in the
  78. * array, as long as it is documented and consistent.
  79. */
  80. address = addr[3] & 0xFF;
  81. address |= ((addr[2] << 8) & 0xFF00);
  82. address |= ((addr[1] << 16) & 0xFF0000);
  83. address |= ((addr[0] << 24) & 0xFF000000);
  84. }
  85. /**
  86. * Utility routine to check if the InetAddress is a
  87. * IP multicast address. IP multicast address is a Class D
  88. * address i.e first four bits of the address are 1110.
  89. * @since JDK1.1
  90. */
  91. public boolean isMulticastAddress() {
  92. return ((address & 0xf0000000) == 0xe0000000);
  93. }
  94. /**
  95. * Returns the hostname for this address.
  96. * If the host is equal to null, then this address refers to any
  97. * of the local machine's available network addresses.
  98. *
  99. * <p>If there is a security manager, its
  100. * <code>checkConnect</code> method is first called
  101. * with the hostname and <code>-1</code>
  102. * as its arguments to see if the operation is allowed.
  103. *
  104. * @return the host name for this IP address.
  105. *
  106. * @exception SecurityException if a security manager exists and its
  107. * <code>checkConnect</code> method doesn't allow the operation .
  108. *
  109. * @see SecurityManager#checkConnect
  110. */
  111. public String getHostName() {
  112. return getHostName(true);
  113. }
  114. /**
  115. * Returns the hostname for this address.
  116. * If the host is equal to null, then this address refers to any
  117. * of the local machine's available network addresses.
  118. * this is package private so SocketPermission can make calls into
  119. * here without a security check.
  120. *
  121. * <p>If there is a security manager, this method first
  122. * calls its <code>checkConnect</code> method
  123. * with the hostname and <code>-1</code>
  124. * as its arguments to see if the calling code is allowed to know
  125. * the hostname for this IP address, i.e., to connect to the host.
  126. *
  127. * @return the host name for this IP address.
  128. *
  129. * @param check make security check if true
  130. *
  131. * @exception SecurityException if a security manager exists and its
  132. * <code>checkConnect</code> method doesn't allow the connection.
  133. *
  134. * @see SecurityManager#checkConnect
  135. */
  136. String getHostName(boolean check) {
  137. if (hostName == null) {
  138. try {
  139. // first lookup the hostname
  140. hostName = impl.getHostByAddr(address);
  141. /* check to see if calling code is allowed to know
  142. * the hostname for this IP address, ie, connect to the host
  143. */
  144. if (check) {
  145. SecurityManager sec = System.getSecurityManager();
  146. if (sec != null) {
  147. sec.checkConnect(hostName, -1);
  148. }
  149. }
  150. /* now get all the IP addresses for this hostname,
  151. * and make sure one of them matches the original IP
  152. * address. We do this to try and prevent spoofing.
  153. */
  154. InetAddress[] arr = getAllByName0(hostName, check);
  155. boolean ok = false;
  156. if(arr != null) {
  157. for(int i = 0; !ok && i < arr.length; i++) {
  158. //System.out.println("check "+this+" "+arr[i]);
  159. ok = (address == arr[i].address);
  160. }
  161. }
  162. //XXX: if it looks a spoof just return the address?
  163. if (!ok) {
  164. hostName = getHostAddress();
  165. return getHostAddress();
  166. }
  167. } catch (SecurityException e) {
  168. hostName = getHostAddress();
  169. } catch (UnknownHostException e) {
  170. hostName = getHostAddress();
  171. }
  172. }
  173. return hostName;
  174. }
  175. /**
  176. * Returns the raw IP address of this <code>InetAddress</code>
  177. * object. The result is in network byte order: the highest order
  178. * byte of the address is in <code>getAddress()[0]</code>.
  179. *
  180. * @return the raw IP address of this object.
  181. */
  182. public byte[] getAddress() {
  183. byte[] addr = new byte[4];
  184. addr[0] = (byte) ((address >>> 24) & 0xFF);
  185. addr[1] = (byte) ((address >>> 16) & 0xFF);
  186. addr[2] = (byte) ((address >>> 8) & 0xFF);
  187. addr[3] = (byte) (address & 0xFF);
  188. return addr;
  189. }
  190. /**
  191. * Returns the IP address string "%d.%d.%d.%d".
  192. *
  193. * @return the raw IP address in a string format.
  194. * @since JDK1.0.2
  195. */
  196. public String getHostAddress() {
  197. return ((address >>> 24) & 0xFF) + "." +
  198. ((address >>> 16) & 0xFF) + "." +
  199. ((address >>> 8) & 0xFF) + "." +
  200. ((address >>> 0) & 0xFF);
  201. }
  202. /**
  203. * Returns a hashcode for this IP address.
  204. *
  205. * @return a hash code value for this IP address.
  206. */
  207. public int hashCode() {
  208. return address;
  209. }
  210. /**
  211. * Compares this object against the specified object.
  212. * The result is <code>true</code> if and only if the argument is
  213. * not <code>null</code> and it represents the same IP address as
  214. * this object.
  215. * <p>
  216. * Two instances of <code>InetAddress</code> represent the same IP
  217. * address if the length of the byte arrays returned by
  218. * <code>getAddress</code> is the same for both, and each of the
  219. * array components is the same for the byte arrays.
  220. *
  221. * @param obj the object to compare against.
  222. * @return <code>true</code> if the objects are the same;
  223. * <code>false</code> otherwise.
  224. * @see java.net.InetAddress#getAddress()
  225. */
  226. public boolean equals(Object obj) {
  227. return (obj != null) && (obj instanceof InetAddress) &&
  228. (((InetAddress)obj).address == address);
  229. }
  230. /**
  231. * Converts this IP address to a <code>String</code>.
  232. *
  233. * @return a string representation of this IP address.
  234. */
  235. public String toString() {
  236. return getHostName() + "/" + getHostAddress();
  237. }
  238. /*
  239. * Cached addresses - our own litle nis, not!
  240. */
  241. private static HashMap addressCache = new HashMap();
  242. private static InetAddress unknownAddress;
  243. private static InetAddress localHost;
  244. private static InetAddress[] unknown_array; // put THIS in cache
  245. static InetAddress anyLocalAddress;
  246. static InetAddressImpl impl;
  247. private static HashMap lookupTable = new HashMap();
  248. static final class CacheEntry {
  249. CacheEntry(String hostname, Object address, long expiration) {
  250. this.hostname = hostname;
  251. this.address = address;
  252. this.expiration = expiration;
  253. }
  254. String hostname;
  255. Object address;
  256. long expiration;
  257. }
  258. private static void cacheAddress(String hostname, Object address) {
  259. // if the cache policy is to cache nothing, just return
  260. int policy = InetAddressCachePolicy.get();
  261. if (policy == 0) {
  262. return;
  263. }
  264. long expiration = -1;
  265. if (policy != InetAddressCachePolicy.FOREVER) {
  266. expiration = System.currentTimeMillis() + (policy * 1000);
  267. }
  268. cacheAddress(hostname, address, expiration);
  269. }
  270. private static void cacheAddress(String hostname, Object address, long expiration) {
  271. hostname = hostname.toLowerCase();
  272. synchronized (addressCache) {
  273. CacheEntry entry = (CacheEntry)addressCache.get(hostname);
  274. if (entry == null) {
  275. entry = new CacheEntry(hostname, address, expiration);
  276. addressCache.put(hostname, entry);
  277. } else {
  278. entry.address = address;
  279. entry.expiration = expiration;
  280. }
  281. }
  282. }
  283. private static Object getCachedAddress(String hostname) {
  284. hostname = hostname.toLowerCase();
  285. if (InetAddressCachePolicy.get() == 0) {
  286. return null;
  287. }
  288. synchronized (addressCache) {
  289. CacheEntry entry = (CacheEntry)addressCache.get(hostname);
  290. if (entry != null && entry.expiration < System.currentTimeMillis() &&
  291. entry.expiration >= 0) {
  292. entry = null;
  293. }
  294. return entry != null ? entry.address : null;
  295. }
  296. }
  297. /*
  298. * generic localHost to give back to applets
  299. * - private so not API delta
  300. */
  301. private static InetAddress loopbackHost;
  302. static {
  303. /*
  304. * Property "impl.prefix" will be prepended to the classname
  305. * of the implementation object we instantiate, to which we
  306. * delegate the real work (like native methods). This
  307. * property can vary across implementations of the java.
  308. * classes. The default is an empty String "".
  309. */
  310. String prefix = (String)AccessController.doPrivileged(
  311. new GetPropertyAction("impl.prefix", ""));
  312. try {
  313. impl = null;
  314. impl = (InetAddressImpl)(Class.forName("java.net." + prefix +
  315. "InetAddressImpl")
  316. .newInstance());
  317. } catch (ClassNotFoundException e) {
  318. System.err.println("Class not found: java.net." + prefix +
  319. "InetAddressImpl:\ncheck impl.prefix property " +
  320. "in your properties file.");
  321. } catch (InstantiationException e) {
  322. System.err.println("Could not instantiate: java.net." + prefix +
  323. "InetAddressImpl:\ncheck impl.prefix property " +
  324. "in your properties file.");
  325. } catch (IllegalAccessException e) {
  326. System.err.println("Cannot access class: java.net." + prefix +
  327. "InetAddressImpl:\ncheck impl.prefix property " +
  328. "in your properties file.");
  329. }
  330. if (impl == null) {
  331. try {
  332. impl = (InetAddressImpl)(Class.forName("java.net.InetAddressImpl")
  333. .newInstance());
  334. } catch (Exception e) {
  335. throw new Error("System property impl.prefix incorrect");
  336. }
  337. }
  338. unknownAddress = new InetAddress();
  339. anyLocalAddress = new InetAddress();
  340. impl.makeAnyLocalAddress(anyLocalAddress);
  341. byte[] IP = new byte[4];
  342. IP[0] = 0x7F;
  343. IP[1] = 0x00;
  344. IP[2] = 0x00;
  345. IP[3] = 0x01;
  346. loopbackHost = new InetAddress("localhost", IP);
  347. /* find the local host name */
  348. try {
  349. localHost = new InetAddress();
  350. localHost.hostName = impl.getLocalHostName();
  351. /* we explicitly leave the address of the local host
  352. * uninitialized. A DNS lookup in this, the static
  353. * initializer, will cause a machine disconnected
  354. * from the network to hang - it'll be trying to query
  355. * a DNS server that isn't there.
  356. *
  357. * Instead, we just get the hostname of the local host.
  358. * The native code for this just calls gethostname()
  359. * which should be pretty innocuous - it shouldn't try
  360. * to contact a DNS server. If any application
  361. * calls InetAddress.getLocalHost(), we initialize
  362. * the local host's address there if not already initialized.
  363. *
  364. * Note that for this to work it is also essential that
  365. * the localHost InetAddress is _NOT_ put into the address cache
  366. * here in the static initializer (which happens if we call
  367. * getByName() from the static initializer). It _IS_ OK
  368. * to put it in the addressCache after initialization.
  369. *
  370. * The unitialized state of the localHost's address is -1,
  371. * or IP address 255.255.255.255 which we know cannot be
  372. * a legal host address.
  373. */
  374. localHost.address = -1;
  375. } catch (Exception ex) { /* this shouldn't happen */
  376. localHost = unknownAddress;
  377. }
  378. /* cache the name/address pair "0.0.0.0"/0.0.0.0 */
  379. String unknownByAddr = "0.0.0.0";
  380. unknown_array = new InetAddress[1];
  381. unknown_array[0] = new InetAddress(unknownByAddr,
  382. unknownAddress.getAddress());
  383. cacheAddress(unknownByAddr, unknown_array, InetAddressCachePolicy.FOREVER);
  384. }
  385. /**
  386. * Determines the IP address of a host, given the host's name. The
  387. * host name can either be a machine name, such as
  388. * "<code>java.sun.com</code>", or a string representing its IP
  389. * address, such as "<code>206.26.48.100</code>".
  390. *
  391. * @param host the specified host, or <code>null</code> for the
  392. * local host.
  393. * @return an IP address for the given host name.
  394. * @exception UnknownHostException if no IP address for the
  395. * <code>host</code> could be found.
  396. */
  397. public static InetAddress getByName(String host)
  398. throws UnknownHostException {
  399. Object obj = null;
  400. if (host == null || host.length() == 0) {
  401. return loopbackHost;
  402. }
  403. if (!Character.isDigit(host.charAt(0))) {
  404. return getAllByName0(host)[0];
  405. } else {
  406. /* The string (probably) represents a numerical IP address.
  407. * Parse it into an int, don't do uneeded reverese lookup,
  408. * leave hostName null, don't cache. If it isn't an IP address,
  409. * (i.e., not "%d.%d.%d.%d") or if any element > 0xFF,
  410. * we treat it as a hostname, and lookup that way.
  411. * This seems to be 100% compliant to the RFC1123 spec:
  412. * a partial hostname like 3com.domain4 is technically valid.
  413. */
  414. int IP = 0x00;
  415. int hitDots = 0;
  416. char[] data = host.toCharArray();
  417. for(int i = 0; i < data.length; i++) {
  418. char c = data[i];
  419. if (c < 48 || c > 57) { // !digit
  420. return getAllByName0(host)[0];
  421. }
  422. int b = 0x00;
  423. while(c != '.') {
  424. if (c < 48 || c > 57) { // !digit
  425. return getAllByName0(host)[0];
  426. }
  427. b = b*10 + c - '0';
  428. if (++i >= data.length)
  429. break;
  430. c = data[i];
  431. }
  432. if(b > 0xFF) { /* bogus - bigger than a byte */
  433. return getAllByName0(host)[0];
  434. }
  435. IP = (IP << 8) + b;
  436. hitDots++;
  437. }
  438. if(hitDots != 4 || host.endsWith(".")) {
  439. return getAllByName0(host)[0];
  440. }
  441. InetAddress in = new InetAddress();
  442. in.address = IP;
  443. in.hostName = null;
  444. return in;
  445. }
  446. }
  447. /**
  448. * Determines all the IP addresses of a host, given the host's name.
  449. * The host name can either be a machine name, such as
  450. * "<code>java.sun.com</code>", or a string representing
  451. * its IP address, such as "<code>206.26.48.100</code>".
  452. *
  453. * <p>If there is a security manager and <code>host</code> is not
  454. * null and <code>host.length() </code> is not equal to zero, the
  455. * security manager's
  456. * <code>checkConnect</code> method is called
  457. * with the hostname and <code>-1</code>
  458. * as its arguments to see if the operation is allowed.
  459. *
  460. * @param host the name of the host.
  461. * @return an array of all the IP addresses for a given host name.
  462. *
  463. * @exception UnknownHostException if no IP address for the
  464. * <code>host</code> could be found.
  465. * @exception SecurityException if a security manager exists and its
  466. * <code>checkConnect</code> method doesn't allow the operation.
  467. *
  468. * @see SecurityManager#checkConnect
  469. */
  470. public static InetAddress[] getAllByName(String host)
  471. throws UnknownHostException {
  472. if (host == null || host.length() == 0) {
  473. throw new UnknownHostException("empty string");
  474. }
  475. if(Character.isDigit(host.charAt(0))) {
  476. InetAddress[] ret = new InetAddress[1];
  477. ret[0] = getByName(host);
  478. return ret;
  479. } else {
  480. return getAllByName0(host);
  481. }
  482. }
  483. private static InetAddress[] getAllByName0 (String host)
  484. throws UnknownHostException
  485. {
  486. return getAllByName0(host, true);
  487. }
  488. /**
  489. * package private so SocketPermission can call it
  490. */
  491. static InetAddress[] getAllByName0 (String host, boolean check)
  492. throws UnknownHostException {
  493. /* If it gets here it is presumed to be a hostname */
  494. /* Cache.get can return: null, unknownAddress, or InetAddress[] */
  495. Object obj = null;
  496. Object objcopy = null;
  497. /* make sure the connection to the host is allowed, before we
  498. * give out a hostname
  499. */
  500. if (check) {
  501. SecurityManager security = System.getSecurityManager();
  502. if (security != null) {
  503. security.checkConnect(host, -1);
  504. }
  505. }
  506. obj = getCachedAddress(host);
  507. /* If no entry in cache, then do the host lookup */
  508. if (obj == null) {
  509. obj = getAddressFromNameService(host);
  510. }
  511. if (obj == unknown_array)
  512. throw new UnknownHostException(host);
  513. /* Make a copy of the InetAddress array */
  514. try {
  515. objcopy = ((InetAddress [])obj).clone();
  516. // the following line is a hack, to ensure that the code
  517. // can compile for both the broken compiler and the fixed one.
  518. if (objcopy == null)
  519. throw new CloneNotSupportedException();
  520. } catch (CloneNotSupportedException cnse) {
  521. cnse.printStackTrace();
  522. }
  523. return (InetAddress [])objcopy;
  524. }
  525. private static Object getAddressFromNameService(String host) {
  526. Object obj = null;
  527. // Check whether the host is in the lookupTable.
  528. // 1) If the host isn't in the lookupTable when
  529. // checkLookupTable() is called, checkLookupTable()
  530. // would add the host in the lookupTable and
  531. // return null. So we will do the lookup.
  532. // 2) If the host is in the lookupTable when
  533. // checkLookupTable() is called, the current thread
  534. // would be blocked until the host is removed
  535. // from the lookupTable. Then this thread
  536. // should try to look up the addressCache.
  537. // i) if it found the address in the
  538. // addressCache, checkLookupTable() would
  539. // return the address.
  540. // ii) if it didn't find the address in the
  541. // addressCache for any reason,
  542. // it should add the host in the
  543. // lookupTable and return null so the
  544. // following code would do a lookup itself.
  545. if ((obj = checkLookupTable(host)) == null) {
  546. // This is the first thread which looks up the address
  547. // this host or the cache entry for this host has been
  548. // expired so this thread should do the lookup.
  549. try {
  550. /*
  551. * Do not put the call to lookup() inside the
  552. * constructor. if you do you will still be
  553. * allocating space when the lookup fails.
  554. */
  555. byte[][] byte_array;
  556. byte_array = impl.lookupAllHostAddr(host);
  557. InetAddress[] addr_array =
  558. new InetAddress[byte_array.length];
  559. for (int i = 0; i < byte_array.length; i++) {
  560. byte addr[] = byte_array[i];
  561. addr_array[i] = new InetAddress(host, addr);
  562. }
  563. obj = addr_array;
  564. } catch (UnknownHostException e) {
  565. obj = unknown_array;
  566. } finally {
  567. // Cache the address.
  568. cacheAddress(host, obj);
  569. // Delete the host from the lookupTable, and
  570. // notify all threads waiting for the monitor
  571. // for lookupTable.
  572. updateLookupTable(host);
  573. }
  574. }
  575. return obj;
  576. }
  577. private static Object checkLookupTable(String host) {
  578. // make sure obj is null.
  579. Object obj = null;
  580. synchronized (lookupTable) {
  581. // If the host isn't in the lookupTable, add it in the
  582. // lookuptable and return null. The caller should do
  583. // the lookup.
  584. if (lookupTable.containsKey(host) == false) {
  585. lookupTable.put(host, null);
  586. return obj;
  587. }
  588. // If the host is in the lookupTable, it means that another
  589. // thread is trying to look up the address of this host.
  590. // This thread should wait.
  591. while (lookupTable.containsKey(host)) {
  592. try {
  593. lookupTable.wait();
  594. } catch (InterruptedException e) {
  595. }
  596. }
  597. }
  598. // The other thread has finished looking up the address of
  599. // the host. This thread should retry to get the address
  600. // from the addressCache. If it doesn't get the address from
  601. // the cache, it will try to look up the address itself.
  602. obj = getCachedAddress(host);
  603. if (obj == null) {
  604. synchronized (lookupTable) {
  605. lookupTable.put(host, null);
  606. }
  607. }
  608. return obj;
  609. }
  610. private static void updateLookupTable(String host) {
  611. synchronized (lookupTable) {
  612. lookupTable.remove(host);
  613. lookupTable.notifyAll();
  614. }
  615. }
  616. /**
  617. * Returns the local host.
  618. *
  619. * <p>If there is a security manager, its
  620. * <code>checkConnect</code> method is called
  621. * with the local host name and <code>-1</code>
  622. * as its arguments to see if the operation is allowed.
  623. *
  624. * @return the IP address of the local host.
  625. *
  626. * @exception UnknownHostException if no IP address for the
  627. * <code>host</code> could be found.
  628. * @exception SecurityException if a security manager exists and its
  629. * <code>checkConnect</code> method doesn't allow the operation.
  630. *
  631. * @see SecurityManager#checkConnect
  632. */
  633. public synchronized static InetAddress getLocalHost() throws UnknownHostException {
  634. if (localHost.equals(unknownAddress)) {
  635. throw new UnknownHostException();
  636. }
  637. /* make sure the connection to the host is allowed: if yes,
  638. * return the "real" localHost; if not, return loopback "127.0.0.1"
  639. */
  640. SecurityManager security = System.getSecurityManager();
  641. try {
  642. /* If the localhost's address is not initialized yet, initialize
  643. * it. It is no longer initialized in the static initializer
  644. * (see comment there).
  645. */
  646. if (localHost.address == -1) {
  647. localHost = getAllByName(localHost.hostName)[0];
  648. /* This puts it in the address cache as well */
  649. }
  650. if (security != null)
  651. security.checkConnect(localHost.getHostName(), -1);
  652. } catch (java.lang.SecurityException e) {
  653. return loopbackHost;
  654. }
  655. return localHost;
  656. }
  657. /**
  658. * Perform class load-time initializations.
  659. */
  660. private static native void init();
  661. }
  662. class InetAddressImpl {
  663. native String getLocalHostName() throws UnknownHostException;
  664. native void makeAnyLocalAddress(InetAddress addr);
  665. native byte[][]
  666. lookupAllHostAddr(String hostname) throws UnknownHostException;
  667. native String getHostByAddr(int addr) throws UnknownHostException;
  668. native int getInetFamily();
  669. }