1 /* 2 * Copyright (c) 2017, 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. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 package jdk.testlibrary; 25 26 import java.io.PrintStream; 27 import java.io.UncheckedIOException; 28 import java.io.IOException; 29 import java.net.Inet4Address; 30 import java.net.Inet6Address; 31 import java.net.InetAddress; 32 import java.net.NetworkInterface; 33 import java.util.Arrays; 34 import java.util.HashMap; 35 import java.util.LinkedList; 36 import java.util.List; 37 import java.util.Map; 38 import java.util.Optional; 39 import java.util.function.Predicate; 40 import java.util.stream.Stream; 41 import static java.net.NetworkInterface.getNetworkInterfaces; 42 import static java.util.Collections.list; 43 44 /** 45 * Helper class for retrieving network interfaces and local addresses 46 * suitable for testing. 47 */ 48 public class NetworkConfiguration { 49 50 static final boolean isWindows = 51 System.getProperty("os.name").startsWith("Windows"); 52 static final boolean isMacOS = 53 System.getProperty("os.name").contains("OS X"); 54 55 private Map<NetworkInterface,List<Inet4Address>> ip4Interfaces; 56 private Map<NetworkInterface,List<Inet6Address>> ip6Interfaces; 57 58 private NetworkConfiguration(Map<NetworkInterface,List<Inet4Address>> ip4Interfaces, 59 Map<NetworkInterface,List<Inet6Address>> ip6Interfaces) 60 { 61 this.ip4Interfaces = ip4Interfaces; 62 this.ip6Interfaces = ip6Interfaces; 63 } 64 65 /** 66 * Returns a stream of interfaces suitable for functional tests. 67 */ 68 public Stream<NetworkInterface> interfaces() { 69 return Stream.concat(ip4Interfaces(), ip6Interfaces()) 70 .distinct(); 71 } 72 73 /** 74 * Returns a stream of interfaces suitable for IPv4 functional tests. 75 */ 76 public Stream<NetworkInterface> ip4Interfaces() { 77 return ip4Interfaces.keySet().stream() 78 .filter(NetworkConfiguration::isNotExcludedInterface) 79 .filter(hasIp4Addresses); 80 } 81 82 /** 83 * Returns a stream of interfaces suitable for IPv6 functional tests. 84 */ 85 public Stream<NetworkInterface> ip6Interfaces() { 86 return ip6Interfaces.keySet().stream() 87 .filter(NetworkConfiguration::isNotExcludedInterface) 88 .filter(hasIp6Addresses); 89 } 90 91 private static boolean isNotExcludedInterface(NetworkInterface nif) { 92 if (isMacOS && nif.getName().contains("awdl")) 93 return false; 94 String dName = nif.getDisplayName(); 95 if (isWindows && dName != null && dName.contains("Teredo")) 96 return false; 97 return true; 98 } 99 100 private final Predicate<NetworkInterface> hasIp4Addresses = nif -> { 101 Optional<?> addr = ip4Interfaces.get(nif).stream() 102 .filter(a -> !a.isAnyLocalAddress()) 103 .findAny(); 104 105 return addr.isPresent(); 106 }; 107 108 private final Predicate<NetworkInterface> hasIp6Addresses = nif -> { 109 Optional<?> addr = ip6Interfaces.get(nif).stream() 110 .filter(a -> !a.isAnyLocalAddress()) 111 .findAny(); 112 113 return addr.isPresent(); 114 }; 115 116 117 /** 118 * Returns a stream of interfaces suitable for IPv4 multicast tests. 119 */ 120 public Stream<NetworkInterface> ip4MulticastInterfaces() { 121 return ip4Interfaces().filter(supportsIp4Multicast); 122 } 123 124 /** 125 * Returns a stream of interfaces suitable for IPv6 multicast tests. 126 */ 127 public Stream<NetworkInterface> ip6MulticastInterfaces() { 128 return ip6Interfaces().filter(supportsIp6Multicast); 129 } 130 131 private final Predicate<NetworkInterface> supportsIp4Multicast = nif -> { 132 try { 133 if (!nif.supportsMulticast() || nif.isLoopback()) 134 return false; 135 136 Optional<?> addr = ip4Interfaces.get(nif).stream() 137 .filter(a -> !a.isAnyLocalAddress()) 138 .findAny(); 139 140 return addr.isPresent(); 141 } catch (IOException e) { 142 throw new UncheckedIOException(e); 143 } 144 }; 145 146 private final Predicate<NetworkInterface> supportsIp6Multicast = nif -> { 147 try { 148 if (!nif.supportsMulticast() || nif.isLoopback()) 149 return false; 150 151 Optional<?> addr = ip6Interfaces.get(nif).stream() 152 .filter(a -> !a.isAnyLocalAddress()) 153 .findAny(); 154 155 return addr.isPresent(); 156 } catch (IOException e) { 157 throw new UncheckedIOException(e); 158 } 159 }; 160 161 /** 162 * Returns all addresses on all "functional" interfaces. 163 */ 164 public Stream<InetAddress> addresses(NetworkInterface nif) { 165 return Stream.concat(ip4Interfaces.get(nif).stream(), 166 ip6Interfaces.get(nif).stream()); 167 } 168 169 /** 170 * Returns all IPv4 addresses on all "functional" interfaces. 171 */ 172 public Stream<Inet4Address> ip4Addresses() { 173 return ip4Interfaces().flatMap(nif -> ip4Addresses(nif)); 174 } 175 176 /** 177 * Returns all IPv6 addresses on all "functional" interfaces. 178 */ 179 public Stream<Inet6Address> ip6Addresses() { 180 return ip6Interfaces().flatMap(nif -> ip6Addresses(nif)); 181 } 182 183 /** 184 * Returns all IPv4 addresses the given interface. 185 */ 186 public Stream<Inet4Address> ip4Addresses(NetworkInterface nif) { 187 return ip4Interfaces.get(nif).stream(); 188 } 189 190 /** 191 * Returns all IPv6 addresses for the given interface. 192 */ 193 public Stream<Inet6Address> ip6Addresses(NetworkInterface nif) { 194 return ip6Interfaces.get(nif).stream(); 195 } 196 197 /** 198 * Return a NetworkConfiguration instance. 199 */ 200 public static NetworkConfiguration probe() throws IOException { 201 Map<NetworkInterface, List<Inet4Address>> ip4Interfaces = new HashMap<>(); 202 Map<NetworkInterface, List<Inet6Address>> ip6Interfaces = new HashMap<>(); 203 204 List<NetworkInterface> nifs = list(getNetworkInterfaces()); 205 for (NetworkInterface nif : nifs) { 206 // ignore interfaces that are down 207 if (!nif.isUp() || nif.isPointToPoint()) 208 continue; 209 210 List<Inet4Address> ip4Addresses = new LinkedList<>(); 211 List<Inet6Address> ip6Addresses = new LinkedList<>(); 212 ip4Interfaces.put(nif, ip4Addresses); 213 ip6Interfaces.put(nif, ip6Addresses); 214 for (InetAddress addr : list(nif.getInetAddresses())) { 215 if (addr instanceof Inet4Address) 216 ip4Addresses.add((Inet4Address)addr); 217 else if (addr instanceof Inet6Address) 218 ip6Addresses.add((Inet6Address)addr); 219 } 220 } 221 return new NetworkConfiguration(ip4Interfaces, ip6Interfaces); 222 } 223 224 @Override 225 public String toString() { 226 StringBuilder sb = new StringBuilder(); 227 interfaces().forEach(nif -> sb.append(interfaceInformation(nif))); 228 return sb.toString(); 229 } 230 231 /** Returns detailed information for the given interface. */ 232 public static String interfaceInformation(NetworkInterface nif) { 233 StringBuilder sb = new StringBuilder(); 234 try { 235 sb.append("Display name: " + nif.getDisplayName() + "\n"); 236 sb.append("Name: " + nif.getName() + "\n"); 237 for (InetAddress inetAddress : list(nif.getInetAddresses())) 238 sb.append("InetAddress: " + inetAddress + "\n"); 239 sb.append("Up? " + nif.isUp() + "\n"); 240 sb.append("Loopback? " + nif.isLoopback() + "\n"); 241 sb.append("PointToPoint? " + nif.isPointToPoint() + "\n"); 242 sb.append("Supports multicast? " + nif.supportsMulticast() + "\n"); 243 sb.append("Virtual? " + nif.isVirtual() + "\n"); 244 sb.append("Hardware address: " + 245 Arrays.toString(nif.getHardwareAddress()) + "\n"); 246 sb.append("MTU: " + nif.getMTU() + "\n"); 247 sb.append("Index: " + nif.getIndex() + "\n"); 248 sb.append("\n"); 249 return sb.toString(); 250 } catch (IOException e) { 251 throw new UncheckedIOException(e); 252 } 253 } 254 255 /** Prints all the system interface information to the give stream. */ 256 public static void printSystemConfiguration(PrintStream out) { 257 try { 258 out.println("*** all system network interface configuration ***"); 259 List<NetworkInterface> nifs = list(getNetworkInterfaces()); 260 for (NetworkInterface nif : nifs) 261 out.print(interfaceInformation(nif)); 262 out.println("*** end ***"); 263 } catch (IOException e) { 264 throw new UncheckedIOException(e); 265 } 266 } 267 }