1 /* 2 * Copyright (c) 2018, 2019, 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 /* 25 * @test 26 * @bug 8215294 27 * @requires os.family == "linux" 28 * @library /test/lib 29 * @build jdk.test.lib.NetworkConfiguration 30 * PromiscuousIPv6 31 * @run main/othervm PromiscuousIPv6 32 * @key randomness 33 */ 34 35 import java.io.IOException; 36 import java.net.DatagramPacket; 37 import java.net.DatagramSocket; 38 import java.net.InetAddress; 39 import java.net.Inet6Address; 40 import java.net.InetSocketAddress; 41 import java.net.MulticastSocket; 42 import java.net.NetworkInterface; 43 import java.net.SocketTimeoutException; 44 import java.net.StandardSocketOptions; 45 import java.util.List; 46 import java.util.Random; 47 import jdk.test.lib.NetworkConfiguration; 48 import jtreg.SkippedException; 49 import static java.lang.System.out; 50 import static java.nio.charset.StandardCharsets.UTF_8; 51 import static java.util.stream.Collectors.toList; 52 53 /* 54 * This test was created as a clone of the Promiscuous test and adapted for 55 * IPv6 node-local and link-local multicast addresses on Linux. 56 */ 57 public class PromiscuousIPv6 { 58 59 static final Random rand = new Random(); 60 61 static final int TIMEOUT = 5 * 1000; // 5 secs 62 63 static int sendDatagram(NetworkInterface nif, InetAddress group, int port) 64 throws IOException 65 { 66 try (MulticastSocket mc = new MulticastSocket()) { 67 mc.setOption(StandardSocketOptions.IP_MULTICAST_IF, nif); 68 69 int id = rand.nextInt(); 70 byte[] msg = Integer.toString(id).getBytes(UTF_8); 71 DatagramPacket p = new DatagramPacket(msg, msg.length); 72 p.setAddress(group); 73 p.setPort(port); 74 75 out.printf("Sending datagram to: %s/%d\n", group, port); 76 mc.send(p); 77 return id; 78 } 79 } 80 81 static void receiveDatagram(DatagramSocket mc, boolean datagramExpected, int id) 82 throws IOException 83 { 84 byte[] ba = new byte[100]; 85 DatagramPacket p = new DatagramPacket(ba, ba.length); 86 try { 87 mc.receive(p); 88 int recvId = Integer.parseInt( 89 new String(p.getData(), 0, p.getLength(), UTF_8)); 90 if (datagramExpected) { 91 if (recvId != id) 92 throw new RuntimeException("Unexpected id, got " + recvId 93 + ", expected: " + id); 94 out.printf("Received message as expected, %s\n", p.getAddress()); 95 } else { 96 throw new RuntimeException("Unexpected message received, " 97 + p.getAddress()); 98 } 99 } catch (SocketTimeoutException e) { 100 if (datagramExpected) 101 throw new RuntimeException("Expected message not received, " 102 + e.getMessage()); 103 else 104 out.printf("Message not received, as expected\n"); 105 } 106 } 107 108 static void test(NetworkInterface nif, InetAddress group1, InetAddress group2) 109 throws IOException 110 { 111 // Bind addresses should include the same network interface / scope, so 112 // as to not reply on the default route when there are multiple interfaces 113 InetAddress bindAddr1 = Inet6Address.getByAddress(null, group1.getAddress(), nif); 114 InetAddress bindAddr2 = Inet6Address.getByAddress(null, group2.getAddress(), nif); 115 116 try (MulticastSocket mc1 = new MulticastSocket(new InetSocketAddress(bindAddr1, 0)); 117 MulticastSocket mc2 = new MulticastSocket(new InetSocketAddress(bindAddr2, mc1.getLocalPort()))) { 118 119 final int port = mc1.getLocalPort(); 120 out.printf("Using port: %d\n", port); 121 122 mc1.setSoTimeout(TIMEOUT); 123 mc2.setSoTimeout(TIMEOUT); 124 125 mc1.joinGroup(new InetSocketAddress(group1, 0), nif); 126 out.printf("mc1 joined the MC group: %s\n", group1); 127 mc2.joinGroup(new InetSocketAddress(group2, 0), nif); 128 out.printf("mc2 joined the MC group: %s\n", group2); 129 130 out.printf("Sending datagram to: %s/%d\n", group1, port); 131 int id = sendDatagram(nif, group1, port); 132 133 // the packet should be received by mc1 only 134 receiveDatagram(mc1, true, id); 135 receiveDatagram(mc2, false, 0); 136 137 138 out.printf("Sending datagram to: %s/%d\n", group2, port); 139 id = sendDatagram(nif, group2, port); 140 141 // the packet should be received by mc2 only 142 receiveDatagram(mc2, true, id); 143 receiveDatagram(mc1, false, 0); 144 145 mc1.leaveGroup(new InetSocketAddress(group1, 0), nif); 146 mc2.leaveGroup(new InetSocketAddress(group2, 0), nif); 147 } 148 } 149 150 public static void main(String args[]) throws IOException { 151 String os = System.getProperty("os.name"); 152 153 if (!os.equals("Linux")) { 154 throw new SkippedException("This test should be run only on Linux"); 155 } else { 156 String osVersion = System.getProperty("os.version"); 157 String prefix = "3.10.0"; 158 if (osVersion.startsWith(prefix)) { 159 throw new SkippedException( 160 String.format("The behavior under test is known NOT to work on '%s' kernels", prefix)); 161 } 162 } 163 164 NetworkConfiguration.printSystemConfiguration(System.out); 165 List<NetworkInterface> nifs = NetworkConfiguration.probe() 166 .ip6MulticastInterfaces() 167 .collect(toList()); 168 169 if (nifs.size() == 0) { 170 throw new SkippedException( 171 "No IPv6 interfaces that support multicast found"); 172 } 173 174 InetAddress interfaceLocal1 = InetAddress.getByName("ff11::3.4.5.6"); 175 InetAddress interfaceLocal2 = InetAddress.getByName("ff11::5.6.7.8"); 176 177 InetAddress linkLocal1 = InetAddress.getByName("ff12::4.5.6.7"); 178 InetAddress linkLocal2 = InetAddress.getByName("ff12::7.8.9.10"); 179 180 for (NetworkInterface nif : nifs) { 181 test(nif, interfaceLocal1, interfaceLocal2); 182 test(nif, linkLocal1, linkLocal2); 183 } 184 } 185 }