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