📄 sockssocketimpl.java
字号:
return port;
}
private static final byte[] getPort(byte[] b, int offset)
{
byte[] port=new byte[2];
port[0]=b[offset];
port[1]=b[offset+1];
return port;
}
private static final int getPortValue(
byte[] b,int offset)
{
int port=b[offset]<0?(short)b[offset]+256:b[offset];
port<<=8;
offset++;
port+=b[offset]<0?(short)b[offset]+256:b[offset];
return port;
}
private static final InetAddress getInetAddress(
int addressType,byte[] b,int offset)throws IOException
{
String host;
switch(addressType)
{
case IP_V4:
StringBuffer destinationHost=new StringBuffer(16);
for(int i=offset;i<offset+4;i++)
{
destinationHost.append(b[i]<0?(short)(b[i]+256):(short)b[i]);
if(i<offset+3)
destinationHost.append('.');
}
host=destinationHost.toString();
break;
case DOMAINNAME:
int length=b[offset++];
if(length<0)length+=256;
host=new String(b,offset,length);
break;
case IP_V6:
throw new IOException("Error: IPV6 is not supported.");
default:
throw new IOException("Error: Unknown IP address type.");
}
return InetAddress.getByName(host);
}
/**
* Setup a SOCKS connection to the remote host through the SOCKS server
*/
private synchronized void doSOCKSConnect()throws IOException
{
if(remoteAddress==null || remotePort==null)
throw new IOException("Error: You Cann't connect without defining the IP address and port of remote host.");
for(int i=0;i<5;i++)//Try fivet time since the proxy server is possible very busy.
{
try
{
if(stream)
{
clientSocket=new Socket(proxyAddress,proxyPort,localAddress,localport);
localAddress=clientSocket.getLocalAddress();
localport=clientSocket.getLocalPort();
}
else//DatagramSocket
{
clientSocket=new Socket(proxyAddress,proxyPort,localAddress,0);
}
clientSocket.setSoTimeout(timeout);
break;
}
catch(IOException e)
{
if(i<4)
{
try
{
Thread.sleep(200);
}
catch (InterruptedException ie){}
}
else
{
close();
throw e;
}
}
}
switch(version)
{
case SOCKS_VERSION_4A:
request_of_V4A(COMMAND_CONNECT,remoteAddress,remotePort,remoteHost);
reply_of_V4A(false);
break;
case SOCKS_VERSION_5:
methodSelection_of_V5();
if(stream)
{
request_of_V5(COMMAND_CONNECT,NULL,remoteAddressType,remoteAddress,remotePort);
reply_of_V5(COMMAND_CONNECT,false);
}
else
{
// request_of_V5(COMMAND_UDP_ASSOCIATE,INTERFACE_REQUEST,remoteAddressType,remoteAddress,remotePort);
request_of_V5(COMMAND_UDP_ASSOCIATE,NULL,remoteAddressType,remoteAddress,remotePort);
reply_of_V5(COMMAND_UDP_ASSOCIATE,false);
}
break;
}
}
private void request_of_V4A(int command,
byte[] destinationAddress,byte[] destinationPort,
byte[] destinationHost)throws IOException
{
outputBuffer.reset();
outputBuffer.write(SOCKS_VERSION_4A);
outputBuffer.write(command);
outputBuffer.write(destinationPort);
outputBuffer.write(destinationAddress);
if(password!=null)
outputBuffer.write(password);//It's the USERID in SOCKS4A.
outputBuffer.write(NULL);//terminate in NULL byte
if(destinationAddress[0]==0)//Such a destination IP address is inadmissible
{
outputBuffer.write(destinationHost);
outputBuffer.write(NULL);//terminate in NULL byte
}
OutputStream out=clientSocket.getOutputStream();
outputBuffer.writeTo(out);
out.flush();
}
private int serverBoundAddressType;
private InetAddress serverBoundAddress=null;
private int serverBoundPort=0;
private int remoteBoundAddressType;
private byte[] remoteBoundAddress=null;
private byte[] remoteBoundPort=null;
/**
* Set command for the specific SOCKS proxy serer.
*/
private int command=COMMAND_CONNECT;
private void reply_of_V4A(boolean isGetRemoteBoundParamaters)throws IOException
{
int count;
String errorMessage=null;
byte[] buffer=new byte[8];
InputStream in=clientSocket.getInputStream();
while((count= in.read(buffer)) >= 0)
{
if(count==0)
continue;
else if(count<8 || buffer[0]!=NULL)
errorMessage="failed to parse the malformed reply from the socks server.";
else
{
switch(buffer[1])
{
case REQUEST_GRANTED:
if(isGetRemoteBoundParamaters)
{
remoteBoundPort=getPort(buffer,2);
remoteBoundAddress=getAddress(IP_V4,buffer,4);
}
else
{
serverBoundPort=getPortValue(buffer,2);
serverBoundAddress=getInetAddress(IP_V4,buffer,4);
}
break;
case REQUEST_REJECTED:
errorMessage="request rejected or failed";
break;
case REQUEST_REJECTED_NO_IDENTD:
errorMessage="request rejected becasue SOCKS server cannot connect to identd on the client";
break;
case REQUEST_REJECTED_DIFF_IDENTS:
errorMessage="request rejected because the client program and identd report different user-ids";
break;
}
}
if(errorMessage!=null)
{
close();
throw new IOException("("+proxyAddress.getHostAddress()+":"+proxyPort+") "+errorMessage);
}
break;
}
if(command!=COMMAND_BIND)return;
{
}
}private String Username_AND_Password_Authentication_of_V5()throws IOException
{
outputBuffer.reset();
outputBuffer.write(0x01);
if(username==null)
outputBuffer.write(0x0);
else
{
outputBuffer.write(username.length);
outputBuffer.write(username);
}
if(password==null)
outputBuffer.write(0x0);
else
{
outputBuffer.write(password.length);
outputBuffer.write(password);
}
OutputStream out=clientSocket.getOutputStream();
outputBuffer.writeTo(out);
out.flush();
int count;
String errorMessage=null;
byte[] buffer=new byte[2];
InputStream in=clientSocket.getInputStream();
while((count= in.read(buffer)) >= 0)
{
if(count==0)
continue;
else if(count<2 || buffer[0]!=0x01)
{
errorMessage="failed to parse the authentication reply from the socks server.";
}
else if(buffer[1]!=0x0)
{
errorMessage="failed to through the authentication reply from the socks server.";
}
if(errorMessage!=null)
{
close();
throw new IOException("("+proxyAddress.getHostAddress()+":"+proxyPort+") "+errorMessage);
}
break;
}
return errorMessage;
}
private void methodSelection_of_V5()throws IOException
{
outputBuffer.reset();
outputBuffer.write(SOCKS_VERSION_5);
//Now only complement the negotiation methods of
// NO_AUTHENTICATION_REQUIRED and USERNAME_AND_PASSWORD
outputBuffer.write(2);//the number of method identifier octets that appear in the METHODS field
outputBuffer.write(NO_AUTHENTICATION_REQUIRED);
// outputBuffer.write(GSSAPI);
outputBuffer.write(USERNAME_AND_PASSWORD);
// outputBuffer.write(CHAP);
OutputStream out=clientSocket.getOutputStream();
outputBuffer.writeTo(out);
out.flush();
int method;
if(username!=null || password!=null)
method=USERNAME_AND_PASSWORD;
else
method=NO_AUTHENTICATION_REQUIRED;
int count;
String errorMessage=null;
byte[] buffer=new byte[2];
InputStream in=clientSocket.getInputStream();
while((count= in.read(buffer)) >= 0)
{
if(count==0)
continue;
else if(count<2 || buffer[0]!=SOCKS_VERSION_5)
errorMessage="failed to parse the reply from the socks server.";
else
{
switch(buffer[1])
{
case NO_AUTHENTICATION_REQUIRED:
break;
case GSSAPI:
errorMessage="GSSAPI negotiation hasn't been still complemented.";
break;
case USERNAME_AND_PASSWORD:
errorMessage=Username_AND_Password_Authentication_of_V5();
break;
case CHAP:
errorMessage="CHAP negotiation hasn't been still complemented.";
break;
case (byte)NO_ACCEPTABLE_METHODS:
errorMessage="No acceptable negotiation method.";
break;
default:
errorMessage="The negotiation method with a METHOD number of "+(int)buffer[1]+" hasn't been still complemented.";
break;
}
}
if(errorMessage!=null)
{
close();
throw new IOException("("+proxyAddress.getHostAddress()+":"+proxyPort+") "+errorMessage);
}
break;
}
}
private void request_of_V5(int command,int flag,
int addressType,byte[] destinationAddress,byte[] destinationPort)throws IOException
{
outputBuffer.reset();
outputBuffer.write(SOCKS_VERSION_5);
outputBuffer.write(command);
outputBuffer.write(flag);//command dependent flag (defaults to X'00')
if(command!=COMMAND_UDP_ASSOCIATE)
{
outputBuffer.write(addressType);
if(addressType==DOMAINNAME)
outputBuffer.write(destinationAddress.length);
outputBuffer.write(destinationAddress);
outputBuffer.write(destinationPort);
}
else
{
outputBuffer.write(IP_V4);
outputBuffer.write(getAddress(localAddress));
outputBuffer.write(getPort(localport));
}
OutputStream out=clientSocket.getOutputStream();
outputBuffer.writeTo(out);
out.flush();
}
private void reply_of_V5(int command,boolean isGetRemoteBoundParamaters)throws IOException
{
int count;
String errorMessage=null;
byte[] buffer=new byte[64];
InputStream in=clientSocket.getInputStream();
while((count= in.read(buffer)) >= 0)
{
if(count==0)
continue;
else if(count<8 || buffer[0]!=SOCKS_VERSION_5)
errorMessage="failed to parse the reply from the socks server.";
else
{
switch(buffer[1])
{
case SUCCEEDED:
int tempBoundAddressType=buffer[3];
int offset=4;
InetAddress tempBoundAddress=getInetAddress(tempBoundAddressType,buffer,offset);
switch(tempBoundAddressType)
{
case DOMAINNAME:
offset+=(buffer[offset+1]<0?buffer[offset+1]+256:buffer[offset+1])+1;
break;
case IP_V4:
offset+=4;
break;
// case IP_V6:
default:
offset+=16;
}
int tempBoundPort=getPortValue(buffer,offset);
if(isGetRemoteBoundParamaters)
{
// remoteBoundAddressType=tempBoundAddressType;
// remoteBoundAddress=tempBoundAddress;
// remoteBoundPort=tempBoundPort;
}
else
{
serverBoundAddressType=tempBoundAddressType;
serverBoundAddress=tempBoundAddress;
serverBoundPort=tempBoundPort;
}
break;
case FAILURE:
errorMessage="general SOCKS server failure";
break;
case NOT_ALLOWED:
errorMessage="connection not allowed by ruleset";
break;
case NETWORK_UNREACHABLE:
errorMessage="Network unreachable";
break;
case HOST_UNREACHABLE:
errorMessage="Host unreachable";
break;
case REFUSED:
errorMessage="Connection refused";
break;
case TTL_EXPIRED:
errorMessage="TTL expired";
break;
case COMMAND_NOT_SUPPORTED:
errorMessage="Command not supported";
break;
case ADDRESS_TYPE_NOT_SUPPORTED:
errorMessage="Address type not supported";
break;
case INVALID_ADDRESS:
errorMessage="Invalid address";
break;
default:
errorMessage="unknown reply code ("+(int)buffer[1]+")";
break;
}
}
if(errorMessage!=null)
{
close();
throw new IOException("("+proxyAddress.getHostAddress()+":"+proxyPort+") "+errorMessage);
}
break;
}
}
/**
* Close the SocksSocket() connection to the SOCKS server.
*
* @exception IOException if an I/O error occurs when closing this socket.
*/
protected void close() throws IOException
{
if (clientSocket != null)
{
try
{
clientSocket.close();
}
catch(java.io.IOException e)
{
}
clientSocket=null;
}
else if(clientDatagramSocket!=null)
{
clientDatagramSocket.close();
clientDatagramSocket=null;
}
}
/*
* instance variable for SO_TIMEOUT
*/
private int timeout=15000;//A timeout of zero is interpreted as an infinite timeout.
/*
* instance variable for TCP_NODELAY
*/
private boolean tcpNoDelay=false;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -