[add] 添加socks授权验证

This commit is contained in:
wujiawei
2025-06-26 21:00:20 +08:00
parent 6c86a41359
commit faabae3d19
9 changed files with 168 additions and 14 deletions

View File

@@ -51,6 +51,7 @@ public class NettyClientSocketApplicationListener implements ApplicationListener
log.warn("配置信息为空,请通过页面添加配置信息:{}", nettyClientProperties); log.warn("配置信息为空,请通过页面添加配置信息:{}", nettyClientProperties);
return; return;
} }
LazyNettyServerPropertiesDO lazyNettyServerPropertiesDO = new LazyNettyServerPropertiesDO(); LazyNettyServerPropertiesDO lazyNettyServerPropertiesDO = new LazyNettyServerPropertiesDO();
lazyNettyServerPropertiesDO.setClientId(clientId); lazyNettyServerPropertiesDO.setClientId(clientId);

View File

@@ -0,0 +1,18 @@
package org.framework.lazy.cloud.network.heartbeat.client.netty.proxy.auth;
import org.framework.lazy.cloud.network.heartbeat.protocol.auth.AbstractNettyPasswordAuth;
import org.framework.lazy.cloud.network.heartbeat.protocol.properties.ProtocolProxyProperties;
public class ClientNettyPasswordAuth extends AbstractNettyPasswordAuth {
public ClientNettyPasswordAuth(ProtocolProxyProperties protocolProxyProperties) {
super(protocolProxyProperties);
}
@Override
public boolean doVerify(String username, String password) {
// 查找用户名称、密码
return false;
}
}

View File

@@ -0,0 +1,29 @@
package org.framework.lazy.cloud.network.heartbeat.protocol.auth;
import org.framework.lazy.cloud.network.heartbeat.protocol.properties.ProtocolProxyProperties;
public abstract class AbstractNettyPasswordAuth implements NettyPasswordAuth {
private final ProtocolProxyProperties protocolProxyProperties;
protected AbstractNettyPasswordAuth(ProtocolProxyProperties protocolProxyProperties) {
this.protocolProxyProperties = protocolProxyProperties;
}
public abstract boolean doVerify(String username, String password);
/**
* 验证账号密码
*
* @param username 用户
* @param password 密码
* @return
*/
@Override
public boolean verify(String username, String password) {
if (protocolProxyProperties.getAuthentication()) {
return doVerify(username, password);
}
return true;
}
}

View File

@@ -0,0 +1,39 @@
package org.framework.lazy.cloud.network.heartbeat.protocol.auth;
import lombok.extern.slf4j.Slf4j;
import org.framework.lazy.cloud.network.heartbeat.protocol.properties.ProtocolProxyProperties;
import org.springframework.stereotype.Component;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
@Slf4j
@Component
public class DefaultNettyPasswordAuth extends AbstractNettyPasswordAuth {
protected Map<String/*username*/, String/*password*/> authMap = new ConcurrentHashMap<>();
protected DefaultNettyPasswordAuth(ProtocolProxyProperties protocolProxyProperties) {
super(protocolProxyProperties);
}
@Override
public boolean doVerify(String username, String password) {
boolean verify = authMap.containsKey(username) && authMap.get(username).equals(password);
if(!verify){
log.error("授权失败");
}
return verify;
}
/**
* 新增授权
*
* @param username 用户
* @param password 密码
*/
public DefaultNettyPasswordAuth addAuth(String username, String password) {
authMap.putIfAbsent(username, password);
return this;
}
}

View File

@@ -0,0 +1,13 @@
package org.framework.lazy.cloud.network.heartbeat.protocol.auth;
public interface NettyPasswordAuth {
/**
* 验证账号密码
*
* @param username 用户
* @param password 密码
* @return
*/
boolean verify(String username, String password);
}

View File

@@ -1,17 +1,14 @@
package org.framework.lazy.cloud.network.heartbeat.protocol.filter; package org.framework.lazy.cloud.network.heartbeat.protocol.filter;
import io.netty.channel.ChannelPipeline; import io.netty.channel.ChannelPipeline;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.socket.SocketChannel; import io.netty.channel.socket.SocketChannel;
import io.netty.handler.codec.socksx.v5.Socks5CommandRequestDecoder; import io.netty.handler.codec.socksx.SocksPortUnificationServerHandler;
import io.netty.handler.codec.socksx.v5.Socks5InitialRequestDecoder; import io.netty.handler.codec.socksx.v5.*;
import io.netty.handler.codec.socksx.v5.Socks5ServerEncoder;
import org.framework.lazy.cloud.network.heartbeat.common.adapter.ChannelTypeAdapter; import org.framework.lazy.cloud.network.heartbeat.common.adapter.ChannelTypeAdapter;
import org.framework.lazy.cloud.network.heartbeat.common.advanced.HandleChannelTypeAdvanced; import org.framework.lazy.cloud.network.heartbeat.common.advanced.HandleChannelTypeAdvanced;
import org.framework.lazy.cloud.network.heartbeat.common.factory.EventLoopGroupFactory;
import org.framework.lazy.cloud.network.heartbeat.common.filter.DebugChannelInitializer; import org.framework.lazy.cloud.network.heartbeat.common.filter.DebugChannelInitializer;
import org.framework.lazy.cloud.network.heartbeat.protocol.handler.NettySocks5CommandRequestHandler; import org.framework.lazy.cloud.network.heartbeat.protocol.auth.NettyPasswordAuth;
import org.framework.lazy.cloud.network.heartbeat.protocol.handler.NettySocks5InitialRequestHandler; import org.framework.lazy.cloud.network.heartbeat.protocol.handler.*;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import java.util.List; import java.util.List;
@@ -25,9 +22,11 @@ import java.util.List;
@Component @Component
public class NettyTcpProxyFilter extends DebugChannelInitializer<SocketChannel> { public class NettyTcpProxyFilter extends DebugChannelInitializer<SocketChannel> {
private final List<HandleChannelTypeAdvanced> handleChannelTypeAdvancedList; private final List<HandleChannelTypeAdvanced> handleChannelTypeAdvancedList;
private final NettyPasswordAuth nettyPasswordAuth;
public NettyTcpProxyFilter(List<HandleChannelTypeAdvanced> handleChannelTypeAdvancedList) { public NettyTcpProxyFilter(List<HandleChannelTypeAdvanced> handleChannelTypeAdvancedList, NettyPasswordAuth nettyPasswordAuth) {
this.handleChannelTypeAdvancedList = handleChannelTypeAdvancedList; this.handleChannelTypeAdvancedList = handleChannelTypeAdvancedList;
this.nettyPasswordAuth = nettyPasswordAuth;
} }
@Override @Override
@@ -35,7 +34,9 @@ public class NettyTcpProxyFilter extends DebugChannelInitializer<SocketChannel>
ChannelPipeline pipeline = ch.pipeline(); ChannelPipeline pipeline = ch.pipeline();
// 类型处理器适配器 // 类型处理器适配器
ChannelTypeAdapter channelTypeAdapter = new ChannelTypeAdapter(handleChannelTypeAdvancedList); ChannelTypeAdapter channelTypeAdapter = new ChannelTypeAdapter(handleChannelTypeAdvancedList);
//
// //添加 SOCKS 协议统一处理器
// pipeline.addLast(new SocksPortUnificationServerHandler());
//socks5响应最后一个encode //socks5响应最后一个encode
pipeline.addLast(Socks5ServerEncoder.DEFAULT); pipeline.addLast(Socks5ServerEncoder.DEFAULT);
@@ -45,10 +46,9 @@ public class NettyTcpProxyFilter extends DebugChannelInitializer<SocketChannel>
// 认证 // 认证
// ch.pipeline().addLast(new Socks5PasswordAuthRequestDecoder()); pipeline.addLast(new Socks5PasswordAuthRequestDecoder());
// ch.pipeline().addLast(new Socks5PasswordAuthRequestInboundHandler()); pipeline.addLast(new NettySocks5PasswordAuthRequestInboundHandler(nettyPasswordAuth));
EventLoopGroup clientWorkGroup = EventLoopGroupFactory.createClientWorkGroup();
// 连接请求 // 连接请求
pipeline.addLast(new Socks5CommandRequestDecoder()); pipeline.addLast(new Socks5CommandRequestDecoder());

View File

@@ -18,8 +18,8 @@ public class NettySocks5InitialRequestHandler extends SimpleChannelInboundHandle
} }
log.info("初始化socket连接"); log.info("初始化socket连接");
// 验证账号密码 // 验证账号密码
Socks5InitialResponse socks5InitialResponse = new DefaultSocks5InitialResponse(Socks5AuthMethod.NO_AUTH); Socks5InitialResponse socks5InitialResponse = new DefaultSocks5InitialResponse(Socks5AuthMethod.PASSWORD);
ctx.writeAndFlush(socks5InitialResponse); ctx.writeAndFlush(socks5InitialResponse);
ctx.pipeline().remove(this); ctx.pipeline().remove(this);

View File

@@ -0,0 +1,50 @@
package org.framework.lazy.cloud.network.heartbeat.protocol.handler;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.socksx.v5.*;
import lombok.extern.slf4j.Slf4j;
import org.framework.lazy.cloud.network.heartbeat.protocol.auth.NettyPasswordAuth;
@Slf4j
public class NettySocks5PasswordAuthRequestInboundHandler extends SimpleChannelInboundHandler<DefaultSocks5PasswordAuthRequest> {
private final NettyPasswordAuth nettyPasswordAuth;
public NettySocks5PasswordAuthRequestInboundHandler(NettyPasswordAuth nettyPasswordAuth) {
this.nettyPasswordAuth = nettyPasswordAuth;
}
@Override
protected void channelRead0(ChannelHandlerContext ctx, DefaultSocks5PasswordAuthRequest msg) throws Exception {
//认证成功
String username = msg.username();
String password = msg.password();
if (nettyPasswordAuth.verify(username, password)) {
log.debug("login with username:{} password:{}", username, password);
log.debug("认证直接成功");
Socks5PasswordAuthResponse passwordAuthResponse = new DefaultSocks5PasswordAuthResponse(Socks5PasswordAuthStatus.SUCCESS);
ctx.writeAndFlush(passwordAuthResponse);
ctx.pipeline().remove(this);
ctx.pipeline().remove(Socks5PasswordAuthRequestDecoder.class);
} else {
log.error("授权失败: with username:{} password:{}", username, password);
// 认证失败
Socks5PasswordAuthResponse passwordAuthResponse = new DefaultSocks5PasswordAuthResponse(Socks5PasswordAuthStatus.FAILURE);
//发送鉴权失败消息完成后关闭channel
ctx.writeAndFlush(passwordAuthResponse).addListener(ChannelFutureListener.CLOSE);
}
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
System.err.println("处理 SOCKS5 密码认证时发生异常: " + cause.getMessage());
ctx.close();
}
}

View File

@@ -13,6 +13,10 @@ import org.springframework.context.annotation.Configuration;
public class ProtocolProxyProperties { public class ProtocolProxyProperties {
public static final String prefix = "spring.lazy.netty.protocol.proxy"; public static final String prefix = "spring.lazy.netty.protocol.proxy";
/**
* 是否验证权限账号
*/
private Boolean authentication=false;
/** /**
* http协议代理 * http协议代理