Глава 15 TFTP: простой протокол передачи данных

Введение

TFTP - это простой протокол передачи файлов. Он, как правило, используется при загрузке бездисковых систем (рабочие станции или X терминалы). В отличие от протокола передачи файлов (FTP - File Transfer Protocol), который мы опишем в главе 27 и который использует TCP, TFTP использует UDP. Это сделано для того, чтобы протокол был как можно проще и меньше. Реализации TFTP (и необходимого UDP, IP и драйвера устройства) могут поместиться в постоянной памяти (ПЗУ).

В этой главе приводится только краткое описание TFTP, потому что в следующей главе мы рассмотрим протокол Bootstrap, который использует TFTP. Мы использовали протокол TFTP, когда загружали из сети хост sun (см. рисунок 5.1). Он выдавал TFTP запрос, после того как получил свой IP адрес с использованием RARP.

RFC 1350 [Sollins 1992] является официальной спецификацией TFTP версия 2. Глава 12 [Stevens 1990] предоставляет полные исходные коды реализации TFTP клиента и сервера и описывает некоторую технику программирования, использованную в TFTP.

Протокол

Обмен между клиентом и сервером начинается с того, что клиент запрашивает сервер либо прочитать, либо записать файл для клиента. В стандартном варианте загрузки бездисковой системы первый запрос - это запрос на чтение (RRQ). На рисунке 15.1 показан формат пяти сообщений TFTP. (Коды операций 1 и 2 имеют одинаковый формат.)

Первые 2 байта TFTP сообщения это код операции (opcode). В запросе на чтение (RRQ) и в запросе на запись (WRQ) имя файла (filename) указывает файл на сервере, который клиент хочет либо считать, либо записать. Мы специально показали на рисунке 15.1, что это имя файла оканчивается нулевым байтом. Режим (mode) это ASCII строка: netascii или octet (любая комбинация больших или маленьких букв), которая также оканчивается байтом 0. netascii означает, что данные являются строками ASCII текста, причем каждая строка оканчивается 2-символьной последовательностью возврата каретки, за которой следует пропуск строки (обозначается - CR/LF).

Рисунок 15.1 Формат пяти TFTP сообщений.

И клиент и сервер должны иметь возможность осуществить преобразование между этим форматом и каким-либо другим (другой разделитель строк), который используется на локальном хосте. Передача octet обозначает, что данные будут передаваться в виде 8-битных байтов без интерпретации.

Каждый пакет данных содержит номер блока (block number), который затем используется в пакете подтверждении. В качестве примера скажем, что когда необходимо осуществить чтение файла, клиент посылает запрос на чтение (RRQ), указывая имя файла и режим. Если файл может быть прочитан клиентом, сервер отвечает пакетом данных с номером блока равным 1. Клиент посылает подтверждение (ACK) на номер блока 1. Сервер отвечает следующим пакетом данных с номером блока равным 2. Клиент подтверждает номер блока 2. Это продолжается до тех пор, пока файл не будет передан. Каждый пакет данных содержит 512 байт данных, за исключением последнего пакета, который содержит от 0 до 511 байт данных. Когда клиент получает пакет данных, который содержит меньше чем 512 байт, он считает, что получил последний пакет.

В случае запроса на запись (WRQ) клиент посылает WRQ, указывая имя файла и режим. Если файл может быть записан клиентом, сервер отвечает подтверждением (ACK) с номером блока равным 0. Клиент посылает первые 512 байт файла с номером блока равным 1, сервер отвечает ACK с номером блока равным 1.

Этот тип передачи данных называется протоколом с остановкой и ожиданием подтверждения (stop-and-wait) . Он используется только в простых протоколах, таких как TFTP. Мы увидим в разделе "Изменение размера окна" главы 20, что TCP предоставляет другую форму подтверждений, которая позволяет добиться более высокой пропускной способности. TFTP разработан таким образом, чтобы реализация была как можно проще, а не для того чтобы повысить пропускную способность.

Последний тип TFTP сообщений это сообщения об ошибках, код операции (opcode) равен 5. Это как раз то, чем сервер отвечает в том случае, если запрос на чтение или запись не может быть обработан. Ошибки чтения или записи в течении передачи файла также приводят к тому, что отправляется сообщение об ошибке, при этом передача прекращается. Номер ошибки (error number) содержит цифровой код ошибки, за которым следует сообщение об ошибке в ASCII формате, которое может содержать дополнительную информацию предоставляемую операционной системой.

Так как TFTP использует ненадежный UDP, то именно от TFTP зависит, как будут обработаны потерянные и дублированные пакеты. В случае потери пакета, отправитель отрабатывает тайм-аут и осуществляет повторную передачу. (Возможно появление проблемы, называемой "синдромом новичка" (sorcerer's apprentice syndrome), которая может возникнуть, если с обеих сторон будет отработан тайм-аут и осуществлена повторная передача. Раздел 12.2 [Stevens 1990] показывает, в результате чего может возникнуть подобная проблема.) Как и в большинстве UDP приложений, контрольная сумма TFTP сообщения не расчитывается, а это означает, что любое повреждение данных может быть определено только с помощью контрольной суммы UDP (см. главу 11, раздел "Контрольная сумма UDP").

Пример

Давайте посмотрим, как работает протокол TFTP. Мы запустим TFTP клиента на хосте bsdi и получим текстовый файл с хоста svr4:

bsdi % tftp svr4 стартуем TFTP клиента
tftp> get test1.c получаем файл с сервера
Received 962 bytes in 0.3 seconds
tftp> quit разрываем соединение
bsdi % ls -l test1.c сколько байт в полученном файле?
-rw-r--r-- 1 rstevens staff 914 Mar 20 11:41 test1.c
bsdi % wc -l test1.c и сколько строк?
48 test1.c

Первый момент, который бросается в глаза, заключается в том, что файл в Unix содержит 914 байт, однако TFTP передает 962 байта. Воспользовавшись программой wc, мы увидим, что в файле 48 строк, таким образом, 48 символов новой строки в Unix были дополнены до 48 пар CR/LF, так как TFTP по умолчанию осуществляет передачу в режиме netascii.

На рисунке 15.2 показан обмен пакетами.

1 0.0 bsdi.1106 > svr4.tftp: 19 RRQ "test1.c"
2 0.287080 (0.2871) svr4.1077 > bsdi.1106: udp 516
3 0.291178 (0.0041) bsdi.1106 > svr4.1077: udp 4
4 0.299446 (0.0083) svr4.1077 > bsdi.1106: udp 454
5 0.312320 (0.0129) bsdi.1106 > svr4.1077: udp 4

Рисунок 15.2 Обмен пакетами в случае TFTP.

В строке 1 показан запрос на чтение от клиента к серверу. Порт назначения UDP для TFTP - заранее известный порт 69, tcpdump просматривает TFTP пакеты и печатает RRQ и имя файла. Длина UDP данных печатается как 19 байт и получается следующим образом: 2 байта - код операции, 7 байт - имя файла, 1 байт равный 0, 8 байт для netascii и еще 1 байт равный 0.

Следующий пакет приходит от сервера (строка 2) и содержит 516 байт: 2 байта - код операции, 2 байта - номер блока и 512 байт данных. Строка 3 - подтверждение на эти данные: 2 байта - код операции и 2 байта - номер блока.

И последний пакет данных (строка 4) содержит 450 байт данных. 512 байт данных в строке 2 и эти 450 байт составляют 962 байта данных, полученные клиентом.

Обратите внимание, что tcpdump не печатает дополнительную информацию о протоколе TFTP для строк 2 - 5, как он это сделал, интерпретировав TFTP сообщение в строке 1. Это происходит потому, что номер порта сервера сменился между строками 1 и 2. Протокол TFTP требует, чтобы клиент отправил первый пакет (RRQ или WRQ) на заранее известный порт UDP сервера (69). Сервер находит какой-либо неиспользуемый динамически назначаемый порт (1077 на рисунке 15.2), который затем используется сервером для дальнейшего обмена пакетами между клиентом и сервером. Номер порта клиента (1106 в данном примере) не меняется. tcpdump не имеет представления о том, что порт 1077 на хосте svr4 используется TFTP сервером.

Причина, по которой меняется номер порта сервера, заключается в том, что сервер не должен захватывать заранее известный порт на большой промежуток времени, требуемый на передачу файла (что может занять от нескольких секунд до нескольких минут). Вместо этого, заранее известный порт остается доступным для других TFTP клиентов, которые могут послать туда свой запрос. Тогда как в это время передача осуществляется через другой порт.

Обратимся к рисунку 10.6. RIP сервер, которому необходимо послать клиенту более чем 512 байт, отправляет обе UDP датаграммы с заранее известного порта сервера. В случае TFTP (из-за отличий в протоколе), долговременного взаимодействия между клиентом и сервером не осуществляется (которое, как мы сказали, может занимать от секунд до минут). Если один процесс сервера будет использовать заранее известный порт все время, пока осуществляется передача файла, возникнет необходимость отказать всем последующим запросам, которые придут от других клиентов, или один процесс сервера должен иметь возможность осуществлять множественную передачу файлов нескольким клиентам в одно и то же время с одного и того же порта (69). Простейшее решение заключается в том, что сервер переходит на другой порт, после того как получил RRQ или WRQ. Клиент определяет новый порт, когда он получает первый пакет данных (строка 2 на рисунке 15.2), а затем посылать все последующие подтверждения (строки 3 и 5) на новый порт.

В разделе "Пример" главы 16 мы увидим, как TFTP используется при загрузке X терминалов.

Безопасность

Обратите внимание на то, что TFTP пакеты (рисунок 15.1) не содержат никаких данных об имени пользователя или пароле. Это брешь в секретности характерная для TFTP. Так как TFTP был разработан для использования в процессе загрузки, он не предоставляет возможности передать имя пользователя и пароль.

Эта характеристика TFTP была использована многими хакерами, чтобы получить копии файла паролей из Unix и затем расшифровать пароли. Чтобы предотвратить подобный доступ, большинство TFTP серверов в настоящее время регламентируют, какие файлы могут быть получены с использованием TFTP (как правило, файлы из директории /tftpboot в Unix системах). Эта директория содержит только загрузочные файлы, необходимые бездисковым системам.

Для дополнительной безопасности TFTP сервер, на Unix системе, обычно устанавливает свой пользовательский идентификатор (UID) и идентификатор группы (GID) в значения, которые не могут быть назначены реальному пользователю. Это позволяет доступ только к файлам, которые доступны для чтения и записи всем.

Краткие выводы

TFTP - это простой протокол, разработанный таким образом, чтобы помещаться в ПЗУ и быть использованным только в процессе загрузки бездисковых систем. Он использует небольшое количество форматов сообщений и протокол с остановкой и ожиданием подтверждения.

Чтобы позволить нескольким клиентам загружаться одновременно, TFTP сервер предоставляет несколько форм одновременной работы. Так как UDP не предоставляет уникального соединения между клиентом и сервером (как это делает TCP), TFTP сервер создает новый UDP порт для каждого клиента. Это позволяет разным клиентам выдавать датаграммы, которые будут демультиплексированы UDP модулем сервера, на основе номеров портов назначения, вместо того чтобы это делал сам сервер.

Протокол TFTP не предоставляет средства безопасности. Большинство реализаций позволяет доступ по протоколу TFTP только к файлам, которые необходимы при загрузке.

В главе 27 мы рассмотрим протокол передачи файлов (FTP - File Transfer Protocol), который разработан для общих целей, а также обеспечивает высокую пропускную способность при передаче файлов.

Упражнения

Прочитайте требования к хостам Host Requirements RFC, чтобы посмотреть, что должен делать TFTP сервер, если он получит запрос, IP адрес назначения которого является широковещательным адресом.
- Как Вы думаете, что произойдет, когда номер блока TFTP изменится с 65535 на 0? Говорится ли что-нибудь по этому поводу в RFC 1350?
- Мы сказали, что TFTP отправитель осуществляет тайм-аут и повторную передачу, чтобы отработать потерю пакетов. Как это отразится на функционировании TFTP, когда он используется как часть процесса загрузки?
- Что является ограничивающим фактором по времени при передаче файла с использованием TFTP?