【问题标题】:Netty (UDP) SSLException : Received close_notify during handskake,close channelNetty (UDP) SSLException:在握手期间收到 close_notify,关闭通道
【发布时间】:2015-11-03 13:35:14
【问题描述】:

我想用 SSL 编写一个 UDP Netty 服务器/客户端。我以类似于 TCP Netty Server/Client 的方式进行操作,效果很好。但我遇到了一个例外:

javax.net.ssl.SSLException:Received close_notify during handskake,close channel...

我的网络是 3.x,SSL 配置运行良好。这是我的 Udp 服务器和客户端的一些代码。服务器:

serverBootstrap = new ConnectionlessBootstrap(
            new NioDatagramChannelFactory(Executors.newCachedThreadPool(),maxThreads));
serverBootstrap.setOption("receiveBufferSizePredictorFactory",
            new FixedReceiveBufferSizePredictorFactory(8192));
 ChannelPipelineFactory fac = null;
 try {

        ServiceDecoder serviceProcessor = (ServiceDecoder)Class.forName(serviceDecoderName).newInstance();

        Class<? extends ChannelPipelineFactory> clazz = (Class<? extends ChannelPipelineFactory>) Class
                .forName(msgFactoryName);

        Constructor ctor = clazz.getConstructor(ChannelProcessor.class,
                ChannelGroup.class, CounterGroup.class, CounterGroupExt.class, String.class,ServiceDecoder.class,
                String.class, Integer.class, String.class, String.class, Boolean.class,Integer.class,Boolean.class,Boolean.class,Context.class);

        logger.info("Using channel processor:{}", getChannelProcessor().getClass().getName());
        fac = (ChannelPipelineFactory) ctor.newInstance(
                getChannelProcessor(), allChannels, counterGroup, counterGroupExt, "udp", serviceProcessor,
                messageHandlerName, maxMsgLength, topic, attr, filterEmptyMsg, maxConnections, isCompressed,enableSsl,context);
    } catch (Exception e) {
        logger.error(
                "Simple Udp Source start error, fail to construct ChannelPipelineFactory with name {}, ex {}",
                msgFactoryName, e);
        stop();
        throw new FlumeException(e.getMessage());
    }

    serverBootstrap.setPipelineFactory(fac);

    try {
        if (host == null) {
            nettyChannel = serverBootstrap
                    .bind(new InetSocketAddress(port));
        } else {
            nettyChannel = serverBootstrap.bind(new InetSocketAddress(host,
                    port));
        }

服务器中的管道:

 if(enableSsl) {
        cp.addLast("ssl", sslInit());
    }
if (processor != null) {

        try {
            Class<? extends SimpleChannelHandler> clazz = (Class<? extends SimpleChannelHandler>) Class
                    .forName(messageHandlerName);

            Constructor<?> ctor = clazz.getConstructor(
                    ChannelProcessor.class, ServiceDecoder.class, ChannelGroup.class,
                    CounterGroup.class, CounterGroupExt.class, String.class, String.class,
                    Boolean.class, Integer.class, Integer.class, Boolean.class);

            SimpleChannelHandler messageHandler = (SimpleChannelHandler) ctor
                    .newInstance(processor, serviceProcessor, allChannels,
                            counterGroup, counterGroupExt, topic, attr,
                            filterEmptyMsg, maxMsgLength, maxConnections, isCompressed);

            cp.addLast("messageHandler", messageHandler);

        } catch (Exception e) {
            e.printStackTrace();
        }
 }
       if (this.protocolType.equalsIgnoreCase(ConfigConstants.UDP_PROTOCOL)) {
            cp.addLast("execution", executionHandler);
        }

客户:

private ConnectionlessBootstrap clientBootstrap;
    clientBootstrap = new ConnectionlessBootstrap(
            new NioDatagramChannelFactory(Executors.newCachedThreadPool()));
    clientBootstrap.setPipelineFactory(new ChannelPipelineFactory() {
        @Override
        public ChannelPipeline getPipeline() throws Exception {
            ChannelPipeline pipeline = Channels.pipeline();

            pipeline.addLast("sslHandler", sslInit());
            pipeline.addLast("orderHandler",new ExecutionHandler(
                    new OrderedMemoryAwareThreadPoolExecutor(cores * 2,
                            1024 * 1024, 1024 * 1024)));
            return pipeline;
        }
    });

在客户端发送消息的两个函数:

public void sendMessage(byte[] data) {
    ChannelBuffer buffer = ChannelBuffers.wrappedBuffer(data);
    sendMessage(buffer);
}

public void sendMessage(ChannelBuffer buffer) {
    Random random = new Random();
    Channel channel = channelList.get(random.nextInt(channelList.size()));
    if(!channel.isConnected()){
        channel.close();
        ChannelFuture cf = clientBootstrap
                .connect(new InetSocketAddress(ip, port));
        if(cf.awaitUninterruptibly(3000, TimeUnit.MILLISECONDS)){
            channel = cf.getChannel();
        }else {
            channelList.remove(channel);
            return;
        }
    }
    ChannelFuture future = channel.write(buffer);
    if(!future.awaitUninterruptibly(3, TimeUnit.SECONDS)){
        logger.warn("send failed!{}",future.getCause());
    }else {
        sendCnt.incrementAndGet();
    }
}

我怀疑 UDP Netty Server/Client 是否支持 SSL。任何提示都表示赞赏。

【问题讨论】:

  • 我也这么怀疑。我很惊讶你能做到这一点。您与哪个同行交流?
  • @EJP 看了几天flume代码,我只想加密从netty客户端到服务器(即flume源)传输的数据,并且已经完成了TCP,但是当我尝试了UDP,它失败了。你能解释一下为什么 UDP 不支持 SSL 吗?非常感谢。
  • 我没有说 UDP 不能支持 SSL。我同意你的评论,也许 Netty 做得不好。

标签: ssl udp netty


【解决方案1】:

与 TCP 不同,UDP 不保证数据包的顺序,因为没有会话。因此,在 SSL 协商期间,可能会出现问题,具体取决于 UDP 数据包的顺序。

根据我阅读的内容,您可能会查看DTLS,它假设在 UDP 数据包中添加一种顺序控制,但许多 SSL 库不支持它。

由于 Netty 只实现了TLS,它可能不适用于 UDP。

【讨论】:

  • 有没有办法将 DTLS 与 netty 或任何示例一起使用?
  • 据我所知,我不知道任何使用 Netty 的 DTLS 实现。但是按照规范,以Netty的TLS实现为起点,应该不会这么复杂,希望...
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-05-17
  • 2022-01-04
  • 1970-01-01
  • 2018-04-14
  • 1970-01-01
  • 2018-03-08
相关资源
最近更新 更多