СЕРГЕЙ СУПРУНОВ
FreeBSD tips: какими возможностями обладает ftpd
Протокол FTP предназначен для передачи файлов по сети. Существует множество очень функциональных ftp-серверов, однако для использования в «личных» целях, как правило, вполне достаточно возможностей входящей в состав FreeBSD программы ftpd.
Программа ftpd представляет собой достаточно простой ftp-сервер. В отличие от таких инструментов, как ProFTPd, PureFTPd и других, ftpd не имеет развитых средств конфигурирования, работы с правами доступа и т. д. Однако если вы не собираетесь строить публичный ftp-сервер, то его возможностей вам вполне хватит для организации «бытовых» функций, таких как обмен файлами между сервером и вашей рабочей машиной, например, для размещения HTML-страниц на веб-сервере или настройки простейшего резервирования.
Начнем с теории
Для начала давайте коротко ознакомимся с самим протоколом FTP. Он описывается довольно объемным документом RFC 959 и определен только для транспортного протокола TCP; UDP-реализации, в отличие от TFTP, нет.
Характерной отличительной особенностью FTP от других протоколов является то, что он для своей работы задействует два порта – порт данных и порт управления. Порт управления используется для установления соединения между клиентом и сервером, для управления режимами работы и т. д.
В то время как порт данных служит для передачи запрашиваемой информации.
Протоколом определены два режима взаимодействия: активный и пассивный, понимание которых крайне важно в случае использования в сети брандмауэров.
Активный режим работы FTP
В активном режиме процесс установления соединения между сервером и клиентом выглядит следующим образом:
- Клиент с непривилегированного порта (с номером больше 1024) отправляет запрос на порт 21 сервера (порт управления).
- После процедуры авторизации (команды USER и PASS) клиент начинает прослушивать порт N и отправляет на сервер команду PORT, сообщающую ему, какой именно порт открыт.
- Сервер, получив команду PORT, устанавливает соединение с указанным портом N со своего порта 20. Это соединение используется для передачи данных.
Посмотрим, как это происходит на практике. Для эмуляции работы управляющего соединения вполне подойдет стандартная утилита telnet. Чтобы посмотреть, как работает порт данных, воспользуемся небольшой программкой на Python:
#!/usr/local/bin/python
# lystener – скрипт для прослушивания указанного порта
import sys, socket
host = str(sys.argv[1])
port = int(sys.argv[2])
s = socket.socket()
s.bind((host, port))
s.listen(1)
m = s.accept()
print 'Connected on', m[1]
while(1):
rsv = str(m[0].recv(256))
print rsv
if rsv == '':
print 'No data more. Connection is closed.'
break;
m[0].close()
s.close()
Этот скрипт будет прослушивать соединение на указанном в параметрах командной строки порту и выводить на экран всю полученную через созданный сокет информацию.
Откроем две терминальные сессии, которые условно назовем cmd (порт управления, обмен данными показан зеленым шрифтом) и data (порт данных, соответствующие строки – серые). Ввод пользователя выделен красным шрифтом. На приведенном ниже листинге строки обоих терминалов показаны вперемежку, отображая хронологию их работы:
cmd: serg$ telnet localhost 21
cmd: Trying 127.0.0.1...
cmd: Connected to localhost.
cmd: Escape character is "^]".
cmd: 220 myserver.ru FTP server (Version 6.00LS) ready.
cmd: USER username
cmd: 331 Password required for username.
cmd: PASS userpasswd
cmd: 230 User username logged in, access restrictions apply.
|
data: serg$ ./lystener localhost 25623
cmd: PORT 127,0,0,1,100,23
cmd: 200 PORT command successful.
cmd: LIST
cmd: 150 Opening ASCII mode data connection for "/bin/ls".
data: Connected on ("127.0.0.1", 20)
data: total 8
data: drwxr-xr-x 2 0 0 512 Jun 4 2001 bin
data: drwxr-xr-x 2 1012 0 512 Sep 21 07:44 downdata
data: drwxr-xr-x 2 1012 0 512 Nov 12 2004 mankit
data: drwxr-xr-x 2 1012 0 512 Aug 26 04:58 updata
data:
data:
data: No data more. Connection is closed.
cmd: 226 Transfer complete.
cmd: QUIT
cmd: 221 Goodbye.
cmd: Connection closed by foreign host.
|
Итак, сначала мы устанавливаем соединение с портом 21 сервера, проходим процедуру аутентификации. Затем запускаем во втором терминале наш скрипт lystener на порту 25623 хоста localhost. Теперь даем серверу команду PORT, сообщая, на каком именно порту мы ждем соединения. Обратите внимание на синтаксис команды: в качестве аргументов указываются шесть октетов (первые четыре соответствуют IP-адресу хоста, последующие два – старший и младший байты номера порта). В нашем случае порт данных – 100*256 + 23 = 25623.
Теперь по команде LIST, запрашивающей список файлов в текущем каталоге, сервер устанавливает соединение с указанным портом (со стороны сервера используется порт 20) и передает запрошенные данные, которые и фиксирует наш сценарий. После выполнения команды соединение по порту данных разрывается, но управляющее соединение сохраняется, пока не будет подана команда QUIT.
Как видите, активный режим удобен для администратора сервера, поскольку при этом задействуются только порты 20 и 21 (причем инициализация соединения – только на 21 порту), а остальные можно смело закрыть брандмауэром. С другой стороны, для клиента этот режим крайне неприятен, так как вынуждает держать открытыми непривилегированные порты. Поскольку общепринятой практикой является запрет любых входящих соединений на клиентские машины (а в случае работы через NAT вообще требуется выполнять «проброс» внешних соединений до клиента либо организовывать работу в режиме прокси-сервера), то в этом плане более удобным является пассивный режим.
Пассивный режим работы FTP
В этом случае все соединения инициируются клиентом, что позволяет обойти ограничения, налагаемые обычно брандмауэром и серверами NAT. Процесс организации соединения теперь выглядит следующим образом:
- Клиент с непривилегированного порта (с номером больше 1024) отправляет запрос на порт 21 сервера (порт управления).
- После процедуры авторизации (команды USER и PASS) клиент отправляет на сервер команду PASV, информирующую о том, что он намерен работать в пассивном режиме.
- Сервер открывает непривилегированный порт и сообщает его номер клиенту.
- Клиент со своего порта N инициирует соединение на указанный сервером порт, который и используется для обмена данными.
Чтобы смоделировать работу FTP-клиента в пассивном режиме достаточно двух telnet-сессий:
cmd: serg$ telnet localhost 21
cmd: Trying 127.0.0.1...
cmd: Connected to localhost.
cmd: Escape character is "^]".
cmd: 220 myserver.ru FTP server (Version 6.00LS) ready.
cmd: USER username
cmd: 331 Password required for username.
cmd: PASS userpasswd
cmd: 230 User username logged in, access restrictions apply.
cmd: PASV
cmd: 227 Entering Passive Mode (127,0,0,1,245,5)
|
data: serg$ telnet localhost 62725
data: Trying 127.0.0.1...
data: Connected to localhost.
data: Escape character is "^]".
cmd: LIST
cmd: 150 Opening ASCII mode data connection for "/bin/ls".
data: total 8
data: drwxr-xr-x 2 0 0 512 Jun 4 2001 bin
data: drwxr-xr-x 2 1012 0 512 Sep 21 07:44 downdata
data: drwxr-xr-x 2 1012 0 512 Nov 12 2004 mankit
data: drwxr-xr-x 2 1012 0 512 Aug 26 04:58 updata
data: Connection closed by foreign host.
cmd: 226 Transfer complete.
cmd: QUIT
cmd: 221 Goodbye.
cmd: Connection closed by foreign host.
|
На этот раз оба соединения устанавливаются со стороны клиента. Порт, на котором следует открывать соединение для передачи данных, сервер указывает в ответ на команду PASV (в данном случае 245*256 + 5 = 62725).
Однако на сервере при этом должны быть разрешены соединения на непривилегированные порты, что не позволяет достаточно жестко ограничивать доступ. Как вы, должно быть, заметили, в пассивном режиме 20 порт не используется.
Расширенные режимы
В дополнение к описанным выше, документ RFC 2428 определяет так называемые расширенные режимы, которые позволяют работать в сетях IPv6. В расширенных режимах вместо команд PORT и PASV используются EPRT и EPSV соответственно. Синтаксис EPRT следующий:
EPRT |протокол|адрес|порт|
Здесь «протокол» может иметь значение 1 (IPv4) или 2 (IPv6), «адрес» – IP-адрес, синтаксис которого должен соответствовать используемому семейству протоколов, «порт» – номер порта.
Команда EPSV может в качестве параметра принимать 1 или 2 (указывает семейство протоколов, которое поддерживает клиент). Кроме того, специальная команда EPSV ALL информирует сервер о том, что в дальнейшем будет использоваться только команда EPSV, и все остальные команды на установление соединения следует отбрасывать.
Что поддерживает ftpd
Сервер ftpd, входящий в состав FreeBSD, по умолчанию может обслуживать как активные, так и пассивные соединения (в том числе и расширенные), режим работы для конкретного сеанса определяется клиентом. Работать ftpd может как в режиме демона (постоянно присутствует в памяти и самостоятельно обслуживает соединения на 21 порт), так и в сотрудничестве с супердемоном inetd, который осуществляет вызов сервера при получении входящего соединения на порту 21.
Если доступ на ваш сервер по FTP требуется довольно редко, то более удобным выглядит использование inetd для запуска сервера (если, конечно, этот демон у вас используется). В этом случае не придется держать в памяти сервер ftpd постоянно – он будет загружаться лишь для обслуживания конкретного соединения.
Типичная строка запуска в /etc/inetd.conf выглядит следующим образом:
# ftp stream tcp nowait root /usr/libexec/ftpd ftpd -l
Снимите с нее комментарий, пошлите сигнал HUP процессу inetd, и вы получите работающий ftp-сервер, настроенный по умолчанию. О том, что это за настройки и как их можно изменить, мы поговорим в следующем разделе.
Если по соображениям безопасности вы не используете inetd, а также если FTP-доступ к вашему серверу выполняется достаточно часто, то выгоднее запустить ftpd в режиме демона (с ключом -D). В этом случае сервер будет постоянно находиться в памяти.
В стартовых сценариях FreeBSD не предусмотрено запуска ftpd в режиме демона, но нужный скрипт несложно написать самостоятельно. Поместите в каталог /etc/rc.d такой файл ftpd:
#!/bin/sh
#
# PROVIDE: ftpd
# REQUIRE: DAEMON LOGIN
# KEYWORD: shutdown
. /etc/rc.subr
name="ftpd"
rcvar=`set_rcvar`
command="/usr/libexec/${name}"
load_rc_config $name
ftpd_flags="-D ${ftpd_flags}"
run_rc_command "$1"
Не забудьте сделать его исполнимым (chmod a+x ftpd). Чтобы этот сценарий мог запускать сервер ftpd, в файл/etc/rc.conf нужно добавить следующие строки:
ftpd_enable="YES"
ftpd_flags="-E"
Вторая строка необязательна и задает дополнительные параметры запуска (ключ -D будет добавлен приведенным выше сценарием автоматически). Теперь ftpd будет автоматически стартовать при загрузке операционной системы. Кроме того, вы можете вручную запускать и останавливать его:
# /etc/rc.d/ftpd start
# /etc/rc.d/ftpd stop
Теперь ftpd будет вести себя так же, как и любой другой сервис.
Поговорим о его работе и настройке.
Как работает ftpd
Сервер ftpd поддерживает авторизованный и анонимный доступ. В любом случае в начале каждого сеанса проводится аутентификация пользователя, после чего пользователь авторизуется для работы в соответствие со следующими условиями:
- Если пользователь имеет пустой пароль, либо его оболочка по умолчанию отсутствует в /etc/shells, либо его имя (или наименование группы, членом которой он является) указано в файле /etc/ftpusers, то соединение разрывается – такому пользователю запрещен доступ по ftp.
- Когда имя пользователя или его группа указаны в файле /etc/ftpchroot, то разрешается ограниченный доступ – пользователь может работать только в пределах своего домашнего каталога.
- В случае, когда в качестве имени указано ftp или anonymous, соединение рассматривается как анонимное (подробнее об анонимном доступе рассказано в следующем подразделе).
- Если же ни одно из приведенных выше условий не выполнено, то в случае указания правильного пароля пользователь получает ftp-доступ ко всей файловой системе согласно имеющимся у него правам.
Анонимный доступ
Чтобы разрешить анонимный доступ по FTP, вам потребуется вручную создать системного пользователя с именем ftp. У этого пользователя должна быть «легальная» оболочка (одна из указанных в /etc/shells), и он должен иметь домашний каталог, в котором и будут размещаться файлы, доступные анонимному пользователю. Также у него не может быть пустого пароля. По умолчанию, анонимный пользователь не может модифицировать или удалять существующие файлы. Разрешено только создавать новые при условии, что пользователь ftp будет иметь достаточно прав на запись. Дополнительно регулировать доступ к каталогам и файлам (например, полностью запретить запись в определенную папку) можно силами операционной системы, выставляя соответствующие права пользователю ftp. В частности, рекомендуется запрещать для пользователя ftp запись в его домашний каталог, чтобы исключить возможность переполнения раздела, на котором он размещен.
Ограниченный доступ
В том случае, если имя пользователя присутствует в файле /etc/ftpchroot, то соответствующий процесс запускается в chroot-окружении, ограничивая пользователю доступ только его домашним каталогом (или тем, который указан во втором поле файла ftpchroot). При необходимости организовать такую работу для большого числа пользователей (например, дать всем абонентам доступ для обновления своих домашних веб-страничек), в ftpchroot можно указать общую для них группу, предварив ее имя символом @. Во втором поле дополнительно может быть указан каталог, который следует использовать в качестве корневого для соответствующего пользователя или группы. Вот пример такого файла:
vasya
petya /var/db/petya
@dialup
Теперь Вася и все пользователи группы dialup смогут работать только в пределах своих домашних каталогов, а для Пети в качестве рабочей будет определена указанная папка /var/db/petya. С помощью разделителя /./ можно указать каталог, отличающийся от корневого, который станет текущим:
serg /home/serg/./public_html
В данном случае для пользователя serg доступ будет ограничен каталогом /home/serg, но в качестве текущего при входе на сервер установится /home/serg/public_html.
Как подстроить ftpd под собственные задачи
Некоторые настройки сервера, в том числе и касающиеся ограничения доступа, можно выполнить с помощью ключей командной строки. Если вы запускаете ftpd из inetd, добавьте нужные параметры в соответствующей строке файла inetd.conf (по умолчанию там записан только ключ l). Если же предпочтете воспользоваться приведенным выше сценарием для запуска ftpd в режиме демона, то дополнительные ключи можно указать в файле rc.conf, в строке ftpd_flags.
Некоторые ключи, которые могут быть полезны:
- -D: запускать ftpd в режиме демона.
- -a <адрес>: в режиме демона принимать соединения только на указанный IP-адрес.
- -d: включить режим отладки (подробная информация о работе будет выдаваться серверу syslog как LOG_FTP).
- -h: не выводить информацию о системе в сообщениях сервера.
- -l: протоколировать все сессии (обычно используется/var/log/xferlog).
- -A: разрешить только анонимный доступ.
- -M: запретить анонимным пользователям создавать папки.
- -m: разрешить анонимным пользователям модифицировать существующие файлы (если для этого достаточно системных прав).
- -o, -O: разрешить только запись на сервер всем пользователям (-o) или только анонимному пользователю (-O). В частности, таким образом можно организовать сбор с удаленных серверов файлов резервных копий, чтение которых пользователями не предусмотрено.
- -r: перевести сервер в режим «только для чтения». Любая модификация размещенных данных будет запрещена.
Дополнительную информацию всегда можно найти на странице руководства man ftpd(8).
Заключение
Как видите, ftpd вполне пригоден для решения большинства типовых задач по обмену файлами. Если ваши потребности не выходят за пределы его возможностей, то вряд ли имеет смысл обременять систему установкой дополнительных пакетов. Однако если вам требуется создать «промышленный» FTP-сервер, позволяющий более гибко управлять правами доступа, пользователями, параметрами передачи файлов, то воспользуйтесь более серьезным решением.