DNS解析流程
当我们访问http://www.itkaoti.top的时候, 浏览器是如何通过www.itkaoti.top 转为ip 来找到我们的服务器资源的?
将域名 转为 ip 就是DNS域名解析。其大概流程如下:
- 先去找hosts文件, 如果存在就直接返回。
我们通过修改hosts 使得我们访问 baidu.itkaoti.top 去访问baidu,
在hosts文件中添加 180.101.49.11 baidu.itkaoti.top, 浏览器访问,百度限制了, 但是我们可以看到域名被重定向了
- 如果hosts中没有设置,就向本地DNS服务器(local DNS server),如果存在就直接返回了
上面 nslookup www.baidu.com, 我上面的119.29.29.29 就是本地dns服务器, 我本地使用的是 DNSPod Public DNS 提供的公共DNS域名解析。
- 如果本地域名也没有就会请求根服务器(13台) , 然后通过轮询或者迭代查询, 返回对应的ip
DNS服务器一般分三种,根DNS服务器,顶级DNS服务器,权威DNS服务器。
总结来说就是3点:
- hosts文件
- 本地DNS服务器
- 域名服务器
DNS查询的方式
上面的第3步, 我们写的比较简单, 会分为2种查询方式
如果有缓存,直接返回不讨论, 因为上面的几个步骤都会有缓存
递归查询
迭代查询
java代码模拟实现
这边不进行特别深入的讲解, 尤其是dns请求响应协议, 我们只用java简单的发送一个udp请求给域名服务器
dnsjava简化我们udp发送字节内容的构建
<dependency>
<groupId>dnsjava</groupId>
<artifactId>dnsjava</artifactId>
<version>2.1.8</version>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.7.11</version>
</dependency>
代码
import cn.hutool.core.io.FileUtil;
import org.xbill.DNS.*;
import java.io.File;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetSocketAddress;
public class DNSClient {
public static void main(String[] args) throws Exception {
DatagramSocket datagramSocket = new DatagramSocket(65532);
send(datagramSocket, "www.itkaoti.top");
receive(datagramSocket);
}
public static void send(DatagramSocket datagramSocket, String domain) throws IOException {
Record queryRecord = Record.newRecord(Name.fromString(domain + "."), Type.A, DClass.IN);
Message queryMessage = Message.newQuery(queryRecord);
// 将二进制写入到文本中
FileUtil.writeBytes(queryMessage.toWire(), new File("C:\\Users\\xiaodoubi\\Desktop\\html\\1.hex"));
byte[] buffer = queryMessage.toWire();
DatagramPacket datagramPacket = new DatagramPacket(buffer, 0, buffer.length, new InetSocketAddress("119.29.29.29", 53));
// 发送
datagramSocket.send(datagramPacket);
}
public static void receive(DatagramSocket datagramSocket) throws Exception {
byte[] bytes = new byte[1024];
DatagramPacket datagramPacket1 = new DatagramPacket(bytes, bytes.length);
datagramSocket.receive(datagramPacket1);
int length = datagramPacket1.getLength();
// System.out.println(Arrays.toString(bytes));
FileUtil.writeBytes(bytes, new File("C:\\Users\\xiaodoubi\\Desktop\\html\\1_resp.hex"), 0, length, false);
}
}
运行代码的时候, 我们要打开wireshark软件, 用来查看 我们向域名服务器发送的报文和接受到的报文。
- 发送的报文(文本, 使用hex打开)
- wireshark抓到的发送的报文
- 接受到报文(文本, 使用hex打开)
- wireshark接收到的报文
将协议点开查看具体的内容
当然我们可以向根域名解析服务器请求(然后一级一级的请求下去), 大家可以试试