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