DNS和ICMP

域名介绍

在网络通信中,需要用到ip加port,但是ip并不方便记忆,于是我们常用域名来对应一个ip

例如:www.baidu.com    对应    156.36.56.98(随便写的)

com: 一级域名. 表示这是一个企业域名. 同级的还有 "net"(网络提供商), "org"(非盈利组织) .

baidu: 二级域名, 公司名.

www: 只是一种习惯用法.

域名解析

域名解析分为两步

1.查本地 /etc/hosts

互连网信息中心(SRI-NIC)会管理一个 hosts 文件,本地主机只需要定期下载即可,里面就是域名和ip的对应

2.使用DNS技术

如果/etc/hosts找不到,那就去向本地DNS服务器发送请求进行查询,本地DNS服务器通常以守护进程形式存在

DNS和ICMP_第1张图片

ICMP协议

ICMP协议是一个网络层协议,不保证可靠传输(没有超时重传机制),无连接,本地主机通过套接字和协议栈来处理响应,目标主机通过协议栈来处理请求,利用ICMP 响应报文来得到路由情况

ICMP 的报文格式 

DNS和ICMP_第2张图片

标准 ICMP Echo Reply 报文格式​

+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|     Type(0)   |     Code(0)   |          Checksum             |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|           Identifier          |        Sequence Number        |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|     Data (可变长度,通常包含时间戳或填充字节)                   |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

DNS和ICMP_第3张图片

ping 命令

ping www.baidu.com

ping命令过程分析:

在终端上写下了这几个字母,随着按下回车,终端模拟器将这几个字母write进主设备,然后驱动程序将主设备数据写进从设备,唤醒从设备等待队列上的进程也就是shell,然后shell读出来,分割字符串,然后创建子进程,进程替换为ping进程,域名通过命令行参数传给了ping进程,然后ping进程去/etc/hosts文件里面查找域名对应ip,如果找不到就向本地DNS守护进程发消息,然后DNS进程开始询问服务器,最后得到对应ip。ping进程接下来的操作如下:

步骤 1:创建原始套接字​

int sock = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
if (sock < 0) {
    perror("socket");  // 需 root 权限或 CAP_NET_RAW 能力
    exit(1);
}

​步骤 2:构造 ICMP 报文​

  • ​报文结构​​:
    0                   1                   2                   3
    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    |     Type(8)   |     Code(0)   |          Checksum             |
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    |           Identifier          |        Sequence Number        |
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    |                          Payload (可选)                        |
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

  • ​字段说明​​:
    • ​Type=8, Code=0​​:表示 Echo Request
    • ​Identifier​​:通常为进程 PID(用于响应能够查找到对应套接字)。
    • ​Sequence Number​​:递增序列号(区分多次请求)。
    • ​Checksum​​:ICMP 校验和(需手动计算)。

​步骤 3:发送报文​

struct sockaddr_in dest_addr;
dest_addr.sin_family = AF_INET;
dest_addr.sin_addr.s_addr = inet_addr("93.184.216.34");  // 目标 IP

// 发送 ICMP 报文
sendto(sock, icmp_packet, sizeof(icmp_packet), 0, 
       (struct sockaddr*)&dest_addr, sizeof(dest_addr));

​步骤 4:接收 Echo Reply​

char recv_buf[1024];
struct sockaddr_in src_addr;
socklen_t addr_len = sizeof(src_addr);

// 阻塞等待响应(内核通过 Identifier 匹配报文)
recvfrom(sock, recv_buf, sizeof(recv_buf), 0, 
         (struct sockaddr*)&src_addr, &addr_len);

ping进程在应用层创建好原始套接字,并且创建好ICMP报文,然后用sendto发送,然后经过ip层和数据链路层封装后发出去,当目标主机收到后,经数据链路层和ip层的解包,交给了ICMP协议的接口,检查ICMP头里的类型,发现是请求,那就构建对应的ICMP响应,然后经IP协议和以太网协议的封装又发回去,源主机收到后开始解包,到ICMP协议层时,根据OS维护的hash表,通过响应里的identifier标识符,找到对应的套接字,然后将ICMP报文写进套接字接收缓冲区,并唤醒等待队列上的进程,ping进程recvfrom从接收缓冲区里读出来完整的ICMP报文,然后根据ICMP报文的内容,write写东西到从设备,终端驱动将从设备数据拷到主设备,然后唤醒终端模拟器,终端模拟器再将东西打到终端上,这就是一次发送数据测试,ping进程会不停发送echo request,并设置序列号来区分这些请求3

​完整流程:ping 命令的 ICMP 请求与响应全链路解析​


​1. ping 进程发送 ICMP Echo Request​

​(1)应用层(用户态)​

  1. ​创建原始套接字​

    int sock = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);

    • ​权限​​:需有CAP_NET_RAW (/bin/ping 已默认配置)。
    • ​作用​​:绕过传输层,直接操作网络层(IP)数据包。
  2. ​构造 ICMP Echo Request​

    • ​报文结构​​:

      Type=8 (Echo Request), Code=0

    • Identifier=进程PID, Sequence=递增序号

    • Payload=时间戳或填充数据

    • ​计算校验和​​:覆盖整个 ICMP 报文。
  3. ​发送请求​

    sendto(sock, icmp_req, sizeof(icmp_req), 0, &dest_addr, addr_len);

​(2)内核协议栈处理​

  1. ​IP 层封装​

    • 添加 IP 头部:
      • 源/目标 IP、TTL(默认 64)、协议号 1(ICMP)。
    • 查询路由表,确定下一跳 ip 地址和发送接口。
  2. ​数据链路层封装​

    • 添加以太网帧头:源/目标 MAC 地址、类型 0x0800(IPv4)。
    • 通过网卡驱动(如 eth0)发送到物理链路。

​2. 目标主机处理与响应​

​(1)网络接口接收​

  1. ​网卡(数据链路层)​

    • 检查目标 MAC 地址,若匹配则接收,剥离以太网帧头。
    • 将 IP 数据包交给内核网络协议栈。
  2. ​IP 层解包​

    • 校验 IP 头部(版本、校验和、目标 IP)。
    • 若 TTL 减至 0,丢弃并返回 ICMP Time Exceeded(Type=11)。
    • 若目标 IP 匹配本机,剥离 IP 头,根据协议类型是1, 交给 ICMP 模块。

​(2)ICMP 协议处理​

  1. ​解析 ICMP 报文​

    • 检查 Type=8(Echo Request),Code=0
    • 内核自动构造 Echo Reply(Type=0),保持相同的 Identifier 和 Sequence
  2. ​发送响应​

    • IP 层封装:源/目标 IP 互换,TTL 重置(如 64)。
    • 数据链路层封装:通过 ARP 获取源主机的 MAC 地址。
    • 网卡发送响应包。

​3. 源主机接收响应​

​(1)网络接口接收​

  1. ​网卡收包​

    • 过滤目标 MAC,剥离以太网帧头,IP 层校验后交给 ICMP 模块。
  2. ​ICMP 协议匹配​

    • 内核根据 Identifier(如 PID 1234)查找原始套接字。
    • 将报文写入套接字接收缓冲区。

​(2)唤醒 ping 进程​

  1. ​从阻塞中恢复​

    • ping 进程此前因 recvfrom() 阻塞,被内核移至就绪队列。
    • 从接收缓冲区读取 Echo Reply 数据。
  2. ​计算 RTT(往返时间)​

    • 对比当前时间与请求报文中的时间戳(Payload),得到延迟。

​(3)终端输出​

  1. ping 进程格式化输出​

    64 bytes from 93.184.216.34: icmp_seq=1 ttl=53 time=11.3 ms

    • ttl:从响应 IP 头部提取。
    • time:RTT 计算结果。
  2. ​终端显示流程​

    • ping 调用 write() 将结果写入标准输出(文件描述符 1)。
    • 终端驱动(如 tty)将数据从 ​​从设备​​(进程缓冲区)拷贝到 ​​主设备​​(终端显示器)。
    • 终端模拟器(如 xterm)渲染最终字符。

补充说明

1.ping 超时​​:内核未收到 Echo Replyrecvfrom() 超时后停止等待(等待默认 1 秒),靠sendto重发请求,也就是说ICMP协议是没有超时重传的功能的,真正能使其超时重传的是ping进程逻辑

2.ping发送请求到目标主机,目标主机通过硬件中断的协议栈就处理了该请求,根本就没涉及到进程和应用层逻辑

3.ping进程本身处理响应却是寄托协议栈加上进程和应用层逻辑,还使用了套接字

你可能感兴趣的:(服务器,linux,网络)