网络进阶:内网穿透、DNS与ICMP实战

💬 开篇:上一篇我们学习了NAT技术和代理服务器,知道了NAT会阻止外网主动访问内网。那么问题来了:如何在没有公网IP的情况下,让外网访问家里的服务器?如何让浏览器知道域名对应的IP地址?如何诊断网络故障?这篇文章将详细讲解内网穿透技术(frp实战部署)、DNS域名解析系统(dig工具使用)、ICMP协议(ping和traceroute原理),帮助你掌握这些实用的网络技术。

👍 点赞、收藏与分享:这篇包含大量实战内容——frp完整部署教程、dig工具使用、网络诊断技巧,还有"浏览器输入URL后发生的事情"这道经典面试题的完整解答。如果对你有帮助,请点赞收藏!

🚀 循序渐进:从内网穿透的原理讲起,到frp实战部署(SSH、Web服务),到DNS解析过程,到ICMP协议应用,一步步掌握网络实战技能。


一、内网穿透

1.1 内网穿透的需求

1. 问题的由来

典型场景


你在家里搭建了一个服务器:

* 运行了一个网站
* 或者运行了NAS(网络存储)
* 或者搭建了游戏服务器

但是:

* 家里的网络是通过NAT上网的
* 没有公网IP(或者是动态公网IP)
* 外网无法主动访问你的服务器

你想在公司、学校、咖啡厅访问家里的服务器
怎么办?

NAT带来的限制


前面讲过,NAT的缺陷:
无法从外部主动建立连接

家里的服务器:192.168.1.100
路由器的公网IP:202.244.174.37

你的朋友想访问你的服务器:

1. 朋友访问 202.244.174.37:80
2. 路由器收到请求
3. 路由器查NAPT表:没有对应的表项(因为是外部主动连接)
4. 路由器不知道转发给谁
5. 丢弃请求
6. 访问失败

即使配置端口映射,仍有问题:

* 很多宽带没有公网IP
* 公网IP是动态的,会变化
* 配置复杂,不方便

2. 解决方案:内网穿透

内网穿透的原理


通过一台有公网IP的服务器做中转
内网服务器主动连接公网服务器
外部用户访问公网服务器
公网服务器把流量转发给内网服务器

关键:内网到公网是主动连接,可以穿透NAT!

基本架构


内网服务器 ←────────┐
(192.168.1.100)     │ 主动连接
↓
公网服务器
(123.45.67.89)
↑
外网──────────→┘

1.2 内网穿透核心原理:反向连接与中继转发

1. 内网穿透的核心思想

问题


外网 → 内网:被NAT阻止 ✗
内网 → 外网:可以穿透NAT ✓

解决思路:
让内网服务器主动建立连接
保持连接不断
外网的数据通过这个连接反向传输

类比:打电话


你在家里(内网)
朋友在公司(外网)

朋友想找你:

* 直接打你家座机:打不通(被拦截)✗

解决办法:

* 你主动打电话给朋友(内网主动连接)✓
* 保持通话不挂断
* 朋友有话要说,通过这个通话传递

2. 详细工作流程

角色说明


* 内网客户端(frpc):部署在家里的电脑上
* 公网服务器(frps):部署在有公网IP的服务器上
* 外网用户:想要访问你家里服务的人

Step 1:建立控制连接


内网客户端启动后:
1动连接公网服务器的控制端口(如7000)
2. 发送配置信息:

* 我要暴露本地的22端口(SSH)
* 请在公网服务器上监听6000端口

3. 建立长连接,保持不断
4. 定期发送心跳包

公网服务器:

1. 收到内网客户端的连接
2. 在6000端口开始监听
3. 等待外网用户的访问

Step 2:外网用户发起访问


外网用户要SSH到你家里的电脑:
ssh user@123.45.67.89 -p 6000
↑           ↑
公网服务器的IP  公网服务器监听的端口

Step 3:公网服务器转发请求


公网服务器:

1. 收到6000端口的连接请求
2. 查找:这个端口对应哪个内网客户端?
3. 找到:对应家里的电脑
4. 通过控制连接通知内网客户端:"有新连接来了"

Step 4:建立数据连接


内网客户端:

1. 收到通知:"有新连接"
2. 再次主动连接公网服务器(建立数据连接)
3. 连接本地的SSH服务(127.0.0.1:22)
4. 开始转发数据

公网服务器:

1. 将外网用户的数据 → 转发到内网客户端
2. 将内网客户端的数据 → 转发到外网用户

完整流程图


外网用户         公网服务器(frps)      内网客户端(frpc)    本地SSH服务
|                  |                    |                  |
|                  |  ←──────────────── |  控制连接         |
|                  |  (frpc主动连接)     |  (一直保持)      |
|                  |                    |                  |
| SSH连接请求      |                    |                  |
| (6000端口)       |                    |                  |
|─── 通知:"新连接"      |                  |
|                  |───────────────────→|                  |
|                  |                    | 建立数据连接      |
|                  |  ←──────────────── | (主动连接)       |
|                  |                    |                  |
|                  |                    | 连接本地SSH       |
|                  |                    |─────────────────→|
|                  |                    |                  |
| SSH数据          |                    |                  |
|───────────────→ |───────────────────→|─────────────────→|
|                  |                    |                  |
|                 |  ←──────────────── | ←───────────────|
| ←───────────────|                    |                  |
|                  |                    |                  |

关键点


1. 内网客户端始终主动连接公网服务器(穿透NAT)
2. 保持控制连接不断(用于通知)
3. 每个新访问建立新的数据连接(用于传输)
4. 公网服务器只是中转,不处理业务逻辑

1.3 frp实战部署

1. frp简介

frp(Fast Reverse Proxy)



一个开源的内网穿透工具
用Go语言开发
支持TCP、UDP、HTTP、HTTPS等协议
配置简单,性能优秀

项目地址:https://github.com/fatedier/frp

frp的组成


frps(服务端):

* 部署在公网服务器上
* 接收内网客户端的连接
* 监听端口供外网访问

frpc(客户端):

* 部署在内网机器上
* 主动连接frps
* 转发流量到本地服务

2. 准备工作

所需资源


1. 公网服务器一台:

   * 有公网IP
   * 操作系统:Linux(Ubuntu/CentOS等)
   * 开放必要的端口

2. 内网机器(你家的电脑):

   * 能访问互联网
   * 运行需要暴露的服务(SSH、Nginx等)

3. frp软件:

   * 下载地址:[https://github.com/fatedier/frp/releases](https://github.com/fatedier/frp/releases)
   * 选择适合你操作系统的版本

下载frp

# 在公网服务器和内网机器上都需要下载

# Linux x86_64
wget https://github.com/fatedier/frp/releases/download/v0.58.1/frp_0.58.1_linux_amd64.tar.gz

# 解压
tar -xzf frp_0.58.1_linux_amd64.tar.gz
cd frp_0.58.1_linux_amd64

frp的文件结构

frp_0.58.1_linux_amd64/
├── frps           # 服务端程序
├── frps.toml      # 服务端配置文件
├── frpc           # 客户端程序
├── frpc.toml      # 客户端配置文件
└── LICENSE
3. 部署frps(公网服务器)

配置frps

# 编辑服务端配置文件
vi frps.toml

frps.toml内容

# frps.toml - 服务端配置

# bindPort = 7000

# 可选:Dashboard(管理面板)
# webServer.addr = "0.0.0.0"
# webServer.port = 7500
# webServer.user = "admin"
# webServer.password = "admin123"

启动frps

# 前台运行(测试用)
./frps -c ./frps.toml

# 后台运行(生产环境)
nohup ./frps -c ./frps.toml &> frps.log &

# 查看进程
ps aux | grep frps

# 查看日志
tail -f frps.log

开放防火墙端口

# Ubuntu/Debian
sudo ufw allow 7000/tcp  # frps监听端口
sudo ufw allow 6000/tcp  # 供外网访问的端口(SSH映射)
sudo ufw allow 8080/tcp  # 供外网访问的端口(Nginx映射)

# CentOS/RHEL
sudo firewall-cmd --permanent --add-port=7000/tcp
sudo firewall-cmd --permanent --add-port=6000/tcp
sudo firewall-cmd --permanent --add-port=8080/tcp
sudo firewall-cmd --reload
4. 场景1:SSH远程登录

需求

在公司远程SSH到家里的电脑
家里的电脑:运行SSH服务(22端口)
家里没有公网IP

配置frpc

# 在家里的电脑上编辑客户端配置
vi frpc.toml

frpc.toml内容

# frpc.toml - 客户端配置

# 公网服务器的地址和端口
serverAddr = "123.45.67.89"  # 替换成你的公网服务器IP
serverPort = 7000

# 定义一个SSH服务的代理
[[proxies]]
name = "ssh"                # 代理名称(任意)
type = "tcp"                # 协议类型
localIP = "127.0.0.1"       # 本地IP
localPort = 22              # 本地端口(SSH默认22)
remotePort = 6000           # 公网服务器监听的端口

启动frpc

# 前台运行(测试用)
./frpc -c ./frpc.toml

# 后台运行
nohup ./frpc -c ./frpc.toml &> frpc.log &

# 查看日志
tail -f frpc.log

测试连接

# 在公司的电脑上,SSH连接公网服务器的6000端口
ssh your_username@123.45.67.89 -p 6000

# 实际上会连接到家里电脑的22端口
# 成功!你现在可以远程操作家里的电脑了

工作流程

公司电脑 → 公网服务器(123.45.67.89:6000) 
         → frps转发 
         → frpc接收
         → 家里电脑(127.0.0.1:22)
5. 场景2:远程访问Nginx网站

需求

家里搭建了一个网站(Nginx)
想让朋友也能访问

安装Nginx(如果还没安装):

# Ubuntu/Debian
sudo apt install nginx

# CentOS/RHEL
sudo yum install nginx

# 启动Nginx
sudo systemctl start nginx

# 默认监听80端口

修改Nginx首页(可选):

# Ubuntu
sudo vi /var/www/html/index.nginx-debian.html

# CentOS
sudo vi /usr/share/nginx/html/index.html

# 改成自己的内容,比如:
# <h1>Welcome to My Home Server!</h1>

配置frpc(添加Nginx代理):

# frpc.toml

serverAddr = "123.45.67.89"
serverPort = 7000

# SSH服务(之前的配置保留)
[[proxies]]
name = "ssh"
type = "tcp"
localIP = "127.0.0.1"
localPort = 22
remotePort = 6000

# Nginx服务(新增)
[[proxies]]
name = "web"
type = "tcp"
localIP = "127.0.0.1"
localPort = 80
remotePort = 8080

重启frpc

# 停止之前的frpc
pkill frpc

# 重新启动
nohup ./frpc -c ./frpc.toml &> frpc.log &

测试访问

# 在浏览器中访问:
http://123.45.67.89:8080

# 或者用curl:
curl http://123.45.67.89:8080

# 应该能看到你家里Nginx的页面
6. 高级配置:HTTP代理

HTTP代理的好处

使用TCP代理需要指定端口(如8080)
使用HTTP代理可以通过域名访问(更友好)

前提条件

你有一个域名(如:home.example.com)
域名解析到公网服务器的IP

修改frps配置

# frps.toml

bindPort = 7000

# 添加HTTP支持
vhostHTTPPort = 80  # HTTP虚拟主机端口

修改frpc配置

# frpc.toml

serverAddr = "123.45.67.89"
serverPort = 7000

# Nginx服务(使用HTTP类型)
[[proxies]]
name = "web"
type = "http"               # 改成HTTP类型
localIP = "127.0.0.1"
localPort = 80
customDomains = ["home.example.com"]  # 绑定域名

重启frps和frpc

# 公网服务器
pkill frps
nohup ./frps -c ./frps.toml &> frps.log &

# 家里的电脑
pkill frpc
nohup ./frpc -c ./frpc.toml &> frpc.log &

访问测试

# 直接通过域名访问(不需要端口号)
http://home.example.com

# 更加友好!
7. 安全建议

1. 加密传输

# frps.toml
transport.tls.enable = true

# frpc.toml
transport.tls.enable = true

2. 身份验证

# frps.toml
auth.method = "token"
auth.token = "your_secret_token_12345"

# frpc.toml
auth.method = "token"
auth.token = "your_secret_token_12345"

3. 限制访问

# 在公网服务器上配置防火墙
# 只允许特定IP访问

sudo ufw allow from 1.2.3.4 to any port 6000

4. 使用HTTPS

# frpc.toml
[[proxies]]
name = "web-https"
type = "https"
localIP = "127.0.0.1"
localPort = 443
customDomains = ["home.example.com"]
8. 常见问题

1. 连接失败

检查清单:
□ 公网服务器的frps是否正常运行
□ 防火墙端口是否开放
□ frpc配置的serverAddr和serverPort是否正确
□ 本地服务是否正常运行

2. 连接不稳定

可能原因:
- 网络不稳定
- frpc进程被kill
- 超时断开

解决方案:
- 配置心跳检测
- 配置自动重启
- 使用systemd管理frpc

3. 性能问题

所有流量都通过公网服务器中转
会有性能损耗

改进方案:
- 选择带宽充足的公网服务器
- 使用P2P模式(需要两端都支持)
- 考虑使用专业的内网穿透服务

4. 使用systemd管理frpc(推荐):

# 创建systemd服务文件
sudo vi /etc/systemd/system/frpc.service

# 内容:
[Unit]
Description=FRP Client
After=network.target

[Service]
Type=simple
User=root
WorkingDirectory=/path/to/frp
ExecStart=/path/to/frp/frpc -c /path/to/frp/frpc.toml
Restart=on-failure
RestartSec=5s

[Install]
WantedBy=multi-user.target

# 启动服务
sudo systemctl start frpc
sudo systemctl enable frpc  # 开机自启

# 查看状态
sudo systemctl status frpc

二、DNS域名解析系统

2.1 DNS的背景

1. IP地址不方便记忆

问题

TCP/IP网络使用IP地址和端口号定位主机和服务
但IP地址是数字,不方便记忆

例如:
- 百度:180.101.49.11
- 谷歌:142.250.185.46
- GitHub:20.205.243.166

试想:如果没有域名,你能记住这些IP吗?

早期的解决方案:hosts文件

人们发明了"主机名"(hostname)
使用hosts文件描述主机名和IP的对应关系

hosts文件内容示例:
180.101.49.11    www.baidu.com
142.250.185.46   www.google.com
20.205.243.166   github.com

访问网站时:
1. 用户输入:www.baidu.com
2. 系统查hosts文件
3. 找到对应IP:180.101.49.11
4. 连接这个IP

hosts文件的问题

最初,hosts文件由互联网信息中心(SRI-NIC)集中管理

遇到的困难:
1. 新电脑接入网络,需要向信息中心申请添加记录
2. IP变更,需要向信息中心申请修改
3. 其他电脑需要定期下载更新hosts文件
4. 互联网规模增长,hosts文件变得巨大
5. 管理和同步极其困难

无法扩展!
2. DNS系统的诞生

DNS的设计思想

分布式管理:
- 不再集中管理一个文件
- 每个组织管理自己的域名
- 通过DNS服务器提供查询

自动查询:
- 用户输入域名
- 系统自动查询DNS服务器
- 获得对应的IP地址
- 无需手动维护hosts文件

DNS的好处

✓ 可扩展:每个组织管理自己的域名
✓ 自动化:系统自动查询,无需手动更新
✓ 灵活:IP变更只需更新DNS服务器
✓ 高效:DNS服务器缓存查询结果

hosts文件的保留

至今,计算机上仍保留hosts文件
在DNS查询之前,会先查hosts文件

位置:
- Linux/Mac: /etc/hosts
- Windows: C:\Windows\System32\drivers\etc\hosts

优先级:
hosts文件 > DNS查询

用途:
- 本地开发(配置测试域名)
- 屏蔽广告(把广告域名指向127.0.0.1)
- 绕过DNS污染

2.2 域名的结构

1. 域名的层次结构

域名是树状结构

                        .(根)
                        |
        ┌───────────────┼───────────────┐
        |               |               |
       com             net              org          cn
        |               |               |            |
    ┌───┴───┐       ┌───┴───┐      ┌───┴───┐    ┌───┴───┐
  baidu  google   cloudflare  github  wikipedia  baidu  qq
    |       |         |         |         |        |      |
   www     www       www       www       www      www    www

在这里插入图片描述

从右到左阅读

www.baidu.com
 │    │    └─ 一级域名(顶级域名,TLD)
 │    └────── 二级域名
 └─────────── 三级域名(主机名)

完整域名(FQDN)

www.baidu.com.
              ↑
           根域名(通常省略)

完整的域名应该以点结尾
但我们平时都省略了
2. 各级域名详解

根域名(Root)

符号:.
全球只有13组根DNS服务器
负责管理顶级域名

一级域名(顶级域名,TLD)

通用顶级域名(gTLD):
- .com:商业机构
- .net:网络服务提供商
- .org:非盈利组织
- .edu:教育机构
- .gov:政府机构
- .mil:军事机构
- .int:国际组织

国家/地区顶级域名(ccTLD):
- .cn:中国
- .us:美国
- .uk:英国
- .jp:日本
- .de:德国

新通用顶级域名:
- .tech:技术
- .app:应用
- .blog:博客
- .shop:商店

二级域名

通常是企业名、组织名、个人名
由域名注册商注册获得

例子:
- baidu.com:百度公司
- google.com:谷歌公司
- github.com:GitHub平台

在某些国家,还有特定的二级域名:
- .com.cn:中国的商业域名
- .gov.cn:中国的政府域名
- .edu.cn:中国的教育域名

三级及以上域名(子域名)

由二级域名的所有者自行创建和管理

例子:
www.baidu.com:
- www:三级域名,通常表示万维网服务

mail.google.com:
- mail:三级域名,谷歌的邮箱服务

api.github.com:
- api:三级域名,GitHub的API服务

blog.csdn.net:
- blog:三级域名,CSDN的博客服务
3. www的由来

www不是必需的

www是一种习惯用法
历史上,人们常用子域名表示服务类型:

www.example.com  → 网站服务(World Wide Web)
ftp.example.com  → FTP文件传输服务
mail.example.com → 邮件服务

现代趋势

很多网站不再使用www:
- google.com(不需要www)
- facebook.com
- twitter.com

但也有网站保留www:
- www.baidu.com
- www.qq.com
- www.taobao.com

技术上,example.com和www.example.com可以:
- 指向同一个IP(完全相同)
- 指向不同的IP(不同服务)
- 一个重定向到另一个

2.3 DNS解析过程

1. DNS查询的类型

递归查询

客户端向DNS服务器发起查询
DNS服务器负责完成整个查询过程
返回最终结果给客户端

客户端 → DNS服务器:"帮我查www.baidu.com"
DNS服务器:自己去查,查到后返回结果
客户端 ← DNS服务器:"IP是180.101.49.11"

迭代查询

DNS服务器之间的查询
如果自己不知道,返回下一个应该查询的服务器地址

DNS服务器A → 根服务器:"www.baidu.com是多少?"
根服务器 → DNS服务器A:"我不知道,但你可以问.com服务器"
DNS服务器A → .com服务器:"www.baidu.com是多少?"
.com服务器 → DNS服务器A:"我不知道,但你可以问baidu.com服务器"
...
2. 完整的DNS解析流程

场景:你在浏览器输入 www.baidu.com

Step 1:检查浏览器缓存

浏览器自己缓存了DNS解析结果
如果之前访问过www.baidu.com,可能有缓存
检查缓存,如果有且未过期,直接使用

Step 2:检查系统缓存

操作系统也有DNS缓存
Windows:ipconfig /displaydns 可以查看
Linux:Linux 是否有系统级缓存取决于发行版/组件(如 systemd-resolved、dnsmasq、nscd 等)。

Step 3:检查hosts文件

查看/etc/hosts(Linux)或C:\Windows\System32\drivers\etc\hosts(Windows)
如果hosts文件中有www.baidu.com的记录,直接使用

Step 4:向本地DNS服务器查询(递归查询)

本地DNS服务器:
- 通常是ISP(运营商)提供的DNS服务器
- 或者是手动配置的DNS服务器(如8.8.8.8,114.114.114.114)

客户端 → 本地DNS服务器(如192.168.1.1)
请求:查询www.baidu.com

本地DNS服务器先检查自己的缓存
如果有缓存且未过期,直接返回

Step 5:本地DNS服务器向根服务器查询(迭代查询)

本地DNS服务器 → 根DNS服务器
请求:"www.baidu.com的IP是多少?"

根DNS服务器 → 本地DNS服务器
响应:"我不知道www.baidu.com,但我知道.com域由哪些服务器管理"
      "去问这些.com顶级域名服务器:[.com NS列表]"

Step 6:向顶级域名服务器查询

本地DNS服务器 → .com顶级域名服务器
请求:"www.baidu.com的IP是多少?"

.com服务器 → 本地DNS服务器
响应:"我不知道www.baidu.com,但我知道baidu.com域由哪些服务器管理"
      "去问这些baidu.com权威DNS服务器:[baidu.com NS列表]"

Step 7:向权威DNS服务器查询

本地DNS服务器 → baidu.com权威DNS服务器
请求:"www.baidu.com的IP是多少?"

baidu.com服务器 → 本地DNS服务器
响应:"www.baidu.com的IP是180.101.49.11"
      "TTL=600秒"

Step 8:本地DNS服务器缓存并返回

本地DNS服务器:
1. 缓存这个解析结果(600秒)
2. 返回给客户端

本地DNS服务器 → 客户端
响应:"www.baidu.com的IP是180.101.49.11"

Step 9:客户端连接

客户端获得IP地址:180.101.49.11
建立TCP连接
发送HTTP请求

完整流程图

客户端                本地DNS      根DNS    .com DNS   baidu.com DNS
  |                     |           |         |            |
  | 1.查询              |           |         |            |
  | www.baidu.com       |           |         |            |
  |-------------------->|           |         |            |
  |                     | 2.查询    |         |            |
  |                     |---------->|         |            |
  |                     | 3.返回    |         |            |
  |                     | .com NS   |         |            |
  |                     |<----------|         |            |
  |                     |                     |            |
  |                     | 4.查询              |            |
  |                     |-------------------->|            |
  |                     | 5.返回              |            |
  |                     | baidu.com NS        |            |
  |                     |<--------------------|            |
  |                     |                                  |
  |                     | 6.查询                           |
  |                     |--------------------------------->|
  |                     | 7.返回IP: 180.101.49.11          |
  |                     |<---------------------------------|
  |                     |                                  |
  | 8.返回IP            |                                  |
  |<--------------------|                                  |
  |                                                        |
  | 9.连接180.101.49.11                                    |
  |-------------------------------------------------------->百度服务器

在这里插入图片描述

2.4 使用dig工具分析DNS

1. 安装dig工具
# CentOS/RHEL
sudo yum install bind-utils

# Ubuntu/Debian
sudo apt install dnsutils

# macOS
# dig通常已预装
2. 基本用法

查询域名

dig www.baidu.com

# 输出示例:
; <<>> DiG 9.16.1-Ubuntu <<>> www.baidu.com
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 12345
;; flags: qr rd ra; QUERY: 1, ANSWER: 3, AUTHORITY: 0, ADDITIONAL: 1

;; QUESTION SECTION:
;www.baidu.com.			IN	A

;; ANSWER SECTION:
www.baidu.com.		600	IN	CNAME	www.a.shifen.com.
www.a.shifen.com.	300	IN	A	180.101.49.11
www.a.shifen.com.	300	IN	A	180.101.49.12

;; Query time: 10 msec
;; SERVER: 192.168.1.1#53(192.168.1.1)
;; WHEN: Mon Jan 15 10:00:00 CST 2024
;; MSG SIZE  rcvd: 100

输出解释

1. 开头部分

dig版本信息和查询的域名

2. HEADER部分

status: NOERROR  → 查询成功
flags: qr rd ra  → 查询标志
  qr: 这是一个响应(query response)
  rd: 期望递归查询(recursion desired)
  ra: 服务器支持递归(recursion available)
QUERY: 11个查询
ANSWER: 33个答案记录

3. QUESTION SECTION

查询的问题:
www.baidu.com.  IN  A
                 │   └ A记录(IPv4地址)
                 └ IN表示Internet类

4. ANSWER SECTION

查询结果:
www.baidu.com.  600  IN  CNAME  www.a.shifen.com.
                 │                └ CNAME:别名记录
                 └ TTL=600秒(10分钟)

www.a.shifen.com.  300  IN  A  180.101.49.11
                    │             └ IP地址
                    └ TTL=300秒(5分钟)

解释:
- www.baidu.com 是 www.a.shifen.com 的别名
- www.a.shifen.com 解析到两个IP地址(负载均衡)

5. 统计信息

Query time: 10 msec         → 查询耗时10毫秒
SERVER: 192.168.1.1#53      → 使用的DNS服务器及端口
3. 常用选项

只显示答案

dig +short www.baidu.com

# 输出:
www.a.shifen.com.
180.101.49.11
180.101.49.12

指定DNS服务器

# 使用Google DNS
dig @8.8.8.8 www.baidu.com

# 使用114 DNS
dig @114.114.114.114 www.baidu.com

查询特定记录类型

# 查询A记录(IPv4)
dig www.baidu.com A

# 查询AAAA记录(IPv6)
dig www.baidu.com AAAA

# 查询MX记录(邮件服务器)
dig baidu.com MX

# 查询NS记录(域名服务器)
dig baidu.com NS

# 查询TXT记录(文本记录,常用于验证)
dig baidu.com TXT

追踪完整解析过程

dig +trace www.baidu.com

# 会显示从根服务器开始的完整查询过程

2.5 DNS缓存与TTL

1. 为什么需要缓存

性能优化

DNS查询需要多次网络请求
每次都查询会很慢

有了缓存:
- 第一次查询:完整的DNS解析流程
- 后续查询:直接从缓存获取
- 大大提高速度

减少DNS服务器负载

如果没有缓存:
- 每次访问网站都要查询DNS
- 全球数十亿设备,数千亿次查询
- DNS服务器压力巨大

有了缓存:
- 大量查询由本地缓存满足
- DNS服务器压力大幅降低
2. 多级缓存

浏览器缓存

Chrome浏览器:
- 查看DNS缓存:chrome://net-internals/#dns
- 清除DNS缓存:chrome://net-internals/#dns → Clear host cache

操作系统缓存

Windows:
- 查看:ipconfig /displaydns
- 清除:ipconfig /flushdns

Linux:
- 通常没有系统级缓存
- 如果安装了nscd:sudo systemctl restart nscd

macOS:
- 清除:sudo dscacheutil -flushcache; sudo killall -HUP mDNSResponder

本地DNS服务器缓存

ISP的DNS服务器缓存大量解析结果
TTL到期后才重新查询
3. TTL(生存时间)

TTL的作用

控制缓存的有效期

例如:
www.baidu.com  600  IN  A  180.101.49.11
                │
               TTL=600秒

意思:
- 这条记录可以缓存600秒(10分钟)
- 600秒后,需要重新查询

TTL的权衡

TTL长(如86400秒=1天):
✓ 减少DNS查询
✓ 提高性能
✗ IP变更后生效慢

TTL短(如60秒):
✓ IP变更后快速生效
✗ 频繁查询DNS
✗ 性能略差

通常设置:
- 稳定的服务:TTL=3600秒(1小时)或更长
- 即将变更IP:提前降低TTL(如60秒)
- 变更完成后:再提高TTL

2.6 浏览器输入URL后发生的事情

经典面试题,综合考察网络知识

完整流程(以访问 http://www.baidu.com 为例):

1. URL解析

浏览器解析URL:
协议:http
域名:www.baidu.com
端口:80(默认)
路径:/(根路径)

2. DNS解析

浏览器发起DNS查询(前面详细讲过的9步流程)
获得IP地址:180.101.49.11

3. 建立TCP连接

三次握手:
浏览器 → 服务器:SYN
浏览器 ← 服务器:SYN+ACK
浏览器 → 服务器:ACK
连接建立

4. 发送HTTP请求

浏览器发送HTTP请求:
GET / HTTP/1.1
Host: www.baidu.com
User-Agent: Mozilla/5.0 ...
Accept: text/html...
...

5. 服务器处理请求

服务器接收请求
解析请求
处理业务逻辑
生成响应

6. 服务器返回HTTP响应

HTTP/1.1 200 OK
Content-Type: text/html; charset=utf-8
Content-Length: 12345
...

<!DOCTYPE html>
<html>
...
</html>

7. 浏览器接收响应

接收HTML内容
解析HTML
发现需要加载的资源(CSS、JS、图片)

8. 加载页面资源

对于每个资源(CSS、JS、图片):
- 可能需要DNS解析(如果是不同域名)
- 建立TCP连接(或复用已有连接)
- 发送HTTP请求
- 接收响应
- 浏览器缓存资源

9. 渲染页面

解析HTML → 构建DOM树
解析CSS → 构建CSSOM树
合并DOM和CSSOM → 渲染树
布局(Layout)
绘制(Paint)
合成(Composite)
页面显示

10. 执行JavaScript

解析和执行JS代码
可能修改DOM
可能发起新的网络请求(Ajax)

11. 持续交互

用户点击、滚动、输入
JavaScript处理事件
可能发起新的网络请求
更新页面内容

涉及的网络协议栈

应用层:HTTP/HTTPS、DNS
传输层:TCP
网络层:IP、ICMP
数据链路层:以太网、ARP
物理层:网线、光纤、WiFi

三、ICMP协议

3.1 ICMP的作用

1. IP协议的局限性

IP协议是不可靠的

IP协议负责数据包的传输
但不保证数据包一定能到达目的地

可能的问题:
- 数据包丢失
- 路由不可达
- TTL超时
- 目标主机不存在

IP协议本身不提供错误报告机制

需要一个辅助协议

需要一个协议来:
1. 报告错误情况
2. 诊断网络问题
3. 测试网络连通性

ICMP就是这个协议!
2. ICMP协议简介

ICMP(Internet Control Message Protocol,互联网控制消息协议)

是网络层协议(虽然它封装在IP数据包中)
用于在IP主机和路由器之间传递控制消息
不传输数据,只传输控制信息

ICMP的主要功能

1. 错误报告:
   - 目标不可达
   - 超时
   - 参数错误

2. 网络诊断:
   - Ping(测试连通性)
   - Traceroute(跟踪路由)

ICMP与IP的关系

ICMP虽然工作在网络层
但它仍然需要IP协议来传输ICMP消息

ICMP消息封装在IP数据包中:
┌────────────────────────────┐
│      IP首部                 │
│  协议号:1(ICMP)          │
├────────────────────────────┤
│      ICMP消息              │
│                            │
└────────────────────────────┘

3.2 ICMP报文格式

基本格式
在这里插入图片描述

┌────────────────────────────────────────┐
│      类型(Type)- 8位                 │
├────────────────────────────────────────┤
│      代码(Code)- 8位                 │
├────────────────────────────────────────┤
│      校验和(Checksum)- 16位          │
├────────────────────────────────────────┤
│      数据部分(根据类型和代码变化)     │
│                                        │
└────────────────────────────────────────┘

常见的ICMP消息类型

类型 代码 说明
0 0 Echo Reply(回显应答,Pong)
3 0 Destination Network Unreachable(目标网络不可达)
3 1 Destination Host Unreachable(目标主机不可达)
3 2 Destination Protocol Unreachable(目标协议不可达)
3 3 Destination Port Unreachable(目标端口不可达)
5 0 Redirect(重定向)
8 0 Echo Request(回显请求,Ping)
11 0 TTL Exceeded(TTL超时)
11 1 Fragment Reassembly Time Exceeded(分片重组超时)

ICMP分为两大类

1. 错误报告消息

类型3:目标不可达
类型11:TTL超时
类型12:参数错误
...

2. 查询消息

类型8:Echo Request(Ping请求)
类型0:Echo Reply(Ping应答)
类型13:时间戳请求
类型14:时间戳应答
...

3.3 ping命令

1. ping命令的作用

ping命令

用于测试网络连通性
基于ICMP Echo Request/Reply实现
最常用的网络诊断工具

基本用法

# ping域名
ping www.baidu.com

# ping IP地址
ping 180.101.49.11

# ping指定次数(Linux)
ping -c 4 www.baidu.com

# ping指定次数(Windows)
ping -n 4 www.baidu.com

# 持续ping(Linux默认,Windows用 -t)
ping www.baidu.com
2. ping命令的输出

示例输出

$ ping www.baidu.com

PING www.a.shifen.com (180.101.49.11): 56 data bytes
64 bytes from 180.101.49.11: icmp_seq=0 ttl=52 time=10.2 ms
64 bytes from 180.101.49.11: icmp_seq=1 ttl=52 time=10.5 ms
64 bytes from 180.101.49.11: icmp_seq=2 ttl=52 time=10.3 ms
64 bytes from 180.101.49.11: icmp_seq=3 ttl=52 time=10.4 ms

--- www.a.shifen.com ping statistics ---
4 packets transmitted, 4 packets received, 0.0% packet loss
round-trip min/avg/max/stddev = 10.2/10.4/10.5/0.1 ms

输出解释

第一行

PING www.a.shifen.com (180.101.49.11): 56 data bytes
                         │
                         └ DNS解析后的IP地址

每一行响应

64 bytes from 180.101.49.11: icmp_seq=0 ttl=52 time=10.2 ms
│              │              │          │      │
│              │              │          │      └ 往返时间(RTT)
│              │              │          └ TTL值
│              │              └ 序列号
│              └ 响应来源IP
└ 数据包大小

统计信息

4 packets transmitted  → 发送了4个包
4 packets received     → 收到了4个包
0.0% packet loss       → 丢包率0%

round-trip min/avg/max/stddev = 10.2/10.4/10.5/0.1 ms
           │   │   │    │
           │   │   │    └ 标准差
           │   │   └ 最大RTT
           │   └ 平均RTT
           └ 最小RTT
3. ping命令的工作原理

发送Echo Request

1. ping程序构造ICMP Echo Request消息:
   ┌─────────────────────────────┐
   │ 类型:8(Echo Request)     │
   │ 代码:0                     │
   │ 校验和:...                 │
   │ 标识符:进程ID              │
   │ 序列号:递增(0, 1, 2...)   │
   │ 数据:填充数据              │
   └─────────────────────────────┘

2. 封装在IP数据包中:
   ┌─────────────────────────────┐
   │ IP首部                      │
   │ 源IP:你的IP                │
   │ 目的IP:180.101.49.11       │
   │ 协议:1(ICMP)             │
   ├─────────────────────────────┤
   │ ICMP Echo Request           │
   └─────────────────────────────┘

3. 通过网络发送
4. 记录发送时间:t1

接收Echo Reply

1. 目标主机收到Echo Request

2. 目标主机构造Echo Reply:
   ┌─────────────────────────────┐
   │ 类型:0(Echo Reply)       │
   │ 代码:0                     │
   │ 校验和:...                 │
   │ 标识符:与请求相同          │
   │ 序列号:与请求相同          │
   │ 数据:与请求相同            │
   └─────────────────────────────┘

3. 返回给源主机

4. 源主机收到Echo Reply
5. 记录接收时间:t2
6. 计算RTT = t2 - t1

TTL的含义

TTL(Time To Live,生存时间):
- IP数据包的跳数限制
- 每经过一个路由器,TTL减1
- TTL减到0时,路由器丢弃数据包,发送ICMP超时消息

ping显示的TTL:
- 是响应包返回时的TTL值
- 不是原始TTL值

例如:
- 百度服务器发送时:TTL=64
- 经过12跳路由器:TTL=64-12=52
- ping显示:ttl=52

通过TTL可以估算跳数:
- Linux/Mac默认TTL=64
- Windows默认TTL=128
- 跳数 ≈ 初始TTL - 当前TTL
4. ping的常见结果

成功

64 bytes from 180.101.49.11: icmp_seq=0 ttl=52 time=10.2 ms

说明:
- 网络连通
- 目标主机可达
- 往返时间正常

目标主机不可达

From 192.168.1.1 icmp_seq=1 Destination Host Unreachable

可能原因:
- 目标主机不存在
- 目标主机关机
- 路由不可达
- 防火墙阻止

请求超时

Request timeout for icmp_seq 0

可能原因:
- 数据包丢失
- 目标主机关机或禁ping
- 网络拥塞
- 防火墙阻止ICMP

丢包

64 bytes from 180.101.49.11: icmp_seq=0 ttl=52 time=10.2 ms
Request timeout for icmp_seq 1
64 bytes from 180.101.49.11: icmp_seq=2 ttl=52 time=10.5 ms

--- ping statistics ---
3 packets transmitted, 2 packets received, 33.3% packet loss

说明:
- 网络不稳定
- 有丢包

3.4 traceroute命令

1. traceroute的作用

traceroute命令

跟踪数据包到达目标的路径
显示经过的每一个路由器
基于ICMP和TTL机制实现

基本用法

# Linux/Mac
traceroute www.baidu.com

# Windows(命令名不同)
tracert www.baidu.com
2. traceroute的输出

示例输出

$ traceroute www.baidu.com

traceroute to www.a.shifen.com (180.101.49.11), 30 hops max, 60 byte packets
 1  192.168.1.1 (192.168.1.1)  1.234 ms  1.123 ms  1.156 ms
 2  100.64.0.1 (100.64.0.1)  5.678 ms  5.234 ms  5.456 ms
 3  61.148.10.1 (61.148.10.1)  8.234 ms  8.123 ms  8.345 ms
 4  202.97.33.1 (202.97.33.1)  10.234 ms  10.123 ms  10.456 ms
 5  202.97.50.1 (202.97.50.1)  12.234 ms  12.123 ms  12.345 ms
 6  * * *
 7  180.101.49.11 (180.101.49.11)  15.234 ms  15.123 ms  15.456 ms

输出解释

第一行

traceroute to www.a.shifen.com (180.101.49.11), 30 hops max, 60 byte packets
                                                  │           │
                                                  │           └ 数据包大小
                                                  └ 最大跳数

每一跳

1  192.168.1.1 (192.168.1.1)  1.234 ms  1.123 ms  1.156 ms
│  │                          │         │         │
│  │                          │         │         └ 第3次测试的RTT
│  │                          │         └ 第2次测试的RTT
│  │                          └ 第1次测试的RTT
│  └ 路由器IP
└ 跳数

特殊符号

*:表示超时,没有收到响应
   可能原因:
   - 路由器不响应ICMP
   - 防火墙阻止
   - 该跳丢包
3. traceroute的工作原理

基于TTL机制

Step 1:发送TTL=1的数据包

1. traceroute发送UDP或ICMP数据包,TTL=1

2. 第一跳路由器收到:
   - TTL减1,变成0
   - 丢弃数据包
   - 发送ICMP超时消息给源主机
   
3. 源主机收到ICMP超时消息:
   - 获得第一跳路由器的IP
   - 记录RTT

第一跳路由器:192.168.1.1

Step 2:发送TTL=2的数据包

1. traceroute发送数据包,TTL=2

2. 第一跳路由器:
   - TTL减1,变成1
   - 转发数据包
   
3. 第二跳路由器收到:
   - TTL减1,变成0
   - 丢弃数据包
   - 发送ICMP超时消息
   
4. 源主机收到消息:
   - 获得第二跳路由器的IP
   - 记录RTT

第二跳路由器:100.64.0.1

Step 3:发送TTL=3的数据包

类似的过程...

第三跳路由器:61.148.10.1

持续增加TTL,直到

1. 到达目标主机:
   - 目标主机返回ICMP端口不可达(UDP方式)
   - 或返回ICMP Echo Reply(ICMP方式)
   
2. 达到最大跳数(默认30)

结束

完整流程图

源主机              路由器1          路由器2          目标主机
  |                   |                |                |
  | TTL=1             |                |                |
  |------------------>|                |                |
  |                   | TTL超时         |                |
  |<------------------|                |                |
  | (ICMP超时消息)     |                |                |
  |                   |                |                |
  | TTL=2             |                |                |
  |------------------>| TTL=1          |                |
  |                   |--------------->|                |
  |                   |                | TTL超时        |
  |                   |<---------------|                |
  |<------------------|                |                |
  | (ICMP超时消息)     |                |                |
  |                   |                |                |
  | TTL=3             |                |                |
  |------------------>| TTL=2          |                |
  |                   |--------------->| TTL=1          |
  |                   |                |--------------->|
  |                   |                |                | 到达目标
  |                   |                |<---------------|
  |                   |<---------------|                |
  |<------------------|                |                |
  | (目标可达响应)     |                |                |

3.5 重要提醒:ping不是端口!

常见的面试陷阱

错误的问题

面试官:"telnet是23端口,ssh是22端口,那么ping是什么端口?"

正确的回答

千万注意!这是面试官的圈套!

ping命令基于ICMP协议
ICMP是网络层协议
而端口号是传输层(TCP/UDP)的概念

在ICMP中根本就不关注端口号这样的信息
ping没有端口号!

为什么容易被误导

因为很多网络工具都有对应的端口:
- telnet: 23端口(TCP)
- ssh: 22端口(TCP)
- http: 80端口(TCP)
- https: 443端口(TCP)
- DNS: 53端口(UDP/TCP)

所以很自然地认为ping也有端口

但是:
ping使用ICMP,不使用TCP/UDP
ICMP在网络层,比传输层更底层
没有端口的概念

ICMP报文的标识

ICMP不使用端口号
而是使用类型(Type)和代码(Code)来区分不同的消息

ping使用:
- Echo Request:类型=8,代码=0
- Echo Reply:类型=0,代码=0

协议层次对比

┌─────────────────────────────┐
│  应用层(HTTP、FTP等)      │
│  使用URL、域名              │
├─────────────────────────────┤
│  传输层(TCP、UDP)         │
│  使用端口号                 │  ← telnet、ssh、http在这一层
├─────────────────────────────┤
│  网络层(IP、ICMP)         │
│  使用IP地址                 │  ← ping在这一层,没有端口!
├─────────────────────────────┤
│  数据链路层(以太网)       │
│  使用MAC地址                │
├─────────────────────────────┤
│  物理层                     │
└─────────────────────────────┘

总结

如果面试官问"ping是什么端口"

正确回ICMP是网络层协议。
端口号是传输层(TCP/UDP)的概念。
ICMP工作在网络层,不涉及端口号。
ICMP使用类型和代码字段来区分不同的消息,
ping使用的是Echo Request(类型8)和Echo Reply(类型0)。"

这样的回答能展示你对网络协议栈的深刻理解!

四、本篇总结

4.1 核心要点回顾

内网穿透

  • ✓ 通过公网服务器中转,解决NAT阻止外部主动连接的问题
  • ✓ 内网客户端主动连接公网服务器,保持长连接
  • ✓ frp实战:可以远程SSH、访问家里的网站、配置HTTP代理
  • ✓ 安全建议:加密传输、身份验证、限制访问、使用HTTPS

DNS域名解析

  • ✓ DNS将域名转换为IP地址,采用分布式、层次化的设计
  • ✓ 域名结构:根域名 → 顶级域名(.com) → 二级域名(baidu) → 三级域名(www)
  • ✓ DNS解析过程:浏览器缓存 → 系统缓存 → hosts文件 → 递归查询 → 迭代查询(9步流程)
  • ✓ dig工具实战:查询域名、指定DNS服务器、查询特定记录类型、追踪完整解析过程
  • ✓ 多级DNS缓存和TTL机制提高性能
  • ✓ 浏览器输入URL后发生的事情:URL解析 → DNS解析 → TCP连接 → HTTP请求/响应 → 渲染页面

ICMP协议

  • ✓ ICMP用于网络诊断和错误报告,是IP协议的辅助协议
  • ✓ ping命令:测试网络连通性,基于ICMP Echo Request/Reply,显示RTT和TTL
  • ✓ traceroute命令:跟踪数据包路径,基于TTL机制,显示每一跳路由器
  • ✓ 重要:ping基于ICMP(网络层),没有端口号的概念!

4.2 常见面试题

1. 内网穿透的原理是什么?

答:
- 核心思想:内网客户端主动连接公网服务器(可以穿透NAT)
- 保持长连接不断
- 外网访问时,通过这个连接反 关键技术:控制连接(通知)、数据连接(传输)、中转服务器

2. 为什么需要DNS?hosts文件不够用吗?

答:
- hosts文件问题:集中管理无法扩展、手动同步效率低、文件巨大、IP变更需所有人更新
- DNS优势:分布式管理可扩展、自动查询无需手动维护、缓存机制提高效率、IP变更只需更新DNS服务器

3. DNS解析的完整过程是什么?

答:
1. 检查浏览器缓存
2. 检查系统缓存
3. 检查hosts文件
4. 向本地DNS服务器查询(递归查询)
5-7. 本地DNS服务器向根服务器、顶级域名服务器、权威DNS服务器查询(迭代查询)
8. 本地DNS服务器缓存并返回
9. 客户端连接

4. ping命令的工作原理?

答:
1. 发送ICMP Echo Request(类型8)
2. 目标主机收到后,返回ICMP Echo Reply(类型0)
3. 计算往返时间(RTT)
4. 根据TTL值估算跳数

关键点:
- 基于ICMP协议(网络层)
- 没有端口号的概念
- 可以测试连通性和延迟

5. traceroute是如何工作的?

答:
- 利用TTL机制
- 发送TTL=1的数据包,第一跳路由器超时,返回ICMP超时消息
- 发送TTL=2的数据包,第二跳路由器超时,返回ICMP超时消息
- 依次增加TTL,直到到达目标
- 每个路由器超时时返回自己的IP
- traceroute收集这些IP,显示路径

6. 浏览器输入URL后发生的事情?

答:
1. URL解析
2. DNS解析(获取IP地址)
3. 建立TCP连接(三次握手)
4. 发送HTTP请求
5. 服务器处理请求并返回响应
6. 浏览器接收响应,解析HTML
7. 加载页面资源(CSS、JS、图片)
8. 渲染页面(构建DOM树、CSSOM树、渲染树、布局、绘制)
9. 执行JavaScript
10. 持续交互

涉及协议:HTTP/HTTPS、DNS、TCP、IP、ICMP、以太网、ARP
如果是 HTTPS:TCP 三次握手之后还会有 TLS 1.2/1.3 握手,再发 HTTP(加密后)

7. 为什么ping不是端口?

答:
- ping基于ICMP协议,ICMP是网络层协议
- 端口号是传输层(TCP/UDP)的概念
- ICMP工作在网络层,不涉及端口号
- ICMP使用类型(Type)和代码(Code)区分消息
- ping使用Echo Request(类型8)和Echo Reply(类型0)

4.3 实战技能总结

学完本篇,你应该能够

内网穿透相关

  • ✓ 使用frp实现内网穿透
  • ✓ 远程SSH到家里的电脑
  • ✓ 让朋友访问家里的网站
  • ✓ 配置HTTP代理通过域名访问
  • ✓ 使用systemd管理frpc服务

DNS相关

  • ✓ 使用dig工具分析域名解析
  • ✓ 配置hosts文件
  • ✓ 清除DNS缓存
  • ✓ 理解浏览器输入URL后的完整过程
  • ✓ 理解TTL的作用

ICMP相关

  • ✓ 使用ping测试网络连通性
  • ✓ 使用traceroute诊断网络问题
  • ✓ 理解TTL的含义
  • ✓ 知道ping没有端口号
  • ✓ 分析ping和traceroute的输出

4.4 网络系列总结

至此,网络部分的内容全部结束!

从应用层(HTTP、HTTPS)到传输层(TCP、UDP)到网络层(IP、ICMP、NAT)到数据链路层(以太网、ARP),再到进阶应用(代理、内网穿透、DNS),你已经掌握了完整的网络知识体系!

接下来可以开始实践了:

  • 写网络程序(Socket编程)
  • 搭建服务器(Nginx、frp)
  • 优化性能(缓存、负载均衡)
  • 诊断问题(ping、traceroute、dig)

把学到的知识应用到实际项目中!


💬 总结:这篇文章详细讲解了三大实战技术。内网穿透让我们能够突破NAT限制,远程访问家里的服务器,包含完整的frp部署教程。DNS域名解析系统让我们理解了域名如何转换为IP地址,掌握了dig工具的使用。ICMP协议让我们能够使用ping和traceroute诊断网络问题,特别强调了"ping不是端口"这个重要知识点。这些技术都非常实用,理解它们的原理能帮助你更好地搭建服务、诊断网络问题。至此,网络进阶系列全部完成!从NAT、代理到内网穿透、DNS、ICMP,你已经掌握了完整的网络进阶技能。接下来就是实践了——搭建服务、优化性能、解决问题,把学到的知识应用到实际项目中!

👍 点赞、收藏与分享:如果这篇内网穿透、DNS和ICMP的实战内容对你有帮助,特别是frp的完整部署教程、dig工具的使用、"浏览器输入URL后发生的事情"这道经典面试题的完整解答,请点赞收藏!网络进阶,从实战开始!

Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐