Reviving a Hobby

The WriteIt! 2.0 Editor (2010)

My experience with Macs began back in late 2006, when my father gifted me a mint-condition PowerBook G3 Pismo running Mac OS X Tiger at the time. The Pismo was a great laptop for a teenager curious about IT and programming, delivering great battery life with its two removable batteries while still easily fitting into my school bag.

It didn't take long before I fired up Xcode 2 on a during every lunch break and started experimenting with the Objective-C programming language, creating a simple text editor called "WriteIt".

With time I started to build other applications to test different concepts and APIs, which ultimately resulted in Cookie Stumbler - an application that would scan your web browsers for tracking cookies using a proprietary heuristics engine and would remove them with a single click.

With university and a full-time job however, it became more and more difficult to find free time to follow this hobby further and I haven't been able to program too much since then.

They say that once one learns how to ride a bike, they can never forget it because it gets stored within the procedural memory. So, let's give it a shot with coding once again over the next two blog posts.

Solving a Problem

Programming for me was always about solving a problem (or more). Whether this was the lack of a proper, lightweight text editor that would let me instantly preview HTML back in 2010, or deleting cookies I never asked for, this was always the ultimate goal.

I recently ran into an issue when building my "home-lab" - I needed to transfer some firmwares to a Cisco ASA firewall and tried doing so via TFTP (Trivial File Transfer Protocol) in OS X Big Sur. There obviously are faster ways of doing so such as via FTP, SFTP and SCP, but none of my virtual servers were ready yet.

As there isn't really a proper client for TFTP on OS X,  I decided to code one on my own as a little exercise. The first step was to make myself familiar with the specifications of the protocol itself:

RFC 783 - TFTP Protocol (revision 2)

TFTP is a pretty simple protocol to understand - there's no authentication mechanism and communication between server and client occurs via a UDP socket on port 69, with each communication featuring an opcode as specified below:

  • RRQ (Read) = 1
  • WRQ (Write) = 2
  • Data = 3
  • ACK (Acknowledgement) = 4
  • ERR = 5
Understanding the Protocol

So from the view of the client, the client would contact the server with data that features an opcode (1 or 2), followed by the name of the file and the transfer mode. All fields, except for the opcode, are NULL terminated.

If everything checks out with the initial request, the server will respond with either ACK or ERR, if it does not. The ACK packet is relatively simple, containing the opcode and the number of the block that is being transmitted. This number will always be zero for the first ACK in case of a write request.

If the client receives an ACK, it sends one back, at which point the server starts feeding data packets and listening for the client sending an ACK to confirm their receipt.

In the initial specification, each data block is fixed at a size of 512 bytes. The client will identify a packet as the last one by the fact that it is less than 512 bytes in size.

RFC2347 supplements this by introducing so-called options to the header, as well as a new opcode - 6, which stands for OACK (Option Acknowledgement). Options are appended to the header and feature a one byte separator.

Now, if one for instance was to pass the option blksize, this would allow the data packet size to be raised on most Cisco equipments to a maximum of 8192 bytes instead of just 512 bytes. This is something we will need to consider for the implementation.

One important thing of note is that any options requested by the client must be acknowledged by the server via an OACK packet, which in turn must be ACK'ed by the client, otherwise the negotiation will fail.

Another important thing to keep in mind is that if options are present in the initial request's header, you must send an OACK instead of an ACK initially. Failure to do so will lead to the transfer running without any options being taken into consideration, i.e. according to RFC783.

I created a simple visual representation of all the different opcode packet types below:

That's it! The next blog post will look at creating a small project that actually implements this logic and functions as a TFTP server.