介绍上一篇我们讲了如何在netty中构建客户端,分别使用tcp和udp协议向DNS服务器请求消息。消息在请求过程中没有加密,所以这个请求是不安全的。那么有同学会问了,只是请求解析一个域名的IP地址,还需要安全通信吗?事实上,未加密的DNS查询消息是非常危险的。如果您访问重要网站时DNS查询报文被监听或篡改,您收到的查询返回的IP地址有可能不是真实地址,而是被篡改后的地址打开了钓鱼网站或其他恶意网站网站,从而造成不必要的损失。因此,还需要保护DNS查询。幸运的是,在DNS传输协议中专门规定了一种加密传输协议,称为DNS-over-TLS,简称“DoT”。那么在netty中是否可以使用DoT进行DNS服务查询呢?一起来看看吧。支持DoT的DNS服务器由于DNS中有很多传输协议规范,但并不是每一个DNS服务器都支持所有的规范,所以在使用DoT之前我们需要先找到一个能够支持DoT协议的DNS服务器。这里我还是选择使用阿里的DNS服务器:223.5.5.5之前,使用TCP和UDP协议时,查询的DNS端口是53,如果改成DoT,那么端口需要改成853。搭建一个支持DoT的netty客户端DoT底层还是TCP协议,也就是TLSoverTCP,所以我们需要使用NioEventLoopGroup和NioSocketChannel搭建一个netty客户端,如下图:EventLoopGroupgroup=newNioEventLoopGroup();Bootstrapb=newBootstrap();b.group(group).channel(NioSocketChannel.class).handler(newDotChannelInitializer(sslContext,dnsServer,dnsPort));最终通道ch=b.connect(dnsServer,dnsPort).sync().channel();这里我们选择NioEventLoopGroup和NioSocketChannel。然后将自定义的DotChannelInitializer传递给Bootstrap。DotChannelInitializer包含自定义处理程序和netty自己的处理程序。我们看一下DotChannelInitializer的定义和它的构造函数:this.dnsServer=dnsServer;this.dnsServer=dnsServer;DNS端口;}DotChannelInitializer需要三个参数,分别是sslContext、dnsServer和dnsPort。这三个参数在sslContext中使用:protectedvoidinitChannel(SocketChannelch){ChannelPipelinep=ch.pipeline();p.addLast(sslContext.newHandler(ch.alloc(),dnsServer,dnsPort)).addLast(newTcpDnsQueryEncoder()).addLast(newTcpDnsResponseDecoder()).addLast(newDotChannelInboundHandler());}SslContext主要用于TLS配置,下面是SslContext的定义:SslProviderprovider=SslProvider.isAlpnSupported(SslProvider.OPENSSL)?SslProvider.OPENSSL:SslProvider.JDK;最终SslContextsslContext=SslContextBuilder.forClient().sslProvider(provider).protocols("TLSv1.3","TLSv1.2").build();因为SslProvider有很多种,可以选择openssl,也可以选择JDK自带的。这里我们使用openssl,为了提供openssl的支持,我们还需要提供openssl的依赖包如下:
