TFTP

読み:てぃーえふてぃーぴー / 英語表記:Trivial File Transfer Protocol

UDPを使ってファイルの読み書きを行う簡易なファイル転送プロトコルである。初回の転送要求はサーバの69番ポートへ送り、標準の動作では最大512バイトずつデータを送って受信確認を待つ。利用者認証や暗号化の機能は持たない。

イマシルちゃんの解説

ルータの起動時に、動くためのプログラムや設定ファイルをサーバから受け取りたいことがあるんだ。
そんな場面で使われる簡単なファイル転送プロトコルがTFTPだよ。
送り手はファイルを小さく分け、受け手から「ここまで受け取ったよ」という返事をもらいながら転送を進めるの。
受け取れなかった分を送り直せるから、途中でデータが失われても回復できるよ。
ただし、利用者の本人確認や通信の暗号化はしてくれないんだ。
使える機器やネットワークを絞って、必要なファイルだけを渡す使い方に向いているよ。

より深い解説

小さな実装でファイルを受け渡す

TFTPはTrivial File Transfer Protocolの略で、基本仕様はRFC 1350で定められている。アプリケーション層のプロトコルであり、下位にはUDPを利用する。FTPのようなディレクトリ一覧の取得や利用者ごとのログイン手順を備えず、指定したファイルを読み書きする機能に絞っている。

実装が小さいため、OSがまだ動いていない起動時や組込み機器でも扱いやすい。ネットワークから起動するPXEでは、DHCPなどによってIPアドレスや起動先の情報を得たあと、TFTPで起動プログラムを取得する構成がある。IPアドレスを配る役割とファイルを運ぶ役割は別である。MicrosoftのPXE起動の説明でもこの順序を確認できる。

「簡易なFTP」と呼ばれることがあっても、FTPの制御コネクションやデータコネクションを省略した互換方式ではない。対応するクライアントとサーバが必要であり、FTP用のユーザ名を渡せば使えるというものでもない。

転送要求とデータ転送でポートが変わる

TFTPの69番ポートは、サーバが最初の要求を受け取るための窓口である。クライアントとサーバは転送ごとにTID(Transfer Identifier)を選び、これをUDPのポート番号として使う。その後のデータと受信確認は、両者が選んだTIDの間でやり取りする。

例えばクライアントがポート50,000を選び、サーバが応答用に51,000を選んだ場合、読出しは次のように進む。数字は説明用の例である。

順序送信元 → 宛先内容
1クライアント50,000 → サーバ69読出し要求であるRRQを送る
2サーバ51,000 → クライアント50,000最初のDATAを送る
3クライアント50,000 → サーバ51,000そのDATAへのACKを返す
4以降サーバ51,000とクライアント50,000の間残りのDATAとACKを交換する

データ転送が始まると、宛先が最初の待受ポートではなくなる点が重要である。単に「TFTP用の宛先ポートを一つ許可する」というACLでは、その後の通信が遮断される場合がある。これは疎通できるのにファイルだけ届かない原因になる。

ファイアウォールやNAT装置には、最初の要求から後続の通信を関連付けるTFTP用のALGを備えた製品がある。ALGはアプリケーションの動作を理解して通信を仲介する機能である。必要な設定や対応状況は機器ごとに確認する。JuniperのTFTP ALG資料は、TIDと後続通信の許可を具体的に説明している。

読出しと書込みの手順

TFTPでは、クライアントが「サーバから受け取りたい」場合も「サーバへ渡したい」場合も、最初に要求を送る。基本仕様のメッセージは次の五種類である。

メッセージ意味
RRQ(Read Request)ファイルの読出しを要求する
WRQ(Write Request)ファイルの書込みを要求する
DATAブロック番号とファイルの一部を送る
ACK受信できたブロック番号を通知する
ERRORファイルがない、アクセスできないなどの理由を通知する

読出しではRRQに対してサーバがDATAを送り、クライアントがACKを返す。書込みではWRQに対してサーバがブロック番号0のACKを返し、それを受けてクライアントが最初のDATAを送る。ファイルのデータに付けるブロック番号は1から始まる。

標準の動作は、一つ送るたびに受信確認を待つ停止待ち方式である。データやACKが失われた場合はタイムアウトを契機に再送し、ブロック番号によって新しいデータと重複したデータを区別する。下位の通信方式が再送を行わなくても、アプリケーション側で回復処理を設けることはできる。

重複したACKを見るたびにDATAを送り直すと、重複が連鎖するおそれがある。TFTPの実装ではこの問題を避ける必要がある。RFC 1123の4.2.3.1節は、同じACKの再受信だけを理由にDATAを再送しないよう定めている。

ファイルの終わりをどう知らせるか

標準のDATAに入るファイルのデータは最大512バイトである。これとは別に、命令を表すオペコードとブロック番号で計4バイトのTFTPヘッダーが付く。さらに下位のプロトコルのヘッダーも付くため、回線を流れるデータ全体がこの最大値に収まるわけではない。

受け手は、DATAのデータ部分が使用中のブロック長より短いことによって終了を知る。ブロック長を変更していない場合、1,300バイトのファイルは「512バイト、512バイト、276バイト」の三つに分かれる。

一方、1,024バイトのファイルは通常サイズの二つのブロックだけでは終了だと判断できない。そこで最後にデータ部分が0バイトのDATAを追加する。ファイルサイズがブロック長の整数倍なら、この空のDATAが必要になる。空でもヘッダーはあり、受信確認の対象となる。RFC 2348でも、ブロック長を変更した場合に同じ終了条件を使うことが明記されている。

転送モードをファイルに合わせる

TFTPには、データの扱い方を指定する転送モードがある。プログラムやファームウェアのように内容を1バイトも変えてはならないファイルには、octetモードを使う。これはバイナリデータをそのまま送るモードである。

文字データ用のnetasciiモードでは、改行表現などをネットワーク上の形式へ変換し、受信側でローカルの表現へ戻す。このためバイナリファイルを文字データとして送ると、内容が変わって正常に利用できなくなる場合がある。古い仕様に記載されたmailモードは廃止された扱いであり、新たな構成で使うものではない。転送モードの位置付けはRFC 3617でも整理されている。

例えばWindowsのTFTPクライアントで、検証用サーバからバイナリファイルを受け取る指定は次のようになる。

tftp -i 192.0.2.20 GET boot.bin received-boot.bin

-i がバイナリ転送の指定、GET が取得の指定である。TFTPクライアント機能が利用できる環境で実行する例であり、アドレスは実際の管理用サーバへ置き換える。GET に利用者認証の意味はない。構文はMicrosoftのコマンド資料を参照する。

オプションで効率を改善する

基本仕様のままでは、小さなデータを送るたびに往復の応答を待つ。このため回線速度が高くても、遅延が大きい経路では十分なスループットが出ない。両者が対応していれば、要求にオプションを付けて転送条件を交渉できる。

サーバがオプションを受け入れると、OACK(Option Acknowledgment)で合意する値を返す。読出しではクライアントが受信確認を返してからデータ転送へ進む。オプションに対応していないサーバが通常の応答を返した場合は、要求した変更が受け入れられたものとして進めてはならない。この交渉はRFC 2347で定義されている。

オプション変えるもの主な効果・確認点
blksize1ブロックのデータ長ACKの回数を減らせるが、経路のMTUを超えるとIPの分割が生じ得る
timeout再送までの待ち時間回線の遅延に合わない短すぎる設定では不要な再送が起きる
tsize転送するファイルのサイズ情報受信前に必要な容量や扱えるサイズを判断できる
windowsizeACKを待たずに続けて送るブロック数毎ブロックの応答待ちを減らせる

ブロック長はRFC 2348、待ち時間とサイズ通知はRFC 2349、複数ブロックの連続送信はRFC 7440に対応する。拡張を使っている通信に対して「TFTPは必ず一つ送るごとに待つ」と断定してはならない。

IP MTUは一つのリンクで運べるIPパケットの最大長である。経路全体で分割を避けるには、途中のリンクを含めた最小値に合わせる。例えばIPv4ヘッダー20バイト、UDPヘッダー8バイト、TFTPヘッダー4バイトで、経路上の最小MTUが1,500バイトなら、データ長の上限は 1,500 − 20 − 8 − 4 = 1,468バイト となる。IPv6、追加のヘッダー、トンネルを使う場合は条件を見直す。大きくすれば必ず速くなるのではなく、途中の損失や再送まで含めて判断する。

標準サイズで応答の往復に20msかかると仮定すると、伝送時間などを無視した概算は次のようになる。ここでは同時に一つのブロックしか送らないものとする。

実効転送速度の概算 = 512 × 8 ÷ 0.020
                     = 204,800bit/s
                     = 約0.205Mbit/s

これは回線容量そのものではなく、応答待ちによる制約を表す。ブロック長や連続送信数を増やすと待ち時間の影響を減らせるが、受信側の処理能力やネットワークの混雑も考慮する必要がある。

安全性と障害をどう判断するか

TFTP自体には利用者認証も暗号化もない。再送で配送上の損失へ対処できても、送信相手の正当性や悪意ある改ざんまで保証するわけではない。RFC 3617も、安全性とアクセス制御の不足を主な制約としている。

管理用ネットワークへ利用範囲を限定し、公開するディレクトリとファイルを絞る。不要な書込みは許可せず、秘密情報を含む設定ファイルの扱いを検討する。ファームウェアはベンダーの署名などで正当性を確認する。一般のファイル転送で認証と暗号化が必要なら、SFTPやHTTPSなど要件を満たす方式を選ぶ。

障害対応では、まず要求が届くか、次に転送用ポートの通信が通るかを確認する。その後にファイル名・権限・転送モード・オプションを調べると、ネットワークの問題とファイルの問題を分けやすい。

症状確認すること
最初の要求に応答がないサーバの起動状態、宛先、経路、要求を許可するACLを確認する
サーバは応答しているが転送が始まらないTIDで選ばれたポート、戻りの通信、ALGやNATの対応を確認する
File not found や Access violation が返るサーバが公開する場所、ファイル名、大文字小文字、読書き権限を確認する
小さいファイルは届くが大きい転送で止まるブロック長、MTU、分割パケットの遮断、タイムアウトや損失を確認する
転送は完了したがプログラムが動かないバイナリ転送の指定、ファイルの種類と対象機器、署名やハッシュを確認する

午後の設計問題では「初回要求のポートを許可しただけでは足りない理由」や「高速回線でも転送が遅い理由」を説明できることが重要である。前者は転送用ポートへの切替え、後者はブロックごとの応答待ちに着目する。どちらもTFTPの通信順序を追えば判断できる。

参考資料

この用語が出てくる記事

↑