1 package org.apache.commons.jcs3.utils.net; 2 3 /* 4 * Licensed to the Apache Software Foundation (ASF) under one 5 * or more contributor license agreements. See the NOTICE file 6 * distributed with this work for additional information 7 * regarding copyright ownership. The ASF licenses this file 8 * to you under the Apache License, Version 2.0 (the 9 * "License"); you may not use this file except in compliance 10 * with the License. You may obtain a copy of the License at 11 * 12 * http://www.apache.org/licenses/LICENSE-2.0 13 * 14 * Unless required by applicable law or agreed to in writing, 15 * software distributed under the License is distributed on an 16 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 * KIND, either express or implied. See the License for the 18 * specific language governing permissions and limitations 19 * under the License. 20 */ 21 22 import java.net.InetAddress; 23 import java.net.NetworkInterface; 24 import java.net.SocketException; 25 import java.net.UnknownHostException; 26 import java.util.ArrayList; 27 import java.util.Enumeration; 28 /* 29 * or more contributor license agreements. See the NOTICE file 30 * distributed with this work for additional information 31 * regarding copyright ownership. The ASF licenses this file 32 * to you under the Apache License, Version 2.0 (the 33 * "License"); you may not use this file except in compliance 34 * with the License. You may obtain a copy of the License at 35 * 36 * http://www.apache.org/licenses/LICENSE-2.0 37 * 38 * Unless required by applicable law or agreed to in writing, 39 * software distributed under the License is distributed on an 40 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 41 * KIND, either express or implied. See the License for the 42 * specific language governing permissions and limitations 43 * under the License. 44 */ 45 import java.util.List; 46 47 import org.apache.commons.jcs3.log.Log; 48 import org.apache.commons.jcs3.log.LogManager; 49 50 /** 51 * Simple utility for getting the local host name. 52 */ 53 public class HostNameUtil 54 { 55 /** The logger. */ 56 private static final Log log = LogManager.getLog( HostNameUtil.class ); 57 58 /** 59 * Gets the address for the local machine. 60 * <p> 61 * @return InetAddress.getLocalHost().getHostAddress() 62 * @throws UnknownHostException 63 */ 64 public static String getLocalHostAddress() throws UnknownHostException 65 { 66 final String hostAddress = getLocalHostLANAddress().getHostAddress(); 67 log.debug( "hostAddress = [{0}]", hostAddress ); 68 return hostAddress; 69 } 70 71 /** 72 * Returns an <code>InetAddress</code> object encapsulating what is most likely the machine's 73 * LAN IP address. 74 * <p> 75 * This method is intended for use as a replacement of JDK method 76 * <code>InetAddress.getLocalHost</code>, because that method is ambiguous on Linux systems. 77 * Linux systems enumerate the loopback network interface the same way as regular LAN network 78 * interfaces, but the JDK <code>InetAddress.getLocalHost</code> method does not specify the 79 * algorithm used to select the address returned under such circumstances, and will often return 80 * the loopback address, which is not valid for network communication. Details <a 81 * href="http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4665037">here</a>. 82 * <p> 83 * This method will scan all IP addresses on all network interfaces on the host machine to 84 * determine the IP address most likely to be the machine's LAN address. If the machine has 85 * multiple IP addresses, this method will prefer a site-local IP address (e.g. 192.168.x.x or 86 * 10.10.x.x, usually IPv4) if the machine has one (and will return the first site-local address 87 * if the machine has more than one), but if the machine does not hold a site-local address, 88 * this method will return simply the first non-loopback address found (IPv4 or IPv6).</p> 89 * <p> 90 * If this method cannot find a non-loopback address using this selection algorithm, it will 91 * fall back to calling and returning the result of JDK method 92 * <code>InetAddress.getLocalHost</code>. 93 * <p> 94 * <a href="http://issues.apache.org/jira/browse/JCS-40">JIR ISSUE JCS-40</a> 95 * <p> 96 * @return InetAddress 97 * @throws UnknownHostException If the LAN address of the machine cannot be found. 98 * @since 3.1 99 */ 100 public static InetAddress getLocalHostLANAddress() 101 throws UnknownHostException 102 { 103 return getLocalHostLANAddresses().stream().findFirst().orElse(null); 104 } 105 106 /** 107 * Returns all <code>InetAddress</code> objects encapsulating what are most likely the machine's 108 * LAN IP addresses. 109 * <p> 110 * This method will scan all IP addresses on all network interfaces on the host machine to 111 * determine the IP addresses most likely to be the machine's LAN addresses. 112 * <p> 113 * @return List<InetAddress> 114 * @throws UnknownHostException If the LAN address of the machine cannot be found. 115 */ 116 public static List<InetAddress> getLocalHostLANAddresses() 117 throws UnknownHostException 118 { 119 List<InetAddress> addresses = new ArrayList<>(); 120 121 try 122 { 123 InetAddress candidateAddress = null; 124 // Iterate all NICs (network interface cards)... 125 final Enumeration<NetworkInterface> ifaces = NetworkInterface.getNetworkInterfaces(); 126 while ( ifaces.hasMoreElements() ) 127 { 128 final NetworkInterface iface = ifaces.nextElement(); 129 130 // Skip loopback interfaces 131 if (iface.isLoopback() || !iface.isUp()) 132 { 133 continue; 134 } 135 136 // Iterate all IP addresses assigned to each card... 137 for ( final Enumeration<InetAddress> inetAddrs = iface.getInetAddresses(); inetAddrs.hasMoreElements(); ) 138 { 139 final InetAddress inetAddr = inetAddrs.nextElement(); 140 if ( !inetAddr.isLoopbackAddress() ) 141 { 142 if (inetAddr.isSiteLocalAddress()) 143 { 144 // Found non-loopback site-local address. 145 addresses.add(inetAddr); 146 } 147 if ( candidateAddress == null ) 148 { 149 // Found non-loopback address, but not necessarily site-local. 150 // Store it as a candidate to be returned if site-local address is not subsequently found... 151 candidateAddress = inetAddr; 152 // Note that we don't repeatedly assign non-loopback non-site-local addresses as candidates, 153 // only the first. For subsequent iterations, candidate will be non-null. 154 } 155 } 156 } 157 } 158 if (candidateAddress != null && addresses.isEmpty()) 159 { 160 // We did not find a site-local address, but we found some other non-loopback address. 161 // Server might have a non-site-local address assigned to its NIC (or it might be running 162 // IPv6 which deprecates the "site-local" concept). 163 addresses.add(candidateAddress); 164 } 165 // At this point, we did not find a non-loopback address. 166 // Fall back to returning whatever InetAddress.getLocalHost() returns... 167 if (addresses.isEmpty()) 168 { 169 final InetAddress jdkSuppliedAddress = InetAddress.getLocalHost(); 170 if ( jdkSuppliedAddress == null ) 171 { 172 throw new UnknownHostException( "The JDK InetAddress.getLocalHost() method unexpectedly returned null." ); 173 } 174 addresses.add(jdkSuppliedAddress); 175 } 176 } 177 catch ( final SocketException e ) 178 { 179 final UnknownHostException unknownHostException = new UnknownHostException( "Failed to determine LAN address: " 180 + e ); 181 unknownHostException.initCause( e ); 182 throw unknownHostException; 183 } 184 185 return addresses; 186 } 187 188 /** 189 * On systems with multiple network interfaces and mixed IPv6/IPv4 get a valid network 190 * interface for binding to multicast 191 * 192 * @return a network interface suitable for multicast 193 * @throws SocketException if a problem occurs while reading the network interfaces 194 */ 195 public static NetworkInterface getMulticastNetworkInterface() throws SocketException 196 { 197 final Enumeration<NetworkInterface> networkInterfaces = NetworkInterface.getNetworkInterfaces(); 198 while (networkInterfaces.hasMoreElements()) 199 { 200 final NetworkInterface networkInterface = networkInterfaces.nextElement(); 201 final Enumeration<InetAddress> addressesFromNetworkInterface = networkInterface.getInetAddresses(); 202 while (addressesFromNetworkInterface.hasMoreElements()) 203 { 204 final InetAddress inetAddress = addressesFromNetworkInterface.nextElement(); 205 if (inetAddress.isSiteLocalAddress() 206 && !inetAddress.isAnyLocalAddress() 207 && !inetAddress.isLinkLocalAddress() 208 && !inetAddress.isLoopbackAddress() 209 && !inetAddress.isMulticastAddress()) 210 { 211 return networkInterface; 212 } 213 } 214 } 215 216 return null; 217 } 218 }