1 /*
   2  * Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package java.net;
  27 
  28 import java.util.Enumeration;
  29 import java.util.NoSuchElementException;
  30 import sun.security.action.*;
  31 import java.security.AccessController;
  32 
  33 /**
  34  * This class represents a Network Interface made up of a name,
  35  * and a list of IP addresses assigned to this interface.
  36  * It is used to identify the local interface on which a multicast group
  37  * is joined.
  38  *
  39  * Interfaces are normally known by names such as "le0".
  40  *
  41  * @since 1.4
  42  */
  43 public final class NetworkInterface {
  44     private String name;
  45     private String displayName;
  46     private int index;
  47     private InetAddress addrs[];
  48     private InterfaceAddress bindings[];
  49     private NetworkInterface childs[];
  50     private NetworkInterface parent = null;
  51     private boolean virtual = false;
  52     private static final NetworkInterface defaultInterface;
  53     private static final int defaultIndex; /* index of defaultInterface */
  54 
  55     static {
  56         AccessController.doPrivileged(new LoadLibraryAction("net"));
  57         init();
  58         defaultInterface = DefaultInterface.getDefault();
  59         if (defaultInterface != null) {
  60             defaultIndex = defaultInterface.getIndex();
  61         } else {
  62             defaultIndex = 0;
  63         }
  64     }
  65 
  66     /**
  67      * Returns an NetworkInterface object with index set to 0 and name to null.
  68      * Setting such an interface on a MulticastSocket will cause the
  69      * kernel to choose one interface for sending multicast packets.
  70      *
  71      */
  72     NetworkInterface() {
  73     }
  74 
  75     NetworkInterface(String name, int index, InetAddress[] addrs) {
  76         this.name = name;
  77         this.index = index;
  78         this.addrs = addrs;
  79     }
  80 
  81     /**
  82      * Get the name of this network interface.
  83      *
  84      * @return the name of this network interface
  85      */
  86     public String getName() {
  87             return name;
  88     }
  89 
  90     /**
  91      * Convenience method to return an Enumeration with all or a
  92      * subset of the InetAddresses bound to this network interface.
  93      * <p>
  94      * If there is a security manager, its <code>checkConnect</code>
  95      * method is called for each InetAddress. Only InetAddresses where
  96      * the <code>checkConnect</code> doesn't throw a SecurityException
  97      * will be returned in the Enumeration. However, if the caller has the
  98      * {@link NetPermission}("getNetworkInformation") permission, then all
  99      * InetAddresses are returned.
 100      * @return an Enumeration object with all or a subset of the InetAddresses
 101      * bound to this network interface
 102      */
 103     public Enumeration<InetAddress> getInetAddresses() {
 104 
 105         class checkedAddresses implements Enumeration<InetAddress> {
 106 
 107             private int i=0, count=0;
 108             private InetAddress local_addrs[];
 109 
 110             checkedAddresses() {
 111                 local_addrs = new InetAddress[addrs.length];
 112                 boolean trusted = true;
 113 
 114                 SecurityManager sec = System.getSecurityManager();
 115                 if (sec != null) {
 116                     try {
 117                         sec.checkPermission(new NetPermission("getNetworkInformation"));
 118                     } catch (SecurityException e) {
 119                         trusted = false;
 120                     }
 121                 }
 122                 for (int j=0; j<addrs.length; j++) {
 123                     try {
 124                         if (sec != null && !trusted) {
 125                             sec.checkConnect(addrs[j].getHostAddress(), -1);
 126                         }
 127                         local_addrs[count++] = addrs[j];
 128                     } catch (SecurityException e) { }
 129                 }
 130 
 131             }
 132 
 133             public InetAddress nextElement() {
 134                 if (i < count) {
 135                     return local_addrs[i++];
 136                 } else {
 137                     throw new NoSuchElementException();
 138                 }
 139             }
 140 
 141             public boolean hasMoreElements() {
 142                 return (i < count);
 143             }
 144         }
 145         return new checkedAddresses();
 146 
 147     }
 148 
 149     /**
 150      * Get a List of all or a subset of the <code>InterfaceAddresses</code>
 151      * of this network interface.
 152      * <p>
 153      * If there is a security manager, its <code>checkConnect</code>
 154      * method is called with the InetAddress for each InterfaceAddress.
 155      * Only InterfaceAddresses where the <code>checkConnect</code> doesn't throw
 156      * a SecurityException will be returned in the List.
 157      *
 158      * @return a <code>List</code> object with all or a subset of the
 159      *         InterfaceAddresss of this network interface
 160      * @since 1.6
 161      */
 162     public java.util.List<InterfaceAddress> getInterfaceAddresses() {
 163         java.util.List<InterfaceAddress> lst = new java.util.ArrayList<InterfaceAddress>(1);
 164         SecurityManager sec = System.getSecurityManager();
 165         for (int j=0; j<bindings.length; j++) {
 166             try {
 167                 if (sec != null) {
 168                     sec.checkConnect(bindings[j].getAddress().getHostAddress(), -1);
 169                 }
 170                 lst.add(bindings[j]);
 171             } catch (SecurityException e) { }
 172         }
 173         return lst;
 174     }
 175 
 176     /**
 177      * Get an Enumeration with all the subinterfaces (also known as virtual
 178      * interfaces) attached to this network interface.
 179      * <p>
 180      * For instance eth0:1 will be a subinterface to eth0.
 181      *
 182      * @return an Enumeration object with all of the subinterfaces
 183      * of this network interface
 184      * @since 1.6
 185      */
 186     public Enumeration<NetworkInterface> getSubInterfaces() {
 187         class subIFs implements Enumeration<NetworkInterface> {
 188 
 189             private int i=0;
 190 
 191             subIFs() {
 192             }
 193 
 194             public NetworkInterface nextElement() {
 195                 if (i < childs.length) {
 196                     return childs[i++];
 197                 } else {
 198                     throw new NoSuchElementException();
 199                 }
 200             }
 201 
 202             public boolean hasMoreElements() {
 203                 return (i < childs.length);
 204             }
 205         }
 206         return new subIFs();
 207 
 208     }
 209 
 210     /**
 211      * Returns the parent NetworkInterface of this interface if this is
 212      * a subinterface, or <code>null</code> if it is a physical
 213      * (non virtual) interface or has no parent.
 214      *
 215      * @return The <code>NetworkInterface</code> this interface is attached to.
 216      * @since 1.6
 217      */
 218     public NetworkInterface getParent() {
 219         return parent;
 220     }
 221 
 222     /**
 223      * Returns the index of this network interface. The index is an integer greater
 224      * or equal to zero, or {@code -1} for unknown. This is a system specific value
 225      * and interfaces with the same name can have different indexes on different
 226      * machines.
 227      *
 228      * @return the index of this network interface or {@code -1} if the index is
 229      *         unknown
 230      * @see #getByIndex(int)
 231      * @since 1.7
 232      */
 233     public int getIndex() {
 234         return index;
 235     }
 236 
 237     /**
 238      * Get the display name of this network interface.
 239      * A display name is a human readable String describing the network
 240      * device.
 241      *
 242      * @return a non-empty string representing the display name of this network
 243      *         interface, or null if no display name is available.
 244      */
 245     public String getDisplayName() {
 246         /* strict TCK conformance */
 247         return "".equals(displayName) ? null : displayName;
 248     }
 249 
 250     /**
 251      * Searches for the network interface with the specified name.
 252      *
 253      * @param   name
 254      *          The name of the network interface.
 255      *
 256      * @return  A <tt>NetworkInterface</tt> with the specified name,
 257      *          or <tt>null</tt> if there is no network interface
 258      *          with the specified name.
 259      *
 260      * @throws  SocketException
 261      *          If an I/O error occurs.
 262      *
 263      * @throws  NullPointerException
 264      *          If the specified name is <tt>null</tt>.
 265      */
 266     public static NetworkInterface getByName(String name) throws SocketException {
 267         if (name == null)
 268             throw new NullPointerException();
 269         return getByName0(name);
 270     }
 271 
 272     /**
 273      * Get a network interface given its index.
 274      *
 275      * @param index an integer, the index of the interface
 276      * @return the NetworkInterface obtained from its index, or {@code null} if
 277      *         there is no interface with such an index on the system
 278      * @throws  SocketException  if an I/O error occurs.
 279      * @throws  IllegalArgumentException if index has a negative value
 280      * @see #getIndex()
 281      * @since 1.7
 282      */
 283     public static NetworkInterface getByIndex(int index) throws SocketException {
 284         if (index < 0)
 285             throw new IllegalArgumentException("Interface index can't be negative");
 286         return getByIndex0(index);
 287     }
 288 
 289     /**
 290      * Convenience method to search for a network interface that
 291      * has the specified Internet Protocol (IP) address bound to
 292      * it.
 293      * <p>
 294      * If the specified IP address is bound to multiple network
 295      * interfaces it is not defined which network interface is
 296      * returned.
 297      *
 298      * @param   addr
 299      *          The <tt>InetAddress</tt> to search with.
 300      *
 301      * @return  A <tt>NetworkInterface</tt>
 302      *          or <tt>null</tt> if there is no network interface
 303      *          with the specified IP address.
 304      *
 305      * @throws  SocketException
 306      *          If an I/O error occurs.
 307      *
 308      * @throws  NullPointerException
 309      *          If the specified address is <tt>null</tt>.
 310      */
 311     public static NetworkInterface getByInetAddress(InetAddress addr) throws SocketException {
 312         if (addr == null) {
 313             throw new NullPointerException();
 314         }
 315         if (!(addr instanceof Inet4Address || addr instanceof Inet6Address)) {
 316             throw new IllegalArgumentException ("invalid address type");
 317         }
 318         return getByInetAddress0(addr);
 319     }
 320 
 321     /**
 322      * Returns all the interfaces on this machine. Returns null if no
 323      * network interfaces could be found on this machine.
 324      *
 325      * NOTE: can use getNetworkInterfaces()+getInetAddresses()
 326      *       to obtain all IP addresses for this node
 327      *
 328      * @return an Enumeration of NetworkInterfaces found on this machine
 329      * @exception  SocketException  if an I/O error occurs.
 330      */
 331 
 332     public static Enumeration<NetworkInterface> getNetworkInterfaces()
 333         throws SocketException {
 334         final NetworkInterface[] netifs = getAll();
 335 
 336         // specified to return null if no network interfaces
 337         if (netifs == null)
 338             return null;
 339 
 340         return new Enumeration<NetworkInterface>() {
 341             private int i = 0;
 342             public NetworkInterface nextElement() {
 343                 if (netifs != null && i < netifs.length) {
 344                     NetworkInterface netif = netifs[i++];
 345                     return netif;
 346                 } else {
 347                     throw new NoSuchElementException();
 348                 }
 349             }
 350 
 351             public boolean hasMoreElements() {
 352                 return (netifs != null && i < netifs.length);
 353             }
 354         };
 355     }
 356 
 357     private native static NetworkInterface[] getAll()
 358         throws SocketException;
 359 
 360     private native static NetworkInterface getByName0(String name)
 361         throws SocketException;
 362 
 363     private native static NetworkInterface getByIndex0(int index)
 364         throws SocketException;
 365 
 366     private native static NetworkInterface getByInetAddress0(InetAddress addr)
 367         throws SocketException;
 368 
 369     /**
 370      * Returns whether a network interface is up and running.
 371      *
 372      * @return  <code>true</code> if the interface is up and running.
 373      * @exception       SocketException if an I/O error occurs.
 374      * @since 1.6
 375      */
 376 
 377     public boolean isUp() throws SocketException {
 378         return isUp0(name, index);
 379     }
 380 
 381     /**
 382      * Returns whether a network interface is a loopback interface.
 383      *
 384      * @return  <code>true</code> if the interface is a loopback interface.
 385      * @exception       SocketException if an I/O error occurs.
 386      * @since 1.6
 387      */
 388 
 389     public boolean isLoopback() throws SocketException {
 390         return isLoopback0(name, index);
 391     }
 392 
 393     /**
 394      * Returns whether a network interface is a point to point interface.
 395      * A typical point to point interface would be a PPP connection through
 396      * a modem.
 397      *
 398      * @return  <code>true</code> if the interface is a point to point
 399      *          interface.
 400      * @exception       SocketException if an I/O error occurs.
 401      * @since 1.6
 402      */
 403 
 404     public boolean isPointToPoint() throws SocketException {
 405         return isP2P0(name, index);
 406     }
 407 
 408     /**
 409      * Returns whether a network interface supports multicasting or not.
 410      *
 411      * @return  <code>true</code> if the interface supports Multicasting.
 412      * @exception       SocketException if an I/O error occurs.
 413      * @since 1.6
 414      */
 415 
 416     public boolean supportsMulticast() throws SocketException {
 417         return supportsMulticast0(name, index);
 418     }
 419 
 420     /**
 421      * Returns the hardware address (usually MAC) of the interface if it
 422      * has one and if it can be accessed given the current privileges.
 423      * If a security manager is set, then the caller must have
 424      * the permission {@link NetPermission}("getNetworkInformation").
 425      *
 426      * @return  a byte array containing the address, or <code>null</code> if
 427      *          the address doesn't exist, is not accessible or a security
 428      *          manager is set and the caller does not have the permission
 429      *          NetPermission("getNetworkInformation")
 430      *
 431      * @exception       SocketException if an I/O error occurs.
 432      * @since 1.6
 433      */
 434     public byte[] getHardwareAddress() throws SocketException {
 435         SecurityManager sec = System.getSecurityManager();
 436         if (sec != null) {
 437             try {
 438                 sec.checkPermission(new NetPermission("getNetworkInformation"));
 439             } catch (SecurityException e) {
 440                 if (!getInetAddresses().hasMoreElements()) {
 441                     // don't have connect permission to any local address
 442                     return null;
 443                 }
 444             }
 445         }
 446         for (InetAddress addr : addrs) {
 447             if (addr instanceof Inet4Address) {
 448                 return getMacAddr0(((Inet4Address)addr).getAddress(), name, index);
 449             }
 450         }
 451         return getMacAddr0(null, name, index);
 452     }
 453 
 454     /**
 455      * Returns the Maximum Transmission Unit (MTU) of this interface.
 456      *
 457      * @return the value of the MTU for that interface.
 458      * @exception       SocketException if an I/O error occurs.
 459      * @since 1.6
 460      */
 461     public int getMTU() throws SocketException {
 462         return getMTU0(name, index);
 463     }
 464 
 465     /**
 466      * Returns whether this interface is a virtual interface (also called
 467      * subinterface).
 468      * Virtual interfaces are, on some systems, interfaces created as a child
 469      * of a physical interface and given different settings (like address or
 470      * MTU). Usually the name of the interface will the name of the parent
 471      * followed by a colon (:) and a number identifying the child since there
 472      * can be several virtual interfaces attached to a single physical
 473      * interface.
 474      *
 475      * @return <code>true</code> if this interface is a virtual interface.
 476      * @since 1.6
 477      */
 478     public boolean isVirtual() {
 479         return virtual;
 480     }
 481 
 482     private native static boolean isUp0(String name, int ind) throws SocketException;
 483     private native static boolean isLoopback0(String name, int ind) throws SocketException;
 484     private native static boolean supportsMulticast0(String name, int ind) throws SocketException;
 485     private native static boolean isP2P0(String name, int ind) throws SocketException;
 486     private native static byte[] getMacAddr0(byte[] inAddr, String name, int ind) throws SocketException;
 487     private native static int getMTU0(String name, int ind) throws SocketException;
 488 
 489     /**
 490      * Compares this object against the specified object.
 491      * The result is <code>true</code> if and only if the argument is
 492      * not <code>null</code> and it represents the same NetworkInterface
 493      * as this object.
 494      * <p>
 495      * Two instances of <code>NetworkInterface</code> represent the same
 496      * NetworkInterface if both name and addrs are the same for both.
 497      *
 498      * @param   obj   the object to compare against.
 499      * @return  <code>true</code> if the objects are the same;
 500      *          <code>false</code> otherwise.
 501      * @see     java.net.InetAddress#getAddress()
 502      */
 503     public boolean equals(Object obj) {
 504         if (!(obj instanceof NetworkInterface)) {
 505             return false;
 506         }
 507         NetworkInterface that = (NetworkInterface)obj;
 508         if (this.name != null ) {
 509             if (!this.name.equals(that.name)) {
 510                 return false;
 511             }
 512         } else {
 513             if (that.name != null) {
 514                 return false;
 515             }
 516         }
 517 
 518         if (this.addrs == null) {
 519             return that.addrs == null;
 520         } else if (that.addrs == null) {
 521             return false;
 522         }
 523 
 524         /* Both addrs not null. Compare number of addresses */
 525 
 526         if (this.addrs.length != that.addrs.length) {
 527             return false;
 528         }
 529 
 530         InetAddress[] thatAddrs = that.addrs;
 531         int count = thatAddrs.length;
 532 
 533         for (int i=0; i<count; i++) {
 534             boolean found = false;
 535             for (int j=0; j<count; j++) {
 536                 if (addrs[i].equals(thatAddrs[j])) {
 537                     found = true;
 538                     break;
 539                 }
 540             }
 541             if (!found) {
 542                 return false;
 543             }
 544         }
 545         return true;
 546     }
 547 
 548     public int hashCode() {
 549         return name == null? 0: name.hashCode();
 550     }
 551 
 552     public String toString() {
 553         String result = "name:";
 554         result += name == null? "null": name;
 555         if (displayName != null) {
 556             result += " (" + displayName + ")";
 557         }
 558         return result;
 559     }
 560 
 561     private static native void init();
 562 
 563     /**
 564      * Returns the default network interface of this system
 565      *
 566      * @return the default interface
 567      */
 568     static NetworkInterface getDefault() {
 569         return defaultInterface;
 570     }
 571 }