TPTFTP Project

by: burt rosenberg
at: university of miami


The original best-effort, packetized data delivery

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.

Specific Objectives

Man Page

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.
    
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. This includes the possibility of a data packet carrying zero bytes of data. We will modify this to do a padding scheme were every packet is the same length, but bytes are added to the end of the real data to show where it might end in the packet.

There is always room for one byte following the data. However there might be more. The first byte following the date is set to 0xff to mark the end. The remaining bytes are set to 0x00 until the end of the packet, to distinguish those byte both from the end of data marker and from any other data.

The unpacking algorithm is to go the last byte in the packet, and move towards lower indexed bytes while a 0x00 is seen. The first non-zero should be 0xff.

The termination condition then applies to the unpadded block; so that in effect, if the last byte is 0xff more blocks follow. If the last byte is 0x00 this is the last block.

The Mode string

The first byte in the protocol is from client to server. It includes whether the interaction will be a read or a write, and the name of the file to read or write. A read is a file on the server being sent to the client, and a write is a file on the client being sent to the server.

We will only implement reads.

This first packet also has a string for the mode of the data. It RFC 1350 it is either netascii, octet or mail. We will use none of these and set the mode to padded, and otherwise the data will be consistent with the octet transfer mode. The octet mode delivers raw bytes without conversion of processing. Any numerical value is permissible in octet mode, even the zero byte, carriage returns or new line codes, which might otherwise be treated as special.

The Foo Sockets

The Foo socket utility aids the project by organizing the sockets into three types.

Security

As a general rule, never let your program do anything you have not expressly allowed it to do.

We are permitting the sending of certain files. Those files are,

  1. Regular files,
  2. in the current directory only,
  3. with world readability.

Implementation notes and restrictions

  1. Of the transfer types, only RRQ is supported.
  2. Of the modes, only the new padded mode is supported.
  3. The block size must be variable, and is set by the define TFTP_LEN in the header file.
  4. The network is big endian. Intel is little endian. Program accordingly.
  5. Do not assume the file transfered is text; do not assume nulls terminate byte buffers; do not assume just because it is written to standard out the characters are printable.
  6. Do not crash because of bad inputs.
  7. Never trust inputs from the network.
  8. It is not excusable that an error surprises your code, and your code crashes. If you want to bail out on bad data, in this class you are free to use an assertion, although user friendly code might handle the error more gracefully.
  9. Be consistent with the RFC in handling of all errrors. Check the TID of the sender and send a non-terminating error as directed in the RFC.
  10. All other errors send a terminating error with correct error number.
  11. Refer to the statment "receiving a packet which cannot be explained by a delay or duplication in the network" for the definition of what is an error.

Debugging run

$ make basic-test
cc  -c -o ttftp-client.o ttftp-client.c
cc -c -o foo-socket.o foo-socket.c
cc  -o ttftp ttftp.c ttftp-client.o foo-socket.o
cc  -c -o ttftp-server.o ttftp-server.c
gcc -o ttftpd ttftpd.c ttftp-server.o foo-socket.o
echo "The date is: `date` !" > hello.txt
./ttftpd  -L -v 3333 &
./ttftp localhost:3333 hello.txt > hello.txt.out
Line 100: server loop entered
Line 101: listening on port 3333
socket_recvfrom (foo-socket.c:160)
	got 25 bytes on port 3333 from 127.0.0.1:41016
	00 01 68 65 6c 6c 6f 2e 74 78 74 00 61 75 74 68 
	65 6e 74 69 63 61 74 65 00 
(ttftp-server.c,86): found file |hello.txt|, mode |4|
goodbye
diff hello.txt hello.txt.out
socket_sendto (foo-socket.c:188)
	sent 48 bytes on port 37476 to 127.0.0.1:41016
	00 03 00 01 54 68 65 20 64 61 74 65 20 69 73 3a 
	20 54 75 65 20 4d 61 72 20 20 35 20 32 32 3a 32 
	39 3a 34 39 20 55 54 43 20 32 30 32 34 20 21 0a 
	socket_recvfrom (foo-socket.c:160)
	got 4 bytes on port 37476 from 127.0.0.1:41016
	00 04 00 01 
***
*** PASSES basic test
***
Creative Commons License
This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 Unported License.

Author: Burton Rosenberg
Created: January 18, 2014 as mytftp
Last Update: 5 March 2024