文章目录
- 前言
- [一、问题现场 : 一台服务器牵出的三个 " 外网 IP "](#一、问题现场 : 一台服务器牵出的三个 " 外网 IP ")
-
- 1、现象描述
- [2、ipconfig 输出解读](#2、ipconfig 输出解读)
- [二、核心知识点 : 一个服务的 " 两个公网 IP "](#二、核心知识点 : 一个服务的 " 两个公网 IP ")
-
- [1、出方向 : 出口 IP](#1、出方向 : 出口 IP)
- [2、入方向 : 发布地址](#2、入方向 : 发布地址)
- [3、NAT 回环 : 为什么本机连不上自己的公网地址](#3、NAT 回环 : 为什么本机连不上自己的公网地址)
- 4、为什么检测网站会 " 检测错误 "
- [三、排查实施 : 三步定位网络变化](#三、排查实施 : 三步定位网络变化)
-
- [1、第一步 : 端口探测脚本](#1、第一步 : 端口探测脚本)
- [2、第二步 : RDAP 查询 IP 注册归属](#2、第二步 : RDAP 查询 IP 注册归属)
- [3、第三步 : 新旧地址对比结论](#3、第三步 : 新旧地址对比结论)
- 四、注意事项与避坑
- 总结
前言
最近接手了一个很典型的问题 : 机房里一台对外提供 Web 服务的 Windows 服务器 , 用户反馈原来的访问地址失效了 , 换了新地址才能打开 ;
排查过程中先后踩了 " 检测网站查 IP 不准 " , " 内网连不通自己的公网地址 " 等一系列坑 ;
本文把整个排查过程和背后的网络知识点完整梳理一遍 , 涉及 NAT , 出口 IP , 发布地址 , NAT 回环 , RDAP 注册查询 等内容 , 希望能帮到遇到同类问题的朋友 ;
一、问题现场 : 一台服务器牵出的三个 " 外网 IP "
1、现象描述
故障现象 :
- 系统原来通过
http://203.0.113.32:20000/Account/Login/appdemo访问 ; - 最近切换为
http://198.51.100.28:20000/Account/Login/appdemo才能打开 ; - 而用 检测网站查 " 本机外网 IP " , 得到的却是 第三个地址
198.51.100.32; - 三个地址互相都对不上 ;
排查目标 : 搞清楚这三个 IP 分别是什么角色 , 为什么会不一致 , 以及旧地址为什么彻底失效 ;
2、ipconfig 输出解读
先看服务器本机的网卡配置 :
text
以太网适配器 以太网:
IPv4 地址 . . . : 169.254.10.120 <- APIPA 自动私有地址
默认网关. . . . : ( 空 ) <- 没有网关 , 等于废卡
以太网适配器 以太网 2:
媒体状态 . . . : 媒体已断开连接 <- 没插线
以太网适配器 外网:
IPv4 地址 . . . : 10.10.10.253 <- 真正在用的内网地址
子网掩码 . . . : 255.255.255.0
默认网关. . . . : 10.10.10.254 <- 出网必经的网关
逐条解读 :
- 169.254 开头的地址 : 这是 APIPA ( Automatic Private IP Addressing , 自动私有地址 ) ; 网卡开启 DHCP 却拿不到地址时 , Windows 会自行分配一个
169.254.0.0/16段的地址 ; 这种地址只能同链路互通 , 不可路由 , 排查时可以直接忽略 ; - 适配器名叫 " 外网 " 不代表它持有公网 IP : 适配器名称只是管理员起的标签 ;
10.10.10.253属于10.0.0.0/8私有地址段 ( RFC 1918 ) , 是纯粹的内网地址 ; - 公网 IP 永远不会出现在本机网卡上 : 服务器位于 NAT ( Network Address Translation , 网络地址转换 ) 之后 , 公网地址 配置在 运营商防火墙与出口网关上 ;
二、核心知识点 : 一个服务的 " 两个公网 IP "
1、出方向 : 出口 IP
使用检测网站检测自己的外部 IP 地址 : 在服务器上可以用浏览器和命令行两种方式查询 ;
- 浏览器方式 : 在服务器浏览器中访问 ip138 , ifconfig.me 等检测网站 , 页面显示的 " 本机 IP " 就是当前线路的出口 IP ;
- 命令行方式 : 直接在服务器命令行执行
curl ifconfig.me或curl ip.sb, 返回的字符串就是出口 IP ;
bash
# 向检测网站发起请求 , 网站读取这条连接的源地址并返回 , 结果即当前出口 IP
curl ifconfig.me

服务器主动访问 外部网站 时 , 数据包 经过 网关 做 源地址转换 ( SNAT ) , 源地址被改写成 运营商分配 的出口地址 ; 检测网站看到的就是该 出口地址 ;
关键结论 : 出口 IP 只代表 " 你出网时的身份 " , 与别人能否访问你的服务毫无关系 ;
2、入方向 : 发布地址
外部用户访问 198.51.100.28:20000 时 , 流量到达运营商防火墙 , 防火墙 按 NAT 映射规则把流量转发到内网 10.10.10.253:20000 ;
这条 映射规则 只存在于防火墙配置里 ;
关键结论 : 发布地址是服务的 " 门牌号 " , 本机网卡看不到它 , 任何检测网站也探测不到它 ;
确认它只有两个途径 : 登录防火墙查看映射配置 , 或者 直接问运营商 ;
3、NAT 回环 : 为什么本机连不上自己的公网地址
排查时 从服务器本机去连 198.51.100.28:20000 , 结果超时 ;
但 外部用户访问一切正常 ;
原因在于大部分防火墙默认不支持 NAT 回环 ( Hairpin NAT ) :
NAT 回环 : 内网主机访问本网络对外的公网 IP 时 , 流量需要在防火墙上 " 出去再绕回来 " ; 若该特性未开启 , 这类流量会被直接丢弃 ;
避坑要点 : 在服务器本机或同内网机器上测试公网地址连通性 , 结果一律不作数 ; 正确做法是换外网环境 ( 例如手机流量热点 ) 测试 , 或直接用内网地址 http://10.10.10.253:20000 验证服务本身 ;
4、为什么检测网站会 " 检测错误 "
检测原理 : ip138 , ifconfig.me 这类网站的实现方式是 : 你向它发一个请求 , 它 读取这条连接的源 IP ; 由于 NAT 改写 , 它 只能看到出口 IP ;
本质 : 检测网站并没有检测错 , 只是它回答的问题是 " 我看到的你是谁 " , 而不是 " 别人该用哪个地址访问你 " ; 这两个问题的答案在 NAT 环境下天然不同 , 类比一下 : 你家快递收件地址是 A ( 发布地址 ) , 但你出门打车报的出发地是 B ( 出口地址 ) ;
三、排查实施 : 三步定位网络变化
1、第一步 : 端口探测脚本
用 Python 对新旧两个地址的 20000 端口做 TCP 与 HTTP 双层探测 :
python
import socket
import urllib.request
import urllib.error
def port_test(ip, port=20000, timeout=6):
# TCP 层 : 判断端口是否可达
try:
s = socket.create_connection((ip, port), timeout=timeout)
s.close()
return "OPEN"
except Exception as e:
return f"closed ({type(e).__name__})"
def http_test(ip, port=20000):
# HTTP 层 : 判断是否有 Web 服务响应
try:
r = urllib.request.urlopen(f"http://{ip}:{port}/", timeout=8)
return f"HTTP {r.status}"
except urllib.error.HTTPError as e:
return f"HTTP {e.code} (服务有响应)"
except Exception as e:
return f"无响应 ({type(e).__name__})"
for ip in ["203.0.113.32", "198.51.100.28"]:
print(ip, "TCP:", port_test(ip), "HTTP:", http_test(ip))
结果解读 : 两个地址从内网探测均超时 ; 结合 NAT 回环知识点可知 , 该结果只说明 " 内网无法回环访问公网地址 " , 不能证明服务故障 ; 旧地址的最终判定还需要下面的注册信息查询 ;
2、第二步 : RDAP 查询 IP 注册归属
RDAP ( Registration Data Access Protocol ) 是 APNIC 等区域注册机构提供的公开查询协议 , 可以查到一段 IP 的注册运营商 :
python
import urllib.request
import ssl
import json
# 跳过证书校验 ( 部分办公网存在 TLS 拦截设备 )
ctx = ssl.create_default_context()
ctx.check_hostname = False
ctx.verify_mode = ssl.CERT_NONE
r = urllib.request.urlopen("https://rdap.apnic.net/ip/203.0.113.32",
timeout=12, context=ctx)
d = json.loads(r.read().decode())
print(d["name"]) # 注册段名称 , 可识别运营商
print(d["startAddress"], d["endAddress"]) # 注册段起止范围
查询要点 : 注册库只能证明 " 这段 IP 属于哪家运营商的哪个大段 " , 无法证明你的线路是否静态 ; 是否固定还要结合业务现象与运营商合同综合判断 ;
3、第三步 : 新旧地址对比结论
对比结果汇总如下 :
| 对比项 | 203.0.113.32 ( 旧 ) | 198.51.100.28 ( 新 ) |
|---|---|---|
| 所属运营商注册段 | 电信 CHINANET 段 | 移动 CMNET 段 |
| 20000 端口现状 | 无响应 , 已退役 | 正常对外提供服务 |
| 角色定位 | 原专线的发布地址 | 现专线的发布地址 |
结论 :
机房出口线路由电信专线整体切换为移动专线 , 公网发布地址随之变更 ;
服务器内网 IP 与 Nginx 监听端口均未改动 , 变化只发生在运营商与防火墙这一层 ;
旧地址所属线路已拆机或映射已撤销 , 不会再恢复 ;
四、注意事项与避坑
本次排查沉淀出的实践清单 :
- 对外地址不要用检测网站查 : 检测网站只能反映出口 IP ; 想知道发布地址 , 唯一可靠途径是查防火墙 NAT 映射或问运营商 ;
- 出口 IP 不能写进任何配置 : 出口 IP 属于运营商地址池 , 存在变更可能 ; 把它写死到文档或客户端里 , 迟早出事 ;
- 旧公网 IP 要尽快清理引用 : 运营商撤下的地址日后可能重新分配给其他单位使用 ; 若客户端仍向旧地址发数据 , 存在数据误发风险 ;
- 本机测试公网地址不作数 : NAT 回环未开启时 , 内网测公网地址一律超时 , 极易误判为服务宕机 ; 验证服务本身用内网地址 , 验证外部可达性用外网设备 ;
- 建议尽早引入域名 : 给服务配一个域名 , A 记录指向发布地址 ; 以后再换线路只需改一次 DNS 解析 , 所有用户无感知 ;
- 不想自建域名也有商业方案 : 云厂商的 DDNS 动态域名解析 , CDN 加速域名等产品可以直接封装这一层 , 适合缺乏域名管理能力的团队 ;
总结
本文通过一次真实的机房网络排查 , 讲清了三个最容易被混淆的概念 : 出口 IP 是你出网时的身份 , 发布地址是别人访问你的门牌号 , 而 NAT 回环决定了内网测公网地址的局限性 ;
排查方法上 , 端口探测负责确认连通性 , RDAP 查询负责确认地址归属 , 两者结合即可快速定位 " 换线路 , 换 IP " 类问题 ;
最后再强调一次 : 对外服务地址以防火墙映射和运营商确认为准 , 检测网站的结果只能用于分析出网方向 ;