1 /** 2 * Licensed to the Apache Software Foundation (ASF) under one 3 * or more contributor license agreements. See the NOTICE file 4 * distributed with this work for additional information 5 * regarding copyright ownership. The ASF licenses this file 6 * to you under the Apache License, Version 2.0 (the 7 * "License"); you may not use this file except in compliance 8 * with the License. You may obtain a copy of the License at 9 * 10 * http://www.apache.org/licenses/LICENSE-2.0 11 * 12 * Unless required by applicable law or agreed to in writing, software 13 * distributed under the License is distributed on an "AS IS" BASIS, 14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 * See the License for the specific language governing permissions and 16 * limitations under the License. 17 */ 18 19 package org.apache.hadoop.net; 20 21 import java.net.InetAddress; 22 import java.net.NetworkInterface; 23 import java.net.SocketException; 24 import java.net.UnknownHostException; 25 import java.util.Collections; 26 import java.util.Enumeration; 27 import java.util.LinkedHashSet; 28 import java.util.Vector; 29 30 import javax.naming.NamingException; 31 import javax.naming.directory.Attributes; 32 import javax.naming.directory.DirContext; 33 import javax.naming.directory.InitialDirContext; 34 35 import org.apache.commons.logging.Log; 36 import org.apache.commons.logging.LogFactory; 37 38 /** 39 * 40 * A class that provides direct and reverse lookup functionalities, allowing 41 * the querying of specific network interfaces or nameservers. 42 * 43 * 44 */ 45 public class DNS { 46 47 public static final Log LOG = LogFactory.getLog(DNS.class); 48 49 /** 50 * Returns the hostname associated with the specified IP address by the 51 * provided nameserver. 52 * 53 * @param hostIp 54 * The address to reverse lookup 55 * @param ns 56 * The host name of a reachable DNS server 57 * @return The host name associated with the provided IP 58 * @throws NamingException 59 * If a NamingException is encountered 60 */ reverseDns(InetAddress hostIp, String ns)61 public static String reverseDns(InetAddress hostIp, String ns) 62 throws NamingException { 63 // 64 // Builds the reverse IP lookup form 65 // This is formed by reversing the IP numbers and appending in-addr.arpa 66 // 67 String[] parts = hostIp.getHostAddress().split("\\."); 68 String reverseIP = parts[3] + "." + parts[2] + "." + parts[1] + "." 69 + parts[0] + ".in-addr.arpa"; 70 71 DirContext ictx = new InitialDirContext(); 72 Attributes attribute = 73 ictx.getAttributes("dns://" // Use "dns:///" if the default 74 + ((ns == null) ? "" : ns) + 75 // nameserver is to be used 76 "/" + reverseIP, new String[] { "PTR" }); 77 ictx.close(); 78 79 String hostname = attribute.get("PTR").get().toString(); 80 int hostnameLength = hostname.length(); 81 if (hostname.charAt(hostnameLength - 1) == '.') { 82 hostname = hostname.substring(0, hostnameLength - 1); 83 } 84 return hostname; 85 } 86 87 /** 88 * @return NetworkInterface for the given subinterface name (eg eth0:0) 89 * or null if no interface with the given name can be found 90 */ getSubinterface(String strInterface)91 private static NetworkInterface getSubinterface(String strInterface) 92 throws SocketException { 93 Enumeration<NetworkInterface> nifs = 94 NetworkInterface.getNetworkInterfaces(); 95 96 while (nifs.hasMoreElements()) { 97 Enumeration<NetworkInterface> subNifs = 98 nifs.nextElement().getSubInterfaces(); 99 100 while (subNifs.hasMoreElements()) { 101 NetworkInterface nif = subNifs.nextElement(); 102 if (nif.getName().equals(strInterface)) { 103 return nif; 104 } 105 } 106 } 107 return null; 108 } 109 110 /** 111 * @param nif network interface to get addresses for 112 * @return set containing addresses for each subinterface of nif, 113 * see below for the rationale for using an ordered set 114 */ getSubinterfaceInetAddrs( NetworkInterface nif)115 private static LinkedHashSet<InetAddress> getSubinterfaceInetAddrs( 116 NetworkInterface nif) { 117 LinkedHashSet<InetAddress> addrs = new LinkedHashSet<InetAddress>(); 118 Enumeration<NetworkInterface> subNifs = nif.getSubInterfaces(); 119 while (subNifs.hasMoreElements()) { 120 NetworkInterface subNif = subNifs.nextElement(); 121 addrs.addAll(Collections.list(subNif.getInetAddresses())); 122 } 123 return addrs; 124 } 125 126 /** 127 * Like {@link DNS#getIPs(String, boolean)}, but returns all 128 * IPs associated with the given interface and its subinterfaces. 129 */ getIPs(String strInterface)130 public static String[] getIPs(String strInterface) 131 throws UnknownHostException { 132 return getIPs(strInterface, true); 133 } 134 135 /** 136 * Returns all the IPs associated with the provided interface, if any, in 137 * textual form. 138 * 139 * @param strInterface 140 * The name of the network interface or subinterface to query 141 * (eg eth0 or eth0:0) or the string "default" 142 * @param returnSubinterfaces 143 * Whether to return IPs associated with subinterfaces of 144 * the given interface 145 * @return A string vector of all the IPs associated with the provided 146 * interface 147 * @throws UnknownHostException 148 * If an UnknownHostException is encountered in querying the 149 * default interface or the given interface can not be found 150 * 151 */ getIPs(String strInterface, boolean returnSubinterfaces)152 public static String[] getIPs(String strInterface, 153 boolean returnSubinterfaces) throws UnknownHostException { 154 if ("default".equals(strInterface)) { 155 return new String[] { 156 InetAddress.getLocalHost().getHostAddress() 157 }; 158 } 159 NetworkInterface netIf; 160 try { 161 netIf = NetworkInterface.getByName(strInterface); 162 if (netIf == null) { 163 netIf = getSubinterface(strInterface); 164 if (netIf == null) { 165 throw new UnknownHostException("Unknown interface " + strInterface); 166 } 167 } 168 } catch (SocketException e) { 169 LOG.warn("Unable to get IP for interface " + strInterface, e); 170 return new String[] { 171 InetAddress.getLocalHost().getHostAddress() 172 }; 173 } 174 175 // NB: Using a LinkedHashSet to preserve the order for callers 176 // that depend on a particular element being 1st in the array. 177 // For example, getDefaultIP always returns the first element. 178 LinkedHashSet<InetAddress> allAddrs = new LinkedHashSet<InetAddress>(); 179 allAddrs.addAll(Collections.list(netIf.getInetAddresses())); 180 if (!returnSubinterfaces) { 181 allAddrs.removeAll(getSubinterfaceInetAddrs(netIf)); 182 } 183 184 String ips[] = new String[allAddrs.size()]; 185 int i = 0; 186 for (InetAddress addr : allAddrs) { 187 ips[i++] = addr.getHostAddress(); 188 } 189 return ips; 190 } 191 192 /** 193 * Returns the first available IP address associated with the provided 194 * network interface 195 * 196 * @param strInterface 197 * The name of the network interface or subinterface to query 198 * (e.g. eth0 or eth0:0) or the string "default" 199 * @return The IP address in text form 200 * @throws UnknownHostException 201 * If one is encountered in querying the default interface 202 */ getDefaultIP(String strInterface)203 public static String getDefaultIP(String strInterface) 204 throws UnknownHostException { 205 String[] ips = getIPs(strInterface); 206 return ips[0]; 207 } 208 209 /** 210 * Returns all the host names associated by the provided nameserver with the 211 * address bound to the specified network interface 212 * 213 * @param strInterface 214 * The name of the network interface or subinterface to query 215 * (e.g. eth0 or eth0:0) or the string "default" 216 * @param nameserver 217 * The DNS host name 218 * @return A string vector of all host names associated with the IPs tied to 219 * the specified interface 220 * @throws UnknownHostException 221 */ getHosts(String strInterface, String nameserver)222 public static String[] getHosts(String strInterface, String nameserver) 223 throws UnknownHostException { 224 String[] ips = getIPs(strInterface); 225 Vector<String> hosts = new Vector<String>(); 226 for (int ctr = 0; ctr < ips.length; ctr++) 227 try { 228 hosts.add(reverseDns(InetAddress.getByName(ips[ctr]), 229 nameserver)); 230 } catch (Exception e) { 231 } 232 233 if (hosts.size() == 0) 234 return new String[] { InetAddress.getLocalHost().getCanonicalHostName() }; 235 else 236 return hosts.toArray(new String[] {}); 237 } 238 239 /** 240 * Returns all the host names associated by the default nameserver with the 241 * address bound to the specified network interface 242 * 243 * @param strInterface 244 * The name of the network interface to query (e.g. eth0) 245 * @return The list of host names associated with IPs bound to the network 246 * interface 247 * @throws UnknownHostException 248 * If one is encountered while querying the deault interface 249 * 250 */ getHosts(String strInterface)251 public static String[] getHosts(String strInterface) 252 throws UnknownHostException { 253 return getHosts(strInterface, null); 254 } 255 256 /** 257 * Returns the default (first) host name associated by the provided 258 * nameserver with the address bound to the specified network interface 259 * 260 * @param strInterface 261 * The name of the network interface to query (e.g. eth0) 262 * @param nameserver 263 * The DNS host name 264 * @return The default host names associated with IPs bound to the network 265 * interface 266 * @throws UnknownHostException 267 * If one is encountered while querying the deault interface 268 */ getDefaultHost(String strInterface, String nameserver)269 public static String getDefaultHost(String strInterface, String nameserver) 270 throws UnknownHostException { 271 if (strInterface.equals("default")) 272 return InetAddress.getLocalHost().getCanonicalHostName(); 273 274 if (nameserver != null && nameserver.equals("default")) 275 return getDefaultHost(strInterface); 276 277 String[] hosts = getHosts(strInterface, nameserver); 278 return hosts[0]; 279 } 280 281 /** 282 * Returns the default (first) host name associated by the default 283 * nameserver with the address bound to the specified network interface 284 * 285 * @param strInterface 286 * The name of the network interface to query (e.g. eth0) 287 * @return The default host name associated with IPs bound to the network 288 * interface 289 * @throws UnknownHostException 290 * If one is encountered while querying the deault interface 291 */ getDefaultHost(String strInterface)292 public static String getDefaultHost(String strInterface) 293 throws UnknownHostException { 294 return getDefaultHost(strInterface, null); 295 } 296 297 } 298