4、TFTP服务器搭建:tftp-hpa vs atftpd,传输性能调优与安全加固

TFTP这玩意儿,说白了就是网络启动里的“送水工”。它不花哨,但没它不行。PXE启动时,BIOS/UEFI从DHCP拿到IP和引导文件位置后,全靠TFTP把vmlinuz、initrd.img这些“粮食”搬进内存。

我这些年经手过的网络启动项目,少说也有几十个了。TFTP这块踩过的坑,够写一本小册子。今天咱们就把tftp-hpa和atftpd这两个主流服务器掰开揉碎,讲讲怎么搭、怎么调、怎么防、怎么修。

核心结论先放这儿:小规模环境(<50台并发)用tftp-hpa,省心;大规模批量部署(>200台)上atftpd,性能优势明显。别问为什么,问就是血泪教训。

TFTP服务器搭建知识体系 TFTP服务器选型 tftp-hpa 特点:轻量、稳定、配置简单 适用:小规模、单机部署 atftpd 特点:多线程、高并发、自适应 适用:批量部署、大规模环境 性能调优 块大小 · 窗口大小 · 超时 安全加固 chroot · 访问控制 · 用户隔离 故障排查 Timeout · File Not Found · 权限 选型建议:并发 < 50 用 tftp-hpa,并发 > 200 用 atftpd,中间地带看心情

4.1 两个主流TFTP服务器的选型对比

先说说tftp-hpa。这是H. Peter Anvin写的,就是那个搞SYSLINUX的大神。它走的是单线程、select模型,每次只能处理一个请求。你想想看,如果50台机器同时PXE启动,它就得排队一个个喂。但好处是——稳,非常稳。我在一个教育城域网里跑了三年,没重启过一次。

atftpd呢,是Jean-Pierre Lefebvre的作品。它用多线程+自适应窗口,能同时伺候几百个客户端。我记得有一次给一家代工厂做批量部署,300台机器同时开机,atftpd扛住了,tftp-hpa直接超时一片。

对比维度 tftp-hpa atftpd
并发模型 单线程 select 多线程 自适应
默认块大小 512字节(RFC标准) 自动协商(最大1468)
配置复杂度 低,一个配置文件搞定 中,参数较多
chroot支持 内置,-s参数 内置,--chroot
日志能力 syslog,较简略 详细,支持debug级别
适用场景 小规模、嵌入式、单机 批量部署、大规模集群

我的建议:如果你刚开始搭PXE环境,先用tftp-hpa上手。等遇到性能瓶颈了,再换atftpd不迟。别一上来就上atftpd,参数调不好反而更慢。

4.2 安装与基础配置

4.2.1 tftp-hpa 安装配置

在Debian/Ubuntu上,一条命令搞定:

apt install tftp-hpa tftpd-hpa

配置文件在 /etc/default/tftpd-hpa。我个人习惯这样配:

TFTP_USERNAME="tftp"
TFTP_DIRECTORY="/srv/tftp"
TFTP_ADDRESS="0.0.0.0:69"
TFTP_OPTIONS="--secure --create --verbose -s -c -p -U 077 -u tftp"

这里解释几个关键参数:

  • --secure:chroot到TFTP目录,这是安全底线
  • -c:允许上传文件(如果你需要客户端回传日志的话)
  • -p:不检查端口范围,提高兼容性
  • -U 077:上传文件的umask,防止权限过大

注意:千万不要在生产环境去掉 --secure 参数。我曾经见过有人为了省事直接暴露根目录,结果被扫到TFTP漏洞,整个/boot被人扒走了。

4.2.2 atftpd 安装配置

apt install atftpd

atftpd的配置在 /etc/default/atftpd:

OPTIONS="--daemon --port 69 --tftpd-timeout 300 --retry-timeout 5 \
  --maxthread 100 --verbose=5 --logfile /var/log/atftpd.log \
  --chroot /srv/tftp"

这里 --maxthread 100 是关键——控制最大并发线程数。我建议根据你的机器内存来调,每线程大约消耗2-3MB内存。

4.3 传输性能调优

TFTP默认的512字节块大小,是1970年代在ARPANET上定的。放到今天千兆网络里,简直是在用吸管喝奶茶。调优的核心就两个参数:块大小(blksize)和窗口大小(windowsize)。

4.3.1 块大小调优

TFTP的RRQ包可以协商blksize。客户端在请求时带上blksize 1468选项,服务器同意后,每个数据包就能塞1468字节。1468这个数字怎么来的?以太网MTU 1500 - IP头20 - UDP头8 - TFTP头4 = 1468。刚刚好。

在tftp-hpa中,客户端这样指定:

tftp -m binary -c get -b 1468 server_ip /pxelinux.0 /tmp/pxelinux.0

atftpd默认会自动协商,但你可以强制指定:

OPTIONS="$OPTIONS --blksize 1468"

我做过对比测试:512字节块大小,传输10MB文件耗时约12秒;调到1468后,直接降到4秒。3倍提升,立竿见影。

4.3.2 窗口大小调优

这是TFTP的“黑科技”。传统TFTP是停等协议——发一个包,等ACK,再发下一个。窗口大小(windowsize)允许连续发多个包再等ACK,大幅减少往返延迟的影响。

atftpd支持这个扩展,tftp-hpa不支持(至少原生不支持)。配置方法:

OPTIONS="$OPTIONS --windowsize 8"

窗口大小设多少合适?我一般建议8-16。设太大(比如64),一旦丢包重传代价很高。设太小,又发挥不出优势。

窗口大小 10MB传输时间(千兆网络) 丢包重传影响
1(传统模式) ~12秒 低
4 ~5秒 中
8 ~3秒 中高
16 ~2.5秒 高

性能调优黄金法则:先调blksize到1468,再调windowsize到8。如果网络环境干净(交换机无丢包),可以试试16。别贪心,稳定比速度重要。

4.4 安全加固

TFTP本身没有认证、没有加密。说白了,谁都能连上来下载文件。所以安全加固不是可选项,是必选项。

4.4.1 chroot 隔离

chroot是TFTP安全的第一道防线。它把TFTP进程的根目录锁定在指定目录,就算被攻破,攻击者也看不到/etc/passwd。

tftp-hpa用 -s 参数:

TFTP_OPTIONS="--secure -s /srv/tftp"

atftpd用 --chroot:

OPTIONS="--chroot /srv/tftp"

注意:chroot后,TFTP目录里必须包含所有客户端需要的文件,包括引导加载器、内核、initrd等。我曾经犯过一个低级错误——chroot后忘了把pxelinux.0拷进去,结果所有客户端报"File not found",排查了半小时才反应过来。

4.4.2 访问控制

光chroot还不够,你还要限制谁能连、能连什么。

方法一:iptables限制源IP

iptables -A INPUT -p udp --dport 69 -s 192.168.100.0/24 -j ACCEPT
iptables -A INPUT -p udp --dport 69 -j DROP

方法二:atftpd内置访问控制

OPTIONS="$OPTIONS --allow-ip 192.168.100.0/24 --deny-ip 0.0.0.0/0"

方法三:文件级权限控制

TFTP目录权限设为755,所有文件644。不要让TFTP用户有写权限,除非你明确需要上传功能。

chown -R root:tftp /srv/tftp
chmod -R 755 /srv/tftp
find /srv/tftp -type f -exec chmod 644 {} \;

安全底线清单:

  • 必须chroot,不要妥协
  • 必须限制源IP,至少限制到内网段
  • TFTP目录不要放敏感文件
  • 定期检查日志,关注异常请求
  • 如果不需要上传,去掉 -c 参数

4.5 常见故障排查

这部分是我花时间最多的。TFTP出问题,症状往往就两个:Timeout 和 File not found。但背后的原因五花八门。

4.5.1 Timeout 超时

客户端报 TFTP timeout,通常原因有这几个:

  1. 防火墙拦了UDP 69端口——这是最常见的。检查iptables、云平台安全组、物理防火墙规则。
  2. TFTP服务没启动——检查进程:ps aux | grep tftp
  3. 端口被占用——netstat -anp | grep :69,看看是不是有其他服务占了69端口
  4. 网络路径MTU问题——如果blksize设了1468但中间设备MTU小于1500,大包会被分片或丢弃。降回512试试看。
  5. 并发太高导致服务端丢包——tftp-hpa单线程处理不过来,换atftpd或加--maxthread

排查命令三板斧:

# 1. 测试连通性
tftp 192.168.100.10 -c get testfile

# 2. 抓包看交互
tcpdump -i eth0 port 69 -vv

# 3. 看服务端日志
tail -f /var/log/syslog | grep tftp

4.5.2 File Not Found

这个错误更气人——明明文件就在那里,客户端就是找不到。原因通常是:

  • 路径问题:chroot后,客户端请求 /pxelinux.0,但文件实际在 /srv/tftp/pxelinux.0。注意chroot后的路径是相对于chroot目录的。
  • 文件名大小写:TFTP协议区分大小写。PXELINUX.0 和 pxelinux.0 是两个文件。我见过有人把文件拷成大写,客户端请求小写,死活找不到。
  • 权限问题:TFTP用户对文件没有读权限。chmod 644 解决。
  • SELinux/AppArmor:这些安全模块会拦截TFTP的读操作。检查审计日志:ausearch -m avc -ts recent

我的排查习惯:先在TFTP服务器本地用 tftp localhost -c get filename 测试。本地能通,就是网络或防火墙问题;本地不通,就是配置或权限问题。这个二分法能省一半时间。

4.5.3 一个真实案例

去年帮一家公司排查PXE启动故障。症状是:100台机器同时开机,前20台正常,后面的全部timeout。我一看,他们用的tftp-hpa,单线程。100个请求排队,每个传输要3-4秒,前20台占掉60-80秒,后面的客户端早就超时放弃了。

解决方案:换成atftpd,设 --maxthread 50 --blksize 1468 --windowsize 8。重启后,100台机器同时启动,全部在30秒内完成。客户当场竖大拇指。

嗯,这就是选对工具、调好参数的价值。