168 lines
4.1 KiB
Java
168 lines
4.1 KiB
Java
package com.runjva.sourceforge.jsocks.protocol;
|
|
|
|
import java.io.DataInputStream;
|
|
import java.io.IOException;
|
|
import java.io.InputStream;
|
|
import java.io.OutputStream;
|
|
import java.net.InetAddress;
|
|
import java.net.UnknownHostException;
|
|
|
|
/**
|
|
* SOCKS4 Reply/Request message.
|
|
*/
|
|
|
|
class Socks4Message extends ProxyMessage {
|
|
|
|
private byte[] msgBytes;
|
|
private int msgLength;
|
|
|
|
/**
|
|
* Server failed reply, cmd command for failed request
|
|
*/
|
|
public Socks4Message(final 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(final int cmd, final InetAddress ip, final int port) {
|
|
this(0, cmd, ip, port, null);
|
|
}
|
|
|
|
/**
|
|
* Client request
|
|
*/
|
|
public Socks4Message(final int cmd, final InetAddress ip, final int port,
|
|
final String user) {
|
|
this(SOCKS_VERSION, cmd, ip, port, user);
|
|
}
|
|
|
|
/**
|
|
* Most general constructor
|
|
*/
|
|
public Socks4Message(final int version, final int cmd,
|
|
final InetAddress ip, final int port, final 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) {
|
|
final 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(final InputStream in, final boolean clientMode)
|
|
throws IOException {
|
|
msgBytes = null;
|
|
read(in, clientMode);
|
|
}
|
|
|
|
public void read(final InputStream in) throws IOException {
|
|
read(in, true);
|
|
}
|
|
|
|
public void read(final InputStream in, final boolean clientMode)
|
|
throws IOException {
|
|
final DataInputStream d_in = new DataInputStream(in);
|
|
version = d_in.readUnsignedByte();
|
|
command = d_in.readUnsignedByte();
|
|
if (clientMode && (command != REPLY_OK)) {
|
|
String errMsg;
|
|
// FIXME: Range should be replaced with cases.
|
|
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();
|
|
final byte[] addr = new byte[4];
|
|
d_in.readFully(addr);
|
|
ip = bytes2IP(addr);
|
|
host = ip.getHostName();
|
|
if (!clientMode) {
|
|
int b = in.read();
|
|
// FIXME: Hope there are no idiots with user name bigger than this
|
|
final 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(final OutputStream out) throws IOException {
|
|
if (msgBytes == null) {
|
|
final Socks4Message msg;
|
|
msg = new Socks4Message(version, command, ip, port, user);
|
|
msgBytes = msg.msgBytes;
|
|
msgLength = msg.msgLength;
|
|
}
|
|
out.write(msgBytes);
|
|
}
|
|
|
|
// Class methods
|
|
static InetAddress bytes2IP(final byte[] addr) {
|
|
final String s = bytes2IPV4(addr, 0);
|
|
try {
|
|
return InetAddress.getByName(s);
|
|
} catch (final 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;
|
|
|
|
}
|