3. TFTP服务器故障:传输超时、文件权限、SELinux/AppArmor拦截、防火墙规则
TFTP这玩意儿,看着简单,坑却不少。我见过太多人卡在PXE启动的最后一步——明明DHCP都拿到了,文件也传了,结果客户端就是报“TFTP timeout”。说白了,TFTP就是网络启动的最后一公里,这公里要是断了,前面全白干。
咱们今天就把TFTP的四大拦路虎挨个捋一遍:传输超时、文件权限、SELinux/AppArmor、防火墙。嗯,按这个顺序排查,基本能解决90%的问题。
核心思路:TFTP故障排查遵循“网络可达 → 服务运行 → 文件可读 → 安全策略放行”的递进逻辑。别一上来就改SELinux,先看看ping通没。
3.1 传输超时:别急着怪网络
TFTP传输超时,客户端报“Timeout”或“Transfer timed out”。很多人第一反应是网络不通。其实不然。我遇到过好几次,ping包正常,tftp命令也能连上,但传大文件就超时。
为什么会这样?TFTP基于UDP,没有拥塞控制。默认超时时间一般是5秒,重试次数5次。如果丢包率稍微高一点,或者服务器响应慢,就容易超时。
我的排查习惯:先用 tftp 服务器IP -c get 小文件 测试,比如传一个1KB的文本文件。如果小文件能传,大文件超时,基本可以锁定是网络丢包或服务器性能问题。
常见原因和解决思路:
- 网络丢包:检查交换机端口、网线、网卡协商速率。用
mtr或ping -f看丢包率。 - 服务器负载过高:TFTP是单线程的,并发请求多时会排队。我建议用
atftpd或dnsmasq的TFTP模块,它们支持多线程。 - MTU问题:TFTP默认块大小512字节,如果网络中间设备限制了MTU,可能导致分片丢失。可以尝试调整块大小(
blksize选项)。 - 客户端超时设置过短:有些PXE ROM的TFTP超时设置只有3秒。这个改不了,只能优化服务器响应速度。
注意:不要盲目增大TFTP超时时间。TFTP的重试机制是线性的,超时太长会导致整个PXE启动过程变慢。我见过有人把超时设成30秒,结果一次启动要等2分钟。
3.2 文件权限:TFTP的“读不到”陷阱
TFTP服务通常以 tftp 或 nobody 用户运行。如果引导文件(如 pxelinux.0、vmlinuz)的权限设置不对,客户端能连接但读不到文件。
我记得有一次帮客户排查,他们死活说TFTP没问题,文件也在目录里。我过去一看,ls -l 显示文件权限是 600,属主是root。TFTP进程根本读不了。
正确的权限设置:
- TFTP根目录:
755(drwxr-xr-x) - 引导文件:
644(-rw-r--r--) - 目录属主:可以是root,但必须保证
other有读和执行权限
检查命令:
# 查看TFTP根目录权限
ls -ld /var/lib/tftpboot/
# 递归检查文件权限
find /var/lib/tftpboot/ -type f -exec ls -l {} \;
# 如果权限不对,批量修复
chmod -R 644 /var/lib/tftpboot/*.0
chmod -R 644 /var/lib/tftpboot/*.cfg
chmod 755 /var/lib/tftpboot/
避坑指南:我曾经把 pxelinux.cfg 目录设成了 700,结果客户端能拿到引导文件,但读不到配置文件,启动到一半卡住。排查了半小时才发现是目录权限问题。记住:目录必须有 r-x 权限。
3.3 SELinux/AppArmor拦截:看不见的墙
这是最容易被忽略的问题。SELinux或AppArmor会在后台默默拦截TFTP的读写操作,而系统日志里可能只有一条模糊的“denied”信息。
我个人的习惯是:在RHEL/CentOS上配TFTP,第一件事就是检查SELinux状态。
SELinux相关命令:
# 查看SELinux状态
getenforce
# 查看TFTP相关的SELinux布尔值
getsebool -a | grep tftp
# 常用布尔值设置
setsebool -P tftp_home_dir on
setsebool -P tftp_anon_write on
# 查看审计日志
ausearch -m avc -ts recent | grep tftp
sealert -a /var/log/audit/audit.log | grep tftp
AppArmor相关命令(Ubuntu/Debian):
# 查看AppArmor状态
aa-status | grep tftp
# 查看TFTP配置文件
cat /etc/apparmor.d/usr.sbin.tftpd
# 临时禁用(不推荐生产环境)
aa-disable /usr/sbin/tftpd
# 重新加载配置
systemctl reload apparmor
| 安全模块 | 典型错误日志 | 快速解决 |
|---|---|---|
| SELinux | avc: denied { read } for pid=... comm="tftpd" |
setsebool -P tftp_home_dir on |
| AppArmor | audit: type=1400 apparmor="DENIED" |
修改 /etc/apparmor.d/usr.sbin.tftpd 添加路径规则 |
警告:生产环境不要直接 setenforce 0 关闭SELinux。正确做法是调整TFTP相关的布尔值,或者给文件打上正确的SELinux上下文标签:chcon -R -t tftpdir_t /var/lib/tftpboot/。
3.4 防火墙规则:UDP 69的“隐形杀手”
TFTP使用UDP 69端口。防火墙规则如果没放行,客户端连都连不上。但这里有个坑:TFTP的数据传输会使用随机高位端口(通常是UDP 1024以上),如果防火墙只开了69端口,数据传输阶段会失败。
我遇到过最典型的情况:客户端能连接,能发起请求,但传了几百KB就卡住。一看防火墙,只开了UDP 69,没开高位端口。
防火墙配置示例:
firewalld(RHEL/CentOS 7+):
# 添加TFTP服务(包含69端口和高位端口)
firewall-cmd --add-service=tftp --permanent
firewall-cmd --reload
# 或者手动添加端口
firewall-cmd --add-port=69/udp --permanent
firewall-cmd --add-port=1024-65535/udp --permanent
firewall-cmd --reload
iptables:
# 允许TFTP控制端口
iptables -A INPUT -p udp --dport 69 -j ACCEPT
# 允许TFTP数据传输端口(根据TFTP服务器配置调整)
iptables -A INPUT -p udp --dport 1024:65535 -j ACCEPT
ufw(Ubuntu):
ufw allow 69/udp
ufw allow proto udp from any to any port 1024:65535
我的建议:如果安全要求高,不想开放所有高位端口,可以配置TFTP服务器使用固定端口范围。比如 atftpd 的 --port-range 20000:20100 参数,然后防火墙只开放这个范围。
3.5 综合排查清单
遇到TFTP故障,按这个顺序查,基本不会漏:
- 网络层:客户端能ping通服务器吗?用
tftp命令手动测试连接。 - 服务层:
systemctl status tftp服务是否运行?ss -tuln | grep :69端口是否监听? - 文件层:文件存在吗?权限是644吗?路径对不对?
- 安全层:SELinux/AppArmor是否拦截?查看
ausearch或aa-status。 - 防火墙层:UDP 69放行了吗?高位端口放行了吗?
终极调试命令:
# 在服务器端抓包,看客户端请求是否到达
tcpdump -i any port 69 -nn -X
# 在客户端抓包,看服务器是否响应
tcpdump -i any port 69 or portrange 1024-65535 -nn
抓包能直接告诉你:是请求没到,还是响应被丢了。这是最直接的证据。
好了,TFTP这部分就这些。说白了,就是网络、服务、文件、安全、防火墙这五层。一层一层剥开,问题跑不掉。下一层咱们聊聊DHCP和TFTP的联动问题,那个更绕,但更有意思。