parent
79b8b744c7
commit
86d5ebc27b
|
@ -0,0 +1,3 @@
|
||||||
|
ant compile
|
||||||
|
ant jar
|
||||||
|
cp bin/jar/asocks.jar ../Orbot/libs
|
|
@ -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>
|
||||||
|
|
|
@ -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 |
|
@ -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.
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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>
|
||||||
|
<
|
|
@ -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;
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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()};
|
||||||
|
}
|
||||||
|
}
|
|
@ -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]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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;
|
||||||
|
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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;
|
||||||
|
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
}
|
|
@ -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;
|
||||||
|
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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
|
||||||
|
|
|
@ -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();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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();
|
||||||
|
}
|
||||||
|
//*/
|
||||||
|
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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();
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
|
@ -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
|
|
@ -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
|
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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();
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue