目录
- 简介
- 支持DoT的DNS服务器
- 搭建支持DoT的netty客户端
- TLS的客户端请求
- 总结
那么有同学会问了,就是请求解析一个域名的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协议,也就是说TLS over TCP,所以我们需要使用NioEventLoopGroup和NioSocketChannel来搭建netty客户端,如下所示:
EventLoopGroup group = new NioEventLoopGroup();Bootstrap b = new Bootstrap();b.group(group).channel(NioSocketChannel.class).handler(new DotChannelInitializer(sslContext, dnsServer, dnsPort));final Channel ch = b.connect(dnsServer, dnsPort).sync().channel();
这里选择的是NioEventLoopGroup和NioSocketChannel 。然后向Bootstrap中传入自定义的DotChannelInitializer即可 。DotChannelInitializer中包含了自定义的handler和netty自带的handler 。
我们来看下DotChannelInitializer的定义和他的构造函数:
class DotChannelInitializer extends ChannelInitializer<SocketChannel> {public DotChannelInitializer(SslContext sslContext, String dnsServer, int dnsPort) {this.sslContext = sslContext;this.dnsServer = dnsServer;this.dnsPort = dnsPort;}
DotChannelInitializer需要三个参数分别是sslContext,dnsServer和dnsPort 。这三个参数都是在sslContext中使用的:
protected void initChannel(SocketChannel ch) {ChannelPipeline p = ch.pipeline();p.addLast(sslContext.newHandler(ch.alloc(), dnsServer, dnsPort)).addLast(new TcpDnsQueryEncoder()).addLast(new TcpDnsResponseDecoder()).addLast(new DotChannelInboundHandler());}
SslContext主要用来进行TLS配置,下面是SslContext的定义:SslProvider provider =SslProvider.isAlpnSupported(SslProvider.OPENSSL)? SslProvider.OPENSSL : SslProvider.JDK;final SslContext sslContext = SslContextBuilder.forClient().sslProvider(provider).protocols("TLSv1.3", "TLSv1.2").build();
因为SslProvider有很多种,可以选择openssl,也可以选择JDK自带的 。这里我们使用的openssl,要想提供openssl的支持,我们还需要提供openssl的依赖包如下:
<dependency><groupId>io.netty</groupId><artifactId>netty-tcnative</artifactId><version>2.0.51.Final</version></dependency><dependency><groupId>io.netty</groupId><artifactId>netty-tcnative-boringssl-static</artifactId><version>2.0.51.Final</version></dependency>
有了provider之后,就可以调用SslContextBuilder.forClient方法来创建SslContext 。这里我们指定SSL的protocol是"TLSv1.3"和"TLSv1.2" 。
然后再调用sslContext的newHandler方法就创建好了支持ssl的handler:
sslContext.newHandler(ch.alloc(), dnsServer, dnsPort)
newHandler还需要指定dnsServer和dnsPort信息 。处理完ssl , 接下来就是对dns查询和响应的编码解码器,这里使用的是TcpDnsQueryEncoder和TcpDnsResponseDecoder 。
TcpDnsQueryEncoder和TcpDnsResponseDecoder在之前介绍使用netty搭建tcp客户端的时候就已经详细解说过了,这里就不再进行讲解了 。
编码解码之后 , 就是自定义的消息处理器DotChannelInboundHandler:
class DotChannelInboundHandler extends SimpleChannelInboundHandler<DefaultDnsResponse>
DotChannelInboundHandler中定义了消息的具体处理方法:private static void readMsg(DefaultDnsResponse msg) {if (msg.count(DnsSection.QUESTION) > 0) {DnsQuestion question = msg.recordAt(DnsSection.QUESTION, 0);log.info("question is :{}", question);}int i = 0, count = msg.count(DnsSection.ANSWER);while (i < count) {DnsRecord record = msg.recordAt(DnsSection.ANSWER, i);if (record.type() == DnsRecordType.A) {//A记录用来指定主机名或者域名对应的IP地址DnsRawRecord raw = (DnsRawRecord) record;log.info("ip address is: {}",NetUtil.bytesToIpAddress(ByteBufUtil.getBytes(raw.content())));}i++;}}
推荐阅读
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 明日之后热晶实验室奇遇任务的完成方法是什么
- 【JVM】关于JVM,你需要掌握这些 | 一文彻底吃透JVM系列
- 死磕面试系列,Java到底是值传递还是引用传递?
- 之七 2流高手速成记:基于Dubbo&Nacos的微服务简要实现
- 金铲铲之战巨岩龙羁绊效果是什么样
- 哈利波特:魔法觉醒黑暗之息时装怎么获取
- 明日之后怎么可以一直玩(明日之后新手建议玩吗)
- 网吧怎么玩明日之后(网吧怎么登录明日之后pc)
- 怎么玩好明日之后(明日之后从零开始教程)
- 低配电脑怎么玩明日之后(电脑如何玩明日之后)