我正在使用Netty 4.1作为MMORPG游戏的NIO套接字服务器。多年来,它一直运行得很完美,但最近我们遭受了DDOS攻击。我已经长时间地与之斗争,但目前我没有更多的想法来改进它。攻击者正在使用来自世界各地成千上万个IP的新连接进行垃圾邮件轰炸。由于攻击看起来非常类似于正常玩家,因此在网络层面上很难切断它。与HTTP服务器遭受的攻击相比,这些攻击并不是很大,但足以使我们的游戏崩溃。
我正在使用5个组:
尽管我立即断开了新连接,我的工作组仍然过载。工作组的PendingTasks(其他所有组都正常)正在增加,这导致普通玩家之间的通信越来越长,并最终被socket_timeouts踢出。我不确定为什么会发生这种情况。在正常服务器使用期间,最繁忙的组是登录和普通组。在网络层面上,服务器很好-它只使用了其带宽限制的约10%。攻击期间,CPU和RAM使用率也不是很高。但经过几分钟的这样的攻击后,所有玩家都将从游戏中踢出并无法再次连接。
我如何使用Netty:
public void startServer() {
bossGroup = new NioEventLoopGroup(1);
workerGroup = new NioEventLoopGroup();
try {
int timeout = (Settings.SOCKET_TIMEOUT*1000);
bootstrap = new ServerBootstrap();
int bufferSize = 65536;
bootstrap.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.childOption(ChannelOption.SO_KEEPALIVE, true)
.childOption(ChannelOption.SO_TIMEOUT, timeout)
.childOption(ChannelOption.SO_RCVBUF, bufferSize)
.childOption(ChannelOption.SO_SNDBUF, bufferSize)
.handler(new LoggingHandler(LogLevel.INFO))
.childHandler(new CustomInitalizer(sslCtx));
ChannelFuture bind = bootstrap.bind(DrServerAdmin.port);
bossChannel = bind.sync();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
初始化器:
public class CustomInitalizer extends ChannelInitializer<SocketChannel> {
public static DefaultEventExecutorGroup normalGroup = new DefaultEventExecutorGroup(16);
public static DefaultEventExecutorGroup loginGroup = new DefaultEventExecutorGroup(8);
public static DefaultEventExecutorGroup commandsGroup = new DefaultEventExecutorGroup(4);
private final SslContext sslCtx;
public CustomInitalizer(SslContext sslCtx) {
this.sslCtx = sslCtx;
}
@Override
public void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
if (sslCtx != null) {
pipeline.addLast(sslCtx.newHandler(ch.alloc()));
}
pipeline.addLast(new CustomFirewall()); //it is AbstractRemoteAddressFilter<InetSocketAddress>
int limit = 32768;
pipeline.addLast(new DelimiterBasedFrameDecoder(limit, Delimiters.nulDelimiter()));
pipeline.addLast("decoder", new StringDecoder(CharsetUtil.UTF_8));
pipeline.addLast("encoder", new StringEncoder(CharsetUtil.UTF_8));
pipeline.addLast(new CustomReadTimeoutHandler(Settings.SOCKET_TIMEOUT));
int id = DrServerNetty.getDrServer().getIdClient();
CustomHandler normalHandler = new CustomHandler();
FlashClientNetty client = new FlashClientNetty(normalHandler,id);
normalHandler.setClient(client);
pipeline.addLast(normalGroup,"normalHandler",normalHandler);
CustomLoginHandler loginHandler = new CustomLoginHandler(client);
pipeline.addLast(loginGroup,"loginHandler",loginHandler);
CustomCommandsHandler commandsHandler = new CustomCommandsHandler(loginHandler.client);
pipeline.addLast(commandsGroup, "commandsHandler", commandsHandler);
}
}
我正在使用5个组:
- 引导 bossGroup - 用于新连接
- 引导 workerGroup - 用于传递消息
- normalGroup - 用于大多数消息
- loginGroup - 用于繁重的登录过程
- commands group - 用于某些繁重的逻辑
protected boolean accept(ChannelHandlerContext ctx, InetSocketAddress remoteAddress) throws Exception {
if(ddosDetected())
return false;
else
return true;
}
尽管我立即断开了新连接,我的工作组仍然过载。工作组的PendingTasks(其他所有组都正常)正在增加,这导致普通玩家之间的通信越来越长,并最终被socket_timeouts踢出。我不确定为什么会发生这种情况。在正常服务器使用期间,最繁忙的组是登录和普通组。在网络层面上,服务器很好-它只使用了其带宽限制的约10%。攻击期间,CPU和RAM使用率也不是很高。但经过几分钟的这样的攻击后,所有玩家都将从游戏中踢出并无法再次连接。
有没有更好的方法可以立即断开所有传入连接并保护已连接的用户?