3. TFTP服务器搭建:从原理到排障

TFTP这玩意儿,说白了就是简化版的FTP。它走UDP 69端口,没有认证,没有目录列表,功能单一到极致——就干一件事:读文件或写文件。但恰恰是这种“傻”,让它成了网络启动场景里的标配。想想看,PXE客户端在内存里刚拉起网卡驱动,哪来的精力去处理复杂的TCP握手和用户认证?

我在早期做无盘工作站项目时,就被TFTP的“简单”坑过好几次。嗯,今天咱们把这层窗户纸捅破,从原理到实战,再到那些让人抓狂的报错,一次性讲透。

3.1 TFTP协议原理:为什么它这么快?

TFTP(Trivial File Transfer Protocol)基于UDP,数据包固定512字节(最后一块不足512字节表示传输结束)。它的核心机制是停等协议——发一个数据块,等一个ACK,再发下一块。

关键特性一览:

  • 传输模式:octet(二进制)或netascii(文本)
  • 端口:UDP 69(监听),数据传输使用临时端口(1024以上)
  • 无认证、无加密、无目录浏览
  • 最大文件大小:32MB(理论值,实际受块号16位限制)

你可能会问:“停等协议效率多低啊?”没错,在局域网里这根本不是问题。PXE启动时传输的通常是内核镜像(vmlinuz)和initrd,加起来也就几十MB,毫秒级就传完了。我见过有人非要在TFTP上跑几百MB的ISO文件,结果超时重传搞到崩溃——那是用错了工具。

TFTP 停等协议交互流程 PXE客户端 TFTP服务器 ① RRQ (读请求, 端口69) ② DATA#1 (512字节, 临时端口) ③ ACK#1 ④ DATA#2 (512字节) ⑤ ACK#2 最后一块 < 512字节 → 传输结束;超时未收到ACK → 重传

3.2 安装与配置tftpd-hpa

Linux下TFTP服务器有好几个流派:tftp-hpa、atftpd、dnsmasq(内置TFTP)。我个人习惯用tftpd-hpa,它是H. Peter Anvin维护的版本,跟PXE生态配合最默契。

3.2.1 安装

# Debian/Ubuntu
sudo apt update
sudo apt install tftpd-hpa tftp-hpa

# CentOS/RHEL 7/8
sudo yum install tftp-server tftp
# 或
sudo dnf install tftp-server tftp

# 启动并设置开机自启
sudo systemctl enable --now tftpd-hpa

小提示:tftp-hpa是客户端工具,tftpd-hpa是服务端。两个都装上,方便本地自测。

3.2.2 配置文件

主配置文件在 /etc/default/tftpd-hpa(Debian系)或 /etc/xinetd.d/tftp(RedHat系)。我直接给你看最常用的配置模板:

# /etc/default/tftpd-hpa
TFTP_USERNAME="tftp"
TFTP_DIRECTORY="/srv/tftp"          # 文件根目录
TFTP_ADDRESS="0.0.0.0:69"           # 监听所有IP的69端口
TFTP_OPTIONS="--secure --create"    # 安全模式 + 允许上传

参数说明:

参数 含义 我的建议
--secure 限制访问根目录,不能跳出 必须开启,否则有安全风险
--create 允许客户端上传新文件 按需开启,PXE启动一般不需要
--timeout 超时秒数(默认5秒) 局域网保持默认即可
--blocksize 数据块大小(默认512) 调大能提速,但部分客户端不兼容

3.2.3 准备文件目录

sudo mkdir -p /srv/tftp
sudo chown -R tftp:tftp /srv/tftp
# 放一个测试文件
echo "Hello TFTP" | sudo tee /srv/tftp/test.txt

权限坑:目录权限必须是 tftp 用户可读。我曾经图省事用 chmod 777,结果被安全审计抓了个正着。正确做法是 chown tftp:tftp /srv/tftp,目录设 755,文件设 644。

3.3 文件传输测试

配置完别急着往PXE环境里怼,先在本地验证。我习惯用三步测试法:

3.3.1 本地回环测试

# 从服务器本机下载
tftp 127.0.0.1
tftp> get test.txt
tftp> quit

# 检查文件
cat test.txt
# 输出: Hello TFTP

3.3.2 跨主机测试

# 在另一台机器上执行
tftp 192.168.1.100
tftp> get test.txt
tftp> verbose   # 开启详细输出,看传输过程
tftp> get test.txt
# 输出类似: received 12 bytes in 0.0 seconds

3.3.3 上传测试(如果开启了--create)

tftp 192.168.1.100
tftp> put localfile.txt
tftp> quit

测试清单:

  1. 本地回环通了吗?→ 验证服务端基本功能
  2. 跨主机通了吗?→ 验证网络和防火墙
  3. 上传/下载权限对吗?→ 验证文件系统权限

3.4 常见错误排查

这部分是重头戏。我这些年踩过的坑,全给你列出来。

3.4.1 超时(Timeout)

现象:Transfer timed out.

原因分析:

  • 防火墙拦截了UDP 69端口
  • 客户端和服务端不在同一广播域(跨网段没配DHCP中继)
  • 服务器负载过高,丢包严重

排查步骤:

# 1. 检查服务端监听
sudo netstat -tulpn | grep :69
# 应该看到: udp 0.0.0.0:69

# 2. 检查防火墙
sudo iptables -L -n | grep 69
# 或
sudo ufw status

# 3. 抓包确认
sudo tcpdump -i eth0 port 69 -nn
# 看有没有RRQ包到达服务器

我曾经遇到过一个奇葩案例:客户说TFTP间歇性超时,查了三天发现是交换机的STP(生成树协议)在作怪——端口在转发和阻塞状态间切换,导致UDP包丢失。最后在接入端口配了 portfast 解决。

3.4.2 权限拒绝(Permission denied)

现象:Error code 2: Access violation

原因:

  • 文件或目录属主不是tftp用户
  • 文件权限不足(比如600)
  • SELinux/AppArmor拦截

快速修复:

# 检查SELinux
getenforce
# 如果是Enforcing,临时放行
sudo setenforce 0
# 确认问题后,永久规则:
sudo semanage fcontext -a -t tftpdir_t "/srv/tftp(/.*)?"
sudo restorecon -Rv /srv/tftp

# 检查AppArmor(Ubuntu)
sudo aa-status | grep tftp
# 如果拦截,编辑 /etc/apparmor.d/usr.sbin.tftpd 添加路径

3.4.3 防火墙规则

很多新手只开了TCP端口,忘了TFTP走的是UDP。我建议你这样配:

# iptables
sudo iptables -A INPUT -p udp --dport 69 -j ACCEPT

# firewalld(CentOS 7+)
sudo firewall-cmd --add-service=tftp --permanent
sudo firewall-cmd --reload

# ufw(Ubuntu)
sudo ufw allow 69/udp

注意:TFTP的数据传输使用临时端口(1024-65535),如果防火墙规则太严,只放行69端口是不够的。客户端发RRQ到69,服务器会用临时端口回传数据。所以要么放行所有UDP高端口(不推荐),要么用状态防火墙自动放行回程流量。iptables的 state 模块可以搞定:-m state --state ESTABLISHED,RELATED -j ACCEPT。

3.4.4 文件未找到(File not found)

现象:Error code 1: File not found

排查:

  • 检查文件名大小写(TFTP区分大小写)
  • 检查文件是否在TFTP根目录下
  • 检查路径是否包含软链接(TFTP默认不跟随软链接)
# 确认文件存在
ls -la /srv/tftp/test.txt
# 确认tftp用户可读
sudo -u tftp cat /srv/tftp/test.txt

3.5 生产环境配置建议

最后,分享几条我自己的生产环境铁律:

场景 配置 理由
PXE启动 只读模式,关闭--create 防止客户端上传恶意文件
多网段 DHCP option 66指定TFTP服务器IP 避免广播域限制
高并发 使用atftpd替代tftpd-hpa atftpd支持多线程,并发性能更好
日志审计 开启rsyslog记录tftp日志 排查问题时能回溯