undefect. CWE-407 — 63 sites patched across 27 ecosystems

Authors: russell@unturf.com · brackishbert@gmail.com · foxhop.net · TimeHexOn.com

Patches, unit tests, benchmarks, whitepaper, and outreach briefs.
Public domain — no copyright claimed. Use freely.
This commit is contained in:
russell@unturf.com 2026-03-26 17:11:57 -04:00
commit 0a580b313d
70422 changed files with 17213626 additions and 0 deletions

View file

@ -0,0 +1,88 @@
/*
* Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 7178362
* @run main/othervm BadProxySelector
*/
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.net.ProxySelector;
import java.net.Socket;
import java.net.SocketAddress;
import java.net.ServerSocket;
import java.net.URI;
import java.util.ArrayList;
import java.util.List;
import java.io.*;
public class BadProxySelector {
public static void main(String[] args) throws Exception {
ProxySelector.setDefault(new HTTPProxySelector());
try (ServerSocket ss = new ServerSocket(0, 0, InetAddress.getLocalHost());
Socket s1 = new Socket(ss.getInetAddress(), ss.getLocalPort());
Socket s2 = ss.accept()) {
}
ProxySelector.setDefault(new NullHTTPProxySelector());
try (ServerSocket ss = new ServerSocket(0, 0, InetAddress.getLocalHost());
Socket s1 = new Socket(ss.getInetAddress(), ss.getLocalPort());
Socket s2 = ss.accept()) {
}
}
// always returns bogus HTTP proxies
private static class HTTPProxySelector extends ProxySelector {
@Override
public void connectFailed(URI uri, SocketAddress sa, IOException ioe) {}
@Override
public List<Proxy> select(URI uri) {
System.out.println(this.getClass().getSimpleName() + " called for " + uri);
List<Proxy> proxies = new ArrayList<>();
proxies.add(new Proxy(Proxy.Type.HTTP,
new InetSocketAddress("localhost", 0)));
proxies.add(new Proxy(Proxy.Type.HTTP,
new InetSocketAddress("localhost", 0)));
return proxies;
}
}
private static class NullHTTPProxySelector extends ProxySelector {
@Override
public void connectFailed(URI uri, SocketAddress sa, IOException ioe) {}
@Override
public List<Proxy> select(URI uri) {
System.out.println(this.getClass().getSimpleName() + " called for " + uri);
List<Proxy> proxies = new ArrayList<>();
proxies.add(null);
proxies.add(new Proxy(Proxy.Type.HTTP,
new InetSocketAddress("localhost", 0)));
return proxies;
}
}
}

View file

@ -0,0 +1,203 @@
/*
* Copyright (c) 2013, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/* @test
* @bug 7100957
* @modules jdk.httpserver
* @library /test/lib
* @summary Java doesn't correctly handle the SOCKS protocol when used over IPv6.
* @run testng SocksIPv6Test
*/
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.Authenticator;
import java.net.InetSocketAddress;
import java.net.URL;
import java.net.Proxy;
import java.lang.Override;
import java.net.InetAddress;
import java.net.Inet6Address;
import java.net.ServerSocket;
import java.net.SocketException;
import java.net.NetworkInterface;
import java.util.Collections;
import java.util.List;
import com.sun.net.httpserver.*;
import java.io.BufferedWriter;
import org.testng.SkipException;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
import jdk.test.lib.NetworkConfiguration;
import static org.testng.Assert.*;
public class SocksIPv6Test {
private HttpServer server;
private SocksServer socks;
private String response = "Hello.";
@BeforeClass
public void setUp() throws Exception {
if (!ensureInet6AddressFamily() || !ensureIPv6OnLoopback()) {
NetworkConfiguration.printSystemConfiguration(System.out);
throw new SkipException("Host does not support IPv6");
}
server = HttpServer.create(new InetSocketAddress("::1", 0), 0);
server.createContext("/", ex -> {
ex.sendResponseHeaders(200, response.length());
try (BufferedWriter writer = new BufferedWriter(
new OutputStreamWriter(ex.getResponseBody(), "UTF-8"))) {
writer.write(response);
}
ex.close();
});
server.start();
socks = new SocksServer(InetAddress.getByName("::1"), 0, false);
socks.addUser("user", "pass");
socks.start();
Authenticator.setDefault(new Authenticator() {
@Override
protected java.net.PasswordAuthentication getPasswordAuthentication() {
return new java.net.PasswordAuthentication(
"user", "pass".toCharArray());
}
});
}
private boolean ensureIPv6OnLoopback() throws Exception {
boolean ipv6 = false;
List<NetworkInterface> nics = Collections.list(NetworkInterface.getNetworkInterfaces());
for (NetworkInterface nic : nics) {
if (!nic.isLoopback()) {
continue;
}
List<InetAddress> addrs = Collections.list(nic.getInetAddresses());
for (InetAddress addr : addrs) {
if (addr instanceof Inet6Address) {
ipv6 = true;
break;
}
}
}
if (!ipv6)
System.out.println("IPv6 is not enabled on loopback. Skipping test suite.");
return ipv6;
}
private boolean ensureInet6AddressFamily() throws IOException {
try (ServerSocket s = new ServerSocket()) {
s.bind(new InetSocketAddress("::1", 0));
return true;
} catch (SocketException e) {
System.out.println("Inet 6 address family is not available. Skipping test suite.");
}
return false;
}
@Test(groups = "unit")
public void testSocksOverIPv6() throws Exception {
Proxy proxy = new Proxy(Proxy.Type.SOCKS, new InetSocketAddress("::1",
socks.getPort()));
URL url = new URL("http://[::1]:" + server.getAddress().getPort());
java.net.URLConnection conn = url.openConnection(proxy);
String actual = "";
try (BufferedReader reader = new BufferedReader(
new InputStreamReader(conn.getInputStream()))) {
actual = reader.readLine();
}
assertEquals(actual, response);
}
@Test(groups = "unit")
public void testSocksOverIPv6Hostname() throws Exception {
InetAddress ipv6Loopback = InetAddress.getByName("::1");
String ipv6Hostname = ipv6Loopback.getHostName();
String ipv6HostAddress = ipv6Loopback.getHostAddress();
InetAddress ipv4Loopback;
String ipv4Hostname;
String ipv4HostAddress;
try {
ipv4Loopback = InetAddress.getByName("127.0.0.1");
ipv4Hostname = ipv4Loopback == null ? null : ipv4Loopback.getHostName();
ipv4HostAddress = ipv4Loopback == null ? null : ipv4Loopback.getHostAddress();
} catch (IOException io) {
ipv4Hostname = null;
ipv4HostAddress = null;
}
System.out.println("ipv6Hostname: " + ipv6Hostname + " / " + ipv6HostAddress);
System.out.println("ipv4Hostname: " + ipv4Hostname + " / " + ipv4HostAddress);
if (ipv6Hostname.equals(ipv6HostAddress)) {
System.out.println("Unable to get the hostname of the IPv6 loopback "
+ "address. Skipping test case.");
return;
}
if (ipv4Hostname != null && ipv6Hostname.equals(ipv4Hostname)) {
System.out.println("IPv6 and IPv4 loopback addresses map to the"
+ " same hostname. Skipping test case.");
return;
}
if (!InetAddress.getByName(ipv6Hostname).getHostAddress()
.equals(ipv6HostAddress)) {
System.out.println(ipv6Hostname + " resolves to \""
+ InetAddress.getByName(ipv6Hostname).getHostAddress()
+ "\", not \"" + ipv6HostAddress +
"\". Skipping test case.");
return;
}
Proxy proxy = new Proxy(Proxy.Type.SOCKS, new InetSocketAddress(ipv6Hostname,
socks.getPort()));
URL url = new URL("http://" + ipv6Hostname + ":" + server.getAddress().getPort());
java.net.URLConnection conn = url.openConnection(proxy);
String actual = "";
try (BufferedReader reader = new BufferedReader(
new InputStreamReader(conn.getInputStream()))) {
actual = reader.readLine();
}
assertEquals(actual, response);
}
@AfterClass
public void tearDown() {
if (server != null) {
server.stop(1);
}
if (socks != null) {
socks.close();
}
}
}

View file

@ -0,0 +1,134 @@
/*
* Copyright (c) 2011, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 6964547 5001942 8129444
* @library /test/lib
* @run main/othervm SocksProxyVersion
* @summary test socksProxyVersion system property
*/
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;
import java.io.IOException;
import java.net.InetAddress;
import java.net.Proxy;
import jdk.test.lib.net.IPSupport;
public class SocksProxyVersion implements Runnable {
final ServerSocket ss;
volatile boolean failed;
volatile boolean stopped = false;
volatile int expected;
public static void main(String[] args) throws Exception {
if (InetAddress.getLocalHost().isLoopbackAddress()) {
System.out.println("Test cannot run. getLocalHost returns a loopback address");
return;
}
new SocksProxyVersion();
}
public SocksProxyVersion() throws Exception {
ss = new ServerSocket(0, 0, InetAddress.getLocalHost());
int port = ss.getLocalPort();
Thread serverThread = new Thread(this);
serverThread.start();
try (ServerSocket socket = ss) {
runTest(port);
} finally {
stopped = true;
}
serverThread.join();
if (failed) {
throw new RuntimeException("socksProxyVersion not being set correctly");
}
}
final void runTest(int port) throws Exception {
/*
* Retrieving the IP Address of the machine
* since "localhost" is bypassed as a non-proxy host
*/
String addr = InetAddress.getLocalHost().getHostAddress();
System.setProperty("socksProxyHost", addr);
System.setProperty("socksProxyPort", Integer.toString(port));
Proxy proxy = new Proxy(Proxy.Type.SOCKS,
new InetSocketAddress(addr, port));
if (IPSupport.hasIPv4()) {
// SOCKS V4 (requires IPv4)
System.setProperty("socksProxyVersion", "4");
this.expected = 4;
check(new Socket(), addr, port);
check(new Socket(proxy), addr, port);
}
// SOCKS V5
System.setProperty("socksProxyVersion", "5");
this.expected = 5;
check(new Socket(), addr, port);
check(new Socket(proxy), addr, port);
}
private void check(Socket socket, String addr, int port)
throws IOException
{
try (Socket s = socket) {
socket.connect(new InetSocketAddress(addr, port));
} catch (SocketException e) {
// java.net.SocketException: Malformed reply from SOCKS server
// This exception is OK, since the "server" does not implement
// the socks protocol. It just verifies the version and closes.
}
}
@Override
public void run() {
int count = 0;
try {
while (!stopped) {
try (Socket s = ss.accept()) {
int version = (s.getInputStream()).read();
if (version != expected) {
System.out.printf("Iteration: %d, Got: %d, expected: %d%n",
count, version, expected);
failed = true;
}
}
count++;
}
} catch (IOException e) {
if (!ss.isClosed()) {
e.printStackTrace();
}
// ignore, server socket was closed
}
}
}

View file

@ -0,0 +1,543 @@
/*
* Copyright (c) 2002, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import java.net.*;
import java.io.*;
import java.util.HashMap;
public class SocksServer extends Thread implements Closeable {
// Some useful SOCKS constant
static final int PROTO_VERS4 = 4;
static final int PROTO_VERS = 5;
static final int DEFAULT_PORT = 1080;
static final int NO_AUTH = 0;
static final int GSSAPI = 1;
static final int USER_PASSW = 2;
static final int NO_METHODS = -1;
static final int CONNECT = 1;
static final int BIND = 2;
static final int UDP_ASSOC = 3;
static final int IPV4 = 1;
static final int DOMAIN_NAME = 3;
static final int IPV6 = 4;
static final int REQUEST_OK = 0;
static final int GENERAL_FAILURE = 1;
static final int NOT_ALLOWED = 2;
static final int NET_UNREACHABLE = 3;
static final int HOST_UNREACHABLE = 4;
static final int CONN_REFUSED = 5;
static final int TTL_EXPIRED = 6;
static final int CMD_NOT_SUPPORTED = 7;
static final int ADDR_TYPE_NOT_SUP = 8;
private int port;
private ServerSocket server;
private boolean useV4 = false;
private HashMap<String,String> users = new HashMap<>();
private volatile boolean done = false;
// Inner class to handle protocol with client
// This is the bulk of the work (protocol handler)
class ClientHandler extends Thread {
private InputStream in;
private OutputStream out;
private Socket client;
private Socket dest;
// Simple tunneling class, moving bits from one stream to another
class Tunnel extends Thread {
private InputStream tin;
private OutputStream tout;
Tunnel(InputStream in, OutputStream out) {
tin = in;
tout = out;
}
public void run() {
int b;
while (true) {
try {
b = tin.read();
if (b == -1) {
tin.close();
tout.close();
return;
}
tout.write(b);
tout.flush();
} catch (IOException e) {
// actually exit from the thread
return;
}
}
}
}
ClientHandler(Socket s) throws IOException {
client = s;
in = new BufferedInputStream(client.getInputStream());
out = new BufferedOutputStream(client.getOutputStream());
}
private void readBuf(InputStream is, byte[] buf) throws IOException {
int l = buf.length;
int count = 0;
int i;
do {
i = is.read(buf, count, l - count);
if (i == -1)
throw new IOException("unexpected EOF");
count += i;
} while (count < l);
}
private boolean userPassAuth() throws IOException {
int ver = in.read();
int ulen = in.read();
if (ulen <= 0)
throw new SocketException("SOCKS protocol error");
byte[] buf = new byte[ulen];
readBuf(in, buf);
String uname = new String(buf);
String password = null;
ulen = in.read();
if (ulen < 0)
throw new SocketException("SOCKS protocol error");
if (ulen > 0) {
buf = new byte[ulen];
readBuf(in, buf);
password = new String(buf);
}
// Check username/password validity here
System.err.println("User: '" + uname);
System.err.println("PSWD: '" + password);
if (users.containsKey(uname)) {
String p1 = users.get(uname);
System.err.println("p1 = " + p1);
if (p1.equals(password)) {
out.write(PROTO_VERS);
out.write(REQUEST_OK);
out.flush();
return true;
}
}
out.write(PROTO_VERS);
out.write(NOT_ALLOWED);
out.flush();
return false;
}
private void purge() throws IOException {
boolean done = false;
int i = 0;
client.setSoTimeout(1000);
while(!done && i != -1) {
try {
i = in.read();
} catch(IOException e) {
done = true;
}
}
}
// Handle the SOCKS version 4 protocl
private void getRequestV4() throws IOException {
int ver = in.read();
int cmd = in.read();
if (ver == -1 || cmd == -1) {
// EOF
in.close();
out.close();
return;
}
if (ver != 0 && ver != 4) {
out.write(PROTO_VERS4);
out.write(91); // Bad Request
out.write(0);
out.write(0);
out.write(0);
out.write(0);
out.write(0);
out.write(0);
out.write(0);
out.flush();
purge();
out.close();
in.close();
return;
}
if (cmd == CONNECT) {
int port = ((in.read() & 0xff) << 8);
port += (in.read() & 0xff);
byte[] buf = new byte[4];
readBuf(in, buf);
InetAddress addr = InetAddress.getByAddress(buf);
// We don't use the username...
int c;
do {
c = (in.read() & 0xff);
} while (c!=0);
boolean ok = true;
try {
dest = new Socket(addr, port);
} catch (IOException e) {
ok = false;
}
if (!ok) {
out.write(PROTO_VERS4);
out.write(91);
out.write(0);
out.write(0);
out.write(buf);
out.flush();
purge();
out.close();
in.close();
return;
}
out.write(PROTO_VERS4);
out.write(90); // Success
out.write((port >> 8) & 0xff);
out.write(port & 0xff);
out.write(buf);
out.flush();
InputStream in2 = new BufferedInputStream(dest.getInputStream());
OutputStream out2 = new BufferedOutputStream(dest.getOutputStream());
Tunnel tunnel = new Tunnel(in2, out);
tunnel.start();
int b = 0;
do {
try {
b = in.read();
if (b == -1) {
in.close();
out2.close();
return;
}
out2.write(b);
out2.flush();
} catch (IOException ex) {
}
} while (!client.isClosed());
}
}
// Negociate the authentication scheme with the client
private void negociate() throws IOException {
int ver = in.read();
int n = in.read();
byte[] buf = null;
if (n > 0) {
buf = new byte[n];
readBuf(in, buf);
}
int scheme = NO_AUTH;
for (int i = 0; i < n; i++)
if (buf[i] == USER_PASSW)
scheme = USER_PASSW;
out.write(PROTO_VERS);
out.write(scheme);
out.flush();
if (scheme == USER_PASSW)
userPassAuth();
}
// Send error message then close the streams
private void sendError(int code) {
try {
out.write(PROTO_VERS);
out.write(code);
out.write(0);
out.write(IPV4);
for (int i=0; i<6; i++)
out.write(0);
out.flush();
out.close();
} catch (IOException ex) {
}
}
// Actually connect the proxy to the destination then initiate tunneling
private void doConnect(InetSocketAddress addr) throws IOException {
dest = new Socket();
try {
dest.connect(addr, 10000);
} catch (SocketTimeoutException ex) {
sendError(HOST_UNREACHABLE);
return;
} catch (ConnectException cex) {
sendError(CONN_REFUSED);
return;
}
// Success
InetAddress iadd = addr.getAddress();
if (iadd instanceof Inet4Address) {
out.write(PROTO_VERS);
out.write(REQUEST_OK);
out.write(0);
out.write(IPV4);
out.write(iadd.getAddress());
} else if (iadd instanceof Inet6Address) {
out.write(PROTO_VERS);
out.write(REQUEST_OK);
out.write(0);
out.write(IPV6);
out.write(iadd.getAddress());
} else {
sendError(GENERAL_FAILURE);
return;
}
out.write((addr.getPort() >> 8) & 0xff);
out.write((addr.getPort() >> 0) & 0xff);
out.flush();
InputStream in2 = new BufferedInputStream(dest.getInputStream());
OutputStream out2 = new BufferedOutputStream(dest.getOutputStream());
Tunnel tunnel = new Tunnel(in2, out);
tunnel.start();
int b = 0;
do {
// Note that the socket might be closed from another thread (the tunnel)
try {
b = in.read();
if (b == -1) {
in.close();
out2.close();
return;
}
out2.write(b);
out2.flush();
} catch(IOException ioe) {
}
} while (!client.isClosed());
}
private void doBind(InetSocketAddress addr) throws IOException {
ServerSocket svr = new ServerSocket();
svr.bind(null);
InetSocketAddress bad = (InetSocketAddress) svr.getLocalSocketAddress();
out.write(PROTO_VERS);
out.write(REQUEST_OK);
out.write(0);
out.write(IPV4);
out.write(bad.getAddress().getAddress());
out.write((bad.getPort() >> 8) & 0xff);
out.write((bad.getPort() & 0xff));
out.flush();
dest = svr.accept();
bad = (InetSocketAddress) dest.getRemoteSocketAddress();
out.write(PROTO_VERS);
out.write(REQUEST_OK);
out.write(0);
out.write(IPV4);
out.write(bad.getAddress().getAddress());
out.write((bad.getPort() >> 8) & 0xff);
out.write((bad.getPort() & 0xff));
out.flush();
InputStream in2 = dest.getInputStream();
OutputStream out2 = dest.getOutputStream();
Tunnel tunnel = new Tunnel(in2, out);
tunnel.start();
int b = 0;
do {
// Note that the socket might be close from another thread (the tunnel)
try {
b = in.read();
if (b == -1) {
in.close();
out2.close();
return;
}
out2.write(b);
out2.flush();
} catch(IOException ioe) {
}
} while (!client.isClosed());
}
// Handle the SOCKS v5 requests
private void getRequest() throws IOException {
int ver = in.read();
int cmd = in.read();
if (ver == -1 || cmd == -1) {
in.close();
out.close();
return;
}
int rsv = in.read();
int atyp = in.read();
String addr = null;
int port = 0;
switch(atyp) {
case IPV4:
{
byte[] buf = new byte[4];
readBuf(in, buf);
addr = InetAddress.getByAddress(buf).getHostAddress();
}
break;
case DOMAIN_NAME:
{
int i = in.read();
byte[] buf = new byte[i];
readBuf(in, buf);
addr = new String(buf);
}
break;
case IPV6:
{
byte[] buf = new byte[16];
readBuf(in, buf);
addr = InetAddress.getByAddress(buf).getHostAddress();
}
break;
}
port = ((in.read()&0xff) << 8);
port += (in.read()&0xff);
InetSocketAddress socAddr = new InetSocketAddress(addr, port);
switch(cmd) {
case CONNECT:
doConnect(socAddr);
break;
case BIND:
doBind(socAddr);
break;
case UDP_ASSOC:
// doUDP(socAddr);
break;
}
}
public void run() {
String line = null;
try {
if (useV4) {
getRequestV4();
} else {
negociate();
getRequest();
}
} catch (IOException ex) {
try {
sendError(GENERAL_FAILURE);
} catch (Exception e) {
}
} finally {
try {
client.close();
} catch (IOException e2) {
}
}
}
}
public SocksServer(int port, boolean v4) throws IOException {
this(port);
this.useV4 = v4;
}
public SocksServer(int port) throws IOException {
this.port = port;
server = new ServerSocket();
if (port == 0) {
server.bind(null);
this.port = server.getLocalPort();
} else {
server.bind(new InetSocketAddress(port));
}
}
public SocksServer(InetAddress addr, int port, boolean useV4) throws IOException {
this.port = port;
this.useV4 = useV4;
server = new ServerSocket();
if (port == 0 && addr == null) {
server.bind(null);
this.port = server.getLocalPort();
} else if (port == 0 && addr != null) {
server.bind(new InetSocketAddress(addr, 0));
this.port = server.getLocalPort();
} else if (addr == null) {
assert port != 0;
server.bind(new InetSocketAddress(port));
} else {
assert port != 0;
server.bind(new InetSocketAddress(addr, port));
}
}
public SocksServer() throws IOException {
this (DEFAULT_PORT);
}
public void addUser(String user, String passwd) {
users.put(user, passwd);
}
public int getPort() {
return port;
}
public void close() {
done = true;
try { server.close(); } catch (IOException unused) {}
}
public void run() {
ClientHandler cl = null;
while (!done) {
try {
Socket s = server.accept();
cl = new ClientHandler(s);
cl.start();
} catch (IOException ex) {
if (cl != null)
cl.interrupt();
}
}
}
}

View file

@ -0,0 +1,111 @@
/*
* Copyright (c) 2019, 2022, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import org.testng.Assert;
import org.testng.annotations.AfterTest;
import org.testng.annotations.BeforeTest;
import org.testng.annotations.Test;
import sun.net.spi.DefaultProxySelector;
import java.io.IOException;
import java.net.InetAddress;
import java.net.Proxy;
import java.net.ProxySelector;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.List;
/**
* @test
* @bug 8230310
* @summary Tests java.net.SocksSocketImpl
* @run testng SocksSocketImplTest
* @modules java.base/sun.net.spi:+open
*/
public class SocksSocketImplTest {
private ProxySelector previousDefault;
@BeforeTest
public void beforeTest() {
previousDefault = ProxySelector.getDefault();
ProxySelector.setDefault(new SchemeStrippedProxySelector());
}
@AfterTest
public void afterTest() {
ProxySelector.setDefault(previousDefault);
}
/**
* Creates a socket connection, which internally triggers proxy selection for the target
* address. The test has been configured to use a {@link SchemeStrippedProxySelector ProxySelector}
* which throws a {@link IllegalArgumentException}. This test then verifies that this IAE gets wrapped
* by {@code java.net.SocksSocketImpl} into an {@link IOException} before being thrown
*
* @throws Exception
*/
@Test
public void testIOEOnProxySelection() throws Exception {
final int backlog = -1;
final int port = 0;
try (ServerSocket ss = new ServerSocket(port, backlog, InetAddress.getLoopbackAddress());
Socket s1 = new Socket(ss.getInetAddress(), ss.getLocalPort());
Socket s2 = ss.accept()) {
Assert.fail("IOException was expected to be thrown, but wasn't");
} catch (IOException ioe) {
// expected
// now verify the IOE was thrown for the correct expected reason
if (!(ioe.getCause() instanceof IllegalArgumentException)) {
// rethrow this so that the test output failure will capture the entire/real
// cause in its stacktrace
throw ioe;
}
}
}
/**
* A {@link ProxySelector} which strips the "scheme" part of the {@link URI}
* before delegating the selection to the {@link DefaultProxySelector}.
* This is to ensure that the {@code DefaultProxySelector} throws an {@link IllegalArgumentException}
* during selection of the proxy
*/
private static final class SchemeStrippedProxySelector extends DefaultProxySelector {
@Override
public List<Proxy> select(final URI uri) {
System.out.println("Proxy selection for " + uri);
final URI schemeStrippedURI;
try {
// strip the scheme and pass the rest
schemeStrippedURI = new URI(null, uri.getHost(), uri.getPath(), null);
} catch (URISyntaxException e) {
throw new RuntimeException(e);
}
System.out.println("Scheme stripped URI " + schemeStrippedURI + " is being used to select a proxy");
return super.select(schemeStrippedURI);
}
}
}

View file

@ -0,0 +1,201 @@
/*
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import org.junit.jupiter.api.Assumptions;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;
import java.io.IOException;
import java.net.Inet6Address;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.Proxy;
import java.net.ProxySelector;
import java.net.Socket;
import java.net.SocketAddress;
import java.net.SocketException;
import java.net.URI;
import java.net.UnknownHostException;
import java.util.List;
import java.util.stream.Stream;
import static org.junit.jupiter.api.Assertions.*;
/**
* @test
* @bug 8318130
* @summary Tests that java.net.SocksSocketImpl produces correct arguments
* for proxy selector
* @run junit/othervm SocksSocketProxySelectorTest
*/
public class SocksSocketProxySelectorTest {
public static final String SHORTEN_IPV6 = "((?<=\\[)0)?:(0:)+";
@BeforeAll
public static void beforeTest() {
ProxySelector.setDefault(new LoggingProxySelector());
}
// should match the host name
public static Stream<String> ipLiterals() {
return Stream.of("127.0.0.1",
"[::1]",
"[fe80::1%1234567890]");
}
// should be wrapped in [ ]
public static Stream<String> shortIpv6Literals() {
return Stream.of("::1",
"fe80::1%1234567890");
}
// with real interface names in scope
// should be wrapped in [ ], repeated 0's not trimmed
public static Stream<String> linkLocalIpv6Literals() throws SocketException {
return NetworkInterface.networkInterfaces()
.flatMap(NetworkInterface::inetAddresses)
.filter(InetAddress::isLinkLocalAddress)
.filter(Inet6Address.class::isInstance)
.map(InetAddress::getHostAddress);
}
public static Stream<InetAddress> hostNames() throws UnknownHostException {
return Stream.of(
InetAddress.getByAddress("localhost", new byte[] {127,0,0,1}),
InetAddress.getByAddress("bugs.openjdk.org", new byte[] {127,0,0,1}),
InetAddress.getByAddress("xn--kda4b0koi.com", new byte[] {127,0,0,1})
);
}
/**
* Creates a socket connection, which internally triggers proxy selection for the target
* address. The test has been configured to use a {@link LoggingProxySelector ProxySelector}
* which throws an {@link IllegalArgumentException} with hostname in exception message.
* The test then verifies that the hostname matches the expected one.
*
* @throws Exception
*/
@ParameterizedTest
@MethodSource("ipLiterals")
public void testIpLiterals(String host) throws Exception {
try (Socket s1 = new Socket(host, 80)) {
fail("IOException was expected to be thrown, but wasn't");
} catch (IOException ioe) {
// expected
// now verify the IOE was thrown for the correct expected reason
if (!(ioe.getCause() instanceof IllegalArgumentException iae)) {
// rethrow this so that the test output failure will capture the entire/real
// cause in its stacktrace
throw ioe;
}
assertNotNull(iae.getMessage(), "Host not found");
assertEquals(host,
iae.getMessage().replaceFirst(SHORTEN_IPV6, "::"),
"Found unexpected host");
}
}
@ParameterizedTest
@MethodSource("shortIpv6Literals")
public void testShortIpv6Literals(String host) throws Exception {
try (Socket s1 = new Socket(host, 80)) {
fail("IOException was expected to be thrown, but wasn't");
} catch (IOException ioe) {
// expected
// now verify the IOE was thrown for the correct expected reason
if (!(ioe.getCause() instanceof IllegalArgumentException iae)) {
// rethrow this so that the test output failure will capture the entire/real
// cause in its stacktrace
throw ioe;
}
assertNotNull(iae.getMessage(), "Host not found");
assertEquals('[' + host + ']',
iae.getMessage().replaceFirst(SHORTEN_IPV6, "::"),
"Found unexpected host");
}
}
@Test
public void testLinkLocalIpv6Literals() throws Exception {
String host = linkLocalIpv6Literals()
.findFirst()
.orElseGet(() -> Assumptions.abort("No IPv6 link-local addresses found"));
System.err.println(host);
try (Socket s1 = new Socket(host, 80)) {
fail("IOException was expected to be thrown, but wasn't");
} catch (IOException ioe) {
// expected
// now verify the IOE was thrown for the correct expected reason
if (!(ioe.getCause() instanceof IllegalArgumentException iae)) {
// rethrow this so that the test output failure will capture the entire/real
// cause in its stacktrace
throw ioe;
}
assertNotNull(iae.getMessage(), "Host not found");
assertEquals('[' + host + ']',
iae.getMessage(),
"Found unexpected host");
}
}
@ParameterizedTest
@MethodSource("hostNames")
public void testHostNames(InetAddress host) throws Exception {
try (Socket s1 = new Socket(host, 80)) {
fail("IOException was expected to be thrown, but wasn't");
} catch (IOException ioe) {
// expected
// now verify the IOE was thrown for the correct expected reason
if (!(ioe.getCause() instanceof IllegalArgumentException iae)) {
// rethrow this so that the test output failure will capture the entire/real
// cause in its stacktrace
throw ioe;
}
assertNotNull(iae.getMessage(), "Host not found");
assertEquals(host.getHostName(),
iae.getMessage(),
"Found unexpected host");
}
}
/**
* A {@link ProxySelector} which throws an IllegalArgumentException
* with the given hostname in exception message
*/
private static final class LoggingProxySelector extends
ProxySelector {
@Override
public List<Proxy> select(final URI uri) {
throw new IllegalArgumentException(uri.getHost());
}
@Override
public void connectFailed(URI uri, SocketAddress sa, IOException ioe) {
}
}
}

View file

@ -0,0 +1,125 @@
/*
* Copyright (c) 2002, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 4727547
* @summary SocksSocketImpl throws NullPointerException
* @build SocksServer
* @run main/othervm SocksV4Test
*/
import java.io.IOException;
import java.net.Authenticator;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.PasswordAuthentication;
import java.net.Proxy;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.UnknownHostException;
public class SocksV4Test {
// An unresolvable host
static final String HOSTNAME = "doesnot.exist.invalid";
static final String USER = "johndoe";
static final String PASSWORD = "helloworld";
public static void main(String[] args) throws Exception {
Authenticator.setDefault(new Auth());
UHETest();
getLocalPortTest();
}
static class Auth extends Authenticator {
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication(USER, PASSWORD.toCharArray());
}
}
public static void getLocalPortTest() throws Exception {
// We actually use V5 for this test because that is the default
// protocol version used by the client and it doesn't really handle
// down grading very well.
InetAddress lba = InetAddress.getLoopbackAddress();
try (SocksServer srvr = new SocksServer(lba, 0, false);
ServerSocket ss = new ServerSocket(0, 0, lba)) {
srvr.addUser(USER, PASSWORD);
int serverPort = ss.getLocalPort();
srvr.start();
int proxyPort = srvr.getPort();
System.out.printf("Server port %d, Proxy port %d\n", serverPort, proxyPort);
Proxy sp = new Proxy(Proxy.Type.SOCKS,
new InetSocketAddress(lba, proxyPort));
// Let's create an unresolved address
InetSocketAddress ad = new InetSocketAddress(lba.getHostAddress(), serverPort);
try (Socket s = new Socket(sp)) {
s.connect(ad, 10000);
int pp = s.getLocalPort();
System.out.println("Local port = " + pp);
if (pp == serverPort || pp == proxyPort)
throw new RuntimeException("wrong port returned");
} catch (UnknownHostException ex) {
throw new RuntimeException(ex);
} catch (IOException ioe) {
throw new RuntimeException(ioe);
}
}
}
public static void UHETest() throws Exception {
// sanity before running the test
assertUnresolvableHost(HOSTNAME);
InetAddress lba = InetAddress.getLoopbackAddress();
// Create a SOCKS V4 proxy
try (SocksServer srvr = new SocksServer(lba, 0, true)) {
srvr.start();
Proxy sp = new Proxy(Proxy.Type.SOCKS,
new InetSocketAddress(lba, srvr.getPort()));
// Let's create an unresolved address
InetSocketAddress ad = new InetSocketAddress(HOSTNAME, 1234);
try (Socket s = new Socket(sp)) {
s.connect(ad, 10000);
} catch (UnknownHostException ex) {
// OK, that's what we expected
} catch (NullPointerException npe) {
// Not OK, this used to be the bug
throw new RuntimeException("Got a NUllPointerException");
}
}
}
static void assertUnresolvableHost(String host) {
InetAddress addr = null;
try {
addr = InetAddress.getByName(host);
} catch (UnknownHostException x) {
// OK, expected
}
if (addr != null)
throw new RuntimeException("Test cannot run. resolvable address:" + addr);
}
}