Опубликована в журнале «Системный администратор«, Июль 2004
При работе в локальной сети правила безопасности на сервере, как правило, относятся сразу ко всей подсети. Причем вполне обычная практика — оставлять в адресном пространстве резерв для будущего расширения. Да и невозможно в принципе задать подсеть, содержащую ровно 7 адресов — все равно придется выделять 14. То есть практически в любой сети есть неиспользуемые адреса, на которые распространяются общие правила доступа. Конечно, любые поползновения извне можно очень эффективно отсекать пакетными фильтрами и прочими изобретениями изворотливого человеческого разума. Но вряд ли найдется организация, в которой системный администратор может свято верить в грамотность, ответственность и порядочность всех без исключения сотрудников, работающих в сети изнутри. А если политика компании включает еще и попытки учитывать и ограничивать трафик с каждого IP-адреса, то нет никаких гарантий, что никому не придет в голову «случайно» прописать в своих настройках адрес соседа…
Данная заметка о том, как решить указанную выше проблему, если роутер, через который локальная сеть выходит в «мир», построен на базе FreeBSD, а сама сеть включает два-три десятка машин, сосредоточенных в одном сегменте (при большем количестве компьютеров эффективность описываемой методики заметно снижается, хотя она и остается вполне работоспособной). Не могу гарантировать, что на всех версиях этой ОС все будет работать так, как описано, но для FreeBSD 5.2 никаких проблем обнаружено не было. Да, собственно, и взяться им неоткуда, настолько все просто.
Сначала — немного теории. Для передачи кадра (речь будет идти об Ethernet) другому устройству сетевой адаптер машины должен знать его физический (MAC) адрес. Удаленное устройство будет принимать только кадры, содержащие в заголовке (поле Destination) его адрес, то есть адресованные именно ему. Ну, еще широковещательные кадры, адресованные на специальный адрес ff:ff:ff:ff:ff:ff. Но поскольку работа протоколов верхних уровней основана на IP-адресах, то кто-то должен уметь сопоставлять IP-адрес сетевого устройства с MAC-адресом его адаптера. Этим «кем-то» является протокол ARP (address resolution protocol).
Собственно говоря, вся работа ARP заключается в том, чтобы по IP-адресу хоста возвратить MAC-адрес его адаптера, который используется для связи с данной машиной. Для этого ARP формирует в памяти компьютера (или другого устройства, на котором он запущен, например, коммутатора) таблицу соответствия, именуемую далее ARP-таблицей. Если требуемый физический адрес в ARP-таблице существует, то все соответствующие кадры направляются на него. Если нет, то отправляется широковещательный фрейм с IP-адресом искомого хоста. Этот фрейм принимают все адаптеры, и если, обработав этот запрос, удаленный хост видит в нем свой Интернет-адрес, то он отсылает ответ запросившему устройству, в котором, помимо прочего, содержится и MAC-адрес его адаптера. Эта информация добавляется в ARP-таблицу для дальнейшего использования.
Формируемые описанным выше способом, то есть динамически, записи в ARP-таблице сохраняются временно. Если в течение 20 минут (значение по умолчанию) обращения к записи не происходит, она удаляется из таблицы.
Помимо динамических записей, в ARP-таблице могут быть созданы постоянные (permanent), они же статические, записи. Они хранятся «вечно» (точнее — до перезагрузки), и, кроме того, попытка установить соединение с «чужим» IP-адресом с треском провалится, а в системном журнале появится сообщение об ошибке. К слову сказать, изменение динамической записи также сопровождается соответствующим сообщением, но соединение при этом устанавливается без каких-либо трудностей. Кроме того, если на момент подмены IP-адреса динамической записи с его участием в ARP-таблице не существует, то и никаких разоблачающих сообщений не появится.
Управлять записями ARP-таблицы позволяет одноименная утилита arp. Ее полный синтаксис доступен в man arp(8). Нам понадобятся следующие команды:
arp -a выводит содержимое таблицы ARP. arpвыводит ARP-запись для заданного хоста. arp -d удаляет запись, соответствующую хосту. arp -d -a удаляет все записи таблицы. arp -s добавляет запись. arp -f добавляет записи из файла соответствия .
Таким образом, дальнейшие действия понятны — для всех «критических» (а если сеть небольшая — то просто для всех) IP-адресов можно создать статические записи в ARP-таблице, тем самым исключив их подмену. Для этого существует два пути:
- Использовать команду arp -s для создания каждой записи;
- Создать файл соответствия и выполнить команду arp -f .
Первый способ слишком трудоемкий, поэтому возьмем на вооружение второй вариант. В этом случае файл соответствия требуется создать один раз, и в дальнейшем будет очень легко обеспечить автоматическое заполнение ARP-таблицы статическими записями при перезагрузке компьютера.
Формат файла соответствия продемонстрирован на следующем примере:
# Host MAC-address 192.168.0.1 00:05:5d:ce:d6:3f 192.168.0.2 00:05:5d:29:ec:f4
То есть в каждой строке записывается IP-адрес хоста (либо его каноническое имя) и через пробелы или символы табуляции — соответствующий ему MAC-адрес. Заполнить его достаточно просто — включите все машины сегмента и обратитесь с них к серверу (или с сервера к ним) любым способом, например, запустите на них браузер или выполните обычный пинг. Это обновит ARP-таблицу, после чего достаточно будет сохранить в файл результат выполнения команды «arp -an» и немного его подправить, удалив все лишнее и добавив нужное. Сократить необходимые правки позволит следующая команда:
# arp -an | awk -v OFS="\t" '{print(substr($2, 2, length($2)-2), $4)}' > ethers
Теперь файл ethers будет заполнен нужным образом. Останется только удалить записи, которые мы хотим оставить динамическими (например, маршрутизаторы CISCO при перезагрузке могут менять MAC-адрес своих интерфейсов, выбирая их из некоторого пула, а добираться среди ночи на работу, чтобы подправить ARP-таблицу — занятие не из приятных).
Для адресов, которые не задействованы в подсети, можно создать статические записи с фиктивными физическими адресами (например, 00:11:22:33:44:55). Это исключит возможность использования кем-либо данных IP-адресов.
Далее очищаем ARP-таблицу и заполняем ее из сформированного файла:
# arp -d -a # arp -f /usr/local/etc/ethers
Естественно, имя и местоположение файла соответствия может быть любым удобным для Вас. Теперь осталось занести указанные команды в сценарий автозапуска, например, с именем /usr/local/etc/rc.d/statarp.sh:
#!/bin/sh # Static ARP-table loader case $1 in start) arp -d -a > /dev/null arp -f /usr/local/etc/ethers > /dev/null echo 'Static ARP-table is loaded' ;; stop) arp -d -a > /dev/null echo 'Static ARP-table is unloaded' ;; restart) arp -d -a > /dev/null arp -f /usr/local/etc/ethers > /dev/null echo 'Static ARP-table is reloaded' ;; status) arp -an ;; *) echo "Usage: `basename $0` {start|stop|restart|status}" >&2 ;; esac exit 0
Осталось не забыть сделать данный файл исполняемым.
Итак, мы получили статическую таблицу соответствия между IP- и MAC-адресами. Теперь выход в Интернет через FreeBSD-сервер с «чужого» IP-адреса станет невозможным, если, конечно, заодно не подменить и MAC-адрес (с последним явлением можно бороться разве что организационными методами).
Но любая палка, как известно, о двух концах. За повышение защищенности сети придется платить дополнительными заботами по администрированию, поскольку теперь добавление новой машины в сеть, замена сетевого адаптера, смена IP-адреса должны сопровождаться правкой и перезагрузкой ARP-таблицы. Хотя это все равно лучше, чем бегать по этажам, «вычисляя» недобросовестного пользователя.