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