sockssocketimpl.java

来自「This is a resource based on j2me embedde」· Java 代码 · 共 823 行 · 第 1/2 页

JAVA
823
字号
/* * @(#)SocksSocketImpl.java	1.15 06/10/10 * * Copyright  1990-2008 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER *  * This program 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 program 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 at /legal/license.txt).  *  * 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 or visit www.sun.com if you need additional * information or have any questions.  */package java.net;import java.io.IOException;import java.io.InputStream;import java.io.OutputStream;import java.io.DataOutputStream;import java.io.BufferedReader;import java.io.InputStreamReader;import java.security.AccessController;import java.security.PrivilegedExceptionAction;/* import org.ietf.jgss.*; *//** * SOCKS (V4 & V5) TCP socket implementation (RFC 1928). * This is a subclass of PlainSocketImpl. * Note this class should <b>NOT</b> be public. */class SocksSocketImpl extends PlainSocketImpl implements SocksConsts {    private String server = null;    private int port = DEFAULT_PORT;    private InetSocketAddress external_address;    private boolean useV4 = false;    private Socket cmdsock = null;    private InputStream cmdIn = null;    private OutputStream cmdOut = null;    SocksSocketImpl(String server, int port) {	this.server = server;	this.port = (port == -1 ? DEFAULT_PORT : port);    }    void setV4() {	useV4 = true;    }    private synchronized void privilegedConnect(final String host,					      final int port,					      final int timeout) 	 throws IOException    { 	try { 	    AccessController.doPrivileged(		  new java.security.PrivilegedExceptionAction() {			  public Object run() throws IOException {			      superConnectServer(host, port, timeout);			      cmdIn = getInputStream();			      cmdOut = getOutputStream();			      return null;			  }		      }); 	} catch (java.security.PrivilegedActionException pae) { 	    throw (IOException) pae.getException(); 	}    }    private void superConnectServer(String host, int port,				    int timeout) throws IOException {	super.connect(new InetSocketAddress(host, port), timeout);    }    private int readSocksReply(InputStream in, byte[] data) throws IOException {	int len = data.length;	int received = 0;	for (int attempts = 0; received < len && attempts < 3; attempts++) {	    int count = in.read(data, received, len - received);	    if (count < 0)		throw new SocketException("Malformed reply from SOCKS server");	    received += count;	}	return received;    }    /**     * Provides the authentication machanism required by the proxy.     */    private boolean authenticate(byte method, InputStream in, 				 DataOutputStream out) throws IOException {	byte[] data = null;	int i;	// No Authentication required. We're done then!	if (method == NO_AUTH)	    return true;	/**	 * User/Password authentication. Try, in that order :	 * - The application provided Authenticator, if any	 * - The user preferences java.net.socks.username & 	 *   java.net.socks.password	 * - the user.name & no password (backward compatibility behavior).	 */	if (method == USER_PASSW) {	    String userName;	    String password = null;	    final InetAddress addr = InetAddress.getByName(server);	    PasswordAuthentication pw = (PasswordAuthentication)		java.security.AccessController.doPrivileged(		    new java.security.PrivilegedAction() {			    public Object run() {				return Authenticator.requestPasswordAuthentication(                                       server, addr, port, "SOCKS5", "SOCKS authentication", null);			    }			});	    if (pw != null) {		userName = pw.getUserName();		password = new String(pw.getPassword());	    } else {		try {		    userName = 			(String) AccessController.doPrivileged(			       new java.security.PrivilegedExceptionAction() {				       public Object run() throws IOException {                                           return null;				       }				   });		} catch (java.security.PrivilegedActionException pae) {		    throw (IOException) pae.getException();		}		if (userName != null) {		    try {			password = 			    (String) AccessController.doPrivileged(				   new java.security.PrivilegedExceptionAction() {					   public Object run() throws IOException {                                               return null;					   }				       });		    } catch (java.security.PrivilegedActionException pae) {			throw (IOException) pae.getException();		    }		} else {		    userName = 			(String) java.security.AccessController.doPrivileged(									     new sun.security.action.GetPropertyAction("user.name"));		}	    }	    if (userName == null)		return false;	    out.write(1);	    out.write(userName.length());	    out.write(userName.getBytes());	    if (password != null) {		out.write(password.length());		out.write(password.getBytes());	    } else		out.write(0);	    out.flush();	    data = new byte[2];	    i = readSocksReply(in, data);	    if (i != 2 || data[1] != 0) {		/* RFC 1929 specifies that the connection MUST be closed if		   authentication fails */		out.close();		in.close();		return false;	    }	    /* Authentication succeeded */	    return true;	}	/**	 * GSSAPI authentication mechanism.	 * Unfortunately the RFC seems out of sync with the Reference	 * implementation. I'll leave this in for future completion.	 */// 	if (method == GSSAPI) {// 	    try {// 		GSSManager manager = GSSManager.getInstance();// 		GSSName name = manager.createName("SERVICE:socks@"+server,// 						     null);// 		GSSContext context = manager.createContext(name, null, null,// 							   GSSContext.DEFAULT_LIFETIME);// 		context.requestMutualAuth(true);// 		context.requestReplayDet(true);// 		context.requestSequenceDet(true);// 		context.requestCredDeleg(true);// 		byte []inToken = new byte[0];// 		while (!context.isEstablished()) {// 		    byte[] outToken // 			= context.initSecContext(inToken, 0, inToken.length);// 		    // send the output token if generated// 		    if (outToken != null) {// 			out.write(1);// 			out.write(1);// 			out.writeShort(outToken.length);// 			out.write(outToken);// 			out.flush();// 			data = new byte[2];// 			i = readSocksReply(in, data);// 			if (i != 2 || data[1] == 0xff) {// 			    in.close();// 			    out.close();// 			    return false;// 			}// 			i = readSocksReply(in, data);// 			int len = 0;// 			len = ((int)data[0] & 0xff) << 8;// 			len += data[1];// 			data = new byte[len];// 			i = readSocksReply(in, data);// 			if (i == len)// 			    return true;// 			in.close();// 			out.close();// 		    }// 		}// 	    } catch (GSSException e) {// 		/* RFC 1961 states that if Context initialisation fails the connection// 		   MUST be closed */// 		e.printStackTrace();// 		in.close();// 		out.close();// 	    }// 	}	return false;    }    private void connectV4(InputStream in, OutputStream out,			   InetSocketAddress endpoint) throws IOException {	out.write(PROTO_VERS4);	out.write(CONNECT);	out.write((endpoint.getPort() >> 8) & 0xff);	out.write((endpoint.getPort() >> 0) & 0xff);	out.write(endpoint.getAddress().getAddress());	String userName = (String) java.security.AccessController.doPrivileged(               new sun.security.action.GetPropertyAction("user.name"));	out.write(userName.getBytes());	out.write(0);	out.flush();	byte[] data = new byte[8];	int n = readSocksReply(in, data);	if (n != 8)	    throw new SocketException("Reply from SOCKS server has bad length: " + n);	if (data[0] != 0 && data[0] != 4) 	    throw new SocketException("Reply from SOCKS server has bad version");	SocketException ex = null;	switch (data[1]) {	case 90:	    // Success!	    external_address = endpoint;	    break;	case 91:	    ex = new SocketException("SOCKS request rejected");	    break;	case 92:	    ex = new SocketException("SOCKS server couldn't reach destination");	    break;	case 93:	    ex = new SocketException("SOCKS authentication failed");	    break;	default:	    ex = new SocketException("Replay from SOCKS server contains bad status");	    break;	}	if (ex != null) {	    in.close();	    out.close();	    throw ex;	}    }    /**     * Connects the Socks Socket to the specified endpoint. It will first     * connect to the SOCKS proxy and negotiate the access. If the proxy     * grants the connections, then the connect is successful and all     * further traffic will go to the "real" endpoint.     *     * @param	endpoint	the <code>SocketAddress</code> to connect to.     * @param	timeout		the timeout value in milliseconds     * @throws	IOException	if the connection can't be established.     * @throws	SecurityException if there is a security manager and it     *				doesn't allow the connection     * @throws  IllegalArgumentException if endpoint is null or a     *          SocketAddress subclass not supported by this socket     */    protected void connect(SocketAddress endpoint, int timeout) throws IOException {	SecurityManager security = System.getSecurityManager();	if (endpoint == null || !(endpoint instanceof InetSocketAddress))	    throw new IllegalArgumentException("Unsupported address type");	InetSocketAddress epoint = (InetSocketAddress) endpoint;	if (security != null) {	    if (epoint.isUnresolved())		security.checkConnect(epoint.getHostName(),				      epoint.getPort());	    else		security.checkConnect(epoint.getAddress().getHostAddress(),				      epoint.getPort());	}	// Connects to the SOCKS server		try {	    privilegedConnect(server, port, timeout);	} catch (Exception e) {	    throw new SocketException(e.getMessage());	}	// cmdIn & cmdOut were intialized during the privilegedConnect() call	DataOutputStream out = new DataOutputStream(cmdOut);	InputStream in = cmdIn;	    	if (useV4) {	    // SOCKS Protocol version 4 doesn't know how to deal with 	    // DOMAIN type of addresses (unresolved addresses here)	    if (epoint.isUnresolved())		throw new UnknownHostException(epoint.toString());	    connectV4(in, out, epoint);	    return;	}	// This is SOCKS V5	out.write(PROTO_VERS);	out.write(2);	out.write(NO_AUTH);	out.write(USER_PASSW);	out.flush();	byte[] data = new byte[2];	int i = readSocksReply(in, data);	if (i != 2 || ((int)data[1]) == NO_METHODS)	    throw new SocketException("SOCKS : No acceptable methods");	if (!authenticate(data[1], in, out)) {	    throw new SocketException("SOCKS : authentication failed");	}	out.write(PROTO_VERS);	out.write(CONNECT);	out.write(0);	/* Test for IPV4/IPV6/Unresolved */	if (epoint.isUnresolved()) {	    out.write(DOMAIN_NAME);	    out.write(epoint.getHostName().length());	    out.write(epoint.getHostName().getBytes());	    out.write((epoint.getPort() >> 8) & 0xff);	    out.write((epoint.getPort() >> 0) & 0xff);	} else if (epoint.getAddress() instanceof Inet6Address) {	    out.write(IPV6);	    out.write(epoint.getAddress().getAddress());	    out.write((epoint.getPort() >> 8) & 0xff);	    out.write((epoint.getPort() >> 0) & 0xff);	} else {	    out.write(IPV4);	    out.write(epoint.getAddress().getAddress());	    out.write((epoint.getPort() >> 8) & 0xff);	    out.write((epoint.getPort() >> 0) & 0xff);	}	out.flush();	data = new byte[4];	i = readSocksReply(in, data);	if (i != 4)	    throw new SocketException("Reply from SOCKS server has bad length");	SocketException ex = null;	int nport, len;	byte[] addr;	switch (data[1]) {	case REQUEST_OK:	    // success!	    switch(data[3]) {	    case IPV4:		addr = new byte[4];		i = readSocksReply(in, addr);		if (i != 4)		    throw new SocketException("Reply from SOCKS server badly formatted");		data = new byte[2];		i = readSocksReply(in, data);		if (i != 2)		    throw new SocketException("Reply from SOCKS server badly formatted");		nport = ((int)data[0] & 0xff) << 8;		nport += ((int)data[1] & 0xff);		break;	    case DOMAIN_NAME:		len = data[1];		byte[] host = new byte[len];		i = readSocksReply(in, host);		if (i != len)		    throw new SocketException("Reply from SOCKS server badly formatted");		data = new byte[2];		i = readSocksReply(in, data);		if (i != 2)		    throw new SocketException("Reply from SOCKS server badly formatted");		nport = ((int)data[0] & 0xff) << 8;		nport += ((int)data[1] & 0xff);		break;	    case IPV6:		len = data[1];		addr = new byte[len];		i = readSocksReply(in, addr);		if (i != len)		    throw new SocketException("Reply from SOCKS server badly formatted");		data = new byte[2];		i = readSocksReply(in, data);		if (i != 2)

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?