added asocks subproject to android svn tree

svn:r20837
This commit is contained in:
Nathan Freitas 2009-10-25 04:59:39 +00:00
parent 79b8b744c7
commit 86d5ebc27b
40 changed files with 6585 additions and 0 deletions

3
asocks/BUILD Normal file
View File

@ -0,0 +1,3 @@
ant compile
ant jar
cp bin/jar/asocks.jar ../Orbot/libs

22
asocks/build.xml Normal file
View File

@ -0,0 +1,22 @@
<project>
<target name="clean">
<delete dir="bin"/>
</target>
<target name="compile">
<mkdir dir="bin/classes"/>
<javac srcdir="src" destdir="bin/classes"/>
</target>
<target name="jar">
<mkdir dir="bin/jar"/>
<jar destfile="bin/jar/asocks.jar" basedir="bin/classes">
<manifest>
</manifest>
</jar>
</target>
</project>

View File

@ -0,0 +1,257 @@
package net.sourceforge.jsocks;
import java.util.*;
import java.io.*;
import java.net.InetAddress;
import java.net.UnknownHostException;
import net.*;
import net.sourceforge.jsocks.socks.*;
import net.sourceforge.jsocks.socks.server.*;
public class SOCKS{
static public void usage(){
System.out.println(
"Usage: java SOCKS [inifile1 inifile2 ...]\n"+
"If none inifile is given, uses socks.properties.\n"
);
}
static public void main(String[] args){
String[] file_names;
int port=1080;
String logFile = null;
String host = null;
IdentAuthenticator auth = new IdentAuthenticator();
OutputStream log = null;
InetAddress localIP = null;
if(args.length == 0){
file_names = new String[1];
file_names[0] = "socks.properties";
}else{
file_names = args;
}
inform("Loading properties");
for(int i=0;i<file_names.length;++i){
inform("Reading file "+file_names[i]);
Properties pr = loadProperties(file_names[i]);
if(pr==null){
System.err.println("Loading of properties from "+
file_names[i]+"failed.");
usage();
return;
}
if(!addAuth(auth,pr)){
System.err.println("Error in file "+file_names[i]+".");
usage();
return;
}
//First file should contain all global settings,
// like port and host and log.
if(i==0){
String port_s = (String) pr.get("port");
if(port_s != null)
try{
port = Integer.parseInt(port_s);
}catch(NumberFormatException nfe){
System.err.println("Can't parse port: "+port_s);
return;
}
serverInit(pr);
logFile = (String) pr.get("log");
host = (String) pr.get("host");
}
//inform("Props:"+pr);
}
if(logFile!=null){
if(logFile.equals("-"))
log = System.out;
else
try{
log = new FileOutputStream(logFile);
}catch(IOException ioe){
System.err.println("Can't open log file "+logFile);
return;
}
}
if(host!=null)
try{
localIP = InetAddress.getByName(host);
}catch(UnknownHostException uhe){
System.err.println("Can't resolve local ip: "+host);
return;
}
inform("Using Ident Authentication scheme:\n"+auth+"\n");
ProxyServer server = new ProxyServer(auth);
server.start(port,5,localIP);
}
static Properties loadProperties(String file_name){
Properties pr = new Properties();
try{
InputStream fin = new FileInputStream(file_name);
pr.load(fin);
fin.close();
}catch(IOException ioe){
return null;
}
return pr;
}
static boolean addAuth(IdentAuthenticator ident,Properties pr){
InetRange irange;
String range = (String) pr.get("range");
if(range == null) return false;
irange = parseInetRange(range);
String users = (String) pr.get("users");
if(users == null){
ident.add(irange,null);
return true;
}
Hashtable uhash = new Hashtable();
StringTokenizer st = new StringTokenizer(users,";");
while(st.hasMoreTokens())
uhash.put(st.nextToken(),"");
ident.add(irange,uhash);
return true;
}
/**
Does server initialisation.
*/
public static void serverInit(Properties props){
int val;
val = readInt(props,"iddleTimeout");
if(val>=0){
ProxyServer.setIddleTimeout(val);
inform("Setting iddle timeout to "+val+" ms.");
}
val = readInt(props,"acceptTimeout");
if(val>=0){
ProxyServer.setAcceptTimeout(val);
inform("Setting accept timeout to "+val+" ms.");
}
val = readInt(props,"udpTimeout");
if(val>=0){
ProxyServer.setUDPTimeout(val);
inform("Setting udp timeout to "+val+" ms.");
}
val = readInt(props,"datagramSize");
if(val>=0){
ProxyServer.setDatagramSize(val);
inform("Setting datagram size to "+val+" bytes.");
}
proxyInit(props);
}
/**
Initialises proxy, if any specified.
*/
static void proxyInit(Properties props){
String proxy_list;
Proxy proxy = null;
StringTokenizer st;
proxy_list = (String) props.get("proxy");
if(proxy_list == null) return;
st = new StringTokenizer(proxy_list,";");
while(st.hasMoreTokens()){
String proxy_entry = st.nextToken();
Proxy p = Proxy.parseProxy(proxy_entry);
if(p == null)
exit("Can't parse proxy entry:"+proxy_entry);
inform("Adding Proxy:"+p);
if(proxy != null)
p.setChainProxy(proxy);
proxy = p;
}
if(proxy == null) return; //Empty list
String direct_hosts = (String) props.get("directHosts");
if(direct_hosts!=null){
InetRange ir = parseInetRange(direct_hosts);
inform("Setting direct hosts:"+ir);
proxy.setDirect(ir);
}
ProxyServer.setProxy(proxy);
}
/**
Inits range from the string of semicolon separated ranges.
*/
static InetRange parseInetRange(String source){
InetRange irange = new InetRange();
StringTokenizer st = new StringTokenizer(source,";");
while(st.hasMoreTokens())
irange.add(st.nextToken());
return irange;
}
/**
Integer representaion of the property named name, or -1 if one
is not found.
*/
static int readInt(Properties props,String name){
int result = -1;
String val = (String) props.get(name);
if(val==null) return -1;
StringTokenizer st = new StringTokenizer(val);
if(!st.hasMoreElements()) return -1;
try{
result = Integer.parseInt(st.nextToken());
}catch(NumberFormatException nfe){
inform("Bad value for "+name+":"+val);
}
return result;
}
//Display functions
///////////////////
public static void inform(String s){
System.out.println(s);
}
static void exit(String msg){
System.err.println("Error:"+msg);
System.err.println("Aborting operation");
System.exit(0);
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 926 B

View File

@ -0,0 +1,386 @@
package net.sourceforge.jsocks;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.DatagramPacket;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.UnknownHostException;
import net.sourceforge.jsocks.socks.Proxy;
import net.sourceforge.jsocks.socks.Socks5DatagramSocket;
import net.sourceforge.jsocks.socks.Socks5Proxy;
import net.sourceforge.jsocks.socks.SocksServerSocket;
import net.sourceforge.jsocks.socks.SocksSocket;
public class SocksEcho
implements
Runnable
{
//Network related members
Proxy proxy=null;
int port;
String host;
Thread net_thread=null;
InputStream in=null;
OutputStream out=null;
Socket sock=null;
ServerSocket server_sock = null;
Socks5DatagramSocket udp_sock;
Object net_lock = new Object();
int mode=COMMAND_MODE;
//Possible mode states.
static final int LISTEN_MODE = 0;
static final int CONNECT_MODE = 1;
static final int UDP_MODE = 2;
static final int COMMAND_MODE = 3;
static final int ABORT_MODE = 4;
//Maximum datagram size
static final int MAX_DATAGRAM_SIZE = 1024;
// Constructors
////////////////////////////////////
public SocksEcho(){
}
//Runnable interface
///////////////////////////////
public void run(){
boolean finished_OK = true;
try{
switch(mode){
case UDP_MODE:
startUDP();
doUDPPipe();
break;
case LISTEN_MODE:
doAccept();
doPipe();
break;
case CONNECT_MODE:
doConnect();
doPipe();
break;
default:
warn("Unexpected mode in run() method");
}
}catch(UnknownHostException uh_ex){
if(mode != ABORT_MODE){
finished_OK = false;
status("Host "+host+" has no DNS entry.");
uh_ex.printStackTrace();
}
}catch(IOException io_ex){
if(mode != ABORT_MODE){
finished_OK = false;
status(""+io_ex);
io_ex.printStackTrace();
}
}finally{
if(mode == ABORT_MODE) status("Connection closed");
else if(finished_OK) status("Connection closed by foreign host.");
onDisconnect();
}
}
//Private methods
////////////////////////////////////////////////////////////////////////
// GUI event handlers.
//////////////////////////
private void onConnect(){
if(mode == CONNECT_MODE){
status("Diconnecting...");
abort_connection();
return;
}else if(mode != COMMAND_MODE)
return;
// if(!readHost()) return;
// if(!readPort()) return;
if(proxy == null){
warn("Proxy is not set");
onProxy();
return;
}
startNetThread(CONNECT_MODE);
status("Connecting to "+host+":"+port+" ...");
}
private void onDisconnect(){
synchronized(net_lock){
mode = COMMAND_MODE;
server_sock = null;
sock = null;
out = null;
in = null;
net_thread = null;
}
}
private void onAccept(){
if(mode == LISTEN_MODE){
abort_connection();
return;
}else if(mode != COMMAND_MODE) return;
// if(!readHost()) return;
// if(!readPort()) port = 0;
if(proxy == null){
warn("Proxy is not set");
onProxy();
return;
}
startNetThread(LISTEN_MODE);
}
private void onUDP(){
if(mode == UDP_MODE){
abort_connection();
return;
}else if(mode == ABORT_MODE) return;
if(proxy == null){
warn("Proxy is not set");
onProxy();
return;
}
startNetThread(UDP_MODE);
}
private void onInput(){
String send_string = "";
switch(mode){
case ABORT_MODE: //Fall through
case COMMAND_MODE:
return;
case CONNECT_MODE://Fall through
case LISTEN_MODE:
synchronized(net_lock){
if(out == null) return;
send(send_string);
}
break;
case UDP_MODE:
// if(!readHost()) return;
// if(!readPort()) return;
sendUDP(send_string,host,port);
break;
default:
print("Unknown mode in onInput():"+mode);
}
print(send_string);
}
private void onClear(){
}
private void onProxy(){
Proxy p;
p = null;//socks_dialog.getProxy(proxy);
if(p != null) proxy = p;
if( proxy != null && proxy instanceof Socks5Proxy)
((Socks5Proxy) proxy).resolveAddrLocally(false);
}
private void onQuit(){
System.exit(0);
}
//Data retrieval functions
//////////////////////////
/**
* Reads the port field, returns false if parsing fails.
*/
private boolean readPort(int newPort){
try{
port = newPort;
}catch(NumberFormatException nfe){
warn("Port invalid!");
return false;
}
return true;
}
private boolean readHost(){
host = "";
host.trim();
if(host.length() < 1){
warn("Host is not set");
return false;
}
return true;
}
//Display functions
///////////////////
private void status(String status){
}
private void println(String s){
}
private void print(String s){
}
private void warn(String s){
status(s);
//System.err.println(s);
}
//Network related functions
////////////////////////////
private void startNetThread(int m){
mode = m;
net_thread = new Thread(this);
net_thread.start();
}
private void abort_connection(){
synchronized(net_lock){
if(mode == COMMAND_MODE) return;
mode = ABORT_MODE;
if(net_thread!=null){
try{
if(sock!=null) sock.close();
if(server_sock!=null) server_sock.close();
if(udp_sock!=null) udp_sock.close();
}catch(IOException ioe){
}
net_thread.interrupt();
net_thread = null;
}
}
}
private void doAccept() throws IOException{
println("Trying to accept from "+host);
status("Trying to accept from "+host);
println("Using proxy:"+proxy);
server_sock = new SocksServerSocket(proxy,host,port);
//server_sock.setSoTimeout(30000);
println("Listenning on: "+server_sock.getInetAddress()+
":" +server_sock.getLocalPort());
sock = server_sock.accept();
println("Accepted from:"+sock.getInetAddress()+":"+
sock.getPort());
status("Accepted from:"+sock.getInetAddress().getHostAddress()
+":"+sock.getPort());
server_sock.close(); //Even though this doesn't do anything
}
private void doConnect() throws IOException{
println("Trying to connect to:"+host+":"+port);
println("Using proxy:"+proxy);
sock = new SocksSocket(proxy,host,port);
println("Connected to:"+sock.getInetAddress()+":"+port);
status("Connected to: "+sock.getInetAddress().getHostAddress()
+":" +port);
println("Via-Proxy:"+sock.getLocalAddress()+":"+
sock.getLocalPort());
}
private void doPipe() throws IOException{
out = sock.getOutputStream();
in = sock.getInputStream();
byte[] buf = new byte[1024];
int bytes_read;
while((bytes_read = in.read(buf)) > 0){
print(new String(buf,0,bytes_read));
}
}
private void startUDP() throws IOException{
udp_sock = new Socks5DatagramSocket(proxy,0,null);
println("UDP started on "+udp_sock.getLocalAddress()+":"+
udp_sock.getLocalPort());
status("UDP:"+udp_sock.getLocalAddress().getHostAddress()+":"
+udp_sock.getLocalPort());
}
private void doUDPPipe() throws IOException{
DatagramPacket dp = new DatagramPacket(new byte[MAX_DATAGRAM_SIZE],
MAX_DATAGRAM_SIZE);
while(true){
udp_sock.receive(dp);
print("UDP\n"+
"From:"+dp.getAddress()+":"+dp.getPort()+"\n"+
"\n"+
//Java 1.2
//new String(dp.getData(),dp.getOffset(),dp.getLength())+"\n"
//Java 1.1
new String(dp.getData(),0,dp.getLength())+"\n"
);
dp.setLength(MAX_DATAGRAM_SIZE);
}
}
private void sendUDP(String message,String host,int port){
if(!udp_sock.isProxyAlive(100)){
status("Proxy closed connection");
abort_connection();
return;
}
try{
byte[] data = message.getBytes();
DatagramPacket dp = new DatagramPacket(data,data.length,null,port);
udp_sock.send(dp,host);
}catch(UnknownHostException uhe){
status("Host "+host+" has no DNS entry.");
}catch(IOException ioe){
status("IOException:"+ioe);
abort_connection();
}
}
private void send(String s){
try{
out.write(s.getBytes());
}catch(IOException io_ex){
println("IOException:"+io_ex);
abort_connection();
}
}
// Main
////////////////////////////////////
public static void main(String[] args){
SocksEcho socksecho = new SocksEcho();
}
}//end class

Binary file not shown.

View File

@ -0,0 +1,19 @@
package net.sourceforge.jsocks;
public class SocksServerException extends Exception {
String message;
public SocksServerException(Exception e) {
this.message = e.getMessage();
}
public SocksServerException(String message) {
this.message = message;
}
@Override
public String getMessage() {
return message;
}
}

View File

@ -0,0 +1,15 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<meta http-equiv="Cache-Control" content="no-cache" />
<meta http-equiv="Pragma" content="no-cache" />
<title>Moma</title>
<link href='include_homepage/styles/display_v4.css'
type='text/css' rel='stylesheet'></link>
<link href='include_homepage/styles/themes/bright2.css' type='text/css' rel='stylesheet' /> <style type='text/css'>
</style>
<script type="text/javascript"
src="include_homepage/scripts/common_v2.js"></script>
<

View File

@ -0,0 +1,34 @@
package net.sourceforge.jsocks.socks;
/**
The Authentication interface provides for performing method specific
authentication for SOCKS5 connections.
*/
public interface Authentication{
/**
This method is called when SOCKS5 server have selected a particular
authentication method, for whch an implementaion have been registered.
<p>
This method should return an array {inputstream,outputstream
[,UDPEncapsulation]}. The reason for that is that SOCKS5 protocol
allows to have method specific encapsulation of data on the socket for
purposes of integrity or security. And this encapsulation should be
performed by those streams returned from the method. It is also possible
to encapsulate datagrams. If authentication method supports such
encapsulation an instance of the UDPEncapsulation interface should be
returned as third element of the array, otherwise either null should be
returned as third element, or array should contain only 2 elements.
@param methodId Authentication method selected by the server.
@param proxySocket Socket used to conect to the proxy.
@return Two or three element array containing
Input/Output streams which should be used on this connection.
Third argument is optional and should contain an instance
of UDPEncapsulation. It should be provided if the authentication
method used requires any encapsulation to be done on the
datagrams.
*/
Object[] doSocksAuthentication(int methodId,java.net.Socket proxySocket)
throws java.io.IOException;
}

View File

@ -0,0 +1,92 @@
/*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
package net.sourceforge.jsocks.socks;
/**
* Exception thrown by various socks classes to indicate errors
* with protocol or unsuccessful server responses.
*
* @author rayc@google.com (Ray Colline)
*/
public class AuthenticationException extends Throwable {
private AuthErrorType errorType;
private String errorString;
/**
* Create an AuthenticationException with the specified type
*
* @param errorType an enum denoting what kind of auth error.
*/
public AuthenticationException(AuthErrorType errorType) {
this.errorType = errorType;
this.errorString = errorType.toString();
}
/**
* Create an AuthenticationException with both the specified type and
* a free-form message
*
* @param errorType an enum denoting what kind of auth error.
* @param errorString a specific string detailing the error.
*/
public AuthenticationException(AuthErrorType errorType,
String errorString) {
this.errorType = errorType;
this.errorString = errorString;
}
/**
* Get the error type associated with this exception.
*
* @return errorType the type associated with this exception.
*/
public AuthErrorType getErrorType() {
return errorType;
}
/**
* Get human readable representation of this exception.
*
* @return String representation of this exception.
*/
@Override
public String toString() {
return errorString;
}
/**
* Returns the message associated with this exception
*
* @return String the error string.
*/
@Override
public String getMessage() {
return errorString;
}
/**
* List of Authentication error types.
*
* @author rayc@google.com (Ray Colline)
*/
public enum AuthErrorType {
MALFORMED_REQUEST,
PASSWORD_TOO_LONG;
}
}

View File

@ -0,0 +1,17 @@
package net.sourceforge.jsocks.socks;
/**
SOCKS5 none authentication. Dummy class does almost nothing.
*/
public class AuthenticationNone implements Authentication{
public Object[] doSocksAuthentication(int methodId,
java.net.Socket proxySocket)
throws java.io.IOException{
if(methodId!=0) return null;
return new Object[] { proxySocket.getInputStream(),
proxySocket.getOutputStream()};
}
}

View File

@ -0,0 +1,442 @@
package net.sourceforge.jsocks.socks;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.*;
/**
* Class InetRange provides the means of defining the range of inetaddresses.
* It's used by Proxy class to store and look up addresses of machines, that
* should be contacted directly rather then through the proxy.
* <P>
* InetRange provides several methods to add either standalone addresses, or
* ranges (e.g. 100.200.300.0:100.200.300.255, which covers all addresses
* on on someones local network). It also provides methods for checking wether
* given address is in this range. Any number of ranges and standalone
* addresses can be added to the range.
*/
public class InetRange implements Cloneable{
Hashtable host_names;
Vector all;
Vector end_names;
boolean useSeparateThread = true;
/**
* Creates the empty range.
*/
public InetRange(){
all = new Vector();
host_names = new Hashtable();
end_names = new Vector();
}
/**
* Adds another host or range to this range.
The String can be one of those:
<UL>
<li> Host name. eg.(Athena.myhost.com or 45.54.56.65)
<li> Range in the form .myhost.net.au <BR>
In which case anything that ends with .myhost.net.au will
be considered in the range.
<li> Range in the form ddd.ddd.ddd. <BR>
This will be treated as range ddd.ddd.ddd.0 to ddd.ddd.ddd.255.
It is not necessary to specify 3 first bytes you can use just
one or two. For example 130. will cover address between 130.0.0.0
and 13.255.255.255.
<li> Range in the form host_from[: \t\n\r\f]host_to. <br>
That is two hostnames or ips separated by either whitespace
or colon.
</UL>
*/
public synchronized boolean add(String s){
if(s == null) return false;
s = s.trim();
if(s.length() == 0) return false;
Object[] entry;
if(s.charAt(s.length()-1) == '.'){
//thing like: 111.222.33.
//it is being treated as range 111.222.33.000 - 111.222.33.255
int[] addr = ip2intarray(s);
long from,to;
from = to = 0;
if(addr == null) return false;
for(int i = 0; i< 4;++i){
if(addr[i]>=0)
from += (((long)addr[i]) << 8*(3-i));
else{
to = from;
while(i<4)
to += 255l << 8*(3-i++);
break;
}
}
entry = new Object[] {s,null,new Long(from),new Long(to)};
all.addElement(entry);
}else if(s.charAt(0) == '.'){
//Thing like: .myhost.com
end_names.addElement(s);
all.addElement(new Object[]{s,null,null,null});
}else{
StringTokenizer tokens = new StringTokenizer(s," \t\r\n\f:");
if(tokens.countTokens() > 1){
entry = new Object[] {s,null,null,null};
resolve(entry,tokens.nextToken(),tokens.nextToken());
all.addElement(entry);
}else{
entry = new Object[] {s,null,null,null};
all.addElement(entry);
host_names.put(s,entry);
resolve(entry);
}
}
return true;
}
/**
* Adds another ip for this range.
@param ip IP os the host which should be added to this range.
*/
public synchronized void add(InetAddress ip){
long from, to;
from = to = ip2long(ip);
all.addElement(new Object[]{ip.getHostName(),ip,new Long(from),
new Long(to)});
}
/**
* Adds another range of ips for this range.Any host with ip address
greater than or equal to the address of from and smaller than or equal
to the address of to will be included in the range.
@param from IP from where range starts(including).
@param to IP where range ends(including).
*/
public synchronized void add(InetAddress from,InetAddress to){
all.addElement(new Object[]{from.getHostAddress()+":"+to.getHostAddress()
,null,new Long(ip2long(from)),
new Long(ip2long(to))});
}
/**
* Checks wether the givan host is in the range. Attempts to resolve
host name if required.
@param host Host name to check.
@return true If host is in the range, false otherwise.
* @see InetRange#contains(String,boolean)
*/
public synchronized boolean contains(String host){
return contains(host,true);
}
/**
* Checks wether the given host is in the range.
* <P>
* Algorithm: <BR>
* <ol>
* <li>Look up if the hostname is in the range (in the Hashtable).
* <li>Check if it ends with one of the speciefied endings.
* <li>Check if it is ip(eg.130.220.35.98). If it is check if it is
* in the range.
* <li>If attemptResolve is true, host is name, rather than ip, and
* all previous attempts failed, try to resolve the hostname, and
* check wether the ip associated with the host is in the range.It
* also repeats all previos steps with the hostname obtained from
* InetAddress, but the name is not allways the full name,it is
* quite likely to be the same. Well it was on my machine.
* </ol>
@param host Host name to check.
@param attemptResolve Wether to lookup ip address which corresponds
to the host,if required.
@return true If host is in the range, false otherwise.
*/
public synchronized boolean contains(String host,boolean attemptResolve){
if(all.size() ==0) return false; //Empty range
host = host.trim();
if(host.length() == 0) return false;
if(checkHost(host)) return true;
if(checkHostEnding(host)) return true;
long l = host2long(host);
if(l >=0) return contains(l);
if(!attemptResolve) return false;
try{
InetAddress ip = InetAddress.getByName(host);
return contains(ip);
}catch(UnknownHostException uhe){
}
return false;
}
/**
* Checks wether the given ip is in the range.
@param ip Address of the host to check.
@return true If host is in the range, false otherwise.
*/
public synchronized boolean contains(InetAddress ip){
if(checkHostEnding(ip.getHostName())) return true;
if(checkHost(ip.getHostName())) return true;
return contains(ip2long(ip));
}
/**
Get all entries in the range as strings. <BR>
These strings can be used to delete entries from the range
with remove function.
@return Array of entries as strings.
@see InetRange#remove(String)
*/
public synchronized String[] getAll(){
int size = all.size();
Object entry[];
String all_names[] = new String[size];
for(int i=0;i<size;++i){
entry = (Object[]) all.elementAt(i);
all_names[i] = (String) entry[0];
}
return all_names;
}
/**
Removes an entry from this range.<BR>
@param s Entry to remove.
@return true if successfull.
*/
public synchronized boolean remove(String s){
Iterator iterator = all.iterator();
while(iterator.hasNext()){
Object[] entry = (Object[]) iterator.next();
if(s.equals(entry[0])){
all.removeElement(entry);
end_names.removeElement(s);
host_names.remove(s);
return true;
}
}
return false;
}
/** Get string representaion of this Range.*/
public String toString(){
String all[] = getAll();
if(all.length == 0) return "";
String s = all[0];
for(int i=1;i<all.length;++i)
s += "; "+all[i];
return s;
}
/** Creates a clone of this Object*/
public Object clone(){
InetRange new_range = new InetRange();
new_range.all = (Vector)all.clone();
new_range.end_names = (Vector) end_names.clone();
new_range.host_names = (Hashtable)host_names.clone();
return new_range;
}
//Private methods
/////////////////
/**
* Same as previous but used internally, to avoid
* unnecessary convertion of IPs, when checking subranges
*/
private synchronized boolean contains(long ip){
Iterator iterator = all.iterator();
while(iterator.hasNext()){
Object[] obj = (Object[]) iterator.next();
Long from = obj[2]==null?null:(Long)obj[2];
Long to = obj[3]==null?null:(Long)obj[3];
if(from != null && from.longValue()<= ip
&& to.longValue() >= ip) return true;
}
return false;
}
private boolean checkHost(String host){
return host_names.containsKey(host);
}
private boolean checkHostEnding(String host){
Iterator iterator = end_names.iterator();
while(iterator.hasNext()){
if(host.endsWith((String) iterator.next())) return true;
}
return false;
}
private void resolve(Object[] entry){
//First check if it's in the form ddd.ddd.ddd.ddd.
long ip = host2long((String) entry[0]);
if(ip >= 0){
entry[2] = entry[3] = new Long(ip);
}else{
InetRangeResolver res = new InetRangeResolver(entry);
res.resolve(useSeparateThread);
}
}
private void resolve(Object[] entry,String from,String to){
long f,t;
if((f=host2long(from))>= 0 && (t=host2long(to)) >= 0){
entry[2] = new Long(f);
entry[3] = new Long(t);
}else{
InetRangeResolver res = new InetRangeResolver(entry,from,to);
res.resolve(useSeparateThread);
}
}
//Class methods
///////////////
//Converts ipv4 to long value(unsigned int)
///////////////////////////////////////////
static long ip2long(InetAddress ip){
long l=0;
byte[] addr = ip.getAddress();
if(addr.length ==4){ //IPV4
for(int i=0;i<4;++i)
l += (((long)addr[i] &0xFF) << 8*(3-i));
}else{ //IPV6
return 0; //Have no idea how to deal with those
}
return l;
}
long host2long(String host){
long ip=0;
//check if it's ddd.ddd.ddd.ddd
if(!Character.isDigit(host.charAt(0))) return -1;
int[] addr = ip2intarray(host);
if(addr == null) return -1;
for(int i=0;i<addr.length;++i)
ip += ((long)(addr[i]>=0 ? addr[i] : 0)) << 8*(3-i);
return ip;
}
static int[] ip2intarray(String host){
int[] address = {-1,-1,-1,-1};
int i=0;
StringTokenizer tokens = new StringTokenizer(host,".");
if(tokens.countTokens() > 4) return null;
while(tokens.hasMoreTokens()){
try{
address[i++] = Integer.parseInt(tokens.nextToken()) & 0xFF;
}catch(NumberFormatException nfe){
return null;
}
}
return address;
}
/*
//* This was the test main function
//**********************************
public static void main(String args[])throws UnknownHostException{
int i;
InetRange ir = new InetRange();
for(i=0;i<args.length;++i){
System.out.println("Adding:" + args[i]);
ir.add(args[i]);
}
String host;
java.io.DataInputStream din = new java.io.DataInputStream(System.in);
try{
host = din.readLine();
while(host!=null){
if(ir.contains(host)){
System.out.println("Range contains ip:"+host);
}else{
System.out.println(host+" is not in the range");
}
host = din.readLine();
}
}catch(java.io.IOException io_ex){
io_ex.printStackTrace();
}
}
********************/
}
class InetRangeResolver implements Runnable{
Object[] entry;
String from, to;
InetRangeResolver(Object[] entry){
this.entry = entry;
from = to = null;
}
InetRangeResolver(Object[] entry,String from,String to){
this.entry = entry;
this.from = from;
this.to = to;
}
public final void resolve(){
resolve(true);
}
public final void resolve(boolean inSeparateThread){
if(inSeparateThread){
Thread t = new Thread(this);
t.start();
}else
run();
}
public void run(){
try{
if(from == null){
InetAddress ip = InetAddress.getByName((String) entry[0]);
entry[1] = ip;
Long l = new Long(InetRange.ip2long(ip));
entry[2] = entry[3] = l;
}else{
InetAddress f = InetAddress.getByName(from);
InetAddress t = InetAddress.getByName(to);
entry[2] = new Long(InetRange.ip2long(f));
entry[3] = new Long(InetRange.ip2long(t));
}
}catch(UnknownHostException uhe){
//System.err.println("Resolve failed for "+from+','+to+','+entry[0]);
}
}
}

View File

@ -0,0 +1,491 @@
package net.sourceforge.jsocks.socks;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import java.io.*;
import net.*;
/**
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 Proxy{
//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 Proxy chainProxy = null;
//Protected static/class variables
protected static Proxy defaultProxy = null;
//Constructors
//====================
Proxy(Proxy chainProxy,
String proxyHost,int proxyPort)throws UnknownHostException{
this.chainProxy = chainProxy;
this.proxyHost = proxyHost;
if(chainProxy == null)
this.proxyIP = InetAddress.getByName(proxyHost);
this.proxyPort = proxyPort;
}
Proxy(String proxyHost,int proxyPort)throws UnknownHostException{
this(null,proxyHost,proxyPort);
}
Proxy(Proxy chainProxy,InetAddress proxyIP,int proxyPort){
this.chainProxy = chainProxy;
this.proxyIP = proxyIP;
this.proxyPort = proxyPort;
}
Proxy(InetAddress proxyIP,int proxyPort){
this(null,proxyIP,proxyPort);
}
Proxy(Proxy 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(Proxy 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 Proxy 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(Proxy p){
defaultProxy = p;
}
/**
Get current default proxy.
* @return Current default proxy, or null if none is set.
*/
public static Proxy getDefaultProxy(){
return defaultProxy;
}
/**
Parses strings in the form: host[:port:user:password], and creates
proxy from information obtained from parsing.
<p>
Defaults: port = 1080.<br>
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 Proxy parseProxy(String proxy_entry){
String proxy_host;
int proxy_port = 1080;
String proxy_user = null;
String proxy_password = null;
Proxy proxy;
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(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);
UserPasswordAuthentication upa = new UserPasswordAuthentication(
proxy_user, proxy_password);
((Socks5Proxy)proxy).setAuthenticationMethod(upa.METHOD_ID,upa);
}
}catch(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(SocksException se){
throw se;
}catch(IOException io_ex){
throw new SocksException(SOCKS_PROXY_IO_ERROR,""+io_ex);
}
}
protected abstract Proxy 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();
ProxyMessage request = formMessage(SOCKS_CMD_CONNECT,
ip,port);
return exchange(request);
}catch(SocksException se){
endSession();
throw se;
}
}
protected ProxyMessage connect(String host,int port)
throws UnknownHostException,SocksException{
try{
startSession();
ProxyMessage request = formMessage(SOCKS_CMD_CONNECT,
host,port);
return exchange(request);
}catch(SocksException se){
endSession();
throw se;
}
}
protected ProxyMessage bind(InetAddress ip,int port)
throws SocksException{
try{
startSession();
ProxyMessage request = formMessage(SOCKS_CMD_BIND,
ip,port);
return exchange(request);
}catch(SocksException se){
endSession();
throw se;
}
}
protected ProxyMessage bind(String host,int port)
throws UnknownHostException,SocksException{
try{
startSession();
ProxyMessage request = formMessage(SOCKS_CMD_BIND,
host,port);
return exchange(request);
}catch(SocksException se){
endSession();
throw se;
}
}
protected ProxyMessage accept()
throws IOException,SocksException{
ProxyMessage msg;
try{
msg = formMessage(in);
}catch(InterruptedIOException iioe){
throw iioe;
}catch(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();
ProxyMessage request = formMessage(SOCKS_CMD_UDP_ASSOCIATE,
ip,port);
if(request != null)
return exchange(request);
}catch(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();
ProxyMessage request = formMessage(SOCKS_CMD_UDP_ASSOCIATE,
host,port);
if(request != null) return exchange(request);
}catch(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(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(SocksException s_ex){
throw s_ex;
}catch(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_NOT_ALLOWED_BY_RULESET =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;
}

View File

@ -0,0 +1,119 @@
package net.sourceforge.jsocks.socks;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.DataInputStream;
import java.net.InetAddress;
import java.net.UnknownHostException;
/**
Abstract class which describes SOCKS4/5 response/request.
*/
public abstract class ProxyMessage{
/** Host as an IP address */
public InetAddress ip=null;
/** SOCKS version, or version of the response for SOCKS4*/
public int version;
/** Port field of the request/response*/
public int port;
/** Request/response code as an int*/
public int command;
/** Host as string.*/
public String host=null;
/** User field for SOCKS4 request messages*/
public String user=null;
/** Connection ID */
private String connectionId = "N/A";
ProxyMessage(int command,InetAddress ip,int port){
this.command = command;
this.ip = ip;
this.port = port;
}
ProxyMessage(){
}
/**
Initialises Message from the stream. Reads server response from
given stream.
@param in Input stream to read response from.
@throws SocksException If server response code is not SOCKS_SUCCESS(0), or
if any error with protocol occurs.
@throws IOException If any error happens with I/O.
*/
public abstract void read(InputStream in)
throws SocksException,
IOException;
/**
Initialises Message from the stream. Reads server response or client
request from given stream.
@param in Input stream to read response from.
@param clinetMode If true read server response, else read client request.
@throws SocksException If server response code is not SOCKS_SUCCESS(0) and
reading in client mode, or if any error with protocol occurs.
@throws IOException If any error happens with I/O.
*/
public abstract void read(InputStream in,boolean client_mode)
throws SocksException,
IOException;
/**
Writes the message to the stream.
@param out Output stream to which message should be written.
*/
public abstract void write(OutputStream out)throws SocksException,
IOException;
/**
Get the Address field of this message as InetAddress object.
@return Host address or null, if one can't be determined.
*/
public InetAddress getInetAddress() throws UnknownHostException{
return ip;
}
/**
Get string representaion of this message.
@return string representation of this message.
*/
public String toString(){
return
"Proxy Message:\n"+
"Version:"+ version+"\n"+
"Command:"+ command+"\n"+
"IP: "+ ip+"\n"+
"Port: "+ port+"\n"+
"User: "+ user+"\n" ;
}
public String getConnectionId() {
return connectionId;
}
public void setConnectionId(String connectionId) {
this.connectionId = connectionId;
}
//Package methods
//////////////////
static final String bytes2IPV4(byte[] addr,int offset){
String hostName = ""+(addr[offset] & 0xFF);
for(int i = offset+1;i<offset+4;++i)
hostName+="."+(addr[i] & 0xFF);
return hostName;
}
static final String bytes2IPV6(byte[] addr,int offset){
//Have no idea how they look like!
return null;
}
}

View File

@ -0,0 +1,569 @@
package net.sourceforge.jsocks.socks;
import net.*;
import net.sourceforge.jsocks.socks.server.ServerAuthenticator;
import java.net.ConnectException;
import java.net.InetAddress;
import java.net.NoRouteToHostException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Random;
import java.io.*;
/**
SOCKS4 and SOCKS5 proxy, handles both protocols simultaniously.
Implements all SOCKS commands, including UDP relaying.
<p>
In order to use it you will need to implement ServerAuthenticator
interface. There is an implementation of this interface which does
no authentication ServerAuthenticatorNone, but it is very dangerous
to use, as it will give access to your local network to anybody
in the world. One should never use this authentication scheme unless
one have pretty good reason to do so.
There is a couple of other authentication schemes in socks.server package.
@see socks.server.ServerAuthenticator
*/
public class ProxyServer implements Runnable{
ServerAuthenticator auth;
ProxyMessage msg = null;
Socket sock=null,remote_sock=null;
ServerSocket ss=null;
UDPRelayServer relayServer = null;
InputStream in,remote_in;
OutputStream out,remote_out;
int mode;
static final int START_MODE = 0;
static final int ACCEPT_MODE = 1;
static final int PIPE_MODE = 2;
static final int ABORT_MODE = 3;
static final int BUF_SIZE = 8192;
Thread pipe_thread1,pipe_thread2;
long lastReadTime;
static int iddleTimeout = 180000; //3 minutes
static int acceptTimeout = 180000; //3 minutes
static Proxy proxy;
private String connectionId;
//Public Constructors
/////////////////////
/**
Creates a proxy server with given Authentication scheme.
@param auth Authentication scheme to be used.
*/
public ProxyServer(ServerAuthenticator auth){
this.auth = auth;
this.connectionId = newConnectionId();
}
//Other constructors
////////////////////
ProxyServer(ServerAuthenticator auth,Socket s, String connectionId){
this.auth = auth;
this.sock = s;
this.connectionId = connectionId;
mode = START_MODE;
}
//Public methods
/////////////////
/**
Set proxy.
<p>
Allows Proxy chaining so that one Proxy server is connected to another
and so on. If proxy supports SOCKSv4, then only some SOCKSv5 requests
can be handled, UDP would not work, however CONNECT and BIND will be
translated.
@param p Proxy which should be used to handle user requests.
*/
public static void setProxy(Proxy p){
proxy =p;
UDPRelayServer.proxy = proxy;
}
/**
Get proxy.
@return Proxy wich is used to handle user requests.
*/
public static Proxy getProxy(){
return proxy;
}
/**
Sets the timeout for connections, how long shoud server wait
for data to arrive before dropping the connection.<br>
Zero timeout implies infinity.<br>
Default timeout is 3 minutes.
*/
public static void setIddleTimeout(int timeout){
iddleTimeout = timeout;
}
/**
Sets the timeout for BIND command, how long the server should
wait for the incoming connection.<br>
Zero timeout implies infinity.<br>
Default timeout is 3 minutes.
*/
public static void setAcceptTimeout(int timeout){
acceptTimeout = timeout;
}
/**
Sets the timeout for UDPRelay server.<br>
Zero timeout implies infinity.<br>
Default timeout is 3 minutes.
*/
public static void setUDPTimeout(int timeout){
UDPRelayServer.setTimeout(timeout);
}
/**
Sets the size of the datagrams used in the UDPRelayServer.<br>
Default size is 64K, a bit more than maximum possible size of the
datagram.
*/
public static void setDatagramSize(int size){
UDPRelayServer.setDatagramSize(size);
}
/**
Start the Proxy server at given port.<br>
This methods blocks.
*/
public void start(int port){
start(port,5,null);
}
/**
Create a server with the specified port, listen backlog, and local
IP address to bind to. The localIP argument can be used on a multi-homed
host for a ServerSocket that will only accept connect requests to one of
its addresses. If localIP is null, it will default accepting connections
on any/all local addresses. The port must be between 0 and 65535,
inclusive. <br>
This methods blocks.
*/
public void start(int port,int backlog,InetAddress localIP){
try{
ss = new ServerSocket(port,backlog,localIP);
while(true){
Socket s = ss.accept();
String connectionId = newConnectionId();
ProxyServer ps = new ProxyServer(auth,s, connectionId);
(new Thread(ps)).start();
}
}catch(IOException ioe){
ioe.printStackTrace();
}
}
/**
* Creates new unique ID for this connection.
*
* @return a random-enough ID.
*/
private String newConnectionId() {
// return "[" + RandomStringUtils.randomAlphanumeric(4) + "]";
return "[" + Math.random()*new java.util.Date().getTime() + "]";
}
/**
Stop server operation.It would be wise to interrupt thread running the
server afterwards.
*/
public void stop(){
try{
if(ss != null) ss.close();
}catch(IOException ioe){
}
}
//Runnable interface
////////////////////
public void run(){
switch(mode){
case START_MODE:
try{
startSession();
}catch(IOException ioe){
handleException(ioe);
ioe.printStackTrace();
}finally{
abort();
if(auth!=null) auth.endSession();
}
break;
case ACCEPT_MODE:
try{
doAccept();
mode = PIPE_MODE;
pipe_thread1.interrupt(); //Tell other thread that connection have
//been accepted.
pipe(remote_in,out);
}catch(IOException ioe){
//log("Accept exception:"+ioe);
handleException(ioe);
}finally{
abort();
}
break;
case PIPE_MODE:
try{
pipe(remote_in,out);
}catch(IOException ioe){
}finally{
abort();
}
break;
case ABORT_MODE:
break;
default:
}
}
//Private methods
/////////////////
private void startSession() throws IOException{
sock.setSoTimeout(iddleTimeout);
try{
auth = auth.startSession(sock);
}catch(IOException ioe){
auth = null;
return;
}
if(auth == null){ //Authentication failed
return;
}
in = auth.getInputStream();
out = auth.getOutputStream();
msg = readMsg(in);
// Set the connection ID in the message.
msg.setConnectionId(connectionId);
handleRequest(msg);
}
private void handleRequest(ProxyMessage msg)
throws IOException{
if(!auth.checkRequest(msg)) {
ProxyMessage response = new Socks5Message(
Proxy.SOCKS_NOT_ALLOWED_BY_RULESET);
response.write(out);
abort();
throw new SocksException(Proxy.SOCKS_NOT_ALLOWED_BY_RULESET);
}
if(msg.ip == null){
if(msg instanceof Socks5Message){
msg.ip = InetAddress.getByName(msg.host);
}else
throw new SocksException(Proxy.SOCKS_FAILURE);
}
switch(msg.command){
case Proxy.SOCKS_CMD_CONNECT:
onConnect(msg);
break;
case Proxy.SOCKS_CMD_BIND:
onBind(msg);
break;
case Proxy.SOCKS_CMD_UDP_ASSOCIATE:
onUDP(msg);
break;
default:
throw new SocksException(Proxy.SOCKS_CMD_NOT_SUPPORTED);
}
}
private void handleException(IOException ioe){
//If we couldn't read the request, return;
if(msg == null) return;
//If have been aborted by other thread
if(mode == ABORT_MODE) return;
//If the request was successfully completed, but exception happened later
if(mode == PIPE_MODE) return;
int error_code = Proxy.SOCKS_FAILURE;
if(ioe instanceof SocksException)
error_code = ((SocksException)ioe).errCode;
else if(ioe instanceof NoRouteToHostException)
error_code = Proxy.SOCKS_HOST_UNREACHABLE;
else if(ioe instanceof ConnectException)
error_code = Proxy.SOCKS_CONNECTION_REFUSED;
else if(ioe instanceof InterruptedIOException)
error_code = Proxy.SOCKS_TTL_EXPIRE;
if(error_code > Proxy.SOCKS_ADDR_NOT_SUPPORTED || error_code < 0){
error_code = Proxy.SOCKS_FAILURE;
}
sendErrorMessage(error_code);
}
private void onConnect(ProxyMessage msg) throws IOException{
Socket s;
ProxyMessage response = null;
if(proxy == null)
s = new Socket(msg.ip,msg.port);
else
s = new SocksSocket(proxy,msg.ip,msg.port);
if(msg instanceof Socks5Message){
response = new Socks5Message(Proxy.SOCKS_SUCCESS,
s.getLocalAddress(),
s.getLocalPort());
}else{
response = new Socks4Message(Socks4Message.REPLY_OK,
s.getLocalAddress(),s.getLocalPort());
}
response.write(out);
startPipe(s);
}
private void onBind(ProxyMessage msg) throws IOException{
ProxyMessage response = null;
if(proxy == null)
ss = new ServerSocket(0);
else
ss = new SocksServerSocket(proxy, msg.ip, msg.port);
ss.setSoTimeout(acceptTimeout);
if(msg.version == 5)
response = new Socks5Message(Proxy.SOCKS_SUCCESS,ss.getInetAddress(),
ss.getLocalPort());
else
response = new Socks4Message(Socks4Message.REPLY_OK,
ss.getInetAddress(),
ss.getLocalPort());
response.write(out);
mode = ACCEPT_MODE;
pipe_thread1 = Thread.currentThread();
pipe_thread2 = new Thread(this);
pipe_thread2.start();
//Make timeout infinit.
sock.setSoTimeout(0);
int eof=0;
try{
while((eof=in.read())>=0){
if(mode != ACCEPT_MODE){
if(mode != PIPE_MODE) return;//Accept failed
remote_out.write(eof);
break;
}
}
}catch(EOFException eofe){
//System.out.println("EOF exception");
return;//Connection closed while we were trying to accept.
}catch(InterruptedIOException iioe){
//Accept thread interrupted us.
//System.out.println("Interrupted");
if(mode != PIPE_MODE)
return;//If accept thread was not successfull return.
}finally{
//System.out.println("Finnaly!");
}
if(eof < 0)//Connection closed while we were trying to accept;
return;
//Do not restore timeout, instead timeout is set on the
//remote socket. It does not make any difference.
pipe(in,remote_out);
}
private void onUDP(ProxyMessage msg) throws IOException{
if(msg.ip.getHostAddress().equals("0.0.0.0"))
msg.ip = sock.getInetAddress();
relayServer = new UDPRelayServer(msg.ip,msg.port,
Thread.currentThread(),sock,auth);
ProxyMessage response;
response = new Socks5Message(Proxy.SOCKS_SUCCESS,
relayServer.relayIP,relayServer.relayPort);
response.write(out);
relayServer.start();
//Make timeout infinit.
sock.setSoTimeout(0);
try{
while(in.read()>=0) /*do nothing*/;
}catch(EOFException eofe){
}
}
//Private methods
//////////////////
private void doAccept() throws IOException{
Socket s;
long startTime = System.currentTimeMillis();
while(true){
s = ss.accept();
if(s.getInetAddress().equals(msg.ip)){
//got the connection from the right host
//Close listenning socket.
ss.close();
break;
}else if(ss instanceof SocksServerSocket){
//We can't accept more then one connection
s.close();
ss.close();
throw new SocksException(Proxy.SOCKS_FAILURE);
}else{
if(acceptTimeout!=0){ //If timeout is not infinit
int newTimeout = acceptTimeout-(int)(System.currentTimeMillis()-
startTime);
if(newTimeout <= 0) throw new InterruptedIOException(
"In doAccept()");
ss.setSoTimeout(newTimeout);
}
s.close(); //Drop all connections from other hosts
}
}
//Accepted connection
remote_sock = s;
remote_in = s.getInputStream();
remote_out = s.getOutputStream();
//Set timeout
remote_sock.setSoTimeout(iddleTimeout);
ProxyMessage response;
if(msg.version == 5)
response = new Socks5Message(Proxy.SOCKS_SUCCESS, s.getInetAddress(),
s.getPort());
else
response = new Socks4Message(Socks4Message.REPLY_OK,
s.getInetAddress(), s.getPort());
response.write(out);
}
private ProxyMessage readMsg(InputStream in) throws IOException{
PushbackInputStream push_in;
if(in instanceof PushbackInputStream)
push_in = (PushbackInputStream) in;
else
push_in = new PushbackInputStream(in);
int version = push_in.read();
push_in.unread(version);
ProxyMessage msg;
if(version == 5){
msg = new Socks5Message(push_in,false);
}else if(version == 4){
msg = new Socks4Message(push_in,false);
}else{
throw new SocksException(Proxy.SOCKS_FAILURE);
}
return msg;
}
private void startPipe(Socket s){
mode = PIPE_MODE;
remote_sock = s;
try{
remote_in = s.getInputStream();
remote_out = s.getOutputStream();
pipe_thread1 = Thread.currentThread();
pipe_thread2 = new Thread(this);
pipe_thread2.start();
pipe(in,remote_out);
}catch(IOException ioe){
}
}
private void sendErrorMessage(int error_code){
ProxyMessage err_msg;
if(msg instanceof Socks4Message)
err_msg = new Socks4Message(Socks4Message.REPLY_REJECTED);
else
err_msg = new Socks5Message(error_code);
try{
err_msg.write(out);
}catch(IOException ioe){}
}
private synchronized void abort(){
if(mode == ABORT_MODE) return;
mode = ABORT_MODE;
try{
if(remote_sock != null) remote_sock.close();
if(sock != null) sock.close();
if(relayServer!=null) relayServer.stop();
if(ss!=null) ss.close();
if(pipe_thread1 != null) pipe_thread1.interrupt();
if(pipe_thread2 != null) pipe_thread2.interrupt();
}catch(IOException ioe){}
}
private void pipe(InputStream in,OutputStream out) throws IOException{
lastReadTime = System.currentTimeMillis();
byte[] buf = new byte[BUF_SIZE];
int len = 0;
while(len >= 0){
try{
if(len!=0){
out.write(buf,0,len);
out.flush();
}
len= in.read(buf);
lastReadTime = System.currentTimeMillis();
}catch(InterruptedIOException iioe){
if(iddleTimeout == 0) return;//Other thread interrupted us.
long timeSinceRead = System.currentTimeMillis() - lastReadTime;
if(timeSinceRead >= iddleTimeout - 1000) //-1s for adjustment.
return;
len = 0;
}
}
}
static final String command_names[] = {"CONNECT","BIND","UDP_ASSOCIATE"};
static final String command2String(int cmd){
if(cmd > 0 && cmd < 4) return command_names[cmd-1];
else return "Unknown Command "+cmd;
}
}

View File

@ -0,0 +1,161 @@
package net.sourceforge.jsocks.socks;
import java.io.*;
import java.net.InetAddress;
import java.net.UnknownHostException;
import net.*;
/**
SOCKS4 Reply/Request message.
*/
class Socks4Message extends ProxyMessage{
private byte[] msgBytes;
private int msgLength;
/**
* Server failed reply, cmd command for failed request
*/
public Socks4Message(int cmd){
super(cmd,null,0);
this.user = null;
msgLength = 2;
msgBytes = new byte[2];
msgBytes[0] = (byte) 0;
msgBytes[1] = (byte) command;
}
/**
* Server successfull reply
*/
public Socks4Message(int cmd,InetAddress ip,int port){
this(0,cmd,ip,port,null);
}
/**
* Client request
*/
public Socks4Message(int cmd,InetAddress ip,int port,String user){
this(SOCKS_VERSION,cmd,ip,port,user);
}
/**
* Most general constructor
*/
public Socks4Message(int version, int cmd,
InetAddress ip,int port,String user){
super(cmd,ip,port);
this.user = user;
this.version = version;
msgLength = user == null?8:9+user.length();
msgBytes = new byte[msgLength];
msgBytes[0] = (byte) version;
msgBytes[1] = (byte) command;
msgBytes[2] = (byte) (port >> 8);
msgBytes[3] = (byte) port;
byte[] addr;
if(ip != null)
addr = ip.getAddress();
else{
addr = new byte[4];
addr[0]=addr[1]=addr[2]=addr[3]=0;
}
System.arraycopy(addr,0,msgBytes,4,4);
if(user != null){
byte[] buf = user.getBytes();
System.arraycopy(buf,0,msgBytes,8,buf.length);
msgBytes[msgBytes.length -1 ] = 0;
}
}
/**
*Initialise from the stream
*If clientMode is true attempts to read a server response
*otherwise reads a client request
*see read for more detail
*/
public Socks4Message(InputStream in, boolean clientMode) throws IOException{
msgBytes = null;
read(in,clientMode);
}
public void read(InputStream in) throws IOException{
read(in,true);
}
public void read(InputStream in, boolean clientMode) throws IOException{
DataInputStream d_in = new DataInputStream(in);
version= d_in.readUnsignedByte();
command = d_in.readUnsignedByte();
if(clientMode && command != REPLY_OK){
String errMsg;
if(command >REPLY_OK && command < REPLY_BAD_IDENTD)
errMsg = replyMessage[command-REPLY_OK];
else
errMsg = "Unknown Reply Code";
throw new SocksException(command,errMsg);
}
port = d_in.readUnsignedShort();
byte[] addr = new byte[4];
d_in.readFully(addr);
ip=bytes2IP(addr);
host = ip.getHostName();
if(!clientMode){
int b = in.read();
//Hope there are no idiots with user name bigger than this
byte[] userBytes = new byte[256];
int i = 0;
for(i =0;i<userBytes.length && b>0;++i){
userBytes[i] = (byte) b;
b = in.read();
}
user = new String(userBytes,0,i);
}
}
public void write(OutputStream out) throws IOException{
if(msgBytes == null){
Socks4Message msg = new Socks4Message(version,command,ip,port,user);
msgBytes = msg.msgBytes;
msgLength = msg.msgLength;
}
out.write(msgBytes);
}
//Class methods
static InetAddress bytes2IP(byte[] addr){
String s = bytes2IPV4(addr,0);
try{
return InetAddress.getByName(s);
}catch(UnknownHostException uh_ex){
return null;
}
}
//Constants
static final String[] replyMessage ={
"Request Granted",
"Request Rejected or Failed",
"Failed request, can't connect to Identd",
"Failed request, bad user name"};
static final int SOCKS_VERSION = 4;
public final static int REQUEST_CONNECT = 1;
public final static int REQUEST_BIND = 2;
public final static int REPLY_OK = 90;
public final static int REPLY_REJECTED = 91;
public final static int REPLY_NO_CONNECT = 92;
public final static int REPLY_BAD_IDENTD = 93;
}

View File

@ -0,0 +1,123 @@
package net.sourceforge.jsocks.socks;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.io.*;
import net.*;
/**
Proxy which describes SOCKS4 proxy.
*/
public class Socks4Proxy extends Proxy implements Cloneable{
//Data members
String user;
//Public Constructors
//====================
/**
Creates the SOCKS4 proxy
@param p Proxy to use to connect to this proxy, allows proxy chaining.
@param proxyHost Address of the proxy server.
@param proxyPort Port of the proxy server
@param user User name to use for identification purposes.
@throws UnknownHostException If proxyHost can't be resolved.
*/
public Socks4Proxy(Proxy p,String proxyHost,int proxyPort,String user)
throws UnknownHostException{
super(p,proxyHost,proxyPort);
this.user = new String(user);
version = 4;
}
/**
Creates the SOCKS4 proxy
@param proxyHost Address of the proxy server.
@param proxyPort Port of the proxy server
@param user User name to use for identification purposes.
@throws UnknownHostException If proxyHost can't be resolved.
*/
public Socks4Proxy(String proxyHost,int proxyPort,String user)
throws UnknownHostException{
this(null,proxyHost,proxyPort,user);
}
/**
Creates the SOCKS4 proxy
@param p Proxy to use to connect to this proxy, allows proxy chaining.
@param proxyIP Address of the proxy server.
@param proxyPort Port of the proxy server
@param user User name to use for identification purposes.
*/
public Socks4Proxy(Proxy p,InetAddress proxyIP,int proxyPort,String user){
super(p,proxyIP,proxyPort);
this.user = new String(user);
version = 4;
}
/**
Creates the SOCKS4 proxy
@param proxyIP Address of the proxy server.
@param proxyPort Port of the proxy server
@param user User name to use for identification purposes.
*/
public Socks4Proxy(InetAddress proxyIP,int proxyPort,String user){
this(null,proxyIP,proxyPort,user);
}
//Public instance methods
//========================
/**
* Creates a clone of this proxy. Changes made to the clone should not
* affect this object.
*/
public Object clone(){
Socks4Proxy newProxy = new Socks4Proxy(proxyIP,proxyPort,user);
newProxy.directHosts = (InetRange)directHosts.clone();
newProxy.chainProxy = chainProxy;
return newProxy;
}
//Public Static(Class) Methods
//==============================
//Protected Methods
//=================
protected Proxy copy(){
Socks4Proxy copy = new Socks4Proxy(proxyIP,proxyPort,user);
copy.directHosts = this.directHosts;
copy.chainProxy = chainProxy;
return copy;
}
protected ProxyMessage formMessage(int cmd,InetAddress ip,int port){
switch(cmd){
case SOCKS_CMD_CONNECT:
cmd = Socks4Message.REQUEST_CONNECT;
break;
case SOCKS_CMD_BIND:
cmd = Socks4Message.REQUEST_BIND;
break;
default:
return null;
}
return new Socks4Message(cmd,ip,port,user);
}
protected ProxyMessage formMessage(int cmd,String host,int port)
throws UnknownHostException{
return formMessage(cmd,InetAddress.getByName(host),port);
}
protected ProxyMessage formMessage(InputStream in)
throws SocksException,
IOException{
return new Socks4Message(in,true);
}
}

View File

@ -0,0 +1,492 @@
package net.sourceforge.jsocks.socks;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.io.*;
import net.*;
/**
Datagram socket to interract through the firewall.<BR>
Can be used same way as the normal DatagramSocket. One should
be carefull though with the datagram sizes used, as additional data
is present in both incomming and outgoing datagrams.
<p>
SOCKS5 protocol allows to send host address as either:
<ul>
<li> IPV4, normal 4 byte address. (10 bytes header size)
<li> IPV6, version 6 ip address (not supported by Java as for now).
22 bytes header size.
<li> Host name,(7+length of the host name bytes header size).
</ul>
As with other Socks equivalents, direct addresses are handled
transparently, that is data will be send directly when required
by the proxy settings.
<p>
<b>NOTE:</b><br>
Unlike other SOCKS Sockets, it <b>does not</b> support proxy chaining,
and will throw an exception if proxy has a chain proxy attached. The
reason for that is not my laziness, but rather the restrictions of
the SOCKSv5 protocol. Basicaly SOCKSv5 proxy server, needs to know from
which host:port datagrams will be send for association, and returns address
to which datagrams should be send by the client, but it does not
inform client from which host:port it is going to send datagrams, in fact
there is even no guarantee they will be send at all and from the same address
each time.
*/
public class Socks5DatagramSocket extends DatagramSocket{
InetAddress relayIP;
int relayPort;
Socks5Proxy proxy;
private boolean server_mode = false;
UDPEncapsulation encapsulation;
/**
Construct Datagram socket for communication over SOCKS5 proxy
server. This constructor uses default proxy, the one set with
Proxy.setDefaultProxy() method. If default proxy is not set or
it is set to version4 proxy, which does not support datagram
forwarding, throws SocksException.
*/
public Socks5DatagramSocket() throws SocksException,
IOException{
this(Proxy.defaultProxy,0,null);
}
/**
Construct Datagram socket for communication over SOCKS5 proxy
server. And binds it to the specified local port.
This constructor uses default proxy, the one set with
Proxy.setDefaultProxy() method. If default proxy is not set or
it is set to version4 proxy, which does not support datagram
forwarding, throws SocksException.
*/
public Socks5DatagramSocket(int port) throws SocksException,
IOException{
this(Proxy.defaultProxy,port,null);
}
/**
Construct Datagram socket for communication over SOCKS5 proxy
server. And binds it to the specified local port and address.
This constructor uses default proxy, the one set with
Proxy.setDefaultProxy() method. If default proxy is not set or
it is set to version4 proxy, which does not support datagram
forwarding, throws SocksException.
*/
public Socks5DatagramSocket(int port,InetAddress ip) throws SocksException,
IOException{
this(Proxy.defaultProxy,port,ip);
}
/**
Constructs datagram socket for communication over specified proxy.
And binds it to the given local address and port. Address of null
and port of 0, signify any availabale port/address.
Might throw SocksException, if:
<ol>
<li> Given version of proxy does not support UDP_ASSOCIATE.
<li> Proxy can't be reached.
<li> Authorization fails.
<li> Proxy does not want to perform udp forwarding, for any reason.
</ol>
Might throw IOException if binding dtagram socket to given address/port
fails.
See java.net.DatagramSocket for more details.
*/
public Socks5DatagramSocket(Proxy p,int port,InetAddress ip)
throws SocksException,
IOException{
super(port,ip);
if(p == null) throw new SocksException(Proxy.SOCKS_NO_PROXY);
if(!(p instanceof Socks5Proxy))
throw new SocksException(-1,"Datagram Socket needs Proxy version 5");
if(p.chainProxy != null)
throw new SocksException(Proxy.SOCKS_JUST_ERROR,
"Datagram Sockets do not support proxy chaining.");
proxy =(Socks5Proxy) p.copy();
ProxyMessage msg = proxy.udpAssociate(super.getLocalAddress(),
super.getLocalPort());
relayIP = msg.ip;
if(relayIP.getHostAddress().equals("0.0.0.0")) relayIP = proxy.proxyIP;
relayPort = msg.port;
encapsulation = proxy.udp_encapsulation;
//debug("Datagram Socket:"+getLocalAddress()+":"+getLocalPort()+"\n");
//debug("Socks5Datagram: "+relayIP+":"+relayPort+"\n");
}
/**
Used by UDPRelayServer.
*/
Socks5DatagramSocket(boolean server_mode,UDPEncapsulation encapsulation,
InetAddress relayIP,int relayPort)
throws IOException{
super();
this.server_mode = server_mode;
this.relayIP = relayIP;
this.relayPort = relayPort;
this.encapsulation = encapsulation;
this.proxy = null;
}
/**
Sends the Datagram either through the proxy or directly depending
on current proxy settings and destination address. <BR>
<B> NOTE: </B> DatagramPacket size should be at least 10 bytes less
than the systems limit.
<P>
See documentation on java.net.DatagramSocket
for full details on how to use this method.
@param dp Datagram to send.
@throws IOException If error happens with I/O.
*/
public void send(DatagramPacket dp) throws IOException{
//If the host should be accessed directly, send it as is.
if(!server_mode && proxy.isDirect(dp.getAddress())){
super.send(dp);
//debug("Sending directly:");
return;
}
byte[] head = formHeader(dp.getAddress(),dp.getPort());
byte[] buf = new byte[head.length + dp.getLength()];
byte[] data = dp.getData();
//Merge head and data
System.arraycopy(head,0,buf,0,head.length);
//System.arraycopy(data,dp.getOffset(),buf,head.length,dp.getLength());
System.arraycopy(data,0,buf,head.length,dp.getLength());
if(encapsulation != null)
buf = encapsulation.udpEncapsulate(buf,true);
super.send(new DatagramPacket(buf,buf.length,relayIP,relayPort));
}
/**
This method allows to send datagram packets with address type DOMAINNAME.
SOCKS5 allows to specify host as names rather than ip addresses.Using
this method one can send udp datagrams through the proxy, without having
to know the ip address of the destination host.
<p>
If proxy specified for that socket has an option resolveAddrLocally set
to true host will be resolved, and the datagram will be send with address
type IPV4, if resolve fails, UnknownHostException is thrown.
@param dp Datagram to send, it should contain valid port and data
@param host Host name to which datagram should be send.
@throws IOException If error happens with I/O, or the host can't be
resolved when proxy settings say that hosts should be resolved locally.
@see Socks5Proxy#resolveAddrLocally(boolean)
*/
public void send(DatagramPacket dp, String host) throws IOException{
if(proxy.isDirect(host)){
dp.setAddress(InetAddress.getByName(host));
super.send(dp);
return;
}
if(((Socks5Proxy)proxy).resolveAddrLocally){
dp.setAddress(InetAddress.getByName(host));
}
byte[] head = formHeader(host,dp.getPort());
byte[] buf = new byte[head.length + dp.getLength()];
byte[] data = dp.getData();
//Merge head and data
System.arraycopy(head,0,buf,0,head.length);
//System.arraycopy(data,dp.getOffset(),buf,head.length,dp.getLength());
System.arraycopy(data,0,buf,head.length,dp.getLength());
if(encapsulation != null)
buf = encapsulation.udpEncapsulate(buf,true);
super.send(new DatagramPacket(buf,buf.length,relayIP,relayPort));
}
/**
* Receives udp packet. If packet have arrived from the proxy relay server,
* it is processed and address and port of the packet are set to the
* address and port of sending host.<BR>
* If the packet arrived from anywhere else it is not changed.<br>
* <B> NOTE: </B> DatagramPacket size should be at least 10 bytes bigger
* than the largest packet you expect (this is for IPV4 addresses).
* For hostnames and IPV6 it is even more.
@param dp Datagram in which all relevent information will be copied.
*/
public void receive(DatagramPacket dp) throws IOException{
super.receive(dp);
if(server_mode){
//Drop all datagrams not from relayIP/relayPort
int init_length = dp.getLength();
int initTimeout = getSoTimeout();
long startTime = System.currentTimeMillis();
while(!relayIP.equals(dp.getAddress()) ||
relayPort != dp.getPort()){
//Restore datagram size
dp.setLength(init_length);
//If there is a non-infinit timeout on this socket
//Make sure that it happens no matter how often unexpected
//packets arrive.
if(initTimeout != 0){
int newTimeout = initTimeout - (int)(System.currentTimeMillis() -
startTime);
if(newTimeout <= 0) throw new InterruptedIOException(
"In Socks5DatagramSocket->receive()");
setSoTimeout(newTimeout);
}
super.receive(dp);
}
//Restore timeout settings
if(initTimeout != 0) setSoTimeout(initTimeout);
}else if(!relayIP.equals(dp.getAddress()) ||
relayPort != dp.getPort())
return; // Recieved direct packet
//If the datagram is not from the relay server, return it it as is.
byte[] data;
data = dp.getData();
if(encapsulation != null)
data = encapsulation.udpEncapsulate(data,false);
int offset = 0; //Java 1.1
//int offset = dp.getOffset(); //Java 1.2
ByteArrayInputStream bIn = new ByteArrayInputStream(data,offset,
dp.getLength());
ProxyMessage msg = new Socks5Message(bIn);
dp.setPort(msg.port);
dp.setAddress(msg.getInetAddress());
//what wasn't read by the Message is the data
int data_length = bIn.available();
//Shift data to the left
System.arraycopy(data,offset+dp.getLength()-data_length,
data,offset,data_length);
dp.setLength(data_length);
}
/**
* Returns port assigned by the proxy, to which datagrams are relayed.
* It is not the same port to which other party should send datagrams.
@return Port assigned by socks server to which datagrams are send
for association.
*/
public int getLocalPort(){
if(server_mode) return super.getLocalPort();
return relayPort;
}
/**
* Address assigned by the proxy, to which datagrams are send for relay.
* It is not necesseraly the same address, to which other party should send
* datagrams.
@return Address to which datagrams are send for association.
*/
public InetAddress getLocalAddress(){
if(server_mode) return super.getLocalAddress();
return relayIP;
}
/**
* Closes datagram socket, and proxy connection.
*/
public void close(){
if(!server_mode) proxy.endSession();
super.close();
}
/**
This method checks wether proxy still runs udp forwarding service
for this socket.
<p>
This methods checks wether the primary connection to proxy server
is active. If it is, chances are that proxy continues to forward
datagrams being send from this socket. If it was closed, most likely
datagrams are no longer being forwarded by the server.
<p>
Proxy might decide to stop forwarding datagrams, in which case it
should close primary connection. This method allows to check, wether
this have been done.
<p>
You can specify timeout for which we should be checking EOF condition
on the primary connection. Timeout is in milliseconds. Specifying 0 as
timeout implies infinity, in which case method will block, until
connection to proxy is closed or an error happens, and then return false.
<p>
One possible scenario is to call isProxyactive(0) in separate thread,
and once it returned notify other threads about this event.
@param timeout For how long this method should block, before returning.
@return true if connection to proxy is active, false if eof or error
condition have been encountered on the connection.
*/
public boolean isProxyAlive(int timeout){
if(server_mode) return false;
if(proxy != null){
try{
proxy.proxySocket.setSoTimeout(timeout);
int eof = proxy.in.read();
if(eof < 0) return false; // EOF encountered.
else return true; // This really should not happen
}catch(InterruptedIOException iioe){
return true; // read timed out.
}catch(IOException ioe){
return false;
}
}
return false;
}
//PRIVATE METHODS
//////////////////
private byte[] formHeader(InetAddress ip, int port){
Socks5Message request = new Socks5Message(0,ip,port);
request.data[0] = 0;
return request.data;
}
private byte[] formHeader(String host,int port){
Socks5Message request = new Socks5Message(0,host,port);
request.data[0] = 0;
return request.data;
}
/*======================================================================
//Mainly Test functions
//////////////////////
private String bytes2String(byte[] b){
String s="";
char[] hex_digit = { '0','1','2','3','4','5','6','7','8','9',
'A','B','C','D','E','F'};
for(int i=0;i<b.length;++i){
int i1 = (b[i] & 0xF0) >> 4;
int i2 = b[i] & 0xF;
s+=hex_digit[i1];
s+=hex_digit[i2];
s+=" ";
}
return s;
}
private static final void debug(String s){
if(DEBUG)
System.out.print(s);
}
private static final boolean DEBUG = true;
public static void usage(){
System.err.print(
"Usage: java Socks.SocksDatagramSocket host port [socksHost socksPort]\n");
}
static final int defaultProxyPort = 1080; //Default Port
static final String defaultProxyHost = "www-proxy"; //Default proxy
public static void main(String args[]){
int port;
String host;
int proxyPort;
String proxyHost;
InetAddress ip;
if(args.length > 1 && args.length < 5){
try{
host = args[0];
port = Integer.parseInt(args[1]);
proxyPort =(args.length > 3)? Integer.parseInt(args[3])
: defaultProxyPort;
host = args[0];
ip = InetAddress.getByName(host);
proxyHost =(args.length > 2)? args[2]
: defaultProxyHost;
Proxy.setDefaultProxy(proxyHost,proxyPort);
Proxy p = Proxy.getDefaultProxy();
p.addDirect("lux");
DatagramSocket ds = new Socks5DatagramSocket();
BufferedReader in = new BufferedReader(
new InputStreamReader(System.in));
String s;
System.out.print("Enter line:");
s = in.readLine();
while(s != null){
byte[] data = (s+"\r\n").getBytes();
DatagramPacket dp = new DatagramPacket(data,0,data.length,
ip,port);
System.out.println("Sending to: "+ip+":"+port);
ds.send(dp);
dp = new DatagramPacket(new byte[1024],1024);
System.out.println("Trying to recieve on port:"+
ds.getLocalPort());
ds.receive(dp);
System.out.print("Recieved:\n"+
"From:"+dp.getAddress()+":"+dp.getPort()+
"\n\n"+
new String(dp.getData(),dp.getOffset(),dp.getLength())+"\n"
);
System.out.print("Enter line:");
s = in.readLine();
}
ds.close();
System.exit(1);
}catch(SocksException s_ex){
System.err.println("SocksException:"+s_ex);
s_ex.printStackTrace();
System.exit(1);
}catch(IOException io_ex){
io_ex.printStackTrace();
System.exit(1);
}catch(NumberFormatException num_ex){
usage();
num_ex.printStackTrace();
System.exit(1);
}
}else{
usage();
}
}
*/
}

View File

@ -0,0 +1,292 @@
package net.sourceforge.jsocks.socks;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.DataInputStream;
import java.net.InetAddress;
import java.net.UnknownHostException;
/**
SOCKS5 request/response message.
*/
class Socks5Message extends ProxyMessage{
/** Address type of given message*/
public int addrType;
byte[] data;
/**
Server error response.
@param cmd Error code.
*/
public Socks5Message(int cmd){
super(cmd,null,0);
data = new byte[3];
data[0] = SOCKS_VERSION; //Version.
data[1] = (byte)cmd; //Reply code for some kind of failure.
data[2] = 0; //Reserved byte.
}
/**
Construct client request or server response.
@param cmd - Request/Response code.
@param ip - IP field.
@paarm port - port field.
*/
public Socks5Message(int cmd,InetAddress ip,int port){
super(cmd,ip,port);
this.host = ip==null?"0.0.0.0":ip.getHostName();
this.version = SOCKS_VERSION;
byte[] addr;
if(ip == null){
addr = new byte[4];
addr[0]=addr[1]=addr[2]=addr[3]=0;
}else
addr = ip.getAddress();
addrType = addr.length == 4 ? SOCKS_ATYP_IPV4
: SOCKS_ATYP_IPV6;
data = new byte[6+addr.length];
data[0] = (byte) SOCKS_VERSION; //Version
data[1] = (byte) command; //Command
data[2] = (byte) 0; //Reserved byte
data[3] = (byte) addrType; //Address type
//Put Address
System.arraycopy(addr,0,data,4,addr.length);
//Put port
data[data.length-2] = (byte)(port>>8);
data[data.length-1] = (byte)(port);
}
/**
Construct client request or server response.
@param cmd - Request/Response code.
@param hostName - IP field as hostName, uses ADDR_TYPE of HOSTNAME.
@paarm port - port field.
*/
public Socks5Message(int cmd,String hostName,int port){
super(cmd,null,port);
this.host = hostName;
this.version = SOCKS_VERSION;
//System.out.println("Doing ATYP_DOMAINNAME");
addrType = SOCKS_ATYP_DOMAINNAME;
byte addr[] = hostName.getBytes();
data =new byte[7+addr.length];
data[0] = (byte) SOCKS_VERSION; //Version
data[1] = (byte) command; //Command
data[2] = (byte) 0; //Reserved byte
data[3] = (byte) SOCKS_ATYP_DOMAINNAME; //Address type
data[4] = (byte) addr.length; //Length of the address
//Put Address
System.arraycopy(addr,0,data,5,addr.length);
//Put port
data[data.length-2] = (byte)(port >>8);
data[data.length-1] = (byte)(port);
}
/**
Initialises Message from the stream. Reads server response from
given stream.
@param in Input stream to read response from.
@throws SocksException If server response code is not SOCKS_SUCCESS(0), or
if any error with protocol occurs.
@throws IOException If any error happens with I/O.
*/
public Socks5Message(InputStream in) throws SocksException,
IOException{
this(in,true);
}
/**
Initializes Message from the stream. Reads server response or client
request from given stream.
@param in Input stream to read response from.
@param clientMode If true read server response, else read client request.
@throws SocksException If server response code is not SOCKS_SUCCESS(0) and
reading in client mode, or if any error with protocol occurs.
@throws IOException If any error happens with I/O.
*/
public Socks5Message(InputStream in,boolean clientMode)throws SocksException,
IOException{
read(in,clientMode);
}
/**
Initialises Message from the stream. Reads server response from
given stream.
@param in Input stream to read response from.
@throws SocksException If server response code is not SOCKS_SUCCESS(0), or
if any error with protocol occurs.
@throws IOException If any error happens with I/O.
*/
public void read(InputStream in) throws SocksException,
IOException{
read(in,true);
}
/**
Initializes Message from the stream. Reads server response or client
request from given stream.
@param in Input stream to read response from.
@param clientMode If true read server response, else read client request.
@throws SocksException If server response code is not SOCKS_SUCCESS(0) and
reading in client mode, or if any error with protocol occurs.
@throws IOException If any error happens with I/O.
*/
@Override
public void read(InputStream in,boolean clientMode) throws SocksException,
IOException{
data = null;
ip = null;
DataInputStream di = new DataInputStream(in);
version = di.readUnsignedByte();
command = di.readUnsignedByte();
if(clientMode && command != 0)
throw new SocksException(command);
int reserved = di.readUnsignedByte();
addrType = di.readUnsignedByte();
byte addr[];
switch(addrType){
case SOCKS_ATYP_IPV4:
addr = new byte[4];
di.readFully(addr);
host = bytes2IPV4(addr,0);
break;
case SOCKS_ATYP_IPV6:
addr = new byte[SOCKS_IPV6_LENGTH];//I believe it is 16 bytes,huge!
di.readFully(addr);
host = bytes2IPV6(addr,0);
break;
case SOCKS_ATYP_DOMAINNAME:
//System.out.println("Reading ATYP_DOMAINNAME");
addr = new byte[di.readUnsignedByte()];//Next byte shows the length
di.readFully(addr);
host = new String(addr);
break;
default:
throw(new SocksException(Proxy.SOCKS_JUST_ERROR));
}
port = di.readUnsignedShort();
if(addrType != SOCKS_ATYP_DOMAINNAME && doResolveIP){
try{
ip = InetAddress.getByName(host);
}catch(UnknownHostException uh_ex){
}
}
}
/**
Writes the message to the stream.
@param out Output stream to which message should be written.
*/
public void write(OutputStream out)throws SocksException,
IOException{
if(data == null){
Socks5Message msg;
if(addrType == SOCKS_ATYP_DOMAINNAME)
msg = new Socks5Message(command,host,port);
else{
if(ip == null){
try{
ip = InetAddress.getByName(host);
}catch(UnknownHostException uh_ex){
throw new SocksException(Proxy.SOCKS_JUST_ERROR);
}
}
msg = new Socks5Message(command,ip,port);
}
data = msg.data;
}
out.write(data);
}
/**
Returns IP field of the message as IP, if the message was created
with ATYP of HOSTNAME, it will attempt to resolve the hostname,
which might fail.
@throws UnknownHostException if host can't be resolved.
*/
public InetAddress getInetAddress() throws UnknownHostException{
if(ip!=null) return ip;
return (ip=InetAddress.getByName(host));
}
/**
Returns string representation of the message.
*/
public String toString(){
String s=
"Socks5Message:"+"\n"+
"VN "+version+"\n"+
"CMD "+command+"\n"+
"ATYP "+addrType+"\n"+
"ADDR "+host+"\n"+
"PORT "+port+"\n";
return s;
}
/**
*Wether to resolve hostIP returned from SOCKS server
*that is wether to create InetAddress object from the
*hostName string
*/
static public boolean resolveIP(){ return doResolveIP;}
/**
*Wether to resolve hostIP returned from SOCKS server
*that is wether to create InetAddress object from the
*hostName string
*@param doResolve Wether to resolve hostIP from SOCKS server.
*@return Previous value.
*/
static public boolean resolveIP(boolean doResolve){
boolean old = doResolveIP;
doResolveIP = doResolve;
return old;
}
/*
private static final void debug(String s){
if(DEBUG)
System.out.print(s);
}
private static final boolean DEBUG = false;
*/
//SOCKS5 constants
public static final int SOCKS_VERSION =5;
public static final int SOCKS_ATYP_IPV4 =0x1; //Where is 2??
public static final int SOCKS_ATYP_DOMAINNAME =0x3; //!!!!rfc1928
public static final int SOCKS_ATYP_IPV6 =0x4;
public static final int SOCKS_IPV6_LENGTH =16;
static boolean doResolveIP = true;
}

View File

@ -0,0 +1,253 @@
package net.sourceforge.jsocks.socks;
import java.net.InetAddress;
import java.net.Socket;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.io.*;
import java.util.Hashtable;
import java.util.Enumeration;
import net.*;
/**
SOCKS5 Proxy.
*/
public class Socks5Proxy extends Proxy implements Cloneable{
//Data members
private Hashtable authMethods = new Hashtable();
private int selectedMethod;
boolean resolveAddrLocally = true;
UDPEncapsulation udp_encapsulation=null;
//Public Constructors
//====================
/**
Creates SOCKS5 proxy.
@param p Proxy to use to connect to this proxy, allows proxy chaining.
@param proxyHost Host on which a Proxy server runs.
@param proxyPort Port on which a Proxy server listens for connections.
@throws UnknownHostException If proxyHost can't be resolved.
*/
public Socks5Proxy(Proxy p,String proxyHost,int proxyPort)
throws UnknownHostException{
super(p,proxyHost,proxyPort);
version = 5;
setAuthenticationMethod(0,new AuthenticationNone());
}
/**
Creates SOCKS5 proxy.
@param proxyHost Host on which a Proxy server runs.
@param proxyPort Port on which a Proxy server listens for connections.
@throws UnknownHostException If proxyHost can't be resolved.
*/
public Socks5Proxy(String proxyHost,int proxyPort)
throws UnknownHostException{
this(null,proxyHost,proxyPort);
}
/**
Creates SOCKS5 proxy.
@param p Proxy to use to connect to this proxy, allows proxy chaining.
@param proxyIP Host on which a Proxy server runs.
@param proxyPort Port on which a Proxy server listens for connections.
*/
public Socks5Proxy(Proxy p,InetAddress proxyIP,int proxyPort){
super(p,proxyIP,proxyPort);
version = 5;
setAuthenticationMethod(0,new AuthenticationNone());
}
/**
Creates SOCKS5 proxy.
@param proxyIP Host on which a Proxy server runs.
@param proxyPort Port on which a Proxy server listens for connections.
*/
public Socks5Proxy(InetAddress proxyIP,int proxyPort){
this(null,proxyIP,proxyPort);
}
//Public instance methods
//========================
/**
* Wether to resolve address locally or to let proxy do so.
<p>
SOCKS5 protocol allows to send host names rather then IPs in the
requests, this option controls wether the hostnames should be send
to the proxy server as names, or should they be resolved locally.
@param doResolve Wether to perform resolution locally.
@return Previous settings.
*/
public boolean resolveAddrLocally(boolean doResolve){
boolean old = resolveAddrLocally;
resolveAddrLocally = doResolve;
return old;
}
/**
Get current setting on how the addresses should be handled.
@return Current setting for address resolution.
@see Socks5Proxy#resolveAddrLocally(boolean doResolve)
*/
public boolean resolveAddrLocally(){
return resolveAddrLocally;
}
/**
Adds another authentication method.
@param methodId Authentication method id, see rfc1928
@param method Implementation of Authentication
@see Authentication
*/
public boolean setAuthenticationMethod(int methodId,
Authentication method){
if(methodId<0 || methodId > 255)
return false;
if(method == null){
//Want to remove a particular method
return (authMethods.remove(new Integer(methodId)) != null);
}else{//Add the method, or rewrite old one
authMethods.put(new Integer(methodId),method);
}
return true;
}
/**
Get authentication method, which corresponds to given method id
@param methodId Authentication method id.
@return Implementation for given method or null, if one was not set.
*/
public Authentication getAuthenticationMethod(int methodId){
Object method = authMethods.get(new Integer(methodId));
if(method == null) return null;
return (Authentication)method;
}
/**
Creates a clone of this Proxy.
*/
public Object clone(){
Socks5Proxy newProxy = new Socks5Proxy(proxyIP,proxyPort);
newProxy.authMethods = (Hashtable) this.authMethods.clone();
newProxy.directHosts = (InetRange)directHosts.clone();
newProxy.resolveAddrLocally = resolveAddrLocally;
newProxy.chainProxy = chainProxy;
return newProxy;
}
//Public Static(Class) Methods
//==============================
//Protected Methods
//=================
protected Proxy copy(){
Socks5Proxy copy = new Socks5Proxy(proxyIP,proxyPort);
copy.authMethods = this.authMethods; //same Hash, no copy
copy.directHosts = this.directHosts;
copy.chainProxy = this.chainProxy;
copy.resolveAddrLocally = this.resolveAddrLocally;
return copy;
}
/**
*
*
*/
protected void startSession()throws SocksException{
super.startSession();
Authentication auth;
Socket ps = proxySocket; //The name is too long
try{
byte nMethods = (byte) authMethods.size(); //Number of methods
byte[] buf = new byte[2+nMethods]; //2 is for VER,NMETHODS
buf[0] = (byte) version;
buf[1] = nMethods; //Number of methods
int i=2;
Enumeration ids = authMethods.keys();
while(ids.hasMoreElements())
buf[i++] = (byte)((Integer)ids.nextElement()).intValue();
out.write(buf);
out.flush();
int versionNumber = in.read();
selectedMethod = in.read();
if(versionNumber < 0 || selectedMethod < 0){
//EOF condition was reached
endSession();
throw(new SocksException(SOCKS_PROXY_IO_ERROR,
"Connection to proxy lost."));
}
if(versionNumber < version){
//What should we do??
}
if(selectedMethod == 0xFF){ //No method selected
ps.close();
throw ( new SocksException(SOCKS_AUTH_NOT_SUPPORTED));
}
auth = getAuthenticationMethod(selectedMethod);
if(auth == null){
//This shouldn't happen, unless method was removed by other
//thread, or the server stuffed up
throw(new SocksException(SOCKS_JUST_ERROR,
"Speciefied Authentication not found!"));
}
Object[] in_out = auth.doSocksAuthentication(selectedMethod,ps);
if(in_out == null){
//Authentication failed by some reason
throw(new SocksException(SOCKS_AUTH_FAILURE));
}
//Most authentication methods are expected to return
//simply the input/output streams associated with
//the socket. However if the auth. method requires
//some kind of encryption/decryption being done on the
//connection it should provide classes to handle I/O.
in = (InputStream) in_out[0];
out = (OutputStream) in_out[1];
if(in_out.length > 2)
udp_encapsulation = (UDPEncapsulation) in_out[2];
}catch(SocksException s_ex){
throw s_ex;
}catch(UnknownHostException uh_ex){
throw(new SocksException(SOCKS_PROXY_NO_CONNECT));
}catch(SocketException so_ex){
throw(new SocksException(SOCKS_PROXY_NO_CONNECT));
}catch(IOException io_ex){
//System.err.println(io_ex);
throw(new SocksException(SOCKS_PROXY_IO_ERROR,""+io_ex));
}
}
protected ProxyMessage formMessage(int cmd,InetAddress ip,int port){
return new Socks5Message(cmd,ip,port);
}
protected ProxyMessage formMessage(int cmd,String host,int port)
throws UnknownHostException{
if(resolveAddrLocally)
return formMessage(cmd,InetAddress.getByName(host),port);
else
return new Socks5Message(cmd,host,port);
}
protected ProxyMessage formMessage(InputStream in)
throws SocksException,
IOException{
return new Socks5Message(in);
}
}

View File

@ -0,0 +1,78 @@
package net.sourceforge.jsocks.socks;
/**
Exception thrown by various socks classes to indicate errors
with protocol or unsuccessful server responses.
*/
public class SocksException extends java.io.IOException{
/**
Construct a SocksException with given error code.
<p>
Tries to look up message which corresponds to this error code.
@param errCode Error code for this exception.
*/
public SocksException(int errCode){
this.errCode = errCode;
if((errCode >> 16) == 0){
//Server reply error message
errString = errCode <= serverReplyMessage.length ?
serverReplyMessage[errCode] :
UNASSIGNED_ERROR_MESSAGE;
}else{
//Local error
errCode = (errCode >> 16) -1;
errString = errCode <= localErrorMessage.length ?
localErrorMessage[errCode] :
UNASSIGNED_ERROR_MESSAGE;
}
}
/**
Constructs a SocksException with given error code and message.
@param errCode Error code.
@param errString Error Message.
*/
public SocksException(int errCode,String errString){
this.errCode = errCode;
this.errString = errString;
}
/**
Get the error code associated with this exception.
@return Error code associated with this exception.
*/
public int getErrorCode(){
return errCode;
}
/**
Get human readable representation of this exception.
@return String represntation of this exception.
*/
public String toString(){
return errString;
}
static final String UNASSIGNED_ERROR_MESSAGE =
"Unknown error message";
static final String serverReplyMessage[] = {
"Succeeded",
"General SOCKS server failure",
"Connection not allowed by ruleset",
"Network unreachable",
"Host unreachable",
"Connection refused",
"TTL expired",
"Command not supported",
"Address type not supported" };
static final String localErrorMessage[] ={
"SOCKS server not specified",
"Unable to contact SOCKS server",
"IO error",
"None of Authentication methods are supported",
"Authentication failed",
"General SOCKS fault" };
String errString;
int errCode;
}//End of SocksException class

View File

@ -0,0 +1,213 @@
package net.sourceforge.jsocks.socks;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.io.*;
import net.*;
/**
SocksServerSocket allows to accept connections from one particular
host through the SOCKS4 or SOCKS5 proxy.
*/
public class SocksServerSocket extends ServerSocket{
//Data members
protected Proxy proxy;
protected String localHost;
protected InetAddress localIP;
protected int localPort;
boolean doing_direct = false;
InetAddress remoteAddr;
/**
* Creates ServerSocket capable of accepting one connection
* through the firewall, uses default Proxy.
*@param host Host from which the connection should be recieved.
*@param port Port number of the primary connection.
*/
public SocksServerSocket(String host,int port)
throws SocksException,UnknownHostException,IOException{
this(Proxy.defaultProxy,host,port);
}
/**
*Creates ServerSocket capable of accepting one connection
*through the firewall, uses given proxy.
*@param p Proxy object to use.
*@param host Host from which the connection should be recieved.
*@param port Port number of the primary connection.
*/
public SocksServerSocket(Proxy p,String host,int port)
throws SocksException,UnknownHostException,IOException{
super(0);
if(p == null) throw new SocksException(Proxy.SOCKS_NO_PROXY);
//proxy=p;
proxy = p.copy();
if(proxy.isDirect(host)){
remoteAddr = InetAddress.getByName(host);
proxy = null;
doDirect();
}else{
processReply(proxy.bind(host,port));
}
}
/**
* Creates ServerSocket capable of accepting one connection
* through the firewall, uses default Proxy.
*@param ip Host from which the connection should be recieved.
*@param port Port number of the primary connection.
*/
public SocksServerSocket(InetAddress ip, int port) throws SocksException,
IOException{
this(Proxy.defaultProxy,ip,port);
}
/**
*Creates ServerSocket capable of accepting one connection
*through the firewall, uses given proxy.
*@param p Proxy object to use.
*@param ip Host from which the connection should be recieved.
*@param port Port number of the primary connection.
*/
public SocksServerSocket(Proxy p,InetAddress ip, int port)
throws SocksException,IOException{
super(0);
if(p == null) throw new SocksException(Proxy.SOCKS_NO_PROXY);
this.proxy = p.copy();
if(proxy.isDirect(ip)){
remoteAddr = ip;
doDirect();
}else{
processReply(proxy.bind(ip,port));
}
}
/**
* Accepts the incoming connection.
*/
public Socket accept() throws IOException{
Socket s;
if(!doing_direct){
if(proxy == null) return null;
ProxyMessage msg = proxy.accept();
s = msg.ip == null? new SocksSocket(msg.host,msg.port,proxy)
: new SocksSocket(msg.ip,msg.port,proxy);
//Set timeout back to 0
proxy.proxySocket.setSoTimeout(0);
}else{ //Direct Connection
//Mimic the proxy behaviour,
//only accept connections from the speciefed host.
while(true){
s = super.accept();
if(s.getInetAddress().equals(remoteAddr)){
//got the connection from the right host
//Close listenning socket.
break;
}else
s.close(); //Drop all connections from other hosts
}
}
proxy = null;
//Return accepted socket
return s;
}
/**
* Closes the connection to proxy if socket have not been accepted, if
* the direct connection is used, closes direct ServerSocket. If the
* client socket have been allready accepted, does nothing.
*/
public void close() throws IOException{
super.close();
if(proxy != null) proxy.endSession();
proxy = null;
}
/**
Get the name of the host proxy is using to listen for incoming
connection.
<P>
Usefull when address is returned by proxy as the hostname.
@return the hostname of the address proxy is using to listen
for incoming connection.
*/
public String getHost(){
return localHost;
}
/**
* Get address assigned by proxy to listen for incomming
* connections, or the local machine address if doing direct
* connection.
*/
public InetAddress getInetAddress(){
if(localIP == null){
try{
localIP = InetAddress.getByName(localHost);
}catch(UnknownHostException e){
return null;
}
}
return localIP;
}
/**
* Get port assigned by proxy to listen for incoming connections, or
the port chosen by local system, if accepting directly.
*/
public int getLocalPort(){
return localPort;
}
/**
Set Timeout.
@param timeout Amount of time in milliseconds, accept should wait for
incoming connection before failing with exception.
Zero timeout implies infinity.
*/
public void setSoTimeout(int timeout) throws SocketException{
super.setSoTimeout(timeout);
if(!doing_direct) proxy.proxySocket.setSoTimeout(timeout);
}
//Private Methods
//////////////////
private void processReply(ProxyMessage reply)throws SocksException{
localPort = reply.port;
/*
* If the server have assigned same host as it was contacted on
* it might return an address of all zeros
*/
if(reply.host.equals("0.0.0.0")){
localIP = proxy.proxyIP;
localHost = localIP.getHostName();
}else{
localHost = reply.host;
localIP = reply.ip;
}
}
private void doDirect(){
doing_direct = true;
localPort = super.getLocalPort();
localIP = super.getInetAddress();
localHost = localIP.getHostName();
}
}

View File

@ -0,0 +1,337 @@
package net.sourceforge.jsocks.socks;
import java.net.InetAddress;
import java.net.Socket;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.io.*;
import net.*;
/**
* SocksSocket tryies to look very similar to normal Socket,
* while allowing connections through the SOCKS4 or 5 proxy.
* To use this class you will have to identify proxy you need
* to use, Proxy class allows you to set default proxy, which
* will be used by all Socks aware sockets. You can also create
* either Socks4Proxy or Socks5Proxy, and use them by passing to the
* appropriate constructors.
* <P>
* Using Socks package can be as easy as that:
*
* <pre><tt>
*
* import Socks.*;
* ....
*
* try{
* //Specify SOCKS5 proxy
* Proxy.setDefaultProxy("socks-proxy",1080);
*
* //OR you still use SOCKS4
* //Code below uses SOCKS4 proxy
* //Proxy.setDefaultProxy("socks-proxy",1080,userName);
*
* Socket s = SocksSocket("some.host.of.mine",13);
* readTimeFromSock(s);
* }catch(SocksException sock_ex){
* //Usually it will turn in more or less meaningfull message
* System.err.println("SocksException:"+sock_ex);
* }
*
* </tt></pre>
*<P>
* However if the need exist for more control, like resolving addresses
* remotely, or using some non-trivial authentication schemes, it can be done.
*/
public class SocksSocket extends Socket{
//Data members
protected Proxy proxy;
protected String localHost, remoteHost;
protected InetAddress localIP, remoteIP;
protected int localPort,remotePort;
private Socket directSock = null;
/**
* Tryies to connect to given host and port
* using default proxy. If no default proxy speciefied
* it throws SocksException with error code SOCKS_NO_PROXY.
@param host Machine to connect to.
@param port Port to which to connect.
* @see SocksSocket#SocksSocket(Proxy,String,int)
* @see Socks5Proxy#resolveAddrLocally
*/
public SocksSocket(String host,int port)
throws SocksException,UnknownHostException{
this(Proxy.defaultProxy,host,port);
}
/**
* Connects to host port using given proxy server.
@param p Proxy to use.
@param host Machine to connect to.
@param port Port to which to connect.
@throws UnknownHostException
If one of the following happens:
<ol>
<li> Proxy settings say that address should be resolved locally, but
this fails.
<li> Proxy settings say that the host should be contacted directly but
host name can't be resolved.
</ol>
@throws SocksException
If one of the following happens:
<ul>
<li> Proxy is is null.
<li> Proxy settings say that the host should be contacted directly but
this fails.
<li> Socks Server can't be contacted.
<li> Authentication fails.
<li> Connection is not allowed by the SOCKS proxy.
<li> SOCKS proxy can't establish the connection.
<li> Any IO error occured.
<li> Any protocol error occured.
</ul>
@throws IOexception if anything is wrong with I/O.
@see Socks5Proxy#resolveAddrLocally
*/
public SocksSocket(Proxy p,String host,int port)
throws SocksException,UnknownHostException{
if(p == null) throw new SocksException(Proxy.SOCKS_NO_PROXY);
//proxy=p;
proxy = p.copy();
remoteHost = host;
remotePort = port;
if(proxy.isDirect(host)){
remoteIP = InetAddress.getByName(host);
doDirect();
}
else
processReply(proxy.connect(host,port));
}
/**
* Tryies to connect to given ip and port
* using default proxy. If no default proxy speciefied
* it throws SocksException with error code SOCKS_NO_PROXY.
@param ip Machine to connect to.
@param port Port to which to connect.
* @see SocksSocket#SocksSocket(Proxy,String,int)
*/
public SocksSocket(InetAddress ip, int port) throws SocksException{
this(Proxy.defaultProxy,ip,port);
}
/**
Connects to given ip and port using given Proxy server.
@param p Proxy to use.
@param ip Machine to connect to.
@param port Port to which to connect.
*/
public SocksSocket(Proxy p,InetAddress ip, int port) throws SocksException{
if(p == null) throw new SocksException(Proxy.SOCKS_NO_PROXY);
this.proxy = p.copy();
this.remoteIP = ip;
this.remotePort = port;
this.remoteHost = ip.getHostName();
if(proxy.isDirect(remoteIP))
doDirect();
else
processReply(proxy.connect(ip,port));
}
/**
* These 2 constructors are used by the SocksServerSocket.
* This socket simply overrides remoteHost, remotePort
*/
protected SocksSocket(String host,int port,Proxy proxy){
this.remotePort = port;
this.proxy = proxy;
this.localIP = proxy.proxySocket.getLocalAddress();
this.localPort = proxy.proxySocket.getLocalPort();
this.remoteHost = host;
}
protected SocksSocket(InetAddress ip,int port,Proxy proxy){
remoteIP = ip;
remotePort = port;
this.proxy = proxy;
this.localIP = proxy.proxySocket.getLocalAddress();
this.localPort = proxy.proxySocket.getLocalPort();
remoteHost = remoteIP.getHostName();
}
/**
* Same as Socket
*/
public void close() throws IOException{
if(proxy!= null)proxy.endSession();
proxy = null;
}
/**
* Same as Socket
*/
public InputStream getInputStream(){
return proxy.in;
}
/**
* Same as Socket
*/
public OutputStream getOutputStream(){
return proxy.out;
}
/**
* Same as Socket
*/
public int getPort(){
return remotePort;
}
/**
* Returns remote host name, it is usefull in cases when addresses
* are resolved by proxy, and we can't create InetAddress object.
@return The name of the host this socket is connected to.
*/
public String getHost(){
return remoteHost;
}
/**
* Get remote host as InetAddress object, might return null if
* addresses are resolved by proxy, and it is not possible to resolve
* it locally
@return Ip address of the host this socket is connected to, or null
if address was returned by the proxy as DOMAINNAME and can't be
resolved locally.
*/
public InetAddress getInetAddress(){
if(remoteIP == null){
try{
remoteIP = InetAddress.getByName(remoteHost);
}catch(UnknownHostException e){
return null;
}
}
return remoteIP;
}
/**
* Get the port assigned by the proxy for the socket, not
* the port on locall machine as in Socket.
@return Port of the socket used on the proxy server.
*/
public int getLocalPort(){
return localPort;
}
/**
* Get address assigned by proxy to make a remote connection,
* it might be different from the host specified for the proxy.
* Can return null if socks server returned this address as hostname
* and it can't be resolved locally, use getLocalHost() then.
@return Address proxy is using to make a connection.
*/
public InetAddress getLocalAddress(){
if(localIP == null){
try{
localIP = InetAddress.getByName(localHost);
}catch(UnknownHostException e){
return null;
}
}
return localIP;
}
/**
Get name of the host, proxy has assigned to make a remote connection
for this socket. This method is usefull when proxy have returned
address as hostname, and we can't resolve it on this machine.
@return The name of the host proxy is using to make a connection.
*/
public String getLocalHost(){
return localHost;
}
/**
Same as socket.
*/
public void setSoLinger(boolean on,int val) throws SocketException{
proxy.proxySocket.setSoLinger(on,val);
}
/**
Same as socket.
*/
public int getSoLinger(int timeout) throws SocketException{
return proxy.proxySocket.getSoLinger();
}
/**
Same as socket.
*/
public void setSoTimeout(int timeout) throws SocketException{
proxy.proxySocket.setSoTimeout(timeout);
}
/**
Same as socket.
*/
public int getSoTimeout(int timeout) throws SocketException{
return proxy.proxySocket.getSoTimeout();
}
/**
Same as socket.
*/
public void setTcpNoDelay(boolean on) throws SocketException{
proxy.proxySocket.setTcpNoDelay(on);
}
/**
Same as socket.
*/
public boolean getTcpNoDelay() throws SocketException{
return proxy.proxySocket.getTcpNoDelay();
}
/**
Get string representation of the socket.
*/
public String toString(){
if(directSock!=null) return "Direct connection:"+directSock;
return ("Proxy:"+proxy+";"+"addr:"+remoteHost+",port:"+remotePort
+",localport:"+localPort);
}
//Private Methods
//////////////////
private void processReply(ProxyMessage reply)throws SocksException{
localPort = reply.port;
/*
* If the server have assigned same host as it was contacted on
* it might return an address of all zeros
*/
if(reply.host.equals("0.0.0.0")){
localIP = proxy.proxyIP;
localHost = localIP.getHostName();
}else{
localHost = reply.host;
localIP = reply.ip;
}
}
private void doDirect()throws SocksException{
try{
//System.out.println("IP:"+remoteIP+":"+remotePort);
directSock = new Socket(remoteIP,remotePort);
proxy.out = directSock.getOutputStream();
proxy.in = directSock.getInputStream();
proxy.proxySocket = directSock;
localIP = directSock.getLocalAddress();
localPort = directSock.getLocalPort();
}catch(IOException io_ex){
throw new SocksException(Proxy.SOCKS_DIRECT_FAILED,
"Direct connect failed:"+io_ex);
}
}
}

View File

@ -0,0 +1,30 @@
package net.sourceforge.jsocks.socks;
/**
This interface provides for datagram encapsulation for SOCKSv5 protocol.
<p>
SOCKSv5 allows for datagrams to be encapsulated for purposes of integrity
and/or authenticity. How it should be done is aggreed during the
authentication stage, and is authentication dependent. This interface is
provided to allow this encapsulation.
@see Authentication
*/
public interface UDPEncapsulation{
/**
This method should provide any authentication depended transformation
on datagrams being send from/to the client.
@param data Datagram data (including any SOCKS related bytes), to be
encapsulated/decapsulated.
@param out Wether the data is being send out. If true method should
encapsulate/encrypt data, otherwise it should decapsulate/
decrypt data.
@throw IOException if for some reason data can be transformed correctly.
@return Should return byte array containing data after transformation.
It is possible to return same array as input, if transformation
only involves bit mangling, and no additional data is being
added or removed.
*/
byte[] udpEncapsulate(byte[] data, boolean out) throws java.io.IOException;
}

View File

@ -0,0 +1,217 @@
package net.sourceforge.jsocks.socks;
import net.*;
import net.sourceforge.jsocks.socks.server.*;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import java.io.*;
/**
UDP Relay server, used by ProxyServer to perform udp forwarding.
*/
class UDPRelayServer implements Runnable{
DatagramSocket client_sock;
DatagramSocket remote_sock;
Socket controlConnection;
int relayPort;
InetAddress relayIP;
Thread pipe_thread1,pipe_thread2;
Thread master_thread;
ServerAuthenticator auth;
long lastReadTime;
// private static final Logger LOG = Logger.getLogger(UDPRelayServer.class);
static Proxy proxy = null;
static int datagramSize = 0xFFFF;//64K, a bit more than max udp size
static int iddleTimeout = 180000;//3 minutes
/**
Constructs UDP relay server to communicate with client
on given ip and port.
@param clientIP Address of the client from whom datagrams
will be recieved and to whom they will be forwarded.
@param clientPort Clients port.
@param master_thread Thread which will be interrupted, when
UDP relay server stoppes for some reason.
@param controlConnection Socket which will be closed, before
interrupting the master thread, it is introduced due to a bug
in windows JVM which does not throw InterruptedIOException in
threads which block in I/O operation.
*/
public UDPRelayServer(InetAddress clientIP,int clientPort,
Thread master_thread,
Socket controlConnection,
ServerAuthenticator auth)
throws IOException{
this.master_thread = master_thread;
this.controlConnection = controlConnection;
this.auth = auth;
client_sock = new Socks5DatagramSocket(true,auth.getUdpEncapsulation(),
clientIP,clientPort);
relayPort = client_sock.getLocalPort();
relayIP = client_sock.getLocalAddress();
if(relayIP.getHostAddress().equals("0.0.0.0"))
relayIP = InetAddress.getLocalHost();
if(proxy == null)
remote_sock = new DatagramSocket();
else
remote_sock = new Socks5DatagramSocket(proxy,0,null);
}
//Public methods
/////////////////
/**
Sets the timeout for UDPRelay server.<br>
Zero timeout implies infinity.<br>
Default timeout is 3 minutes.
*/
static public void setTimeout(int timeout){
iddleTimeout = timeout;
}
/**
Sets the size of the datagrams used in the UDPRelayServer.<br>
Default size is 64K, a bit more than maximum possible size of the
datagram.
*/
static public void setDatagramSize(int size){
datagramSize = size;
}
/**
Port to which client should send datagram for association.
*/
public int getRelayPort(){
return relayPort;
}
/**
IP address to which client should send datagrams for association.
*/
public InetAddress getRelayIP(){
return relayIP;
}
/**
Starts udp relay server.
Spawns two threads of execution and returns.
*/
public void start() throws IOException{
remote_sock.setSoTimeout(iddleTimeout);
client_sock.setSoTimeout(iddleTimeout);
log("Starting UDP relay server on "+relayIP+":"+relayPort);
log("Remote socket "+remote_sock.getLocalAddress()+":"+
remote_sock.getLocalPort());
pipe_thread1 = new Thread(this,"pipe1");
pipe_thread2 = new Thread(this,"pipe2");
lastReadTime = System.currentTimeMillis();
pipe_thread1.start();
pipe_thread2.start();
}
/**
Stops Relay server.
<p>
Does not close control connection, does not interrupt master_thread.
*/
public synchronized void stop(){
master_thread = null;
controlConnection = null;
abort();
}
//Runnable interface
////////////////////
public void run(){
try{
if(Thread.currentThread().getName().equals("pipe1"))
pipe(remote_sock,client_sock,false);
else
pipe(client_sock,remote_sock,true);
}catch(IOException ioe){
}finally{
abort();
log("UDP Pipe thread "+Thread.currentThread().getName()+" stopped.");
}
}
//Private methods
/////////////////
private synchronized void abort(){
if(pipe_thread1 == null) return;
log("Aborting UDP Relay Server");
remote_sock.close();
client_sock.close();
if(controlConnection != null)
try{ controlConnection.close();} catch(IOException ioe){}
if(master_thread!=null) master_thread.interrupt();
pipe_thread1.interrupt();
pipe_thread2.interrupt();
pipe_thread1 = null;
}
static private void log(String s){
}
private void pipe(DatagramSocket from,DatagramSocket to,boolean out)
throws IOException{
byte[] data = new byte[datagramSize];
DatagramPacket dp = new DatagramPacket(data,data.length);
while(true){
try{
from.receive(dp);
lastReadTime = System.currentTimeMillis();
if(auth.checkRequest(dp,out))
to.send(dp);
}catch(UnknownHostException uhe){
log("Dropping datagram for unknown host");
}catch(InterruptedIOException iioe){
//log("Interrupted: "+iioe);
//If we were interrupted by other thread.
if(iddleTimeout == 0) return;
//If last datagram was received, long time ago, return.
long timeSinceRead = System.currentTimeMillis() - lastReadTime;
if(timeSinceRead >= iddleTimeout -100) //-100 for adjustment
return;
}
dp.setLength(data.length);
}
}
}

View File

@ -0,0 +1,75 @@
package net.sourceforge.jsocks.socks;
/**
SOCKS5 User Password authentication scheme.
*/
public class UserPasswordAuthentication implements Authentication{
/**SOCKS ID for User/Password authentication method*/
public final static int METHOD_ID = 2;
String userName, password;
byte[] request;
/**
Create an instance of UserPasswordAuthentication.
@param userName User Name to send to SOCKS server.
@param password Password to send to SOCKS server.
*/
public UserPasswordAuthentication(String userName,String password){
this.userName = userName;
this.password = password;
formRequest();
}
/** Get the user name.
@return User name.
*/
public String getUser(){
return userName;
}
/** Get password
@return Password
*/
public String getPassword(){
return password;
}
/**
Does User/Password authentication as defined in rfc1929.
@return An array containnig in, out streams, or null if authentication
fails.
*/
public Object[] doSocksAuthentication(int methodId,
java.net.Socket proxySocket)
throws java.io.IOException{
if(methodId != METHOD_ID) return null;
java.io.InputStream in = proxySocket.getInputStream();
java.io.OutputStream out = proxySocket.getOutputStream();
out.write(request);
int version = in.read();
if(version < 0) return null; //Server closed connection
int status = in.read();
if(status != 0) return null; //Server closed connection, or auth failed.
return new Object[] {in,out};
}
//Private methods
//////////////////
/** Convert UserName password in to binary form, ready to be send to server*/
private void formRequest(){
byte[] user_bytes = userName.getBytes();
byte[] password_bytes = password.getBytes();
request = new byte[3+user_bytes.length+password_bytes.length];
request[0] = (byte) 1;
request[1] = (byte) user_bytes.length;
System.arraycopy(user_bytes,0,request,2,user_bytes.length);
request[2+user_bytes.length] = (byte) password_bytes.length;
System.arraycopy(password_bytes,0,
request,3+user_bytes.length,password_bytes.length);
}
}

View File

@ -0,0 +1,161 @@
package net.sourceforge.jsocks.socks.server;
import java.net.ConnectException;
import java.net.Socket;
import java.io.*;
import java.util.StringTokenizer;
import net.*;
/**
Class Ident provides means to obtain user name of the owner of the socket
on remote machine, providing remote machine runs identd daemon.
<p>
To use it:
<tt><pre>
Socket s = ss.accept();
Ident id = new Ident(s);
if(id.successful) goUseUser(id.userName);
else handleIdentError(id.errorCode,id.errorMessage)
</pre></tt>
*/
public class Ident{
/** Error Message can be null.*/
public String errorMessage;
/** Host type as returned by daemon, can be null, if error happened*/
public String hostType;
/** User name as returned by the identd daemon, or null, if it failed*/
public String userName;
/** If this is true then userName and hostType contain valid values.
Else errorCode contain the error code, and errorMessage contains
the corresponding message.
*/
public boolean successful;
/** Error code*/
public int errorCode;
/** Identd on port 113 can't be contacted*/
public static final int ERR_NO_CONNECT = 1;
/** Connection timed out*/
public static final int ERR_TIMEOUT = 2;
/** Identd daemon responded with ERROR, in this case errorMessage
contains the string explanation, as send by the daemon.
*/
public static final int ERR_PROTOCOL = 3;
/**
When parsing server response protocol error happened.
*/
public static final int ERR_PROTOCOL_INCORRECT = 4;
/** Maximum amount of time we should wait before dropping the
connection to identd server.Setting it to 0 implies infinit
timeout.
*/
public static final int connectionTimeout = 10000;
/**
Constructor tries to connect to Identd daemon on the host of the
given socket, and retrieve user name of the owner of given socket
connection on remote machine. After constructor returns public
fields are initialised to whatever the server returned.
<p>
If user name was successfully retrieved successful is set to true,
and userName and hostType are set to whatever server returned. If
however for some reason user name was not obtained, successful is set
to false and errorCode contains the code explaining the reason of
failure, and errorMessage contains human readable explanation.
<p>
Constructor may block, for a while.
@param s Socket whose ownership on remote end should be obtained.
*/
public Ident(Socket s ){
Socket sock = null;
successful = false; //We are pessimistic
try{
sock = new Socket(s.getInetAddress(),113);
sock.setSoTimeout(connectionTimeout);
byte[] request = (""+s.getPort()+" , "+
s.getLocalPort()+"\r\n").getBytes();
sock.getOutputStream().write(request);
BufferedReader in = new BufferedReader(
new InputStreamReader(sock.getInputStream()));
parseResponse(in.readLine());
}catch(InterruptedIOException iioe){
errorCode = ERR_TIMEOUT;
errorMessage = "Connection to identd timed out.";
}catch(ConnectException ce){
errorCode = ERR_NO_CONNECT;
errorMessage = "Connection to identd server failed.";
}catch(IOException ioe){
errorCode = ERR_NO_CONNECT;
errorMessage = ""+ioe;
}finally{
try{ if(sock!=null) sock.close();}catch(IOException ioe){};
}
}
private void parseResponse(String response){
if(response == null){
errorCode = ERR_PROTOCOL_INCORRECT;
errorMessage = "Identd server closed connection.";
return;
}
StringTokenizer st = new StringTokenizer(response,":");
if(st.countTokens() < 3){
errorCode = ERR_PROTOCOL_INCORRECT;
errorMessage = "Can't parse server response.";
return;
}
st.nextToken(); //Discard first token, it's basically what we have send
String command = st.nextToken().trim().toUpperCase();
if(command.equals("USERID") && st.countTokens() >= 2){
successful = true;
hostType = st.nextToken().trim();
userName = st.nextToken("").substring(1);//Get all that is left
}else if(command.equals("ERROR")){
errorCode = ERR_PROTOCOL;
errorMessage = st.nextToken();
}else{
errorCode = ERR_PROTOCOL_INCORRECT;
System.out.println("Opa!");
errorMessage = "Can't parse server response.";
}
}
///////////////////////////////////////////////
//USED for Testing
/*
public static void main(String[] args) throws IOException{
Socket s = null;
s = new Socket("gp101-16", 1391);
Ident id = new Ident(s);
if(id.successful){
System.out.println("User: "+id.userName);
System.out.println("HostType: "+id.hostType);
}else{
System.out.println("ErrorCode: "+id.errorCode);
System.out.println("ErrorMessage: "+id.errorMessage);
}
if(s!= null) s.close();
}
//*/
}

View File

@ -0,0 +1,153 @@
package net.sourceforge.jsocks.socks.server;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.Vector;
import java.net.InetAddress;
import java.net.Socket;
import java.io.*;
import net.*;
import net.sourceforge.jsocks.socks.InetRange;
import net.sourceforge.jsocks.socks.ProxyMessage;
/**
An implementation of socks.ServerAuthentication which provides
simple authentication based on the host from which the connection
is made and the name of the user on the remote machine, as reported
by identd daemon on the remote machine.
<p>
It can also be used to provide authentication based only on the contacting
host address.
*/
public class IdentAuthenticator extends ServerAuthenticatorNone{
/** Vector of InetRanges */
Vector hosts;
/** Vector of user hashes*/
Vector users;
String user;
/**
Constructs empty IdentAuthenticator.
*/
public IdentAuthenticator(){
hosts = new Vector();
users = new Vector();
}
/**
Used to create instances returned from startSession.
@param in Input stream.
@param out OutputStream.
@param user Username associated with this connection,could be
null if name was not required.
*/
IdentAuthenticator(InputStream in,OutputStream out, String user){
super(in,out);
this.user = user;
}
/**
Adds range of addresses from which connection is allowed. Hashtable
users should contain user names as keys and anything as values
(value is not used and will be ignored).
@param hostRange Range of ip addresses from which connection is allowed.
@param users Hashtable of users for whom connection is allowed, or null
to indicate that anybody is allowed to connect from the hosts within given
range.
*/
public synchronized void add(InetRange hostRange,Hashtable users){
this.hosts.addElement(hostRange);
this.users.addElement(users);
}
/**
Grants permission only to those users, who connect from one of the
hosts registered with add(InetRange,Hashtable) and whose names, as
reported by identd daemon, are listed for the host the connection
came from.
*/
public ServerAuthenticator startSession(Socket s)
throws IOException{
int ind = getRangeIndex(s.getInetAddress());
String user = null;
//System.out.println("getRangeReturned:"+ind);
if(ind < 0) return null; //Host is not on the list.
ServerAuthenticatorNone auth = (ServerAuthenticatorNone)
super.startSession(s);
//System.out.println("super.startSession() returned:"+auth);
if(auth == null) return null;
//do the authentication
Hashtable user_names = (Hashtable) users.elementAt(ind);
if(user_names != null){ //If need to do authentication
Ident ident;
ident = new Ident(s);
//If can't obtain user name, fail
if(!ident.successful) return null;
//If user name is not listed for this address, fail
if(!user_names.containsKey(ident.userName)) return null;
user = ident.userName;
}
return new IdentAuthenticator(auth.in,auth.out,user);
}
/**
For SOCKS5 requests allways returns true. For SOCKS4 requests
checks wether the user name supplied in the request corresponds
to the name obtained from the ident daemon.
*/
public boolean checkRequest(ProxyMessage msg,java.net.Socket s){
//If it's version 5 request, or if anybody is permitted, return true;
if(msg.version == 5 || user == null)
return true;
if(msg.version != 4) return false; //Who knows?
return user.equals(msg.user);
}
/** Get String representaion of the IdentAuthenticator.*/
public String toString(){
String s = "";
for(int i=0;i<hosts.size();++i)
s += "Range:"+hosts.elementAt(i)+"\nUsers:"+userNames(i)+"\n";
return s;
}
//Private Methods
//////////////////
private int getRangeIndex(InetAddress ip){
int index = 0;
Iterator iterator = hosts.iterator();
while(iterator.hasNext()){
InetRange ir = (InetRange) iterator.next();
if(ir.contains(ip)) return index;
index++;
}
return -1; //Not found
}
private String userNames(int i){
if(users.elementAt(i) == null) return "Everybody is permitted.";
Iterator iterator = ((Hashtable)users.elementAt(i)).keySet().iterator();
if(!iterator.hasNext()) return "";
String s = iterator.next().toString();
while(iterator.hasNext())
s += "; "+iterator.next();
return s;
}
}

View File

@ -0,0 +1,120 @@
package net.sourceforge.jsocks.socks.server;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.net.DatagramPacket;
import net.sourceforge.jsocks.socks.ProxyMessage;
import net.sourceforge.jsocks.socks.UDPEncapsulation;
/**
Classes implementing this interface should provide socks server with
authentication and authorization of users.
**/
public interface ServerAuthenticator{
/**
This method is called when a new connection accepted by the server.
<p>
At this point no data have been extracted from the connection. It is
responsibility of this method to ensure that the next byte in the
stream after this method have been called is the first byte of the
socks request message. For SOCKSv4 there is no authentication data and
the first byte in the stream is part of the request. With SOCKSv5 however
there is an authentication data first. It is expected that implementaions
will process this authentication data.
<p>
If authentication was successful an instance of ServerAuthentication
should be returned, it later will be used by the server to perform
authorization and some other things. If authentication fails null should
be returned, or an exception may be thrown.
@param s Accepted Socket.
@return An instance of ServerAuthenticator to be used for this connection
or null
*/
ServerAuthenticator startSession(Socket s) throws IOException;
/**
This method should return input stream which should be used on the
accepted socket.
<p>
SOCKSv5 allows to have multiple authentication methods, and these methods
might require some kind of transformations being made on the data.
<p>
This method is called on the object returned from the startSession
function.
*/
InputStream getInputStream();
/**
This method should return output stream to use to write to the accepted
socket.
<p>
SOCKSv5 allows to have multiple authentication methods, and these methods
might require some kind of transformations being made on the data.
<p>
This method is called on the object returned from the startSession
function.
*/
OutputStream getOutputStream();
/**
This method should return UDPEncapsulation, which should be used
on the datagrams being send in/out.
<p>
If no transformation should be done on the datagrams, this method
should return null.
<p>
This method is called on the object returned from the startSession
function.
*/
UDPEncapsulation getUdpEncapsulation();
/**
This method is called when a request have been read.
<p>
Implementation should decide wether to grant request or not. Returning
true implies granting the request, false means request should be rejected.
<p>
This method is called on the object returned from the startSession
function.
@param msg Request message.
@return true to grant request, false to reject it.
*/
boolean checkRequest(ProxyMessage msg);
/**
This method is called when datagram is received by the server.
<p>
Implementaions should decide wether it should be forwarded or dropped.
It is expecteed that implementation will use datagram address and port
information to make a decision, as well as anything else. Address and
port of the datagram are always correspond to remote machine. It is
either destination or source address. If out is true address is destination
address, else it is a source address, address of the machine from which
datagram have been received for the client.
<p>
Implementaions should return true if the datagram is to be forwarded, and
false if the datagram should be dropped.
<p>
This method is called on the object returned from the startSession
function.
@param out If true the datagram is being send out(from the client),
otherwise it is an incoming datagram.
@return True to forward datagram false drop it silently.
*/
boolean checkRequest(DatagramPacket dp, boolean out);
/**
This method is called when session is completed. Either due to normal
termination or due to any error condition.
<p>
This method is called on the object returned from the startSession
function.
*/
void endSession();
}

View File

@ -0,0 +1,172 @@
package net.sourceforge.jsocks.socks.server;
import net.sourceforge.jsocks.socks.ProxyMessage;
import net.sourceforge.jsocks.socks.UDPEncapsulation;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PushbackInputStream;
import java.net.Socket;
/**
An implementation of ServerAuthenticator, which does <b>not</b> do
any authentication.
<P>
<FONT size="+3" color ="FF0000"> Warning!!</font><br> Should not be
used on machines which are not behind the firewall.
<p>
It is only provided to make implementing other authentication schemes
easier.<br>
For Example: <tt><pre>
class MyAuth extends socks.server.ServerAuthenticator{
...
public ServerAuthenticator startSession(java.net.Socket s){
if(!checkHost(s.getInetAddress()) return null;
return super.startSession(s);
}
boolean checkHost(java.net.Inetaddress addr){
boolean allow;
//Do it somehow
return allow;
}
}
</pre></tt>
*/
public class ServerAuthenticatorNone implements ServerAuthenticator{
static final byte[] socks5response = {5,0};
InputStream in;
OutputStream out;
/**
Creates new instance of the ServerAuthenticatorNone.
*/
public ServerAuthenticatorNone(){
this.in = null;
this.out = null;
}
/**
Constructs new ServerAuthenticatorNone object suitable for returning
from the startSession function.
@param in Input stream to return from getInputStream method.
@param out Output stream to return from getOutputStream method.
*/
public ServerAuthenticatorNone(InputStream in, OutputStream out){
this.in = in;
this.out = out;
}
/**
Grants access to everyone.Removes authentication related bytes from
the stream, when a SOCKS5 connection is being made, selects an
authentication NONE.
*/
public ServerAuthenticator startSession(Socket s)
throws IOException{
PushbackInputStream in = new PushbackInputStream(s.getInputStream());
OutputStream out = s.getOutputStream();
int version = in.read();
if(version == 5){
if(!selectSocks5Authentication(in,out,0))
return null;
}else if(version == 4){
//Else it is the request message allready, version 4
in.unread(version);
}else
return null;
return new ServerAuthenticatorNone(in,out);
}
/**
Get input stream.
@return Input stream speciefied in the constructor.
*/
public InputStream getInputStream(){
return in;
}
/**
Get output stream.
@return Output stream speciefied in the constructor.
*/
public OutputStream getOutputStream(){
return out;
}
/**
Allways returns null.
@return null
*/
public UDPEncapsulation getUdpEncapsulation(){
return null;
}
/**
* Checks the request. For this stub always return true.
*
* @returns true if request is OK or false if its not.
*/
public boolean checkRequest(ProxyMessage msg) {
return true;
}
/**
* Checks the request. For this stub always return true.
*/
public boolean checkRequest(java.net.DatagramPacket dp, boolean out){
return true;
}
/**
Does nothing.
*/
public void endSession(){
}
/**
Convinience routine for selecting SOCKSv5 authentication.
<p>
This method reads in authentication methods that client supports,
checks wether it supports given method. If it does, the notification
method is written back to client, that this method have been chosen
for authentication. If given method was not found, authentication
failure message is send to client ([5,FF]).
@param in Input stream, version byte should be removed from the stream
before calling this method.
@param out Output stream.
@param methodId Method which should be selected.
@return true if methodId was found, false otherwise.
*/
static public boolean selectSocks5Authentication(InputStream in,
OutputStream out,
int methodId)
throws IOException{
int num_methods = in.read();
if (num_methods <= 0) return false;
byte method_ids[] = new byte[num_methods];
byte response[] = new byte[2];
boolean found = false;
response[0] = (byte) 5; //SOCKS version
response[1] = (byte) 0xFF; //Not found, we are pessimistic
int bread = 0; //bytes read so far
while(bread < num_methods)
bread += in.read(method_ids,bread,num_methods-bread);
for(int i=0;i<num_methods;++i)
if(method_ids[i] == methodId){
found = true;
response[1] = (byte) methodId;
break;
}
out.write(response);
return found;
}
}

View File

@ -0,0 +1,73 @@
package net.sourceforge.jsocks.socks.server;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
/**
This class implements SOCKS5 User/Password authentication scheme as
defined in rfc1929,the server side of it.
*/
public class UserPasswordAuthenticator extends ServerAuthenticatorNone{
static final int METHOD_ID = 2;
UserValidation validator;
/**
Construct a new UserPasswordAuthentication object, with given
UserVlaidation scheme.
@param validator UserValidation to use for validating users.
*/
public UserPasswordAuthenticator(UserValidation validator){
this.validator = validator;
}
@Override
public ServerAuthenticator startSession(Socket s) throws IOException{
InputStream in = s.getInputStream();
OutputStream out = s.getOutputStream();
if(in.read() != 5) return null; //Drop non version 5 messages.
if(!selectSocks5Authentication(in,out,METHOD_ID))
return null;
if(!doUserPasswordAuthentication(s,in,out))
return null;
return new ServerAuthenticatorNone(in,out);
}
//Private Methods
//////////////////
private boolean doUserPasswordAuthentication(Socket s,
InputStream in,
OutputStream out)
throws IOException{
int version = in.read();
if(version != 1) return false;
int ulen = in.read();
if(ulen < 0) return false;
byte[] user = new byte[ulen];
in.read(user);
int plen = in.read();
if(plen < 0) return false;
byte[] password = new byte[plen];
in.read(password);
if(validator.isUserValid(new String(user), new String(password),s)){
//System.out.println("user valid");
out.write(new byte[]{1,0});
}else{
//System.out.println("user invalid");
out.write(new byte[]{1,1});
return false;
}
return true;
}
}

View File

@ -0,0 +1,21 @@
package net.sourceforge.jsocks.socks.server;
/**
Interface which provides for user validation, based on user name
password and where it connects from.
*/
public interface UserValidation{
/**
Implementations of this interface are expected to use some or all
of the information provided plus any information they can extract
from other sources to decide wether given user should be allowed
access to SOCKS server, or whatever you use it for.
@return true to indicate user is valid, false otherwise.
@param username User whom implementation should validate.
@param password Password this user provided.
@param connection Socket which user used to connect to the server.
*/
boolean isUserValid(String username,String password,
java.net.Socket connection);
}

View File

@ -0,0 +1,125 @@
package net.sourceforge.jsocks.test;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import java.io.*;
import net.*;
/** Plain SOCKS unaware echo client.*/
public class Echo implements Runnable{
private int port;
private InetAddress peerIp;
private Socket ss;
private InputStream in;
private OutputStream out;
private static final int BUF_SIZE = 1024;
public Echo(String host,int port,String peerHost,int peerPort)
throws IOException,UnknownHostException{
this.peerIp = InetAddress.getByName(peerHost);
this.port = port;
ss = new Socket(host, port,peerIp,peerPort);
out = ss.getOutputStream();
in = ss.getInputStream();
System.out.println("Connected...");
System.out.println("TO: "+host+":"+port);
System.out.println("LocalAddress: "+ss.getLocalAddress().getHostAddress()
+":"+ss.getLocalPort());
}
public Echo(String host,int port)
throws IOException,UnknownHostException{
System.out.println("Connecting...");
ss = new Socket(host, port);
out = ss.getOutputStream();
in = ss.getInputStream();
System.out.println("TO: "+host+":"+port);
System.out.println("LocalAddress: "+ss.getLocalAddress().getHostAddress()
+":"+ss.getLocalPort());
}
public void send(String s) throws IOException{
//System.out.println("Sending:"+s);
out.write(s.getBytes());
}
public void run(){
byte[] buf = new byte[1024];
int bytes_read;
try{
while((bytes_read = in.read(buf)) > 0){
System.out.write(buf,0,bytes_read);
System.out.flush();
}
}catch(IOException io_ex){
io_ex.printStackTrace();
}
}
public static void usage(){
System.err.print(
"Usage: java Echo host port [peerHost peerPort]\n");
}
public static void main(String args[]){
int port;
String host,peerHost;
int peerPort;
Echo echo = null;
if(args.length > 1){
try{
host = args[0];
port = Integer.parseInt(args[1]);
if(args.length ==4){
peerHost = args[2];
peerPort =Integer.parseInt(args[3]);
echo = new Echo(host,port,peerHost,peerPort);
}else{
echo = new Echo(host,port);
}
Thread thread = new Thread(echo);
thread.start();
BufferedReader in = new BufferedReader(
new InputStreamReader(System.in));
String s;
s = in.readLine();
Thread.currentThread().setPriority(Thread.NORM_PRIORITY);
while(s != null){
echo.send(s+"\r\n");
s = in.readLine();
}
}catch(IOException io_ex){
io_ex.printStackTrace();
System.exit(1);
}catch(NumberFormatException num_ex){
usage();
num_ex.printStackTrace();
System.exit(1);
}finally{
if(echo!=null) try{echo.ss.close();}catch(Exception e){}
}
}else{
usage();
}
}
}//End of class

View File

@ -0,0 +1,129 @@
package net.sourceforge.jsocks.test;
import java.io.*;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import net.sourceforge.jsocks.socks.*;
//import net.sourceforge.jsocks.socks.Proxy;
/** SOCKS aware echo client*/
public class SocksTest implements Runnable{
private int port;
private InetAddress hostIP;
private Socket ss;
private InputStream in;
private OutputStream out;
private static final int BUF_SIZE = 1024;
static final int defaultProxyPort = 1080; //Default Port
static final String defaultProxyHost = "www-proxy"; //Default proxy
public SocksTest(String host,int port)
throws IOException,UnknownHostException,SocksException{
this.port = port;
ss = new SocksSocket(host, port);
out = ss.getOutputStream();
in = ss.getInputStream();
System.out.println("Connected...");
System.out.println("TO: "+host+":"+port);
System.out.println("ViaProxy: "+ss.getLocalAddress().getHostAddress()
+":"+ss.getLocalPort());
}
public void close()throws IOException{
ss.close();
}
public void send(String s) throws IOException{
out.write(s.getBytes());
}
public void run(){
byte[] buf = new byte[1024];
int bytes_read;
try{
while((bytes_read = in.read(buf)) > 0){
System.out.write(buf,0,bytes_read);
}
}catch(IOException io_ex){
io_ex.printStackTrace();
}
}
public static void usage(){
System.err.print(
"Usage: java SocksTest host port [socksHost socksPort]\n");
}
public static void main(String args[]){
int port;
String host;
int proxyPort;
String proxyHost;
if(args.length > 1 && args.length < 5){
try{
host = args[0];
port = Integer.parseInt(args[1]);
proxyPort =(args.length > 3)? Integer.parseInt(args[3])
: defaultProxyPort;
host = args[0];
proxyHost =(args.length > 2)? args[2]
: defaultProxyHost;
Proxy.setDefaultProxy(proxyHost,proxyPort,"KOUKY001");
//Proxy.setDefaultProxy(proxyHost,proxyPort);
InetRange inetRange = new InetRange();
inetRange.add(InetAddress.getByName("localhost"));
Proxy.getDefaultProxy().setDirect(inetRange);
SocksTest st = new SocksTest(host,port);
Thread thread = new Thread(st);
thread.start();
BufferedReader in = new BufferedReader(
new InputStreamReader(System.in));
String s;
s = in.readLine();
while(s != null){
st.send(s+"\r\n");
//try{
//Thread.currentThread().sleep(10);
//}catch(InterruptedException i_ex){
//}
s = in.readLine();
}
st.close();
System.exit(1);
}catch(SocksException s_ex){
System.err.println("SocksException:"+s_ex);
s_ex.printStackTrace();
System.exit(1);
}catch(IOException io_ex){
io_ex.printStackTrace();
System.exit(1);
}catch(NumberFormatException num_ex){
usage();
num_ex.printStackTrace();
System.exit(1);
}
}else{
usage();
}
}
}//End of class

View File

@ -0,0 +1,103 @@
package net.sourceforge.jsocks.test;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.io.*;
import net.sourceforge.jsocks.socks.*;
/** SOCKS aware UDP echo client.<br>
Reads input line by line and sends it to given on command line
host and port, using given proxy, then blocks until reply datagram
recieved, not really echo, single threaded client, I just used it
for testing before UDP actually worked.
*/
public class SocksUDPEcho{
public static void usage(){
System.err.print(
"Usage: java SocksUDPEcho host port [socksHost socksPort]\n");
}
static final int defaultProxyPort = 1080; //Default Port
static final String defaultProxyHost = "www-proxy"; //Default proxy
public static void main(String args[]){
int port;
String host;
int proxyPort;
String proxyHost;
InetAddress ip;
if(args.length > 1 && args.length < 5){
try{
host = args[0];
port = Integer.parseInt(args[1]);
proxyPort =(args.length > 3)? Integer.parseInt(args[3])
: defaultProxyPort;
host = args[0];
ip = InetAddress.getByName(host);
proxyHost =(args.length > 2)? args[2]
: defaultProxyHost;
Proxy.setDefaultProxy(proxyHost,proxyPort);
Proxy p = Proxy.getDefaultProxy();
p.addDirect("lux");
DatagramSocket ds = new Socks5DatagramSocket();
BufferedReader in = new BufferedReader(
new InputStreamReader(System.in));
String s;
System.out.print("Enter line:");
s = in.readLine();
while(s != null){
byte[] data = (s+"\r\n").getBytes();
DatagramPacket dp = new DatagramPacket(data,0,data.length,
ip,port);
System.out.println("Sending to: "+ip+":"+port);
ds.send(dp);
dp = new DatagramPacket(new byte[1024],1024);
System.out.println("Trying to recieve on port:"+
ds.getLocalPort());
ds.receive(dp);
System.out.print("Recieved:\n"+
"From:"+dp.getAddress()+":"+dp.getPort()+
"\n\n"+
new String(dp.getData(),dp.getOffset(),dp.getLength())+"\n"
);
System.out.print("Enter line:");
s = in.readLine();
}
ds.close();
System.exit(1);
}catch(SocksException s_ex){
System.err.println("SocksException:"+s_ex);
s_ex.printStackTrace();
System.exit(1);
}catch(IOException io_ex){
io_ex.printStackTrace();
System.exit(1);
}catch(NumberFormatException num_ex){
usage();
num_ex.printStackTrace();
System.exit(1);
}
}else{
usage();
}
}
}

View File

@ -0,0 +1,241 @@
package net.sourceforge.jsocks.test;
import java.io.*;
import java.net.InetAddress;
import java.net.ServerSocket;
import net.sourceforge.jsocks.socks.*;
import net.sourceforge.jsocks.socks.Proxy;
public class TestClient extends TestService{
/** Proxy which should be used*/
Proxy proxy;
/** Host on which TestServer is running*/
String testHost;
int timeout = 15000;
int acceptTimeout = 0;
BufferedReader in;
Writer out;
public TestClient(Proxy p,String testHost){
this.proxy = p;
this.testHost = testHost;
if(log == null) log = System.out;
}
public void start(){
connectTests(true);
acceptTests(true);
udpTests(true);
connectTests(false);
acceptTests(false);
udpTests(false);
}
void connectTests(boolean useString){
try{
open(ECHO, useString);
testEcho();
s.close();
open(DISCARD, useString);
testDiscard();
s.close();
open(CHARGEN, useString);
for(int i = 0; i< 3;){
try{
testChargen();
break;
}catch(InterruptedIOException ioe){
log("IO interrupted:"+i);
i++;
}
}
s.close();
}catch(IOException ioe){
ioe.printStackTrace();
}
}
void acceptTests(boolean useString){
try{
testAccept(ECHO, useString);
testEcho();
s.close();
testAccept(DISCARD, useString);
testDiscard();
s.close();
testAccept(CHARGEN, useString);
for(int i = 0; i< 3;){
try{
testChargen();
break;
}catch(InterruptedIOException ioe){
log("IO interrupted:"+i);
i++;
}
}
s.close();
}catch(IOException ioe){
ioe.printStackTrace();
}
}
void udpTests(boolean useString){
log("Udp tests are not yet implemented");
}
void testEcho() throws IOException{
log("Testing echo.");
for(int i=0;i<5;++i){
out.write("String number "+i+"\r\n");
out.flush();
log("Echo:"+in.readLine());;
}
log("Echo finished");
}
void testDiscard() throws IOException{
log("Testing discard");
for(int i =0; i < 5;++i){
log("Sending discard message:"+i);
out.write("Discard message:"+i+"\r\n");
out.flush();
}
log("Discard finished");
}
void testChargen() throws IOException{
log("Testing chargen");
String s;
s = in.readLine();
while(s!=null){
log("ChGen:"+s);
s = in.readLine();
}
log("Chargen finished.");
}
void testAccept(int service,boolean useString)throws IOException{
open(CONNECT,useString);
log("Testing accept");
ServerSocket ss;
if(useString)
ss = new SocksServerSocket(proxy,testHost,servicePorts[service]);
else
ss = new SocksServerSocket(proxy,InetAddress.getByName(testHost),
servicePorts[service]);
log("Listenning on "+ss.getInetAddress()+":"+ss.getLocalPort());
ss.setSoTimeout(acceptTimeout);
out.write(""+ss.getLocalPort()+" "+service+"\r\n");
out.flush();
String line = in.readLine();
if(line != null){
log("Accept failed:"+line);
}
s.close();
s = ss.accept();
log("Accepted:"+s);
s.setSoTimeout(timeout);
out = new OutputStreamWriter(s.getOutputStream());
in = new BufferedReader(new InputStreamReader(s.getInputStream()));
ss.close();
}
void open(int service,boolean useString) throws IOException{
if(!useString){
s = new SocksSocket(proxy,InetAddress.getByName(testHost),
servicePorts[service]);
}else{
s = new SocksSocket(proxy,testHost,servicePorts[service]);
}
s.setSoTimeout(timeout);
out = new OutputStreamWriter(s.getOutputStream());
in = new BufferedReader(new InputStreamReader(s.getInputStream()));
}
//Main function
///////////////
static void usage(){
System.err.println(
"Usage: java Testclient testhost proxy [directhosts]");
}
static Proxy initProxy(String ps){
java.util.StringTokenizer st = new java.util.StringTokenizer(ps,",;");
Proxy proxy = null;
while(st.hasMoreElements()){
String entry = st.nextToken();
Proxy p = Proxy.parseProxy(entry);
if( p == null){
log("Proxy "+entry+" invalid.");
return null;
}
p.setChainProxy(proxy);
proxy = p;
}
return proxy;
}
static void addDirectHosts(Proxy p, String directHosts){
java.util.StringTokenizer st = new java.util.StringTokenizer(
directHosts,",;");
while(st.hasMoreElements()){
String entry = st.nextToken();
log("Adding direct host:"+entry);
p.addDirect(entry);
}
}
public static void main(String[] argv){
if(argv.length < 2){
usage();
return;
}
log = System.out;
String testHost = argv[0];
String proxyHost = argv[1];
String directHosts = argv.length >2 ? argv[2] : null;
Proxy p = initProxy(proxyHost);
if(p == null){
log("Can't init proxy.");
return;
}
if(directHosts!=null) addDirectHosts(p,directHosts);
if(p instanceof Socks5Proxy)
((Socks5Proxy) p).resolveAddrLocally(false);
TestClient tc = new TestClient(p,testHost);
tc.start();
}
}

View File

@ -0,0 +1,83 @@
package net.sourceforge.jsocks.test;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import net.*;
/**
Server to used perform tests for SOCKS library.
*/
public class TestServer implements Runnable{
static PrintStream log = null;
int service;
/**
Creates a TestServer object which will listen on the port associated
with given service.
@param service Service to provide
*/
public TestServer(int service){
this.service = service;
}
public void run(){
try{
server(service);
}catch(IOException ioe){
log("Exception:"+ioe);
ioe.printStackTrace();
}
}
//Static functions
/////////////////
/**
Listens on the port associated with given service.
<p>
When connection is accepted, speciefied service is performed.
It is being done in separate thread.
@return Never returns.
*/
static public void server(int service) throws IOException{
ServerSocket ss = new ServerSocket(TestService.servicePorts[service]);
Socket s;
s = ss.accept();
while(s!=null){
TestService st = new TestService(s,service);
Thread t = new Thread(st);
t.start();
s = ss.accept();
}
}
/**
Performs logging.
*/
static synchronized void log(String s){
if(log != null) log.println(s);
}
//Main Function
///////////////
public static void main(String[] args){
log = System.out;
TestService.log = log;
TestServer st;
for( int i = 0; i< TestService.serviceNames.length;++i){
log("Starting service "+TestService.serviceNames[i]+" at port "+
TestService.servicePorts[i]+".");
st = new TestServer(i);
Thread t = new Thread(st);
t.start();
}
}
}

View File

@ -0,0 +1,275 @@
package net.sourceforge.jsocks.test;
import java.io.*;
import java.net.Socket;
import net.*;
/**
Server to used perform tests for SOCKS library.
*/
public class TestService implements Runnable{
static final String chargenSequence = " !\"#$%&'()*+,-./0123456789:;<=>?@"+
"ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefg";
static final String serviceNames[] = {"echo","discard","chargen","connect"};
static final int servicePorts[] = {5678,5679,5680,5681};
static final int ECHO = 0;
static final int DISCARD = 1;
static final int CHARGEN = 2;
static final int CONNECT = 3;
static final int BUF_SIZE = 1024;
static final int CHARGEN_WAIT = 1000; //1 second
static final int MAX_WAIT = 60000; //1 minute
static PrintStream log = null;
//Class constants
Socket s;
int service;
/**
Creates new TestService object, which will perform particular
service on given socket.
@param s Socket on which to perform service.
@param service Service which to provide.
*/
public TestService(Socket s, int service){
this.s = s;
this.service = service;
}
/**
Default constructor.
*/
public TestService(){
this.s = null;
this.service = -1;
}
public void run(){
try{
serve(s,service);
}catch(IOException ioe){
log("Exception:"+ioe);
ioe.printStackTrace();
}
try{ s.close();}catch(IOException ioe){}
}
//Static functions
/////////////////
/**
Maps service name to the integer id, does it in simple
linear search manner.
@param serviceName Name of the service whose id one needs.
@return Integer identifier for this servuce, or -1, if service
can't be found.
*/
static public int getServiceId(String serviceName){
serviceName = serviceName.toLowerCase();
for(int i = 0;i < serviceNames.length;++i)
if(serviceName.equals(serviceNames[i]))
return i;
//Couldn't find one.
return -1;
}
/**
Performs given service on given socket.
<p>
Simply looks up and calls associated method.
@param s Socket on which to perform service.
@param service Id of the service to perform.
@return true if service have been found, false otherwise.
*/
static public boolean serve(Socket s, int service) throws IOException{
switch(service){
case ECHO:
echo(s);
break;
case DISCARD:
discard(s);
break;
case CHARGEN:
chargen(s,CHARGEN_WAIT,MAX_WAIT);
break;
case CONNECT:
connect(s);
break;
default:
log("Unknown service:"+service);
return false;
}
return true;
}
/**
Echos any input on the socket to the output.
Echo is being done line by line.
@param s Socket on which to perform service.
*/
static public void echo(Socket s) throws IOException{
BufferedReader in = new BufferedReader(new InputStreamReader(
s.getInputStream()));
OutputStream out = s.getOutputStream();
log("Starting \"echo\" on "+s);
String line = in.readLine();
while(line != null){
out.write((line+"\n").getBytes());
log(line);
line = in.readLine();
}
log("Echo done.");
}
/**
Reads input from the socket, and does not write anything back.
logs input in line by line fashion.
@param s Socket on which to perform service.
*/
static public void discard(Socket s) throws IOException{
BufferedReader in = new BufferedReader(new InputStreamReader(
s.getInputStream()));
log("Starting discard on "+s);
String line = in.readLine();
while(line != null){
log(line);
line = in.readLine();
}
log("Discard finished.");
}
/**
Generates characters and sends them to the socket.
<p>
Unlike usual chargen (port 19), each next line of the generated
output is send after increasingly larger time intervals. It starts
from wait_time (ms), and each next time wait time is doubled.
Eg. 1 2 4 8 16 32 64 128 256 512 1024 2048 4096 8192 ... well
you got the idea.
<p>
It starts if either connection is clsoed or the wait time grows
bigger than max_wait.
@param s Socket on which to perform service.
@param wait_time Time in ms, from which timing sequence should begin.
@param max_wait Time in ms, after reaching timeout greater than this
value, chargen will stop.
*/
static public void chargen(Socket s,long wait_time,long max_wait)
throws IOException{
byte[] buf = chargenSequence.getBytes();
int pos = 0;
OutputStream out = s.getOutputStream();
InputStream in = s.getInputStream();
s.setSoTimeout(100); //0.1 ms
log("Starting \"chargen\" on "+s);
while(true){
log("Sending message.");
out.write(buf,pos,buf.length - pos);
out.write(buf,0,pos);
out.write("\n".getBytes());
pos++;
try{
if(wait_time > max_wait) break;
log("Going to sleep for "+wait_time+" ms.");
Thread.currentThread().sleep(wait_time);
wait_time *= 2;
if(in.read() < 0) break; //Connection closed
}catch(InterruptedException ie){
}catch(InterruptedIOException ioe){
}
}
log("Chargen finished.");
}
/**
Models connect back situation.
<p>
Reads a line from the socket connection, line should be in the
form port service_id. Connects back to the remote host to port
specified in the line, if successful performs a service speciefied
by id on that new connection. If accept was successful closes the
control connection, else outputs error message, and then closes
the connection.
@param s Control connection.
*/
static public void connect(Socket s)throws IOException{
String line = null;
Socket sock;
int port;
int service_id;
BufferedReader in = new BufferedReader(new InputStreamReader(
s.getInputStream()));
OutputStream out = s.getOutputStream();
log("Starting \"connect\" on "+s);
line = in.readLine();
if(line == null) return; //They closed connection
java.util.StringTokenizer st = new java.util.StringTokenizer(line);
if(st.countTokens() < 2){ //We need at least 'port' and "id"
out.write("Expect: port serviceId.\n".getBytes());
log("Invalid arguments.");
return;
}
try{
port = Integer.parseInt(st.nextToken());
service_id = Integer.parseInt(st.nextToken());
}catch(NumberFormatException nfe){
out.write("Expect: port serviceId.\n".getBytes());
log("Invalid arguments.");
return;
}
try{
log("Connecting to "+s.getInetAddress()+":"+port);
sock = new Socket(s.getInetAddress(),port);
}catch(IOException ioe){
out.write(("Connect to "+s.getInetAddress()+
":"+port+" failed").getBytes());
log("Connect failed.");
return;
}
s.close();
log("About to serve "+service_id);
serve(sock,service_id);
}
/**
Pipes data from the input stream to the output.
@param in Input stream.
@param out Output stream.
*/
static public void pipe(InputStream in, OutputStream out)
throws IOException{
byte[] buf = new byte[BUF_SIZE];
int bread = 0;
while(bread >= 0){
bread = in.read(buf);
out.write(buf,0,bread);
}
}
/**
Performs logging.
*/
static synchronized void log(String s){
if(log != null) log.println(s);
}
}

View File

@ -0,0 +1,151 @@
package net.sourceforge.jsocks.test;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.io.*;
import net.*;
/**
Plain SOCKS unaware UDP echo server and client.
*/
public class UDPEcho implements Runnable{
private int port;
private InetAddress hostIP;
private DatagramSocket sock;
private static final int BUF_SIZE = 1024;
public UDPEcho(String host,int port)
throws IOException,UnknownHostException{
this.hostIP = InetAddress.getByName(host);
this.port = port;
sock = new DatagramSocket();
System.out.println("UDP: "+sock.getLocalAddress()+":"+
sock.getLocalPort());
//sock.connect(hostIP,port);
}
public void send(String s) throws IOException{
System.out.println("Sending:"+s);
DatagramPacket packet = new DatagramPacket(s.getBytes(),
s.length(),
hostIP,
port);
sock.send(packet);
}
public void run(){
byte[] buf = new byte[BUF_SIZE];
DatagramPacket incomingData = new DatagramPacket(buf,buf.length);
try{
while(true){
sock.receive(incomingData);
System.out.println("UDP From:"+
incomingData.getAddress().getHostAddress()+":"+
incomingData.getPort());
System.out.println(new String(incomingData.getData(),
0,incomingData.getLength()));
System.out.flush();
incomingData.setLength(buf.length);
}
}catch(IOException io_ex){
io_ex.printStackTrace();
}
}
public static void usage(){
System.err.print(
"Usage: java UDPEcho host port\n"+
"OR\n"+
"Usage: java UDPEcho port\n");
}
public static void doEcho(int port)throws IOException{
byte[] buf = new byte[BUF_SIZE];
DatagramPacket packet = new DatagramPacket(buf,buf.length);
DatagramSocket sock = new DatagramSocket(port);
System.out.println("Starting UDP echo on"+
sock.getLocalAddress().getHostAddress()+
":"+sock.getLocalPort());
while(true){
try{
sock.receive(packet);
sock.send(packet);
System.out.print(
"UDP From: "+packet.getAddress().getHostAddress()+":"+
packet.getPort()+
"\n"+
new String(packet.getData(),0,packet.getLength())+
"\n"
);
System.out.flush();
packet.setLength(buf.length);
//packet = new DatagramPacket(buf,buf.length);
}catch(IOException io_ex){
}
}
}
public static void main(String args[]){
int port;
String host;
if(args.length == 1){
try{
port = Integer.parseInt(args[0]);
doEcho(port);
}catch(IOException io_ex){
io_ex.printStackTrace();
System.exit(1);
}catch(NumberFormatException num_ex){
num_ex.printStackTrace();
System.exit(1);
}
}else if(args.length == 2){
try{
host = args[0];
port = Integer.parseInt(args[1]);
UDPEcho ut = new UDPEcho(host,port);
Thread thread = new Thread(ut);
thread.start();
BufferedReader in = new BufferedReader(
new InputStreamReader(System.in));
String s;
System.out.print("Enter datagram:");
s = in.readLine();
while(s != null){
ut.send(s);
try{
Thread.currentThread().sleep(100);
}catch(InterruptedException i_ex){
}
System.out.print("Enter datagram:");
s = in.readLine();
}
System.exit(1);
}catch(IOException io_ex){
io_ex.printStackTrace();
System.exit(1);
}catch(NumberFormatException num_ex){
num_ex.printStackTrace();
System.exit(1);
}
}else{
usage();
}
}
}//End of class

View File

@ -0,0 +1,41 @@
package net.sourceforge.jsocks.test;
import net.sourceforge.jsocks.socks.*;
import net.sourceforge.jsocks.socks.server.*;
import java.net.Socket;
/** Test file for UserPasswordAuthentictor */
public class UPSOCKS implements UserValidation{
String user, password;
UPSOCKS(String user,String password){
this.user = user;
this.password = password;
}
public boolean isUserValid(String user,String password,Socket s){
System.err.println("User:"+user+"\tPassword:"+password);
System.err.println("Socket:"+s);
return (user.equals(this.user) && password.equals(this.password));
}
public static void main(String args[]){
String user, password;
if(args.length == 2){
user = args[0];
password = args[1];
}else{
user = "user";
password = "password";
}
UPSOCKS us = new UPSOCKS(user,password);
UserPasswordAuthenticator auth = new UserPasswordAuthenticator(us);
ProxyServer server = new ProxyServer(auth);
server.start(1080);
}
}