🐙

GoでTFTPサーバ自作(RFC 1350編)

に公開

この記事の内容

この記事ではRFC 1350に従ってTFTPサーバを自作します
学習目的の記事なのでAIは使用しません

TFTP関連のRFC

TFTPサーバの使用は以下のRFCに記載されています

RFC 内容
RFC 1350 TFTPの基本的な仕様
RFC 2347 TFTPの拡張(オプションの追加)
RFC 2348 ブロックサイズオプションの仕様(blksize)
RFC 2349 タイムアウトオプションの仕様(timeout)、ファイルサイズオプションの仕様(tsize)
RFC 7440 ウィンドウサイズオプションの仕様(windowsize)

RFC 2347はオプションそのものの仕様です

TFTPの通信

詳細はRFCをご覧ください

概要

TFTPによるファイル転送はクライアントのリクエストから開始します
リクエストの種類は読み込みと書き込みの二種類です ※1
読み込みリクエストに対してサーバは512バイト固定長のデータをクライアントに返します ※2
このデータをブロックと呼びます
ブロックには連続した番号が振られます
ブロック番号は1始まりです ※3
クライアントはブロックを受信したらACKパケットを送り返します
サーバはACKパケットを受け取ったら次のブロックを送信します ※4
送信/受信したブロックが512バイト未満の場合、通信を終了します
ただし、クライアントは最後の受信ブロックに対してもACKパケットを送ります

※1 今回の実装では読み込みのみ実装します
※2 RFC 2348でブロック長を変更可能になっています
※3 読み込みの場合
※4 RFC 7440で一度に送るブロックの数を変更可能になっています

詳細

全てのTFTPパケットは必ずopcodeを持ち、以下の5種類に分類されます

種類 opcode 内容
RRQ 01 読み込み対象のファイル名と通信に必要な設定
WRQ 02 書き込み対象のファイル名と通信に必要な設定
DATA 03 ファイルデータとそのブロック番号
ACK 04 受信完了したブロック番号
ERROR 05 エラーコードとエラーメッセージ

さらに具体的にはそれぞれ以下のフォーマットで記述されます

種類 フォーマット
RRQ Opcode: 2 bytes
Filename: string
0: 1 bytes
Mode: string
0: 1 byte
WRQ Opcode: 2 bytes
Filename: string
0: 1 bytes
Mode: string
0: 1 byte
DATA Opcode: 2 bytes
Block #: 2 bytes
Data: n bytes
ACK Opcode: 2 bytes
Block #: 2 bytes
ERROR Opcode: 2 bytes
ErrorCode: 2 bytes
ErrMsg: string
0: 1 byte

区切り文字としてNULL文字0が使われます
stringは任意長です
Modeは以下三種類です。今回はoctetのみ実装します

Mode 内容
netascii ascii文字
octet バイナリ
mail 詳細不明

ErrorCodeは以下の8種類が定義されています

ErrorCode 内容
0 Not defined, see error message (if any).
1 File not found.
2 Access violation.
3 Disk full or allocation exceeded.
4 Illegal TFTP operation.
5 Unknown transfer ID.
6 File already exists.
7 No such user.

transfer IDはUDPポートのことです

実装

概要

大雑把なシーケンスは以下です

今回はブロック長512バイト、ブロックの最大個数は65535個です
最大で送信できるファイルサイズは32MBになります
また、ファイルは全てメモリに載せてしまいます
ブロック長の変更とブロック番号のロールオーバーは今後対応します
https://github.com/callus-corn/tao/tree/v1.0.0/internal/tftp

動作確認

サーバ側

$ head -c 10000 /dev/urandom > file10k
$ make ; sudo ./build/tao

クライアント側

$ scp 192.168.1.101:/home/ubuntu/file10k ./correct_file10k
$ curl tftp://192.168.1.101/file10k -o file10k
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100 10000    0 10000    0     0   234k      0 --:--:-- --:--:-- --:--:--  234k
100 10000    0 10000    0     0   233k      0 --:--:-- --:--:-- --:--:--  233k
$ cmp file10k correct_file10k
$ 

Discussion