您的位置:

DNS在哪一层

一、什么是DNS

DNS(Domain Name System)是互联网中的一个命名系统,用于将域名与IP地址相互映射。借助DNS,用户只需要输入易于记忆和理解的域名,即可访问到远程主机。

DNS是一个分布式的数据库系统,同时也是一个应用层协议。可提供两种服务:解析和逆向解析。解析将域名转换成IP地址,逆向解析将IP地址转换成域名。

二、DNS在哪一层

DNS作为一个应用层协议,位于OSI七层模型中的应用层。DNS的数据传输使用的是TCP和UDP协议,TCP常用于大数据传输,UDP常用于小数据传输,例如DNS的查询。

三、DNS的工作原理

DNS的工作可以分为两个阶段:递归查询和缓存查询。

1.递归查询

当用户查询一个域名时,本地域名服务器(Local DNS Server)会先查询本地缓存是否存在该域名对应的IP地址。如果存在,则直接将IP地址返回给用户。如果不存在,则本地域名服务器需要向根域名服务器(Root DNS Server)查询该域名对应的顶级域名服务器(TLD DNS Server)的IP地址。

然后本地域名服务器会向TLD DNS Server发送一个查询请求,询问负责该域名的下一级域名服务器的IP地址。例如,www.example.com的顶级域名是.com,则TLD DNS Server需要返回负责.com域名解析的域名服务器IP地址。

本地域名服务器再向负责.com域名解析的域名服务器发送询问请求,询问www.example.com对应的IP地址。域名服务器查询自己的缓存。如果缓存中有该域名对应的IP地址,则返回,否则继续向上级域名服务器查询,直到返回该域名对应的IP地址。

最后,本地域名服务器将查询结果返回给用户,并将结果缓存,以备下次查询时使用。

2.缓存查询

缓存查询指的是本地域名服务器在递归查询过程中,将查询结果缓存起来,以便在下次查询时能够更快地返回结果。缓存可以设置生存时间,超过生存时间就需要重新从根域名服务器查询。

四、DNS的代码示例

以下是一个使用Node.js实现的简单DNS服务器,它可以响应简单的DNS查询请求。

const dns = require('dns');
const dgram = require('dgram');
const server = dgram.createSocket('udp4');

server.on('error', (err) => {
  console.log(`server error:\n${err.stack}`);
  server.close();
});

server.on('message', (msg, rinfo) => {
  console.log(`server got: ${msg} from ${rinfo.address}:${rinfo.port}`);
  const domain = msg.slice(12, msg.length - 5);
  dns.lookup(domain, (err, address) => {
    if (err) {
      console.log('lookup error:', err);
      return;
    }
    const response = Buffer.alloc(16);
    response.writeUInt16BE(msg.readUInt16BE(0), 0); // 事务ID
    response.writeUInt16BE(0x8180, 2); // 标准响应,无递归和权威答案
    response.writeUInt16BE(msg.readUInt16BE(4), 4); // 问题数量
    response.writeUInt16BE(1, 6); // 回答数量
    response.writeUInt16BE(0, 8); // 权威域名数量
    response.writeUInt16BE(0, 10); // 额外信息数量
    response.write(msg.slice(12, msg.length)); // 问题部分
    response.writeUInt16BE(0xc00c, response.length - 4); // 回答部分域名偏移量
    response.writeUInt16BE(1, response.length - 2); // 回答部分类型
    response.writeUInt16BE(1, response.length); // 回答部分类
    response.writeUInt32BE(0, response.length + 2); // 回答部分缓存时间
    response.writeUInt16BE(4, response.length + 6); // 回答部分数据长度
    const addressParts = address.split('.');
    for (let i = 0; i < addressParts.length; i++) {
      response.writeUInt8(parseInt(addressParts[i]), response.length + 8 + i); // 回答部分数据
    }
    server.send(response, rinfo.port, rinfo.address);
  });
});

server.on('listening', () => {
  const address = server.address();
  console.log(`server listening ${address.address}:${address.port}`);
});

server.bind(53);