网易首页 > 网易号 > 正文 申请入驻

没错,请求DNS服务器还可以使用UDP协议

0
分享至

简介

之前我们讲到了如何在netty中构建client向DNS服务器进行域名解析请求。使用的是最常见的TCP协议,也叫做Do53/TCP。

事实上除了TCP协议之外,DNS服务器还接收UDP协议。这个协议叫做DNS-over-UDP/53,简称(“Do53”)。

本文将会一步一步带领大家在netty中搭建使用UDP的DNS客户端。

搭建netty客户端

因为这里使用的UDP协议,netty为UDP协议提供了专门的channel叫做NioDatagramChannel。EventLoopGroup还是可以使用常用的NioEventLoopGroup,这样我们搭建netty客户端的代码和常用的NIO UDP代码没有太大的区别,如下所示:

EventLoopGroup group = new NioEventLoopGroup();
Bootstrap b = new Bootstrap();
b.group(group)
.channel(NioDatagramChannel.class)
.handler(new Do53UdpChannelInitializer());
final Channel ch = b.bind(0).sync().channel();

这里的EventLoopGroup使用的是NioEventLoopGroup,作为client端Bootstrap的group。

因为要使用UDP协议进行传输,所以这里的channel使用的是NioDatagramChannel。

设置好channel之后,传入我们自定义的handler,netty client就搭建完毕了。

因为是UDP,所以这里没有使用TCP中的connect方法,而是使用bind方法来获得channel。

Do53UdpChannelInitializer中包含了netty提供的UDP DNS的编码解码器,还有自定义的消息处理器,我们会在后面的章节中详细进行介绍。

在netty中发送DNS查询请求

搭建好netty客户端之后,接下来就是使用客户端发送DNS查询消息了。

先看具体的查询代码:

int randomID = (int) (System.currentTimeMillis() / 1000);
DnsQuery query = new DatagramDnsQuery(null, addr, randomID).setRecord(
DnsSection.QUESTION,
new DefaultDnsQuestion(queryDomain, DnsRecordType.A));
ch.writeAndFlush(query).sync();
boolean result = ch.closeFuture().await(10, TimeUnit.SECONDS);
if (!result) {
log.error("DNS查询失败");
ch.close().sync();

查询的逻辑是先构建UDP的DnsQuery请求包,然后将这请求包写入到channel中,然后等待消息处理完毕。

DnsQuery之前我们已经介绍过了,他是netty中所有DNS查询的基础类。

public interface DnsQuery extends DnsMessage

DnsQuery的子类有两个,分别是DatagramDnsQuery和DefaultDnsQuery。这两个实现类一个表示UDP协议的查询,一个表示TCP协议的查询。

我们看下UDP协议的DatagramDnsQuery具体定义:

public class DatagramDnsQuery extends DefaultDnsQuery implements AddressedEnvelope

可以看到DatagramDnsQuery不仅仅继承自DefaultDnsQuery,还实现了AddressedEnvelope接口。

AddressedEnvelope是netty中UDP包的定义,所以要想在netty中发送基于UDP协议的数据包,就必须实现AddressedEnvelope中定义的方法。

作为一个UDP数据包,除了基本的DNS查询中所需要的id和opCode之外,还需要提供两个额外的地址,分别是sender和recipient:

private final InetSocketAddress sender;
private final InetSocketAddress recipient;

所以DatagramDnsQuery的构造函数可以接收4个参数:

public DatagramDnsQuery(InetSocketAddress sender, InetSocketAddress recipient, int id, DnsOpCode opCode) {
super(id, opCode);
if (recipient == null && sender == null) {
throw new NullPointerException("recipient and sender");
} else {
this.sender = sender;
this.recipient = recipient;

这里recipient和sender不能同时为空。

在上面的代码中,我们构建DatagramDnsQuery时,传入了服务器的InetSocketAddress:

final String dnsServer = "223.5.5.5";
final int dnsPort = 53;
InetSocketAddress addr = new InetSocketAddress(dnsServer, dnsPort);

并且随机生成了一个ID。然后调用setRecord方法填充查询的数据。

.setRecord(DnsSection.QUESTION,
new DefaultDnsQuestion(queryDomain, DnsRecordType.A));

DnsSection有4个,分别是:

QUESTION,
ANSWER,
AUTHORITY,
ADDITIONAL;

这里是查询操作,所以需要设置DnsSection.QUESTION。它的值是一个DnsQuestion:

public class DefaultDnsQuestion extends AbstractDnsRecord implements DnsQuestion

在这个查询中,我们传入了要查询的domain值:www.flydean.com,还有查询的类型A:address,表示的是域名的IP地址。

DNS消息的处理

在Do53UdpChannelInitializer中为pipline添加了netty提供的UDP编码解码器和自定义的消息处理器:

class Do53UdpChannelInitializer extends ChannelInitializer {
@Override
protected void initChannel(DatagramChannel ch) throws Exception {
ChannelPipeline p = ch.pipeline();
p.addLast(new DatagramDnsQueryEncoder())
.addLast(new DatagramDnsResponseDecoder())
.addLast(new Do53UdpChannelInboundHandler());

DatagramDnsQueryEncoder负责将DnsQuery编码成为DatagramPacket,从而可以在NioDatagramChannel中进行传输。

public class DatagramDnsQueryEncoder extends MessageToMessageEncoder> {

DatagramDnsQueryEncoder继承自MessageToMessageEncoder,要编码的对象是AddressedEnvelope,也就是我们构建的DatagramDnsQuery。

看一下它里面最核心的encode方法:

protected void encode(ChannelHandlerContext ctx, AddressedEnvelope in, List out) throws Exception {
InetSocketAddress recipient = (InetSocketAddress)in.recipient();
DnsQuery query = (DnsQuery)in.content();
ByteBuf buf = this.allocateBuffer(ctx, in);
boolean success = false;
try {
this.encoder.encode(query, buf);
success = true;
} finally {
if (!success) {
buf.release();

out.add(new DatagramPacket(buf, recipient, (InetSocketAddress)null));

基本思路就是从AddressedEnvelope中取出recipient和DnsQuery,然后调用encoder.encode方法将DnsQuery进行编码,最后将这些数据封装到DatagramPacket中。

这里的encoder是一个DnsQueryEncoder实例,专门用来编码DnsQuery对象。

DatagramDnsResponseDecoder负责将接受到的DatagramPacket对象解码成为DnsResponse供后续的自定义程序读取使用:

public class DatagramDnsResponseDecoder extends MessageToMessageDecoder

看一下它的decode方法:

protected void decode(ChannelHandlerContext ctx, DatagramPacket packet, List out) throws Exception {
try {
out.add(this.decodeResponse(ctx, packet));
} catch (IndexOutOfBoundsException var5) {
throw new CorruptedFrameException("Unable to decode response", var5);

上面的decode方法实际上调用了DnsResponseDecoder的decode方法进行解码操作。

最后就是自定义的Do53UdpChannelInboundHandler用来进行消息的读取和解析:

private static void readMsg(DatagramDnsResponse msg) {
if (msg.count(DnsSection.QUESTION) > 0) {
DnsQuestion question = msg.recordAt(DnsSection.QUESTION, 0);
log.info("question is :{}", question);
for (int i = 0, count = msg.count(DnsSection.ANSWER); i < count; i++) {
DnsRecord record = msg.recordAt(DnsSection.ANSWER, i);
if (record.type() == DnsRecordType.A) {
//A记录用来指定主机名或者域名对应的IP地址
DnsRawRecord raw = (DnsRawRecord) record;
System.out.println(NetUtil.bytesToIpAddress(ByteBufUtil.getBytes(raw.content())));

自定义handler接受的是一个DatagramDnsResponse对象,处理逻辑也很简单,首先读取msg中的QUESTION,并打印出来。

然后读取msg中的ANSWER字段,如果ANSWER的类型是A address,那么就调用NetUtil.bytesToIpAddress方法将其转换成为IP地址输出。

最后我们可能得到下面的输出:

question is :DefaultDnsQuestion(www.flydean.com. IN A)
49.112.38.167
总结

以上就是在netty中使用UDP协议进行DNS查询的详细讲解。

本文的代码,大家可以参考:

learn-netty4

更多内容请参考 http://www.flydean.com/55-netty-dns-over-udp/ 最通俗的解读,最深刻的干货,最简洁的教程,众多你不知道的小技巧等你来发现! 欢迎关注我的公众号:「程序那些事」,懂技术,更懂你!


特别声明:以上内容(如有图片或视频亦包括在内)为自媒体平台“网易号”用户上传并发布,本平台仅提供信息存储服务。

Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.

相关推荐
热点推荐
落寞?朱婷回归首秀仅发1次球!孤立场边,未与队长击掌冲上热搜

落寞?朱婷回归首秀仅发1次球!孤立场边,未与队长击掌冲上热搜

我爱英超
2024-05-29 21:42:48
3-1!中国女排逆转荷兰,世联赛稳居前四,世界排名甩开日本

3-1!中国女排逆转荷兰,世联赛稳居前四,世界排名甩开日本

天涯沦落人
2024-05-29 21:43:24
中国一则爆料疯传全网!父亲多年前4000枚比特币意外寻获 现价已破20亿元人民币

中国一则爆料疯传全网!父亲多年前4000枚比特币意外寻获 现价已破20亿元人民币

FX168链界观察
2024-05-29 12:42:11
“把握前进方向”!时隔5年,高规格会议再次召开,有重要部署

“把握前进方向”!时隔5年,高规格会议再次召开,有重要部署

政知新媒体
2024-05-29 21:08:22
中国女排最新消息!赖亚文约谈朱婷:你不再是球队核心!

中国女排最新消息!赖亚文约谈朱婷:你不再是球队核心!

元爸体育
2024-05-29 20:33:58
庚欣:五角大楼主动放风中美防长会晤,传递了什么信号?

庚欣:五角大楼主动放风中美防长会晤,传递了什么信号?

直新闻
2024-05-29 21:46:03
将近40岁满脸褶,却尬演18岁少女,是谁给了她“强行装嫩”的勇气

将近40岁满脸褶,却尬演18岁少女,是谁给了她“强行装嫩”的勇气

娱乐圈十三太保
2024-05-28 13:56:53
小伙赴云南失联被法院判决宣告死亡 两年后回家:申请撤销死亡宣告

小伙赴云南失联被法院判决宣告死亡 两年后回家:申请撤销死亡宣告

红星新闻
2024-05-29 18:58:08
郭碧婷和李胜利被曝恩爱合照,还有当年的订婚瓜!这次是彻底惹怒

郭碧婷和李胜利被曝恩爱合照,还有当年的订婚瓜!这次是彻底惹怒

热闹吃瓜大姐
2024-05-29 21:08:02
国税总局原副局长表示:五口之家靠一人工作,工资4000,就能脱贫

国税总局原副局长表示:五口之家靠一人工作,工资4000,就能脱贫

六目先生
2024-05-28 21:34:24
请铭记今天!2024.5.28,它们集体走上了“邪路”!

请铭记今天!2024.5.28,它们集体走上了“邪路”!

大碗楼市
2024-05-29 08:07:37
以色列议会拟推动认定联合国机构为恐怖组织!

以色列议会拟推动认定联合国机构为恐怖组织!

鲁中晨报
2024-05-29 09:30:09
多国政客谈论“开战”可能,俄方警告或致局势失控,欧洲对俄乌冲突分歧加剧

多国政客谈论“开战”可能,俄方警告或致局势失控,欧洲对俄乌冲突分歧加剧

环球网资讯
2024-05-29 06:36:25
贾跃亭:将正式发布中美汽车产业桥梁战略!将售价30万美金FF91核心技术赋能大众车型,让美国大众享受

贾跃亭:将正式发布中美汽车产业桥梁战略!将售价30万美金FF91核心技术赋能大众车型,让美国大众享受

和讯网
2024-05-29 14:30:34
太现实!央视三胎宣传片,网友:看了这宣传片谁还敢生孩子了呀!

太现实!央视三胎宣传片,网友:看了这宣传片谁还敢生孩子了呀!

户外钓鱼哥阿勇
2024-05-29 21:48:28
国务院:2024—2025年逐步取消各地新能源汽车购买限制

国务院:2024—2025年逐步取消各地新能源汽车购买限制

每日经济新闻
2024-05-29 20:28:02
杨幂这个腿非得这样吗?知道她腿美,也不用这么刻意吧!

杨幂这个腿非得这样吗?知道她腿美,也不用这么刻意吧!

娱乐八卦木木子
2024-05-29 21:00:30
iPhone15降价,中国销量激增52%!多数国人愿花费4000+买手机,仅33%人有高端手机,面临华为Mate 70竞争

iPhone15降价,中国销量激增52%!多数国人愿花费4000+买手机,仅33%人有高端手机,面临华为Mate 70竞争

和讯网
2024-05-29 09:47:24
伊利牛奶事件持续发酵,伊利回应引热议,官方评论区已关闭

伊利牛奶事件持续发酵,伊利回应引热议,官方评论区已关闭

大宗看萌宠
2024-05-29 16:39:35
“歼-20具备超音速巡航能力”引外媒关注,军事专家解读

“歼-20具备超音速巡航能力”引外媒关注,军事专家解读

环球网资讯
2024-05-29 06:56:08
2024-05-30 00:14:44
flydean程序那些事
flydean程序那些事
最通俗的解读,最深刻的干货!
356文章数 438关注度
往期回顾 全部

科技要闻

王传福再放狠话,燃油车要成“非主流”

头条要闻

中方点名:在本届世卫大会涉台问题上 日本跳得尤其高

头条要闻

中方点名:在本届世卫大会涉台问题上 日本跳得尤其高

体育要闻

华子面临横扫时 想起他还从没被横扫过

娱乐要闻

张若昀怎么剧外比剧内更惨兮兮…

财经要闻

国务院:逐步取消各地新能源汽车购买限制

汽车要闻

新哈弗H6苦练内功 向燃油车绝缘智能SAY NO

态度原创

教育
房产
本地
家居
军事航空

教育要闻

别让“乖巧”,束缚了孩子的成长

房产要闻

牛X!单日销量超20亿!仁恒长天雲汀开盘真爆了!

本地新闻

食味印象|歙县限定!枇杷味儿的清甜初夏

家居要闻

与美共生 空间线条勾勒生活风雅

军事要闻

俄罗斯国防部"大洗牌" 1个月内5名高官接连"落马"

无障碍浏览 进入关怀版