资讯动态

Linux网络排障核心:DNS、ICMP与NAPT详解与实战

发布时间:2026/10/6 8:35:41 来源:尧图企业网站定制
1. 为什么把DNS、ICMP、NAPT放在一起讲1.1 一台Linux服务器去上网要过哪三道关卡做Linux运维这些年我排查最多的网络问题不是业务代码本身而是网络层里的“老三样”——DNS解析、ICMP探测、NAT/NAPT转换。很多人把它们当成三个孤立的概念来背其实在日常工作中它们经常是一条链路里的三个环节。你在浏览器输入一个域名系统首先要通过DNS把这个域名“翻译”成IP地址这是第一关“找地址”数据从内网机器发往公网时如果这台机器用的是私网地址就要靠NAPT把源地址和源端口转换成公网地址和对应端口这是第二关“转流量”而中间出了故障你怎么判断网络通不通、走到哪一跳断了、数据包被谁丢了这时候就离不开ICMP这是第三关“探通路”。我经常跟团队里新来的同事说把这三件事串成一条线去理解Linux网络排障的基本功就算打了一半底子。这篇文章想做的就是把DNS、ICMP、NAPT三块内容完整拆开从配置、原理、抓包到故障排查结合我在实际服务器上折腾过的经验来讲。无论你是刚开始接触Linux的运维新人还是准备面试的开发者或是要独立把一台Linux配成网关、自建DNS服务器的老手都能在这篇里找到可以直接照抄的命令和配置。1.2 一个典型的“内网访问公网”场景长什么样先画一个我工作中最常见的拓扑一台Linux服务器一块网卡接内网比如192.168.1.1一块网卡接公网比如202.100.x.x内网的一堆PC和服务器都通过这台Linux上网。PC要访问一个公网域名时它的请求大概会经历这些步骤PC先向Linux上跑的DNS服务或者上游公共DNS发起解析请求查到目标公网服务器的真实IP。PC把数据包发给默认网关也就是Linux服务器的内网网卡IP。Linux服务器收到这台PC发来的包发现源地址是192.168.1.x这种私网地址不能直接路由到公网于是通过NAPT把源IP变成Linux服务器的公网IP把源端口映射成一个空闲的随机端口然后从公网网卡发出去。目标服务器回包时目的地是Linux服务器的公网IP加那个随机端口Linux再根据连接跟踪表反向查一下把包送回原来的那台PC。整个过程里DNS负责“把域名翻译成目标IP”NAPT负责“把私网源地址翻译成公网源地址”而一旦中途出问题你ping一下、traceroute一下用到的是ICMP。三者缺一环用户就会反馈“上不了网”“域名解析不出来”“时通时断”。所以我一直觉得这三个技术根本不应该分开学。下面我按顺序把每一块掰开揉碎地讲。2. DNS在Linux下的“四层皮”配置、缓存、排障、加固2.1 从输入域名到拿到IPLinux其实走了一条链很多人以为解析域名就是“查一下DNS服务器”但Linux系统内部其实有一条完整的解析链顺序错了结果就完全不一样。以最常见的glibc系统为例一次域名解析大致会经过/etc/hosts-/etc/nsswitch.conf里定义的解析顺序 -/etc/resolv.conf里指定的DNS服务器 - 系统缓存 - 上游DNS递归。先说/etc/hosts。这个文件里手工指定的“域名-IP”映射是优先度极高的几乎可以覆盖所有域名解析。有些人会在这里做内网域名映射也有些人会用它临时屏蔽某个域名把域名指向127.0.0.1。但它的问题是条目多了以后很难管理而且普通用户没法修改所以定位要清楚它只适合做少量、固定的主机映射。接下来是/etc/nsswitch.conf很多人不知道它的存在。它决定了系统按什么顺序去获取主机信息典型配置里有这么一行hosts: files dnsfiles表示先查/etc/hostsdns表示再走DNS。如果哪一天你改了/etc/hosts却不生效先去看是不是这行的顺序变成了dns files有时候系统某个服务会自动改掉这个配置。然后才是/etc/resolv.conf。传统情况下它里面写着nameserver比如nameserver 223.5.5.5 nameserver 114.114.114.114系统会按顺序选择DNS服务器发起查询。现代Ubuntu系统里这个文件往往是一个软链接指向systemd-resolved生成的stub解析器这也是很多人改完它重启后又“变回去”的根本原因。最后是缓存。systemd-resolved、dnsmasq、nscd都可以做DNS缓存。缓存在提升速度的同时也会带来“修改了DNS不生效”“域名换了IP还是解析到旧地址”的假故障。我处理过太多类似的工单第一反应基本都是先清缓存再谈其他。2.2 Ubuntu 22.04上改DNS最容易踩的几个坑Ubuntu 22.04默认使用netplan管理网络DNS又被systemd-resolved接管于是改DNS成了一件“看起来简单做起来容易翻车”的事。我见过最多的坑有三个改完/etc/resolv.conf重启失效、只改netplan但没应用、误删了resolv.conf软链接导致解析直接挂掉。先说最稳妥的做法如果你的网卡配置由netplan管理修改/etc/netplan/下的yaml文件在对应网卡里加上network: version: 2 ethernets: ens33: dhcp4: true nameservers: addresses: - 223.5.5.5 - 114.114.114.114然后执行sudo netplan apply。注意yaml文件的缩进非常严格一个空格错了都可能报错建议修改前先备份。如果系统没装netplan或者你是用NetworkManager管理的还可以直接改/etc/systemd/resolved.conf[Resolve] DNS223.5.5.5 114.114.114.114 FallbackDNS119.29.29.29保存后执行sudo systemctl restart systemd-resolved。验证是否生效用resolvectl status能看到当前每个网卡绑定的DNS服务器。还有一种情况是你临时想试一下某个DNS不想改任何文件那直接加一条命令sudo resolvectl dns ens33 223.5.5.5这是最轻量的方式重启后失效适合做对比测试。不论哪种方式改完务必用dig 新DNS 域名去验证一下不要只看配置文件里写了什么就以为生效了。顺带提一句很多人在Docker环境里遇到过容器内域名解析慢的问题这跟宿主机DNS其实是一套逻辑Docker守护进程默认从宿主的resolv.conf继承DNS如果宿主机配置了奇怪的DNS或者用了systemd-resolved的localhost stub容器内部解析就可能异常。可以在/etc/docker/daemon.json里显式指定{ dns: [223.5.5.5, 114.114.114.114] }然后重启Docker。这个做法就是“把上游DNS固定住”原理和Linux改DNS完全一样只是换了个配置文件的位置。2.3 dig、nslookup、getent排查DNS问题的一线命令说到排查DNS问题我最常用的命令不是ping域名而是dig、nslookup和getent三个命令干的活其实不一样。dig展示的是原始的DNS报文内容最直观。你看一个最简单查询dig www.example.com输出里重点看ANSWER SECTION里面有解析出来的IP看Query time判断解析耗时看SERVER确认是从哪台DNS服务器返回的。怀疑上游DNS有问题时可以直接指定服务器dig 223.5.5.5 www.example.com dig 114.114.114.114 www.example.com对比两组结果很快就能判断是“所有DNS都解析不了”还是“某一家的DNS有问题”。想跟踪完整递归过程用dig trace可以看到从根域名服务器到权威服务器的完整路径这个命令对理解DNS层级非常有帮助面试时讲解析流程也比背书生动得多。nslookup更老派但脚本里很好用加-debug参数可以看到详细的查询过程包括重试了几次。getent hosts 域名则跟前面提到的NSS机制相关它测试的是系统程序实际解析时会走的完整路径因为ping、curl这类程序是走glibc的NSS流程的而dig是直接发DNS请求的两者结果可能不一致。所以我的习惯是怀疑系统级解析问题时先getent hosts怀疑上游DNS内容问题时才dig 服务器。再补充两个运维场景。第一个是查看本地DNS缓存systemd-resolved可以用resolvectl statistics看缓存命中统计想清空缓存就sudo resolvectl flush-caches。第二个是抓包看DNS报文tcpdump -i eth0 port 53 -nn -vv能看到请求发给谁、响应返回了什么这是判断“是不是有设备在劫持DNS”的最硬核手段。2.4 自建DNS服务器dnsmasq与bind9怎么选讲到“自己搭建DNS服务器”很多人第一反应是装bind9其实大多数场景根本用不上。我自己的经验是小型局域网、嵌入式网关、临时缓存加速用dnsmasq就够了正式的权威解析、多域管理、复杂ACL才需要bind9。dnsmasq的配置文件是/etc/dnsmasq.conf核心就几项listen-address192.168.1.1 resolv-file/etc/resolv.dnsmasq.conf cache-size1000 address/internal.lan/10.0.0.5它既能做缓存DNS又能配置内网域名解析还能把某个域名直接解析到指定IP也就是address这一行非常适合作网关设备。很多家用路由器、嵌入式Linux里的DNS功能底层跑的就是dnsmasq。好处是轻量、内存占用小、配置简单缺点是权威区域管理和权限控制比较弱。bind9更适合正经的域名服务。生产环境里我一般会在/etc/bind/named.conf.options里设置递归白名单避免被外部滥用options { directory /var/cache/bind; recursion yes; allow-query { 10.0.0.0/8; 192.168.0.0/16; }; allow-recursion { 10.0.0.0/8; 192.168.0.0/16; }; forwarders { 223.5.5.5; 114.114.114.114; }; dnssec-validation auto; };这里面最关键的一点是限制递归查询来源。如果你不做限制任何人都能用你的DNS服务器做递归解析轻则被当成肉鸡DDoS放大器重则被运营商拉黑IP这是我踩过的最深的坑。自建DNS还有一个常见用途给内网服务提供稳定的域名入口比如内网GitLab、NAS、监控平台配好之后不再依赖外部DNS长期用下来明显比在/etc/hosts里堆条目稳定得多。2.5 用DNS做安全防线恶意域名过滤的正确姿势DNS不只能解析域名也是一道非常有价值的安全防线。现实中很多攻击流量会跟恶意域名做通信比如C2回连、挖矿脚本下载、勒索软件请求等。把恶意域名在DNS层面“拆掉”往往比在防火墙上封IP更彻底因为域名会变IP但域名本身的特征很难变。我之前遇到过一个典型的黑产反复攻击场景服务器被植入了一个恶意脚本会定期向外网某个可疑域名发起请求。处理步骤大致是先在网络层把可疑目标的IP通过iptables drop掉阻断最直接的通信然后在DNS层把该域名解析到黑洞地址比如返回0.0.0.0或者NXDOMAIN让依赖域名解析的攻击代码找不到目标同时翻系统日志、抓包定位脚本是怎么进来的、改了哪些文件最后做主机加固清掉计划任务、SSH公钥和异常用户再在WAF或者IDS里加上对应的规则防止下次再进来。这里要强调的是DNS过滤只能防“依赖域名解析”的那一类攻击如果攻击代码直接写死IP通信光靠DNS就拦不住了必须配合网络层封禁。所以安全处理一定要分步骤联动而不是只做一个动作。另外生产环境的DNS服务器上还可以启用DNSSEC验证防止DNS缓存投毒这个基础安全项在自建DNS时建议直接开启。3. ICMP协议ping通了不等于网络没问题3.1 ICMP报文里到底装了什么ICMP全称是Internet Control Message Protocol很多人把它看作是“网络自带的报错与诊断工具”。它并不像TCP/UDP那样承载业务数据而是封装在IP报文里专门用来传递控制信息和差错报告。在IP头里ICMP的协议号是1你抓包时如果看到IP层里有一个“Protocol: ICMP (1)”的字段那就是它。ICMP报文结构比TCP简单得多头部就三块类型Type、代码Code、校验和Checksum后面跟着的是具体数据内容。光一个类型字段就能区分很多种用途我列几个最常碰到的类型代码含义常见场景00Echo Replyping的回复80Echo Requestping的请求30Destination Network Unreachable网络不可达31Destination Host Unreachable主机不可达33Port Unreachable端口不可达110Time Exceeded数据包TTL超时130Timestamp Request时间戳请求常见于安全扫描搞懂类型和代码的对应关系看抓包分析就能少很多迷惑。比如traceroute能逐跳显示路由器靠的就是“Time Exceeded”类型你访问某台服务器的某个端口不通返回“Port Unreachable”说明路由是通的问题出在目标机器的端口上。这比直接用“网络不通”四个字去排查要精确得多。3.2 ping与traceroute背后的机制很多人理解是错的ping命令是最常见的ICMP应用。它发送一个Type8的Echo Request报文目标是主机收到后返回一个Type0的Echo Reply报文。Linux下默认的ping会持续发送所以脚本里记得加-c指定次数比如ping -c 4 223.5.5.5。常用参数还有-i控制发送间隔、-s指定payload大小、-I指定源IP。判断网络是否通畅重点看有没有回复以及时间RTT稳不稳、有没有丢包。但很多人把“ping通了”等同于“业务正常”这是大忌。ICMP只证明了IP层可达不代表TCP端口能连上更不代表应用层正常。我自己排障时遇到过太多这样的场景用户说“外网不通”我ping域名能通但curl一直卡住最后发现是防火墙把TCP 443端口给DROP了ICMP倒是放行的。所以结论还是那句话ping不通网络大概率有问题ping通了只能说明三层通不能说明二到七层没问题。traceroute的原理比ping更巧妙值得展开讲。它利用IP报文里的TTL生存时间字段每经过一个路由器TTL减1减到0时路由器会回一个“Time Exceeded”的ICMP报文。traceroute先发一个TTL1的探测包第一个路由器收到后TTL变0被迫回复“超时”于是traceroute记录下第一个跳的IP再发TTL2的包第二个路由器回复这样逐跳增加TTL就能把整条路径上的每一跳都给“逼问”出来。Linux版本默认用UDP探测包发往高端口33434开始Windows的tracert默认用ICMP的Echo Request所以跨系统对比路径时看到结果有差异不要觉得奇怪。3.3 Wireshark抓ICMP包手把手解析一个echo请求抓包永远是理解协议最直观的方式。我常用的组合是PC上开Wireshark过滤框输入icmp然后在终端里执行ping baidu.com再回来看捕获的报文。这里提一句很多人都知道过滤icmp但不知道怎么进一步过滤某个类型比如只想看echo请求就输入icmp.type 8只想看echo回复就输入icmp.type 0。实际点开一个Echo Request报文你会看到三层信息。第一层以太网头能看到源MAC和目的MAC。第二层IP头注意里面有个很重要的字段叫TTLLinux默认发出的ping包TTL通常是64Windows通常是128这也是为什么网上经常有人靠TTL初值猜测对方系统类型。第三层才是ICMP头Type8表示请求Identifier和Sequence Number用于匹配请求与回复我实际操作时经常会去看这两个值因为多台机器同时ping的时候就是靠它们区分报文到底是哪台机器发出的。如果是wireshark没有纯命令行环境用tcpdump也一样能看sudo tcpdump -i eth0 icmp -nn输出里可以看到类似这样的内容IP 192.168.1.10 223.5.5.5: ICMP echo request, id 1, seq 1, length 64 IP 223.5.5.5 192.168.1.10: ICMP echo reply, id 1, seq 1, length 64一条是请求一条是回复id和seq能对上说明ping是通的。抓包最大的好处是能把“我以为的”变成“实际的”比如之前有人报告ping不通某台服务器我抓包一看请求发出去了回复也回来了但ICMP报文在网络中间被人为丢掉了。这种情况单看命令行永远只能看到丢包问题定位就会跑偏。3.4 ICMP的安全风险时间戳探测、ping flood与隧道ICMP是诊断工具也是攻击面。至少有三个风险点是网络加固时必须考虑的。第一个是ICMP时间戳请求Type13。它本来是让主机回复当前时间的但攻击者可以利用它探测主机存活状态、校正时间、甚至在特定场景下泄露系统运行时间信息。我做Windows Server 2012安全整改的时候就经常接到要求“关闭ICMP时间戳响应”。Windows上可以通过防火墙的高级入站规则阻止“Core Networking - ICMPv4-In”里的Timestamp RequestLinux上则可以通过iptables直接丢弃这类报文或者在内核参数里忽略异常ICMP报文。这类整改看起来很小等保测评和红队评估里却很常见。第二个是ping flood攻击也就是大量Echo Request涌入目标机器消耗带宽和CPU属于DDoS的一种简单形态。防护思路是不让外部直接ping自己生产环境我一般会在防火墙把入站的echo request丢弃但保留一种例外允许“内网主动发起的ping返回”。也就是说别人ping不进你但你可以ping出去。这个用iptables的-m state --state ESTABLISHED逻辑就能实现只放行已有连接关联的回复。第三个是ICMP隧道。攻击者可以把数据封装在ICMP payload里穿透只放行ICMP的防火墙让恶意流量看起来像普通的ping请求。这类行为靠单纯的“禁ping”防不住需要配合流量审计看ICMP报文的大小是否异常、频率是否规律。遇到内网上线的新设备疯狂发ICMP包不要只当它是“误报”先抓包看几眼再说。4. NAPT技术一台Linux如何让整个内网上网4.1 公网IPv4不够用之后NAPT解决了什么与代价IPv4公网地址只有四十多亿个全球设备数量早就远超这个数。于是就有了NATNetwork Address Translation网络地址转换这类技术把私网地址映射成公网地址后再访问外部网络。NAT有几种形态静态NAT是一对一映射适合需要被外部访问的服务器动态NAT是把一组公网IP映射给多个私网设备但同一时刻每个私网设备独占一个公网IP而NAPTNetwork Address Port Translation网络地址端口转换更进一步允许“多对一”映射。形象的类比是这样一个公司只对外公布一个总机号码员工外呼时总机分配一个内部专线分机外部回电话时就拨总机号码加分机号总机再找到对应的员工。NAPT就是这个总机公网IP是总机号码端口号就是分机号。多台私网机器同时上网时NAPT把不同的源端口动态分配给不同的内网设备于是只需要一个公网IP就能支撑成百上千台设备的出站访问。NAPT解决了地址短缺问题但代价也要讲清楚。第一外网主动访问内网变得困难因为对外只暴露一个IP加一堆动态端口外部设备根本不知道请求应该发给谁所以需要端口映射DNAT才能让外网主动访问内网服务。第二NAPT会改写数据包里的IP和端口对一些要求端到端透明的协议不友好例如IPsec、部分P2P应用、FTP的主动模式等处理不好就会变成“连不上”。第三NAPT依赖连接跟踪表表的容量和老化时间直接决定了网络的并发能力。4.2 conntrack是理解NAPT的钥匙NAPT在Linux里的实现离不开一个关键模块连接跟踪conntrackconnection tracking。简单说Linux内核会为每一条经过NAT的会话建立一张表项记录这条连接的原始五元组源IP、源端口、目标IP、目标端口、协议和转换后的五元组以及当前连接的状态。回程的数据包到了之后内核就靠查这张表确定应该转给哪台内网机器。实际查看连接跟踪表可以读/proc/net/nf_conntrack这个虚拟文件也可以用conntrack命令比如sudo conntrack -L每行记录大概长这样tcp 6 431999 ESTABLISHED src192.168.1.100 dst180.101.50.242 sport45678 dport443 src202.100.x.x dst192.168.1.100 sport443 dport45678 [ASSURED] mark0 use1前面的src和sport是内网机器的原始地址和端口中间的是转换成公网地址后的数据最后是回程对应的逆向映射。看到这里你就明白NAPT为什么能同时撑那么多连接只要映射出去的“公网IP端口”组合不冲突两条连接到同一个目标IP的同一端口也能被区分开。连接跟踪表不是无限大的它由内核参数控制。常见的调优项有这么几个net.netfilter.nf_conntrack_max 65536 net.netfilter.nf_conntrack_tcp_timeout_established 432000 net.netfilter.nf_conntrack_udp_timeout 30 net.netfilter.nf_conntrack_icmp_timeout 30当表满了之后新连接会直接失败现象就是“网络突然断了重启后又恢复”。排查这类问题先看dmesg | tail里有没有nf_conntrack: table full, dropping packet这样的报错然后调整nf_conntrack_max并确认系统内存是否足够。这是我排过最多的NAT故障之一。调试NAPT还有一个很实用的工具链ss -tnp查看本机端口占用iptables -t nat -L -n -v查看NAT规则命中次数再加上conntrack表基本能覆盖绝大多数排查场景。4.3 iptables/nftables实现NAPT最常用的几条命令Linux做NAPT绕不开的就是netfilter框架。传统写法用的是iptables新系统里越来越多的是nftables但命令逻辑是相通的。我给一个最少必要配置大家可以直接抄第一步开启内核转发。没有这一步Linux收到内网网卡的数据包后根本不会把它发往公网sudo sysctl -w net.ipv4.ip_forward1想永久生效写到/etc/sysctl.conf或者/etc/sysctl.d/99-forward.conf里内容一行net.ipv4.ip_forward 1第二步设置NAT规则。最常用的两种写法一种是固定公网IP用SNATiptables -t nat -A POSTROUTING -s 192.168.1.0/24 -o eth0 -j SNAT --to-source 202.100.x.x另一种是公网IP是动态获取的比如PPPoE拨号用户公网IP可能变用MASQUERADE更省心iptables -t nat -A POSTROUTING -s 192.168.1.0/24 -o eth0 -j MASQUERADEMASQUERADE会自动从出口网卡上取当前IP做转换不需要手写具体地址所以IP变了也不用改规则代价是会稍微多一些开销。第三步放行FORWARD链。很多人在NAT配置好了之后内网还是上不了网十有八九是FORWARD链默认策略是DROP。要增加两条iptables -A FORWARD -i eth1 -o eth0 -m state --state RELATED,ESTABLISHED -j ACCEPT iptables -A FORWARD -i eth0 -o eth1 -j ACCEPT第一条允许“从外面回来、属于已有连接”的报文进入内网第二条允许内网发出的报文出去。这里要强调-m state --state RELATED,ESTABLISHED非常重要不能省略否则内网机器发出去的包可以出去但外部回包进不来实际效果就是“单向通”。如果用的是更现代的Debian系新版系统nftables写法类似nft add table nat nft add chain nat postrouting { type nat hook postrouting priority 100; } nft add rule nat postrouting ip saddr 192.168.1.0/24 masquerade核心逻辑跟iptables完全一致只是语法换了风格。不管用哪种工具做完之后都建议用iptables -t nat -L -n -v看规则命中计数有没有流量匹配到规则一眼就能看出来。4.4 NAPT常见故障表满、NAT回流、存量连接断开用了这么多年NAPT我把遇到过的典型故障归纳成四类每一种都有固定的排查套路。第一类能出去、回不来。现象是内网机器ping公网IP有去无回。排查时先看FORWARD链的ESTABLISHED规则是不是写反了再看conntrack表里有没有对应条目。如果表里有条目但回包还是进不来就要抓包看回包到达Linux服务器时的目标IP和端口是不是跟NAPT映射的完全对应。这里有一个很容易错的地方在PREROUTING链做了DNAT的回包会自动走反向转换如果你在POSTROUTING链又重复做SNAT就可能造成回包源地址和连接跟踪不匹配被内核丢包。第二类conntrack表满。现象前面说了新连接全失败老连接还能坚持一阵。临时缓解是先改大nf_conntrack_max并清空一次表sudo sysctl -w net.netfilter.nf_conntrack_max262144 sudo conntrack -F根治思路是找为什么连接数会这么大是正常业务高峰是攻击扫描还是NAT老化时间太长导致表里堆满了僵尸连接如果是僵尸连接太多可以把TCP和UDP的超时时间调短同时让内网应用主动复用连接减少新建连接的频率。第三类NAT回流问题。内网用户用公网域名访问内网自己发布的Web服务结果访问不通。原因在于内网机器发往公网域名的包经过NAPT转换后从公网口出去了可目标服务器的回应又因为目标IP指向公网地址绕回NAT设备时conntrack无法正确把流量导回原来的内网机器。解决办法有三种一是做hairpin NAT让NAT设备在内部直接转发这个流量二是用DNS视图让内网用户解析到内网IP直接走内网访问三是在PREROUTING链对目标IP做DNAT到内网服务地址。我最推荐的是第二个方案简单可靠性能也好。第四类存量连接在NAT规则变更后全部断开。比如重新加载了iptables规则、重启了iptables服务或者清空了conntrack表这个比较常见因为Linux的NAT规则和conntrack表是联动的规则一变已有连接要么被丢弃要么被重置。所以生产环境里修改NAT规则要尽量在维护窗口执行先备份规则改完规则后用conntrack -L确认现有业务连接是否还在不要为了改一条规则把线上连接全打断。4.5 Linux共享上网实操从网关配置到验证讲完理论给一套可以直接照抄的共享上网完整方案。假设Linux服务器内网网卡是eth1IP 192.168.1.1公网网卡是eth0拨号或者静态IP都可以下面按顺序来检查内核是否支持转发功能执行sysctl net.ipv4.ip_forward如果不是1就设置。有的内核默认开启IPv6转发但IPv4没有所以一定要单独确认。配置内网网卡地址如果网卡还没有静态IP用netplan或者ip命令配置都行关键是网关机器的内网IP要固定在最前面几位方便内网设备填默认网关。然后是NAT规则公网IP固定就选SNATIP会变就选MASQUERADE。我这种拨号环境的机器几乎都用MASQUERADE。再设好FORWARD链放行规则上面已经给了命令。最后再做一个很重要的小细节给内网设备分配DNS。如果局域网里没有自建DNS可以在dnsmasq里加个配置统一指向上游简单一点直接在客户端把DNS指到223.5.5.5这种公共DNS但这样要求内网设备得有外网权限。想省心的话在Linux网关上跑一个dnsmasq监听内网口把上游指向公共DNS这样内网设备的DNS就填192.168.1.1既能解析外网域名以后要加内网域名解析的时候也方便。配置完成后的验证步骤我喜欢按这个顺序走先在Linux本机上ping 223.5.5.5确认公网口有网再让内网某台PC设置网关和DNS先ping 192.168.1.1确认内网能到网关然后ping 223.5.5.5确认NAPT转发生效最后dig www.baidu.com确认DNS解析正常。如果中间某一步挂了基本就能定位到大致的故障范围不用东查西查。5. 一次真实的故障排查实录DNS、ICMP、NAPT一起上5.1 故障现象与初步判断全网“上不了网”其实是假象聊了这么多理论不如拿一个真实案例收一收。有一回接手一个办公网的“网络报障”内网PC普遍反映网页打不开但企业微信这种即时通信软件却偶尔能用。我第一反应就是这么奇怪的现象说明“所有网络都断了”是假象可能是域名解析挂了部分软件因为内置了IP直连或者有本地缓存的IP所以还能跑。这正是DNS问题的典型特征IP通信还有但域名解析不行。为了快速核实我在一台内网PC上做了四个动作第一ping 网关通第二ping 223.5.5.5这个公网IP通说明NAPT和路由没问题第三nslookup www.baidu.com提示超时这就把矛头指向了DNS第四用nslookup www.baidu.com 223.5.5.5直接指定公共DNS查询居然也是超时。当时我就判断问题多半不在局域网内的DNS服务器而是整条出口到外部的UDP 53端口流量都被拦截了。后来在网关上抓包tcpdump -i eth0 udp port 53 -nn发现查询包发出去了但没有任何回应包进来。最后查到是出口防火墙策略误伤把目的端口为53的UDP报文当成了风险流量直接丢弃。把策略改回放行后域名解析立刻恢复。这类“全网断网”的报障排查顺序记住一句口诀先通不通再能不能解析。先ping网关、再ping公网IP、最后解析域名每一步都能把故障范围缩小一半。DNS超时和网络完全不通的区别单靠浏览器是判断不出来的必须自己动手分层测。5.2 分层排查的完整流程三层法我把上面这个案例抽象成一套可以复用的三层排查流程。第一层物理和数据链路层。看网卡状态ip link看是否up有没有RX/TX错误计数网线或Wi-Fi是不是稳定。交换机端口如果有大量CRC错误优先怀疑网线或光纤模块问题。这一层很多人跳过了但恰恰是“时通时断”问题的高发区因为三层以上一切都是正常的却因为二层丢包导致应用层表现异常。第二层网络层和NAT。在出问题的PC上ping 网关通了说明二层和三层的本地路由没问题然后ping 公网IP通说明NAPT转发、防火墙FORWARD、出口路由基本正常。这一步如果失败就要去Linux网关上iptables -t nat -L -n -v查NAT规则命中次数cat /proc/sys/net/ipv4/ip_forward查转发开关conntrack -L | wc -l看连接表是否已满。第三层DNS和应用层。nslookup解析域名dig 公共DNS 域名指定公共DNS测试对比是不是某个DNS服务器的问题再curl -I http://域名看HTTP响应。这一层真正对应了用户感知的“能用还是不能用”。三层法最大的价值不是技术高深而是让排查有次序、有边界不瞎猜。5.3 问题根因与修复定位到防火墙策略回到那个案例根因是出口防火墙策略误伤UDP 53。修复动作说起来简单在防火墙策略里放行内网到公共DNS服务器的UDP 53流量并把日志加上方便以后审计。但真正有价值的是复盘为什么策略会误伤因为最初写策略的人把“所有出UDP流量”一刀切地限制了只放行了一些特定端口没考虑DNS用的就是UDP 53。这类问题在Linux系统里同样常见比如你写iptables规则时只放行了TCP端口忘了UDP那内网设备虽然能正常上网但一解析域名就卡死现象和这个案例一模一样。修复后我还在网关和公共DNS之间做了一次连通性验证nc -uvz 223.5.5.5 53虽然UDP的“连通”判断不太可靠但只要出口有回包就说明UDP 53链路是通的再跑一次ping 域名确认解析恢复。这种“先网络后服务、先系统后应用”的思维其实每个运维都会用只是遇到压力时容易乱建议大家把三层法写进自己的排障手册。5.4 这个案例教会我的排查习惯每次复盘我都会跟同事强调两个习惯。第一个习惯是不要只听现象描述要自己动手分步骤复现。用户能告诉你的只是“网页打不开”但网页打不开的原因可能有几十种必须靠命令一层层往下逼。第二个习惯是排查网络问题一定要把“缓存”这个变量考虑进去。当时如果我先在内网PC上清了浏览器缓存、清了系统DNS缓存可能就能更快地发现“不是解析不了而是解析结果有误”这一层能少走很多弯路。有些问题在使用dig指定的公共DNS时表现正常但系统默认DNS却解析异常这种就高度怀疑是DNS服务器配置或者本地缓存问题。遇到这种情况直接把DNS临时改成公共DNS测试一次是效率最高的动作。而我个人更倾向于在Linux网关上给内网设备统一下发稳定的DNS并且把systemd-resolved的缓存清空命令教给值班同事毕竟故障排查中“想当然地认为某个环节没问题”才是最大的问题。6. 相关面试题、常用命令与我的个人建议6.1 Linux网络排查命令速查表这篇文章里提到的命令我整理成一个速查表干活时贴在手边很方便排查目标常用命令关键输出本机IP/网卡状态ip addr、ip linklink state、inet地址路由表ip route、route -n默认网关、出口网卡端口监听ss -tlnp、netstat -tunlp监听IP和进程连通性测试ping -c 4 目标IP通断、丢包、RTT路径测试traceroute -n 目标IP每一跳的延迟与IPDNS解析dig short 域名、nslookup 域名解析结果、查询耗时NSS测试getent hosts 域名系统实际解析路径抓包tcpdump -i eth0 port 53、tcpdump -i eth0 icmp报文内容NAT规则iptables -t nat -L -n -v规则命中计数连接跟踪cat /proc/net/nf_conntrack、sudo conntrack -L会话条目内核转发sysctl net.ipv4.ip_forward是否等于1防火墙规则iptables -L -n -v策略和命中计数命令不用全背只要知道“想看什么用哪条”就行。真正干活的效率来自熟练度建议大家在测试环境多抓几次包、多清几次conntrack用多了自然就记住了。6.2 面试经常会问到的三个“魔鬼细节”第一个问题讲一下一次完整的DNS解析过程。很多人的回答停留在“客户端问DNS服务器DNS返回IP”但真正的完整流程要区分递归和迭代。客户端向本地DNS服务器发起递归查询本地DNS服务器若没有缓存就替客户端去问根域名服务器根服务器告诉它“去问com域的权威服务器”然后再去问com域的权威服务器它再指向目标域名的权威服务器最后拿到A记录。这个过程面试官真正想听的不是背出这个链条而是你能把dig trace的输出对应到每一层。我建议准备面试的朋友拿一个真实域名跑一遍dig trace你会看到从根到权威的完整路径印象会非常深。第二个问题ping通了TCP连接却失败可能的原因是什么这个问题考察的是“网络分层”思维。ICMP只代表IP层可达TCP连接还需要经过三次握手所以可能的根因包括对端防火墙丢弃了TCP SYN报文、目标服务本身没监听对应端口、中间设备做了TCP粒度限制、或者MTU导致大包被丢弃。如果面试者能说出“ping只看三层TCP要看四层”这个点基本就算合格了。第三个问题一台服务器只有一个公网IP为什么能让几百个内网用户同时访问外网这个问题考察的就是NAPT。关键在于端口复用不同内网用户访问同一个外部IP时NAPT会把它们的源端口映射成不同端口所以外部服务器返回数据包时根据目标端口就能区分是哪个用户的请求再由连接跟踪表还原给对应的内网机器。面试时再加上“如果端口不够用、连接跟踪表满会发生什么”的延伸就能很自然地体现出实操深度。6.3 我给刚入行的人提几个实在建议从我做Linux运维的体感来说网络这块不是靠看书学会的而是靠一个个故障“喂”出来的。所以我建议大家刻意给自己安排一些实验找两台虚拟机一台当网关一台当内网PC自己把NAT配一遍然后用tcpdump抓包看连接建立过程自己改坏一次resolv.conf体验一下“什么都上不了网”的感觉再动手修好自己开一台dnsmasq给局域网内一个自定义域名做解析看看返回结果跟外部DNS有什么不同。这些实验做完之后DNS、ICMP、NAPT就不再是书本上的抽象名词而是脑子里实实在在的网络模型。还要提醒一点网络排障一定要懂得“留证据”。不要等出问题的时候才想起来抓包平时就要养成习惯修改配置前备份原文件操作命令前记录当前状态出现故障第一时间保留dmesg、conntrack -L、iptables -L -n -v的输出。很多问题事后复盘时缺少当时的现场状态就只能靠猜。我吃过的亏已经不少了希望大家不要再重复踩这个坑。最后再分享一个我个人的小技巧排查DNS问题时不要只测一个域名。很多设备的DNS策略对常见大域名和冷门域名结果不一样多测几个不同域名的解析比单测一个更接近真实用户感受。与之类似排查NAPT问题时不要只看当前一条连接要看整体连接数、表容量和老化超时很多间歇性网络故障的根因都藏在“量”上。这套“DNS、ICMP、NAPT”的组合拳我不敢说能解决所有网络问题但至少能覆盖掉我日常遇到的八成以上希望对你有用。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑