Setting up the tftp server

  • by Patrick Ogenstad
  • April 25, 2018

Before starting this step, please note that as previously mentioned a Linux server is required. The other requirement is that you have to be running Python 3.

We begin with creating a directory where we will place our files and setup a Python virtualenv. You can, of course, store these in any location of your choice.

mkdir -p /opt/ztp/tftproot
cd /opt/ztp
apt-get update
apt-get install python3-venv
python3 -m venv venv
source venv/bin/activate
pip install fbtftp
python
import fbtftp
exit()

Once you have everything installed and ready to go we can create our TFTP server. Create the file /opt/ztp/ztp_tftp.py and paste the code below.

from fbtftp.base_handler import BaseHandler
from fbtftp.base_server import BaseServer

import os


LISTEN_ON = '0.0.0.0'
SERVER_PORT = 69
TFTP_ROOT = '/opt/ztp/tftproot'
RETRIES = 3
TIMEOUT = 5


class TftpData:

    def __init__(self, filename):
        path = os.path.join(TFTP_ROOT, filename)
        self._size = os.stat(path).st_size
        self._reader = open(path, 'rb')

    def read(self, data):
        return self._reader.read(data)

    def size(self):
        return self._size

    def close(self):
        self._reader.close()


class StaticHandler(BaseHandler):

    def get_response_data(self):
        return TftpData(self._path)


class TftpServer(BaseServer):

    def get_handler(self, server_addr, peer, path, options):
        return StaticHandler(
            server_addr, peer, path, options, session_stats)


def session_stats(stats):
    print('')
    print('#' * 60)
    print('Peer: {} UDP/{}'.format(stats.peer[0], stats.peer[1]))
    print('File: {}'.format(stats.file_path))
    print('Sent Packets: {}'.format(stats.packets_sent))
    print('#' * 60)


def main():
    server = TftpServer(LISTEN_ON, SERVER_PORT, RETRIES, TIMEOUT)
    try:
        server.run()
    except KeyboardInterrupt:
        server.close()


if __name__ == '__main__':
    main()

Now we have the complete code for a working TFTP server, currently, it will only serve up static files. Later we will add some dynamic capabilities, but for now, we are good. Now we can create a test file in the TFTP root directory. We’ll call it /opt/ztp/tftproot/sample.cfg with this content:

hostname FIRST_DEVICE

end

Now we can start the server with python ztp_tftp.py

(venv) vagrant@vagrant:/vagrant/tutorial/setup$ python ztp_tftp.py
Traceback (most recent call last):
  File "ztp_tftp.py", line 62, in <module>
    main()
  File "ztp_tftp.py", line 54, in main
    server = TftpServer(LISTEN_ON, SERVER_PORT, RETRIES, TIMEOUT)
  File "/opt/ztp/venv/lib/python3.6/site-packages/fbtftp/base_server.py", line 211, in __init__
    self._listener.bind((address, port))
PermissionError: [Errno 13] Permission denied
(venv) vagrant@vagrant:/vagrant/tutorial/setup$

You might end up with an error message like the one above. The problem in that case is that we are trying to start a server running on a priviledged port, on a Unix system these are ports below 1024 and TFTP runs on UDP/69. So we need to start the server as the root user.

python ztp_tftp.py
WARNING:root:No callback specified for server statistics logging, will continue without

As the code is currently written you will see a warning regarding the lack of a callback to collect statistics. Just ignore that part as we won’t care about statistics in this tutorial.

Before continuing make sure you can download the sample file from the server using a tftp client, install one on your computer if you don’t have it.

deploy@srv-deploy-1:~$ tftp 172.29.50.12
tftp> get sample.cfg
Received 32 bytes in 0.0 seconds
tftp> quit
deploy@srv-deploy-1:~$ cat sample.cfg
hostname FIRST_DEVICE

end

deploy@srv-deploy-1:~$

Notice the output in the window where you have the TFTP server running, you can see the output from the clients request.

Serve files with tftp

As you might have noticed the output from the TFTP server is produced by the function session_stats() in the code above.

Make sure this step works before continuing.