Skip to content

Commit

Permalink
feat: 添加连接目标服务器之前的拦截点
Browse files Browse the repository at this point in the history
  • Loading branch information
monkeyWie committed Aug 3, 2021
1 parent 0f71a9e commit 1de3aab
Show file tree
Hide file tree
Showing 9 changed files with 58 additions and 43 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ Proxyee is a JAVA written HTTP proxy server library that supports HTTP, HTTPS, W
<dependency>
<groupId>com.github.monkeywie</groupId>
<artifactId>proxyee</artifactId>
<version>1.5.0</version>
<version>1.5.1</version>
</dependency>
```

Expand Down Expand Up @@ -126,7 +126,7 @@ Currently only basic authentication are supported.
HttpProxyServerConfig config = new HttpProxyServerConfig();
config.setAuthenticationProvider(new BasicHttpProxyAuthenticationProvider() {
@Override
protected boolean authenticate(String usr, String pwd) {
protected BasicHttpToken authenticate(String usr, String pwd) {
if ("admin".equals(usr) && "123456".equals(pwd)) {
return new BasicHttpToken(usr, pwd);
}
Expand Down
4 changes: 2 additions & 2 deletions README_zh-CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ Proxyee 是一个 JAVA 编写的 HTTP 代理服务器类库,支持 HTTP、HTTP
<dependency>
<groupId>com.github.monkeywie</groupId>
<artifactId>proxyee</artifactId>
<version>1.5.0</version>
<version>1.5.1</version>
</dependency>
```

Expand Down Expand Up @@ -131,7 +131,7 @@ openssl req -sha256 -new -x509 -days 365 -key ca.key -out ca.crt \
HttpProxyServerConfig config = new HttpProxyServerConfig();
config.setAuthenticationProvider(new BasicHttpProxyAuthenticationProvider() {
@Override
protected boolean authenticate(String usr, String pwd) {
protected BasicHttpToken authenticate(String usr, String pwd) {
if ("admin".equals(usr) && "123456".equals(pwd)) {
return new BasicHttpToken(usr, pwd);
}
Expand Down
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

<groupId>com.github.monkeywie</groupId>
<artifactId>proxyee</artifactId>
<version>1.5.0</version>
<version>1.5.1</version>
<build>
<plugins>
<plugin>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
import com.github.monkeywie.proxyee.intercept.HttpProxyIntercept;
import com.github.monkeywie.proxyee.intercept.HttpProxyInterceptInitializer;
import com.github.monkeywie.proxyee.intercept.HttpProxyInterceptPipeline;
import com.github.monkeywie.proxyee.intercept.HttpTunnelIntercept;
import com.github.monkeywie.proxyee.proxy.ProxyConfig;
import com.github.monkeywie.proxyee.proxy.ProxyHandleFactory;
import com.github.monkeywie.proxyee.server.HttpProxyServer;
Expand Down Expand Up @@ -42,7 +41,6 @@ public class HttpProxyServerHandler extends ChannelInboundHandlerAdapter {
private final ProxyConfig proxyConfig;
private final HttpProxyInterceptInitializer interceptInitializer;
private HttpProxyInterceptPipeline interceptPipeline;
private final HttpTunnelIntercept tunnelIntercept;
private final HttpProxyExceptionHandle exceptionHandle;
private List requestList;
private boolean isConnect;
Expand All @@ -59,11 +57,10 @@ public HttpProxyExceptionHandle getExceptionHandle() {
return exceptionHandle;
}

public HttpProxyServerHandler(HttpProxyServerConfig serverConfig, HttpProxyInterceptInitializer interceptInitializer, HttpTunnelIntercept tunnelIntercept, ProxyConfig proxyConfig, HttpProxyExceptionHandle exceptionHandle) {
public HttpProxyServerHandler(HttpProxyServerConfig serverConfig, HttpProxyInterceptInitializer interceptInitializer, ProxyConfig proxyConfig, HttpProxyExceptionHandle exceptionHandle) {
this.serverConfig = serverConfig;
this.proxyConfig = proxyConfig;
this.interceptInitializer = interceptInitializer;
this.tunnelIntercept = tunnelIntercept;
this.exceptionHandle = exceptionHandle;
}

Expand Down Expand Up @@ -168,7 +165,7 @@ private boolean authenticate(ChannelHandlerContext ctx, HttpRequest request) {
ctx.writeAndFlush(response);
return false;
}
HttpAuthContext.setToken(ctx.channel(),httpToken);
HttpAuthContext.setToken(ctx.channel(), httpToken);
}
return true;
}
Expand All @@ -179,22 +176,18 @@ private void handleProxyData(Channel channel, Object msg, boolean isHttp) throws
if (isHttp && !(msg instanceof HttpRequest)) {
return;
}
if (interceptPipeline == null) {
interceptPipeline = buildOnlyConnectPipeline();
interceptPipeline.setRequestProto(new RequestProto(host, port, isSsl));
}
interceptPipeline.beforeConnect(channel);

// by default we use the proxy config set in the pipeline
ProxyHandler proxyHandler = ProxyHandleFactory.build(
interceptPipeline == null || interceptPipeline.getProxyConfig() == null ? proxyConfig : interceptPipeline.getProxyConfig());
/*
* 添加SSL client hello的Server Name Indication extension(SNI扩展) 有些服务器对于client
* hello不带SNI扩展时会直接返回Received fatal alert: handshake_failure(握手错误)
* 例如:https://cdn.mdn.mozilla.net/static/img/favicon32.7f3da72dcea1.png
*/
RequestProto requestProto;
if (!isHttp) {
requestProto = new RequestProto(host, port, isSsl);
if (this.tunnelIntercept != null) {
this.tunnelIntercept.handle(requestProto);
}
} else {
requestProto = interceptPipeline.getRequestProto();
ProxyHandler proxyHandler = ProxyHandleFactory.build(interceptPipeline.getProxyConfig() == null ?
proxyConfig : interceptPipeline.getProxyConfig());

RequestProto requestProto = interceptPipeline.getRequestProto();
if (isHttp) {
HttpRequest httpRequest = (HttpRequest) msg;
// 检查requestProto是否有修改
RequestProto newRP = ProtoUtil.getRequestProto(httpRequest);
Expand All @@ -208,6 +201,12 @@ private void handleProxyData(Channel channel, Object msg, boolean isHttp) throws
}
}
}

/*
* 添加SSL client hello的Server Name Indication extension(SNI扩展) 有些服务器对于client
* hello不带SNI扩展时会直接返回Received fatal alert: handshake_failure(握手错误)
* 例如:https://cdn.mdn.mozilla.net/static/img/favicon32.7f3da72dcea1.png
*/
ChannelInitializer channelInitializer = isHttp ? new HttpProxyInitializer(channel, requestProto, proxyHandler)
: new TunnelProxyInitializer(channel, proxyHandler);
Bootstrap bootstrap = new Bootstrap();
Expand Down Expand Up @@ -283,4 +282,11 @@ public void afterResponse(Channel clientChannel, Channel proxyChannel, HttpConte
interceptInitializer.init(interceptPipeline);
return interceptPipeline;
}

// fix issue #186: 不拦截https报文时,暴露一个扩展点用于代理设置,并且保持一致的编程接口
private HttpProxyInterceptPipeline buildOnlyConnectPipeline() {
HttpProxyInterceptPipeline interceptPipeline = new HttpProxyInterceptPipeline(new HttpProxyIntercept());
interceptInitializer.init(interceptPipeline);
return interceptPipeline;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,18 @@
import io.netty.handler.codec.http.HttpRequest;
import io.netty.handler.codec.http.HttpResponse;

/**
* http拦截器
* beforeForward -> beforeRequest -> afterResponse
*/
public class HttpProxyIntercept {

/**
* 在与目标服务器建立连接之前拦截
*/
public void beforeConnect(Channel clientChannel, HttpProxyInterceptPipeline pipeline) throws Exception {
}

/**
* 拦截代理服务器到目标服务器的请求头
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@
public class HttpProxyInterceptPipeline implements Iterable<HttpProxyIntercept> {

private List<HttpProxyIntercept> intercepts;
private HttpProxyIntercept defaultIntercept;

private int posBeforeConnect = 0;
private int posBeforeHead = 0;
private int posBeforeContent = 0;
private int posAfterHead = 0;
Expand All @@ -38,17 +38,20 @@ public RequestProto getRequestProto() {
return requestProto;
}

public ProxyConfig getProxyConfig(){ return proxyConfig; }
public ProxyConfig getProxyConfig() {
return proxyConfig;
}

public void setRequestProto(RequestProto requestProto) {
this.requestProto = requestProto;
}

public void setProxyConfig(ProxyConfig proxyConfig) { this.proxyConfig = proxyConfig; }
public void setProxyConfig(ProxyConfig proxyConfig) {
this.proxyConfig = proxyConfig;
}

public HttpProxyInterceptPipeline(HttpProxyIntercept defaultIntercept) {
this.intercepts = new LinkedList<>();
this.defaultIntercept = defaultIntercept;
this.intercepts.add(defaultIntercept);
}

Expand All @@ -64,8 +67,12 @@ public HttpProxyIntercept get(int index) {
return this.intercepts.get(index);
}

public HttpProxyIntercept getDefault() {
return this.defaultIntercept;
public void beforeConnect(Channel clientChannel) throws Exception {
if (this.posBeforeConnect < intercepts.size()) {
HttpProxyIntercept intercept = intercepts.get(this.posBeforeConnect++);
intercept.beforeConnect(clientChannel, this);
}
this.posBeforeConnect = 0;
}

public void beforeRequest(Channel clientChannel, HttpRequest httpRequest) throws Exception {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
import com.github.monkeywie.proxyee.exception.HttpProxyExceptionHandle;
import com.github.monkeywie.proxyee.handler.HttpProxyServerHandler;
import com.github.monkeywie.proxyee.intercept.HttpProxyInterceptInitializer;
import com.github.monkeywie.proxyee.intercept.HttpTunnelIntercept;
import com.github.monkeywie.proxyee.proxy.ProxyConfig;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.Channel;
Expand Down Expand Up @@ -43,7 +42,6 @@ public class HttpProxyServer {
private HttpProxyCACertFactory caCertFactory;
private HttpProxyServerConfig serverConfig;
private HttpProxyInterceptInitializer proxyInterceptInitializer;
private HttpTunnelIntercept tunnelIntercept;
private HttpProxyExceptionHandle httpProxyExceptionHandle;
private ProxyConfig proxyConfig;

Expand Down Expand Up @@ -122,11 +120,6 @@ public HttpProxyServer caCertFactory(HttpProxyCACertFactory caCertFactory) {
return this;
}

public HttpProxyServer tunnelIntercept(HttpTunnelIntercept tunnelIntercept) {
this.tunnelIntercept = tunnelIntercept;
return this;
}

public void start(int port) {
start(null, port);
}
Expand Down Expand Up @@ -185,7 +178,7 @@ private ChannelFuture doBind(String ip, int port) {
protected void initChannel(Channel ch) throws Exception {
ch.pipeline().addLast("httpCodec", new HttpServerCodec());
ch.pipeline().addLast("serverHandle",
new HttpProxyServerHandler(serverConfig, proxyInterceptInitializer, tunnelIntercept, proxyConfig,
new HttpProxyServerHandler(serverConfig, proxyInterceptInitializer, proxyConfig,
httpProxyExceptionHandle));
}
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -152,4 +152,5 @@ public void setAuthenticationProvider(final HttpProxyAuthenticationProvider auth
public AddressResolverGroup<?> resolver() {
return resolver;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,10 @@
import com.github.monkeywie.proxyee.server.auth.HttpAuthContext;
import com.github.monkeywie.proxyee.server.auth.model.BasicHttpToken;
import io.netty.channel.Channel;
import io.netty.handler.codec.http.HttpRequest;

public class AuthHttpProxyServer {

// curl -i -x 127.0.0.1:9999 -U admin:123456 http://www.baidu.com
// curl -i -x 127.0.0.1:9999 -U admin:123456 https://www.baidu.com
public static void main(String[] args) throws Exception {
HttpProxyServerConfig config = new HttpProxyServerConfig();
config.setAuthenticationProvider(new BasicHttpProxyAuthenticationProvider() {
Expand All @@ -32,9 +31,8 @@ protected BasicHttpToken authenticate(String usr, String pwd) {
public void init(HttpProxyInterceptPipeline pipeline) {
pipeline.addLast(new HttpProxyIntercept() {
@Override
public void beforeRequest(Channel clientChannel, HttpRequest httpRequest, HttpProxyInterceptPipeline pipeline) throws Exception {
public void beforeConnect(Channel clientChannel, HttpProxyInterceptPipeline pipeline) throws Exception {
System.out.println(HttpAuthContext.getToken(clientChannel));
super.beforeRequest(clientChannel, httpRequest, pipeline);
}
});
}
Expand Down

0 comments on commit 1de3aab

Please sign in to comment.