草庐IT

DNS

ys-wang 2023-03-28 原文

DNS

什么是DNS

DNS是域名系统(Domain Name System),简单来说就是平时上网输入的URL,如 www.baidu.com 就是域名,而DNS就是将这个域名解析成IP地址,如 www.baidu.com 的一个IP地址为 14.215.177.38,DNS使用的端口号为53,使用UDP协议

为什么需要DNS

因为在我们上网的过程中,IP地址很难记住,而域名相对说就简单很多,所以需要把我们的域名转换成IP地址

计算机为什么不使用域名和使用IP地址?

因为域名长度可变,计算机处理起来困难,而IP地址是定长的,处理起来简单很多

为什么需要分不同的域名服务器(如根域名...)

从理论上来讲,可以只需要一台服务器把所有的域名都装入这台服务器就可以,大家查询DNS的时候访问这个DNS服务器即可,为了安全也可以设置多个服务器,每台服务器都装入所有的IP地址,个人认为这样显然是可以的(如果担心访问量太大导致网络瘫痪就设置多个这样的服务器,而且同一个IP可以用多台主机来进行处理),书上的解释就是所有的主机都访问这一台DNS服务器导致瘫痪,期待更合理的解释

DNS解析过程

  1. 首先看浏览器DNS的缓存,如果浏览器DNS缓存有,那么就直接访问;
  2. 如果浏览器DNS没有相应的缓存,则看HOST文件,如果HOST有文件,则直接访问即可;
  3. 如果发现还没有对应的IP地址,则主机需要向本地DNS服务器(ISP服务器或者自己手动设置的DNS服务器)发起查询,但是这里有一个问题,本地DNS服务器地址哪里来的?(如果是通过运营商上网的,会自动分配IP与设置DNS,如果是通过路由器上网的,那么就会通过DHCP的方式配置IP与DNS地址,具体可以百度DHCP客户端请求IP地址的过程,这里暂时还不太清楚,留下这个坑)
  4. 本地DNS服务器收到请求后,会查看本机的DNS缓存,值得注意的是,本地DNS缓存需要安装诸如systemd-resolved,dnsmasq或nscd之类的缓存服务,如果没有安装,则没有操作系统级别的DNS缓存;
  5. 本地DNS服务器发起请求(Ubuntu可以通过cat /etc/resolv.confnslookup [host]查看)
    ,在Ubuntu下,查看本地DNS的服务器的地址为127.0.0.53,显然这个是一个环回地址(环回地址的意思就是主机向自身发送消息,环回地址的IP为127.0.0.1 - 127.255.255.254),那么显然这个数据发送给本机的,本机肯定不能解析这个IP地址,实际上127.0.0.53相当于本地DNS服务器,127.0.0.53还有一个上游DNS服务器的地址(可以通过resolvectl查看)
    ,如果是通过路由器连接网络的,通常上游DNS的地址为路由器本身的地址,如192.168.1.1,那么这个上游DNS服务器怎么来的?本地主机连接路由器的时候,通过DHCP分配本机的IP地址,同时也会告诉主机DNS服务器地址,具体看DHCP篇,梳理一下这个过程就很好理解了,DNS请求首先发给本地DNS服务器127.0.0.53,本地DNS服务器把DNS请求发给路由器,之后路由器再根据上网方式的不同,比如路由器也可以通过DHCP上网,那么路由器也会获得DNS服务器的地址,比如进入路由器后台,查看得到路由器得到的两个DNS服务器地址,那么就是路由器收到DNS请求就把该请求转发路由器得到的这两个DNS服务器地址,之后就是DNS正常解析的流程
  6. 需要补充的是,主机到本地DNS服务器(127.0.0.53)通常都是递归的方式进行查询,而本地DNS服务器与顶级域名服务器···(一级,二级,三级)通常都是迭代,如何从顶级域名到各级域名服务器可以百度,比较简单;

wireshark抓包分析

  1. DNS数据报格式
  • 事务 ID(2字节):DNS 报文的 ID 标识。对于请求报文和其对应的应答报文,该字段的值是相同的。通过它可以区分 DNS 应答报文是对哪个请求进行响应的;

  • 标志(2字节):DNS 报文中的标志字段;

    • QR(Response):查询请求/响应的标志信息。查询请求时,值为 0;响应时,值为 1。
    • Opcode:操作码。其中,0 表示标准查询;1 表示反向查询;2 表示服务器状态请求。
    • AA(Authoritative):授权应答,该字段在响应报文中有效。值为 1 时,表示名称服务器是权威服务器;值为 0 时,表示不是权威服务器。
    • TC(Truncated):表示是否被截断。值为 1 时,表示响应已超过 512 字节并已被截断,只返回前 512 个字节。
    • RD(Recursion Desired):期望递归。该字段能在一个查询中设置,并在响应中返回。该标志告诉名称服务器必须处理这个查询,这种方式被称为一个递归查询。如果该位为 0,且被请求的名称服务器没有一个授权回答,它将返回一个能解答该查询的其他名称服务器列表。这种方式被称为迭代查询。
    • RA(Recursion Available):可用递归。该字段只出现在响应报文中。当值为 1 时,表示服务器支持递归查询。
    • Z:保留字段,在所有的请求和应答报文中,它的值必须为 0。
    • rcode(Reply code):返回码字段,表示响应的差错状态。当值为 0 时,表示没有错误;当值为 1 时,表示报文格式错误(Format error),服务器不能理解请求的报文;当值为 2 时,表示域名服务器失败(Server failure),因为服务器的原因导致没办法处理这个请求;当值为 3 时,表示名字错误(Name Error),只有对授权域名解析服务器有意义,指出解析的域名不存在;当值为 4 时,表示查询类型不支持(Not Implemented),即域名服务器不支持查询类型;当值为 5 时,表示拒绝(Refused),一般是服务器由于设置的策略拒绝给出应答,如服务器不希望对某些请求者给出应答。
  • 问题计数(2字节):DNS 查询请求的数目;

  • 回答资源记录数(2字节):DNS 响应的数目;

  • 权威名称服务器计数(2字节):权威名称服务器的数目;

  • 附加资源记录数(2字节):额外的记录数目(权威名称服务器对应 IP 地址的数目)。

以上,为DNS的头部,长度固定,为12字节

  • 问题部分

其中,查询名长度不固定,查询类型2字节,查询类长度2字节,在DNS请求报文中,只有以上部分,而查询名长度不固定,所以查询类型和查询类是通过DNS报文最后4个字节来确定的;

以上,就是DNS请求的所有部分

  • 在回复报文中,除了以上部分,还有如下三个:

    • 域名:DNS 请求的域名。
    • 类型:资源记录的类型,与问题部分中的查询类型值是一样的。
    • 类:地址类型,与问题部分中的查询类值是一样的。
    • 生存时间:以秒为单位,表示资源记录的生命周期,一般用于当地址解析程序取出资源记录后决定保存及使用缓存数据的时间。它同时也可以表明该资源记录的稳定程度,稳定的信息会被分配一个很大的值。
    • 资源数据长度:资源数据的长度。
    • 资源数据:表示按查询段要求返回的相关资源记录的数据。
  1. 发送的DNS请求包,如图

    分别有以太网首部(14字节),IP数据报首部(固定部分20字节),之后是DNS数据报格式

  2. 接收的DNS数据包

有关DNS的更多相关文章

  1. ruby - 在 Ruby 中获取 DNS TXT 记录 - 2

    我需要从DNS记录中获取txt字段。是否有任何ruby​​api可以做这样的事情?nslookup-q=txtxxxx.com 最佳答案 尝试安装dnsrubygem。代码得到积极维护,并在一些重要的生产系统中使用。require'rubygems'require'dnsruby'includeDnsruby#Usethesystemconfigurednameserverstorunaqueryres=Dnsruby::Resolver.newret=res.query("google.com",Types.TXT)printre

  2. ruby - 在 Ruby 中反向 DNS? - 2

    我处在一个有很多计算机的环境中适当盘点。基本上,没有人知道哪个IP对应哪个mac地址和哪个主机名。所以我写了以下内容:#ThisscriptgoesdowntheentireIPrangeandattemptsto#retrievetheHostnameandmacaddressandoutputsthem#intoafile.Yay!require"socket"TwoOctets="10.26"defcomputer_exists?(computerip)system("ping-c1-W1#{computerip}")enddefappend_to_file(line)file=

  3. ruby-on-rails - "gem install rails"因 DNS 错误而失败 - 2

    $rvmuseUsing/home/owner/.rvm/gems/ruby-2.1.2$geminstallrailsERROR:Whileexecutinggem...(Gem::RemoteFetcher::FetchError)Errno::ECONNREFUSED:Connectionrefused-connect(2)for"your-dns-needs-immediate-attention.network"port80(http://your-dns-needs-immediate-attention.network/quick/Marshal.4.8/thread_s

  4. 【操作系统】十分钟了解关于TCP/IP网络的基础知识(二)ARP、路由器、DHCP、DNS以及TCP/IP - 2

    承接上篇文章(十分钟了解关于TCP/IP网络的基础知识)五.ARP(地址解析协议)        虽说使用IP地址确实方便了我们使用者记忆以及整理归类、寻找信息的发送目的地,但是最终接收数据的地方,还是MAC地址,于是乎,为了实现有IP地址到MAC地址的转换,引入了名为ARP(AddressResolutionProtocol)又称之为地址解析协议。      ARP通过广播(Broadcast,这是个专业名词,后面还会继续提起)的方式对LAN中所有的计算机提问:“哎,谁IP地址是10.165.7.116(上篇文章中的例子)呀?你MAC地址多少啊,快过来登记一下!”,如果有哪台计算机回复了MA

  5. javascript - 在 AJAX 请求中更新域名的 DNS - 2

    我们有DNS故障转移设置,TTL为180秒。当服务器出现故障时,它会将A主机记录上的IP地址更新为工作服务器的IP地址。目前,我们的网站使用AJAX请求定期刷新。当其中一台服务器出现故障时,DNS会更新并进行故障转移,因此如果您对域执行ping操作,它就会拥有正确的IP。但出于某种原因,在浏览器内部和TTL过期很久之后,AJAX请求仍然保留分配给域名的旧IP地址(注意无法在浏览器中重新加载页面)。我知道在阅读其他问题时,您不能强制刷新客户端上的DNS缓存。我的问题是,你们中有人知道使用javascript或AJAX来完成此任务的其他方法或技巧吗?谢谢。 最佳

  6. k8s教程(service篇)-DNS服务搭建和配置 - 2

    文章目录01引言02DNS服务在k8s的发展2.1SkyDNS2.2KubeDNS2.3CoreDNS03搭建CoreDNS服务3.1修改每个Node上kubelet的DNS启动参数3.2部署CoreDNS服务3.2.1ConfigMap3.2.2Deployment3.2.3Service04服务名的DNS解析05CoreDNS配置5.1示例一:设置插件5.2示例二:自定义域名5.3示例三:转发域名查询到上游DNS服务器上06引言01引言声明:本文为《Kubernetes权威指南:从Docker到Kubernetes实践全接触(第5版)》的读书笔记作为服务发现机制的基本功能,在集群内需要能够

  7. javascript - 使用 JavaScript 执行 DNS 查找以将主机名解析为 IP 地址 - 2

    是否可以使用Javascript解析主机名?这里是假设的代码:varhostname="www.yahoo.com";varipAddress=DnsLookup(hostname);console.log(ipAddress);我正在寻找神奇的DnsLookup()函数。:-) 最佳答案 虽然JavaScript中没有标准的DNS功能,但您始终可以调用执行DNS解析的第3方公共(public)API。例如,EncloudprovidessuchanAPI,你可以为它创建一个XMLHttpRequest:varoReq=newXML

  8. go - 如何使用 Go 获取客户端 DNS IP - 2

    我想使用Go获取客户端缓存DNSIP看看下面我试过的代码import("fmt""net")funcmain(){//UsuallyDNSServerusing53portnumber//Thiscase,TCPprotocolisnotconsideredport:=":53"protocol:="udp"varbuf[2048]byte//BuildtheaddressudpAddr,err:=net.ResolveUDPAddr(protocol,port)iferr!=nil{fmt.Println("WrongAddress")return}fmt.Println("List

  9. go - 使用 DNSutil 从域中提取名称服务器 |类型 dns.RR 没有字段或方法 Hdr - 2

    我正在尝试使用GoLang从DNS记录中提取名称服务器。我遇到的问题是我无法从结构中读取字段。我正在将Response转换为JSON,这样我就可以“读取”它有哪些字段,为此我使用了以下代码:json,_:=json.Marshal(ns)fmt.Println(string(json))打印出来:{"Hdr":{"Name":"example.com.","Rrtype":2,"Class":1,"Ttl":172800,"Rdlength":16},"Ns":"ns2.example.eu."}现在,当我尝试使用以下方法从该字符串中打印出Name值时:fmt.Println(ns.H

  10. go - Go 有内置包来创建 DNS 服务器吗? - 2

    关闭。这个问题不符合StackOverflowguidelines.它目前不接受答案。我们不允许提问寻求书籍、工具、软件库等的推荐。您可以编辑问题,以便用事实和引用来回答。关闭7年前。Improvethisquestion我对构建DNS服务器知之甚少,但仍然..Go有内置的包来创建DNS服务器吗?

随机推荐