control_socket = new Socket( Proxy.NO_PROXY );
control_socket.connect( new InetSocketAddress( socks_host, socks_port ));
DataOutputStream dos = new DataOutputStream( new BufferedOutputStream( control_socket.getOutputStream(), 256 ));
DataInputStream dis = new DataInputStream( control_socket.getInputStream());
dos.writeByte( (byte)5 ); // socks 5
dos.writeByte( (byte)2 ); // 2 methods
dos.writeByte( (byte)0 ); // no auth
dos.writeByte( (byte)2 ); // user/pw
dos.flush();
dis.readByte(); // version byte
byte method = dis.readByte();
if ( method != 0 && method != 2 ){
throw new IOException( "SOCKS 5: no valid method [" + method + "]" );
}
// auth
if ( method == 2 ) {
dos.writeByte( (byte)1 ); // user/pw version
dos.writeByte( (byte)socks_user.length() ); // user length
dos.write( socks_user.getBytes() );
dos.writeByte( (byte)socks_password.length() ); // password length
dos.write( socks_password.getBytes() );
dos.flush();
dis.readByte(); // version byte
byte status = dis.readByte();
if ( status != 0 ){
throw( new IOException( "SOCKS 5: authentication fails [status=" +status+ "]" ));
}
}
String mapped_ip;
if ( target.isUnresolved() || target.getAddress() == null ){
// deal with long "hostnames" that we get for, e.g., I2P destinations
mapped_ip = AEProxyFactory.getAddressMapper().internalise( target.getHostName() );
}else{
mapped_ip = target.getAddress().getHostName();
}
dos.writeByte( (byte)5 ); // version
dos.writeByte( (byte)3 ); // udp associate
dos.writeByte( (byte)0 ); // reserved
dos.writeByte((byte)1);
dos.write( new byte[4] );
dos.writeShort( (short)delegate.getPort()); // port
dos.flush();
dis.readByte(); // ver
byte reply = dis.readByte();
if ( reply != 0 ){
throw( new IOException( "SOCKS 5: udp association fails [reply=" +reply+ "]" ));
}
dis.readByte(); // reserved
InetAddress relay_address;
byte atype = dis.readByte();
if ( atype == 1 ){
byte[] bytes = new byte[4];
dis.readFully( bytes );
relay_address = InetAddress.getByAddress( bytes );
}else if ( atype == 3 ){
byte len = dis.readByte();
byte[] bytes = new byte[(int)len&0xff ];
dis.readFully( bytes );
relay_address = InetAddress.getByName( new String( bytes ));
}else{
byte[] bytes = new byte[16];
dis.readFully( bytes );
relay_address = InetAddress.getByAddress( bytes );
}
int relay_port = ((dis.readByte()<<8)&0xff00) | (dis.readByte() & 0x00ff );
if ( relay_address.isAnyLocalAddress()){
relay_address = control_socket.getInetAddress();
}