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