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 android.system.ErrnoException;
29 
30 import java.io.FileDescriptor;
31 import java.util.ArrayList;
32 import java.util.Arrays;
33 import java.util.Collections;
34 import java.util.Enumeration;
35 import java.util.HashMap;
36 import java.util.List;
37 import java.util.Map;
38 import java.util.NoSuchElementException;
39 
40 import android.system.StructIfaddrs;
41 import libcore.io.IoUtils;
42 import libcore.io.Libcore;
43 import sun.security.action.*;
44 import java.security.AccessController;
45 
46 import static android.system.OsConstants.*;
47 
48 // Android-note: NetworkInterface has been rewritten to avoid native code.
49 // Fix upstream bug not returning link-down interfaces. http://b/26238832
50 /**
51  * This class represents a Network Interface made up of a name,
52  * and a list of IP addresses assigned to this interface.
53  * It is used to identify the local interface on which a multicast group
54  * is joined.
55  *
56  * Interfaces are normally known by names such as "le0".
57  *
58  * @since 1.4
59  */
60 public final class NetworkInterface {
61     private String name;
62     private String displayName;
63     private int index;
64     private InetAddress addrs[];
65     private InterfaceAddress bindings[];
66     // Android-changed: Rewrote NetworkInterface on top of Libcore.io.
67     // private NetworkInterface childs[];
68     private List<NetworkInterface> childs;
69     private NetworkInterface parent = null;
70     private boolean virtual = false;
71     private static final NetworkInterface defaultInterface;
72     private static final int defaultIndex; /* index of defaultInterface */
73 
74     // Android-changed: Fix upstream bug not returning link-down interfaces. http://b/26238832
75     private byte[] hardwareAddr;
76 
77     static {
78         // Android-removed: Android doesn't need to call native init.
79         /*
80         AccessController.doPrivileged(
81             new java.security.PrivilegedAction<Void>() {
82                 public Void run() {
83                     System.loadLibrary("net");
84                     return null;
85                 }
86             });
87 
88         init();
89         */
90         defaultInterface = DefaultInterface.getDefault();
91         if (defaultInterface != null) {
92             defaultIndex = defaultInterface.getIndex();
93         } else {
94             defaultIndex = 0;
95         }
96     }
97 
98     /**
99      * Returns an NetworkInterface object with index set to 0 and name to null.
100      * Setting such an interface on a MulticastSocket will cause the
101      * kernel to choose one interface for sending multicast packets.
102      *
103      */
NetworkInterface()104     NetworkInterface() {
105     }
106 
NetworkInterface(String name, int index, InetAddress[] addrs)107     NetworkInterface(String name, int index, InetAddress[] addrs) {
108         this.name = name;
109         this.index = index;
110         this.addrs = addrs;
111     }
112 
113     /**
114      * Get the name of this network interface.
115      *
116      * @return the name of this network interface
117      */
getName()118     public String getName() {
119             return name;
120     }
121 
122     /**
123      * Convenience method to return an Enumeration with all or a
124      * subset of the InetAddresses bound to this network interface.
125      * <p>
126      * If there is a security manager, its {@code checkConnect}
127      * method is called for each InetAddress. Only InetAddresses where
128      * the {@code checkConnect} doesn't throw a SecurityException
129      * will be returned in the Enumeration. However, if the caller has the
130      * {@link NetPermission}("getNetworkInformation") permission, then all
131      * InetAddresses are returned.
132      * @return an Enumeration object with all or a subset of the InetAddresses
133      * bound to this network interface
134      */
getInetAddresses()135     public Enumeration<InetAddress> getInetAddresses() {
136 
137         class checkedAddresses implements Enumeration<InetAddress> {
138 
139             private int i=0, count=0;
140             private InetAddress local_addrs[];
141 
142             checkedAddresses() {
143                 local_addrs = new InetAddress[addrs.length];
144                 boolean trusted = true;
145 
146                 SecurityManager sec = System.getSecurityManager();
147                 if (sec != null) {
148                     try {
149                         sec.checkPermission(new NetPermission("getNetworkInformation"));
150                     } catch (SecurityException e) {
151                         trusted = false;
152                     }
153                 }
154                 for (int j=0; j<addrs.length; j++) {
155                     try {
156                         if (sec != null && !trusted) {
157                             sec.checkConnect(addrs[j].getHostAddress(), -1);
158                         }
159                         local_addrs[count++] = addrs[j];
160                     } catch (SecurityException e) { }
161                 }
162 
163             }
164 
165             public InetAddress nextElement() {
166                 if (i < count) {
167                     return local_addrs[i++];
168                 } else {
169                     throw new NoSuchElementException();
170                 }
171             }
172 
173             public boolean hasMoreElements() {
174                 return (i < count);
175             }
176         }
177         return new checkedAddresses();
178 
179     }
180 
181     /**
182      * Get a List of all or a subset of the {@code InterfaceAddresses}
183      * of this network interface.
184      * <p>
185      * If there is a security manager, its {@code checkConnect}
186      * method is called with the InetAddress for each InterfaceAddress.
187      * Only InterfaceAddresses where the {@code checkConnect} doesn't throw
188      * a SecurityException will be returned in the List.
189      *
190      * @return a {@code List} object with all or a subset of the
191      *         InterfaceAddresss of this network interface
192      * @since 1.6
193      */
getInterfaceAddresses()194     public java.util.List<InterfaceAddress> getInterfaceAddresses() {
195         java.util.List<InterfaceAddress> lst = new java.util.ArrayList<InterfaceAddress>(1);
196         // BEGIN Android-changed: Cherry-picked upstream OpenJDK9 change rev 59a110a38cea
197         // http://b/30628919
198         if (bindings != null) {
199             SecurityManager sec = System.getSecurityManager();
200             for (int j=0; j<bindings.length; j++) {
201                 try {
202                     if (sec != null) {
203                         sec.checkConnect(bindings[j].getAddress().getHostAddress(), -1);
204                     }
205                     lst.add(bindings[j]);
206                 } catch (SecurityException e) { }
207             }
208         }
209         // END Android-changed: Cherry-picked upstream OpenJDK9 change rev 59a110a38cea
210         return lst;
211     }
212 
213     /**
214      * Get an Enumeration with all the subinterfaces (also known as virtual
215      * interfaces) attached to this network interface.
216      * <p>
217      * For instance eth0:1 will be a subinterface to eth0.
218      *
219      * @return an Enumeration object with all of the subinterfaces
220      * of this network interface
221      * @since 1.6
222      */
getSubInterfaces()223     public Enumeration<NetworkInterface> getSubInterfaces() {
224         // Android-changed: Rewrote NetworkInterface on top of Libcore.io.
225         return Collections.enumeration(childs);
226     }
227 
228     /**
229      * Returns the parent NetworkInterface of this interface if this is
230      * a subinterface, or {@code null} if it is a physical
231      * (non virtual) interface or has no parent.
232      *
233      * @return The {@code NetworkInterface} this interface is attached to.
234      * @since 1.6
235      */
getParent()236     public NetworkInterface getParent() {
237         return parent;
238     }
239 
240     /**
241      * Returns the index of this network interface. The index is an integer greater
242      * or equal to zero, or {@code -1} for unknown. This is a system specific value
243      * and interfaces with the same name can have different indexes on different
244      * machines.
245      *
246      * @return the index of this network interface or {@code -1} if the index is
247      *         unknown
248      * @see #getByIndex(int)
249      * @since 1.7
250      */
getIndex()251     public int getIndex() {
252         return index;
253     }
254 
255     /**
256      * Get the display name of this network interface.
257      * A display name is a human readable String describing the network
258      * device.
259      *
260      * @return a non-empty string representing the display name of this network
261      *         interface, or null if no display name is available.
262      */
getDisplayName()263     public String getDisplayName() {
264         /* strict TCK conformance */
265         return "".equals(displayName) ? null : displayName;
266     }
267 
268     /**
269      * Searches for the network interface with the specified name.
270      *
271      * @param   name
272      *          The name of the network interface.
273      *
274      * @return  A {@code NetworkInterface} with the specified name,
275      *          or {@code null} if there is no network interface
276      *          with the specified name.
277      *
278      * @throws  SocketException
279      *          If an I/O error occurs.
280      *
281      * @throws  NullPointerException
282      *          If the specified name is {@code null}.
283      */
getByName(String name)284     public static NetworkInterface getByName(String name) throws SocketException {
285         if (name == null)
286             throw new NullPointerException();
287 
288         // Android-changed: Rewrote NetworkInterface on top of Libcore.io.
289         NetworkInterface[] nis = getAll();
290         for (NetworkInterface ni : nis) {
291             if (ni.getName().equals(name)) {
292                 return ni;
293             }
294         }
295         return null;
296     }
297 
298     /**
299      * Get a network interface given its index.
300      *
301      * @param index an integer, the index of the interface
302      * @return the NetworkInterface obtained from its index, or {@code null} if
303      *         there is no interface with such an index on the system
304      * @throws  SocketException  if an I/O error occurs.
305      * @throws  IllegalArgumentException if index has a negative value
306      * @see #getIndex()
307      * @since 1.7
308      */
getByIndex(int index)309     public static NetworkInterface getByIndex(int index) throws SocketException {
310         if (index < 0)
311             throw new IllegalArgumentException("Interface index can't be negative");
312 
313         // Android-changed: Rewrote NetworkInterface on top of Libcore.io.
314         NetworkInterface[] nis = getAll();
315         for (NetworkInterface ni : nis) {
316             if (ni.getIndex() == index) {
317                 return ni;
318             }
319         }
320         return null;
321     }
322 
323     /**
324      * Convenience method to search for a network interface that
325      * has the specified Internet Protocol (IP) address bound to
326      * it.
327      * <p>
328      * If the specified IP address is bound to multiple network
329      * interfaces it is not defined which network interface is
330      * returned.
331      *
332      * @param   addr
333      *          The {@code InetAddress} to search with.
334      *
335      * @return  A {@code NetworkInterface}
336      *          or {@code null} if there is no network interface
337      *          with the specified IP address.
338      *
339      * @throws  SocketException
340      *          If an I/O error occurs.
341      *
342      * @throws  NullPointerException
343      *          If the specified address is {@code null}.
344      */
getByInetAddress(InetAddress addr)345     public static NetworkInterface getByInetAddress(InetAddress addr) throws SocketException {
346         if (addr == null) {
347             throw new NullPointerException();
348         }
349         if (!(addr instanceof Inet4Address || addr instanceof Inet6Address)) {
350             throw new IllegalArgumentException ("invalid address type");
351         }
352 
353         // Android-changed: Rewrote NetworkInterface on top of Libcore.io.
354         NetworkInterface[] nis = getAll();
355         for (NetworkInterface ni : nis) {
356             for (InetAddress inetAddress : Collections.list(ni.getInetAddresses())) {
357                 if (inetAddress.equals(addr)) {
358                     return ni;
359                 }
360             }
361         }
362         return null;
363     }
364 
365     /**
366      * Returns all the interfaces on this machine. The {@code Enumeration}
367      * contains at least one element, possibly representing a loopback
368      * interface that only supports communication between entities on
369      * this machine.
370      *
371      * NOTE: can use getNetworkInterfaces()+getInetAddresses()
372      *       to obtain all IP addresses for this node
373      *
374      * @return an Enumeration of NetworkInterfaces found on this machine
375      * @exception  SocketException  if an I/O error occurs.
376      */
377 
getNetworkInterfaces()378     public static Enumeration<NetworkInterface> getNetworkInterfaces()
379         throws SocketException {
380         final NetworkInterface[] netifs = getAll();
381 
382         // Android-changed: Rewrote NetworkInterface on top of Libcore.io.
383         // specified to return null if no network interfaces
384         if (netifs.length == 0)
385             return null;
386 
387         return Collections.enumeration(Arrays.asList(netifs));
388     }
389 
390     // BEGIN Android-changed: Rewrote NetworkInterface on top of Libcore.io.
391     // private native static NetworkInterface[] getAll()
392     //    throws SocketException;
getAll()393     private static NetworkInterface[] getAll() throws SocketException {
394         // Group Ifaddrs by interface name.
395         Map<String, List<StructIfaddrs>> inetMap = new HashMap<>();
396 
397         StructIfaddrs[] ifaddrs;
398         try {
399             ifaddrs = Libcore.os.getifaddrs();
400         } catch (ErrnoException e) {
401             throw e.rethrowAsSocketException();
402         }
403 
404         for (StructIfaddrs ifa : ifaddrs) {
405             String name = ifa.ifa_name;
406 
407             List<StructIfaddrs> ifas;
408             if ((ifas = inetMap.get(name)) == null) {
409                 ifas = new ArrayList<>();
410                 inetMap.put(name, ifas);
411             }
412 
413             ifas.add(ifa);
414         }
415 
416         // Populate NetworkInterface instances.
417         Map<String, NetworkInterface> nis = new HashMap<>(inetMap.size());
418         for (Map.Entry<String, List<StructIfaddrs>> e : inetMap.entrySet()) {
419             String name = e.getKey();
420             int index = Libcore.os.if_nametoindex(e.getKey());
421             if (index == 0) {
422                 // This interface has gone away between getifaddrs and if_nametoindex
423                 continue;
424             }
425 
426             NetworkInterface ni = new NetworkInterface(name, index, null);
427             ni.displayName = name;
428 
429             List<InetAddress> addrs = new ArrayList<>();
430             List<InterfaceAddress> binds = new ArrayList<>();
431 
432             for (StructIfaddrs ifa : e.getValue()) {
433                 if (ifa.ifa_addr != null) {
434                     addrs.add(ifa.ifa_addr);
435                     binds.add(new InterfaceAddress(ifa.ifa_addr, (Inet4Address) ifa.ifa_broadaddr,
436                                                    ifa.ifa_netmask));
437                 }
438 
439                 if (ifa.hwaddr != null) {
440                     ni.hardwareAddr = ifa.hwaddr;
441                 }
442             }
443 
444             ni.addrs = addrs.toArray(new InetAddress[addrs.size()]);
445             ni.bindings = binds.toArray(new InterfaceAddress[binds.size()]);
446             ni.childs = new ArrayList<>(0);
447             nis.put(name, ni);
448         }
449 
450         // Populate childs/parent.
451         for (Map.Entry<String, NetworkInterface> e : nis.entrySet()) {
452             NetworkInterface ni = e.getValue();
453             String niName = ni.getName();
454             int colonIdx = niName.indexOf(':');
455             if (colonIdx != -1) {
456                 // This is a virtual interface.
457                 String parentName = niName.substring(0, colonIdx);
458                 NetworkInterface parent = nis.get(parentName);
459 
460                 ni.virtual = true;
461                 ni.parent = parent;
462                 parent.childs.add(ni);
463             }
464         }
465 
466         return nis.values().toArray(new NetworkInterface[nis.size()]);
467     }
468     // END Android-changed: Rewrote NetworkInterface on top of Libcore.io.
469 
470     /**
471      * Returns whether a network interface is up and running.
472      *
473      * @return  {@code true} if the interface is up and running.
474      * @exception       SocketException if an I/O error occurs.
475      * @since 1.6
476      */
477 
isUp()478     public boolean isUp() throws SocketException {
479         // Android-changed: Rewrote NetworkInterface on top of Libcore.io.
480         final int mask = IFF_UP | IFF_RUNNING;
481         return (getFlags() & mask) == mask;
482     }
483 
484     /**
485      * Returns whether a network interface is a loopback interface.
486      *
487      * @return  {@code true} if the interface is a loopback interface.
488      * @exception       SocketException if an I/O error occurs.
489      * @since 1.6
490      */
491 
isLoopback()492     public boolean isLoopback() throws SocketException {
493         // Android-changed: Rewrote NetworkInterface on top of Libcore.io.
494         return (getFlags() & IFF_LOOPBACK) != 0;
495     }
496 
497     /**
498      * Returns whether a network interface is a point to point interface.
499      * A typical point to point interface would be a PPP connection through
500      * a modem.
501      *
502      * @return  {@code true} if the interface is a point to point
503      *          interface.
504      * @exception       SocketException if an I/O error occurs.
505      * @since 1.6
506      */
507 
isPointToPoint()508     public boolean isPointToPoint() throws SocketException {
509         // Android-changed: Rewrote NetworkInterface on top of Libcore.io.
510         return (getFlags() & IFF_POINTOPOINT) != 0;
511     }
512 
513     /**
514      * Returns whether a network interface supports multicasting or not.
515      *
516      * @return  {@code true} if the interface supports Multicasting.
517      * @exception       SocketException if an I/O error occurs.
518      * @since 1.6
519      */
520 
supportsMulticast()521     public boolean supportsMulticast() throws SocketException {
522         // Android-changed: Rewrote NetworkInterface on top of Libcore.io.
523         return (getFlags() & IFF_MULTICAST) != 0;
524     }
525 
526     /**
527      * Returns the hardware address (usually MAC) of the interface if it
528      * has one and if it can be accessed given the current privileges.
529      * If a security manager is set, then the caller must have
530      * the permission {@link NetPermission}("getNetworkInformation").
531      *
532      * @return  a byte array containing the address, or {@code null} if
533      *          the address doesn't exist, is not accessible or a security
534      *          manager is set and the caller does not have the permission
535      *          NetPermission("getNetworkInformation")
536      *
537      * @exception       SocketException if an I/O error occurs.
538      * @since 1.6
539      */
getHardwareAddress()540     public byte[] getHardwareAddress() throws SocketException {
541         // BEGIN Android-changed: Fix upstream not returning link-down interfaces. http://b/26238832
542         /*
543         for (InetAddress addr : addrs) {
544             if (addr instanceof Inet4Address) {
545                 return getMacAddr0(((Inet4Address)addr).getAddress(), name, index);
546             }
547         }
548         return getMacAddr0(null, name, index);
549          */
550         NetworkInterface ni = getByName(name);
551         if (ni == null) {
552             throw new SocketException("NetworkInterface doesn't exist anymore");
553         }
554         return ni.hardwareAddr;
555         // END Android-changed: Fix upstream not returning link-down interfaces. http://b/26238832
556     }
557 
558     /**
559      * Returns the Maximum Transmission Unit (MTU) of this interface.
560      *
561      * @return the value of the MTU for that interface.
562      * @exception       SocketException if an I/O error occurs.
563      * @since 1.6
564      */
getMTU()565     public int getMTU() throws SocketException {
566         // Android-changed: Rewrote NetworkInterface on top of Libcore.io.
567         // return getMTU0(name, index);
568         FileDescriptor fd = null;
569         try {
570             fd = Libcore.rawOs.socket(AF_INET, SOCK_DGRAM, 0);
571             return Libcore.rawOs.ioctlMTU(fd, name);
572         } catch (ErrnoException e) {
573             throw e.rethrowAsSocketException();
574         } catch (Exception ex) {
575             throw new SocketException(ex);
576         } finally {
577             IoUtils.closeQuietly(fd);
578         }
579     }
580 
581     /**
582      * Returns whether this interface is a virtual interface (also called
583      * subinterface).
584      * Virtual interfaces are, on some systems, interfaces created as a child
585      * of a physical interface and given different settings (like address or
586      * MTU). Usually the name of the interface will the name of the parent
587      * followed by a colon (:) and a number identifying the child since there
588      * can be several virtual interfaces attached to a single physical
589      * interface.
590      *
591      * @return {@code true} if this interface is a virtual interface.
592      * @since 1.6
593      */
isVirtual()594     public boolean isVirtual() {
595         return virtual;
596     }
597 
598     // BEGIN Android-removed: Rewrote NetworkInterface on top of Libcore.io.
599     /*
600     private native static boolean isUp0(String name, int ind) throws SocketException;
601     private native static boolean isLoopback0(String name, int ind) throws SocketException;
602     private native static boolean supportsMulticast0(String name, int ind) throws SocketException;
603     private native static boolean isP2P0(String name, int ind) throws SocketException;
604     private native static byte[] getMacAddr0(byte[] inAddr, String name, int ind) throws SocketException;
605     private native static int getMTU0(String name, int ind) throws SocketException;
606     */
607     // END Android-removed: Rewrote NetworkInterface on top of Libcore.io.
608 
609     // BEGIN Android-added: Rewrote NetworkInterface on top of Libcore.io.
getFlags()610     private int getFlags() throws SocketException {
611         FileDescriptor fd = null;
612         try {
613             fd = Libcore.rawOs.socket(AF_INET, SOCK_DGRAM, 0);
614             return Libcore.rawOs.ioctlFlags(fd, name);
615         } catch (ErrnoException e) {
616             throw e.rethrowAsSocketException();
617         } catch (Exception ex) {
618             throw new SocketException(ex);
619         } finally {
620             IoUtils.closeQuietly(fd);
621         }
622     }
623     // END Android-added: Rewrote NetworkInterface on top of Libcore.io.
624 
625     /**
626      * Compares this object against the specified object.
627      * The result is {@code true} if and only if the argument is
628      * not {@code null} and it represents the same NetworkInterface
629      * as this object.
630      * <p>
631      * Two instances of {@code NetworkInterface} represent the same
632      * NetworkInterface if both name and addrs are the same for both.
633      *
634      * @param   obj   the object to compare against.
635      * @return  {@code true} if the objects are the same;
636      *          {@code false} otherwise.
637      * @see     java.net.InetAddress#getAddress()
638      */
equals(Object obj)639     public boolean equals(Object obj) {
640         if (!(obj instanceof NetworkInterface)) {
641             return false;
642         }
643         NetworkInterface that = (NetworkInterface)obj;
644         if (this.name != null ) {
645             if (!this.name.equals(that.name)) {
646                 return false;
647             }
648         } else {
649             if (that.name != null) {
650                 return false;
651             }
652         }
653 
654         if (this.addrs == null) {
655             return that.addrs == null;
656         } else if (that.addrs == null) {
657             return false;
658         }
659 
660         /* Both addrs not null. Compare number of addresses */
661 
662         if (this.addrs.length != that.addrs.length) {
663             return false;
664         }
665 
666         InetAddress[] thatAddrs = that.addrs;
667         int count = thatAddrs.length;
668 
669         for (int i=0; i<count; i++) {
670             boolean found = false;
671             for (int j=0; j<count; j++) {
672                 if (addrs[i].equals(thatAddrs[j])) {
673                     found = true;
674                     break;
675                 }
676             }
677             if (!found) {
678                 return false;
679             }
680         }
681         return true;
682     }
683 
hashCode()684     public int hashCode() {
685         return name == null? 0: name.hashCode();
686     }
687 
toString()688     public String toString() {
689         String result = "name:";
690         result += name == null? "null": name;
691         if (displayName != null) {
692             result += " (" + displayName + ")";
693         }
694         return result;
695     }
696 
697     // Android-removed: Android doesn't need to call native init.
698     // private static native void init();
699 
700     /**
701      * Returns the default network interface of this system
702      *
703      * @return the default interface
704      */
getDefault()705     static NetworkInterface getDefault() {
706         return defaultInterface;
707     }
708 }
709