package com.runjva.sourceforge.jsocks.protocol; import java.io.IOException; import java.io.InputStream; import java.io.InterruptedIOException; import java.io.OutputStream; import java.net.InetAddress; import java.net.Socket; import java.net.UnknownHostException; /** * Abstract class Proxy, base for classes Socks4Proxy and Socks5Proxy. Defines * methods for specifying default proxy, to be used by all classes of this * package. */ public abstract class SocksProxyBase { // Data members protected InetRange directHosts = new InetRange(); protected InetAddress proxyIP = null; protected String proxyHost = null; protected int proxyPort; protected Socket proxySocket = null; protected InputStream in; protected OutputStream out; protected int version; protected SocksProxyBase chainProxy = null; // Protected static/class variables protected static SocksProxyBase defaultProxy = null; // Constructors // ==================== SocksProxyBase(SocksProxyBase chainProxy, String proxyHost, int proxyPort) throws UnknownHostException { this.chainProxy = chainProxy; this.proxyHost = proxyHost; if (chainProxy == null) { this.proxyIP = InetAddress.getByName(proxyHost); } this.proxyPort = proxyPort; } SocksProxyBase(String proxyHost, int proxyPort) throws UnknownHostException { this(null, proxyHost, proxyPort); } SocksProxyBase(SocksProxyBase chainProxy, InetAddress proxyIP, int proxyPort) { this.chainProxy = chainProxy; this.proxyIP = proxyIP; this.proxyPort = proxyPort; } SocksProxyBase(InetAddress proxyIP, int proxyPort) { this(null, proxyIP, proxyPort); } SocksProxyBase(SocksProxyBase p) { this.proxyIP = p.proxyIP; this.proxyPort = p.proxyPort; this.version = p.version; this.directHosts = p.directHosts; } // Public instance methods // ======================== /** * Get the port on which proxy server is running. * * @return Proxy port. */ public int getPort() { return proxyPort; } /** * Get the ip address of the proxy server host. * * @return Proxy InetAddress. */ public InetAddress getInetAddress() { return proxyIP; } /** * Adds given ip to the list of direct addresses. This machine will be * accessed without using proxy. */ public void addDirect(InetAddress ip) { directHosts.add(ip); } /** * Adds host to the list of direct addresses. This machine will be accessed * without using proxy. */ public boolean addDirect(String host) { return directHosts.add(host); } /** * Adds given range of addresses to the lsit of direct addresses, machines * within this range will be accessed without using proxy. */ public void addDirect(InetAddress from, InetAddress to) { directHosts.add(from, to); } /** * Sets given InetRange as the list of direct address, previous list will be * discarded, any changes done previously with addDirect(Inetaddress) will * be lost. The machines in this range will be accessed without using proxy. * * @param ir * InetRange which should be used to look up direct addresses. * @see InetRange */ public void setDirect(InetRange ir) { directHosts = ir; } /** * Get the list of direct hosts. * * @return Current range of direct address as InetRange object. * @see InetRange */ public InetRange getDirect() { return directHosts; } /** * Check wether the given host is on the list of direct address. * * @param host * Host name to check. * @return true if the given host is specified as the direct addresses. */ public boolean isDirect(String host) { return directHosts.contains(host); } /** * Check wether the given host is on the list of direct addresses. * * @param host * Host address to check. * @return true if the given host is specified as the direct address. */ public boolean isDirect(InetAddress host) { return directHosts.contains(host); } /** * Set the proxy which should be used to connect to given proxy. * * @param chainProxy * Proxy to use to connect to this proxy. */ public void setChainProxy(SocksProxyBase chainProxy) { this.chainProxy = chainProxy; } /** * Get proxy which is used to connect to this proxy. * * @return Proxy which is used to connect to this proxy, or null if proxy is * to be contacted directly. */ public SocksProxyBase getChainProxy() { return chainProxy; } /** * Get string representation of this proxy. * * @returns string in the form:proxyHost:proxyPort \t Version versionNumber */ public String toString() { return ("" + proxyIP.getHostName() + ":" + proxyPort + "\tVersion " + version); } // Public Static(Class) Methods // ============================== /** * Sets SOCKS4 proxy as default. * * @param hostName * Host name on which SOCKS4 server is running. * @param port * Port on which SOCKS4 server is running. * @param user * Username to use for communications with proxy. */ public static void setDefaultProxy(String hostName, int port, String user) throws UnknownHostException { defaultProxy = new Socks4Proxy(hostName, port, user); } /** * Sets SOCKS4 proxy as default. * * @param ipAddress * Host address on which SOCKS4 server is running. * @param port * Port on which SOCKS4 server is running. * @param user * Username to use for communications with proxy. */ public static void setDefaultProxy(InetAddress ipAddress, int port, String user) { defaultProxy = new Socks4Proxy(ipAddress, port, user); } /** * Sets SOCKS5 proxy as default. Default proxy only supports * no-authentication. * * @param hostName * Host name on which SOCKS5 server is running. * @param port * Port on which SOCKS5 server is running. */ public static void setDefaultProxy(String hostName, int port) throws UnknownHostException { defaultProxy = new Socks5Proxy(hostName, port); } /** * Sets SOCKS5 proxy as default. Default proxy only supports * no-authentication. * * @param ipAddress * Host address on which SOCKS5 server is running. * @param port * Port on which SOCKS5 server is running. */ public static void setDefaultProxy(InetAddress ipAddress, int port) { defaultProxy = new Socks5Proxy(ipAddress, port); } /** * Sets default proxy. * * @param p * Proxy to use as default proxy. */ public static void setDefaultProxy(SocksProxyBase p) { defaultProxy = p; } /** * Get current default proxy. * * @return Current default proxy, or null if none is set. */ public static SocksProxyBase getDefaultProxy() { return defaultProxy; } /** * Parses strings in the form: host[:port:user:password], and creates proxy * from information obtained from parsing. *
* Defaults: port = 1080.
* If user specified but not password, creates Socks4Proxy, if user not
* specified creates Socks5Proxy, if both user and password are speciefied
* creates Socks5Proxy with user/password authentication.
*
* @param proxy_entry
* String in the form host[:port:user:password]
* @return Proxy created from the string, null if entry was somehow
* invalid(host unknown for example, or empty string)
*/
public static SocksProxyBase parseProxy(String proxy_entry) {
String proxy_host;
int proxy_port = 1080;
String proxy_user = null;
String proxy_password = null;
SocksProxyBase proxy;
final java.util.StringTokenizer st = new java.util.StringTokenizer(
proxy_entry, ":");
if (st.countTokens() < 1) {
return null;
}
proxy_host = st.nextToken();
if (st.hasMoreTokens()) {
try {
proxy_port = Integer.parseInt(st.nextToken().trim());
} catch (final NumberFormatException nfe) {
}
}
if (st.hasMoreTokens()) {
proxy_user = st.nextToken();
}
if (st.hasMoreTokens()) {
proxy_password = st.nextToken();
}
try {
if (proxy_user == null) {
proxy = new Socks5Proxy(proxy_host, proxy_port);
} else if (proxy_password == null) {
proxy = new Socks4Proxy(proxy_host, proxy_port, proxy_user);
} else {
proxy = new Socks5Proxy(proxy_host, proxy_port);
final UserPasswordAuthentication upa = new UserPasswordAuthentication(
proxy_user, proxy_password);
((Socks5Proxy) proxy).setAuthenticationMethod(
UserPasswordAuthentication.METHOD_ID, upa);
}
} catch (final UnknownHostException uhe) {
return null;
}
return proxy;
}
// Protected Methods
// =================
protected void startSession() throws SocksException {
try {
if (chainProxy == null) {
proxySocket = new Socket(proxyIP, proxyPort);
} else if (proxyIP != null) {
proxySocket = new SocksSocket(chainProxy, proxyIP, proxyPort);
} else {
proxySocket = new SocksSocket(chainProxy, proxyHost, proxyPort);
}
in = proxySocket.getInputStream();
out = proxySocket.getOutputStream();
} catch (final SocksException se) {
throw se;
} catch (final IOException io_ex) {
throw new SocksException(SOCKS_PROXY_IO_ERROR, "" + io_ex);
}
}
/**
* Create a copy of this proxy for use by individual threads.
*
* @return proxy
*/
protected abstract SocksProxyBase copy();
protected abstract ProxyMessage formMessage(int cmd, InetAddress ip,
int port);
protected abstract ProxyMessage formMessage(int cmd, String host, int port)
throws UnknownHostException;
protected abstract ProxyMessage formMessage(InputStream in)
throws SocksException, IOException;
protected ProxyMessage connect(InetAddress ip, int port)
throws SocksException {
try {
startSession();
final ProxyMessage request = formMessage(SOCKS_CMD_CONNECT, ip,
port);
return exchange(request);
} catch (final SocksException se) {
endSession();
throw se;
}
}
protected ProxyMessage connect(String host, int port)
throws UnknownHostException, SocksException {
try {
startSession();
final ProxyMessage request = formMessage(SOCKS_CMD_CONNECT, host,
port);
return exchange(request);
} catch (final SocksException se) {
endSession();
throw se;
}
}
protected ProxyMessage bind(InetAddress ip, int port) throws SocksException {
try {
startSession();
final ProxyMessage request = formMessage(SOCKS_CMD_BIND, ip, port);
return exchange(request);
} catch (final SocksException se) {
endSession();
throw se;
}
}
protected ProxyMessage bind(String host, int port)
throws UnknownHostException, SocksException {
try {
startSession();
final ProxyMessage request = formMessage(SOCKS_CMD_BIND, host, port);
return exchange(request);
} catch (final SocksException se) {
endSession();
throw se;
}
}
protected ProxyMessage accept() throws IOException, SocksException {
ProxyMessage msg;
try {
msg = formMessage(in);
} catch (final InterruptedIOException iioe) {
throw iioe;
} catch (final IOException io_ex) {
endSession();
throw new SocksException(SOCKS_PROXY_IO_ERROR,
"While Trying accept:" + io_ex);
}
return msg;
}
protected ProxyMessage udpAssociate(InetAddress ip, int port)
throws SocksException {
try {
startSession();
final ProxyMessage request = formMessage(SOCKS_CMD_UDP_ASSOCIATE,
ip, port);
if (request != null) {
return exchange(request);
}
} catch (final SocksException se) {
endSession();
throw se;
}
// Only get here if request was null
endSession();
throw new SocksException(SOCKS_METHOD_NOTSUPPORTED,
"This version of proxy does not support UDP associate, use version 5");
}
protected ProxyMessage udpAssociate(String host, int port)
throws UnknownHostException, SocksException {
try {
startSession();
final ProxyMessage request = formMessage(SOCKS_CMD_UDP_ASSOCIATE,
host, port);
if (request != null) {
return exchange(request);
}
} catch (final SocksException se) {
endSession();
throw se;
}
// Only get here if request was null
endSession();
throw new SocksException(SOCKS_METHOD_NOTSUPPORTED,
"This version of proxy does not support UDP associate, use version 5");
}
protected void endSession() {
try {
if (proxySocket != null) {
proxySocket.close();
}
proxySocket = null;
} catch (final IOException io_ex) {
}
}
/**
*Sends the request to SOCKS server
*/
protected void sendMsg(ProxyMessage msg) throws SocksException, IOException {
msg.write(out);
}
/**
* Reads the reply from the SOCKS server
*/
protected ProxyMessage readMsg() throws SocksException, IOException {
return formMessage(in);
}
/**
*Sends the request reads reply and returns it throws exception if
* something wrong with IO or the reply code is not zero
*/
protected ProxyMessage exchange(ProxyMessage request) throws SocksException {
ProxyMessage reply;
try {
request.write(out);
reply = formMessage(in);
} catch (final SocksException s_ex) {
throw s_ex;
} catch (final IOException ioe) {
throw (new SocksException(SOCKS_PROXY_IO_ERROR, "" + ioe));
}
return reply;
}
// Private methods
// ===============
// Constants
public static final int SOCKS_SUCCESS = 0;
public static final int SOCKS_FAILURE = 1;
public static final int SOCKS_BADCONNECT = 2;
public static final int SOCKS_BADNETWORK = 3;
public static final int SOCKS_HOST_UNREACHABLE = 4;
public static final int SOCKS_CONNECTION_REFUSED = 5;
public static final int SOCKS_TTL_EXPIRE = 6;
public static final int SOCKS_CMD_NOT_SUPPORTED = 7;
public static final int SOCKS_ADDR_NOT_SUPPORTED = 8;
public static final int SOCKS_NO_PROXY = 1 << 16;
public static final int SOCKS_PROXY_NO_CONNECT = 2 << 16;
public static final int SOCKS_PROXY_IO_ERROR = 3 << 16;
public static final int SOCKS_AUTH_NOT_SUPPORTED = 4 << 16;
public static final int SOCKS_AUTH_FAILURE = 5 << 16;
public static final int SOCKS_JUST_ERROR = 6 << 16;
public static final int SOCKS_DIRECT_FAILED = 7 << 16;
public static final int SOCKS_METHOD_NOTSUPPORTED = 8 << 16;
static final int SOCKS_CMD_CONNECT = 0x1;
static final int SOCKS_CMD_BIND = 0x2;
static final int SOCKS_CMD_UDP_ASSOCIATE = 0x3;
}