Initial load
diff --git a/test/java/net/Socks/SocksServer.java b/test/java/net/Socks/SocksServer.java
new file mode 100644
index 0000000..8f6fad5
--- /dev/null
+++ b/test/java/net/Socks/SocksServer.java
@@ -0,0 +1,523 @@
+/*
+ * Copyright 2002 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+import java.net.*;
+import java.io.*;
+
+public class SocksServer extends Thread {
+ // 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 java.util.Hashtable users = new java.util.Hashtable();
+ private 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);
+ } catch (IOException e) {
+ // actually exit from the thread
+ return;
+ }
+ }
+ }
+ }
+
+ ClientHandler(Socket s) throws IOException {
+ client = s;
+ in = client.getInputStream();
+ out = 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 = (String) 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 = dest.getInputStream();
+ OutputStream out2 = 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);
+ } 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 = dest.getInputStream();
+ OutputStream out2 = 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);
+ } 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);
+ } 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);
+ int i = 0;
+ StringBuffer sb = new StringBuffer();
+ for (i = 0; i < 4; i++) {
+ sb.append(buf[i]&0xff);
+ if (i < 3)
+ sb.append('.');
+ }
+ addr = sb.toString();
+ }
+ 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);
+ int i = 0;
+ StringBuffer sb = new StringBuffer();
+ for (i = 0; i<16; i++) {
+ sb.append(Integer.toHexString(buf[i]&0xff));
+ if (i < 15)
+ sb.append(':');
+ }
+ addr = sb.toString();
+ }
+ 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();
+ server.bind(new InetSocketAddress(port));
+ }
+
+ public SocksServer() throws IOException {
+ this (DEFAULT_PORT);
+ }
+
+ public void addUser(String user, String passwd) {
+ users.put(user, passwd);
+ }
+
+ public synchronized void terminate() {
+ done = true;
+ }
+
+ 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();
+ }
+ }
+ }
+}
diff --git a/test/java/net/Socks/SocksV4Test.java b/test/java/net/Socks/SocksV4Test.java
new file mode 100644
index 0000000..091d5d4
--- /dev/null
+++ b/test/java/net/Socks/SocksV4Test.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2002 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/*
+ * @test
+ * @bug 4727547
+ * @summary SocksSocketImpl throws NullPointerException
+ * @build SocksServer
+ */
+
+import java.net.*;
+import java.io.*;
+
+public class SocksV4Test {
+ public static void main(String[] args) throws IOException {
+ // Create a SOCKS V4 proxy on port 8888
+ SocksServer srvr = new SocksServer(8888, true);
+ srvr.start();
+ System.setProperty("socksProxyHost", "localhost");
+ System.setProperty("socksProxyPort", "8888");
+ // Let's create an unresolved address
+ InetSocketAddress ad = new InetSocketAddress("doesnt.exist.name", 1234);
+ Socket s = new Socket();
+ try {
+ 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");
+ } finally {
+ srvr.terminate();
+ srvr.interrupt();
+ }
+ }
+}