Netty-如何在DDOS中生存?

时间:2019-03-06 11:55:13

标签: java sockets netty game-development ddos

我正在将netty 4.1用作MMORPG游戏的NIO套接字服务器。它运行了好几年,但是最近我们正遭受DDOS攻击。我已经为之奋斗了很长时间,但是目前,我对如何改进它没有更多的想法。 Ddoser散布着来自世界各地成千上万个IP的新连接。在网络级别上很难削减它,因为攻击看上去与普通播放器非常相似。与对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-用于繁重的登录过程
  • 命令组-适用于一些繁琐的逻辑

我正在监视新连接和消息的数量,因此我可以立即找出是否正在进行攻击。在攻击过程中,我不再接受新的连接:在自定义防火墙(AbstractRemoteAddressFilter)中返回false。

protected boolean accept(ChannelHandlerContext ctx, InetSocketAddress remoteAddress) throws Exception {
    if(ddosDetected())
       return false;
    else
        return true;
}

但是即使我立即删除新的连接,我的工作组也变得超负荷。工人组(所有其他组都很好)的PendingTasks正在增长,这导致普通玩家之间的通信时间越来越长,最后,它们被socket_timeouts踢了。我不确定为什么会这样。在服务器正常使用期间,最繁忙的组是登录名和普通组。在网络级服务器上很好-它仅使用带宽限制的10%。攻击期间CPU和RAM的使用也不是很高。但是经过这样的攻击几分钟后,我所有的玩家都被踢出了游戏,无法再进行连接了。

有没有更好的方法可以立即断开所有传入的连接并保护区域连接的用户?

1 个答案:

答案 0 :(得分:1)

我认为您将需要通过例如iptables在内核级别“修复此问题”。否则,只有在接受连接后才能关闭连接,这在这种情况下听起来不够好。