1 /* 2 * Copyright (c) 2013, 2014, 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 /* @test 25 * @bug 7100957 26 * @summary Java doesn't correctly handle the SOCKS protocol when used over IPv6. 27 * @run testng SocksIPv6Test 28 */ 29 30 package test.java.net.Socks; 31 32 import java.io.BufferedReader; 33 import java.io.IOException; 34 import java.io.InputStream; 35 import java.io.InputStreamReader; 36 import java.io.OutputStreamWriter; 37 import java.net.Authenticator; 38 import java.net.InetSocketAddress; 39 import java.net.URL; 40 import java.net.Proxy; 41 import java.lang.Override; 42 import java.net.InetAddress; 43 import java.net.Inet6Address; 44 import java.net.ServerSocket; 45 import java.net.SocketException; 46 import java.net.NetworkInterface; 47 import java.net.UnknownHostException; 48 import java.util.Collections; 49 import java.util.List; 50 51 import libcore.net.NetworkSecurityPolicy; 52 53 import com.google.mockwebserver.MockResponse; 54 import com.google.mockwebserver.MockWebServer; 55 import org.testng.annotations.AfterClass; 56 import org.testng.annotations.BeforeClass; 57 import org.testng.annotations.Test; 58 59 import static org.testng.Assert.*; 60 61 public class SocksIPv6Test { 62 63 // Android-added: value set before this test execution. 64 private NetworkSecurityPolicy oldNetworkSecurityPolicy; 65 // Android-changed: com.sun.net.httpserver. is not available on Android. 66 // private HttpServer server; 67 private MockWebServer server; 68 private SocksServer socks; 69 private String response = "Hello."; 70 private static boolean shouldRun = false; 71 72 @BeforeClass setUp()73 public void setUp() throws Exception { 74 shouldRun = ensureInet6AddressFamily() && ensureIPv6OnLoopback(); 75 76 // Android-added: cleartext communication might not be allowed. 77 oldNetworkSecurityPolicy = NetworkSecurityPolicy.getInstance(); 78 NetworkSecurityPolicy.setInstance(new NetworkSecurityPolicy.DefaultNetworkSecurityPolicy()); 79 80 // Android-changed: use MockWebServer instead of HttpServer. 81 /* 82 server = HttpServer.create(new InetSocketAddress(0), 0); 83 server.createContext("/", ex -> { 84 ex.sendResponseHeaders(200, response.length()); 85 try (BufferedWriter writer = new BufferedWriter( 86 new OutputStreamWriter(ex.getResponseBody(), "UTF-8"))) { 87 writer.write(response); 88 } 89 ex.close(); 90 }); 91 server.start(); 92 */ 93 server = new MockWebServer(); 94 server.enqueue(new MockResponse().setResponseCode(200).setBody(response)); 95 server.play(); 96 97 socks = new SocksServer(0, false); 98 socks.addUser("user", "pass"); 99 socks.start(); 100 101 Authenticator.setDefault(new Authenticator() { 102 @Override 103 protected java.net.PasswordAuthentication getPasswordAuthentication() { 104 return new java.net.PasswordAuthentication( 105 "user", "pass".toCharArray()); 106 } 107 }); 108 } 109 ensureIPv6OnLoopback()110 private boolean ensureIPv6OnLoopback() throws Exception { 111 boolean ipv6 = false; 112 113 List<NetworkInterface> nics = Collections.list(NetworkInterface.getNetworkInterfaces()); 114 for (NetworkInterface nic : nics) { 115 if (!nic.isLoopback()) { 116 continue; 117 } 118 List<InetAddress> addrs = Collections.list(nic.getInetAddresses()); 119 for (InetAddress addr : addrs) { 120 if (addr instanceof Inet6Address) { 121 ipv6 = true; 122 break; 123 } 124 } 125 } 126 if (!ipv6) 127 System.out.println("IPv6 is not enabled on loopback. Skipping test suite."); 128 return ipv6; 129 } 130 ensureInet6AddressFamily()131 private boolean ensureInet6AddressFamily() throws IOException { 132 try (ServerSocket s = new ServerSocket()) { 133 s.bind(new InetSocketAddress("::1", 0)); 134 return true; 135 } catch (SocketException e) { 136 System.out.println("Inet 6 address family is not available. Skipping test suite."); 137 } 138 return false; 139 } 140 141 @Test(groups = "unit") testSocksOverIPv6()142 public void testSocksOverIPv6() throws Exception { 143 if (!shouldRun) return; 144 145 Proxy proxy = new Proxy(Proxy.Type.SOCKS, new InetSocketAddress("::1", 146 socks.getPort())); 147 // Android-changed: different server implementation is used. 148 // URL url = new URL("http://[::1]:" + server.getAddress().getPort()); 149 URL url = new URL("http://[::1]:" + server.getPort()); 150 java.net.URLConnection conn = url.openConnection(proxy); 151 String actual = ""; 152 try (BufferedReader reader = new BufferedReader( 153 new InputStreamReader(conn.getInputStream()))) { 154 actual = reader.readLine(); 155 } 156 assertEquals(actual, response); 157 } 158 159 @Test(groups = "unit") testSocksOverIPv6Hostname()160 public void testSocksOverIPv6Hostname() throws Exception { 161 if (!shouldRun) return; 162 163 String ipv6Hostname = InetAddress.getByName("::1").getHostName(); 164 String ipv4Hostname = InetAddress.getByName("127.0.0.1").getHostName(); 165 166 if (ipv6Hostname.equals(InetAddress.getByName("::1").getHostAddress())) { 167 System.out.println("Unable to get the hostname of the IPv6 loopback " 168 + "address. Skipping test case."); 169 return; 170 } 171 172 if (ipv6Hostname.equals(ipv4Hostname)) { 173 System.out.println("IPv6 and IPv4 loopback addresses map to the" 174 + " same hostname. Skipping test case."); 175 return; 176 } 177 178 Proxy proxy = new Proxy(Proxy.Type.SOCKS, new InetSocketAddress(ipv6Hostname, 179 socks.getPort())); 180 // Android-changed: different server implementation is used. 181 // URL url = new URL("http://" + ipv6Hostname + ":" + server.getAddress().getPort()); 182 URL url = new URL("http://" + ipv6Hostname + ":" + server.getPort()); // server.getAddress().getPort()); 183 java.net.URLConnection conn = url.openConnection(proxy); 184 String actual = ""; 185 try (BufferedReader reader = new BufferedReader( 186 new InputStreamReader(conn.getInputStream()))) { 187 actual = reader.readLine(); 188 } 189 assertEquals(actual, response); 190 } 191 192 @AfterClass tearDown()193 public void tearDown() { 194 // Android-changed: different server implementation is used. Also restore old 195 // NetworkSecurityPolicy. 196 /* 197 if (server != null) { 198 server.stop(1); 199 } 200 */ 201 if (oldNetworkSecurityPolicy != null) { 202 NetworkSecurityPolicy.setInstance(oldNetworkSecurityPolicy); 203 } 204 if (socks != null) { 205 socks.terminate(); 206 } 207 } 208 209 // Android-added: shutdown MockWebServer. 210 @AfterClass shutdownServer()211 public void shutdownServer() throws Exception { 212 if (server != null) { 213 server.shutdown(); 214 } 215 } 216 } 217