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 | バイナリ |
詳細不明 |
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になります
また、ファイルは全てメモリに載せてしまいます
ブロック長の変更とブロック番号のロールオーバーは今後対応します
動作確認
サーバ側
$ 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