/* * 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;
publicclass SocksServer extendsThreadimplements Closeable { // Some useful SOCKS constant
privateint port; private ServerSocket server; privateboolean useV4 = false; private HashMap<String,String> users = new HashMap<>(); privatevolatileboolean done = false; // Inner class to handle protocol with client // This is the bulk of the work (protocol handler) class ClientHandler extendsThread { private InputStream in; private OutputStream out; private Socket client; private Socket dest;
// Simple tunneling class, moving bits from one stream to another
class Tunnel extendsThread { private InputStream tin; private OutputStream tout;
Tunnel(InputStream in, OutputStream out) {
tin = in;
tout = out;
}
publicvoid 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());
}
privatevoid 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) thrownew IOException("unexpected EOF");
count += i;
} while (count < l);
}
privateboolean userPassAuth() throws IOException { int ver = in.read(); int ulen = in.read(); if (ulen <= 0) thrownew SocketException("SOCKS protocol error"); byte[] buf = newbyte[ulen];
readBuf(in, buf);
String uname = new String(buf);
String password = null;
ulen = in.read(); if (ulen < 0) thrownew SocketException("SOCKS protocol error"); if (ulen > 0) {
buf = newbyte[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(); returntrue;
}
}
out.write(PROTO_VERS);
out.write(NOT_ALLOWED);
out.flush(); returnfalse;
}
privatevoid 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
privatevoid 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 = newbyte[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 privatevoid negociate() throws IOException { int ver = in.read(); int n = in.read(); byte[] buf = null; if (n > 0) {
buf = newbyte[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 privatevoid 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
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());
}
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
privatevoid 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 = newbyte[4];
readBuf(in, buf);
addr = InetAddress.getByAddress(buf).getHostAddress();
} break; case DOMAIN_NAME:
{ int i = in.read(); byte[] buf = newbyte[i];
readBuf(in, buf);
addr = new String(buf);
} break; case IPV6:
{ byte[] buf = newbyte[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;
}
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.