СЕРГЕЙ СУПРУНОВ
FreeBSD tips: работаем с TFTP
Для некоторых задач обмена файлами по сети многие возможности протокола FTP оказываются избыточными. Чтобы не тратить ресурсы на их поддержку, был разработан протокол TFTP.
Протокол TFTP (Trivial File Transfer Protocol – тривиальный протокол передачи файлов) благодаря своей предельной простоте довольно часто используется в различном оборудовании (маршрутизаторах, коммутаторах, модулях DSLAM и т.п.). Его удобно применять для обмена файлами внутри локальной сети, при необходимости он легко может быть интегрирован в разрабатываемую программу. В последнее время все большую популярность приобретают бездисковые рабочие станции, первоначальная загрузка которых выполняется по сети также с использованием протокола TFTP. В данной статье мы рассмотрим реализацию TFTP в системе FreeBSD.
Протокол TFTP (a.k.a. RFC1350)
Сначала коротко рассмотрим сам протокол, как он определен в документе RFC1350. Поскольку главное требование к протоколу – простота, то в нем поддерживается лишь необходимый минимум функций: возможность чтения файла с удаленного хоста и записи файла на хост. Протоколом не предусматривается ни аутентификация/авторизация пользователя, ни навигация по каталогам, ни даже просмотр содержимого каталога.
Нет в TFTP и отдельной процедуры соединения, как это происходит в случае с FTP – соединение устанавливается по запросу на чтение или запись, после завершения операции оно разрывается. С этой точки зрения TFTP больше похож на HTTP, также работающий без поддержания постоянного соединения.
В качестве стандартного порта для протокола TFTP определен порт 69. Основным транспортным протоколом для TFTP является UDP, однако работа поверх TCP также возможна. Чтобы прочитать файл, на этот порт посылается запрос на чтение, содержащий код операции (opcode, равный 1 (RRQ)), имя запрашиваемого файла и режим передачи, который может быть «netascii» или «octet». Стандартом также определен режим «mail», предназначенный для передачи сообщений электронной почты, но он считается устаревшим и не рекомендуется к применению. Эти значения соответствуют тому, что обычно именуется «текстовым» и «двоичным» режимами: в режиме netascii предусматривается обработка управляющих символов (например, перевода строки) в соответствии со стандартами, принятыми на той или иной платформе; в режиме octet данные должны быть переданы в «сыром» виде, без какой-либо обработки.
В ответ на запрос, если нужный файл существует и доступен для чтения, сервер отсылает первую порцию данных, содержащую opcode 3 «DATA», номер блока (1) и собственно данные. Данные передаются блоками по 512 байт, после отправки каждого из них сервер должен дождаться подтверждения от клиента (opcode 4, ACK). Если подтверждение не будет получено, то через определенный период времени сервер должен повторить отправку последнего блока. Если подтверждение так и не придет в течение тайм-аута, заданного для сеанса связи, то соединение разрывается. Вообще нужно иметь в виду, что тайм-ауты играют очень важную роль в TFTP-соединении.
Блок данных менее 512 байт рассматривается как последний, и соединение после его получения разрывается. Если размер файла кратен 512 и последний блок имеет размер также 512 байт, то должен быть отправлен еще один блок нулевой длины.
Запись файла выполняется аналогично, с той разницей, что в ответ на запрос о записи (opcode 2, WRQ) сервер отсылает подтверждение с номером блока 0.
Для оповещения удаленной стороны о возникновении ошибки используются специальные пакеты с opcode = 5 (ERROR).
Как видите, протокол отводит два байта для указания номера отсылаемого блока, что накладывает ограничение на размер передаваемого файла в 32 Мб. Существуют документы RFC 1782 – 1785, расширяющие возможности TFTP. В частности, RFC1783 определяет дополнительный параметр blksize, позволяющий задать размер блока, отличный от 512 байт. Помимо увеличения максимального размера файла данная возможность также способствует увеличению скорости передачи в средах с большим значением MTU.
Клиент tftp
Система FreeBSD включает в себя как TFTP-сервер (tftpd), так и утилиту tftp, выполняющую функции клиента. Программа tftp представляет собой интерактивную оболочку для работы с TFTP-серверами (в отличие от одноименной утилиты в Windows, которая требует в качестве параметра сразу указывать и выполняемую операцию). По команде «?» можно получить список и краткое описание всех доступных команд (в приведенном листинге вместо оригинальных описаний команд стоят мои комментарии):
serg$ tftp
tftp> ?
Команды могут сокращаться, пока сохраняется уникальность.
connect указать сервер, с которым будет устанавливаться соединение
mode установить режим передачи (ascii|netascii|binary|image|octet)
put отправить файл на сервер
get получить файл с сервера
quit выйти из tftp
verbose вкл./откл. подробные сообщения
trace вкл./откл. трассировку пакетов в ходе обмена с сервером
status показать текущие настройки
binary включить режим обмена octet
ascii включить режим обмена netascii
rexmt установить таймаут, используемый для каждого пакета
timeout установить общий таймаут сеанса
? вывести на экран эту справку
|
Установка соединения и обмен данными обеспечивается командами put и get, все остальные служат для настройки поведения клиента:
tftp> trace
tftp> verbose
tftp> conn localhost
tftp> status
Connected to localhost.
Mode: netascii Verbose: on Tracing: on
Rexmt-interval: 5 seconds, Max-timeout: 25 seconds
|
tftp> get config
getting from localhost:config to config [netascii]
sent RRQ
sent RRQ
sent RRQ
sent RRQ
sent RRQ
Transfer timed out.
|
На приведенном выше листинге показана попытка считать файл при неработающем сервере. Как видите, клиент не обнаруживает наличие проблемы и через каждые 5 секунд (параметр Rexmt-interval) повторяет попытки установить соединение, передавая запрос RRQ и ожидая первый блок данных. Спустя 25 секунд (Max-timeout) эти попытки прекращаются. Обратите внимание, что приглашение вы получите в любом случае, независимо от того, запущен ли на указанном узле TFTP-сервер или нет. Как было описано выше, попытка установить соединение выполняется только при отправке запроса на чтение или запись. До этого момента клиент ничего не знает о наличии сервера на удаленной машине.
Пример успешной записи файла на сервер выглядит так (включена трассировка):
tftp> verbose
tftp> trace
tftp> put messages
putting messages to test.ru:messages [netascii]
sent WRQ
received ACK
sent DATA
received ACK
sent DATA
received ACK
sent DATA
received ACK
sent DATA
received ACK
sent DATA
received ACK
sent DATA
received ACK
sent DATA
received ACK
sent DATA
received ACK
sent DATA
received ACK
Sent 4216 bytes in 0.1 seconds [337280 bits/sec]
|
Клиент tftp не поддерживает согласование размера блока по RFC1783, поэтому размер передаваемого файла ограничивается значением 32 Мб. На трассировке это выглядит следующим образом:
.. .. .. ..
sent DATA
received ACK
sent DATA
received ACK
sent WRQ
sent WRQ
received ACK
sent WRQ
received ACK
sent WRQ
received ACK
sent WRQ
received ACK
Transfer timed out.
|
То есть клиент (рассматривается отправка файла), отослав блок номер 65535, не может отослать следующий из-за переполнения счетчика и повторно отправляет запрос на запись WRQ. Сервер же ожидает следующий блок, повторяя периодически подтверждение блока 65535. По истечении тайм-аута соединение разрывается. При этом передаваемый файл сохраняется на сервере частично (он вроде бы и есть, но попытка его использовать приведет к ошибке). Таким образом, не следует использовать TFTP для обмена большими файлами.
Сервер tftpd
Несмотря на букву «d» в конце имени, tftpd не является демоном, его запуск выполняется супердемоном inetd при появлении запроса на порту 69. По умолчанию соответствующая строка в /etc/inetd.conf закомментирована, и для активизации сервера комментарий нужно удалить и перезапустить процесс inetd.
Все настройки поведения сервера выполняются с помощью ключей командной строки путем редактирования файла /etc/inetd.conf. Наиболее часто используются следующие опции:
- -s <каталог>: после запуска tftpd установит указанный каталог как корневой, используя функцию chroot. Если не указан пользователь (см. опцию -u), то процесс получает права nobody.
- -c: позволяет привязывать корневой каталог сервера к IP-адресу удаленного хоста. Используется совместно с опцией –s, указывающей базовый каталог. Например, если базовый каталог определен как /var/tftp, то при получении запроса с адреса 1.2.3.4 корневым каталогом будет являться /var/tftp/1.2.3.4. Если данный каталог отсутствует, соединение разрывается.
- -C: аналогична ключу -c, но при отсутствии каталога, соответствующего адресу клиента, корневым каталогом становится базовый.
- -l: включает режим протоколирования работы, используя syslog (сообщения сохраняются как LOG_FTP).
- -u <пользователь>: указывается имя непривилегированного пользователя, с правами которого будет работать сервер после переключения в chroot. Пользователь должен быть задан по имени, использование UID недопустимо.
- -w: разрешает создавать несуществующие файлы по запросу на запись. По умолчанию запись файла разрешена только в том случае, если он существует и доступен для записи пользователю, от имени которого работает процесс tftpd.
Особое внимание следует уделить вопросу безопасности. Поскольку сам сервер tftpd не выполняет никаких проверок авторизации, то доступ к нему необходимо ограничивать. Наиболее часто для этого используют брандмауэры, пропуская пакеты на 69-й порт только с разрешенных узлов. Также может быть удобен файл /etc/hosts.allow, которым руководствуется inetd, решая, запускать ли соответствующий процесс при попытке установить соединение на том или ином порту или нет.
Если нужно позволить клиентам запись любых файлов, то рекомендуется использовать опцию -w совместно с -c, чтобы такая запись была разрешена только с указанных известных адресов. Однако не забывайте о возможности подмены IP-адреса отправителя, что открывает возможность для атаки типа «Отказ в обслуживании» путем переполнения соответствующей файловой системы.
Также рекомендуется с файлов, которые предназначены только для считывания, снимать права на запись. Если файл требуется записывать на сервер, но он не предназначен для чтения другими пользователями, можно поставить на него права 222 (-w--w--w-). При включенной опции –w это можно автоматизировать с помощью ключа «-U mask», который определяет маску для создаваемых (самим процессом tftpd по запросу на запись) файлов. Для описанного выше примера следует указать «-U 555» – в этом случае каждый созданный по запросу клиента файл получит разрешение только на запись и не сможет быть никем прочитан (кроме администратора сервера, разумеется).
Обмен файлами с маршрутизатором CISCO
В качестве примера рассмотрим применение TFTP для сохранения на сервер конфигурации с CISCO (например, для более удобного редактирования или как резервную копию) и последующую загрузку на CISCO с сервера.
Итак, предполагая, что обмен с CISCO выполняется по изолированной сети 10.100.100.0/24, а интересующие нас устройства имеют адреса 10.100.100.1 и 10.100.100.2, запуск tftpd удобно выполнять со следующими ключами:
tftpd -clw -s /var/tftp/cisco -u tftp
Создаем каталог /var/tftp/cisco, и в нем две директории 10.100.100.1 и 10.100.100.2, владельцем которых делаем пользователя tftp (создать его придется вручную). Разрешаем прохождение соединений на порт 69 с указанных адресов через все запущенные в системе пакетные фильтры. Теперь после перезапуска inetd (или перезагрузки сервера) tftpd готов к работе.
На CISCO копирование на сервер выполняется командой copy:
Host>ena
Host #copy running-config tftp:
Address or name of remote host []? 10.100.100.254
Destination filename [host-confg]? config
!!!!!!
20693 bytes copied in 1.044 secs (19821 bytes/sec)
|
Аналогично можно загружать конфигурацию с сервера на CISCO, поменяв местами аргументы команды copy.
Заключительное слово
Надеюсь, эта статья поможет вам эффективно использовать протокол TFTP в своей работе. Главное – не забывайте о безопасности, которую приходится обеспечивать внешними по отношению к TFTP средствами.