Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

web socket dose not work in socks5 proxy #1623

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Expand Up @@ -33,6 +33,7 @@
import io.netty.handler.proxy.Socks5ProxyHandler;
import io.netty.handler.ssl.SslHandler;
import io.netty.handler.stream.ChunkedWriteHandler;
import io.netty.resolver.AddressResolverGroup;
import io.netty.resolver.NameResolver;
import io.netty.util.Timer;
import io.netty.util.concurrent.*;
Expand Down Expand Up @@ -392,55 +393,79 @@ public Future<Bootstrap> getBootstrap(Uri uri, NameResolver<InetAddress> nameRes

final Promise<Bootstrap> promise = ImmediateEventExecutor.INSTANCE.newPromise();

if (uri.isWebSocket() && proxy == null) {
return promise.setSuccess(wsBootstrap);

} else if (proxy != null && proxy.getProxyType().isSocks()) {
Bootstrap socksBootstrap = httpBootstrap.clone();
ChannelHandler httpBootstrapHandler = socksBootstrap.config().handler();

nameResolver.resolve(proxy.getHost()).addListener((Future<InetAddress> whenProxyAddress) -> {
if (whenProxyAddress.isSuccess()) {
socksBootstrap.handler(new ChannelInitializer<Channel>() {
@Override
public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
httpBootstrapHandler.handlerAdded(ctx);
super.handlerAdded(ctx);
}

@Override
protected void initChannel(Channel channel) throws Exception {
InetSocketAddress proxyAddress = new InetSocketAddress(whenProxyAddress.get(), proxy.getPort());
Realm realm = proxy.getRealm();
String username = realm != null ? realm.getPrincipal() : null;
String password = realm != null ? realm.getPassword() : null;
ProxyHandler socksProxyHandler;
switch (proxy.getProxyType()) {
case SOCKS_V4:
socksProxyHandler = new Socks4ProxyHandler(proxyAddress, username);
break;

case SOCKS_V5:
socksProxyHandler = new Socks5ProxyHandler(proxyAddress, username, password);
break;

default:
throw new IllegalArgumentException("Only SOCKS4 and SOCKS5 supported at the moment.");
}
channel.pipeline().addFirst(SOCKS_HANDLER, socksProxyHandler);
}
});
promise.setSuccess(socksBootstrap);

} else {
promise.setFailure(whenProxyAddress.cause());
}
});
// direct connect
if (proxy == null) {
if (uri.isWebSocket()) {
promise.setSuccess(wsBootstrap);
} else {
promise.setSuccess(httpBootstrap);
}
return promise;
}

} else {
// http proxy
if (proxy.getProxyType().isHttp()) {
promise.setSuccess(httpBootstrap);
return promise;
}

// socks proxy
Bootstrap bs;
ChannelHandler handler;
if (uri.isWebSocket()) {
bs = wsBootstrap;
handler = wsBootstrap.config().handler();
} else {
bs = httpBootstrap;
handler = httpBootstrap.config().handler();
}

final Bootstrap wrapFinalBs = bs;
final ChannelHandler wrapFinalHandler = handler;

nameResolver.resolve(proxy.getHost()).addListener((Future<InetAddress> whenProxyAddress) -> {
if (!whenProxyAddress.isSuccess()) {
promise.setFailure(whenProxyAddress.cause());
return;
}
wrapFinalBs.handler(new ChannelInitializer<Channel>() {
@Override
public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
wrapFinalHandler.handlerAdded(ctx);
super.handlerAdded(ctx);
}

@Override
protected void initChannel(Channel channel) throws Exception {
InetSocketAddress proxyAddress = new InetSocketAddress(whenProxyAddress.get(), proxy.getPort());
Realm realm = proxy.getRealm();
String username = realm != null ? realm.getPrincipal() : null;
String password = realm != null ? realm.getPassword() : null;
ProxyHandler socksProxyHandler;
switch (proxy.getProxyType()) {
case SOCKS_V4:
socksProxyHandler = new Socks4ProxyHandler(proxyAddress, username);
break;

case SOCKS_V5:
socksProxyHandler = new Socks5ProxyHandler(proxyAddress, username, password);
break;

default:
throw new IllegalArgumentException("Only SOCKS4 and SOCKS5 supported at the moment.");
}
channel.pipeline().addFirst(SOCKS_HANDLER, socksProxyHandler);
}
});
if (proxy.getProxyType().isSocks()) {
AddressResolverGroup addressResolverGroup = proxy.getAddressResolverGroup();
if (addressResolverGroup != null) {
wrapFinalBs.resolver(addressResolverGroup);
}
}
promise.setSuccess(wrapFinalBs);
});

return promise;
}

Expand Down
Expand Up @@ -37,6 +37,7 @@
import org.asynchttpclient.netty.channel.*;
import org.asynchttpclient.netty.timeout.TimeoutsHolder;
import org.asynchttpclient.proxy.ProxyServer;
import org.asynchttpclient.proxy.ProxyType;
import org.asynchttpclient.resolver.RequestHostnameResolver;
import org.asynchttpclient.uri.Uri;
import org.asynchttpclient.ws.WebSocketUpgradeHandler;
Expand All @@ -46,6 +47,7 @@
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.util.ArrayList;
import java.util.List;

import static io.netty.handler.codec.http.HttpHeaderNames.EXPECT;
Expand Down Expand Up @@ -342,7 +344,16 @@ private <T> Future<List<InetSocketAddress>> resolveAddresses(Request request,
InetSocketAddress unresolvedRemoteAddress = InetSocketAddress.createUnresolved(proxy.getHost(), port);
scheduleRequestTimeout(future, unresolvedRemoteAddress);
return RequestHostnameResolver.INSTANCE.resolve(request.getNameResolver(), unresolvedRemoteAddress, asyncHandler);

} else if (proxy != null && proxy.isResolveDomain() && proxy.getProxyType().isSocks()) {
// resolve domain in socks 5 server
int port = uri.getExplicitPort();
InetSocketAddress unresolvedRemoteAddress = InetSocketAddress.createUnresolved(uri.getHost(), port);
final Promise<List<InetSocketAddress>> unResolvedPromise = ImmediateEventExecutor.INSTANCE.newPromise();
List<InetSocketAddress> unresolvedLiWrapper = new ArrayList<>(1);
unresolvedLiWrapper.add(unresolvedRemoteAddress);
scheduleRequestTimeout(future, unresolvedRemoteAddress);
unResolvedPromise.trySuccess(unresolvedLiWrapper);
return unResolvedPromise;
} else {
int port = uri.getExplicitPort();

Expand Down
25 changes: 24 additions & 1 deletion client/src/main/java/org/asynchttpclient/proxy/ProxyServer.java
Expand Up @@ -16,6 +16,7 @@
*/
package org.asynchttpclient.proxy;

import io.netty.resolver.AddressResolverGroup;
import org.asynchttpclient.Realm;

import java.util.ArrayList;
Expand All @@ -36,6 +37,8 @@ public class ProxyServer {
private final Realm realm;
private final List<String> nonProxyHosts;
private final ProxyType proxyType;
private AddressResolverGroup addressResolverGroup;
// server can resolve domain in socks 5

public ProxyServer(String host, int port, int securedPort, Realm realm, List<String> nonProxyHosts,
ProxyType proxyType) {
Expand All @@ -47,6 +50,12 @@ public ProxyServer(String host, int port, int securedPort, Realm realm, List<Str
this.proxyType = proxyType;
}

public ProxyServer(String host, int port, int securedPort, Realm realm, List<String> nonProxyHosts,
ProxyType proxyType, AddressResolverGroup addressResolverGroup) {
this(host, port, securedPort, realm, nonProxyHosts, proxyType);
this.addressResolverGroup = addressResolverGroup;
}

public String getHost() {
return host;
}
Expand All @@ -71,6 +80,14 @@ public ProxyType getProxyType() {
return proxyType;
}

public AddressResolverGroup getAddressResolverGroup() {
return addressResolverGroup;
}

public boolean isResolveDomain() {
return addressResolverGroup != null;
}

/**
* Checks whether proxy should be used according to nonProxyHosts settings of
* it, or we want to go directly to target host. If <code>null</code> proxy is
Expand Down Expand Up @@ -118,6 +135,7 @@ public static class Builder {
private Realm realm;
private List<String> nonProxyHosts;
private ProxyType proxyType;
private AddressResolverGroup addressResolverGroup;

public Builder(String host, int port) {
this.host = host;
Expand Down Expand Up @@ -157,11 +175,16 @@ public Builder setProxyType(ProxyType proxyType) {
return this;
}

public Builder setAddressResolverGroup(AddressResolverGroup addressResolverGroup) {
this.addressResolverGroup = addressResolverGroup;
return this;
}

public ProxyServer build() {
List<String> nonProxyHosts = this.nonProxyHosts != null ? Collections.unmodifiableList(this.nonProxyHosts)
: Collections.emptyList();
ProxyType proxyType = this.proxyType != null ? this.proxyType : ProxyType.HTTP;
return new ProxyServer(host, port, securedPort, realm, nonProxyHosts, proxyType);
return new ProxyServer(host, port, securedPort, realm, nonProxyHosts, proxyType, this.addressResolverGroup);
}
}
}