Weekend Project: Set Up a TFTP Server on Linux


Most users are familiar with FTP, but if you want to kickstart Red Hat installs, PXE boot systems, auto-provision VoIP phones or unbrick a Linux-based router, you want a Trivial File Transfer Protocol (TFTP) server. Setting one up on Linux is easy, and a perfect project to take on over the weekend.

TFTP (RFC 1350) is very low-overhead variant of the more familiar FTP that you are probably already used to interacting with. It is optimized for transferring files over a local network to small devices that may not even have permanent storage. In the old days, that originally meant thin clients booting over the network. Today there are still network services that depend on TFTP (most notably the Linux Terminal Server Project and Red Hat’s Kickstart remote-installation system) but it has taken on a second important role in VoIP, as the preferred way to “auto-provision” many IP telephones and analog telephone adapters (ATAs), distributing configuration files at boot time in a manner similar to DHCP. In addition to that, if you accidentally brick your Linux-based router while installing DD-WRT, TFTP may be your only path to restoring it. Fortunately, even though the protocol might not get the same public respect as FTP, Linux supports it just fine.

TFTP uses UDP as its transport protocol, on the reserved port 69. Like FTP, it can be used in either ASCII or binary mode, but unlike FTP it has no directory-listing or navigation features, because it was not primarily designed for interactive client use. Instead, TFTP clients typically boot up and request a specific file. If a listening server has the file, it acknowledges the request and begins transferring it.

This is a very simple process, which is what makes TFTP popular for thin client setups like Preboot eXecution Environment (PXE) and for embedded devices without built-in or USB-attachable storage. But it also includes no authentication step or access control methods, which makes man-in-the-middle attacks a very real security issue when dealing with VoIP deployments that require a support server to be running constantly.

An attacker that compromises the TFTP server can send rogue configuration files that do anything from register phones with different Session Initiation Protocol (SIP) gateways to perform denial-of-service by setting bad configuration parameters. Attacking a PXE system is a little more difficult, since the setup also includes DHCP, but it is certainly possible to upload a bad bootimage to thin clients.

On the other hand, if you just need to unbrick your router or flash a device with new firmware over TFTP, you do not need to run a TFTP server constantly. If you are really paranoid, you can just disconnect the WAN connection during the process. Since the two use cases are so different, the best choice for a static TFTP server probably is not the choice you would want just for an isolated job. We will consider each in turn.

Setting up static TFTP

For administrating a netboot or VoIP deployment, there are two main Linux TFTP server projects to choose from: tftpd-hpa and atftpd. The former is a port of OpenBSD’s TFTP daemon, though the Linux version has diverged over the course of several releases. Atftpd (which stands for Advanced TFTPd) is native to Linux. Both include support for several newer TFTP revision options, such as negotiable transfer block sizes and negotiable time-outs.

Your distribution may package one or the other, or both. If you are faced with a choice, the main differences between the two are in their security features and support for multicast TFTP.

Atftpd provides only host-level security using the libwrap TCP wrapper library. You can add TFTP clients by host name or address to /etc/hosts.allow or use exclusion rules in /etc/hosts.deny. Tftpd-hpa, on the other hand, respects rules in both hosts.allow and hosts.deny, but also implements several other security features. By default, it can only serve files that are publicly readable (i.e., o+r), and will only allow files to be uploaded by clients if the filename in question already exists and is publicly writable. Finally, starting the daemon with the -s option performs a chroot to the TFTP file directory to prevent an attacker from accessing anything else on the server.

Only atftpd, however, supports multicast TFTP, both the version specified in RFC 2090 and the slightly-different version that is part of the PXE specification. Thus, if you need to support PXE thin clients, atftpd is the better choice, but for all others, including VoIP provisioning, the added security features of tftpd-hpa are worth having.

Both servers can be started either by inetd or as standalone daemons, and store a configuration file in /etc/default/.

The tftpd-hpa server’s file is /etc/default/tftpd-hpa. By default it includes the line RUN_DAEMON="no", which allows it to be started and managed by inetd. Change this value to “yes” to start the server as a daemon instead. The OPTIONS= line lists a quoted series of run-time configuration flags, the most important of which is -s /path/to/tftp/directory.

Atftpd’s configuration is found in /etc/default/atftpd. By default, it includes USE_INETD=true to indicate inetd management; change this to false to run atftpd as a daemon. Aftpd requires that you specify the TFTP directory as the final argument, after all of the command-line switches, so you would simply append /var/tftpd to the end of its OPTIONS line.

Next, make sure that you create the TFTP directory you intend to use (say, /var/tftp/), and give it the proper ownership and permissions. Both daemons run as user nobody by default, so run chown -R nobody /var/tftp to set the ownership correctly, and chmod -R 777 /var/tftp to assign the correct permissions. Then, start the daemon: either execute /etc/init.d/atftpd restart or /etc/init.d/tftpd-hpa restart. Both services uses the standard Linux syslog utility, with run-time verbosity control so you can monitor their behavior.

For advanced usage, each of the servers also provides a way to serve alternate contents when it receives a specific file request, based on regular-expression matching and replacement. This can be useful when a device is hard-coded to request a specific firmware image, but you need to flash it with a newer replacement. But the two servers differ in their implementations. Atftpd uses Perl-Compatible Regular Expressions (PCREs), and allows for simple pattern/replacement pairs based on filename. Tftpd-hpa uses POSIX regular expression syntax, which is not as flexible, but it allows file remapping rules to be based on client IP address in addition to matching filenames alone.

The Simpler Case: TFTPing a Single File

If all you need to do is make one file available over TFTP for a short period of time, including restoring the factory firmware to a bricked router or uploading an update to your Cisco IP phone, you do not need to install and configure a full service like either of those discussed above. While it would be nice if Linksys and Cisco provided a simple command-line or GUI TFTP application for these occasions, neither do.

There is at least one robust, painless-to-use standalone TFTP app for Linux, though: tftpgui. Written in Python, tftpgui is meant to run as a user-initiated interactive application. The author documents its use with a variety of Cisco equipment, and it has also been tested with Vonage, Sipura, Linksys, and Grandstream hardware.

Currently, no distributions package tftpgui, so you will need to grab the latest tarball from the project’s downloads page. You can unpack its contents anywhere; it does not need to be compiled and installed to be used. In order to run on the default port of 69, you must launch the GUI as root, so execute sudo python ./tftpgui.py & to get started.

There are four buttons at the top: Start and Stop enable and disable the server, Exit closes the GUI, and Setup allows you to specify configuration rules. You must select a TFTP directory holding the files you need to move, and you can specify a log directory and change the UDP port on which the server listens.

The one security feature tftpgui includes is the ability to restrict incoming TFTP requests to a specific subnet, so if you must run the application in a hostile environment, you can at least try to isolate yourself to a vacant subnet before starting. You can also enter the remote clients IP address and specify a subnet mask of 32, even though purists may call that cheating.

After you apply any configuration settings and press Start in the main window, the main canvas will report any TFTP requests and return codes. You can then restart the remote device and watch its TFTP request hit the server, or if you are attempting to de-brick a router, follow whatever steps the instructions tell you to do.

Tftpgui does not support any of the extended protocol options like filename replacement or multicasting, but if you were stuck without a simple way to serve up a replacement firmware image or provisioning file, it may fit the bill.

In some ways, TFTP is a relic from the 1980s. As embedded devices get smarter and memory gets cheaper, more and more OEM products that used to use TFTP alone as their update mechanism are starting to include embedded HTTP stacks. That certainly makes it easier to troubleshoot, since most Linux boxes have Apache or another web server already installed. Still, when you find yourself trapped with a device that speaks only an unfamiliar protocol, it is reassuring to see that on Linux machines, old RFCs never die.