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