The Trivially Padded File Transfer Project
The Trivially Padded Trivial File Transfer Protocol is a simplification and modification of the Internet standard Trivial File Transfer Protocol (TFTP), defined in 1981 by RFC 783, and updated in RFC 1350.
NAME tptftp, tptftpd SYNOPSIS tptftpd [-vL] _port_ tptftp [-v] _hostname_:_port_ _filename_ DESCRIPTION Implements a client and a server for the tptftp protocol. The deamon executable, tptftpd, implements the server listening on port _port_. The client the program tptftp uses the tptftp protocol to read file _filename_ from host _hostname_ connecting to the server listening on port _port_. The client writes the received bytes to standard out. The server implements basic security by requiring that filename is in the current directory and is world readable. Else an error is returned. OPTIONS -L If invoked as server, do not loop. Service one read request then exit. -v Verbose. Helpful debugging output to stdout. NOTES Implement only read. If requested return an error packet with message "mode not supported". The mode is "padded". The size of the data portion of the buffer is fixed, and that of the overall packet is 5 bytes larger. Padding is used to determine the actual data in the buffer. The padding scheme is that the byte following the last data byte of 0xff, followed by sufficient 0x00 bytes to fill the packet to its fixed size. Maximum filename length is 256 characters, and cannot contain a pathname. Server must be multi-thread, perhaps using the fork system call. Time-outs and resend are not implemented. BUGS Due to the protocol being non-standard, you might have to open your firewall for all inbound UDP traffic. In the case of AWS, use the private IP addresses. HISTORY First introduced in Fall 2003. Made Truly Trivial in Spring 2015. Authentication by challenge/response added Spring 2023. Spring 2024 padding added, other extensions removed. LAST UPDATED March 5, 2024
Protocol Description
Please read TFTP RFC 1350.
UDP is a best effort delivery. Packets may be lost, duplicated, or arrive out of order. To create a reliable enough data channel for file transfer, the technique of positive acknowledgements is used.
The file is packetized into equal size packets, called a block, and each is sent individually with its block number. After a data packet is sent, the sender awaits an acknowledgement packet with matching block number. On receiving the acknowledgement it moves on to sending the next data packet.
The other side of the communication waits for data packets and responds with acknowledgement packets. The software pays attention to the block numbers, looking for exactly the block number it expects. If there is a problem, the parties can resend their packets, typically based on a timeout.
THE TFTP PROTOCOL ROUNDS FOR RRQ CLIENT <----> SERVER round 0 ------- client sends RRQ -----> server receives RRQ and sends DATA block 1 <----- client gets DATA block 1 round 1 ------- client ACK's block 1 -----> server receives ACK 1 and sends DATA block 2 <----- client gets DATA block 2 round 2 ------- ... round n ------- client ACK's block n (last block) -----> server closes socket
The port numbers on both side of this communication protocol are taken as a pair to form, along with the IP addresses, a session. A block matching these four elements, two IP's and two port's, belong to that session. The client leads off by sending it request from an ephemeral port (x) to the well known port (69) of the server. The server responds by moving to an ephemeral port (y) in its reply. Between these two computers, the pair (x,y) represents the connection and are called the TIDs, transfer identifiers.
In the RFC 1350 protocol, the last packet is known by it being shorter than the maximum length. We will do a different padding scheme.
The padding scheme used is that the last byte of every data packets is either a 0xff or a 0x00. If it is 0x00, this is the last packet in the transfer; else expect another packet.
In both cases, starting from the last byte work backwards to the first 0xff byte. The data packet, after the first 4 bytes of the packet, up to but not including this byte, is data.
Note that it is possible that the entire packet is 0xff followed by 0x00's. That means the packet carried no user data, and is just sent to signal the end of data.
The Mode string
The first packet in the protocol is from client to server. In our implementation, it will be a RRQ packet with the name of the file to read. Read means to transfer the file from the server to the client.
Included in this first packet is an ascii string with the mode. We change RCF 1350 by not supporting any of the modes there described, and supporting only a newly defined mode called padded. The mode field must be set to the string padded for your program to be correct.
Security
You will have to open your SecurityGroup rules for UDP return packets coming from the 3333 port (or whatever is the server port) and the ephermal port space for the return packets. Best to use open for the network address of your AWS Private IP space. Ask in class or on slack about how this is done.
A general rule for accepting commands over the network:
Treat commands as suggestions, and only do explicitly allowed actions.
It would be as if the command received is a number 1 to N and the server does the N-th preprogrammed action. This obviously cannot be fully implemented. In our case, we have restricted to request to just one paramater, a file name. So we should make sure that the file,
Time Outs and Errors
Packet resend rules for sender retries The receiver (client) sends the RRQ and expects DATA 1. If the client receives DATA i, it sends ACK i and expects DATA i+1 If the client receives DATA i expecting DATA i+1, it resends ACK i. The client does not respond to a DATA j if j is not the expected or the previously expected block. After the client receives the last DATA packet and sends the last ACK, it can exit. The sender (server) sends DATA i and expects ACK i. If after the time out the server has not received the expected ACK i, it resends DATA i If the server receives ACK i it sends DATA i+1 and expects ACK i+1 If after the third send of DATA i without and ACK i, the server aborts. When the server receives the ACK for the last DATA packet, the server exits
After the RRQ, the server and client exchange DATA and ACK packets. The block number of the DATA packets should increase, and the ACK packets reply with the block number in the DATA packet.
Lost packets will break this pattern of exchange and one or the other side will resend their packet to try to start the pattern again. This must be done carefully to avoid the Sorcerer's Apprentice bug that was discovered in the original TFTP protocol.
If you are asked to implement times outs, we will implement a scheme where the sender is responsible for the resend. For a RRQ the sender is the server and the receiver is the client.
After the client has sent the RRQ, it only responds to packets received. (The exception to this is a resend of the RRQ of DATA 1 is not received.) The reason for sender retries is after the last DATA-ACK pair, the receiver has nothing to expect.
The Foo Sockets
The Foo socket utility aids the project by organizing the sockets into three types.
create_foo_socket(0)
.
socket_sendto(sock_c, to_host, to_port, buf, msgsize)
.
socket_recvfrom(sock_c, buf, buf_len)
.
socket_replyto(sock_c, buf, numbytes)
, so that
packets to back to the server's selected ephemeral port.
create_foo_socket(listen_port)
, giving the port to listen on.
socket_recvfrom( sock_listen, buf, buf_len)
.
create_session_socket(sock_listen)
,
which binds to an ephemeral port, and has the client's port copied over from sock_listen
.
socket_replyto( sock_session, buf, numbytes )
.
socket_recvfrom( sock_session, buf, buf_len )
.
Implementation notes and restrictions
Debugging run
$ make run-server echo "The date is: `date` !" > hello.txt ./tptftpd -v 3333 Line __: server loop entered Line __: listening on port 3333 socket_recvfrom (foo-socket.c:184) got 19 bytes on port 3333 from 54.162.229.55:35195 00 01 68 65 6c 6c 6f 2e 74 78 74 00 70 61 64 64 65 64 00 (tptftp-server.c,__): found file |hello.txt|, mode |4| socket_sendto (foo-socket.c:212) sent 37 bytes on port 51684 to 54.162.229.55:35195 00 03 00 01 54 68 65 20 64 61 74 65 20 69 73 3a 20 4d 6f 6e 20 4d 61 72 20 32 34 20 30 30 3a 34 36 3a 35 38 ff socket_recvfrom (foo-socket.c:184) got 4 bytes on port 51684 from 54.162.229.55:35195 00 04 00 01 socket_sendto (foo-socket.c:212) sent 37 bytes on port 51684 to 54.162.229.55:35195 00 03 00 02 20 55 54 43 20 32 30 32 35 20 21 0a ff 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 socket_recvfrom (foo-socket.c:184) got 4 bytes on port 51684 from 54.162.229.55:35195 00 04 00 02
$ make run-client ./tptftp -v 3.84.208.125:3333 hello.txt (tptftp-client.c,__): tptftp_client entered socket_sendto (foo-socket.c:157) sent 19 bytes on port 35195 to 3.84.208.125:3333 00 01 68 65 6c 6c 6f 2e 74 78 74 00 70 61 64 64 65 64 00 socket_recvfrom (foo-socket.c:184) got 37 bytes on port 35195 from 3.84.208.125:51684 00 03 00 01 54 68 65 20 64 61 74 65 20 69 73 3a 20 4d 6f 6e 20 4d 61 72 20 32 34 20 30 30 3a 34 36 3a 35 38 ff The date is: Mon Mar 24 00:46:58socket_sendto (foo-socket.c:212) sent 4 bytes on port 35195 to 3.84.208.125:51684 00 04 00 01 socket_recvfrom (foo-socket.c:184) got 37 bytes on port 35195 from 3.84.208.125:51684 00 03 00 02 20 55 54 43 20 32 30 32 35 20 21 0a ff 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 socket_sendto (foo-socket.c:212) sent 4 bytes on port 35195 to 3.84.208.125:51684 00 04 00 02 client says goodbye
Author: Burton Rosenberg
Created: January 18, 2014 as mytftp
Last Update: 24 March 2025