• What I learned from making a DNS client in Rust 译文(Rust 实现一个 DNS 客户端,我从中学到什么)
  • 原文链接:https://blog.adamchalmers.com/making-a-dns-client/
  • 原文作者:Adam Chalmers
  • 译文来自:https://github.com/suhanyujie/article-transfer-rs/
  • 译者:suhanyujie
  • ps:水平有限,翻译不当之处,还请指正。
  • 标签:Rust, DNS, DNS client

在过去的几周里,我构建了我自己的 DNS 客户端。主要是因为我认为 dig(一个标准的 DNS 客户端)有点笨重。另一部分原因是我想了解更多关于 DNS 的知识。这就是我如何创建它,也是你如何创建 dns 客户端的过程。它是一个很棒的“周末项目”,我从完成它中学到了很多。

为什么?

Julia Evans 给我提供了一些思路。她是我最喜欢的技术博客作者之一。她的博客总能给我一些启发,经常激励我去学习新的东西。她也很擅长把复杂的话题总结成简单的小漫画,比如这个:

但我看完这个漫画后,我震惊了 —— DNS 查询协议比我想象的要简单得多。并且,我所在的公司在 DNS 领域算是一个大玩家。我理应更了解这个。

计划

我想构建 DNS 客户端的另一个原因是我可以使用一些优秀的 Rust crate 来快速实现(节省很多步骤)。

  1. 使用 picoargs 解析 CLI 参数

它没有 clap 那么强大,clap 可以视为 Rust 的“企业级” crate,它依赖了很多其他 crate。但我并不需要那么多高级特性,而且 picoargs 的编译速度会快_很多_。

  1. 使用 bitvec 序列化 DNS 查询,它是一个强大且通用的读写“位”值的库。

在做 Advent of Code 时,我学会了使用 Nom 解析“位”协议,我也考虑过使用 deku,但最后还是不使用它了。

  1. 使用 stdlib UdpSocket 类型与 DNS 解析器通信

我不知道怎么使用,但 Rust stdlib 有很详细的相关文档,所以我有信心能够学会它。

  1. 使用 Nom 解析响应的二进制数据

    在做 Advent of Code 的时候,我学会如何使用 Nom 解析位协议。我之前的(博客)(/nom-dns) 中更加详细的描述了解析 DNS 头部指南,使用 Nom 解析位级别的 1 个标志位和 4 个位数值。

  2. 使用 println! 将响应发送给用户

实现的怎么样了?

它用了大概 800 行代码,一个周末就能完成。规范中只有一小部分还没实现:消息的压缩(MC)。不幸的是,我又要花一个周末去完成 —— 详见下方描述。

我把它命名为 Dingo,因为它听起来像 dig,它让我想起了澳大利亚,我的家。无论如何,它可以正常工作!

你可以安装它,也可以在 github 查看源代码。

我学到了什么?

阅读 RFC 文档

我认为很多程序员会被 rfc 吓到。至少我有这种感觉,因为我也被吓到过。可能我的其他同行是喜欢 rfc 的怪物吧,他们在阅读存文本的 ASCII 时会感到兴奋不已。。。但他们从未提过。

RFC 1035 定义了 DNS 消息协议,所以我必须非常仔细地阅读它。这是我第一次真正地从上到下阅读 RFC,文档详细的程度让我感到吃惊。我不断地参考它,并将 RFC 中的关键字和一些关键句子粘贴到源代码注释中,以帮助理解代码的实现原因。也有可能是 RFC 1035 是唯一容易理解的文档,其他都是难理解的。无论如何,我喜欢它。

(作为一个历史留下来的文档,自从 1980 年以来,它发生了很大的变化,了解过去的程序员是如何设计互联网是非常有趣的)

Sockets

一直以来,我对 socket 不是很喜欢。大学的时候,我试着阅读 Beej 的 socket 编程指南,但当时没有合适的操作系统、网络和 c 技能来完成学习。我了解 TCP 和 UDP,但对统一他们的底层抽象却一无所知。

这个项目使我第一次不得不打开一个 UDP socket —— 在常规编程中,我都是依赖于一些网络库来处理底层细节。所以,我阅读了 Rust 的 UDP socket 文档,它写的很清楚。UdpSocket 上的很多方法直接对应于 Linux 系统调用。当我再回过头来重新阅读 Beej 的 socket 编程指南时,发现很容易懂了。所有的系统调用都比较熟悉 —— 它们只是 Rust 的 stdlib 中的网络方法!

事实上,如果我使用 dtruss(一个MacOS工具,用于检查您的程序有哪些系统调用),我可以确切地看到程序在使用哪个系统调用。

$ sudo dtruss dingo -t A www.twitter.com
# Skipping lots of syscalls just for starting a process on MacOS...
getentropy(0x7FF7BE8734E0, 0x20, 0x0)  = 0 0 # Used by `rand` to generate a random DNS request ID
socket(0x2, 0x2, 0x0)  = 3 0 # Create the UDP socket, aka "file descriptor 3"
ioctl(0x3, 0x20006601, 0x0)  = 0 0 # Not sure, something about the UDP socket
setsockopt(0x3, 0xFFFF, 0x1022)  = 0 0 # Set the options on the UDP socket
bind(0x3, 0x7FF7BE87346C, 0x10)  = 0 0 # Bind the UDP socket to a local address
setsockopt(0x3, 0xFFFF, 0x1006)  = 0 0 # Set more options, dunno why it needs more...
connect(0x3, 0x7FF7BE873584, 0x10)  = 0 0 # Connect to the remote DNS resolver
sendto(0x3, 0x7FAE060041F0, 0x21)  = 33 0 # Send the request to the remote DNS resolver
recvfrom(0x3, 0x7FAE060043F0, 0x200)  = 79 0 # Get the response from the remote DNS resolver
close_nocancel(0x3)  = 0 0 # Close the UDP socket
# Skipping lots of syscalls just for ending a process on MacOS

系统调用 connectsendtorecvfrom 都来自于 Rust 中的方法 UdpSocket::{connect, send_to, recv_from} —— 它们将会 1:1 转换成真正的系统调用!这很酷。

Bitvec

我真的很喜欢 Bitvec。它结合了 Vec<bool> 类型的可用性和可读性,并具备“位”的可操作性。而这正是 Rust 毫不妥协的“人体工程学、速度和正确性”的体现。

标准库公开了 BitArray,BitVec 和 BitSlice 类型。它们的工作原来基本相同,但我发现了两个小问题,它们的工作方式不同。这些很容易通过单元测试发现,所以我想这是一个不错的学习方式。作者希望在 Rust 发布 const generics后,会发布 Bitvec 2.0,使这些类型都能以类似的方式使用。

Dig 的奇怪输出

我之前提到过,我讨厌使用 dig。它有那么多令人困惑的无关信息。我只是想看看一些主机名的解析是什么,而 dig 展示了很多我并不关心的额外信息。

$ dig adamchalmers.com; <<>> DiG 9.10.6 <<>> adamchalmers.com
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 51459
;; flags: qr rd ra; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 1;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;adamchalmers.com.      IN  A;; ANSWER SECTION:
adamchalmers.com.   300 IN  A   104.19.237.120
adamchalmers.com.   300 IN  A   104.19.238.120;; Query time: 80 msec
;; SERVER: 2600:1700:280:1f40::1#53(2600:1700:280:1f40::1)
;; WHEN: Sun Apr 10 17:48:43 CDT 2022
;; MSG SIZE  rcvd: 77

但在实现了一个 DNS 客户端之后,我根进一步了解了这些相关知识。例如,“IN”并不是英文单词“in”的意思,它是“Internet”的缩写,因为从技术上讲,DNS 支持许多名称空间(只是我们基本上只使用 dig 来进行 Internet DNS 查询)。

现在看 dig 输出有点酷,因为它提醒我学到了多少东西。是的,我还了解到,dig 查询很容易就能得到你想要的信息:

$ dig +short adamchalmers.com
104.19.238.120
104.19.237.120

。。。如果我早在一月份就知道这些,我可能永远不会开始这个项目

【译】Rust 实现一个 DNS 客户端,我从中学到什么相关推荐

  1. c语言dns客户端程序,C中的DNS客户端

    我目前正在做一个学校项目,要求我实现一个DNS客户端,而不使用任何库函数. 我已经到了发送DNS请求并接收回复的程度.我在分析答复时遇到麻烦了.我接收到一个char*数组中的回复,我想把它转换成一个有 ...

  2. [译]使用 Rust 开发一个简单的 Web 应用,第 4 部分 —— CLI 选项解析

    原文地址:A Simple Web App in Rust, Part 4 -- CLI Option Parsing 原文作者:Joel's Journal 译文出自:掘金翻译计划 本文永久链接:g ...

  3. 实战:配置DNS客户端域名搜索后缀构造域名进行域名解析

    2.1 实战:配置客户端使用DNS服务器解析计算机名 实战目的: ü 在内网,用户习惯使用计算机名而不是计算机全名访问资源,你需要配置客户端,解析计算机名时在计算机名称后添加一个DNS后缀构造一个域名 ...

  4. linux 网络慢 dns,Linux DNS客户端解析域名慢解决

    Linux DNS客户端解析域名慢的问题: Linux系统下域名解析的配置文件是/etc/resolv.conf cat /etc/resolv.conf # Generated by Network ...

  5. 关于我遇到的一个DNS问题

    最近遇到一个小问题,在某些用户的请求中会莫名其妙的出现重定向然后导致404,在这里分享下导致这种问题的原因. 这里不会介绍DNS和CDN,如果想了解请google或百度,有好几斤的数据可以看,我也没必 ...

  6. 用 Node.js 手写一个 DNS 服务器

    DNS 是实现域名到 IP 转换的网络协议,当访问网页的时候,浏览器首先会通过 DNS 协议把域名转换为 IP,然后再向这个 IP 发送 HTTP 请求. DNS 是我们整天在用的协议,不知道大家是否 ...

  7. DIY一个DNS查询器:了解DNS协议

    每当我们在浏览器上敲入任何一个域名访问某个网站的时候,我们都要使用Dns协议进行一次"域名:IP"的查询;作为命令行使用者,与dns有关用的最多的就是Nslookup 命令吧:作为 ...

  8. chrome扩展推荐:有我,你又省了一个ssh客户端 --- Secure Shell

    严格上说这并不是一个扩展,而是一个chrome的应用,它比扩展能实现的东东更多,是个可以单独运行的application. 还是先上图,然后再说话. 和现在阿里云和腾讯云的web控制台差不多,是一个s ...

  9. http默认超时时间_Bof 是一个HTTP客户端,旨在尽可能方便用户使用

    Bof Bof是一个HTTP客户端,旨在尽可能方便用户使用. 它使最经典的用例(例如下载文件,与JSON API交互或提交表单)尽可能地简单. 由于Bof基于Guzzle,因此可以直接使用Guzzle ...

最新文章

  1. Google Protocol Buffers介绍
  2. android监控来电显示
  3. LCD RGB 控制技术 时钟篇(下)
  4. LAMP+LNMP(四)PHP安装实践
  5. 《锋利的jQuery》bug总结(1)
  6. Win32 Application 、Win32 Console Application、MFC工程项目
  7. 扒开医院的围墙,互联网怎么个战法?
  8. 黑马博客——详细步骤(七)项目功能的实现之文章管理
  9. pytorch---模型加载与保存(2)
  10. 两部委联合查处一批网店侵权 淘宝易趣成重灾区
  11. Android 中获取符合分辨率的视频
  12. 想破解游戏协议?你知道客户端和服务器是怎么通信的?我来告诉你怎么定义的
  13. 后缀自动机入门/基本概念
  14. Arduino Uno 实验15——MQ-135 气体传感器模块
  15. HTML学生个人网站作业设计:电影网站设计——叮当电影(5页) HTML+CSS+JavaScript 简单DIV布局个人介绍网页模板代码 DW学生个人网站制作成品下载
  16. Word去除目录主页页码
  17. mysql转拼音首字母大写_Mysql中文汉字转拼音的实现  mysql首字母转化为大写
  18. 《小狗钱钱》 读后感
  19. C语言快速画直线和画圆的代码
  20. 可能是第十好的Android 开源 日历 Calendar 仿小米

热门文章

  1. using werkzeug to build a shorly url app
  2. c语言y为奇数的关系表达,设y是int型,请写出y为奇数的关系表达式
  3. 阿里珍贵技术资料免费下载
  4. HTML5期末大作业:动漫网站设计——福五鼠动漫(6页)带轮播特效 高质量代码 HTML+CSS+JavaScript 毕设网页设计HTML
  5. datawhale组队学习task9—文件与文件系统
  6. python应用程序无法正常启动0xc0000142_应用程序无法正常启动(0xc0000142)的解决办法...
  7. rsa/ecb/pkcs1padding php,PHPJAVA RSA/ECB/PKCS1Padding 加密解密
  8. iPad上支持手柄的游戏推荐 - PUSDN
  9. 腾讯安全与青藤云安全联合发布“天眼云镜”主机安全产品
  10. 4个星期=一百万美金?网页创造的神话!