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:
commit
0a580b313d
70422 changed files with 17213626 additions and 0 deletions
543
test/jdk/java/net/Socks/SocksServer.java
Normal file
543
test/jdk/java/net/Socks/SocksServer.java
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue