package org.appwork.utils.net.httpconnection;
import java.io.IOException;
import java.net.ConnectException;
import java.net.Socket;
import java.net.SocketException;
import java.net.URL;
import org.appwork.utils.StringUtils;
public class Socks5HTTPConnectionImpl extends SocksHTTPconnection {
public Socks5HTTPConnectionImpl(final URL url, final HTTPProxy proxy) {
super(url, proxy);
}
@Override
protected void authenticateProxyPlain() throws IOException {
try {
final String user = this.proxy.getUser() == null ? "" : this.proxy.getUser();
final String pass = this.proxy.getPass() == null ? "" : this.proxy.getPass();
this.proxyRequest.append("->AUTH user:pass\r\n");
final byte[] username = user.getBytes("ISO-8859-1");
final byte[] password = pass.getBytes("ISO-8859-1");
/* must be 1 */
this.socksoutputstream.write((byte) 1);
/* send username */
this.socksoutputstream.write((byte) username.length);
this.socksoutputstream.write(username);
/* send password */
this.socksoutputstream.write((byte) password.length);
this.socksoutputstream.write(password);
/* read response, 2 bytes */
final byte[] resp = this.readResponse(2);
if (resp[0] != 1) { throw new ProxyConnectException(this.proxy); }
if (resp[1] != 0) {
this.proxyRequest.append("<-AUTH Invalid!\r\n");
throw new ProxyAuthException(this.proxy);
} else {
this.proxyRequest.append("<-AUTH Valid!\r\n");
}
} catch (final IOException e) {
try {
this.sockssocket.close();
} catch (final Throwable e2) {
}
if (e instanceof HTTPProxyException) { throw e; }
throw new ProxyConnectException(e, this.proxy);
}
}
@Override
protected Socket establishConnection() throws IOException {
try {
/* socks5 */
this.socksoutputstream.write((byte) 5);
/* tcp/ip connection */
this.socksoutputstream.write((byte) 1);
/* reserved */
this.socksoutputstream.write((byte) 0);
/* we use domain names */
this.socksoutputstream.write((byte) 3);
/* send domain name */
this.proxyRequest.append("->SEND tcp connect request by domain\r\n");
final byte[] domain = this.httpHost.getBytes("ISO-8859-1");
this.socksoutputstream.write((byte) domain.length);
this.socksoutputstream.write(domain);
/* send port */
/* network byte order */
this.socksoutputstream.write(this.httpPort >> 8 & 0xff);
this.socksoutputstream.write(this.httpPort & 0xff);
this.socksoutputstream.flush();
/* read response, 4 bytes and then read rest of response */
final byte[] resp = this.readResponse(4);
if (resp[0] != 5) { throw new ProxyConnectException("Socks5HTTPConnection: invalid Socks5 response", this.proxy); }
switch (resp[1]) {
case 0:
break;
case 3:
throw new SocketException("Network is unreachable");
case 4:
throw new SocketException("Host is unreachable");
case 5:
throw new ConnectException("Connection refused");
case 1:
case 2:
throw new ProxyConnectException("Socks5HTTPConnection: connection not allowed by ruleset", this.proxy);
case 6:
case 7:
case 8:
throw new ProxyConnectException("Socks5HTTPConnection: could not establish connection, status=" + resp[1], this.proxy);
}
if (resp[3] == 1) {
/* ip4v response */
this.readResponse(4 + 2);
this.proxyRequest.append("<-CONNECT IP\r\n");
} else if (resp[3] == 3) {
/* domain name response */
this.readResponse(1 + domain.length + 2);
this.proxyRequest.append("<-CONNECT Domain\r\n");
} else {
throw new ProxyConnectException("Socks5HTTPConnection: unsupported address Type " + resp[3], this.proxy);
}
return this.sockssocket;
} catch (final IOException e) {
try {
this.sockssocket.close();
} catch (final Throwable e2) {
}
if (e instanceof HTTPProxyException) { throw e; }
throw new ProxyConnectException(e, this.proxy);
}
}
@Override
protected AUTH sayHello() throws IOException {
try {
this.proxyRequest.append("->SOCKS5 Hello\r\n");
/* socks5 */
this.socksoutputstream.write((byte) 5);
/* only none ans password/username auth method */
boolean plainAuthPossible = false;
if (!StringUtils.isEmpty(this.proxy.getUser()) || !StringUtils.isEmpty(this.proxy.getPass())) {
plainAuthPossible = true;
}
if (plainAuthPossible) {
this.socksoutputstream.write((byte) 2);
this.proxyRequest.append("->SOCKS5 Offer None&Plain Authentication\r\n");
/* none */
this.socksoutputstream.write((byte) 0);
/* username/password */
this.socksoutputstream.write((byte) 2);
this.socksoutputstream.flush();
} else {
this.socksoutputstream.write((byte) 1);
this.proxyRequest.append("->SOCKS5 Offer None Authentication\r\n");
/* none */
this.socksoutputstream.write((byte) 0);
this.socksoutputstream.flush();
}
/* read response, 2 bytes */
final byte[] resp = this.readResponse(2);
if (resp[0] != 5) { throw new ProxyConnectException("Socks5HTTPConnection: invalid Socks5 response", this.proxy); }
if (resp[1] == 255) {
this.proxyRequest.append("<-SOCKS5 Authentication Denied\r\n");
throw new ProxyConnectException("Socks5HTTPConnection: no acceptable authentication method found", this.proxy);
}
if (resp[1] == 2) {
if (plainAuthPossible == false) {
this.proxyRequest.append("->SOCKS5 Plain auth required but not offered!\r\n");
}
return AUTH.PLAIN;
}
if (resp[1] == 0) { return AUTH.NONE; }
throw new IOException("Unsupported auth " + resp[1]);
} catch (final IOException e) {
try {
this.sockssocket.close();
} catch (final Throwable e2) {
}
if (e instanceof HTTPProxyException) { throw e; }
throw new ProxyConnectException(e, this.proxy);
}
}
@Override
protected void validateProxy() throws IOException {
if (this.proxy == null || !this.proxy.getType().equals(HTTPProxy.TYPE.SOCKS5)) { throw new IOException("Socks5HTTPConnection: invalid Socks5 Proxy!"); }
}
}