BSDA в вопросах и ответах

Евгений Миньковский

Ревизия 180, сборка 20 июня 2008 года.

Аннотация

Данная книга задумана как методическое пособие для подготовки к экзамену BSDA. Книга, тем не менее, может быть полезна не только тем кто собирается сдавать этот экзамен, но и просто широкому кругу IT-специалистов, желающих систематизировать свои знания об операционных системах семейства BSD (NetBSD, OpenBSD, FreeBSD, DragonFly BSD).

В формате HTML книга доступна в виде одной большой страницы (данный вариант) и в многостраничном варианте .

Собственно вопросы экзамена BSDA можно посмотреть отдельно.

[Замечание]Замечание

Работа ещё только начата, в оглавлении приняты следующие обозначения:

«Избранный» раздел: автор удивлён, что данный раздел получился так хорошо;
Раздел в целом закончен, хотя возможно, будет дорабатываться в будущем;
Раздел находится в работе;
К написанию данного раздела автор не приступал.

Впрочем, в Москве даже на улицах светофоры не всегда горят правильно, что уж говорить об этом труде...


Содержание

Мычание
1. Легенда (условные обозначения)
2. Экзаменационные блоки
3. Источники информации
3.1. Официальные источники
3.2. Неофициальные источники
3.3. Специализированные поисковые машины
[-]1. Установка и обновление операционной системы и програмного обеспечения
[-]1.1. Разбираться в программах установки каждой операционной системы
[-]1.2. Разбираться какие команды доступны для upgrade'а операционной системы
[-]1.3. Понимание разницы между заранее скомпилированными бинарными дистрибутивами и компиляцией из исходников
[-]1.4. Понимание когда выгодно инсталлировать прекомпилированные бинарники и как это делать
[-]1.5. Разбираться в методах настройки и компилирования бинарников
[-]1.6. Определять, какое програмное обеспечение инсталлировано в системе
[-]1.7. Определять, какое програмное обеспечение нуждается в обновлении
[-]1.8. Обновлять установленное програмное обеспечение
[-]1.9. Определять, какое програмное обеспечение имеет проблемы с безопасностью
[-]1.10. Следовать инструкциям секьюрити-консультантов и накладывать security-patch
[*]2. Безопасность в операционной системе
[*]2.1. Определить уровень безопасности системы
[*]2.1.1. Установка уровня безопасности системы
[*]2.1.2. Допустимые значения переменной securelevel
[*]2.1.3. Ссылки
[-]2.2. Конфигурирование сервера SSH в соответствии с требованиями
[-]2.3. Конфигурировние SSH сервера для аутентификации по ключу
[-]2.4. Предохранение ключа при обновлении системы
[-]2.5. Разбираться в альтернативных механизмах аутентификации
[-]2.6. Разбираться в альтернативных методах авторизации
[-]2.7. Разбираться в основных рекомендованных методах доступа [до хоста]
[*]2.8. Разбираться в брандмауэрах BSD и синтаксисе конфигурационных файлов
[-]2.8.1. Общие принципы работы с брандмауэрами
[-]2.8.2. Сравнение брандмауэров BSD
[-]2.9. Разбираться в механизмах использования шифровальных устройств BSD
[-]2.10. Разбираться в методах проверки аутентичности бинарного файла
[*]2.11. Разбираться в способах запуска сервиса в изолированной среде (restraining service)
[+]2.11.1. chroot(8)
[+]2.11.2. jail(8)
[-]2.11.3. systrace(1)
[-]2.11.4. Xen
[+]2.12. Смена алгоритма шифрования используемого для защиты базы с паролями
[+]2.12.1. Устройство базы паролей
[+]2.12.2. /etc/login.conf(5)
[+]2.12.3. /etc/auth.conf(5)
[+]2.12.4. /etc/passwd.conf(5)
[+]2.12.5. adduser(8)
[+]2.12.6. Итого: Blowfish HOWTO
[-]2.13. Смена приветствия системы
[-]2.14. Защита аутентификационных данных
[-]3. Файлы, файловые системы и диски
[-]3.1. Монтирование и размонтирование файловых систем
[-]3.2. Конфигурирование NFS
[-]3.3. Определение какие файловые системы смонтированы и какие будут смонтированы при загрузке
[-]3.4. Определять ёмкость диска и какие файлы занимают больше места
[-]3.5. Создание и просмотр символических и жёстких ссылок
[-]3.6. Просмотр и изменение ACL
[-]3.7. Просмотр и изменение пермиссий с использованием как символьных, так и восьмеричных мод
[-]3.8. Изменение владельца файла и группы
[-]3.9. Резервное копирование и восстановление файлов и директорий на локальный диск или ленту
[-]3.10. Резервное копирование и восстановление файловой системы
[-]3.11. Знание структуры каталогов системы
[-]3.12. Ручной запуск программы проверки файловой системы и средств её восстановления
[-]3.13. Определение и изменение флагов файлов
[-]3.14. Слежение за состоянием виртуальной памяти системы
[*]4. Пользователи и управление учётными записями
[*]4.1. Создание, изменение и удаление учётных записей
[*]4.1.1. Введение
[*]4.1.2. Добавление пользователя
[*]4.1.3. Изменение параметров пользовательской учётной записи
[*]4.1.4. Удаление учётной записи
[*]4.2. Создание системных учётных записей
[-]4.3. Отключение или включение учётной записи (lock и unlock)
[-]4.4. Идентификация и членство в группах
[-]4.5. Определение кто сейчас присутствует в системе или последнего времени входа в систему
[-]4.5.1. finger(1)
[-]4.6. Включение слежения за учётными записями и просмотр статистики
[-]4.7. Изменение пользовательской оболочки
[-]4.8. Контролировать какие файлы будут копироваться в новую пользовательскую директорию при создании учётной записи
[-]4.9. Смена пароля
[-]5. Основы системного администрирования
[-]5.1. Определение какой процесс расходует основную часть ресурсов ЦПУ
[-]5.2. Определять активные процессы и посылать им сигналы
[-]5.3. Использование скриптов rc(8) для определения запущенных сервисов, их запуск, остановка и перезапуск
[*]5.4. Определение установленного оборудования и его конфигурирование
[+]5.4.1. Утилита dmesg(8)
[-]5.5. Определение какие модули ядра загружены, их загрузка и выгрузка
[-]5.6. Изменение на лету переменных ядра
[-]5.7. Изучение состояния програмного RAID'а (mirror or stripe)
[-]5.8. Определение какой MTA используется системой
[-]5.9. Конфигурирование системы ведения системных журналов
[-]5.10. Просмотр журналов для разрешения проблем и слежения за поведением системы
[-]5.11. Понимание основных проблем с принтером
[-]5.12. Создание или изменение почтовых псевдонимов в Sendmail и Postfix
[-]5.13. Остановка, перезагрузка или перевод системы в однопользовательский режим
[-]5.14. Отличие жёстких ограничений от мягких и изменение существующих системных ограничений
[-]5.15. Знание утилит BSD для регулировки трафика и контроля за полосой пропускания
[-]5.16. Знание распространённых конфигурационных системных файлов и, возможно, сторонних конфигурационных файлов различных сервисов
[-]5.17. Конфигурирование сервисов для автоматического старта при запуске системы
[-]5.17.1. Система инициализации BSD
[-]5.17.2. Суперсервер inetd(8)
[-]5.18. Конфигурирование скриптов, нужных для различных задач по обслуживанию системы, для периодического запуска
[-]5.19. Просмотр очереди Sendmail'а или Postfix'а
[-]5.20. Определение когда последний раз была запущена система и какова её загруженность
[-]5.21. Слежение за операциями ввода/вывода на диске
[-]5.22. Работа с занятыми устройствами
[-]5.23. Определение информации характеризующей операционную систему
[-]5.24. Понимание преимуществ использования лицензии BSD
[*]6. Сетевое администрирование
[+]6.1. Определение существующих установок TCP/IP
[+]6.1.1. ifconfig(8) — настройки сетевых интерфейсов
[+]6.1.2. netstat(1)
[+]6.1.3. route(8)
[+]6.1.4. /etc/resolv.conf(5)
[+]6.1.5. hostname(1)
[+]6.2. Установка параметров TCP/IP
[+]6.2.1. hostname(1) — задание имени машины
[+]6.2.2. ifconfig(8) — настройки сетевых интерфейсов
[+]6.2.3. route(8) — настройка таблицы маршрутизации
[+]6.2.4. resolv.conf(5) — настройка клиента DNS
[+]6.2.5. hosts(5) — локальная база имён
[+]6.2.6. Как сохранить установленные сетевые параметры
[+]6.3. Определение какие TCP или UDP порты открыты в системе
[+]6.3.1. fstat(1)
[+]6.3.2. sockstat(1)
[+]6.3.3. lsof(1)
[*]6.3.4. nmap(1)
[*]6.4. Проверка доступности TCP/IP сервиса
[+]6.4.1. ping(8)
[+]6.4.2. traceroute(1)
[*]6.4.3. hping(8)
[+]6.4.4. telnet(1), nc(1)
[*]6.5. Запрос к серверу DNS
[*]6.5.1. Теория вопроса
[+]6.5.2. host(1)
[+]6.5.3. dig(1)
[+]6.5.4. nslookup(1)
[+]6.6. Определение кто ответственный за зону DNS
[+]6.6.1. Обратное преобразование имён
[+]6.6.2. whois(1)
[+]6.7. Изменение порядка разрешения имён
[+]6.7.1. nsswitch.conf(5)
[+]6.8. Перевод сетевой маски между системами точечно-десятичной, точечно-шестнадцатеричной или CIDR
[+]6.8.1. Что такое маска подсети
[+]6.8.2. Маска подсети в формате CIDR
[+]6.8.3. Перевод десятичных чисел в двоичные
[+]6.9. Собирать информацию используя IP адрес и маску подсети
[+]6.9.1. Определение адреса подсети по маске
[+]6.9.2. Вычисление диапазона адресов IP и широковещательного адреса
[+]6.10. Понимание теории адресации IPV6
[+]6.10.1. Синтаксис IPv6
[+]6.10.2. Типы IPv6 адресов
[+]6.10.3. Назначение адреса IPv6
[+]6.10.4. Автоконфигурирование в IPv6
[+]6.10.5. Программы для конфигурирования IPv6 в BSD
[+]6.11. Демонстрация основных навыков работы с утилитой tcpdump(1)
[+]6.11.1. Работа с программой tcpdump(1)
[-]6.11.2. Графический сниффер Wireshark/Ethereal/tEhereal
[+]6.11.3. Анализатор tcpdstat
[+]6.11.4. ngrep
[+]6.12. Работа с ARP и кешем найденных соседей
[+]6.12.1. arp(8)
[+]6.12.2. ndp(8)
[+]6.13. Конфигурирование системы для использования NTP
[+]6.13.1. TP (RFC 868) и rdate(8)
[+]6.13.2. NTP
[-]6.14. Просмотр и обновление «арендованных» данных DHCP
[-]6.15. Знание как и когда устанавливать или удалять алиасы сетевого интерфейса
[+]7. Базовые навыки работы в Unix
[+]7.1. Перенаправление вывода и использование tee(1)
[+]7.1.1. Особенности csh(1)
[+]7.2. Определение просмотр и изменение переменных окружения
[+]7.2.1. Просмотр и изменение переменных окружения
[+]7.2.2. csh(1), set, setenv
[+]7.3. Навыки работы в vi(1)
[+]7.3.1. Normal mode
[+]7.3.2. Insert Mode
[+]7.3.3. Search mode
[+]7.3.4. Command line mode
[+]7.4. Определение является ли файл бинарным, текстовым или содержащим данные
[+]7.5. Поиск файлов и бинарников в системе
[+]7.5.1. whatis(1)
[+]7.5.2. whereis(1), which(1)
[+]7.5.3. locate(1)
[+]7.5.4. find(1)
[+]7.5.5. sh type
[+]7.6. Поиск файла по заданным атрибутам
[+]7.6.1. Условия для поиска командой find(1)
[+]7.6.2. Действия выполняемые командой find(1) с найденными файлами
[+]7.6.3. Связка с командой xargs
[+]7.7. Написание несложных Bourne-скриптов
[+]7.7.1. Магическая строка (shebang)
[+]7.7.2. Почему sh(1)?
[+]7.7.3. Программирование в Bourne Shell
[+]7.8. Поиск нужной документации
[+]7.8.1. Справочная система man(1)
[+]7.8.2. Гипертекстовая справка info(1)
[+]7.8.3. Прочие источники
[+]7.9. Понимание различий в страницах man
[+]7.10. Проверка контрольной суммы файла
[+]7.10.1. cksum(1)
[+]7.10.2. md5(1)
[+]7.10.3. sha1(1)
[+]7.10.4. openssl(1)
[+]7.10.5. Примеры
[+]7.11. Продемонстрировать знакомство с оболочками используемыми по умолчанию в системе
[+]7.11.1. Предотвращение уничтожения существующих файлов
[+]7.11.2. Некоторые отличия между sh(1) и csh(1)
[+]7.11.3. Модификаторы переменных в csh(1)
[+]7.11.4. Работа с историей команд
[+]7.12. Чтение почты на локальной машине
[+]7.12.1. Работа с mail(1) в интерактивном режиме
[+]7.12.2. Использование mail(1) с командной строки
[+]7.13. Использование контроля за задачами (job control)
[+]7.14. Применение регулярных выражений
[+]7.14.1. Диалекты регулярных выражений
[+]7.14.2. Возможности команды grep(1)
[+]7.15. Преодоление ограничений на длину командной строки
[-]7.16. Понимание значения термина домен в различных контекстах
[+]7.17. Работа с cron
[+]7.17.1. Системный crontab
[+]7.17.2. Каталоги с периодически выполняемыми заданиями во FreeBSD
[+]7.17.3. Особенности OpenBSD и NetBSD
[+]7.17.4. Пользовательский crontab
[+]A. Список команд и файлов обсуждаемых в книге
[*]B. Некоторые сведения о стеке протоколов TCP/IP
[*]B.1. Классификация сетевых протоколов
[*]B.1.1. Физический уровень OSI
[*]B.1.2. Канальный уровень OSI
[*]B.1.3. Сетевой уровень OSI
[*]B.1.4. Транспортный уровень OSI
[*]B.1.5. Уровни приложения, представления и сеансовый
[*]C. Пакетный фильтр OpenBSD — pf(4)
[+]C.1. Введение в работу с пакетным фильтром OpenBSD
[*]C.2. Конфигурационный файл pf.conf(5)
[+]C.2.1. Основы конфигурирования пакетного фильтра
[+]C.2.2. Углублённое конфигурирование Пакетного фильтра
[+]C.2.3. Дополнительные разделы
[+]C.2.4. Пример: брандмауэр для дома или небольшого офиса
[*]C.3. Управление пакетным фильтром OpenBSD при помощи утилиты pfctl(8)
[*]C.3.1. Примеры
[*]C.4. Интеграция пакетного фильтра с програмным окружением
[+]C.4.1. Активное реагирование на события на примере борьбы с атаками bruteforce на SSH
[+]C.5. Программы для удобной работы с пакетным фильтром
[+]C.5.1. pfstat
[+]C.5.2. pftop
[+]C.5.3. ftpsesame
[-]D. Пакетный фильтр NetBSD — ipf(8)
[*]E. Брандмауэр FreeBSD — ipfw(8)
[+]E.1. IPFW HOWTO
[+]E.1.1. Как включить ipfw(4)
[+]E.1.2. Основы синтаксиса правил ipfw
[+]E.1.3. Углублённое изучение синтаксиса правил ipfw
[+]E.1.4. Журналирование
[+]E.1.5. Фильтрация с учётом состояния соединений
[+]E.1.6. Управление трафиком при помощи dummynet(4)
[*]F. /etc/login.conf(5)
[*]F.1. /etc/login.conf в FreeBSD
[*]F.2. /etc/login.conf в OpenBSD
Глоссарий
Литература

Список таблиц

1. Легенда (условные обозначения)
2.1. Опции запуска jail(8)
2.2. Переменные ядра (MIB) связанные с jail(8)
2.3. Возможные значения опций crypt_default (FreeBSD) и localcipher, ypcipher (OpenBSD)
6.1. Типы записей в файле зоны DNS
6.2. Аргументы команды arp(8)
7.1. Пользовательске переменные окружения [environ(7)]
7.2. Движения в vi(1), Normal mode
7.3. Действия в vi(1), Normal mode
7.4. Регулярные выражения в vi(1)
7.5. Некоторые команды vi(1)
7.6. Некоторые опции vi(1) выставляемые командой :set
7.7. Синтаксическая таблица Bourne Shell
7.8. Специальные переменные в Bourne Shell
7.9. Опции команды test(1)
7.10. Навигационные клавиши в системе info(1)
7.11. Модификаторы переменных в csh(1)
7.12. Команды программы mail(1)
7.13. Некоторые сигналы, представляющие интерес для администратора
7.14. Регулярные выражения. Сводная синтаксическая таблица
7.15. Регулярные выражения и шаблоны командной Bourne shell
7.16. Короткие имена используемые в crontab(5) для описания времени выполнения заданий
A.1. Раскладка файлов и команд по операционным системам
B.1. Типы сообщений ICMP
B.2. Формат TCP заголовка
B.3. Флаги TCP
B.4. Состояния TCP (по [RFC-793])
E.1. ICMP unreachable коды
E.2. типы ICMP сообщений опознаваемые брандмауэром IPFW
F.1. Ограничение ресурсов средствами login.conf(5)
F.2. Формирование окружения средствами login.conf(5)
F.3. Аутентификационные данные в login.conf(5)
F.4. Зарезервированные поля в login.conf(5) FreeBSD
F.5. Поля в login.conf(5) характерные для OpenBSD

Список примеров

7.1. Системный crontab файл
C.1. Просмотр статистики на интерфейсе выбранном при помощи опции loginterface
C.2. Кто из заблокированных взломщиков пытался пройти в систему в последнее время?
C.3. Просмотр таблицы состояний
C.4. Сколько пакетов на какое правило попало?

Мычание

В 2005 году стартовал проект сертификации BSDA-специалистов. BSDA расшифровывается как BSD Associate и подразумевает под собой совокупность операционных систем семейства BSD: NetBSD, OpenBSD, FreeBSD и DragonFly BSD. В рамках проекта была образована BSD CG — сертификационная группа BSD. Её сайт можно найти по адресу http://www.bsdcertification.org/. К октябрю 2005 года BSD CG разработала список тем для экзаменационных вопросов. Этот труд и лёг в основу данного пособия.

В данной книге, вы, конечно, найдёте не всё, с чем приходится сталкиваться в процессе администрирования систем. Здесь опущены такие важные темы, как администрирование web-сервера Apache, настройка proxy сервера squid, работа с системой samba, администрирование баз данных MySQL или PostgreSQL. В книге затронуты главным образом основные сервисы операционных систем BSDA, поставляемые в составе операционных систем.

Настоящая книга состоит из 7-и глав соответствующих 7-и блокам экзаменационных вопросов BSDA. Далее идут приложения в которых я постараюсь несколько более системно изложить некоторые теоретические вопросы, на которые опираются экзаменационные билеты.

1. Легенда (условные обозначения)

Таблица 1. Легенда (условные обозначения)

ЗнакЗначение
Обозначения в оглавлении
«Избранный» раздел — автор сам удивлён почему у него всё так хорошо получилось.
Раздел написан, но это не значит, что он никогда не подвергнется ревизии.
Раздел не окончен.
К написанию раздела автор не приступал.
Приглашения в листингах
$ Команда выполнялась в /bin/sh (или /usr/local/bin/bash) непривилегированным пользователем.
# Команда выполнялась в /bin/sh (или /usr/local/bin/bash) привилегированным пользователем[a].
% Команда выполнялась в /bin/csh
Принятые шрифты[b]
text Команда
text Опция
text Файл
text Акроним
Картинки
Текст относится к FreeBSD
Текст относится к OpenBSD
Текст относится к FreeBSD и OpenBSD
Orphus — система, написанная Дмитрием Котеровым (см. http://dklab.ru/chicken/nablas/24.html) для повышения грамотности рунета. Мне, как автору, редко удаётся писать текст сразу без ошибок, увы. Если вы хотите сообщить мне о найденной ошибке, не обязательно орфографической, вы можете просто выделить её в браузере и нажать сочетание клавиш <Ctrl>+<Enter>.

[a] Если команда выполнена привилегированным пользователем, это ещё не значит, что её нельзя выполнить от непривилегированного пользователя. Например, пакетным фильтром OpenBSD может управлять непривилегированный пользователь при наличии специальных прав на устройство /dev/pf. А запускать сниффер tcpdump(1) может пользователь, у которого есть права на уствойство /dev/bpf.

[b] К сожалению, надо признать, что шрифтовые выделения по тексту расставлены халтурно. И даже данная часть таблицы ещё недописана

2. Экзаменационные блоки

  1. Установка и обновление операционной системы и програмного обеспечения (10 вопросов)
  2. Безопасность в операционной системе (14 вопросов)
  3. Файлы, файловые системы и диски (14 вопросов)
  4. Пользователи и управление учётными записями (9 вопросов)
  5. Основы системного администрирования (24 вопроса)
  6. Сетевое администрирование (15 вопросов)
  7. Базовые Unix-навыки (17 вопросов)

Касательно подготовки к экзамену по данной книге следует привести уведомление BSD CG:

  • Помните, что экзамен BSDA подтверждает ваши практические навыки. Не следует учить man-страницы наизусть, экспериментируйте с командами для того, чтобы разобраться в man-страницах.
  • BSDA это экзамен начального уровня. Не нужно знать всё, однако мы ожидаем, что вы продемонстрируете возможность довести до конца любую администраторскую задачу.
  • Если в экзаменационных вопросах встречается слово «разбираться», это означает, что вы должны знать что нечто есть, но необязательно полностью владеть материалом. Например, в теме 2.11 кандидат должен разбираться в том, что BSD системы имеют возможности для создания сервисов и в том, какие утилиты нужны для этого. Однако кандидат BSDA не обязан иметь опыт по конфигурированию jail.
  • В случае, если утилиты упомянутые в разделе «Практика» реализованы в различных BSD-системах совсем по-разному, об этом упоминается, но детально вся разница между ними в этом разделе не описана. Вместо этого в приложении А приведена таблица в помощь подготовке к экзамену. Эта таблица содержит список команд в алфавитном порядке и их доступность в той или иной операционной системе BSD.

3. Источники информации

3.1. Официальные источники

3.1.1. Англоязычные

3.1.1.1. Сайты проектов
3.1.1.3. Руководства, handbook, FAQ и прочее

3.2. Неофициальные источники

3.2.1. Англоязычные

3.2.2. Русскоязычные

3.3. Специализированные поисковые машины

Глава 1. Установка и обновление операционной системы и програмного обеспечения

1.1. Разбираться в программах установки каждой операционной системы

Описание:  От кандидата BSDA не требуется составить план инсталляции, но он должен уметь начать и закончить инсталляцию операционной системы в соответствии с приведёнными требованиями. Поскольку процедура инсталляции зависит от конкретной системы, кандидату рекомендуется иметь опыт работы со средствами установки каждой BSD системы предлагаемыми в этих системах по умолчанию. Так же ожидается, что кандидат имеет знания об основных релизах (т.е. релизах с номером X.0) и где найти информацию о них на соответствующих сайтах BSD-проектов.

Практика: http://www.bsdinstaller.org для DragonFly BSD, sysinstall(8) для FreeBSD, sysinst на инсталляционном диске NetBSD, и INSTALL.[arch] на инсталляционном диске OpenBSD.

1.2. Разбираться какие команды доступны для upgrade'а операционной системы

Описание:  Кандидат BSDA должен разбираться в утилитах используемых для поддержания операционных систем в актуальном состоянии. Некоторые утилиты общие для разных систем BSD, некоторые утилиты специфичные для конкретной системы доступны в другой в виде стороннего програмного продукта.

Практика: make(1) включая цели "buildworld", "installworld" и "quickworld" и прочие похожие цели; mergemaster(8), cvs(1), и сторонние продукты cvsup и cvsync; build.sh, etcupdate(8), postinstall(8) и afterboot(8); src/UPDATING и src/BUILDING.

1.3. Понимание разницы между заранее скомпилированными бинарными дистрибутивами и компиляцией из исходников

Описание:  Кандидат должен быть знаком с тем, где по умолчанию находится дерево портов и пакетов (ports collention, pkgsrc collection) и какая из систем BSD какое дерево использует. Кандидат должен уметь определить расширение используемое пакетами. Кандидат должен понимать преимущества и недостатки инсталляции заранее скомпилированных бинарников и преимущества и недостатки сборки бинарников из исходного кода.

1.4. Понимание когда выгодно инсталлировать прекомпилированные бинарники и как это делать

Описание:  Кандидат BSDA должен понимать, что заранее скомпилированные бинарники просты и быстры в установке, но не дают возможности настройки бинарника к нуждам системы. Кандидат должен знать как установить заранее скомпилированный бинарник из удалённого источника, или с локальной машины, так же как и знать как удалить установленный пакет.

Практика: pkg_add(1), pkg_delete(1)

1.5. Разбираться в методах настройки и компилирования бинарников

Описание:  Для поддержки опций программы make(1), нужной для компилирования бинарника с нужными функциями, существует множество различных программ. Поскольку все системы BSD используют make(1), кандидат BSDA должен рабираться какая система BSD какие механизмы использует для сохранения опций make(1).

Практика:  Dragonfly BSD: mk.conf(5) или make.conf(5), PKG_OPTIONS, CFLAGS FreeBSD: -DWITH_* или WITH_*=, pkgtools.conf(5), make.conf(5)NetBSD: PKG_OPTIONS.<pkg>, CFLAGS, mk.conf(5), PKG_DEFAULT_OPTIONS OpenBSD: bsd.port.mk(5)

1.6. Определять, какое програмное обеспечение инсталлировано в системе

Описание:  Кандидат BSDA должен разбираться как определить какое програмное обеспечение установлено на BSD, проследить зависимости при помощи менеджера пакетов в случае, если программы установлены при помощи портов или пакетов (packages, ports или pkgsrc). Кандидат должен уметь узнать через менеджер пакетов какое програмное обеспечение стоит на машине и какой версии.

Практика: pkg_info(1)

1.7. Определять, какое програмное обеспечение нуждается в обновлении

Описание:  Кандидат должен понимать важность соблюдения равновесия между сохранением програмого обеспечения в актуальном состоянии и минимизации воздействий на производительность системы. Dragonfly BSD и NetBSD используют pkgsrc предоставляющую утилиты позволяющие определить какое програмное обеспечение устарело. FreeBSD предоставляет pkg_version и сторонние утилиты интегрированные с менеджером пакетов.

Практика:  pkgsrc/pkgtool/pkg_chk и make show-downlevel для Dragonfly BSD и NetBSD; pkg_version(1), и сторонняя программа portupgrade(1).

1.8. Обновлять установленное програмное обеспечение

Описание:  Кандидат BSDA должен разбираться во встроенных и сторонних средствах обновления установленного програмного обеспечения. В добавок кандидат должен знать какие системы используют pkgsrc.

Практика: DragonFly BSD и NetBSD предлагают pkgsrc/pkgtools/pkg_chk, pkgsrc/pkgtools/pkg_comp, make update и make replace; portupgrade и cvsup доступны как сторонние продукты.

1.9. Определять, какое програмное обеспечение имеет проблемы с безопасностью

Описание:  Кандидат BSDA должен понимать важность слежения за обнаруживаемыми уязвимостями в безопасности програмного обеспечения. Кандидат должен разбираться в сторонних утилитах интегрированных с менеджером пакетов предназначенных для обнаружения програмного обеспечения с уязвимостями в системе безопасности.

Практика:  audit-packages для Dragonfly BSD и NetBSD; portaudit и vuxml для FreeBSD и OpenBSD

1.10. Следовать инструкциям секьюрити-консультантов и накладывать security-patch

Описание:  Кандидат BSDA должен быть осведомлён о том, что каждый проект BSD сопровождается советниками по безопасности, чьи советы доступны как через Интернет, так и через почтовые списки рассылок. Кандидат должен уметь следовать инструкциям данным в этих советах.

Практика: patch(1), make(1), и fetch(1); ftp(1) и build.sh

Глава 2. Безопасность в операционной системе

Содержание

[*]2.1. Определить уровень безопасности системы
[*]2.1.1. Установка уровня безопасности системы
[*]2.1.2. Допустимые значения переменной securelevel
[*]2.1.3. Ссылки
[-]2.2. Конфигурирование сервера SSH в соответствии с требованиями
[-]2.3. Конфигурировние SSH сервера для аутентификации по ключу
[-]2.4. Предохранение ключа при обновлении системы
[-]2.5. Разбираться в альтернативных механизмах аутентификации
[-]2.6. Разбираться в альтернативных методах авторизации
[-]2.7. Разбираться в основных рекомендованных методах доступа [до хоста]
[*]2.8. Разбираться в брандмауэрах BSD и синтаксисе конфигурационных файлов
[-]2.8.1. Общие принципы работы с брандмауэрами
[-]2.8.2. Сравнение брандмауэров BSD
[-]2.9. Разбираться в механизмах использования шифровальных устройств BSD
[-]2.10. Разбираться в методах проверки аутентичности бинарного файла
[*]2.11. Разбираться в способах запуска сервиса в изолированной среде (restraining service)
[+]2.11.1. chroot(8)
[+]2.11.2. jail(8)
[-]2.11.3. systrace(1)
[-]2.11.4. Xen
[+]2.12. Смена алгоритма шифрования используемого для защиты базы с паролями
[+]2.12.1. Устройство базы паролей
[+]2.12.2. /etc/login.conf(5)
[+]2.12.3. /etc/auth.conf(5)
[+]2.12.4. /etc/passwd.conf(5)
[+]2.12.5. adduser(8)
[+]2.12.6. Итого: Blowfish HOWTO
[-]2.13. Смена приветствия системы
[-]2.14. Защита аутентификационных данных

Признаком хорошего системного администратора является осведомлённость о проблемах безопасности и забота о безопасности системы. Ожидается, что кандидат BSDA знаком с распростанёнными средствами обеспечения безопасности системы. Системы BSD реализованы с учётом проблем безопасности и предоставляют множество средств позволяющих администратору подстроить систему к требованиям политики безопасности его организации. Кандидат не может всегда отвечать за реализацию механизмов безопасности, но должен знать о свойствах и этих средств и доступных командах.

2.1. Определить уровень безопасности системы

Описание:  Системы BSD предоставляют несколько предопределённых настроек безопасности, известных как уровни безопасности (securelevels). Кандидат должен знать на каком он уровне безопасности, можно ли поднять или опустить уровень безопасности и как.

Практика: init(8), sysctl(8), rc.conf(5)

Комментарий

[Замечание]Замечание
Данный текст прислан Дмитрием Орловым, но подвергся моей редактуре. Е.М.

Функциональность securelevel можно рассматривать как метод защиты ядра, сырых устройств (raw devices), и файловой системы от атак злоумышленника, которому удалось взломать учётную запись суперпользователя. Защита ядра в общем случае включает в себя невозможность загрузки собственных модулей ядра и прослушивания проходящего через систему трафика. Функциональность securelevel/security присуствует во всех BSD системах с небольшими отличиями.

2.1.1. Установка уровня безопасности системы

Уровни безопасности служат для ограничения возможностей системы до такой степени, которая соответствует её рабочему окружению (среде работы). В OpenBSD он устанавливается скриптом rc.securelevel(8):

#       $OpenBSD: rc.securelevel,v 1.16 2004/07/06 04:05:03 deraadt Exp $
#
# в этом скрипте определяются действия, которые можно осуществить ДО
# того, как система перейдёт в безопасный режим. Действия, которые можно
# совершить ПОСЛЕ того, как будет определён уровень безопасности
# системы, должны помещаться в скрипт /etc/rc.local

# Здесь определяется желаемый уровень безопасности
# XXX
# XXX it is not really acceptable to put this value in a configuration
# XXX file, because locking it down requires immutability on about
# XXX 5 files instead of 2 (the kernel and init)
# XXX
securelevel=1

echo -n 'starting pre-securelevel daemons:'

#
# Сюда следует поместить ваши команды
#

echo '.'
        

В FreeBSD значение уровня безопасности выставляется в файле /etc/rc.conf:

kern_securelevel_enable="YES"
kern_securelevel=1
        

В DragonFly BSD уровень безопасности выставляется так же как в FreeBSD, за исключением того, что переменной kern_securelevel_enable выставлять не надо.

В NetBSD уровень безопасности так же выставляется через файл /etc/rc.conf:

securelevel=1
        

Уровень безопасности может быть прочитан или установлен с помощью утиллиты sysctl(8) через переменную kern.securelevel. По окончании процесса загрузки системы вы можете узнать текущий уровень безопасности системы набрав в командной строке:

$ sysctl kern.securelevel
kern.securelevel: -1
        

Вы можете повысить уровень безопасности командой:

# sysctl -w kern.securelevel=2
        

В процессе работы уровень безопасности системы может только повышаться. Уменьшение значения переменной ядра kern.securelevel запрещено.

2.1.2. Допустимые значения переменной securelevel

Ядра OpenBSD и NetBSD предоставляют 4 уровня системной безопаности, а FreeBSD и DragonFly BSD — 5. Последний уровень в них разбит на два подуровня.

-1 — полностью небезопасный уровень
Данный уровень, это уровень по умолчанию. Фактически он означает, что механизм securelevel вообще не включён. Документация по FreeBSD не рекомендует использовать данный уровень. В качестве небезопасного уровня документация FreeBSD рекумендует 0-й уровень.
0 — небезопасный уровень

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

На NetBSD, в дополнении к сказанному, запрещена трассировка процесса init(8).

1 — безопасный уровень

  • режим по умолчанию для многопользовательской системы
  • уровень безопасности не может быть понижен, кроме как при помощи init(8)
  • запрещена запись в устройства /dev/mem, /dev/kmem и /dev/io.
  • устройства сырых дисков (такие как /dev/ad0 и т.п.) в смонтированных файловых системах доступны только для чтения
  • системные файловые флаги immutable и append-only не могут быть сброшены (но не пользовательские, т.е. флаг schg и sappnd снять нельзя, а uchg и uappnd можно).
  • модули ядра не могут быть загружены или выгружены

На OpenBSD, в дополнении к сказанному, действуют следующие ограничения на изменения переменных ядра:

  • переменная fs.posix.setuid не может быть изменена
  • переменная net.inet.ip.sourceroute не может быть изменена
  • переменная machdep.kbdreset не может быть изменена
  • значения переменных ddb.console и ddb.panic не могут повышены
  • значение переменной machdep.allowaperture не может быть повышено

На NetBSD, в дополнении к сказанному, действуют следующие ограничения:

  • Запрещено изменение переменной ядра net.inet.ip.sourceroute.
  • Запрещено добавление и удаление переменных ядра.
  • Запрещено изменение времени (в OpenBSD и FreeBSD это сделано на 2-м уровне).
  • Нельзя изменить переменные ядра влияющие на то, будет ли изготавливаться coredump файл из програм с SUID-битом.

2 — наивысший уровень безопасности

идентичен уровню 1, кроме:

  • дисковые устройства всегда доступны только на чтение, не зависимо от того, смонтированы они или нет
  • settimeofday(2) и clock_settime(2) не могут установить время, меньше текущего
  • pf(4) фильтр и правила NAT не могут быть изменены

Наивысший уровень безопасности во FreeBSD и DragonFly BSD разбит на два уровня. Невозможность изменения правил pf(8) и NAT вынесены на уровень 3.

Режим повышенной безопасности может показаться драконовским, но он задумывался как последняя линия обороны в случае если учётная запись суперпользователя вскрыта.

Эти эффекты предотвращают обход файловых флагов путем прямой модификации сырых дисковых устройств или стирание файловой системы при помощи команды newfs(8). Далее, они могут ограничить потенциальное разрушающее действие (потенциальный вред от) вскрытого файрвола, путем запрещения модификации правил пакетного фильтра pf(8). Предотвращение перевода системного времени назад помогает при послеаварийном анализе и прибавляет уверенности в корректности журнальных файлов. При этом несколько страдает точность вычисления времени, так как блокировка времени осуществляется немгновенно.

Так как уровень безопасности может быть изменён при помощи отладчика ddb(4), вполне логично заблокировать его работу, как представлено уровнями 1 и 2 (и 3 во FreeBSD и DragonFly BSD). Это обеспечивается установкой переменных ядра ddb.console и ddb.panic в 0.

Не лишним будет упомянуть, что установку переменных на этапе загрузки можно выполнить в конфигурационном файле /etc/sysctl.conf. Например:

ddb.console=0
ddb.panic=0 
        

2.1.3. Ссылки

В разных системах семейства BSD придаётся различный смысл различным уровням безопасности. Чтобы получить конкретную информацию по вашей операционной системе, используйте следующие ссылки:

2.2. Конфигурирование сервера SSH в соответствии с требованиями

Описание:  Кандидат BSDA должен знать как настроить встроенный демон sshd(8) для ограничения доступа к системе через SSH.

Практика: sshd_config(5)

2.3. Конфигурировние SSH сервера для аутентификации по ключу

Описание:  Кандидат должен понимать теорию публичных/приватных ключей включая: какие протоколы доступны для генерирования пар ключей, выбор подходящего bit size, предоставления "начальной строки"(?) (seed), passphrase, и проверки отпечатка (fingerprint). В дополнение, кандидат должен уметь генерировать свои ключи и использовать их для аутентификации.

Практика: ssh-keygen(1) включая следующие ключевые слова: authorized_keys, id_rsa и id_rsa.pub.

2.4. Предохранение ключа при обновлении системы

Описание:  В добавок к знанию о том как генерируются системные SSH ключи, кандидат BSDA должен знать где расположены системные ключи и как предохранить их при обновлении или замене системы.

Практика:  /etc/ssh/ssh_host*_key*

2.5. Разбираться в альтернативных механизмах аутентификации

Описание:  От кандидата BSDA не требуется знания того как сконфигурировать альтернативный метод аутентификации. Однако кандидат должен понимать основы теории аутентификации, знать, что аутентификация по имени пользователя и паролю — не единственный способ аутентификации в системах BSD. Кандидат должен понимать основы PAM и знать, что он доступен в DragonFly BSD, FreeBSD и NetBSD 3.x. Он должен так же знать основы теории касающейся Kerberos, OTP и RADIUS.

2.6. Разбираться в альтернативных методах авторизации

Описание:  Кандидат должен понимать основы теории авторизации и как MAC и ACL расширяют стандартные UNIX-пермиссии.

Практика: mac(4) и acl(3) на FreeBSD; systrace(1) на NetBSD и OpenBSD.

2.7. Разбираться в основных рекомендованных методах доступа [до хоста]

Описание:  Кандидат BSDA должен быть знаком с обычными для администраторский практики методами снижения рисков связанными с доступом к системе. Включая использование ssh(1) вместо telnet(1), запрещение логина от пользователя root, использование сторонней утилиты sudo(8) вместо su(1) и минимизация использования группы wheel.

Практика: ttys(5), sshd_config(5), ftpusers(5); сторонняя утилита sudo(8), включая visudo(8), suedit(?) и sudoers(5).

2.8. Разбираться в брандмауэрах BSD и синтаксисе конфигурационных файлов

Описание:  Каждая система BSD снабжена хотя бы одним брандмауэром. Кандидат BSDA должен знать какие брандмауэры в каких системах доступны и какие команды доступны для просмотра набора правил брандмауэра.

Практика: ipfw(8), ipf(8), ipfstate(8), pfctl(8) и firewall(7)

Комментарий

В разных операционных системах BSD доступны разные брандмауэры, с разным синтаксисом и разной идеологией и разными возможностями. Однако операционные системы BSD обмениваются идеями и кодом. Так в настоящий момент в ядре FreeBSD доступно сразу три брандмауэра: «родной» — ipfw(8), пакетный фильтр NetBSD — ipf(8) и пакетный фильтр OpenBSD — pf(4).

Описание брандмауэров BSD настолько обширная тема, что в данной работе она вынесена в отдельные разделы: Приложение C, Пакетный фильтр OpenBSD — pf(4), Приложение D, Пакетный фильтр NetBSD — ipf(8) и Приложение E, Брандмауэр FreeBSD — ipfw(8). В данном разделе обсуждаются лишь некоторые концепции построения брандмауэров и проводится сравнение возможностей брандмауэров BSD.

2.8.1. Общие принципы работы с брандмауэрами

2.8.2. Сравнение брандмауэров BSD

2.9. Разбираться в механизмах использования шифровальных устройств BSD

Описание:  Кандидат BSDA должен знать, что в BSD могут использоваться шифровальные устройства и какие утилиты доступны для этого на каких BSD системах.

Практика: gbde(4) и gbde(8) на FreeBSD; cgd(4) на NetBSD; vnd(4) на OpenBSD.

2.10. Разбираться в методах проверки аутентичности бинарного файла

Описание:  Кандидат BSDA должен разбираться в утилитах проверки подлинности файла, таких как tripware. Он должен так же разбираться во встроенных методах проверки предлагаемых некоторыми BSD.

Практика: security(7) или (8); security.conf(5); veriexecctl(8)

2.11. Разбираться в способах запуска сервиса в изолированной среде (restraining service)

Описание:  Кандидат BSDA должен понимать преимущества запуска сервисов в изолированной среде на машинах открытых для Интернет, и какие утилиты предназначены для этого в какой BSD.

Практика: chroot(8); jail(8); systrace(1); Стороннее приложение Xen.

Комментарий

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

Чтобы противодействовать данному виду атак, многие службы запускают в изолированной среде — «sandbox» или «песочнице». Существует множество способов построения «песочниц»:

Виртуальная машина

Это, пожалуй, самое радикальное средство изоляции сервисов. Вы запускаете образ машины, устанавливаете на неё любую полюбившуюся операционную систему и выставляете эту «машину» в Интернет. В случае взлома вы просто восстанавливаете её из образа. В этой ситуации риск повреждения материнской системы практически полностью исключён. Однако накладные расходы очень велики — быстродействие виртуальной машины в десятки раз ниже быстродействия материнской.

Известные эмуляторы: vmware — коммерческий продукт выпускающийся под Linux его можно запустить в FreeBSD используя «эмулятор» Linux. Другое решение — qemu. Qemu ставится из портов в любую систему, это OpenSource, но выбор эмулируемого железа в нём ограничен.

Псевдоэмуляция

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

Примером такого рода эмуляции является рассмотренный ниже Xen, реализованный в NetBSD, OpenBSD и FreeBSD.

Смена корневого каталога

Это один из самых простых и один из самых древних методов построения «песочницы». Хотя системый вызов chroot(2) не входит в стандарт POSIX, он реализован практически повсеместно. Приложение выполняет системный вызов chroot(2), после чего любое обращение к корневому каталогу ядро транслирует в некоторый другой каталог — корень «песочницы». Таким образом, приложение лишено возможности испортить файлы за пределами «песочницы». В тоже время, приложение работает с сокетами материнской системы, если мы создаём в песочнице каталог /dev с файлами устройств, то оно будет иметь доступ к устройствам на низком уровне и, при достаточном количестве полномочий может даже вырваться за пределы песочницы.

Данный метод построения «песочниц» очень распространён. Существуют сервисы, такие как BIND, которые по умолчанию запускаются в окружении chroot(8).

jail(8), тюрьма
Этот метод находится посередине, между псевдоэмулятором и chroot(8). Фактически это просто усовершенствованный chroot(8). Реализация jail(8) довольно сложна, это решение принято только в FreeBSD и DragonFly BSD. В отличие от chroot(2), в jail(2) приложение не только меняет корневой каталог, но даже работает с другими сетевыми сокетами; jail(8)'у можно выдать свой IP адрес. Мы можем говорить о jail, как о дополнительном (возможно не одном) виртуальном сервере FreeBSD.
Ограничение системных вызовов
Решение применяемое в OpenBSD и NetBSD — система systrace(1), предназначена для контроля за тем какие системые вызовы имеет право выполнить та или иная программа. С помощью данного средства можно расписать политики в которых будет сказано какие вызовы может выполнять программа, имеет ли она право открыть сокет на таком-то порту и т.д. Можно, например, запретить на уровне ядра программе named(8) слушать какой бы то ни было порт кроме 53-го.

2.11.1. chroot(8)

Команда chroot(8) позволяет запускать приложения в ограниченной среде путём смены корневого каталога. Для начала, давайте попробуем запустить в ограниченной среде программу csh(1). В дополнение к ней мы скопируем в ограниченную среду команду tree(1), чтобы с её помощью убедиться что у нас всё получилось. Для этого нам надо выполнить следующие действия:

  • Создать каталог («песочницу») в который мы будем chroot'иться.
  • В этом каталоге создать файловую иерархию характерную для UNIX, для начала нам хватит каталогов /bin и /lib.
  • Определить с какими динамическими библиотеками слинкована наша программа. Для этого нам понадобится программа ldd(1), а что-то мы определим методом проб и ошибок.
  • Скопировать все библиотеки, исполнимые файлы и необходимые конфигурационные файлы в соответствующие каталоги «песочницы». (Для нашей учебной задачи конфигурационные файлы можно и не копировать.)
  • Запустить csh(1) в ограниченном окружении:
$ mkdir -p sandbox/bin sandbox/lib
$ ldd /bin/csh 1
/bin/csh:
        libncurses.so.6 => /lib/libncurses.so.6 (0x280b9000)
        libcrypt.so.3 => /lib/libcrypt.so.3 (0x280f8000)
        libc.so.6 => /lib/libc.so.6 (0x28110000)
$ ldd /usr/local/bin/tree
/usr/local/bin/tree:
        libc.so.5 => /lib/libc.so.5 (0x2807c000)
$ cp /lib/libc.so.5 /lib/libncurses.so.6 /lib/libcrypt.so.3 /lib/libc.so.6 sandbox/lib/
$ cp /bin/csh /usr/local/bin/tree sandbox/bin/ 2
# chroot sandbox/ csh 3
Password:
ELF interpreter /libexec/ld-elf.so.1 not found 4
Abort trap: 6
$ mkdir sandbox/libexec
$ cp /libexec/ld-elf.so.1 sandbox/libexec/
# chroot sandbox/ csh
csh: Cannot open /etc/termcap.
csh: using dumb terminal settings. 5
%pwd
pwd: Command not found.
%tree /
/
|-- bin
|   |-- csh
|   `-- tree
|-- lib
|   |-- libc.so.5
|   |-- libc.so.6
|   |-- libcrypt.so.3
|   `-- libncurses.so.6
`-- libexec
    `-- ld-elf.so.1

3 directories, 7 files
%exit
exit
        
1 Узнаём с какими библиотеками слинкованы csh(1) и tree(1).
2 Копируем библиотеки и исполнимые файлы
3 Для выполнения системного вызова chroot(2) необходимы права суперпользователя
4 Оопс! Одного файла не хватает. Копируем и его тоже.
5 На этот раз у нас всё получилось. Правда система отругала нас за то, что мы не скопировали необходимых конфигурационных файлов, но csh(1) запустился. Ниже видно, что мы не можем выполнить команду pwd(1), так как это внешняя команда, не встроенная в csh(1). Затем, при помощи команды tree(1) мы рассматриваем всю файловую иерархию которая нам доступна.

Некоторым приложениям может понадобиться наличие каталога /dev с файлами устройств. Для систем не поддерживающих devfs надо создать эти файлы при помощи команды mknod(8), а для систем поддерживающих devfs, например для FreeBSD, понадобится смонтировать в «песочницу» файловую систему devfs. Однако при этом вам может понадобиться создать не все, а только некоторые файлы устройств. Для этого надо воспользоваться утилитой devfs(8):

$ mkdir sandbox/dev
# mount_devfs devfs sandbox/dev/
Password:
$ ls sandbox/dev/ 1
acd0        console     fd/         nfs4        sysmouse    ttyv5
acd0t01     consolectl  fd0         nfslock     ttyd0       ttyv6
acpi        ctty        fido        null        ttyd0.init  ttyv7
ad0         cuad0       geom.ctl    pass0       ttyd0.lock  ttyv8
ad0s1       cuad0.init  io          pci         ttyd1       ttyv9
ad0s1a      cuad0.lock  kbd0@       psm0        ttyd1.init  ttyva
ad0s1b      cuad1       klog        ptyp0       ttyd1.lock  ttyvb
ad0s1c      cuad1.init  kmem        ptyp1       ttyp0       ttyvc
ad0s1d      cuad1.lock  lpt0        ptyp2       ttyp1       ttyvd
agpgart     devctl      lpt0.ctl    ptyp3       ttyp2       ttyve
apm         devstat     mdctl       ptyp4       ttyp3       ttyvf
ata         dri/        mem         random      ttyp4       urandom@
atkbd0      dsp0.0      mixer0      rtc         ttyv0       usb
audio0.0    dsp0.1      net/        sndstat     ttyv1       usb0
audio0.1    dspW0.0     net1@       stderr@     ttyv2       usb1
bpsm0       dspW0.1     net2@       stdin@      ttyv3       xpt0
cd0         dspr0.1     network     stdout@     ttyv4       zero
# devfs -m sandbox/dev/ rule apply hide
$ ls sandbox/dev/ 2
# devfs -m sandbox/dev/ rule apply path zero unhide
# devfs -m sandbox/dev/ rule apply path null unhide
# devfs -m sandbox/dev/ rule apply path random unhide
$ ls sandbox/dev/ 3
null    random  zero
# chroot sandbox/ csh
csh: Cannot open /etc/termcap.
csh: using dumb terminal settings.
%tree /
/
|-- bin
|   |-- csh
|   `-- tree
|-- dev 4
|   |-- null
|   |-- random
|   `-- zero
|-- lib
|   |-- libc.so.5
|   |-- libc.so.6
|   |-- libcrypt.so.3
|   `-- libncurses.so.6
`-- libexec
    `-- ld-elf.so.1

4 directories, 10 files
%exit
exit
        
1 После монтирования файловой системы devfs в каталог sandbox/dev/, в нём оказались доступны все файлы устройств. В ряде случаев это неудачная идея.
2 При помощи команды devfs(8) мы скрыли все файлы устройств в каталоге sandbox/dev/.
3 Теперь мы три файла устройств снова сделали доступными. После мы можем безопасно выполнять команду chroot(8). В ограниченной среде будут доступны только созданные три устройства.
4 Команда tree(1) показывает, что в «песочнице» доступны только созданные три файла устройств.

2.11.2. jail(8)

Команда jail(8) может рассматриваться как средство для запуска программы в ограниченном окружении, а может рассматриваться как средство виртуализации. В первом случае настройка jail(8) выглядит аналогично рассмотренному выше chroot(8). К уже имеющемуся окружению sandbox/ мы добавим команду ifconfig(8):

          # ifconfig rl0 add 172.19.0.234/24
$ ifconfig rl0
rl0: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> mtu 1500
        options=8<VLAN_MTU>
        inet 172.19.0.5 netmask 0xffffff00 broadcast 172.19.0.255
        inet 172.19.0.234 netmask 0xffffff00 broadcast 172.19.0.255 1
        ether 4c:00:10:54:dd:8e
        media: Ethernet autoselect (100baseTX <full-duplex>)
        status: active
lo0: flags=8049<UP,LOOPBACK,RUNNING,MULTICAST> mtu 16384
        inet 127.0.0.1 netmask 0xff000000 
$ mkdir sandbox/sbin 2
$ cp /sbin/ifconfig sandbox/sbin
$ ldd /sbin/ifconfig 
/sbin/ifconfig:
        libipx.so.3 => /lib/libipx.so.3 (0x28082000)
        libc.so.6 => /lib/libc.so.6 (0x28085000)
$ cp /lib/libipx.so.3 sandbox/lib
# jail sandbox/ testhostname 172.19.0.234 /bin/csh 3
csh: Cannot open /etc/termcap.
csh: using dumb terminal settings.
%/sbin/ifconfig 
rl0: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> mtu 1500
        options=8<VLAN_MTU>
        inet 172.19.0.234 netmask 0xffffff00 broadcast 172.19.0.255 4
        ether 4c:00:10:54:dd:8e
        media: Ethernet autoselect (100baseTX <full-duplex>)
        status: active
lo0: flags=8049<UP,LOOPBACK,RUNNING,MULTICAST> mtu 16384
%exit
exit  
        
1 Для начала мы добавляем IP адрес материнской системе. Без этого не присвоится IP jail'у.
2 Теперь копируем в созданную раньше «песочницу» команду ifconfig(8) с библиотеками
3 Вызываем jail(8)
4 Видно, что внутри jail(8) присвоен выбранный нами IP

Если теперь мы добавим адрес 192.168.0.34 как алиас для интерфейса материнской машины, то по нему мы сможем взаимодействовать с внутренней машиной.

Поговорим об использовании jail(8) в качестве эмулятора.

Таблица 2.1. Опции запуска jail(8)

ОпцияОписание
Необязательные аргументы
-i Вывести идентификатор созданной «тюрьмы».
-J JidFile Создать JidFile, аналогично PidFile. В него записывается jailid, путь к sandbox, hostname, IP адрес, и команда запущенная в jail.
-l Выполнить программу в чистых переменных окружения. Переменные окружения уничтожаются за исключением переменных HOME, SHELL, TERM и USER. Переменная TERM импортируется из текущего окружения, остальные выставляются согласно выполненному в песочнице логину.
-s securelevel Устанавливает переменную ядра kern.securelevel в указанное значение внутри созданной «тюрьмы». Эта опция появилась только в FreeBSD 6.2
-u username Имя пользователя от имени которого осуществляется запуск jail(8)
-U username Имя пользователя от имени которого выполняется команда внутри jail(8).
Обязательные аргументы
path Путь к sandbox
hostname hostname внутри jail(8)
IP Адрес jail(8). Пока на один jail(8) можно дать только один адрес.
command Команда, которая будет выполнена в jail(8)

2.11.2.1. Краткое HOWTO, как запустить FreeBSD в jail(8)

2.11.2.1.1. Создание дерева для «песочницы»

Ниже я перечислю нужные для этого команды, естественно удалив их стандартный вывод — он огромен.

$ D=/path/to/sandbox
$ mkdir -p $D
$ cd /usr/src
# make world DESTDIR=$D
# make distribution DESTDIR=$D
# mount_devfs devfs $D/dev
            

Таким образом, будет собрана вторая копия FreeBSD в каталоге /path/to/sandbox/. Разумеется, если ваша цель состоит только в запуске какого-то конкретного сервиса, а не предоставления виртуального хостинга, то данные действия, мягко говоря, избыточны. вероятно имеет смысл создать маленькую «тюрьму» и добавлять в неё файлы, пока она не заработает. Такой путь сложнее чем путь удаления файлов из «толстой тюрьмы», но приводит к лучшему результату. Кроме того, монтирование всей файловой системы devfs, тоже небезопасно, поэтому далее следует исключить некоторые файлы устройств (как минимум жёсткие диски) способом описанным выше, в Раздел 2.11.1, «chroot(8)».

2.11.2.1.2. Настройка материнской системы

Прежде всего, следует исключить ситуацию, когда сервисы материнской системы слушают адрес присвоенный jail(8). Некоторые сервисы придётся отключить, некоторые перенастроить. В частности, надо заставить суперсервер inetd(8) слушать некоторый конкретный адрес, принадлежащий материнской системе. Имеет смысл добавить в файл /etc/rc.conf следующие строки:

sendmail_enable="NO"
inetd_flags="-wW -a 192.168.11.23"
rpcbind_enable="NO"
            

Где 192.168.11.23 — адрес материнской системы. Демоны запущенные не через inetd(8) должны быть переконфигурированы. Некоторые могут быть перенастроены при помощи /etc/rc.conf, некоторые через свои конфигурационные файлы. В некоторых клинических случаях демонов придётся пересобирать.

Для конфигурирования sshd(8) следует воспользоваться файлом /etc/ssh/sshd_config(5).

Для конфигурирования sendmail(8) — /etc/mail/sendmail.cf

named(8) — /etc/namedb/named.conf.

Сервисы, основанные на rpc(3), такие как rpcbind(8), nfsd(8), mountd(8) придётся пересобирать.

Так или иначе, сервисы, которым невозможно объяснить какой они слушают адрес не должны запускаться на материнской системе, если они не должны интерферировать с программами в jail(8).

2.11.2.1.3. Конфигурирование jail(8)

Первый запуск jail(8) происходит в системе, в которой не настроены сетевые интерфейсы, нет учётных записей пользователей и т.д. Некоторые из этих вещей можно настроить только если у вас запущен виртуальный сервер внутри jail(8). Запустите jail(8):

# jail /data/jail/192.168.11.100 testhostname 192.168.11.100 /bin/sh
            

Если всё будет в порядке, то теперь в этом окружении можно выполнить настройку системы при помощи утилиты /usr/sbin/sysinstall(8) или вручную отредактировать /etc/rc.conf в окружении jail(8).

Выполните следующие шаги:

  • Создайте пустой файл /etc/fstab дабы избежать сообщений о его отсутствии.
  • Отключите portmapper (rpcbind_enable="NO" в /etc/rc.conf)
  • Сконфигурируйте /etc/resolv.conf
  • Выполните команду newaliases(1), чтобы избежать предупреждений от sendmail(8).
  • Отключите конфигурирование сетевых интерфейсов дабы избежить предупреждений от ifconfig(8) (network_interfaces="" в /etc/rc.conf)
  • Установите пароль root. Будет лучше, если он будет отличен от пароля в материнской системе.
  • Установите timezone. Для этого надо скопировать подходящий файл (например /usr/share/zoneinfo/Europe/Moscow) под именем /etc/localtime.
  • Добавьте пользовательские учётные записи
  • Инсталлируйте необходимые пакеты

Кроме того, вам возможно понадобится сконфигурировать какое-нибудь програмное обеспечение внутри jail(8). Например web-сервер, ssh-сервер и т.д. Возможно вы захотите чтобы syslogd(8) материнской системы слушал сокет в jail(8). В рассматриваемом примере его надо направить на сокет /data/jail/192.168.11.100/var/run/log.

После произведённых настроек можно выйти из оболочки запущенной в jail(8).

2.11.2.1.4. Запуск jail(8)

Теперь вы готовы запускать виртуальный сервер в jail(8). Для этого надо выполнить в jail(8) скрипт /etc/rc.

[Важно]Важно
Если вы собираетесь предоставлять доступ неизвестным пользователям с правами root в jail(8), выставите переменную ядра security.jail.set_hostname_allowed в 0 до запуска jail(8). В Раздел 2.11.2.1.5, «Управление jail(8)» сказано чем это может быть полезно.

Вот команды для запуска виртуального сервера:

# ifconfig bge0 add 172.19.0.133/24
# mount_devfs devfs /opt/sandbox/dev
# jail /opt/sandbox/ jail-hp.house.hcn-strela.ru 172.19.0.133 /bin/sh /etc/rc
Loading configuration files.
jail-hp.house.hcn-strela.ru
Setting hostname: jail-hp.house.hcn-strela.ru.
Creating and/or trimming log files:.
ln: /dev/log: Operation not permitted
Starting syslogd.
ELF ldconfig path: /lib /usr/lib /usr/lib/compat
a.out ldconfig path: /usr/lib/aout /usr/lib/compat/aout
Starting local daemons:.
Updating motd.
Starting sshd.
Starting cron.
Local package initialization:.

Thu Feb 22 11:41:09 MSK 2007
$ ssh guest@172.19.0.133 1
The authenticity of host '172.19.0.133 (172.19.0.133)' can't be established.
DSA key fingerprint is 95:cc:e5:38:e7:19:9e:0a:aa:40:a0:04:80:7b:be:53.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '172.19.0.133' (DSA) to the list of known hosts.
Password:
Last login: Thu Feb 22 10:58:50 2007 from 172.19.0.33
Copyright (c) 1980, 1983, 1986, 1988, 1990, 1991, 1993, 1994
        The Regents of the University of California.  All rights reserved.
...............................................................................
$ ifconfig 2
fwe0: flags=108802<BROADCAST,SIMPLEX,MULTICAST,NEEDSGIANT> mtu 1500
        options=8<VLAN_MTU>
        ether 02:02:3f:15:33:0c
        ch 1 dma -1
bge0: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> mtu 1500
        options=1b<RXCSUM,TXCSUM,VLAN_MTU,VLAN_HWTAGGING>
        inet 172.19.0.133 netmask 0xffffff00 broadcast 172.19.0.255
        ether 00:17:08:2f:a6:90
        media: Ethernet autoselect (100baseTX <full-duplex>)
        status: active
plip0: flags=108810<POINTOPOINT,SIMPLEX,MULTICAST,NEEDSGIANT> mtu 1500
lo0: flags=8049<UP,LOOPBACK,RUNNING,MULTICAST> mtu 16384
            
1 Заходим в тюрьму по ssh(1). Учётная запись guest и sshd(8) демон настроены заранее.
2 Это уже команда выполненная внутри тюрьмы.

Вы получите некоторое количество предупреждений связанных с тем, что внутри jail(8) нельзя выполнить большинство вызовов sysctl(8). Однако всё должно работать. Вы можете увидеть при помощи команды ps(1) процессы запущенные в jail(8) с флагом J.

Можно запускать jail(8) автоматически при старте системы. Для этого надо вписать строки типа jail_* в /etc/rc.conf(5).

Например, для того, чтобы при старте системы автоматически запускалось три jail'а, надо поместить в /etc/rc.conf(5) следующие строки:

jail_enable="YES"
jail_list="one,two,three"
jail_one_hostname="www.propeller.ru"
jail_two_hostname="www.samovar.ru"
jail_three_hostname="www.avtoclav.ru"
jail_one_ip="192.168.11.100"
jail_two_ip="192.168.11.101"
jail_three_ip="192.168.11.102"
jail_one_rootdir="/data/jail/192.168.11.100"
jail_two_rootdir="/data/jail/192.168.11.101"
jail_three_rootdir="/data/jail/192.168.11.102"
            

Это программа-минимум. С помощью других опций описанных в /etc/rc.conf(5) вы можете оговорить нужно ли перед запуском jail(8) монтировать внутри него procfs, devfs, какие устройства нужно активировать внутри devfs и т.п.

Можно управлять jail(8) при помощи стартового скрипта /etc/rc.d/jail:

# /etc/rc.d/jail start
# /etc/rc.d/jail stop
# /etc/rc.d/jail start myjail
# /etc/rc.d/jail stop myjail
            
2.11.2.1.5. Управление jail(8)

Обычные команды типа shutdown(8), halt(8) или reboot(8) в jail(8) не работают. Вместо них можно зайти в jail(8) и выполнить одну из команд:

# kill -TERM -1
# kill -KILL -1
            

в зависимости от того, что вы хотите сделать. Возможно вы захотите выполнить скрипт /etc/rc.sutdown внутри jail(8).

Если вы находитесь снаружи jail(8) и хотите выполнить команду внутри него, вы можете воспользоваться командой jexec(8):

#jexec 6 kill -KILL -1
            

Эта команда выполнит команду kill(1) внутри jail с jid=6.

В каталоге /proc, если вы его используете, в файле /proc/<pid>/status в последнем поле находится имя хоста для jail или знак - если процесс запущен не в jail. Кроме того, команда ps(1) показывает знак J если процесс запущен в jail. Однако hostname может быть изменён внутри jail и тогда значение из файла /proc/<pid>/status оказывается ни с чем не связано. Чтобы запретить смену hostname надо выставить переменную ядра security.jail.set_hostname_allowed в 0. (см. Раздел 5.6, «Изменение на лету переменных ядра»). Это повлияет на всю «пенитенциарную систему».

Чтобы увидеть список процессов с их Jail ID вы можете выполнить команду

$ ps ax -o pid,jid,args
            

Чтобы увидеть процессы в jail(8) номер 3, и послать им сигналы, можно использовать команды

$ pgrep -lfj 3
# pkill -j 3
            

или

# killall -j 3
            

Таблица 2.2. Переменные ядра (MIB) связанные с jail(8)

ПеременнаяУмолчаниеОписание
security.jail.allow_raw_sockets0 Переменная определяет может ли root в «тюрьме» открывать сырые сокеты. Установка переменной в 1 позволит запускать в тюрьме такие утилиты как ping(8) и traceroute(8).
security.jail.enforce_statfs2 Определяет какая информация о точках монтирования доступна для процессов в jail(8). 0 — все точки монтирования доступны без ограничений; 1 — Доступны только точки монтирвания внутри каталога jail(8), путь к каталогу jail(8) удаляется; 2 — можно работать только с точкой монтирования в которой разположен jail(8).
security.jail.set_hostname_allowed1 Определяет может ли приложение в jail(8) сменить hostname.
security.jail.socket_unixiproute_only0 По умолчанию процессы в jail(8) могут взаимодействовать с доменными сокетами UNIX, IPv4 сокетами и routing sockets. Смена данной переменной приведёт к тому, что процессам в jail(8) станут доступны и другие сокеты.
security.jail.sysvipc_allowed0 Могут ли процессы в jail(8) использовать примитивы System V IPC. Установка этой переменной в 1 позволит процессам в jail(8) взаимодействовать с процессами в других «тюрьмах» и с процессами материнской системы.
security.jail.chflags_allowed0 Как взаимодействует root в jail(8) с флагами выставленными командой chflags(1). 0 — root считается непривилегированным пользователем и не может менять этот флаг. 1 — root считается привилегированным пользователем и может манипулировать флагами согласно секущему уровню kern.securelevel.
Существуют две переменные, которые можно менять внутри jail(8) их значение будет действовать только внутри данной «тюрьмы».
kern.securelevel  
kern.hostname  
2.11.2.1.5.1. Некоторые программы для работы с jail(8)

jls(8) Программа предоставляет список запущенных тюрем:

$ jls
   JID  IP Address      Hostname                      Path
     6  172.19.0.133    jail-hp.house.hcn-strela.ru   /opt/sandbox
                

jexec(8).  Программа позволяет выполнить в jail(8) произвольную команду:

# jexec 6 kill -TERM -1
                

Эта команда приведёт к остановке 6-й тюрьмы.

security/jailaudit Порт генерирующий вывод команды portaudit(1) для тюрем.

sysutils/ezjail Порт предназначенный для облегчения создания и управления тюрьмами.

sysutils/jailadmin Порт для администрирования тюрьмами.

sysutils/jailctl Порт для администрирования тюрьмами.

sysutils/jailer Порт для управления запуском и остановкой тюрем.

sysutils/jailutils Порт с несколькими программами для манипулирования тюрьмами.

Для получения более подробной информации о портах выполните команду:

$ cat /usr/ports/<category>/<port>/pkg-descr
              

2.11.2.2. Ограничения jail(8)

  • На один jail(8) может быть выдан только один IP адрес. В будущем эту ситуацию собираются исправить. Для ветви FreeBSD CURRENT существует патч, позволяющий установить несколько IP-адресов на один jail. Мне неизвестно работает ли он с FreeBSD 6.x.
  • Пространство UID у jail(8) и у материнской системы общее. Это значит, что ресурсы принадлежащие пользователю с UID=1001 в тюрьмах номер 4, 7, 9 и т.д., на самом деле принадлежат одному пользователю, имеющему UID=1001 в материнской системе. Как следствие, файловые квоты в jail(8) будут работать некорректно.
  • Многие ресурсы jail(8) и материнской системы — общие. Выполнение следующего кода в jail(8) может вызвать серёзные проблемы как в материнской системе, так и в соседних тюрьмах:
    $ while :; do cat /dev/zero | md5 & done
                  

2.11.3. systrace(1)

2.11.4. Xen

2.12. Смена алгоритма шифрования используемого для защиты базы с паролями

Описание:  Кандидат BSDA должен уметь по данному скриншоту базы паролей определить используемый метод шифрования и знать как его сменить. Кандидат должен иметь базовое понимание того когда надо использовать DES, MD5 и Blowfish.

Практика: login.conf(5); auth.conf(5); passwd.conf(5) и adduser(8).

Комментарий

Жизнь показывает, что существует множество путей при помощи которых может «утекать» база с паролями пользователей. Один из распространённых случаев — утечка с backup'ами. Главное оружие любого системного администратора, это валидол и backup. Администратор, который понял эту истину может уподобиться белке, которая рассовывает орешки где попало и забывает где их положила. Так же могут быть распределены в системе резервные копии. Особенно, если система резервного копирования написана самим администратором. Такая система, быть может ничем не плоха, но на стадии отладки, пока подбирались опции, на жёстких дисках оказалось несколько копий резервных файлов с правами 644...

Чем это чревато? Злоумышленник может попыться найти базу с паролями и взломать её. Что может ему помешать? Во первых пароли должны быть качественными, во вторых, они должны быть качествено зашифрованы. Надо сразу сказать, что первое намного важнее второго. Как бы качественно ни был зашифрован пароль 12345, его вскроют за доли секунды.

Существует несколько способов шифрования паролей. Так или иначе, используется некоторая необратимая функция, при помощи которой, шифруется пароль. Т.е. система ваш пароль вообще не знает. Когда вы его вводите, она шифрует его заново и сверяет результаты шифрования со своей базой.

В системах BSD можно выбирать несколько алгоритмов шифрования паролей, однако ни один из них не является панацеей от взлома. Иметь стойкий пароль, намного важнее, чем строго его шифровать. Хотя последнее тоже может быть важно.

2.12.1. Устройство базы паролей

База с аутентификационными данными состоит из 4-х файлов. Основной — /etc/master.passwd и генерирующихся из него при помощи pwd_mkdb(8) трёх файлов: /etc/passwd(5), /etc/pwd.db и /etc/spwd.db.

/etc/master.passwd

В данном файле содержится собственно аутентификационная информация: зашифрованный пароль, сведения о пользовательских настройках (т.н. класс пользователя), срок действия пароля. Ниже приведён фрагмент файла /etc/master.passwd(5).

user1:*LOCKED*cuqW.GIKHV/xs:1001:1001:russian:0:0:Poluect,dse-m,1234567,7654321,hello_world:/home/user:/usr/sbin/nologin
user2:*LOCKED*76aSxdZIXKXfk:1002:1002:russian:0:0:Poluect,dse-m,1234567,7654321,hello_world:/home/user:/usr/sbin/nologin
user3:*LOCKED*$1$UmWRc8Kh$WyHRN96T7vQ7nZP0ChVjc/:1003:1003:russian:0:0:Poluect,dse-m,1234567,7654321,hello_world:/home/user:/usr/sbin/nologin
user4:*LOCKED*$1$OgtF.3Zb$EafLlWm6H.OZ1sKkheySr.:1004:1004:russian:0:0:Poluect,dse-m,1234567,7654321,hello_world:/home/user:/usr/sbin/nologin
user5:*LOCKED*$2a$04$HXoymCDzRfi9ctGmfrOqeu9Hn16XcWmQuVnA6C3aifKkkM7qrKauO:1005:1005:russian:0:0:Poluect,dse-m,1234567,7654321,hello_world:/home/user:/usr/sbin/nologin
user6:*LOCKED*$2a$04$GO.hiRaXx7wp5cdAfJP9xOAOeXV48/kBYOJ2VaJRhknUg/VWLw/N.:1005:1005:russian:0:0:Poluect,dse-m,1234567,7654321,hello_world:/home/user:/usr/sbin/nologin
user7:*LOCKED*$3$$2d20d252a479f485cdf5e171d93985bf:1006:1006:russian:0:0:Poluect,dse-m,1234567,7654321,hello_world:/home/user:/usr/sbin/nologin
user8:*LOCKED*$3$$2d20d252a479f485cdf5e171d93985bf:1007:1007:russian:0:0:Poluect,dse-m,1234567,7654321,hello_world:/home/user:/usr/sbin/nologin
              

Здесь имеется 10 полей разделённых двоеточиями. Вот их значение:

  • Логин пользователя
  • Пароль пользователя. Никакой пароль не может содержать в себе звёздочек, или восклицательных знаков. Поэтому поле *LOCKED* свидетельствует о том, что данная учётная запись заблокирована. Ни один пароль не совпадёт с ней при процедуре аутентификации. Для блокирования учётной записи таким способом можно применять команду pw(8) (см. Раздел 4.1, «Создание, изменение и удаление учётных записей»).

    [Внимание]Внимание
    Существуют способы войти в систему без проверки пароля, например при аутентификации в ssh(1) по паре сгенерированных ключей (см. Раздел 2.7, «Разбираться в основных рекомендованных методах доступа [до хоста]»). Поэтому такой способ блокирования учётной записи можно считать необходимым, но не достаточным. Кроме этого действия надо ещё сменить пользователю оболочку на /usr/sbin/nologin.

    У всех восьми упомянутых здесь пользователей пароль одинаковый — qwerty. Однако он приведён в разных форматах. Всего мы обсудим 4 формата паролей:

    DES

    Пароль qwerty При помощи алгоритма DES шифруется в строку cuqW.GIKHV/xs. Однако было бы ошибкой дать злоумышленнику возможность определить у кого из наших пользователей пароли совпадают, просто на основании того, что совпадают шифры. Поэтому при шифровании используется т.н. «соль». В момент заведения пароля генерируется случайное число. это число в символьном виде приписывается к паролю и далее шифруется пароль вместе с солью. Таким образом, следующая строка: 76aSxdZIXKXfk это тоже qwerty.

    Алгоритм DES не является достаточно криптостойким. Современная компьютерная техника позволяет взломать эти пароли методом перебора за незначительный промежуток времени. По этой причине большинство современных UNIX-систем шифруют пароли при помощи алгоритма MD5:

    MD5

    Пароль qwerty в формате MD5 может выглядеть следующим образом: $1$UmWRc8Kh$WyHRN96T7vQ7nZP0ChVjc/. В данном примере пароль состоит из трёх полей, разделённых знаками $:

    • $1$ — Указание на алгоритм шифрования MD5;
    • UmWRc8Kh — «соль», которая добавляется к паролю при вычислении MD5 суммы (см. выше, описание DES).
    • WyHRN96T7vQ7nZP0ChVjc/ — собственно зашифрованный пароль.

    В интернете можно встретить много истерических замечаний по поводу якобы взломанного алгоритма MD5. Правда на настоящий момент такова: некие китайские(?) математики нашли алгоритм при помощи которого можно находить коллизии в MD5. Т.е. если md5(xm)=y, то существует алгоритм по которому зная y можно найти другой xn, такой, что md5(xn)=md5(xm). Однако, если злоумышленник знает пароль, то знание коллизии к паролю ему уже не нужно. Что касается обратимости, то алгоритм md5 по прежнему необратим, и единственный вид атаки на него, это bruteforce — атака грубой силой, путём перебора паролей. Математики смогли снизить количество вычислений, необходимых для этой атаки на несколько порядков, однако это по прежнему актуальная бесконечность.

    Blowfish
    Алгоритм Blowfish не скомпрометирован пока ни в каком смысле. Кроме того, для его взлома нужно больше вычислений, а вероятность коллизий в нём меньше. Идентификатор $2 в начале строки пароля свидетельствует о применении данного алгоритма. Поле $04$ указывает на то, сколько проходов совершено при шифровании. (Внимание! Последняя фраза лишь догадка автора.)
    NT-hash
    Поле пароля устроено как в MD5, идентификатор алгоритма — $3. Обратите внимание: в случае использования алгоритма NT-hash соль не генерируется и хеши одинаковых паролей одинаковы! Я не знаю устройства этого алгоритма, но результат просто отвратителен! Данный эксперимент ставился в системе FreeBSD 6.1-RELEASE.
  • UID — идентификационный номер пользователя
  • GID — номер основной группы, которой принадлежит пользователь. Один пользователь может быть членом разных групп, но одна из них основная.
  • Класс пользователя — используется программой login(1) и другими для настройки характеристик учётной записи. С его помощью программы отыскивают свои настройки в базе /etc/login.conf(5) и устанавливают переменные окружения или делают иные настройки (см. Приложение F, /etc/login.conf(5)).
  • Время (в секундах от начала UNIX эры по гринвичу) когда истечёт срок действия пароля.
  • Время (в секундах от начала UNIX эры по гринвичу) когда истечёт время действия учётной записи.
  • GECOS — информация о пользователе: имя, место работы, рабочий и домашний телефон. Эту и другую информацию использует в работе утилита finger(1):

    $ finger user
    Login: user                             Name: Poluect
    Directory: /home/user                   Shell: /usr/sbin/nologin
    Office: dse-m, 123-4567                 Home Phone: 765-4321
    Never logged in.
    No Mail.
    No Plan.
                      
  • Домашний каталог пользователя.
  • Оболочка пользователя.
/etc/passwd(5)

Данный файл нужен, главным образом, для совместимости. Он присутствует во всех UNIX'ах и везде имеет одинаковую структуру. В BSD он не первичен, т.е. генерируется из файла /etc/master.passwd при помощи команды pwd_mkdb(8). В файле присутствует информация о логине пользователя, его оболочке и др. Поля разделены двоеточиями:

user:*:1001:1001:Poluect,dse-m,1234567,7654321,hello_world:/home/user:/bin/csh
                

  1. Логин.
  2. В давние времена здесь писали пароль, сейчас это поле его не содержит, данный файл открыт на чтение всем.
  3. UID — идентификационный номер пользователя.
  4. GID — номер основний группы, которой принадлежит пользователь.
  5. GECOS: информация о пользователе.
  6. Домашний каталог пользователя.
  7. Стартовая оболочка пользователя.
/etc/pwd.db
Бинарная база содержащая в себе несекретную часть аутентификационной информации. Создаётся из /etc/master.passwd(5) командой pwd_mkdb(8).
/etc/spwd.db
Бинарная база содержащая в себе секретную часть аутентификационной информации. Создаётся из /etc/master.passwd(5) командой pwd_mkdb(8).

2.12.2. /etc/login.conf(5)

Данный файл является базой данных для различных программ, в том числе для программы login(1). С его помощью можно задавать переменные окружения, настройки учётных записей вроде сроков действия учётных записей, метода шифрования и т.д.

Полное описание формата этого файла можно найти в Приложение F, /etc/login.conf(5).

Файл /etc/login.conf непосредственно системой не читается. После его редактирования надо создать бинарную базу /etc/login.conf.db при помощи команды:

# cap_mkdb /etc/login.conf
        

Поля в файле /etc/login.conf разделяются двоеточиями. В первом поле каждой записи указано для кого она предназначена. Здесь указывается «класс» пользователя (5-е поле файла master.passwd(5)). Ключевое слово default соответствует любому пользователю с ненулевым UID (т.е. не root'у). В FreeBSD и DragonFly BSD пользователи могут заводить свои собственные файлы ~/.login.conf в домашнем каталоге, где они должны указывать ключевое слово me.

Пример:

default:\
        :passwd_format=nth:\
        :copyright=/etc/COPYRIGHT:\
        :welcome=/etc/motd:\
        :setenv=MAIL=/var/mail/$,BLOCKSIZE=K,FTP_PASSIVE_MODE=YES:\
        :path=/sbin /bin /usr/sbin /usr/bin /usr/games /usr/local/sbin /usr/local/bin /usr/X11R6/bin ~/bin:\
        :nologin=/var/run/nologin:\
        :cputime=unlimited:\
............................
        :umask=022:
        

Для смены алгоритма шифрования пароля в FreeBSD следует поменять значение опции passwd_format, а в OpenBSD — localcipher (и, возможно, ypcipher). Эти опции описаны в Приложение F, /etc/login.conf(5), их значения в Таблица 2.3, «Возможные значения опций crypt_default (FreeBSD) и localcipher, ypcipher (OpenBSD

2.12.3. /etc/auth.conf(5)

В этом файле находятся умолчания, которые ипользует системная функция crypt_set_format(3). По хорошему, сюда надо записать что-то вроде:

crypt_default   =       blf
        

Однако при заведении новых паролей в этот файл система смотрит в последнюю очередь, и более важным окажется файл /etc/login.conf(5) (см. Приложение F, /etc/login.conf(5)).

Таблица 2.3. Возможные значения опций crypt_default (FreeBSD) и localcipher, ypcipher (OpenBSD)

ОпцияОписаниеOS
desDES
md5MD5
blfBlowfish
nthNT-hash
oldDES
newsalt,<rounds> Newsalt; rounds — 24-битное целое, минимум 7250 (число проходов алгоритма).
blowfish,<rounds> Blowfish; rounds — от 4-х до 31-го (логарифм по основанию 2 от числа проходов алгоритма).

2.12.4. /etc/passwd.conf(5)

Данный файл присутствует только в NetBSD и, по смыслу похож на /etc/login.conf(5) из других систем. В файле /etc/passwd.conf хранится информация о том, какой алгоритм шифроваения для каких пользователей использовать. Например:

default:
           localcipher = md5
           ypcipher = old
root:
           localcipher = blowfish,5
        

Здесь мы используем алгоритм md5 для локальных пользователей и старый des для пользователей NIS, а для root используем blowfish, который применяется к паролю 2 в 5-й степени раз (32 раза).

2.12.5. adduser(8)

Утилита adduser(8) предназначена для добавления пользователей в систему. Она может работать как интерактивно, так и из скриптов. Основной утилитой по управлению учётными записями является pw(8), она накладывает ограничение на длину пароля и т.п. Интерактивно вызванная утилита спрашивает у администратора имя пользователя, полное имя (GECOS) и др.

[Замечание]Замечание
Имя пользователя обычно не должно быть более 16 символов и должно состоять из букв и цифр. Эти ограничения наложены по историческим причинам, если вы хотите более длинные имена, вы можете переопределить переменную UT_NAMESIZE в <utmp.h> и пересобрать world. Однако после этого могут быть проблемы с бинарниками скомпилированными в других системах. Кроме того, NIS предполагает, что пароли бывают только 8-ми символьные.

2.12.6. Итого: Blowfish HOWTO

Суммируя сказанное выше, приведём краткое Blowfish HOWTO: как перевести базу паролей в формат Blowfish:

  1. В файл /etc/login.conf(5) в секции default:\ помещаем строки:
    default:\
            :passwd_format=blf:\
                
    По вкусу можем добавить строк мешающих создавать простые пароли (заметим, что в этом больше смысла, чем просто в включении шифрования Blowfish):
            :passwordtime=48d:\
            :mixpasswordcase=true:\
            :minpasswordlen=10:\
            :idletime=60:
                
    (см. Приложение F, /etc/login.conf(5)).
  2. Перестраиваем базу:
    # cap_mkdb /etc/login.conf
                
  3. В файл /etc/auth.conf(8) добавляем строку
    crypt_default=blf
                
    Это необязательное, но желательное действие.
  4. Чтобы перекодировать пароли из текущих форматов в Blowfish, придётся заново ввести все пароли.

2.13. Смена приветствия системы

Описание:  Кандидат должен понимать, что приветствие системы зависить от того, каким способом пользователь получил доступ к системе и знать, какие файлы за это отвечают.

Практика: motd(5), login.conf(5), gettytab(5), sshd_config(5).

2.14. Защита аутентификационных данных

Описание:  Для предотвращения атак против системы путём взлома базы паролей, системы BSD хранят эти данные в шифрованном виде доступными только системным процессам. BSDA кандидат должен понимать где хранятся эти данные и какие на них должны быть пермиссии (права доступа).

Практика: passwd(5), pwd_mkdb(8)

Глава 3. Файлы, файловые системы и диски

3.1. Монтирование и размонтирование файловых систем

Описание:  Кандидат BSDA должен свободно ориентироваться в проблемах монтирования и размонтирования локальных файловых систем, включая: как смонтировать/размонтировать конкретную файловую систему, как смонтировать все файловые системы, как сконфигурировать систему для монтирования файловой системы при загрузке. Передача опций команде mount(8), и разрешение ошибок возникших при выполнении mount(8).

Практика: mount(8), umount(8), fstab(5)

3.2. Конфигурирование NFS

Описание:  Кандидат BSDA должен быть знаком с утилитами связанными с NFS и знать о проблемах с безопасностью, которые могут возникнуть при открытии RPC через брандмауэр. Кандидат должен уметь конфигурировать NFS сервер или клиент в соответствии с указанными требованиями к доступности данных.

Практика: exports(5), nfsd(8), mountd(8), rpcbind(8) или portmap(8), rpc.lockd(8), rpc.statd(8), rc.conf(5) и mount_nfs(8)

3.3. Определение какие файловые системы смонтированы и какие будут смонтированы при загрузке

Описание:  Кандидат должен уметь определять какие файловые системы смонтированы и какие будут смонтированы при загрузке.

Практика: mount(8), du(1), fstab(5)

3.4. Определять ёмкость диска и какие файлы занимают больше места

Описание:  Кандидат BSDA должен уметь работать с UNIX утилитами для быстрого определения какой файл занял много места на жёстком диске.

Практика: du(1), df(1), find(1), sort(1), systat(1)

3.5. Создание и просмотр символических и жёстких ссылок

Описание:  Кандидат должен знать разницу между символьными и жёсткими ссылками, как их создавать просматривать и удалять. Кандидат должен уметь временно разрешить проблему с нехваткой дискового пространства через использование символьных ссылок.

Практика: ln(1), ls(1), rm(1), stat(1)

3.6. Просмотр и изменение ACL

Описание:  Кандидат BSDA должен уметь определить использует ли FreeBSD ACL и если да, то на каких файловых системах. Кандидат должен уметь просматривать и изменять файловые ACL на FreeBSD.

Практика: mount(8), ls(1), getfacl(1)

3.7. Просмотр и изменение пермиссий с использованием как символьных, так и восьмеричных мод

Описание:  Ожидается, что кандидат BSDA знаком с традиционными UNIX пермиссиями включая: как просмотреть и изменить пермиссии, почему sticky-bit важен на каталоге /tmp и других каталогах общего пользования, определять и использовать SUID и SGID биты, понимать разницу между символьным и восьмеричным представлением пермиссий. Вдобавок кандидат должен понимать откуда оболочка берёт умолчальные пермиссии для вновь создаваемых файлов и каталогов, по заданному значению umask определять с какими пермиссиями будет создан файл.

Практика: ls(1), chmod(1), umask(1) или (2)

3.8. Изменение владельца файла и группы

Описание:  Кандидат BSDA должен уметь сменить владельца файла как требуется. Кандидат должен понимать как важно проверить кем он является в системе, до того как создать файл.

Практика: chown(8), chgrp(1); su(1), mtree(8)

3.9. Резервное копирование и восстановление файлов и директорий на локальный диск или ленту

Описание:  Кандидат должен иметь опыт работы с распространёнными в UNIX утилитами командной строки для резервного копирования. Кандидат должен знать имена устройств для ленточных ностителей.

Практика: tar(1), cpio(1), pax(1), cp(1), cpdup(1)

3.10. Резервное копирование и восстановление файловой системы

Описание:  Кандидат должен разбираться в утилитах используемых для резервного копирования всей файловой системы в целом и различных уровнях утилиты dump(1).

Практика: dump(8), restore(8), dd(1)

3.11. Знание структуры каталогов системы

Описание:  Кандидат BSDA должен быстро ориентироваться в структуре каталогов системы BSD.

Практика: hier(7)

3.12. Ручной запуск программы проверки файловой системы и средств её восстановления

Описание:  Кандидат BSDA должен знать утилиты для проверки содержимого файловой системы и использовать их.

Практика: fsck(8)

3.13. Определение и изменение флагов файлов

Описание:  Кандидат BSDA должен понимать как флаги расширяют традиционные пермиссии UNIX и знать как посмотреть и изменить флаги неизменяемости, "дописываемости" и неудаляемости (immutable, append-only, undelete).

Практика: ls(1), chflags(1)

3.14. Слежение за состоянием виртуальной памяти системы

Описание:  Виртуальная память имеет важное значение для производительности системы. Кандидат BSDA должен уметь конфигурировать устройство swap и следить за его использованием.

Практика: pstat(8), systat(1), top(1), vmstat(8); swapctl(8), swapinfo(8)

Глава 4. Пользователи и управление учётными записями

4.1. Создание, изменение и удаление учётных записей

Описание:  Важная часть системного администрования — манипулирование учётными записями. Кандидат BSDA должен быть знаком с различными утилитами для манипулирования учётными записями и уметь использовать их в соответствии с поставленными задачами.

Практика: vipw(8); pw(8), adduser(8), adduser.conf(5), useradd(8), userdel(8), rmuser(8), userinfo(8), usermod(8), и user(8)

Комментарий

[Замечание]Замечание
Данный текст прислан Дмитрием Орловым, но подвергся моей незначительной редактуре. Е.М.

После установки системы требуется перейти к задаче управления локальными пользователями системы. Даже в том случае, если вы единственный пользователь, системы семейства BSD настоятельно рекомендуют завести некоего пользователя и пользоваться привилегированным аккаунтом при помощи команды su(8), что предохранит вас от неожиданного разрушения собственной системы. Существует другая крайность, это создание множества пользователей с административными правами, что может привести как минимум к нестабильности системы, к ее вскрытию злоумышленниками или даже разрушению.

4.1.1. Введение

Можно выделить три основных типа учётных записей: суперпользователь, системные пользователи, и учётные записи пользователей. Учётная запись суперпользователя, обычно называемая root, используется для управления системой без ограничения привилегий. Системные пользователи запускают сервисы и, как правило, не могут входить (login) в систему. Учётные записи пользователей необходимы остальным для входа в систему, чтения почты, работы с документами, создания приложений и так далее.

С каждой учётной записью в системе *BSD связана определённая идентификационная информация:

Имя пользователя

Имя пользователя в том виде, в каком оно вводится в приглашение login:. Имена пользователей должны быть уникальны в пределах одного компьютера; не может быть двух пользователей с одинаковым именем пользователя. Существует множество правил для создания правильных имён пользователей, документированных в passwd(5); вы как правило будете использовать имена пользователей, состоящие из восьми или меньшего количества символов, все символы в нижнем регистре.

Вообще-то это не является какой-то догмой. Но некоторый софт расчитывает, что на имя пользователя наложены некоторые ограничения. Так, старые реализации системы NIS расчитывали, то имя пользователя состоит не более чем из восьми символов. В настоящий момент вы можете не соблюдать это ограничение. Почтовая система sendmail(8) при доставке почты переводит символы в нижний регистр. Поэтому пользователь в имени которого есть буквы из верхнего регистра будет лишён почты. Многие файловые форматы расчитывают на то, что в имени нет двоеточия и т.п. Если по каким-то причинам вы хотите, чтобы в имени были большие буквы, точки и т.п. Вам надо подумать над архитектурой програмного обеспечения. Например, если вы хотите, чтобы в вашем домене существовали электронные адреса типа Mikhail.Kutuzov@borodino.ru, вам слеует хранить почтовые аккаунты, например, в базе данных PostgreSQL, а не в виде учётных записей UNIX.

Пароль
С каждой учётной записью связан пароль. Пароль может быть пустым, в этом случае для доступа к системе не нужен пароль. Обычно это очень плохая идея; у каждой учётной записи должен быть пароль.
ID пользователя (User ID, UID)
The UID это номер, традиционно от 0 до 65535, используемый для однозначной идентификации пользователя в системе. Сама система *BSD для идентификации пользователей использует UID — любая команда *BSD, позволяющая вам указывать имя пользователя, первым делом преобразует его к UID. Это означает, что вы можете создать несколько учётных записей с различными именами пользователей, но с одним UID. *BSD будет воспринимать эти учётные записи как одного пользователя. Например, в системе FreeBSD имеются учётные записи root и toor с одинаковым UID=0. Вы можете заблокировать логин пользователя root, но при необходимости ходить в систему как toor и иметь при этом права суперпользователя. Это плохая идея с точки зрения безопасности, однако возможность такая есть. Кроме того, многие характеристики учётных записей, такие как оболочка, домашний каталог и даже почтовый spool, привязаны не к UID а именно к имени. Таким образом, имея альтернативные имена для одного пользователя вы можете иметь альтернативные пароли, оболочки и пр. при одинаковом наборе прав.
ID группы (Group ID, GID)
GID это номер, традиционно от 0 до 65535, используемый для однозначной идентификации главной группы, к которой принадлежит пользователь. Группы это механизм для контроля доступа к ресурсам на основе GID пользователя вместо его UID. Это может значительно уменьшить размер некоторых файлов настройки. Кроме того, пользователь может быть включен более чем в одну группу.
Класс логина
Классы логинов это расширение к механизму групп, позволяющее системе более гибко управлять различными пользователями. Например, ограничение использования ресурсов системы (login.conf(5), passwd(5), см. так же Приложение F, /etc/login.conf(5)).
Время изменения пароля
По умолчанию *BSD не принуждает пользователей периодически менять пароли. Вы можете включить эту функцию для определённых пользователей, заставив некоторых или всех пользователей менять пароли по прошествии некоторого времени.
Время истечения действия учетной записи
По умолчанию в *BSD время действия учётных записей не ограничено. Если вы создаёте учётные записи, продолжительность жизни которых ограничена, например учётные записи для студентов в школе, вы можете определить время истечения действия учётной записи. После наступления этого времени учётная запись не может использоваться для входа в систему, хотя каталоги и файлы этой учётной записи останутся нетронутыми.
Полное имя пользователя
Имя пользователя является уникальным идентификатором учётной записи в *BSD, но недостаточно для сопоставления с реальным именем пользователя. Спустя некоторое время после заведения учётной записи с именем vjhe56 вы уже не вспомните кто это такой. Реальное имя и другая информация может быть добавлена в виде так называемой GECOS information в базу учётных записей. Это необязательное действие.
Домашний каталог
Домашний каталог это полный путь к каталогу в системе, в котором пользователь начнёт работать после входа в систему. По общепринятому соглашению все домашние каталоги пользователей помещаются в /home/username. Пользователи хранят личные файлы в домашнем каталоге и в любых подкаталогах, создаваемых внутри домашнего каталога.
Оболочка пользователя
Оболочка необходима пользователям как средство взаимодействия с системой по умолчанию. Существует множество различных видов оболочек, опытные пользователи работают с собственными настройками, которые могут быть отражены в установках их учетных записей.

4.1.2. Добавление пользователя

Самый простой и интерактивный способ добавить нового пользователя, это использовать команду adduser(8) (нет в NetBSD). Пример использования adduser(8). (Скопировано из OpenBSD FAQ).

# adduser
Use option ``-silent'' if you don't want to see all warnings and questions.

Reading /etc/shells
Reading /etc/login.conf
Check /etc/master.passwd
Check /etc/group

Ok, let's go.
Don't worry about mistakes. I will give you the chance later to correct any input.
Enter username []: testuser
Enter full name []: Test FAQ User
Enter shell csh ksh nologin sh [sh]: ksh
Uid [1002]: Enter
Login group testuser [testuser]: guest
Login group is ``guest''. Invite testuser into other groups: guest no [no]: no
Login class auth-defaults auth-ftp-defaults daemon default staff [default]: <Enter>
Enter password []: <Набираете пароль и нажимаете Enter>
Enter password again []: <Набираете пароль и нажимаете Enter>

Name:        testuser
Password:    ****
Fullname:    Test FAQ User
Uid:         1002
Gid:         31 (guest)
Groups:      guest
Login Class: default
HOME:        /home/testuser
Shell:       /bin/ksh
OK? (y/n) [y]: y
Added user ``testuser''
Copy files from /etc/skel to /home/testuser
Add another user? (y/n) [y]: n
Goodbye!
        

Значения по умолчанию для adduser(8) можно создать в файле /etc/adduser.conf

# adduser -config_create
        

Вот пример файла /etc/adduser.conf:

# Конфигурационный файл для утилиты adduser(8).
# ЗАМЕЧАНИЕ: only *some* variables are saved.
# Последнее изменение Fri Mar 30 14:04:05 EST 2004.

defaultLgroup=
defaultclass=
defaultgroups=
passwdtype=yes
homeprefix=/home
defaultshell=/bin/csh
udotdir=/usr/share/skel
msgfile=/etc/adduser.msg
disableflag=
upwexpire=91d # Срок годности паролей истекает через 91 день
        

Скрипт adduser(8) вначале читает /etc/group, /etc/passwd, /etc/shells и другие конфигурационные файлы на предмет целостности и инициализации значений по умолчанию, а так же получения допустимых значений. Добавляет домашнюю директорию и создает пользователя, а так же заносит его в требуемые группы. Интересующиеся тонкостями могут просмотреть сам скрипт /usr/sbin/adduser.

В OpenBSD и NetBSD в командной строке пользователя можно дабавить при помощи утилиты user(8). Метод достаточно прост и полезен для использования в сценариях. Следует только учитывать, когда заводится пользователь данной командой, то используется УЖЕ шифрованный пароль. Таким образом, для вышеописанного пользователя мы получаем следующую последовательность действий (пример сделан в OpenBSD):

# encrypt -p -b 6
Enter string:
$2a$06$YOdOZM3.4m6MObBXjeZtBOWArqC2.uRJZXUkOghbieIvSWXVJRzlq

# user add -p '$2a$06$YOdOZM3.4m6MObBXjeZtBOWArqC2.uRJZXUkOghbieIvSWXVJRzlq' -u 1002 \
-s /bin/ksh -c "Test FAQ User" -m -g guest testuser
        

В FreeBSD и DragonFly BSD для этих целей используется утилита pw(8)

4.1.3. Изменение параметров пользовательской учётной записи

BSD системы поддерживают «классический», древнейший способ изменения пользовательской информации — vipw(8).Использование этой утилиты весьма удобно, так как после рабоиы vipw(8) проверяет синтаксис файла и, если администратор не совершил никаких ошибок, обновляет данные в файле /etc/master.passwd, строит из него /etc/passwd и бинарные базы /etc/pwd.db и /etc/spwd.db. (См. Раздел 2.12.1, «Устройство базы паролей».)

Однако, этот способ следует рекомендовать лишь в том случае, если вы понимаете формат файла /etc/master.passwd. Поэтому начинающие и ине только начинающие администраторы используют команду chpass(1).

При запуске chpass(1) запускает редактор vi(1) (см. Раздел 7.3, «Навыки работы в vi(1)») и предлагает изменить следующие настройки учётной записи:

# chpass testuser

Changing user database information for testuser.
Login: testuser
Encrypted password:$2a$06$YOdOZM3.4m6MObBXjeZtBOWArqC2.uRJZXUkOghbieIvSWXVJRzlq
Uid [#]: 1002
Gid [# or name]: 31
Change [month day year]:
Expire [month day year]:
Class:
Home directory: /home/testuser
Shell: /bin/ksh
Full Name: Test FAQ User
Office Location:
Office Phone:
Home Phone:
        

В случе если команда вызвана непривилегированным поьзователем, она позволяет изменить информацию только в рамках полномочий пользователя:

$ chpass

#Changing user information for paakai.
Shell: /usr/local/bin/bash
Full Name: Paakai Sudoer
Office Location:
Office Phone:
Home Phone:
Other information:
        

После успешного изменения информации о пользователе, chpass(8) вызывает pwd_mkdb(8) для актуализации изменений в базах данных пользователей (/etc/master.passwd и /etc/passwd).

Другие, команды для изменения информации о пользователях: user mod, usermod, pw usermod.

4.1.4. Удаление учётной записи

Быстро и эффективно удалить пользователя можно с помощью команды rmuser(8). rmuser(8) старается удалить всё, относящееся к указанному пользователю: домашнюю директорию, письма, задачи в crontab(1)/at(1), уничтожает запущенные процессы этого пользователя, созданные им временные файлы в /tmp и, разумеется, удаляет его из /etc/master.passwd и /etc/group.

# rmuser
Enter login name for user to remove: testuser
Matching password entry:
testuser:$2a$06$YOdOZM3.4m6MObBXjeZtBOWArqC2.uRJZXUkOghbieIvSWXVJRzlq:1002
:31::0:0:Test FAQ User:/home/testuser:/bin/ksh
Is this the entry you wish to remove? y
Remove user's home directory (/home/testuser)? y
Updating password file, updating databases, done.
Updating group file: done.
Removing user's home directory (/home/testuser): done.
        

Для удаления пользователя так же можно вопользоваться командами: userdel, user del, pw userdel.

К сожалению, в UNIX (да и вообще, наверное ни в одной операционной системе) не существует абсолютно надёжного метода удалить пользователя. Никто не может гарантировать вам, что этот пользователь не прикопал своих файлов где-то вне своего домашнего каталога. Что никто не выдал ему прав на ресурсы используя метод ACL. rmuser(8) не в силах удалить связанные с пользователем почтовые алиасы. Если спустя время вы заведёте нового пользователя, то ему может быть выдан UID старого пользователя и он завладеет брошенными файлами. Если имя нового пользователя совпадёт с именем удалённого, то он завладеет почтовыми алиасами и др.

В связи со сказанным, в ряде случаев блокирование пользователей оказывается более желательно, чем удаление их учётных записей.

4.2. Создание системных учётных записей

Описание:  Кандидат должен понимать, что многие сервисы требуют учётных записей и что эти записи должны быть недоступны для логина.

Практика: nologin(8); использование * в поле пароля в passwd(5)

Комментарий

[Замечание]Замечание
Данный текст прислан Дмитрием Орловым, спасибо.

Системные пользователи создаются для запусков сервисов (демонов), таких как DNS, почта, веб-серверы и так далее, и не могут быть использованы для входа в систему. Это необходимо по соображениям безопасности: если сервис работает с правами суперпользователя, он может действовать без ограничений, а значит, в случае взлома сервиса злоумыленником, последний получает полный контроль над атакованной системой.

nobody это классический непривилегированный системный пользователь. Тем не менее, необходимо помнить, что чем больше сервисов используют nobody, тем больше файлов и процессов ассоциировано с этим пользователем, и следовательно тем больше прав появляется у этого пользователя.

Для системных пользователей в качестве оболочки указывается /sbin/nologin, который при попытке входа в систему, выдаёт сообщение "This account is currently not available", или же то, которое вы укажите в файле /etc/nologin.txt (например, "Daemons are deathless"). Если же при помощи vipw(8) вместо пароля указать "*", то мы не получим даже такого политкорректного nologin сообщения, нам сразу скажут — "Login incorrect".

4.3. Отключение или включение учётной записи (lock и unlock)

Описание:  Кандидат BSDA должен знать как определить включены ли учётная запись и как её включить.

Практика: vipw(8); chpass(1), chfn(1), chsh(1), pw(8), user(8)

4.4. Идентификация и членство в группах

Описание:  В системе пермиссий UNIX важно уметь определить кем вы являетесь и каково ваше членство в группах. Кандидат должен это уметь.

Практика: id(1), groups(1), who(1), whoami(1), su(1)

4.5. Определение кто сейчас присутствует в системе или последнего времени входа в систему

Описание:  Системы BSD поддерживают базы данных с детальной информацией о логинах. Кандидат BSDA должен знать что это за базы, где они хранятся и какими утилитами можно воспользоваться, чтобы получить информацию о логинах.

Практика: wtmp(5), utmp(5), w(1), who(1), users(1), last(1), lastlogin(8), lastlog(5), finger(1)

4.5.1. finger(1)

4.6. Включение слежения за учётными записями и просмотр статистики

Описание:  Кандидат BSDA должен быть осведомлён когда следует включить систему сбора статистики об учётных записях (accaunting), знать какие для этого нужны утилиты и как просматривать собранную статистику.

Практика: ac(8), sa(8), accton(8), lastcomm(1), last(1)

4.7. Изменение пользовательской оболочки

Описание:  Кандидат должен знать какая оболочка по умолчанию у пользователя и у суперпользователя. Он должен знать как сменить оболочку в каждой из операционных систем.

Практика: vipw(8); chpass(1), chfn(1), chsh(1), pw(8), user(8)

4.8. Контролировать какие файлы будут копироваться в новую пользовательскую директорию при создании учётной записи

Описание:  Системы BSD используют каталог skel содержащий файлы, которые должны быть скопированы при создании домашнего каталога пользователя при заведении учётной записи. Кандидат BSDA должен знать где в какой системе находиться данный каталог и как отменить его копирование при создании учётной записи.

Практика: pw(8), adduser.conf(5), useradd(8) и usermgmt.conf(5)

4.9. Смена пароля

Описание:  Кандидат BSDA должен уметь сменить свой пароль и пароль пользователя.

Практика: passwd(1), vipw(8)

Глава 5. Основы системного администрирования

Содержание

[-]5.1. Определение какой процесс расходует основную часть ресурсов ЦПУ
[-]5.2. Определять активные процессы и посылать им сигналы
[-]5.3. Использование скриптов rc(8) для определения запущенных сервисов, их запуск, остановка и перезапуск
[*]5.4. Определение установленного оборудования и его конфигурирование
[+]5.4.1. Утилита dmesg(8)
[-]5.5. Определение какие модули ядра загружены, их загрузка и выгрузка
[-]5.6. Изменение на лету переменных ядра
[-]5.7. Изучение состояния програмного RAID'а (mirror or stripe)
[-]5.8. Определение какой MTA используется системой
[-]5.9. Конфигурирование системы ведения системных журналов
[-]5.10. Просмотр журналов для разрешения проблем и слежения за поведением системы
[-]5.11. Понимание основных проблем с принтером
[-]5.12. Создание или изменение почтовых псевдонимов в Sendmail и Postfix
[-]5.13. Остановка, перезагрузка или перевод системы в однопользовательский режим
[-]5.14. Отличие жёстких ограничений от мягких и изменение существующих системных ограничений
[-]5.15. Знание утилит BSD для регулировки трафика и контроля за полосой пропускания
[-]5.16. Знание распространённых конфигурационных системных файлов и, возможно, сторонних конфигурационных файлов различных сервисов
[-]5.17. Конфигурирование сервисов для автоматического старта при запуске системы
[-]5.17.1. Система инициализации BSD
[-]5.17.2. Суперсервер inetd(8)
[-]5.18. Конфигурирование скриптов, нужных для различных задач по обслуживанию системы, для периодического запуска
[-]5.19. Просмотр очереди Sendmail'а или Postfix'а
[-]5.20. Определение когда последний раз была запущена система и какова её загруженность
[-]5.21. Слежение за операциями ввода/вывода на диске
[-]5.22. Работа с занятыми устройствами
[-]5.23. Определение информации характеризующей операционную систему
[-]5.24. Понимание преимуществ использования лицензии BSD

5.1. Определение какой процесс расходует основную часть ресурсов ЦПУ

Описание:  Кандидат BSDA должен уметь следить за работой процессов и заметить ненормально высокую загруженность CPU. Кандидат должен уметь завершить процесс или изменить его приоритет.

Практика: top(1), systat(1), ps(1), nice(1), renice(1), kill(1)

5.2. Определять активные процессы и посылать им сигналы

Описание:  Кандидат должен знать названия и номера наиболее употребляемых в UNIX'е сигналов и знать как послать сигнал активному процессу. Кандидат должен знать разницу между SIGTERM и SIGKILL.

Практика: ps(1); kill(1); killall(1); pkill(1); pgrep(1)

5.3. Использование скриптов rc(8) для определения запущенных сервисов, их запуск, остановка и перезапуск

Описание:  В дополнении к тому, чтобы знать как непосредственно послать сигнал процессу, кандидат BSDA должен знать, что системы BSD поставляют скрипты, которые могут быть использованы для того, чтобы проверить состояние процесса, остановить, запустить или перезапустить процесс. Кандидат должен знать где в какой системе находятся эти скрипты. Эта тема не относится к OpenBSD.

Практика: rc(8), rc.conf(5)

5.4. Определение установленного оборудования и его конфигурирование

Описание:  Операционные системы BSD поставляются со множеством утилит для определения установленного оборудования. Кандидат BSDA должен знать как определить какое оборудование было обнаружено при загрузке и какие специфичные для BSD утилиты могут быть использованы для разрешения проблем и манипулирования PCI, ATA и устройствими SCSI.

Практика: dmesg(8), /var/run/dmesg.boot, pciconf(8), atacontrol(8) и camcontrol(8); atactl(8) и /kern/msgbuf; scsictl(8) или scsi(8)

Комментарий

5.4.1. Утилита dmesg(8)

Утилита dmesg(8) предназначена для вывода на экран последних сообщений ядра. В процессе загрузки операционной системы ядро определяет оборудование. Информация об этом может быть найдена при помощи данной утилиты. Однако в процессе работы системы информация помещённая в dmesg(8) может быть вытеснена новыми сообщениями ядра. Чтобы всегда иметь доступ к начальним, «загрузочным» сообщениям ядра, мы можем обратиться к файлу /var/run/dmesg.boot. Так же сегодняшний и вчерашний журнал сообщений ядра можно найти в файлах /var/log/dmesg.today и /var/log/dmesg.yesterday соответственно.

Copyright (c) 1992-2008 The FreeBSD Project.
Copyright (c) 1979, 1980, 1983, 1986, 1988, 1989, 1991, 1992, 1993, 1994
	The Regents of the University of California. All rights reserved.
FreeBSD is a registered trademark of The FreeBSD Foundation.
FreeBSD 7.0-RELEASE #0: Fri Feb 29 12:05:47 MSK 2008
    root@ws-505-287.infosec.ru:/usr/obj/usr/src/sys/GENERIC
Timecounter "i8254" frequency 1193182 Hz quality 0
CPU: Intel(R) Celeron(R) CPU 2.40GHz (2394.01-MHz 686-class CPU)
  Origin = "GenuineIntel"  Id = 0xf34  Stepping = 4
  Features=0xbfebfbff<FPU,VME,DE,PSE,TSC,MSR,PAE,MCE,CX8,APIC,SEP,MTRR,PGE,MCA,CMOV,PAT,PSE36,CLFLUSH,DTS,ACPI,MMX,FXSR,SSE,SSE2,SS,HTT,TM,PBE>
  Features2=0x441d<SSE3,RSVD2,MON,DS_CPL,CNXT-ID,xTPR>
real memory  = 502464512 (479 MB)
avail memory = 477736960 (455 MB)
ACPI APIC Table: <A M I  OEMAPIC >
ioapic0 <Version 2.0> irqs 0-23 on motherboard
kbd1 at kbdmux0
kqemu version 0x00010300
kqemu: KQEMU installed, max_locked_mem=238924kB.
ath_hal: 0.9.20.3 (AR5210, AR5211, AR5212, RF5111, RF5112, RF2413, RF5413)
hptrr: HPT RocketRAID controller driver v1.1 (Feb 29 2008 12:05:13)
acpi0: <A M I OEMXSDT> on motherboard
acpi0: [ITHREAD]
acpi0: Power Button (fixed)
acpi0: reservation of 0, a0000 (3) failed
acpi0: reservation of 100000, 1def0000 (3) failed
Timecounter "ACPI-fast" frequency 3579545 Hz quality 1000
acpi_timer0: <24-bit timer at 3.579545MHz> port 0x808-0x80b on acpi0
cpu0: <ACPI CPU> on acpi0
p4tcc0: <CPU Frequency Thermal Control> on cpu0
pcib0: <ACPI Host-PCI bridge> port 0xcf8-0xcff on acpi0
pci0: <ACPI PCI bus> on pcib0
vgapci0: <VGA-compatible display> port 0xefe0-0xefe7 mem 0xf0000000-0xf7ffffff,0xfe780000-0xfe7fffff at device 2.0 on pci0
agp0: <Intel 82865G (865G GMCH) SVGA controller> on vgapci0
agp0: detected 32636k stolen memory
agp0: aperture size is 128M
uhci0: <Intel 82801EB (ICH5) USB controller USB-A> port 0xef00-0xef1f irq 16 at device 29.0 on pci0
uhci0: [GIANT-LOCKED]
uhci0: [ITHREAD]
usb0: <Intel 82801EB (ICH5) USB controller USB-A> on uhci0
usb0: USB revision 1.0
uhub0: <Intel UHCI root hub, class 9/0, rev 1.00/1.00, addr 1> on usb0
uhub0: 2 ports with 2 removable, self powered
uhci1: <Intel 82801EB (ICH5) USB controller USB-B> port 0xef20-0xef3f irq 19 at device 29.1 on pci0
uhci1: [GIANT-LOCKED]
uhci1: [ITHREAD]
usb1: <Intel 82801EB (ICH5) USB controller USB-B> on uhci1
usb1: USB revision 1.0
uhub1: <Intel UHCI root hub, class 9/0, rev 1.00/1.00, addr 1> on usb1
uhub1: 2 ports with 2 removable, self powered
uhci2: <Intel 82801EB (ICH5) USB controller USB-C> port 0xef40-0xef5f irq 18 at device 29.2 on pci0
uhci2: [GIANT-LOCKED]
uhci2: [ITHREAD]
usb2: <Intel 82801EB (ICH5) USB controller USB-C> on uhci2
usb2: USB revision 1.0
uhub2: <Intel UHCI root hub, class 9/0, rev 1.00/1.00, addr 1> on usb2
uhub2: 2 ports with 2 removable, self powered
uhci3: <Intel 82801EB (ICH5) USB controller USB-D> port 0xef80-0xef9f irq 16 at device 29.3 on pci0
uhci3: [GIANT-LOCKED]
uhci3: [ITHREAD]
usb3: <Intel 82801EB (ICH5) USB controller USB-D> on uhci3
usb3: USB revision 1.0
uhub3: <Intel UHCI root hub, class 9/0, rev 1.00/1.00, addr 1> on usb3
uhub3: 2 ports with 2 removable, self powered
ehci0: <Intel 82801EB/R (ICH5) USB 2.0 controller> mem 0xfe77bc00-0xfe77bfff irq 23 at device 29.7 on pci0
ehci0: [GIANT-LOCKED]
ehci0: [ITHREAD]
usb4: EHCI version 1.0
usb4: companion controllers, 2 ports each: usb0 usb1 usb2 usb3
usb4: <Intel 82801EB/R (ICH5) USB 2.0 controller> on ehci0
usb4: USB revision 2.0
uhub4: <Intel EHCI root hub, class 9/0, rev 2.00/1.00, addr 1> on usb4
uhub4: 8 ports with 8 removable, self powered
pcib1: <ACPI PCI-PCI bridge> at device 30.0 on pci0
pci1: <ACPI PCI bus> on pcib1
fxp0: <Intel 82801BA (D865) Pro/100 VE Ethernet> port 0xdf00-0xdf3f mem 0xfe5ff000-0xfe5fffff irq 20 at device 8.0 on pci1
miibus0: <MII bus> on fxp0
inphy0: <i82562ET 10/100 media interface> PHY 1 on miibus0
inphy0:  10baseT, 10baseT-FDX, 100baseTX, 100baseTX-FDX, auto
fxp0: Ethernet address: 00:11:d8:12:79:a8
fxp0: [ITHREAD]
isab0: <PCI-ISA bridge> at device 31.0 on pci0
isa0: <ISA bus> on isab0
atapci0: <Intel ICH5 UDMA100 controller> port 0x1f0-0x1f7,0x3f6,0x170-0x177,0x376,0xfc00-0xfc0f at device 31.1 on pci0
ata0: <ATA channel 0> on atapci0
ata0: [ITHREAD]
ata1: <ATA channel 1> on atapci0
ata1: [ITHREAD]
atapci1: <Intel ICH5 SATA150 controller> port 0xefa8-0xefaf,0xefa4-0xefa7,0xef68-0xef6f,0xefa0-0xefa3,0xeed0-0xeedf irq 18 at device 31.2 on pci0
atapci1: [ITHREAD]
ata2: <ATA channel 0> on atapci1
ata2: [ITHREAD]
ata3: <ATA channel 1> on atapci1
ata3: [ITHREAD]
pci0: <serial bus, SMBus> at device 31.3 (no driver attached)
pci0: <multimedia, audio> at device 31.5 (no driver attached)
acpi_button0: <Power Button> on acpi0
atkbdc0: <Keyboard controller (i8042)> port 0x60,0x64 irq 1 on acpi0
atkbd0: <AT Keyboard> irq 1 on atkbdc0
kbd0 at atkbd0
atkbd0: [GIANT-LOCKED]
atkbd0: [ITHREAD]
sio0: configured irq 4 not in bitmap of probed irqs 0
sio0: port may not be enabled
sio0: configured irq 4 not in bitmap of probed irqs 0
sio0: port may not be enabled
sio0: <16550A-compatible COM port> port 0x3f8-0x3ff irq 4 flags 0x10 on acpi0
sio0: type 16550A
sio0: [FILTER]
sio1: configured irq 3 not in bitmap of probed irqs 0
sio1: port may not be enabled
sio1: configured irq 3 not in bitmap of probed irqs 0
sio1: port may not be enabled
sio1: <16550A-compatible COM port> port 0x2f8-0x2ff irq 3 on acpi0
sio1: type 16550A
sio1: [FILTER]
fdc0: <floppy drive controller (FDE)> port 0x3f0-0x3f5,0x3f7 irq 6 drq 2 on acpi0
fdc0: [FILTER]
fd0: <1440-KB 3.5" drive> on fdc0 drive 0
pmtimer0 on isa0
ppc0: <Parallel port> at port 0x378-0x37f irq 7 on isa0
ppc0: SMC-like chipset (ECP/EPP/PS2/NIBBLE) in COMPATIBLE mode
ppc0: FIFO with 16/16/9 bytes threshold
ppbus0: <Parallel port bus> on ppc0
ppbus0: [ITHREAD]
plip0: <PLIP network interface> on ppbus0
lpt0: <Printer> on ppbus0
lpt0: Interrupt-driven port
ppi0: <Parallel I/O> on ppbus0
ppc0: [GIANT-LOCKED]
ppc0: [ITHREAD]
sc0: <System console> at flags 0x100 on isa0
sc0: VGA <16 virtual consoles, flags=0x300>
vga0: <Generic ISA VGA> at port 0x3c0-0x3df iomem 0xa0000-0xbffff on isa0
ums0: <vendor 0x1267 USB Mouse, class 0/0, rev 1.00/2.30, addr 2> on uhub1
ums0: 3 buttons and Z dir.
Timecounter "TSC" frequency 2394009873 Hz quality 800
Timecounters tick every 1.000 msec
hptrr: no controller detected.
acd0: CDROM <TEAC CD-552G/74S2> at ata0-master UDMA33
ad4: 76319MB <Seagate ST380817AS 3.42> at ata2-master SATA150
Trying to mount root from ufs:/dev/ad4s2a
        

Данный листинг показывает список устройств обнаруженных при старте системы. Каждая строка в этом листинге начинается с имени устройства с номером. Устройства в BSD называются по имени дрйвера, поэтому информацию о том или ином устройстве можно получить с соответствующей страницы man(1):

$ man 4 ums
        

Таким образом, можно получить детальную информацию о типе устройства и наборе чипсетов поддерживаемых подгруженным драйвером.

5.5. Определение какие модули ядра загружены, их загрузка и выгрузка

Описание:  Кандидат BSDA должен понимать разницу между статически скомпилированным ядром и ядром использующим подгружаемые модули. Кандидат должен уметь просматривать список загруженных модулей, загружать и выгружать модули, однако он должен знать, что в системах NetBSD и OpenBSD использование модулей ядра не одобряется.

Практика: kldstat(8), kldload(8), kldunload(8), и loader.conf(5); modstat(8), modload(8), modunload(8), и lkm.conf(5)

5.6. Изменение на лету переменных ядра

Описание:  Системы BSD используют переменные ядра MIB, что позволяет системному администратору просматривать и изменять состояние ядра на работающей системе. Кандидат должен уметь изменять эти переменные как на лету во время работы системы, так и постоянно, выставляя начальные значения действующие в момент загрузки системы. Кандидат должен понимать как изменить переменную MIB доступную только для чтения.

Практика: sysctl(8), sysctl.conf(5)

5.7. Изучение состояния програмного RAID'а (mirror or stripe)

Описание:  В дополнении к тому, что системы BSD предоставляют драйвера к аппаратным RAID контроллерам, BSD предоставляет встроенный програмный RAID. Кандидат должен знать разницу между RAID уровня 0, 1, 3 и 5 и какие утилиты доступны в различных системах BSD для конфигурирования програмного RAID'а.

Практика: vinum(8), gmirror(8), gstripe(8), graid3(8), raidctl(8), ccdconfig(8)

5.8. Определение какой MTA используется системой

Описание:  Кандидат BSDA должен понимать роль MTA, определять какой(ие) MTA доступен(ны) во время установки системы, какой конфигурационный файл указывает на то, какой MTA используется системой. Кандидат должен знать разницу между форматами хранения почты mailbox и maildir.

Практика: mailer.conf

5.9. Конфигурирование системы ведения системных журналов

Описание:  Кандидат BSDA должен знать, что система автоматически создаёт и манипулирует множеством журнальных файлов. Кандидат должен уметь настраивать ротацию журнальных файлов по времени или размеру, понимать термины «средство» и «важность», смотреть сжатые журнальные файлы. (К сожалению, в русском языке закрепилась традиция перевода термина syslog facilities как средства syslog. Перевод крайне неудачный, но такова традиция — прим. переводчика.)

Практика: newsyslog(8), newsyslog.conf(5), syslog.conf(5), zmore(1), bzcat(1)

5.10. Просмотр журналов для разрешения проблем и слежения за поведением системы

Описание:  Кандидат должен знать насколько важно регулярно просматривать журнальные файлы и как просматривать их во время решения проблем.

Практика: tail(1), /var/log/*, syslog.conf(5), grep(1), dmesg(8)

5.11. Понимание основных проблем с принтером

Описание:  Кандидат BSDA должен уметь просмотреть очередь печати и манипулировать заданиями в очереди. Кандидат должен понимать значение первых двух полей в файле /etc/printcap.

Практика: lpc(8), lpq(1), lprm(1), printcap(5)

5.12. Создание или изменение почтовых псевдонимов в Sendmail и Postfix

Описание:  Кандидат BSDA должен понимать когда надо создать почтовый псевдоним (алиас) и как это сделать в Sendmail и в Postfix

Практика: newaliases(1), aliases(5), postaliases(1)

5.13. Остановка, перезагрузка или перевод системы в однопользовательский режим

Описание:  Кандидат BSDA должен понимать последствия связанные с остановкой, перезагрузкой ли переводом системы в однопользовательский режим, понимать когда это необходимо и как минимизировать при этом воздействие на сервер.

Практика: shutdown(8)

5.14. Отличие жёстких ограничений от мягких и изменение существующих системных ограничений

Описание:  Кандидат должен понимать, что ограничения ресурсов наследуются от оболочки и уметь изменять их постоянно или временно. Кандидат должен понимать разницу между мягким и жёстким ограничением.

Практика: limit(1), limits(1), login.conf(5), sysctl(8) на NetBSD

5.15. Знание утилит BSD для регулировки трафика и контроля за полосой пропускания

Описание:  Кандидат должен понимать когда следует создать политики для контроля ширины полосы пропускания для доступа к некоторым сервисам. Кандидат должен знать какие средства доступны для контроля ширины полос пропускания.

Практика: ipfw(8), altq(4), dummynet(4), altq(9), altqd(8), altq.conf(5)

5.16. Знание распространённых конфигурационных системных файлов и, возможно, сторонних конфигурационных файлов различных сервисов

Описание:  Системы BSD часто используют для предоставления услуг Интернет. Кандидата BSDA могут попросить найти, рассмотреть и сделать какие-нибудь изменения в конфигурационных файлах каких-нибудь сервисов. Кандидат должен знать как называются конфигурационные файлы и с какими они связаны сервисами.

Практика: httpd.conf(5), sendmail.cf, master.cf, dhcpd.conf(5), named.conf(5), smb.conf(5)

5.17. Конфигурирование сервисов для автоматического старта при запуске системы

Описание:  Кандидат BSDA должен знать, что в процессе загрузки BSD не используются уровни запуска (runlevels из SystemV — примечание переводчика). Для того, чтобы минимизировать воздействие на систему перезагрузок, кандидат должен уметь сконфигурировать систему так, чтобы сервисы стартовали при загрузке системы автоматически. Причём сделать это надо собственными средствами BSD.

Практика: rc.conf(5), rc(8), inetd(8)

5.17.1. Система инициализации BSD

5.17.2. Суперсервер inetd(8)

5.18. Конфигурирование скриптов, нужных для различных задач по обслуживанию системы, для периодического запуска

Описание:  Системы BSD предоставляют множество скриптов для управления и проверки системы. Если требуется, кандидат BSDA должен уметь найти эти скрипты и запустить вручную, а так же уметь сделать так, чтобы они запускались регулярно раз в день, еженедельно, ежемесячно, на любой системе BSD.

Практика: periodic.conf(5) и periodic(8) на DragonFly BSD и FreeBSD; security.conf(5), daily.conf(5), weekly.conf(5) и monthly.conf(5) на NetBSD; daily(8), weekly(8) и monthly(8) на OpenBSD

5.19. Просмотр очереди Sendmail'а или Postfix'а

Описание:  Кандидат BSDA должен уметь просмотреть почтовую очередь, чтобы определить какое письмо застряло. Если необходимо, надо уметь заставить MTA заново обработать почту, или очистить её.

Практика: mailq(1), postqueue(1)

5.20. Определение когда последний раз была запущена система и какова её загруженность

Описание:  Кандидат BSDA должен уметь определить загруженность системы за последнюю минуту, 5 и 15 минут, а так же время прошедшее с последней перезагрузки.

Практика: uptime(1), w(1), top(1)

5.21. Слежение за операциями ввода/вывода на диске

Описание:  Операции ввода/вывода на диске сильно влияют на производительность системы. Кандидат BSDA должен знать какие утилиты доступны на системах BSD для контроля за операциями дискового ввода/вывода и как интерпретировать их результаты.

Практика: iostat(8), stat(1), vmstat(1), nfsstat(1)

5.22. Работа с занятыми устройствами

Описание:  Кандидат BSDA должен понимать что может вызвать зависание процесса, как обнаружить такой процесс и что делать в сложившейся ситуации.

Практика: ps(1), fstat(1), kill(1), umount(8) и сторонняя утилита lsof(8)

5.23. Определение информации характеризующей операционную систему

Описание:  Кандидат BSDA должен уметь определить тип и версию установленной операционной системы.

Практика: uname(1), sysctl(1); /etc/release на NetBSD.

5.24. Понимание преимуществ использования лицензии BSD

Описание:  Кандидат BSDA должен знать о лицензии BSD состоящей из 2-х параграфов, и знать, что эта лицензия неограничивает интеграцию продуктов OpenSource в коммерческие продукты.

Глава 6. Сетевое администрирование

Содержание

[+]6.1. Определение существующих установок TCP/IP
[+]6.1.1. ifconfig(8) — настройки сетевых интерфейсов
[+]6.1.2. netstat(1)
[+]6.1.3. route(8)
[+]6.1.4. /etc/resolv.conf(5)
[+]6.1.5. hostname(1)
[+]6.2. Установка параметров TCP/IP
[+]6.2.1. hostname(1) — задание имени машины
[+]6.2.2. ifconfig(8) — настройки сетевых интерфейсов
[+]6.2.3. route(8) — настройка таблицы маршрутизации
[+]6.2.4. resolv.conf(5) — настройка клиента DNS
[+]6.2.5. hosts(5) — локальная база имён
[+]6.2.6. Как сохранить установленные сетевые параметры
[+]6.3. Определение какие TCP или UDP порты открыты в системе
[+]6.3.1. fstat(1)
[+]6.3.2. sockstat(1)
[+]6.3.3. lsof(1)
[*]6.3.4. nmap(1)
[*]6.4. Проверка доступности TCP/IP сервиса
[+]6.4.1. ping(8)
[+]6.4.2. traceroute(1)
[*]6.4.3. hping(8)
[+]6.4.4. telnet(1), nc(1)
[*]6.5. Запрос к серверу DNS
[*]6.5.1. Теория вопроса
[+]6.5.2. host(1)
[+]6.5.3. dig(1)
[+]6.5.4. nslookup(1)
[+]6.6. Определение кто ответственный за зону DNS
[+]6.6.1. Обратное преобразование имён
[+]6.6.2. whois(1)
[+]6.7. Изменение порядка разрешения имён
[+]6.7.1. nsswitch.conf(5)
[+]6.8. Перевод сетевой маски между системами точечно-десятичной, точечно-шестнадцатеричной или CIDR
[+]6.8.1. Что такое маска подсети
[+]6.8.2. Маска подсети в формате CIDR
[+]6.8.3. Перевод десятичных чисел в двоичные
[+]6.9. Собирать информацию используя IP адрес и маску подсети
[+]6.9.1. Определение адреса подсети по маске
[+]6.9.2. Вычисление диапазона адресов IP и широковещательного адреса
[+]6.10. Понимание теории адресации IPV6
[+]6.10.1. Синтаксис IPv6
[+]6.10.2. Типы IPv6 адресов
[+]6.10.3. Назначение адреса IPv6
[+]6.10.4. Автоконфигурирование в IPv6
[+]6.10.5. Программы для конфигурирования IPv6 в BSD
[+]6.11. Демонстрация основных навыков работы с утилитой tcpdump(1)
[+]6.11.1. Работа с программой tcpdump(1)
[-]6.11.2. Графический сниффер Wireshark/Ethereal/tEhereal
[+]6.11.3. Анализатор tcpdstat
[+]6.11.4. ngrep
[+]6.12. Работа с ARP и кешем найденных соседей
[+]6.12.1. arp(8)
[+]6.12.2. ndp(8)
[+]6.13. Конфигурирование системы для использования NTP
[+]6.13.1. TP (RFC 868) и rdate(8)
[+]6.13.2. NTP
[-]6.14. Просмотр и обновление «арендованных» данных DHCP
[-]6.15. Знание как и когда устанавливать или удалять алиасы сетевого интерфейса

Комментарий

В данной главе содержится краткий материал изложенный в стиле «шпаргалки». Более систематично вопросы работы сети обсуждаются в Приложение B, Некоторые сведения о стеке протоколов TCP/IP. Предполагается, что содержание данной главы будет полезно тем, кто овладел материалом изложенным в указанном приложении.

6.1. Определение существующих установок TCP/IP

Описание.  Кандидат BSDA должен уметь определить IP адреса системы, маску подсети, шлюз, первичный и вторичный сервер DNS и имя хоста.

Практика. ifconfig(8), netstat(1), resolv.conf(5), route(8), hostname(1)

Комментарий

Итак, в этом разделе речь идёт не о настройке сети, а лишь об определении текущих настроек. Разберёмся в возможностях упомянутых здесь утилит.

Во имя целостности повествования мы выйдем за рамки задач поставленных в экзаменационном билете. Надеюсь читатель не останется внакладе.

6.1.1. ifconfig(8) — настройки сетевых интерфейсов

Утилита ifconfig(8) предназначена для настройки сетевых интерфейсов и диагностики текущих настроек. Как мы и договаривались, в данном разделе мы изучаем только возможности по диагностике, а настройкой займёмся в другом разделе (См. Раздел 6.2.2, «ifconfig(8) — настройки сетевых интерфейсов»).

1-й уровень OSI[1] (физический):

  • наличие несущей в проводе подведённом к интерфейсу;
  • характеристики Ethernet;

2-й уровень OSI (канальный):

  • MAC-адрес (он же hardware address);
  • флаги интерфейса (см расшифровку флагов сетевых интерфейсов ниже);

3-й уровень OSI (сетевой):

  • MTU — Maximum Transfer Unit — максимальный размер пакета, который можно передать/принять через данный интерфейс. Пакет имеется ввиду на сетевом уровне модели OSI, порция информации на канальном уровне называется «кадр»;
  • IP-адрес;
  • IPv6-адрес;
  • маска подсети;
  • широковещательный адрес;

Вот пример того, как может выглядеть вывод команды ifconfig(8):

$ifconfig -a 1
rl0: 2 flags=8802<BROADCAST,SIMPLEX,MULTICAST> mtu 1500 3
        options=8<VLAN_MTU> 4
        inet xxx.yyy.zzz.180 netmask 0xffffff80 broadcast xxx.yyy.zzz.255 5
        ether 00:80:48:2d:f7:15 6
        media: Ethernet autoselect (100baseTX <full-duplex>) 7
        status: active 8
rl1: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> mtu 1500
        options=8<VLAN_MTU>
        inet 172.16.0.1 netmask 0xfffffffc broadcast 172.16.0.3
        inet 192.168.0.1 netmask 0xffffff00 broadcast 192.168.0.255 9
        ether 4c:00:10:13:15:1d
        media: Ethernet autoselect (100baseTX <full-duplex>)
        status: active
pflog0: flags=141<UP,RUNNING,PROMISC> mtu 33208 10
pfsync0: flags=0<> mtu 2020
lp0: flags=8851<UP,POINTOPOINT,RUNNING,SIMPLEX,MULTICAST> mtu 1500 11
        inet 10.0.0.1 --> 10.0.0.2 netmask 0xff000000
lo0: flags=8049<UP,LOOPBACK,RUNNING,MULTICAST> mtu 16384 12
        inet 127.0.0.1 netmask 0xff000000
        
1 Команде ifconfig(8) необходимо указать по каким интерфейсам она должна вывести сведения. Если вместо этого указать аргумент -a будут выведены сведения обо всех интерфейсах, с опцией -u только об интерфейсах активных в данный момент, точнее об интерфейсах с установленным флагом UP (в данном случае rl1, pflog0 и lo0). В NetBSD и OpenBSD флаг -u отстутствует. В FreeBSD интерфейс указывать необязательно: если вы вызываете ifconfig(8) без аргументов, по умолчанию подразумевается ключ -a. В NetBSD и OpenBSD обязательно надо указать или интерфейс или ключ -a.
2 Указание на то, что следующий абзац относится к интерфейсу rl0. Специально для поклонников Linux отметим: в BSD принято называть интерфейсы по именам отвечающих за них драйверов. За сетевые карты на чипсете RealTek отвечает драйвер rl(4). Узнать о специфических настройках для устройств на остове этого чипсета можно из справочной страницы man 4 rl.
3

Флаги в угловых скобках подробно описаны ниже. В них собрана информация о возможностях интерфейса и текущем режиме его работы.

mtu — maximum transfer unit в байтах.

4
5 Характеристики интерфейса на сетевом уровне: IP-адрес, маска подсети и широковещательный адрес. Характреристики в адресном пространстве IPv6 сообщаются отдельной строкой и здесь непоказаны.
6 Аппаратный адрес (он же MAC-адрес) устройства. (Канальный уровень.)
7 media — характеристики передающей среды (физический уровень). Ethernet autoselect — скорость обмена данными автоматически определяется при взаимодействии с устройством на противоположном конце провода, выбирается наивысшая скорость из поддерживаемых обоими устройствами, если среда не поддерживает сигнал на этой скорости (например сопротивление в проводе слишком большое) а оба устройства договорились о передаче на большой скорости, необходимо хотя бы одно из них вручную перевести на более низкую скорость передачи данных; 100baseTX: 100 — выбрана скорость передачи данных 100 Мб/сек, base — для передачи используется вся частотная полоса (у ADSL-модема это не так: он может одновременно на одной частоте передавать обычный телефонный сигнал, а на другой интернет-трафик), TX — для передачи используется витая пара (twisted pair); full-duplex — возможна одновременная передача данных в обе стороны, если это не так, будет написано half-duplex.
8 Физическая характеристика — наличие несущей в проводе. Возможные значения active или no carrier. В последнем случае, это значит, что провод вышел из гнезда, или его разорвал экскаватор, или прибор с той стророны выключен.
9 Здесь показан пример того, как выглядит конфигурация интерфейса, когда на нём поднято одновременно несколько IP-адресов (алиасов). В Linux в этом случае заводится новое устройство (например в дополнение к интерфейсу eth0 появляется eth0:0, eth0:1 и т.д.), что в ряде случаев бывает удобно. Так, если мы какому-нибудь сервису предписываем посылать пакеты через интерфейс rl1 неочевидно какой IP он будет использовать.
10 Это пример виртуального интерфейса. Данный интерфейс используется пакетным фильтром OpenBSD — pf(4). (В настоящий момент данный брандмауэр используется не только в OpenBSD, но так же и в FreeBSD начиная с версии 5.3 и в NetBSD.)
11 Это параллельный порт сконфигурированный для связи типа точка-точка.
12 И, наконец, кольцевой интерфейс.

Флаги сетевых интерфейсов (информацию о некоторых флагах можно получить из девятой страницы man(1), см. ifnet(9). Более полно флаги описаны в книге [McKusick-2004]):

UP
Интерфейс доступен для использования, т.е. сконфигурирован и готов передавать сообщения. Когда мы запускаем команду ifconfig(8) с опцией -u, мы выводим информацию именно об интерфейсах с этим флагом.
RUNNING
Интерфейсу (драйверу) выделены системные ресурсы. В принципе возможна ситуация, когда этот флаг не установлен, а флаг UP стоит. Разумеется, для функционирования устройства необходимы оба флага.
BROADCAST
С интерфейса можно передавать широковещательные пакеты.
MULTICAST
Поддерживаются широковещательные пакеты для группы адресов.
SIMPLEX
Интерфейс не ловит пакеты, которые он отправляет. В частности, при отправке широковещательного пакета, интерфейс сам не может его получить. Чтобы сеть при этом работала корректно, функция отправки широковещательного пакета в ядре делает вид, что она получила широковещательный пакет, когда она его отправляет.
PROMISC
Включён «неразборчивый» (promiscuous) режим. Интерфейс ловит все пакеты вне зависимости от того, кому они предназначены. Этим режимом могут пользоваться так называемые «снифферы» — программы для подслушивания сетевого трафика. В частности, программа tcpdump(1), предназначенная для диагностических целей.
ALLMULTI
Аналогично флагу PROMISC, но ловятся пакеты предназначенные группе адресов.
MONITOR
Режим контроля запрошенный пользователем: пакеты не передаются, а полученные пакеты уничтожаются после получения устройством bpf(4) (т.е. после попадания в tcpdump(1))
POINTTOPOINT
Интерфейс предназначен для соединения типа точка-точка.
LINK0, LINK1, LINK2
Флаги специфичны для канального уровня. Так, например для интерфейса SLIP, LINK0 означает, что разрешена сжатая передача (CSLIP), LINK1 — сжатая передача разрешена только при получении сжатого пакета с другого конца, LINK2 — все пакеты ICMP уничтожаются. (См. [Stevens-2003-ru])
LOOPBACK
Кольцевой интерфейс.
SMART
Интерфейс самостоятельно управляет своими маршрутами.
NOARP
Интерфейс не использует протокол ARP.
STATICARP
Интерфейс использует только статическую таблицу ARP
OACTIVE
Интерфейс занят выводом. Этот флаг устанавливается когда попытка ввода недопустима.
POLLING
Интерфейс в режиме опроса.
DEBUG
Включена отладка в драйвере интерфейса.

Здесь упомянуты не все возможные флаги, а лишь флаги упомянутые в [McKusick-2004]. В [Stevens-2003-ru] можно найти упоминание других флагов, например NOTRAILERS — управление концевой инкапсуляцией при формировании кадра из пакета. Полный обозор флагов не входит в наши цели.

Каждый флаг это некоторый бит в числе характеризующем состояние интерфейса. Это число приведено перед списком флагов в угловых скобках В ШЕСТНАДЦАТЕРИЧНОМ представлении. Так число 8843 переводится в двоичную систему как 1000100001000011 и означает набор флагов <UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST>. Здесь за флаг UP отвечает самый правый бит, BROADCAST — второй справа, RUNNING — 7-й справа. Переключая флаги нетрудно вычислить какой бит чему соответствует. Легко видеть, что для того, чтобы интерфейс работал, необходимо (но недостаточно), чтобы число было нечётным.

Некоторые флаги поддерживаются не во всех операционных системах, что связано, возможно (это мои домыслы), с разрядностью числа характеризующего состояние сетевого интерфейса в них. Так флаг STATICARP (20-й бит справа) есть только в FreeBSD и отсутствует в OpenBSD и NetBSD. То же относится к флагу MONITOR (19-й бит).

6.1.2. netstat(1)

Утилита netstat(1) предназначена для диагностики работы TCP/IP стека. Она выводит разнообразную информацию о работе сетевых интерфейсов на сетевом и транспортном уровнях:

  • Таблицу маршрутизации системы.
  • Статистику о трафике в целом, по протокольно, поинтерфейсно.
  • Список работающих в данный момент интернет сервисов и открытых сокетов.

6.1.2.1. Таблица маршрутизации

$ netstat -nr
Routing tables

Internet:
Destination        Gateway            Flags    Refs      Use  Netif Expire
default            xxx.yyy.zzz.254    UGS         0  1056785    rl0
127.0.0.1          127.0.0.1          UH          0    39839    lo0
172.16/30          link#2             UC          0        0    rl1
172.16.0.2         4c:00:10:54:dd:8e  UHLW        0    30428    rl1   1045
xxx.yyy.zzz.128/25 link#1             UC          0        0    rl0
xxx.yyy.zzz.254    00:50:8b:5c:98:4f  UHLW        1     1888    rl0   1189
          

Аргумент -r заставил команду netstat(1) напечатать таблицу маршрутизации, а -n заставил не заменять IP-адреса хостов на их имена.

Рассмотрение этой таблицы начнём с третьего столбца: флаги. Мы видим, что во всех строках стоит флаг U, это значит, что все марршруты в настоящий момент активны (Up). В строках посвящённых адресам 127.0.0.1, 172.16.0.2 и xxx.yyy.zzz.254 имеется флаг H, это значит, что данный адрес относится не к сети, а к хосту (Host). Такие маршруты имеют приоритет перед маршрутом к сети, таким образом, мы можем жёстко прописать маршрут к некоторой машине, даже если маршрут к сети в которой она находится — иной. Флаг G означает, что данная машина является шлюзом, поэтому при обращении к ней надо при инкапсулировании пакета в кадр заменить MAC-адрес машины которой предназначен пакет, на MAC-адрес шлюза (если MAC-адрес назначения почему-то известен). Дальнейшей маршрутизацией этого пакета будет заниматься шлюз. В данном разделе мы не обсуждаем вопрос откуда берутся маршруты.

Итак, пусть у нас есть три пакета, первый предназначен машине 172.16.0.2, второй xxx.yyy.zzz.200 и третий xxx.yyy.zzz.100.

Для первого пакета машина сразу находит запись с флагом H, понимает, что его надо отправить через интерфейс rl1, формирует Ethernet-кадр дописывая к IP пакету MAC-адрес машины 172.16.0.2 (4c:00:10:54:dd:8e) и интерфейса rl1 и отправляет пакет.

Для второго пакета запись в таблице маршрутизации с флагом H ненайдена, но найдена сеть xxx.yyy.zzz.128/25, которой принадлежит машина xxx.yyy.zzz.200. Флаг G отсутствует, поэтому формируется кадр с MAC адресом получающей стороны, и MAC-адресом интерфейса rl0. В таком виде кадр отсылается с интерфейса rl0.

Для третьего пакета, увы не найдено никаких маршрутов — хост xxx.yyy.zzz.100 машине неизвестен и ни одной сети он не принадлежит. Поэтому он направляется на маршрут по умолчанию — default xxx.yyy.zzz.254. Этот маршрут помечен флагом G, поэтому даже если мы знаем MAC-адрес получателя, что маловероятно, но вполне реально, мы заменяем его на MAC-адрес шлюза xxx.yyy.zzz.254 (00:50:8b:5c:98:4f), дописываем MAC-адрес интерфейса rl0 и отсылаем, в надежде на то, что шлюз знает что делать с этим пакетом.

В колонке «Use»сказано сколько пакетов прошло по тому или иному маршруту.

Маршрут действует в течение некоторого периода времени, после которого он должен быть или выброшен из таблицы маршрутизации или продлён. Оставшееся время жизни маршрута указывается в колонке «Expire» в секундах.

6.1.2.2. Статистика

$netstat -ni
Name    Mtu Network       Address              Ipkts Ierrs    Opkts Oerrs  Coll
rl0    1500 <Link#1>      00:80:48:2d:f7:15 51129385     0  1081628     0     0
rl0    1500 xxx.yyy.zzz.1 xxx.yyy.zzz.180     459392     -   421556     -     -
rl1    1500 <Link#2>      4c:00:10:13:15:1d  4116747     0  7617322     1     0
rl1    1500 172.16/30     172.16.0.1         1604297     -  6705688     -     -
pflog 33208 <Link#3>                               0     0        0     0     0
pfsyn  2020 <Link#4>                               0     0        0     0     0
lo0   16384 <Link#5>                           39988     0    39988     0     0
lo0   16384 your-net      127.0.0.1            39863     -    39863     -     -
          

Как и раньше, аргумент -n подавляет раскрытие адресов в имена. Из этой таблицы мы можем определить сколько пакетов было передано через тот или иной сетевой интерфейс в ту или иную стророну. Чтобы измерить трафик в байтах можно добавить ещё два аргумента: -b чтобы выводить информацию в байтах и -d чтобы сообщать об отброшенных (droped) пакетах:

$ netstat -nibd
Name    Mtu Network       Address              Ipkts Ierrs     Ibytes    Opkts Oerrs     Obytes  Coll Drop
rl0    1500 <Link#1>      00:80:48:2d:f7:15 51141983     0 1282650574  1082806     0  221186433     0   0
rl0    1500 xxx.yyy.zzz.1 xxx.yyy.zzz.180     459467     -  295420865   421634     -  136159516     -   -
rl1    1500 <Link#2>      4c:00:10:13:15:1d  4117877     0 3436868162  7618633     1 1263505336     0   0
rl1    1500 172.16/30     172.16.0.1         1604327     - 3270648640  6705718     -  168875424     -   -
pflog 33208 <Link#3>                               0     0          0        0     0          0     0   0
pfsyn  2020 <Link#4>                               0     0          0        0     0          0     0   0
lo0   16384 <Link#5>                           39992     0    4836343    39992     0    4836343     0   0
lo0   16384 127           127.0.0.1            39867     -    4803206    39867     -    4803206     -   -
          

Итак, через интерфейс rl0 на машину с MAC-адресом 00:80:48:2d:f7:15 (как мы видели раньше, это шлюз) прошло наружу 1082806 пакетов, или 221186433 байт. В обратном направлении пришло 51141983 пакета или 1282650574 байт.

Обратите так же внимание на столбец «Coll» — это счётчик коллизий. В сетях Ethernet 10BaseTX, 100BaseTX и 1000BaseTX, построенных на коммутаторах, а не повторителях (на свитчах, а не на хабах), в принципе не может быть никаких коллизий, так как домен коллизий сводится всего к двум машинам благодаря коммутации на канальном уровне, а две машины не могут совершить коллизию, так как они соединены многожильным кабелем и TX/RX сигналы разнесены по разным парам проводов.

Мы можем смотреть как меняется статистика во времени. Если мы укажем команде netstat(1) в аргументе -w период обновления в секундах.

$ netstat -w2
            input        (Total)           output
   packets  errs      bytes    packets  errs      bytes colls
        51     0       4077          1     0        178     0
        46     0       3676          1     0        178     0
        49     0       3794          1     0        178     0
        51     0       3779          1     0        178     0
^C
          

Здесь программа netstat(1) каждые две секунды отчитывается о том, сколько пакетов и байт входит в машину через все интерфесы вместе.

Запустив в фоновом режиме утилиту ping(8), посылающую ICMP-пакеты через интерфейс rl1, мы можем видеть эти пакеты командой netstat(1)

$ ping 172.16.0.2 > /dev/null &
$ netstat -w2 -I rl1
            input          (rl1)           output
   packets  errs      bytes    packets  errs      bytes colls
         2     0        196          2     0        196     0
         2     0        196          2     0        196     0
         2     0        196          2     0        196     0
         2     0        196          2     0        196     0
^C
$ fg
ping 172.16.0.2 > /dev/null
^C
          

Утилита ping(8) посылает пакеты раз в секунду, поэтому netstat(1) с опцией -w2, добавляя по строке раз в две секунды, каждый раз видит по 2 пакета.

6.1.2.3. Работающие интернет сервисы и открытые сокеты

[Замечание]Замечание
Аналогичную информацию можно получить так же при помощи программы sockstat(1). См Раздел 6.3.2, «sockstat(1)»

При запуске утилиты netstat(1) без каких либо аргументов, можно получить информацию об открытых сокетах. Мы запустим утилиту как всегда с опцией -n с тем, чтобы адреса не преобразовывались в имена, и номера сервисов тоже были бы представлены числами:

$ netstat -n
Active Internet connections
Proto Recv-Q Send-Q  Local Address          Foreign Address        (state)
tcp4       0     52  194.87.141.180.22      62.117.108.7.1833   ESTABLISHED 1
tcp4       0      0  194.87.141.180.22      62.117.108.7.64544  ESTABLISHED
tcp4       0      0  172.16.0.1.53882       172.16.0.2.22       ESTABLISHED
tcp4       0      0  194.87.141.180.22      62.117.108.7.64344  ESTABLISHED
tcp4       0      0  194.87.141.180.22      62.117.108.7.64286  ESTABLISHED
tcp4       0      0  194.87.141.180.22      62.117.108.7.64242  ESTABLISHED
udp4       0      0  127.0.0.1.123          *.* 2
udp4       0      0  172.16.0.1.123         *.*
udp4       0      0  194.87.141.180.123     *.*
udp4       0      0  127.0.0.1.53           *.*
udp4       0      0  172.16.0.1.53          *.*
udp4       0      0  194.87.141.180.53      *.*
udp4       0      0  172.16.0.1.706         172.16.0.2.2049 3
udp4       0      0  172.16.0.1.743         172.16.0.2.2049
udp4       0      0  172.16.0.1.690         172.16.0.2.2049
udp4       0      0  172.16.0.1.633         172.16.0.2.2049
udp4       0      0  172.16.0.1.701         172.16.0.2.2049
udp4       0      0  172.16.0.1.887         172.16.0.2.2049
udp4       0      0  172.16.0.1.991         172.16.0.2.2049
udp4       0      0  172.16.0.1.852         172.16.0.2.2049
Active UNIX domain sockets
Address  Type   Recv-Q Send-Q    Inode     Conn     Refs  Nextref Addr
c10897a8 stream      0      0        0 c1089af0        0        0
c1089af0 stream      0      0        0 c10897a8        0        0
c10892bc stream      0      0        0 c10899d8        0        0
c10899d8 stream      0      0        0 c10892bc        0        0
c10888c0 stream      0      0        0 c1089ec4        0        0
c1089ec4 stream      0      0        0 c10888c0        0        0
c108971c stream      0      0        0 c1088af0        0        0
c1088af0 stream      0      0        0 c108971c        0        0
c1089834 stream      0      0        0 c10894ec        0        0
c10894ec stream      0      0        0 c1089834        0        0
c1088834 stream      0      0        0 c1089a64        0        0 /var/run/dovecot/login/default 4
c1089a64 stream      0      0        0 c1088834        0        0
c1089c94 stream      0      0        0 c1089604        0        0
c1089604 stream      0      0        0 c1089c94        0        0
c1089e38 stream      0      0        0 c10887a8        0        0 /var/run/dovecot/login/default
c10887a8 stream      0      0        0 c1089e38        0        0
c1089460 stream      0      0        0 c10891a4        0        0
c10891a4 stream      0      0        0 c1089460        0        0
c1209000 stream      0      0        0 c108894c        0        0 /var/run/dovecot/login/default
c108894c stream      0      0        0 c1209000        0        0
c108994c stream      0      0        0 c108871c        0        0
c108871c stream      0      0        0 c108994c        0        0
c10893d4 stream      0      0 c1867738        0        0        0 /var/run/dovecot/auth-worker.53422
c1088a64 stream      0      0        0 c1089118        0        0
c1089118 stream      0      0        0 c1088a64        0        0
c1209118 stream      0      0 c1ac0c60        0        0        0 /var/run/dovecot/login/default
c1089b7c stream      0      0 c138f738        0        0        0 /tmp/mysql.sock
c1089d20 stream      0      0 c11fed68        0        0        0 /var/run/cgisock.536
c10882bc stream      0      0        0 c1088230        0        0
c1088230 stream      0      0        0 c10882bc        0        0
c108808c stream      0      0        0 c1088000        0        0
c1088000 stream      0      0        0 c108808c        0        0
c1088c08 stream      0      0 c10b4a50        0        0        0 /var/run/rpcbind.sock
c1089000 stream      0      0 c1078d68        0        0        0 /var/run/devd.pipe
c10883d4 dgram       0      0        0 c1088e38        0 c1089348
c1089348 dgram       0      0        0 c1088e38        0 c1088460
c10884ec dgram       0      0        0 c1088dac        0        0
c1088460 dgram       0      0        0 c1088e38        0 c1088348
c1088348 dgram       0      0        0 c1088e38        0 c10881a4
c10881a4 dgram       0      0        0 c1088e38        0 c1088118
c1088118 dgram       0      0        0 c1088e38        0 c1088604
c1088604 dgram       0      0        0 c1088e38        0 c1088b7c
c1088b7c dgram       0      0        0 c1088e38        0 c1088c94
c1088c94 dgram       0      0        0 c1088e38        0        0
c1088d20 dgram       0      0 c108a108        0        0        0 /var/named/var/run/log
c1088dac dgram       0      0 c108a210        0 c10884ec        0 /var/run/log
c1088e38 dgram       0      0 c108a318        0 c10883d4        0 /var/run/logpriv
c1088ec4 dgram       0      0 c1078210        0        0        0 /var/run/log
          

Отчёт команды netstat(1) состоит из двух частей: в первой перечислены открытые в настоящий момент соединения интернет, а во второй перечислены используемые системой сокеты.

1 Как видно, в настоящий момент, наша машина xxx.yyy.zzz.180 имеет шесть соединений по протоколу ssh (порт 22). Из них пять открыто из Интернет на нашу машину (с хоста xyz.yzx.zxy.yxz) и одно открыто с нашей машины, с адреса 172.16.0.1 на машину 172.16.0.2. Все шесть соединений открыты и потому пребывают в состоянии ESTABLISHED.
2 На портах 123 (NTP, служба времени) и 53 (DNS) висят какие-то службы и ждут входящего соединения (поскольку никаких флагов тут не обозначено)
3 С хоста 172.16.0.2 импортировано несколько каталогов по NFS.
4 В этой части таблицы перечислены активные в настоящий момент сокеты. Некоторые из них имеют интерфейс файлов.

Программа netstat(1) выводит сведения о состоянии TCP (см. флаг ESTABLISHED выше), согласно [RFC-793]. Что такое «состояние TCP» и какие они бывают, мы описываем в Раздел B.1.4.3.4, «Состояние соединения TCP». Подробное обсуждение этой темы можно найти в [Stevens-2003-ru].

При помощи флага -a можно получить информацию обо всех сокетах, в том числе пребывающих в состоянии LISTEN.

# netstat -na | grep LISTEN
tcp4       0      0  *.587                  *.*                    LISTEN
tcp4       0      0  *.25                   *.*                    LISTEN
tcp4       0      0  *.22                   *.*                    LISTEN
tcp4       0      0  *.80                   *.*                    LISTEN
tcp4       0      0  *.143                  *.*                    LISTEN
tcp4       0      0  *.965                  *.*                    LISTEN
tcp4       0      0  *.2049                 *.*                    LISTEN
tcp4       0      0  *.701                  *.*                    LISTEN
tcp4       0      0  *.730                  *.*                    LISTEN
tcp4       0      0  *.111                  *.*                    LISTEN
tcp4       0      0  127.0.0.1.953          *.*                    LISTEN
tcp4       0      0  127.0.0.1.53           *.*                    LISTEN
tcp4       0      0  172.19.0.2.53          *.*                    LISTEN
          

Таким образом, можно узнать какие порты прослушиваются нашей машиной.

Видимо необходимо некоторое пояснение к термину «состояние сокета». Рассмотрим как осуществляется открытие и закрытие соединения TCP:

6.1.2.3.1. Открытие TCP соединения (тройное рукопожатие)

Пусть клиент открывает соединение с сервером. Тогда говорят, что клиент осуществляет активное открытие соединения, а сервер пассивное открытие соединения. Изначально сервер находится в состоянии LISTEN.

  1. Клиент посылает запрос на открытие соединения и переходит в состояние SYN-SENT.
  2. Сервер получает этот запрос и отправляет в одном пакете два сообщения: 1) подтверждение получения запроса на открытие соединения, 2) свой собственный запрос на открытие соединения. При этом сервер переходит из состояния LISTEN в состояние SYN-RECEIVED.
  3. Клиент получает подтверждение на запрос об открытии соединения и запрос на открытие соединения, посланные в одном пакете. В ответ он посылает подтверждение серверу. После этого клиент уже может посылать данные. Он может начать посылать данные сразу, в одном пакете со своим подтверждением. Таким образом он переходит из состояния SYN-SENT в состояние ESTABLISHED. Сервер получив от него подтверждение начинает принимать данные и тоже переходит в состояние ESTABLISHED (из состояния SYN-RECEIVED).

Теперь стороны могут обмениваться данными в обе стороны, в состоянии ESTABLISHED, обе стороны высылают друг другу пакеты с данными, время от времени присылая подтверждения о получении этих пакетов, причём в одном подтверждении может подтверждаться получение большого числа пакетов.

Процесс открытия соединения часто называется тройным рукопожатием, так как происходит обмен тремя пакетами в обеих направлениях. (См. так же Раздел B.1.4.3.2, «Открытие соединения TCP, тройное рукопожатие».)

6.1.2.3.2. Закрытие TCP соединения

Пусть клиент закрывает соединение с сервером. Тогда говорят, что клиент выполняет активное закрытие, а сервер пассивное закрытие. Изначально оба хоста пребывают в состоянии ESTABLISHED.

  1. Клиент посылает запрос на закрытие соединения и переходит в состояние FIN-WAIT-1
  2. Сервер получил этот запрос и выслал подтверждение о его получении. Теперь он перешёл в состояние CLOSE-WAIT
  3. Клиент получил подтверждение и перешёл из FIN-WAIT-1 в FIN-WAIT-2. Говорят, что это соединение «полузакрыто»: клиент не может посылать данные серверу, но сервер может посылать данные клиенту, ведь он ещё не закрыл соединение. Клиент сказал, что разговор окончен, а сервер ответил, что он услышал, но сервер ещё не сказал, что разговор окончен, он может продолжать посылать данные.
  4. Сервер дозрел и тоже стал закрывать соединение. Он посылает клиенту запрос на закрытие соединения и переходит из CLOSE-WAIT в LAST-ACK
  5. Клиент получил этот пакет и послал подтверждение. При этом он перешел в состояние TIME-WAIT. Если подтверждение посланное клиентом недошло до сервера, сервер вновь пошлёт запрос на закрытие соединения и клиент снова на него отреагирует. А если со стороны сервера ничего не пришло, значит он получил подтверждение. Время для TIME-WAIT выбирается такое, в течение которого пакеты заведомо успевают пройти в обе стороны. Когда сервер получает подтверждение на свой запрос, он переходит из состояния LAST-ACK в CLOSED (или снова LISTEN). Клиент, переходит из TIME-WAIT в CLOSED если в течение указанного периода времени он не получил никаких ответов.

6.1.3. route(8)

Утилита route(8) больше предназначена для управления таблицей маршрутизации, однако с её помощью тоже можно получить некоторую диагностическую информацию. Допустим нам надо узнать маршрут к машине с адресом 192.168.3.4

$ route get 192.168.3.4
   route to: 192.168.3.4
destination: default
       mask: default
    gateway: xxx.yyy.zzz.254
  interface: rl0
      flags: <UP,GATEWAY,DONE,STATIC>
 recvpipe  sendpipe  ssthresh  rtt,msec    rttvar  hopcount      mtu     expire
       0         0         0         0         0         0      1500         0
        

В NetBSD и OpenBSD есть так же команда show, которая заставляет route(8) распечатать таблицу маршрутизации целиком, подобно netstat -r:

$ route -n show
Routing tables

Internet:
Destination      Gateway            Flags
default          **************     UG
127.0.0.0        localhost          UG
**************   localhost          UGH
192.168.26.0     link#1             U
**************   0:10:e0:0:e9:cd    UH
192.168.26.2     0:10:e0:0:7c:46    UH
192.168.26.7     0:e:a6:66:2d:c5    UH
BASE-ADDRESS.MCA localhost          U

Internet6:
Destination      Gateway            Flags
default          ****************** UG
default          ****************** UG
**************** ****************** UH
::127.0.0.0      ****************** UG
::224.0.0.0      ****************** UG
::255.0.0.0      ****************** UG
::ffff:0.0.0.0   ****************** UG
2002::           ****************** UG
2002:7f00::      ****************** UG
2002:e000::      ****************** UG
2002:ff00::      ****************** UG
fe80::           ****************** UG
fe80::%le0       link#1             U
fe80::%lo0       fe80::1%lo0        U
fec0::           ****************** UG
ff01::           ****************** U
ff02::%le0       link#1             U
ff02::%lo0       fe80::1%lo0        U
        

При помощи команды route monitor можно следить за изменениями маршрутной таблицы в реальном времени.

6.1.4. /etc/resolv.conf(5)

Когда машине надо обратиться к некоторому адресу в интернет, она должна преобразовать символьное имя машины (такое, как example.ru), в IP (или IPv6) адрес. Осуществляется это при помощи библиотечной функции gethostbyname(3). Типичное поведение этой функции выглядит так: 1) изучается файл /etc/hosts в котором перечислено какие имена соответствуют некоторым адресам; 2) затем, если поиск не дал результатов, при помощи resolver(3)'а осуществляются запросы к серверам DNS. На порядок этих действий можно влиять при помощи файла /etc/nsswitch.conf, это описано в Раздел 6.7, «Изменение порядка разрешения имён».

За работу resolver'а отвечает настроечный файл /etc/resolv.conf. Вот его мы и рассмотрим в данном разделе.

Файл /etc/resolv.conf является настроечным файлом для клиентской части системы DNS — resolver'а. Синтаксис файла предельно прост: в нём перечисляются DNS сервера в порядке убывания приоритета. Перед IP адресом сервера DNS указывается ключевое слово nameserver.

nameserver 127.0.0.1
nameserver 192.168.0.1
search somewhere.ru ru ua org
        

Здесь сказано, что для разрешения имён в IP-адреса, нужно сперва обратиться к локальной машине (предполагается, что на ней запущен свой собственный named(8)), а если обратиться к нему неудастся (если он не запущен), обратиться к DNS на машине 192.168.0.1. Здесь сервер DNS на машине 127.0.0.1 называется первичным DNS-сервером (primary), а 192.168.0.1 — вторичным (secondary). Обратите внимание: если первичный сервер DNS не сможет разрешить имя, он вернёт отрицательный ответ и запрос к вторичному серверу выполнен не будет (ведь ответ пришёл, просто он отрицательный).

resolver использует для работы первые три сервера DNS.

Допустим, мы хотим разрешить имя host, а в нашем файле /etc/resolv.conf имеются только записи типа nameserver. В этом случае resolver попытается найти машину host., такой машины конечно же нет, следующее действие resolver'а будет таким: он возьмёт имя домена в котором находится наша машина и допишет этот домен. Если наша машина имеет имя client.somewhere.ru, то resolver попытается разрешить имя host.somewhere.ru.

На это поведение можно влиять двумя способами: 1) с помощью директивы domain указать какой-нибудь другой домен и тогда поиск будет осуществляться в нём.

2) при помощи директивы search явно перечислить через пробел домены в которых следует производить поиск, как это показано в листинге выше. В нашем примере если resolver не сможет разрешить имя host, то он допишет к нему домен «somewhere.ru» и попробует разрешить имя host.somewhere.ru, затем будет осуществлена попытка разрешить имя host.ru, host.ua и host.org:

$ host -v host
Trying domain "somewhere.ru" 1
rcode = 3 (Non-existent domain), ancount=0
Trying domain "ru" 2
rcode = 0 (Success), ancount=1
The following answer is not authoritative:
The following answer is not verified as authentic by the server:
host.ru 1800 IN A       195.2.70.38
For authoritative answers, see:
host.ru 1800 IN NS      dns1.zenon.net
host.ru 1800 IN NS      dns2.zenon.net
Additional information:
dns1.zenon.net  1412 IN A       195.2.64.38
dns2.zenon.net  1412 IN A       195.2.83.38
        
1 Здесь осуществлена попытка разрешить имя host.somewhere.ru. Эта попытка завершилась неудачей — такого хоста нет.
2 Теперь система пытается разрешить имя host.ru. Такое имя существует, машина с этим именем имеет IP 195.2.70.38, за неё отвечает два сервера DNS: dns1.zenon.net и dns2.zenon.net с IP адресами 195.2.64.38 и 195.2.83.38. (Про команду host(1) мы будем говорить в Раздел 6.5, «Запрос к серверу DNS».)

Попробуем обнаружить машину соответствующую озеру Леприндо, расположенному в Читинской области на БАМе у подножия горного массива Кодар:

$ host -v leprindo
Trying domain "somewhere.ru"
rcode = 3 (Non-existent domain), ancount=0
Trying domain "ru"
rcode = 3 (Non-existent domain), ancount=0
Trying domain "ua"
rcode = 3 (Non-existent domain), ancount=0
Trying domain "org"
rcode = 3 (Non-existent domain), ancount=0
Host not found.
        

Как видим, resolver выполнил 4 запроса к DNS, попытавшись обнаружить машины leprindo.somewhere.ru, leprindo.ru, leprindo.ua и leprindo.org, и потерпел неудачу.

Наконец, в этом файле можно задавать некоторые опции. Следующая строка во-первых, включает режим отладки, а во-вторых объявляет, что надо пытаться разрешить имя при помощи списка из директивы search, если в нём менее 2-х точек (а не одной, как по умолчанию). Т.е. по умолчанию, если в имени нет точек, то оно сперва ищется в списке доменов из директивы search, а со включённой ниже опцией это поведение распространяется на имена содержащие одну точку.

options debug ndots:2
        

После редактирования файла /etc/resolv.conf никаких специальных действий не требуется, изменения немедленно вступают в силу.

6.1.5. hostname(1)

Утилита hostname(1) служит для того, чтобы сообщить имя машины, на которой она запущена. Используется во множестве разнообразных скриптов. Имеет всего один необязательный аргумент служащий для удаления имени домена:

$ hostname
myhost.example.org
$ hostname -s
myhost
        

6.2. Установка параметров TCP/IP

Описание.  Кандидат должен уметь изменять настройки TCP/IP как временно, так и постоянно, так, чтобы изменения сохранялись после перезагрузки.

Практика. hostname(1), ifconfig(8), route(8), resolv.conf(5), rc.conf(5), hosts(5), hostname.if(5), myname(5), mygate(5), netstart(8)

Комментарий

Теперь мы снова рассмотрим те же утилиты, что и в Раздел 6.1, «Определение существующих установок TCP/IP», но на этот раз с точки зрения управления параметрами. Как и в прошлый раз, мы выйдем за рамки задачи постваленной в данном экзаменационном билете, во имя целостности повествования.

6.2.1. hostname(1) — задание имени машины

Утилита hostname(1) может не только сообщать имя машины, но и устанавливать новое:

$ hostname
myhost.example.org
$ hostname -s
myhost
# hostname other.example.org
$ hostname
other.example.org
        

6.2.2. ifconfig(8) — настройки сетевых интерфейсов

Утилита ifconfig(8) позволяет не только просматривать, но и манипулировать настройками сетевого интерфейса. Причём даже на физическом уровне OSI. (О модели OSI можно прочесть в глоссарии: OSI.)

Здесь описаны не все возможности утилиты ifconfig(8). Существуют некоторые опции, характерные для данных операционных систем и т.д. Сверяйтесь со справкой вашей операционной системы. Например, OpenBSD позволяет объединять интерфейсы вгруппы, а FreeBSD такой особенностью не обладает.

6.2.2.1. Изменение настроек физического уровня

В общем случае, для конфигурирования физических параметров интерфейса надо предварительно изучить справку по соответствующему драйверу. Мы приведём примеры на основе драйвера к распространённому чипсету RealTek. (См. man rl.) Для этого драйвера можно изменять скорость передачи данных (10 или 100 Mbps) и режим передачи (half-duplex — одновременная передача пакетов в обе стороны не поддерживается; или full-duplex — поддерживается одновременная передача пакетов в обе стороны).

$ifconfig rl0
rl0: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> mtu 1500
        options=8<VLAN_MTU>
        inet6 fe80::250:22ff:feb0:7f39%rl0 prefixlen 64 scopeid 0x1
        inet 192.168.25.158 netmask 0xffffff00 broadcast 192.168.25.255
        ether 00:50:22:b0:7f:39
        media: Ethernet autoselect (100baseTX <full-duplex>)
        status: active
          

Переведём интерфейс вручную на скорость 10 мегабит в секунду (Mbps):

# ifconfig rl0 media 10baseT/UTP
$ ifconfig rl0
rl0: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> mtu 1500
        options=8<VLAN_MTU>
        inet6 fe80::250:22ff:feb0:7f39%rl0 prefixlen 64 scopeid 0x1
        inet 192.168.25.158 netmask 0xffffff00 broadcast 192.168.25.255
        ether 00:50:22:b0:7f:39
        media: Ethernet 10baseT/UTP
        status: active
          

Здесь в командной строке опция media принадлежит команде ifconfig(8), а значение 10baseT/UTP взято из справки по драйверу rl.

Теперь мы можем вручную выставить обратно 100baseTX, командой ifconfig rl0 media 100baseTX, а можем включить назад автоопределение.

# ifconfig rl0 media autoselect
$ ifconfig rl0
rl0: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> mtu 1500
        options=8<VLAN_MTU>
        inet6 fe80::250:22ff:feb0:7f39%rl0 prefixlen 64 scopeid 0x1
        inet 192.168.25.158 netmask 0xffffff00 broadcast 192.168.25.255
        ether 00:50:22:b0:7f:39
        media: Ethernet autoselect (none)
        status: no carrier
$ ifconfig rl0
rl0: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> mtu 1500
        options=8<VLAN_MTU>
        inet6 fe80::250:22ff:feb0:7f39%rl0 prefixlen 64 scopeid 0x1
        inet 192.168.25.158 netmask 0xffffff00 broadcast 192.168.25.255
        ether 00:50:22:b0:7f:39
        media: Ethernet autoselect (100baseTX <full-duplex>)
        status: active
          

Обратите внимание: после включения автоопределения некоторое время интерфейс был недоступен. При этом флаг UP был установлен, т.е. приложения имели право его использовать, но интерфейс вёл себя так, как буд-то из него вынули провод: status: no carrier. Что неудивитеьно, пока интерфейс не знает на какой скорости вести передачу, о какой несущей может идти речь?

Наконец, переключение дуплекса, здесь нас ждёт некоторая недокументированная неожиданность:

# ifconfig rl0 media 100baseTX
$ ifconfig rl0
rl0: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> mtu 1500
        options=8<VLAN_MTU>
        inet6 fe80::250:22ff:feb0:7f39%rl0 prefixlen 64 scopeid 0x1
        inet 192.168.25.158 netmask 0xffffff00 broadcast 192.168.25.255
        ether 00:50:22:b0:7f:39
        media: Ethernet 100baseTX
        status: active
          

В настоящий момент наш интерфейс пребывает в режиме half-duplex, потому что это режим по умолчанию. Соответственно никакой опции для его включения нет, и при попытке задать её получится ошибка, с некоторой совершенно дикой диагностикой:

# ifconfig rl0 mediaopt half-duplex
ifconfig: SIOCSIFMEDIA (mediaopt): Device not configured
          

Что поделаешь, и на солнце есть пятна. Итак, в настоящий момент наш интерфейс пребывает в режиме half-duplex, а для перевода его в full-duplex, мы можем употребить следующую команду:

# ifconfig rl0 mediaopt full-duplex
$ ifconfig rl0
rl0: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> mtu 1500
        options=8<VLAN_MTU>
        inet6 fe80::250:22ff:feb0:7f39%rl0 prefixlen 64 scopeid 0x1
        inet 192.168.25.158 netmask 0xffffff00 broadcast 192.168.25.255
        ether 00:50:22:b0:7f:39
        media: Ethernet 100baseTX <full-duplex>
        status: active
          

Сравните это с первым скриншотом:

        ...
        media: Ethernet autoselect (100baseTX <full-duplex>)
        ...
          

Как видно, выставлено всё тоже самое, только отсутствует автоопределение. Если мы не добиваемся какого-то специального эффекта, то лучше оставить автоопределение. Из моего личного опыта: однажды мне пришлось вручную понижать скорость работы интерфейсов, которые были соединены некачественным проводом. Сопротивление в медном проводе было вдвое выше нормы. Интерфейсы договаривались о передаче данных на скорости 100Mbps в режиме full-duplex, но реально вести передачу на такой скорости не могли и их пришлось вручную «тормозить».

6.2.2.2. Изменение настроек канального уровня

6.2.2.2.1. Изменение MAC-адреса:
$ ifconfig rl0
rl0: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> mtu 1500
        options=8<VLAN_MTU>
        inet6 fe80::250:22ff:feb0:7f39%rl0 prefixlen 64 scopeid 0x1
        inet 192.168.25.158 netmask 0xffffff00 broadcast 192.168.25.255
        ether 00:50:22:b0:7f:39
        media: Ethernet 100baseTX <full-duplex>
        status: active
# ifconfig rl0 lladdr 40:50:22:b0:7f:39
$ ifconfig rl0
rl0: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> mtu 1500
        options=8<VLAN_MTU>
        inet6 fe80::250:22ff:feb0:7f39%rl0 prefixlen 64 scopeid 0x1
        inet 192.168.25.158 netmask 0xffffff00 broadcast 192.168.25.255
        ether 40:50:22:b0:7f:39
        media: Ethernet 100baseTX <full-duplex>
        status: active
            

Здесь для смены аппатарного адреса применяется ключевое слово lladdr, объясняющее, что речь идёт об адресе канального уровня (link-layer address = lladdr), т.е. о MAC-адресе. Этот аргумент работает в FreeBSD и в OpenBSD. В FreeBSD действуют так же синонимы link и ether — смысл тот же. В NetBSD ifconfig(8) не умеет сменить MAC-адрес (!?).

При смене MAC-адреса интерфейс временно отключается, а затем поднимается заново. Неисключено, что в некоторых реализациях ifconfig(8), эти действия надо проделать вручную.

[Важно]Важно

Важно, чтобы в одной сети не было машин с одинаковыми MAC-адресами. Консорциум IEEE выделяет производителям оборудования диапазоны MAC-адресов, так называемые OUI — это первые три байта MAC-адреса. Остальные три байта назначает сам производитель. На сайте IEEE можно узнать какой OUI выделен какому производителю: http://standards.ieee.org/regauth/oui/index.shtml. Таким образом, вы можете по первым трём байтам MAC-адреса узнать производителя устройства.

Из этого есть два следствия: 1) вы не должны менять MAC-адрес без нужды, 2) если вы меняете MAC-адрес, вы должны выставить в единицу второй бит, что означает, что MAC-адрес изменён локально. Таким образом, первый из шести байт MAC-адреса, если вы производите изменения, должен быть в диапазонах от 64 до 127 (в шестнадцатеричной записи от 40 до 7F) или от 192 до 255 (в шестнадцатеричной записи от С0 до FF).

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

Сходив по указанной ссылке мы можем узнать, что для адресов начинающихся с 00:50:22 производителем является:

00-50-22   (hex)      ZONET TECHNOLOGY, INC.
005022     (base 16)          ZONET TECHNOLOGY, INC.
                              830 ROOM, BLDG. 53, 195, SEC.4
                              CHUNG HSIUNG RD, CHUTUNG
                              HSINCHA
                              TAIWAN, REPUBLIC OF CHINA
            
6.2.2.2.2. Смена флагов канального уровня

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

up/down
Поднять/опустить интерфейс. Переключается флаг UP
promisc/-promisc
Включить/выключить «неразборчивый» (promiscuous) режим работы интерфейса. Переключается флаг PROMISC. Опция есть в FreeBSD, но отсутствует в OpenBSD и NetBSD.
monitor/-monitor
Интерфейс переводится/выводится в/из режим[а] мониторинга. В режиме мониторинга пакеты не передаются, а все полученные пакеты уничтожаются после обработки bpf(4). Переключается флаг MONITOR. Опция есть во FreeBSD, отсутствует в NetBSD и OpenBSD.
link[0-2]/-link[0-2]
Переключаются флаги LINK0, LINK1 и LINK2. При помощи них можно включить сжатие в интерфейсе SLIP или переключить тип коннектора на некоторых Ethernet картах.
arp/-arp
Включение/выключение поддержки протокола ARP на интерфейсе. По умолчанию ARP включён. Переключает флаг NOARP.
staticarp/-staticarp
Переключает флаг STATICARP. При включённом флаге интерфейс использует только статическую таблицу ARP. Присутствует в FreeBSD, отсутствует в OpenBSD и NetBSD.
debug/-debug
Включение/выключение отладочного режима в драйвере устройства. Обычно приводит к дополнтельным сообщениям в syslog(3). Переключает флаг DEBUG.

Пример:

$ ifconfig rl0
rl0: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> mtu 1500
        options=8<VLAN_MTU>
        inet6 fe80::250:22ff:feb0:7f39%rl0 prefixlen 64 scopeid 0x1
        inet 192.168.25.158 netmask 0xffffff00 broadcast 192.168.25.255
        ether 00:50:22:b0:7f:39
        media: Ethernet autoselect (100baseTX <full-duplex>)
        status: active
# ifconfig rl0 -arp
$ ifconfig rl0
rl0: flags=88c3<UP,BROADCAST,RUNNING,NOARP,SIMPLEX,MULTICAST> mtu 1500
        options=8<VLAN_MTU>
        inet6 fe80::250:22ff:feb0:7f39%rl0 prefixlen 64 scopeid 0x1
        inet 192.168.25.158 netmask 0xffffff00 broadcast 192.168.25.255
        ether 00:50:22:b0:7f:39
        media: Ethernet autoselect (100baseTX <full-duplex>)
        status: active
            

6.2.2.3. Изменение настроек сетевого уровня

6.2.2.3.1. MTU

MTU переключается оцией mtu. Снижая mtu вы с одной стороны замедляете работу сети, с другой стороны повышаете вероятность того, что ваши пакеты дойдут до адресата без фрагментирования. (Некоторые брандмауэры отбрасывают фрагментированные пакеты.) Однозначных рекомендаций тут дать невозможно. Даже тезис о том, что снижение MTU приводит к снижению скорости передачи данных, несовсем верен. Безусловно возрастают накладные расходы на протокол TCP, увеличивается удельный вес заголовков и общий трафик, однако Ричард Стивенс [Stevens-2003-ru] приводит убедительный пример того, как фрагментированные пакеты быстрее передаются в сети через серию маршрутизаторов, в силу более равномерного использования каналов связи (пока второй пакет передаётся первому шлюзу, первый пакет уже может быть отправлен второму шлюзу, если бы оба пакета были объединены, участок между первым и вторым шлюзом простаивал бы вдвое дольше).

Ограничение сверху на MTU накладывает природа передающей среды. В сетях Fast Ethernet MTU не может превышать 1500 байт.

По поводу IPv6 и MTU уместно процитировать «википедию» [url://wiki-IPv6-ru]:

В IPv6 пакеты не могут фрагментироваться и собираться маршрутизаторами. Отправитель должен заранее выяснить максимальный размер пакетов (MTU), поддерживаемый на всём пути до получателя, и, при необходимости, выполнить фрагментацию своими силами. Оговаривается, что MTU не может быть меньше 576 байт. Снятие с маршрутизаторов функций фрагментации также способствует повышению эффективности их работы, но усложняет работу оконечных систем.

6.2.2.3.2. IP, маска подсети, широковещательный адрес

Адрес интерфейса и маску подсети можно задавать в традиционном формате, в шестнадчатеричном, а так же в формате CIDR (ifconfig(8) OpenBSD не понимает формат CIDR). Следующие команды эквивалентны:

# ifconfig rl0 172.16.0.0 netmask 255.255.0.0
# ifconfig rl0 172.16.0.0 netmask 0xffff0000
# ifconfig rl0 0xac100000 netmask 0xffff0000
# ifconfig rl0 172.16.0.0/16
            

Последний вариант, повторимся, не работает в OpenBSD.

Во всех случаях широковещательный адрес вычисляется автоматически (172.16.255.255). Если вам почему-то надо указать какой-то экзотический широковещательный адрес, вы можете сделать это явно:

# ifconfig 172.16.0.0 netmask 255.255.0.0 broadcast 172.16.255.253
            

Во всех приведённых примерах неявно подразумевается перед IP ключевое слово inet. (По умолчанию действует оно, а не lladdr, например).

Ключевое слово alias (или add) позволяет добавить к сетевому интерфейсу ещё один адрес, возможно в другой сети.

Можно указывать символьное имя машины, если соответствующая запись есть базе /etc/hosts.

6.2.2.3.3. IPv6

Аналогично добавляются адреса в нотации IPv6, с использованием ключевого слова inet6.

6.2.2.3.4. Другие протоколы сетевого уровня

Команда ifconfig(8) позволяет конфигурировать интерфейс не только для работы со стеком TCP/IP. Вы можете сконфигурировать его для работы с AppleTalk, и другими протоколами. Информация об этом присутствует в справочной странице.

6.2.3. route(8) — настройка таблицы маршрутизации

Команда route(8) служит для управления таблицей маршрутизации. С её помощью можно:

  1. Просматривать маршрут к хосту (команды get и show (последней нет в FreeBSD)).
  2. Следить за изменениями в маршрутной таблице в реальном времени (команда monitor).
  3. Добавить маршрут (команда add).
  4. Удалить маршрут (команда delete).
  5. Изменить маршрут (команда change).
  6. Полностью очистить таблицу маршрутизации (команда flush). Поскольку таблиц маршрутизации несколько для каждого протокола (IP, IPv6, AppleTalk и др.) можно указать какую именно таблицу надо очистить при помощи необязательной опции -inet, -inet6, -atalk и др.

Ключевое слово default означает, что добавляется маршрут поумолчанию. В распечатке команды netstat(1) записи добавленные командой route(8) имеют флаг S, означающий, что они добавлены вручную.

Для явного обозначения сетей, хостов и интерфейсов можно использовать агрументы -host, -net и -interface. Некоторые операционные системы (точно скажу про FreeBSD) могут понимать запись в формате CIDR.

Примеры:

# route add default 192.168.0.1
# route add -net 192.168.0 -interface rl0
# route add -net 192.168.1.0 -netmask 255.255.255.128 -interface rl1
        

6.2.4. resolv.conf(5) — настройка клиента DNS

Файл /etc/resolv.conf нужен для настройки клиента DNS. Когда мы обращаемся к какой-то удалённой машине по имени, первое, что происходит, это преобразование имени в адрес IP (или IPv6). Обычно ситуация устроена следующим образом: сперва система ищет имена в файле /etc/hosts, где записано какие имена имеют машины с тем или иным IP-адресом, а затем, если имя в данном файле ненайдено, осуществляется запрос к серверу DNS. В файле /etc/resolv.conf перечислены DNS серверы, к которым осуществляется запрос. Порядок действий (сперва изучается /etc/hosts, затем делается запрос к DNS) можно изменить, это обсуждается в Раздел 6.7, «Изменение порядка разрешения имён». Синтаксис файла /etc/resolv.conf подробно описан в Раздел 6.1.4, «/etc/resolv.conf(5)».

6.2.5. hosts(5) — локальная база имён

Как было сказано в предыдущем разделе, типичное поведение системы состоит в том, что сперва она пытается разрешить имя используя файл /etc/hosts и только потом обращается к серверу DNS. В файле /etc/hosts на каждой строке имеется некоторый IP (или IPv6) адрес, а затем через пробелы перечислены имена соответствующие ему. Комментарий начинается с решётки (#). Например:

# $FreeBSD: src/etc/hosts,v 1.16 2003/01/28 21:29:23 dbaker Exp $
#
# Host Database
#
# Данный файл должен содержать адреса и алиасы для локальных машин
# Замените 'my.domain' ниже вашим доменом.
#
# В присутствии DNS или NIS данный файл может неиспользоваться вовсе,
# для определеня порядка в котором рассматриваются базы имён смотрите
# файл /etc/nsswitch.conf
#
#
::1                     localhost localhost.my.domain
127.0.0.1               localhost localhost.my.domain
#
# Воображаемая сеть.
#10.0.0.2               myname.my.domain myname
#10.0.0.3               myfriend.my.domain myfriend
#
# Согласно RFC 1918 следующие сети можно использовать для приватных
# сетей. Этих адресов не существует в Интернет:
#
#       10.0.0.0        -   10.255.255.255
#       172.16.0.0      -   172.31.255.255
#       192.168.0.0     -   192.168.255.255
#
        

Я перевёл часть комментариев на русский язык, сочтя их полезными.

Обратите внимание: многие сервисы используют файл /etc/hosts для своей работы. Когда вы переносите такие сервисы в среду chroot, вы должны перенести туда же копию данного файла.

6.2.6. Как сохранить установленные сетевые параметры

Увы, это самое мутное место. Кажется нет двух систем BSD с одинаковой системой инициализации.

6.2.6.1. FreeBSD

В FreeBSD все настройки собраны в единый файл /etc/rc.conf, в том числе это касается и настроек сетевых интерфейсов. Если точнее, то имеется системный файл /etc/defaults/rc.conf, который редактироваться не должен (система сделает попытку перезаписать его, если вы выполните процедуру make buildworld, см. Раздел 1.2, «Разбираться какие команды доступны для upgrade'а операционной системы»), а в файле /etc/rc.conf находятся пользовательские настройки, которые имеют больший приоритет. В том или ином виде этот файл существует во всех системах BSD, однако настройки сетевых интерфейсов в OpenBSD и NetBSD вынесены в другие места.

В файле /etc/rc.conf для каждого сетевого интерфейса должна быть строка вида ifconfig_rl0="...". Если для интерфейса нужны дополнительные имена (алиасы), применяется строка вида: ifconfig_rl0_alias0="...", ifconfig_rl0_alias1="...".

Следующая строка объясняет, что интерфейс rl0 надо настроить с использованием DHCP:

ifconfig_rl0="DHCP"
          

В следующем листинге имеется ошибка:

ifconfig_rl0_alias0="inet 172.16.0.1/24"
ifconfig_rl0_alias1="inet 172.16.0.2/24"
ifconfig_rl0_alias2="inet 172.16.0.3/24"
ifconfig_rl0_alias4="inet 172.16.0.4/24"
          

Ошибка состоит в том, что после alias2 сразу описан alias4. К сожалению, это приведёт к тому, что сработают только первые три строки.

Все настройки связанные с функционированием IPv6, ppp, gif(4) и проч. так же должны находиться в файле /etc/rc.conf. С этими настройками можно ознакомиться в справочной системе man rc.conf.

Имя машины и маршрут по умолчанию задаются здесь же, можно здесь же задавать статические маршруты:

hostname="host.example.ru"
defaultrouter="172.16.0.254"
static_routes="somenetwork othernetwork"
route_somenetwork="192.168.0.0/24 172.19.0.14"
route_othernetwork="192.168.1.0/24 172.19.0.25"
          

6.2.6.2. OpenBSD

Для запуска настройки сети в системе OpenBSD используется скрипт Bourne shell /etc/netstart (см netstart(8)). В этом скрипте имя сети и адрес шлюза явно берутся из файлов /etc/myname и /etc/mygate:

.....................
# /etc/myname contains my symbolic name
hostname=`cat /etc/myname`
hostname $hostname
.....................
# /etc/mygate, if it exists, contains the name of my gateway host
# that name must be in /etc/hosts.
if [ -f /etc/mygate ]; then
        route -n add -host default `cat /etc/mygate`
fi
.....................
          

Настройки специфичные для каждого сетевого интерфейса хранятся в файлах /etc/hostname.$if, где $if — имя интерфейса. Уже упоминавшийся скрипт /etc/netstart парсит эти файлы и настраивает соответствующим образом интерфейсы, используя команду ifconfig(8). Строки начинающиеся с решётки (#) являются комментариями, а строки начинающиеся с восклицательного знака (!) — команды Bourne shell. Остальные строки передаются команде ifconfig(8) и, возможно, dhclient(8). Например:

inet 10.0.1.12 255.255.255.0 10.0.1.255 media 100baseTX description Uplink
inet alias 10.0.1.13 255.255.255.255 10.0.1.13
inet alias 10.0.1.14 255.255.255.255 NONE
inet alias 10.0.1.15 255.255.255.255
inet alias 10.0.1.16 0xffffffff
inet6 alias fec0::1 64
inet6 alias fec0::2 64 anycast
# Это пример закомментированной строки
!wicontrol \$if -t 2  # Установить скорость 2Mbps
          

\$if будет заменено на имя интерфейса.

6.2.6.3. NetBSD

В NetBSD настройки сетевых интерфейсов могут находиться в файлах /etc/ifconfig.$if, где $if — имя интерфейса, либо в файле /etc/rc.conf, аналогично FreeBSD. Но, при этом, алиасы должны быть перечислены в переменной ifconfig_aliases_rl0 как список пар адрес сетевая_маска:

hostname="host.example.ru"
defaultroute="192.168.0.1"
ifconfig_tlp0="192.168.0.2"
ifaliases_tlp0="192.168.1.2 255.255.255.0 192.168.2.2 255.255.255.0"
          

Имя машины и маршрут по умолчанию добавляется тут же. Обратите внимание: в NetBSD надо писать defaultroute, а в FreeBSD — defaultrouter. Правда мило? Каждый раз консультируйтесь со справочной страницей, а ещё лучше со скриптами, которые все эти настройки вызывают.

6.3. Определение какие TCP или UDP порты открыты в системе

Описание.  Кандидат BSDA должен уметь использовать программы входящие в состав BSD, а так же сторонние программы, для определения того, какие порты в системе открыты, и какие порты видны через брандмауэр.

Практика. netstat(1), services(5), fstat(1); sockstat(1) и сторонное продукты nmap и lsof.

Комментарий

Как было показано выше (см. Раздел 6.1.2.3, «Работающие интернет сервисы и открытые сокеты»), команда netstat(1) пригодна для того, чтобы определить открытые tcp/udp соединения и их состояние. Другим средством для определения состояния файлов и сокетов являются команды fstat(1) и sockstat(1). Первая позволяет понять какие файловые дескрипторы какими пользователями открыты, вторая перечисляет открытые сокеты.

Жизнедеятельность всех программ выполняемых в пространстве пользователя может быть отслежена при помощи обращения к устройствам /dev/mem и /dev/kmem, предоставляющим информацию непосредственно из ядра системы. Файловой системы /proc в системах BSD нет. (Если она нужна для совместимости с какими-то программами, её можно специально смонтировать, при условии, что в ядре имеется поддержка PROCFS.) Программы fstat(1) и sockstat(1) берут информацию из упомянутых устройств.

В некоторых случаях названия протоколов употребляются символьные (вроде ssh, imap), в других случаях явно номера портов (22, 143). Соответствие символьных названий протоколов и их номеров указано в файле /etc/services.

6.3.1. fstat(1)

Команда fstat(1) выводит информацию обо всех открытых файловых дескрипторах. С её помощью можно получить информацию обо всех запущенных программах, так как каждая из них имеет по нескольку открытых файловых дескрипторов или сокетов, даже если в данный момент она не выполняет никакой работы. Пример, приведённый ниже, сильно урезан, так как всего в выводе команды fstat(1) было более семисот строк.

$ fstat > fstat-output
$ cat fstat-output
USER     CMD          PID   FD MOUNT      INUM MODE         SZ|DV R/W
emin     fstat      84130 root /             2 drwxr-xr-x     512  r 1
emin     fstat      84130   wd /usr     5958657 drwxr-xr-x    2048  r
emin     fstat      84130 text /usr     447995 -r-xr-sr-x   14716  r
emin     fstat      84130    0 /dev         68 crw--w----   ttyp0 rw
emin     fstat      84130    1 /usr     5958902 -rw-r--r--       0  w
emin     fstat      84130    2 /dev         68 crw--w----   ttyp0 rw
emin     fstat      84130    3 /dev         20 crw-r-----     mem  r
emin     fstat      84130    4 /dev         21 crw-r-----    kmem  r
emin     fstat      84130    5 /          8381 -rw-r--r--   40960  r
......
root     getty        633 root /             2 drwxr-xr-x     512  r 2
root     getty        633   wd /             2 drwxr-xr-x     512  r
root     getty        633 text /usr     565434 -r-xr-xr-x   21016  r
root     getty        633    0 /dev         39 crw-------   ttyv7 rw
root     getty        633    1 /dev         39 crw-------   ttyv7 rw
root     getty        633    2 /dev         39 crw-------   ttyv7 rw
......
root     getty        626 root /             2 drwxr-xr-x     512  r
root     getty        626   wd /             2 drwxr-xr-x     512  r
root     getty        626 text /usr     565434 -r-xr-xr-x   21016  r
root     getty        626    0 /dev         32 crw-------   ttyv0 rw
root     getty        626    1 /dev         32 crw-------   ttyv0 rw
root     getty        626    2 /dev         32 crw-------   ttyv0 rw
......
root     devd         242 root /             2 drwxr-xr-x     512  r
root     devd         242   wd /             2 drwxr-xr-x     512  r
root     devd         242 text /           112 -r-xr-xr-x  281208  r
root     devd         242    0 /dev          8 crw-rw-rw-    null rw
root     devd         242    1 /dev          8 crw-rw-rw-    null rw
root     devd         242    2 /dev          8 crw-rw-rw-    null rw
root     devd         242    3 /dev          5 crw-------  devctl  r
root     devd         242    4* local stream c1089000
root     adjkerntz    179 root /             2 drwxr-xr-x     512  r
root     adjkerntz    179   wd /             2 drwxr-xr-x     512  r
root     adjkerntz    179 text /           117 -r-xr-xr-x    6912  r
root     adjkerntz    179    0 -         -         bad    -
root     adjkerntz    179    1 -         -         bad    -
root     adjkerntz    179    2 -         -         bad    -
root     init           1 root /             2 drwxr-xr-x     512  r 3
root     init           1   wd /             2 drwxr-xr-x     512  r
root     init           1 text /            47 -r-x------  485892  r
        
1

Прежде всего, конечно, отметилась сама программа fstat(1). Видно, что от имени пользователя emin выполняется команда fstat с PID 84130. В поле FD перечислены файловые дескрипторы этой команды. Обратите внимание: дескрипторы 0, 1, и 2 отвечают за STDIN, STDOUT и STDERR. Поскольку в нашем случае вывод был направлен в файл, перый дескриптор в поле MOUNT указывает на /usr (на испытуемой машине там находятся пользовательские каталоги). Если бы мы направили вывод на консоль, то в этом месте был бы /dev:

$ fstat
USER     CMD          PID   FD MOUNT      INUM MODE         SZ|DV R/W
emin     fstat        748 root /             2 drwxr-xr-x     512  r
emin     fstat        748   wd /usr     75413572 drwxr-xr-x    1536  r
emin     fstat        748 text /usr     34739458 -r-xr-sr-x   14716  r
emin     fstat        748    0 /dev        114 crw--w----   ttyp0 rw
emin     fstat        748    1 /dev        114 crw--w----   ttyp0 rw
emin     fstat        748    2 /dev        114 crw--w----   ttyp0 rw
emin     fstat        748    3 /dev         10 crw-r-----     mem  r
emin     fstat        748    4 /dev         11 crw-r-----    kmem  r
emin     fstat        748    5 /         25101 -rw-r--r--   73728  r
......
            

а если в pipe, то вывод будет выглядеть так:

$ fstat | less
USER     CMD          PID   FD MOUNT      INUM MODE         SZ|DV R/W
emin     less         731 root /             2 drwxr-xr-x     512  r
emin     less         731   wd /usr     75413572 drwxr-xr-x    1536  r
emin     less         731 text /usr     34739548 -r-xr-xr-x   97736  r
emin     less         731    0* pipe c1ca4780 <-> c1ca482c      0 rw
emin     less         731    1 /dev        114 crw--w----   ttyp0 rw
emin     less         731    2 /dev        114 crw--w----   ttyp0 rw
emin     fstat        730 root /             2 drwxr-xr-x     512  r
emin     fstat        730   wd /usr     75413572 drwxr-xr-x    1536  r
emin     fstat        730 text /usr     34739458 -r-xr-sr-x   14716  r
emin     fstat        730    0 /dev        114 crw--w----   ttyp0 rw
emin     fstat        730    1* pipe c1ca482c <-> c1ca4780      0 rw
emin     fstat        730    2 /dev        114 crw--w----   ttyp0 rw
emin     fstat        730    3 /dev         10 crw-r-----     mem  r
emin     fstat        730    4 /dev         11 crw-r-----    kmem  r
emin     fstat        730    5 /         25101 -rw-r--r--   73728  r
......
            

Видно, что fstat(1) открыл pipe с номерами сокетов c1ca4780 и c1ca482c файловом дескрипторе 1 (STDOUT), а less сделал то же, но в обратном порядке и в файловом дескрипторе 0 (STDIN), через них идёт обмен данными.

Вернёмся к примеру. Второй файловый дескриптор направлен, как видно, на консоль ttyp0 (Это поток STDERR).

Дескрипторы 3 и 4 общаются с устройствами /dev/mem и /dev/kmem именно из них fstat(1) и берёт всю представленную здесь информацию. В операционных системах BSD нет виртуальной файловой системы /proc. Вся информация предостваляется ядром через упомянутые устройства. Хотя впринципе, если это надо для совместимости с какими-то программами, можно эмулировать наличие файловой системы /proc.

Перед перечнем файловых дескрипторов с номерами, мы видим три строки (самые первые) с отметками в поле файлового дескриптора root, wd, text. Их значение:

root
корневой inod
wd
рабочий каталог (current working directory)
text
текст исполнимого файла (собственно код)
tr
kernel trace file
mmap
memory-mapped file

Зная точку монтирования и номер inod можно найти к чему относятся приведённые значения wd, text и др.:

$ fstat
USER     CMD          PID   FD MOUNT      INUM MODE         SZ|DV R/W
......
emin     fstat        748   wd /usr     75413572 drwxr-xr-x    1536  r
emin     fstat        748 text /usr     34739458 -r-xr-sr-x   14716  r
......
$ find -x /usr \( -inum 75413572 -o -inum 34739458 \) -ls 2>/dev/null
34739458       32 -r-xr-sr-x    1 root kmem   14716 30 авг  2005 /usr/bin/fstat
75413572        4 drwxr-xr-x   21 emin emin    1536 20 мар 21:13 /usr/home/emin
            

Синтаксис программы find(1) обсуждается в Раздел 7.6, «Поиск файла по заданным атрибутам». Команда lsof(1), обсуждающаяся ниже, печатает в выводе не только номера inod, но и имена файлов, которые она берёт из кеша ядра.

2 Здесь, для примера, приведены записи о 8-ми экземплярах команды getty(8), которые открыты на терминалах ttyv0ttyv7 и ждут логина пользователя. (Мы прошли на машину по ssh(1), поэтому ни один из терминалов неиспользован).
3 В конце приведены сведения о процессе init(8) — родительском процессе для всех прочих процессов.

6.3.2. sockstat(1)

Программа sockstat(1) предоставляет информацию о сокетах, как сетевых, так и сокетах доступных в виде файлов.

$ sockstat
USER     COMMAND    PID   FD PROTO  LOCAL ADDRESS         FOREIGN ADDRESS
emin     sshd       84087 3  stream -> ??
emin     sshd       84087 4  tcp4   xxx.yyy.zzz.180:22    xyz.yzx.zxy.yxz:56325
root     sshd       84084 4  tcp4   xxx.yyy.zzz.180:22    xyz.yzx.zxy.yxz:56325
root     sshd       84084 5  stream -> ??
dovecot  imap-login 72803 0  tcp4   *:143                 *:*
dovecot  imap-login 72803 3  stream -> ??
dovecot  imap-login 72803 8  stream -> /var/run/dovecot/login/default
dovecot  imap-login 63557 0  tcp4   *:143                 *:*
dovecot  imap-login 63557 3  stream -> ??
dovecot  imap-login 63557 8  stream -> /var/run/dovecot/login/default
dovecot  imap-login 59983 0  tcp4   *:143                 *:*
dovecot  imap-login 59983 3  stream -> ??
dovecot  imap-login 59983 8  stream -> /var/run/dovecot/login/default
www      httpd      58349 3  tcp4   *:80                  *:*
www      httpd      58348 3  tcp4   *:80                  *:*
www      httpd      58347 3  tcp4   *:80                  *:*
www      httpd      46549 3  tcp4   *:80                  *:*
www      httpd      11184 3  tcp4   *:80                  *:*
www      httpd      81458 3  tcp4   *:80                  *:*
www      httpd      32934 3  tcp4   *:80                  *:*
root     dovecot-au 53422 0  stream -> ??
root     dovecot-au 53422 3  stream /var/run/dovecot/login/default
root     dovecot-au 53422 7  stream /var/run/dovecot/login/default
root     dovecot-au 53422 8  stream /var/run/dovecot/login/default
root     dovecot-au 53422 9  stream /var/run/dovecot/login/default
root     dovecot    53421 5  tcp4   *:143                 *:*
root     dovecot    53421 6  dgram  -> /var/run/logpriv
root     dovecot    53421 9  stream /var/run/dovecot/login/default
root     dovecot    53421 10 stream -> ??
root     dovecot    53421 11 stream -> ??
root     dovecot    53421 13 stream -> ??
root     dovecot    53421 14 stream /var/run/dovecot/auth-worker.53422
root     dovecot    53421 15 stream -> ??
www      httpd      39377 3  tcp4   *:80                  *:*
mysql    mysqld     636   3  tcp4   *:3306                *:*
mysql    mysqld     636   4  stream /tmp/mysql.sock
www      httpd      612   3  tcp4   *:80                  *:*
www      httpd      609   3  tcp4   *:80                  *:*
www      httpd      606   3  stream /var/run/cgisock.536
root     httpd      536   3  tcp4   *:80                  *:*
root     cron       499   6  dgram  -> /var/run/logpriv
smmsp    sendmail   484   3  dgram  -> /var/run/log
root     sendmail   480   3  dgram  -> /var/run/logpriv
root     sendmail   480   4  tcp4   *:25                  *:*
root     sendmail   480   5  tcp4   *:587                 *:*
root     sshd       475   3  tcp4   *:22                  *:*
root     ntpd       454   3  dgram  -> /var/run/logpriv
root     ntpd       454   4  udp4   *:123                 *:*
root     ntpd       454   5  udp4   xxx.yyy.zzz.180:123   *:*
root     ntpd       454   6  udp4   172.16.0.1:123        *:*
root     ntpd       454   7  udp4   127.0.0.1:123         *:*
daemon   rpc.lockd  409   3  udp4   *:901                 *:*
daemon   rpc.lockd  409   4  tcp4   *:803                 *:*
daemon   rpc.lockd  409   5  dgram  -> /var/run/logpriv
daemon   rpc.lockd  409   7  udp4   *:797                 *:*
_pflogd  pflogd     402   5  stream -> ??
root     pflogd     400   4  stream -> ??
root     pflogd     400   5  dgram  -> /var/run/logpriv
root     rpc.lockd  390   3  udp4   *:901                 *:*
root     rpc.lockd  390   4  tcp4   *:803                 *:*
root     rpc.lockd  390   5  dgram  -> /var/run/logpriv
root     rpc.lockd  390   6  udp4   *:720                 *:*
root     rpc.lockd  390   7  udp4   *:797                 *:*
root     rpc.statd  385   4  udp4   *:743                 *:*
root     rpc.statd  385   5  tcp4   *:966                 *:*
root     rpc.statd  385   6  dgram  -> /var/run/logpriv
root     nfsd       375   3  tcp4   *:2049                *:*
root     mountd     373   4  udp4   *:891                 *:*
root     mountd     373   5  tcp4   *:925                 *:*
root     rpcbind    351   5  stream /var/run/rpcbind.sock
root     rpcbind    351   6  dgram  -> /var/run/logpriv
root     rpcbind    351   7  udp4   *:111                 *:*
root     rpcbind    351   8  udp4   *:796                 *:*
root     rpcbind    351   9  tcp4   *:111                 *:*
bind     named      279   3  dgram  -> /var/run/logpriv
bind     named      279   20 udp4   xxx.yyy.zzz.180:53    *:*
bind     named      279   21 tcp4   xxx.yyy.zzz.180:53    *:*
bind     named      279   22 udp4   172.16.0.1:53         *:*
bind     named      279   23 tcp4   172.16.0.1:53         *:*
bind     named      279   24 udp4   127.0.0.1:53          *:*
bind     named      279   25 tcp4   127.0.0.1:53          *:*
bind     named      279   26 udp4   *:59517               *:*
bind     named      279   27 tcp4   127.0.0.1:953         *:*
root     syslogd    264   3  dgram  /var/run/log
root     syslogd    264   4  dgram  /var/run/logpriv
root     syslogd    264   5  dgram  /var/run/log
root     syslogd    264   6  dgram  /var/named/var/run/log
root     syslogd    264   7  udp4   *:514                 *:*
root     devd       242   4  stream /var/run/devd.pipe
        

Здесь запись типа xxx.yyy.zzz.180:53 означает, что система слушает интерфейс с адресом IP xxx.yyy.zzz.180, порт 53 (из файла /etc/services узнаём, что это сервер DNS). Запись типа *:22 означает, что на 22-м порту запущен демон sshd.

Вот некоторые полезные опции данной команды:

-l
Список портов открытых на прослушивание
-c
Список установленных соединений
-4, -6
Только протокол IPv4 или IPv6
-n
Не производить reverse-DNS запросы (опция присутсвует не во всех реализациях)
-u
Перечислит открытые локальные UNIX-сокеты.
-p 21-23,25,80,110
Фильтр по номерам портов. В данном случае позвляет вывести информацию только по портам 21, 22, 23, 25, 80 и 110.

Аналогичную информацию можно получить при анализе вывода программы netstat(1). См. Раздел 6.1.2, «netstat(1)» и Раздел 6.1.2.3, «Работающие интернет сервисы и открытые сокеты».

6.3.3. lsof(1)

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

С опцией -i она может рассказать об открытых интернет-соединениях:

$ lsof -i -n | head
COMMAND    PID  USER   FD   TYPE     DEVICE SIZE/OFF NODE NAME
syslogd    306  root    5u  IPv4 0xc18cc708      0t0  UDP *:syslog
ntpd       439  root    4u  IPv4 0xc18cc654      0t0  UDP *:ntp
ntpd       439  root    5u  IPv4 0xc18cc5a0      0t0  UDP 192.168.0.4:ntp
ntpd       439  root    6u  IPv4 0xc18cc4ec      0t0  UDP 192.168.0.6:ntp
ntpd       439  root    7u  IPv4 0xc18cc438      0t0  UDP 127.0.0.1:ntp
sshd       470  root    3u  IPv4 0xc18fade0      0t0  TCP *:ssh (LISTEN)
sendmail   476  root    4u  IPv4 0xc18fac24      0t0  TCP 127.0.0.1:smtp (LISTEN)
mysqld     570 mysql    3u  IPv4 0xc18fa8ac      0t0  TCP *:3306 (LISTEN)
mysqld     570 mysql    3u  IPv4 0xc18fa8ac      0t0  TCP *:3306 (LISTEN)
        

Здесь в скобках показано состояние соединения TCP (расшифровку см. выше). Сделав поиск по слову ESTABLISHED мы можем узнать соединения, по которым в данный момент могут передаваться данные:

$ lsof -i -n | grep ESTABLISHED | head
sshd     53540  root    4u  IPv4 0xc28ae1bc      0t0  TCP xxx.yyy.zzz.xyz:ssh->xxx.yyy.zzz.zyx:52954 (ESTABLISHED)
sshd     53542  emin    4u  IPv4 0xc28ae1bc      0t0  TCP xxx.yyy.zzz.xyz:ssh->xxx.yyy.zzz.zyx:52954 (ESTABLISHED)
httpd    47448   www   66u  IPv4 0xc1f296f0      0t0  TCP xxx.yyy.zzz.xyz:http->**************:31825 (ESTABLISHED)
httpd    51286   www   66u  IPv4 0xc2407378      0t0  TCP xxx.yyy.zzz.xyz:http->***********:2381 (ESTABLISHED)
httpd    51314   www   66u  IPv4 0xc21c3534      0t0  TCP xxx.yyy.zzz.xyz:http->*************:11009 (ESTABLISHED)
httpd    51316   www   66u  IPv4 0xc1b6dde0      0t0  TCP xxx.yyy.zzz.xyz:http->************:3664 (ESTABLISHED)
httpd    52426   www   66u  IPv4 0xc2407a68      0t0  TCP xxx.yyy.zzz.xyz:http->************:10555 (ESTABLISHED)
httpd    53595   www   66u  IPv4 0xc208ec24      0t0  TCP xxx.yyy.zzz.xyz:http->*************:55420 (ESTABLISHED)
httpd    53666   www   66u  IPv4 0xc43adde0      0t0  TCP xxx.yyy.zzz.xyz:http->**************:3339 (ESTABLISHED)
httpd    53778   www   66u  IPv4 0xc1fa8534      0t0  TCP xxx.yyy.zzz.xyz:http->*************:33735 (ESTABLISHED)
        

Следующий скрипт отслеживает количество соединений с web-сервером apache, и печатает статистику, по которой можно установить с какого IP пришло слишком много запросов.

#!/bin/sh
while :
do
    echo "========== `/bin/date` =========="
    /usr/local/bin/lsof -i -n |\
        /usr/bin/awk '/^httpd.*ESTABLISHED/{print $9}' |\
        /usr/bin/sed 's/.*->\([0-9.]*\):.*/\1/' |\
        /usr/bin/sort | /usr/bin/uniq -c | /usr/bin/sort -n -k1,1
    /bin/sleep 5
done
        

Ту же задачу, впрочем, можно решить и при помощи команды netstat(1):

#!/bin/sh
while :
do
    echo "========== `/bin/date` =========="
    /usr/bin/netstat -n | /usr/bin/awk '/62\.117\.108\.4\.80 .*ESTABLISHED/{print $5}' |\
        /usr/bin/sed 's/\.[0-9]*$//' |\
        /usr/bin/sort | /usr/bin/uniq -c | /usr/bin/sort -n -k1,1
    /bin/sleep 5
done
        

Без опции -i программа lsof(1) выводит информацию об открытых файлах. Вывод её несколько удобнее, чем у программы fstat(1), так как включает в себя не только номера inod'ов, но и имена файлов, которые она берёт из кеша ядра.

6.3.4. nmap(1)

Программа nmap(1) сканирует порты, доступные на системе, иногда позволяет по fingerprint'у определить тип операционной системы на изучаемой системе:

$ nmap scanme.nmap.org

Starting Nmap 4.00 ( http://www.insecure.org/nmap/ ) at 2006-03-24 18:56 MSK
Interesting ports on scanme.nmap.org.48.153.217.205.in-addr.arpa (205.217.153.62):
(The 1660 ports scanned but not shown below are in state: filtered)
PORT    STATE  SERVICE
22/tcp  open   ssh
25/tcp  closed smtp
53/tcp  open   domain
70/tcp  closed gopher
80/tcp  open   http
113/tcp closed auth
135/tcp open   msrpc
136/tcp open   profile
137/tcp open   netbios-ns
138/tcp open   netbios-dgm
139/tcp open   netbios-ssn
445/tcp open   microsoft-ds

Nmap finished: 1 IP address (1 host up) scanned in 258.100 seconds
        

Программа nmap(1) имеет различные опции указывающие каким образом она должна смотреть открыт ли порт. Разумеется программа эта может быть использована как во благо (тестирование своего собственного брандмауэра), так и во вред. Тем более администратор должен знать о её возможностях.

По умолчанию программа занимается тем, что по очереди перебирает порты и посылает по ним SYN пакеты, а в ответ на SYN/ACK пакет высылается пакет RST (см. Раздел B.1.4.3, «TCP»). Возможны и другие способы сканирования, путём отсылки ACK пакетов, UDP пакетов и др. Всё это подробным образом освещяется в справочной странице по nmap(1). По необъяснимой для меня причине столь разрушительная программа в портах FreeBSD устанавливается так, что запустить её может кто угодно. На мой взгляд, первое, что должен выполнить администратор после установки такой программы, это команду: chmod 500 /usr/local/bin/nmap. Я конечно понимаю, что пользователь всё равно может собрать её локально, но зачем же его к этому подталкивать? Это я понять немогу.

В следующем разделе я расскажу о неменее разрушительной программе hping(8), которая, почему-то не входит в курс BSDA.

6.4. Проверка доступности TCP/IP сервиса

Описание.  Кандидат BSDA должен уметь определить доступна ли удалённая система через TCP/IP и, если да, уметь при помощи telnet(1) убедиться отвечает ли сервис на клиентские запросы.

Практика. ping(8), traceroute(8), telnet(1), nc(1) на FreeBSD и OpenBSD

Комментарий

6.4.1. ping(8)

Утилита ping предназначена для того, чтобы при помощи отправки ICMP пакетов убедиться в работоспособности хоста. Утилита настолько широкоизвестна, что наверное нет необходимости подробно о ней говорить. Заметим только, то, о чём многие порой забывают: у утилиты ping(8) есть масса разных аргументов, и её можно использовать для разнообразнейшей диагностики. В скриптах полезно бывает применять опцию -c при помощи которой можно сказать после какого числа посланных и принятых (или не принятых) ICMP пакетов работа программы остановится (по умолчанию, она работает бесконечно, пока пользователь не нажмёт сочетание клавиш Ctrl+C). Опция -i позволяет задать интервал времени между пакетами (по умолчанию 1 секунда). Опция -I позволяет задать конкретный интерфейс, с которого будет отправлен пакет (если вопреки таблице маршрутизации его надо послать куда-то в другое место). -S позволяет задать некоторый конкретный IP адрес источника пинга. Очень разрушительная опция, но весьма полезная в диагностике состояния сети — -f позволяет совместно с опцией -c отправить одновременно множество ICMP пакетов (устроить так называемый флуд (flood — наводнение, поток, жарг. болтовня)). В случае наличия помех в сети часть пакетов будет потеряна, при нормальном пинге пакеты скорее всего пройдут полностью. Ниже дан пример такой «атаки» совершённой в сети с некачественным оборудованием (не качественным на физическом уровне).

$ ping -f -c 10000 192.168.0.12
Password:
PING 192.168.0.12 (192.168.0.12): 56 data bytes
...............................................
--- 192.168.0.12 ping statistics ---
10000 packets transmitted, 6301 packets received, 36% packet loss
round-trip min/avg/max/stddev = 0.159/0.173/0.594/0.017 ms
        

Как видим, 36% пакетов было потеряно. В нормальной локальной сети, с хорошими проводами и не перенапряжёнными коммутаторами, такая «атака» не должна приводить к значительным потерям пакетов.

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

Не все хосты обязаны отвечать на запросы программы ping(8). Обычно программа ping(8) посылает пакеты, которые называются ECHO_REQUEST и ожидает получить пакет ECHO_RESPONSE. Однако варианты ответов могут быть разными. Ниже показан вариант с ответом «Destination Port Unreachable». Такой ответ, однако, означает, что на той стороне есть «живая» машина.

$ ping -c1 192.168.25.24
PING cube.mccme.ru (192.168.25.24): 56 data bytes
92 bytes from cube.mccme.ru (192.168.25.24): Destination Port Unreachable
Vr HL TOS  Len   ID Flg  off TTL Pro  cks      Src      Dst
 4  5  00 5400 f8d6   0 0000  40  01 fcfe 192.168.25.158  192.168.25.24

--- 192.168.25.24 ping statistics ---
1 packets transmitted, 0 packets received, 100% packet loss
        

Немного напоминает знаменитый диалог Винни-Пуха и Пятачка:

Тут он наклонился, сунул голову в нору и крикнул:

— Эй! Кто-нибудь дома?

Вместо ответа послышалась какая-то возня, а потом снова стало тихо.

— Я спросил: «Эй! Кто-нибудь дома?» — повторил Пух громко-громко.

— Нет! — ответил чей-то голос. — И незачем так орать, — прибавил он, — я и в первый раз прекрасно тебя понял.

— Простите!  — сказал Винни-Пух. — А что, совсем-совсем никого нет дома?

— Совсем-совсем никого! — отвечал голос. Тут Винни-Пух вытащил голову из норы и задумался.

Он подумал так: «Не может быть, чтобы там совсем-совсем никого не было! Кто-то там всё-таки есть — ведь кто-нибудь должен же был сказать: «Совсем-совсем никого!»»

Не путайте ответы «Destination Port Unreachable» и «Destination Host Unreachable». Последний генерируется маршрутизатором (или, в частном случае вашей собственной машиной), если он не знает куда послать пакет:

$ ping -c1 192.168.25.1
PING 192.168.25.1 (192.168.25.1): 56 data bytes
36 bytes from gateway (172.16.0.1): Destination Host Unreachable
Vr HL TOS  Len   ID Flg  off TTL Pro  cks      Src      Dst
 4  5  00 5400 9514   0 0000  40  01 5fd9 172.16.0.2  192.168.25.1


--- 192.168.25.1 ping statistics ---
1 packets transmitted, 0 packets received, 100% packet loss
        

В первом («Винни-Пуховском») примере мы получили ответ от машины, которую мы и пинговали, следовательно она всё-таки включена. А во втором примере, пакет не был доставлен машине, так как она не была найдена (в приведённом примере не была найдена не только машина, но даже сеть, в которой она должна находиться).

6.4.2. traceroute(1)

Команда traceroute(1) в некоторых случаях позволяет выяснить маршрут от одного компьютера до другого. Для этого она посылает пакеты на целевую машину последовательно увеличивая параметр TTL (time to live). В норме TTL должен уменьшаться на единицу на каждом маршрутизаторе, пока не станет равным нулю. Если он обнулится, пакет будет отброшен, а отославшей его стороне вернётся пакет ICMP TIME_EXCEEDED. В этом пакете будет присутствовать IP маршрутизатора, который его послал. По этой информации traceroute(1) сможет перечислить машины, через которые идут пакеты до целевой машины.

[Замечание]Замечание
Имейте ввиду: не все маршрутизаторы уменьшают TTL. Некоторые из них могут оказаться прозрачными для traceroute(1).

Для примера, попробуем выяснить маршрут к несуществующей сети:

$ traceroute -n 10.0.0.1
traceroute to 10.0.0.1 (10.0.0.1), 64 hops max, 40 byte packets
 1  172.16.0.1  0.418 ms  0.781 ms  0.228 ms
 2  172.16.0.1  1.703 ms !H  0.585 ms !H  0.491 ms !H
        

Здесь мы выполняли команду traceroute(1) на машине 172.16.0.2. Она не знает маршрута к хосту 10.0.0.1 и пересылает пакет на машину 172.16.0.1 — свой маршрутизатор по умолчанию, а тот вернул ответ «Destination Host Unreachable», о чём свидетельствует флаг !H. Эта строка появилась потому, что брандмауэр на маршрутизаторе 172.16.0.1 не выпускает пакеты предназначенные для приватных сетей на свой дефолтный маршрутизатор возвращая ICMP пакет с сообщением об ошибке. Строка с номером 1 это результат работы первого пакета ICMP, в котором TTL был выставлен в 1. Этот пакет достиг машины 172.16.0.1, но дальнейшей маршрутизации не претерпел, так как у него истёк срок жизни, поэтому сообщение об ошибке сгенерировано не было. И только следующий пакет ICMP с TTL=2, породил сообщение об ошибке.

Далее идут несколько умозрительные примеры, почёрпнутые из справки по команде traceroute(1).

$ traceroute -n 192.168.2.1
traceroute to 192.168.5.1 (192.168.5.1), 64 hops max, 40 byte packet
 1  172.16.0.1  0.418 ms  0.781 ms  0.228 ms
 2  192.168.0.1  39 ms  39 ms  19 ms
 3  192.168.0.1  39 ms  39 ms  19 ms
 4  192.168.1.1  39 ms  40 ms  39 ms
 5  192.168.2.1  39 ms  39 ms  39 ms
        

Заметьте, что строки 2 и 3 совпадают — это происходит потому, что на втором маршрутизаторе имеются ошибки в ядре — система 4.3BSD маршрутизирует пакет с нулевым TTL.

$ traceroute -n 192.168.9.1
traceroute to 192.168.9.1 (192.168.9.1), 64 hops max
 1  172.16.0.1  0.418 ms  0.781 ms  0.228 ms
 2  192.168.0.1  39 ms  39 ms  19 ms
 3  192.168.0.1  39 ms  39 ms  19 ms
 4  192.168.1.1  39 ms  40 ms  39 ms
 5  192.168.2.1  39 ms  39 ms  39 ms
 6  * * *
 7  192.168.4.1  259 ms  499 ms  279 ms
 8  * * *
 9  * * *
10  * * *
11  * * *
12  192.168.9.1  339 ms  279 ms  279 ms
        

Шлюзы 6, 8, 9, 10 и 11 либо не высылают нам ICMP с сообщением «time exceeded», либо у их сообщений слишком маленький TTL и оно нас не достигает. В точности нельзя сказать, что происходит на маршрутизаторе 12. Например, это может быть следствием ошибок в ядре 4.[23]BSD: BSD 4.x (x меньше либо равен 3) высылали сообщение об ошибке используя TTL оригинального пакета. Таким образом, ICMP «time exceeded» принципиально не мог до нас добраться.

У программы traceroute(1) есть ещё один полезный аргумент: -P [TCP|UDP|ICMP|...], с помощью которого можно задать используемый протокол. По умолчанию в системах BSD (и в Linux тоже) traceroute(1) высылает пакеты UDP направленные на абстрактный верхний порт. Такие пакеты могут резать брандмауэры, поэтому и предусмотрена возможность выбора протокола. Опция -I включает протокол ICMP. С её помощью traceroute(1) работает так же, как утилита tracert в Windows.

Ещё большую функциональность предлагает команда hping(8), описанная ниже.

6.4.3. hping(8)

Данная программа не входит в курс BSDA, тем не менее я очень советую с ней поупражняться. Как и программа nmap(1), hping(8) мощное средство тестирования брандмауэров, с её помощью можно генерировать разнообразный «неправильный» трафик.

[Важно]Важно
При помощи команды hping(8) можно сделать так называемую «back door» — чёрный ход. Команда hping(8) может запускаться только с правами суперпользователя. При этом, у неё есть режим в котором она ищет в приходящих пакетах некоторую метку и выполняет команды, которые встретятся после метки. Таким образом, если злоумышленник взломает вашу машину и сможет собрать и запустить hping(8) с нужными аргументами, то потом он сможет выполнять на атакованной системе произвольный код с полномочиями суперпользователя не осуществляя никаких операций связанных с аутентификацией.

Часто машина не отвечает на пакеты ECHO_REQUEST, но при этом на ней успешно работает web-сервер и она отвечает на попытку установить соединение с 80-м портом. Программа hping(8) может «пинговать» хосты не только при помощи ICMP пакетов, которые часто отвергаются брандмауэрами, но так же и при помощи TCP и UDP пакетов.

Так же программа hping(8) позволяет при помощи TCP пакетов с плавно изменяющимся TTL выяснить маршрут к хосту, даже если это не смогла сделать программа traceroute(1). Принцип работы тот, же, но TCP пакеты, мягко говоря, реже уничтожаются брандмауэрами.

Проделаный ниже эксперимент проводился с хорошо известным в нашей стране интернет-магазином, который работает круглосуточно, но на пинги не откликается. Все имена в распечатке заменены, так как мне неизвестно из каких соображений администрация магазина выбрала такую политику безопасности.

$ ping -c1 example.org
PING example.org (192.0.34.166): 56 data bytes

--- example.org ping statistics ---
1 packets transmitted, 0 packets received, 100% packet loss
# hping -p 80 -S -c 1 example.org
HPING example.org (rl0 192.0.34.166) S set, 40 headers + 0 data bytes
len=46 ip=192.0.34.166 ttl=121 id=47606 sport=80 flags=SA seq=0 win=16384 rtt=18.6 ms

--- example.org hping statistic ---
1 packets tramitted, 1 packets received, 0% packet loss
round-trip min/avg/max = 18.6/18.6/18.6 ms
$ traceroute example.org
traceroute to example.org (192.0.34.166), 64 hops max, 40 byte packets
 1  ****** (***.***.***.***)  0.432 ms  0.244 ms  4.614 ms
 2  ****** (***.***.***.***)  0.751 ms  10.655 ms  1.809 ms
 3  ****** (***.***.***.***)  0.859 ms  5.817 ms  10.049 ms
 4  ****** (***.***.***.***)  13.455 ms  13.785 ms  17.565 ms
 5  ****** (***.***.***.***)  18.931 ms  19.907 ms  18.807 ms
 6  ****** (***.***.***.***)  25.173 ms  20.845 ms  20.466 ms
 7  * * *
 8  * * *
^C
# hping -p 80 -S -c 8 --traceroute example.org
HPING example.org (rl0 192.0.34.166): S set, 40 headers + 0 data bytes
hop=1 TTL 0 during transit from ip=***.***.***.*** name=******
hop=1 hoprtt=0.4 ms
hop=2 TTL 0 during transit from ip=***.***.***.*** name=******
hop=2 hoprtt=0.7 ms
hop=3 TTL 0 during transit from ip=***.***.***.*** name=******
hop=3 hoprtt=1.4 ms
hop=4 TTL 0 during transit from ip=***.***.***.*** name=******
hop=4 hoprtt=11.9 ms
hop=5 TTL 0 during transit from ip=***.***.***.*** name=******
hop=5 hoprtt=28.3 ms
hop=6 TTL 0 during transit from ip=***.***.***.*** name=******
hop=6 hoprtt=40.0 ms
len=46 ip=192.0.34.166 ttl=121 id=48766 sport=80 flags=SA seq=6 win=16384 rtt=20.3 ms
len=46 ip=192.0.34.166 ttl=121 id=8660 sport=80 flags=SA seq=7 win=16384 rtt=32.5 ms

--- example.org hping statistic ---
8 packets tramitted, 8 packets received, 0% packet loss
round-trip min/avg/max = 0.4/16.9/40.0 ms
        

Как видим, если послать «пинг» при помощи пакета TCP на порт 80 с выставленным флагом SYN, на него приходит ответ. (Иначе не мог бы функционировать магазин). Таким же образом, мы можем выяснить и маршрут до него. При этом ни команда ping(8), ни traceroute(8) с задачей не справляются.

Подробное описание программы hping имеется в работе Николая Малых [url://Malyh-hping2-2005].

6.4.4. telnet(1), nc(1)

Основное назначение программы telnet(1) заключается в том, что она предоставляет удалённый терминал, позволяя управлять машиной на расстоянии. К сожалению, программа telnet(1) не шифрует трафик и даже пароли передаёт в открытом виде. Мы покажем чем это опасно, когда будем обсуждать программу tcpdump(1).

[Важно]Важно
Использовать программу telnet(1) по назначению — дурной тон. Это крайне небезопасно! Вместо неё следует использовать программу ssh(1).

Однако программу telnet(1) можно использовать для того, чтобы провести диалог с удалённым сервером, проверить работу сервиса прослушивающего соответствующий порт. Например, при передаче почты, устанавливается связь с 25-м портом почтового сервера и далее идут команды SMTP протокола. Ниже приведён короткий пример такого диалога. Здесь символ | означает, что на этой строке приведено служебное сообщение программы telnet(1), > — строка которую мы вводим с клавиатуры, т.е. её клиент отсылает серверу, < — ответ сервера.

$ telnet mxs.mail.ru 25
| Trying 194.67.23.20...
| Connected to mxs.mail.ru.
| Escape character is '^]'.
< 220 Mail.Ru ESMTP
> HELO somewhere.org
< 250 mx8.mail.ru ready to serve
> QUIT
< 221 mx8.mail.ru closing connection
| Connection closed by foreign host.
        

Обратите внимание на фразу Escape character is '^]'. Если по каким-то причинам вы не можете дождаться ответа сервера и вам надо разорвать соединение, нажмите клавиши <Ctrl>+] и перед вами появится командная строка telnet(1). В ней вы можете набрать команду quit и завершить сеанс:

$ telnet mxs.mail.ru 25
Trying 194.67.23.20...
Connected to mxs.mail.ru.
Escape character is '^]'.
220 Mail.Ru ESMTP
^]
telnet> quit
Connection closed.
        

Работа с telnet(1) может быть неудобна тем, что вы не всегда можете отредактировать свой текст в случае ошибки, к тому же некоторые сервисы, расчитанные на работу с роботом могут завершить соединение по таймауту, если вы набираете команды недостаточно быстро. Наконец, telnet(1) невозможно использовать в скриптах.

Чтобы преодолеть эти недостатки, вместо telnet(1) можно использовать программу nc(1) (netcat). В следующем примере, мы делаем тоже, что и в предыдущем, но две команды SMTP (HELO example.org и QUIT) мы посылаем на стандартный ввод команде nc(1), а на STDOUT мы получаем ответы почтового сервера (вместо команды echo, использована команда printf(1), для того, чтобы напечатать команды HELO и QUIT на двух разных строках):

$ printf 'HELO example.org\nQUIT' | nc mxs.mail.ru 25
220 Mail.Ru ESMTP
250 mx19.mail.ru ready to serve
        

Конечно программой nc(1) можно пользоваться и интерактивно, если не назначить ей STDIN, она, как и положено любой UNIX программе, будет брать STDIN с клавиатуры:

$ nc msx.mail.ru 25
< 220 Mail.Ru ESMTP
> HELO somehere.ru
< 250 mx18.mail.ru ready to serve
> QUIT
< 221 mx18.mail.ru closing connection
        

В качестве примера скрипта использующего программу nc(1) приведём программу, которая пытается определить правильность некоторого адреса email. Приведённая программа первым делом разбирает адрес email, находя в нём часть отвечающую за имя сервера. Затем делает запрос к серверу DNS при помощи программы dig(1) определяя имя почтового сервера. И, наконец, при помощи nc(1) проводит диалог с этим сервером пытаясь при помощи команды SMTP RCPT определить существование почтового адреса на данной машине. Почтовый сервер на эту команду должен дать положительный ответ (код больше двухсот, но меньше трёхсот) и надпись <Recipient ok>. Но может и не дать никакого ответа по соображениям безопасности (смотря как настроен почтовый сервер). Тонкости работы команды dig(1) рассмотрены в Раздел 6.5, «Запрос к серверу DNS». Программирование в Bourne shell в Раздел 7.7, «Написание несложных Bourne-скриптов».

#!/bin/sh

if [ $# -lt 1 ]
then
    echo "Usage mailtest.sh user@server"
    exit 1
fi

# Вычленяем имя сервера из почтового адреса
server=`echo $1 | sed s/.*@//`

# Определяем почтовый сервер ответственный за передачу писем на
# сервер $server
mxserver=$( dig $server MX |\
        egrep 'MX[[:space:]]+[0-9]+[[:space:]]+[^[:space:]]+\.' |\
        sort -n -k5,5 |\
        head -1 | awk '{print $6}' | sed 's/\.$//' )

echo Investigate: $1
echo Server:      $server
echo MX server:   $mxserver

# Пытаемся провести SMTP диалог с почтовым сервером
nc $mxserver 25 << EOF
HELO example.org
MAIL From: postmaster@example.org
RCPT To: $1
QUIT
EOF
        

Программа nc(1) штатно присутствует в FreeBSD и OpenBSD, а в DragonFly BSD и NetBSD её надо ставить отдельно, как сторонний продукт.

В Раздел C.2.1.6.4.3, «TCP proxy» можно найти пример в котором nc(1) используется в качестве прокси-сервера.

6.5. Запрос к серверу DNS

Описание.  Кандидат BSDA должен понимать основы теории DNS, включая типы DNS записей обратное преобразование имён и перенос зон. Кандидат должен уметь посылать запросы серверу DNS о записях нужного типа, понимать какой сервер авторитетен за зону и понимать готов ли сервер к пересылке зоны.

Практика. dig(1), host(1), nslookup(1), ping(8), telnet(1)

Комментарий

6.5.1. Теория вопроса

Литература по настройке серверов DNS чрезвычайно обильна. Я пройдусь по теме насколько это возможно кратко.

Итак, протоколы IP и IPv6 устроены таким образом, что адресация происходит при помощи числовых адресов. Нельзя сказать, что человека это должно как-то напрягать, ведь никто не протестует против применения семизначных, десятизначных и даже более длинных телефонных номеров. Однако иметь более мнемоничные адреса несомненно удобнее. Почти сразу, как только появился интернет, появились таблицы соответствия IP адресов и символьных имён машин. Эти таблицы и по сей день хранятся в файле /etc/hosts. Однако задача синхронизации данного файла между машинами очень скоро стала непомерно сложной. В настоящий момент можно с уверенностью сказать, что она вообще нереальна. Для решения этой проблемы возникла система DNS — распределённая база данных.

Распределённая, значит ни один сервер не содержит в себе сведений обо всём пространстве имён Интернета. Каждый сервер ответственен за свой участок этого пространства. Говорят, что данный сервер авторитетен для данной зоны.

Таким образом, пространство имён Интернета поделено на зоны. Каждый сервер может отвечать за ноль и более зон. Рассмотрим, что происходит когда некоторой машине надо узнать IP адрес машины www.dragonflybsd.org.

  1. Первым делом будет осуществлён поиск в файле /etc/hosts, затем, в случае неудачи, будет изучен файл /etc/resolv.conf. Дополнительную информацию об этих этапах можно узнать из Раздел 6.1.4, «/etc/resolv.conf(5)» и Раздел 6.7, «Изменение порядка разрешения имён». Сейчас нам важно, что в итоге мы сделали запрос к некоторому серверу DNS.
  2. Сервер DNS должен самостоятельно узнать адрес машины www.dragonflybsd.org. и сообщить его клиенту даже если он не является авторитетным для зоны в которой находится данная машина (т.е. зоны dragonflybsd.org.). Сервер, который в состоянии выполнить всю работу по розыску адреса, задав все вопросы другим серверам DNS самостоятельно называется рекурсивным. В /etc/resolv.conf можно указывать только рекурсивные сервера DNS.

    Первым делом наш сервер посылает запрос одному из корневых серверов DNS. Разумеется ни один из корневых серверов не знает ответа на этот вопрос. Больше того, ни один из них и не будет разбираться в вопросе, т.е. ни один из них не является рекурсивным. Зато они знают, какие сервера ответственны за зону org. И этой информацией делятся.

  3. Наш сервер посылает запрос о машине www.dragonflybsd.org. на сервер отвечающий за зону org. Тот тоже не знает где эта машина и он тоже, с гарантией нерекурсивен, но он знает о том, какая машина отвечает за зону dragonflybsd.org.
  4. Наш сервер посылает запрос на сервер ответственный за зону dragonflybsd.org. Тот располагает авторитетной информацией и сразу даёт ответ. Надо заметить, что этот сервер в принципе мог бы быть рекурсивным. Если это так, и если бы нас интересовал узел 4-го уровня вложенности (host.www.dragonflybsd.org.) то сервер ответственный за зону dragonflybsd.org. сам мог бы послать запрос серверу ответственному за зону www.dragonflybsd.org.

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

Заметьте, что есть чёткая иерархия зон, но нет иерархии серверов DNS. Сервер DNS первым делом осуществляет запрос к корневому серверу, а вовсе не к «своему начальнику». Понятие старшинства среди серверов отсутствует, оно есть только для зон. Конечно сервер должен задать кому-то самый первый вопрос. Этот вопрос он задаёт корневому серверу. Адреса корневых серверов он берёт из специальной зоны подсказок, которая распространяется с исходным кодом сервера. Ниже я покажу как получить эту информацию.

[Замечание]Замечание
Иерархию серверов DNS можно создать искуственно при помощи опции forwarders и зон типа forward. Это может быть полезно, если на предприятии поднимаеться свой локальный «национальный» домен типа local. и в нём поддомены типа finans.local., kb.local., где будут хосты типа glavbuh.finans.local., ingeneer.finans.local., причём на зоны втророго уровня ответственны свои DNS сервера, отличные от центрального сервера, ответственного за зону local..

В каждой зоне могут быть записи следующих типов:

Таблица 6.1. Типы записей в файле зоны DNS

ЗаписьОписание
SOA Определение параметров зоны DNS (таймауты, адрес ответственного лица)
NS Определение DNS-серверов ответственных (авторитетных) за зоны, делегирование полномочий поддоменам.
Записи типа SOA и NS обязательны, остальных записей может не быть вовсе.
A Преобразование имени в IP адрес
AAAA или A6 Преобразование имени в IPv6 адрес
PTR Преобразование IP адреса в имя
MX Указание почтового сервера ответственного за зону
KEY Открытый ключ шифрования для имени DNS
CNAME Псевдоним, алиас, синоним.
SRV Распределение нагрузки на сервис
TXT Текстовая запись используется с самой разной целью
HINFO Информация о машине, например архитектура и операционная система.

В каждой зоне обязательно должны присутствовать записи типа SOA и NS. Если для домена example.org. почту принимает машина mx.example.org., то для неё должна существовать специальная MX запись. Почтовых машин отвечающих за домен может быть несколько. В записи типа MX упоминается их приоритет. Почту принимает машина с наименьшим значением приоритета, а если она недоступна, то следующая. Если запись MX для домена example.org. отсутствует, то эту почту принимает машина example.org.

6.5.1.1. Настройка прямой и обратной зон

Полное описание работы с сервером BIND выходит за рамки данного раздела. Мы лишь опишем настройку файла зоны, с тем, чтобы администратор мог сознательно применять утилиты host(1), dig(1) и nslookup(1).

6.5.1.1.1. named.conf(5)

Сначала зона должна быть объявлена в конфигурационном файле сервиса named(8) — named.conf(5). Этот конфигурационный файл может находиться в файле /etc/namedb/named.conf, а может в /var/named/etc/namedb/named.conf. Сервис named(8) часто запускается в окружении chroot(8) в каталоге /var/named/, однако для удобства администрирования всё равно оставляют мягкую ссылку /etc/namedb/named.conf.

Зона, оъявленная в BIND, может иметь один из следующих типов: master, slave, hint или forward. Зона hint содержит в себе адреса корневых серверов DNS, с которых начинает опрос рекурсивный сервер DNS. Эта зона практически не подвержена никаким изменениям и обычно не должна редактироваться администратором.

Зона типа master должна быть описана в файле. Файл описания зоны мы рассмотрим ниже, а сейчас взглянем на объявление зоны типа master:

...skip...

options {
    directory "/etc/namedb";

...skip...

}

...skip...

zone "example.org." {
    type master;
    file "master/example.zone";
};

...skip...
            

Здесь сказано, что зона example.org. описана в файле master/example.zone. Этот адрес дан относительно каталога /etc/namedb (см. опцию directory).

Зону типа master редактирует администратор, но за эту зону может отвечать несколько серверов DNS. Для того, чтобы все они обладали одинаковой согласованной информацией, на всех прочих серверах DNS поднимается зона типа slave, которая синхронизируется с зоной типа master. Зона типа slave объявляется следующим образом:

zone "example.org." {
    type slave;
    file "slave/example.zone";
    masters {
        192.168.1.1;
    };
};
            

Здесь сказано, что зона имеет тип slave, а сервер, с которого надо брать информацию о ней (master) имеет адрес 192.168.1.1. Информация о зоне (файл зоны) будет сохраняться в файле slave/example.zone. Последняя опция необязательна, если файл не указан, информация будет храниться в памяти и при перезагрузке сервера DNS пропадёт.

Зона типа forward применяется в редких случаях, когда надо заставить наш сервер DNS делать запрос о зоне для которой он не авторитетен не к одному из корневых серверов, перечисленных в зоне hint, а к некоторому конкретному серверу. Например, пусть DNS A, расположенный на некотором предприятии, описывает локальную зону local. и делегирует зону finans.local. серверу DNS B. Поскольку сервер A не авторитетен для зоны finans.local., при попытке разрешить имя major-buhg.finans.local., он обратится к корневому серверу DNS (несмотря на то, что он сам делегировал зону finans.local. серверу B) и потерпит неудачу, так как зоны local. с точки зрения корневых серверов не существует. Поэтому на сервере A мы должны описать зону finans.local. типа forward для того, чтобы он переадресовывал запросы к этой зоне на авторитетный для неё сервер B:

zone "local." {
    type master;
    file "master/local.zone";
};

zone "finans.local." {
    type forward;
    masters {
        192.168.1.2; // server B
    };
};
            

В свою очередь, на сервере B нам, вероятно, надо указать опцию forwarders, в которой указать сервер A, тогда опрос сервер B будет производить не с корневых серверов, а с сервера A и разрешение имён находящихся в зоне local. будет работать корректно. Кроме того, такое действие полезно, если на предприятии поднято несколько серверов DNS, а выход в Интернет на брандмауэре разрешён только серверу A.

...skip...

options {
    directory "/etc/namedb";
    forwarders {
      192.168.1.1; // server A
    };

...skip...

}
            
6.5.1.1.2. Синтаксис файла зоны

Файл зоны состоит из перечня записей различного типа. Типы записей в файле зоны были перечислены в Таблица 6.1, «Типы записей в файле зоны DNS». Как уже говорилось, обязательных записей в этом файле всего две: запись типа SOA и запись типа NS в которой указан сервер DNS ответственный за данную зону.

В каждой записи имеется необязательное поле, в котором указывается время жизни данной записи в кешах серверов DNS. Чтобы не указывать эту величину в каждой строке (как правило нет никакого смысла делать различные времена жизни для разных записей) её можно указать в самом начале файла, задав переменную $TTL.

Все адреса в файле зоны должны заканчиваться на точку (т.н. формат FQDN: fully qualified domain name — полностью описанное имя домена). Если имя не кончается на точку, к нему дописывается содержимое переменной $ORIGIN. Если данная переменная не задана явно, то в ней содержится имя зоны, т.е. то, что объявлено в файле named.conf(5).

Другая интересная переменная — $INCLUDE позволяет включить внутрь одного файла зоны другой файл.

Комментарии в файле зоны начинаются с символа ;.

Первая запись в файле зоны — запись типа SOA. помимо необязательного поля TTL в записи SOA имеется десять обязательных полей, поэтому записать её в одну строку весьма затруднительно. Для того, чтобы запись типа SOA можно было написать в несколько строк, применяются круглые скобки. запись не кончится, пока не закроется круглая скобка.

Вот пример файла зоны с описанием:

$TTL      36000

@         IN        SOA       ns.example.ru. root.example.ru.  (
                                        2006011700  ; Serial
                                        3600        ; Refresh
                                        900         ; Retry
                                        3600000     ; Expire
                                        3600 )      ; Minimum
          IN        NS        ns.example.ru.
          IN        NS        ns1.example.ru.
          IN        NS        ns2.otherplace.ru.
          IN        MX   5    smtp.example.ru.
          IN        MX   15   smtp.otherplace.ru.
ns        IN        A         192.168.0.1
ns1       IN        A         192.168.0.2
smtp      IN        A         192.168.0.1
www       IN        A         192.168.0.3
site1     IN        CNAME     www
site2     IN        CNAME     www
            

В приведённом примере сперва задана переменная $TTL, затем сделано двенадцать записей: первая запись типа SOA, три типа NS, две типа MX, четыре типа A и две типа CNAME.

SOA
  1. Имя домена. Знак @ будет заменён на содержимое переменной $ORIGIN, но мы могли бы написать явно example.ru..
  2. TTL — необязательное поле, в данном примере отсутствует.
  3. Класс записи. Практически всегда IN. Теоретически возможны и другие варианты: IN — Internet, CH — ChaosNet, HS — Hesoid — информационная служба, являющаяся надстройкой BIND и используюемая крайне редко.
  4. Тип записи (в данном случае SOA).
  5. Имя мастер сервера DNS, отвечающего за данную зону. Ниже, в записи типа NS снова будет назван этот сервер, но записей типа NS может быть много, так как у зоны может быть много авторитетных серверов. При этом один из них master, а остальные slave. В данном поле записи SOA указано какой из этих серверов будет сервером master.
  6. Электронный адрес человека ответственного за данную зону. Поскольку знак @ применяться в файле зоны не может (как уже было сказано, он заменяется на переменную $ORIGIN), вместо него используется точка. данная запись выглядит как доменное имя. Можно написать просто root, в этом случае имя будет достроено до FQDN из переменной $ORIGIN, и первая точка будет заменена на знак @. Таким образом, запись root в данном поле превратится в адрес root@example.ru.
  7. Серийный номер зоны. Его формат не важен, важно, чтобы при каждом изменении зоны админимстратор увеличивал этот номер. Периодически сервер типа slave будет связываться с сервером master и сравнивать серийные номера зон. Если окажется, что серийный номер на сервере slave меньше, чем, на master, будет начата пересылка зоны с master на slave. Удобно в этом месте писать дату изменения. Длина поля не должна превышать десять знаков, однако этого достаточно, чтобы, как в приведённом случае хранить год, месяц, день и ещё две цифры. Такой формат даёт возможность указывать дату изменения и номер изменения в указанный день и номер будет всегда увеличиваться.
  8. Интервал времени, через которое сервер slave сверяет серийный номер с сервером master.
  9. Интервал повторных попыток сверки серийного номера. Если сервер slave по какой-то причине не смог сверить серийный номер, он будет повторять попытки через указанное здесь время.
  10. В случае, если все попытки сверить зону окажутся неудачными, через данное время slave сервер будет считать, что данной зоны больше не существует и перестанет отвечать на запросы по данной зоне.
  11. Время жизни в кешах серверов DNS отрицательных ответов. Для BIND 8.2 и более старых это поле так же определяло TTL по умолчанию. В новых версиях TTL по умолчанию находится в переменной $TTL.
NS

В записи типа NS, в данном примере, отсутствует первое поле. Это значит, что оно будет взято из предыдущей записи. Таким образом, все три записи NS относятся к зоне example.ru. и описывают три сервера авторитетных для данной зоны. Два из них будут slave, а один, упомянутый в записи SOA — master.

Поле с классом записи (IN) так же как и TTL необязательное, и тоже, как и TTL могло бы отсутствовать.

В остальном синтаксис достаточно прост, назначение данной записи — перечислить ответственные за зону сервера DNS, поэтому обязательных полей здесь два: тип записи и имя сервера.

Разумеется сервер DNS не обязан находиться в описываемой зоне. В данном случае упомянут один сервер DNS из другой зоны otherplace.ru. Если сервер находится в нашей зоне, мы должны ниже, в записи типа A указать его адрес, если он в другой зоне, то его адрес должны указать там. Тем не менее нет никаких причин не включить этот сервер ещё и в нашу зону. Это удобнее, так как мы, в этом случае можем сами указать соответствующий IP.

[Замечание]Замечание
Не следует в данной записи указывать IP или имена заданные в записях типа CNAME. Указанные здесь имена должны быть описаны ниже в записи типа A или AAAA.
[Важно]Важно
Хотя согласно правилам построения системы DNS для зоны достаточно иметь один сервер DNS (поэтому запись типа NS обязательна, но может быть единственной), если вы описываете домен второго уровня внутри зоны ru., то по правилам RIPE вы обязаны иметь не менее двух серверов DNS в различных сетях класса C. Т.е. у этих двух серверов обязан отличаться как минимум третий байт в адресе IPv4.
Запись типа MX

Здесь описано какие хосты ответственны за приём почты направляющейся в домен example.ru. Если такой записи нет вообще, то почту будет принимать машина с именем example.ru. Если таких записей много, то сперва будет предпринята попытка доставить почту на машину с самым низким значением поля с приоритетом, затем, в случае неуспеха, на машину со следующим приоритетом и так далее.

Итак, данная запись отличается только тем, что в ней добавлено поле с приоритетом записи, сразу после типа записи MX.

[Важно]Важно
Не следует в данной записи указывать IP или имена заданные в записях типа CNAME. Указанные здесь имена должны быть описаны ниже в записи типа A или AAAA.
Запись типа A

Данная запись указывает соответствие между именем и адресом IP. В случае, если в файле зоны имеется несколько записей с одинаковым именем, но разными адресами, например:

www       IN        A         192.168.0.1
www       IN        A         192.168.0.2
www       IN        A         192.168.0.3
                  

...адреса будут выдаваться сервером DNS циклически: в ответ на первый запрос о имени www.example.ru сервер DNS даст адрес 192.168.0.1, следующему клиенту дадут адрес 192.168.0.2 и дальше по кругу. Это один из способов распределения нагрузки между различными серверами. К сожалению, это не самый удачный способ распределения нагрузки: при аварии на одном из серверов, даже если принять оперативные меры по редактированию файла зоны, в многочисленных кешах ещё долго будет сидеть информация о неработающем сервере и треть клиентов продолжит получать неправильную информацию. Снижение TTL на данные записи приведёт к увеличению нагрузки на систему DNS и в конечном итоге приведёт к замедлению обслуживания клиентов.

CNAME
Запись типа CNAME указывает на то, что данные имена это имена одной и той же машины. Такие записи удобны, например, при создании виртуальных веб-серверов.
SRV

Запись этого типа нужна для того, чтобы клиентское програмное обеспечение могло самостоятельно разыскивать машину, на которой поднят нужный сервис и осуществлять распределение нагрузки. К сожалению, немногие браузеры могут похвастать поддержкой этого типа записи в файле зоны. И всё же:

;; _служба._протокол.имя   [ttl]   IN SRV приоритет  вес   порт   сервер 
_http._tcp.www                     IN SRV     0       1    80     www.server.ru.
                                   IN SRV     0       3    8080   old.server.ru.
                  

В приведённом примере браузер должен осуществить запрос с целью определить на каком сервере и на каком порту обслуживают злужбу http по протоколу tcp. Как результат он получает информацию о том, что эти запросы обслуживают две машины: www.server.ru и old.server.ru. Причём первая обслуживает 25% запросов и работает на порту 80, а вторая обслуживает 75% запросов и работает на порту 8080. Распределение нагрузки осуществляется на основе поля «вес» на добровольной основе, т.е. дано на откуп клиенту.

Поле «приоритет» имеет то же значение, что и для записи MX. Клиент должен обращаться к записи с наименьшим числом в поле «приоритет», и переходить к записи с большим приоритетом, только если сервера из записей с меньшим недоступны.

Имя службы и протокола должно начинаться с подчерка, чтобы не перепутать их с обычными именами. Имена служб и протоколов описаны в [RFC-1700].

TXT

Текстовая запись. В ней может находиться самая разнообразная информация. Например стихи:

poem    IN      TXT     ( "The Road goes ever on and on"
                        "Down from the door where it began."
                        "Now far ahead the Road has gone,"
                        "And I must follow, if I can,"
                        "Purshuing it with eager feet,"
                        "Until it joins some larger way"
                        "Where many paths and errands meet."
                        "And whither then? I cannot say." )
                  

Ёмкость этой записи — пара килобайт. Мы вполне можем использовать её для хранения коротких стихотворений, создав доменные имена для разных поэтов... Однако у этой записи есть множество других, более полезных применений. В некоторых случаях в ней хранят публичные ключи. Старые версии BIND хранили в записях TXT информацию о том, кому можно отвечать на запросы к зоне (в новых версиях это делается при помощи директивы allow-query).

Итак, администратор должен уметь не только определять IP адрес машины, но и запрашивать записи о зоне определённого типа. Для осуществления этих запросов существует три команды: host(1), dig(1), nslookup(1).

[Замечание]Замечание
Имейте ввиду, все три утилиты работают с системой DNS и ни одна из них не проверяет файл /etc/hosts. Таким образом, информация полученная при помощи данных утилит не обязательно даёт ответ на вопрос «почему мой веб-браузер идёт на адрес XYZ, когда я ввожу URL http://xyz.org/?».

6.5.2. host(1)

Программа host(1) существует во многих вариантах. В FreeBSD она умеет сообщать практически ту же информацию, что и dig(1), но в других системах это может быть не так. Здесь мы приведём примеры на базе FreeBSD, как наиболее полные.

Запрос IP по адресу:

$ host mail.ru
mail.ru has address 194.67.57.26
mail.ru mail is handled (pri=10) by mxs.mail.ru
        

Как видно, нам сообщили не только IP машины mail.ru, но и некоторую дополнительную информацию (имя почтовой машины и её приоритет). Эта информация приходит от сервера DNS в том же UDP пакете и её получение не требует со стороны программы host(1) никаких специальных действий. И всё же, некоторые варианты этой программы могут не сообщать всей информации.

Программе можно явно указать сервер DNS, в этом случае запрос будет сделан к нему:

$ host mail.ru 194.67.23.130
Using domain server 194.67.23.130:

mail.ru has address 194.67.57.26
mail.ru mail is handled (pri=10) by mxs.mail.ru
        

И наконец, можно запросить конкретный тип записи:

$ host -t NS mail.ru
mail.ru name server ns2.mail.ru
mail.ru name server ns3.mail.ru
mail.ru name server ns4.mail.ru
mail.ru name server ns5.mail.ru
mail.ru name server ns.mail.ru
mail.ru name server ns1.mail.ru
$ host -t SOA mail.ru
mail.ru start of authority      ns.mail.ru hostmaster.mail.ru (
                        3209013119      ;serial (version)
                        300     ;refresh period
                        900     ;retry refresh this often
                        172800  ;expiration period
                        300     ;minimum TTL
                        )
        

Опция -v включает режим verbose.

$ host -t NS -v mail.ru
Trying null domain
rcode = 0 (Success), ancount=6
The following answer is not authoritative:
The following answer is not verified as authentic by the server:
mail.ru 16141 IN        NS      ns4.mail.ru
mail.ru 16141 IN        NS      ns5.mail.ru
mail.ru 16141 IN        NS      ns.mail.ru
mail.ru 16141 IN        NS      ns1.mail.ru
mail.ru 16141 IN        NS      ns2.mail.ru
mail.ru 16141 IN        NS      ns3.mail.ru
Additional information:
ns.mail.ru      153899 IN       A       194.67.23.130
ns1.mail.ru     299802 IN       A       194.67.57.103
ns2.mail.ru     167593 IN       A       194.67.57.104
ns3.mail.ru     278118 IN       A       194.67.23.17
ns4.mail.ru     278118 IN       A       194.67.57.4
ns5.mail.ru     278118 IN       A       194.67.23.232
$ host -t SOA -v mail.ru
Trying null domain
rcode = 0 (Success), ancount=1
The following answer is not authoritative:
The following answer is not verified as authentic by the server:
mail.ru 21455 IN        SOA     ns.mail.ru hostmaster.mail.ru (
                        3209013119      ;serial (version)
                        300     ;refresh period
                        900     ;retry refresh this often
                        172800  ;expiration period
                        300     ;minimum TTL
                        )
For authoritative answers, see:
mail.ru 15127 IN        NS      ns.mail.ru
mail.ru 15127 IN        NS      ns1.mail.ru
mail.ru 15127 IN        NS      ns2.mail.ru
mail.ru 15127 IN        NS      ns3.mail.ru
mail.ru 15127 IN        NS      ns4.mail.ru
mail.ru 15127 IN        NS      ns5.mail.ru
Additional information:
ns.mail.ru      152885 IN       A       194.67.23.130
ns1.mail.ru     298788 IN       A       194.67.57.103
ns2.mail.ru     166579 IN       A       194.67.57.104
ns3.mail.ru     277104 IN       A       194.67.23.17
ns4.mail.ru     277104 IN       A       194.67.57.4
ns5.mail.ru     277104 IN       A       194.67.23.232
        

В последнем случае нам даже явно рекомендуют обращаться за информацией на авторитетные серверы и указывают их адреса. С опцией -v отчёт программы host(1) становится похож на отчёт dig(1) (см. ниже) и начинает повтрять синтаксис файла зоны.

6.5.3. dig(1)

Утилита dig(1) более «разговорчива». Одна из особенностей её отчётов состоит в том, что они даются сразу в формате файла зоны:

$ dig mail.ru

; <<>> DiG 8.3 <<>> mail.ru 
;; res options: init recurs defnam dnsrch
;; got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 9099
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 6, ADDITIONAL: 6
;; QUERY SECTION:
;;      mail.ru, type = A, class = IN

;; ANSWER SECTION:
mail.ru.                1h56m42s IN A   194.67.57.26

;; AUTHORITY SECTION:
mail.ru.                4h21m12s IN NS  ns2.mail.ru.
mail.ru.                4h21m12s IN NS  ns3.mail.ru.
mail.ru.                4h21m12s IN NS  ns4.mail.ru.
mail.ru.                4h21m12s IN NS  ns5.mail.ru.
mail.ru.                4h21m12s IN NS  ns.mail.ru.
mail.ru.                4h21m12s IN NS  ns1.mail.ru.

;; ADDITIONAL SECTION:
ns.mail.ru.             1d18h37m10s IN A  194.67.23.130
ns1.mail.ru.            3d11h8m53s IN A  194.67.57.103
ns2.mail.ru.            1d22h25m24s IN A  194.67.57.104
ns3.mail.ru.            3d5h7m29s IN A  194.67.23.17
ns4.mail.ru.            3d5h7m29s IN A  194.67.57.4
ns5.mail.ru.            3d5h7m29s IN A  194.67.23.232

;; Total query time: 9 msec
;; FROM: aluminum.mccme.ru to SERVER: 62.117.108.2
;; WHEN: Wed Apr  5 14:37:57 2006
;; MSG SIZE  sent: 25  rcvd: 244

        

Символ ; в файле зоны является комментарием. Заметим, что мы не требовали от программы dig(1) информацию о серверах NS, и всё же он запросил её у сервера DNS. Разумеется, это не вся информация о зоне.

Попробуем запросить информацию о записях SOA и MX.

$ dig MX mail.ru

; <<>> DiG 8.3 <<>> MX mail.ru 
;; res options: init recurs defnam dnsrch
;; got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 28695
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 6, ADDITIONAL: 7
;; QUERY SECTION:
;;      mail.ru, type = MX, class = IN

;; ANSWER SECTION:
mail.ru.                4h6m37s IN MX   10 mxs.mail.ru.

;; AUTHORITY SECTION:
mail.ru.                4h6m37s IN NS   ns2.mail.ru.
mail.ru.                4h6m37s IN NS   ns3.mail.ru.
mail.ru.                4h6m37s IN NS   ns4.mail.ru.
mail.ru.                4h6m37s IN NS   ns5.mail.ru.
mail.ru.                4h6m37s IN NS   ns.mail.ru.
mail.ru.                4h6m37s IN NS   ns1.mail.ru.

;; ADDITIONAL SECTION:
mxs.mail.ru.            2h4m39s IN A    194.67.23.20
ns.mail.ru.             1d18h22m35s IN A  194.67.23.130
ns1.mail.ru.            3d10h54m18s IN A  194.67.57.103
ns2.mail.ru.            1d22h10m49s IN A  194.67.57.104
ns3.mail.ru.            3d4h52m54s IN A  194.67.23.17
ns4.mail.ru.            3d4h52m54s IN A  194.67.57.4
ns5.mail.ru.            3d4h52m54s IN A  194.67.23.232

;; Total query time: 2 msec
;; FROM: aluminum.mccme.ru to SERVER: 62.117.108.2
;; WHEN: Wed Apr  5 14:52:31 2006
;; MSG SIZE  sent: 25  rcvd: 264

$ dig SOA mail.ru

; <<>> DiG 8.3 <<>> SOA mail.ru 
;; res options: init recurs defnam dnsrch
;; got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 59976
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 6, ADDITIONAL: 6
;; QUERY SECTION:
;;      mail.ru, type = SOA, class = IN

;; ANSWER SECTION:
mail.ru.                5h51m47s IN SOA  ns.mail.ru. hostmaster.mail.ru. (
                                        3209013119      ; serial
                                        5M              ; refresh
                                        15M             ; retry
                                        2D              ; expiry
                                        5M )            ; minimum


;; AUTHORITY SECTION:
mail.ru.                4h6m19s IN NS   ns5.mail.ru.
mail.ru.                4h6m19s IN NS   ns.mail.ru.
mail.ru.                4h6m19s IN NS   ns1.mail.ru.
mail.ru.                4h6m19s IN NS   ns2.mail.ru.
mail.ru.                4h6m19s IN NS   ns3.mail.ru.
mail.ru.                4h6m19s IN NS   ns4.mail.ru.

;; ADDITIONAL SECTION:
ns.mail.ru.             1d18h22m17s IN A  194.67.23.130
ns1.mail.ru.            3d10h54m IN A   194.67.57.103
ns2.mail.ru.            1d22h10m31s IN A  194.67.57.104
ns3.mail.ru.            3d4h52m36s IN A  194.67.23.17
ns4.mail.ru.            3d4h52m36s IN A  194.67.57.4
ns5.mail.ru.            3d4h52m36s IN A  194.67.23.232

;; Total query time: 6 msec
;; FROM: aluminum.mccme.ru to SERVER: 62.117.108.2
;; WHEN: Wed Apr  5 14:52:50 2006
;; MSG SIZE  sent: 25  rcvd: 275

        

Для запроса к конкретному серверу DNS его адрес необходимо предварять символом at:

$ dig mail.ru @194.67.23.130

; <<>> DiG 8.3 <<>> mail.ru @194.67.23.130 
; (1 server found)
;; res options: init recurs defnam dnsrch
;; got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 62910
;; flags: qr aa rd; QUERY: 1, ANSWER: 1, AUTHORITY: 6, ADDITIONAL: 6
;; QUERY SECTION:
;;      mail.ru, type = A, class = IN

;; ANSWER SECTION:
mail.ru.                6H IN A         194.67.57.26

;; AUTHORITY SECTION:
mail.ru.                6H IN NS        ns.mail.ru.
mail.ru.                6H IN NS        ns1.mail.ru.
mail.ru.                6H IN NS        ns2.mail.ru.
mail.ru.                6H IN NS        ns4.mail.ru.
mail.ru.                6H IN NS        ns5.mail.ru.
mail.ru.                6H IN NS        ns3.mail.ru.

;; ADDITIONAL SECTION:
ns.mail.ru.             6H IN A         194.67.23.130
ns1.mail.ru.            6H IN A         194.67.57.103
ns2.mail.ru.            6H IN A         194.67.57.104
ns4.mail.ru.            6H IN A         194.67.57.4
ns5.mail.ru.            6H IN A         194.67.23.232
ns3.mail.ru.            6H IN A         194.67.23.17

;; Total query time: 91 msec
;; FROM: aluminum.mccme.ru to SERVER: 194.67.23.130
;; WHEN: Wed Apr  5 15:05:16 2006
;; MSG SIZE  sent: 25  rcvd: 244

        

Заметьте, что в этом запросе размеры таймаутов стали более «круглыми» — ровно по 6 часов. Причина в том, что мы задали вопрос авторитетному за эту зону серверу. Ответы, которые мы получали до сих пор мы брали из кешей неавторитетных серверов, поэтому в качестве TTL мы получали время указывающее на то, сколько осталось жить в кеше той или иной записи.

Давайте попробуем узнать с помощью команды dig(1) адреса серверов отвечающих за корневую зону (.) и время жизни записей о корневых серверах.

$ dig NS .

; <<>> DiG 8.3 <<>> NS . 
;; res options: init recurs defnam dnsrch
;; got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 5359
;; flags: qr rd ra; QUERY: 1, ANSWER: 13, AUTHORITY: 0, ADDITIONAL: 1
;; QUERY SECTION:
;;      ., type = NS, class = IN

;; ANSWER SECTION:
.                       5d1h8m12s IN NS  F.ROOT-SERVERS.NET.
.                       5d1h8m12s IN NS  G.ROOT-SERVERS.NET.
.                       5d1h8m12s IN NS  H.ROOT-SERVERS.NET.
.                       5d1h8m12s IN NS  I.ROOT-SERVERS.NET.
.                       5d1h8m12s IN NS  J.ROOT-SERVERS.NET.
.                       5d1h8m12s IN NS  K.ROOT-SERVERS.NET.
.                       5d1h8m12s IN NS  L.ROOT-SERVERS.NET.
.                       5d1h8m12s IN NS  M.ROOT-SERVERS.NET.
.                       5d1h8m12s IN NS  A.ROOT-SERVERS.NET.
.                       5d1h8m12s IN NS  B.ROOT-SERVERS.NET.
.                       5d1h8m12s IN NS  C.ROOT-SERVERS.NET.
.                       5d1h8m12s IN NS  D.ROOT-SERVERS.NET.
.                       5d1h8m12s IN NS  E.ROOT-SERVERS.NET.

;; ADDITIONAL SECTION:
J.ROOT-SERVERS.NET.     6d1h8m12s IN A  192.58.128.30

;; Total query time: 2 msec
;; FROM: aluminum.mccme.ru to SERVER: 62.117.108.2
;; WHEN: Thu Apr  6 11:37:56 2006
;; MSG SIZE  sent: 17  rcvd: 244

        

Очень хорошо, теперь мы знаем что думает о корневых серверах, в настоящий момент обслуживающий нас сервер DNS. Мы видим, что время жизни информации о корневых серверах истечёт через пять дней, один час, восемь минут, двенадцать секунд. Кстати нам, кроме имён корневых серверов, в разделе ADDITIONAL SECTION сказали ещё и адрес одного из серверов. Давайте зададим этот вопрос снова, но теперь не нашему серверу DNS, а сервру j.root-servers.net. с адресом IP 192.58.128.30. Он авторитетен за корневую зону и полученная от него информация будет истиной в последней инстанции.

$ dig NS . @192.58.128.30

; <<>> DiG 8.3 <<>> NS . @192.58.128.30 
; (1 server found)
;; res options: init recurs defnam dnsrch
;; got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 50893
;; flags: qr aa rd; QUERY: 1, ANSWER: 13, AUTHORITY: 0, ADDITIONAL: 13
;; QUERY SECTION:
;;      ., type = NS, class = IN

;; ANSWER SECTION:
.                       6D IN NS        E.ROOT-SERVERS.NET.
.                       6D IN NS        D.ROOT-SERVERS.NET.
.                       6D IN NS        A.ROOT-SERVERS.NET.
.                       6D IN NS        H.ROOT-SERVERS.NET.
.                       6D IN NS        C.ROOT-SERVERS.NET.
.                       6D IN NS        G.ROOT-SERVERS.NET.
.                       6D IN NS        F.ROOT-SERVERS.NET.
.                       6D IN NS        B.ROOT-SERVERS.NET.
.                       6D IN NS        J.ROOT-SERVERS.NET.
.                       6D IN NS        K.ROOT-SERVERS.NET.
.                       6D IN NS        L.ROOT-SERVERS.NET.
.                       6D IN NS        M.ROOT-SERVERS.NET.
.                       6D IN NS        I.ROOT-SERVERS.NET.

;; ADDITIONAL SECTION:
E.ROOT-SERVERS.NET.     5w6d16h IN A    192.203.230.10
D.ROOT-SERVERS.NET.     5w6d16h IN A    128.8.10.90
A.ROOT-SERVERS.NET.     5w6d16h IN A    198.41.0.4
H.ROOT-SERVERS.NET.     5w6d16h IN A    128.63.2.53
C.ROOT-SERVERS.NET.     5w6d16h IN A    192.33.4.12
G.ROOT-SERVERS.NET.     5w6d16h IN A    192.112.36.4
F.ROOT-SERVERS.NET.     5w6d16h IN A    192.5.5.241
B.ROOT-SERVERS.NET.     5w6d16h IN A    192.228.79.201
J.ROOT-SERVERS.NET.     5w6d16h IN A    192.58.128.30
K.ROOT-SERVERS.NET.     5w6d16h IN A    193.0.14.129
L.ROOT-SERVERS.NET.     5w6d16h IN A    198.32.64.12
M.ROOT-SERVERS.NET.     5w6d16h IN A    202.12.27.33
I.ROOT-SERVERS.NET.     5w6d16h IN A    192.36.148.17

;; Total query time: 299 msec
;; FROM: aluminum.mccme.ru to SERVER: 192.58.128.30
;; WHEN: Thu Apr  6 11:44:56 2006
;; MSG SIZE  sent: 17  rcvd: 436

        

Как видим, истинное время жизни составляет без малого шесть недель (1000 часов). При помощи такого большого TTL сервера пытаются снизить нагрузку на себя.

Поскольку команда dig(1) выдаёт информацию в формате файла зоны, если мы вдруг почему-то потеряли файл с настройками зоны hint, мы можем сохранить вывод данной команды в файл и использовать его.

Наконец, мы можем сделать запрос записи типа TXT, содержащей короткое стихотворение. Это стихотворение мы записали в файл зоны раньше.

$ dig TXT poem.house.hcn-strela.ru

; <<>> DiG 9.3.2 <<>> TXT poem.house.hcn-strela.ru
;; global options:  printcmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 8468
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 3, ADDITIONAL: 1

;; QUESTION SECTION:
;poem.house.hcn-strela.ru.      IN      TXT

;; ANSWER SECTION:
poem.house.hcn-strela.ru. 36000 IN      TXT     "The Road goes ever on
        and on" "Down from the door where it began." "Now far ahead the
        Road has gone," "And I must follow, if I can," "Purshuing it
        with eager feet," "Until it joins some larger way" "Where many
        paths and errands meet." "And whither then? I cannot say."

;; AUTHORITY SECTION:
house.hcn-strela.ru.    36000   IN      NS      ns.hcn-strela.ru.
house.hcn-strela.ru.    36000   IN      NS      ns1.hcn-strela.ru.
house.hcn-strela.ru.    36000   IN      NS      ns.house.hcn-strela.ru.

;; ADDITIONAL SECTION:
ns.house.hcn-strela.ru. 36000   IN      A       83.102.236.196

;; Query time: 3 msec
;; SERVER: 127.0.0.1#53(127.0.0.1)
;; WHEN: Sat Feb 17 12:05:09 2007
;; MSG SIZE  rcvd: 376

        

6.5.4. nslookup(1)

nslookup(1) самая древняя программа из этих трёх. Кроме всего прочего она интересна ещё и тем, что входит в стандартную поставку большинства операционных систем компании MicroSoft.

Её синтаксис несколько напоминает синтаксис команды host(1):

$ nslookup mail.ru
Server:  ns.mccme.ru
Address:  62.117.108.2

Non-authoritative answer:
Name:    mail.ru
Address:  194.67.57.26

$ nslookup mail.ru 194.67.23.130
Server:  ns.mail.ru
Address:  194.67.23.130

Name:    mail.ru
Address:  194.67.57.26

        

Но главная изюминка nslookup(1) состоит в том, что она умеет работать интерактивно:

$ nslookup
Default Server:  ns.mccme.ru
Address:  62.117.108.2

> server 194.67.23.130
Default Server:  ns.mail.ru
Address:  194.67.23.130

> set type=MX
> mail.ru
Server:  ns.mail.ru
Address:  194.67.23.130

mail.ru preference = 10, mail exchanger = mxs.mail.ru
mail.ru nameserver = ns.mail.ru
mail.ru nameserver = ns1.mail.ru
mail.ru nameserver = ns2.mail.ru
mail.ru nameserver = ns4.mail.ru
mail.ru nameserver = ns5.mail.ru
mail.ru nameserver = ns3.mail.ru
mxs.mail.ru     internet address = 194.67.23.20
ns.mail.ru      internet address = 194.67.23.130
ns1.mail.ru     internet address = 194.67.57.103
ns2.mail.ru     internet address = 194.67.57.104
ns4.mail.ru     internet address = 194.67.57.4
ns5.mail.ru     internet address = 194.67.23.232
ns3.mail.ru     internet address = 194.67.23.17
> set type=SOA
> mail.ru
Server:  ns.mail.ru
Address:  194.67.23.130

mail.ru
        origin = ns.mail.ru
        mail addr = hostmaster.mail.ru
        serial = 3209013119
        refresh = 300 (5M)
        retry   = 900 (15M)
        expire  = 172800 (2D)
        minimum ttl = 300 (5M)
mail.ru nameserver = ns.mail.ru
mail.ru nameserver = ns1.mail.ru
mail.ru nameserver = ns2.mail.ru
mail.ru nameserver = ns4.mail.ru
mail.ru nameserver = ns5.mail.ru
mail.ru nameserver = ns3.mail.ru
ns.mail.ru      internet address = 194.67.23.130
ns1.mail.ru     internet address = 194.67.57.103
ns2.mail.ru     internet address = 194.67.57.104
ns4.mail.ru     internet address = 194.67.57.4
ns5.mail.ru     internet address = 194.67.23.232
ns3.mail.ru     internet address = 194.67.23.17
> exit
        

6.6. Определение кто ответственный за зону DNS

Описание.  Кандидат должен уметь выполнить обратный DNS запрос для определения сети, в которой находится машина с данным IP адресом и собрать информацию об этой сети.

Практика. dig(1), whois(1)

Комментарий

6.6.1. Обратное преобразование имён

Обратное преобразование имён, это преобразование IP адреса в имя машины. Для данного преобразования существует специальная PTR запись в файле зоны. Ответственен за эту зону провайдер, выделивший адрес IP в зоне типа C. Зона устроена следующим образом: в корневом домене имеется зона in-addr.arpa. внутри которой делают зоны для адресов класса A, внутри которых зоны для адресов класса B внутри которых зоны для адресов класса C. Когда вы при помощи команды host(1) пытаетесь разрешить IP адрес, он записывается задом наперёд, к нему добавляется справа домен in-addr.arpa. и делается DNS запрос о соответствующем адресе. Для команды dig(1) надо оформить запрос более конкретно:

$ host 194.87.0.50
50.0.87.194.in-addr.arpa domain name pointer www.ru.
$ dig PTR 50.0.87.194.in-addr.arpa

; <<>> DiG 9.3.1 <<>> PTR 50.0.87.194.in-addr.arpa
;; global options:  printcmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 8640
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 3, ADDITIONAL: 4

;; QUESTION SECTION:
;50.0.87.194.in-addr.arpa.  IN  PTR

;; ANSWER SECTION:
50.0.87.194.in-addr.arpa. 85912 IN  PTR www.ru.

;; AUTHORITY SECTION:
87.194.in-addr.arpa.    85912   IN  NS  ns1.demos.net.
87.194.in-addr.arpa.    85912   IN  NS  ns.ripe.net.
87.194.in-addr.arpa.    85912   IN  NS  ns.demos.su.

;; ADDITIONAL SECTION:
ns.ripe.net.        172314  IN  A   193.0.0.193
ns.demos.su.        38415   IN  A   194.87.0.8
ns.demos.su.        38415   IN  A   194.87.0.9
ns1.demos.net.      60316   IN  A   194.58.241.26

;; Query time: 13 msec
;; SERVER: 172.16.0.1#53(172.16.0.1)
;; WHEN: Sun Apr  9 11:09:48 2006
;; MSG SIZE  rcvd: 200

        

6.6.2. whois(1)

Сервис whois(1) предназначен для работы с доменами первого уровня. С его помощью можно узнать кто ответственен за тот или иной домен:

$ whois yandex.ru
% By submitting a query to RIPN's Whois Service
% you agree to abide by the following terms of use:
% http://www.ripn.net/about/servpol.html#3.2 (in Russian)
% http://www.ripn.net/about/en/servpol.html#3.2 (in English).

domain:     YANDEX.RU
type:       CORPORATE
nserver:    ns1.yandex.ru. 213.180.193.1
nserver:    ns2.yandex.ru. 213.180.199.34
nserver:    ns4.yandex.ru. 213.180.202.100
nserver:    ns5.yandex.ru. 213.180.204.1
state:      REGISTERED, DELEGATED
org:        YANDEX, LLC.
phone:      +7 495 9743555
fax-no:     +7 495 9743565
e-mail:     noc@yandex.net
registrar:  RUCENTER-REG-RIPN
created:    1997.09.23
paid-till:  2006.10.01
source:     TC-RIPN


Last updated on 2006.04.09 11:03:15 MSK/MSD

        

Используя данную информацию можно, например, узнать давно ли существует тот или иной интернет-магазин, какие DNS серверы ответствены за его зону. Понимая сегодняшние реалии пространства .ru я не стал бы принимать указанные телефоны близко к сердцу. Хотя, надо признать, что ситуация в домене .ru много лучше, чем в зоне .com. В нашей стране, при регистрации домена на физическое лицо, требуют хотя бы паспорт. Поэтому компетентные органы имеют хоть какой-то шанс найти ответственное лицо.

6.7. Изменение порядка разрешения имён

Описание.  Кандидат BSDA должен уметь определить в каком порядке опрашиваются различные системы при разрешении имён и знать в каком конфигурационном файле это определяется

Практика. ping(8), telnet(1), nsswitch.conf(5), resolv.conf(5), host.conf(5)

Комментарий

6.7.1. nsswitch.conf(5)

По умолчанию имена хостов просматриваются сперва в локальной базе /etc/hosts, затем в распределённой базе DNS. Можно считать, что это и то и другое это одна большая база данных, состоящая из двух источников: локального файла и удалённой системы. За то в каком порядке опрашивать эти источники отвечает системный вызов nsdispatch(3), который конфигурируется при помощи файла nsswitch.conf(5). Диспетчер имён nsdispatch(3) отвечает не только за порядок опроса источников в базе имен хостов (т.е. за работу системного вызова gethostbyname(3)) Но и за работу некоторых других баз (см. ниже). Далее фрагментарно дан перевод к соответствующей странице man(1) выполненный мною.

Файл nsswitch.conf(5) служит для конфигурирования системы nsdispatch(3).

Данный конфигурационный файл управляет процессами разрешения имён в базах данных хостов, пользователей, групп и т.д. Каждая база данных состоит из нескольких источников (локальные файлы, DNS, NIS), а порядок просмотра этих источников задаётся в nsswitch.conf(5).

Каждая запись в nsswitch.conf(5) состоит из имени базы и списка источников разделённых пробелами.

Поле с источниками может включать следующие имена:

files
локальные файлы: /etc/hosts, /etc/passwd и проч.
dns
Система DNS. Базы hosts и networks используют записи класса IN остальные базы используют класс HS (Hesoid)
nis
NIS (YP)
compat
Поддерживает +/- в базах passwd и group. Если такой источник имеется, он дожен быть единственным для данной базы.

Поддерживаются следующие базы данных:

group
getgrent(3)
hosts
gethostbyname(3)
networks
getnetbyname(3)
passwd
getpwent(3)
shells
getusershell(3)
[Замечание]Замечание
Всё сказанное в настоящем разделе верно для FreeBSD, NetBSD и DragonFly BSD, но не для OpenBSD. В OpenBSD файла nsswitch.conf(5) нет. В BSD nsswitch.conf(5) впервые появился в NetBSD, затем перекочевал в FreeBSD и DragonFly BSD.

6.8. Перевод сетевой маски между системами точечно-десятичной, точечно-шестнадцатеричной или CIDR

Описание.  Кандидат BSDA должен знать как устроена адресация IPv4 и как конвертировать адреса и сетевые маски из одного формата в другой.

Комментарий

Кому-то это может показаться странным, но на экзамене CISCO CCNA требуется умение в уме, без помощи калькулятора, переводить десятичные числа в двоичные. Люди могут попытаться возразить: как же так, уж у администратора всегда под рукой есть, не только калькулятор, но целый компьютер! Что тут можно сказать, элементарные навыки устного счёта входят в необходимый багаж знаний каждого жителя современного мегаполиса, а перевод подсетей из одного формата в другой, входит в необходимые культурные навыки каждого администратора. Не уметь в уме перевести маску подсети ***/26 в 255.255.255.192, это всё равно что в театре в носу ковырять, простите.

Однако жить вообще без калькулятора так же глупо, как глупо не уметь обходиться без него. Тем, кому нужен подобный сервис можно порекомендовать порт ipcalc:

$ ipcalc 192.168.0.1/26
Address:   192.168.0.1          11000000.10101000.00000000.00 000001
Netmask:   255.255.255.192 = 26 11111111.11111111.11111111.11 000000
Wildcard:  0.0.0.63             00000000.00000000.00000000.00 111111
=>
Network:   192.168.0.0/26       11000000.10101000.00000000.00 000000
HostMin:   192.168.0.1          11000000.10101000.00000000.00 000001
HostMax:   192.168.0.62         11000000.10101000.00000000.00 111110
Broadcast: 192.168.0.63         11000000.10101000.00000000.00 111111
Hosts/Net: 62                    Class C, Private Internet
        

В данном разделе я опишу что такое маска подсети, формат CIDR, а затем опишу удобные приёмы устного пересчёта десятичных чисел в двоичные.

6.8.1. Что такое маска подсети

При помощи маски подсети система роутинга определяет находится ли данный адрес IP в данной подсети. Для этого используется операция побитового сложения. Маска подсети обязана состоять из некоторого количества единиц идущих подряд и следом за ними нулей. Маска подсети однозначно определяет насколько много адресов может быть в данной сети. Адрес находится в нашей подсети, если после побитового сложения с маской подсети, он дал адрес подсети (или т.н. базовый IP-адрес).

Рассмотрим пример: Пусть у нас есть адреса 192.168.0.1 и 192.168.0.65, какой из них находится в подсети 192.168.0.0 с маской 255.255.255.192 (Или в нотации CIDR 192.168.0.0/26). Побитовое сложение: 1+1=1 (истина и истина = истина), 1+0=0+1=0, 0+0=0.

192.168.0.1     = 11000000.10101000.00000000.00000001
255.255.255.192 = 11111111.11111111.11111111.11000000
сумма           = 11000000.10101000.00000000.00000000 = 192.168.0.0

192.168.0.65    = 11000000.10101000.00000000.01000001
255.255.255.192 = 11111111.11111111.11111111.11000000
сумма           = 11000000.10101000.00000000.01000000 = 192.168.0.64
        

Как видно, адрес 192.168.0.65 при сложении с маской подсети дал другую подсеть, он находится в подсети 192.168.0.64/26.

6.8.2. Маска подсети в формате CIDR

Как видно, маска подсети обязана состоять из некоторого количества единиц и следующих за ними нулей. В десятичной записи, маска подсети должна состоять из 0 и более байтов 255, и следующего за ними байта 0, либо 128 (1000 0000), либо 192 (1100 0000), либо 224, либо 240, либо 248, 252 (1111 1100). Бит 254 невозможен, так как в этом случае не останется адресов ни для одного хоста (в такой сети будет возможно только два адреса, при этом один будет соостветствовать адресу сети, а другой широковещательному адресу).

Таким образом, интересна не сама маска, а её длина. В нотации CIRD указывается сколько бит занимает маска подсети. Например, маска 255.255.255.192 занимает 8+8+8+2 бита и равна 26. Записывают её через дробь с адресом подсети: 192.168.0.0/26. Следующая подсеть с такой же маской — 192.168.0.64/26. Если адрес сети заканчивается на нули, то иногда их не указывают. Ряд приложений может понять запись 192.168/26, дополнив недостающие байты нулями, другие могут и не понять. (И вообще, запись CIDR, понимают далеко не все программы, увы.)

6.8.3. Перевод десятичных чисел в двоичные

Операции устного сложения и вычитания даются человеку легче, чем операции умножения и деления, поэтому не стоит пытаться последовательно делить десятичное число на степени двойки, вычисляя остатки. Лучше сразу вычитать из числа степени двойки. Конечно вы можете избрать любой удобный для вас алгоритм, я делаю это так:

Пусть надо представить в двоичном формате число 170.

Для начала нам понадобится таблица степеней двойки:

2021222324252627
1248163264128

Теперь мы будем последовательно сравнивать наше число со степенями двойки, если число больше либо равно степени, мы записываем единицу, и вычитаем из числа степень двойки, если меньше, записываем ноль и идём дальше:

170>128  ⇒ 1    170-128=42
 42<64   ⇒ 0
 42>32   ⇒ 1      42-32=10
 10<16   ⇒ 0
 10>8    ⇒ 1       10-8=2
  2<4    ⇒ 0  
  2=2    ⇒ 1        2-2=0
  0<1    ⇒ 0

Итого: 170 = 10101010
        

Обратное преобразование делается ещё проще: надо просто сложить те степени двойки, которым соответствуют единицы в двоичном числе.

6.9. Собирать информацию используя IP адрес и маску подсети

Описание:  Зная IP адрес и маску подсети кандидат должен уметь определить адрес подсети, широковещательный адрес, адреса хостов возможные в данной подсети.

Комментарий

Для начала ещё раз сошлёмся на работу утилиты ipcalc:

$ ipcalc 192.168.0.1/26
Address:   192.168.0.1          11000000.10101000.00000000.00 000001
Netmask:   255.255.255.192 = 26 11111111.11111111.11111111.11 000000
Wildcard:  0.0.0.63             00000000.00000000.00000000.00 111111
=>
Network:   192.168.0.0/26       11000000.10101000.00000000.00 000000
HostMin:   192.168.0.1          11000000.10101000.00000000.00 000001
HostMax:   192.168.0.62         11000000.10101000.00000000.00 111110
Broadcast: 192.168.0.63         11000000.10101000.00000000.00 111111
Hosts/Net: 62                    Class C, Private Internet
        

6.9.1. Определение адреса подсети по маске

Эта тема обсуждалась в Раздел 6.8.1, «Что такое маска подсети». Для определения адреса подсети надо побитово сложить маску подсети с IP-адресом:

192.168.0.1     = 11000000.10101000.00000000.00000001
255.255.255.192 = 11111111.11111111.11111111.11000000
сумма           = 11000000.10101000.00000000.00000000 = 192.168.0.0
        

Переводу десятичных чисел в двоичные был посвящён Раздел 6.8.3, «Перевод десятичных чисел в двоичные».

Таким образом, мы вручную вычислили строку, которая в листинге команды ipcalc начиналась со слова Network.

6.9.2. Вычисление диапазона адресов IP и широковещательного адреса

Возьмём адрес подсети и заполним единицами те поля, которым в маске подсети соответствуют нули:

192.168.0.0     = 11000000.10101000.00000000.00000000
255.255.255.192 = 11111111.11111111.11111111.11000000
                  11000000.10101000.00000000.00111111 = 192.168.0.63
        
[Замечание]Замечание
Для того, чтобы удобно в уме перевести число 111111 в десятичную систему, не надо складывать 20+21+22+23+24+25. Это тоже самое, что 26-1.

Таким образом, мы понимаем, что в подсети 192.168.0.0/26 возможны адреса от 192.168.0.0 до 192.168.0.63. При этом два адреса уйдут на адрес сети 192.168.0.0 и широковещательный адрес.

Какой адрес будет широковещательным? Быстрый ответ на этот вопрос — 192.168.0.63. Именно его мы видим в листинге команды ipcalc в строке озаглавленной Broadcast. Именно поэтому мы видим в этом листинге диапазон допустимых адресов машин от 192.168.0.1 до 192.168.0.62. Да, в подавляющем большинстве случаев это так, но тут есть одно лукавство:

Строго говоря, такого явления как широковещательный адрес IP вообще не существует. Широковещательная передача осуществляется на канальном уровне модели OSI. Широковещательный пакет, это пакет, у которого указан MAC-адрес назначения ff:ff:ff:ff:ff:ff. Т.е. аппаратный адрес назначения состоит только из единиц. Только такой пакет будет доставлен коммутаторами (работающими на канальном уровне OSI) ко всем сетевым интерфейсам.

Что же до широковещательного адреса IP, то это такой адрес, которому ваш сетевой интерфейс при маршрутизации (т.е. процессе выбора MAC-адреса назначения) поставит в соответствие широковещательный MAC-адрес. Какой именно IP будет соответствовать широковещательной передаче, это ваше личное дело. В подавляющем большинстве случаев выбирается последний адрес из доступного диапазона, т.е. в нашем случае 192.168.0.63, но это не догма.

[Замечание]Замечание
Конечно, существуют операционные системы, которые не в состоянии назначить нестандартный широковещательный IP, но BSD (да и Linux) не из их числа.

6.10. Понимание теории адресации IPV6

Описание.  Кандидат BSDA должен понимать основы адресации IPv6, включая: компоненты адреса IPv6; поддержку нескольких адресов (link, local, global) на интерфейсе; различные способы записи адреса: запись префикса (aaaa:bbbb::dddd/17) и адресный формат (48 бит на префикс, 16 бит на подсеть и 64 бита на хост). В дополнение кандидат должен понимать процесс автоконфигурирования когда маршрутизатор отсылает префиксы или опрашивается, и как хост добавляет 64 бита, которые получаются из MAC-адреса. Наконец, кандидат должен уметь решать проблемы связи по протоколу IPv6.

Практика. ifconfig(8), ping6(8), rtsol(8)

Комментарий

Вот уже более 10 лет нам пророчат пришествие протокола IPv6 в замен IPv4, а между тем его всё нет как нет. Между тем закрывать на него глаза и дальше становится просто опасно. Во многих операционных системах в той или иной степени поддержка IPv6 уже включена и BSD из их числа. Многие администраторы, к сожалению, закрывают глаза на то, что в их IPv4 сетях уже фактически поднята сеть IPv6, а они об этом даже не подозревают. Закрывают брандмауэром порты по протоколу IPv4, а трафик IPv6 просто не видят. Видимо правильным решением было бы отключение данного протокола на уровне ядра, в случае, если он не поднят в сети. В системе FreeBSD для этого можно закомментировать в ядре опцию

options         INET6                   # IPv6 communications protocols
        

О проблемах безопасности связанных с появлением протокола IPv6 можно прочитать в статье Натальи Мельниковой [url://IPv6-security].

Что касается документации по IPv6, как ни странно, её довольно мало. В основном речь идёт о переводах RFC. Оригинальная документация на английском языке (список, конечно, неполный):

  • [RFC-2460] — собственно протокол IPv6.
  • [RFC-2462] — автоматическая настройка адреса IPv6.
  • [RFC-2463] — протокол ICMPv6.
  • [RFC-3513] — адресация в IPv6.

Что до переводов на русский язык, я могу порекомендовать читателю замечательную статью А.Ю. Семёнова [url://Семёнов-IPv6], которая на 98% представляет собой перевод упомянух RFC. А так же своеобразный HOWTO из FreeBSD-handbook [url://FB-handbook-IPv6-ru], который, в части касающейся документации IPv6 так же является цитатой из упомянутых RFC. Фактически никакой другой документации в настоящий момент в сети нет. (А может и не надо.)

6.10.1. Синтаксис IPv6

6.10.1.1. Правила записи адреса

Адреса в IPv6 настолько длинные, что их запись в привычной десятичной нотации становится весьма неудобной (128 бит = 16 байт). Поэтому их записывают в шестнадцатеричном формате. Но даже и в этом случае адреса оказываются слишком длинными, поэтому придуманы некоторые способы сокращённой записи.

Итак, адреса делят на 8 пар байт символом двоеточия: FEDC:BA98:7654:3210:FEDC:BA98:7654:3210. Лидирующие нули в паре байт можно не записывать, нулевые пары байт можно заменять на ::. Таким образом, следующие три строки обозначают один и тот же адрес: 1080:0000:0000:0000:0008:0800:200C:417A, 1080:0:0:0:8:800:200C:417A, 1080::8:800:200C:417A. Разумеется в адресе может встретиться только один знак :: иначе возникнет неоднозначность.

Допустимо записывать часть адреса в десятичном формате, разделяя десятичные знаки точками: ::FFFF:129.144.52.38. Такая форма удобна в случаях, когда адрес IPv4 является частью адреса IPv6 (см. ниже).

6.10.1.2. Запись префикса

Левая часть адреса IPv6 может являться префиксом сети. В этом случае её длина в битах записывается через дробь, подобно записи CIDR.

Варианты правильного написания префикса 12AB00000000CD3: 12AB:0000:0000:CD30:0000:0000:0000:0000/60, 12AB::CD30:0:0:0:0/60, 12AB:0:0:CD30::/60.

А вот так писать нельзя:

12AB:0:0:CD3/60
Можно опускать нули слева, но не справа.
12AB::CD30/60
Адрес слева от / раскроется в 12AB:0000:0000:0000:0000:000:0000:CD30
12AB::CD3/60
Адрес слева от / раскроется в 12AB:0000:0000:0000:0000:000:0000:0CD3

6.10.2. Типы IPv6 адресов

Адреса IPv6 бывают:

Unicast
предназначенные конкретному интерфейсу.
Anycast
предназначенные некоторому набору хостов. Пакет посланный на адрес anycast будет доставлен только одному хосту — ближайшему с точки зрения маршрутизатора.
Multicast
предназначенные некоторому набору хостов. Пакет посланный на адрес multicast будет доставлен всем хостам из этого набора.

Широковещательных (broadcast) адресов в IPv6 нет, их функции выполняют адреса multicast.

6.10.2.1. Unicast

Тип пакета IPv6 можно определить по префиксу. Вот некоторые префиксы адресов unicast:

FE80::/10 (первые биты 1111111010)

Канальный адрес (link-local unicast).

Предполагается, что у любого интерфейса всегда есть как минимум один IPv6 адрес полученный из его MAC-адреса, либо из EUI-64. EUI-64 это тот же MAC, только между первыми тремя байтами и последними тремя вставлено ещё два байта: FFFE. Так, для интерфейса с MAC-адресом 00:50:22:B0:7F:39 будет определён адрес IPv6 FE80::250:22FF:FEB0:7F39/64. Здесь первые 64 бита являются префиксом сети: FE80::/64, а последние 8 байт получены из аппаратного адреса, всё вместе представляет собой unicast адрес IPv6.

При этом, за кольцевым интерфейсом, у которого, конечно никакого аппаратного адреса не существует, закреплён адрес FE80::1/64

Канальные адреса иногда записывают в форме FE80::%rl0/64 и FE80::%lo0/64, что указывает на то, что последние байты должны быть сконструированы из аппаратного адреса соответствующего интерфейса.

[Замечание]Замечание
Теоретически, данные адреса приватны и не должны выходить за пределы организации. Это, однако, не означает, что MAC-адрес не может «утечь» наружу. Механизм автоконфигурирования включает сложение префикса сети и аппаратного адреса, о чём пишется в статье Натальи Мельниковой [url://IPv6-security]. В некотором смысле, такое свойство протокола нарушает права пользователей в части конфиденциальности.
FEC0::/10 (первые биты 1111111011)

Обычный локальный адрес (site-local unicast).

Этот адрес так же приватный, от канального адреса его отличает то, что он не обязан включать в себя MAC адрес интерфейса.

4000::/3 (первые биты 010)

Провайдерские unicast адреса. Последующие биты — ID регистрации (провайдера), ID провайдера, ID подписчика, Интра подписчика.

ID регистрации — регистратор, который задает провайдерскую часть адреса.

ID провайдера — собственно провайдер.

ID подписчика — часть адреса выдаваемая подписчику провайдером.

Интра подписчика — внутренние адреса, которые находятся в распоряжении подписчика.

8000::/3 (первые биты 100)
Зарезервировано под географические unicast адреса.
::0000:d.d.d.d и ::ff:d.d.d.d
Фактически это адреса IPv4. Первый придуман для того, чтобы в адресном пространтстве IPv6 представить адрес маршрутизатора IPv6 имеющего адрес IPv4 d.d.d.d. Пакет дошедший до этого интерфейса со стороны пространтсва IPv6 будет через туннель IPv4 направлен на следующий маршрутизатор IPv6. Второй адрес используется для предоставления пакета тем маршрутизаторам IPv4, которые не поддерживают IPv6.
::1
Адрес кольцевого интерфейса
::
Несуществующий адрес, вернее адрес означающий отсутствие адреса. Этим адресом подписывается машина до того как она получила настоящий адрес.

6.10.2.2. Anycast

Адрес anycast синтаксически не отличим от unicast. Адреса anycast выделяются из адресного пространства unicast и всё их отличие состоит в том, что один адрес anycast может быть присвоен нескольким маршрутизаторам. Пакет высланный на этот адрес получит ближайший маршрутизатор, где ближайший маршрутизатор определяется по метрике протокола маршрутизации.

Одно из возможных применений адреса anycast — идентификация набора маршрутизаторов провайдера. Префикс адреса anycast фактически указывает на топологическую группу которой принадлежит адрес.

Существует один предопределённый адрес anycast: 111111101[10] префикс_подсети 00..00. Этот адрес соответствует маршрутизатору подсети.

6.10.2.3. Multicast

FF00::/8 (первые биты 11111111)
Мультикаст — аналог широковещательного адреса. Широковещательных (broadcast) адресов в IPv6 нет, они заменены на мультикасты.

6.10.3. Назначение адреса IPv6

Один интерфейс может иметь множество различных адресов IPv6. (Подобно тому, как у интерфейса может быть много адресов IPv4.) Таким образом, интерфейс может одновременно иметь приватный и публичный IPv6 адреса.

Далее следует прямая цитата из [url://Семёнов-IPv6]:

ЭВМ должна распознавать следующие адреса, как обращенные к нему:

  • Её локальный адрес канала для каждого из интерфейсов
  • Выделенные уникаст-адреса
  • Адрес обратной связи
  • Мультикастинг-адрес для обращения ко всем узлам
  • Мультикастинг-адрес активного узла (solicited-node multicast address) для каждого из приписанных ей уникаст и эникастных адресов
  • Мультикаст-адреса всех групп, к которым принадлежит ЭВМ.

Маршрутизатор должен распознавать следующие адреса (as identifying itself):

  • Его локальный адрес канала для каждого из интерфейсов
  • Выделенные уникаст-адреса
  • Адрес обратной связи
  • Эникастные адреса маршрутизатора субсети для каналов, где он имеет интерфейсы.
  • Все другие эникастные адреса, которые использовались при маршрутизации.
  • Мультикастинг-адрес для обращения ко всем узлам
  • Мультикастинг-адрес для обращения ко всем маршрутизаторам
  • Мультикаст-адрес активного узла (solicited-node multicast address) для каждого приписанного ему уникаст и эникастного адресов.
  • Мультикастные адреса всех прочих групп, принадлежащих маршрутизатору.

Приложение должно предопределить только следующие адресные префиксы:

  • Не специфицированный адрес
  • Адрес обратной связи
  • Мультикаст-префикс (FF)
  • Локально используемые префиксы (link-local и site-local)
  • Предопределенные мультикаст-адреса
  • Префиксы, совместимые с IPv4

Приложения должны считать все остальные адреса уникастными, если противоположное не оговорено при конфигурации (например, эникастные адреса).

6.10.4. Автоконфигурирование в IPv6

Одна из целей создателей протокола IPv6 состояла в автоконфигурировании интерфейсов. Система поддерживающая IPv6 должна уметь получать адреса автоматически.

Процесс автоконфигурации включает получение локального канального адреса и проверки его уникальности, определение того, какая информация должна быть автосконфигурирована (адреса, другая информация или и то и другое) и, в случае, если надо автосконфигурировать адрес, через какой механизм он должен быть сконфигурирован: stateless или stateful.

Механизм автоконфигурирования stateless не требует ручного конфигурирования хостов, требует минимального конфигурирования маршрутизаторов и никаких дополнительных серверов. Данный механизм позволяет хосту сгенерировать собственный адрес из информации доступной локально и информации объявленной маршрутизатором. Маршрутизатор объявляет префикс идентифицирующий подсеть, а хост использует уникальный идентификатор интерфейса. Соединяя их вместе хост получает адрес IPv6. В отсутствии маршрутизатора хост может сформировать только локальный канальный адрес. Однако такой адрес даст ему возможность работать с ближайшими машинами находящимися в его подсети.

В случае использования механизма автоконфигурирования stateful, хост получает адрес интерфейса и/или другую информацию с сервера. На серверах должна находиться некая база данных, в которой записано какой адрес с каким хостом проассоциирован. Stateless и stateful механизмы дополняют друг друга. Автоконфигурирование по механизму stateful является частью будущей работы (DHCPv6).

Механизм stateless может использоваться когда точные адреса непринципиальны, stateful, наоборот, когда требуется выдача конкретных адресов. Оба механизма могут использоваться совместно. Администратор может определить какой метод будет использоваться при помощи «Router Advertisement messages» — специальных ICMPv6 сообщений.

Адрес IPv6 выдаётся на фиксированное (возможно бесконечное) время. Каждый адрес имеет ассоциированное с ним время жизни в течение которого он привязан к интерфейсу. Когда время жизни истекает, адрес теряет связь с интерфейсом и может быть присвоен другой точке в Интернете. Дабы не возникало казусов, в течение жизни адрес проходит через две стадии: «preferred» — адрес, которым пользоваться предпочтительно, и «deprecated» — адрес, который вскорости будет утрачен. Новые соединения должны, насколько это возможно, использовать адрес в состоянии «preferred». Адрес «deprecated» может использоваться только приложениями, которые уже использовали его и не могут запросто переключиться на новый адрес.

Чтобы убедиться, что все сконфигурированные адреса уникальны, до присвоения адреса используется специальный механизм Duplicate Address Detection.

Маршрутизаторы должны конфигурироваться несколько иным способом, но это не мешает им иметь локальный канальный адрес полученный аналогичным образом.

6.10.5. Программы для конфигурирования IPv6 в BSD

Настройка интерфейсов через команду ifconfig(8) никаких принципиальных отличий от IPv4 не имеет. За информацией о работе этой программы можно обратиться к Раздел 6.1, «Определение существующих установок TCP/IP» и Раздел 6.2, «Установка параметров TCP/IP».

Утилита ping6(8) используется вместо ping(8) в протоколе IPv6. Аналагично для выяснения маршрута можно применять утилиту traceroute6(8).

Утилита rtsol(8) выполняет «Router Solicition» запросы, пытаясь обнаружить доступный IPv6 маршрутизатор, чтобы получить от него в пакете «Router Advertisement» префикс сети и сформировать адрес. Эта же утилита, под именем rtsold(8) может работать в режиме демона. Утилита не предназначена для работы на маршрутизаторах — только на хостах.

6.11. Демонстрация основных навыков работы с утилитой tcpdump(1)

Описание.  По данному выводу команды tcpdump(1) кандидат BSDA должен уметь дать ответ на основные вопросы связанные со связью по сети. Для этого кандидат должен знать обычные номера портов для распространённых TCP и UDP сервисов, разницу между TCP/IP сервером и клиентом и о «тройном рукопожатии».

Практика. tcpdump(1)

Комментарий

В Приложение B, Некоторые сведения о стеке протоколов TCP/IP рассказано многое о функционировании протоколов стека TCP/IP. В частности о процедуре открытия соединения TCP (процедуре «тройного рукопожатия») рассказано в Раздел B.1.4.3.2, «Открытие соединения TCP, тройное рукопожатие». О том какие номера портов каким протоколам соответствуют можно справиться в файле /etc/services.

6.11.1. Работа с программой tcpdump(1)

Утилита tcpdump(1) отностится к числу так называемых «снифферов» — программ предназначенных для перехвата сетевого трафика. Одним словом, tcpdump(1) предназначен для подслушивания. С одной стороны, это одно из самых мощных средств диагностики и администратор без tcpdump(1) будет лишён глаз и ушей, с другой стороны, сама возможность применения этой программы потенциально опасна.

tcpdump(1) не единственный сниффер, которым может пользоваться администратор. Кроме tcpdump(1). есть ещё замечательная программа wireshark(1) (более известная как ethereal) — сниффер с графическим интерфейсом, который может обрабатывать дампы сделаные программой tcpdump(1) и другие. Этот сниффер будет описан в Раздел 6.11.2, «Графический сниффер Wireshark/Ethereal/tEhereal». Описание работы tcpdump и ethereal можно также найти в работах Николая Малых: [url://Malyh-tcpdump-2005], [url://Malyh-ethereal-2005]

tcpdump(1) работает при помощи интерфейса bpf(4) (Berkeley Packet Filter). Если поддержку этого устройства отключить, сниффинг в BSD окажется невозможен.

[Замечание]Замечание
Права на запуск программы tcpdump(1) определяются правами доступа к устройсву bpf(4) (/dev/bpf0). Эти права можно регулировать через devfs(8). Если вы предоставляете, например, группе operator права на чтение из этого устройства, то это значит, что все члены этой группы смогут перехватывать любой трафик, в том числе трафик суперпользователя.

Если программа tcpdump(1) вызвана для прослушивания некоторого интерфейса, она переводит его в «promiscuous mode» — «неразборчивый режим». В этом режиме интерфейс ловит вообще все пакеты, которые до него добрались, а не только пакеты адресованные непосредственно ему. Таким образом, если сеть собрана не на коммураторах (switch'ах), а на репитерах (hub'ах), то tcpdump(1) позволит перехватить трафик между посторонними машинами, т.е. подслушать разговор двух сторонних машин. Сказанное не означает, что перехват трафика невозможен в сети собранной на коммутаторах (подробно об этом мы говорим в Раздел B.1.2, «Канальный уровень OSI»). Впрочем, интерфейс можно и не переводить в promiscous mode, если передать программе аргумент -p.

tcpdump(1) — утилита с интерфейсом командной строки. Несмотря на повсеместную распространённость (существуют даже порты под Windows) эта утилита не входит в стандарт POSIX и может отсутствовать или присутствовать, но не работать по причине указанной в предыдущих абзацах. Если вы являетесь сторонником графического интерфейса, вы можете найти и альтернативные программы в системе портов, например ethereal(1). Однако все они будут работать через bpf(4) (или не будут работать, если вы его исключите из ядра). Эти программы могут предоставлять больше удобств, но вряд ли окажутся более функциональными.

Итак, опции tcpdump(1) можно разделить на несколько типов:

Выбор объекта
Какой интерфейс прослушивать, читать ли данные из файла, сохранять ли их в файл.
Опции форматирования
В каком виде представить дату, выводить ли шестнадцатеричный дамп пакета и т.п.
Прочие опции
Объём захватываемой информации, привилегии, буферизация, запись в файлы в стиле logrotate и вращение записанных файлов, и др.
Условия
Т.е. какие пакеты перехватывать: можно перехватывать только пинги, или только ARP запросы, или только почтовый трафик. Например, если вы зашли по ssh(1) с машины A на машину B и изучаете на ней работу сети командой tcpdump(1) разумно исключить из рассмотрения трафик между машиной A и 22-м портом машины B.

6.11.1.1. Выбор объекта

ОпцииОписание
-i interface Какой интерфейс должен прослушиваться программой.
-w file В норме отчёт программы tcpdump(1) выводится на терминал в режиме реального времени, однако можно попросить при помощи опции -w записывать всю информацию в файл в бинарном виде, т.е. сделать dump того, что происходит на сетевом интерфейсе. В последствии эту информацию можно заново проанализировать при помощи опции -r.
-r file Эта опция применяется вместо -i и служит для того, чтобы прочитать данные из файла. Файл в бинарном формате можно создать заранее при помощи опции -w. Кроме того, есть и другие программы, которые создают файлы в формате бинарного файла tcpdump(1), например в этом формате сохраняет журнальный файл брандмауэр pf(4).
-D Перечислить доступные интерфейсы (которые можно прослушивать при помощи опции -i).
# tcpdump -D
1.rl0
2.pflog0 1
3.rl1
4.lo0
          
1 Интерфейс pflog принадлежит пакетному фильтру pf(4). (Это брандмауэр OpenBSD, который так же доступен в FreeBSD, см. Приложение C, Пакетный фильтр OpenBSD — pf(4)) Данный брандмауэр позволяет читать журнальный файл в режиме реального времени, для этого можно воспользоваться программой tcpdump(1) нацелив её на интерфейс pflog0. Сам журнальный файл ведётся в бинарном формате так, чтобы его можно было прочитать при помощи tcpdump(1) с опцией -r

6.11.1.2. Форматирование вывода

ОпцииОписание
-q Вывод информации в краткой форме. Одно из «неудобств» программы tcpdump(1) состоит в том, что она очень информативна. Из-за этого информация о перехватываемых сообщениях не влезает в строку в терминале. Данная опция призвана разрешить эту проблему.
-A
-x
-xx
-X
-XX
Эти опции включают вывод содержимого пакета. Опция -A — в формате ASCII, -x — в шестнадцатеричном виде и -X одновременно и в ASCII и в шестнадцатеричном виде. К сожалению, я ещё ни разу не видел чтобы опция -A работала. На протестированных мною версиях она была эквивалентна опции -x. Двухбуквенные опции делают то же, что и их однобуквенные аналоги, но не отбрасывают заголовки канального уровня. Для просмотра содержимого пакетов может быть так же полезна опция -s (см. далее).
-v
-vv
-vvv
Verbouse — подробный вывод информации о заголовке пакета. Чем больше букв v тем подробнее вывод.
-t
-tt
-ttt
-tttt
Разный формат вывода даты: 1) не выводит информации о времени, 2) время выводится в секундах от начала UNIX эры, 3) выводится информация о том, сколько прошло микросекунд после предыдущей строки, 4) обычный формат (час:мин:сек.микросек), но спереди добавлена текущая дата (год-месяц-число).
-f
-n
-N
-f использует числовые IP адреса вместо символьных. -n ещё строже: не только адреса, но и номера протоколов выводятся в числовом виде. Опцию -f разработчики рекомендуют для борьбы с багами в NIS серверах SUN. Считается, что они могут виснуть при попытке разрешить нелокальный адрес. Опция -N заставляет вместо полного доменного имени писать только имя хоста. Т.е. вместо www.ru просто www.
-e Выводится информация о заголовках канального уровня (MAC-адреса).

Для примера мы запустим ping(1) и будем при помощи программы tcpdump(1) ловить пары ICMP пакетов. Для этого нам понадобится опция -c обрывающая пинг после получения заданного количества пакетов и мы используем условие icmp, которое заставит tcpdump(1) отчитываться только о пакетах принадлежащих протоколу ICMP.

#tcpdump -i rl0 -c2 icmp
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on rl0, link-type EN10MB (Ethernet), capture size 96 bytes
15:51:48.309703 IP 192.168.25.158 > mccme.ru: ICMP echo request, id 64479, seq 63, length 64
15:51:48.310409 IP mccme.ru > 192.168.25.158: ICMP echo reply, id 64479, seq 63, length 64
2 packets captured
30 packets received by filter
0 packets dropped by kernel

#tcpdump -i rl0 -c2 -t icmp
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on rl0, link-type EN10MB (Ethernet), capture size 96 bytes
IP 192.168.25.158 > mccme.ru: ICMP echo request, id 64479, seq 135, length 64
IP mccme.ru > 192.168.25.158: ICMP echo reply, id 64479, seq 135, length 64
2 packets captured
10 packets received by filter
0 packets dropped by kernel

#tcpdump -i rl0 -c2 -t -vv icmp
tcpdump: listening on rl0, link-type EN10MB (Ethernet), capture size 96 bytes
IP (tos 0x0, ttl  64, id 13694, offset 0, flags [none], proto: ICMP (1), length: 84) 192.168.25.158 > mccme.ru: ICMP echo request, id 64479, seq 217, length 64
IP (tos 0x0, ttl  63, id 40953, offset 0, flags [none], proto: ICMP (1), length: 84) mccme.ru > 192.168.25.158: ICMP echo reply, id 64479, seq 217, length 64
2 packets captured
8 packets received by filter
0 packets dropped by kernel

#tcpdump -i rl0 -c2 -t -e -vv icmp
tcpdump: listening on rl0, link-type EN10MB (Ethernet), capture size 96 bytes
00:50:22:b0:7f:39 (oui Unknown) > 00:10:e0:00:e9:cd (oui Unknown), ethertype IPv4 (0x0800), length 98: (tos 0x0, ttl  64, id 19710, offset 0, flags [none], proto: ICMP (1), length: 84) 192.168.25.158 > mccme.ru: ICMP echo request, id 64479, seq 5499, length 64
00:10:e0:00:e9:cd (oui Unknown) > 00:50:22:b0:7f:39 (oui Unknown), ethertype IPv4 (0x0800), length 98: (tos 0x0, ttl  63, id 46235, offset 0, flags [none], proto: ICMP (1), length: 84) mccme.ru > 192.168.25.158: ICMP echo reply, id 64479, seq 5499, length 64
2 packets captured
13 packets received by filter
0 packets dropped by kernel

#tcpdump -i rl0 -c2 -t -X -vv icmp
tcpdump: listening on rl0, link-type EN10MB (Ethernet), capture size 96 bytes
IP (tos 0x0, ttl  64, id 17657, offset 0, flags [none], proto: ICMP (1), length: 84) 192.168.25.158 > mccme.ru: ICMP echo request, id 64479, seq 3514, length 64
        0x0000:  4500 0054 44f9 0000 4001 b0ed c0a8 199e  E..TD...@....... 1
        0x0010:  3e75 6c07 0800 a34d fbdf 0dba 447e e252  >ul....M....D~.R 2
        0x0020:  000d 3937 0809 0a0b 0c0d 0e0f 1011 1213  ..97............
        0x0030:  1415 1617 1819 1a1b 1c1d 1e1f 2021 2223  .............!"#
        0x0040:  2425 2627 2829 2a2b 2c2d 2e2f 3031 3233  $%&'()*+,-./0123
        0x0050:  3435                                     45
IP (tos 0x0, ttl  63, id 44250, offset 0, flags [none], proto: ICMP (1), length: 84) mccme.ru > 192.168.25.158: ICMP echo reply, id 64479, seq 3514, length 64
        0x0000:  4500 0054 acda 0000 3f01 4a0c 3e75 6c07  E..T....?.J.>ul. 3
        0x0010:  c0a8 199e 0000 ab4d fbdf 0dba 447e e252  .......M....D~.R
        0x0020:  000d 3937 0809 0a0b 0c0d 0e0f 1011 1213  ..97............
        0x0030:  1415 1617 1819 1a1b 1c1d 1e1f 2021 2223  .............!"#
        0x0040:  2425 2627 2829 2a2b 2c2d 2e2f 3031 3233  $%&'()*+,-./0123
        0x0050:  3435                                     45
2 packets captured
7 packets received by filter
0 packets dropped by kernel
          
1

Здесь приведён шестнадцатеричный dump пакета IP. Начинается он с заголовка IP:

4500
4 и 5 это соответственно номер версии протокола IP (IPv4) и IHL — длина заголовка (5 32-х разрядных машинных слов = 20 байт). 00 — поле TOS (Type of service).
0054
Общая длина в байтах в данном случае 84 байта. (54 это конечно шестнадцатеричное число). В нашей распечатке налицо 82 байта, куда провалились ещё два, не знаю.
44f9
Идентификатор пакета (см. число 17657 в расшифровке строкой выше).
0000
Флаги и смещение фрагмента.
4001
40 это TTL (64 в десятичной системе). 01  — номер протокола. Номера протоколов транспортного уровня можно посмотреть в файле /etc/protocols. 1 это ICMP, 6 — TCP, 17 — UDP.
b0ed
Контрольная сумма заголовка.
c0a8 199e
IP адрес источника 192.168.25.158
2
3e75 6c07
IP адрес назначения 62.117.108.7

На этом закончились 20 байт заголовка IP, теперь пошёл пакет ICMP

0800
08 это тип сообщения ICMP (echo request), 00 — код.
3 Легко видеть, что адреса источника и назначения поменялись местами, а тип ICMP пакета изменлся с 08 на 00, (с echo request на echo reply).

6.11.1.3. Прочее

ОпцииОписание
-l Сделать буферизацию построчной. Это полезно, если вы перенаправляете вывод tcpdump(1) в pipe, например направляете его на вход команде tee(1) или awk(1). (См Раздел 7.1, «Перенаправление вывода и использование tee(1)»).
-c count Выйти из программы после получения count пакетов.
-C size Если выбрана опция -w файл не должен превысить размера size. Если объём оказывается больше, то запись производится в другой файл, имя которого определяется путём дописывания номера к имени файла. size задаётся в миллионах байт.
-W num Используется одновременно с -C. Ограничивает количество файлов числом num.
-F file Условие (см следующий раздел) читать не из командной строки, а из файла.
-s size Захватывать size байт от каждого пакета. По умолчанию перехватываются только первые 96 байт, это существенно уменьшает размер файла, котрый записывает программа. В большинстве случаев первых 96 байт достаточно для прояснения ситуации, однако, если вы хотите именно перехватить трафик целиком, т.е. заниматься сниффингом, и хотите использовать опции -x или -X, вам стоит выставить size равным MTU.
-p Отключить promiscous mode
-Z user После запуска сделать владельцем процесса пользователя user. В качестве группы будет назначена основная группа, в которую входит user.

6.11.1.4. Условия

Условия определяют то, какие пакеты будут перехвачены. Если не указано никаких условий, будут перехвачены все пакеты, если условия указаны, то только те пакеты, для которых это условие истинно.

Условие состоит из некоторого количества примитивов. Примитив состоит из идентификатора (числа или имени) перед которым идёт оператор одного из трёх типов:

тип
чем является идентификатор? Допустимые значения: host, net, port, portrange. Например, возможны следующие примитивы: host somehost, net 128.3, port 20, portrange 6000-6008
направление
куда относительно идентификатора направлен пакет? Возможные направления: src, dst, src or dst, src and dst. Например: src somehost, dst net 128.3, src or dst port ssh. Если направление не указано, подразумевается src or dst.
протокол
ограничивает пакеты некоторым протоколом. Возможные протоколы: ether, fddi, tr, wlan, ip, ip6, arp, rarp, decnet, lat, sca, moprc, mopdl, iso, esis, isis, icmp, icmp6, tcp и udp. Например: ether src somehost, arp net 128.3, tcp port 21, udp portrange 7000-7009. Некоторые из этих протоколов являются синонимами, см. страницу man(1). Если протокол не указан подразумеваются все пригодные протоколы. Например: src somehost эквивалентно (ip or arp or rarp) src somehost (За исключением того, что синтаксис последнего выражения негоден.) port 53 означает (tcp or udp) port 53.

Кроме того, есть примитивы, за которыми не следует шаблона: gateway, broadcast, less, greater. Можно строить сложные условия объединяя примитивы при помощи следующих операторов: and, or, not.

Допустимые примитивы:

dst host xxx
Истина, если пакет направлен хосту xxx
src host xxx
Истина, если пакет отправлен хостом xxx
host xxx
Истина, если пакет отправлен хостом xxx или предназначен хосту xxx. Перед перечисленными примитивами могут быть упомянуты протоколы ip, ip6, arp, rarp. ip host xxx эквивалентно ether proto \ip and host xxx. Замечание: «ip» — ключевое слово, поэтому мы должны защитить его обратным слешем (а в shell'е двумя бекслешами).
ether dst host xxx
Истина, если пакет предназначен хосту с канальным адресом xxx (т.е. MAC адрес xxx).
ether src host xxx
аналогично, но в обратную сторону
ether host xxx
Истина, если MAC адрес назначения или MAC адрес источника xxx.
gateway xxx
Истина, если пакет использует xxx в качестве шлюза. Т.е. если MAC адрес источника или назначения соответствует xxx, но ни IP адрес источника ни IP адрес назначения не являются xxx. xxx должен быть именем, и разрешаться машиной как в IP так и в MAC (возможно с использованием файла /etc/ethers). Эквивалентная конструкция ether host xx1 and not host xxx2, где xxx1 это аппаратный адрес хоста xxx, а xxx2 — IP адрес xxx.
dst net xxx
Истина, если IP адрес назначения принадлежит сети xxx
src host xxx
Истина, если IP адрес источника принадлежит сети xxx
net xxx
Истина если один из адресов (источника или назначения) принадлежит сети xxx.
net xxx mask yyy
То же, но позволяет задавать CIDR сети, т.е. сети не по классам A, B, C, а по безклассовой системе.
net xxx/len
То же.
dst port xxx
Порт назначения xxx. Работает с пакетами ip/tcp, ip/udp, ip6/tcp и ip6/udp. xxx можно задать числом, а можно символьно, в этом случае номер порта будет взят из файла /etc/services.
src port xxx
порт источника xxx
port xxx
один из портов (назначения или источника) xxx
dst portrange xxx-yyy
Истина, если порт назначения лежит в диапазоне между xxx yyy. xxx и yyy можно задавать как численно, так и по имени.
src portrange xxx-yyy
Аналогично
portrange xxx-yyy
Аналогично
less xxx
Истина, если размер пакета меньше xxx
greater
Истина, если размер пакета больше xxx
ip proto xxx
Истина, если пакет принадлежит протоколу xxx. Протокол может быть задан по номеру или по имени. Допустимы следующие имена: icmp, icmp6, igmp, igrp, pim, ah, esp, vrrp, udp, tcp. Замечание: идентификаторы tcp, udp и icmp являются ключевыми словами и должны защищаться обратным слешем (а в shell'е двумя бекслешами).
ip6 proto xxx
Истина, если пакет IPv6 принадлежит протоколу xxx.
ip6 protochain xxx
Истина, если пакет IPv6 содержит заголовок протокола xxx в своём заголовке. Например ip6 protochain 6 соответствует пакет IPv6 с заголовком TCP. Пакет может содержать, например, аутентификационный заголовок, маршрутизационный заголовок или дополнительный hop-by-hop заголовок.
ip protochain xxx
То же, но для IPv4
ether broadcast
Истина, если данный пакет отправлен на широковещательный канальный адрес.
ip broadcast
Истина, если пакет отправлен на широковещательный IP адрес
ether multicast
Истина, если пакет направлен на мультикастный канальный адрес. Ключевое слово ether можно опустить. Данный примитив эквивалентен ether[0] & 1 != 0.
ip multicast
Истина, если пакет направлен на мультикастный IPv4 адрес
ip6 multicast
Истина, если пакет направлен на мультикастный IPv6 адрес
ether proto xxx

Истина, если пакет принадлежит канальному протоколу xxx. Протокол может быть передан по номеру или символьно. Допустимы следующие имена: ip, ip6, arp, rarp, atalk, aarp, decnet, sca, lat, mopdl, moprc, iso, stp, ipx, netbeui. Замечание: некоторые из этих идентификаторов — ключевые слова и должны быть экранированы обратным слешем (а в shell'е двумя бекслешами).

В случае FDDI надо писать fddi proto arp, Token ring — tr proto arp, беспроводные сети IEEE 802.11 — wlan proto arp. Впрочем, fddi, wlan, tr и ether ведут себя как синонимы.

decnet src xxx, decnet dst xxx, decnet host xxx
DECNET доспупна на соответствующим образом сконфигурированной системе ULTRIX.
ip, ip6, arp, rarp, atalk, aarp, decnet, iso, stp, ipx
Аббревиатуры для выражения ether proto p, где p — один из перечисленных протоколов.
lat, moprc, mopdl
То же, но верно следующее замечание: tcpdump(1) пока не умеет разбирать данные протоколы (т.е. умеет только детектировать их).
vlan [xxx]
Естина, если пакет является пакетом IEEE 802.1Q VLAN. Если указан [xxx], проверяется так же и идентификатор VLAN. Первое ключевое слово vlan приводит к расшифровке пакета. Таким образом, условию vlan 100 && vlan 200 соответствуеют пакеты vlan 200 упакованные в пакеты vlan 100. Условию vlan && vlan 300 && ip соответствуют пакеты IPv4 упакованные в vlan 300, которые упакованы в vlan верхнего уровня.
tcp, udp, icmp
Аббревиатуры для выражения ip proto p or ip6 proto p, где p — один из перечисленных протоколов.
iso proto xxx
Истина, если пакет является пакетом OSI протокола xxx. Протокол может быть задан номером или по имени. Допустимы следующие имена: clnp, esis, isis.
clnp, esis, isis
Аббревиатуры для выражения iso proto p, где p — один из перечисленных протоколов.
l1, l2, iih, lsp, snp, csnp, psnp
Аббревиатуры для IS-IS PDU.
vpi xxx, vci xxx, lane, llc, oamf4s, oamf4e, oamf4, oam, metac, bcc, sc, ilmic, connectmsg, metaconnect
Эти правила относятся к пакетам ATM для SunATM Solaris. Поскольку я не являюсь специалистом в данной системе, я не считаю возможным переводить на русский эту часть руководства.

Программа tcpdump(1), как отмечалось выше, может использоваться пакетным фильтром (PF) OpenBSD для обработки журнальных файлов (при помощи опции -r), а так же для чтения журнала в режиме реального времени при помощи опции -i через устройство pflog (см. Раздел C.2.3.1, «Журналирование в пакетном фильтре»). Пакетный фильтр OpenBSD работает не только в OpenBSD, но и в FreeBSD. В последней системе он сперва появился как порт, а затем был добавлен в ядро начиная с версии FreeBSD 5.2.1. Теперь он портируется в ядро FreeBSD при каждом релизе.

Пакетный фильтр помещает в пакеты, которые он направляет в журнал специфическую информацию, о том, какое правило отправило пакет в журнал, какие действия предприняты с этим пакетом и проч. Для работы с этой информацией tcpdump(1) имеет специальные примитивы. Перечисленные ниже примитивы пригодны только для работы с журналом PF.

ifname xxx
Истина, если пакет прошёл через заданный интерфейс.
on xxx
Синоним ifname
rnr xxx
Истина, если пакет соответствует правилу номер xxx.
rulenum xxx
Синоним rnr
reason xxx
Истина, если пакет попал в журнал по соответствуюей причине (reason). Эта «причина» добавляется к пакету брандмауэром. Можно указывать следующие коды: match, bad-offset, fragment, short, normalize, memory.
rset xxx
Истина, если пакет попал в журнал так как соответствовал правилу из набора (anchor) с именем xxx (см. Раздел C.2.2.3, «Anchors»).
ruleset xxx
Синоним rset
srnr xxx
Истина если пакет попал в журнал от того, что соответствовал правилу номер xxx из поднабора правил (см. Раздел C.2.2.3, «Anchors»)
subrulenum xxx
Синоним srnr
action xxx
Истина, если пакетный фильтр проделал с пакетом действие xxx. Допустимые значения pass и block.

Дополнительный примитив — арифметический:

expr relop expr

Истина, если выполнено данное отношение, где relop может быть: >, <, >=, <=, =, !=, а expr — арифметическое выражение составленное из целых чисел (стандартный синтаксис языка C) и бинарных операторов: +, -, *, /, &, |, <<, >>, а так же оператора длины и специальных операторов доступа к данным пакета. Замечание: все сравнения беззнаковые, т.е. 0x80000000 и 0xffffffff больше нуля.

Для доступа к данным пакета используйте следующий синтаксис: proto [ expr : size ], proto может быть: ether, fddi, tr, wlan, ppp, slip, link, ip, arp, rarp, tcp, udp, icmp, ip6, radio и определяет уровень протокола, для операции взятия индекса. (ether, fddi, wlan, tr, ppp, slip и link ссылаются на канальный уровень, radio ссылается на radio header добавляемый в некоторые пакеты 802.11). Замечание: tcp, udp и другие протоколы верхнего уровня применимы пока только к IPv4, но не к IPv6, что должно быть исправлено в будущем.

expr — означает смещение в байтах для протокола данного уровня. size необязательная величина, означает количество захватываемых байт. По умолчанию size равен единице, можно подставить два три или четыре. Оператор len возвращает длину пакета в байтах.

Для понимания приведённых ниже примеров объясним, что делает бинарный оператор &. & — это оператор бинарного сложения. Пусть надо сложить бинарно числа 11 и 13. Для этого мы запишем их в бинарном виде, и сложим побитово. При этом сумма есть результат логической операции, в которой 0 это ложь, а 1 — истина. Т.е. 0+0=0, 0+1=1+0=0, 1+1=1.

13=1101 
11=1011 
 1001=9

Таким образом, 11&13=9.

Примеры: выражение ether[0] & 1 != 0 захватывает весь мультикастный трафик (для него есть так же примитив multicast, см выше). Пояснение: здесь проверяется на чётность первый байт заголовка канального уровня. При этом заголовок канального уровня начинается с 6 байт канального адреса назначения. Таким образом, данное условие выясняет равен ли единице восьмой бит 48-битного MAC адреса.

Выражение ip[0] & 0xf != 5 захватывает все пакеты IPv4 с опциями. Пояснение: здесь берётся первый байт пакета IPv4 и складывается с числом 0xf (в десятичной системе 15, в двоичной 1111). Если в результате сложения получится число 5 (101), то значит первый байт был xxxx1010 т.е. вторая половина первого байта была равна 5. А как мы видели в листинге выше, вторая половина первого байта отвечает за длину IPv4 заголовка в 32-х разрядных словах. Если длина заголовка 5 32-битных слов, то значит никаких дополнительных опций в нём нет, так как это наименьшая возможная длина заголовка IP. А если результат операции не равен 5, то значит он больше пяти и в нём есть какие-то дополнительные опции.

Выражение ip[6:2] & 0x1fff = 0 соответствует нефрагментированным пакетам IPv4, либо нулевому фрагменту фрагментированного пакета. Пояснение: здесь берётся два байта пакета IPv4: седьмой и восьмой (отсчёт идёт с нуля, таким образом, ip[6] это седьмой байт) и складываются с числом 0x1fff (1111111111111), таким образом из них «вырезаются» последние 13 бит, отвечающие за номер фрагмента.

Некоторые «смещения» предопределены и имеют названия. например: icmptype, icmpcode, tcpflags. Так же предопределены и значения: icmp-echoreply, icmp-unreach, icmp-sourcequench, icmp-redirect, icmp-echo, icmp-routeradvert, icmp-routersolicit, icmp-timxceed, icmp-paramprob, icmp-tstamp, icmp-tstampreply, icmp-ireq, icmp-ireqreply, icmp-maskreq, icmp-maskreqreply, а так же для флагов TCP: tcp-fin, tcp-syn, tcp-rst, tcp-push, tcp-ack, tcp-urg.

Примитивы могут объединяться при помощи следующих операторов:

! или not
Отрицание. Имеет наибольший приоритет
|| или or
Альтернатива
&& или and
Объединение

Кроме того, для указания приоритета можно использовать круглые скобки.

Если идентификатор отсутствует, подразумевается последний использованный. Так not host vs and ace эквивалентно not host vs and host ace.

6.11.1.5. Примеры

Все пакеты относящиеся к трафику с машиной sundown:

# tcpdump host sundown
          

Трафик между машиной helios и машинами hot или ace:

# tcpdump host helios and \( hot or ace \)
          

Все пакеты IP идущие между ace и любым хостом кроме helios:

# tcpdump ip host ace and not helios
          

Весь ftp трафик идущий через шлюз snup:

# tcpdump 'gateway snup and (port ftp or ftp-data)'
          

Весь трафик, который не направлен в нашу локальную сеть и не выходит из неё, (т.е. транзитный трафик).

# tcpdump ip and not net localnet
          

Начальные и конечные пакеты TCP (т.е. пакеты с флагами SYN и FIN) соединений вызванных не нашими машинами:

# tcpdump 'tcp[tcpflags] & (tcp-syn|tcp-fin) != 0 and not src and dst net localnet'
          

Все IPv4 пакеты протокола HTTP направленные на 80 порт или с 80-го порта. Причём только пакеты содержащие данные, не захватывая пакеты SYN, FIN или пакеты в которых есть только флаг ACK. (Такое выражение поможет перехватить веб трафик).

# tcpdump 'tcp port 80 and (((ip[2:2] - ((ip[0]&0xf)<<2)) - ((tcp[12]&0xf0)>>2)) != 0)'
          

Пояснение:

Бинарные операторы << и >> — это операторы сдвига.

Пример в двоичной системеТо же в десятичной системе
1010>>1=010110>>1=5
1010>>2=001010>>2=2
1011<<3=101100011<<3=88

ip[2:2] это третий и четвёртый байт заголовка IP, т.е. длина всего пакета в байтах.

Далее, выражение ip[0]&0xf берёт первый байт заголовка IP и вырезает из него последние 4 бита (т.к. 0xf=00001111), в этих битах содержится длина заголовка IP. Полученную величину сдвигают влево на два бита, так, как длина заголовка IP задаётся в 32-битных словах, а не в байтах. Таким образом длина заголовка IP переведена в байты.

Наконец, tcp[12] берёт 13-й байт заголовка TCP. Первые его 4 бита соответствуют длине заголовка. Их вырезают выражением tcp[12]&0xf0 (т.к. 0xf0=1111000). Полученное выражение сдвигают вправо на два бита и получается длина заголовка TCP в байтах.

Из длины пакета вычитают длину заголовка IP и длину заголовка TCP, таким образом в этом правиле осуществляется проверка на то, является ли пакет пустым. А по флагам никаких проверок то и нет!

Следующее выражение соответствует пакетам длиннее 576 байт посылаемым через шлюз snup:

# tcpdump 'gateway snup and ip[2:2] > 576'
          

Следующий пример: выражение соответствует пакетам посылаемым на широковещательный или мультикастный IP, но не рассылаемым через широковещательный или мультикастный Ethernet адрес:

# tcpdump 'ether[0] & 1 = 0 and ip[16] >= 224'
          

Здесь выражение ether[0]&1 вычисляет равен ли нулю восьмой бит MAC адреса назначения (что означает, что адрес не широковещательный и не мультикастный). А выражение ip[16] оперирует с первым байтом адреса назначения.

Следующий пример: выражение соответствует пакетам ICMP если это не «пинги», т.е. не echo-request и не echo-reply:

# tcpdump 'icmp[icmptype] != icmp-echo and icmp[icmptype] != icmp-echoreply'
# tcpdump 'icmp[0] != 8 and icmp[0] != 0'
          

Приведённые команды эквивалентны.

6.11.2. Графический сниффер Wireshark/Ethereal/tEhereal

Описание работы wireshark(1) выходит за рамки данного труда, однако не упомянуть о них в связи с tcpdump(1) невозможно. wireshark — графический анализатор протоколов. С его помощью удобно разбирать сделанные при помощи tcpdump(1) и других анализаторов файлы, кроме того она сама позволяет прослушивать сеть и делать dump'ы в формате программы tcpdump(1).

У программы wireshark(1) несколько имён:

wireshark
Новое имя программы
ethereal
Старое имя программы. Название программы сменилось в 2006 году по лицензионным причинам. Так или иначе, программа широко известна под старым именем и информацию о ней следует искать в первую очередь под старым именем.
tethereal
Текстовый вариант программы. В этом виде её функционал сравним с функционалом tcpdump(1).

Пока данный раздел не написан я просто приведу скриншот программы wireshark(1), в которой открыт файл pflog — журнальный файл пакетного фильтра OpenBSD. (См. Приложение C, Пакетный фильтр OpenBSD — pf(4)). Дополнительную информацию об wireshark вы можете найти в работе Николая Малых: [url://Malyh-ethereal-2005].

Screenshot программы ethereal
В программе wireshark(1) (старое имя ethereal) открыт журнальный файл пакетного фильтра OpenBSD, который ведётся в формате tcpdump(1).

6.11.3. Анализатор tcpdstat

Существует не мало разнообразных анализаторов, которые выводят разнообразную статистику из файлов в формате libpcap (формат программы tcpdump(1)). Для примера приведу программу tcpdstat. Программа устанавливается из порта net/tcpdstat.

Вот пример отчёта, который генерирует данная программа:

# tcpdump -i rl1 -w dump
tcpdump: listening on rl1, link-type EN10MB (Ethernet), capture size 96 bytes
^C1458 packets captured
1461 packets received by filter
0 packets dropped by kernel
$ tcpdstat dump

DumpFile:  dump
FileSize: 0.14MB
Id: 200705030906
StartTime: Thu May  3 09:06:47 2007
EndTime:   Thu May  3 09:16:03 2007
TotalTime: 555.58 seconds
TotalCapSize: 0.12MB  CapLen: 96 bytes
# of packets: 1458 (364.58KB)
AvgRate: 16.17Kbps  stddev:52.23K

### IP flow (unique src/dst pair) Information ###
# of flows: 72  (avg. 20.25 pkts/flow)
Top 10 big flow size (bytes/total in %):
 38.8% 20.5% 19.1%  5.7%  4.5%  2.1%  1.6%  0.8%  0.4%  0.4%

### IP address Information ###
# of IPv4 addresses: 38 
Top 10 bandwidth usage (bytes/total in %):
 100.0% 41.1% 24.9% 20.6%  4.6%  2.4%  0.6%  0.6%  0.4%  0.4%
### Packet Size Distribution (including MAC headers) ###
<<<<
 [   32-   63]:        143
 [   64-  127]:        681
 [  128-  255]:        149
 [  256-  511]:        344
 [  512- 1023]:         41
 [ 1024- 2047]:        100
>>>>


### Protocol Breakdown ###
<<<<
     protocol		packets			bytes		bytes/pkt
------------------------------------------------------------------------
[0] total             1458 (100.00%)           373331 (100.00%)    256.06
[1] ip                1430 ( 98.08%)           371651 ( 99.55%)    259.90
[2]  tcp               742 ( 50.89%)           252248 ( 67.57%)    339.96
[3]   http(s)          133 (  9.12%)           151371 ( 40.55%)   1138.13
[3]   http(c)          123 (  8.44%)            11761 (  3.15%)     95.62
[3]   ssh              486 ( 33.33%)            89116 ( 23.87%)    183.37
[2]  udp               140 (  9.60%)            19795 (  5.30%)    141.39
[3]   dns              140 (  9.60%)            19795 (  5.30%)    141.39
[2]  icmp              306 ( 20.99%)            23212 (  6.22%)     75.86
[2]  other             242 ( 16.60%)            76396 ( 20.46%)    315.69
>>>>

        

6.11.4. ngrep

Другая удобная утилита предназначенная для анализа сетевого трафика и дампов в формате libpcap — ngrep. Эта программа (устанавливается из порта net/ngrep) позволяет искать пакеты, содержимое которых соответствует заданному шаблону:

# ngrep -d rl0 -i password port 23
interface: rl0 (172.19.0.0/255.255.255.0)
filter: (ip) and ( port 23 )
match: password
############################################
T 192.168.0.1:23 -> 172.19.0.33:38250 [AP]
  Password:                                                                  
##################exit
62 received, 0 dropped
        

В приведённом примере прослушивался интерфейс rl0. При этом в пакетах разыскивался шаблон password без учёта регистра (опция -i). Выражение port 23 это фильтр (синтаксис такой же как у tcpdump(1)). Пакеты в которых указанный шаблон не найден обозначаются в отчёте решётками. Для пакетов в которых шаблон найден выводится информация о пакете и найденная строка.

Шаблоны являются регулярными выражениями и пишутся в формате egrep(1). (см. Раздел 7.14, «Применение регулярных выражений»)

6.12. Работа с ARP и кешем найденных соседей

Описание.  Кандидат должен понимать основы работы протокола ARP: обнаружение соседей, изучение arp-кеша, использование в сетях IPv6. Кандидат должен уметь просмотреть, изменить и очистить этот кеш, а так же понять когда это надо сделать.

Практика. arp(8), ndp(8)

Комментарий

6.12.1. arp(8)

Назначение протокола ARP описано в Раздел B.1.3.1, «ARP». Коротко, оно заключается в связи между сетевым и канальным уровнем модели OSI, обеспечивая преобразование IP адресов в аппаратные (MAC) адреса.

Утилита arp(8) используется для того, чтобы управлять ARP кешем. Когда системе надо послать пакет на адрес IP, сперва необходимо узнать какому аппаратному адресу он соответствует, для того, чтобы сформировать Ethernet-кадр. Система посылает широковещательный ARP запрос «кто имеет данный IP?». Получив ответ, система помещает его в кеш и хранит его там около двух минут. При помощи команды arp(8) можно просмотреть содержимое этого кеша:

$ arp -an 1
? (81.xxx.xxx.145) at 00:04:27:fd:3c:d0 on fxp0 [ethernet]
? (81.xxx.xxx.146) at 00:0f:fe:17:b0:85 on fxp0 permanent [ethernet]
? (192.168.0.3) at 00:50:04:af:06:19 on rl0 [ethernet]
? (192.168.0.4) at 00:a0:c9:85:1c:d4 on rl0 [ethernet]
? (192.168.0.5) at 00:0e:a6:88:34:79 on rl0 [ethernet]
? (192.168.0.6) at 00:11:5b:a3:f9:09 on rl0 [ethernet]
? (192.168.0.9) at 00:30:05:64:9c:b7 on rl0 [ethernet]
? (192.168.0.10) at 00:05:5d:2e:40:99 on rl0 [ethernet]
? (192.168.0.11) at 00:a0:c9:a0:dd:a9 on rl0 [ethernet]
? (192.168.0.49) at 00:11:2f:06:b5:2e on rl0 [ethernet]
? (192.168.0.50) at 00:04:75:94:d0:ac on rl0 [ethernet]
? (192.168.0.60) at 00:30:65:df:bd:00 on rl0 [ethernet]
? (192.168.0.65) at 00:0a:95:ed:0c:ea on rl0 [ethernet]
? (192.168.0.70) at 00:30:65:4b:8b:4a on rl0 [ethernet]
? (192.168.0.93) at 00:02:b3:1f:ff:a7 on rl0 [ethernet]
? (192.168.0.125) at 00:03:93:d6:7f:64 on rl0 [ethernet]
? (192.168.0.147) at 00:0d:93:70:be:52 on rl0 [ethernet]
? (192.168.0.150) at 00:03:93:95:97:e6 on rl0 [ethernet]
? (192.168.0.220) at 00:0a:95:94:ff:d0 on rl0 [ethernet]
? (192.168.0.254) at (incomplete) on rl0 [ethernet] 2
? (192.168.0.255) at ff:ff:ff:ff:ff:ff on rl0 permanent [ethernet] 3
? (192.168.1.1) at 00:0d:88:43:77:33 on rl1 [ethernet]
? (192.168.1.2) at 00:0d:88:43:77:29 on rl1 [ethernet]
? (192.168.1.22) at 00:11:95:1d:22:bb on rl1 permanent [ethernet]
? (192.168.1.255) at ff:ff:ff:ff:ff:ff on rl1 permanent [ethernet]
        
1 Здесь применён аргумент -a, чтобы перечислить все записи кеша, и -n, чтобы не преобразовывать IP адреса в имена. Команда выполнена на роутере с тремя сетевыми интерфейсами.
2 Перед выполнением команды был пропингован не существующий адрес. ARP запрос не был удовлетворён, поэтому вместо MAC адреса сетевой карты программа arp(8) пишет в отчёте «incomplit».
3 Перед выполнением команды был пропингован широковещательный адрес, для того, чтобы получить информацию о всех машинах в сети.

Команда arp(8) позволяет так же управлять кешем ARP: удалять из него записи при помощи аргумента -d, или наоборот, при помощи аргумента -s заводить новые записи (временные или постоянные). При помощи аргумента -f можно импортитовать таблицу ARP из внешнего файла.

Таблица 6.2. Аргументы команды arp(8)

АргументОписание
-a Программа выводит (или удаляет) все записи из таблицы ARP.
-d Удаление записи из таблицы arp(8). Может быть объединён с флагом -a для удаления всех записей из кеша. совместно с ключевым словом pub удаляет только публичные записи, т.е. записи, на запросы о которых машина отвечает сама (как ARP сервер).
-i интерфейс Вывести записи касающиеся данного интерфейса
-n Не делать обратного преобразования имён, т.е. показывать адреса численно, а не по именам.
-s hostname ether [temp] [pub] Добавить запись в таблицу ARP. если задано ключевое слово temp, то это будет не статическая, временная запись, если задано слово pub, то это будет «публичная» запись. Т.е. наша машина будет отвечать на ARP запросы по этому IP как ARP сервер.
-S То же, что -s, но существующая запись предварительно удаляется.
-f file Взять данные для таблицы ARP из файла. В файле строки оформляются в том же стиле, что и в опции -s. Комментарий начинается с #.

6.12.2. ndp(8)

В протоколе IPv6 отменён протокол ARP. Вместо него используется своя процедура поиска соседей при помощи протокола NDP: Neighbor Discovery Protocol. Для управления им служит утилита ndp(8). Её синтаксис напоминает синтаксис команды arp(8).

6.13. Конфигурирование системы для использования NTP

Описание.  Кандидат BSDA должен быть знаком с основными идеями RFC 868, важностью синхронизации времени, какие сервисы чувствительны ко времени. Кандидат должен уметь сконфигурировать NTP и, если это требуется, вручную синхронизировать время с сервером времени.

Практика. ntpd(8), ntpd.conf(5), rc.conf(5), rdate(8)

Комментарий

В наше время трудно представить себе машину не снабжённую встроенным таймером, ондако в принципе существуют и такие. Ещё важнее, что существует большое количество машин на которых таймер есть, но работает некорректно и способен за несколько месяцев уйти вперёд или назад на десятки минут. Другая проблема состоит в том, что работа таймера зависит от питания и если с батареей, встроенной в материнскую плату что-то происходит, он может сбрасывать время в ноль, т.е. например в начало UNIX-эры — 1-е января 1970 года.

Такое рассогласование системного времени может приводить к разнообразным проблемам при согласовании данных между машинами. Часто такие помехи приводят к некорректной работе системы контроля версий, системы изготовления backup'ов. Ошибки могут возникать как со стороны машин, так и со стороны персонала.

Важно, чтобы системное время было согласовано хотя бы в масштабах предприятия. И нет ни малейших причин, почему бы не согласовать время со всем миром.

Для решения этой задачи существует несколько протоколов. Мы опишем TP (Time Protocol) и NTP (Network Time Protocol)

6.13.1. TP (RFC 868) и rdate(8)

Time Protocol описан в [RFC-868]. Согласно указанному документу на сервере времени поднимается сервис, который слушает 37-й порт, как UDP, так и TCP.

Если клиент связывается по TCP, он должен подключиться к данному порту, после чего сервер вышлет ему пакет содержащий в себе время в бинарном формате как 32-битное число секунд прошедших с 1-го января 1900 года (а не с начала UNIX эры!). Легко видеть, что в 2036-м году этот протокол прикажет долго жить. Между прочим, всего 30 лет осталось — меньше, чем живёт UNIX.

Если клиент предпочитает обмениваться UDP пакетами, то он должен выслать пустую датаграмму на 37-й порт сервера и получить ответную, содержащую в себе время.

Для реализации этого протокола со стороны клиента, существует программа rdate(8). Она входит в состав всех BSD, кроме FreeBSD, где она доступна в виде отдельного порта.

Стоит ли говорить, что протокол это страдает неточностями и давно устарел? Например, в протоколе не учитывается сколько времени шла датаграмма от сервера к клиенту. Впрочем, для подавляющего большинства нужд погрешность в 10 секунд неважна.

6.13.2. NTP

Протокол NTP предоставляет более развитый сервис. В качестве порта для обмена данными он использует порт 123. Для синхронизации времени запускается демон ntpd(8), Который предоставляет как услуги сервера, так и клиента. Для его запуска в FreeBSD следует вставить в /etc/rc.conf(5) следующую строку:

ntpd_enable="YES"
        

А так же, написать для демона конфигурационный файл /etc/ntp.conf(5), в котором бы указывалось, с каких серверов он берёт точное время, и какие сервисы предоставляет другим машинам.

Многие научные институты и коммерческие организации, такие как Apple или Microsoft предоставляют в общее пользование серверы точного времени. существует специальная сеть NTP-серверов в домене ntp.org. (См. http://ntp.org). В этом домене имеется множество национальных ntp серверов, в том числе и в России.

Вот пример конфигурационного файла /etc/ntp.conf(5) для нашей страны:

server 0.ru.pool.ntp.org
server 1.ru.pool.ntp.org
server 2.ru.pool.ntp.org
server ru.pool.ntp.org
driftfile /var/db/ntp.drift
        

Демон ntpd(8) последовательно опрашивает все эти серверы вычисляет разницу с системным временем и записывает её в driftfile. Затем он постепенно, маленькими порциями приводит системное время на машине ко времени указанному на серверах времени. Таким образом, скачка времени не происходит. После того как время выставлено в правильное значение, демон ntpd(8) вычисляет погрешность системного таймера и постоянно корректирует его.

Если на одном из серверов времени время значительно отличается от других, он не используется. Если при старте на клиенте время значительно отличается от времени на серверах, демон откажется корректировать его в автоматическом режиме, о чём появится соответствующая запись в журнальном файле /var/log/messages. Вы можете отметить какой-нибудь сервер как наиболее предпочтительный при помощи опции prefer.

Может быть весьма разумной практика, когда вы поднимаете свой сервер времени на предприятии, а всем клиентам прописываете обращаться за точным временем к нему. Сервер ntpd(8) может успешно обслуживать клиентов с оперционными системами MAC OS 9, MAC OS X, Windows NT 4, Windows 2000, Windows XP.

Протокол NTP позволяет менять время не только на клиенте, но и на сервере (для этого вместо применённого выше ключевого слова server, применяется ключевое слово peer). Поэтому в настроечном файле имеются опции позволяющие изменять время лишь при обращении с определённых IP-адресов, и даже осуществлять шифрованную аутентификацию.

В конфигурационном файле могут быть оговорены различные таймауты по запросам и т.п.

Наконец, в FreeBSD можно и вовсе обойтись без конфигурационного файла. Сервер времени можно просто указать в /etc/rc.conf(5) вместе с опцией включающей запуск при старте системы собственно демона ntpd(8).

ntpd_enable="YES"
ntpdate_hosts="0.ru.pool.ntp.org 1.ru.pool.ntp.org 2.ru.pool.ntp.org"
        

6.14. Просмотр и обновление «арендованных» данных DHCP

Описание.  Кандидат BSDA должен быть знаком с основами DHCP, должен знать как сконфигурировать клиента, перебить настройки полученные с сервера DHCP. В добавок, кандидат должен уметь просмотреть текущие «арендованные» настройки, сбросить их и получить новые. Поскольку DHCP клиенты используются разные, кандидат должен быть знаком с использованием команд DHCP клиента на каждой BSD.

Практика. dhclient(8), dhclient.leases(5), dhclient.conf(5), rc.conf(5)

6.15. Знание как и когда устанавливать или удалять алиасы сетевого интерфейса

Описание.  Кандидат BSDA должен уметь определить когда следует удалить или установить алиас (псевдоним) для сетевого интерфейса и какие команды доступны для этого в разных BSD.

Практика. ifconfig(8), rc.conf(5), ifaliases(5), hostname.if(5)



[1] О модели OSI можно прочитать в глоссарии OSI

Глава 7. Базовые навыки работы в Unix

Содержание

[+]7.1. Перенаправление вывода и использование tee(1)
[+]7.1.1. Особенности csh(1)
[+]7.2. Определение просмотр и изменение переменных окружения
[+]7.2.1. Просмотр и изменение переменных окружения
[+]7.2.2. csh(1), set, setenv
[+]7.3. Навыки работы в vi(1)
[+]7.3.1. Normal mode
[+]7.3.2. Insert Mode
[+]7.3.3. Search mode
[+]7.3.4. Command line mode
[+]7.4. Определение является ли файл бинарным, текстовым или содержащим данные
[+]7.5. Поиск файлов и бинарников в системе
[+]7.5.1. whatis(1)
[+]7.5.2. whereis(1), which(1)
[+]7.5.3. locate(1)
[+]7.5.4. find(1)
[+]7.5.5. sh type
[+]7.6. Поиск файла по заданным атрибутам
[+]7.6.1. Условия для поиска командой find(1)
[+]7.6.2. Действия выполняемые командой find(1) с найденными файлами
[+]7.6.3. Связка с командой xargs
[+]7.7. Написание несложных Bourne-скриптов
[+]7.7.1. Магическая строка (shebang)
[+]7.7.2. Почему sh(1)?
[+]7.7.3. Программирование в Bourne Shell
[+]7.8. Поиск нужной документации
[+]7.8.1. Справочная система man(1)
[+]7.8.2. Гипертекстовая справка info(1)
[+]7.8.3. Прочие источники
[+]7.9. Понимание различий в страницах man
[+]7.10. Проверка контрольной суммы файла
[+]7.10.1. cksum(1)
[+]7.10.2. md5(1)
[+]7.10.3. sha1(1)
[+]7.10.4. openssl(1)
[+]7.10.5. Примеры
[+]7.11. Продемонстрировать знакомство с оболочками используемыми по умолчанию в системе
[+]7.11.1. Предотвращение уничтожения существующих файлов
[+]7.11.2. Некоторые отличия между sh(1) и csh(1)
[+]7.11.3. Модификаторы переменных в csh(1)
[+]7.11.4. Работа с историей команд
[+]7.12. Чтение почты на локальной машине
[+]7.12.1. Работа с mail(1) в интерактивном режиме
[+]7.12.2. Использование mail(1) с командной строки
[+]7.13. Использование контроля за задачами (job control)
[+]7.14. Применение регулярных выражений
[+]7.14.1. Диалекты регулярных выражений
[+]7.14.2. Возможности команды grep(1)
[+]7.15. Преодоление ограничений на длину командной строки
[-]7.16. Понимание значения термина домен в различных контекстах
[+]7.17. Работа с cron
[+]7.17.1. Системный crontab
[+]7.17.2. Каталоги с периодически выполняемыми заданиями во FreeBSD
[+]7.17.3. Особенности OpenBSD и NetBSD
[+]7.17.4. Пользовательский crontab

Корни систем BSD находятся в Unix, многие Unix утилиты изначально разработаны в BSD. Кандидат BSDA должен продемонстрировать знакомство с основными утилитами командной строки Unix.

7.1. Перенаправление вывода и использование tee(1)

Описание:  Кандидат BSDA должен уметь перенаправлять стандартный вывод, ввод или поток ошибок программы, использовать pipe чтобы послать вывод одной программы в другую программу или в файл. Использовать tee(1) чтобы копировать стандартный ввод на стандартный вывод.

Практика: <, >, |, tee(1), >& и |&

Комментарий

За каждой программой запущенной в UNIX (и не только UNIX) закреплено минимум три файловых дескриптора: стандартный ввод (STDIN), стандартный вывод (STDOUT) и стандартный вывод ошибок (STDERR). Хотя мы говорим «файловый дескриптор», на самом деле это не обязательно именно файлы. Речь идёт об «обобщённых файлах» — некоторых объектах, куда можно писать и откуда можно читать. В норме, приложение запущенное в терминале направляет STDOUT и STDERR на консоль. Таким образом, мы видим результат деятельности программы напечатанным на экране. STDIN программы, это поток информации читаемый ею с клавиатуры.

Напрмер, запустим программу grep следующим образом:

$ grep r
          

В этом случае программа grep будет искать строки содержащие букву r в потоке STDIN (то есть в тексте набираемом с клавиатуры), и выводить этот текст на STDOUT (то есть на экран). Сразу после запуска ничего не происходит: команда grep ожидает ввода с клавиатуры т.е. читает STDIN. Мы печатаем текст и нажимаем клавишу <Enter>. После этого строка попадает в grep и если она содержит букву r она печатается второй раз на экране т.е. grep печатает её на STDOUT.

Ниже приведён листинг такого примера. Знаком < помечены строки котороые набрал пользователь (STDIN), а знаком > строки напечатанные в ответ программой grep(1).

$ grep r
< DragonFly BSD
> DragonFly BSD
< FreeBSD
> FreeBSD
< OpenBSD
< NetBSD
        

В нашем листинге STDIN и STDOUT обозначены значками < и >. В жизни этого, конечно, не происходит. Всё вперемешку, что крайне неудобно. Да и вообще, трудно представить себе что кто-то будет руками набивать текст только для того, чтобы его профильтровал grep(1). Гораздо удобнее пользоваться символами перенаправления для переопределения стандартного ввода и вывода.

Пусть у нас есть файл BSDA содержащий названия изучаемых нами BSD систем.

$ cat BSDA
DragonFly BSD
FreeBSD
OpenBSD
NetBSD
        

Применим grep для того, чтобы выяснить какие системы BSD содержат в своём названии букву r. Для этого мы переопределим STDIN команды grep. Теперь вместо того, чтобы читать текст с клавиатуры, grep(1) будет читать его из файла BSDA:

$ grep r < BSDA
DragonFly BSD
FreeBSD
        

А что если нам надо сохранить вывод программы grep в файл? Тогда мы должны переопределить ещё и STDOUT:

$ grep r < BSDA > BSDA-r
        

Теперь у нас появился файл с названием BSDA-r содержащий две строки:

$ cat BSDA-r
DragonFly BSD
FreeBSD
        

Но а что если нам надо узнать сколько систем BSD имеют в своём имени букву r? Для этого мы можем воспользоваться программой wc(1) с аргументом -l. Команда wc -l считает строки в своём STDIN и печатает результат на STDOUT. Таким образом, мы можем выполнить последовательно 2 команды:

$ grep r < BSDA > BSDA-r
$ wc -l < BSDA-r
         2
        

Но это неудобно: мы зачем-то создавали временный файл, передавали копеечную информацию и для этого обращались к диску, а это медленная операция. А если бы у нас было много информации, то наши действия тоже были бы нерациональны: Весь STDOUT grep(1)'а мог не поместиться на диске (может там миллион строк!), но он и не нужен wc(1) для работы, wc(1) может каждый отдельный момент работать с кусочком файла.

Напрашивается естественный вывод: надо переопределить STDOUT grep'а так, чтобы он стал STDIN'ом wc(1). Такую конструкцию называют pipe или конвейер.

$ grep r < BSDA | wc -l
         2
        

Стандартный вывод wc(1) (число 2) тоже можно передать на стандартный ввод другой программы, таким образом длину конвейера или трубы (pile-line) можно сделать сколь угодно длинной. В следующем примере количество систем BSD содержащих в своём названии букву r будет распечатано на принтере:

$ grep r < BSDA | wc -l | lpr
        

А чтоже делать, если мы хотим и список систем получить и посчитать их количество? Можно как и прежде выполнить 2 действия поочереди: сперва создать файл BSDA-r, полюбоваться на него, а потом скормить его программе wc. А можно воспользоваться программой tee(1). tee ничего не делает с потоком данных, которые через неё идут, она просто копирует STDIN в STDOUT. Но если ей в качестве аргумента задать некоторый файл, то она будет заодно записывать эту информацию и в него. Таких файлов команде tee можно задать много. Таким образом, tee является разветвителем в трубе:

$ grep r < BSDA | tee BSDA-r | wc -l
         2
$ cat BSDA-r
DragonFly BSD
FreeBSD
        

tee можно использовать как здесь — для сохранения промежуточных результатов, а можно использовать для того, чтобы протоколировать в файл то, что администратор видит на экране. Напрмер, ниже программа make будет писать что-то на экран, но впоследствии мы сможем прочитать что она там писала из файла make-log:

$ make | tee make-log
        

В этом примере мы добились развоения стандартного вывода программы make: этот поток информации одновременно пишется в файл make-log и печатается в окне терминала обычным образом.

Теперь поговорим про STDERR. Пусть у нас в текущем каталоге есть два файла get.sh и put.sh, и более ничего нет. Выполним следующее действие:

$ ls *sh *gz
ls: *gz: No such file or directory
get.sh  put.sh
        

Мы видим, что на экране присуствует как список файлов с расширением sh так и сообщение об ошибке связанное с тем, что в текущем каталоге отсутствуют файлы с расширением gz. Обе эти строки напечатаны в окне терминала, но это два разных потока. Сообщение об ошибке было напечатано в стандартный вывод ошибок — STDERR. Убедимся в этом:

$ ls *sh *gz > /dev/null
ls: *gz: No such file or directory
$ ls *sh *gz 2> /dev/null
get.sh  put.sh
        

В приведённом примере мы в первом случае перенаправили STDOUT в файл /dev/null (это уcтройство поглащающее байты вроде «чёрной дыры»), а во втором случае мы перенаправили STDERR. Поэтому в первом случае у нас напечаталось только сообщение об ошибке, а во втором только список файлов с расширением sh.

Файловые дескрипторы соответствующие STDIN, STDOUT и STDERR имеют номера, соответственно 0, 1 и 2. Когда мы пишем знак >, система неявно предполагает, что мы перенаправляем дескриптор с номером 1 и перенаправляет STDOUT. Если же мы хотим перенаправить STDERR нам надо явно указать его номер: 2>.

[Важно]Важно
2> пишется слитно без пробела.

Вы можете объединить файловые дескрипторы, если вам надо, например, писать сообщения выводящиеся на STDOUT и STDERR в один файл:

$ make > make.log 2>&1
        

Здесь мы направили стандартный вывод в файл make.log (написав > make.log), а затем STDERR перенаправили в STDOUT (написав 2>&1). Причём порядок действий здесь важен. Команда

$ make 2>&1 > make.log
        

приведёт к тому, что в файл make.log будет направлен только STDOUT, так как STDERR был перенаправлен тогда, когда STDOUT направлялся ещё на консоль.

7.1.1. Особенности csh(1)

Синтаксис перенаправления в csh(1) отличается от синтакиса в sh(1). Ниже приведены эквивалентные команды на sh(1) и на csh(1):

sh:  $ make 2>&1 > make.log
csh: % make >& make.log

sh:  $ make 2>&1 | less
csh: % make |& less

sh:  $ make 2>/dev/null > make.log
csh: % (make > make.log) >& /dev/null
        

В последней строке продемонстрировано досадное ограничение csh(1): для того, чтобы перенаправить STDERR и STDOUT в разные места приходится заворачиваться в блин: перенаправить произвольный файловый дескриптор по его номеру, увы, нельзя. Можно лишь пользоваться перенаправлением суммы STDERR и STDOUT используя символы |& и >&.

7.2. Определение просмотр и изменение переменных окружения

Описание:  Кандидат BSDA должен уметь просматривать и изменять переменные окружения временно и постоянно для любой оболочки поставляемой с системой BSD.

Практика: env(1), sh(1), csh(1), tcsh(1), environ(7)

Комментарий

Многие программы в UNIX берут настроечную информацию из переменных окружения. Это хороший способ передать в программу информацию, общую для разных программ. Например программа df(1) будучи вызвана без аргументов выводит информацию о свободном месте в единицах заданных в переменной BLOCKSIZE. Другие программы (du(1), ls(1)) берут эту же информацию из этой же переменной. Не будь механизма с переменными окружения, нам понадобился бы некоторый общий реестр с переменными, в котором скорее всего царил бы полный хаос.

Ниже приведён некоторый список переменных влияющих на поведение разнообразных программ и их значение. Список приведён по данным страницы man environ(7).

Таблица 7.1. Пользовательске переменные окружения [environ(7)]

ПеременнаяОписание
BLOCKSIZE Размер блока используемый некоторыми командами, в частности df(1), du(1) и ls(1). BLOCKSIZE может быть указан в байтах, а может в килобайтах, мегабайтах или гигабайтах, если указать суффикс K, k, M, m, G или g. величины менее 512 или более 1G игнорируются
COLUMNS Предпочитаемая пользователем ширина вывода для терминала. Используется такими утилитами, как ls(1) и who(1) для форматирования вывода на терминал. Если переменная неустановлена или пуста утилиты используют вызов ioctl(2) чтобы выяснить ширину терминала.
EDITOR Имя текстового редактора по умолчанию
EXINIT Список команд выполняемых при старте ex(1) и vi(1).
HOME Пользовательский каталог. Устанавливается login(1) из файла passwd(5).
LANG Локаль. Эта переменная влияет на все программы использующие вызов setlocale(3).
LC_ALL Локаль. Переписывает значение переменных LC_COLLATE, LC_CTYPE, LC_MESSAGES, LC_MONETARY, LC_NUMERIC и LC_TIME.
LC_COLLATE Локаль. Сортировка строк.
LC_CTYPE Переменная для определения того, какие символы являются буквой, пробелом, цифрой и т.п. в данной локали. Какой порядок байт принят в локали.
LC_MESSAGES Локаль для диагностических сообщений
LC_MONETARY Локаль для указания формата валют.
LC_NUMERIC Локаль для отображения чисел
LC_TIME Локаль для отображения дат
MAIL Расположение почтового ящика пользователя (вместо используемого по умолчанию /var/mail), используется mail(1), sh(1) и многими другими почтовыми клиентами.
NLSPATH Список каталогов используемых для поиска сообщений диагностических сообщений LC_MESSAGES. См. catopen(3).
PAGER Название используемой по умолчанию программы-пейджера для постраничного вывода на экран (например less). Переменная используется mail(1), man(1), ftp(1), для вывода на экран сообщений неумещающихся на экран.
PATH Список каталогов разделённых двоеточием, в которых осуществляется поиск исполнимых файлов программами csh(1), sh(1), system(3), execvp(3), и пр.
PRINTER Имя используемого по умолчанию принтера для программ lpr(1), lpq(1), и lprm(1).
PWD Текущий рабочий каталог
SHELL Полный путь к пользовательской оболочке
TERM Имя текущего терминала. Используется командами nroff(1) или plot(1) для определения функциональности терминала. Полный список типов терминалов приведён в файле /usr/share/misc/termcap (termcap(5)).
TERMCAP Строка описывающая терминал или, если начинается со '/' — имя файла termcap. См. TERMPATH ниже и termcap(5)
TERMPATH перечень файлов termcap разделённых двоеточием или пробелом, в которых ищется описание терминала. Отсутствие TERMPATH эквивалентно наличию переменной TERMPATH равной $HOME/.termcap:/etc/termcap. TERMPATH неиспользуется, если TERMCAP содржит полный путь к файлу.
TMPDIR Каталог для хранения временных файлов. Большинство приложений используют /tmp или /var/tmp. Установка этой переменной может заставить их использовать другое место.
TZ Часовой пояс (timezone) для отображения дат. указывает путь относительно каталога /usr/share/zoneinfo. Напимер, чтобы узнать сколько времени в Москве env TZ=Europe/Moscow date, в Иркутске — env TZ=Asia/Irkuts date См. также tzset(3).
USER Имя пользователя (логин).

7.2.1. Просмотр и изменение переменных окружения

7.2.1.1. env(1), printenv(1)

Утилита env нужна для просмотра текущих переменных окружения и/или запуска программ в специфическом окружении. Будучи вызвана без аргументов она печатает список текущих переменных и их значения. Можно задать команде env список переменных и их значения и команду. Тогда эта команда будет выполнена с указанными переменными. Опция -i может применяться для того, чтобы env(1) не наследовала уже заданных переменных. Чтобы узнать значение конкретной переменной можно так же использовать команду printenv(1). Например:

$ env | grep TZ
TZ=Europe/Moscow
$ date
среда, 15 февраля 2006 г. 22:14:28 (MSK)
$ env TZ=Asia/Irkutsk date
четверг, 16 февраля 2006 г. 03:14:38 (IRKT)
$ date
среда, 15 февраля 2006 г. 22:14:41 (MSK)
$ printenv TZ
Europe/Moscow
          

Есть распространённая практика писать утилиту env(1) в «магичекую строку» (shebang), с которой обычно начинаются сценарии:

#!/usr/bin/env python
          

Таким способом программисты страхуются от того, что интерпретатор python(1) может находиться в неправильном месте. Так, в FreeBSD, DragonFly BSD и OpenBSD python(1) будет скорее всего установлен в каталог /usr/local/bin, в NetBSD в /usr/pkg/bin, в Linux он возможно будет стоять в /usr/bin. Чтобы магическая строка всегда работала нужно либо переписывать её при инсталляции скрипта (Обычно инсталляторы так и желают), либо писать как выше в расчёте на то, что путь к языку python(1) у пользователя прописан в переменной PATH.

Такой подход по ряду причин надо признать крайне неудачным. Во-первых, такой скрипт будет работать не всегда. Будучи вызван из crontab он может работать в ситуации, когда переменная PATH вообще не задана. Кроме того, влияя на переменную PATH пользователь может подсунуть поддельный интерпретатор. Если вы выдали недобросовесному судоеру права на запуск утилиты /root/bin/util.py с правами root, а в утилите в магической строке python(1) вызывается через env(1), то судоер может переопределив PATH подсунуть поддельный python и получить полный контроль над системой.

С другой стороны, прежде чем выдавать права суперпользователя на исполнения некоторого скрипта, надо хорошо понимать как работает интерпретатор, который вы используете. Рассмотрим пример с тем же python(1). Пусть у нас есть скрипт hello.py такого содержания:

#!/usr/local/bin/python
print "Hello World!"
          

Запустив этот скрипт командой

$ sudo env PYTHONINSPECT="1" ./test.py
Hello World
>>>
          

судоер по завершении скрипта получит приглашение командной строки интерпретатора python(1) через которую он получит полную власть над системой. Чтобы избежать этого, надо либо явно указать в скрипте инструкцию выхода:

#!/usr/local/bin/python
import sys
print "Hello World!"
sys.exit()
          

либо ограничить пользователя в использовании переменных окружения:

#!/usr/bin/env -i /usr/local/bin/python
print "Hello World!"
          

7.2.1.2. sh(1), export

В интерпретаторе sh можно задать значение переменной путём присваивания: var=value, например NEW=1. После этого переменную можно использовать, на её значение можно ссылаться из по имени $NEW, но она ещё не стала переменной окружения. Чтобы эта переменная стала видна программе как переменная окружения, её надо экспортировать командой export.

$ NEW=1
$ echo $NEW
1
$ printenv NEW
$ export NEW
$ printenv NEW
1
          

Таким образом, переменные могут быть экспортированными и неэкспортированными. Только экспортированные переменные будут видны вызываемым программам и скриптам. Неэкспортированные переменные, тем не менее можно использовать в текущем сценарии. Они удобны тем, что не влияют на работу вызываемых программ.

Полный список переменных можно узнать командой set без аргументов, а список экспортированных переменных командой export без аргументов.

7.2.2. csh(1), set, setenv

В языке csh переменная устанавливается командой set, а переменная окружения командой setenv. Причём переменные и переменные окружения это два совершенно разных массива. Может быть одновременно определена переменная и переменная окружения с тем же именем, но другим значнием:

% set NEW=1
% printenv NEW
% echo $NEW
1
$ setenv NEW 2
$ printenv NEW
2
$ echo $NEW
1
        

Обратите внимание: команды set и setenv имеют разный синтаксис.

7.3. Навыки работы в vi(1)

Описание:  по умолчанию в системах BSD используется редактор vi(1) многие системные утилиты используют его в своей работе. Кандидат BSDA должен уметь использовать этот редактор: редактировать файлы, редактировать файлы доступные только для чтения, выходить из редактора без сохранения.

Практика: vi(1) including: :w, :wq, :wq!, :q!, dd, y, p, x, i, a, /, :, :r, ZZ, :set number, :set list

Комментарий

Тем, кто сталкивается с vi(1) впервые, может показаться, что программист написавший его был сумасшедшим. Я знаю человека, который утверждал, что при его первом знакомстве с vi(1) он не смог из этого редактора выйти и был вынужден... перезагрузить компьютер reset'ом (ну и кто, спрашивается сумасшедший, программист или пользователь?). vi(1) упомянут в качестве текстового редактора в стандарте POSIX. По этой причине vi(1) есть в любой операционной системе семейства UNIX (принимая во внимание оговорки из следующих двух абзацев). Так что надо сжать зубы и выучить vi(1). Без этого никуда.

Небольшое замечание про vi(1) и vim(1). В мире существует огромное множество клонов редактора vi(1). В стандарте POSIX описаны некоторые свойства редактора vi(1), но конечно не настаивается на том, чтобы люди использовали именно vi(1) и ни что другое. Просто в каталоге /usr/bin/ должно располагаться нечто под названием vi(1), обладающее такими-то свойствами. Пользователям же хотелось, чтобы текстовый редактор как-то развивался, добавлялись новые функции: синтаксическая подсветка, работа с текстами набранными в различных кодировках, фолдинг и многое другое. Потому-то и существует множество клонов стандартного vi(1). Одним из самых удачных и распространённых является редактор vim(1), написанный голландским программистом Брамом Мооленааром (Bram Moolenaar). Название vim расшифровывается как Vi iMproovement т.е. усовершенствованный vi(1). Это чрезвычайно мощное средство редактирования текстов. Если вам кажется, что vim(1) чего-то не умеет, значит вы не дочитали документацию до конца. Весь этот документ, кстати, написан в vim(1). Что особенно приятно, vim(1) портирован во все мыслимые операционные системы (кроме откровенно эзотерических) и везде ведёт себя одинаково.

Текстовый редактор vim(1) написан как полная замена vi(1). В нём есть режим работы полностью эмулирующий vi(1) «за исключением явных ошибок», как пишет об этом Брам. В большинстве дистрибутивов Linux текстовый редактор vi(1) заменён на vim(1). vim(1) запускается под именем vi(1) и входит в vi-compatible режим. Это не единственное место, где авторы дистрибутивов Linux вольно обращаются с утилитами входящими в POSIX. Другими такими примерами являются sh(1) и awk(1), заменённые на bash(1) и gawk(1), но запускающиеся по соображениям совместимости под старыми именами. Во всех BSD системах в каталоге /usr/bin находится оригинальный vi(1). vim(1) доступен только как сторонний продукт и устанавливается из портов.

Кроме vi(1) существует множество более простых редакторов с более или менее очевидным поведением. Большинство из них устанавливается в виде отдельных портов, однако некоторые входят в стандартный комплект и поставляются вместе с операционной системой. Например с FreeBSD поставляется редактор ee(1), написанный в расчёте на то, что с ним сможет работать любой человек, совершенно ничему не обученный. Но все системные утилиты без указания переменной окружения EDITOR будут вызывать именно vi(1).

[Важно]Важно
В данном разделе описан не vim(1), а vi(1) версии 1.79 (10/23/96) The CSRG, University of California, Berkeley. Эта версия сама по себе, обладет некоторыми особенностями отсутсвующими в POSIX-vi. Например, описываемый vi(1) обладает опцией searchinc и возможностью редактирования текста в нескольких окнах (:N).

Основное отличие vi(1) от прочих текстовых редакторов — невозможность набирать текст непосредственно после запуска. Я настоятельно рекомендую новичкам установить порт vim(1) и выполнить команду vimtutor(1). Таким образом, вы познакомитесь с основными клавишами vi(1) и режимами работы. На худой конец, прочтите этот раздел до конца прежде чем приметесь за эксперименты.

vi(1) имеет несколько режимов работы:

Normal mode
Основной режим работы vi(1). В этом режиме нельзя непосредственно набирать текст. В этом режиме осуществляется перемещение по тексту, операции копирования текста в буфер обмена, вставка из буфера и удаления текста в буфер. (Удалить текст не в буфер нельзя, поэтому удаляя текст вы стираете то, что было в буфере до этого.)
Insert mode
Этот режим предназначен для набора текста.
Search mode
Режим предназначен для поиска текста.
Command line mode
В этом режиме можно выполнять разнообразные команды: поиск с заменой, сохранение текста в файл, открыть на редактирование другой файл, выход из редактора установка внутренних переменных в то или иное значение.

7.3.1. Normal mode

Очень важным элементом работы в vi(1) является «движение». Важно уметь передвигаться в vi(1) не посимвольно, при помощи стрелочек, а именно при помощи его буквенных команд, упомянутых ниже. В комбинации с другими командами это даст вам большие возможности по редактированию текста.

Таблица 7.2. Движения в vi(1), Normal mode

КомандаМнемоникаОписание
h j k lнет Это клавиши посимвольного перемещения, тождестенные стрелкам. Стрелки есть не на всех клавиатурах, кроме того, для людей владеющих слепым набором такой способ перемещения удобен, так как им не приходится снимать руки с клавиатуры, для того, чтобы добраться до нужного символа.
wwordПеремещение к началу следующего слова
WWORD Перемещение к началу следующего слова, но под словом подразумевается не совокупность букв, а совокупность непробельных символов. Таким образом, URL http://www.vim.org/ состоит из нескольких слов, но из одного СЛОВА.
eendПеремещение вперёд, к концу слова
EENDПеремещение вперёд, к концу СЛОВА
bbeginПеремещение назад, к началу слова
BBEGINПеремещение назад, к началу СЛОВА
nnext Применяется после поиска в Search mode. Повторить поиск вперёд.
NнетПовторить поиск назад.
}нетПеремещение в конец абзаца
{нетПеремещение в начало абзаца
)нетПеремещение в конец предложения
(нетПеремещение в начало предложения
0нетПеремещение в начало строки
^нетПеремещение к первому символу в строке
$нетПеремещение в конец строки
+нетПеремещение в начало следующей строки
-нетПеремещение в начало предыдущей строки
f<letter>find Перемещение на следующий в строке символ <letter>
F<letter>find Перемещение на предыдущий в строке символ <letter>
t<letter>till Перемещение на позицию предшествующую следующему в строке символу <letter>
T<letter>till Перемещение на позицию следующую сразу за предыдущим в строке символом <letter>
;нет повторить последнее движение заданное клавишами f, F, t, или T
,нетТо же, что ; но в другом направлении
%нет Перемещается на скобку соответствующую той, что под курсором

Перед движением можно вводить числовой префикс. Например: 3} — переместиться на 3 абзаца вниз.

Если перед движением указать некоторое действие, то оно будет проделано с той областью текста, через которую проходит курсор при движении. Например: dw — стереть слово.

Таблица 7.3. Действия в vi(1), Normal mode

КомандаМнемоникаОписание
<move>ddelete Удалить текст, через который осуществлялось движение. При удалении текст помещается в буфер
dddeleteУдаляет целиком текущую строку
Ddelete Удаляет текст от текущего символа до конца строки
<move>yyank Поместить текст через который осуществлялось движение в буфер (не удаляя)
yyyankПоместить в буфер целиком текущую строку
YyankТо же, что и yy, как ни странно
<move>cchange Удалить текст через который осуществлялось движение и немедленно перейти в Insert mode
ccchange Удалить текущую строку и немедленно перейти в Insert mode
Cchange Удалить текст от текущей позиции до конца строки и немедленно перейти в Insert mode
ppasteВставить текст из буфера
PpasteВставить текст из буфера слева от курсора
xнет Удалить символ под курсором. (На заметку: сочетание клавиш xp меняет местами два символа. Почему?)
Xнет Удалить символ слева от курсора (как клавиша BackSpace)
~нет Инвертировать регистр букв (строчная буква меняется на прописную, а прописная на строчную). Например сменить UNIX на unix: 4~
r<letter>нетЗаменить символ находящийся под курсором на <letter>
< <move>нет Уменьшить отступ у текста захваченного движением <move>
> <move>нет Увеличить отступ у текста захваченного движением <move>
Uundo Отменить последнее действие. В vi(1) можно сделать многократное undo, весма нетривиальным способом, на первый взгляд оно кажется однократным[a]. В vim(1) объём undo можно задать любым.
.нетПовторить последнее действие
iinsertВход в Insert mode слева от курсора
IinsertВход в Insert mode в начале строки
aappend Вход в Insert mode справа от курсора (это удобно, если вы переместились в конец слова клавишей e)
AappendВход в Insert mode в конце строки
Rinsert Вход в Replace mode (то же, что Insert, но при наборе символы замещают текст)
oнет Добавить строку под курсором, встать на неё и войти в Insert mode
Oнет Добавить строку над курсором, встать на неё и войти в Insert mode
/нетВход в Search mode для поиска вперёд
?нетВход в Search mode для поиска назад
ZZнетЗаписать файл и выйти

[a] Если вы в vi(1), в Normal mode нажимаете клавишу «u» вы делаете undo. Повторное нажатие приведёт к тому, что вы сделаете undo на undo (т.е. redo). Однако, если вы после нажатия на «u» (undo) нажмёте на точку «.», то вы совершите повтор последнего действия, т.е. ещё одно undo. Таким образом, если вам надо отменить 5 действий, вы должны нажать в Normal mode «u4.». Аналогично можно сделать несколько redo.

Например, если у нас есть надпись <entry>НАДПИСЬ</entry> и нам надо заменить её на <entry>ЬСИПДАН</entry> мы встаём на начало строки и выполняем такое действие: f>lct<ЬСИПДАН правда всё просто и очевидно? Потренируйтесь, обещаю вам, что через неделю вы перестанете понимать как вы до сих пор обходились без vi(1).

7.3.2. Insert Mode

Из Insert mode главное — уметь выходить. Для этого есть миниму два способа: <Esc> или Ctrl+C. Последнее удобнее по эргономичным соображениям.

Вас может удивить, что в vi(1) в Insert mode не всегда можно перемещаться стрелками, не всегда работает BackSpace. Научитесь пользоваться «родными» клавишами vi(1) — их главное преимущество состоит в том, что они работают всегда на всех терминалах, заходите ли вы с чужого макинтоша на тостер под управлением NetBSD или запустили экзотический эмулятор терминала и держите в руках клавиатуру SUN на которой все кнопки другие, а видете её первый (и быть может последний) раз в жизни.

7.3.3. Search mode

Поиск в vi(1) осуществляется либо вперёд, либо назад. Соответственно вход в этот режим осуществляется клавишими / или ?. Выход, так же как и из Insert mode — <Esc> или Ctrl+C.

vi(1) осуществляет поиск при помощи регулярных выражений. В vim(1) их возможности были сильно расширены. В настоящий момент возможности регулярных выражений в vim(1) даже превосходят возможности регулярных выражений в perl(1). К сожалению, работают они значительно медленнее. Но мы рассматриваем не vim(1), а чистый vi(1).

Таблица 7.4. Регулярные выражения в vi(1)

ОператорОписание
.любой символ
[abc]любой символ из указанного набора
[^abc]любой символ отсутствующий в указанном наборе
<atom>* «квантификатор» — vi(1) ищет сколько угодно вхождений <atom'а>
\ Экранирование последующего символа, например, если нам надо найти текст a* мы должны искать a\*, чтобы * не была интерпретирована как квантификатор

Увы, в изначальном vi(1) синтаксис регулярных выражений не был столь развит как в современном vim(1).

В vi(1) FreeBSD можно выставить переменную searchinc (как именно, сказано ниже) и тогда поиск станет инкрементным (т.е. курсор будет перемещаться в процессе набора текста в строке поиска). В vim(1) для этого служит переменная incsearch. По всей видимости, какие-то усовершенствования в vi(1) всётаки вносились...

7.3.4. Command line mode

Некоторые действия можно выполнить в vi(1) только с командной строки. Например задание значения переменной. Вход в командную строку осуществляется из Normal mode клавишей :. Переменные могут принимать числовые значения, а могут выставляться в истину или ложь. В последнем случае они должны задаваться с префиксом no:

  • :set tabstop=8 — приравнять ширину табулятора 8 символам
  • :set tabstop? — Узнать ширину табулятора
  • :set number — включить нумерацию строк
  • :set nonumber — выключить нумерацию строк
  • :set all — вывести список переменных и их значения

Многие команды можно задавать не полностью выписывая имя команды, например :r, :re, :rea и :read это одна и та же команда. Такое имя мы будем записывать так: :r[ead]

Опции тоже могут записываться сокращённо. Таким образом, команды :set nonumber и :se nonu эквивалентны.

Таблица 7.5. Некоторые команды vi(1)

КомандаОписание
:se[t] <option>управляет переменными (см. выше в тексте)
:r[ead] <file> Читает <file> и вставляет его содержимое после курсора
:r[ead]!<cmd> Выполняет в команду <cmd> и вставляет её вывод после курсора
:!<cmd>Выполняет в команду <cmd>
:w[rite] [file] Записать file, если file не указан, записывается текущий файл (т.е. как «кнопка Save»)
:w[rite]! [file] То же, что и :w, но позволяет перезаписать файл открытый в режиме «только для чтения» (например, если вы владелец файла и у вас на него пермиссии r--, vi(1) временно изменит их на rw-).
:q[uit]Выйти из редактора (без сохранения)
:q[uit]! Выйти из редактора (без сохранения) даже если текст был изменён
:wq, :x ZZ Записать файл и выйти из редактора (ZZ в Normal mode)
:wq!, :x! Записать файл даже если он был открыт в режиме «только для чтения» (см. выше) и выйти из редактора
:[range]s[ubstitute]/pattern/subst/[flags] В строках из указанного диапазона искать pattern и заменять его на subst. Если диапазон не указан, замена осуществляется только в текущей строке, если указан флаг g замена производится любое количество раз в каждой строке (иначе заменяется только первое вхождение). Диапазон может указываться в формате n,m (где n и m — номера строк или специальные символы: . — текущая строка, $ — последняя строка в файле). Чтобы произвести замену во всём файле надо указать диапазон 1,$ или %.
:ve[rsion] Напечатать версию редактора vi(1)
:N <file> Разбить окно на две части и открыть файл во втором окне. Переключаться между окнами Ctrl+w. Внимание! Этой функции нет в POSIX vi(1). В vim(1) это делается другим способом. Эта функция есть только в описываемой версии vi встроенной в FreeBSD.

В приведённой ниже таблице перечислены некоторые опции vi(1). если в поле «тип» написано bool, это значит, что переменная имеет логическое значение и устанавливается командой :set option или :set nooption. Если в столбце POSIX стоит «-», то этой опции нет в POSIX-vi, она есть только в описываемой версии vi(1) FreeBSD и с высокой вероятностью в vim(1) эта опция выставляется другим способом.

Таблица 7.6. Некоторые опции vi(1) выставляемые командой :set

ОпцияТипPOSIXОписание
краткаяполная
listlistbool+ Видоизменяет отображение файла таким образом, чтобы пользователь мог отличить пробелы от табуляторов
nunumberbool+Отображает номера строк
tstabstopinteger+задаёт ширину табулятора
swshiftwidthinteger+ задаёт величину отступа добавляемую, например, командой >
searchincsearchincbool-включает инкрементный поиск
rulerrulerbool- Отображает номер строки и колонки в нижней строке экрана
icignorecasebool+Неразличать регистр при поиске
roreadonlybool+ Файл открыт в режиме «только для чтения»
wswrapscanbool+ При поиске, по достижении конца файла, продолжить поиск с начала до курсора. Т.е. искать во всём файле.

Надо честно признаться, я не осветил возможностей vi(1) и на 20%, не говоря уже о vim(1). С другой стороны, объём сведений данных здесь достаточен для повседневной работы и для сдачи экзамена BSDA.

7.4. Определение является ли файл бинарным, текстовым или содержащим данные

Описание:  Системы BSD используют соглашения об именовании файлов, для того, чтобы было проще определить чем является файл. Однако кандидат должен понимать, что это только соглашения и уметь использовать базу данных magic для определения того, чем является файл.

Практика: file(1), magic(5)

Комментарий

Команда file(1) предназначена для того, чтобы определить тип файла.

$ file test.pdf
test.pdf: PDF document, version 1.4
$ mv test.pdf test
$ file test
test: PDF document, version 1.4
        

Как видите, команда file(1) в состоянии распознать тип файла даже если он лишён расширения. Делает это она при помощи некоторой базы данных с «магическими» числами: /usr/share/misc/magic. Формат этой базы описан в странице man magic(5).

Первым делом команда file(1) пытается выяснить чем собственно является файл не изучая его содержимого, при помощи системного вызова stat(2). Таким образом определяется является ли файл файлом, каталогом, символьной ссылкой, сокетом, устройством или именованным каналом. Если это файл, то не пуст ли он.

Затем, если это файл, изучается его содержимое. На этой стадии выясняется является ли этот файл исполнимым, если да, то в каком формате. Ниже я скопировал исполнимый файл /bin/bash с Linux-машины и напустил команду file(1) на него и на bash собранный для FreeBSD.

$ file ./bash /usr/local/bin/bash
./bash:              ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV),
for GNU/Linux 2.0.0, dynamically linked (uses shared libs), stripped
/usr/local/bin/bash: ELF 32-bit LSB executable, Intel 80386, version 1
(FreeBSD), for FreeBSD 5.0.2, dynamically linked (uses shared libs), stripped
        

Как видите, file отличает для какой операционной системы скомпилирована программа. Правила, по которым она это делает, как уже говорилось, прописаны в базе данных /usr/share/misc/magic. В этом файле сказано что где и как надо искать в файле для того, чтобы отнести его к какому-нибудь виду. Например, файлы в формате PDF как правило начинаются со стороки

$ head -1 test.pdf
%PDF-1.4
        

В базе magic(5) про формат PDF написано так:

#------------------------------------------------------------------------------
# pdf:  file(1) magic for Portable Document Format
#

0       string          %PDF-           PDF document   1
>5      byte            x               \b, version %c 2
>7      byte            x               \b.%c          3
        

1 Начиная с нулевого байта искать строку %PDF- (т.е. файл обязан начинаться именно так).
2 Пятый байт обозначает номер версии
3 Седьмой байт — младший номер версии

7.5. Поиск файлов и бинарников в системе

Описание:  Кандидат BSDA должен уметь быстро найти где находится нужный файл и знать какие утилиты нужны для обнаружения бинарников, исходных кодов, страниц man и файлов. Кандидат должен уметь обновить базу данных locate(1)

Практика: whatis(1), whereis(1), which(1), locate(1), find(1), sh(1) включая встроенную команду type и опции -v и -V, locate.updatedb(8), locate.conf(5).

Комментарий

7.5.1. whatis(1)

Команда whatis(1) ищет краткое описание программы в некоторой индексированной базе данных. База данных создаётся командой makewhatis. Она разбита на файлы, хранящиеся там же, где и сами базы man: */man/whatis. Обычно это делается раз в неделю при помощи демона cron (в DragonFly BSD и FreeBSD при помощи задания из системы periodic, в OpenBSD при помощи /etc/weekly).

$ whatis grep
grep(1), egrep(1), fgrep(1), zgrep(1), zegrep(1), zfgrep(1), bzgrep(1), bzegrep(1),
bzfgrep(1) - print lines matching a pattern
        

7.5.2. whereis(1), which(1)

Команда whereis(1) в FreeBSD и DragonFly BSD ищет расположение бинарного файла, соответствующей ему страницы man и расположение каталога с исходным кодом для этой программы.

$ whereis grep
grep: /usr/bin/grep /usr/share/man/man1/grep.1.gz /usr/src/gnu/usr.bin/grep
        

В OpenBSD и NetBSD whereis(1) более лаконична и сообщает только о расположение исполнимого файла. Таким образом, в этих системах она не отличима от команды which(1).

7.5.3. locate(1)

Команда locate(1) позволяет искать файлы в индексированной базе данных. Поиск в такой базе осуществляется практически мгновенно, что выгодным образом отличает команду locate(1) от команды find(1). Однако база данных locate нуждается в постоянном обновлении. Иначе результат работы этой команды может оказаться неактуальным. Обычно обновление базы locate осуществляется через демон cron, как и обновление базы whatis. В DragonFly BSD и FreeBSD это задание присутствует в списке задач periodic(1) weekly, в OpenBSD и в NetBSD в скрипте /etc/weekly.

Обновление базы данных по всех системах BSD производится программой locate.updatedb(8) находящейся по адресу /usr/libexec/locate.updatedb. Конфигурационный файл этой программы в DragonFly BSD, FreeBSD и OpenBSD — /etc/locate.rc. В NetBSD — /etc/locate.conf.

Запуск команды locate.updatedb(8) в правами root не лучшая идея. В этом случае в базу данных locate(1) — /var/db/locate.database попадёт вся информация о файловой системе, и злоумышленник сможет получить информацию о составе каталогов, на которые у него нет прав чтения. Обычно команду locate.updatedb(8) запускают от пользователя nobody, если у вас есть сомнения, посмотрите как это сделано в скриптах вызываемых через cron. В FreeBSD можно выполнить команду /etc/periodic/weekly/310.locate.

7.5.4. find(1)

Команда find(1) тоже предназначена для поиска файлов, однако она, в отличие от locate, осуществляет реальный поиск в системе, а не заглядывает в базы данных. Работает она, поэтому, значительно медленнее, однако её возможности чрезвычайно велики. Подробнее она будет описана ниже (см. Раздел 7.6, «Поиск файла по заданным атрибутам»).

7.5.5. sh type

Не все команды вызываются при помощи сценариев или бинарников. Есть ещё встроенные команды оболочки, определённые функции. Так, например, по команде which alias мы увидим некоторый бинарный файл /usr/bin/alias. Но на самом деле, alias это встроенная команда, как в sh(1), так и в csh(1). Чтобы отличить встроенную команду от обычной существует команда type. Она же поможет нам определить не является ли используемая нами команда собственно alias'ом (псевдонимом).

$ type alias
alias is a shell builtin
$ type grep
grep is /usr/bin/grep
$ type ls
ls is aliased to `ls -GF'
        

В csh команды type нет.

7.6. Поиск файла по заданным атрибутам

Описание:  Утилита find(1) незаменима при поиске файлов с заданными параметрами. Кандидат BSDA должен свободно владеть ею. На экзамене его могут попросить найти файл с заданным последним временем изменения, размером, типом, файловыми флагами, UID, GID, пермиссиями или содержащим в названии какой-то шаблон.

Практика: find(1)

Комментарий

Команда find(1) предназначена для поиска файлов по заданному критерию. Формат команды:

find [опции] где_искать [что искать (условия)] [действие]
        

Опции могут быть различные, они регулируют поведение find(1) при поиске. К тому же они в разных версиях и в разных системах разные. Так, напрмер, опция -E, изменяющая синтаксис регулярных выражений в опциях -regex и -iregex подобно аналогичной опции в grep(1), имеется только в FreeBSD.

Пожалуй важно знать опцию -x. Она предотвращает поиск на устройствах отличных от устройства, с которого поиск начался. Например:

find -x /home/user
        

Эта команда выведет список всех файлов в домашнем каталоге пользователя user и во всех подкаталогах, кроме каталогов являющихся точками монтирования других устройств (/home/user/mnt/floppy, /home/user/mnt/cdrom, /home/user/mnt/nfs).

Путь надо указывать обязательно. Некоторые версии GNU find проводят поиск относительно текущего каталога, если им не указать путь, find в BSD требует явного указания пути. В особых случаях, когда путь, в котором надо производить поик имеет необычное имя, можно указать его как аргумент опции -f.

7.6.1. Условия для поиска командой find(1)

Условия для поиска задаются опциями, перечисленными ниже. При задании нескольких опций, они объединяются через оператор «и». Связку «и» можно задать явно используя опцию -and. Связка «или» задаётся опцией -or. Унарное отрицание — ! и символы группировки — (...), в sh и csh необходимо защищать используя либо кавычки, либо \.

-amin n -cmin n -mmin n
Условие истинно, если разница между временем когда был запущен поиск и временем файла меньше n минут. Здесь под временем файла имеется ввиду: -amin — access time (время последнего доступа к файлу), -cmin — change of file status information (время изменения информации о состоянии файла) -mtime — modification time (время изменения файла)
-anewer file -cnewer file -mnewer file
Условие истинно, найденный файл моложе указанного. Здесь под временем файла имеется ввиду: -anewer — access time (время последнего доступа к файлу), -cnewer — change of file status information (время изменения информации о состоянии файла) -mnewer — modification time (время изменения файла)
-atime n -ctime n -mtime n

Условие истинно, если разница между временем когда был запущен поиск и временем файла округлённая вверх, в точности n суток. Здесь под временем файла имеется ввиду: -amin — access time (время последнего доступа к файлу), -cmin — change of file status information (время изменения информации о состоянии файла) -mtime — modification time (время изменения файла)

У времени можно задавать знак: -mtime -7 — ищем файлы изменённые за последнюю неделю, -mtime +7 — ищем файлы не менявшиеся в течение недели.

В FreeBSD имеется расширение синтаксиса: опциям -atime, -ctime и -mtime можно указывать время с размерностью в секундах, минутах, часах, днях и неделях. Например 2s, 3m, 4h, 5d, 6w. Можно комбинировать размерности: 5d6w — шесть недель и пять дней.

В OpenBSD и NetBSD для аналогичного поиска придётся пользоваться опциями -amin, -cmin и -mmin, переводить время в минуты и использовать где надо отрицание !.

-newer file
Условие истинно, если найденный файл изменён позже указанного
-newerXY file

Опция есть только в FreeBSD!

Условие истинно, если найденный файл имеет большее время доступа (X=a), изменения статуса (X=c), модификации (X=m) указанного чем время доступа (Y=a), изменения статуса (Y=c), модификации (Y=m) у указанного файла.

-empty
Условие истинно, если найденный файл или каталог пуст
-flags [-] flags
Условие истинно, если найденный файл или каталог имеет указанные флаги. Флаги являются свойством файловой системы UFS и описаны в справочной странице chflags(1). Если знак - не указан, условие истинно, если флаги в точности соответствуют указанным. Если знак - указан, условие совпадает, если как минимум указанные флаги присутствуют.
-perm [-] mode
mode может быть как символьным (chmod), так и восьмеричным. - имеет то же значение, что и в опции -flags.
-group group, -user user
Условие истинно, если найденный файл принадлежит пользователю user или группе group. Можно указавать как имена, так и ID (если указано чисто и пользователя с таким именем нет, оно толкуется как ID).
-nogroup, -nouser
Условие истинно, если найденный файл принадлежит неизвестному пользователю или неизвестной группе.
-type type

Условие истинно, если найденный файл имеет указанный тип. Возможные типы файла:

bblock specialблочное устройство
ccharacter specialсимвольное устройство
ddirectoryкаталог
fregular fileобычный файл
lsymbolic linkсимвольная ссылка
pFIFOименованный канал
ssoketсокет

-fstype type
Условие истинно, если найденный файл находится на устройстве с файловой системой типа type. Возможные типы файловых систем можно узнать при помощи sysctl(8) (sysctl vfs). Кроме того, можно использовать ключевые слова local и rdonly.
-[i]name pattern
Имя файла. Можно указать шаблон с *, ? и []. Опция -iname отличается тем, что игнорирует регистр.
-[i]path pattern
Путь к файлу. Можно указывать шаблон с *, ? и []. / считается обычным символом. Вариант нечувствителоьный к регистру реализован в FreeBSD и NetBSD.
-[i]regex pattern

Опция не реализована в OpenBSD!

Условие истинно, если имя файла (вместе с путём) полностью соответствует регулярному выражению pattern. Что значит полностью? Шаблон foo не соответствует пути ./foo/bar, а .*foo.* соответствует. Вариант -iregex нечувтвителен к регистру.

-size n[c]
Условие истинно, если файл занимает n блоков по 512 байт. Внимание! команда find(1) не использует переменную окружения BLOCKSIZE. Если указан суффикс c, то размер берётся точно в байтах. Так же как и в случае с опцией -atime можно задавать знак: -size -1024c — искать файлы размером меньше килобайта.
-maxdepth n и -mindepth n
Максимальная и манимальная глубина погружения в подкаталоги. Например: -maxdepth 1 искать файлы только в текущем каталоге, не погружаясь в подкаталоги.

7.6.2. Действия выполняемые командой find(1) с найденными файлами

Простейшее действие — напечатать имя файла на STDOUT. Это действие по умолчанию предпринимается если ничего другого не указано. Оно эквивалентно указанию опции -print.

-print
Действие по умолчанию. Напечатать имя файла.
-print0
Напечатать имя файла. Имена при этом будут разделяться нулевым символом. Опция сделана для совместной работы с командой xargs(1).
-ls
Про каждый файл выводится подробная информация. Так, как будто к файлам применили команду ls -dgils.
-delete

Опция есть только в FreeBSD!

Удалить найденные файлы и директории.

-exec команда [опции [{}]] ;
Наиболее общий случай. Позволяет применить к найденным файлам произвольную команду. Опции будут переданы этой команде. Если в опциях встретится пара скобок {}, то она будет заменена именем файла (с путём). Символ ; означает, что в этом месте закончилась команда и её опции.
-execdir команда [опции [{}]] ;
То же, что и -exec, но при выполнении команды find(1) переходит в каталог, где находится файл, а {} заменяет на имя файла без пути.
-ok команда [опции [{}]] ;
То же, что и -exec, но перед выполнением команды find(1) запрашивает подтверждение у пользователя.
-exec команда [опции [{}]] +

Опция есть только в FreeBSD!

Эквивалентна опции -exec ... ;, но замещает {} не одним найденным файлом, а списком файлов. Таким образом, указанная команда вызывается лишь однажды. Это работает как же, как связка с командой xargs(1).

7.6.3. Связка с командой xargs

xargs [опции] команда с аргументами
        

Команда xargs(1) читает список файлов из своего STDIN и подставляет эти файлы в качестве аргумента команде указываемой ей в аргументе. Её удобно применять в связке с find(1). Например, пусть нам надо узнать сколько строк в каком из журнальных файлов на нашей системе.

$ find /var/log \! -name *bz2 -type f | xargs wc -l
     875 /var/log/auth.log
     125 /var/log/cron
     270 /var/log/debug.log
     .....
        

Знак \ перед ! мы поставили для того, чтобы sh не интерпретировал его по-своему. Аналогичного результата мы могли бы добиться используя опцию -exec.

$ find /var/log \! -name *bz2 -type f -exec wc -l {} \;
     875 /var/log/auth.log
     125 /var/log/cron
     270 /var/log/debug.log
     .....
        

Даже на современной, быстродействующей машине разница в выполнении этих двух команд видна невооружённым взглядом. Мы можем её измерить:

$  time find /var/log \! -name *bz2 -type f | xargs wc -l > /dev/null

real    0m0.032s
user    0m0.000s
sys     0m0.024s

$ time find /var/log \! -name *bz2 -type f -exec wc -l {} \; > /dev/null

real    0m0.242s
user    0m0.040s
sys     0m0.191s
        

Разница составила целый порядок. А ведь здесь ещё мало файлов. В чём же дело? А дело в том, что find(1) с опцией -exec для каждого найденного файла заново вызывает команду wc(1). Вызов команд в UNIX (и не только в нём) — очень дорогая процедура. В случае с использованием xargs(1), мы вызвали wc(1) только один раз. Подсчёт статистики связанный с чтением и анализом содержиного файла более прост, чем сам вызов wc(1).

Ещё очень полезной особенностью xargs(1), является то, что он может разбирать список файлов с STDIN, считая символом разделителем не пробел, а нулевой символ, которого в принципе не может быть в имени файла. Это может быть очень важно, например, при работе с разделами Windows или Macintosh.

$ find /mnt/samba ... -print0 | xargs -0 ...
        

Теперь, какие бы причудливые имена ни встретились нам, даже если они содержат кавычки, пробелы, символы конца строки, они будут обработаны корректно.

7.7. Написание несложных Bourne-скриптов

Описание:  Большинство задач системного администрирования могут быть автоматизарованы с использованием shell-скриптов. Кандидат BSDA должен знать о преимуществах и недостатках использования скриптов Bourne shell более, нежели csh(1) или bash(1). Кандидат должен различать «магическую строку» (shebang), комментарии, позиционные параметры и специальные параметры, маски в шаблонах, знать как правильно использовать кавычки и обратные слеши, операторы for, while, if, case и esec. Кандидат должен знать как сделать скрипт исполнимым и как его отлаживать.

Практика: sh(1), chmod(1)

Комментарий

sh(1) используется не столько как интерактивный shell (надо признать, что sh(1) в работе не так удобен, как его более современные аналоги), сколько как язык программирования используемый для автоматизации рутинных процедур. На sh(1) написано множество скриптов используемых при старте системы, а так же скриптов обслуживающих её функционирование.

В первом приближнии sh(1) позволяет попросту перечислить внешние команды, которые необходимо выполнить. Оданко sh(1) так же обладает возможностью делать проверки, выполнять циклы, обрабатывать исключительные ситуации (перехватывать сигналы) и многими другими возможностями. Не стоит забывать, однако, что sh(1), это всего лишь удобное средство автоматизации. Несмотря на циклы и логику, несмотря на наличие собственной целочисленной арифметики, главное, для чего используется sh(1) — это вызов внешних программ, которые, собственно, и делают основную работу.

7.7.1. Магическая строка (shebang)

С чего начинается скрипт? С некоторой магической строки — shebang. Вообще, последовательность действий операционной системы с файлом при попытке пользователя запустить его на исполнение, выглядит примерно так:

  1. Сперва система пытается понять является ли вызываемый файл исполнимым бинарным файлом. Если да, то его можно сразу запустить.
  2. Если нет, то надо посмотреть на первые два символа файла. Если это #! то перед нами «магическая строка» (shebang). Вся строка от третьего символа до конца строки является указателем на интерпретатор. Надо выполнить указанную строку, подав интерпретатору на вход скрипт. Такая конструкция позволяет запускать интерпретатор с дополнительными опциями: #!/usr/local/bin/perl -w или делать сложные вызовы, указывая специальные переменные окружения: #!/usr/bin/env -i /usr/local/bin/python.
  3. Наконец, если и магической строки не найдено, файл передаётся на исполнение интерпретатору /bin/sh.

Даже несмотря на наличие такого умолчания, разумно указывать интерпретатор в явном виде. Сценарии sh должны начинаться со строки #!/bin/sh.

На вход интерпретатору подаётся весь скрипт целиком, включая первую строку с shebang. Поэтому скриптовый язык обязан воспринимать знак #как символ комментария, как минимум в первой строке. В этом легко убедится. Пусть у нас есть скрипт test.cat состоящий из двух строк:

#!/bin/cat
Hello
        

При попытке выполнить скрипт мы получим:

$ chmod 755 test.cat
$ ./test.cat
#!/bin/cat
Hello
        

Ещё одной особенностью скрипта является то, что он обязан иметь пермиссии не только на исполнение, но и на чтение. В противном случае скрипт не сможет быть направлен на стандартный вход указанному интерпретатору.

В разделе посвящённом переменным окружения обсуждается вопрос использования утилиты env(1) в shebang и вопросы связанные с безопасностью при использовании различных интерпретаторов в «магической строке».

7.7.2. Почему sh(1)?

Надо честно признать, повседневно работать в sh(1) неудобно. Да, sh(1) неудобный интерпретатор, ему есть множество альтернатив, которые, к тому же, порой полностью совместимы по синтаксису. Почему же в операционных системах BSD так упорно цепляются за него? Для начала приведу выдержку из FreeBSD FAQ.

Вопрос 7.8:  Почему возможности /bin/sh так малы? Почему бы во FreeBSD не использовать bash или какой-либо другой командный процессор?

Ответ:  Потому что в стандарте POSIX сказано, что все командные процессоры должны вести себя так же, как shell.

Более подробный ответ заключается в следующем: многим требуется, чтобы разрабатываемые скрипты для командного процессора были переносимы между многими системами. Именно поэтому в POSIX очень подробно описан командный процессор и набор утилит. Большинство скриптов пишутся на языке процессора Bourne shell, к тому же некоторые важные программные вызовы (make(1), system(3), popen(3) и их аналоги на языках скриптов высокого уровня, таких как Perl или Tcl) предполагают для интерпретации команд использование именно Bourne shell. Так как Bourne shell используется столь широко и часто, то очень важно, чтобы он стартовал очень быстро, его поведение было строго регламентировано и при этом потребности в оперативной памяти были малы.

В имеющейся реализации мы приложили максимум усилий для воплощения в жизнь всех этих требований одновременно. Для того, чтобы сохранить /bin/sh небольшим по размеру, мы не включили многие из обычных возможностей, которые имеются в других командных процессорах. Однако в Коллекцию Портов включены командные процессоры, обладающие гораздо большими возможностями, такие, как bash, scsh, tcsh и zsh. (Вы можете сами сравнить использование памяти всеми этими оболочками, посмотрев в колонки «VSZ» и «RSS» вывода команды ps -u).

Думается, что слова эти нуждаются в некотором дополнительном пояснении. Когда UNIX запускает новый процесс, ядро осуществляет следующую сложную цепочку действий: сперва оно выполняет системный вызов fork(2) и копирует область памяти соответствующую родительскому процессу. Появляется два совершенно одинаковых родительских процесса, которые различаются только кодом возврата функции fork(2). Родитель получает PID потомка, а потомок — 0. По этому нулю потомок догадывается, что он потомок и осуществляет системный вызов exec(2), в результате чего он полностью замещается новым процессом.

Из сказанного должно быть ясно, что во-первых вызов новой программы, это очень дорогая операция (мы видели это, когда сравнивали работу аргумента -exec у программы find(1) и использование команды xargs(1) в Раздел 7.6, «Поиск файла по заданным атрибутам»), а во-вторых, чем сложнее программа вызывающая новый процесс, тем дороже эта операция. Между тем, программирование на Bourne Shell сводится именно к написанию большого количества вызовов внешних программ.

Сравним работу двух одинаковых с виду программ на sh:

#!/bin/sh

i=0
while [ $i -lt 1000 ]
do
  i=`echo $i+1|/usr/bin/bc`
done
echo $i
        

и на bash:

#!/usr/local/bin/bash

i=0
while [ $i -lt 1000 ]
do
  i=`echo $i+1|/usr/bin/bc`
done
echo $i
        

Как видите, эти программы отличаются только первой строчкой. В этих программах осуществляется в цикле тысячекратный вызов программы bc(1), крохотного калькулятора, для увеличения счётчика. И столько же раз вызвана команда test(1) (см. ниже).

$ time ./test.sh
1000

real    0m7.447s
user    0m1.428s
sys     0m5.812s

$ time ./test.bash
1000

real    0m14.223s
user    0m2.273s
sys     0m11.559s
        

Легко видеть, что тяжеловесный bash(1) ворочал этот скрипт почти вдвое дольше. На разных опробованных мною системах соотношение времени выполнения этого скрипта bash/sh колебалось от 1.3 до 1.9.

7.7.3. Программирование в Bourne Shell

7.7.3.1. Синтаксис

Таблица 7.7. Синтаксическая таблица Bourne Shell

ЭлементОписание
#Комментарий
;Конец команды. Тождественен концу строки. Команда будет выполнена в foreground, т.е. sh(1) будет ждать, пока она выполнится (ср. с & ниже).
&Конец команды. Команда будет выполнена в фоновом режиме, т.е. sh(1) не будет ждать, пока она выполнится (ср. с ; выше). Не путать с &&
&&Логическое И. если до && стоит команда, которая выдала нулевой код возврата (истина), то выполняется команда следующая за &&, суммарным кодом возврата будет код возврата второй команды. Если нет, то вторая команда не выполняется, а код возврата берётся от первой операции (т.е. ложь).
||Логическое ИЛИ. если до || стоит команда, которая выдала ненулевой код возврата (ложь), то выполняется команда следующая за ||, суммарным кодом возврата будет код возврата второй команды. Если нет, то вторая команда не выполняется, а код возврата берётся от первой операции (т.е. истина).
|Символ pipe (труба). STDOUT команды перед | перенапрвляется на STDIN следующей команде. Подробно о перенаправлении говорится в Раздел 7.1, «Перенаправление вывода и использование tee(1)». Команды объединённые через | вместе называются конвейером (pipeline). Код возврата конвейера равен коду возврата последней команды в конвейере.
[n]>&mПеренаправление STDOUT или файлового дескриптора n в файловый дескриптор m. Подробно о перенаправлении говорится в Раздел 7.1, «Перенаправление вывода и использование tee(1)».
[n]> fileПеренаправление STDOUT или файлового дескриптора n в файл. Подробно о перенаправлении говорится в Раздел 7.1, «Перенаправление вывода и использование tee(1)».
[n]< fileПеренаправление STDIN, либо файлового дескриптора n из файла. Подробно о перенаправлении говорится в Раздел 7.1, «Перенаправление вывода и использование tee(1)».
[n]<&-Закрыть STDIN, либо файловый дескриптор n
[n]>&-Закрыть STDOUT, либо файловый дескриптор n
var=...Присваивание переменной var
$varВызов значения переменной var
\Экранирование следующего символа. Например, если find(1) ожидает получить в качестве аргумента знак ;, то, для того, чтобы этот знак не был интерпретирован sh(1), а был-бы благополучно доставлен в find(1), в командной строке следует написать \;
'Внутри одинарных кавычек решительно все символы не имеют никакого специального значения. Полное экранирование.
`Команда внутри обратных кавычек будет выполнена, а её STDOUT будет подставлен в командную строку вместо кавычек. При этом концы строк будут заменены на пробелы.
"Неполное экранирование. Внутри двойных кавычек не экранируются обратные кавычки и знак $ (ссылка на переменную).
!Инвертирует код возврата последующей команды (или конвейера).
$(...)То же, что и обратные кавычки, но может быть вложенным.
$((...))Ожидается, что внутри будет арифметическое выражение. Оно будет вычислено и подставлено в командную строку вместо скобок. Внимание! Аналогичные скобки $[...], это расширение bash(1) и sh(1) его не поддерживает.
(...)команды в круглых скобках будут выполнены в отдельном подпроцессе. Область видимости переменных, определённых в скобках, не выйдет за их пределы.
name () {...}Определение функции (см. ниже).
. filenameВыполнение набора команд из файла filename. (См. ниже про «модули»)
:Встроенная команда ничего не делающая, но возвращающая истину.

7.7.3.2. Работа с переменными в sh(1)

Присваивание переменной осуществляется при помощи оператора =. Вызов определённой ранее переменной, при помощи префикса $. Например:

$ PI=3.1415926535897931
$ echo $PI
3.1415926535897931
          

Следует подчеркнуть: переменные и переменные окружения это не одно и то же. Любая переменная окружения видна как переменная, но не любая переменная видна как переменная окружения. Чтобы переменная стала переменной окружения её надо экспортировать:

$ PI=3.1415926535897931
$ echo $PI
3.1415926535897931
$ printenv PI
$ echo $?
1
$ export PI
$ printenv PI
3.1415926535897931
          

Т.е. до вызова команды export, Переменная PI была, а переменной окружения PI не было. (Подробно о команде printenv(1) можно узнать в разделе Раздел 7.2.1.1, «env(1), printenv(1)») Здесь использована так же переменная $? в которой хранится код возврата последней операции. Подробно специальные переменные перечислены в таблице ниже.

Таблица 7.8. Специальные переменные в Bourne Shell

ПеременнаяОписание
$*Список аргументов, с которыми был вызван скрипт.
$@Список аргументов, с которыми был вызван скрипт.
$#Число аргументов, с которыми был вызван скрипт.
$?Код возврата последней команды (последнего конвейера).
$-Список аргументов, с которыми вызван sh(1)
$$PID родительской оболочки
$!PID последнего отправленного в фон процесса.

7.7.3.3. Условные операторы

В качестве условия в sh(1) выполняется некоторая команда, и изучается её код возврата. Если код возврата равен нулю, и, следовательно, программа завершилась успешно, sh(1) трактует это как истину, если программа вернула код возврата больше нуля, sh(1) трактует это как ложь.

Проверки можно комбинировать при помощи знаков && (логическое «и») и || (логическое «или»).

В простейшем случае можно вообще обойтись без явного условного оператора, используя лишь комбинацию этих знаков:

uname | grep -q BSD && echo "Это какая-то BSD!" || echo "Не знаю что это."
          

Такой синтаксис краток, но не следует им злоупотреблять. В конечном счёте это ведёт к трудно читаемым программам. Ту же проверку лучше осуществить с использованием явного оператора if:

if uname | grep -q BSD
then echo "Это какая-то BSD!"
else echo "Не знаю, что это."
fi
          

Если эти операторы понадобится написать в одну строку, то надо понимать, что ключевые слова if, then, else и fi, это самостоятельные команды и они в строке они должны предваряться знаком ;.

Ветвь else, разумеется, необязательна. Если нам надо проверить несколько альтернатив, то, чтобы не вкладывать много условных операторов друг в друга, мы можем использовать оператор elif.

if uname | grep -q FreeBSD
then
  echo "Это FreeBSD, на ней может получиться удобная рабочая станция"
elif uname | grep -q OpenBSD
then
  echo "Это OpenBSD, знаменитая своей безопасностью."
  echo "Прекрасный выбор для сервера"
elif uname | grep -q NetBSD
then
  echo "Это NetBSD, она поддерживает самые немыслимые архитектуры."
  echo "Хороший выбор для тостера или холодильника."
else
  echo "Не знаю, что это."
fi
          

Недостатком данной конструкции является то, что здесь шесть раз вызываются программы uname(1) и grep(1). Существует более очевидная конструкция для проверки на соответвие строки списку значений.

case "`uname`" in
FreeBSD)
  echo "Это FreeBSD, на ней может получиться удобная рабочая станция";;
OpenBSD)
  echo "Это OpenBSD, знаменитая своей безопасностью."
  echo "Прекрасный выбор для сервера";;1
NetBSD)
  echo "Это NetBSD, она поддерживает самые немыслимые архитектуры."
  echo "Хороший выбор для тостера или холодильника.";;
BSD|[Dd][Aa][Rr][Vv][Ii][Nn])2
  echo "Есть основания полагать, что это тоже BSD";;
*)3
  echo "Не знаю, что это.";;
esac
          
1 Каждый список команд должен заканчиваться двумя следующими друг за другом точками с запятой — ;;.
2 Перед закрывающей круглой скобкой должен следовать шаблон набранный по правилам shell. (Т.е. допустимы классы в [] и символ *.) Если условию может удовлетворять несколько альтернатив, то их можно объединить через «или» — |. На прмере слова Darvin (так идентифицирует себя ядро MacOS X), показано как сделать проверку нечувствительной к регистру.
3 Это пример того, как при помощи конструкции case...esac сделать аналог ветви else, которая будет срабатывать всегда, когда не сработали все перечисленные варианты.

Специально для условного оператора sh(1) существует программа осуществляющая математические проверки, проверки на существование файловых объектов и равенство строк. В зависимости от результата сравнения эта программа возвращает либо ноль, либо единицу. Речь идёт о программе test(1).

Таблица 7.9. Опции команды test(1)

ОпцияОписание
Проверки файловых объектов
-e <file>Истина, если <file> существует независимо от того, чем он является
-r <file>Истина, если <file> существует и из него можно читать
-w <file>Истина, если <file> существует и в него можно писать
-x <file>Истина, если <file> существует и его можно выполнить
-s <file>Истина, если <file> существует и не пуст
-b <file>Истина, если <file> существует и является блочным устройством
-c <file>Истина, если <file> существует и является символьным устройством устройством
-d <file>Истина, если <file> существует и является каталогом
-f <file>Истина, если <file> существует и является обычным файлом
-h <file> -L <file>Истина, если <file> существует и является символьной ссылкой. Опция -h оставлена для совместимости и не рекомендуется к использованию.
-p <file>Истина, если <file> существует и является именованным каналом (FIFO)
-S <file>Истина, если <file> существует и является сокетом
-k <file>Истина, если <file> существует и на нём установлен stiсky-бит
-t <num>Истина, если файловый дескриптор <num> существует и направлен на терминал. С помощью этой проверки можно убедиться направлен ли вывод скрипта на терминал или перенаправлен в файл
-O <file>Истина, если <file> существует и его владелец тот же, что и EUID данного процесса
-G <file>Истина, если <file> существует и его группа та же, что и EGID данного процесса
<file1> -nt <file2>Истина, если файл <file1> новее (newer then) чем файл <file2>
<file1> -ot <file2>Истина, если файл <file1> старше (older then) чем файл <file2>
<file1> -et <file2>Истина, если файл <file1> и файл <file2> указывают на один и тот же файл
Проверки строк
-n <string>Истина, если строка <string> не пуста
<string>Истина, если строка <string> не пуста
-z <string>Истина, если строка <string> пуста
<s1> = <s2>Истина, если строки <s1> и <s2> одинаковы
<s1> != <s2>Истина, если строки <s1> и <s2> отличаются
<s1> < <s2>Истина, если строка <s1> должна идти перед <s2> по кодам ASCII. Например "abc" < "abd"
<s1> > <s2>Истина, если строка <s1> должна идти после <s2> по кодам ASCII
Проверки чисел
<n1> -eq <n2>Истина, если числа <n1> и <n2> равны (equal)
<n1> -ne <n2>Истина, если числа <n1> и <n2> не равны (not equal)
<n1> -ge <n2>Истина, если число <n1> больше либо равно <n2> (grater or equal)
<n1> -gt <n2>Истина, если число <n1> строго больше <n2> (grater then)
<n1> -le <n2>Истина, если число <n1> меньше либо равно <n2> (less or equal)
<n1> -lt <n2>Истина, если число <n1> строго меньше <n2> (less then)
Объединение условий
-aИ (and)
-oИли (or)
!инвертирование проверки
(...)группирование для операторов «и» или «или»

Для команды test(1) существует альтернативное имя [. Если она вызывается по имени [, то она разбирает командную строку вплоть до того, пока не встретит закрывающую квадратную скобку. Таким образом, следующие четыре конструкции эквивалентны:

$ test -d /usr/ports && echo "найдено дерево портов" || echo "Дерево портов не найдено"
$ [ -d /usr/ports ] && echo "найдено дерево портов" || echo "Дерево портов не найдено"
$ if test -d /usr/ports
> then echo "найдено дерево портов"
> else echo "Дерево портов не найдено"
> fi
$ if [ test -d /usr/ports ]
> then echo "найдено дерево портов"
> else echo "Дерево портов не найдено"
> fi
          

Обратите внимание: вокруг квадратных скобок обязательно должны быть пробелы, потому что [ это не синтаксическая конструкция sh(1), а обычная команда на подобии test(1).

7.7.3.4. Циклы

В sh(1) имеется два вида циклов: цикл с условием и цикл с перебором. Первый действует до тех пор, пока верно некоторое условие. Второй перебирает значения некоторого списка, приравнивая переменную (итератор) каждый раз к новому значению из этого списка. Кроме того, имеются обычные команды для прерывания цикла.

7.7.3.4.1. while — цикл с условием

Следующая программа выводит список квадратов натуральных чисел от 1 до 100, используя цикл с условием while:

i=1
while [ $i -le 100 ]
do
  echo $(($i*$i))
  i=$(($i+1))
done
            

Ключевые слова do и done ограничивают тело цикла, при написании в одной строке они должны предваряться ;.

i=1; while [ $i -le 100 ]; do echo $(($i*$i)); i=$(($i+1)); done
            

Цикл может быть прерван встроенной командой break:

i=1
while :
do
  echo $(($i*$i))
  i=$(($i+1))
  if [ $i -gt 100 ]; then break; fi
done
            

Встроенная команда : всегда возвращает истину (см. Таблица 7.7, «Синтаксическая таблица Bourne Shell»). Вместо неё можно было бы употребить команду /usr/bin/true.

Встроенная команда continue предназначена для прерывания текущей итерации. Т.е. выполнение цикла будет продолжено, но текущая итерация будет прервана. Если после команд break или continue указано число, то оно означает глубину цикла, который будет ими прерван.

7.7.3.4.2. for — цикл с перебором списка

Следующая программа конвертирует все картинки в каталоге image из формата GIF в формат PNG

for filename in image/*.jpg
do
  # Действительно ли это JPEG?
  if ! file $filename | grep -q "JPEG image data"
  then continue
  fi

  # Конвертируем JPEG в PNG
  if convert $filename ${filename%jpg}png
  then echo "$filename -> ${filename%jpg}png"
  else echo "$filename don't converted"
  fi

done
            

Утилита convert(1) — сторонняя утилита. Не входит ни в одну операционную систему BSD по-умолчанию и доставляется отдельно из портов или пакетов.

Конструкция image/*.jpg превратится в список файлов в каталоге image имя которых оканчивается на .jpg.

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

Обратите внимание на использование кавычек: внутри двойных кавычек переменные раскрываются в свои значения. Кавычки мы использовали для того, чтобы в одном случае строка трактовалась бы утилитой grep(1) как один аргумент, несмотря на наличие в ней пробелов, в другом случае, чтобы защитить символ > и в третьем случае защитить одинарную кавычку.

Конструкция ${filename%jpg} указывает sh(1), что надо взять значение переменной $filename и отрезать с конца фрагмент jpg.

7.7.3.5. Функции

sh(1) позволяет определять функции и вызывать их. Переменные $1, $2 и т.д. внутри функций ссылаются не на аргументы скрипта, а на аргументы с которыми функция вызывалась. Ниже определена функция для вычисления квадрата натурального числа и переписан цикл выводящий список квадратов натуральных чисел:

sqrt () {
  echo $(($1*$1))
}

i=1
while [ $i -le 100 ]
do
  sqrt $i
  i=$(($i+1))
done
          

При помощи директивы return функция может вернуть свой собственный код возврата.

7.7.3.6. «Модули»

В sh(1) существует конструкция, позволяющая подгружать внешние файлы с определёнными в них функциями и переменными. Допустим у нас есть файл math в котором имеются следующие определения:

# Описываем константы
PI=3.1415926535897931

# Функция для возведения в квадрат
sqrt () {
  echo $(($1*$1))
}

# Длина окружности
circlen () {
  echo "$PI*$1*2" | /usr/bin/bc
}

# Площадь круга
circarea () {
  sq=`sqrt $1`
  echo "$PI*$sq" | /usr/bin/bc
}
          

Теперь, если мы захотим вычислить длину окружности, или её площадь, нам достаточно внутри скрипта подгрузить данный «модуль». Это делается при помощи оператора . (точка). После того, как модуль подгружен, мы можем использовать все функции и константы, которые в нём определены.

#!/bin/sh

. math

echo "Длина окружности радиуса 3 см равна `circlen 3` см"
echo "А площадь круга того же радиуса равна `circarea 3` см^2"
echo "Причина этого явления в том, что число пи, по прежнему"
echo "равно $PI, и со времён древних греков"
echo "существенно не изменилось..."
          

В этом скрипте мы подгружаем «модуль» math и вызываем функцию подсчёта длины окружности и площади круга, которые в нём определены, а так же ссылаемся на определённую в нём переменную $PI. Этот приём часто используется при написании системных скриптов. В частности, именно так реализованы файлы /etc/defaults/rc.conf и /etc/rc.conf в FreeBSD. Оба являются модулями, в первом определяются константы, вроде:

.................................
inetd_enable="NO"               # Run the network daemon dispatcher (YES/NO).
inetd_program="/usr/sbin/inetd" # path to inetd, if you want a different one.
inetd_flags="-wW -C 60"         # Optional flags to inetd
.................................
          

Во втором они могут частично переопределяться, например:

.................................
inetd_enable="YES"
.................................
          

При этом оба файла последовательно подгружаются в файле /etc/rc.subr в функции load_rc_config().

7.7.3.7. Некоторые приёмы используемые при программировании на sh(1)

7.7.3.7.1. Чтение конфигурационных файлов
7.7.3.7.2. Разбор командной строки

Команда getopts входит в стандарт POSIX и является встроенной командой sh(1). У команды getopts имеется два аргумента: 1) — строка с перечнем возможных опций. После опций у которых возможно значение, ставится двоеточие. 2) — имя переменной, в которую будет сохраняться имя опции. Значение переменной будет сохраняться в переменной $OPTARG. Пример:

#!/bin/sh

while getopts e:h option
do
  case $option in
      h)
      echo "Usage: `/usr/bin/basename $0` [-h|-e text]";;
      e)
      echo Hello, $OPTARG;;
      \?)
      $0 -h;;
  esac
done
            

Теперь вызовем этот скрипт (назовём его getopts.sh).

$ ./getopts.sh -h
Usage: getopts.sh [-h|-e text]
$ ./getopts.sh -a
Illegal option -a
Usage: getopts.sh [-h|-e text]
$ ./getopts.sh -e BSD
Hello, BSD
$ ./getopts.sh -h -e BSD
Usage: getopts.sh [-h|-e text]
Hello, BSD
            
7.7.3.7.3. Конструирование скрипта «на лету», раскрытие переменных

Команда eval просто выполняет свой аргумент. Это позволяет «сконструировать скрипт» складывая команды и аргументы в некоторую переменную, а потом подставить её на выполнение команде eval.

Ниже приведено другое остроумное применение данной команды. Пример взят из файла /etc/rc.subr, являющегося «модулем» для некоторых системных скриптов FreeBSD. Рассмотрим функцию проверяющую значение переменной. Этой функции передаётся имя переменной. Функция проверяет значение этой переменной и, если там стоит слово «no» возвращает единицу, если «yes» — 0, в противном случае предупреждает об ошибке. Для того, чтобы манипулировать и с именем переменной и с её значением применяется команда eval. С её помощью значение переменной помещается в отдельную переменную _value, а имя переменной доступно как аргумент функции, т.е. $1:

#
# checkyesno var
#       Test $1 variable, and warn if not set to YES or NO.
#       Return 0 if it's "yes" (et al), nonzero otherwise.
#
checkyesno()
{
eval _value=\$${1}
debug "checkyesno: $1 is set to $_value."
case $_value in

  #     "yes", "true", "on", or "1"
[Yy][Ee][Ss]|[Tt][Rr][Uu][Ee]|[Oo][Nn]|1)
  return 0
  ;;

  #     "no", "false", "off", or "0"
[Nn][Oo]|[Ff][Aa][Ll][Ss][Ee]|[Oo][Ff][Ff]|0)
  return 1
  ;;
*)
  warn "\$${1} is not set properly - see rc.conf(5)."
  return 1
  ;;
esac
}
            
7.7.3.7.4. Обработка сигналов

Встроенная в sh(1) команда trap позволяет зарегистрировать обработчик сигнала. Если в процессе выполнения скрипт получит указанный в команде trap сигнал, то вместо обычного поведения, он вызовет указанный обработчик:

terminator () {
echo "Не умру ни за что" >&2
}
trap terminator 15
            

Теперь, если скрипт получит сигнал SIGTERM (номер 15), то вместо того, чтобы нормально завершиться, он напечатает на стандартный вывод ошибок сообщение и продолжит работу.

Более разумным применением этого механизма было бы стирание временных файлов и корректное завершение работы.

7.7.3.7.5. Объединение вывода нескольких команд в общий конвейер

Эта задача может быть легко решена при помощи запуска подзадач внутри подпроцесса, т.е. в круглых скобках:

$ (
> for i in Apple Microsoft "Free Software Foundation"
> do
>     echo $i
> done
> ) | grep Free
Free Software Foundation
            

В заключение следует сказать, что после того, как вы написали могучий сценарий sh(1), ему не мешает дать пермиссии на выполнение, командой chmod(1).

7.8. Поиск нужной документации

Описание:  Системы BSD хорошо документированы. Существует множество доступных администратору ресурсов. Кандидат должен уметь воспользоваться локальной документацийе, а так же знать о документации доступной в сети Internet.

Практика: apropos(1), man(1), man.conf(5), whatis(1), и info(1); share/doc и share/examples; в добавок, каждый проект BSD имеет on-line документацию и несколько почтовых списков рассылки.

Комментарий

7.8.1. Справочная система man(1)

Справочная система UNIX основана на так называемых страницах man(1). Для получения справки по какой-нибудь команде или файлу, надо отдать команду

$ man cp
        

В результате вызова этой команды вы получите справку по команде cp(1). В данном руководстве, а так же во множестве иных мест, вы можете увидеть возле команд и имён конфигурационных файлов в круглых скобках некоторое число. Это номер «страницы» man(1). Для того, чтобы вызвать именно эту страницу, её номер надо указать между командой man(1) и обязательным аргументом. Если же номер не указан, то выводится справка о самой первой странице. Например: существует две справочные страницы с именем passwd: первая и пятая. Первая рассказывает о команде passwd(1), а пятая о синтаксисе файла /etc/passwd(5). Эти страницы можно прочитать, используя следующие две команды:

$ man passwd
$ man 5 passwd
        

Первая команда покажет первую страницу, так как по умолчанию будет выбран самый младший номер, а вторая — пятую, так как номер указан явно. Смысл этих номеров описан в следующем разделе: Раздел 7.9, «Понимание различий в страницах man».

В операционных системах OpenBSD и NetBSD существует конфигурационный файл man.conf(5), в котором описано как должны называться справочные страницы и где их искать. В FreeBSD и DragonFly BSD следует обратить внимание на файл login.conf(5) (см. Таблица F.2, «Формирование окружения средствами login.conf(5)»).

Страница man записана в некотором малопригодном для чтения виде, перед выводом на экран она обрабатывается утилитой groff(1) и выводится пользователю при помощи постраничного пейджера more(1). Нынешний more(1), уже не тот что прежде. Он умеет искать текст и листает как вперёд, так и назад. Однако, если вам больше нравится less(1) (как известно, less(1) is more than more(1)), то вы можете для этого переопределить переменную окружения PAGER:

$ PAGER=less; export PAGER
        

Лично меня, например, раздражает, что more(1), долистав справку до конца прекращает работу, таким образом, если вам, по несчастью, показали последнюю строку справки, то чтобы посмотреть потом на её начало, вам надо перезапускать man(1). Хотя в середине файла вам спокойно дают листать в обоих направлениях.

Команда man(1) хороша, но она предполагает, что вы знаете, что вы ищете. А как быть, если вы, допустим, не знаете какая команда отвечает за копирование файлов? Для этого есть команда apropos(1):

$ apropos copy | fgrep '(1)'
cp(1)            - copy files
cpio(1)          - copy files to and from archives
dd(1)            - convert and copy a file
objcopy(1)       - copy and translate object files
pax(1)           - read and write file archives and copy directory hierarchies
rcp(1)           - remote file copy
scp(1)           - secure copy (remote file copy program)
tcopy(1)         - copy and/or verify mag tapes
dvicopy(1)       - produce modified copy of DVI file
neon-config(1)   - script providing information about installed copy of neon library
tiffcp(1)        - copy (and possibly convert) a TIFF file
        

Как видим, в представленном списке можно разобраться и понять, что нам надо. Краткую справку вроде показанной, можно получить и при помощи команды whatis(1):

$ whatis cp
cp(1)                    - copy files
$ whatis gcc
gcc(1), g++(1)           - GNU project C and C++ Compiler (gcc-3.2.1)
gccmakedep(1)            - create dependencies in makefiles using 'gcc -M'
        

Обе команды ищут в одной базе данных, только whatis(1) ищет среди имён команд, а apropos(1) среди описаний. Эта база данных строится при помощи команды makewhatis(1) раз в неделю при помощи демона cron. (См. Раздел 7.17.2, «Каталоги с периодически выполняемыми заданиями во FreeBSD»)

7.8.2. Гипертекстовая справка info(1)

Существуют страницы man(1) настолько обширные, что пользоваться ими становится неудобно. В таких случаях на выручку приходит система info(1). При прочих равных страницы info(1) как правило более подробны, однако основное их преимущество — наличие гипертекстовой навигации. Эта система написана на основе текстового редактора emacs(1).

$ info gcc
File: gcc.info,  Node: Top,  Next: G++ and GCC,  Up: (DIR)

Introduction
************

This manual documents how to use the GNU compilers, as well as their
features and incompatibilities, and how to report bugs.  It corresponds
to GCC version 3.3.3.  The internals of the GNU compilers, including
how to port them to new targets and some information about how to write
front ends for new languages, are documented in a separate manual.
*Note Introduction: (gccint)Top.

* Menu:

* G++ and GCC::     You can compile C or C++ programs.
* Standards::       Language standards supported by GCC.
* Invoking GCC::    Command options supported by `gcc'.
* C Implementation:: How GCC implements the ISO C specification.
* C Extensions::    GNU extensions to the C language family.
* C++ Extensions::  GNU extensions to the C++ language.
* Objective-C::     GNU Objective-C runtime features.
* Compatibility::   Binary Compatibility
--zz-Info: (gcc.info.gz)Top, 39 lines --Top----*** Tags out of Date ***---------
Welcome to Info version 4.6. Type ? for help, m for menu item.
        

Итак, мы попали в справку о gcc(1). Теперь, если мы поместим курсор на строку с гипертекстовой ссылкой (гипертекстовые ссылки находятся между * и ::) и нажмём клавишу <Enter>, то мы попадём на соответствующую страницу. Вопросительный знак выводит справку по навигации в info(1), а выход из системы осуществляется при нажатии клавиши q. Выход из справки клавиша l, а не q, потому что q вообще закроет emacs(1)!

Таблица 7.10. Навигационные клавиши в системе info(1)

КлавишаОписание
nСледующая нода
pПредыдущая нода
uНа уровень выше
m Перейти к некоторому пункту меню. Будет вызвана командная строка в которой можно будет ввести имя интересующей ноды из меню. При этом можно пользоваться клавишей <TAB>. В случае, если подходит несколько вариантов, они все будут показаны.
rПройти по перекрёстной ссылке (имя будет спрошено).
lВыйти из данной ноды назад, где были до неё
t Выйти на самый верхний уровень (где перечислены все страницы info(1) установленные в системе).
<TAB>Переместиться в тексте к следующей ссылке
M-<TAB> Переместиться в тексте к предыдущей ссылке. Необходимо пояснение: имеется ввиду клавиша «мета». На большинстве клавиатур речь идёт о сочетании клавиш <Alt>+<TAB>. В тоже время, многие оболочки, в том числе многие window-менеджеры системы X(1), перехватывают сочетание клавиш <Alt>+<TAB> для своих целей, например для переключения окон. Чтобы эта функция не мешала, нажатие на клавишу «мета» можно заменить нажатием на <ESC>. Т.е. везде, где в emacs(1) требуют ОДНОВРЕМЕННО нажать «мета» и что-то, можно вместо этого ПОСЛЕДОВАТЕЛЬНО нажать сперва <ESC>, потом что-то.
<ENTER>Перейти на ноду под курсором
Перемещения на странице
<Home> <End>Перейти в начало или в конец ноды
<Space> <Del>Страница вперёд или назад
Прочее
iИндекс
g перейти на ноду по имени (можно указать имя файла)
sПоиск текста внутри ноды
Всего несколько сот(!) клавишесочетаний

К стыду своему, я не понимаю как сказать по-русски слово «нода». Имеется ввиду тема, про которую рассказано в info(1). Вся система организована, как дерево «нод».

7.8.3. Прочие источники

В каталогах share/doc и share/examples можно найти дополнительную документацию в форматах txt или html, а так же примеры конфигурационных файлов с комментариями. Там действительно много полезной справочной информации, авторам которой просто не хватило времени и желания на то, чтобы оформить их в каком-то другом виде.

В разделе Раздел 3, «Источники информации» перечислены ссылки на интерактивную справочную информацию. Для русскоязычных пользователей хочется особо отметить прекрасный перевод Handbook по FreeBSD. На курсах, которые я читаю по операционной системе Linux, я рекомендую слушателям заглядывать в этот источник, хотя он и не нацелен непосредственно на пользователей Linux.

7.9. Понимание различий в страницах man

Описание:  Кандидат BSDA должен знать на какой странице man(1) какая находится информация. Кандидат должен уметь определить какая страница man(1) ему нужна. Кандидат должен уметь осуществлять поиск в справочной системе man(1).

Практика: man(1), intro с (1) по (9), "/".

Комментарий

Как было сказано в предыдущем разделе Раздел 7.8.1, «Справочная система man(1)», Справочник man(1) состоит из нескольких страниц и в них можно заходить явно указывая их номер:

$ man passwd
$ man 5 passwd
        

Первая команда покажет первую страницу, так как по умолчанию будет выбран самый младший номер, а вторая — пятую, так как номер указан явно.

Таким образом, не мешает знать на какой странице man(1) что рассказывается, с тем, чтобы уметь определять, какая страница нам нужна. Каждая страница man(1) сопровождается описанием intro. Так, например, для того, чтобы узнать что расположено на 6-й странице man(1), надо выполнить команду

man 6 intro
        

1
Эта страница посвящена пользовательским командам. Тем, которые обычно располагаются в различных файловых иерархиях в каталоге /bin. Например: cp(1), mv(1), passwd(1), sh(1), csh(1), crontab(1)
2
На этой странице описана библиотека libc — стандартная библиотека языка C.
3
Прочие библиотеки языка C.
4
Описание файлов устройств и драйверов.
5
Описание синтаксиса конфигурационных файлов, например passwd(5), rc.conf(5)
6
Игры. Игра fortune(6) используется в FreeBSD для вывода «совета дня». Для этого в файл ~/.login можно добавить такую строку: [ -x /usr/games/fortune ] && /usr/games/fortune freebsd-tips
7
Дополнительная страница
8
Администраторские программы: fsck(8), ifconfig(8), arp(8), route(8). Т.е. то, что заведомо не понадобится простым пользователям.
9
Програмный интерфейс ядра

Полагаю, что наиболее полезны для администратора страницы 1, 5 и 8.

Внутри интерактивной справки man(1) пользователь попадает в программу more(1) (если иного не указано в переменной oкружения PAGER). Работа с этой программой очень похожа на работу с less(1). Во всяком случае, так же как и в less(