域名系统 DNS

DNS 概述

        域名系统 DNS(Domain Name System)是因特网使用的命名系统,用来把便于人们使用的机器名字转换成为 IP 地址。域名系统其实就是名字系统。为什么不叫“名字”而叫“域名”呢?这是因为在这种因特网的命名系统中使用了许多的“域(domain)”,因此就出现了“域名”这个名词。“域名系统”明确地指明这种系统是应用在因特网中。我们都知道,IP 地址是由 32 位的二进制数字组成的。用户与因特网上某台主机通信时,显然不愿意使用很难记忆的长达 32 位的二进制主机地址。即使是点分十进制 IP 地址也并不太容易记忆。相反,大家愿意使用比较容易记忆的主机名字。但是,机器在处理 IP 数据报时,并不是使用域名而是使用 IP 地址。 这是因为 IP 地址长度固定,而域名的长度不固定,机器处理起来比较困难。
        例如,www.baidu.com 就是一个域名,那么域名解析的过程就是:
www.baidu.com-->DNS 服务器(把域名转成 IP)-->转换为 IP(http://14.215.177.39/)

DNS 协议运行在 UDP 协议上面,是一个 UDP 的“回显”程序,使用 53 号端口

因特网的域名结构

从语法上讲,每一个域名都是有标号(label)序列组成,而各标号之间用点(小数点)隔开。如下例子所示:

        上图这是中央电视台用于手法电子邮件的计算机的域名,它由三个标号组成,其中标号com 是顶级域名,标号 cctv 是二级域名,标号 mail 是三级域名。
        DNS 规定,域名中的标号都有英文和数字组成, 每一个标号不超过 63 个字符 ( 为了记忆方 便,一般不会超过 12 个字符 ) ,也不区分大小写字母。
        级别最低的域名写在最左边,而级别最高的字符写在最右边。由多个标号组成的完整域名总共不超过 255 个字符。
        DNS 既不规定一个域名需要包含多少个下级域名,也不规定每一级域名代表什么意思。各级域名由其上一级的域名管理机构管理,而最高的顶级域名则由 ICANN 进行管理。用这种方法可使每一个域名在整个互联网范围内是唯一的,并且也容易设计出一种查找域名的机制。

DNS 协议

首部格式

        DNS 请求与响应的格式是一致的,其头部分为 Header Question Answer Authority
Additional5 部分,如下图所示:

Header 部分是一定有的,长度固定为 12 个字节;其余 4 部分可能有也可能没有,并且长度也不一定,这个在 Header 部分中有指明。 Header 的结构如下:

下面说明一下各个字段的含义 :
1. 标识符:占 16
        ID:占 16 位。该值由发出 DNS 请求的程序生成,DNS 服务器在响应时会使用该 ID,这样便于请求程序区分不同的 DNS 响应。
2. 标志:占 16
        QR:占 1 位。指示该消息是请求还是响应。0 表示请求;1 表示响应。
        OPCODE:占 4 位。指示请求的类型,有请求发起者设定,响应消息中复用该值。0 表示标准查询;1 表示反转查询;2 表示服务器状态查询。3~15 目前保留,以备将来使用。
        AA(Authoritative Answer,权威应答):占 1 位。表示响应的服务器是否是权威DNS 服务器。只在响应消息中有效。
        TC(TrunCation,截断):占 1 位。指示消息是否因为传输大小限制而被截断。
        RD(Recursion Desired,期望递归):占 1 位。该值在请求消息中被设置,响应消息复用该值。如果被设置,表示希望服务器递归查询。但服务器不一定支持递归查询。
        RA(Recursion Available,递归可用性):占 1 位。该值在响应消息中被设置或被清除,以表明服务器是否支持递归查询。
        Z:占 3 位。保留备用。
        RCODE(Response code):占 4 位。该值在响应消息中被设置。取值及含义如下:
                0:No error condition,没有错误条件;
                1:Format error,请求格式有误,服务器无法解析请求;
                2:Server failure,服务器出错。
                3:Name Error,只在权威 DNS 服务器的响应中有意义,表示请求中的域名不存在。
                4:Not Implemented,服务器不支持该请求类型。
                5:Refused,服务器拒绝执行请求操作。
                6~15:保留备用。QDCOUNT:占 16 位(无符号)。指明 Question 部分的包含的实体数量。
        ANCOUNT:占 16 位(无符号)。指明 Answer 部分的包含的 RR(Resource Record)数 量。
        NSCOUNT:占 16 位(无符号)。指明 Authority 部分的包含的 RR(Resource Record)数量。
        ARCOUNT:占 16 位(无符号)。指明 Additional 部分的包含的 RR(Resource Record)数量。

数据区域

查询名:
        查询名部分长度不定,一般为要查询的域名(也会有 IP 的时候,即反向查询)。 此部分由一个或者多个标示符序列组成,每个标示符以首字节数的计数值来说明该标示符长度,每个名字以 0 结束。计数字节数必须是 0~63 之间。该字段无需填充字节。还是借个例子来说明更直观些,查询名为 http://gemini.tuc.noao.edu 的话,查询名字段如下
查询类型:

查询类:
        一般为 IN(枚举值 1) ,即 Internet 数据

DNS 客户端程序实例

#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <linux/socket.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <dirent.h>
#include <unistd.h>

int sock;
struct sockaddr_in sa;

/*
generate_question:解析域名数据
*/
void generate_question(char*dns_name,char*buf,int*len)
{
    char*pos = dns_name;//指向域名当前位置
    char*ptr = buf;
    int n = 0;
    *len = 0;
    while(1)
    {
            n = strlen(pos) - (strstr(pos , ".") ? strlen(strstr(pos , ".")) : 0);//在 pos 中查找"."子串
        //返回"."在 pos 中第一次出现的地址,若没有找到返回 NULL
        printf("%d\n", n);
        *ptr++ = (unsigned char)n;
        memcpy(ptr,pos,n);
        printf("%lu\n",strlen(ptr));
        printf("%s\n", ptr);
        *len += n + 1;
        ptr += n;
        if(!strstr(pos , "."))
        {
            *ptr = (unsigned char)0;
            ptr ++;
            *len += 1;
            break;
        }
        pos += n + 1;
        printf("%s\n", pos);
    }
}

/*
send_dns_request:解析域名数据,并发送数据包
*/
void send_dns_request(char * dns_name)
{
    unsigned char request[256] = {0}; //保存整个请求报文
    unsigned char *ptr = request;
    unsigned char question[128];//存储域名解析数据
    int question_len;
    //产生请求(把字符串表示的域名转换成 DNS 要求的格式)
    generate_question(dns_name , question ,&question_len);
    printf("%s\n", question);
    printf("%d\n", question_len);
    *((unsigned short*)ptr) = 1; //会话标识 ID
    ptr += 2;
    *((unsigned short*)ptr) = htons(0x0100); //flags
    ptr += 2;
    *((unsigned short*)ptr) = htons(1); //Quetions 问题数,通常为 1
    ptr += 2;
    *((unsigned short*)ptr) = 0;
    ptr += 2;
    *((unsigned short*)ptr) = 0;
    ptr += 2;
    *((unsigned short*)ptr) = 0;
    ptr += 2;
    //把域名(www.baidu.com)装换为相应的问题格式保存在此处,以\0 结尾
    memcpy(ptr , question , question_len);
    ptr += question_len;
    *((unsigned short*)ptr) = htons(1); //获取 IPV4 地址,查询类型
    ptr += 2;
    *((unsigned short*)ptr) = htons(1); //指互联网地址,查询类,一般为 1,表明是 Internet 数据
    int re = sendto(sock, request,question_len+16 ,0, (structsockaddr*)&sa, sizeof(sa));
    printf("re = %d\n",re);
    int i;
    for(i=0;i<re;i++)//以 16 进制格式打印出来
    {
        printf("%02X ",(unsigned char)request[i]);
    } 
    printf("===================\n");
}

/*
    recv_dns_response:获取域名所对应的 IP 地址,并打印
*/
void recv_dns_response()
{
    struct sockaddr_in src_addr;
    socklen_t addrlen = sizeof(src_addr);
    char buf[255] = {0};
    int r = recvfrom(sock, buf, 255, 0, (struct sockaddr*)&src_addr,&addrlen);
    printf("r == %d\n", r);
    if(r > 0)//收到大于 0 的数据
    {
        int i;
        for(i=r-4;i<r;i++)//以 16 进制格式打印出来
        {
            if(i != r-1)
                printf("%d.",(unsigned char)buf[i]);
            else
                printf("%d\n",(unsigned char)buf[i]);
        } 
    }
}

//例./main www.baidu.com
int main(int argc, char *argv[])
{
    if(argc != 2)
    {
        printf("Usage : %s <domain name>\n",argv[0]);
        return -1;
    }
    //step 1: 创建一个套接字
    sock = socket(AF_INET, SOCK_DGRAM, 0);
    if (sock == -1)
    {
        perror("socket error:");
        return -1;
    }

    //step 2: 绑定一个地址(ip+端口号)
    memset(&sa, 0,sizeof(sa));
    sa.sin_family = AF_INET;
    sa.sin_port = htons(53); //按"网络字节序"来保存一个整数
    sa.sin_addr.s_addr = inet_addr("114.114.114.114");
    //发送解析请求
    send_dns_request(argv[1]);
    //接收分析结果
    recv_dns_response();
    close(sock);
    return 0;
}

可以看到当按正确的报文形式发送给 DNS 服务器后,接收到的报文后面四个字节存储了解析的 IP 地址

域名解析函数(gethostbyname)

【头文件】
#include <netdb.h>
#include <sys/socket.h>
extern int h_errno;
【函数原型】
struct hostent *gethostbyname(const char *name);
【函数功能】
        使用域名或主机名获取地址
【参数含义】
        [name]: 待解析的域名或主机名
【返回值】
        失败返回 NULL 指针
        成功返回的非空指针指向如下的 hostent 结构体指针
struct hostent
{
    char *h_name; /* 主机正式名称 */
    char **h_aliases; /* 别名列表。 */
    int h_addrtype; /* 主机地址类型。*/
    int h_length; /* 地址的长度。 */
    char **h_addr_list; /*来自名称服务器的地址列表。 */
    #ifdef __USE_MISC
    # define h_addr h_addr_list[0] /* 地址,用于向后兼容。*/
    #endif
};
【示例】
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <stdio.h>
extern int h_errno;

int main(int argc, char **argv)
{
    if (argc != 2) {
        printf("Use example: %s www.google.com\n", *argv);
        return -1;
    }
    char *name = argv[1];
    struct hostent *hptr;
    hptr = gethostbyname(name);
    if (hptr == NULL) {
        printf("gethostbyname error for host: %s: %s\n", name, 
        hstrerror(h_errno));
        return -1;
    }
    //输出主机的规范名
    printf("\tofficial: %s\n", hptr->h_name);
    //输出主机的别名
    char **pptr;
    char str[INET_ADDRSTRLEN];
    for (pptr=hptr->h_aliases; *pptr!=NULL; pptr++) {
        printf("\ttalias: %s\n", *pptr);
    }
    //输出 ip 地址
    switch (hptr->h_addrtype) {
        case AF_INET:
            pptr = hptr->h_addr_list;
            for (; *pptr!=NULL; pptr++) {
                printf("\taddress: %s\n",inet_ntop(hptr->h_addrtype, hptr->h_addr, str, sizeof(str)));
        }
            break;
        default:
            printf("unknown address type\n");
            break;
    }
    return 0;
}

获取本地主机名(gethostname)

【头文件】
#include <unistd.h>
【函数原型】
int gethostname(char *name, size_t len);
【函数功能】
        获取本地主机名
【参数含义】
        [name]: 保存获取的主机名
        [len]: naem 的最大长度
【返回值】
        成功返回 0,失败返回-1
【示例】
char buf[256] = {0};
int t = gethostname(buf,256);
if(t == 0)
{
    printf("%s\n",buf);
}

设置本地主机名(sethostname)

【头文件】
#include <unistd.h>
【函数原型】
int sethostname(const char *name, size_t len);
【函数功能】
        设置本地主机名
【参数含义】
        [name]: 设置的主机名
        [len]: naem 的最大长度
【返回值】
        成功返回 0,失败返回-1
【示例】
sethostname ( "jiuyue" , 6 );

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/110238.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

S5PV210裸机(九):ADC

本文主要探讨210的ADC相关知识。 ADC ADC:模数转换&#xff08;模拟信号转数字信号&#xff09; 量程:模拟电压信号范围(210为0&#xff5e;3.3V) 精度:若10二进制位来表示精度&#xff08;210为10位或12位&#xff09;,量…

线性代数 第三章 向量

一、运算 加法、数乘、内积 施密特正交化 二、线性表出 概念&#xff1a;如果&#xff0c;则称可由线性表出&#xff08;k不要求不全为0&#xff09; 判定&#xff1a; 非齐次线性方程组有解无关&#xff0c;相关 如果两个向量组可以互相线性表出&#xff0c;则称这两个…

Xilinx 7 系列 1.8V LVDS 和 2.5V LVDS 信号之间的 LVDS 兼容性

如果通过LVDS进行接口&#xff0c;可以按照以程图中的步骤操作&#xff0c;以确保满足正确使用LVDS的所有要求。 40191 - 7 系列 - 1.8V LVDS 和 2.5V LVDS 信号之间的 LVDS 兼容性 与LVDS兼容驱动器和接收器连接时&#xff0c;7系列LVDS和LVDS_25输入和输出应该不存在兼容性问…

案例分析真题-系统建模

案例分析真题-系统建模 2009年真题 【问题1】 【问题2】 【问题3】 2012年真题 【问题1】 【问题2】 【问题3】 2014年真题 【问题1】 【问题2】 骚戴理解&#xff1a;这个题目以前经常考&#xff0c;不知道今年会不会考&#xff0c;判断的话就是看加工有没有缺少输入和输出&a…

C++面试——多线程详解

C11提供了语言层面上的多线程&#xff0c;包含在头文件<thread>中。它解决了跨平台的问题&#xff0c;提供了管理线程、保护共享数据、线程间同步操作、原子操作等类。C11 新标准中引入了5个头文件来支持多线程编程&#xff0c;如下图所示&#xff1a; 多进程与多线程 多…

SSH 无密登录设置

1 &#xff09; 配置 ssh &#xff08;1&#xff09;基本语法 ssh 另一台电脑的 IP 地址&#xff08;2&#xff09;ssh 连接时出现 Host key verification failed 的解决方法 [libaihadoop102 ~]$ ssh hadoop103 ➢ 如果出现如下内容 Are you sure you want to continue c…

MAC缓解WebUI提示词反推

当前环境信息&#xff1a; 在mac上安装好stable diffusion后&#xff0c;能做图片生成了之后&#xff0c;遇到一些图片需要做提示词反推&#xff0c;这个时候需要下载一个插件&#xff0c;参考&#xff1a; https://gitcode.net/ranting8323/stable-diffusion-webui-wd14-tagg…

mac 安装homebrew ,golang

mac 安装homebrew ,golang 安装homebrew安装golang选择 apple arm 版本安装配置环境变量 安装homebrew /bin/zsh -c "$(curl -fsSL https://gitee.com/cunkai/HomebrewCN/raw/master/Homebrew.sh)"回车执行指令后&#xff0c;根据提示操作。具体包括以下提示操作&am…

ios 代码上下文截屏之后导致的图片异常问题

业务场景&#xff0c;之前是直接将当前的collectionview截长屏操作&#xff0c;第一次截图会出现黑色部分原因是视图未完全布局&#xff0c;原因是第一次使用了Masonry约束然后再截图的时候进行了frame赋值&#xff0c;可以查看下Masonry约束和frame的冲突&#xff0c;全部修改…

除自身以外数组的乘积

给你一个整数数组 nums&#xff0c;返回 数组 answer &#xff0c;其中 answer[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积 。 题目数据 保证 数组 nums之中任意元素的全部前缀元素和后缀的乘积都在 32 位 整数范围内。 请 不要使用除法&#xff0c;且在 O(n) 时间复杂…

Qt 重写QSlider简单实现滑动解锁控件(指定百分比回弹效果)

组件效果图&#xff1a; 应用场景&#xff1a; 用于滑动解锁相关场景&#xff0c;Qt的控件鼠标监听机制对于嵌入式设备GUI可触摸屏依旧可用。 实现方式&#xff1a; 主要是通过继承QSlider以及搭配使用QStyleOptionSlider来实现效果。 注意细则&#xff1a; QStyleOption…

【IDEA】每个方法之间如何设置分隔线

修改后效果&#xff1a; 各个方法之间出现了分隔线

洞察运营机会的数据分析利器

这套分析方法包括5个分析工具&#xff1a; 用“描述性统计”来快速了解数据的整体特点。用“变化分析”来寻找数据的问题和突破口。用“指标体系”来深度洞察变化背后的原因。用“相关性分析”来精确判断原因的影响程度。用“趋势预测”来科学预测未来数据的走势&#xff0c;

浅谈js代码的封装方法(2023.10.30)

常见的js代码封装方法 2023.10.30 需求1、js代码封装的优缺点2、js代码封装方式2.1 方式一&#xff1a;function function declarations2.1.1 示例 2.2 方式二&#xff1a;class2.2.1 class declarations2.2.2 Class expressions 2.3 变量函数2.4 变量闭包匿名函数2.5 闭包函数…

vscode开启emmet语法

需要在setting.json中添加配置 首先进入设置&#xff0c;然后点击右上角 Vue项目添加如下配置 "emmet.syntaxProfiles": { "vue-html": "html", "vue": "html" },React项目添加如下配置 "emmet.includeLanguages&quo…

剑指JUC原理-5.synchronized底层原理

Java对象头 以32位虚拟机为例&#xff1a; 普通对象 在Java虚拟机中&#xff0c;每个对象都有一个对象头&#xff08;Object Header&#xff09;&#xff0c;其中包含了一些用于管理对象的元数据信息。对象头通常由两部分组成&#xff1a;mark word&#xff08;标记字&#x…

第三章 远程连接服务器

目录 1、远程连接服务器简介 2、连接加密技术简介 第一阶段&#xff1a;TCP三次握手版本协商过阶段&#xff1a; 第二阶段&#xff1a;协商算法和确定对称秘钥阶段 3、用户登录ssh服务器 4.举例说明 例一&#xff1a;Linux互连 第一步&#xff1a;生成非对称秘钥&#…

【Linux】权限

目录 1&#xff0c;切换用户 1&#xff0c;su 普通用户名 2&#xff0c;su - 普通用户名 2&#xff0c;权限的管理 1&#xff0c;文件访问者的分类&#xff08;人) 2&#xff0c;文件类型和访问权限&#xff08;事物属性&#xff09; 3&#xff0c;文件权限值的表示方法…

信息系统项目管理师教程 第四版【第8章-项目整合管理-思维导图】

信息系统项目管理师教程 第四版【第8章-项目整合管理-思维导图】 课本里章节里所有蓝色字体的思维导图