Я использую netty 4.1 в качестве сервера сокетов NIO для игры MMORPG.Он работал отлично в течение многих лет, но в последнее время мы страдаем от DDOS-атак.Я боролся с этим долгое время, но в настоящее время у меня нет больше идей о том, как я могу улучшить это.Ddoser спамит новыми подключениями от тысяч ips со всего мира.Это трудно сократить на сетевом уровне, потому что атаки выглядят очень похоже на обычных игроков.Атаки не очень велики по сравнению с атаками на HTTP-серверах, но достаточно велики, чтобы вывести из строя нашу игру.
Как я использую 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 групп:
- bootstrap bossGroup - для новых подключений
- bootstrap workerGroup - для доставки сообщений
- normalGroup - для большинства сообщений
- loginGroup - для интенсивного процесса входа в систему
- группа команд - для некоторой сложной логики
Я отслеживаю количество новых подключений и сообщений, чтобы сразу узнать, есть лиидет атака.Во время атаки я больше не принимаю новые подключения: я возвращаю false в пользовательском брандмауэре (AbstractRemoteAddressFilter).
protected boolean accept(ChannelHandlerContext ctx, InetSocketAddress remoteAddress) throws Exception {
if(ddosDetected())
return false;
else
return true;
}
Но даже из-за того, что я сбрасываю новые соединения, моя рабочая группа перегружена.PendingTasks для рабочей группы (все остальные группы в порядке) растут, что приводит к более длительной и продолжительной связи для нормальных игроков и, наконец, они получают удовольствие от socket_timeouts.Я не уверен, почему это случилось.При обычном использовании сервера самыми загруженными группами являются логин и обычная группа.На сетевом уровне сервер в порядке - он использует только ~ 10% от своей пропускной способности.Использование ЦП и ОЗУ также не очень высоко во время атаки.Но после нескольких минут такой атаки все мои игроки вышвырнуты из игры и больше не могут подключаться.
Есть ли лучший способ мгновенно отбросить все входящие соединения и защитить пользователей, которые являются постоянными?связано?