master
fengfei 7 years ago
parent 778b616540
commit d0869c0894
  1. 2
      README.md
  2. 32
      proxy-client/src/main/java/org/fengfei/lanproxy/client/ClientChannelMannager.java
  3. 40
      proxy-client/src/main/java/org/fengfei/lanproxy/client/handlers/ClientChannelHandler.java
  4. 1
      proxy-client/src/main/java/org/fengfei/lanproxy/client/handlers/RealServerChannelHandler.java
  5. 4
      proxy-client/src/test/resources/config.properties
  6. 6
      proxy-client/src/test/resources/log4j.properties
  7. 4
      proxy-server/src/main/java/org/fengfei/lanproxy/server/handlers/ServerChannelHandler.java

@ -1,7 +1,7 @@
lanproxy lanproxy
-------- --------
lanproxy是一个将局域网个人电脑、服务器代理到公网的工具,目前仅支持tcp流量转发,可支持任何tcp上层协议(ssh访问、web服务器访问、远程桌面...)。目前市面上提供类似服务的有花生壳、TeamView、GoToMyCloud等等,但天下没有免费的午餐,要使用第三方的公网服务器就必须为第三方付费,并且这些服务器都有各种各样的限制,此外,由于数据包会流经第三方,因此对数据安全也是一大隐患。 lanproxy是一个将局域网个人电脑、服务器代理到公网的内网穿透工具,目前仅支持tcp流量转发,可支持任何tcp上层协议(ssh访问、web服务器访问、远程桌面...)。目前市面上提供类似服务的有花生壳、TeamView、GoToMyCloud等等,但天下没有免费的午餐,要使用第三方的公网服务器就必须为第三方付费,并且这些服务器都有各种各样的限制,此外,由于数据包会流经第三方,因此对数据安全也是一大隐患。
### 实现方案 ### 实现方案

@ -2,12 +2,15 @@ package org.fengfei.lanproxy.client;
import java.util.Iterator; import java.util.Iterator;
import java.util.Map; import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel; import io.netty.channel.Channel;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelOption; import io.netty.channel.ChannelOption;
import io.netty.util.AttributeKey; import io.netty.util.AttributeKey;
@ -61,8 +64,16 @@ public class ClientChannelMannager {
return realServerChannels.remove(userId); return realServerChannels.remove(userId);
} }
public static boolean isRealServerReadable(Channel realServerChannel) {
return realServerChannel.attr(CLIENT_CHANNEL_WRITEABLE).get()
&& realServerChannel.attr(USER_CHANNEL_WRITEABLE).get();
}
public static void setRealServerChannelReadability(Channel realServerChannel, Boolean client, Boolean user) { public static void setRealServerChannelReadability(Channel realServerChannel, Boolean client, Boolean user) {
logger.info("update real server channel readability, {} {}", client, user); logger.debug("update real server channel readability, {} {} {}", realServerChannel, client, user);
if (realServerChannel == null) {
return;
}
if (client != null) { if (client != null) {
realServerChannel.attr(CLIENT_CHANNEL_WRITEABLE).set(client); realServerChannel.attr(CLIENT_CHANNEL_WRITEABLE).set(client);
@ -78,26 +89,25 @@ public class ClientChannelMannager {
} else { } else {
realServerChannel.config().setOption(ChannelOption.AUTO_READ, false); realServerChannel.config().setOption(ChannelOption.AUTO_READ, false);
} }
} }
public static void notifyChannelWritabilityChanged(Channel channel) { public static void notifyChannelWritabilityChanged(Channel channel) {
logger.info("channel writability changed, {}", channel.isWritable()); logger.debug("channel writability changed, {}", channel.isWritable());
Iterator<Entry<String, Channel>> entryIte = realServerChannels.entrySet().iterator();
Iterator<String> ite = realServerChannels.keySet().iterator(); while (entryIte.hasNext()) {
while (ite.hasNext()) { setRealServerChannelReadability(entryIte.next().getValue(), channel.isWritable(), null);
Channel realServerChannel = realServerChannels.get(ite.next());
setRealServerChannelReadability(realServerChannel, channel.isWritable(), null);
} }
} }
public static void clearRealServerChannels() { public static void clearRealServerChannels() {
logger.warn("channel closed, clear real server channels"); logger.warn("channel closed, clear real server channels");
Iterator<String> ite = realServerChannels.keySet().iterator(); Iterator<Entry<String, Channel>> ite = realServerChannels.entrySet().iterator();
while (ite.hasNext()) { while (ite.hasNext()) {
Channel realServerChannel = realServerChannels.get(ite.next()); Channel realServerChannel = ite.next().getValue();
realServerChannel.close(); if (realServerChannel.isActive()) {
realServerChannel.writeAndFlush(Unpooled.EMPTY_BUFFER).addListener(ChannelFutureListener.CLOSE);
}
} }
realServerChannels.clear(); realServerChannels.clear();

@ -8,6 +8,7 @@ import org.slf4j.LoggerFactory;
import io.netty.bootstrap.Bootstrap; import io.netty.bootstrap.Bootstrap;
import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel; import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener; import io.netty.channel.ChannelFutureListener;
@ -36,20 +37,20 @@ public class ClientChannelHandler extends SimpleChannelInboundHandler<ProxyMessa
protected void channelRead0(ChannelHandlerContext ctx, ProxyMessage proxyMessage) throws Exception { protected void channelRead0(ChannelHandlerContext ctx, ProxyMessage proxyMessage) throws Exception {
logger.debug("recieved proxy message, type is {}", proxyMessage.getType()); logger.debug("recieved proxy message, type is {}", proxyMessage.getType());
switch (proxyMessage.getType()) { switch (proxyMessage.getType()) {
case ProxyMessage.TYPE_CONNECT: case ProxyMessage.TYPE_CONNECT:
handleConnectMessage(ctx, proxyMessage); handleConnectMessage(ctx, proxyMessage);
break; break;
case ProxyMessage.TYPE_DISCONNECT: case ProxyMessage.TYPE_DISCONNECT:
handleDisconnectMessage(ctx, proxyMessage); handleDisconnectMessage(ctx, proxyMessage);
break; break;
case ProxyMessage.TYPE_TRANSFER: case ProxyMessage.TYPE_TRANSFER:
handleTransferMessage(ctx, proxyMessage); handleTransferMessage(ctx, proxyMessage);
break; break;
case ProxyMessage.TYPE_WRITE_CONTROL: case ProxyMessage.TYPE_WRITE_CONTROL:
handleWriteControlMessage(ctx, proxyMessage); handleWriteControlMessage(ctx, proxyMessage);
break; break;
default: default:
break; break;
} }
} }
@ -75,9 +76,10 @@ public class ClientChannelHandler extends SimpleChannelInboundHandler<ProxyMessa
private void handleDisconnectMessage(ChannelHandlerContext ctx, ProxyMessage proxyMessage) { private void handleDisconnectMessage(ChannelHandlerContext ctx, ProxyMessage proxyMessage) {
String userId = proxyMessage.getUri(); String userId = proxyMessage.getUri();
Channel userChannel = ClientChannelMannager.removeRealServerChannel(userId); Channel realServerChannel = ClientChannelMannager.removeRealServerChannel(userId);
if (userChannel != null) { logger.debug("handleDisconnectMessage, {} {}", userId, realServerChannel);
userChannel.close(); if (realServerChannel != null) {
realServerChannel.writeAndFlush(Unpooled.EMPTY_BUFFER).addListener(ChannelFutureListener.CLOSE);
} }
} }
@ -93,8 +95,10 @@ public class ClientChannelHandler extends SimpleChannelInboundHandler<ProxyMessa
public void operationComplete(ChannelFuture future) throws Exception { public void operationComplete(ChannelFuture future) throws Exception {
if (future.isSuccess()) { if (future.isSuccess()) {
Channel realServerChannel = future.channel(); Channel realServerChannel = future.channel();
ClientChannelMannager.setRealServerChannelReadability(realServerChannel, true, logger.debug("connect realserver success, {}, clientChannelWriteable {}", realServerChannel,
channel.isWritable()); channel.isWritable());
ClientChannelMannager.setRealServerChannelReadability(realServerChannel, channel.isWritable(),
true);
ClientChannelMannager.addRealServerChannel(userId, realServerChannel); ClientChannelMannager.addRealServerChannel(userId, realServerChannel);
ClientChannelMannager.setRealServerChannelUserId(realServerChannel, userId); ClientChannelMannager.setRealServerChannelUserId(realServerChannel, userId);
ProxyMessage proxyMessage = new ProxyMessage(); ProxyMessage proxyMessage = new ProxyMessage();

@ -49,6 +49,7 @@ public class RealServerChannelHandler extends SimpleChannelInboundHandler<ByteBu
ClientChannelMannager.removeRealServerChannel(userId); ClientChannelMannager.removeRealServerChannel(userId);
Channel channel = ClientChannelMannager.getChannel(); Channel channel = ClientChannelMannager.getChannel();
if (channel != null) { if (channel != null) {
logger.debug("channelInactive, {}", realServerChannel);
ProxyMessage proxyMessage = new ProxyMessage(); ProxyMessage proxyMessage = new ProxyMessage();
proxyMessage.setType(ProxyMessage.TYPE_DISCONNECT); proxyMessage.setType(ProxyMessage.TYPE_DISCONNECT);
proxyMessage.setUri(userId); proxyMessage.setUri(userId);

@ -1,9 +1,9 @@
client.key=client client.key=client
ssl.enable=true ssl.enable=false
ssl.jksPath=test.jks ssl.jksPath=test.jks
ssl.keyStorePassword=123456 ssl.keyStorePassword=123456
server.host=127.0.0.1 server.host=127.0.0.1
#default ssl port is 4993 #default ssl port is 4993
server.port=4993 server.port=4900

@ -1,7 +1,9 @@
log4j.rootLogger=info,stdout log4j.rootLogger=error,stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - <%m>%n log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - <%m>%n
log4j.logger.io.netty=warn log4j.logger.io.netty=warn
log4j.logger.org.fengfei.lanproxy.client.handlers.ClientChannelHandler=info
log4j.logger.org.fengfei.lanproxy.protocol.IdleCheckHandler=warn

@ -9,6 +9,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel; import io.netty.channel.Channel;
import io.netty.channel.ChannelFutureListener; import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelHandlerContext;
@ -76,8 +77,7 @@ public class ServerChannelHandler extends SimpleChannelInboundHandler<ProxyMessa
Channel userChannel = ProxyChannelManager.removeUserChannel(ctx.channel(), userId); Channel userChannel = ProxyChannelManager.removeUserChannel(ctx.channel(), userId);
if (userChannel != null) { if (userChannel != null) {
// 数据发送完成后再关闭连接,解决http1.0数据传输问题 // 数据发送完成后再关闭连接,解决http1.0数据传输问题
ByteBuf buf = ctx.alloc().buffer(0); userChannel.writeAndFlush(Unpooled.EMPTY_BUFFER).addListener(ChannelFutureListener.CLOSE);
userChannel.writeAndFlush(buf).addListener(ChannelFutureListener.CLOSE);
} }
} }

Loading…
Cancel
Save