Ревизия 180, сборка 20 июня 2008 года.
Copyright © 2006, 2007 Евгений Миньковский
Аннотация
Данная книга задумана как методическое пособие для подготовки к экзамену BSDA. Книга, тем не менее, может быть полезна не только тем кто собирается сдавать этот экзамен, но и просто широкому кругу IT-специалистов, желающих систематизировать свои знания об операционных системах семейства BSD (NetBSD, OpenBSD, FreeBSD, DragonFly BSD).
В формате HTML книга доступна в виде одной большой страницы (данный вариант) и в многостраничном варианте .
Собственно вопросы экзамена BSDA можно посмотреть отдельно.
![]()  | Замечание | 
|---|---|
Работа ещё только начата, в оглавлении приняты следующие обозначения: 
 Впрочем, в Москве даже на улицах светофоры не всегда горят правильно, что уж говорить об этом труде...  | 
Содержание
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.2. Конфигурирование сервера SSH в соответствии с требованиями
2.3. Конфигурировние SSH сервера для аутентификации по ключу
2.4. Предохранение ключа при обновлении системы
2.5. Разбираться в альтернативных механизмах аутентификации
2.6. Разбираться в альтернативных методах авторизации
2.7. Разбираться в основных рекомендованных методах доступа [до хоста]
2.8. Разбираться в брандмауэрах BSD и синтаксисе конфигурационных файлов
2.9. Разбираться в механизмах использования шифровальных устройств BSD
2.10. Разбираться в методах проверки аутентичности бинарного файла
2.11. Разбираться в способах запуска сервиса в изолированной среде (restraining service)
2.12. Смена алгоритма шифрования используемого для защиты базы с паролями
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.2. Создание системных учётных записей
4.3. Отключение или включение учётной записи (lock и unlock)
4.4. Идентификация и членство в группах
4.5. Определение кто сейчас присутствует в системе или последнего времени входа в систему
4.6. Включение слежения за учётными записями и просмотр статистики
4.7. Изменение пользовательской оболочки
4.8. Контролировать какие файлы будут копироваться в новую пользовательскую директорию при создании учётной записи
4.9. Смена пароля
5. Основы системного администрирования
5.1. Определение какой процесс расходует основную часть ресурсов ЦПУ
5.2. Определять активные процессы и посылать им сигналы
5.3. Использование скриптов rc(8) для
определения запущенных сервисов, их запуск, остановка и
перезапуск
5.4. Определение установленного оборудования и его конфигурирование
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.18. Конфигурирование скриптов, нужных для различных задач по обслуживанию системы, для периодического запуска
5.19. Просмотр очереди Sendmail'а или Postfix'а
5.20. Определение когда последний раз была запущена система и какова её загруженность
5.21. Слежение за операциями ввода/вывода на диске
5.22. Работа с занятыми устройствами
5.23. Определение информации характеризующей операционную систему
5.24. Понимание преимуществ использования лицензии BSD
6. Сетевое администрирование
6.1. Определение существующих установок TCP/IP
6.2. Установка параметров TCP/IP
6.3. Определение какие TCP или UDP порты открыты в системе
6.4. Проверка доступности TCP/IP сервиса
6.5. Запрос к серверу DNS
6.6. Определение кто ответственный за зону DNS
6.7. Изменение порядка разрешения имён
6.8. Перевод сетевой маски между системами точечно-десятичной, точечно-шестнадцатеричной или CIDR
6.9. Собирать информацию используя IP адрес и маску подсети
6.10. Понимание теории адресации IPV6
6.11. Демонстрация основных навыков работы с утилитой
      tcpdump(1)
6.12. Работа с ARP и кешем найденных соседей
6.13. Конфигурирование системы для использования NTP
6.14. Просмотр и обновление «арендованных» данных DHCP
6.15. Знание как и когда устанавливать или удалять алиасы сетевого интерфейса
7. Базовые навыки работы в Unix
7.1. Перенаправление вывода и использование
      tee(1)
7.2. Определение просмотр и изменение переменных окружения
7.3. Навыки работы в vi(1)
7.4. Определение является ли файл бинарным, текстовым или содержащим данные
7.5. Поиск файлов и бинарников в системе
7.6. Поиск файла по заданным атрибутам
7.7. Написание несложных Bourne-скриптов
7.8. Поиск нужной документации
7.9. Понимание различий в страницах man
7.10. Проверка контрольной суммы файла
7.11. Продемонстрировать знакомство с оболочками используемыми по
      умолчанию в системе
7.12. Чтение почты на локальной машине
7.13. Использование контроля за задачами (job control)
7.14. Применение регулярных выражений
7.15. Преодоление ограничений на длину командной строки
7.16. Понимание значения термина домен в различных контекстах
7.17. Работа с cron
A. Список команд и файлов обсуждаемых в книге
B. Некоторые сведения о стеке протоколов TCP/IP
C. Пакетный фильтр OpenBSD — pf(4)
D. Пакетный фильтр NetBSD — ipf(8)
E. Брандмауэр FreeBSD — ipfw(8)
F. /etc/login.conf(5)Список таблиц
crypt_default
          (FreeBSD) и localcipher,
          ypcipher (OpenBSD)crontab(5) для описания
          времени выполнения заданийlogin.conf(5)login.conf(5)login.conf(5)login.conf(5) FreeBSDlogin.conf(5) характерные для OpenBSDСписок примеров
Содержание
В 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. Легенда (условные обозначения)
| Знак | Значение | 
|---|---|
| Обозначения в оглавлении | |
               
             | «Избранный» раздел — автор сам удивлён почему у него всё так хорошо получилось. | 
               
             | Раздел написан, но это не значит, что он никогда не подвергнется ревизии. | 
               
             | Раздел не окончен. | 
               
             | К написанию раздела автор не приступал. | 
| Приглашения в листингах | |
 | Команда выполнялась в /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 может управлять
                  непривилегированный пользователь при наличии
                  специальных прав на устройство
                   [b] К сожалению, надо признать, что шрифтовые выделения по тексту расставлены халтурно. И даже данная часть таблицы ещё недописана  | |
Касательно подготовки к экзамену по данной книге следует привести уведомление BSD CG:
Содержание
1.1. Разбираться в программах установки каждой операционной системы
1.2. Разбираться какие команды доступны для upgrade'а операционной
      системы
1.3. Понимание разницы между заранее скомпилированными бинарными
      дистрибутивами и компиляцией из исходников
1.4. Понимание когда выгодно инсталлировать прекомпилированные
      бинарники и как это делать
1.5. Разбираться в методах настройки и компилирования бинарников
1.6. Определять, какое програмное обеспечение инсталлировано в
      системе
1.7. Определять, какое програмное обеспечение нуждается в
      обновлении
1.8. Обновлять установленное програмное обеспечение
1.9. Определять, какое програмное обеспечение имеет проблемы с
      безопасностью
1.10. Следовать инструкциям секьюрити-консультантов и накладывать
      security-patchОписание: От кандидата BSDA не требуется составить план инсталляции, но он должен уметь начать и закончить инсталляцию операционной системы в соответствии с приведёнными требованиями. Поскольку процедура инсталляции зависит от конкретной системы, кандидату рекомендуется иметь опыт работы со средствами установки каждой BSD системы предлагаемыми в этих системах по умолчанию. Так же ожидается, что кандидат имеет знания об основных релизах (т.е. релизах с номером X.0) и где найти информацию о них на соответствующих сайтах BSD-проектов.
Практика: http://www.bsdinstaller.org для DragonFly BSD, sysinstall(8) для FreeBSD, sysinst на инсталляционном диске NetBSD, и INSTALL.[arch] на инсталляционном диске OpenBSD.
Описание: Кандидат 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.
    
Описание: Кандидат должен быть знаком с тем, где по умолчанию находится дерево портов и пакетов (ports collention, pkgsrc collection) и какая из систем BSD какое дерево использует. Кандидат должен уметь определить расширение используемое пакетами. Кандидат должен понимать преимущества и недостатки инсталляции заранее скомпилированных бинарников и преимущества и недостатки сборки бинарников из исходного кода.
Описание: Кандидат BSDA должен понимать, что заранее скомпилированные бинарники просты и быстры в установке, но не дают возможности настройки бинарника к нуждам системы. Кандидат должен знать как установить заранее скомпилированный бинарник из удалённого источника, или с локальной машины, так же как и знать как удалить установленный пакет.
Практика: pkg_add(1), pkg_delete(1)
Описание: Для поддержки опций программы 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)
Описание: Кандидат BSDA должен разбираться как определить какое програмное обеспечение установлено на BSD, проследить зависимости при помощи менеджера пакетов в случае, если программы установлены при помощи портов или пакетов (packages, ports или pkgsrc). Кандидат должен уметь узнать через менеджер пакетов какое програмное обеспечение стоит на машине и какой версии.
Практика: pkg_info(1)
Описание: Кандидат должен понимать важность соблюдения равновесия между сохранением програмого обеспечения в актуальном состоянии и минимизации воздействий на производительность системы. Dragonfly BSD и NetBSD используют pkgsrc предоставляющую утилиты позволяющие определить какое програмное обеспечение устарело. FreeBSD предоставляет pkg_version и сторонние утилиты интегрированные с менеджером пакетов.
Практика: pkgsrc/pkgtool/pkg_chk и make show-downlevel для Dragonfly BSD и NetBSD; pkg_version(1), и сторонняя программа portupgrade(1).
Описание: Кандидат BSDA должен разбираться во встроенных и сторонних средствах обновления установленного програмного обеспечения. В добавок кандидат должен знать какие системы используют pkgsrc.
Практика: DragonFly BSD и NetBSD предлагают pkgsrc/pkgtools/pkg_chk, pkgsrc/pkgtools/pkg_comp, make update и make replace; portupgrade и cvsup доступны как сторонние продукты.
Описание: Кандидат BSDA должен понимать важность слежения за обнаруживаемыми уязвимостями в безопасности програмного обеспечения. Кандидат должен разбираться в сторонних утилитах интегрированных с менеджером пакетов предназначенных для обнаружения програмного обеспечения с уязвимостями в системе безопасности.
Практика: audit-packages для Dragonfly BSD и NetBSD; portaudit и vuxml для FreeBSD и OpenBSD
Описание: Кандидат BSDA должен быть осведомлён о том, что каждый проект BSD сопровождается советниками по безопасности, чьи советы доступны как через Интернет, так и через почтовые списки рассылок. Кандидат должен уметь следовать инструкциям данным в этих советах.
Практика: patch(1), make(1), и fetch(1); ftp(1) и build.sh
Содержание
2.1. Определить уровень безопасности системы
2.2. Конфигурирование сервера SSH в соответствии с требованиями
2.3. Конфигурировние SSH сервера для аутентификации по ключу
2.4. Предохранение ключа при обновлении системы
2.5. Разбираться в альтернативных механизмах аутентификации
2.6. Разбираться в альтернативных методах авторизации
2.7. Разбираться в основных рекомендованных методах доступа [до хоста]
2.8. Разбираться в брандмауэрах BSD и синтаксисе конфигурационных файлов
2.9. Разбираться в механизмах использования шифровальных устройств BSD
2.10. Разбираться в методах проверки аутентичности бинарного файла
2.11. Разбираться в способах запуска сервиса в изолированной среде (restraining service)
2.12. Смена алгоритма шифрования используемого для защиты базы с паролями
2.13. Смена приветствия системы
2.14. Защита аутентификационных данныхПризнаком хорошего системного администратора является осведомлённость о проблемах безопасности и забота о безопасности системы. Ожидается, что кандидат BSDA знаком с распростанёнными средствами обеспечения безопасности системы. Системы BSD реализованы с учётом проблем безопасности и предоставляют множество средств позволяющих администратору подстроить систему к требованиям политики безопасности его организации. Кандидат не может всегда отвечать за реализацию механизмов безопасности, но должен знать о свойствах и этих средств и доступных командах.
Описание: Системы BSD предоставляют несколько предопределённых настроек безопасности, известных как уровни безопасности (securelevels). Кандидат должен знать на каком он уровне безопасности, можно ли поднять или опустить уровень безопасности и как.
Практика: init(8), sysctl(8),
      rc.conf(5)
![]()  | Замечание | 
|---|---|
| Данный текст прислан Дмитрием Орловым, но подвергся моей редактуре. Е.М. | 
Функциональность securelevel можно рассматривать как метод защиты ядра, сырых устройств (raw devices), и файловой системы от атак злоумышленника, которому удалось взломать учётную запись суперпользователя. Защита ядра в общем случае включает в себя невозможность загрузки собственных модулей ядра и прослушивания проходящего через систему трафика. Функциональность securelevel/security присуствует во всех BSD системах с небольшими отличиями.
Уровни безопасности служат для ограничения возможностей системы до такой степени, которая соответствует её рабочему окружению (среде работы). В 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 запрещено.
Ядра OpenBSD и NetBSD предоставляют 4 уровня системной безопаности, а FreeBSD и DragonFly BSD — 5. Последний уровень в них разбит на два подуровня.
На NetBSD, в дополнении к сказанному, запрещена трассировка процесса init(8).
/dev/mem,
                  /dev/kmem и
                  /dev/io.
                /dev/ad0 и т.п.) в смонтированных
                  файловых системах доступны только для чтения
                
На OpenBSD, в дополнении к сказанному, действуют следующие ограничения на изменения переменных ядра:
На NetBSD, в дополнении к сказанному, действуют следующие ограничения:
идентичен уровню 1, кроме:
Наивысший уровень безопасности во 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 
        В разных системах семейства BSD придаётся различный смысл различным уровням безопасности. Чтобы получить конкретную информацию по вашей операционной системе, используйте следующие ссылки:
Описание: Кандидат BSDA должен знать как настроить встроенный демон sshd(8) для ограничения доступа к системе через SSH.
Практика: sshd_config(5)
Описание: Кандидат должен понимать теорию публичных/приватных ключей включая: какие протоколы доступны для генерирования пар ключей, выбор подходящего bit size, предоставления "начальной строки"(?) (seed), passphrase, и проверки отпечатка (fingerprint). В дополнение, кандидат должен уметь генерировать свои ключи и использовать их для аутентификации.
Практика: ssh-keygen(1) включая следующие ключевые слова: authorized_keys, id_rsa и id_rsa.pub.
Описание: В добавок к знанию о том как генерируются системные SSH ключи, кандидат BSDA должен знать где расположены системные ключи и как предохранить их при обновлении или замене системы.
Практика: /etc/ssh/ssh_host*_key*
Описание: От кандидата BSDA не требуется знания того как сконфигурировать альтернативный метод аутентификации. Однако кандидат должен понимать основы теории аутентификации, знать, что аутентификация по имени пользователя и паролю — не единственный способ аутентификации в системах BSD. Кандидат должен понимать основы PAM и знать, что он доступен в DragonFly BSD, FreeBSD и NetBSD 3.x. Он должен так же знать основы теории касающейся Kerberos, OTP и RADIUS.
Описание: Кандидат должен понимать основы теории авторизации и как MAC и ACL расширяют стандартные UNIX-пермиссии.
Практика: mac(4) и acl(3) на FreeBSD; systrace(1) на NetBSD и OpenBSD.
Описание: Кандидат 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).
    
Описание: Каждая система 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.
Описание: Кандидат BSDA должен знать, что в BSD могут использоваться шифровальные устройства и какие утилиты доступны для этого на каких BSD системах.
Практика: gbde(4) и gbde(8) на FreeBSD; cgd(4) на NetBSD; vnd(4) на OpenBSD.
Описание: Кандидат BSDA должен разбираться в утилитах проверки подлинности файла, таких как tripware. Он должен так же разбираться во встроенных методах проверки предлагаемых некоторыми BSD.
Практика: security(7) или (8);
      security.conf(5);
      veriexecctl(8)
Описание: Кандидат 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).
Команда chroot(8) позволяет запускать приложения в ограниченной среде путём смены корневого каталога. Для начала, давайте попробуем запустить в ограниченной среде программу csh(1). В дополнение к ней мы скопируем в ограниченную среду команду tree(1), чтобы с её помощью убедиться что у нас всё получилось. Для этого нам надо выполнить следующие действия:
/bin и /lib.
        $mkdir -p sandbox/bin sandbox/lib$ldd /bin/csh/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/![]()
#chroot sandbox/ cshPassword: ELF interpreter /libexec/ld-elf.so.1 not found
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.![]()
%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
        Некоторым приложениям может понадобиться наличие каталога
        /dev с файлами устройств. Для систем не
        поддерживающих devfs надо создать эти файлы
        при помощи команды mknod(8), а для систем
        поддерживающих devfs, например для
        FreeBSD, понадобится смонтировать в
        «песочницу» файловую систему devfs.
        Однако при этом вам может понадобиться создать не все, а только
        некоторые файлы устройств. Для этого надо воспользоваться
        утилитой devfs(8):
      
$mkdir sandbox/dev#mount_devfs devfs sandbox/dev/ Password:$ls sandbox/dev/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/![]()
#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/null random zero
#chroot sandbox/ csh csh: Cannot open /etc/termcap. csh: using dumb terminal settings.%tree / / |-- bin | |-- csh | `-- tree |-- dev| |-- 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
        Команда 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 
        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 
$ 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 
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 
        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  
        Если теперь мы добавим адрес 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) | 
Ниже я перечислю нужные для этого команды, естественно удалив их стандартный вывод — он огромен.
$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)».
          
            Прежде всего, следует исключить ситуацию, когда сервисы
            материнской системы слушают адрес присвоенный
            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).
Первый запуск 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 дабы
              избежать сообщений о его отсутствии.
            rpcbind_enable="NO" в
              /etc/rc.conf)
            /etc/resolv.confnetwork_interfaces="" в
              /etc/rc.conf)
            /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).
Теперь вы готовы запускать виртуальный сервер в 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.133The 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. ...............................................................................
$ifconfigfwe0: 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
   | Заходим в тюрьму по ssh(1). Учётная запись guest и sshd(8) демон настроены заранее. | 
   | Это уже команда выполненная внутри тюрьмы. | 
Вы получите некоторое количество предупреждений связанных с тем, что внутри 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
Обычные команды типа 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_sockets | 0 | Переменная определяет может ли root в «тюрьме» открывать сырые сокеты. Установка переменной в 1 позволит запускать в тюрьме такие утилиты как ping(8) и traceroute(8). | 
security.jail.enforce_statfs | 2 | Определяет какая информация о точках монтирования доступна для процессов в jail(8). 0 — все точки монтирования доступны без ограничений; 1 — Доступны только точки монтирвания внутри каталога jail(8), путь к каталогу jail(8) удаляется; 2 — можно работать только с точкой монтирования в которой разположен jail(8). | 
security.jail.set_hostname_allowed | 1 | Определяет может ли приложение в jail(8) сменить hostname. | 
security.jail.socket_unixiproute_only | 0 | По умолчанию процессы в jail(8) могут взаимодействовать с доменными сокетами UNIX, IPv4 сокетами и routing sockets. Смена данной переменной приведёт к тому, что процессам в jail(8) станут доступны и другие сокеты. | 
security.jail.sysvipc_allowed | 0 | Могут ли процессы в jail(8) использовать примитивы System V IPC. Установка этой переменной в 1 позволит процессам в jail(8) взаимодействовать с процессами в других «тюрьмах» и с процессами материнской системы. | 
security.jail.chflags_allowed | 0 | 
                    Как взаимодействует root в
                    jail(8) с флагами выставленными
                    командой chflags(1).
                    0 — root считается непривилегированным
                    пользователем и не может менять этот флаг.
                    1 — root считается привилегированным
                    пользователем и может манипулировать флагами
                    согласно секущему уровню
                    kern.securelevel.
                   | 
| Существуют две переменные, которые можно менять внутри jail(8) их значение будет действовать только внутри данной «тюрьмы». | ||
kern.securelevel | ||
kern.hostname | ||
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
              
$ while :; do cat /dev/zero | md5 & done
              Описание: Кандидат BSDA должен уметь по данному скриншоту базы паролей определить используемый метод шифрования и знать как его сменить. Кандидат должен иметь базовое понимание того когда надо использовать DES, MD5 и Blowfish.
Практика: login.conf(5); auth.conf(5);
      passwd.conf(5) и adduser(8).
    
Жизнь показывает, что существует множество путей при помощи которых может «утекать» база с паролями пользователей. Один из распространённых случаев — утечка с backup'ами. Главное оружие любого системного администратора, это валидол и backup. Администратор, который понял эту истину может уподобиться белке, которая рассовывает орешки где попало и забывает где их положила. Так же могут быть распределены в системе резервные копии. Особенно, если система резервного копирования написана самим администратором. Такая система, быть может ничем не плоха, но на стадии отладки, пока подбирались опции, на жёстких дисках оказалось несколько копий резервных файлов с правами 644...
        Чем это чревато? Злоумышленник может попыться найти базу с
        паролями и взломать её. Что может ему помешать? Во первых пароли
        должны быть качественными, во вторых, они
        должны быть качествено зашифрованы. Надо сразу сказать, что
        первое намного важнее второго. Как бы качественно ни был
        зашифрован пароль 12345, его вскроют
        за доли секунды.
      
Существует несколько способов шифрования паролей. Так или иначе, используется некоторая необратимая функция, при помощи которой, шифруется пароль. Т.е. система ваш пароль вообще не знает. Когда вы его вводите, она шифрует его заново и сверяет результаты шифрования со своей базой.
В системах BSD можно выбирать несколько алгоритмов шифрования паролей, однако ни один из них не является панацеей от взлома. Иметь стойкий пароль, намного важнее, чем строго его шифровать. Хотя последнее тоже может быть важно.
        База с аутентификационными данными состоит из 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,a-sys,1234567,7654321,hello_world:/home/user:/usr/sbin/nologin
user2:*LOCKED*76aSxdZIXKXfk:1002:1002:russian:0:0:Poluect,a-sys,1234567,7654321,hello_world:/home/user:/usr/sbin/nologin
user3:*LOCKED*$1$UmWRc8Kh$WyHRN96T7vQ7nZP0ChVjc/:1003:1003:russian:0:0:Poluect,a-sys,1234567,7654321,hello_world:/home/user:/usr/sbin/nologin
user4:*LOCKED*$1$OgtF.3Zb$EafLlWm6H.OZ1sKkheySr.:1004:1004:russian:0:0:Poluect,a-sys,1234567,7654321,hello_world:/home/user:/usr/sbin/nologin
user5:*LOCKED*$2a$04$HXoymCDzRfi9ctGmfrOqeu9Hn16XcWmQuVnA6C3aifKkkM7qrKauO:1005:1005:russian:0:0:Poluect,a-sys,1234567,7654321,hello_world:/home/user:/usr/sbin/nologin
user6:*LOCKED*$2a$04$GO.hiRaXx7wp5cdAfJP9xOAOeXV48/kBYOJ2VaJRhknUg/VWLw/N.:1005:1005:russian:0:0:Poluect,a-sys,1234567,7654321,hello_world:/home/user:/usr/sbin/nologin
user7:*LOCKED*$3$$2d20d252a479f485cdf5e171d93985bf:1006:1006:russian:0:0:Poluect,a-sys,1234567,7654321,hello_world:/home/user:/usr/sbin/nologin
user8:*LOCKED*$3$$2d20d252a479f485cdf5e171d93985bf:1007:1007:russian:0:0:Poluect,a-sys,1234567,7654321,hello_world:/home/user:/usr/sbin/nologin
              Здесь имеется 10 полей разделённых двоеточиями. Вот их значение:
                  Пароль пользователя. Никакой пароль не может содержать
                  в себе звёздочек, или восклицательных знаков. Поэтому
                  поле *LOCKED*
                  свидетельствует о том, что данная учётная запись
                  заблокирована. Ни один пароль не совпадёт с ней при
                  процедуре аутентификации. Для блокирования учётной
                  записи таким способом можно применять команду
                  pw(8) (см. Раздел 4.1, «Создание, изменение и удаление учётных записей»).
                
![]()  | Внимание | 
|---|---|
| Существуют способы войти в систему без проверки пароля, например при аутентификации в ssh(1) по паре сгенерированных ключей (см. Раздел 2.7, «Разбираться в основных рекомендованных методах доступа [до хоста]»). Поэтому такой способ блокирования учётной записи можно считать необходимым, но не достаточным. Кроме этого действия надо ещё сменить пользователю оболочку на /usr/sbin/nologin. | 
                  У всех восьми упомянутых здесь пользователей пароль
                  одинаковый — qwerty. Однако он приведён в
                  разных форматах. Всего мы обсудим 4 формата паролей:
                
                        Пароль qwerty При
                        помощи алгоритма DES
                        шифруется в строку cuqW.GIKHV/xs. Однако
                        было бы ошибкой дать злоумышленнику
                        возможность определить у кого из наших
                        пользователей пароли совпадают, просто на
                        основании того, что совпадают шифры. Поэтому
                        при шифровании используется т.н.
                        «соль». В момент заведения пароля
                        генерируется случайное число.  это число в
                        символьном виде приписывается к паролю и далее
                        шифруется пароль вместе с солью.  Таким
                        образом, следующая строка: 76aSxdZIXKXfk это тоже
                        qwerty.
                      
Алгоритм DES не является достаточно криптостойким. Современная компьютерная техника позволяет взломать эти пароли методом перебора за незначительный промежуток времени. По этой причине большинство современных UNIX-систем шифруют пароли при помощи алгоритма 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 — атака грубой силой, путём перебора паролей. Математики смогли снизить количество вычислений, необходимых для этой атаки на несколько порядков, однако это по прежнему актуальная бесконечность.
$2 в начале строки пароля
                      свидетельствует о применении данного алгоритма.
                      Поле $04$ указывает на
                      то, сколько проходов совершено при шифровании.
                      (Внимание! Последняя фраза лишь догадка автора.)
                    $3. Обратите внимание: в
                      случае использования алгоритма NT-hash соль не
                      генерируется и хеши одинаковых паролей одинаковы!
                      Я не знаю устройства этого алгоритма, но результат
                      просто отвратителен! Данный эксперимент ставился
                      в системе
                      FreeBSD 6.1-RELEASE.
                    /etc/login.conf(5) и устанавливают
                переменные окружения или делают иные настройки (см.
                Приложение F, /etc/login.conf(5)).
              GECOS — информация о пользователе: имя, место работы, рабочий и домашний телефон. Эту и другую информацию использует в работе утилита finger(1):
$ finger user
Login: user                             Name: Poluect
Directory: /home/user                   Shell: /usr/sbin/nologin
Office: a-sys, 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,a-sys,1234567,7654321,hello_world:/home/user:/bin/csh
                /etc/pwd.db/etc/master.passwd(5) командой
            pwd_mkdb(8).
          /etc/spwd.db/etc/master.passwd(5) командой
            pwd_mkdb(8).
          Данный файл является базой данных для различных программ, в том числе для программы 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)»
      
        В этом файле находятся умолчания, которые ипользует системная
        функция 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 | 
|---|---|---|
des | DES | 
                 
               | 
md5 | MD5 | 
                 
               | 
blf | Blowfish | 
                 
               | 
nth | NT-hash | 
                 
               | 
old | DES | 
                 
               | 
newsalt,<rounds> | Newsalt; rounds — 24-битное целое, минимум 7250 (число проходов алгоритма). | 
                 
               | 
blowfish,<rounds> | Blowfish; rounds — от 4-х до 31-го (логарифм по основанию 2 от числа проходов алгоритма). | 
                 
               | 
        Данный файл присутствует только в 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 раза).
Утилита adduser(8) предназначена для добавления пользователей в систему. Она может работать как интерактивно, так и из скриптов. Основной утилитой по управлению учётными записями является pw(8), она накладывает ограничение на длину пароля и т.п. Интерактивно вызванная утилита спрашивает у администратора имя пользователя, полное имя (GECOS) и др.
![]()  | Замечание | 
|---|---|
        Имя пользователя обычно не должно быть более 16 символов и
        должно состоять из букв и цифр. Эти ограничения наложены по
        историческим причинам, если вы хотите более длинные имена, вы
        можете переопределить переменную UT_NAMESIZE
        в <utmp.h> и пересобрать world.
        Однако после этого могут быть проблемы с бинарниками
        скомпилированными в других системах. Кроме того,
        NIS предполагает, что пароли бывают только
        8-ми символьные.
       | 
Суммируя сказанное выше, приведём краткое Blowfish HOWTO: как перевести базу паролей в формат Blowfish:
/etc/login.conf(5) в секции default:\ помещаем строки:
          
default:\
        :passwd_format=blf:\
            
        :passwordtime=48d:\
        :mixpasswordcase=true:\
        :minpasswordlen=10:\
        :idletime=60:
            /etc/login.conf(5)).
        
# cap_mkdb /etc/login.conf
            /etc/auth.conf(8) добавляем строку
          
crypt_default=blf
            Описание: Кандидат должен понимать, что приветствие системы зависить от того, каким способом пользователь получил доступ к системе и знать, какие файлы за это отвечают.
Практика: motd(5), login.conf(5),
      gettytab(5), sshd_config(5).
    
Описание: Для предотвращения атак против системы путём взлома базы паролей, системы BSD хранят эти данные в шифрованном виде доступными только системным процессам. BSDA кандидат должен понимать где хранятся эти данные и какие на них должны быть пермиссии (права доступа).
Практика: passwd(5), pwd_mkdb(8)
Содержание
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. Слежение за состоянием виртуальной памяти системыОписание: Кандидат BSDA должен свободно ориентироваться в проблемах монтирования и размонтирования локальных файловых систем, включая: как смонтировать/размонтировать конкретную файловую систему, как смонтировать все файловые системы, как сконфигурировать систему для монтирования файловой системы при загрузке. Передача опций команде mount(8), и разрешение ошибок возникших при выполнении mount(8).
Практика: mount(8), umount(8),
      fstab(5)
Описание: Кандидат 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)
Описание: Кандидат должен уметь определять какие файловые системы смонтированы и какие будут смонтированы при загрузке.
Практика: mount(8), du(1),
      fstab(5)
Описание: Кандидат BSDA должен уметь работать с UNIX утилитами для быстрого определения какой файл занял много места на жёстком диске.
Практика: du(1), df(1), find(1), sort(1), systat(1)
Описание: Кандидат должен знать разницу между символьными и жёсткими ссылками, как их создавать просматривать и удалять. Кандидат должен уметь временно разрешить проблему с нехваткой дискового пространства через использование символьных ссылок.
Практика: ln(1), ls(1), rm(1), stat(1)
Описание: Кандидат BSDA должен уметь определить использует ли FreeBSD ACL и если да, то на каких файловых системах. Кандидат должен уметь просматривать и изменять файловые ACL на FreeBSD.
Практика: mount(8), ls(1), getfacl(1)
Описание: Ожидается, что кандидат BSDA знаком с традиционными UNIX пермиссиями включая: как просмотреть и изменить пермиссии, почему sticky-bit важен на каталоге /tmp и других каталогах общего пользования, определять и использовать SUID и SGID биты, понимать разницу между символьным и восьмеричным представлением пермиссий. Вдобавок кандидат должен понимать откуда оболочка берёт умолчальные пермиссии для вновь создаваемых файлов и каталогов, по заданному значению umask определять с какими пермиссиями будет создан файл.
Практика: ls(1), chmod(1), umask(1) или (2)
Описание: Кандидат BSDA должен уметь сменить владельца файла как требуется. Кандидат должен понимать как важно проверить кем он является в системе, до того как создать файл.
Практика: chown(8), chgrp(1); su(1), mtree(8)
Описание: Кандидат должен иметь опыт работы с распространёнными в UNIX утилитами командной строки для резервного копирования. Кандидат должен знать имена устройств для ленточных ностителей.
Практика: tar(1), cpio(1), pax(1), cp(1), cpdup(1)
Описание: Кандидат должен разбираться в утилитах используемых для резервного копирования всей файловой системы в целом и различных уровнях утилиты dump(1).
Практика: dump(8), restore(8), dd(1)
Описание: Кандидат BSDA должен быстро ориентироваться в структуре каталогов системы BSD.
Практика: hier(7)
Описание: Кандидат BSDA должен знать утилиты для проверки содержимого файловой системы и использовать их.
Практика: fsck(8)
Описание: Кандидат BSDA должен понимать как флаги расширяют традиционные пермиссии UNIX и знать как посмотреть и изменить флаги неизменяемости, "дописываемости" и неудаляемости (immutable, append-only, undelete).
Практика: ls(1), chflags(1)
Описание: Виртуальная память имеет важное значение для производительности системы. Кандидат BSDA должен уметь конфигурировать устройство swap и следить за его использованием.
Практика: pstat(8), systat(1), top(1), vmstat(8); swapctl(8), swapinfo(8)
Содержание
4.1. Создание, изменение и удаление учётных записей
4.2. Создание системных учётных записей
4.3. Отключение или включение учётной записи (lock и unlock)
4.4. Идентификация и членство в группах
4.5. Определение кто сейчас присутствует в системе или последнего времени входа в систему
4.6. Включение слежения за учётными записями и просмотр статистики
4.7. Изменение пользовательской оболочки
4.8. Контролировать какие файлы будут копироваться в новую пользовательскую директорию при создании учётной записи
4.9. Смена пароляОписание: Важная часть системного администрования — манипулирование учётными записями. Кандидат 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), что предохранит вас от неожиданного разрушения собственной системы. Существует другая крайность, это создание множества пользователей с административными правами, что может привести как минимум к нестабильности системы, к ее вскрытию злоумышленниками или даже разрушению.
Можно выделить три основных типа учётных записей: суперпользователь, системные пользователи, и учётные записи пользователей. Учётная запись суперпользователя, обычно называемая root, используется для управления системой без ограничения привилегий. Системные пользователи запускают сервисы и, как правило, не могут входить (login) в систему. Учётные записи пользователей необходимы остальным для входа в систему, чтения почты, работы с документами, создания приложений и так далее.
С каждой учётной записью в системе *BSD связана определённая идентификационная информация:
              Имя пользователя в том виде, в каком оно вводится в
              приглашение login:.  Имена пользователей должны быть
              уникальны в пределах одного компьютера; не может быть двух
              пользователей с одинаковым именем пользователя. Существует
              множество правил для создания правильных имён
              пользователей, документированных в
              passwd(5); вы как правило будете
              использовать имена пользователей, состоящие из восьми или
              меньшего количества символов, все символы в нижнем
              регистре.
            
Вообще-то это не является какой-то догмой. Но некоторый софт расчитывает, что на имя пользователя наложены некоторые ограничения. Так, старые реализации системы NIS расчитывали, то имя пользователя состоит не более чем из восьми символов. В настоящий момент вы можете не соблюдать это ограничение. Почтовая система sendmail(8) при доставке почты переводит символы в нижний регистр. Поэтому пользователь в имени которого есть буквы из верхнего регистра будет лишён почты. Многие файловые форматы расчитывают на то, что в имени нет двоеточия и т.п. Если по каким-то причинам вы хотите, чтобы в имени были большие буквы, точки и т.п. Вам надо подумать над архитектурой програмного обеспечения. Например, если вы хотите, чтобы в вашем домене существовали электронные адреса типа Mikhail.Kutuzov@borodino.ru, вам слеует хранить почтовые аккаунты, например, в базе данных PostgreSQL, а не в виде учётных записей UNIX.
login.conf(5),
              passwd(5), см. так же Приложение F, /etc/login.conf(5)).
            /home/username. Пользователи хранят
              личные файлы в домашнем каталоге и в любых подкаталогах,
              создаваемых внутри домашнего каталога.
            Самый простой и интерактивный способ добавить нового пользователя, это использовать команду 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 []:testuserEnter full name []:Test FAQ UserEnter shell csh ksh nologin sh [sh]:kshUid [1002]:EnterLogin group testuser [testuser]:guestLogin group is ``guest''. Invite testuser into other groups: guest no [no]:noLogin 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/kshOK? (y/n) [y]:y Added user ``testuser'' Copy files from /etc/skel to /home/testuserAdd 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 6Enter 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)
        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.
        Быстро и эффективно удалить пользователя можно с помощью команды
        rmuser(8).  rmuser(8)
        старается удалить всё, относящееся к указанному пользователю:
        домашнюю директорию, письма, задачи в
        crontab(1)/at(1),
        уничтожает запущенные процессы этого пользователя, созданные им
        временные файлы в /tmp и, разумеется,
        удаляет его из /etc/master.passwd и
        /etc/group.
      
#rmuserEnter 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/kshIs this the entry you wish to remove?yRemove 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 старого пользователя и он завладеет брошенными файлами. Если имя нового пользователя совпадёт с именем удалённого, то он завладеет почтовыми алиасами и др.
В связи со сказанным, в ряде случаев блокирование пользователей оказывается более желательно, чем удаление их учётных записей.
Описание: Кандидат должен понимать, что многие сервисы требуют учётных записей и что эти записи должны быть недоступны для логина.
Практика: 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".
      
Описание: Кандидат BSDA должен знать как определить включены ли учётная запись и как её включить.
Практика: vipw(8); chpass(1), chfn(1), chsh(1), pw(8), user(8)
Описание: В системе пермиссий UNIX важно уметь определить кем вы являетесь и каково ваше членство в группах. Кандидат должен это уметь.
Практика: id(1), groups(1), who(1), whoami(1), su(1)
Описание: Системы BSD поддерживают базы данных с детальной информацией о логинах. Кандидат BSDA должен знать что это за базы, где они хранятся и какими утилитами можно воспользоваться, чтобы получить информацию о логинах.
Практика: wtmp(5), utmp(5),
      w(1), who(1),
      users(1), last(1),
      lastlogin(8), lastlog(5),
      finger(1)
Описание: Кандидат BSDA должен быть осведомлён когда следует включить систему сбора статистики об учётных записях (accaunting), знать какие для этого нужны утилиты и как просматривать собранную статистику.
Практика: ac(8), sa(8), accton(8), lastcomm(1), last(1)
Описание: Кандидат должен знать какая оболочка по умолчанию у пользователя и у суперпользователя. Он должен знать как сменить оболочку в каждой из операционных систем.
Практика: vipw(8); chpass(1), chfn(1), chsh(1), pw(8), user(8)
Описание: 
      Системы BSD используют каталог skel
      содержащий файлы, которые должны быть скопированы при создании
      домашнего каталога пользователя при заведении учётной записи.
      Кандидат BSDA должен знать где в какой системе
      находиться данный каталог и как отменить его копирование при
      создании учётной записи.
    
Практика: pw(8), adduser.conf(5),
      useradd(8) и
      usermgmt.conf(5)
Содержание
5.1. Определение какой процесс расходует основную часть ресурсов ЦПУ
5.2. Определять активные процессы и посылать им сигналы
5.3. Использование скриптов rc(8) для
определения запущенных сервисов, их запуск, остановка и
перезапуск
5.4. Определение установленного оборудования и его конфигурирование
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.18. Конфигурирование скриптов, нужных для различных задач по обслуживанию системы, для периодического запуска
5.19. Просмотр очереди Sendmail'а или Postfix'а
5.20. Определение когда последний раз была запущена система и какова её загруженность
5.21. Слежение за операциями ввода/вывода на диске
5.22. Работа с занятыми устройствами
5.23. Определение информации характеризующей операционную систему
5.24. Понимание преимуществ использования лицензии BSDОписание: Кандидат BSDA должен уметь следить за работой процессов и заметить ненормально высокую загруженность CPU. Кандидат должен уметь завершить процесс или изменить его приоритет.
Практика: top(1), systat(1), ps(1), nice(1), renice(1), kill(1)
Описание: 
      Кандидат должен знать названия и номера наиболее употребляемых в
      UNIX'е сигналов и знать как послать сигнал
      активному процессу.  Кандидат должен знать разницу между
      SIGTERM и SIGKILL.
    
Практика: ps(1); kill(1); killall(1); pkill(1); pgrep(1)
Описание: В дополнении к тому, чтобы знать как непосредственно послать сигнал процессу, кандидат BSDA должен знать, что системы BSD поставляют скрипты, которые могут быть использованы для того, чтобы проверить состояние процесса, остановить, запустить или перезапустить процесс. Кандидат должен знать где в какой системе находятся эти скрипты. Эта тема не относится к OpenBSD.
Практика: rc(8), rc.conf(5)
Описание: Операционные системы 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)
        Утилита 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
        Таким образом, можно получить детальную информацию о типе устройства и наборе чипсетов поддерживаемых подгруженным драйвером.
Описание: Кандидат BSDA должен понимать разницу между статически скомпилированным ядром и ядром использующим подгружаемые модули. Кандидат должен уметь просматривать список загруженных модулей, загружать и выгружать модули, однако он должен знать, что в системах NetBSD и OpenBSD использование модулей ядра не одобряется.
Практика: kldstat(8), kldload(8),
      kldunload(8), и
      loader.conf(5); modstat(8),
      modload(8), modunload(8), и
      lkm.conf(5)
Описание: Системы BSD используют переменные ядра MIB, что позволяет системному администратору просматривать и изменять состояние ядра на работающей системе. Кандидат должен уметь изменять эти переменные как на лету во время работы системы, так и постоянно, выставляя начальные значения действующие в момент загрузки системы. Кандидат должен понимать как изменить переменную MIB доступную только для чтения.
Практика: sysctl(8), sysctl.conf(5)
Описание: В дополнении к тому, что системы BSD предоставляют драйвера к аппаратным RAID контроллерам, BSD предоставляет встроенный програмный RAID. Кандидат должен знать разницу между RAID уровня 0, 1, 3 и 5 и какие утилиты доступны в различных системах BSD для конфигурирования програмного RAID'а.
Практика: vinum(8), gmirror(8), gstripe(8), graid3(8), raidctl(8), ccdconfig(8)
Описание: Кандидат BSDA должен понимать роль MTA, определять какой(ие) MTA доступен(ны) во время установки системы, какой конфигурационный файл указывает на то, какой MTA используется системой. Кандидат должен знать разницу между форматами хранения почты mailbox и maildir.
Практика: mailer.conf
Описание: Кандидат BSDA должен знать, что система автоматически создаёт и манипулирует множеством журнальных файлов. Кандидат должен уметь настраивать ротацию журнальных файлов по времени или размеру, понимать термины «средство» и «важность», смотреть сжатые журнальные файлы. (К сожалению, в русском языке закрепилась традиция перевода термина syslog facilities как средства syslog. Перевод крайне неудачный, но такова традиция — прим. переводчика.)
Практика: newsyslog(8),
      newsyslog.conf(5),
      syslog.conf(5), zmore(1),
      bzcat(1)
Описание: Кандидат должен знать насколько важно регулярно просматривать журнальные файлы и как просматривать их во время решения проблем.
Практика: tail(1), /var/log/*,
      syslog.conf(5), grep(1),
      dmesg(8)
Описание: 
      Кандидат BSDA должен уметь просмотреть очередь печати и
      манипулировать заданиями в очереди. Кандидат должен понимать
      значение первых двух полей в файле
      /etc/printcap.
    
Практика: lpc(8), lpq(1),
      lprm(1), printcap(5)
Описание: Кандидат BSDA должен понимать когда надо создать почтовый псевдоним (алиас) и как это сделать в Sendmail и в Postfix
Практика: newaliases(1), aliases(5),
      postaliases(1)
Описание: Кандидат BSDA должен понимать последствия связанные с остановкой, перезагрузкой ли переводом системы в однопользовательский режим, понимать когда это необходимо и как минимизировать при этом воздействие на сервер.
Практика: shutdown(8)
Описание: Кандидат должен понимать, что ограничения ресурсов наследуются от оболочки и уметь изменять их постоянно или временно. Кандидат должен понимать разницу между мягким и жёстким ограничением.
Практика: limit(1), limits(1),
      login.conf(5), sysctl(8)
      на NetBSD
Описание: Кандидат должен понимать когда следует создать политики для контроля ширины полосы пропускания для доступа к некоторым сервисам. Кандидат должен знать какие средства доступны для контроля ширины полос пропускания.
Практика: ipfw(8), altq(4), dummynet(4), altq(9),
      altqd(8), altq.conf(5)
Описание: Системы BSD часто используют для предоставления услуг Интернет. Кандидата BSDA могут попросить найти, рассмотреть и сделать какие-нибудь изменения в конфигурационных файлах каких-нибудь сервисов. Кандидат должен знать как называются конфигурационные файлы и с какими они связаны сервисами.
Практика: httpd.conf(5),
      sendmail.cf, master.cf,
      dhcpd.conf(5),
      named.conf(5), smb.conf(5)
Описание: Кандидат BSDA должен знать, что в процессе загрузки BSD не используются уровни запуска (runlevels из SystemV — примечание переводчика). Для того, чтобы минимизировать воздействие на систему перезагрузок, кандидат должен уметь сконфигурировать систему так, чтобы сервисы стартовали при загрузке системы автоматически. Причём сделать это надо собственными средствами BSD.
Практика: rc.conf(5), rc(8),
      inetd(8)
Описание: Системы 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
Описание: Кандидат BSDA должен уметь просмотреть почтовую очередь, чтобы определить какое письмо застряло. Если необходимо, надо уметь заставить MTA заново обработать почту, или очистить её.
Практика: mailq(1), postqueue(1)
Описание: Кандидат BSDA должен уметь определить загруженность системы за последнюю минуту, 5 и 15 минут, а так же время прошедшее с последней перезагрузки.
Практика: uptime(1), w(1), top(1)
Описание: Операции ввода/вывода на диске сильно влияют на производительность системы. Кандидат BSDA должен знать какие утилиты доступны на системах BSD для контроля за операциями дискового ввода/вывода и как интерпретировать их результаты.
Практика: iostat(8), stat(1), vmstat(1), nfsstat(1)
Описание: Кандидат BSDA должен понимать что может вызвать зависание процесса, как обнаружить такой процесс и что делать в сложившейся ситуации.
Практика: ps(1), fstat(1), kill(1), umount(8) и сторонняя утилита lsof(8)
Описание: Кандидат BSDA должен уметь определить тип и версию установленной операционной системы.
Практика: uname(1), sysctl(1);
      /etc/release на NetBSD.
    
Содержание
6.1. Определение существующих установок TCP/IP
6.2. Установка параметров TCP/IP
6.3. Определение какие TCP или UDP порты открыты в системе
6.4. Проверка доступности TCP/IP сервиса
6.5. Запрос к серверу DNS
6.6. Определение кто ответственный за зону DNS
6.7. Изменение порядка разрешения имён
6.8. Перевод сетевой маски между системами точечно-десятичной, точечно-шестнадцатеричной или CIDR
6.9. Собирать информацию используя IP адрес и маску подсети
6.10. Понимание теории адресации IPV6
6.11. Демонстрация основных навыков работы с утилитой
      tcpdump(1)
6.12. Работа с ARP и кешем найденных соседей
6.13. Конфигурирование системы для использования NTP
6.14. Просмотр и обновление «арендованных» данных DHCP
6.15. Знание как и когда устанавливать или удалять алиасы сетевого интерфейса
В данной главе содержится краткий материал изложенный в стиле «шпаргалки». Более систематично вопросы работы сети обсуждаются в Приложение B, Некоторые сведения о стеке протоколов TCP/IP. Предполагается, что содержание данной главы будет полезно тем, кто овладел материалом изложенным в указанном приложении.
Описание. Кандидат BSDA должен уметь определить IP адреса системы, маску подсети, шлюз, первичный и вторичный сервер DNS и имя хоста.
Практика. ifconfig(8), netstat(1),
      resolv.conf(5), route(8),
      hostname(1)
Итак, в этом разделе речь идёт не о настройке сети, а лишь об определении текущих настроек. Разберёмся в возможностях упомянутых здесь утилит.
Во имя целостности повествования мы выйдем за рамки задач поставленных в экзаменационном билете. Надеюсь читатель не останется внакладе.
Утилита ifconfig(8) предназначена для настройки сетевых интерфейсов и диагностики текущих настроек. Как мы и договаривались, в данном разделе мы изучаем только возможности по диагностике, а настройкой займёмся в другом разделе (См. Раздел 6.2.2, «ifconfig(8) — настройки сетевых интерфейсов»).
MAC-адрес (он же hardware address);
        IP-адрес;
        IPv6-адрес;
        Вот пример того, как может выглядеть вывод команды ifconfig(8):
$ifconfig -arl0:
flags=8802<BROADCAST,SIMPLEX,MULTICAST> mtu 1500
options=8<VLAN_MTU>
inet xxx.yyy.zzz.180 netmask 0xffffff80 broadcast xxx.yyy.zzz.255
ether 00:80:48:2d:f7:15
media: Ethernet autoselect (100baseTX <full-duplex>)
status: active
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
ether 4c:00:10:13:15:1d media: Ethernet autoselect (100baseTX <full-duplex>) status: active pflog0: flags=141<UP,RUNNING,PROMISC> mtu 33208
pfsync0: flags=0<> mtu 2020 lp0: flags=8851<UP,POINTOPOINT,RUNNING,SIMPLEX,MULTICAST> mtu 1500
inet 10.0.0.1 --> 10.0.0.2 netmask 0xff000000 lo0: flags=8049<UP,LOOPBACK,RUNNING,MULTICAST> mtu 16384
inet 127.0.0.1 netmask 0xff000000
   | 
            Команде ifconfig(8) необходимо указать по
            каким интерфейсам она должна вывести сведения. Если вместо
            этого указать аргумент -a будут выведены
            сведения обо всех интерфейсах, с опцией -u
            только об интерфейсах активных в данный момент, точнее об
            интерфейсах с установленным флагом UP (в данном случае rl1,
            pflog0 и lo0). В NetBSD и
            OpenBSD флаг -u
            отстутствует. В FreeBSD интерфейс
            указывать необязательно: если вы вызываете
            ifconfig(8) без аргументов, по умолчанию
            подразумевается ключ -a. В
            NetBSD и OpenBSD
            обязательно надо указать или интерфейс или ключ
            -a.
           | 
   | Указание на то, что следующий абзац относится к интерфейсу rl0. Специально для поклонников Linux отметим: в BSD принято называть интерфейсы по именам отвечающих за них драйверов. За сетевые карты на чипсете RealTek отвечает драйвер rl(4). Узнать о специфических настройках для устройств на остове этого чипсета можно из справочной страницы man 4 rl. | 
   | Флаги в угловых скобках подробно описаны ниже. В них собрана информация о возможностях интерфейса и текущем режиме его работы. mtu — maximum transfer unit в байтах.  | 
   | |
   | Характеристики интерфейса на сетевом уровне: IP-адрес, маска подсети и широковещательный адрес. Характреристики в адресном пространстве IPv6 сообщаются отдельной строкой и здесь непоказаны. | 
   | Аппаратный адрес (он же MAC-адрес) устройства. (Канальный уровень.) | 
   | media — характеристики передающей среды (физический уровень). Ethernet autoselect — скорость обмена данными автоматически определяется при взаимодействии с устройством на противоположном конце провода, выбирается наивысшая скорость из поддерживаемых обоими устройствами, если среда не поддерживает сигнал на этой скорости (например сопротивление в проводе слишком большое) а оба устройства договорились о передаче на большой скорости, необходимо хотя бы одно из них вручную перевести на более низкую скорость передачи данных; 100baseTX: 100 — выбрана скорость передачи данных 100 Мб/сек, base — для передачи используется вся частотная полоса (у ADSL-модема это не так: он может одновременно на одной частоте передавать обычный телефонный сигнал, а на другой интернет-трафик), TX — для передачи используется витая пара (twisted pair); full-duplex — возможна одновременная передача данных в обе стороны, если это не так, будет написано half-duplex. | 
   | Физическая характеристика — наличие несущей в проводе. Возможные значения active или no carrier. В последнем случае, это значит, что провод вышел из гнезда, или его разорвал экскаватор, или прибор с той стророны выключен. | 
   | Здесь показан пример того, как выглядит конфигурация интерфейса, когда на нём поднято одновременно несколько IP-адресов (алиасов). В Linux в этом случае заводится новое устройство (например в дополнение к интерфейсу eth0 появляется eth0:0, eth0:1 и т.д.), что в ряде случаев бывает удобно. Так, если мы какому-нибудь сервису предписываем посылать пакеты через интерфейс rl1 неочевидно какой IP он будет использовать. | 
   | Это пример виртуального интерфейса. Данный интерфейс используется пакетным фильтром OpenBSD — pf(4). (В настоящий момент данный брандмауэр используется не только в OpenBSD, но так же и в FreeBSD начиная с версии 5.3 и в NetBSD.) | 
   | Это параллельный порт сконфигурированный для связи типа точка-точка. | 
   | И, наконец, кольцевой интерфейс. | 
Флаги сетевых интерфейсов (информацию о некоторых флагах можно получить из девятой страницы man(1), см. ifnet(9). Более полно флаги описаны в книге [McKusick-2004]):
-u,
            мы выводим информацию именно об интерфейсах с этим флагом.
          Здесь упомянуты не все возможные флаги, а лишь флаги упомянутые в [McKusick-2004]. В [Stevens-2003-ru] можно найти упоминание других флагов, например NOTRAILERS — управление концевой инкапсуляцией при формировании кадра из пакета. Полный обозор флагов не входит в наши цели.
Каждый флаг это некоторый бит в числе характеризующем состояние интерфейса. Это число приведено перед списком флагов в угловых скобках В ШЕСТНАДЦАТЕРИЧНОМ представлении. Так число 8843 переводится в двоичную систему как 1000100001000011 и означает набор флагов <UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST>. Здесь за флаг UP отвечает самый правый бит, BROADCAST — второй справа, RUNNING — 7-й справа. Переключая флаги нетрудно вычислить какой бит чему соответствует. Легко видеть, что для того, чтобы интерфейс работал, необходимо (но недостаточно), чтобы число было нечётным.
Некоторые флаги поддерживаются не во всех операционных системах, что связано, возможно (это мои домыслы), с разрядностью числа характеризующего состояние сетевого интерфейса в них. Так флаг STATICARP (20-й бит справа) есть только в FreeBSD и отсутствует в OpenBSD и NetBSD. То же относится к флагу MONITOR (19-й бит).
Утилита netstat(1) предназначена для диагностики работы TCP/IP стека. Она выводит разнообразную информацию о работе сетевых интерфейсов на сетевом и транспортном уровнях:
$ 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» в секундах.
$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 пакета.
        
![]()  | Замечание | 
|---|---|
| Аналогичную информацию можно получить так же при помощи программы 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 ESTABLISHEDtcp4 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 *.*
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
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
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) состоит из двух частей: в первой перечислены открытые в настоящий момент соединения интернет, а во второй перечислены используемые системой сокеты.
Программа 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:
Пусть клиент открывает соединение с сервером. Тогда говорят, что клиент осуществляет активное открытие соединения, а сервер пассивное открытие соединения. Изначально сервер находится в состоянии LISTEN.
Теперь стороны могут обмениваться данными в обе стороны, в состоянии ESTABLISHED, обе стороны высылают друг другу пакеты с данными, время от времени присылая подтверждения о получении этих пакетов, причём в одном подтверждении может подтверждаться получение большого числа пакетов.
Процесс открытия соединения часто называется тройным рукопожатием, так как происходит обмен тремя пакетами в обеих направлениях. (См. так же Раздел B.1.4.3.2, «Открытие соединения TCP, тройное рукопожатие».)
Пусть клиент закрывает соединение с сервером. Тогда говорят, что клиент выполняет активное закрытие, а сервер пассивное закрытие. Изначально оба хоста пребывают в состоянии ESTABLISHED.
Утилита 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 можно следить за изменениями маршрутной таблицы в реальном времени.
        Когда машине надо обратиться к некоторому адресу в интернет, она
        должна преобразовать символьное имя машины (такое, как
        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"rcode = 3 (Non-existent domain), ancount=0 Trying domain "ru"
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
   | Здесь осуществлена попытка разрешить имя host.somewhere.ru. Эта попытка завершилась неудачей — такого хоста нет. | 
   | Теперь система пытается разрешить имя 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
        никаких специальных действий не требуется, изменения немедленно
        вступают в силу.
      
Описание. Кандидат должен уметь изменять настройки 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», но на этот раз с точки зрения управления параметрами. Как и в прошлый раз, мы выйдем за рамки задачи постваленной в данном экзаменационном билете, во имя целостности повествования.
Утилита hostname(1) может не только сообщать имя машины, но и устанавливать новое:
$hostname myhost.example.org$hostname -s myhost#hostname other.example.org$hostname other.example.org
Утилита ifconfig(8) позволяет не только просматривать, но и манипулировать настройками сетевого интерфейса. Причём даже на физическом уровне OSI. (О модели OSI можно прочесть в глоссарии: OSI.)
Здесь описаны не все возможности утилиты ifconfig(8). Существуют некоторые опции, характерные для данных операционных систем и т.д. Сверяйтесь со справкой вашей операционной системы. Например, OpenBSD позволяет объединять интерфейсы вгруппы, а FreeBSD такой особенностью не обладает.
В общем случае, для конфигурирования физических параметров интерфейса надо предварительно изучить справку по соответствующему драйверу. Мы приведём примеры на основе драйвера к распространённому чипсету 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, но реально вести передачу на такой скорости не могли и их пришлось вручную «тормозить».
$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
            Выше был приведён перечень флагов канального уровня, характеризующих работу сетевого интерфейса. Некоторые из этих флагов можно переключать используя команду ifconfig(8).
up/downpromisc/-promiscmonitor/-monitorlink[0-2]/-link[0-2]arp/-arpstaticarp/-staticarpdebug/-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
            MTU переключается оцией mtu. Снижая mtu вы
            с одной стороны замедляете работу сети, с другой стороны
            повышаете вероятность того, что ваши пакеты дойдут до
            адресата без фрагментирования. (Некоторые брандмауэры
            отбрасывают фрагментированные пакеты.) Однозначных
            рекомендаций тут дать невозможно. Даже тезис о том, что
            снижение MTU приводит к снижению скорости передачи данных,
            несовсем верен. Безусловно возрастают накладные расходы на
            протокол TCP, увеличивается удельный вес заголовков и общий
            трафик, однако Ричард Стивенс
            [Stevens-2003-ru] приводит убедительный
            пример того, как фрагментированные пакеты быстрее передаются
            в сети через серию маршрутизаторов, в силу более
            равномерного использования каналов связи (пока второй пакет
            передаётся первому шлюзу, первый пакет уже может быть
            отправлен второму шлюзу, если бы оба пакета были объединены,
            участок между первым и вторым шлюзом простаивал бы вдвое
            дольше).
          
Ограничение сверху на MTU накладывает природа передающей среды. В сетях Fast Ethernet MTU не может превышать 1500 байт.
По поводу IPv6 и MTU уместно процитировать «википедию» [url://wiki-IPv6-ru]:
В IPv6 пакеты не могут фрагментироваться и собираться маршрутизаторами. Отправитель должен заранее выяснить максимальный размер пакетов (MTU), поддерживаемый на всём пути до получателя, и, при необходимости, выполнить фрагментацию своими силами. Оговаривается, что MTU не может быть меньше 576 байт. Снятие с маршрутизаторов функций фрагментации также способствует повышению эффективности их работы, но усложняет работу оконечных систем.
Адрес интерфейса и маску подсети можно задавать в традиционном формате, в шестнадчатеричном, а так же в формате 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.
          
            Аналогично добавляются адреса в нотации IPv6, с
            использованием ключевого слова inet6.
          
Команда route(8) служит для управления таблицей маршрутизации. С её помощью можно:
-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
        Файл /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)».
      
        Как было сказано в предыдущем разделе, типичное поведение
        системы состоит в том, что сперва она пытается разрешить имя
        используя файл /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, вы должны перенести
        туда же копию данного файла.
      
Увы, это самое мутное место. Кажется нет двух систем BSD с одинаковой системой инициализации.
          В 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"
          
          Для запуска настройки сети в системе
          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 будет заменено на имя
          интерфейса.
        
          В 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. Правда мило? Каждый раз консультируйтесь со справочной страницей, а ещё лучше со скриптами, которые все эти настройки вызывают.
Описание. Кандидат 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.
      
Команда 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 remin 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
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
root init 1 wd / 2 drwxr-xr-x 512 r root init 1 text / 47 -r-x------ 485892 r
   | 
            Прежде всего, конечно, отметилась сама программа
            fstat(1). Видно, что от имени
            пользователя  
а если в pipe, то вывод будет выглядеть так: 
            Видно, что fstat(1) открыл pipe с
            номерами сокетов  
            Вернёмся к примеру. Второй файловый дескриптор направлен,
            как видно, на консоль ttyp0 (Это поток
             
            Дескрипторы 3 и 4 общаются с устройствами
             
            Перед перечнем файловых дескрипторов с номерами, мы видим
            три строки (самые первые) с отметками в поле файлового
            дескриптора  
 
            Зная точку монтирования и номер inod можно найти к чему
            относятся приведённые значения  
 Синтаксис программы find(1) обсуждается в Раздел 7.6, «Поиск файла по заданным атрибутам». Команда lsof(1), обсуждающаяся ниже, печатает в выводе не только номера inod, но и имена файлов, которые она берёт из кеша ядра.  | 
   | 
            Здесь, для примера, приведены записи о 8-ми экземплярах
            команды getty(8), которые открыты на
            терминалах ttyv0—ttyv7 и ждут логина пользователя. (Мы
            прошли на машину по ssh(1), поэтому ни
            один из терминалов неиспользован).
           | 
   | В конце приведены сведения о процессе init(8) — родительском процессе для всех прочих процессов. | 
Программа 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-n-u-p 21-23,25,80,110Аналогичную информацию можно получить при анализе вывода программы netstat(1). См. Раздел 6.1.2, «netstat(1)» и Раздел 6.1.2.3, «Работающие интернет сервисы и открытые сокеты».
Это тоже очень полезная программа, которая умеет рассказывать об открытых сокетах, сетевых соединениях и открытых файлах. Данная программа не входит в состав 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'ов, но и имена файлов, которые она берёт из кеша
        ядра.
      
Программа 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.
Описание. Кандидат BSDA должен уметь определить доступна ли удалённая система через TCP/IP и, если да, уметь при помощи telnet(1) убедиться отвечает ли сервис на клиентские запросы.
Практика. ping(8), traceroute(8), telnet(1), nc(1) на FreeBSD и OpenBSD
        Утилита 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
        В первом («Винни-Пуховском») примере мы получили ответ от машины, которую мы и пинговали, следовательно она всё-таки включена. А во втором примере, пакет не был доставлен машине, так как она не была найдена (в приведённом примере не была найдена не только машина, но даже сеть, в которой она должна находиться).
Команда 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), описанная ниже.
Данная программа не входит в курс 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].
Основное назначение программы 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) используется в качестве прокси-сервера.
Описание. Кандидат BSDA должен понимать основы теории DNS, включая типы DNS записей обратное преобразование имён и перенос зон. Кандидат должен уметь посылать запросы серверу DNS о записях нужного типа, понимать какой сервер авторитетен за зону и понимать готов ли сервер к пересылке зоны.
Практика. dig(1), host(1), nslookup(1), ping(8), telnet(1)
Литература по настройке серверов DNS чрезвычайно обильна. Я пройдусь по теме насколько это возможно кратко.
        Итак, протоколы IP и IPv6 устроены таким образом, что адресация
        происходит при помощи числовых адресов. Нельзя сказать, что
        человека это должно как-то напрягать, ведь никто не протестует
        против применения семизначных, десятизначных и даже более
        длинных телефонных номеров. Однако иметь более мнемоничные
        адреса несомненно удобнее. Почти сразу, как только появился
        интернет, появились таблицы соответствия IP адресов и символьных
        имён машин. Эти таблицы и по сей день хранятся в файле
        /etc/hosts. Однако задача синхронизации
        данного файла между машинами очень скоро стала непомерно
        сложной. В настоящий момент можно с уверенностью сказать, что
        она вообще нереальна. Для решения этой проблемы возникла система
        DNS — распределённая база данных.
      
Распределённая, значит ни один сервер не содержит в себе сведений обо всём пространстве имён Интернета. Каждый сервер ответственен за свой участок этого пространства. Говорят, что данный сервер авторитетен для данной зоны.
Таким образом, пространство имён Интернета поделено на зоны. Каждый сервер может отвечать за ноль и более зон. Рассмотрим, что происходит когда некоторой машине надо узнать IP адрес машины www.dragonflybsd.org.
/etc/hosts, затем, в случае неудачи,
          будет изучен файл /etc/resolv.conf.
          Дополнительную информацию об этих этапах можно узнать из Раздел 6.1.4, «/etc/resolv.conf(5)» и Раздел 6.7, «Изменение порядка разрешения имён».
          Сейчас нам важно, что в итоге мы сделали запрос к некоторому
          серверу DNS.
        
            Сервер DNS должен самостоятельно узнать адрес машины
            www.dragonflybsd.org. и сообщить его клиенту даже если он не
            является авторитетным для зоны в которой находится данная
            машина (т.е. зоны dragonflybsd.org.). Сервер, который в
            состоянии выполнить всю работу по розыску адреса, задав все
            вопросы другим серверам DNS самостоятельно называется
            рекурсивным. В /etc/resolv.conf можно
            указывать только рекурсивные сервера DNS.
          
Первым делом наш сервер посылает запрос одному из корневых серверов DNS. Разумеется ни один из корневых серверов не знает ответа на этот вопрос. Больше того, ни один из них и не будет разбираться в вопросе, т.е. ни один из них не является рекурсивным. Зато они знают, какие сервера ответственны за зону 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.
Полное описание работы с сервером BIND выходит за рамки данного раздела. Мы лишь опишем настройку файла зоны, с тем, чтобы администратор мог сознательно применять утилиты host(1), dig(1) и nslookup(1).
            Сначала зона должна быть объявлена в конфигурационном файле
            сервиса 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.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.
          
@ будет
                    заменён на содержимое переменной $ORIGIN, но мы могли бы написать
                    явно example.ru..
                  @
                    применяться в файле зоны не может (как уже было сказано,
                    он заменяется на переменную $ORIGIN), вместо него
                    используется точка. данная запись выглядит как доменное
                    имя. Можно написать просто root, в этом случае имя будет
                    достроено до FQDN из переменной $ORIGIN, и первая точка будет
                    заменена на знак @. Таким
                    образом, запись root в данном поле превратится в адрес
                    root@example.ru.
                  В записи типа 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. | 
Здесь описано какие хосты ответственны за приём почты направляющейся в домен example.ru. Если такой записи нет вообще, то почту будет принимать машина с именем example.ru. Если таких записей много, то сперва будет предпринята попытка доставить почту на машину с самым низким значением поля с приоритетом, затем, в случае неуспеха, на машину со следующим приоритетом и так далее.
Итак, данная запись отличается только тем, что в ней добавлено поле с приоритетом записи, сразу после типа записи MX.
![]()  | Важно | 
|---|---|
| Не следует в данной записи указывать IP или имена заданные в записях типа CNAME. Указанные здесь имена должны быть описаны ниже в записи типа A или AAAA. | 
Данная запись указывает соответствие между именем и адресом 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 и в конечном итоге приведёт к замедлению обслуживания клиентов.
Запись этого типа нужна для того, чтобы клиентское програмное обеспечение могло самостоятельно разыскивать машину, на которой поднят нужный сервис и осуществлять распределение нагрузки. К сожалению, немногие браузеры могут похвастать поддержкой этого типа записи в файле зоны. И всё же:
;; _служба._протокол.имя   [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].
Текстовая запись. В ней может находиться самая разнообразная информация. Например стихи:
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/?».
       | 
Программа 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) (см. ниже) и начинает повтрять
        синтаксис файла зоны.
      
Утилита 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
        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
Описание. Кандидат должен уметь выполнить обратный DNS запрос для определения сети, в которой находится машина с данным IP адресом и собрать информацию об этой сети.
Практика. dig(1), whois(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
Сервис 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. В нашей стране, при регистрации домена на физическое лицо, требуют хотя бы паспорт. Поэтому компетентные органы имеют хоть какой-то шанс найти ответственное лицо.
Описание. Кандидат BSDA должен уметь определить в каком порядке опрашиваются различные системы при разрешении имён и знать в каком конфигурационном файле это определяется
Практика. ping(8), telnet(1),
      nsswitch.conf(5),
      resolv.conf(5), host.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) состоит из
        имени базы и списка источников разделённых пробелами.
      
Поле с источниками может включать следующие имена:
/etc/hosts,
            /etc/passwd и проч.
          Поддерживаются следующие базы данных:
![]()  | Замечание | 
|---|---|
        Всё сказанное в настоящем разделе верно для
        FreeBSD, NetBSD и
        DragonFly BSD, но не для
        OpenBSD. В OpenBSD файла
        nsswitch.conf(5) нет. В BSD
        nsswitch.conf(5) впервые появился в
        NetBSD, затем перекочевал в
        FreeBSD и
        DragonFly BSD.
       | 
Описание. Кандидат 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, а затем опишу удобные приёмы устного пересчёта десятичных чисел в двоичные.
При помощи маски подсети система роутинга определяет находится ли данный адрес 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.
Как видно, маска подсети обязана состоять из некоторого количества единиц и следующих за ними нулей. В десятичной записи, маска подсети должна состоять из 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, понимают далеко не все программы, увы.)
Операции устного сложения и вычитания даются человеку легче, чем операции умножения и деления, поэтому не стоит пытаться последовательно делить десятичное число на степени двойки, вычисляя остатки. Лучше сразу вычитать из числа степени двойки. Конечно вы можете избрать любой удобный для вас алгоритм, я делаю это так:
Пусть надо представить в двоичном формате число 170.
Для начала нам понадобится таблица степеней двойки:
| 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 
| 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128 | 
Теперь мы будем последовательно сравнивать наше число со степенями двойки, если число больше либо равно степени, мы записываем единицу, и вычитаем из числа степень двойки, если меньше, записываем ноль и идём дальше:
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
        Обратное преобразование делается ещё проще: надо просто сложить те степени двойки, которым соответствуют единицы в двоичном числе.
Описание: Зная 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.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.
Возьмём адрес подсети и заполним единицами те поля, которым в маске подсети соответствуют нули:
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) не из их числа. | 
Описание. Кандидат 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. Оригинальная документация на английском языке (список, конечно, неполный):
Что до переводов на русский язык, я могу порекомендовать читателю замечательную статью А.Ю. Семёнова [url://Семёнов-IPv6], которая на 98% представляет собой перевод упомянух RFC. А так же своеобразный HOWTO из FreeBSD-handbook [url://FB-handbook-IPv6-ru], который, в части касающейся документации IPv6 так же является цитатой из упомянутых RFC. Фактически никакой другой документации в настоящий момент в сети нет. (А может и не надо.)
Адреса в 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
          (см. ниже).
        
Левая часть адреса 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/6012AB::CD30/6012AB:0000:0000:0000:0000:000:0000:CD3012AB::CD3/6012AB:0000:0000:0000:0000:000:0000:0CD3Адреса IPv6 бывают:
Широковещательных (broadcast) адресов в IPv6 нет, их функции выполняют адреса multicast.
Тип пакета 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)::0000:d.d.d.d и ::ff:d.d.d.dd.d.d.d. Пакет дошедший до этого
                интерфейса со стороны пространтсва IPv6 будет через
                туннель IPv4 направлен на следующий маршрутизатор IPv6.
                Второй адрес используется для предоставления пакета тем
                маршрутизаторам IPv4, которые не поддерживают IPv6.
              ::1::Адрес anycast синтаксически не отличим от unicast. Адреса anycast выделяются из адресного пространства unicast и всё их отличие состоит в том, что один адрес anycast может быть присвоен нескольким маршрутизаторам. Пакет высланный на этот адрес получит ближайший маршрутизатор, где ближайший маршрутизатор определяется по метрике протокола маршрутизации.
Одно из возможных применений адреса anycast — идентификация набора маршрутизаторов провайдера. Префикс адреса anycast фактически указывает на топологическую группу которой принадлежит адрес.
          Существует один предопределённый адрес anycast: 111111101[10] префикс_подсети 00..00.
          Этот адрес соответствует маршрутизатору подсети.
        
Один интерфейс может иметь множество различных адресов IPv6. (Подобно тому, как у интерфейса может быть много адресов IPv4.) Таким образом, интерфейс может одновременно иметь приватный и публичный IPv6 адреса.
Далее следует прямая цитата из [url://Семёнов-IPv6]:
ЭВМ должна распознавать следующие адреса, как обращенные к нему:
- Её локальный адрес канала для каждого из интерфейсов
 - Выделенные уникаст-адреса
 - Адрес обратной связи
 - Мультикастинг-адрес для обращения ко всем узлам
 - Мультикастинг-адрес активного узла (solicited-node multicast address) для каждого из приписанных ей уникаст и эникастных адресов
 - Мультикаст-адреса всех групп, к которым принадлежит ЭВМ.
 Маршрутизатор должен распознавать следующие адреса (as identifying itself):
- Его локальный адрес канала для каждого из интерфейсов
 - Выделенные уникаст-адреса
 - Адрес обратной связи
 - Эникастные адреса маршрутизатора субсети для каналов, где он имеет интерфейсы.
 - Все другие эникастные адреса, которые использовались при маршрутизации.
 - Мультикастинг-адрес для обращения ко всем узлам
 - Мультикастинг-адрес для обращения ко всем маршрутизаторам
 - Мультикаст-адрес активного узла (solicited-node multicast address) для каждого приписанного ему уникаст и эникастного адресов.
 - Мультикастные адреса всех прочих групп, принадлежащих маршрутизатору.
 Приложение должно предопределить только следующие адресные префиксы:
- Не специфицированный адрес
 - Адрес обратной связи
 - Мультикаст-префикс (FF)
 - Локально используемые префиксы (link-local и site-local)
 - Предопределенные мультикаст-адреса
 - Префиксы, совместимые с IPv4
 Приложения должны считать все остальные адреса уникастными, если противоположное не оговорено при конфигурации (например, эникастные адреса).
Одна из целей создателей протокола 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.
Маршрутизаторы должны конфигурироваться несколько иным способом, но это не мешает им иметь локальный канальный адрес полученный аналогичным образом.
Настройка интерфейсов через команду 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) может работать в режиме демона. Утилита не предназначена для работы на маршрутизаторах — только на хостах.
Описание. По данному выводу команды tcpdump(1) кандидат BSDA должен уметь дать ответ на основные вопросы связанные со связью по сети. Для этого кандидат должен знать обычные номера портов для распространённых TCP и UDP сервисов, разницу между TCP/IP сервером и клиентом и о «тройном рукопожатии».
Практика. tcpdump(1)
        В Приложение B, Некоторые сведения о стеке протоколов TCP/IP рассказано многое о
        функционировании протоколов стека TCP/IP. В частности о
        процедуре открытия соединения TCP (процедуре «тройного
        рукопожатия») рассказано в Раздел B.1.4.3.2, «Открытие соединения TCP, тройное рукопожатие». О
        том какие номера портов каким протоколам соответствуют можно
        справиться в файле /etc/services.
      
Утилита 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) можно разделить на несколько типов:
| Опции | Описание | 
|---|---|
-i interface | Какой интерфейс должен прослушиваться программой. | 
-w file | 
                  В норме отчёт программы tcpdump(1)
                  выводится на терминал в режиме реального времени,
                  однако можно попросить при помощи опции
                  -w записывать всю информацию в файл в
                  бинарном виде, т.е. сделать dump того, что происходит
                  на сетевом интерфейсе. В последствии эту информацию
                  можно заново проанализировать при помощи опции
                  -r.
                 | 
-r file | 
                  Эта опция применяется вместо -i и
                  служит для того, чтобы прочитать данные из файла. Файл
                  в бинарном формате можно создать заранее при помощи
                  опции -w. Кроме того, есть и другие
                  программы, которые создают файлы в формате бинарного
                  файла tcpdump(1), например в этом
                  формате сохраняет журнальный файл брандмауэр
                  pf(4).
                 | 
-D | 
                  Перечислить доступные интерфейсы (которые можно
                  прослушивать при помощи опции -i).
                 | 
   | 
              Интерфейс pflog принадлежит пакетному
              фильтру pf(4). (Это брандмауэр
              OpenBSD, который так же доступен в
              FreeBSD, см. Приложение C, Пакетный фильтр OpenBSD — pf(4)) Данный брандмауэр позволяет
              читать журнальный файл в режиме реального времени, для
              этого можно воспользоваться программой
              tcpdump(1) нацелив её на интерфейс
              pflog0. Сам журнальный файл ведётся в
              бинарном формате так, чтобы его можно было прочитать при
              помощи tcpdump(1) с опцией
              -r
             | 
| Опции | Описание | |||||
|---|---|---|---|---|---|---|
-q | Вывод информации в краткой форме. Одно из «неудобств» программы tcpdump(1) состоит в том, что она очень информативна. Из-за этого информация о перехватываемых сообщениях не влезает в строку в терминале. Данная опция призвана разрешить эту проблему. | |||||
  | 
                  Эти опции включают вывод содержимого пакета. Опция
                  -A — в формате ASCII,
                  -x — в шестнадцатеричном
                  виде и -X одновременно и в ASCII и в
                  шестнадцатеричном виде. К сожалению, я ещё ни разу не
                  видел чтобы опция -A работала. На
                  протестированных мною версиях она была эквивалентна
                  опции -x. Двухбуквенные опции делают
                  то же, что и их однобуквенные аналоги, но не
                  отбрасывают заголовки канального уровня. Для просмотра
                  содержимого пакетов может быть так же полезна опция
                  -s (см. далее).
                 | |||||
  | 
                  Verbouse — подробный вывод информации о
                  заголовке пакета. Чем больше букв v
                  тем подробнее вывод.
                 | |||||
  | Разный формат вывода даты: 1) не выводит информации о времени, 2) время выводится в секундах от начала UNIX эры, 3) выводится информация о том, сколько прошло микросекунд после предыдущей строки, 4) обычный формат (час:мин:сек.микросек), но спереди добавлена текущая дата (год-месяц-число). | |||||
  | 
                  -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...@.......0x0010: 3e75 6c07 0800 a34d fbdf 0dba 447e e252 >ul....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 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.
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
| Опции | Описание | 
|---|---|
-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.
                 | 
Условия определяют то, какие пакеты будут перехвачены. Если не указано никаких условий, будут перехвачены все пакеты, если условия указаны, то только те пакеты, для которых это условие истинно.
Условие состоит из некоторого количества примитивов. Примитив состоит из идентификатора (числа или имени) перед которым идёт оператор одного из трёх типов:
host, net, port, portrange. Например, возможны
              следующие примитивы: host
                somehost, net 128.3,
              port 20, portrange 6000-6008src,
              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.
        
Допустимые примитивы:
ip host xxx эквивалентно ether proto \ip and host xxx.
              Замечание: «ip» — ключевое слово,
              поэтому мы должны защитить его обратным слешем (а в
              shell'е двумя бекслешами).
            /etc/ethers). Эквивалентная
              конструкция ether host xx1 and not host xxx2, где xxx1 это
              аппаратный адрес хоста xxx, а xxx2 — IP адрес
              xxx.
            /etc/services.
            icmp,
              icmp6,
              igmp,
              igrp,
              pim,
              ah,
              esp,
              vrrp,
              udp,
              tcp.
              Замечание: идентификаторы tcp,
              udp и icmp являются ключевыми словами и
              должны защищаться обратным слешем (а в shell'е двумя
              бекслешами).
            ip6
                protochain 6 соответствует пакет IPv6 с
              заголовком TCP. Пакет может содержать, например,
              аутентификационный заголовок, маршрутизационный заголовок
              или дополнительный hop-by-hop заголовок.
            ether
              можно опустить. Данный примитив эквивалентен ether[0] & 1 != 0.
            
                Истина, если пакет принадлежит канальному протоколу 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 ведут себя
              как синонимы.
              
ether proto p,
              где p — один из перечисленных протоколов.
            vlan 100
                && vlan 200 соответствуеют пакеты vlan
              200 упакованные в пакеты vlan 100. Условию vlan && vlan 300 &&
                ip соответствуют пакеты IPv4 упакованные в vlan
              300, которые упакованы в vlan верхнего уровня.
            ip proto p
                or ip6 proto p, где p — один из
              перечисленных протоколов.
            clnp,
              esis,
              isis.
            iso proto
                p, где p — один из перечисленных
              протоколов.
            
          Программа tcpdump(1), как отмечалось выше,
          может использоваться пакетным фильтром (PF)
          OpenBSD для обработки журнальных файлов
          (при помощи опции -r), а так же для чтения
          журнала в режиме реального времени при помощи опции
          -i через устройство pflog (см. Раздел C.2.3.1, «Журналирование в пакетном фильтре»). Пакетный фильтр
          OpenBSD работает не только в
          OpenBSD, но и в FreeBSD.
          В последней системе он сперва появился как порт, а затем был
          добавлен в ядро начиная с версии
          FreeBSD 5.2.1. Теперь он портируется в
          ядро FreeBSD при каждом релизе.
        
Пакетный фильтр помещает в пакеты, которые он направляет в журнал специфическую информацию, о том, какое правило отправило пакет в журнал, какие действия предприняты с этим пакетом и проч. Для работы с этой информацией tcpdump(1) имеет специальные примитивы. Перечисленные ниже примитивы пригодны только для работы с журналом PF.
ifnamematch,
              bad-offset,
              fragment,
              short,
              normalize,
              memory.
            pass и
              block.
            Дополнительный примитив — арифметический:
                Истина, если выполнено данное отношение, где 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 host vs and
            ace эквивалентно not host vs and
            host ace.
        
Все пакеты относящиеся к трафику с машиной 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=0101 | 10>>1=5 | 
1010>>2=0010 | 10>>2=2 | 
1011<<3=1011000 | 11<<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'
Приведённые команды эквивалентны.
Описание работы wireshark(1) выходит за рамки данного труда, однако не упомянуть о них в связи с tcpdump(1) невозможно. wireshark — графический анализатор протоколов. С его помощью удобно разбирать сделанные при помощи tcpdump(1) и других анализаторов файлы, кроме того она сама позволяет прослушивать сеть и делать dump'ы в формате программы tcpdump(1).
У программы wireshark(1) несколько имён:
        Пока данный раздел не написан я просто приведу скриншот
        программы wireshark(1), в которой открыт файл
        pflog — журнальный файл
        пакетного фильтра OpenBSD. (См. Приложение C, Пакетный фильтр OpenBSD — pf(4)). Дополнительную информацию об
        wireshark вы можете найти в работе Николая
        Малых: [url://Malyh-ethereal-2005].
      

        Существует не мало разнообразных анализаторов, которые выводят
        разнообразную статистику из файлов в формате 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 >>>>
        Другая удобная утилита предназначенная для анализа сетевого
        трафика и дампов в формате 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, «Применение регулярных выражений»)
Описание. Кандидат должен понимать основы работы протокола ARP: обнаружение соседей, изучение arp-кеша, использование в сетях IPv6. Кандидат должен уметь просмотреть, изменить и очистить этот кеш, а так же понять когда это надо сделать.
Практика. arp(8), ndp(8)
Назначение протокола ARP описано в Раздел B.1.3.1, «ARP». Коротко, оно заключается в связи между сетевым и канальным уровнем модели OSI, обеспечивая преобразование IP адресов в аппаратные (MAC) адреса.
Утилита arp(8) используется для того, чтобы управлять ARP кешем. Когда системе надо послать пакет на адрес IP, сперва необходимо узнать какому аппаратному адресу он соответствует, для того, чтобы сформировать Ethernet-кадр. Система посылает широковещательный ARP запрос «кто имеет данный IP?». Получив ответ, система помещает его в кеш и хранит его там около двух минут. При помощи команды arp(8) можно просмотреть содержимое этого кеша:
$arp -an? (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]
? (192.168.0.255) at ff:ff:ff:ff:ff:ff on rl0 permanent [ethernet]
? (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]
        Команда 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. Комментарий начинается с #.
               | 
Описание. Кандидат 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)
Time Protocol описан в [RFC-868]. Согласно указанному документу на сервере времени поднимается сервис, который слушает 37-й порт, как UDP, так и TCP.
Если клиент связывается по TCP, он должен подключиться к данному порту, после чего сервер вышлет ему пакет содержащий в себе время в бинарном формате как 32-битное число секунд прошедших с 1-го января 1900 года (а не с начала UNIX эры!). Легко видеть, что в 2036-м году этот протокол прикажет долго жить. Между прочим, всего 30 лет осталось — меньше, чем живёт UNIX.
Если клиент предпочитает обмениваться UDP пакетами, то он должен выслать пустую датаграмму на 37-й порт сервера и получить ответную, содержащую в себе время.
Для реализации этого протокола со стороны клиента, существует программа rdate(8). Она входит в состав всех BSD, кроме FreeBSD, где она доступна в виде отдельного порта.
Стоит ли говорить, что протокол это страдает неточностями и давно устарел? Например, в протоколе не учитывается сколько времени шла датаграмма от сервера к клиенту. Впрочем, для подавляющего большинства нужд погрешность в 10 секунд неважна.
        Протокол 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"
        Описание. Кандидат BSDA должен быть знаком с основами DHCP, должен знать как сконфигурировать клиента, перебить настройки полученные с сервера DHCP. В добавок, кандидат должен уметь просмотреть текущие «арендованные» настройки, сбросить их и получить новые. Поскольку DHCP клиенты используются разные, кандидат должен быть знаком с использованием команд DHCP клиента на каждой BSD.
Практика. dhclient(8),
      dhclient.leases(5),
      dhclient.conf(5),
      rc.conf(5)
Описание. Кандидат BSDA должен уметь определить когда следует удалить или установить алиас (псевдоним) для сетевого интерфейса и какие команды доступны для этого в разных BSD.
Практика. ifconfig(8), rc.conf(5),
      ifaliases(5), hostname.if(5)
Содержание
7.1. Перенаправление вывода и использование
      tee(1)
7.2. Определение просмотр и изменение переменных окружения
7.3. Навыки работы в vi(1)
7.4. Определение является ли файл бинарным, текстовым или содержащим данные
7.5. Поиск файлов и бинарников в системе
7.6. Поиск файла по заданным атрибутам
7.7. Написание несложных Bourne-скриптов
7.8. Поиск нужной документации
7.9. Понимание различий в страницах man
7.10. Проверка контрольной суммы файла
7.11. Продемонстрировать знакомство с оболочками используемыми по
      умолчанию в системе
7.12. Чтение почты на локальной машине
7.13. Использование контроля за задачами (job control)
7.14. Применение регулярных выражений
7.15. Преодоление ограничений на длину командной строки
7.16. Понимание значения термина домен в различных контекстах
7.17. Работа с cronКорни систем BSD находятся в Unix, многие Unix утилиты изначально разработаны в BSD. Кандидат BSDA должен продемонстрировать знакомство с основными утилитами командной строки Unix.
Описание: Кандидат 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 направлялся ещё на консоль.
      
Синтаксис перенаправления в 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 используя
        символы |& и >&.
      
Описание: Кандидат 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 | Имя пользователя (логин). | 
          Утилита 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!"
          
          В интерпретаторе sh можно задать значение переменной путём
          присваивания: var=value, например
          NEW=1. После этого переменную
          можно использовать, на её значение можно ссылаться из по
          имени $NEW, но она ещё не стала
          переменной окружения. Чтобы эта переменная стала видна
          программе как переменная окружения, её надо экспортировать
          командой export.
        
$NEW=1$echo $NEW 1$printenv NEW$export NEW$printenv NEW 1
Таким образом, переменные могут быть экспортированными и неэкспортированными. Только экспортированные переменные будут видны вызываемым программам и скриптам. Неэкспортированные переменные, тем не менее можно использовать в текущем сценарии. Они удобны тем, что не влияют на работу вызываемых программ.
          Полный список переменных можно узнать командой set без аргументов, а список
          экспортированных переменных командой export без аргументов.
        
        В языке csh переменная устанавливается командой set, а переменная окружения командой
        setenv. Причём переменные и
        переменные окружения это два совершенно разных массива. Может
        быть одновременно определена переменная и переменная окружения
        с тем же именем, но другим значнием:
      
%set NEW=1%printenv NEW%echo $NEW 1$setenv NEW 2$printenv NEW 2$echo $NEW 1
        Обратите внимание: команды set и
        setenv имеют разный синтаксис.
      
Описание: по умолчанию в системах 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) имеет несколько режимов работы:
Очень важным элементом работы в vi(1) является «движение». Важно уметь передвигаться в vi(1) не посимвольно, при помощи стрелочек, а именно при помощи его буквенных команд, упомянутых ниже. В комбинации с другими командами это даст вам большие возможности по редактированию текста.
Таблица 7.2. Движения в vi(1), Normal mode
| Команда | Мнемоника | Описание | 
|---|---|---|
| h j k l | нет | Это клавиши посимвольного перемещения, тождестенные стрелкам. Стрелки есть не на всех клавиатурах, кроме того, для людей владеющих слепым набором такой способ перемещения удобен, так как им не приходится снимать руки с клавиатуры, для того, чтобы добраться до нужного символа. | 
| w | word | Перемещение к началу следующего слова | 
| W | WORD | Перемещение к началу следующего слова, но под словом подразумевается не совокупность букв, а совокупность непробельных символов. Таким образом, URL http://www.vim.org/ состоит из нескольких слов, но из одного СЛОВА. | 
| e | end | Перемещение вперёд, к концу слова | 
| E | END | Перемещение вперёд, к концу СЛОВА | 
| b | begin | Перемещение назад, к началу слова | 
| B | BEGIN | Перемещение назад, к началу СЛОВА | 
| n | next | Применяется после поиска в 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>d | delete | Удалить текст, через который осуществлялось движение. При удалении текст помещается в буфер | 
| dd | delete | Удаляет целиком текущую строку | 
| D | delete | Удаляет текст от текущего символа до конца строки | 
| <move>y | yank | Поместить текст через который осуществлялось движение в буфер (не удаляя) | 
| yy | yank | Поместить в буфер целиком текущую строку | 
| Y | yank | То же, что и yy, как ни странно | 
| <move>c | change | Удалить текст через который осуществлялось движение и немедленно перейти в Insert mode | 
| cc | change | Удалить текущую строку и немедленно перейти в Insert mode | 
| C | change | Удалить текст от текущей позиции до конца строки и немедленно перейти в Insert mode | 
| p | paste | Вставить текст из буфера | 
| P | paste | Вставить текст из буфера слева от курсора | 
| x | нет | Удалить символ под курсором. (На заметку: сочетание клавиш xp меняет местами два символа. Почему?) | 
| X | нет | Удалить символ слева от курсора (как клавиша BackSpace) | 
| ~ | нет | Инвертировать регистр букв (строчная буква меняется на прописную, а прописная на строчную). Например сменить UNIX на unix: 4~ | 
| r<letter> | нет | Заменить символ находящийся под курсором на <letter> | 
| < <move> | нет | Уменьшить отступ у текста захваченного движением <move> | 
| > <move> | нет | Увеличить отступ у текста захваченного движением <move> | 
| U | undo | Отменить последнее действие. В vi(1) можно сделать многократное undo, весма нетривиальным способом, на первый взгляд оно кажется однократным[a]. В vim(1) объём undo можно задать любым. | 
| . | нет | Повторить последнее действие | 
| i | insert | Вход в Insert mode слева от курсора | 
| I | insert | Вход в Insert mode в начале строки | 
| a | append | Вход в Insert mode справа от курсора (это удобно, если вы переместились в конец слова клавишей e) | 
| A | append | Вход в Insert mode в конце строки | 
| R | insert | Вход в Replace mode (то же, что Insert, но при наборе символы замещают текст) | 
| o | нет | Добавить строку под курсором, встать на неё и войти в Insert mode | 
| O | нет | Добавить строку над курсором, встать на неё и войти в Insert mode | 
| / | нет | Вход в Search mode для поиска вперёд | 
| ? | нет | Вход в Search mode для поиска назад | 
| ZZ | нет | Записать файл и выйти | 
[a] Если вы в
                    vi(1), в Normal mode нажимаете
                    клавишу «  | ||
Например, если у нас есть надпись <entry>НАДПИСЬ</entry> и нам надо заменить её на <entry>ЬСИПДАН</entry> мы встаём на начало строки и выполняем такое действие: f>lct<ЬСИПДАН правда всё просто и очевидно? Потренируйтесь, обещаю вам, что через неделю вы перестанете понимать как вы до сих пор обходились без vi(1).
Из Insert mode главное — уметь выходить. Для этого есть миниму два способа: <Esc> или Ctrl+C. Последнее удобнее по эргономичным соображениям.
Вас может удивить, что в vi(1) в Insert mode не всегда можно перемещаться стрелками, не всегда работает BackSpace. Научитесь пользоваться «родными» клавишами vi(1) — их главное преимущество состоит в том, что они работают всегда на всех терминалах, заходите ли вы с чужого макинтоша на тостер под управлением NetBSD или запустили экзотический эмулятор терминала и держите в руках клавиатуру SUN на которой все кнопки другие, а видете её первый (и быть может последний) раз в жизни.
Поиск в 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) всётаки вносились...
Некоторые действия можно выполнить в vi(1) только с командной строки. Например задание значения переменной. Вход в командную строку осуществляется из Normal mode клавишей :. Переменные могут принимать числовые значения, а могут выставляться в истину или ложь. В последнем случае они должны задаваться с префиксом no:
Многие команды можно задавать не полностью выписывая имя команды, например :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 | Описание | |
|---|---|---|---|---|
| краткая | полная | |||
| list | list | bool | + | Видоизменяет отображение файла таким образом, чтобы пользователь мог отличить пробелы от табуляторов | 
| nu | number | bool | + | Отображает номера строк | 
| ts | tabstop | integer | + | задаёт ширину табулятора | 
| sw | shiftwidth | integer | + | задаёт величину отступа добавляемую, например, командой > | 
| searchinc | searchinc | bool | - | включает инкрементный поиск | 
| ruler | ruler | bool | - | Отображает номер строки и колонки в нижней строке экрана | 
| ic | ignorecase | bool | + | Неразличать регистр при поиске | 
| ro | readonly | bool | + | Файл открыт в режиме «только для чтения» | 
| ws | wrapscan | bool | + | При поиске, по достижении конца файла, продолжить поиск с начала до курсора. Т.е. искать во всём файле. | 
Надо честно признаться, я не осветил возможностей vi(1) и на 20%, не говоря уже о vim(1). С другой стороны, объём сведений данных здесь достаточен для повседневной работы и для сдачи экзамена BSDA.
Описание: Системы 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>5 byte x \b, version %c
>7 byte x \b.%c
![]()
   | 
            Начиная с нулевого байта искать строку %PDF- (т.е. файл обязан начинаться
            именно так).
           | 
   | Пятый байт обозначает номер версии | 
   | Седьмой байт — младший номер версии | 
Описание: Кандидат 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).
    
        Команда 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
        Команда 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).
        Команда 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.
      
Команда find(1) тоже предназначена для поиска файлов, однако она, в отличие от locate, осуществляет реальный поиск в системе, а не заглядывает в базы данных. Работает она, поэтому, значительно медленнее, однако её возможности чрезвычайно велики. Подробнее она будет описана ниже (см. Раздел 7.6, «Поиск файла по заданным атрибутам»).
Не все команды вызываются при помощи сценариев или бинарников. Есть ещё встроенные команды оболочки, определённые функции. Так, например, по команде 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 нет.
Описание: Утилита 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.
      
        Условия для поиска задаются опциями, перечисленными ниже. При
        задании нескольких опций, они объединяются через оператор
        «и». Связку «и» можно задать явно используя
        опцию -and. Связка «или» задаётся
        опцией -or. Унарное отрицание —
        ! и символы группировки —
        (...), в sh и
        csh необходимо защищать используя либо
        кавычки, либо \.
      
-amin n -cmin n
            -mmin nn
              минут. Здесь под временем файла имеется ввиду:
              -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- не указан, условие истинно, если флаги
              в точности соответствуют указанным. Если знак
              - указан, условие совпадает, если как
              минимум указанные флаги присутствуют.
            -perm [-] mode- имеет то же
              значение, что и в опции -flags.
            -group group, -user user-nogroup, -nouser-type typeУсловие истинно, если найденный файл имеет указанный тип. Возможные типы файла:
b | block special | блочное устройство | 
c | character special | символьное устройство | 
d | directory | каталог | 
f | regular file | обычный файл | 
l | symbolic link | символьная ссылка | 
p | FIFO | именованный канал | 
s | soket | сокет | 
-fstype typelocal и
              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
              искать файлы только в текущем каталоге, не погружаясь в
              подкаталоги.
            
        Простейшее действие — напечатать имя файла на
        STDOUT.  Это действие по умолчанию
        предпринимается если ничего другого не указано. Оно эквивалентно
        указанию опции -print.
      
-print-print0-ls-dgils.
            -deleteОпция есть только в FreeBSD!
Удалить найденные файлы и директории.
-exec команда [опции [{}]] ;{}, то она будет заменена именем файла (с
              путём). Символ ; означает, что в этом
              месте закончилась команда и её опции.
            -execdir команда [опции [{}]] ;-exec, но при выполнении
              команды find(1) переходит в каталог,
              где находится файл, а {} заменяет на имя
              файла без пути.
            -ok команда [опции [{}]] ;-exec, но перед выполнением
              команды find(1) запрашивает
              подтверждение у пользователя.
            -exec команда [опции [{}]] +Опция есть только в FreeBSD!
              Эквивалентна опции -exec ... ;, но
              замещает {} не одним найденным файлом, а
              списком файлов. Таким образом, указанная команда
              вызывается лишь однажды. Это работает как же, как связка с
              командой xargs(1).
            
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 ...
        Теперь, какие бы причудливые имена ни встретились нам, даже если они содержат кавычки, пробелы, символы конца строки, они будут обработаны корректно.
Описание: Большинство задач системного администрирования могут быть автоматизарованы с использованием 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) — это вызов внешних программ, которые, собственно, и делают основную работу.
С чего начинается скрипт? С некоторой магической строки — shebang. Вообще, последовательность действий операционной системы с файлом при попытке пользователя запустить его на исполнение, выглядит примерно так:
#! то перед нами «магическая
          строка» (shebang). Вся строка от третьего символа до
          конца строки является указателем на интерпретатор. Надо
          выполнить указанную строку, подав интерпретатору на вход
          скрипт. Такая конструкция позволяет запускать интерпретатор с
          дополнительными опциями: #!/usr/local/bin/perl -w или
          делать сложные вызовы, указывая специальные переменные
          окружения: #!/usr/bin/env -i /usr/local/bin/python.
        
        Даже несмотря на наличие такого умолчания, разумно указывать
        интерпретатор в явном виде. Сценарии sh должны начинаться со
        строки #!/bin/sh.
      
        На вход интерпретатору подаётся весь скрипт целиком, включая
        первую строку с shebang. Поэтому скриптовый язык обязан
        воспринимать знак #как символ комментария, как
        минимум в первой строке. В этом легко убедится. Пусть у нас есть
        скрипт test.cat состоящий из двух строк:
      
#!/bin/cat
Hello
        При попытке выполнить скрипт мы получим:
$chmod 755 test.cat$./test.cat #!/bin/cat Hello
Ещё одной особенностью скрипта является то, что он обязан иметь пермиссии не только на исполнение, но и на чтение. В противном случае скрипт не сможет быть направлен на стандартный вход указанному интерпретатору.
В разделе посвящённом переменным окружения обсуждается вопрос использования утилиты env(1) в shebang и вопросы связанные с безопасностью при использовании различных интерпретаторов в «магической строке».
Надо честно признать, повседневно работать в 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. Синтаксическая таблица 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. (См. ниже про
                  «модули») | 
: | Встроенная команда ничего не делающая, но возвращающая истину. | 
          Присваивание переменной осуществляется при помощи оператора
          =. Вызов определённой ранее
          переменной, при помощи префикса $. Например:
        
$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 последнего отправленного в фон процесса. | 
В качестве условия в 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 "Прекрасный выбор для сервера";;NetBSD) echo "Это NetBSD, она поддерживает самые немыслимые архитектуры." echo "Хороший выбор для тостера или холодильника.";; BSD|[Dd][Aa][Rr][Vv][Ii][Nn])
echo "Есть основания полагать, что это тоже BSD";; *)
echo "Не знаю, что это.";; esac
Специально для условного оператора 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).
В sh(1) имеется два вида циклов: цикл с условием и цикл с перебором. Первый действует до тех пор, пока верно некоторое условие. Второй перебирает значения некоторого списка, приравнивая переменную (итератор) каждый раз к новому значению из этого списка. Кроме того, имеются обычные команды для прерывания цикла.
            Следующая программа выводит список квадратов натуральных
            чисел от 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 указано число, то оно
            означает глубину цикла, который будет ими прерван.
          
            Следующая программа конвертирует все картинки в каталоге
            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.
          
          sh(1) позволяет определять функции и
          вызывать их. Переменные $1, $2 и т.д. внутри функций ссылаются не
          на аргументы скрипта, а на аргументы с которыми функция
          вызывалась. Ниже определена функция для вычисления квадрата
          натурального числа и переписан цикл выводящий список
          квадратов натуральных чисел:
        
sqrt () {
  echo $(($1*$1))
}
i=1
while [ $i -le 100 ]
do
  sqrt $i
  i=$(($i+1))
done
          При помощи директивы return функция может вернуть свой собственный код возврата.
          В 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().
        
            Команда 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
Команда 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
}
            Встроенная в sh(1) команда trap позволяет зарегистрировать обработчик сигнала. Если в процессе выполнения скрипт получит указанный в команде trap сигнал, то вместо обычного поведения, он вызовет указанный обработчик:
terminator () {
echo "Не умру ни за что" >&2
}
trap terminator 15
            
            Теперь, если скрипт получит сигнал
            SIGTERM (номер 15), то вместо того,
            чтобы нормально завершиться, он напечатает на стандартный
            вывод ошибок сообщение и продолжит работу.
          
Более разумным применением этого механизма было бы стирание временных файлов и корректное завершение работы.
В заключение следует сказать, что после того, как вы написали могучий сценарий sh(1), ему не мешает дать пермиссии на выполнение, командой chmod(1).
Описание: Системы BSD хорошо документированы. Существует множество доступных администратору ресурсов. Кандидат должен уметь воспользоваться локальной документацийе, а так же знать о документации доступной в сети Internet.
Практика: apropos(1), man(1),
      man.conf(5), whatis(1), и
      info(1); share/doc и
      share/examples; в добавок, каждый проект BSD
      имеет on-line документацию и несколько почтовых списков рассылки.
    
Справочная система 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»)
Существуют страницы 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). Вся система организована, как дерево «нод».
        В каталогах share/doc и
        share/examples можно найти дополнительную
        документацию в форматах txt или html, а так же примеры
        конфигурационных файлов с комментариями. Там действительно много
        полезной справочной информации, авторам которой просто не
        хватило времени и желания на то, чтобы оформить их в каком-то
        другом виде.
      
В разделе Раздел 3, «Источники информации» перечислены ссылки на интерактивную справочную информацию. Для русскоязычных пользователей хочется особо отметить прекрасный перевод Handbook по FreeBSD. На курсах, которые я читаю по операционной системе Linux, я рекомендую слушателям заглядывать в этот источник, хотя он и не нацелен непосредственно на пользователей Linux.
Описание: Кандидат 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
        
/bin. Например:
            cp(1), mv(1),
            passwd(1), sh(1),
            csh(1), crontab(1)passwd(5),
            rc.conf(5)~/.login
            можно добавить такую строку:
            [ -x /usr/games/fortune ] && /usr/games/fortune freebsd-tips
Полагаю, что наиболее полезны для администратора страницы 1, 5 и 8.
        Внутри интерактивной справки man(1)
        пользователь попадает в программу more(1)
        (если иного не указано в переменной oкружения
        PAGER). Работа с этой программой очень похожа
        на работу с less(1). Во всяком случае, так же
        как и в less(1) поиск вперёд осуществляется
        клавишей /, а назад —
        ?. Переход на следующее или предыдущее
        вхождение найденного слова клавишами n и
        N соответственно.
      
Описание: Кандидат должен быть знаком с началами теории вычисления конторльной суммы и почему вообще важно её вычислять. Кандидат должен уметь вычислить контрольную сумму файла, проверить контрольную сумму.
Практика: md5(1), openssl(1), sha1(1), cksum(1).
Различные утилиты для подсчёта контрольных сумм служат для того, чтобы пользователь мог убедиться в аутентичности файла, которым он располагает. Так, например, устанавливая программу sudo(1) из исходного кода, или из заранее скомпилированного бинарника, полезно убедиться, что то что вы скачали действительно то, что вы хотели скачать. Для этого надо подсчитать контрольную сумму файла. Теоретически можно представить, что злоумышленник смог изменить файл таким образом, что его размер и контрольная сумма при этом не изменились, т.е. найти коллизию (коллизия, это когда два файла имеют одну контрольную сумму), но представить себе при этом, что он сумел сохранить функциональность программы крайне трудно. В особенности, если вы проверите две разные контрольные суммы двумя разными алгоритмами.
        Наличие этой программы требуется стандартом
        POSIX. У данной программы есть необязательный
        аргумент -o, при помощи которого можно задать
        различные «исторические» (читай устаревшие) алгоритмы
        подсчёта контрольной суммы.
      
В настоящее время программа cksum(1) вычисляет контрольную сумму (CRC) по стандарту ISO/IEC 8802-3:1989. Алгоритм описан в справочной странице man(1).
Команда cksum(1) выводит два числа: контрольную сумму и число байт.
        Программа для подсчёта hash-суммы по одноимённому алгоритму.
        Данный алгоритм используется по умолчанию при работе с паролями.
        Полезные аргументы: -q не выводить ничего,
        кроме самой суммы (полезно в скриптах) и -r
        выводить в начале сумму и только потом имя файла. Это облегчает
        визуальную проверку, если надо сравнить два файла —
        суммы будут написаны строго друг под другом.
      
Длина суммы — 128 бит.
Идея хеширования состоит в том, что мы имеем некоторую очень резко меняющуюся и необратимую функцию, таким образом, даже от очень похожих строк получаются катастрофически разные результаты, а по хеш сумме невозможно восстановить оригинальную информацию. Это делает данный механизм пригодным для хранения шифрованных паролей.
Алгоритм хеширования MD5 до сих пор не взломан, хотя существует способ находить коллизии — когда несколько вхождений дают один результат. Но для того, чтобы найти коллизию, надо знать оригинал, таким образом, неясно как это могло бы скомпрометировать данный метод.
Идея аналогична md5(1), однако использован иной алгоритм и суммы получаются более длинные (160 бит).
Команда sha1(1) есть не во всех BSD. В её отсутствии можно пользоваться командой openssl(1), которая позволяет посчитать контрольную сумму различными алгоритмами (в том числе MD5 и SHA1).
Программа openssl(1) предназначена для создания ключей RSA, DH, DSA, создания сертификатов X.509, CSR, CRL, подсчёта контрольных сумм различными алгоритмами, шифрования и дешифрования, проверки SSL/TLS, обработки шифрованной почты.
Запустив программу без параметров вы войдёте в интерактивный режим, в которм можно применять команды list-standard-commands, list-message-digest-commands, list-cipher-commands. А можно передать эти команды в качестве аргуметна openssl(1). Так или иначе, вы получите список команд поддерживаемых openssl(1). Команды эти также перечислены и в странице man(1) по openssl(1) с кратким описанием какая команда для чего служит.
        Чтобы получить справку по каждой команде
        openssl(1) существует отдельная страница
        man(1). Так, для того, чтобы получить справку
        по команде openssl dgst надо
        выполнить команду man dgst.
        Аргумента, который бы выводил справочную информацию по опциям
        команды нет. Поэтому, как это ни глупо, я знаю только один
        способ вызвать список аргументов в интерактивном режиме работы с
        openssl(1) — передать ей неверный
        аргумент, например -help:
      
$ openssl dgst -help
unknown option '-help'
options are
-c              to output the digest with separating colons
-d              to output debug info
-hex            output as hex dump
-binary         output in binary form
-sign   file    sign digest using private key in file
-verify file    verify a signature using public key in file
-prverify file  verify a signature using private key in file
-keyform arg    key file format (PEM or ENGINE)
-signature file signature to verify
-binary         output in binary form
-engine e       use engine e, possibly a hardware device.
-md5 to use the md5 message digest algorithm (default)
-md4 to use the md4 message digest algorithm
-md2 to use the md2 message digest algorithm
-sha1 to use the sha1 message digest algorithm
-sha to use the sha message digest algorithm
-mdc2 to use the mdc2 message digest algorithm
-ripemd160 to use the ripemd160 message digest algorithm
        Увы, на официальном сайте OpenSSL — http://www.openssl.org/docs/ документация помечена как незаконченная. Фактически там есть только страницы man(1) и очень скудные howto.
Ниже приведены примеры подсчёта контрольных сумм файла ядра:
$cksum /boot/kernel/kernel 3008568191 5910343 /boot/kernel/kernel![]()
$md5 /boot/kernel/kernel MD5 (/boot/kernel/kernel) = c56259ae98a151be7e00a278a3aa41ba$md5 -r /boot/kernel/kernel c56259ae98a151be7e00a278a3aa41ba /boot/kernel/kernel$md5 -q /boot/kernel/kernel c56259ae98a151be7e00a278a3aa41ba$openssl dgst -md5 /boot/kernel/kernel MD5(/boot/kernel/kernel)= c56259ae98a151be7e00a278a3aa41ba$openssl dgst -sha1 /boot/kernel/kernel SHA1(/boot/kernel/kernel)= 02df35b5dc3af65ce515531c549507ea34ce5c1b$openssl list-message-digest-commands md2 md4 md5 mdc2 rmd160 sha sha1
        Один из способов применения программ md5(1) и
        её аналогов, может состоять в примитивном сравнительном тесте
        производительности ЭВМ. Идея состоит в
        сравнении времени подсчёта хеш-суммы от некоторого фрагмента
        устройства /dev/zero.
      
$ time head -c 100000000 /dev/zero | md5 > /dev/null
real    0m2.309s
user    0m1.685s
sys     0m0.375s
        Сравнивая эти величины полученные на разны машинах, можно грубо, с оговорками, судить об их производительности.
Другой пример: проверка правильно ли записался на iso образ CD:
$burncd -f /dev/acd0 data livecd-i686-installer-2006.0.iso fixate next writeable LBA 0 writing from file livecd-i686-installer-2006.0.iso size 713270 KB written this track 713270 KB (100%) total 713270 KB fixating CD, please wait..$md5 -r livecd-i686-installer-2006.0.iso 5ceb2ed4041bad12b9e4feceede86b6f livecd-i686-installer-2006.0.iso$dd if=/dev/acd0 bs=2048 2> /dev/null | md5 5ceb2ed4041bad12b9e4feceede86b6f
Совпадение хеш-сумм свидетельствует об идентичности записанного диска своему образу.
Описание: Кандидат BSDA должен свободно пользоваться оболочками sh(1), csh(1) или tcsh(1). Кандидат должен уметь изменять поведение обеих оболочек временно или постоянно, включая: предотвращать уничтожение существующих файлов, использовать историю команд, определять псевдонимы команд для экономии времени в командной строке. Кандидат должен знать как временно отменить псевдоним.
Практика: 
      sh(1), csh(1) и tcsh(1), включая !,
      !!, $, 0,
      h, t, r,
      p, \.
    
В системах BSD поставляется две оболочки, наличие которых требуется стандартом POSIX: sh(1) и csh(1). Первая традичионно используется для написания сценариев. Вторая больше приспособлена для работы в интерактивном режиме. Конечно ничто не мешает вам установить у себя bash(1) или другую, более или менее «продвинутую» оболочку, однако в нашем курсе мы изучаем только штатные средства BSD, и на то есть свои основания (см. Раздел 7.7.2, «Почему sh(1)?»).
Поскольку данный раздел посвящён интерактивной работе с оболочками, мы будем описывать в нём почти исключительно csh(1). Полное описание данной оболочки, на русском языке, доступно здесь: [url://csh-1998].
С другой стороны, я отдаю себе полный отчёт в том, насколько популярна оболочка bash(1) среди системных администраторов, поэтому иногда буду делать реверансы в её сторону в стиле «... а в bash(1) тоже есть подобная функция, она делатся так: ...». Кроме того, в случае если некая упоминаемая возможность есть и в bash(1) и в sh(1) я буду делать реверансы в пользу sh(1), хотя последний крайне неудачен с точки зрения интерактивной работы.
![]()  | Важно | 
|---|---|
csh(1) по умолчанию является оболочкой
        пользователя root. Никогда не меняйте её на
        bash(1) или любую другую оболочку из иерархии
        /usr/local! От пользователя root требуются
        некоторые действия в критические моменты жизнедеятельности системы,
        когда иерархия /usr несмонтирована. Поэтому
        уметь работать в csh(1) может быть жизненно
        важно.
       | 
        Для этой цели в оболочках существует режим
        «noclobber». В csh(1) он включается
        путём задания переменной окружения noclobber.
      
%touch test%set noclobber=1%echo hello > test test: Файл существует.%unset noclobber%echo hello > test
        В sh(1) этот режим можно включить используя
        аргумент командной строки -C. Таким образом, можно использовать
        shebang #!/bin/sh -C.
      
Существует ряд отличий между оболочками с точки зрения языка. Язык csh(1) сделан более C-подобным. Изменения довольно глубоки, в частности csh(1) трактует 1 как истину, а 0 как ложь, в отличие от sh(1), поэтому он преобразует на лету коды возврата программ 0 к 1, а всё, что больше 0 к нулю. В csh(1) иной синтаксис написания циклов и других конструкций, больше типов данных. Так в csh(1) поддерживаются массивы (массивы поддерживаются и в bash(1)).
csh(1) поддерживает работу с историей команд и completion. (К стыду своему не знаю как это будет по-русски, имеется ввиду явление когда имена файлов дописываются при нажатии клавиши <TAB>). Ни то, ни другое не поддерживается в sh(1) (но поддерживается в bash(1)).
Если в переменной в csh(1) содержится имя файла, то с ним можно работать используя различные модификаторы:
%set name=/home/emin/BSDCert/BSDCert.xml%echo $name /home/emin/BSDCert/BSDCert.xml%echo $name:h/home/emin/BSDCert
%echo $name:t BSDCert.xml%echo $name:e xml%echo $name:h:h/home/emin
%set names=(/home/emin/BSDCert/*)![]()
%echo $names /home/emin/BSDCert/BSDCert.xml /home/emin/BSDCert/Makefile /home/emin/BSDCert/de fault.css /home/emin/BSDCert/index.shtml /home/emin/BSDCert/macro.vim /home/emin /BSDCert/single.xsl /home/emin/BSDCert/split.xsl%echo $names[1]/home/emin/BSDCert/BSDCert.xml
%echo $names[1]:h /home/emin/BSDCert%echo $names[1]:t BSDCert.xml%echo $names:h/home/emin/BSDCert /home/emin/BSDCert/Makefile /home/emin/BSDCert/default.css /h ome/emin/BSDCert/index.shtml /home/emin/BSDCert/macro.vim /home/emin/BSDCert/sin gle.xsl /home/emin/BSDCert/split.xsl
%echo $names:gh/home/emin/BSDCert /home/emin/BSDCert /home/emin/BSDCert /home/emin/BSDCert /hom e/emin/BSDCert /home/emin/BSDCert /home/emin/BSDCert
%echo $names:gt BSDCert.xml Makefile default.css index.shtml macro.vim single.xsl split.xsl%echo $names:ge xml css shtml vim xsl xsl
Похожие фокусы возможны, впрочем, и в sh(1) (правда в нём нет массивов):
$name=/home/emin/BSDCert/BSDCert.xml$echo $name /home/emin/BSDCert/BSDCert.xml$echo ${name%/*} /home/emin/BSDCert$echo ${name##*/} BSDCert.xml$echo ${name##*.} xml
Впрочем, последний пример явно потерпит фиаско, если в имени файла расширения не будет, и, что ещё хуже, если в имени файла его не будет, а в имени каталога, в котором он находится, оно будет.
Таблица 7.11. Модификаторы переменных в csh(1)
| Модификатор | Описание | 
|---|---|
| h | Удалить имя файла, сохранив компоненты пути (то есть удалить в слове текст справа до ближайшего символа /). От слова head. | 
| gh | Применить модификатор h глобально ко всем элементам массива | 
| r | Удалить расширение файла, указанное через точку, и саму точку | 
| gr | Применить модификатор r глобально ко всем элементам массива | 
| e | Удалить имя файла вместе с точкой, сохранив расширение имени | 
| ge | Применить модификатор e глобально ко всем элементам массива | 
| t | Сохранить имя файла, удалив компоненты пути (то есть удалить текст слева от самого правого символа / и сам этот символ). От слова «tail». | 
| gt | Применить модификатор t глобально ко всем элементам массива | 
| q | Запретить дальнейшую модификацию слова. Слово заключается в кавычки | 
| x | Разбить на слова по разделителям и запретить дальнейшую модификацию. Результат заключается в кавычки. | 
Для просмотра истории команд служит встроенная команда history:
% history
   1  14:27   set name=/home/emin/BSDCert/BSDCert.xml
   2  14:28   echo $name
   3  14:28   echo $name:h
   4  14:28   echo $name:t
   5  14:28   echo $name:e
   6  14:28   echo $name:h:h
   7  14:29   set names= ( /home/emin/BSDCert/* )
   8  14:29   echo $names[1]
   9  14:29   echo $names[1]:h
  10  14:30   echo $names[1]:t
  11  14:30   echo $names:h
  12  14:30   echo $names:gh
  13  14:30   echo $names:gt
  14  14:30   echo $names:ge
        
        При помощи символа ! можно выполнить
        некоторые действия из истории, например:
      
%!1set name=/home/emin/BSDCert/BSDCert.xml
%!7 set names= ( /home/emin/BSDCert/* )%!?his?history 1 14:27 set name=/home/emin/BSDCert/BSDCert.xml 2 14:28 echo $name 3 14:28 echo $name:h 4 14:28 echo $name:t 5 14:28 echo $name:e 6 14:28 echo $name:h:h 7 14:29 set names= ( /home/emin/BSDCert/* ) 8 14:29 echo $names[1] 9 14:29 echo $names[1]:h 10 14:30 echo $names[1]:t 11 14:30 echo $names:h 12 14:30 echo $names:gh 13 14:30 echo $names:gt 14 14:30 echo $names:ge 15 15:30 history 16 15:31 set name=/home/emin/BSDCert/BSDCert.xml 17 15:31 set names= ( /home/emin/BSDCert/* ) 18 15:31 history
%-2set names= ( /home/emin/BSDCert/* )
%!!set names= ( /home/emin/BSDCert/* )
%!eecho $names:ge xml css shtml vim xsl xsl
Разберём чуть более сложный пример:
%touch abc cba%cat !!*cat abc cba
%echo 'aaa\?bbb\?ccc' > abc%echo 'aaa\?bcb\?ccc'> cba%diff !t*diff abc cba 2c2 < bbb --- > bcb
%echo !t:0echo touch touch
%echo !t:1 !t:2echo abc cba abc cba
%echo !?ab?%echo abc abc
%echo !t^ !t$echo abc cba abc cba
        Разрешается не ставить двоеточие перед знаками
        *, ^, $,
        - и %
      
В работе с историей команд можно использовать модификаторы. Некоторые модификаторы были рассмотрены выше, есть и специфические модификаторы, которые применяются только здесь:
p&s/pattern/subst/Пусть после выполнения команды history на экран дисплея выведено:
% history
  1  cat /home/ivanov/file1.c
  2  cc pa1.c pa2.c pa3.c pa4.c >& errors &
  ...
        Тогда следующие команды приведут к следующим действиям:
!1:0  !1^:t:rcat. Затем первое слово первой
            строки (/home/ivanov/file1.c),
            к которому будет последовательно применено два
            модификатора: :t и :r, в
            результате останется file1.
            Итого, получаем команду cat
              file1.
          !1:0  !1^:h/documentcat
              /home/ivanov/document.
          !1:0  !1^:h:s?ivanov?sidorov?/documentcat /home/sidorov/document!1:0  !1^:h:s?ivanov?sidorov?/doc !1^:&:pcat /home/sidorov/doc
              /home/sidorov/file1.c. Здесь модификатор
            & заставляет повторить предыдущую
            замену, а модификатор :p заставляет
            просто напечатать результат на экране, вместо того, чтобы
            выполнить действие.
          !1:0 !2:1-4:gs?pa?ff?:pg) делается замена
            pa на ff, результат печатается:
            cat ff1.c ff2.c ff3.c ff4.cСуществует способ редактирования последней командной строки:
%echo abc cba abc cba%^abc^cba^ echo cba cba cba cba
Представьте себе, что у вас определён следующий псевдоним:
% alias sp "sort \!* | print"
        
        Теперь команды sp one two и sort one two | print тождественны, так
        как в !* будут подставлены аргументы, с
        которыми вызвана команда sp.
      
Описание: Кандидат должен знать, что различные системные сообщения высылаются по почте пользователю root, а многие сторонние почтовые клиенты (MUA) не всегда могут быть установлены. Кандидат должен уметь как читать, так и посылать почту при помощи встроенной почтовой программы mail(1). Кандидат должен знать где расположены почтовые ящики пользователей.
Практика: mail(1), /var/mail/$USER.
    
        Spool с пользовательской почтой находится в файле
        /var/mail/$USER. Существует множество
        способов читать почту и множество способов её посылать. Начиная
        с непосредственного чтения указанного файла программой
        less(1) или vi(1) и
        пересылки через sendmail(8) командой типа
      
$ cat letter | sendmail somebody@example.org
        
На всех системах BSD в стандартный комплект поставки входит программа mail(1) — пользовательский почтовый агент, предназначенный для чтения почтового ящика и отправки писем. Основная ценность этой программы в том, что она есть везде. Стандарт POSIX требует наличия в системе программы mailx(1). Легко убедиться, что mail(1) и mailx(1) в BSD это дна и та же программа, с идентичным интерфейсом.
![]()  | Замечание | 
|---|---|
| mail(1) гарантированно присутствует в любой UNIX-системе, даже если там нет ни одного установленного порта и им вполне можно читать служебную почту root'а. | 
Интерфейс программы mail(1) трудно назвать дружественным и, быть может, следовало бы рекомендовать пользователю что-то более совершенное, например mutt(1), однако администратор должен знать mail(1) подобно тому, как он должен знать sh(1), хотя пользоваться bash(1)'ем как интерактивным shell'ом может быть более разумно.
        Будучи запущена без аргументов, программа
        mail(1) открывает пользовательский ящик и
        выводит знак & в качестве приглашения
        командной строки. Если надо открыть не
        /var/mail/$USER, а какой-то другой файл,
        его следует указать в аргументе -f.
      
$ mail
Mail version 8.1 6/6/93.  Type ? for help.
"/var/mail/emin": 1039 messages
>   1 **********@yahoo.com  Mon Oct 11 23:18  59/2153  "Re: home address"
  2 *****@xxx.ru          Tue Oct 12 10:42  56/2048  "Re: home address"
  3 *****@xxx.ru          Wed Oct 13 17:10 109/4842  "Demons and signals"
  4 ****@xxxxx.ru         Wed Oct 13 17:10 156/4509  "(fwd) Re: subversion"
  5 ***@xxx.ru            Wed Oct 13 21:17 217/10906 "=?koi8-r?B?9MXL09Qgz9"
  6 *****@xxx.ru          Thu Oct 14 10:09 101/3849  "Re[2]: Demons and sig"
  7 ****@xxxxxx.ru        Thu Oct 14 10:09 10221/783178 "=?koi8-r?B?5s/Uy8k"
  8 *****@xxxxx.ru        Thu Oct 14 15:15  81/2613  "Re: some questions"
  9 ****@xxxxx.ru         Fri Oct 15 10:35  46/1780  "Re: Phone+Cd"
 10 ****@xxxxx.ru         Fri Oct 15 14:23  68/2888  "Re: Phone+Cd"
 11 *****@xxxxx.ru        Fri Oct 15 18:10  61/2350  "Re: StarOfficce"
 12 ****@xxxxxx.ru        Mon Oct 18 00:48 7554/578402 "=?koi8-r?B?UmVbMl06"
 13 ******@xxxxxxxxxxxx.  Mon Oct 18 16:35 113/5041  "Re: Jornal"
 14 ****@xxxxx.ru         Wed Oct 20 19:54  56/2220  "Re: uzkaya koleya"
 15 ****@xxxxxx.ru        Wed Oct 20 23:46  48/1911  "=?koi8-r?B?UmVbNF06IO"
 16 ******@xxxxx.net      Fri Oct 22 00:07  45/1790  "Re: (fwd) Re: uzkaya "
 17 *****@xxxxx.ru        Fri Oct 22 09:22  70/2740  "Re: some questions"
 18 ****@xxxxx.ru         Fri Oct 22 14:19  52/2098  "fish"
 19 ****@xxxxx.ru         Fri Oct 22 14:39  63/2271  "Re: Spisok"
 20 ****@xxxxx.ru         Fri Oct 22 14:39  58/2092  "Re: Spisok"
&
        
        В командной строке, начинающейся со знака
        &, можно набирать следующие команды:
      
Таблица 7.12. Команды программы mail(1)
| Команда | Описание | |
|---|---|---|
| краткая | полная | |
| ? | help | Справка | 
| h | headers | Показать список писем (в окресностях активного письма). Список писем виден, например, на скриншоте перед таблицей. Чтобы посмотреть следующие 20 писем, надо «прыгнуть» писем через 20 (например командой «n+20») и снова ввести команду h. | 
| p | вывести на экран (через more(1)) текущее письмо | |
| + или n | next | вывести на экран (через more(1)) следующее письмо | 
| - | вывести на экран (через more(1)) предыдущее письмо | |
| x или ex | exit | Выйти из mail(1) без сохранения | 
| q | quit | Выйти из mail(1) с сохранением | 
| d | delete | Удалить сообщение, принимает в качестве необязательного аргумента список сообщений. Изменения записываются при выходе из программы. | 
| dp или dt | Удалить текущее сообщение и напечатать следующее. | |
| r | reply | Ответить всем адресатам письма | 
| R | Reply | Ответить одному адресату письма | 
| s | save | Сохранить письмо, дописав к указанному файлу. | 
| Существует ещё большое количество команд предназначенных скорее для тех, кто собирается всерьёз использовать данную программу в качестве повседневного почтового клиента. | ||
Часто команду mail(1) используют просто для того, чтобы автоматизировать посылку писем с командной строки. Мы рассмотрим её здесь в этом качестве. Следует отметить, что несмотря на то, что некоторые другие команды (тот же mutt(1) тоже умеют посылать письма с командной строки, mail(1) имеет то преимущество, что он принят в стандарте POSIX. (Точнее, принят mailx(1), см. выше.) С другой стороны, программа mail(1) не дожидается окончания работы sendmail(8) и потому из её кода возврата невозможно понять действительно ли письмо ушло. Тот же mutt(1) лишён этого недостатка. Поэтому может было бы неглупой идеей в скриптах не пользоваться mail(1)'ом вообще, а использовать непосредственно sendmail(8).
        Для отправки письма, достаточно подать его на вход команде
        mail(1), а в качестве аргументов перечислить
        почтовые адреса. Дополнительно в опциях -s,
        -c, -b можно описать поля
        Subject, Cc и Bcc. Ещё следует упомянуть аргумент
        -E, который не посылает письмо, в случае если
        оно пустое, что может быть полезно для того, чтобы высылать
        STDERR из задания в cron.
      
$ cat letter | mail -s Hello somebody@example.org
        Строка для crontab(1) могла бы выглядеть так:
* * * * * mytask.sh 2>&1 >/dev/null | mail -E -s "Errors in mytask" debug@somebody.org
        
        Странная, на первый взгляд, строка 2>&1 >/dev/null
        перенапрвляет STDOUT в
        /dev/null, а STDERR
        туда, где раньше был STDOUT, таким образом,
        мы направляем на конвейер именно STDERR, а от
        ненужного нам STDOUT'а избавляемся.
      
Описание: Кандидат должен знать как запустить процесс в фоновом режиме, переместить запущенный процесс в фон, вернуть на передний план процесс работающий в фоне. Кандидат должен уметь проверить запущены ли какие-нибуть задачи в фоновом режиме и знать разницу между командой kill(1) и встроенной в оболочку командой kill.
Практика: &, ^Z,
      jobs, fg,
      bg, и встроенная в оболочку
      kill.
    
        Каждая команда (или, точнее, каждый конвейер, pipeline) в
        sh(1) должен заканчиваться либо знаком ;, либо &.
        В случае, если нет ни того ни другого, а в конце команды
        пользователь просто нажал на клавишу <Enter>, неявно
        подразумевается знак ;.
      
        Конвейер заканчивающийся на ;
        выполняется «на переднем плане» (foreground). Оболочка
        не возвращает приглашения до тех пор, пока конвейер не
        отработает. Т.е. оболочка ждёт пока закончится процесс
        выполняющийся на переднем плане.
      
        Конвейер заканчивающийся на &
        выполняется «в фоновом режимме» (в background).
        Оболочка сразу возвращает приглашение, а процесс выполняется
        параллельно с оболочкой.
      
        Список Конвейеров и их статус можно посмотреть при помощи
        встроенной в оболочку команды jobs. Эта
        команда перечисляет запущенные в фоновом режиме процессы и
        объясняет выполняются они или остановлены. В квадратных скобках
        jobs сообщает номер задания, следующее
        число — PID процесса. Если у
        задания стоит знак +, то это «текущее
        задание». С ним по умолчанию будут работать команды
        bg и fg.
      
Конвейер выполняющийся в фоновом режиме можно перевести на передний план при помощи команды fg [%n]. Необязательный аргумент — номер задания, его сообщяет команда jobs, если он не указан, на передний план будет переведено «текущее задание».
        Чтобы перевести задание с переднего плана в фоновый режим, надо
        послать ему из оболочки сигнал SIGSTOP нажав
        сочетание клавиш <Ctrl>+Z. После этого оболочка вернёт
        приглашение, но процесс будет остановлен. Теперь надо послать
        процессу сигнал SIGCONT, для этого надо
        выполнить либо команду fg и вернуть его на
        передний план, либо bg и продолжить его в
        фоновом режиме. Мне приходилось наблюдать как люди запускают
        vi(1) (см. Раздел 7.3, «Навыки работы в vi(1)») и нажимат
        в нём <Ctrl>+Z пребывая в заблуждении, что так выходят из
        редактора. Спустя короткое время у них в оболочке накапливается
        большое количество остановленных vi(1).
      
        Для того, чтобы послать запущенному заданию иной сигнал, служит
        встроенная команда kill. Она ведёт себя
        идентично внешней команде kill(1), но в
        отличие от последней, может послать сигнал заданию, не только по
        PID, но и по номеру, выдаваемому командой
        jobs. Для этого, номер надо предварить знаком
        %. Если скомандовать kill % без номера, будет уничтожено
        «текущее задание».
      
![]()  | Замечание | 
|---|---|
| Команда kill в sh(1) нереализована. Она есть только в csh(1) (и конечно в bash(1)). Остальные команды имеются в обоих интерпретаторах. | 
Ниже приведён пример на csh(1).
%sleep 1000 & sleep 2000 & sleep 3000 &[1] 2028 [2] 2029 [3] 2030
%fg %2sleep 2000 ^Z
Suspended
%jobs [1] - Выполняется sleep 1000 [2] + Suspended sleep 2000 [3] Выполняется sleep 3000%kill %[2] Прервано sleep 2000
%jobs [1] + Выполняется sleep 1000 [3] - Выполняется sleep 3000%fg %3sleep 3000 ^Z Suspended
%bg[3] sleep 3000 &
%jobs [1] + Выполняется sleep 1000 [3] Выполняется sleep 3000%kill %3[3] Прервано sleep 3000
%kill -STOP %[1] + Suspended (signal) sleep 1000
%kill -CONT % [1] sleep 1000 &%jobs [1] + Выполняется sleep 1000%
![]()  | Важно | 
|---|---|
        Никогда не запускайте команду sudo(8) в
        фоновом режиме. Это типичная ошибка начинающего администратора:
        напустить команду вроде: sudo find /etc ... &
        Следующим номером программы утилита sudo(8)
        спрашивает у администратора пароль, он вводит его не гладя на
        экран и нажимает на <Enter>. Увы, пароль он вводит при
        этом не в программу sudo(8), а в оболочку
        (ведь sudo(8) запущена в фоне). После этого
        пароль в открытом виде не только отображается на экран, но так
        же сохраняется в разнообразных буферах и history-файлах. Лучше
        запустите программу sudo(8) на переднем
        плане, введите пароль, а потом переведите её в фоновый режим
        описанным выше способом (<Ctrl>+Z и
        bg).
       | 
Перечень сигналов, которые посылает команда kill, и их описание можно найти в man signal. С точки зрения администрирования продставляют интерес следующие сигналы:
Таблица 7.13. Некоторые сигналы, представляющие интерес для администратора
| Сигнал | Номер | Описание | 
|---|---|---|
| SIGHUP | 1 | Посылается демонам для перечитывания ими конфигурационных файлов, а так же всем процессам-потомкам при уничтожении родителя. Если в терминале надо запустить программу, которая будет продолжаться и после закрытия терминала, её можно, как вариант, запустить внутри программы nohup(1), которая будет перехватывать данный сигнал. Команда nohup встроена в оболочку csh(1). Из sh(1) её можно вызвать как внешнюю программу. | 
| SIGINT | 2 | Прерывание процесса. Этот сигнал посылается процессу, когда в оболочке пользователь нажимает клавишесочетание <Ctrl>+C | 
| SIGKILL | 9 | Уничтожение процесса. Этот сигнал неперехватывается приложением, больше того, оно даже ничего не узнаёт о том, что применён данный сигнал. Фактически это сигнал ядру о том, что данный процесс должен быть уничтожен. | 
| SIGTERM | 15 | Програмное завершение процесса. Приложение имеет возможность перехватить его и выполнить необходимые финализационные действия: стереть временные файлы, освободить иные ресурсы и т.п. Именно этот сигнал посылается приложению по умолчанию, когда команде kill не указано какой сигнал надо доставить процессу. | 
| SIGSTOP | Остановить процесс (нельзя перехватить, направляется ядру). Этот сигнал посылается процессу, когда в оболочке пользователь нажимает клавишесочетание <Ctrl>+Z | |
| SIGCONT | Продолжить остановленный процесс | 
        Если сигнал направлен на PID равный -1, он
        доставляется всем процессам (если его вызвал суперпользователь)
        или всем процессам данного пользователя. В
        OpenBSD и NetBSD есть
        дополнительные псевдо-PID'ы 0 и -pgid,
        служащие для доставки сигнала группам процессов.
      
Описание: Работа с регулярными выражениями является частью повседневной работы системного администратора. Кандидат BSDA должен быть способен искать текстовые шаблоны при анализе вывода программ или поиске в файлах. Кандидат должен уметь указать диапазон символов в скобках [], определить литерал (?!), использовать квантификаторы, отличать метасимволы и создавать инвертированные фильтры.
Практика: grep(1), egrep(1), fgrep(1), re_format(7).
Регулярные выражения это то, с чем администратор имеет дело почти ежеминутно. В этом вопросе безусловно нужна практика. Вместе с тем, чтобы полностью описать всё богатство возможностей регулярных выражений, все их недостатки, плюсы и минусы различных механизмов поиска, нужно потратить годы. К счастью, в нашем распоряжении есть перевод замечательной книги Дж. Фридла «Регулярные выражения» [Friedl-2001-ru]. К сожалению, издатели не планируют переиздавать её, однако любезно выложили для всеобщего использования текст этой книги. Вот небольшая цитата из предисловия к этой книге:
Небольшой тест — попробуйте определить понятие «между». Помните: определяемое слово не может использоваться в определении! Ну как, получилось? Нет? Действительно, задача не из простых. Хорошо, что смысл этого слова понятен всем, иначе нам пришлось бы подолгу разъяснять его всем несведущим. Даже такие простые концепции бывает трудно описать кому-то, кто еще не знаком с ними.
До определенной степени сказанное относится и к регулярным выражениям. На самом деле регулярные выражения не так сложны, как их описания и объяснения.
С другой стороны, положа руку на сердце, для задач администрироания не нужно прибегать ко всему богатству возможностей регулярных выражений. От администратора требуется лишь знание основных синтаксических конструкций, а в данном разделе я явно вышел за рамки того, что реально нужно в работе администратору. Web-программисту и, тем более, для верстальщику в LaTeX'е требуется больше.
Итак, регулярные выражения — это способ описания текста и манипулирования с ним. При помощи регулярных выражений вы можете создавать шаблоны для поиска нужных вам фрагментов текста.
        Реальный пример: допустим вам нужно найти все IP-адреса, с
        которых на вашу машину пытались пройти используя несуществующие
        имена пользователей. Для этой цели вы можете изучить журнальный
        файл /var/log/auth.log разыскивая сообщения
        демона sshd, содержащие слова «Invalid
        user»:
      
$ awk '/sshd.*Invalid user/{print $10}' /var/log/auth.log | sort | uniq
125.243.235.194
193.158.246.173
218.248.33.225
        
        Здесь команда awk(1) вырезает 10-й столбец из
        всех строк, которые соответствуют регулярному выражению sshd.*Invalid user. Конструкция .* означает сколько угодно чего угодно.
        Т.е. мы ищем в журнальном файле строку в которой написано sshd
        затем возможно какие-то ещё слова и цифры и Invalid user.
      
Это тривиальный пример, но такие тривиальные примеры рождаются каждую минуту. Он написан очень просто, хотя и не очень корректно. На реальном журнальном файле вероятность сбоя такого регулярного выражения исчисляется сотыми долями процента, так как сам журнальный файл написан автоматом и имеет строго определённый формат. Менее тривиальные примеры в администраторской практике появляются редко и нужны скорее при написании каких-то служебных программ. Например: найти на диске скрипты в которых утилита env(1) используется для вызова программ по неабсолютному пути. (Чем это может быть опасно рассматривается в Раздел 7.2.1.1, «env(1), printenv(1)».) Поскольку таких программ будет найдено во множестве, мы ограничились лишь первыми десятью в качестве примера.
$find / -type f -perm +a+x -print0 2>/dev/null | \>xargs -0 egrep '/usr/bin/env +([^ ]+=[^ ]* +)*[^/][^=]+( |$)' | head /usr/local/lib/python2.4/test/pystone.py:#! /usr/bin/env python /usr/local/lib/python2.4/test/re_tests.py:#!/usr/bin/env python /usr/local/lib/python2.4/test/regrtest.py:#! /usr/bin/env python /usr/local/lib/python2.4/test/test_al.py:#! /usr/bin/env python /usr/local/lib/python2.4/test/test_array.py:#! /usr/bin/env python /usr/local/lib/python2.4/test/test_binhex.py:#! /usr/bin/env python /usr/local/lib/python2.4/test/test_bsddb.py:#! /usr/bin/env python /usr/local/lib/python2.4/test/test_cd.py:#! /usr/bin/env python /usr/local/lib/python2.4/test/test_cl.py:#! /usr/bin/env python /usr/local/lib/python2.4/test/test_cmath.py:#! /usr/bin/env python
        Регулярное выражение, написанное в аргументе команды
        egrep(1): /usr/bin/env +([^ ]+=[^ ]* +)*[^/][^=]+( |$)
        «переводится» на русский язык следующим образом: мы
        ищем текст /usr/bin/env, за которым возможно идёт несколько
        объявлений содержащих в себе знак равенства (т.е. объявление что
        некоторая переменная окружения равна какому-то значению), после
        которой идёт слово не содержащее в себе знак равенства и
        начинающееся не со знака / (т.е. не являющееся абсолютным
        путём). Разберём подробнее (если вы не знакомы с синтаксисом
        регулярных выражений, переходите к следующему подразделу, а потом
        вернитесь):
      
/usr/bin/env +/usr/bin/env, за которым идёт не менее
            одного пробела.
          ([^ ]+=[^ ]* +)*[^/][^=]+( |$)
Первое впечатление от всего этого механизма состоит в том, что перед нами некоторое глобальное жульничество. Между прочим, так оно и есть.
![]()  | Важно | 
|---|---|
| Помните: регулярные выражения это удобный, но ненадёжный способ поиска. Как правило они ищут не то, что от них просят, а то, что удобнее искать. | 
Автор данного текста, однажды, по заданию издательства URSS, писал регулярное выражение для поиска фамилий и инициалов в тексте. Этот труд занял несколько дней. 90% времени ушло на тестирование и, в результате, полученный монстр работал с КПД не более 98%. В мире есть множество весьма необычных фамилий и вариантов написания инициалов, а так же разнообразных приставок вроде фон-, ван-дер-, де-, ибн- и т.п.
Многие регулярные выражения могут и должны писаться автоматически. Мне приходилось видеть работу регулярного выражения длиной 2 мегабайта. Ничего, живенько работало. Однако, это не прерогатива системного администратора. Просто, для программистов скажу, что если вы можете заменить регулярное выражение стековой машиной — сделайте это. Стековая машина работает намного корректнее и часто быстрее, хотя и требует большего количества телодвижений.
![]()  | Важно | 
|---|---|
| Существуют задачи принципиально не имеющие решения в рамках механизма регулярных выражений. Например, поскольку регулярное выражение не может считать сколько конструкций оно захватило, с его помощью невозможно в общем виде решить задачу поиска ответной скобки, хотя и можно решить частный случай, когла известно, что глубина вложенности скобок не превышает n. В общем случае задача поиска ответной скобки, это задача для стековой машины. | 
Регулярное выражение для поиска ответной фигурной скобки при условии ограниченной вложенности скобок, написанное на perl(1):
{[^{}]*} 
{([^{}]*|{[^{}]*})*} 
{([^{}]*|{([^{}]*|{[^{}]*})*})*} 
{([^{}]*|{([^{}]*|{([^{}]*|{[^{}]*})*})*})*} 
        
Заметим, что начиная с некоторого уровня вложенности у этого регулярного выражения начнутся явные проблемы с производительностью, кроме того, существует некоторая критическая величина вложенности круглых скобок, при которой у интерпретатора окажется превышен лимит рекурсии.
        Однако вернёмся к нашему регулярному выражению для поиска
        «плохих» скриптов: /usr/bin/env +([^ ]+=[^ ]* +)*[^/][^=]+( |$).
        Что если записать его попроще? Давайте сравним его с вот таким
        регулярным выражением: /usr/bin/env +[^/]. Мы убрали из
        регулярного выражения весь его «ум». А теперь давайте
        посмотрим правде в глаза: 1) этот ум был несовершенен
        (например, он не учитывал ситуацию, когда вызов
        env(1) и утилиты были бы записаны на разных
        строках, через обратный слеш); 2) результат ухудшится не
        более чем на 1-2%, так как ситуация, когда определяется какая-то
        переменная редка.
      
Мораль: будьте проще и не зацикливайтесь на регулярных выражениях.
К сожалению, от программы к программе часто меняются не только возможности регулярных выражений, но и их синтаксис. Стало быть, нам понадобится некоторая сводная таблица.
В первом столбце этой таблицы приведён синтаксис языка программирования perl(1). Этот диалект весьма распространён, встречается он и в других языках, например в python(1).
Второй столбец посвящён регулярным выражениям редактора vim(1). Не путайте его с vi(1). Возможности vi(1) намного скромнее. По поводу vim(1) хочется заметить вот что: здесь не перечислено и половины его возможностей. Это самый богатый диалект регулярных выражений, который я знаю, даже богаче perl(1). Но это же и самый медленный диалект.
        grep(1) и egrep(1)
        представленные в третьем и четвёртом столбцах, являются одной
        и той же программой. egrep(1) это
        grep(1) вызванный с опцией
        -E, и хотя в man(1)
        сказано, что эта опция включает расширенные регулярные
        выражения, ничего она не включает, это не более чем
        переключатель синтаксиса (см. ниже).
      
Синтаксис регулярных выражений grep(1) совпадает с синтаксисом таких утилит, как sed(1) или awk(1), так как они слинкованы с той же библиотекой регулярных выражений, и описан в re_format(7), хотя и весьма не наглядно. (Точнее, синтаксис sed(1) совпадает с синтаксисом grep(1), а синтаксис регулярных выражений awk(1) совпадает с синтаксисом egrep(1).) Кроме того, поскольку эти программы вызываются из разнообразных скриптов, (например apropos(1), это скрипт Bourne shell), то регулярные выражения grep(1) реально используются много где, даже если в документации про это ничего не сказано.
Таблица 7.14. Регулярные выражения. Сводная синтаксическая таблица
| perl(1) | vim(1) | grep(1) | egrep(1) | Описание | 
|---|---|---|---|---|
| Классы | ||||
[a-zA-Z] | [a-zA-Z] | [a-zA-Z] | [a-zA-Z] | Класс. Соответствие символу указанному в наборе, можно указывать диапазоны. В примере описано множество букв | 
[^a-zA-Z] | [^a-zA-Z] | [^a-zA-Z] | [^a-zA-Z] | Инвертированный класс. Соответствие символу отсутствующему в указанном в наборе. В примере описано множество небукв | 
| Предопределённые классы (список неполон) | ||||
. | . | . | . | Любой символ | 
\w | \w | [[:alnum:]_] | [[:alnum:]_] | Алфавитно-цифровой символ и подчерк (word) | 
\W | \W | [^[:alnum:]_] | [^[:alnum:]_] | Множество дополнительное множеству word | 
\d | \d | [[:digit:]] | [[:digit:]] | Цифры | 
\D | \D | [^[:digit:]] | [^[:digit:]] | Не цифры | 
\s | \s | [[:space:]] | [[:space:]] | Пробельные символы (пробел, табулятор, и т.п.) | 
\S | \S | [^[:space:]] | [^[:space:]] | Непробельные символы символы | 
| Квантификаторы «жадные» | ||||
* | * | * | * | Повтор предыдущего символа 0 и более раз | 
+ | \+ | \+ | + | Повтор предыдущего символа 1 и более раз | 
? | \? | \? | ? | Повтор предыдущего символа 0 или 1 раз | 
{n,m} | \{n,m} | \{n,m\} | {n,m} | Повтор предыдущего символа от n до m раз | 
{n,} | \{n,} | \{n,\} | {n,} | Повтор предыдущего символа минимум n раз | 
{n} | \{n} | \{n\} | {n} | Повтор предыдущего символа строго n раз | 
| Квантификаторы «нежадные» | ||||
*? | \{-} | Повтор предыдущего символа 0 и более раз, но как можно меньше | ||
+? | \{-1,} | Повтор предыдущего символа 1 и более раз, но как можно меньше | ||
{n,m}? | \{-n,m} | Повтор предыдущего символа от n до m раз, но как можно меньше | ||
{n,}? | \{-n,} | Повтор предыдущего символа минимум n раз, но как можно меньше | ||
| Специальные позиции | ||||
^ | ^ | ^ | ^ | Начало строки | 
$ | $ | $ | $ | Конец строки | 
\b | \< | \< | \< | Левая граница слова | 
\b | \> | \> | \> | Правая граница слова | 
\B | Позиция не являющаяся границей слова | |||
(?=atom) | atom\@= | Заглядывание вперёд. Позиция за которой идёт atom. В vim(1) атом имеет право быть переменной длины, в perl(1) это не так. | ||
(?!atom) | atom\@! | Заглядывание вперёд. Позиция за которой нет atom'а | ||
(?<=atom) | atom\@<= | Заглядывание назад. Позиция перед которой есть atom | ||
(?<!atom) | atom\@<! | Заглядывание назад. Позиция перед которой нет atom'а | ||
                При помощи заглядываний вперёд или назад можно
                пытаться найти некоторый текст не содержащий заданного
                слова. Например, шаблон <section>(.(?!<section\b))*</section>
                ищет текст от <section> до
                </section>, если
                внутри него не случилось другого тега <section
               | ||||
| Или | ||||
| | \| | \| | | | Оператор «или» | 
| Группировка | ||||
() | \(\) | \(\) | () | 
                Группа: 1) ограничивает действие оператора
                «или»: «Слава (КПСС|КПРФ)»
                2) объединяет различные атомы вместе так, чтобы к
                ним можно было применить общий квантификатор,
                3) кроме того, впоследствии на текст
                соответствующий группе можно ссылаться по номеру (все
                группы последовательно нумеруются, а попавший в группу
                текст запоминается).
               | 
(?:...) | \%(...\) | Ненумерующаяся группа | ||
\n | \n | \n | \n | 
                Ссылка на группу номер n: выражение ([a-z])\1 ищет удвоенные буквы.
                Заметьте, это не то же саме, что [a-z]{2}, которое ище две
                буквы, даже, если они неодинаковые.
               | 
Шаблоны встречающиеся в командной строке sh(1) тоже в некотором смысле являются регулярными выражениями.
Есть только одно обстоятельство, которое регулярным выражением так просто не записать: шаблоны Bourne shell не ищут совпадения с файлами начинающимися с точки, если это не указано явно.
В BSD установлен GNU grep(1).
Опции команды grep(1) можно ражделить на несколько типов: 1) синтаксические опции; 2) формат вывода: опции влияющие на характер выводимой информации; 3) опции влияющие на то где осуществляется поиск.
-E, --extended-regex-F, --fixed-strings-i, --ignore-case-w, --word-regexpgrep -w
              grep найдёт слово grep, не не найдёт egrep.
            -x, --line-regexp-v, --invert-matchegrep -v '^(#|$)' test.sh
              напечатает непустые строки, в которых нет комментария.
            -v, --invert-matchegrep -v '^(#|$)' test.sh
              напечатает непустые строки, в которых нет комментария.
            -C [NUM], -NUM, --context[=NUM]-A NUM, --after-context=NUM, -B NUM, --before-context=NUM-c, --count-H, --with-filename-h, --no-filename-l, --files-with-matches-L, --files-without-matches-b, --byte-offset-n, --line-number-q, --quiet, --silent, -s, --no-messages-q подавляет вывод
              информации на STDOUT, а
              -s на STDERR. В
              man(1) содержится рекомендация не
              использовать эти опции при написании скриптов, которые
              должны быть абсолютно переносимыми, пользуясь вместо них
              обычным перенаправлением вывода.
            --null-print0 команды
              find(1) и предназначено для
              ассоциации с командой xargs(1). (см.
              Раздел 7.15, «Преодоление ограничений на длину командной строки» и Раздел 7.6.3, «Связка с командой xargs»)
            -r, --recursive-d recurse.
              Возможно более разумно пользоваться связкой
              find-xargs-grep, во всяком случае, это надёжнее. Если
              вас посетила идея искать слово во всех файлах
              компьютера, то команда find / -type f -print0 |
                xargs -0 grep pattern имеет шансы успешно
              завершиться, чего не приходится ожидать от команды
              grep pattern -r / — такая
              команда в лучшем случае повиснет. Опцию
              -r имеет смысл применять лишь на
              небольших файловых иерархиях, про которые вы можете
              уверенно сказать, что в них нет симлинков ведущих
              наружу, а так же файлов устройств.
            -d ACTION, --directories=ACTIONACTION равно skip,
              ничего не делать, если
              read — искать в них как в
              файлах, если recurse,
              grep(1) рекурсивно ищет во всех
              файлах, встретившихся в данном каталоге и во всех
              подкаталогах. См. так же замечание к предыдущей опции.
            -a, --text, --binary-files=text-I, --files-without-match,
                --binary-files=without-match--binary-files=TYPETYPE. Значения text и
              without-match только что были описаны,
              по умолчанию используется значение
              binary, означающее, что при наличии
              совпадения будет выдано соответствующее сообщение из
              одной строки.
            Описание: Длина командной строки ограничена. Порой приходится создавать командные строки, которые не помещаются в отведённых пределах. Кандидат должен знать как запустить команду несколько раз с различными аргументами, используя xargs(1) или цикл while.
Практика: xargs(1), find(1).
В различных оболочках допустимая длина строки может различаться, но, как правило, она имеет некоторый предел, определённый в момент компиляции. Поэтому, когда нам надо предпринять некоторые действия над большим списком файлов, передать их все в аргументе командной строки оказывается невозможно.
Для того, чтобы обойти эту проблему существует команда xargs(1), разработанная как команда парная команде find(1). Эта программа получает список аргументов со стандартного ввода (как правило через pipe) и несколько раз вызывает программу указанную в её аргументе передавая ей всё новые и новые порции аргументов. Совместная работа find(1) и xargs(1) подробно описана в Раздел 7.6.3, «Связка с командой xargs». Здесь же посмотрим, как программа xargs(1) позволяет обойти ограничение на длину командной строки.
Для этого напишем следующий скрипт:
#!/bin/sh
echo $# >> invoke
        
        Назовём его test.sh и вызовем следующим
        образом:
      
$ find / 2>/dev/null -print0 | xargs -0 ./test.sh
        
        По завершении его работы мы найдём, что в файле
        invoke скопилось несколько сот записей
        свидетельствующих о запуске test.sh, при этом
        количество аргументов, с которыми был вызван скрипт, будет
        колебаться от пятисот, до двух с половинй тысяч.
      
        Если же мы попробуем запустить test.sh один
        раз, передав ему сразу все аргументы, нас конечно ждёт фиаско:
      
$ ./test.sh `find / 2>/dev/null`
./test.sh: Argument list too long
        
Описание: Термин "домен" используется в UNIX в различных значениях. Кандидат должен понимать значение этого термина в контексте NIS, DNS, Kerberos и доменах NTLM.
Практика: domainname(1),
      resolv.conf(5),
      krb5.conf(5), smb.conf(5)
Описание: 
      Кандидат должен понимать разницу между системным crontab
      и пользовательским. В добавок, он должен владеть редактором
      crontab, разбираться в его полях и понимать важность
      предварительного тестирования скрипта перед тем как записать его в
      crontab. Кандидат так же должен знать про то, что он может создать
      файлы /etc/cron/allow и
      /etc/cron/deny и для чего они нужны.
    
Практика: crontab(1), cron(8),
      crontab(5)
        Система cron предназначена для запуска заданий по расписанию.
        Написан cron программистом Паулем Викси (Paul Vixie). Как и
        многие другие популярные программы, cron имеет множество
        инкарнаций.  Больше того, существует множество разных
        vixie-cron'ов. В основном авторы клонов cron'а занимались тем,
        что добавляли те или иные удобства в синтаксис файла
        crontab(5).
      
Итак, демон cron раз в минуту перечитывает все crontab-файлы, системный и пользовательские.
Системный файл crontab расположен в каталоге /etc. рассмотрим пример:
Пример 7.1. Системный crontab файл
# /etc/crontab - root's crontab for FreeBSD
#
# $FreeBSD: src/etc/crontab,v 1.32 2002/11/22 16:13:39 tom Exp $
#
SHELL=/bin/sh
PATH=/etc:/bin:/sbin:/usr/bin:/usr/sbin
HOME=/var/log
#
#minute hour    mday    month   wday    who     command
#
*/5     *       *       *       *       root    /usr/libexec/atrun
#
# Save some entropy so that /dev/random can re-seed on boot.
*/11    *       *       *       *       operator /usr/libexec/save-entropy
#
# Rotate log files every hour, if necessary.
0       *       *       *       *       root    newsyslog
#
# Perform daily/weekly/monthly maintenance.
1       3       *       *       *       root    periodic daily
15      4       *       *       6       root    periodic weekly
30      5       1       *       *       root    periodic monthly
#
# Adjust the time zone if the CMOS clock keeps local time, as opposed to
# UTC time.  See adjkerntz(8) for details.
1,31    0-5     *       *       *       root    adjkerntz -a
        Как видно, в начале этого файла задаются некоторые переменные окружения. Стоит обратить внимание на некоторые из них:
MAILTO="") то письмо не будет
            отправлено никому. Если же она просто неопределена, письмо
            будет отправлено хозяину файла crontab или root'у если это
            системный crontab.
          #!/usr/bin/env python явно или неявно
            расчитывающих на наличие переменной PATH
            там быть недолжно.
          Далее следуют пять полей отвечающих за время, когда будет выполнено задание: минуты, часы, дни (месяца), месяца и дни недели. Касательно дней недели следует заметить, что их не 7, как кто-то мог подумать, а 8: 0 и 7 соответствуют воскресенью. Таким образом, те кто считают, что первый день недели это понедельник, могут отсчитывать дни с единицы, а кто думает, что первый день недели это воскресенье — с нуля.
        Формат каждого поля: числа должны перечисляться через запятую.
        * — то же, что
        перечисленные через запятую все числа. Диапазон можно указывать
        через-. Таким образом, следующие
        записи эквивалентны:
      
0       *        *       *       *       root    cmd
0       0-23     *       *       *       root    cmd
0       0,1,2-23 *       *       *       root    cmd
        
        Можно задавать через/ условия типа
        «каждый второй». Например */2 в поле час эквивалентно
        заданию каждый второй час. Обратите внимане: каждый второй это
        не тоже самое, что каждый чётный. например:
      
# следующие два задания выполняются каждый чётный час
0       */2     *       *       *       root    cmd
0       0-23/2  *       *       *       root    cmd
# а следующее задание выполняется каждый  НЕчётный час
0       1-23/2  *       *       *       root    cmd
        BSD варианты файла crontab допускают использование ключевых слов вместо пяти полей отвечающих за дату:
Таблица 7.16. Короткие имена используемые в crontab(5) для описания
          времени выполнения заданий
| Ключевое слово | Эквивалент | 
|---|---|
@reboot | Запускается при старте системы | 
@yearly | 0 0 1 1 * | 
@annually | @yearly | 
@monthly | 0 0 1 * * | 
@weekly | 0 0 * * 0 | 
@daily | 0 0 * * * | 
@midnight | @daily | 
@hourly | 0 * * * * | 
Шестое поле системного файла crontab указывает на то, от чьего имени будет выполнено задание. И, наконец, седьмое поле — сама задача.
![]()  | Важно | 
|---|---|
        Будьте осторожны используя знак % в
        команде в crontab. В файле crontab %
        используется для обозначения конца строки и для использования
        его в аргументах команд, его необходимо защищать:
       | 
# Поздравляем пользователя root с новым годом # и высылаем ему содержимое файла /etc/motd @yearly root echo "Счастливого нового года!"%/bin/cat /etc/motd# Эквивалентная форма записи: @yearly root echo "Счастливого нового года!"; /bin/cat /etc/motd
# каждую минуту посылаем пользователю root письмо в котором написано
# сколько времени * * * * * root /bin/date '+\%x \%c'
Вернёмся к системному файлу crontab. Обратите внимание на строки приведённые ниже между отточиями:
# /etc/crontab - root's crontab for FreeBSD
#
# $FreeBSD: src/etc/crontab,v 1.32 2002/11/22 16:13:39 tom Exp $
#
SHELL=/bin/sh
PATH=/etc:/bin:/sbin:/usr/bin:/usr/sbin
HOME=/var/log
#
#minute hour    mday    month   wday    who     command
#
........................................................................
# Perform daily/weekly/monthly maintenance.
1       3       *       *       *       root    periodic daily
15      4       *       *       6       root    periodic weekly
30      5       1       *       *       root    periodic monthly
........................................................................
        В других (не BSD) системах вместо отточенных строк было бы что-то вроде:
# Perform daily/weekly/monthly maintenance.
1       3       *       *       *       root    run-parts /etc/cron.daily
15      4       *       *       6       root    run-parts /etc/cron.weekly
30      5       1       *       *       root    run-parts /etc/cron.monthly
        Скрипт run-parts заходит внутрь указанных каталогов и выполняет все найденные в них сценарии.
        В FreeBSD принят иной механизм, более сложный
        и гибкий: имеется sh-сценарий
        /usr/sbin/periodic, который получает аргумент
        daily, или weekly, или monthly, или security.  Этот скрипт
        изучает переменные заданные в файлах
        /etc/defaults/periodic.conf и
        /etc/periodic.conf (как всегда в подобных
        случаях файл /etc/defaults/periodic.conf
        исправлять не следует, вместо него надо писать пользовательские
        переопределения в /etc/periodic.conf). В
        этих конфигурационных файлах записано какие из периодических
        скриптов надо выполнять и с какими аргументами (если они нужны),
        какие им надо задать переменные окружения, куда направлять вывод
        (в почту или в файл). Синтаксис описан в man странице
        periodic.conf(5)
      
        Сами периодически выполняемые скрипты могут находиться в
        каталогах /etc/periodic/daily,
        /etc/periodic/weekly,
        /etc/periodic/monthly или в аналогичных
        подкаталогах в иерархии
        /usr/local/etc/periodic или
        /usr/X11R6/etc/periodic.
      
        Недокументированной особенностью скрипта
        periodic является его относительная
        всеядность к аргументам. Например, вы можете создать собственный
        каталог с заданиями расчитанными на ваш период
        /usr/local/etc/periodic/myperiod, положить
        в него задание mytask и выполнять его
        командой periodic myperiod. При этом у вас
        будут все возможности влиять на работу вашего скрипта через файл
        /etc/periodic.conf. Останется только
        добавить в системный (или пользовательский) crontab вызов
        задания periodic myperiod.
      
$mkdir /usr/local/etc/periodic/myperiod$vi /usr/local/etc/periodic/myperiod/mytask ....$cat /usr/local/etc/periodic/myperiod/mytask #!/bin/sh echo Hello world | tee /tmp/hello$periodic myperiod Hello world -- End of myperiod output --
В OpenBSD и NetBSD системный crontab отсутствует (что не означает, что его не может быть в принципе). Все действия осуществляются путём работы с пользовательскими crontab'ами (в том числе crontab пользователя root).
Каталогов с периодически выполняемыми заданиями тоже нет. Вместо них имеются shell сценарии /etc/daily, /etc/weekly и /etc/monthly запускаемые из crontab пользователя root и настраиваемые при помощи файлов /etc/daily.conf, /etc/weekly.conf и /etc/monthly.conf соответственно.
        В OpenBSD соответствующую справку можно
        получить из страниц man daily.conf(5),
        weekly.conf(5),
        monthly.conf(5). В
        NetBSD daily(8),
        weekly(8), monthly(8).
      
Пользовательский crontab файл отличается от системного тем, что в нём нет шестого поля с указанием от чьего имени выполняется команда. Команда может выполняться только от имени владельца файла crontab.
Расположены пользовательские crontab файлы в каталоге /var/cron/tabs и названы по именам пользователей. Владельцем всех crontab файлов является root. Таким образом, если пользователь окажется переименован, но его UID останется прежним это не спасёт его от потери своего файла crontab. Это редкий случай когда в UNIX нечто завязано не на UID, а именно на имя пользователя.
        Пользовательские файлы crontab создаются при помощи утилиты
        crontab(1). Будучи запущена пользователем
        user с аргументом -e эта утилита вызывает
        редактор заданный в переменной окружения
        EDITOR (если эта переменная не задана,
        вызывается vi(1)) и в этом редакторе
        пользователь может редактировать свой файл crontab.
        Суперпользователь может редактировать чужие файлы crontab,
        задавая пользователя в аргументе -u.
      
Можно рекомендовать администратору не править системный crontab с целью внедрения в него своих скриптов, дабы облегчить себе работу с mergemaster(8) при обновлении системы. Вместо этого удобнее править crontab пользователя root
 $ sudo crontab
            -u root -e
        
        Имеется способ ограничить пользователей в написании файлов
        crontab: файлы /etc/cron/allow и
        /etc/cron/deny (это не ошибка, в
        Linux файлы называются по-другому). В них
        можно перечислить пользователей которым разрешено или запрещено
        запускать программу crontab(1)
      
В следующей таблице представлен алфавитный список команд и файлов упомянутых в разделах «Практика» экзаменационных тем. Цель таблицы — помочь кандидату в обучении.
Кандидат должен понимать, что доступность и расположение этих команд может со временем меняться. Мы просим тех кандидатов, которые заметят, что некоторая команда доступна в системе, тогда, как в таблице сказано, что это не так, связаться с BSD CG через website, указать имя команды и версию операционной системы. Актуальная версия таблицы поддерживается на http://www.bsdcertification.org/.
Обозначения в таблице:
Таблица A.1. Раскладка файлов и команд по операционным системам
| Command or File | Dragonfly BSD | FreeBSD | NetBSD | OpenBSD | 
|---|---|---|---|---|
/etc/release | X | |||
/etc/ssh/* | X | X | X | X | 
/kern/msgbuf | X | |||
/var/log/* | X | X | X | X | 
/var/mail/$USER | X | X | X | X | 
/var/run/dmesg.boot | X | X | X | X | 
| ac(8) | X | X | X | X | 
| accton(8) | X | X | X | X | 
| acl(3) | X | X | ||
adduser.conf(5) | X | X | ||
| adduser(8) | X | X | X | |
| afterboot(8) | X | X | ||
aliases(5) | X | X | X | X | 
altq.conf(5) | X | |||
| altq(4) или (9) | X | X | X | |
| altqd(8) | X | |||
| apropos(1) | X | X | X | X | 
| arp(8) | X | X | X | X | 
| atacontrol(8) | X | X | ||
| atactl(8) | X | X | ||
| audit-packages | P | P | ||
auth.conf(5) | X | X | ||
bsd.port.mk(5) | X | |||
| build.sh | X | |||
| bzcat(1) (bzip) | X | X | X | P | 
| camcontrol(8) | X | X | ||
| ccdconfig(8) | X | X | X | X | 
| cgd(4) | X | |||
| chflags(1) | X | X | X | X | 
| chfn(1) | X | X | X | X | 
| chgrp(1) | X | X | X | X | 
| chmod(1) | X | X | X | X | 
| chown(8) | X | X | X | X | 
| chpass(1) | X | X | X | |
| chroot(8) | X | X | X | X | 
| chsh(1) | X | X | X | X | 
| cksum(1) | X | X | X | X | 
| cp(1) | X | X | X | X | 
| cpdup(1) | X | P | ||
| cpio(1) или (1L) | X | X | X | X | 
| cron(8) | X | X | X | X | 
| crontab(1) | X | X | X | X | 
crontab(5) | X | X | X | X | 
| csh(1) | X | X | X | X | 
| cvs(1) | X | X | X | X | 
| cvsup(1) | P | P | P | P | 
| cvsync(1) | P | P | P | P | 
daily.conf(5) | X | |||
| daily(8) | X | |||
| dd(1) | X | X | X | X | 
| df(1) | X | X | X | X | 
dhclient.conf(5) | X | X | X | X | 
dhclient.leases(5) | X | X | X | X | 
| dhclient(8) | X | X | X | X | 
| dig(1) | X | X | X | X | 
| dmesg(8) | X | X | X | X | 
| domainname(1) | X | X | X | X | 
| du(1) | X | X | X | X | 
| dump(8) | X | X | X | X | 
| egrep(1) | X | X | X | X | 
| env(1) | X | X | X | X | 
| environ(7) | X | X | X | X | 
| etcupdate(8) | X | |||
exports(5) | X | X | X | X | 
| fetch(1) | X | X | ||
| fgrep(1) | X | X | X | X | 
| file(1) | X | X | X | X | 
| find(1) | X | X | X | X | 
| finger(1) | X | X | X | X | 
| firewall(7) | X | X | ||
| fsck(8) | X | X | X | X | 
| fsdb(8) | X | X | X | X | 
fstab(5) | X | X | X | X | 
| fstat(1) | X | X | X | X | 
| ftp(1) | X | X | X | X | 
ftpusers(5) | X | |||
| gbde(4)(8) | X | |||
| getfacl(1) | X | |||
gettytab(5) | X | X | X | X | 
| gmirror(8) | X | |||
| graid3(8) | X | |||
| grep(1) | X | X | X | X | 
| groups(1) | X | X | X | X | 
| gstripe(8) | X | |||
| hier(7) | X | X | X | X | 
| host(1) | X | X | X | X | 
hostname.if(5) | X | |||
| hostname(1) | X | X | X | X | 
host.conf(5) | X | |||
hosts(5) | X | X | X | X | 
| id(1) | X | X | X | X | 
ifaliases(5) | X | |||
| ifconfig(8) | X | X | X | X | 
| inetd(8) | X | X | X | X | 
| info(1) | X | X | X | X | 
| init(8) | X | X | X | X | 
| intro с (1) по (9) | X | X | X | X | 
| iostat(8) | X | X | X | X | 
| ipf(8) | X | X | X | |
| ipfstat(8) | X | X | X | |
| ipfw(8) | X | X | ||
| jail(8) | X | X | ||
| kill(1) | X | X | X | X | 
| killall(1) | X | X | ||
| kldload(8) | X | X | ||
| kldstat(8) | X | X | ||
| kldunload(8) | X | X | ||
krb5.conf(5) | X | X | X | X | 
| last(1) | X | X | X | X | 
| lastcomm(1) | X | X | X | X | 
lastlog(5) | X | X | X | X | 
| lastlogin(8) | X | X | X | |
| limit(1) | X | X | X | X | 
| limits(1) | X | X | X | |
lkm.conf(5) | X | |||
| ln(1) | X | X | X | X | 
loader.conf(5) | X | X | ||
locate.conf(5) | X | |||
| locate.updatedb(8) | X | X | X | X | 
| locate(1) | X | X | X | X | 
login.conf(5) | X | X | X | X | 
| lpc(8) | X | X | X | X | 
| lpq(1) | X | X | X | X | 
| lprm(1) | X | X | X | X | 
| ls(1) | X | X | X | X | 
| lsof(8) | P | P | P | |
| mac(4) | X | |||
magic(5) | X | X | X | X | 
| mail(1) | X | X | X | X | 
mailer.conf(5) | X | X | X | X | 
| mailq(1) или (8) | X | X | X | X | 
make.conf(5) | X | X | ||
| make(1) | X | X | X | X | 
| make buildworld | X | X | X | X | 
| make installworld | X | X | X | X | 
| make replace | X | X | ||
| make show-downlevel | X | X | ||
| make update | X | X | ||
| make quickworld | X | |||
man.conf(5) | X | X | ||
| man(1) | X | X | X | X | 
| master.cf (postfix) | P | X | P | |
| md5(1) | X | X | X | X | 
| mergemaster(8) | X | X | P | |
mk.conf(5) | X | X | ||
| modload(8) | X | X | ||
| modstat(8) | X | X | ||
| modunload(8) | X | X | ||
monthly.conf(5) | X | |||
| monthly(8) | X | |||
motd(5) | X | X | X | X | 
| mount(8) | X | X | X | X | 
| mountd(8) | X | X | X | X | 
| mount_nfs(8) | X | X | X | X | 
| mtree(8) | X | X | X | X | 
mygate(5) | * | X | ||
myname(5) | * | X | ||
| nc(1) (netcat) | P | X | P | X | 
| ndp(8) | X | X | X | X | 
| netstart(8) | X | |||
| netstat(1) | X | X | X | X | 
| newaliases(1) или (8) | X | X | X | X | 
newsyslog.conf(5) | * | X | X | X | 
| newsyslog(8) | X | X | X | X | 
| nfsd(8) | X | X | X | X | 
| nfsstat(1) | X | X | X | X | 
| nice(1) | X | X | X | X | 
| nmap(1) | P | P | P | P | 
| nologin(8) | X | X | X | X | 
| nslookup(1) или (8) | X | X | X | X | 
nsswitch.conf(5) | X | X | X | |
ntpd.conf(5) | X | X | X | X | 
| ntpd(8) | X | X | X | X | 
| openssl(1) | X | X | X | X | 
| packages(7) или ports(7) | X | X | ||
passwd.conf(5) | X | |||
| passwd(1) и (5) | X | X | X | X | 
| patch(1) | X | X | X | X | 
| pax(1) | X | X | X | X | 
| pciconf(8) | X | X | ||
periodic.conf(5) | X | X | ||
| periodic(8) | X | X | ||
| pf(4) | X | X | X | X | 
| pfctl(8) | X | X | X | X | 
| pgrep(1) | X | X | X | X | 
| ping(8) | X | X | X | X | 
| ping6(8) | X | X | X | X | 
| pkg_add(1) | X | X | X | X | 
| pkg_chk | P | P | ||
| pkg_comp | P | P | ||
| pkg_delete(1) | X | X | X | X | 
| pkg_info(1) | X | X | X | X | 
pkgtools.conf(5) | X | |||
| pkg_version(1) | X | X | ||
| pkill(1) | X | X | X | X | 
| portaudit(1) | P | |||
| portmap(8) | X | X | X | |
| portupgrade(1) | P | |||
| postalias(1) (postfix) | P | X | P | |
| postinstall(8) | X | |||
| postqueue(1) (postfix) | P | X | P | |
printcap(5) | X | X | X | X | 
| ps(1) | X | X | X | X | 
| pstat(8) | X | X | X | X | 
| pw(8) | X | X | ||
| pwd_mkdb(8) | X | X | X | X | 
| raidctl(8) | X | X | ||
rc.conf(5) или (8) | X | X | X | X | 
| rc(8) | X | X | X | X | 
| rdate(8) | X | P | X | X | 
| re_format(7) | X | X | X | X | 
| renice(1) или (8) | X | X | X | X | 
resolv.conf(5) | X | X | X | X | 
| restore(8) | X | X | X | X | 
| rm(1) | X | X | X | X | 
| rmuser(8) | X | X | X | |
| route(8) | X | X | X | X | 
| rpc.lockd(8) | X | X | X | X | 
| rpc.statd(8) | X | X | X | |
| rpcbind(8) | X | X | ||
| rtsol(8) | X | X | X | X | 
| sa(8) | X | X | X | X | 
| scsi(4) или (8) | X | X | X | |
| scsictl(8) | X | |||
security.conf(5) | X | |||
| security(7) или (8) | X | X | X | |
sendmail.cf | X | X | X | X | 
services(5) | X | X | X | X | 
| sh(1) | X | X | X | X | 
| sha1(1) | X | X | X | X | 
share/doc | X | X | X | X | 
share/examples | X | X | X | |
| shutdown(8) | X | X | X | X | 
| sockstat(1) | X | X | X | |
| sort(1) | X | X | X | X | 
src/BUILDING | X | |||
src/UPDATING | X | X | ||
| ssh-keygen(1) | X | X | X | X | 
sshd_config(5) | X | X | X | X | 
| sshd(8) | X | X | X | X | 
| stat(1) или stat(2) | X | X | X | X | 
| su(1) | X | X | X | X | 
| sudo(8) | P | P | P | X | 
| sudoedit(8) (sudo) | P | P | P | X | 
sudoers(5) (sudo) | P | P | P | X | 
| swapctl(8) | X | X | X | |
| swapinfo(8) | X | X | ||
sysctl.conf(5) | X | X | X | X | 
| sysctl(8) | X | X | X | X | 
| sysinstall(8) | X | |||
syslog.conf(5) | X | X | X | X | 
| systat(1) | X | X | X | X | 
| systrace(1) | X | X | ||
| tail(1) | X | X | X | X | 
| tar(1) | X | X | X | X | 
| tcsh(1) | X | X | P | P | 
| tee(1) | X | X | X | X | 
| telnet(1) | X | X | X | X | 
| top(1) | X | X | X | X | 
| traceroute(8) | X | X | X | X | 
ttys(5) | X | X | X | X | 
| umask(1) или (2) | X | X | X | X | 
| umount(8) | X | X | X | X | 
| uptime(1) | X | X | X | X | 
| user(8) | X | X | ||
| useradd(8) | X | X | ||
| userdel(8) | X | X | ||
usermgmt.conf(5) | X | X | ||
| usermod(8) | X | X | ||
| users(1) | X | X | X | X | 
utmp(5) | X | X | X | X | 
| veriexecctl(8) | X | |||
| vi(1) | X | X | X | X | 
| vinum(8) | X | X | ||
| vipw(8) | X | X | X | X | 
visudo(5) (sudo) | P | P | P | X | 
| vmstat(1) или (8) | X | X | X | X | 
| vnd(4) | X | X | ||
| vuxml | P | |||
| w(1) | X | X | X | X | 
weekly.conf(5) | X | |||
| weekly(8) | X | |||
| whatis(1) | X | X | X | X | 
| whereis(1) | X | X | X | X | 
| which(1) | X | X | X | X | 
| who(1) | X | X | X | X | 
| whoami(1) | X | X | X | X | 
| whois(1) | X | X | X | X | 
wtmp(5) | X | X | X | X | 
| xargs(1) | X | X | X | X | 
| Xen | P | |||
| zmore(1) | X | X | X | X | 
Содержание
Данный раздел написан для суммирования знаний о функционировании сети. Предполагается, что без знания этого раздела не стоит переходить к освоению Глава 6, Сетевое администрирование (а так же некоторых других вопросов, например связанных с функционированием брандмауэров). В то же время, данный раздел не претендует на полноту. В любом случае я настоятельно рекомендую всем администраторам ознакомиться с книгой Р. Стивенса [Stevens-2003-ru]. Разумеется, множество ресурсов можно найти в сети Интернет. Документация по различным протоколам может быть найдена в различных RFC. RFC это не только сухая документация, но и учебники, например [RFC-1180]. Данный ресурс переведён на русский язык: [RFC-1180-ru]. Неплохим источником информации в данной области может служить сайт http://ru.wikipedia.org/ (Примечание: по ряду причин данная похвала относится лишь к разделу отвечающему за сетевые технологии). Википедия не страдает полнотой, но в ней почти нет неверной информации (в данном разделе), что само по себе уже неплохо.
Для классификации сетевых протоколов применяют так называемую эталонную семиуровневую модель OSI (см. [url://wiki-OSI-ru]).
Сетевая модель OSI (англ. Open Systems Interconnection Reference Model — модель взаимодействия открытых систем) — абстрактная модель для сетевых коммуникаций и разработки сетевых протоколов.
Модель разбивает сетевые протоколы на семь уровней:
Физический уровень предназначен непосредственно для передачи сигнала. В протоколах физического уровня описывается, например, как должен быть устроен провод (витая пара) для того, чтобы он гарантированно пропускал сигнал в стандарте Ethernet 100base-TX: толщина отдельных жил, их сопротивление, частота обвива, минимально расстояние от провода до силового кабеля, максисмальное количество витков в бухте и минимальный радиус бухты, длина провода от ретранслятора до ретранслятора количество соединений типа шнур-розерка, способ разводки жил в разъёме RJ45.
На физическом уровне работают концентраторы и репитеры (они же ретрансляторы). Назначение репитеров состоит в том, чтобы усиливать сигнал. Они нужны в том случае, если надо передать сигнал дальше чем это предусмотрено в стандарте. Концентратор (так же известный как hub) нужен для того, чтобы не только усиливать сигнал, но и передавать его из одного провода в несколько других, таким образом, хаб нужен для объединения нескольких устройств Ethernet в сегмент.
На канальном уровне происходит упаковка сигналов в кадры (frames). Действует контроль ошибок. В заголовке кадра присутствует информация об адресате в виде его аппаратного адреса (MAC-адрес).
На данном уровне работают коммутаторы (switch), мосты (bridge) и, конечно, собственно Ethernet-адаптеры (сетевые карты).
        Заметим, что раз на данном уровне появилось понятие адреса,
        следовательно должна существовать маршрутизация. Канальная
        маршрутизация выполнена на аппаратном уровне. Коммутатор знает
        какой адрес за каким портом (разъёмом RJ45) находится и высылает
        кадр через данный порт. Если кадр адресован на специальный
        аппаратный адрес ff:ff:ff:ff:ff:ff,
        то он доставляется всем адресатам (т.н. широковещательный адрес).
      
Если сеть собрана не на коммутаторах, а на концентраторах (т.е. не на switch'ах, а на hub'ах; для такой сети есть меткое жаргонное выражение «похабная сеть»), все кадры доставляются всем. Такая организация плоха не только с точки зрения безопасности, но, главным образом, с точки зрения производительности. Если два устройства Ethernet одновременно посылают в сегмент кадры, то произойдёт коллизия — оба кадра пропадут. Будет выполнена повторная отправка кадров. Для того, чтобы коллизия не повторилась, повторная отправка происходит с задержкой на случайный промежуток времени. Чем больше устройств в сети, тем выше вероятность коллизии. Про устройства, которые могут войти в подобный конфликт, говорят, что они находятся в одном «домене коллизий». Таким образом, главное преимущество switch'ей перед hub'ами состоит в том, что они дробят сеть на множество незначительных доменов коллизий, тем самым существенно повышая производительность сети.
По поводу безопасности следует сказать следующее: сеть устроенная на hub'ах, позволяет всем слушать всех. В такой сети любой сетевой интерфейс может принять кадр предназначенный не ему и, тем самым, подслушать важную информацию. Иногда администраторы используют hub'ы в сети с диагностической целью (в последнее время найти hub не так то просто, так как они фактически сняты с производства и повсеместно заменяются на switch'и). Однако, было бы ошибкой думать, что использование switch'ей является гарантией отсутствия подслушивания в сети. Во-первых, MAC'адрес легко подделать програмным образом, во-вторых в системе, где работает протокол ARP (см. ниже) можно «подсунуть» свой MAC-адрес вместо адреса машины, трафик с которой интересует атакующего, и осуществить атаку типа man in the middle. (См. http://www.monkey.org/~dugsong/dsniff/faq.html)
        Для мониторинга заголовков канального уровня в программе
        tcpdump(1) предусмотрена опция
        -e. (См. Раздел 6.11, «Демонстрация основных навыков работы с утилитой
      tcpdump(1)»).
      
На данном уровне функционируют протоколы IP, IPv6, ARP, RARP и некоторые другие, однако нас здесь будут интересовать лишь эти четыре.
Протокол ARP предназначен для того, чтобы преобразовывать адреса IP в MAC адреса. Таким образом, его предназначение состоит в том, чтобы обеспечить взаимодействие между сетевым и канальным уровнями, причём не любого сетевого протокола, а именно IP (не IPv6).
Когда у хоста появляется необходимость передать кадр с одного сетевого интерфейса на другой сетевой интерфейс другого хоста, он сверяется со своей маршрутной таблицей (алгоритм работы с маршрутной таблицей описан далее) и решает находится ли хост назначения поблизости, то есть непосредственно в зоне досягаемости, или между ними есть роутер (маршрутизатор). В первом случае надо направить кадр непосредственно на сетевой интерфейс получателя, во втором на данный роутер, который в свою очередь будет сам решать задачу о том, куда ему направить данный Ethernet кадр. В обоих случаях надо превратить IP адрес в аппаратный MAC адрес, только в первом случае это будет IP назначения, а во втором IP маршрутизатора.
          Для того, чтобы узнать MAC адрес по IP хост должен послать
          широковещательный запрос на MAC-адрес ff:ff:ff:ff:ff:ff. Данный запрос
          «слышат» все сетевые интерфейсы данного сегмента и
          тот интерфейс, которому соответствует данный IP адрес должен
          ответить, т.е. выслать свой MAC адрес:
        
# tcpdump -i rl0 -n arp
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on rl0, link-type EN10MB (Ethernet), capture size 96 bytes
14:53:52.850637 arp who-has 192.168.25.158 tell 192.168.25.1
14:53:52.850695 arp reply 192.168.25.158 is-at 00:50:22:b0:7f:39
          
          В приведённом примере машина 192.168.25.1 выясняла аппаратный
          адрес машины 192.168.25.158.
        
Чтобы система не делала ARP запросы при каждой попытке отправить кадр, заводится некоторый ARP кеш, в котором находятся записи соответствия между IP адресами и MAC адресами. Обычно время жизни записи в этом кеше — 2 минуты. Даже в сильно нагруженной сети ARP запросы в норме совершаются 1 или 2 раза в секунду. Таким образом, сам по себе протокол ARP не нагружает систему, однако он уязвим с точки зрения безопасности: запрос ARP «слышат» все машины, в том числе и предполагаемый злоумышленник (конечно, если ему удалось проникнуть в сегмент сети), ничто не мешает злоумышленнику сформировать ложный ответ и, таким образом, перехватить трафик. Для борьбы с этим видом атаки существует множество разных способов, в том числе, можно использовать статические ARP таблицы и попросить сетевой интерфейс отключить у себя ARP протокол и не делать ARP запросов, а так же не отвечать на них.
Reverse ARP, обратный ARP протокол служит для того, чтобы по имеющемуся MAC адресу узнать IP адрес. Этот протокол используется в бездисковых машинах, загружающихся по сети. Первым делом такая машина должна узнать свой IP адрес, и параметры сети, чтобы она могла обратиться по сети, допустим к TFTP серверу, с которого она будет скачивать загрузочную запись. Единтсвенное, что знает о себе эта машина — её MAC адрес. Она посылает в сеть широковещательный запрос с поиском RARP сервера и спрашивает у него, какой IP адрес будет ей соответствовать, если у неё вот такой MAC адрес. Это не тоже самое, что DHCP, хотя смысл похожий.
Протокол IP предназначен для передачи по сети пакетов IP. В соответствии с данным протоколом, на основании маршрутной таблицы, выбирается сетевой интерфейс через который должны передаваться данные, затем осуществляется ARP запрос (см. выше) и выясняется MAC адрес назначения, из пакета формируется кадр, а далее работает канальный уровень модели OSI.
Маршрутная таблица, это таблица в ядре, в которой сказано через какой интерфейс надо посылать пакеты в ту или иную сеть, а так же, надо ли высылать пакеты непосредственно хосту получателю или их надо передать через следующий маршрутизатор, т.е. чей MAC адрес надо использовать, конечного хоста или следующего маршрутизатора. Всё это подробно освящается в Раздел 6.1.2.1, «Таблица маршрутизации».
Протокол IP предназначен для передачи пакетов, задача формирования пакетов, контроль ошибок, в функции протокола IP не входят. Это прерогатива более высокоуровневых протоколов, таких как TCP, UDP, ICMP.
В Раздел 6.11, «Демонстрация основных навыков работы с утилитой tcpdump(1)» приводится листинг программы tcpdump(1) с перехватом двух ICMP пакетов. На этом примере подробно описано из чего состоит заголовок пакета IP.
Задачи протокола IPv6 те же, что и у IP, однако механизм их реализации иной. В частности протокол ARP не используется протоколом IPv6, его функции IPv6 берёт на себя сам, производя запросы Router Solicition. Протокол подробно описан в Раздел 6.10, «Понимание теории адресации IPV6».
На транспортном уровне нас будут интересовать в первую очередь протоколы ICMP, UDP и TCP.
Протокол ICMP служит для передачи служебных сообщений. Протокол описан в [RFC-792]. Существует перевод данного RFC на руский язык: [RFC-792-ru].
Таблица B.1. Типы сообщений ICMP
| Код | Описание | |
|---|---|---|
| 0 | Echo Reply | ответ на запрос эхо | 
| 3 | Destination Unreachable | адресат недостижим | 
| 4 | Source Quench | приостановка отправителя | 
| 5 | Redirect | переадресация | 
| 8 | Echo | эхо-запрос | 
| 11 | Time Exceeded | превышение контрольного времени | 
| 12 | Parameter Problem | проблемы с параметрами | 
| 13 | Timestamp | штамп времени | 
| 14 | Timestamp Reply | ответ на запрос штампа времени | 
| 15 | Information Request | запрос информации | 
| 16 | Information Reply | ответ на запрос информации | 
| Примечание: в некоторых других, более поздних RFC могут быть добавлены дополнительные коды ICMP. Например в RFC 950 добавлены сообщения Address Mask Request (код 17) и Address Mask Reply (код 18) | ||
Название протокола ICMP расшифровывается как Internet Control Message Protocol, таким образом, протокол претендует на то, чтобы контролировать за функционированием Интернета. Примером может быть сообщение ICMP redirect. Пусть есть сеть в которой есть три машины A, B и C. Машина C является роутером (маршрутизатором), но у машины A в качестве маршрутизатора по каким-то причинам прописана машина B. В этом случае, когда машина A попробует связаться с внешним миром (например с машиной D), она обратится к машине B, а та вернёт ей ICMP redirect сообщение, с тем чтобы на адрес D машина A ходила напрямую через C. Таким образом, в данном случае, сообщения ICMP влияют на внутренние таблицы маршрутизации.
Наиболее изветсные сообщения ICMP, это пожалуй echo request и echo reply. Обычно они используются в целях тестирования. В Раздел 6.4.2, «traceroute(1)» рассказывается как программа traceroute(8) с их помощью определяет маршрут от точки до точки.
Протокол UDP служит для передачи данных без коррекции ошибок. Есть целый класс данных в которых скорость передачи данных намного важнее качества. Например потоковое видео и аудио. Клиент переживёт потерю несколких букв, но замедление потока непростит. Другой пример — система DNS. Серверы DNS обслуживают десятки тысяч запросов в секунду. Гарантированная доставка в таких условиях просто невозможна, так как контроль ошибок очень ресурсоёмок (см. ниже, описание протокола TCP).
В задачу протокола UDP входит разбиение потока данных на пакеты. Каждый пакет имеет заголовок в котором указаны IP (или IPv6) адреса источника и назначения и порты источника и назначения. Номера портов идентифицируют программы на хосте источнике и на хосте назначения между которыми осуществляется передача данных.
Протокол UDP действует по принципу «выстрелил и забыл». Он не только не гарантирует доставку пакетов, но даже не гарантирует, что доставленные пакеты придут в том же порядке, в котором они были высланы. Тем не менее, в надёжных сетях во имя роста производительности можно в некоторых приложениях использовать протокол UDP. Одно время сетевая файловая система NFS была основана на протоколе UDP, а контроль ошибок осуществлялся на более высоких уровнях OSI. Однако в настоящий момент от этой практики отказались.
И наконец, протокол TCP отличается от протокола UDP тем, что в нём действует механизм контроля ошибок. Для реализации этого механизма в заголовок добавлено дополнительное поле с флагами TCP. (Это не единственное усложнение в сравнении с UDP, но нас будет интересовать именно оно.) Каждый пакет TCP подтверждается пакетом с флагом ACK (acknowledgement). Один пакет с флагом ACK может подтверждать получение нескольких пакетов. В протоколе оговорена сложная процедура подтверждений, которые происходят при открытии и закрытии соединения.
Ниже приведена структура пакета TCP. В начале пакета идёт заголовок в котором указаны адреса и порты источника и назначения пакета, флаги TCP (в таблице указаны сокращённо по первой букве) и прочая служебная информация, затем собственно данные.
Таблица B.2. Формат TCP заголовка
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | a | b | c | d | e | f | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | a | b | c | d | e | f | 
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Source Port | Destination Port | ||||||||||||||||||||||||||||||
| Sequence Number | |||||||||||||||||||||||||||||||
| Acknowledgment Number | |||||||||||||||||||||||||||||||
| Data Offset | Reserved | W | E | U | A | P | R | S | F | Window | |||||||||||||||||||||
| Checksum | Urgent Pointer | ||||||||||||||||||||||||||||||
| Options | Padding | ||||||||||||||||||||||||||||||
| ... | |||||||||||||||||||||||||||||||
| Data | |||||||||||||||||||||||||||||||
Таблица B.3. Флаги TCP
| Флаг | Описание | |
|---|---|---|
| W | CWR | отправитель информирует получателя о замедлении пересылки (см. [RFC-3168]) | 
| E | ECE | уведомление о перегрузке (см. Раздел C.2.2.4.2.5, «Явное уведомление о перегрузке (ECN)») | 
| U | URG | поле срочного указателя задействовано | 
| A | ACK | поле подтверждения задействовано | 
| P | PSH | функция проталкивания | 
| R | RST | перезагрузка данного соединения | 
| S | SYN | синхронизация номеров очереди | 
| F | FIN | нет больше данных для передачи | 
Соединение TCP, в отличие от UDP, поддерживает понятие «сеанса связи». Это означает, что данные могут идти от источника к получателю одним потоком. Протокол гарантирует контроль ошибок. Данные не могут теряться или повторяться или обгонять друг друга. Для реализации этого требовния организуется ответный трафик от получателя к отправителю, в котором получатель отчитывается о том, какие пакеты он получил и сообщает их контрольные суммы. Для этого высылаются пакеты с выставленным флагом ACK.
Приведённая схема иллюстрирует однонаправленный поток данных. Т.е. даже для однонаправленного потока данных требуется передача пакетов в обе стороны. Между тем, большинство соединений TCP двунаправленны, так как протоколы уровня приложений (HTTP, SMTP и т.п.) передают данные в обе стороны. Так, если браузер должен скачать некоторый ресурс, то со стороны браузера посылается запрос GET <имя ресурса>, а со стороны сервера собственно ресурс. Рассмотрим как открывается такое двунаправленное соединение.
Сперва одна из сторон, будем называть её «клиент» посылает другой строне («серверу») пакет с выставленным флагом SYN. Это своего рода заявка на открытие соединения.
Сервер должен подтвердить получение этого пакета и выслать в ответ пакет с выставленным флагом ACK. Но поскольку соединение должно быть двунаправленным, он должен тоже выслать клиенту пакет с заявкой на открытие соединения, т.е. с флагом SYN. Эти два пакета, с флагами ACK и SYN могут быть объединены в один пакет.
Клиент получил от сервера пакет SYN, теперь он должен его подтвердить, и он высылает серверу пакет ACK подтверждающий открытие соединения от сервера к клиенту.
Итак, клиент и сервер обменялись тремя пакетами: 1) клиент сделал заявку на открытие соединения от клиента к серверу; 2) сервер подтвердил открытие этого соединения и сделал заявку на открытие соединения от сервера к клиенту; 3) клиент подтвердил открытие соединения от сервера к клиенту. Данная процедура обмена тремя пакетами называется процедурой «тройного рукопожатия» (threeway handshaking).
Клиент |                    | Сервер
       |--------SYN-------->|
       |<-----ACK,SYN-------|
       |--------ACK-------->|
       |....................|
       |------------------->|
       |------------------->|
       |------------------->|
       |<-------ACK---------|
       |....................|
            Проведём следующий эксперимент: запустим программу tcpdump(1) и будем с её помощью фильтровать пакеты которыми наша машина обменивается с хостом 213.180.204.8 (ya.ru), а в это время в браузере откроем страницу http://ya.ru.
#tcpdump -i rl0 -n host 213.180.204.8
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on rl0, link-type EN10MB (Ethernet), capture size 96 bytes
16:57:19.343549 IP 192.168.25.158.65083 > 213.108.204.8.80: S 2721116495:2721116495(0) win 65535 <mss 1460,nop,wscale 0,nop,nop,timestamp 707044109 0,sackOK,eol>
16:57:19.344320 IP 213.108.204.8.80 > 192.168.25.158.65083: S 576822871:576822871(0) ack 2721116496 win 65535 <mss 1460,nop,wscale 1,nop,nop,timestamp 117290804 707044109,nop,nop,sackOK>
16:57:19.344402 IP 192.168.25.158.65083 > 213.108.204.8.80: . ack 1 win 65535 <nop,nop,timestamp 707044110 117290804>
16:57:19.346082 IP 192.168.25.158.65083 > 213.108.204.8.80: P 1:466(465) ack 1 win 65535 <nop,nop,timestamp 707044111 117290804>
16:57:19.347377 IP 213.108.204.8.80 > 192.168.25.158.65083: P 1:206(205) ack 466 win 33304 <nop,nop,timestamp 117290804 707044111>
16:57:19.347441 IP 213.108.204.8.80 > 192.168.25.158.65083: F 206:206(0) ack 466 win 33304 <nop,nop,timestamp 117290804 707044111>
16:57:19.347527 IP 192.168.25.158.65083 > 213.108.204.8.80: . ack 207 win 65535 <nop,nop,timestamp 707044113 117290804>
16:57:19.516256 IP 192.168.25.158.65083 > 213.108.204.8.80: F 466:466(0) ack 207 win 65535 <nop,nop,timestamp 707044282 117290804>
16:57:19.517433 IP 213.108.204.8.80 > 192.168.25.158.65083: . ack 467 win 33303 <nop,nop,timestamp 117290821 707044282>
            Первые три пакета, которые мы тут наблюдаем как раз и относятся к процедуре тройного рукопожатия. Видно, что первый пакет имел флаг SYN (на это указывает заглавная буква S в распечатке), второй тоже имел флаг SYN и впридачу флаг ACK. Третий пакет не имел никаких флагов кроме ACK.
Следующие два пакета (4-й и 5-й) в нашей распечатке это пакеты ответственные за передачу данных по протоколу HTTP. В первом из них клиент выслал запрос http-ресурса командой протокола HTTP GET. Так как весь запрос уложился в один пакет, то в этом пакете был выставлен флаг PSH (push). Этот флаг ставится для того, чтобы заставить сервер отправить все накопившиеся пакеты приложению которое их ожидает (т.е. веб-серверу). В ответ сервер высылает страницу html. Эта страница так же поместилась в один пакет, и потому в нём тоже установлен флаг PSH.
Наконец последние четыре пакета соответствуют процедуре закрытия соединения TCP и будут рассмотрены ниже.
Соединение TCP, как уже говорилось выше, двунаправленное, поэтому оно закрывается отдельно клиентом и сервером. Таким образом порождается 4 пакета: 1) сервер посылает уведомление о закрытии канала от сервера к клиенту, пакет с флагом FIN; 2) клиент подтверждает его получение пакетом с флагом ACK; 3) клиент высылает пакет FIN — уведомление о закрытии канала от клиента к серверу; 4) сервер подтверждает его получение. Иногда пакеты 2 и 3 объединяются, подобно тому, как это происходит при тройном рукопожатии.
После того как хост выслал пакет с флагом FIN он больше не имеет право высылать данные через этот же сокет.
Почему же клиент не высылает пакет FIN в том же пакете, в котором он высылает флаг ACK? Потому что закрытие каналов — независимая процедура. Она осуществляется в тот момент когда приложение (браузер или вебсервер) совершит вызов функции close(2). В принципе, после того как соединение со стороны сервера к клиенту закрылось и пребывает в таком полузакрытом состоянии, клиент ещё может продолжать передавать какие-то данные на сервер.
Клиент |                    | Сервер
       |....................|
       |<-------FIN---------|
       |--------ACK-------->|
       |....................|
       |--------FIN-------->|
       |<-------ACK---------|
       |                    |
            В данной процедуре имеется некоторая проблема: когда клиент получил последний пакет с флагом ACK подтверждающий получение пакета с флагом FIN сервером, он ничего серверу не высылает. Как же сервер узнает, что клиент получил его пакет ACK? Чтобы не впасть в порочный круг и не высылать до бесконечности подтверждения на подтверждения, в протоколе TCP избран следующий алгоритм: существует некоторая абстрактная величина, называемая «предельная задержка сегмента» (MSL maximum segment lifetime). Этот параметр характеризует предполагаемый максимально возможный срок пребывания сегмента в сети до того, как он будет где-либо отброшен. В [RFC-793] рекомендовано значение MSL равное 2 минутам. На практике это время зависит от конкретной реализации операционой системы и может быть и меньше. Сервер после отправки пакета ACK ждёт удвоенное время MSL и если за это время он не получил повторного пакета FIN, то он считает, что его пакет ACK благополучно добрался до клиента и закрывает сокет.
В процессе обмена данными по протоколу TCP сокеты на хостах с обеих сторон соединения пребывают в некоторых состояниях. Названия этих состояний для типичного сеанса связи приведены ниже. Более подробно о них можно узнать в [Stevens-2003-ru]. Выяснить какие сокеты открыты в настоящий момент и в каком они находятся состоянии можно при помощи команды netstat(1), о чём подробно рассказано в Раздел 6.1.2.3, «Работающие интернет сервисы и открытые сокеты».
     Клиент |                    | Сервер
            |                    |
            |--------SYN-------->|
   SYN_SENT |                    | SYN_RCVD
            |<-----SYN,ACK-------|
ESTABLISHED |                    | 
            |--------ACK-------->|
            |                    | ESTABLISHED
            |....................|
            |                    |
            |--------FIN-------->|
 FIN_WAIT_1 |                    | CLOSE_WAIT
            |<-------ACK---------|
 FIN_WAIT_2 |                    |
            |....................|
            |                    |
            |<-------FIN---------|
  TIME_WAIT |                    | LAST_ACK
            |--------ACK-------->|
   .......  |                    | CLOSED
            |                    |
     CLOSED |                    |
            |                    |
            Обратите внимание, состояние TIME_WAIT, как уже отмечалось, длится удвоенное время MSL, т.е. до 4 минут. В это состояние попадает только та сторона, которая выполняет активное закрытие соединения. На приведённой диаграмме это клиент, а в распечатке tcpdump(1) в примере с вебсервером, это был сервер. В ситуации, когда активное закрытие выполняет сервер (а для вебсервера это именно так) может накапливаться большое количество незакрытых сокетов. Рано или поздно для перегруженных вебсерверов это может превратиться в серъёзную беду. По этой причине большинство современных операционных систем в данном месте не соответствуют RFC. FreeBSD пребывает в состоянии TIME_WAIT в течение одной минуты.
Таблица B.4. Состояния TCP (по [RFC-793])
| Состояние | Описание | 
|---|---|
| LISTEN | Ожидание запроса на соединение с любого адреса и любого порта | 
| SYN-SENT | Послан запрос на открытие соединение, ожидается ответ | 
| SYN-RECEIVED | Получен запрос на открытие соединения, послано подтверждение на него и ответный запрос на открытие соединения, ожидается ответ (см. ниже про «тройное рукопожатие») | 
| ESTABLISHED | Соединение открыто, по нему могут передаваться данные | 
| FIN-WAIT-1 | Удалённому хосту послан запрос на закрытие соединения, ожидается ответ | 
| FIN-WAIT-2 | Ожидается запрос на закрытие соединения от удалённого хоста | 
| CLOSE-WAIT | ожидается запрос на закрытие соединения от локального пользователя, т.е. со стороны удалённого хоста соединение закрыто, а с нашей стороны ещё нет | 
| CLOSING | ожидается получение подтверждения на посланный удалённому хосту запрос на закрытие канала (при одновременном закрытии) | 
| LAST-ACK | удалённому хосту послан запрос на закрытие соединения ожидается получение подтверждения получения этого запроса | 
| TIME-WAIT | Таймаут выдерживаемый для того, чтобы убедиться, что удалённый хост получил подтверждение на закрытие соединения. | 
| CLOSED | Соединение закрыто | 
Разделение на данные три уровня не входят в модель TCP/IP. Стек протоколов TCP/IP подразумевает, что над транспортным уровнем сразу находится уровень приложения. Что же до эталонной модели OSI подразумевается, что на сеансовом уровне должны работать протоколы отвечающие за поддержание сеанса связи между источником и получателем; уровень представления ответственнен за кодирование и декодирование данных, в том числе за шифрование; а уровень приложения это собственно программы использующие сеть для коммуникации.
На уровне приложения работают такие протоколы как SMTP, HTTP, FTP и другие. Ввиду обширности этой темы мы рассмотрим лишь некоторые из них и не здесь, а далее в отдельных разделах.
Содержание
      Пакетный фильтр OpenBSD в настоящий момент
      успешно портирован во все рассматриваемые в этом курсе системы: в
      FreeBSD, NetBSD и
      DragonFly BSD. Большинство описанных в
      этом обзоре функций, таких как authpf(8) или
      CARP и
        pfsync портированы во все четыре системы. (pfsync(4), кажется нет в
      NetBSD.) Но при этом самая свежая и наиболее
      функциональная версия входит в OpenBSD, а
      остальные системы могут от неё отставать больше или меньше.
    
Здесь описана версия OpenBSD 4.0, и кое где по тексту упоминаются отличия свойственные FreeBSD 6.2.
Для активации пакетного фильтра в OpenBSD надо добавить строкуpf=YES в файл
      /etc/rc.conf.local(5). В
      FreeBSD понадобятся следующие строки в файле
      /etc/rc.conf(5):
    
pf_enable="YES"                 # Включить PF (Подгрузить модуль, если требуется)
pf_rules="/etc/pf.conf"         # Откуда подгружать правила для pf
pf_flags=""                     # дополнительные флаги для управляющей программы pfctl(8)
pflog_enable="YES"              # запуск pflogd(8) (система журналирования)
pflog_logfile="/var/log/pflog"  # где pflogd должен хранить журнал
pflog_flags=""                  # дополнительные флаги для pflogd
      Кроме того, пакетный фильтр можно запустить при помощи команды
# pfctl -e
        
# pfctl -d
        Эти две команды не подгружают правила, а только запускают брандмауэр. Для подгрузки правил надо воспользоваться командой
# pfctl -f /etc/some-ruleset-file
      Вот некоторые примеры использования команды pfctl(8):
#pfctl -f /etc/pf.conf Загрузить файл pf.conf#pfctl -nf /etc/pf.conf Проверить синтаксис, но не загружать#pfctl -Nf /etc/pf.conf Загрузить только правила NAT#pfctl -Rf /etc/pf.conf Загрузить только фильтрующие правила#pfctl -sn Показать текущие правила NAT#pfctl -sr Показать текущие правила фильтра#pfctl -ss Показать текущую таблицу состояний (state table)#pfctl -si Показать статистику#pfctl -sa Показать ВСЁ что можно
      Для ведения журнала может использоваться система
      pflogd(8), которая создаёт псевдо сетевой
      интерфейс pflog0. Это позволяет
      слушать журнал «на лету» при помощи утилиты
      tcpdump(8) (см. Раздел 6.11, «Демонстрация основных навыков работы с утилитой
      tcpdump(1)»).
      Кроме того, pflogd(8)сохраняет журнал в
      отдельный файл, который пишется в двоичном формате. Для чтения
      журнального файла тоже применяется утилита
      tcpdump(8), — в ней, для этого,
      предусмотрено несколько характерных условий, предназначенных
      не для прослушивания сети (основное её предназначение), а
      специально для анализа журнальных файлов
      pf(4).
    
Данный раздел на 80% состоит из перевода официальной документации по пакетному фильтру OpenBSD. Остальные 20% — мои добавления из других источников.
        Пакетный фильтр OpenBSD при запуске считывает
        правила из конфигурационного файла. По умолчанию это файл
        /etc/pf.conf(5). Ниже мы опишем его
        синтаксис.
      
Списки позволяют удобным образом задать несколько похожих критериев в одном правиле. Например: вместо того, чтобы писать по одному правилу на каждый IP-адрес, который мы хотим заблокировать, мы можем использовать одно правило и передать в него список блокируемых адресов. Когда pfctl(8) встречает в конфигурационном файле список, он автоматически заменяется на несколько правил. Например:
block out on fxp0 from { 192.168.0.1, 10.5.32.6 } to any
          Заменяется на
block out on fxp0 from 192.168.0.1 to any
block out on fxp0 from 10.5.32.6 to any
          В одном правиле можно употреблять несколько списков:
rdr on fxp0 proto tcp from any to any port { 22 80 } -> 192.168.0.6
block out on fxp0 proto { tcp udp } from { 192.168.0.1, 10.5.32.6 } \
        to any port { ssh telnet }
          списки могут быть вложенными:
trusted = "{ 192.168.1.2 192.168.5.36 }"
pass in inet proto tcp from { 10.10.0.0/24 $trusted } to port 22
          Будьте осторожны с отрицаниями в списках. Следующий пример демонстрирует распространённую ошибку:
pass in on fxp0 from { 10.0.0.0/8, !10.1.2.3 }
          Эта запись означает не «любой адрес из сети 10.0.0.0/8 кроме 10.1.2.3», а раскрывается в следующие два правила:
pass in on fxp0 from 10.0.0.0/8
pass in on fxp0 from !10.1.2.3
          Если больше нет никаких других ограничивающих правил, такое сочетание приведёт к тому, что будут пропущены вообще все пакеты кроме пакета с машины 10.1.2.3. Для решения такой задачи лучше применять таблицы (см. Раздел C.2.1.3, «Таблицы»).
          Макросы, это определённые пользователем переменные, которые
          могут содержать IP-адреса, номера портов, имена интерфейсов
          и т.п. Имя макроса подчиняется традиционным для
          большинства языков программирования правилам: начинаться оно
          должно с буквы, а за ней должны идти буквы, цифры или
          символы подчерка. Имя не должно быть зарезервированным
          словом, таким как pass, out или queue.
        
ext_if = "fxp0"
block in on $ext_if from any to any
          
          Здесь создан макрос ext_if. Когда
          надо сослаться на макрос, его имя начинают со знака $.
        
Макросы могут раскрываться в списки:
friends = "{ 192.168.1.1, 10.0.2.5, 192.168.43.53 }"
          Макросы можно вкладывать друг в друга, но, поскольку в двойных кавычках макрос указывать нельзя, следует использовать следующий синтакс:
host1 = "192.168.1.1"
host2 = "192.168.1.2"
all_hosts = "{" $host1 $host2 "}"
          
          Макрос $all_hosts в этом примере
          будет раскрыт в список { 192.168.1.1,
            192.168.1.2 }.
        
          При помощи команды pfctl(8) можно
          переопределять значения макросов с помощью опции
          -D. Например:
        
# pfctl -D friends="{ 192.168.1.1, 10.1.2.3 }"
          Таблицы используются для хранения адресов IPv4 и/или IPv6. Поиск в них осуществляется очень быстро, они расходуют значительно меньше памяти и процессорного времени, чем списки. Таблицы, таким образом, идеальны для хранения больших массивов адресов, поскольку поиск в таблице с 50 000 записей происходит не на много медленнее, чем в таблице с 50 адресами. Таблицы можно использовать следующим образом:
route-to,
            reply-to,
            dup-to,
          
          Таблицы можно создавать как в конфигурационном файле
          pf.conf(5), так и при помощи
          управляющей утилиты pfctl(8).
        
          В конфигуационном файле pf.conf(5)
          таблицы создаются при помощи директивы table. У таблицы могут быть следующие
          атрибуты:
        
const, persist
          Пример (имя таблицы указывается в угловых скобках <...>):
        
table <goodguys> { 192.0.2.0/24 }
table <rfc1918> const { 192.168.0.0/16, 172.16.0.0/12, 10.0.0.0/8 }
table <spammers> persist
block in on fxp0 from { <rfc1918>, <spammers> } to any
pass  in on fxp0 from <goodguys> to any
          
          Адреса так же можно употреблять с отрицательным знаком (!), или с ключевым словом not:
        
table <goodguys> { 192.0.2.0/24, !192.0.2.5 }
          
          Таблица <goodguys>, таким
          образом, включает в себя всю сеть 192.0.2.0/24 кроме адреса
          192.0.2.5.
        
Содержимое таблицы можно брать из файла:
table <spammers> persist file "/etc/spammers"
block in on fxp0 from <spammers> to any
          
          Файл /etc/spammers должен содержать
          IP-адреса и/или блоки сетей в формате CIDR по одному на
          строку. Строки начинающиеся с #
          считаются комментарием и игнорируются.
        
            Таблицей можно манипулировать при помощи утилиты
            pfctl(8). Например, следующая команда
            добавляет в таблицу <spammers> ещё одну сеть:
          
# pfctl -t spammers -T add 218.70.0.0/16
            
            Кроме того, указанная команда создаст таблицу <spammers>, если её ещё нет.
            Чтобы перечислить все вхождения в таблицу можно
            использовать следующую команду:
          
# pfctl -t spammers -T show
            
            Опция -v может использваться вместе с
            -Tshow для того, чтобы увидеть статистику
            по каждому пункту в таблице:
          
# pfctl -t crackers -Ts -v
    222.122.26.172
        Cleared:     Sun Jan 21 18:45:49 2007
        In/Block:    [ Packets: 0                  Bytes: 0                  ]
        In/Pass:     [ Packets: 0                  Bytes: 0                  ]
        Out/Block:   [ Packets: 0                  Bytes: 0                  ]
        Out/Pass:    [ Packets: 0                  Bytes: 0                  ]
    222.175.172.2
        Cleared:     Sun Jan 21 18:45:49 2007
        In/Block:    [ Packets: 0                  Bytes: 0                  ]
        In/Pass:     [ Packets: 0                  Bytes: 0                  ]
        Out/Block:   [ Packets: 0                  Bytes: 0                  ]
        Out/Pass:    [ Packets: 0                  Bytes: 0                  ]
....................
            Чтобы удалить адрес из таблицы можно использовать команду
# pfctl -t spammers -T delete 218.70.0.0/16
            См. так же Раздел C.3, «Управление пакетным фильтром OpenBSD при помощи утилиты pfctl(8)».
            Хосты в таблицах можно указывать не только в виде
            IP-адреса, но так же и по имени. В этом случае имена будут
            разрешены и все адреса, соответствующие данному имени,
            попадут в таблицу.  Кроме того, можно указывать имя
            интерфейса или ключевое слово self. В этом случае в таблицу буду
            добавлены все адреса, соответствующие данному интерфейсу, или
            все адреса данной машины (включая кольцевой интерфейс)
            соответственно.
          
Ограничение: адреса 0.0.0.0/0 и 0/0 в таблицах не работают. Используйте списки.
При поиске в таблице находится «наиболее подходящий» адрес, т.е. сеть с самой большой маской. (Наибольшая маска у самой «узкой» сети.) Например:
table <goodguys> { 172.16.0.0/16, !172.16.1.0/24, 172.16.1.100 }
block in on dc0 all
pass  in on dc0 from <goodguys> to any
            
            Адрес источника каждого пакета пришедшего через интерфейс
            dc0 будет искаться в таблице
            <goodguys>:
          
Фильтрация пакетов заключается в том, что пакеты пропускаются или отбрасываются при прохождении через сетевой интерфейс в соответствии с правилами. Правила основаны на заголовках пакетов сетевого и транспортного уровней модели OSI (см. OSI). Наиболее часто используемые критерии — адреса источника и назначения, номера портов источника и назначения, протоколы.
          Правила фильтра состоят из критерия и действия, которое надо
          предпринять, если пакет соответствует критерию. Действие
          может быть или block или pass. Правила применяются по очереди
          от первого к последнему, при этом последнее
            правило выигрывает если только не встретится
          ключеве слово quick. Таким
          образом, если в самом начале конфигурационного файла задано
          правило «пропускать все пакеты», или
          «отбрасывать все пакеты», то это ни что иное, как
          политика по умолчанию — именно это правило будет
          применено к пакету, который не соответствует ни одному
          правилу ниже по ходу файла.
        
Ниже приведена упрощённая синтаксическая схема:
action [direction] [log] [quick] [on interface] [af] [proto protocol] \
    [from src_addr [port src_port]] [to dst_addr [port dst_port]] \
    [flags tcp_flags] [state]
            actionpass, либо block. Действие pass приводит к тому, что пакет
                возвращается в ядро и направляется на другие правила.
                Действие block приводит к
                тому, что срабатывают настройки из политики block-policy (см. Раздел C.2.2.1, «Опции в пакетном фильтре», или настройки
                определённые при помощи опций
                if-bound). (Назначение данной
                политики состоит в том, чтобы просто отбросить пакет,
                или выслать назад какой-нибудь пакет: TCP с флагом reset
                или ICMP Unreachable.) Политика может быть
                переопределена в правиле: block
                  drop или block
                  return.
              directionin или out.
              logkeep state, modulate state или synproxy state —
                в журнал попадают только пакеты открывшие соединение.
                Если надо, чтобы в журнал попали вообще все пакеты,
                применяйте правило log (all).
              quickquick, то данное правило
                считается последним и к пакету немедленно применяется
                действие action. (Т.е. если у
                всех правил будет высталена опция quick, то мы будем иметь дело с
                брандмауэром в котором первое правило выигрывает.)
              interfaceИмя сетевого интерфейса, через который проходит пакет, или имя группы сетевых интерфейсов. Группы можно создавать при помощи команды ifconfig(8) (только в OpenBSD). Кроме того, некоторые группы создаются ядром автоматически:
egress, который
                    содержит все интерфейсы, через которые проходят
                    маршруты по умолчанию.
                  ppp или carp).
                  afinet для адресов IPv4 и inet6 для адресов IPv6. Обычно
                пакетный фильтр может определить требуемый протокол по
                указанным в правиле адресам.
              protocolПротокол транспортного уровня. Возможные варианты:
tcpudpicmp/etc/protocols.
                  src_addr, dst_addrАдрес источника или назначения пакета. Возможные варианты:
/netmask (например /24). Ко всем адресам
                    закреплённым за данным интерфейсом, будет добавлена
                    данная сетевая маска, и полученные сети CIDR будут
                    добавлены в данное правило.
                  (...).
                    Данное правило будет автоматически меняться при
                    смене адреса закреплённого за интерфейсом.  Это
                    полезно для DHCP клиентов.
                  Имя сетевого интерфейса, за которым идёт один из следующих модификаторов:
:network:broadcast:peer
                      Кроме того, за именем интерфейса или за любым из
                      перечисленных выше модификаторов, может
                      следовать модификатор :0, указывающий на то,
                      что нас не интересуют алиасы, т.е.
                      дополнительные адреса, котрые можно добавить к
                      сетевому интерфейсу (см. Раздел 6.15, «Знание как и когда устанавливать или удалять алиасы сетевого интерфейса»).  Например: fxp0:network:0.
                    
!.
                  any,
                    означающее все адреса.
                  all,
                    которое является эквивалентом конструкции from any to any.
                  src_port, dst_port
Порт источника или назначения в заголовке транспортного уровня. Возможны следующие варианты:
/etc/services.
                    Диапазоны портов с применением следующих операторов:
!=<><=>=><<>:
                        Последние три оператора бинарные (принимают
                        два аргумента). При этом <> и >< не включают
                        аргументы в диапазон, а : включает.
                      
tcp_flagsproto tcp. Флаги задаются
                как flags check/mask.
                mask — список
                проверяемых флагов, check — список
                флагов, которые должны быть включены.  Например
                директива flags S/SA
                означает, что мы ищем пакет у которого выключен флаг
                ACK, и включён флаг SYN, а остальные флаги нас не
                интересуют.
              state
Указывает сохраняется ли данным правилом информация о состоянии соединения. Возможные варианты:
keep statemodulate statesynproxy statekeep state и modulate state.
                      
            Полная синтаксическая схема приведена в справочной странице
            man(1) по
            pf.conf(5). В неё входят не упомянутые
            здесь опции. Если вы только изучаете пакетный фильтр,
            возможно вам стоит пропустить дальнейший список и перейти к
            разделу Раздел C.2.1.4.2, «Политика», или
            просто кратко ознакомиться с возможностями фильтра.
          
![]()  | Внимание | 
|---|---|
            В разных системах BSD присутствуют разные
            версии пакетного фильтра и не все возможности описанные
            здесь могут быть реализованы в вашей системе. Больше того,
            не все возможности описанные в вашем
            man по pf.conf(5)
            реализованы в вашей системе, так как при портировании
            man, увы, не редактируют.
           | 
![]()  | Замечание | 
|---|---|
            Имейте в виду, что данный ниже список носит ознакомительный
            характер и перед применением вам следует справиться о
            синтаксисе в вашей странице man по
            pf.conf(5) | 
user <user><user>.
              group <group>;icmp-type <type> code <code>icmp6-type <type> code <code>tos <string|number>
                  Правило соответствует пакетам с указанным значением
                  TOS. Возможные варианты: lowdelay, throughput, reliability или десятичное или
                  шестнадцатеричное значение. Например, следующие строки
                  эквивалентны:
                
pass all tos lowdelay
pass all tos 0x10
pass all tos 16
                  allow-optslabel <string>
                  Правило метится при помощи метки <string>. Просмотреть
                  статистику по помеченным правилам можно при помощи
                  команды pfctl(8) с опцией
                  -s label. Метки можно использовать для
                  предотвращения оптимизации, что важно при написании
                  биллинговой системы.
                
При объявлении меток можно использовать следующие макросы:
$if$srcaddr$dstaddr$srcport$dstport$proto$nrНапример:
ips = "{ 1.2.3.4, 1.2.3.5 }"
pass in proto tcp from any to $ips \
     port > 1023 label "$dstaddr:$dstport"
                  эквивалентно
pass in proto tcp from any to 1.2.3.4 \
      port > 1023 label "1.2.3.4:>1023"
pass in proto tcp from any to 1.2.3.5 \
      port > 1023 label "1.2.3.5:>1023"
                  queue <queue> | (<queue>, <queue>)tag <string>tagged <string>fastrouteroute-to <interface> [nexthop]reply-to <interface> [nexthop]dup-to <interface> [nexthop]route-to. Оригинальный пакет
                маршрутизируется обычным образом.
              rtable <number>probability <num>Вероятность срабатывания правила. Задаётся как дробь от 0 до 1 или в процентах. Например, следующее правило отбрасывает пакеты ICMP с вероятностью 20%:
block in proto icmp probability 20%
                  Рекомендуемая практика при написании брандмауэров — делать политику «default deny», т.е. по умолчанию отбрасывать все пакеты, а потом пропускать некоторые разрешённые пакеты. Для создания политики «default deny» надо сделать следующие первые два правила:
block in  all
block out all
            Эти правила блокируют весь трафик на всех интерфейсах вне зависимости от направления.
Теперь нам надо явно разрешить прохождение трафика, чтобы он не был заблокирован политикой. Здесь понадобятся такие критерии как номера портов источника и назначения, адреса источника и назначения, протоколы. Правила должны быть настолько строгими, насколько это возможно, для того, чтобы через брандмауэр проходил только нужный трафик.
Например:
# Пропускать трафик из локальной сети (192.168.0.0/24) идущий через
# интерфейс dc0 на машину OpenBSD (FreeBSD, NetBSD) с адресом 192.168.0.1,
# а так же выпускать ответный трафик.
pass in  on dc0 from 192.168.0.0/24 to 192.168.0.1
pass out on dc0 from 192.168.0.1 to 192.168.0.0/24
# Пропускать TCP трафик на интерфейсе fxp0 направленный на web сервер
# запущенный на нашей OpenBSD (FreeBSD, NetBSD) машине. Имя интерфейса
# использовано в качестве адреса назначения, поэтому правилу
# соответствуют только пакеты направленные к нам.
pass in on fxp0 proto tcp from any to fxp0 port www
            
            Как было замечено выше, пакеты проходят через все правила
            от начала до конца. Пакет, который пометился правилом как
            проходящий (pass) может
            многократно сменить действие с pass на block и обратно, в процессе
            прохождения через правила. Последнее правило
              выигрывает, если только пакет не встретит
            правило с ключевым словом quick, которое останавливает
            прохождение пакета по правилам.
          
Вот пара примеров:
Неправильный пример:
block in on fxp0 proto tcp from any to any port ssh
pass  in all
              
            В этом случае правило block
            возможно применяется к пакетам ssh, но в итоге никогда не
            срабатывает, так как дальше идёт правило, которое
            разрешает весь трафик.
          
Правильный пример:
block in quick on fxp0 proto tcp from any to any port ssh
pass  in all
              
            В данном примере трафик ssh будет отброшен немедленно,
            так как встретилось ключевое слово quick, и все другие правила
            относящиеся к трафику ssh будут проигноророваны.
          
Неоднозначный пример:
pass  in all
block in on fxp0 proto tcp from any to any port ssh
              Такие два правила возможно приведут к блокированию трафика, а может быть и нет. В зависимости от того, какие правила окажутся ниже по тексту.
Одна из важных возможностей пакетного фильтра — отслеживание состояния соединений («stateful inspection»). Stateful inspection возможна благодаря возможности пакетного фильтра отслеживать состояния сетевых соединений. Состояние каждого соединения хранится в таблице состояний. Пакетный фильтр может быстро определить принадлежит ли пакет уже открытому соединению. Если пакет принадлежит уже открытому соединению, то его пропускают, не направляя на другие фильтрующие правила.
Использование таблицы состояний имеет много преимуществ: от упрощения правил фильтрации, до увеличения производительности брандмауэра. Пакетный фильтр может определить принадлежность пакета открытому соединению независимо от направления в котором идёт пакет. Это освобождает от необходимости написания правил пропускающих ответный трафик. А поскольку пакет не направляется ни на какие правила, время прохождения пакета через брандмауэр существенно уменьшается.
            Если в правиле присутсвует опция keep state, первый пакет
            соответствующий правилу создаёт запись в таблице состояний
            связывающую источник и получателя пакета. Теперь не только
            пакеты идущие от источника к получателю, но и обратные
            пакеты будут соответствовать созданной записи в таблице
            состояний и не будут подвергаться проверке. Например:
          
pass out on fxp0 proto tcp from any to any keep state
            
            Это правило разрешает любой исходящий трафик на
            интерфейсе fxp0, а так же
            разрешает прохождение всего ответного трафика через
            брандмауэр. Функция keep state замечательна так же
            тем, что значительно улучшает производительность
            брандмауэра, так как поиск в таблице состояний намного
            быстрее чем проверка пакета при помощи правил фильтрации.
          
            Функция modulate state
            работает так же как keep state, но применима
            только к пакетам TCP. При использовании modulate state, начальный
            номер последовательности (ISN) исходящих соединений
            выбирается случайным образом. Это полезно для защиты
            соединений инициализированных операционными системами,
            проделывающими более слабую работу по выбору номера ISN.
            Начиная с OpenBSD 3.5 правило
            modulate state можно
            употреблять не только для протокола TCP (рандомизация
            последовательности при этом будет работать для TCP
            протокола, а для UDP и ICMP будет работать keep state).
          
Сохранять состояние TCP, UDP и ICMP трафика, и рандомизировать ISN в TCP:
pass out on fxp0 proto { tcp, udp, icmp } from any to any modulate state
            
            Другое преимущество таблицы состояний состоит в том, что
            трафик ICMP соответствующий открытому соединению тоже
            пропускается через брандмауэр. Например: если keep state указан для
            соединения TCP, и получено сообщение ICMP source-quench
            относящееся к данному соединению TCP, то оно будет
            пропущено через брандмауэр (ICMP пакет source-quench
            уменьшает скорость отправки пакетов через маршрутизатор и
            отсылается маршрутизатором или конечным хостом если,
            например, у них переполнен буфер).
          
            Область действия записи в таблице состояния ограничивается
            задаваемой глобально опцией state-policy (см. Раздел C.2.2.1, «Опции в пакетном фильтре», или при помощи опций
            if-bound), group-bound и floating, задаваемых непосредственно
            в правилах. Они имеют то же значение, что и заданные
            глобально политики state-policy.
            Пример:
          
pass out on fxp0 proto { tcp, udp, icmp } from any \
  to any modulate state (if-bound)
            
            Это правило гласит, что пакет будет соответствовать записи в
            таблице состояний только если он идёт через интерфейс fxp0.
          
            Правила nat, binat и rdr тоже создают записи в
            таблице состояний.
          
            Кто-то может подумать, что для протокола UDP нельзя делать
            записи в таблице состояний, так как это
            «stateless» протокол. Однако пакетный фильтр
            может отслеживать его состояния. Несмотря на отсутствие
            «стартового» пакета, пакетный фильтр следит за
            пакетами на основании таймаутов и номеров портов источника и
            назначения. По достижении таймаута таблица состояний
            очищается от соответствующей записи.  Величину таймаута можно
            задать в разделе «опции»
            pf.conf, см. Раздел C.2.2.1, «Опции в пакетном фильтре»
          
            Можно использовать некоторые опции для управления поведением
            записей в таблице состояний, созданных при помощи команд
            keep state, modulate state или synproxy state. Вот список этих
            опций:
          
max numbersource-trackЭта опция даёт возможность отслеживать количество записей в таблице состояний в пересчёте на каждый адрес источника. Возможные форматы опции:
source-track rule —
                    Максимальное количество записей в таблице
                    состояний созданных данным правилом ограничивается
                    опциями max-src-nodes и
                    max-src-states,
                    заданными в этом правиле. Счётчики заводятся не
                    глобальные, а локальные.
                  source-track global —
                    То же что и в предыдущем слуаче, но счётчики
                    ведутся глобально. При этом каждое правило может
                    иметь свои пределы max-src-nodes и max-src-states, однако
                    счётчики будут общими для всех правил.
                  
                  Общее количество адресов источников, для которых
                  осуществляется глобальный контроль количества строк
                  в таблице состояний, ограничивается при помощи опции
                  src-nodes. (См. Раздел C.2.2.1, «Опции в пакетном фильтре»)
                
max-src-nodes numbersource-track опция max-src-nodes ограничивает
                количество IP-адресов с которых можно одновременно
                открыть соединения.
              max-src-states numbersource-track опция max-src-states ограничивает
                количество соединений с одного IP-адреса.
              Например:
pass in on $ext_if proto tcp to $web_server \
    port www flags S/SA keep state \
    (max 200, source-track rule, max-src-nodes 100, max-src-states 3)
            Это правило означает следующее:
Отдельные ограничения можно ввести для TCP соединений прошедших тройное рукопожатие (см. Раздел B.1.4.3.2, «Открытие соединения TCP, тройное рукопожатие»):
max-src-conn numbermax-src-conn-rate number / interval
            Обе опции автоматически включают опцию state-track rule и не совместимы с
            state-track global.
          
В комбинации с данными опциями можно употреблять более агрессивные опции, для «наказания» «провинившихся».
overload <table>flash [global]global
                записи в таблице состояний сбрасываются независимо от
                того, какое правило её создало.
              Пример:
table <abusive_hosts> persist
block in quick from <abusive_hosts>
pass in on $ext_if proto tcp to $web_server \
    port www flags S/SA keep state \
    (max-src-conn 100, max-src-conn-rate 15/5, overload <abusive_hosts> flush)
            Эти правила делают следующее:
block).
            
            При открытии соединения TCP пакетный фильтр должен изучить
            флаги TCP выставленные в заголовке пакета. Описание флагов
            дано в Таблица B.3, «Флаги TCP». Для изучения флагов
            применяется ключевое слово flags check/mask. mask указывает фильтру, что он
            изучает только указанные в этом поле флаги, а поле check указывает какие флаги должны
            быть включены, чтобы удовлетворять данному правилу.
          
pass in on fxp0 proto tcp from any to any port ssh flags S/SA
            Приведённое правило пропускает весь TCP трафик c установленным флагом SYN, при этом изучаются флаги SYN и ACK. Пакет с флагами SYN и ECE будет пропущен данным правилом, а пакет в котором выставлены флаги SYN и ACK или просто ACK не будет пропущен.
![]()  | Замечание | 
|---|---|
            В старых версиях поддерживался синтаксис ... flags S, в новых
            версиях фильтра маска всегда должна указываться.
           | 
            Часто флаги указываются вместе с правилом keep state для создания записи
            в таблице состояний:
          
pass out on fxp0 proto tcp all flags S/SA keep state
            Данное правило разрешает исходящие соединения начинающиеся с пакета в котором выставленн флаг SYN, а флага ACK нет.
Будьте внимательны при использовании флагов. Понимайте что вы делаете и зачем, особенно когда пользуетесь чьими-то советами. Некоторые люди предлагают открывать соединения если указан флаг SYN и никакой другой:
. . . flags S/FSRPAUEW  плохая идея!!
            Теоретически первый пакет должен содержать флаг SYN и никакой другой, однако некоторые хосты выставляют флаг ECN и будут отвергнуты данным правилом. Более разумным будет следующее правило:
. . . flags S/SAFR
            Это практично и безопасно, однако в этом нет необходимости, если трафик был нормализован при помощи scrub. Процесс нормализации трафика заставляет пакетный фильтр отбрасывать пакеты с неправильными сочетаниями флагов (вроде SYN+RST) или подозрительным счетанием (SYN+FIN). Крайне желательно всегда подвергать трафик нормализации:
scrub in on fxp0
.
.
.
pass in on fxp0 proto tcp from any to any port ssh flags S/SA keep state
            В обычной ситуации клиент выполняет тройное рукопожатие с сервером (см. Раздел B.1.4.3.2, «Открытие соединения TCP, тройное рукопожатие»). Пакетный фильтр умеет выполнять в этой процедуре функцию посредника. При этом фильтр выполняет тройное рукопожатие с клиентом, затем проводит рукопожатие с сервером, и уже после этого начинает пробрасывать пакеты между клиентом и сервером. Этот метод позволяет избежать TCP SYN флуда (разновидность сетевой DOS атаки, когда клиент забрасывает сервер заявками на открытие соединения, но соединение не открывает. В результате у сервера могут исчерпаться сокеты. см. так же DOS атака).
            Проксирование рукопожатия проводится при помощи ключевого
            слова synproxy state:
          
pass in on $ext_if proto tcp from any to $web_server port www \
    flags S/SA synproxy state
            В этом примере проксируется входящее соединение к web-серверу.
            synproxy state включает в
            себя функционал keep state
            и modulate state.
          
![]()  | Замечание | 
|---|---|
| SYN proxy невозможен, если пакетный фильтр работает на мосту. (См. bridge.) | 
IP-спуфинг — подделка исходящих адресов в заголовке IP пакета (см. spoofing).
            Пакетный фильтр может осуществлять защиту от спуфинга при
            помощи правил начинающихся с ключевого слова antispoof:
          
antispoof [log] [quick] for interface [af]
            logquickinterfaceafinet и inet6.
              Пример:
antispoof for fxp0 inet
            
            Каждое правило antispoof
            превращается в два правила фильтра. Например, если за
            интерфейсом fxp0 закреплён адрес 10.0.0.1 и сетевая маска
            255.255.255.0 (т.е. /24), то предыдущее правило
            превратится в следующие два правила:
          
block in on ! fxp0 inet from 10.0.0.0/24 to any
block in inet from 10.0.0.1 to any
            Эти правила означают следующее:
![]()  | Замечание | 
|---|---|
              Правило  
set skip on lo0
antispoof for fxp0 inet
               | 
![]()  | Замечание | 
|---|---|
              Использование правила  
block drop in on ! fxp0 inet all
block drop in inet all
              и может заблокировать весь входящий трафик на всех интерфейсах.  | 
Начиная с OpenBSD 4.0 в пакетном фильтре появилась возможность проверять исходящие адреса при помощи таблицы маршрутизации. Если пакет подвергается проверке uRPF, исходящий IP адрес разыскивается в таблице маршрутизации, и если указанный в ней интерфейс соответствует интерфейсу, через который пришёл пакет, то пакет проходит проверку, а если нет — то мы имеем дело с IP-спуфингом.
            Проверка uRPF осуществляется при помощи ключевого слова
            urpf-failed:
          
block in quick from urpf-failed label uRPF
            Проверка uRPF работает только при симметричной маршрутизации. В противном случае трафик будет заблокирован.
            Если машина является конечной точкой IPSec туннеля, нельзя
            включать проверку uRPF на интерфейсе enc0, иначе будет
            заблокирован весь инкапсулированный трафик. Рекомендуется
            пропускать все пакеты на интерфейсе enc0: set skip on enc0 или
            делать так:
          
block in quick on ! enc0 from urpf-failed label uRPF
            ![]()  | Замечание | 
|---|---|
| В FreeBSD uRPF пока не портирован. | 
![]()  | Замечание | 
|---|---|
| В FreeBSD интерфейс аналогичный упомянутому здесь интерфейсу OpenBSD enc0 будет называться gif0. | 
            Пакетный фильтр обладает возможностью определять из какой
            операционной системы был отправлен SYN пакет. Делается это
            на основе некоторых характерных особенностей работы TCP
            стека разных систем. Так, известно, что операционные
            системы Windows NT склонны
            выставлять поле TTL в 128, тогда как
            Linux,
            FreeBSD — 64. Особенности
            работы стека приведены в файле
            /etc/pf.os. Это обычный текстовый файл,
            формат которого описан в нём же в комментариях. Текущий
            список fingerprint'ов можно увидеть при помощи команды
          
# pfctl -s osfp
Class   Version Subtype(subversion)
-----   ------- -------------------
AIX
AIX     4.3
AIX     4.3     2
AIX     4.3     2-3
AIX     4.3     3
AIX     5.1
AIX     5.1-5.2
AIX     5.2
AIX     5.3
AIX     5.3     ML1
.......
            В моей системе насчитывается 330 fingerprint'ов. Включая Zaurus (наладонник фирмы Sharp с Linux'ом) 2-х версий.
            Фильтрацию можно осуществлять при помощи ключевого слова
            os:
          
pass  in on $ext_if from any os OpenBSD keep state
block in on $ext_if from any os "Windows 2000"
block in on $ext_if from any os "Linux 2.4 ts"
block in on $ext_if from any os unknown
            
            Ключевое слово unknown означает
            пакет от системы чьи характеристики пакетному фильтру
            неизвестены.
          
![]()  | Замечание | 
|---|---|
  | 
            По умолчанию пакетный фильтр отбрасывает IP пакеты с
            выставленными опциями, для затруднения работы программ
            пытающихся узнать тип нашей операционной системы, например
            nmap(1). Если у вас есть приложения
            нуждающиеся в прохождении такого трафика, например
            multicast или IGMP, используйте опцию allow-opts:
          
pass in quick on fxp0 all allow-opts
            Ниже приведён краткий пример конфигурационного файла для брандмауэра между небольшой внутренней сетью и Интернетом. Здесь приведены только правила фильтрации, nat, rdr, queue опущены.
ext_if  = "fxp0"
int_if  = "dc0"
lan_net = "192.168.0.0/24"
# Таблица содержит все IP адреса принадлежащие брандмауэру
table <firewall> const { self }
# Не фильтруем пакеты на кольцевом интерфейсе
set skip on lo0
# Нормализуем входящий трафик
scrub in all
# Политика по умолчанию
block all
# Включаем защиту от спуфинга на внутреннем интерфейсе
antispoof quick for $int_if inet
# Разрешаем ssh соединения из локальной сети только с доверенного
# компьютера 192.168.0.15. Использование "block return" приведёт  тому,
# что будет возвращаться пакет TCP RST для того, чтобы заблокированное
# соединение закрывалось правильным образом. "quick" используется для
# того, чтобы идущие ниже правила pass не переопределили данное
# действие.
block return in quick on $int_if proto tcp from ! 192.168.0.15 \
    to $int_if port ssh flags S/SA
# Разрешить весь трафик из локальной сети к брандмауэру и обратно
pass in  on $int_if from $lan_net to any
pass out on $int_if from any to $lan_net
# Пропустить исходящие tcp, udp и icmp пакеты на внешнем интерфейсе.
# Сохранять состояния соединений.
pass out on $ext_if proto tcp all modulate state flags S/SA
pass out on $ext_if proto { udp, icmp } all keep state
# Разрешить сединения ssh на внешнем интерфейсе если они направлены не
# брандмауэру, а другой машине (во внутренней сети). Первый пакет
# заносить в журнал, чтобы потом можно было сказать кто решил открыть
# соединение. Использовать syn proxy для защиты от syn флуда.
pass in log on $ext_if proto tcp from any to ! <firewall> \
    port ssh flags S/SA synproxy state
            Суть трансляции адресов NAT описана в глоссарии: NAT.
Когда клиент из внутренней сети пытается послать IP пакет в Интернет в этом пакете подменяется исходящий IP адрес на адрес шлюза, а так же, при необходимости, подменяется номер порта источника у пакетов TCP и UDP. Делается запись в таблице состояний.
Обратные пакеты находятся в таблице состояний и с ними проделывается аналогичное обратное преобразование.
Ни внутренняя машина, ни внешняя не знают о существовании NAT. Всё происходит прозрачно. Для внутренней машины NAT это просто шлюз, а внешняя машина ничего не знает о внутренней и считает, что соединение открыто шлюзом. Обнаружить NAT можно только по косвенным признакам.
            Пакеты подвергаемые трансляции проходят через фильтр и
            будут отброшены или пропущены в зависимости от правил
            которые там встретятся. Единственное
            исключение — если в правиле NAT встретится
            ключевое слово pass, то в этом
            случае пакет не будет подвергнут фильтрации.
          
Трансляция осуществляется до фильтрации. Правила фильтра увидят уже оттранслированные пакеты.
            Поскольку NAT всегда используется на шлюзах и
            маршрутизаторах, необходимо включить проброс пакетов. Для
            этого надо выставить переменную ядра net.inet.ip.forwarding в истину.
            Для этого во всех системах BSD
            используется программа sysctl(8)
          
#sysctl -w net.inet.ip.forwarding=1#sysctl -w net.inet6.ip6.forwarding=1 <==(если исппользуется IPv6)
            Чтобы сделать эти изменения постоянными следует
            добавить в файл /etc/sysctl.conf
            такие строки:
          
net.inet.ip.forwarding=1
net.inet6.ip6.forwarding=1
            
            Синтаксическая диаграмма правила NAT в
            pf.conf(5) выглядит следующим
            образом:
          
nat [pass [log]] on interface [af] from src_addr [port src_port] to \
    dst_addr [port dst_port] -> ext_addr [pool_type] [static-port]
            natpasslogpass, пакеты заносятся в журнал
                при помощи pflogd(8). В норме в
                журнал попадает только первый пакет, при необходимости
                журналировать все пакеты используйте log (all).
              interfaceafinet для адресов IPv4 и inet6 для адресов IPv6. Обычно
                пакетный фильтр может определить требуемый протокол по
                указанным в правиле адресам.
              src_addr, dst_addrАдрес источника или назначения пакета. Возможные варианты:
/netmask (например /24). Ко всем адресам
                    закреплённым за данным интерфейсом, будет
                    добавлена данная сетевая маска, и полученные сети
                    CIDR будут добавлены в данное правило.
                  (...).
                    Данное правило будет автоматически меняться при
                    смене адреса закреплённого за интерфейсом.  Это
                    может быть полезно, например, для DHCP клиентов.
                  Имя сетевого интерфейса, за которым идёт один из следующих модификаторов:
:network:broadcast:peer
                      Кроме того, за именем интерфейса или за любым из
                      перечисленных выше модификаторов, может
                      следовать модификатор :0, указывающий на то,
                      что нас не интересуют алиасы, т.е.
                      дополнительные адреса, котрые можно добавить к
                      сетевому интерфейсу (см. Раздел 6.15, «Знание как и когда устанавливать или удалять алиасы сетевого интерфейса»).  Например: fxp0:network:0.
                    
!.
                  any,
                    означающее все адреса.
                  all,
                    которое является эквивалентом конструкции from any to any.
                  src_port, dst_port
Порт источника или назначения в заголовке транспортного уровня. Возможны следующие варианты:
/etc/services.
                    Диапазоны портов с применением следующих операторов:
!=<><=>=><<>:
                        Последние три оператора бинарные (принимают
                        два аргумента). При этом <> и >< не включают
                        аргументы в диапазон, а : включает.
                      
ext_addrsrc_addr и dst_addr, кроме таблиц,
                отрицаний с помощью ! и
                ключевого слова any. Нельзя
                использовать модификатор :broadcast.
              pool_typestatic-portВ большинстве случаев для NAT трансляции годится примерно такая строка:
nat on tl0 from 192.168.1.0/24 to any -> 24.5.0.5
            Это правило указывает, что надо осуществить NAT трансляцию на интерфейсе tl0 для каждого пакета пришедшего из сети 192.168.1.0/24 подменив адрес источника на 24.5.0.5.
Предыдущая строка корректна, но рекомендуется для облегчения поддержки брандмауэра использовать другую форму записи (в примере dc0 внутренний интерфейс, а tl0 внешний):
nat on tl0 from dc0:network to any -> tl0
            
            При использовании имени интерфейса, как указано выше,
            адрес будет определён и подставлен когда
            pf.conf загружается, но не на лету.
            Это может вызвать проблемы, если адрес интерфейсу
            присваивается по DHCP и меняется во время работы.  Чтобы
            избежать этой проблемы надо указывать адрес интерфейса в
            круглых скобках.
          
nat on tl0 from dc0:network to any -> (tl0)
            Трансляция работает как для IPv4 так и для IPv6.
            Соответствия между двумя хостами 1:1 можно достичь при
            помощи правила binat. Это
            правило ставит в соответствие один IP адрес другому. Это
            можно использовать, например, для того, чтобы предоставить
            доступ к web-серверу во внутренней сети по внешнему
            IP-адресу. Соединения из Интернета к внешнему адресу шлюза
            будут перенаправлены на внутренний web-сервер, а
            соединения от сервера (например DNS запросы) будут
            превращены в запросы шлюза. binat никогда не меняет номера
            портов TCP и UDP.
          
Пример:
web_serv_int = "192.168.1.100"
web_serv_ext = "24.5.0.6"
binat on tl0 from $web_serv_int to any -> $web_serv_ext
            
            Можно сделать исключения из трансляции при помощи
            ключевого слова no. Например,
            правила NAT трансляции из примера выше можно изменить
            следующим образом:
          
no nat on tl0 from 192.168.1.208 to any
nat on tl0 from 192.168.1.0/24 to any -> 24.2.74.79
            Вся сеть 192.168.1.0/24 будет транслироваться к адресу 24.2.74.79, кроме пакетов идущих от хоста 192.168.1.208.
            Здесь первое правило выигрывает. Если
            есть ключевое слово no
            трансляция не производится. Ключевое слово no можно употреблять с правилами
            binat и rdr.
          
            Чтобы увидеть состояния соединений подвергаемых NAT
            трансляции можно воспользоваться командой
            pfctl(8) с аргументом
            -s state.
          
# pfctl -s state
fxp0 TCP 192.168.1.35:2132 -> 24.5.0.5:53136 -> 65.42.33.245:22 TIME_WAIT:TIME_WAIT
fxp0 UDP 192.168.1.35:2491 -> 24.5.0.5:60527 -> 24.2.68.33:53   MULTIPLE:SINGLE
            Этот отчёт (первая срока) означает следующее:
Если у вас работает NAT, вам доступен весь Интернет, но как быть если за шлюзом с NAT, в приватной сети находится машина доступ к которой нужен снаружи? Здесь нам поможет проброс портов. С его помощью мы можем перенаправлять входящий трафик на машину расположенную за шлюзом с NAT.
Пример:
rdr on tl0 proto tcp from any to any port 80 -> 192.168.1.20
            С помощью этого правила все обращения к 80 порту будут пробрасываться на машину 192.168.1.20. (В Linux netfilter это действие называется DNAT, так как у пакета подменяется не source IP, а destination IP.)
            Директива from any to any
            полезна, но если вы знаете из какий сетей будут приходить
            запросы, вы можете сузить правило:
          
rdr on tl0 proto tcp from 27.146.49.0/24 to any port 80 -> \
   192.168.1.20
            Таким образом, можно пробросить только некоторую подсеть. Данный подход позволяет так же пробрасывать разные подсети на разные хосты. Мы можем использовать это свойство для того, чтобы давать пользователям доступ к их компьютерам в локальной сети на основании адреса с которого они обращаются к шлюзу:
rdr on tl0 proto tcp from 27.146.49.14 to any port 80 -> \
   192.168.1.20
rdr on tl0 proto tcp from 16.114.4.89 to any port 80 -> \
   192.168.1.22
rdr on tl0 proto tcp from 24.2.74.178 to any port 80 -> \
   192.168.1.23
            Так же можно пробрасывать диапазоны портов:
rdr on tl0 proto tcp from any to any port 5000:5500 -> \ 192.168.1.20rdr on tl0 proto tcp from any to any port 5000:5500 -> \ 192.168.1.20 port 6000
rdr on tl0 proto tcp from any to any port 5000:5500 -> \ 192.168.1.20 port 7000:*
![]()
Транслированные пакеты, как и в случае с NAT, направляются на правила фильтра и могут быть как приняты, так и отброшены.
            Единственное исключение: если в правиле rdr присутствует ключевое слово pass. В этом случае пакет не
            направляется в фильтр. Вы можете считать, что это такой
            короткий способ записать два правила, в одном из которых
            осуществляется трансляция, а в другом употребляется ключевое
            слово pass с keep state. Однако, если вы хотите
            использовать какие-то другие возможности пакетного фильтра,
            например modulate state или synproxy state, вам придётся
            расписывать это подробно, т.е. rdr
              pass в этом случае не подходит.
          
Кроме того, имейте в виду, что на фильтр пакеты посылаются после трансляции.
Рассмотрим следующий сценарий:
Правило перенаправления:
rdr on tl0 proto tcp from 192.0.2.1 to 24.65.1.13 port 80 \
   -> 192.168.1.5 port 8000
            Вид пакета перед трансляцией:
Вид пакета после трансляции:
Правила фильтра увидят что пакет идёт на машину 192.168.1.5 на порт 8000
Создание подобных отверстий в брандмауэре связано с уменьшением безопасности системы. Например, если у вас во внутренней сети находится web-сервер и вы пропустили на него трафик из Интернет, то злоумышленник может используя уязвимости в работе web-сервера или CGI сценария, получить доступ к web-серверу и, таким образом, проникнет в защищённую вами локальную сеть.
Снизить риск возникновения подобной ситуации можно путём построения демилитаризованной зоны DMZ (см. DMZ).
Перенаправление часто используется для предоставления доступа внешним машинам к внутреннему серверу:
server = 192.168.1.40
rdr on $ext_if proto tcp from any to $ext_if port 80 -> $server \
   port 80
            
            Однако при тестировании правил перенаправления из внутренней
            сети они не работают. Дело в том, что пакеты из внутренней
            сети не проходят через внешний интерфейс шлюза ($ext_if в примере) и потому не
            подвергаются трансляции.
          
            Добавление второго rdr правила не
            спасает ситуацию: пакет проходит через внутренний интерфейс,
            ему заменяют адрес назначения и он направляется на сервер,
            однако исходящий адрес при этом не исправляется и поэтому
            сервер будет овечать непосредственно клиенту минуя шлюз.
            Клиент при этом ждёт ответа от шлюза, а не от сервера. Таким
            образом, соединение так и не будет установлено.
          
И всё таки желательно из внутренней сети видеть сервер так же как он виден из внешней и так, чтобы для клиента всё было прозрачно. Существует несколько способов решения этой проблемы.
Сервер DNS можно настроить так, что он будет давать разные ответы в разные сети. Можно сделать так, чтобы локальные клиенты ходили на сервер непосредственно, без помощи шлюза. Такое решение, к тому же, снижает нагрузку на шлюз.
Можно переместить сервер в отдельную сеть (см. так же DMZ) и добавить новый сетевой интерфейс в шлюз.
              Можно произвести проксирование TCP соединений при помощи
              приложений из userspace. Приложение перехватывает
              соединение, устанавливает соединение с сервером и далее
              пробрасывает данные через себя. Простейший пример можно
              сделать при помощи inetd(8) (см. Раздел 5.17.2, «Суперсервер inetd(8)»)и nc(1) (см.
              Раздел 6.4.4, «telnet(1), nc(1)»). Следующая строка в
              /etc/inetd.conf(5) создаёт сокет
              привязанный к кольцевому интерфейсу, порт номер 5000.
              Соединение пробрасывается на 80-й порт машины
              192.168.1.10:
            
127.0.0.1:5000 stream tcp nowait nobody /usr/bin/nc nc -w 20 192.168.1.10 80
              Теперь на внутреннем интерфейсе мы можем связать 80-й порт с нашим proxy-сервером:
rdr on $int_if proto tcp from $int_net to $ext_if port 80 -> \
   127.0.0.1 port 5000
              И наконец, в комбинации с правилом NAT можно достичь того, что трансляция адресов источника так же будет осуществляться и соединение будет устанавливаться ожидаемым образом.
rdr on $int_if proto tcp from $int_net to $ext_if port 80 -> $server 
no nat on $int_if proto tcp from $int_if to $int_net
nat on $int_if proto tcp from $int_net to $server port 80 -> $int_if
              
              Эти правила приведут к тому, что первый пакет поступивший
              от клиента будет  заново транслирован, когда будет
              отправлен через внутренний интерфейс, при этом у него
              будет подменён адрес источника на внутренний адрес шлюза.
              Внутренний сервер ответит шлюзу, который вернёт адреса
              обратно благодаря NAT и RDR трансляциям и пакет отправится
              к клиенту. Это достаточно сложный приём. Нужна
              осторожность, чтобы не применить правила NAT к другому
              трафику, например к внешним соединениям (прошедшим через
              другие правила rdr) или к
              соединениям самого шлюза. Так же имейте ввиду, что это
              преобразование приводит к тому, что TCP/IP стек видит
              данные пакеты, полученные внутренним интерфейсом, как
              направляющиеся внутрь сети.
            
Авторы документации к пакетному фильтру рекомендуют в общем случае использовать какое-нибудь из предыдущих решений вместо последнего.
          Пакетный фильтр предоставляет различные способы упрощения
          конфигурационного файла. Хорошим примером является
          использование списков и
            макросов. Вдобавок язык и грамматика
          pf.conf(5) весьма гибки и позволяют в
          ряде случаев опускать ключевые слова и употреблять их в разном
          порядке, таким образом администратор не обязан зубрить
          синтаксис файла pf.conf(5). В целом можно
          сказать, что чем проще правила, тем проще осуществлять
          поддержку брандмауэра.
        
            Макросы полезны так как позволяют использовать понятные
            имена вместо имён интерфейсов и адресов. Если меняется IP
            адрес сервера можно просто переопределить макрос вместо
            того, чтобы переписывать весь файл. Аналогичные соображения
            касаются имён интерфейсов. Макросы позволяют упростить
            модифицирование pf.conf(5) в случае
            замены сетевой карты или при необходимости переноса одного и
            того же файла с одной машины на другую.
          
Пример:
# define macros for each network interface
IntIF = "dc0"
ExtIF = "fxp0"
DmzIF = "fxp1" 
# define our networks
IntNet = "192.168.0.0/24"
ExtAdd = "24.65.13.4"
DmzNet = "10.0.0.0/24"
            Если в LAN появятся новые сети, или сети будут перенумерованы, достаточно будет поменять одну строку:
IntNet = "{ 192.168.0.0/24, 192.168.1.0/24 }"
            Теперь после перезагрузки правил всё будет работать по-прежнему.
Следующие 8 строк служат для того, чтобы блокировать трафик связанный с приватными сетями, описаными в [RFC-1918], Нахождение таких пакетов в глобальной сети может вызвать проблемы.
block in  quick on tl0 inet from 127.0.0.0/8 to any
block in  quick on tl0 inet from 192.168.0.0/16 to any
block in  quick on tl0 inet from 172.16.0.0/12 to any
block in  quick on tl0 inet from 10.0.0.0/8 to any
block out quick on tl0 inet from any to 127.0.0.0/8
block out quick on tl0 inet from any to 192.168.0.0/16
block out quick on tl0 inet from any to 172.16.0.0/12
block out quick on tl0 inet from any to 10.0.0.0/8
            Упростим эти правила при помощи списков:
block in  quick on tl0 inet from { 127.0.0.0/8, 192.168.0.0/16, \
   172.16.0.0/12, 10.0.0.0/8 } to any
block out quick on tl0 inet from any to { 127.0.0.0/8, \
   192.168.0.0/16, 172.16.0.0/12, 10.0.0.0/8 }
            Ещё лучше, если мы сделаем это с использованием макросов:
NoRouteIPs = "{ 127.0.0.0/8, 192.168.0.0/16, 172.16.0.0/12, \
   10.0.0.0/8 }" 
ExtIF = "tl0"
block in  quick on $ExtIF from $NoRouteIPs to any
block out quick on $ExtIF from any to $NoRouteIPs
            
            Заметьте, что макросы и списки упрощают файл
            pf.conf, однако предыдущие строки всё
            равно раскрываются в те же 8 правил.
          
Макросы можно использовать не только для хранения адресов, интерфейсов и портов, но вообще везде:
pre = "pass in quick on ep0 inet proto tcp from "
post = "to any port { 80, 6667 } keep state"
# David's classroom
$pre 21.14.24.80 $post
# Nick's home
$pre 24.2.74.79 $post
$pre 24.2.74.178 $post
            Эти правила раскрываются в следующие:
pass in quick on ep0 inet proto tcp from 21.14.24.80 to any \
   port = 80 keep state
pass in quick on ep0 inet proto tcp from 21.14.24.80 to any \
   port = 6667 keep state
pass in quick on ep0 inet proto tcp from 24.2.74.79 to any \
   port = 80 keep state
pass in quick on ep0 inet proto tcp from 24.2.74.79 to any \
   port = 6667 keep state
pass in quick on ep0 inet proto tcp from 24.2.74.178 to any \
   port = 80 keep state
pass in quick on ep0 inet proto tcp from 24.2.74.178 to any \
   port = 6667 keep state
            Пакетный фильтр обладает гибкой в тоже время человечной грамматикой. Нет необходимости строго помнить порядок ключевых слов и строго придерживаться какого-то определённого стиля.
Для определения политики отбрасывающей по умолчанию пакеты, следует задать два правила:
block in  all
block out all
              Это можно сократить до
block all
              Когда направление не указано, пакетный фильтр считает, что пакеты следуют в обе стороны.
              Аналогично можно не писать from any to
                any и all, например:
            
block in on rl0 all
pass  in quick log on rl0 proto tcp from any to any port 22 keep state
              Можно упростить до
block in on rl0
pass  in quick log on rl0 proto tcp to port 22 keep state
              Первое правило блокирует все пакеты входящие через интерфейс rl0. Второе пропускает входящие пакеты, если они идут на 22-й порт.
Правила блокирующие пакеты и отсылающие пакеты TCP RST и ICMP Unreachable должны выглядеть так:
block in all
block return-rst in proto tcp all
block return-icmp in proto udp all
block out all
block return-rst out proto tcp all
block return-icmp out proto udp all
              Их можно упростить до одной строки:
block return
              
              Когда пакетный фильтр видит ключевое словоreturn, он сам догадывается на
              какой протокол каким пакетом следует отвечать, а на какие
              протоколы вообще не следует посылать никакого ответа при
              блокировании соединений.
            
Порядок следования ключевых слов в большинстве случаев гибок. Например, следующее правило:
pass in log quick on rl0 proto tcp to port 22 \
   flags S/SA keep state queue ssh label ssh
              Можно переписать так:
pass in quick log on rl0 proto tcp to port 22 \
   queue ssh keep state label ssh flags S/SA
              Другие похожие варианты тоже будут работать.
          Опции в pf.conf(5) устанавливаются при
          помощи директивы set.
        
![]()  | Замечание | 
|---|---|
| Начиная с OpenBSD 3.7 сменилось поведение пакетного фильтра относительно опций: раньше, если опция устанавливалась, она уже никогда не принимала своего значения по умолчанию. Теперь, опция принимает значение по умолчанию, если её удаляют из правил, а затем перезагружают правила. | 
Пример задания опций в пакетном фильтре:
set timeout interval 10
set timeout frag 30
set limit { frags 5000, states 2500 }
set optimization high-latency
set block-policy return
set loginterface dc0
set fingerprints "/etc/pf.os.test"
set skip on lo0
set state-policy if-bound
          set block-policy optionУстановить поведение по умолчанию для правил фильтра, когда срабатывает правило block. Возможные варианты:
drop — пакет
                  молча отбрасывается;
                return — для
                  отброшенных пакетов TCP отсылается пакет TCP RST, для
                  прочих ICMP Unreachable.
                
                В конкретных правилах значение опции может быть
                переопределено. Умолчание —
                drop
              
set debug optionУстановить уровень отладки для пакетного фильтра:
none — не
                  показывать отладочных сообщений;
                urgent —
                  отладочные сообщения показываются для серьёзных
                  ошибок.
                misc —
                  отладочные сообщения выводятся для различных ошибок
                  (помогает узнать состояние системы нормализации
                    трафика (scrub) и ошибки в работе таблицы
                  состояний);
                loud —
                  Отладочные сообщения общего плана (позволяет изучать
                  сообщения от системы osfp).
                
                Умолчание — urgent. Уровень
                отладки можно также изменять при помощи команды
                pfctl(8) (опция -x,
                см. Раздел C.3, «Управление пакетным фильтром OpenBSD
      при помощи утилиты pfctl(8)»).
              
set fingerprints file/etc/pf.os.
            set limit option valueУстановить предел для различных опций:
frags —
                  Максимальное количество записей в пуле отвечающем за
                  нормализацию
                    трафика (scrub). По умолчанию —
                  100.
                src-nodes —
                  Максимальное количество записей в пуле отвечающем за
                  отслеживание исходящих IP адресов. (Пул генерируется
                  правилами с ключевыми словами
                  sticky-addressи
                  source-track).
                  Умолчание — 10000.
                states —
                  Максимальное количество вхождений в пул отвечающий за
                  состояние таблицы состояний соединений (Которая
                  заводится при помощи правил с ключевой фразой
                  keep state, см.
                  Раздел C.2.1.4, «Фильтрация пакетов»). Умолчание
                  10000.
                
                Допустим синтаксис: set limit {
                  states 20000, frags 20000, src-nodes 2000 }
              
set loginterface interface
                Задать интерфейс для которого пакетный фильтр собирает
                статистическую информацию: количество прошедших пакетов,
                количество заблокированных пакетов, сколько байт вошло,
                сколько вышло. Статистику можно собирать одновременно
                только на одном интерфейсе.  При этом, счётчики match, bad-offset и т.п., а также
                счётчики в таблице состояний, работают независимо от
                этой опции.  Чтобы отключить сбор статистики следует
                выставить опцию в none. Значение по
                умолчанию — none.
              
                Просмотреть статистику можно при помощи команды
                pfctl(8) с опцией
                -s info.
                См. Пример C.1, «Просмотр статистики на интерфейсе выбранном при помощи
          опции loginterface»
              
set releset-optimization value
                Это усовершенствование введено в
                OpenBSD 4.1 и пока ещё нигде не
                внедрено. Оптимизацию теперь можно задавать
                непосредственно в pf.conf(5), а не
                только как опцию pfctl(8) (см. Раздел C.3, «Управление пакетным фильтром OpenBSD
      при помощи утилиты pfctl(8)», опция -o).
              
                value может принимать следующие
                значения:
              
nonebasicВыполняет следующую оптимизацию: 1) удаляет дублирующиеся правила; 2) удаляет правила, являющиеся подмножеством других правил; 3) объединяет несколько правил в таблицу, где это возможно; 4) пересортирует правила для лучшей производительности.
                      То же достигается указанием опции
                      -o команды
                      pfctl(8).
                    
profilequick.
                      Того же эффекта можно добиться при помощи двух
                      опций -oo в программе
                      pfctl(8).
                    
                При оптимизации может измениться порядок правил, что
                может привести к нарушению в работе биллинговой системы.
                Для предотвращения оптимизации можно расставлять в
                правилах метки label.
              
set optimization valueУстановить оптимизацию пакетного фильтра для различного поведения сети:
normal —
                  подходит ко всем сетям.
                high-latency —
                  подходит для сетей работающих с большими задержками,
                  например через спутник.
                aggressive —
                  агрессивно очищать таблицу состояний. Это может
                  существенно уменьшить требования к памяти на
                  загруженном брандмауэре, однако связано с риском
                  преждевременного разрыва соединений.
                conservative —
                  крайне консервативный брандмауэр. Предотвращает разрыв
                  соединений, однако приводит к большому расходу памяти.
                
                Умолчание —normal
              
set skip on interfaceset state-policy valueПоведение пакетного фильтра при использовании таблицы состояний (см. Раздел C.2.1.4, «Фильтрация пакетов»). Это поведение может быть переопределено в конкретных правилах фильтрации:
if-bound — Состояние
                  привязывается к конкретному интерфейсу, через который
                  прошёл первый пакет. Если ответ пришёл через другой
                  интерфейс, он не будет соответствовать данному
                  соединению.
                group-bound — то же, но
                  привязано к группе интерфейсов (в
                  OpenBSD, но не в
                  FreeBSD, интерфейсы можно объединять
                  в группы).
                floating — Записи в
                  таблице состояний не привязаны к интерфейсам.
                
                Умолчание — floating
              
set timeout option valueЗадаёт таймауты в секундах:
intervalinterval секунд, прежде
                    чем запись будет удалена из
                    таблицы состояний.  Умолчание —
                    10fragment30.
                  src.track0.
                  proto.modifier
                      Время в течение которого в таблице состояний
                      хранится запись о коннекте. Здесь
                      proto может быть
                      tcp, udp,
                      icmp или что-то (здесь
                      other), а
                      modifier указывает на состояние
                      коннекта. Конкретнее:
                    
TCP:
tcp.firsttcp.openingtcp.establishedtcp.closingtcp.finwaittcp.closedUDP:
udp.firstudp.singleudp.multipleICMP:
icmp.firsticmp.error
                      Прочие протоколы обрабатываются как и
                      UDP:
                      other.first,
                      other.single,
                      other.multiple
                    
set adaptive.start valueadaptive.end -
                    количество_записей_в_табилце_состояний) /
                    (adaptive.end -
                     adaptive.start)
                  set adaptive.end value
                Пример: пусть в pf.conf(5)
                написано:
              
set timeout tcp.first 120
set timeout tcp.established 86400
set timeout { adaptive.start 6000, adaptive.end 12000 }
set limit states 10000
                
                Тогда, если количество записей в таблице сотояний
                достигло 9000, то все таймауты будут уменьшены на 50%, в
                частности tcp.first будет равен 30
                секунд, а tcp.established 43200 секунд.
              
Нормализация трафика нужна для того, чтобы исключить неопределённость с тем куда направляется пакет. Кроме того, при нормализации собираются вместе фрагментированные пакеты, происходит защита операционных систем от некоторого вида атак и отбрасываются TCP пакеты с невозможным сочетанием флагов. Простейшая директива выглядит так:
scrub in all
          Это приводит к нормализации всего входящего трафика на всех интерфейсах.
          Одна из возможных причин для неиспользования
          нормализации — использование NFS. Некоторые не
          OpenBSD платформы используют странные
          пакеты — фрагментированные, но с выставленным
          битом «нефрагментировано», которые должны
          отбрасываться пакетным фильтром при нормализации. Эту проблему
          можно разрешить при использовании опции
          no-df. Другая причина может состоять в том,
          что некоторые многопользовательские сетевые игры блокируются
          пакетным фильтром с запущенным нормализатором. Во всех
          остальных случаях, кроме приведённых весьма необычных
          ситуаций, нормализация трафика крайне желательна.
        
          Синтаксис директивы scrub весьма напоминает
          синтаксис правил фильтрации (см. Раздел C.2.1.4, «Фильтрация пакетов»). Как и в случае с NAT
          трансляцией, первое правило выигрывает.
          Перед директивой scrub можно употреблять
          ключевое слово no, чтобы указанные пакеты не
          нормализовались.
        
Scrub имеет следующие опции:
no-dfrandom-id.
            random-idmin-ttl nummax-mss numfragment reassemblefragment cropfragment crop, второе —
              fragment drop-ovl. В обоих случаях пакеты
              не буферизируются как в случае fragment
                reassemble.
            fragment drop-ovlreassemble tcp
                Нормализация соединений TCP на основе таблицы состояний.
                При использовании данной опции нельзя указывать
                направление in/out.
                Осуществляется следующая нормализация:
              
Пример:
scrub in on fxp0 all fragment reassemble min-ttl 15 max-mss 1400
scrub in on fxp0 all no-df
scrub    on fxp0 all reassemble tcp
          ![]()  | Замечание | 
|---|---|
| Все мои попытки перевести это слово на руссий язык увенчались неудачей. Смысл при переводе полностью утрачивается, поэтому я буду употреблять слово anchor. Если что, то дословный перевод — якорь. Смысл примерно такой: якорь — это место куда подгружается поднабор правил и одновременно якорь это имя поднабора. Данный здесь текст частично основан на переводе выполненном Михаилом Сгибневым. Михаил словом «якорь» называл точку привязки правил, а поднабор правил Михаил называл «именованный поднабор правил». Я сохранил этот стиль в данном подразделе. | 
Вдобавок к обычным наборам правил пакетный фильтр может использовать поднаборы. Если таблицы можно использовать для динамической смены на лету наборов IP-адресов, то поднаборы правил можно использовать для динамического переконфигурирования брандмауэра. С их помощью можно менять наборы правил фильтра, nat, binat и rdr.
Поднаборы правил можно объявлять при помощи «якорей», — anchor Существует четыре типа anchor'ов:
anchor name — выполняются все
            правила фильтра из
            набора name;
          binat-anchor name — выполняются все
            правила binat трансляции из
            набора name;
          nat-anchor name — выполняются все
            правила nat трансляции из
            набора name;
          rdr-anchor name — выполняются все
            правила перенаправления из
            набора name;
          
          Поднаборы могут быть вложенными и вызывать друг друга по
          цепочке. Правила anchor обрабатываются в том месте, где они
          вызываются. Например, правило anchor в
          основном конфигурационном файле создаёт поднабор, родителем
          которого являентся главный набор правил, другие поднаборы
          загружаемые в данном поднаборе при помощи директивы
          load anchor являются его потомками.
        
Именованный набор — это группа правил фильтрации, и/или правил трансляции, которым было назначено имя. Когда пакетный фильтр обнаруживает якорь в главном наборе правил, он производит проверку всех поднаборов правил привязанных к нему.
Пример:
ext_if = "fxp0"
block on $ext_if all
pass  out on $ext_if all keep state
anchor goodguys
            
            Этот набор правил устанавливает по умолчанию запретительную
            политику на интерфейсе fxp0 для
            всего входящего и исходящего трафика. Разрешается весь
            исходящий трафик и подгружается именованный набор правил
            goodguys.  Якоря могут быть связаны с правилами двумя
            методами:
          
loadЗагрузка правил указывает pfctl(8) загрузить правила из текстового файла. Например:
load anchor goodguys:ssh from "/etc/anchor-goodguys-ssh"
            
            Когда будет загружен главный набор, правила, перечисленные в
            файле /etc/anchor-goodguys-ssh будут
            загружены в именованный набор ssh, ассоциированный с якорем goodguys. 
          
Используя pfctl(8) можно добавить правило к якорю:
# echo "pass in proto tcp from 192.0.2.3 to any port 22" | pfctl -a goodguys:ssh -f -
            
            Таким образом, мы добавляем правило pass к именованному набору ssh связанному с якорем goodguys. Пакетный фильтр будет
            проверять эти правила, когда доберётся до якоря goodguys.
          
Правила также могут быть сохранены и загружены из текстового файла:
#cat >> /etc/anchor-goodguys-www pass in proto tcp from 192.0.2.3 to any port 80 pass in proto tcp from 192.0.2.4 to any port { 80 443 }#pfctl -a goodguys:www -f /etc/anchor-goodguys-www
            Эта операция загрузит правила из файла
            /etc/anchor-goodguys-www в именованый
            набор правил www якоря
            goodguys. 
          
Поскольку наборы правил могут быть вложенными, существует возможность вызвать все правила вложенные в некоторый набор:
anchor "spam/*"
            Синтаксис правил в подгружаемых наборах правил такой же как и в главном наборе правил, но все используемые макросы должны быть определены в пределах этого же набора: макросы, определённые в главном наборе не видны из именованного набора.
Каждый именованный набор существует обособленно от остальных. Операции, проводимые над ним, такие как сброс правил, не имеют эффекта над остальными. Кроме того, удаление указателя на якорь не приводит к удалению ни самого якоря ни привязанных к нему именованных наборов правил. Именованный набор существует до тех пор, пока все его правила не будут сброшены, используя pfctl(8). Якорь уничтожается как только не остается ни одного привязанного к нему набора правил.
            Правило anchor позволяет так же
            указать интерфейс, протокол, адреса источника и назначения и
            прочее. Синтаксис аналогичен синтаксису правил фильтрации.
            Если эта информация есть, то набор правил соответствующих
            якорю используется для пакета только данные критерии
            удовлетворены:
          
ext_if = "fxp0"
block on $ext_if all
pass  out on $ext_if all keep state
anchor ssh in on $ext_if proto tcp from any to any port 22
            
            Правила из якоря ssh будут
            использоваться только если пакет был TCP и пришёл на 22-й
            порт через интерфейс fxp0.
            Правила к якорю могут добавляться так: 
          
# echo "pass in from 192.0.2.10 to any" | pfctl -a ssh:allowed -f -
            Несмотря на то, что в правиле не определён ни порт, ни протокол, ни интерфейс, хосту 192.0.2.10 будет разрешена работа только по протоколу ssh, в силу определений сделанных при объявлении якоря.
Управление именованными наборами правил осуществляется при помощи утилиты pfctl(8). Она позволяет удалять и добавлять правила в набор без перезагрузки главного набора правил.
            Вывести список правил из набора ssh:
          
# pfctl -a ssh -s rules
            
            Сбросить набор правил ssh:
          
# pfctl -a ssh -F rules
            Поставить что-то в очередь, значит сохранить это до обработки. При работе в сети, данные получаемые хостом поступают в очередь и ждут, когда они будут обработаны операционной системой, при этом она решает, какие именно пакеты и в каком порядке обрабатывать. Изменение порядка обработки пакетов может оказать влияние на производительность сети. В идеальном случае, пакеты ssh должны обрабатываться в первую очередь, так как этот протокол очень чувствителен к задержкам. При нажатии клавиши в ssh-клиенте ожидается немедленный ответ, но идущая передача по ftp вызывает задержку в несколько секунд. Что может произойти в случае, когда роутер обрабатывает большое количество ftp пакетов? Пакеты ssh сохраняются в очереди, а то и просто отбрасываются в случае малого буфера и в результате ssh сессия может вообще прерваться. Изменение стратегии организации очередей может позволить распределить пропускную способность между различными приложениями, пользователями и хостами.
Обратите внимание, что организация очереди имеет смысл только для исходящих соединений, потому что как только пакет попал на входящий интерфейс с ним уже поздно что-либо делать, так как полоса пропускания канала была уже использована. Единственным решением этой проблемы может стать организация очереди на смежном маршрутизаторе или позволять организацию очереди на внутреннем интерфейсе, если хост сам является смежным маршрутизатором.
Планировщиком называется то, что организовывает очередь и определяет порядок обработки пакетов. По умолчанию в OpenBSD в качестве планировщика используется FIFO, очередь. Принцип её работы очень прост — первый вошёл — первый вышел. Новоприбывший пакет добавляется в конец очереди. При превышении максимального размера очереди пакет отбрасывается. Это явление известно как tail-drop (отброс хвоста, как у ящерицы).
Есть и другие планировщики. OpenBSD (и FreeBSD) поддерживает ещё три планировщика:
В очередях базирующиеся на классах (CBQ) алгоритм организации очереди построен на разделении полосы пропускания между различными очередями или классами. Трафик присоединяется к очереди на основании адреса источника или отправителя, порта, протокола и т.д. Очередь может быть сконфигурирована на заимствование произвольной полосы пропускания от родительской очереди, если та занимает свой канал не полностью. Очереди также могут работать с системой приоритетов, например, пропуская ssh трафик в первую очередь, по сравнению с трафиком ftp.
В CBQ очереди размещаются иерархическим способом. В самом верху — родительская очередь, определяющая общую пропускную способность. Дочерним очередям назначается некоторая часть от полосы пропускания родительской очереди. Например, очереди могут быть определены следующим способом:
Root Queue (2Mbps)
   Queue A (1Mbps)
   Queue B (500kbps)
   Queue C (500kbps)
              Здесь общая полоса пропускания — 2 мегабита в секунду (megabits per second — Mbps), Которая разделена на три подочереди.
![]()  | Замечание | 
|---|---|
| Полосу пропускания обычно измеряют в битах в секунду. При этом 1000 bps = 1 kbps, 1000 kbps = 1 Mbps. 1 Mbps = 125000 байт в секунду или 122 килобайта в секунду. | 
Иерархия может быть расширена с использованием вложенности. Для того, чтобы разделить полосу пропускания между различными пользователями, при этом сделав так, что бы различные виды трафика не мешали друг другу, можно создать следующую структуру очередей:
Root Queue (2Mbps)
   UserA (1Mbps)
      ssh (50kbps)
      bulk (950kbps)
   UserB (1Mbps)
       audio (250kbps)
       bulk (750kbps)
          http (100kbps)
          other (650kbps)
              Обратите внимание, что на каждом уровне сумма полос пропускания не может быть больше родительской.
Очередь может быть настроена таким образом, что будет заимствовать (borrow) полосу пропускания у родителя в случае неиспользования ее другими очередями. Рассмотрим такую организацию очереди:
Root Queue (2Mbps)
   UserA (1Mbps)
      ssh (100kbps)
      ftp (900kbps, borrow)
UserB (1Mbps)
              Если трафик в очереди ftp превышает 900 kbps, а трафик в очереди UserA — меньше чем 1 Mbps (потому что очередь ssh использует меньше чем 100 kbps), полоса пропускания ftp может быть увеличена. Таким образом очередь ftp способна использовать больше чем назначенные ей 900 kbps, но в случае увеличения очереди ssh заимствованая полоса освобождается.
CBQ может назначать каждой группе определённый приоритет. В моменты перегрузки предпочтение отдается очередям с более высоким приоритетом в случае наличия у них одного родителя. При одинаковых приоритетах очереди обслуживаются циклически. Для примера:
Root Queue (2Mbps)
  UserA (1Mbps, priority 1)
     ssh (100kbps, priority 5)
     ftp (900kbps, priority 3)
UserB (1Mbps, priority 1)
              Очереди UserA и UserB будут обрабатываться циклически, так как их приоритеты равны. В случае перегрузки в сети, предпочтение будет отдаваться ssh, так как её приоритет больше, чем у очереди ftp. При этом очереди ssh и ftp не имеют приоритета перед очередями UserA и UserB, так как они находятся на более низком уровне.
Детальная информация о CBQ приведена в References on CBQ.
Приоритетные очереди (PRIQ) создаются на сетевом интерфейсе, причем структура очередей является плоской — нельзя создавать дочерние очереди. Сперва определяется корневая очередь с указанием общей пропускной способности, а за ней все дочерние очереди. Например:
Root Queue (2Mbps)
   Queue A (priority 1)
   Queue B (priority 2)
   Queue C (priority 3)
              Пропускная способность основной очереди определена как 2 Mbps, следом идут дочерние.
При использовании PRIQ вы должны очень тщательно планировать очереди, так как они обрабатываются строго по приоритетам и если трафик с высоким приоритетом займёт весь канал, пакеты принадлежащие трафику с низким приоритетом будут отбрасываться.
Очереди закреплённые за интерфейсом выстраиваются в иерархическое древо, каждая очередь может иметь потомка. Каждая очередь может иметь свой приоритет и свою полосу пропускания. Этот вид очереди похож на CBQ. Основное отличие HFSC от CBQ в том, что она позволяет отдельно регулировать задержки и пропускную способность очереди.
В CBQ единственный параметр очереди это полоса пропускания. Если мы нарисуем «кривую сервиса» (прохождение пакетов по времени), то это будет некоторая прямая. Единственный способ снизить задержки при работе такой очереди состоит в том, чтобы увеличить полосу пропускания.
В HFSC кривая сервиса состоит из двух линейных участков:

Дополнительная информация о HFSC может быть найдена по адресу http://www.cs.cmu.edu/~hzhang/HFSC/main.html.
Случайное раннее обнаружение (Random Early Detection, RED) — это алгоритм определения перегрузки канала. Его целью является предотвращение переполнения очереди. Делается это путём непрерывного сравнения текущей длины очереди с минимальным и максимальным порогами. Если минимальный порог не достигнут — все пакеты пропускаются. Если достигнут максимальные порог — все пакеты отбрасываются. В промежутке пакеты отбрасываются с определённой вероятностью, зависящей от размера очереди. Чем ближе к максимальному порогу — тем выше вероятность. Пакеты для отбрасывания выбираются случайным образом из разных сессий. Чем большая полоса пропускания занимается сессией, тем выше вероятность сброса из неё пакета.
RED весьма полезен, так как позволяет избежать ситуации, называемой «глобальной синхронизацией», она проявляется в том, что связь полностью прекращается из-за одновременно отбрасываемых пакетов с разных сессий. Например, если перегрузка происходит на маршрутизаторе, обслуживающем 10 одновременных сессий ftp и будут отброшены пакеты от большинства или всех сессий, общая пропускная способность резко понизится. RED позволяет избежать этого, выбирая сессии из которых терять пакеты случайным образом. Поскольку сессии занимающие больше полосы пропускания имеют больший шанс на потерю пакета, то возможность возникновения перегрузки исчезнет и больших потерь трафика не произойдет. Кроме того, RED позволяет обработать взрывной всплеск трафика, так как начинает отбрасывать пакеты до переполнения очереди.
RED должен использоваться только тогда, когда транспортный протокол способен реагировать на индикаторы перегрузки сети. В большинстве случаев это означает, что RED должен применяться только к очередям TCP, а не к очередям UDP или ICMP.
Детальная информация о RED приведена в References on RED.
Явное уведомление о перегрузке (ECN) работает совместно с RED и применяется для уведомления двух связанных хостов о перегрузке сети. Делается это разрешением RED установить флаг в заголовке пакета, вместо того, чтобы отбросить пакет. Если удалённый хост поддерживает ECN и читает флаги ECE и CWR, то он начинает снижать исходящий трафик (см. Таблица B.3, «Флаги TCP», [RFC-3168]).
Начиная с OpenBSD 3.0 Alternate Queueing (ALTQ) стал частью основной системы, а с версии OpenBSD 3.3 ALTQ был интегрирован в пакетный фильтр и, следовательно, портирован вместе с ним и в FreeBSD. Реализация ALTQ в OpenBSD поддерживает планировщики CBQ PRIQ и RED вместе с ECN.
            Очереди конфигурируются в файле
            /etc/pf.conf(5). Есть два типа
            директив, которые используются для конфигурирования
            очередей:
          
altq onqueue
            Синтаксис директивы altq:
          
altq on interface scheduler bandwidth bw qlimit qlim \
   tbrsize size queue { queue_list }
            interfaceschedulercbq и priq. На интерфейсе в один момент
                времени можно установить только один планировщик.
              bwqlimsizequeue_listПриведённый здесь текст является моим домыслом, и не имеет отношения к оригинальной документации по пакетному фильтру:
При регулировке полосы пропускания иногда применяют концепцию токенов: есть некоторая корзина (bucket) в которую регулярно, скажем раз в секунду, кладут билет (token). Пакет идущий сквозь очередь должен взять билет из корзины и проходить. Если билета в корине нет, пакет отбрасывается, если пакеты через очередь не идут, билеты копятся в корзине, пока она не переполнится.
Таким образом, если корзина очень большая, у нас после паузы в трафике могут наблюдаться резкие всплески. Если корзина маленькая — трафик будет равномерен, но малейшие флуктуации в скорости могут привести к отбросу пакетов.
Вот этот параметр и есть, по-видимому, token bucket regulator.
Итак:
altq on fxp0 cbq bandwidth 2Mb queue { std, ssh, ftp }
            
            Это правило запускает CBQ на интерфейсе
            fxp0, пропускная способность
            канала 2 Mb и создаются три дочерние очереди: std, ssh
            и ftp.
          
            Синтаксис директивы queue:
          
queue name [on interface] bandwidth bw [priority pri] [qlimit qlim] \
   scheduler ( sched_options ) { queue_list }
            namealtq
                опцией queue_list. Для cbq
                это также может быть запись имени очереди в предыдущей
                директиве queue параметре
                queue_list. Имя не должно быть
                длиннее 15 символов.
              interfacebwpriqlimschedulersched_options
дополнительные опции для управления планировщиками:
defaultredrioecnborrowqueue_list
Следующие три опции применяются только для очереди типа HFSC.
realtime <sc>upperlimit <sc>linkshare <sc>
                    Здесь <sc> это
                    сокращение для service curve — кривая
                    сервиса. Кривая состоит из двух линейных участков и
                    описывается тремя числами (m1, d, m2).
                    m1 — начальная полоса пропускания (т.е.
                    наклон первой кривой), d время в течении которого
                    действует первичная полоса пропускания в
                    миллисекундах и m2 — наклон второго
                    линейного участка — т.е. реальная полоса
                    пропускания.
                  
Столь детальное описание кривой сервиса позволяет отдельно регулировать задержки при работе очереди и полосу пропускания, тогда как в CBQ есть только регулировка полосы пропускания и, следовательно, единственный способ снизить задержки состоит в увеличении полосы пропускания.
Продолжение примера:
queue std bandwidth 50% cbq(default)
queue ssh { ssh_login, ssh_bulk }
   queue ssh_login priority 4 cbq(ecn)
   queue ssh_bulk cbq(ecn)
queue ftp bandwidth 500Kb priority 3 cbq(borrow red)
            Здесь определяются дочерние очереди. Очереди std назначается 50% пропускной способности от материнской очереди и она назначается дефолтной. Очередь ssh определяет две дочерние очереди, ssh_login и ssh_bulk. Ssh_login дают более высокий приоритет чем ssh_bulk, и обе работают с ECN. Ftp назначена полоса пропускания в 500 kbps и дан приоритет 3. Эта очередь может арендовать свободную пропускную способность других очередей и используется red.
Для направления трафика в очередь используется ключевое слово queue в правилах пакетного фильтра. Для примера рассмотрим следующую строку:
pass out on fxp0 from any to any port 22
              Пакеты из этого правила можно направить в очередь следующим способом:
pass out on fxp0 from any to any port 22 queue ssh
              
              Если ключевое слово queue
              используется совместно с block,
              все пакеты TCP RST или ICMP Unreachable ставятся в
              указанную очередь.
            
              Обратите внимание, что queue
              может приключиться для другого интерфейса, чем было
              определено директивой altq: 
            
altq on fxp0 cbq bandwidth 2Mb queue { std, ftp }
queue std cbq(default)
queue ftp bandwidth 1.5Mb
pass in on dc0 from any to any port 21 queue ftp
              Очередь определяется на fxp0, но указание на неё встречается на dc0. Если пакет, соответствующий правилу выходит с интерфейса fxp0, то он будет поставлен в очередь ftp. Этот тип очередей может быть очень полезен на маршрутизаторах.
              Обычно с ключевым словом queue
              используется только одно имя очереди, но если определено и
              второе имя, то очередь будет использоваться для пакетов с
              Type of Service (ToS) низкой задержки и для пакетов TCP ACK
              без полезного груза данных. Хороший пример может быть
              найден при использовании ssh: во время открытия сессии ToS
              устанавливается в low-delay пока не откроется сессия SCP
              или SFTP. PF может использовать информацию о находящихся в
              очереди пакетах для того. чтобы отличить пакеты на ввод
              логина от остальных пакетов. Возможно будет полезным
              разнести по приоритетам пакеты авторизации от пакетов
              данных: 
            
pass out on fxp0 from any to any port 22 queue(ssh_bulk, ssh_login)
              Повышение приоритета пакетов TCP ACK имеет смысл на асинхронных соединениях, таких как ADSL, где скорость входящего и исходящего потока не равны между собой. На ADSL линии при полностью занятом исходящем канале будет снижаться и полезное использование входящего канала, так как пакеты TCP ACK будут теряться и задерживаться. Тестирования показали, что для достижения наибольшей эффективности, полоса пропускания должна быть немного меньше, возможностей канала. Например, если ADSL линия дает максимальную скорость в 640 kbps, установите значение пропускной способности для корневой линии в 600 kb. Оптимальное значение находится путем проб и ошибок.
              Когда ключевое слово queue
              используется с правилами keep
                state, пакетный фильтр будет делать запись
              очереди в таблице состояний таким образом, что пакеты с
              fxp0 соответствующие образовавшемуся соединению будут
              оказываться в очереди ssh:
            
pass in on fxp0 proto tcp from any to any port 22 flags S/SA \
   keep state queue ssh
              
              Обратите внимание, что ключевое слово queue применяется к правилам,
              обслуживающим входящий трафик.
            
    [ Alice ]    [ Charlie ]
        |             |                              ADSL
     ---+-----+-------+------ dc0 [ OpenBSD ] fxp0 -------- ( Internet )
              |
           [ Bob ]
            В этом примере OpenBSD используется как шлюз в Интернет для маленькой домашней сети с тремя рабочими станциями. На шлюзе работает NAT и фильтрация пакетов. Выход в Интернет осуществляется по ADSL с входящей скоростью 2Mbps и исходящей 640Kbps.
Для очередей действуют следующие правила:
            Ниже представлены правила, реализующие эту политику.
            Обратите внимание, что в pf.conf не
            представлены правила nat, rdr, options, и т.д.
            непосредственно не имеющие отношения к данной задаче.
          
# Включаем очереди на внешнем интерфейсе для контроля за трафиком
# выходящим в Интернет. Используем планировщик priq для контроля только
# по приоритетам. Устанавливает ширину пропускания 610 kbps для
# оптимального пропускания очереди TCP ACK
altq on fxp0 priq bandwidth 610Kb queue { std_out, ssh_im_out, dns_out, \
    tcp_ack_out }
# определяем параметры дочерних очередей
# std_out      - стандартная очередь. Любые правила ниже, в которых
#                очередь не указана явно, добавляют трафик к этой
#                очереди.
# ssh_im_out   - интерактивный SSH и интернет пейджеры
# dns_out      - запросы DNS
# tcp_ack_out  - пакеты TCP ACK не несущие полезной нагрузки
queue std_out     priq(default)
queue ssh_im_out  priority 4 priq(red)
queue dns_out     priority 5
queue tcp_ack_out priority 6
# Включаем очереди на внутреннем интерфейсе для контроля трафика
# пришедшего из Интернет. Используем планировщик cbq для контроля полосы
# пропускания. Максимальная полоса 2 Mbps.
altq on dc0 cbq bandwidth 2Mb queue { std_in, ssh_im_in, dns_in, bob_in }
# определяем параметры дочерних очередей
# std_in       - стандартная очередь. Любые правила ниже, в которых
#                очередь не указана явно, добавляют трафик к этой
#                очереди.
# ssh_im_in    - интерактивный SSH и интернет пейджеры
# dns_in       - ответы DNS
# bob_in       - Полоса зарезервированная для Боба, разрешаем ему
#                увеличивать полосу по мере возможности (borrow)
queue std_in    bandwidth 1.6Mb cbq(default)
queue ssh_im_in bandwidth 200Kb priority 4
queue dns_in    bandwidth 120Kb priority 5
queue bob_in    bandwidth 80Kb cbq(borrow)
# ... раздел фильтрации ...
alice         = "192.168.0.2"
bob           = "192.168.0.3"
charlie       = "192.168.0.4"
local_net     = "192.168.0.0/24"
ssh_ports     = "{ 22 2022 }"
im_ports      = "{ 1863 5190 5222 }"
# правила фильтрации входящего трафика на fxp0
block in on fxp0 all
# правила фильтрации исходящего трафика на fxp0
block out on fxp0 all
pass  out on fxp0 inet proto tcp from (fxp0) to any flags S/SA \
    keep state queue(std_out, tcp_ack_out)
pass  out on fxp0 inet proto { udp icmp } from (fxp0) to any keep state
pass  out on fxp0 inet proto { tcp udp } from (fxp0) to any port domain \
    keep state queue dns_out
pass  out on fxp0 inet proto tcp from (fxp0) to any port $ssh_ports \
    flags S/SA keep state queue(std_out, ssh_im_out)
pass  out on fxp0 inet proto tcp from (fxp0) to any port $im_ports \
    flags S/SA keep state queue(ssh_im_out, tcp_ack_out)
# правила фильтрации входящего трафика на dc0
block in on dc0 all
pass  in on dc0 from $local_net
# правила фильтрации исходящего трафика на dc0
block out on dc0 all
pass  out on dc0 from any to $local_net
pass  out on dc0 proto { tcp udp } from any port domain to $local_net \
    queue dns_in
pass  out on dc0 proto tcp from any port $ssh_ports to $local_net \
    queue(std_in, ssh_im_in)
pass  out on dc0 proto tcp from any port $im_ports to $local_net \
    queue ssh_im_in
pass  out on dc0 from any to $bob queue bob_in
            
  ( IT Dept )  [ Boss's PC ]
       |          |                                   T1
     --+----+-----+---------- dc0 [ OpenBSD ] fxp0 -------- ( Internet )
            |                         fxp1
         [ COMP1 ]    [ WWW ]         /
                         |           /
                       --+----------'
            В этом примере OpenBSD выступает в роли системы сетевой защиты для корпоративной сети. В компании работает WWW сервер, установленный в DMZ. Клиенты обновляют свои сайты через FTP. У IT одела имеется собственная подсеть, соединённая с главной, босс использует свой компьютер для почты и серфинга по сети. Соединение с Интернетом осуществляется на скорости T1 (1.5 Mbps) в обе стороны. Все прочие сетевые сегменты используют Fast Ethernet (100 Mbps).
Сетевой администратор выбрал следующую политику:
Трафик между WWW сервером и Интернетом ограничивается 500 kbps:
            Ниже представлены правила, реализующие эту политику.
            Обратите внимание, что в pf.conf не
            представлены правила nat, rdr, options, и т.д.
            непосредственно не имеющие отношения к данной задаче.
          
# Включаем очереди на внешнем интерфейсе для пакетов выходящих в
# Интернет. Используем планировщик cbq чтобы контролировать полосу
# пропускания каждой очереди. Максимальная исходящая полоса 1.5 Mbps
altq on fxp0 cbq bandwidth 1.5Mb queue { std_ext, www_ext, boss_ext }
# определяем параметры дочерних очередей
# std_ext        - стандартная очередь. Так же является очередью для
#                  исходящего трафика на интерфейсе fxp0
# www_ext        - контейнер для очередей WWW сервера. Размер 500 kbps
#   www_ext_http - http трафик WWW сервера - высший приоритет
#   www_ext_misc - не-http трафик WWW сервера
# boss_ext       - трафик пришедший с компьютера босса
queue std_ext        bandwidth 500Kb cbq(default borrow)
queue www_ext        bandwidth 500Kb { www_ext_http, www_ext_misc }
  queue www_ext_http bandwidth 50% priority 3 cbq(red borrow)
  queue www_ext_misc bandwidth 50% priority 1 cbq(borrow)
queue boss_ext       bandwidth 500Kb priority 3 cbq(borrow)
# Включить очереди на внутреннем интерфейсе для контроля трафика
# входящего из интернета или из DMZ. Используем планировщик cbq для
# контроля за каждой очередью. Полоса пропускания устанавливается в
# максимум. Трафику из DMZ позволяется использовать всю полосу, а
# трафику пришедшему из Интернет рарешается использовать 1.0 Mbps
# (поскольку 0.5 Mbps (500 kbps) зарезервировано на fxp1).
altq on dc0 cbq bandwidth 100% queue { net_int, www_int }
# определяем параметры дочерних очередей
# net_int    - Контейнер для трафика из Интернет. Полоса 1.0 Mbps
#   std_int  - Стандартная очередь. Так же является оередью по умолчанию
#              для исходящего трафика на dc0
#   it_int   - Трафик IT-отдела. Им зарезервировано 500 kbps
#   boss_int - Трафик босса имеет высший приоритет
# www_int    - Трафик WWW сервера из DMZ не имеет ограничений
queue net_int    bandwidth 1.0Mb { std_int, it_int, boss_int }
  queue std_int  bandwidth 250Kb cbq(default borrow)
  queue it_int   bandwidth 500Kb cbq(borrow)
  queue boss_int bandwidth 250Kb priority 3 cbq(borrow)
queue www_int    bandwidth 99Mb cbq(red borrow)
# Включаем очереди на интерфейсе DMZ для контроля трафика идущего к WWW
# серверу. Используем планировщик cbq для контроля за полосой
# пропускания. Полоса выставляется в максимум. Трафик из внутренней сети
# может использовать всю полосу пропускания, а трафик из Интернет
# ограничен 500 kbps.
altq on fxp1 cbq bandwidth 100% queue { internal_dmz, net_dmz }
# определяем параметры дочерних очередей
# internal_dmz   - трафик из внутренней сети
# net_dmz        - контейнер для очередей трафика идущего из Интернет
#   net_dmz_http - http трафик, наивысший приоритет
#   net_dmz_misc - не-http трафик. Это очередь по умолчанию
queue internal_dmz   bandwidth 99Mb cbq(borrow)
queue net_dmz        bandwidth 500Kb { net_dmz_http, net_dmz_misc }
  queue net_dmz_http bandwidth 50% priority 3 cbq(red borrow)
  queue net_dmz_misc bandwidth 50% priority 1 cbq(default borrow)
# ... раздел фильтрации ...
main_net  = "192.168.0.0/24"
it_net    = "192.168.1.0/24"
int_nets  = "{ 192.168.0.0/24, 192.168.1.0/24 }"
dmz_net   = "10.0.0.0/24"
boss      = "192.168.0.200"
wwwserv   = "10.0.0.100"
# default deny
block on { fxp0, fxp1, dc0 } all
# правила фильтрации входящего трафика на интерфейсе fxp0
pass in on fxp0 proto tcp from any to $wwwserv port { 21, \
    > 49151 } flags S/SA keep state queue www_ext_misc
pass in on fxp0 proto tcp from any to $wwwserv port 80 \
    flags S/SA keep state queue www_ext_http
# правила фильтрации исходящего трафика на интерфейсе fxp0
pass out on fxp0 from $int_nets to any keep state
pass out on fxp0 from $boss to any keep state queue boss_ext
# правила фильтрации входящего трафика на интерфейсе dc0
pass in on dc0 from $int_nets to any keep state
pass in on dc0 from $it_net to any queue it_int
pass in on dc0 from $boss to any queue boss_int
pass in on dc0 proto tcp from $int_nets to $wwwserv port { 21, 80, \
    > 49151 } flags S/SA keep state queue www_int
# правила фильтрации исходящего трафика на интерфейсе dc0
pass out on dc0 from dc0 to $int_nets
# правила фильтрации входящего трафика на интерфейсе fxp1
pass in on fxp1 proto { tcp, udp } from $wwwserv to any port 53 \
    keep state
# правила фильтрации исходящего трафика на интерфейсе fxp1
pass out on fxp1 proto tcp from any to $wwwserv port { 21, \
    > 49151 } flags S/SA keep state queue net_dmz_misc
pass out on fxp1 proto tcp from any to $wwwserv port 80 \
    flags S/SA keep state queue net_dmz_http
pass out on fxp1 proto tcp from $int_nets to $wwwserv port { 80, \
    21, > 49151 } flags S/SA keep state queue internal_dmz
            
          Адресным пулом называется адресное пространство более чем из
          двух адресов, используемое группой пользователей. Адресный пул
          может быть указан в правилах перенаправления, трансляции и
          указан как адрес назначения в опциях фильтрации route-to, reply-to и dup-to. 
        
Существует четыре способа использования адресных пулов:
bitmaskrandomsource-hashsource-hash в шестнадцатеричном
              формате или как строка. По умолчанию,
              pfctl(8) генерирует случайный ключ при
              каждой загрузке набора правил.
            round-robin
          За исключением метода round-robin,
          пул адресов должен быть определён как блок адресов
          CIDR. В методе round-robin используется назначение
          адресов из таблицы. 
        
          Опция sticky-address (дословно
          «липкий адрес») может использоваться с пулами random и round-robin для гарантии назаначения
          всегда одного и того же адреса источника в адрес пула. 
        
Пул адресов можно использовать для трансляции адресов в правилах nat. Адрес источника транслируется не в отдельный адрес, а в адрес взятый при помощи одного из перечисленных выше методов из пула. Это может оказаться очень полезным в случае. когда пакетный фильтр транслирует адреса для очень большой сети. Так как число одновременных NAT соединений на один внешний адрес ограниченно, выделение для этих целей пула адресов позволит значительно увеличить число пользователей.
В следующем примере пул из двух адресов используется для трансляции исходящих пакетов. Для каждого исходящего соединения пакетный фильтр производит ротацию адресов методом round-robin:
nat on $ext_if inet from any to any -> { 192.0.2.5, 192.0.2.10 }
            Существенным недостатком этого метода будет то, что не всегда будет соблюдаться соответствие между исходным адресом и адресом трансляции. Это может вызвать проблему при заходе на web-узлы: они не смогут корректно обрабатывать информацию о сессиях. Решением этой проблемы может стать использование метода source-hash для привязки внутреннего адреса к адресу трансляции. В этом случае адресный пул должен быть определён как сетевой блок CIDR:
nat on $ext_if inet from any to any -> 192.0.2.4/31 source-hash
            
            В этом правиле nat используется пул адресов 192.0.2.4/31
            (192.0.2.4 — 192.0.2.5) как адреса трансляции
            для исходящих пакетов. Каждый внутренний адрес будет всегда
            транслироваться в свой внешний адрес, так как указано
            ключевое слово source-hash. 
          
Пулы адресов также могут использоваться для балансировки нагрузки входящих подключений. Для примера, входящие подключения на web-сервер могут быть распределены между серверной фермой:
web_servers = "{ 10.0.0.10, 10.0.0.11, 10.0.0.13 }"
rdr on $ext_if proto tcp from any to any port 80 -> $web_servers \
   round-robin sticky-address
            Все соединения циклически будут перенаправляться на серверы фермы используя метод round-robin. При этом пакеты принадлежащие одному соединению будут направляться одному серверу ("sticky connection"), но следующее соединение открытое этим же хостом, будет направлено следующему серверу.
            Пулы адресов могут использоваться для балансировки нагрузки
            между двумя и более внешними каналами с использованием опции
            route-to в случае невозможности организовать динамическую
            маршрутизацию (например, с использованием протокола BGP4).
            Совместное использование route-to
            и пула адресов round-robin
            позволяет распределить исходящие соединения между разными
            провайдерами. 
          
            В качестве дополнительной информации необходимо указать
            адреса маршрутизаторов для каждого Интернет-соединения. Это
            нужно для опции route-to, дабы
            управлять исходящими пакетами. 
          
Следующий пример иллюстрирует балансировку нагрузки между двумя каналами:
lan_net = "192.168.0.0/24"
int_if  = "dc0"
ext_if1 = "fxp0"
ext_if2 = "fxp1"
ext_gw1 = "68.146.224.1"
ext_gw2 = "142.59.76.1"
pass in on $int_if route-to \
   { ($ext_if1 $ext_gw1), ($ext_if2 $ext_gw2) } round-robin \
   from $lan_net to any keep state 
            
            Опция route-to используется для
            приёма трафика на внутреннем интерфейсе и назначения ему
            внешнего сетевого интерфейса и шлюза, таким образом
            обеспечивая балансировку. Обратите внимание, что опция
            route-to должна быть указана в
            каждом правиле, предназначенном для балансировки трафика.
            Ответные пакеты приходят на тот интерфейс, с которого ушёл
            запрос и они будут перенаправлены во внутрь как обычно. 
          
Для гарантии того, что пакеты с $ext_if1 всегда направляются к $ext_gw1 (и соответственно для $ext_if2 к $ext_gw2), в правилах можно указать следующее:
pass out on $ext_if1 route-to ($ext_if2 $ext_gw2) from $ext_if2 to any
pass out on $ext_if2 route-to ($ext_if1 $ext_gw1) from $ext_if1 to any
            NAT можно использовать на каждом внешнем интерфейсе:
nat on $ext_if1 from $lan_net to any -> ($ext_if1)
nat on $ext_if2 from $lan_net to any -> ($ext_if2)
            Ниже дан полный пример правил для балансировки внешнего трафика:
lan_net = "192.168.0.0/24"
int_if  = "dc0"
ext_if1 = "fxp0"
ext_if2 = "fxp1"
ext_gw1 = "68.146.224.1"
ext_gw2 = "142.59.76.1"
#  правила nat для исходящих соединений на каждом внешнем интерфейсе
nat on $ext_if1 from $lan_net to any -> ($ext_if1)
nat on $ext_if2 from $lan_net to any -> ($ext_if2)
#  default deny
block in  from any to any
block out from any to any
#  пропускаем все исходящие пакеты на внутреннем итерфейсе
pass out on $int_if from any to $lan_net
#  пропускаем (quick) пакеты предназначенные самому шлюзу
pass in quick on $int_if from $lan_net to $int_if
#  балансировка исходящего tcp трафика идущего из внутренней сети
pass in on $int_if route-to \
    { ($ext_if1 $ext_gw1), ($ext_if2 $ext_gw2) } round-robin \
    proto tcp from $lan_net to any flags S/SA modulate state
#  балансировка исходящего icmp и udp трафика идущего из внутренней сети
pass in on $int_if route-to \
    { ($ext_if1 $ext_gw1), ($ext_if2 $ext_gw2) } round-robin \
    proto { udp, icmp } from $lan_net to any keep state
#  основные "выпускаюшие" правила на внешнем интерфейсе
pass out on $ext_if1 proto tcp from any to any flags S/SA modulate state
pass out on $ext_if1 proto { udp, icmp } from any to any keep state
pass out on $ext_if2 proto tcp from any to any flags S/SA modulate state
pass out on $ext_if2 proto { udp, icmp } from any to any keep state
#  маршрутизация пакетов идущих с любого IP на $ext_if1 через $ext_gw1 и
#  пакетов идущих  на $ext_if2 через $ext_gw2
pass out on $ext_if1 route-to ($ext_if2 $ext_gw2) from $ext_if2 to any 
pass out on $ext_if2 route-to ($ext_if1 $ext_gw1) from $ext_if1 to any 
            Маркирование пакетов — способ пометить пакет внутренним идентификатором для дальнейшего использования в качестве критерия в правилах трансляции и фильтрации. Маркирование позволяет создать «доверие» между интерфейсами, а так же помогает оределить был ли пакет обработан правилами трансляции. Также становится возможным переход от фильтрации, основанной на правилах, к фильтрации, основанной на политиках.
            Для присвоения маркера используется ключевое слово tag:
          
pass in on $int_if all tag INTERNAL_NET keep state
            
            Маркер INTERNAL_NET будет присвоен
            любому пакету соответствующему правилу.
          
Маркер может быть присвоен с использованием макросов, например:
name = "INTERNAL_NET"
pass in on $int_if all tag $name keep state
            Существует набор предопределённых макросов, которые можно использовать для этих целей:
$if$srcaddr$dstaddr$srcport$dstport$proto$nrЭти макросы определяются во время загрузки, а не во время работы.
Маркирование подчиняется следующим правилам:
tag.
            Рассмотрим следующий пример:
pass in on $int_if tag INT_NET keep statepass in quick on $int_if proto tcp to port 80 tag INT_NET_HTTP keep state
pass in quick on $int_if from 192.168.1.5 keep state
![]()
            В правилах nat, rdr и binat тоже можно метить пакеты при
            помощи ключевого слова tag.
          
            Для проверки установленных маркеров используется ключевое
            слово tagged:
          
pass out on $ext_if tagged INT_NET keep state
            
            Это правило соответствует исходящим пакетам на интерфейсе
            $ext_if помеченным маркером
            INT_NET. Восклицательный знак используется для
            инвертирования правила:
          
pass out on $ext_if ! tagged WIFI_NET keep state
            
            В правилах nat, rdr и binat так же допускается использование
            ключевого слова tagged.
          
Фильтрация пакетов на основе политик несколько отличается от фильтрации на основе правил. В политиках устанавливаются правила, по которым некоторый вид трафика должен быть пропущен, а некоторый запрещён. Пакеты классифицируются внутри политик на основе традиционных критериев — IP адреса источника/назначения, протокола и т.д. Рассмотрим следующий пример:
Заметьте, что политики охватывают весь трафик идущий через брандмауэр. В круглых скобках указаны маркеры используемые для данной политики.
Правила фильтрации и трансляции:
rdr on $ext_if proto tcp from <spamd> to port smtp \
   tag SPAMD -> 127.0.0.1 port 8025
nat on $ext_if tag LAN_INET_NAT tagged LAN_INET -> ($ext_if)
block all
pass in on $int_if from $int_net tag LAN_INET keep state
pass in on $int_if from $int_net to $dmz_net tag LAN_DMZ keep state
pass in on $ext_if proto tcp to $www_server port 80 tag INET_DMZ keep state
            Таким образом, мы установили какой трафик соответствует какой политике. Теперь разрешим проход трафика принадлежащего политикам SPAMD, LAN_INET_NAT, LAN_DMZ и INET_DMZ:
pass in  quick on $ext_if tagged SPAMD keep state
pass out quick on $ext_if tagged LAN_INET_NAT keep state
pass out quick on $dmz_if tagged LAN_DMZ keep state
pass out quick on $dmz_if tagged INET_DMZ keep state
            
            Теперь все политики определены. Если мы захотим добавить
            POP3/SMTP сервер в DMZ, нам надо будет добавить следующие
            строки в pf.conf(5):
          
mail_server = "192.168.0.10"
...
pass in on $ext_if proto tcp to $mail_server port { smtp, pop3 } \
   tag INET_DMZ keep state
            Таким образом, трафик электронной почты будет соответствовать политике INET_DMZ и будет пропущен.
Полный набор правил:
# macros
int_if  = "dc0"
dmz_if  = "dc1"
ext_if  = "ep0"
int_net = "10.0.0.0/24"
dmz_net = "192.168.0.0/24"
www_server = "192.168.0.5"
mail_server = "192.168.0.10"
table <spamd> persist file "/etc/spammers"
# классификация пакетов основанная на определённых в брандмауэре
# политиках
rdr on $ext_if proto tcp from <spamd> to port smtp \
    tag SPAMD -> 127.0.0.1 port 8025
nat on $ext_if tag LAN_INET_NAT tagged LAN_INET -> ($ext_if)
block all
pass in on $int_if from $int_net tag LAN_INET keep state
pass in on $int_if from $int_net to $dmz_net tag LAN_DMZ keep state
pass in on $ext_if proto tcp to $www_server port 80 tag INET_DMZ keep state 
pass in on $ext_if proto tcp to $mail_server port { smtp, pop3 } \
    tag INET_DMZ keep state 
# применение политик -- фильтрация на основе опрелелённых в брандмауэре
# политиках
pass in  quick on $ext_if tagged SPAMD keep state
pass out quick on $ext_if tagged LAN_INET_NAT keep state
pass out quick on $dmz_if tagged LAN_DMZ keep state
pass out quick on $dmz_if tagged INET_DMZ keep state
            
            Если машина работает как мост на канальном уровне (в
            OpenBSD см. bridge(4)
            в FreeBSD
            if_bridge(4)) пакетный фильтр может
            маркировать кадры ethernet. При создании правил трансляции
            при помощи команды brconfig(8)
            (характерна для OpenBSD) можно установить
            маркер с помощью опции tag:
          
# brconfig bridge0 rule pass in on fxp0 src 0:de:ad:be:ef:0 tag USER1
            
            Далее можно ссылаться на этот маркер в
            pf.conf(5):
          
pass in on fxp0 tagged USER1
            
          Журналирование в пакетном фильтре осуществляется при помощи
          демона pflogd(8) слушающего сетевой
          интерфейс pflog0 и записывающего
          пакеты в журнальный файл /var/log/pflog в
          бинарном формате libpcap, который можно просматривать при
          помощи программы tcpdump(1) или
          wireshark(1), она же
          ethereal(1) (см. Раздел 6.11, «Демонстрация основных навыков работы с утилитой
      tcpdump(1)»).
          У программы tcpdump(1) есть специальные
          правила для работы с пакетным
            фильтром. Кроме того, программа
          tcpdump(1) позволяет просматривать журнал
          «на лету» если запустить её на прослушивание
          интерфейса pflog0.  Для помещения в
          журнал, можно применять ключевое  слово log (или log
            (all)) в правилах фильтрации.
        
Лирическое отступление:
В 1999 году меня разбил сильный приступ радикулита. Родственник доставили меня в диагностический центр и мне сделали рентген. После рентгена я получил на руки «описание снимка» — в нём было написано шариковой ручкой, что на полученном снимке присутствует позвоночник, к которому прикреплены рёбра. А сам снимок на руки не давали (видимо из-за серебра...). Его давали только врачу, если он сам придёт и попросит.
Многие брандмауэры кладут в журнал сообщение о том, что через них прошёл некоторый пакет. Могут описать его: мол, пакет выглядет так-то и так-то.
Пакетный фильтр кладёт в журнал сами пакеты.
            Для журналирования пакета надо поместить ключевое слово log в правило фильтрации, nat или rdr.
            Заметьте, что в пактном фильтре нельзя создать правило
            только для журналирования пакета — должна
            присутствовать либо директива block
            либо pass.
          
            Ключевому слову log можно передать
            следующие опции:
          
allkeep state.
              userto <interface>
            Опции указываются в круглых скобках после ключевого слова
            log. Несколько опций можно указать
            через запятую или через пробел:
          
pass in log (all) on $ext_if inet proto tcp to $ext_if port 22 keep state
            Это правило помещает в журнал все входящие пакеты, идущие на 22-й порт.
Журнальный файл записанный pflogd(8) имеет бинарный формат, его нельзя читать при помощи текстового редакора. Он предназначен для чтения утилитой tcpdump(1) (или другой программой скомпилированной с поддержкой библиотеки libpcap, например wireshark(1)).
Для просмотра журнального файла выполните команду
# tcpdump -n -e -ttt -r /var/log/pflog
            Для просмотра журнала в режиме реального времени:
# tcpdump -n -e -ttt -i pflog0
            ![]()  | Внимание | 
|---|---|
              При чтении журнала с применением режима verbose
              (активируется флагом  Кроме того, имейте в виду, что pflogd(8) по умолчанию помещает в журнал первые 96 байт пакета. В этих байтах могут находиться критические данные, такие как пароли telnet(1) или ftp(1).  | 
Поскольку pflogd(8) сохраняет данные в формате tcpdump(1), при просмотре данных журнала можно использовать правила фильтрации tcpdump(1). Например, для просмотра данных касающихся некоторого конкретного порта можно применять команду:
# tcpdump -n -e -ttt -r /var/log/pflog port 80
            Этот пример можно слегка изменить, чтобы ограничить фильтрацию некоторым конкретным хостом:
# tcpdump -n -e -ttt -r /var/log/pflog port 80 and host 192.168.1.3
            
            Та же идея может использоваться при чтении данных из
            устрйства pflog0:
          
# tcpdump -n -e -ttt -i pflog0 host 192.168.4.2
            Правила фильтрации в tcpdump(1) специально расширены для взаимодействия с pflogd(8). В данной работе синтаксис правил tcpdump(1) подробно рассмотрен в Раздел 6.11, «Демонстрация основных навыков работы с утилитой tcpdump(1)», в том же разделе рассматриваются дополнительные правила tcpdump(1) для работы с журналом pflogd(8).
Ещё один пример:
# tcpdump -n -e -ttt -i pflog0 inbound and action block and on wi0
            
            В этом примере мы в режиме реального времени следим за
            входящими пакетами блокирующимися на интерфейсе wi0.
          
Во многих случаях желательно вести журнал брандмауэра в текстовом формате и отправлять данные журнала на внешний журнальный сервер.
Увы, никакого естественного метода для этого документация по пакетному фильтру нам не предлагает. Всё что нам предлагают, это раз в 5 минут пропускать бинарный файл через pipe:
# tcpdump -n -e -ttt -r /var/log/pflog | logger -t pf -p local0.info
            Пошаговое HOWTO для направления данных журнала через logger(1) демону syslogd(8) можно найти на сайте разработчиков пакетого фильтра. Я не планирую пересказывать эту методику в данной книге, так как считаю её увечной.
Насколько большую полосу пропускания может обслуживать пакетный фильтр? Насколько мощный компьютер мне нужен для обслуживания соединений с Интернет?
Простого ответа на эти вопросы нет. Для некоторых целей будет достаточно процессора 486/66 с парой хороших сетевых карт ISA, при этом будет происходить трансляция NAT и обрабатываться трафик до 5 Mbps. Для других целей может не будет хватать даже более быстрой машины с более мощными сетевыми интерфейсами. Оценивать следует не количество байт в секунду, а количество пакетов в секунду.
Производительность пакетного фильтра определяется несколькими величинами:
keep
              state и quick тем лучше
            производительность. Чем больше правил через которые пройдёт
            пакет, тем хуже производительность.
          Часто люди спрашивают про benchmark для пакетного фильтра. Benchmark для вашей системы с вашим окружением можете сделать только вы.
Пакетный фильтр используют на некоторых очень больших системах с очень большим трафиком. Разработчики — люди компетентные. Это не плохая для вас новость.
Подробнее вопросы производительности пакетного фильтра изложены в работе Дэниэла Хартмайера [url://Hartmeier-2006-en], [url://Hartmeier-2006-ru].
FTP это протокол, который создавался, когда Интернет был маленький и все в нём друг друга знали. Нужды в фильтрации трафика в те годы не было, поэтому FTP сконструирован без оглядки на брандмауэры и трансляцию NAT.
Существует два режима функционирования FTP: пассивный и активный. Выбор между ними, это выбор между тем, у кого будут проблемы с фильтрацией трафика. Если вы хотите, чтобы ваши пользователи были счастливы, вам придётся приспособиться к обоим режимам.
Активный FTP. Когда клиент посылает серверу команду о передаче данных, сервер «ведёт себя активно» — открывает соединение к клиенту. Клиент выбирает случайный верхний порт и сообщает его серверу, последний открывает соединение на указанный порт клиента для передачи данных. Такое поведение затрудняет работу NAT: FTP сервер пытается открыть соединение с машиной, на которой работает NAT, а он просто не знает, что делать с этими соединениями.
Пассивный FTP. При передаче данных сервер выбирает случайный верхний порт и сообщает его клиенту. Клиент открывает соединение на указанный верхний порт сервера, и по этому соединению передаются данные. Такая практика не всегда возможна и не всегда желательна, так как брандмауэр может блокировать трафик идущий на эти случайные порты. Зато с NAT с клиентской стороны, напротив нет никаких проблем, так как все соединения идут от клиента к серверу.
            Для тестирования можно применять программу
            ftp(1). В всех системах
            BSD эта программа по умолчанию работает в
            пассивном режиме. В активный режим её можно перевести с
            использованием аргумента -A или уже во
            время работы при помощи команды passive
              off отданной в ответ на приглашение  (а вернуться
            в пассивный режим командой ftp>passive
              on).
          
Как сказано выше протокол FTP плохо взаимодействует с брандмауэрами и NAT.
Для решения этой проблемы пакетный фильтр предлагает воспользоваться прокси сервером FTP. Этот процесс пропускает FTP трафик добавляя и удаляя правила в пакетный фильтр при помощи системы якорей. Демон ftp-proxy(8) используется пакетным фильтром в OpenBSD 3.9. В старых версиях существовал другой демон с тем же названием.
            Чтобы использовать его, поместите следующие строки в раздел
            NAT файла /etc/pf.conf(5):
          
nat-anchor "ftp-proxy/*"
rdr-anchor "ftp-proxy/*"
rdr on $int_if proto tcp from any to any port 21 -> 127.0.0.1 port 8021
            Первые два правила создают пару якорей, которые будут использоваться демоном ftp-proxy(8) для добавления и удаления правил, т.е. для управления трафиком FTP.
Последняя строка перенаправляет трафик FTP от клиентов программе ftp-poxy(8), которая будет слушать порт 8021.
Вам так же понадобится якорь в области фильтрации:
anchor "ftp-proxy/*"
            
            Вам так же понадобится сделать так, чтобы демон
            ftp-proxy(8) стартовал при запуске
            системы. Для этого в OpenBSD надо в файл
            /etc/rc.conf.local добавить строку:
          
ftpproxy_flags=""
            Можно запустить программу вручную, чтобы не перезагружать машину.
            Для работы активного FTP вам понадобится ключ
            -r для ftp-proxy(8)
          
              В FreeBSD и NetBSD
              функциональность ftp-proxy(8) ниже, чем
              в OpenBSD. Фактически, в этих системах
              пока применяется устаревшая версия
              ftp-proxy(8).
              Вместо ftp-proxy(8) в этих системах
              можно использовать порт
              ftp/ftpsesame. См. Раздел C.5.3, «ftpsesame». Далее описано, как
              используется старая версия программы
              ftp-proxy(8), которой укомплектована
              FreeBSD.
            
              В FreeBSD
              ftp-proxy(8) запускается из
              суперсервера inetd(8). Для этого в
              /etc/pf.conf(5) мы добавляем примерно
              такое правило:
            
int_if = "xl0"
rdr pass on $int_if proto tcp from any to any port 21 -> 127.0.0.1 port 8021
              
              Затем мы конфигурируем inetd(8) так,
              чтобы он начал слушать порт 8021. Для этого в файл
              /etc/inetd.conf вписываем строку:
            
ftp-proxy stream tcp nowait root /usr/libexec/ftp-proxy ftp-proxy
              Таким образом, ftp-proxy(8) пробрасывает командный канал FTP, а для передачи данных необходимо добавить разрешающие правила в брандмауэр:
block in on $ext_if proto tcp all
pass  in on $ext_if inet proto tcp from any to $ext_if \
   port > 49151 keep state
              
              Это правило разрешает подключение к портам от 49151 до
              65535. Программе ftp-proxy(8) можно
              задавать диапазоны портов при помощи опций
              -m и -M. Подробнее см.
              man(1) по команде
              ftp-proxy(8). Диапазон портов
              используемых демоном ftpd(8) в
              FreeBSD можно регулировать при помощи
              переменных ядра net.inet.ip.portrange.first net.inet.ip.portrange.last, а в
              OpenBSD net.inet.ip.porthifirst и net.inet.ip.porthilast.
            
              Надо признать, что вариант с динамическими правилами,
              работающий в OpenBSD выглядит разумнее.
              Остаётся надеяться, что в будущем он будет портирован в
              FreeBSD, а пока, повторюсь, мы можем
              использовать порт ftp/ftpsesame.
            
            При функционировании пакетного фильтра и FTP сервера на
            одной машине достаточно разрешить в обе стороны коннекты в
            диапазоне портов от 49151 до 65535. Этот диапазон портов
            используется по умолчанию системным FTP серврером
            ftpd(8). Диапазон портов можно
            регулировать в FreeBSD при помощи
            переменных ядра net.inet.ip.portrange.first net.inet.ip.portrange.last, а в
            OpenBSD net.inet.ip.porthifirst и net.inet.ip.porthilast.
          
pass in on $ext_if proto tcp from any to any port 21 keep state
pass in on $ext_if proto tcp from any to any port > 49151 keep state
            В этом случае брандмауэр должен перенаправлять FTP трафик сервера и не блокировать нужные порты. Для этого мы вновь приходим к необходимости использовать ftp-proxy(8).
ftp-proxy(8) может быть запущен в режиме перенаправления всего FTP трафика на один сервер FTP. Обычно мы настраиваем брандмауэр так, чтобы он слушал порт 21 и пробрасываем трафик на внутренний сервер FTP:
ftpproxy_flags="-R 10.10.10.1 -p 21 -b 192.168.0.1"
            Здесь 10.10.10.1 — адрес сервера FTP, а работает он на порту 21. 192.168.0.1 — внешний адрес брандмауэра, к которому мы привязываем программу ftp-proxy(8).
            Правила pf.conf:
          
ext_ip = "192.168.0.1"
ftp_ip = "10.10.10.1"
nat-anchor "ftp-proxy/*"
nat on $ext_if inet from $int_if -> ($ext_if)
rdr-anchor "ftp-proxy/*"
pass in on $ext_if inet proto tcp to $ext_ip port 21 \
    flags S/SA keep state
pass out on $int_if inet proto tcp to $ftp_ip port 21 \
    user proxy flags S/SA keep state
anchor "ftp-proxy/*"
            
            Опция user proxy нужна для того,
            чтобы убедиться, что только программа
            ftp-proxy(8) может пробрасывать пакеты.
          
![]()  | Замечание | 
|---|---|
            В FreeBSD и NetBSD
            вместо ftp-proxy(8) можно использовать
            порт ftp/ftpsesame. См. Раздел C.5.3, «ftpsesame».
           | 
          authpf(8) — пользовательская
          оболочка для авторизации на шлюзе. При использовании этой
          программы шлюз работает как обычный маршрутизатор, но
          пропускает пользовательский трафик только если пользователь
          аутентифицировался на нём. Если пользовательская оболочка
          выставлена в /etc/sbin/authpf (т.е.
          вместо csh(1) и пр.) и пользователь зашёл в
          систему, например через ssh(1),
          authpf(8) динамически настраивает пакетный
          фильтр так, чтобы он начал пропускать трафик пользователя,
          осуществлял нужные пользователю перенаправления и трансляции.
          Когда пользователь прекращает сессию
          ssh(1), authpf(8)
          удаляет правила из пакетного фильтра и удаляет записи из
          таблицы состояний. Таким образом, пользователь способен
          сохранять соединение только пока открыта сессия
          ssh(1).
        
          authpf(8) загружает правила фильтрации и
          трансляции используя  уникальный для каждого пользователя
          якорь. Название
          якоря является комбинацией из имени пользователя и PID
          экземпляра authpf(8) в формате username(PID). Каждый пользовательский
          якорь находится внутри якоря authpf, который уже находится в
          основном наборе правил. Таким образом, «полностью
          разрешённое имя якоря» выглядит как
        
main_ruleset/authpf/username(PID)
          Правила, которые может загрузить authpf(8) могут быть индивидуальными для каждого пользователя, а могут быть глобальными.
Вот примеры использования authpf(8):
Информация об аутентифицировавшихся пользователях журналируется через syslogd(8). Это позволяет администратору вычислять кто когда пользовался Интернетом и вычислять какой пользователь использовал большее количество трафика.
Полностью конфигурирование authpf(8) описано в man(1) странице по authpf(8).
              В системе должен существовать конфигурационный файл
              /etc/authpf/authpf.conf. В нём
              содержатся конфигурационные опции
              authpf(8). Если файла не существует,
              authpf(8) будет завершать работу сразу
              после аутентификации. Если он существует, но пуст, будут
              использованы умолчания.
            
В этом файле могут присутствовать следующие две опции:
              authpf(8) помещается в основной набор
              правил при помощи правила anchor:
            
nat-anchor "authpf/*"
rdr-anchor "authpf/*"
binat-anchor "authpf/*"
anchor "authpf/*"
              Пакетный фильтр перейдёт к изучению правил входящих в эти якоря там, где они расположены. Нет нужды всегда использовать все якоря. Например, если authpf(8) не настроен на то, чтобы осуществлять трансляцию NAT, то соответствующий якорь не нужен.
authpf(8) подгружает правила из файлов
/etc/authpf/users/$USER/authpf.rules/etc/authpf/authpf.rulesСперва ищется первый, потом второй, если существуют оба — используется только один. Таким образом, в первом файле должны находится правила характерные для конкретного пользователя и они будут перебивать глобальные правила заданные во втором файле. Как минимум один файл должен существовать, иначе authpf(8) не запустится.
Правила трансляции такие же как и в основном файле, однако определены два макроса:
$user_ip$user_id
              Рекомендуется использовать $user_id для того, чтобы был
              разрешён только трафик с пользовательской машины.
            
              В добавок к макросу $user_ip
              authpf(8) может использовать для
              хранения всех аутентифицировавшихся пользователей таблицу
              authpf_users если она
              существует. Убедитесь, что вы определили её, прежде чем
              использовать:
            
table <authpf_users> persist
pass in on $ext_if proto tcp from <authpf_users> \
    to port smtp flags S/SA keep state
              Эта таблица должна использоваться в правилах, которые относятся ко всем аутентифицировавшимся пользователям.
              Пользователям можно запретить пользоваться
              authpf(8) для этого надо создать файл в
              каталоге /etc/authpf/banned/. Файл
              должен называться по имени пользователя. Его содержимое
              будет показано пользователю перед обрывом связи. Таким
              образом, в нём можно указать причины прекращения доступа и
              как связаться с ответственным лицом.
            
              Кроме того, в файле
              /etc/authpf/authpf.allow можно
              перечислить пользователей, которым разрешено входить в
              систему с использованием authpf(8).
              Если файл существует, действует политика «что не
              разрешено, то запрещено». Если файла нет, или если в
              нём звёздочка * —
              authpf(8) позволяет зайти всем, кто
              успешно залогинился через ssh(1), если
              только его не «забанили» в каталоге
              /etc/authpf/banned/.
            
              Если authpf(8) не может определить
              разрешено польователю входить или нет, он печатает
              предупреждение и не пускает пользователя.
              /etc/authpf/banned/ всегда главнее
              /etc/authpf/authpf.allow.
            
Когда пользователь успешно аутентифицируется в системе, ему будет напечатано приветственное сообщение
Hello charlie. You are authenticated from host "64.59.56.140"
              
              Это сообщение можно дополнить сообщением из файла
              /etc/authpf/authpf.message.
            
Чтобы authpf(8) заработал, его надо сделать оболочкой пользователя. Когда пользователь успешно зайдёт в систему через ssh(1), authpf(8) будет запущен в качестве оболочки. Он проверит можно ли пользователю его использовать, загрузит нужные правила и т.д.
Есть два способа назначить пользователю authpf(8) в качестве оболочки:
login.conf(5).
                (см. Приложение F, /etc/login.conf(5)).
              ![]()  | Замечание | 
|---|---|
            Что такое классы, зачем они нужны, как их создавать,
            подробно описано в Приложение F, /etc/login.conf(5).
           | 
В системе, где есть одновременно обычные пользователи и пользователи для authpf(8) удобно создать для последних специальный класс. Это позволит сделать разные политики для разных пользователей. Например, в классе можно указать:
shell/usr/sbin/authpf так, что её
                невозможно будет сменить через программу
                chsh(1) — эта опция
                login.conf(5) имеет приоритет перед
                содержимым файла passwd(5).
              welcome
            Класс создаётся в файле
            /etc/login.conf. Вот пример класса для
            пользователей authpf(8):
          
authpf:\
    :welcome=/etc/motd.authpf:\
    :shell=/usr/sbin/authpf:\
    :tc=default:
            
            После редактирования файла
            /etc/login.conf не забудьте выполнить
            команду
          
# cap_mkdb /etc/login.conf
            Назначить пользователю класс можно разными способами. Например: chsh(1), pw(8), vipw(8).
Чтобы просмотреть список пользователей из класса authpf, можно выполнить такую команду:
# awk -F: '$5=="authpf"{print $1}' /etc/master.passwd | sort
            После того, как пользователь успешно вошёл в систему, authpf(8) меняет заголовок процесса, помещая в него имя пользователя и IP адрес с которого он пришёл:
$ ps -ax | grep authpf
23664 p0  Is+     0:00.11 -authpf: charlie@192.168.1.3 (authpf)
            
            Послав этому процессу сигнал SIGTERM
            можно насильно прервать сессию пользователя. При этом
            authpf(8) удалит все правила из пакетного
            фильтра и прекратит коннект пользователя.
            А если послать сигнал SIGKILL,
            то не удалит, и пользователь по прежнему будет ходить через
            шлюз!
        
# kill -TERM 23664
          
            Пусть пакетный фильтр используется на машине
            OpenBSD, которая является шлюзом для
            беспроводной сети, которая является частью большой
            университетской сети. Если пользователь аутентифицировался,
            и он не находится в списке запрещённых пользователей
            (/etc/authpf/banned/), ему разрешают
            SSH наружу, использовать web, и, конечно, открывают доступ к
            DNS.
          
            Файл /etc/authpf/authpf.rules содержит
            следующие строки:
          
wifi_if = "wi0"
pass in quick on $wifi_if proto tcp from $user_ip to port { ssh, http, \
   https } flags S/SA keep state
            Администратор charlie должен иметь доступ к SMTP, POP3, а так же web и SSH.
            Файл
            /etc/authpf/users.charlie/authpf.rules
            содержит следующие строки:
          
wifi_if = "wi0"
smtp_server = "10.0.1.50"
pop3_server = "10.0.1.51"
pass in quick on $wifi_if proto tcp from $user_ip to $smtp_server \
   port smtp flags S/SA keep state
pass in quick on $wifi_if proto tcp from $user_ip to $pop3_server \
   port pop3 flags S/SA keep state
pass in quick on $wifi_if proto tcp from $user_ip to port { ssh, http, \
   https } flags S/SA keep state
            
            Основной файл с правилами, расположенный в
            /etc/pf.conf содержит следующие строки:
          
# macros
wifi_if = "wi0"
ext_if  = "fxp0"
dns_servers = "{ 10.0.1.56, 10.0.2.56 }"
table <authpf_users> persist
scrub in all
# filter
block drop all 
pass out quick on $ext_if inet proto tcp from \
   { $wifi_if:network, $ext_if } flags S/SA modulate state
pass out quick on $ext_if inet proto { udp, icmp } from \
   { $wifi_if:network, $ext_if } keep state 
pass in quick on $wifi_if inet proto tcp from $wifi_if:network to $wifi_if \
   port ssh flags S/SA keep state 
pass in quick on $wifi_if inet proto { tcp, udp } from <authpf_users> \
   to $dns_servers port domain keep state 
anchor "authpf/*" in on $wifi_if 
            Правила очень просты. Вот, что они значат:
            Основная идея в том, чтобы заблокировать всё и открыть
            настолько мало, насколько это возможно. Трафик может
            свободно покидать внешний интерфейс, однако он заблокирован
            политикой default deny на внутреннем (wi0) интерфейсе. Когда
            пользователь аутентифицируется, его трафик оказывается
            разрешён для прохода на внутреннем интерфейсе и, таким
            образом, проходит наружу. Ключевое слово quick используется для того, чтобы
            добавляемые на лету правила не сказывались на конструкции
            брандмауэра.
          
CARP — Common Address Redundancy Protocol (Общий Протокол Избыточных Адресов, я не знаю есть ли общепринятый перевод на русский язык). Основная задача протокола — дать возможность различным хостам в локальной сети использовать общий IP адрес. CARP является свободной и безопасной альтернативой протоколам VRRP (Virtual Router Redundancy Protocol, см. [RFC-3768]) и HSRP (Hot Standby Router Protocol, см. [RFC-2281]). К сожалению, на этот протокол не опубликовано RFC. Кроме того, уже сужествует другой протокол с тем же названием: (Cache Array Routing Protocol, [RFC-3040] — протокол используемый Microsoft ISA).
История вопроса такова (по данным wikipedia): В конце 90-х годов IETF начало работу над проблемой отказоустойчивости сервисов. В 1997 году Cisco проинформировало, что проблема уже решена при помощи запатентованной ими технологии. В 1998 году Cisco опубликовала запатентованный протокол HSRP. Несмотря на это IETF продолжила работу над своим протоколом VRRP. После некоторых дебатов было решено, что запатентованную технологию можно использовать в качестве стандарта при условии лицензирования по «разумной и не дискриминационной» лицензии. Однако, поскольку VRRP решало некоторые проблемы HSRP сама Cisco перешла на использование VRRP при этом называя его своим.
Cisco проинформировала разработчиков OpenBSD, что они не могут использовать патентованный VRRP. Возможно это было связано с судебными тяжбами Cisco с Alсatel (звучит загадочно — Е.М.). Таким образом, свободную реализацию VRRP сделать было нельзя, поэтому OpenBSD принялись за разработку альтернативного протокола CARP.
В настоящий момент CARP реализован не только в OpenBSD, но так же портирован в FreeBSD и NetBSD (и, следовательно в DragonFly BSD).
IANA до сих по не выделила официальный номер протокола для CARP. Это связано, по всей видимости, с отсутствием его описания. Разработчики OpenBSD самовольно присвоили ему номер 112 (конфликтующий с VRRP). То же касается и протокола
pfsync.
CARP позволяет группе хостов использовать общий IP адрес. Эта группа хостов называется «избыточная группа» (redundancy group). Избыточной группе присваивается общий адрес, затем, среди её членов назначается «мастер» и запасные машины (backup). Мастер, это та машина, которой в данный момент принадлежит общий адрес IP. Он отвечает на ARP запросы, обращённые к этому адресу. Каждый хост может принадлежать более чем к одной «избыточной группе».
Один из способов использования CARP — построение избыточных брандмауэров. Виртуальный IP адрес, принадлежащий группе, указывают клиентам в качестве маршрута по умолчанию. Если брандмауэр оказывается недоступен, IP адрес переходит к другой, запасной машине в группе и работа сети продолжается.
            Мастер-хост группы регулярно посылает оповещения в локальную
            сеть, чтобы запасные хосты знали, что он ещё жив. Если
            запасной хост в течении некоторого времени не получает
            уведомления от мастера, то он может принять на себя
            обязанности мастера. (Какой именно — зависит от
            значения advbase и advskew).
          
В одной локальной сети может находиться несколько групп CARP, так как в оповещении, рассылаемом мастером присутствует Virtual Host ID, по которому запасные машины могут понять какой группе адресовано оповещение.
Чтобы предотвратить рассылку поддельных оповещений CARP, каждая группа может быть сконфигурирована с паролем. Каждый пакет CARP снабжается этим паролем в виде SHA1 HMAC.
CARP рассылается при помощи собственного протокола сетевого уровня (номер 112, официально не утверждён IANA) и ему нужно отдельное правило в брандмауэре:
pass out on $carp_dev proto carp keep state
            
            Здесь $carp_dev —
            физический интерфейс через который передаются оповещения
            CARP.
          
            Каждая группа CARP представлена
            виртуальным сетевым интерфейсом carp(4). Таким образом,
            CARP можно настроить используя команду
            ifconfig(8):
          
#ifconfig <carpN> create#ifconfig <carpN> vhid <vhid> [pass <password>] [carpdev <carpdev>] \ [advbase <advbase>] [advskew <advskew>] [state <state>] <ipaddress> \ netmask <mask>
carpNN — целое число,
                номер интерфейса, например 10.
              vhidpasswordcarpdevadvbaseadvskewadvbase.
                На основе величин advbase и
                advskew происходит выбор
                мастера в группе: чем меньше advbase, который может
                использовать хост, тем выше у него приоритет. По
                умолчанию 0. Допустимые значения от 0 до 254.
              stateinit, backup, master. Аргумент отсутствует в
                FreeBSD.
              ipaddressmaskПоведением CARP пожно управлять через sysctl(8). Вот некоторые переменные ядра:
Приведённые ниже переменные ядра работают как в OpenBSD, так и в FreeBSD:
net.inet.carp.allownet.inet.carp.preempt
                  Позволяет мастеру передать его обязанности другим
                  членам группы CARP имеющим лучшие
                  показатели advbase и advskew. Кроме того, позволяет
                  обработать ситуацию отказа — если
                  физический интерфейс отказал, на других интерфейсах с
                  включённым CARP advskew выставляется в 240.
                
                  Поясню: Пусть имеется маршрутизатор A с двумя
                  интерфейсами в CARP и advskew=0 и маршрутизатор B с
                  advskew=100. Если данная
                  переменная ядра выставлена в истину, и на
                  маршрутизаторе A падает один интерфейс. В этом случае
                  advskew на A увеличивается
                  до 240 и обязанности мастера берёт маршрутизатор B.
                
По умолчанию выставлен в 0 (нет)
net.inet.carp.lognet.inet.carp.arpbalance
            Дополнительную информацию можно получить из руководства
            man(1) по carp(4) и из [url://Sgibnev-CARP-2006].
          
Пример конфигурации CARP:
#sysctl -w net.inet.carp.allow=1![]()
#ifconfig carp1 create![]()
#ifconfig carp1 vhid 1 pass mekmitasdigoat carpdev em0 \ advskew 100 10.0.0.1 netmask 255.255.255.0![]()
            Чтобы просмотреть состояние интерфейса carp1 мы можем вновь использовать
            команду ifconfig(8)
          
$ ifconfig carp1
carp1: flags=8802<UP,BROADCAST,SIMPLEX,MULTICAST> mtu 1500
     carp: BACKUP carpdev em0 vhid 1 advbase 1 advskew 100
     groups: carp
     inet 10.0.0.1 netmask 0xffffff00 broadcast 10.0.0.255
            
            Интерфейс pfsync(4) используется
            для наблюдения за таблицей состояний пакетного фильтра. При
            помощи утилиты tcpdump(8) можно следить
            за таблицей состояний в режиме реального времени. Кроме
            того, pfsync(4) позволяет
            посылать информацию об изменениях в таблице состояний по
            сети. Таким образом, другие пакетные фильтры на других
            машинах могут заносить эту информацию в свои таблицы. Таким
            образом, pfsync(4) позволяет
            модифицировать таблицы состояния по сети.
          
            По умолчанию pfsync(4) не
            получает и не отсылает информации о состоянии соединений.
            Это не мешает следить за его деятельностью локально, при
            помощи tcpdump(8).
          
            Когда pfsync(4) конфигурируется
            для отправки или получения информации, он начинает рассылать
            её при помощи multicast пакетов в локальной сети. Все
            оповещения pfsync(4) отсылает без
            аутентификации. Наилучшая практика состоит в том, чтобы:
          
syncdev (см. ниже).
            syncpeer (см. ниже). Это приведёт к
              тому, что информация будет отсылаться по unicast адресу.
              Затем надо зашифровать трафик между партнёрами при помощи
              ipsec(4).
            
            При обмене сообщениями pfsync(4)
            надо сконфигурировать пакетный фильтр так, чтобы он начал
            этот трафик пропускать (pfsync использует свой протокол
            сетевого уровня, номер 240, этот номер официально не
            утверждён IANA):
          
pass on $sync_if proto pfsync
            
            Здесь $sync_if —
            интерфейс, через который идёт обмен информацией.
          
            Поскольку pfsync(4) —
            виртуальный сетевой интерфейс, его можно конфигурировать
            используя ifconfig(8):
          
ifconfig <pfsyncN> syncdev <syncdev> [syncpeer <syncpeer>]
            pfsyncNpfsync(4). При
                использовании ядра GENERIC интерфейс pfsync0 существует по умолчанию.
                Это относится и к OpenBSD и к
                FreeBSD.
              syncdevpfsync(4) для сетевых обновлений.
              syncpeerpfsync(4) использует адрес
                multicast, а с данной опцией использует unicast.
              Пример:
# ifconfig pfsync0 syncdev em1
            
            Эта команда включает pfsync(4) на
            интерфейсе em1. Исходящие пакеты
            отправляются при помощи multicast и доступны всем хостам в
            сети, на которых запущен pfsync.
          
Совместное использование CARP и pfsync позволяет создать два и более брандмауэра и объединить их в устойчивый полнофункциональный кластер. При этом CARP реализует отказоустойчивую систему, а pfsync позволяет синхронизировать данные таблиц состояния, так, что при отказе мастера, запасная машина берёт на себя его функции и при этом не обрывает имеющиеся соединения.
Например, пусть у нас имеется два брандмауэра — fw1 и fw2:
              +----| WAN/Internet |----+
              |                        |
              |      общий адрес       |
              | +----192.0.2.100-----+ |
              | |                    | |
 192.0.2.1:em2|/                      \|em2:192.0.2.2
           +-----+        10.10.10.2+-----+
           | fw1 |-em1----------em1-| fw2 |
           +-----+10.10.10.1        +-----+
172.16.0.1:em0|\                      /|em0:172.16.0.2
              | |                    | | 
              | +----172.16.0.100----+ |
              |      общий адрес       |
              |                        |
           ---+-------Shared LAN-------+---
            Брандмауэры соединены «спина к спине» через кросс через интерфейсы em1. Оба соединены с локальной сетью при помощи интерфейсов em0 и с внешней сетью через интерфейсы em2. Адреса показаны на схеме. Мастер — fw1.
Конфигурируем fw1:
Выполняем необходимые настройки в ядре:#sysctl -w net.inet.carp.preempt=1 Настраиваем pfsync#ifconfig em1 10.10.10.1 netmask 255.255.255.0#ifconfig pfsync0 syncdev em1#ifconfig pfsync0 up Настраиваем CARP на внутреннем интерфейсе#ifconfig carp1 create#ifconfig carp1 vhid 1 carpdev em0 pass lanpasswd \ 172.16.0.100 netmask 255.255.255.0 Настраиваем CARP на внешнем интерфейсе#ifconfig carp2 create#ifconfig carp2 vhid 2 carpdev em2 pass netpasswd \ 192.0.2.100 netmask 255.255.255.0
Конфигурируем fw2:
Выполняем необходимые настройки в ядре:#sysctl -w net.inet.carp.preempt=1 Настраиваем pfsync#ifconfig em1 10.10.10.2 netmask 255.255.255.0#ifconfig pfsync0 syncdev em1#ifconfig pfsync0 up Настраиваем CARP на внутреннем интерфейсе#ifconfig carp1 create#ifconfig carp1 vhid 1 carpdev em0 pass lanpasswd \ advskew 128 172.16.0.100 netmask 255.255.255.0 Настраиваем CARP на внешнем интерфейсе#ifconfig carp2 create#ifconfig carp2 vhid 2 carpdev em2 pass netpasswd \ advskew 128 192.0.2.100 netmask 255.255.255.0
            Некоторые распространённые проблемы при использовании
            CARP и pfsync(4).
          
              И carpN и pfsyncN являются сетевыми
              интерфейсами и настраиваются так как дожны настраиваться
              обычные сетевые интерфейсы (см: Раздел 6.2.6, «Как сохранить установленные сетевые параметры»). В OpenBSD
              создаётся файл hostname.if:
            
              Файл /etc/hostname.carp1:
            
inet 172.16.0.100 255.255.255.0 172.16.0.255 vhid 1 carpdev em0 \
    pass lanpasswd
              
              Файл /etc/hostname.pfsync0:
            
up syncdev em1
              
              В FreeBSD вам понадобятся следующие
              строки в /etc/rc.conf:
            
ifconfig_carp1="172.16.0.100/24 vhid 1 carpdev em0 pass lanpasswd"
ifconfig_pfsync0="up suncdev em1"
              Иногда бывает нужно перенести мастера с одного хоста на другой. Например, надо останивить мастера для профилактических работ или для отладки. Здесь обсуждается как это сделать не вредя имеющимся коннектам, чтобы пользователи ничего не заметили.
              Для этих целей вы можете остановить интерфейс carp. Мастер при этом выставит
              бесконечно большое значение advbase и advskew запасные машины немедленно
              это обнаружат и одна из них примет на себя обязанности
              мастера.
            
# ifconfig carp1 down
              
              Другой вариант состоит в том, что вы увеличиваете значение
              advbase и advskew при этом обязанности
              мастера перейдут к запасной машине, но данная машина не
              будет удалена из группы CARP.
            
              Третий вариант состоит в том, чтобы управлять
              CARP'ом при помощи переменной
              demotion. Эта возможность пока
              реализована только в OpenBSD.
            
![]()  | Внимание | 
|---|---|
              Описанный механизм связанный с переменной
              demotion работает только в
              OpenBSD.
             | 
              Переменная demotion присваивается
              группе интерфейсов. Повышая эту величину вы можете
              опустить CARP на заданной группе
              интерфейсов. Текущее значение demotion
              можно увидеть при помощи команды
              ifconfig(8):
            
$ ifconfig -g carp
carp: carp demote count 0
              
              Здесь показано значение ассоциированное с группой carp.
            
Рассмотрим такой пример: имеется два брандмауэра с запущенным CARP со следующими CARP интерфейсами:
carp1carp2carp3carp4
              Задача состоит в том, чтобы перенести группы carp1 и carp2 на второй сервер.
            
Для начала присвоим эти интерфейсы группе «internal»:
#ifconfig carp1 group internal#ifconfig carp2 group internal$ifconfig internal carp1: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> mtu 1500 carp: MASTER carpdev em0 vhid 1 advbase 1 advskew 100 groups: carp internal inet 10.0.0.1 netmask 0xffffff00 broadcast 10.0.0.255 carp2: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> mtu 1500 carp: MASTER carpdev em1 vhid 2 advbase 1 advskew 100 groups: carp internal inet 10.0.1.1 netmask 0xffffff00 broadcast 10.0.1.255
              Теперь увеличим счётчик demotion для группы internal при
              помощи ifconfig(8):
            
$ifconfig -g internal internal: carp demote count 0#ifconfig -g internal carpdemote 50$ifconfig -g internal internal: carp demote count 50
              Теперь CARP передаст полномочия по
              интерфейсам carp1 и carp2 на вторую машину, но
              останется мастером для carp3 и
              carp4.
            
Чтобы вернуть полномчия обратно надо выполнить команду:
#ifconfig -g internal -carpdemote 50$ifconfig -g internal internal: carp demote count 0
              Некоторые сетевые демоны, такие как
              OpenBGPD и
              sasyncd(8) используют счётчик
              demotion для того, чтобы перед тем как
              установить BGP сессию или перед тем как синхронизировать
              IPSec SA, выяснить — является ли брандмауэр
              мастером.
            
              Фильтр должен работать на физическом
              интерфейсе, не на виртуальном интерфейсе carp0. Напрмер:
            
pass in on fxp0 inet proto tcp from any to carp0 port 22
              
              Если вы замените fxp0 на carp0 правило будет работать не
              так, как вы этого ожидаете.
            
![]()  | Замечание | 
|---|---|
              Не забывайте пропускать протокол CARP
              при помощи правила proto carp и
              трафик proto pfsync.
             | 
В данном примере пакетный фильтр используется как брандмауэр и NAT в домашней сети или небольшом офисе. Задача состоит в том, чтобы обеспечить доступ из внутренней сети в Интернет, обеспечить ограниченный доступ к брандмауэру из Интернета и обеспечить доступ к внутреннему web-серверу из Интернет.
Топология сети:
             WWW-server
[ COMP1 ]    [ COMP3 ]
   |            |                               
---+------+-----+------- xl0 [ BSD ] fxp0 -------- ( Internet )
          |
      [ COMP2 ]
            Во внутренней сети есть некоторое количество компьютеров. Сколько именно — неважно. У нас на диаграмме показано три. На компьютере COMP3 работает небольшой web-сервер. Внутренняя сеть 192.168.0.0/24
            Брандмауэр работает на OpenBSD (или любой
            другой BSD) на процессоре
            Celeron 300MHz с двумя сетевыми картами: 3com 3c905B
            (xl0) и Intel EtherExpress
            Pro/100 (fxp0). Брандмауэр
            соединён кабелем FastEthernet с провайдером. Для выхода
            внутренних машин в сеть используется NAT. Внешний адрес
            назначается провайдером динамически.
          
Разрешить следующий входящий трафик:
Мы считаем, что машина сконфигурирована как шлюз (т.е. включён проброс пакетов с интерфейса на интерфейс) и пакетный фильтр включён. О том как это делать написано в Раздел C.1, «Введение в работу с пакетным фильтром OpenBSD».
Определяем макросы для облегчения управления брандмауэром и упрощения набора правил:
ext_if="fxp0"
int_if="xl0"
tcp_services="{ 22, 113 }"
icmp_types="echoreq"
comp3="192.168.0.3"
            Первые две строки определяют сетевые интерфейсы брандмауэра. Если нам придётся перенести брандмауэр с машины на машину, нам надо будет изменить только эти две строчки, остальные правила будут по прежнему работоспособны. Третья и червёртая строки определяют номера открытых портов и типы ICMP сообщений принимаемых шлюзом. В последней строке задан адрес машины COMP3.
![]()  | Замечание | 
|---|---|
            Если соединение установлено через PPPoE, NAT трансляция
            должна осуществляться на интерфейсе tun0, не на fxp0.
           | 
Следующие две опции определяют поведение системы при блокировании пакетов и включают журналирование для внешнего интерфейса:
set block-policy return
set loginterface $ext_if
            Каждая UNIX-система имеет кольцевой интерфейс, необходимый для того, чтобы программы могли общаться друг с другом при помощи сетевых протоколов внутри машины. Фильтрацию на кольцевом интерфейсе лучше отключить — чтобы не мешать работе программ.
set skip on lo
            ![]()  | Замечание | 
|---|---|
            В OpenBSDlo
            это группа кольцевых интерфейсов, поэтому при появлении
            нового сетевого интерфейса вам не придётся ни о чём
            специально заботиться. В остальных системах,
            FreeBSD, NetBSD,
            DragonFly BSD, вам придётся
            определить эту опцию отдельно для каждого сетевого
            интерфейса lo0, lo1 и т.д. (Случай когда их больше
            одного не част).
           | 
Нет причин не использовать рекомендованные алгоритмы нормализации трафика. Поэтому нормализация, это всего одна строка:
scrub in
            Следующее правило используется для трансляции NAT всей внутренней сети:
nat on $ext_if from !($ext_if) to any -> ($ext_if)
            
            Мы можем заменить !($ext_if) на
            $int_if, но тогда нам придётся
            добавлять правила в брандмауэр, если мы добавим в шлюз ещё
            один интерфейс, который будет смотреть в другую внутреннюю
            сеть.
          
Круглые скобки вокруг интерфейса стоят потому, что адрес ему назначается динамически.
Для работы FTP-прокси, добавим якорь:
nat-anchor "ftp-proxy/*"
            Во-первых, нам понадобится правило перенаправления для работы ftp-proxy(8), чтобы клиенты из локальной сети могли пользоваться FTP:
rdr-anchor "ftp-proxy/*"
rdr on $int_if proto tcp from any to any port 21 -> 127.0.0.1 port 8021
            
            Заметим, что здесь будет перенаправляться только FTP с
            управляющим каналом на порту 21. Если пользователи регулярно
            используют другие порты, следует использовать список: from any to any port {21, 221}.
          
Во-вторых, нам надо перенаправить все входящие соединения на 80-й порт машины COMP3.
rdr on $ext_if proto tcp from any to any port 80 -> $comp3
            Для начала определяем политику default deny:
block in
            Здесь мы блокировали весь входящий трафик, даже из внутренней сети. Теперь мы будем по очереди описывать правила пропускающие нужный трафик.
Имейте ввиду, что пакетный фильтр может блокировать отдельно входящий трафик и отдельно исходящий. Мы с вами блокировали весь входящий трафик, но если пакет уже вошёл (т.е. он соответствовал разрешающему правилу, которое будет записано ниже), то мы можем его выпустить:
pass out keep state
            Нам понадобится якорь для ftp-proxy(8):
anchor "ftp-proxy/*"
            Неполохо так же защититься от спуфинга:
antispoof quick for { lo $int_if }
            Теперь откроем порты, используемые сервисами, котрые должны быть доступны из Интернет. Для начала, трафик предназначеный самому брандмауэру:
pass in on $ext_if inet proto tcp from any to ($ext_if) \
   port $tcp_services flags S/SA keep state
            
            Благодаря указанию портов в макросе $tcp_services добавление нового
            сервиса предельно упрощается: достаточно просто
            отредактировать определение макроса и перегрузить набор
            правил. Чтобы добавить сервисы UDP можно просто добавить
            макрос $udp_services аналогичным
            образом. При этом понадобится вставить такое же правило с
            указанием proto udp.
          
Далее надо пропустить трафик идущий на машину COMP3, который прошёл трансляцию rdr:
pass in on $ext_if inet proto tcp from any to $comp3 port 80 \
    flags S/SA synproxy state
            Чтобы немного увеличить безопасность web-сервера мы используем TCP SYN Proxy.
Пропускаем трафик ICMP:
pass in inet proto icmp all icmp-type $icmp_types keep state
            
            Аналогично макросу $tcp_services,
            мы можем редактировать макрос $icmp_types, чтобы варьировать типы
            пакетов принимаемых брандмауэром. Заметьте, это правило
            касается всех интерфейсов.
          
Теперь мы пропускаем весь трафик из внутренней сети. Мы предполагаем, что пользователи во внутренней сети знают что они делают и это не вызовет проблем. Однако во многих случаях это не так и понадобятся более жёсткие ограничения.
pass in quick on $int_if
            
            Трафик TCP, UDP и ICMP может покидать машину благодаря
            правилу «pass out keep
              state». Информация о состояниях сохраняется,
            таким образом, ответные пакеты тоже будут пропущены.
          
# макросы
ext_if="fxp0"
int_if="xl0"
tcp_services="{ 22, 113 }"
icmp_types="echoreq"
comp3="192.168.0.3"
# опции
set block-policy return
set loginterface $ext_if
set skip on lo
# нормализация трафика
scrub in
# nat/rdr
nat on $ext_if from !($ext_if) -> ($ext_if:0)
nat-anchor "ftp-proxy/*"
rdr-anchor "ftp-proxy/*"
rdr pass on $int_if proto tcp to port ftp -> 127.0.0.1 port 8021
rdr on $ext_if proto tcp from any to any port 80 -> $comp3
# Фильтрация
block in
pass out keep state
anchor "ftp-proxy/*"
antispoof quick for { lo $int_if }
pass in on $ext_if inet proto tcp from any to ($ext_if) \
   port $tcp_services flags S/SA keep state
pass in on $ext_if inet proto tcp from any to $comp3 port 80 \
    flags S/SA synproxy state
pass in inet proto icmp all icmp-type $icmp_types keep state
pass quick on $int_if
          Программа pfctl(8) предназначена для управления системой pf(4). Она позволяет устанавливать правила, менять значения параметров и выводить статистическую информацию. Ниже описаны опции данной команды.
-e-d-h-n-f file-n
          -oВключить опимизацию правил. Оптимизатор может улучшить производительность пакетного фильтра путём удаления повторов и расположения правил в другом порядке. Вот что он делает:
            При указании второй опции -o, оптимизатор
            начинает вставлять ключевое слово quick в правила.
          
            Побочным эффектом оптимизации может явиться изменение
            статистической информации по правилам. Если это важно для
            системы учёта трафика (биллинговой системы), вам придётся
            расставить опцию lable, дабы
            предотвратить пересортировку правил оптимизатором.
          
-z-i interface-p device/dev/pf.
          -A-N-O-R-a anchor
            Применять опции -f, -F и
            -s только к правилам соответствующим якорю
            anchor. Например, следующая команда позволит просмотреть
            правила добавленные при помощи команды
            authpf(8) для пользователя smith, при
            условии, что программа authpf имеет pid 1234:
          
# pfctl -a "authpf/smith(1234)" -s rules
            Кроме того, данная опция позволяет ограничивать область видимости таблицы:
# pfctl -a foo/bar -t mytable -T add 1.2.3.4 5.6.7.8
            
            Данная команда изменит таблицу созданную в якоре foo/bar но не тронет глобальную
            таблицу, даже в случае конфликта имён.
          
-k hostСбросить все записи в таблице состояний, относящиеся к указанному хосту. Можно употребить несколько раз:
# pfctl -k host1 -k host2
            Сбросит все записи относящиеся к соединениям между host1 и host2.
-mУстановить явно заданные опции без сброса прочих:
# echo "set loginterface fxp0" | pfctl -mf -
            -D macro=value-F modifierСбросить параметр modifier в пакетном фильтре. Можно указать всего одной буквой:
-F nat | Сбросить правила nat | 
-F queue | Сбросить правила queue | 
-F rules | Сбросить правила фильтрации | 
-F state | Сбросить таблицу состояния (для nat и фильтрации) | 
-F Sources | Сбросить информацию о источниках пакетов (см. Раздел C.2.1.4.7, «Опции таблицы состояний») | 
-F info | Сбросить статистическую информацию (не привязанную к правилам фильтрации) | 
-F Tables | Сбросить содержимое всех таблиц | 
-F osfp | Сбросить содержимое таблицы для пассивного детектирования операционной системы | 
-F all | Сбросить всё | 
-s modifierПоказывать параметры пакетного фильтра, указанные в modifier:
-s nat | Показать загруженные правила nat | 
-s queue | 
                      Показать загруженные очереди. При указании совместно
                      с опцией -v показывается статистика
                      по очередям. При указании двух флагов
                      -v -v, пакетный фильтр входит в
                      цикл и показывает информацию on-line обновляя её раз
                      в 5 минут. При этом видна так же измеренная полоса
                      пропускания по каждой очереди.
                     | 
-s rules | 
                      Показать загруженные правила фильтрации. При
                      использовании совместно с ключём -v
                      показывается статистика по каждому правилу:
                      количество срабатываний, количество пакетов и байт
                      прошедших через правило. Оптимизация «set
                      step», включённая в ядре по умолчанию,
                      отключает вычисление статистики, когда это только
                      возможно. Пакеты соответствующие правилу учитывающему
                      состояни (keep state) учитываются только в этом
                      правиле.
                     | 
-s Anchors | 
                      Показать якоря, загруженные непосредственно из
                      главного набора правил. Если надо просмотреть
                      вложенные якоря, надо употребить аргумент
                      -a anchor. При указании опции
                      -v все якоря рекурсивно
                      разворачиваются.
                     | 
-s state | Показать таблицу состояний | 
-s Sources | Показать информацию о источниках пакетов (см. Раздел C.2.1.4.7, «Опции таблицы состояний») | 
-s info | 
                      Показать статистическую информацию и счётчики. При
                      использовании совместно с -v
                      показывает информацию об источниках пакетов.
                     | 
-s labels | Показать статистику по каждому правилу. (Метки, количество срабатываний, количество пакетов, количество байт). | 
-s timeouts | Показать установленные таймауты. | 
-s memory | Показать текущие ограничения на размеры пулов памяти. | 
-s Tables | Показать список загруженных таблиц. | 
-s osfp | Показать список известных операционных систем для пассивного детектирования операцонной системы. | 
-s Interfaces | 
                      Показать список интерфейсов и драйверов интерфейсов,
                      доступных пакетному фильтру. Совметстно с двумя
                      аргументами -v -v может показать
                      статистикку на интерфейсе. Можно ограничить
                      статистику одним интерфейсом, если использовать
                      совместно с опцией -i interface.
                     | 
-s all | Паказать всю информацию, кроме списка интерфейсов и списка операционных систем. | 
-t table-T команда [адреса ...]Указывает действие, которое можно совершить с таблицей. Команда может быть сокращена до одной буквы. Допустимы следующие команды:
-T kill | Уничтожить таблицу | 
-T flush | Очистить таблицу | 
-T add | Добавить адреса в таблицу. Если таблица не существует, она автоматически создаётся | 
-T delete | Удалить указанные адреса из таблицы | 
-T replace | Заменить адреса в таблице. Если таблица не существует, она автоматически создаётся | 
-T show | Показать содержимое таблицы | 
-T test | Проверить, принадлежит ли указанный адрес таблице | 
-T zero | Очистить статистическую информацию по таблице | 
-T load | 
                      Загрузить только определения таблиц. Используется
                      совместно с опцией -f
                     | 
            Для опций add, delete,
            replace и test адреса
            можно задавать как в командной строке, так и в файле,
            с помощью опции -f. Комментарии в
            текстовом файле с перечнем адресов, можно начинать с
            символа #. Можно использовать
            один или два раза флаг -v для того, чтобы
            информация о проделанных действиях печаталась подробнее.
            При этом перед каждым адресом будет печататься следующий
            флаг:
          
| A | Добавлен адрес (сеть) | 
| C | Адрес (сеть) изменены | 
| D | Адрес (сеть) удалены | 
| M | 
                      Адрес (сеть) найдены в таблице (для операции
                      test)
                     | 
| X | Адрес (сеть) дублируются (уже есть в таблице), поэтому игнорированы | 
| Y | 
                      Адрес (сеть) не могут быть добавлены или удалены,
                      так как конфликтуют с записью с знаком !
                     | 
| Z | Статистика по этому адресу сброшена | 
            В каждой таблице есть счётчики, которые можно просмотреть
            при помощи флага -v. Например, следующая
            команда создаёт открытый всем ветрам брандмауэр и посылает
            десять пингов на сервер ftp.openbsd.org:
          
#printf "table <test> { ftp.openbsd.org }\n \ pass out to <test> keep state\n" | pfctl -f-$ping -qc10 ftp.openbsd.org
            Теперь мы можем использовать команду show для того, чтобы просмотреть
            статистику по адресам из таблицы:
          
# pfctl -t test -vTshow
   129.128.5.191
        Cleared:     Thu Feb 13 18:55:18 2003
        In/Block:    [ Packets: 0        Bytes: 0        ]
        In/Pass:     [ Packets: 10       Bytes: 840      ]
        Out/Block:   [ Packets: 0        Bytes: 0        ]
        Out/Pass:    [ Packets: 10       Bytes: 840      ]
            Строка Cleared показывает когда начался учёт.
            Аналогично можно просматривать общую информацию о таблицах
            используя флаг -v дважды с командой
            -s Tables. Таким образом, мы получим
            информацию о количестве адресов в таблицах, количестве
            правил ссылающихся на таблицу, и общую статистику по
            таблице.
          
# pfctl -vvsTables
--a-r-  test
    Addresses:   1
    Cleared:     Thu Feb 13 18:55:18 2003
    References:  [ Anchors: 0        Rules: 1        ]
    Evaluations: [ NoMatch: 3496     Match: 1        ]
    In/Block:    [ Packets: 0        Bytes: 0        ]
    In/Pass:     [ Packets: 10       Bytes: 840      ]
    In/XPass:    [ Packets: 0        Bytes: 0        ]
    Out/Block:   [ Packets: 0        Bytes: 0        ]
    Out/Pass:    [ Packets: 10       Bytes: 840      ]
    Out/XPass:   [ Packets: 0        Bytes: 0        ]
            Как видно из строки Evaluations, только один пакет соответствовал правилу, остальные, однако корректно учтены таблицей, так как соответствовали записи в таблице состояний. Перезагрузка правил не влияет на счётчики в таблице. Строки XPass увеличиваются в том случае, если пакет пропускается благодаря записи в таблице состояний, но при этом более не соответствует таблице. (Например, если адрес удалён из таблицы, уже открытые соединения не должны оборваться, если они соответвуют таблице состояний.)
            С одним флагом -v будет выведена только
            первая строка, в которой приведены флаги таблицы и её
            названия. Вот перечень флагов:
          
| c | 
                      Константа. Содержимое таблицы не может быть
                      изменено вне pf.conf(5)
                     | 
| p | persist — таблица не удаляется автоматически, когда на неё не ссылается ни одно правило. | 
| a | 
                      Активная таблица. Таблицы без этого флага реально
                      не существуют, они не могут содержать адреса и
                      видны только если задан флаг -g.
                     | 
| i | inactive — неактивная таблица. Этот влаг выставляется на таблице, на время, в течение которого в неё «заливаются» данные. | 
| r | На данную таблицу есть ссылки, т.е. на неё реально ссылаются какие-то правила. | 
| h | Таблица скрыта (на время), так как при помощи якоря загружена другая таблица с таким же именем. | 
-v-g-x levelУровень отладки. Можно сокращать до одной буквы:
-x none | Не выводить отладочных сообщений | 
-x urgent | Выводить отладочные сообщения только для серьёзных ошибок. По умолчанию включён он. | 
-x misc | Выводить отладочные сообщения только для различных ошибок. | 
-x loud | Выводить всяческую отладочную информацию | 
Пример C.1. Просмотр статистики на интерфейсе выбранном при помощи
          опции loginterface
          Опция loginterface в файле
          /etc/pf.conf может указать один (и только
          один) интерфейс, для которого собирается полная статистическая
          информация. (См. Раздел C.2.2.1, «Опции в пакетном фильтре».)
        
# pfctl -s info
Status: Enabled for 14 days 10:02:15          Debug: Urgent
Hostid: 0xd56f1383
Interface Stats for rl1               IPv4             IPv6
  Bytes In                       193781803                0
  Bytes Out                     1799932863                0
  Packets In
    Passed                         1716610                0
    Blocked                           7973                0
  Packets Out
    Passed                         2013028                0
    Blocked                              0                0
State Table                          Total             Rate
  current entries                        5               
  searches                         3848785            3.1/s
  inserts                            77192            0.1/s
  removals                           77187            0.1/s
Counters
  match                             206160            0.2/s
  bad-offset                             0            0.0/s
  fragment                               0            0.0/s
  short                                  0            0.0/s
  normalize                              0            0.0/s
  memory                                 0            0.0/s
  bad-timestamp                          0            0.0/s
  congestion                             0            0.0/s
  ip-option                              0            0.0/s
  proto-cksum                            0            0.0/s
  state-mismatch                       604            0.0/s
  state-insert                           0            0.0/s
  state-limit                            0            0.0/s
  src-limit                              0            0.0/s
  synproxy                               0            0.0/s
        Пример C.2. Кто из заблокированных взломщиков пытался пройти в систему в последнее время?
# pfctl -t crackers -v -v -Ts | grep "In/Block:.*Packets: [^0]" -B2
   59.124.47.229
        Cleared:     Fri Apr 20 19:29:30 2007
        In/Block:    [ Packets: 159                Bytes: 9540               ]
--
   61.109.245.208
        Cleared:     Mon Apr 23 03:13:25 2007
        In/Block:    [ Packets: 159                Bytes: 9540               ]
--
   62.193.224.155
        Cleared:     Sun Apr 15 00:03:19 2007
        In/Block:    [ Packets: 1                  Bytes: 60                 ]
--
   66.34.136.28
        Cleared:     Wed Apr 25 00:06:03 2007
        In/Block:    [ Packets: 3744               Bytes: 164736             ]
--
   67.15.8.50
        Cleared:     Tue Apr 24 03:44:28 2007
        In/Block:    [ Packets: 568                Bytes: 34080              ]
--
   88.2.123.116
        Cleared:     Sat Apr 21 11:31:02 2007
        In/Block:    [ Packets: 48                 Bytes: 2880               ]
--
   210.87.136.171
        Cleared:     Sun Apr 15 00:03:19 2007
        In/Block:    [ Packets: 1                  Bytes: 60                 ]
--
   219.153.32.201
        Cleared:     Mon Apr 23 10:54:24 2007
        In/Block:    [ Packets: 164                Bytes: 9840               ]
        Пример C.3. Просмотр таблицы состояний
#pfctl -ss self tcp 172.19.0.2:22 <- 172.19.0.34:60730 ESTABLISHED:ESTABLISHED self tcp 172.19.0.2:22 <- 172.19.0.34:43768 ESTABLISHED:ESTABLISHED self pfsync 172.19.0.2 -> 0.0.0.0 SINGLE:NO_TRAFFIC#pfctl -vvss self tcp 172.19.0.2:22 <- 172.19.0.34:60730 ESTABLISHED:ESTABLISHED [3302985293 + 64096] wscale 1 [3073141737 + 66608] wscale 5 age 06:30:34, expires in 24:00:00, 16093:13420 pkts, 1181656:3943411 bytes, rule 5 id: 4621338700019ddb creatorid: d56f1383 self tcp 172.19.0.2:22 <- 172.19.0.34:43768 ESTABLISHED:ESTABLISHED [2485562129 + 63136] wscale 1 [4004983129 + 66608] wscale 5 age 05:08:21, expires in 23:59:58, 2743:2321 pkts, 184400:1056475 bytes, rule 5 id: 4621338700019f1d creatorid: d56f1383 self pfsync 172.19.0.2 -> 0.0.0.0 SINGLE:NO_TRAFFIC age 02:33:08, expires in 00:00:29, 15314:14760 pkts, 6238352:826560 bytes, rule 14 id: 462133870001ca8b creatorid: d56f1383
          При наличии на интерфейсе NAT трансляции, она отображается в
          данном отчёте. Это было показано при обсуждении
          pf.conf(5) в Раздел C.2.1.5.7, «Проверка состояния правил NAT».
        
См. так же Раздел C.5.2, «pftop».
Пример C.4. Сколько пакетов на какое правило попало?
# pfctl -vvsr 
@0 scrub in all fragment reassemble
  [ Evaluations: 8292326   Packets: 3818454   Bytes: 0           States: 0     ]
@0 block return in log all
  [ Evaluations: 389809    Packets: 2153      Bytes: 935446      States: 0     ]
@1 pass quick on lo0 all
  [ Evaluations: 389809    Packets: 237302    Bytes: 62225678    States: 0     ]
@2 pass in quick on rl1 inet proto udp from any to 172.19.0.2 port = domain
  [ Evaluations: 152507    Packets: 19368     Bytes: 1286672     States: 0     ]
@3 pass in quick on rl1 inet proto tcp from <trusted_ip:8> to 172.19.0.2 port = ssh keep state
  [ Evaluations: 48415     Packets: 19371     Bytes: 2672486     States: 0     ]
@4 block return in log quick on rl1 inet proto tcp from <crackers:314> to 172.19.0.2 port = ssh
  [ Evaluations: 46532     Packets: 7310      Bytes: 371716      States: 0     ]
@5 pass in on rl1 inet proto tcp from any to 172.19.0.2 port = ssh flags S/SA keep state
  [ Evaluations: 39219     Packets: 822253    Bytes: 144372004   States: 2     ]
@6 pass in on rl1 inet proto tcp from any to 172.19.0.2 port = smtp flags S/SA keep state
  [ Evaluations: 39400     Packets: 49654     Bytes: 41860091    States: 0     ]
@7 pass in on rl1 inet proto tcp from any to 172.19.0.2 port = domain flags S/SA keep state
  [ Evaluations: 39400     Packets: 763       Bytes: 44898       States: 0     ]
@8 pass in on rl1 inet proto tcp from any to 172.19.0.2 port = http flags S/SA keep state
  [ Evaluations: 39400     Packets: 2409271   Bytes: 1888003875  States: 0     ]
@9 pass in on rl1 inet proto tcp from any to 172.19.0.2 port = imap flags S/SA keep state
  [ Evaluations: 39400     Packets: 53382     Bytes: 36933799    States: 0     ]
@10 pass in on rl1 inet proto udp from any port = domain to 172.19.0.2 keep state
  [ Evaluations: 41095     Packets: 293       Bytes: 21590       States: 0     ]
@11 pass in inet proto icmp all keep state
  [ Evaluations: 47877     Packets: 0         Bytes: 0           States: 0     ]
@12 pass in on rl1 from <internal_ip:3> to any keep state
  [ Evaluations: 47877     Packets: 23966     Bytes: 2072826     States: 0     ]
@13 pass out on rl1 from any to <internal_ip:3> keep state
  [ Evaluations: 125819    Packets: 0         Bytes: 0           States: 0     ]
@14 pass out on rl1 all keep state
  [ Evaluations: 77942     Packets: 1184788   Bytes: 239933074   States: 1     ]
        В отчёте, там, где даны имена таблиц, указано сколько в них записей.
Все эти данные позволяют применять утилиту pfctl(8) не только для управления пакетным фильтром, но и для сбора разнообразных данных и постоения биллинговых систем. Некоторое уже готовое програмное обеспечение на эту тему предствлено в Раздел C.4, «Интеграция пакетного фильтра с програмным окружением».
Здесь я приведу пример интеграции пакетного фильтра с програмным окружением существующим в BSD, на примере борьбы с атаками brute-force — лобовым подбором паролей к машине. Любая система с запущенным на ней sshd(8) демоном подвергается многочисленным атакам brute-force. Если в вашей системе присутствуют пользователи со слабыми паролями, в виду многочисленности таких атак вас рано или поздно взломают. Существует множество способов защиты от атак brute-force. Их обилие свидетельствует о том, что все они плохи.
                Обычно такой метод реализуется через систему PAM. В
                Linux для этих целей есть специальный
                модуль — pam_tally.
                В BSD никаких аналогов я не знаю,
                однако его не сложно реализовать при помощи модуля pam_exec. Идея состоит в том, что в
                некоторой базе данных фиксируются попытки неудачного
                захода от каждого пользователя. Если оказывается превышен
                некоторый лимит, т.е. пользователь предпринял более 5
                неудачных попыток входа, он блокируется и разблокировать
                его может только суперпользователь.
              
Данный метод неудачен во всех отношениях: главный его недостаток — идеологический. Модуль наказывает не атакующего, а атакуемого. Задача защиты поставлена с ног на голову. Некоторые brain-damaged администраторы всерьёз предполагают, что таким образом можно защититься от атаки. Это не так:
pam_tally никак этому
                  воспрепятствовать не может.
                
                У модуля pam_tally есть
                многочисленные дополнительные опции, которые позволяют
                сделать его работу более или менее вменяемой. Например,
                можно запретить блокировку root'а и обеспечить
                авторазблокирование по истечении некоторого периода
                времени.  Однако модуль неправильно задуман, при его
                проектировании была сделана неправильная посылка, это
                неисправимо.
              
![]()  | Замечание | 
|---|---|
SSH может не использовать модули PAM
                вообще. Проверьте содержимое опции UsePAM
                в конфигурационном файле
                /etc/ssh/sshd_config.
               | 
![]()  | Замечание | 
|---|---|
OpenBSD не использует систему
                PAM вообще. Похожего функционала в ней
                можно, вероятно, добиться через пользовательские стили
                аутентификации, описанные в Раздел F.2, «/etc/login.conf в OpenBSD».
               | 
                В настройках демона sshd(8) можно
                задать опции AllowUsers,
                AllowGroups, DenyUsers и
                DenyGroups. Таким образом, вы можете явно
                указать какие пользователи могут пользоваться сервисом
                SSH на вашей системе. Это полезно, если
                вам надо обеспечить доступ для одного-двух
                «судоеров» (уполномоченных пользователей). Но
                если речь идёт о машине предоставляющей shell-хостинг,
                такая схема не подходит.
              
![]()  | Замечание | 
|---|---|
                Независимо ни от чего, безусловно надо выставлять опцию
                PermitRootLogin в No.
                Это сделано по умолчанию во всех системах
                BSD, но многие
                Linux-системы по умолчанию допускают
                bruteforce пользователя root! Особенно это относится к
                разнообразным Desktop'ам.
               | 
                Большего функционала можно добиться при помощи модулей
                PAM.  В FreeBSD при помощи модуля pam_login_access можно указать
                какие пользователи с каких хостов и с каких терминалов
                могут входить в систему. Эта информация хранится в файле
                /etc/login.access(5).
              
Наконец, вы можете в брандмауэре открыть проход на 22-й порт только с некоторых IP-адресов, однако в этом случае у вас не будет информации о логинах. Таким образом, этот метод хуже метода с использованием PAM, так как менее гибок, однако он больше экономит ресурсы системы.
Все эти способы ограничения атак имеют один общий недостаток — они неприменимы в случае, если shell доступ надо предоставить всем, или почти всем и в случае, если пользователи склонны перемещаться в пространстве и заходить в систему из разных мест.
Сканированием интернета занимаются роботы. Есть сообщения, что некоторые роботы прекращают работу, если брандмауэр блокирует сессию. Мы можем попробовать в брандмауэре блокировать сессии, если они образуются чаще, чем три раза в минуту, например. Т.е. средствами брандмауэра запретить устанавливать сессию чаще чем три раза в минуту. Это может отпугнуть некоторых роботов.
                Данное действие надо осуществлять на уровне брандмауэра, а
                не на уровне модуля PAM. В пакетном
                фильтре этого функционала можно добиться при помощи опции
                max-src-conn-rate (см. Раздел C.2.1.4.7, «Опции таблицы состояний»).
              
                Идеологически данный метод плох тем же, чем и метод с
                pam_tally —
                наказывается не атакующий, а атакуемый. Кроме того, мне
                кажется, что эффективность такого метода сильно
                преувеличена. Когда я блокирую у себя злоумышленника, он
                продолжает попытки достучаться до сервера ещё в течение
                получаса.
              
                Сервер sshd(8) заносит сообщения в
                журнал от системы auth уровня важности info. По умолчанию
                они попадают в журнальный файл
                /var/log/auth.log:
              
Apr 19 00:18:22 house sshd[15877]: Invalid user adam from 83.19.31.123
Apr 19 00:18:25 house sshd[15879]: Invalid user stephen from 83.19.31.123
Apr 19 04:19:27 house sshd[22644]: Invalid user test from 86.54.112.218
Apr 19 04:19:28 house sshd[22646]: Invalid user guest from 86.54.112.218
Apr 19 04:19:28 house sshd[22648]: Invalid user admin from 86.54.112.218
Apr 19 04:19:29 house sshd[22650]: Invalid user admin from 86.54.112.218
Apr 19 04:19:35 house sshd[22660]: Invalid user test from 86.54.112.218
                На основании этих записей можно на лету заносить адреса злоумышленников в чёрный список и блокировать в брандмауэре.
Эта идея тоже не лишена недостатков: за одним IP адресом может скрываться большое количество хостов (выходящих через NAT) и многие из них могут принадлежать добросовестным пользователям. Да и сам источник атаки, возможно, о ней не подозревает... Однако здесь «наказывается» атакующая сторона.
                В сети немало готового програмного обеспечения, борющегося
                с атаками brute-force подобным образом. Как вариант, вы
                можете попробовать рассмотреть программу
                sshguard. (В FreeBSD
                см. порт security/sshguard.)
                sshguard незлопамятна — она
                не ведёт никаких собственных баз с вредными IP адресами и
                не занимается разбором существующих журнальных файлов. Она
                лишь осуществляет мониторинг текущих событий. Несомненным
                преимуществом sshguard является то, что
                она не громоздка — маленькая программка
                написанная на C, и при этом может взаимодействовать с
                пакетным фильтром OpenBSD,
                ipfw(8) FreeBSD и
                iptables(8) в Linux.
              
Мы рассмотрим как реализовать эту методику самостоятельно при помощи пакетного фильтра и дополнительного программного обеспечения: Python, SQLite.
Пусть имеется некоторый хост с запущенной а нём операционной системой BSD, всё равно какой: FreeBSD, OpenBSD, NetBSD или DragonFly BSD. В системе запущен демон sshd(8). Настройки SSH стандартны — демон слушает 22-й порт. На сервере запущен пакетный фильтр от OpenBSD.
Преступление: Критерий атаки — 8 попыток аутентификации под несуществующим логином или одна попытка аутентификации под метапользователем (root, toor и системные сервисы).
Наказание: Блокируем в брандмауэре доступ с «проштрафившегося» IP на 22-й порт сервера навсегда.
          В журнал syslogd(8) записи от демона
          sshd(8) попадают от средства auth и имеют уровень важности info. Сообщения о попытке логина от
          пользователя root выглядят следующим
          образом:
        
Mar 22 17:48:13 house sshd[16889]: error: PAM: authentication error for root from 218.26.165.234
Mar 22 17:49:48 house sshd[16893]: error: PAM: authentication error for root from 218.26.165.234
Mar 22 17:49:50 house sshd[16893]: error: PAM: authentication error for root from 218.26.165.234
Mar 22 17:51:38 house sshd[16916]: error: PAM: authentication error for root from 218.26.165.234
Mar 22 17:51:40 house sshd[16916]: error: PAM: authentication error for root from 218.26.165.234
          Сообщения о попытке логина под несуществующим логином:
Apr 19 00:14:51 house sshd[15782]: Invalid user admin from 83.19.31.123
Apr 19 00:14:58 house sshd[15784]: Invalid user admin from 83.19.31.123
Apr 19 00:15:04 house sshd[15786]: Invalid user admin from 83.19.31.123
Apr 19 00:15:09 house sshd[15799]: Invalid user admin from 83.19.31.123
Apr 19 00:15:31 house sshd[15809]: Invalid user test from 83.19.31.123
Apr 19 00:15:36 house sshd[15811]: Invalid user test from 83.19.31.123
Apr 19 00:15:41 house sshd[15813]: Invalid user webmaster from 83.19.31.123
Apr 19 00:15:55 house sshd[15817]: Invalid user username from 83.19.31.123
          ![]()  | Замечание | 
|---|---|
| И пусть владельцы этих адресов не обижаются, что попали в Историю :) — логи настоящие. | 
Отлавливать IP адреса можно при помощи следующего регулярного выражения (здесь и далее применяется язык программирования Python):
# Следующие строки сгенерированы автоматически при помощи awk(1):
# awk -F: '$3<999 {printf("    \"%s\",\n", $1)}' /etc/passwd
# При использовании vim (:!cmd) не забудьте защитить знак '%'.
METAUSERS = [
    "root", "toor", "daemon", "operator", "bin", "tty", "kmem", "games",
    "news", "man", "sshd", "smmsp", "mailnull", "bind", "proxy", "_pflogd",
    "_dhcp", "uucp", "pop", "www", "mailman", "mysql", "alias", "cyrus",
    ]
METAUSERS_SQL = " or ".join(['login = "%s"'%x for x in METAUSERS])
# Регулярное выражение для поиска злоумышленников
SSH_BAD_USER = re.compile(r"""(?xm)
    ^(?P<date>(?:Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\ +\d+\ \d+:\d+:\d+)\s
    house\s
    sshd\[\d+\]:\ (?:I(?:nvalid|llegal)\ user\ (?P<login>\S+)|
                     error:\ PAM:\ authentication\ error\ for\ (?P<metauser>%s))\s
    from\ (?P<ip>\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})
    """%"|".join(METAUSERS))
          Для того, чтобы реагировать на события немедленно, можно записывать сообщения о событиях не только в файл, но и через pipe в скрипт. Конечно, мы могли бы поместить сценарий реагирующий на события в cron(8), и он бы разбирал журнальные файлы раз в полчаса, однако это привело бы к снижению в оперативности и к неоправданному расходу ресурсов системы. Демон syslogd(8) во многих дистрибутивах Linux умеет записывать только в именованный канал. Возможности syslogd(8) в BSD более привлекательны — он позволяет писать непосредственно на стандартный ввод программе, таким образом, он сам следит за тем, чтобы программа обработчик событий была запущена.
          Итак, в файл /etc/syslog.conf(5) помещаем
          следующие строки:
        
auth.info;authpriv.info                         /var/log/auth.log
auth.info                                       | exec /root/bin/bfdefender -a
          
          Здесь подразумевается, что
          /root/bin/bfdefender это программа
          обработчик событий, которая читает стандартный ввод, если
          вызвана с аргументом -a. Поскольку, команда,
          после знака | выполняется
          syslogd(8) демоном через
          sh(1), мы применили команду exec. Она замещает процесс
          sh(1) на bfdefender.
        
          Вот как выглядит дерево процессов при использовании ключевого
          слова exec:
        
$pgrep python2.5 90433$pstree -p 90433 -+= 00000 root [swapper] \-+= 00001 root /sbin/init -- \-+= 25867 root /usr/sbin/syslogd -l /var/run/log -l /var/named/var/run/log \--= 90433 root /usr/local/bin/python2.5 /root/bin/bfdefender -a
          А вот как оно выглядит, если про команду exec забыть:
        
$pgrep python2.5 90385$pstree -p 90385 -+= 00000 root [swapper] \-+= 00001 root /sbin/init -- \-+= 25867 root /usr/sbin/syslogd -l /var/run/log -l /var/named/var/run/log \-+= 90383 root sh -c /root/bin/bfdefender -a \--= 90385 root /usr/local/bin/python2.5 /root/bin/bfdefender -a
В пакетном фильтре необходимо создать две таблицы: таблицу с «хорошими» адресами, дабы случайно не заблокировать что-то не то, и таблицу с плохими адресами:
table <crackers> persist file "/etc/crackers"
table <trusted_ip> persist { \
   62.117.108.0/26\
   212.57.97.252\
}
.....
pass in quick on $ext_if inet proto tcp from <trusted_ip> \
    to $ext_if port ssh keep state
block in log quick on $ext_if inet proto tcp from <crackers> \
    to $ext_if port ssh
          
          Таблицу <crackers> мы будем
          на лету модифицировать при помощи скрипта, обрабатывающего
          журнальные события.
        
# pfctl -t crackers -Ta 218.26.165.234 83.19.31.123
2/2 addresses added.
          Что же должен делать обработчик событий?
/etc/crackers из которого будет брать
            информацию пакетный фильтр при перезапуске.
          В каком виде обработчик должен хранить промежуточную информацию? Сценарий на python(1) может хранить информацию в различных форматах. В виде конфигурационных файлов, в виде сериализованных объектов, во внешних базах данных, таких как MySQL и её аналоги. (Забегая вперёд, скажу, что сам я предпочёл вариант с SQLite.)
Недостатком конфигурационных файлов является то, что их трудно разбирать, это значит, что либо мы будем тратить несколько драгоценных секунд (а может быть и минут) при каждом запуске сценария, либо мы должны хранить уже «пережёванную» информацию.
Дело в том, что, согласно поставленной задаче, мы должны сохранять информацию не только о том, кто проштрафился (это список из нескольких сот IP адресов), но и информацию о том, под каким именем и сколько раз к нам подсоединялись злоумышленники. Это усложнит строение конфигурационного файла.
          Пожалуй лучшее решение, которое тут можно
          предложить — на лету писать сценарий на
          python(1) и подгружать его в качестве модуля.
          Т.е. использовать сам python(1) в качестве
          парсера конфигурационного файла.  Это и решит, отчасти, проблему
          со скоростью, и упростит резервное копирование. Однако при этом
          мы будем мусорить по диску прекомпилированными файлами
          .pyc и .pyo, которые
          будут содержать в себе секретную информацию, и нам придётся за
          всем этим безобразием следить. Не лучший вариант.
        
Мы можем хранить информацию при помощи сериализованных объектов python(1). Это позволит ещё сильнее ускорить запуск. Однако работать с таким файлом не очень удобно — его формат непрозрачен. Человек, разбирающийся с python(1) легко с ним сладит, но не многие сочтут такой способ удобным. (Хотя в том, что таковые найдутся — не сомневаюсь.)
Наконец, можно хранить данные во внешней базе данных.
Для этого мы можем использовать СУБД, типа MySQL или PostgreSQL. Однако такое решение представляется слишком громоздким и опасным — при выходе из строя базы данных (конструкция, как ни крути, сложная и капризная) наш програмный комплекс сломается.
Более разумным представляется использование сисемы SQLite. SQLite не требует никакого демона, Python будет обращаться непосредственно файлу с базой данных. Это достаточно быстро и весьма надёжно.
Я не могу здесь рассказывать о том, как программировать на Python. Эта задача явно выходит за рамки данного учебника. Здесь будет приведено описание принципов работы скрипта и HOWTO: как его применять. Сам скрипт можно найти по следующей ссылке: bfdefender — скрипт для защиты от bruteforce атак.
          Для работы данного скрипта нам понадобится установить следующие
          порты: lang/python25, databases/sqlite3 и databases/py-sqlite3.
        
          Для начала, скрипт надо запустить с опцией -i:
        
# ./bfdefender -i
          
          Это приведёт к тому, что скрипт проанализирует все журнальные
          файлы /var/log/auth.log*, включая сжатые
          bzip2, и создаст базу данных
          /var/db/crackers. С этой базой в дальнейшем
          можно общаться при помощи утилиты-клиента
          sqlite3(1). Например, если нас одолеет
          любопытство, когда к нам пытались зайти используя логин
          закачивающийся на root и сколькко раз
          к нам пытались зайти под именем admin, мы можем сделать к базе SQL
          следующие запросы:
        
#sqlite3 /var/db/crackers SQLite version 3.3.15 Enter ".help" for instructionssqlite>.explain onsqlite>.width 20 15 15sqlite>SELECT * FROM crackers WHERE login LIKE "%_root" LIMIT 10; date ip login -------------------- --------------- --------------- 2007-03-28 14:14:56 89.149.195.132 11root 2007-03-28 14:16:17 89.149.195.132 wwwroot 2007-03-28 14:16:37 89.149.195.132 xxxroot 2006-11-22 08:12:45 217.160.173.110 nfsroot 2006-11-22 08:14:15 217.160.173.110 webroot 2007-02-19 13:12:39 221.254.131.203 gamroot 2007-01-25 02:15:24 148.244.79.94 cvsroot 2007-01-25 02:15:27 148.244.79.94 cvsroot 2006-10-23 23:36:17 208.57.150.227 gamroot 2006-10-13 13:48:34 208.57.150.227 gamrootsqlite>SELECT COUNT(*) FROM crackers WHERE login = "admin"; COUNT(*) -------------------- 1862sqlite>.exit
С помощью утилиты sqlite3(1) можно делать резервные копии базы, однако этот механизм в нашем случае внедрён прямо в скрипт.
          Следующее действие — мы модифицируем файлы
          /etc/pf.conf и
          /etc/syslog.conf как было показано выше.
        
          /etc/pf.conf:
        
table <crackers> persist file "/etc/crackers"
table <trusted_ip> persist { \
   62.117.108.0/26\
   212.57.97.252\
}
.....
pass in quick on $ext_if inet proto tcp from <trusted_ip> \
    to $ext_if port ssh keep state
block in log quick on $ext_if inet proto tcp from <crackers> \
    to $ext_if port ssh
          
          /etc/syslog.conf:
        
auth.info;authpriv.info                         /var/log/auth.log
auth.info                                       | exec /root/bin/bfdefender -a
          В crontab(8) помещаем следующее задание:
@monthly                                /root/bin/bfdefender -b
          
          Это задание будет ежемесячно изготавливать резервную копию с
          нашей базы данных. Сама база, как говорилось, находится в файле
          /var/db/crackers, а резервная копия в файле
          /var/db/crackers.sql.bz2 — это
          обычный текстовый файл. Восстановить базу можно командой
        
# ./bfdefender -r
          
          Это всё, что касается установки скрипта. Дополнительные
          возможности по его использованию, можно узнать передав скрипту
          параметр -h или --help. Скрипт
          позволяет собирать некоторую статистическую информацию:
        
# ./bfdefender -s
===========================================================================
                             bfdefender report                             
===========================================================================
Detected 62309 attacks
user root: 161
user toor: 0
user daemon: 0
user operator: 0
user bin: 0
user tty: 0
user kmem: 0
user games: 0
user news: 0
user man: 0
user sshd: 0
user smmsp: 0
user mailnull: 0
user bind: 0
user proxy: 0
user _pflogd: 0
user _dhcp: 0
user uucp: 0
user pop: 0
user www: 0
user mailman: 0
user mysql: 0
user alias: 0
user cyrus: 0
===========================================================================
2006 May:  3981 attacks
2006 Jun:  2098 attacks
2006 Jul:  2094 attacks
2006 Aug:  6397 attacks
2006 Sep: 11202 attacks
2006 Oct: 11982 attacks
2006 Nov:    12 attacks
2006 Dec:  8921 attacks
2007 Jan:  4861 attacks
2007 Feb:  8693 attacks
2007 Mar:  2068 attacks
===========================================================================
poplar logins: 20 top
admin ................ 1862
test .................. 985
guest ................. 558
apache ................ 427
user .................. 403
info .................. 295
tester ................ 277
oracle ................ 272
webmaster ............. 271
ftp ................... 267
web ................... 252
sales ................. 239
adm ................... 231
postgres .............. 230
testing ............... 219
ftpuser ............... 218
administrator ......... 216
alex .................. 193
student ............... 168
paul .................. 165
          Наслаждайтесь :)
        pfstat — небольшая утилита,
        собирающая статистику при помощи пакетного фильтра и
        предоставляющая её в графическом виде, подобно широко известной
        программе mrtg. Устанавливается из порта
        sysutils/pfstat.
      
Программа должна регулярно запускаться при помощи cron. Сбор статистики при этом должен быть включён либо командой
# pfctl -i sis0
        Либо при помощи опции
set loginterface sis0
        
        в pf.conf(5). Просмотр отчёта
        осуществляется из браузера при помощи cgi сценария.
      





        Другая аналогичная программа — symon
        (порт sysutils/symon).
        symon собирает разнообразную статистику (не
        только по пакетному фильтру, но так же загруженность CPU и т.п.)
        и отправляет её на общий сервер, где она хранится в единой базе
        данных RRDtool (порт net/rrdtool, Round
        Robin Database). Из этой базы можно строить разнообразные
        картинки.
      
        Программа pftop устанавливается из порта
        sysutils/pftop.
      
Назначение программы: сбор статистики о коннектах в режиме on-line (подобно программе top(1)). Программа непрерывно изучает таблицу состояний и выводит информацию о её содержимом:
$ pftop
pfTop: Up State 1-46/175, View: default, Order: none, Cache: 10000                                11:59:30
PR   DIR SRC                  DEST                      STATE                AGE       EXP   PKTS    BYTES
tcp  In  172.19.0.34:60730    172.19.0.2:22    ESTABLISHED:ESTABLISHED  02:58:55  23:59:40  22192  3862199
tcp  In  172.19.0.34:34489    172.19.0.2:22    ESTABLISHED:ESTABLISHED  03:04:41  23:08:18    818   123203
tcp  In  172.19.0.34:43768    172.19.0.2:22    ESTABLISHED:ESTABLISHED  01:36:42  22:26:49    837   123931
tcp  In  81.26.141.122:40448  172.19.0.2:80     FIN_WAIT_2:FIN_WAIT_2   00:00:12  00:01:23     18     9917
tcp  In  81.26.141.122:44774  172.19.0.2:80     FIN_WAIT_2:FIN_WAIT_2   00:00:12  00:01:24    111    95323
tcp  In  66.249.72.142:65077  172.19.0.2:80    ESTABLISHED:ESTABLISHED  00:00:09  24:00:00    950   905145
tcp  In  66.249.72.142:63902  172.19.0.2:80     FIN_WAIT_2:FIN_WAIT_2   00:00:20  00:01:16     19     8588
tcp  In  91.192.58.182:2701   172.19.0.2:80     FIN_WAIT_2:FIN_WAIT_2   00:00:02  00:01:28      7      296
tcp  In  91.192.58.182:2708   172.19.0.2:80      TIME_WAIT:TIME_WAIT    00:00:02  00:01:29     17    12235
udp  Out 172.19.0.2:61667     192.129.4.1:53      MULTIPLE:SINGLE       00:00:32  00:00:00      4      620
udp  Out 172.19.0.2:61667     194.105.16.1:53     MULTIPLE:SINGLE       00:00:23  00:00:07      2      214
udp  Out 172.19.0.2:61667     193.231.32.1:53     MULTIPLE:SINGLE       00:00:32  00:00:00      2      211
udp  Out 172.19.0.2:61667     212.118.58.1:53     MULTIPLE:MULTIPLE     00:00:33  00:00:27      8      600
udp  Out 172.19.0.2:61667     193.110.75.1:53     MULTIPLE:MULTIPLE     00:00:57  00:00:13      4      532
...................
        Внешний вид зависит от ширины терминала. Данный скриншот получен при помощи xterm(1), но если изучать вывод в обычном терминале шириной 80 символов, состояния будут даны лишь цифрами, Направление (DIR) будет дано одной буквой и т.д.
У программы есть опции позволяющие менять формат вывода данных.
См. так же Пример C.3, «Просмотр таблицы состояний».
        Порт ftp/ftpsesame может применяться для
        проксирования трафика FTP через пакетный
        фильтр. В последних выпусках пакетного фильтра в
        OpenBSD функционал этой программы вошёл в
        программу ftp-proxy, отднако в других
        системах: FreeBSD, NetBSD,
        DragonFly BSD, можно использовать
        ftpsesame для осуществления проброса
        FTP.
      
Программа ftpsesame осуществляет управление пакетным фильтром на лету при помощи якорей. См. Раздел C.2.3.3.2, «FTP клиент за брандмауэром» и Раздел C.2.3.3.4, «FTP сервер защищённый внешним пакетным фильтром с запущенным на нём NAT».
    Идеологически брандмауэр ipf(4) похож на pf(4). Синтаксис правил так
    же довольно схож, поэтому я не буду здесь на нём сосредотачиваться.
    Интересующихся отправлю к предыдущей
      главе. Однако будьте готовы к тому, что
    ipf(5) в некоторых тонкостях может отличаться
    от pf.conf(5). Сверяйтесь со справкой с 5-го
    раздела man(1).
  
Изюминкой данного брандмауэра являются утилиты позволяющие следить за ситуацией в брандмауэре в режиме on-line: ipmon(8) и др.
Содержание
Брандмауэр ipfw(8) Применяется в FreeBSD, DragonFly BSD и Darwin (ядре операционной системы MacOS X). Это наиболее старый из брандмауэров FreeBSD, её «родной» брандмауэр. Остальные были портированы в FreeBSD: пакетный фильтр PF из OpenBSD, а ipf(8) из NetBSD. ipfw(8) весьма архаичен, однако распространён и вполне функционален.
Существует две основные версии ipfw: собственно ipfw и ipfw2, Последняя появилась в пятой ветке FreeBSD и в MacOS 10.4 (Tiger). В операционной системе MacOS X брандмауэр ipfw настраивается так же как и в FreeBSD, переменные ядра так же переключаются при помощи программы sysctl(8). Графический интерфейс для настройки брандмауэра крайне убог и позволяет только переключаться между некоторыми предопределёнными настройками. Однако имеется платное програмное обеспечение, которое позволяет настраивать брандмауэр более гибко. Пользователи макинтошей должны выбрать: готовы ли они читать далее данный текст, или они предпочтут купить это програмное обеспечение...

Некоторые усовершенствования появившиеся в ipfw2:
Собственно программа ipfw(8) служит для управления брандмауэром. Однако некоторые его настройки вообще неуправляемы налету. Так, например, политика по умолчанию задаётся на стадии компилирования ядра операционной системы.
Данный раздел пока не столько пишется, сколько задумывается. Пока здесь будет накапливаться перевод источника [url://ipfw-howto]. К сожалению, данный источник выглядит несколько устаревшим, кроме того, он содержит большое количество ошибок. Перевод man по ipfw(8), который тут был, в версиях до 152, возможно снова появится позже. Кто скучает по этому тексту, изучите: http://www.asmodeus.com.ua/library/os/freebsd/ipfw.htm
Конфигурация брандмауэра IPFW может быть «закрытой» или «открытой»
IPFW можно включить одним из двух способов: добавить нужные строки к конфигурационному файлу ядра и пересобрать его, или воспользоваться программой kldload и подгрузить нужный модуль ядра. Однако только метод пересборки ядра позволяет регулировать некоторые функции, например включить журналирование.
Динамическое включение IPFW:
# kldload ipfw
        Для статического включения IPFW в конфигурационный файл ядра следует поместить строку
options         IPFIREWALL
        затем пересобрать ядро и перезагрузить машину.
Но не всё так просто, как кажется. Нужны ещё некоторые телодвижения. Дело в том, что брандмауэр, как было сказано выше, может быть закрытым и открытым. По умолчанию он закрыт. Это может стать настоящим кошмаром при конфигурировании брандмауэра удалённо. Поначалу, пока не наберётесь опыта, старайтесь не включать IPFW удалённо ни статически ни динамически. Если такая неоходимость есть, попробуйте использовать команду at(1) для того, чтобы отменить включение брандмауэра через десять минут. Если всё будет в порядке, вы можете командой atrm(1) отменить поставленное задание по снятию IPFW.
Если вы хотите динамически включить IPFW удалённо, сделайте это так:
#at +10minutes ipfw disable firewall Job 59 will be executed using /bin/sh#kldload ipfw && \ ipfw -q add 65000 allow all from any to any#atrm 59
Такое действие приведёт к тому, что брандмауэр после включения будет открыт и вы не потеряете связь с ним, а если всётаки что-то пойдёт не так, то через 10 минут брандмауэр откроется сам собой, благодаря команде at(1). При локальной работе за консолью, такое действие не требуется.
        Включение IPFW статически на удалённой машине, требует некоторых
        дополнительных действий. После того, как ядро пересобрано, перед
        перезагрузкой, надо указать как минимум две дополнительные опции в
        /etc/rc.conf(5) для включения брандмауэра и
        задания открытой политики:
      
firewall_enable="YES"
firewall_type="OPEN"
        Существуют и другие политики, мы рассмотрим их ниже в Раздел E.1.1.1.1.1, «Предопределённые типы брандмауэров» и Раздел E.1.1.1.1.2, «Пользовательские типы брандмауэров», однако открытый брандмауэр — рекомендуемая практика для новичков. Можно вкомпилировать политику непосредственно в ядро. Для этого в конфигурационном файле ядра следует указать следующую опцию:
options         IPFIREWALL_DEFAULT_TO_ACCEPT
        
        В этом случае нет необходимости задавать политику при включении
        IPFW и нет необходимости делать это в
        rc.conf(5), так как это уже сделано в ядре.
        Однако, рекомендуемая практика состоит в том, чтобы всё равно
        указывать политику в rc.conf(5), так как
        позже мы будем в этом файле указывать свои собственные политики,
        созданные в /etc/rc.firewall. Если вы
        включаете IPFW динамически, то вам тоже следует вписать описанные
        выше строки в /etc/rc.conf(5) —
        опция firewall_enable="YES" служит так
        же и для подгрузки модуля ядра ipfw.ko.
      
В дополнение к указанным опциям, в конфигурационном файле ядра можно указать ещё и следующие опции:
options         IPFIREWALL_VERBOSE
options         IPFIREWALL_FORWARD
options         IPFIREWALL_VERBOSE_LIMIT=#
        Кроме опций в конфигурационном файле ядра, данными возмоностями можно управлять через переменные ядра при помощи команд
#sysctl -w net.inet.ip.fw.verbose=1#sysctl -w net.inet.ip.fw.verbose_limit=#
IPFIREWALL_VERBOSE
              Включение журналирования: каждое правило содержащее ключевое
              слово log порождает сообщение для
              демона syslogd(8). Подробнее см. Раздел E.1.4, «Журналирование».
            
              Соответствующая переменная ядра net.inet.ip.fw.verbose
            
IPFIREWALL_FORWARDfwd. 
            IPFIREWALL_VERBOSE_LIMIT=#
              Предел журналирования — правило с ключевым
              словом log не может породить
              журнальных сообщений больше, чем указано в этой опции.
              (# следует заменить на некоторое
              число, 0 — отсутствие ограничения.)
            
              Соответствующая переменная ядра net.inet.ip.fw.verbose_limit
            
Если система поддерживает IPv6, можно включить в ядре следующие опции:
options         IPV6FIREWALL
options         IPV6FIREWALL_VERBOSE
options         IPV6FIREWALL_VERBOSE_LIMIT=100
options         IPV6FIREWALL_DEFAULT_TO_ACCEPT
        Специальных переменных ядра влияющих на журналирование IPv6 нет. Существуют и другие переменные ядра для настройки IPFW, однако они будут освещены в других местах, так как они не нужны для активации брандмауэра, а требуются для более тонкой настройки.
        Переменные ядра следует указать так же в файле
        /etc/sysctl.conf. В этом случае они будут
        устанавливаться при загрузке системы.
      
        Кроме того, если ваша машина выступает в качестве шлюза, вам
        понадобится включить проброс пакетов между интерфейсами. Для этого
        в rc.conf надо вписать опцию
      
gateway_enable="YES"
        
        или оперировать переменной ядра net.inet.ip.forwarding
      
          Независимо от того, указан ли тип брандмауэра в
          /etc/rc.conf, если в нём есть строка firewall_enable="YES", при запуске
          системы будет выполняться сценарий
          /etc/rc.firewall. В этом сценарии, для
          начала, будут выполнены следующие команды:
        
ipfw add 100 pass all from any to any via lo0
ipfw add 200 deny all from any to 127.0.0.0/8
ipfw add 300 deny ip from 127.0.0.0/8 to any
          Их назначение — пропускать весь локальный трафик на кольцевом интерфейсе и предотвращать попытки обращения к внутренним адресам машины из внешнего мира. Если этих правил не будет, поломается множество внутренних сервисов — RPC, X11 и др.
          Если тип брандмауэра в rc.conf определёно
          как OPEN, то слеующим срабатывает
          правило
        
ipfw add 65000 pass all from any to any
          
          Это правило пропускает весь внешний трафик внутрь и весь
          внутренний трафик наружу. Оно выполняет ту же функцию, что и
          опция IPFIREWALL_DEFAULT_TO_ACCEPT
          в ядре. Если в ядре вкомпилирована открытая политика, то при
          этом создаётся правило номер 65535, allow ip from any to any, вместо deny ip from any to any, что делает
          правило номер 65000 ненужным. Чтобы избежать добавления
          правила номер 65000, можно использовать тип брандмауэра UNKNOWN. Это имеет смысл сделать тем,
          кто просто хочет поупражняться с брандмауэром или просто
          заброкировать трафик с какого-то конкретного хоста. Для этого,
          оставьте брандмауэр открытым и переходите к Раздел E.1.2, «Основы синтаксиса правил ipfw». Если же вы не хотите
          использовать открытый брандмауэр, ни тип OPEN, ни UNKNOWN, разумеется, вам не годятся.
        
            Есть две возможности: либо использовать предопределённые
            типы брандмауэра из rc.firewall, либо
            создать пользовательский тип. Второе предпочтительнее по
            следующим причинам:
          
rc.firewall.
            
              Разумеется последнее слово в выборе типа брандмауэра за
              администратором. Если вам почему-то хочется именно
              использовать один из предустановленных типов, хотя бы
              посмотрите скрипт rc.firewall, чтобы
              понимать, что он делает. Тип брандмауэра задаётся в файле
              /etc/rc.conf(5) опцией
            
firewall_type="..."
              
              Тип брандмауэра можно задавать в любом регистре: OPEN, open, OpEn.
              Помимо обсуждавшегося выше типа OPEN имеются ещё три:
            
CLIENTrc.firewall,
                    так как в нём надо указать номера IP адресов хоста и
                    сети, а так же сетевую маску, так что лучше уж
                    написать пользовательский тип.
                  SIMPLE
                    Несмотря на название, этот тип более сложен, чем
                    CLIENT. Назначение этого
                    типа брандмауэра — работа на
                    шлюзе (маршрутизаторе). В брандмауэре присутствует
                    защита от спуфинга (см. spoofing), Блокируется трафик в
                    немаршрутизируемые сети и из немаршрутизируемых
                    сетей на внешнем интерфейсе (что не всегда удачная
                    идея, будьте внимательны если у вас есть приватные
                    сети во внешнем окружении), осуществляется
                    трансляция NAT (при включении опции natd_enable в
                    rc.conf). Брандмауэр написан в
                    расчёте на то, что на шлюзе работает DNS сервер, Web
                    сервер и принимается почта, а так же работает служба
                    NTP. Остальной трафик блокируется политикой.
                  
Этот тип вам так же придётся отредактировать, чтобы вписать реальные названия интерфейсов и адреса.
CLOSEDrc.firewall расчитан на работу
                    при политике блокирующей любой трафик.
                  ![]()  | Внимание | 
|---|---|
              Корректная работа скрипта rc.firewall
              возможна только если в ядре выбрана блокирующая политика.
              Если вы выставили в ядре опцию IPFIREWALL_DEFAULT_TO_ACCEPT, все
              перечисленные типы окажутся непригодны. В частности тип
              Брандмауэра CLOSE ничего не
              закроет. Мораль — остерегайтесь искуственного
              интеллекта пока не поймёте как он работает. Пишите правила
              фильтрации сами.
             | 
              Разумная практика состоит в том, чтобы самому написать
              правила брандмауэра, и подгружать их как пользовательский
              тип в rc.conf. Например так:
            
   | 
                  Загружать правила из файла
                  /etc/rc.firewall.rules
                 | 
   | Загружать правила «молча» — не выводить информации о загружаемых правилах на экран. | 
              Синтаксис файла rc.firewall.rules
              будет слегка отличаться от
              rc.firewall.
              rc.firewall.rules —
              самостоятельный sh(1) сценарий и в нём
              не определены переменные, исользовавшиеся в
              rc.firewall. Если программирование в
              sh(1) представляет для вам
              проблему — не пугайтесь. Вам просто надо
              подряд много раз вызвать команду
              ipfw(8) с некоторыми аргументами,
              которые мы ниже обсудим. Но если вы хотите использовать
              всю мощь sh(1) обратитесь к Раздел 7.7, «Написание несложных Bourne-скриптов».
            
Синтаксис правил IPFW довольно прост. Каждое правило можно добавить в консоли при помощи команды ipfw(8). Прежде чем мы углубимся в изучение синтаксиса, посмотрим как можно просмотреть имеющиеся правила.
          Команда list позволяет просмотреть
          список активированных правил:
        
# ipfw list
65000 allow ip from any to any
65535 deny ip from any to any
          
          Опция -t позволяет увидеть когда прошёл
          последний пакет соответствовавший данному правилу:
        
# ipfw -t list
65000 Wed Jun  6 13:41:05 2007 allow ip from any to any
65535                         deny ip from any to any
          
          Опция -a или команда show показывает значение
          счётчиков — сколько пакетов и сколько байт прошло
          через каждое правило.
        
#ipfw -a list 65000 722 331414 allow ip from any to any 65535 0 0 deny ip from any to any#ipfw show 65000 760 336294 allow ip from any to any 65535 0 0 deny ip from any to any
Теперь посмотрим, какие правила можно использовать для настройки stateless фильтрации. (Т.е. фильтрации без учёта состояния соединений. stateful фильтрация — фильтрация с учётом состояния соединений, позволяет заметно упростить набор правил и повысить эффективность работы брандмауэра. Они будут рассмотрены в Раздел E.1.5, «Фильтрация с учётом состояния соединений»).
Правила в брандмауэр можно добавлять как при помощи утилиты ipfw(8) так и из файла:
# ipfw /etc/ipfw.rules
          В последнем случае в файл строка за строкой кладутся аргуметы команды ipfw(8). Например:
add 1000 allow all from any to any
          
          Мы с вами уже встречали это правло раньше, когда смотрели на
          открытый тип брандмауэра. Ключевые слова allow, accept, pass и permit — синонимы. В данном
          правиле разрешено проходит всем пакетам в любом направлении. В
          большинстве случаев, когда оказывается, что пакет соответствует
          данному правилу, его прохождение по цепочке правил
          прекращается и к нему применяется указанное в правиле
          действие. Т.е. первое правило выигрывает.
        
В простейшем случае синтаксис правил IPFW выглядит следующим образом:
<команда> [<номер правила>] <действие> <протокол> from <источник> to <назначение>
          
          Важные команды: add и delete — их смысл очевиден
          из названия. Номера правил колеблются от 0 до 65535. Последнее
          правило зарезервировано — это политика указанная в
          ядре. Даже если у вас открытый тип брандмауэра, последнее
          правило будет отражать политику указанную в ядре. Однако,
          поскольку первое правило выигрывает, правило с номером 65000,
          открывающее брандмауэр, будет работать, а на политику не
          попадёт ни один пакет.
        
Действие может быть одним из следующего списка:
allow или accept или pass или permitdeny или dropresetcountПосчитать пакеты, соответствующие правилу. При этом пакеты продолжают идти по цепочке правил. Данное правило используется при написании биллинговых систем (систем учёта трафика).
Пример:
#ipfw add 100 allow icmp from 172.19.0.2 to any 00100 allow icmp from 172.19.0.2 to any#ipfw add 200 allow icmp from any to any 00200 allow icmp from any to any$ping -c3 172.19.0.34 PING 172.19.0.34 (172.19.0.34): 56 data bytes 64 bytes from 172.19.0.34: icmp_seq=0 ttl=64 time=1.263 ms 64 bytes from 172.19.0.34: icmp_seq=1 ttl=64 time=1.987 ms 64 bytes from 172.19.0.34: icmp_seq=2 ttl=64 time=1.095 ms --- 172.19.0.34 ping statistics --- 3 packets transmitted, 3 packets received, 0% packet loss round-trip min/avg/max/stddev = 1.095/1.448/1.987/0.387 ms#ipfw show 00100 3 252 allow icmp from 172.19.0.2 to any 00200 3 252 allow icmp from any to any 65535 0 0 deny ip from any to any
Итак, в этом примере мы создали два одинаковых правила, Под правило номер 100 попадают исходящие пакеты ICMP («пинги»), а под второе попадают все пакеты ICMP, но так как пинги уже пропущены сотым правилом, то правилу номер 200 достались только ответные пакеты («понги»). Поэтому оба правила насчитали три пакета.
                Теперь заменим в 100-м правиле действие allow на действие count:
              
#ipfw delete 100#ipfw add 100 count icmp from 172.19.0.2 to any 00100 count icmp from 172.19.0.2 to any#ipfw zero 200 Entry 200 cleared.$ping -c3 172.19.0.34 PING 172.19.0.34 (172.19.0.34): 56 data bytes 64 bytes from 172.19.0.34: icmp_seq=0 ttl=64 time=1.453 ms 64 bytes from 172.19.0.34: icmp_seq=1 ttl=64 time=4.426 ms 64 bytes from 172.19.0.34: icmp_seq=2 ttl=64 time=1.413 ms --- 172.19.0.34 ping statistics --- 3 packets transmitted, 3 packets received, 0% packet loss round-trip min/avg/max/stddev = 1.413/2.431/4.426/1.411 ms#ipfw show 00100 3 252 count icmp from 172.19.0.2 to any 00200 6 504 allow icmp from any to any 65535 0 0 deny ip from any to any
                В этом примере, мы изменили правило номер 100, затем
                обнулили счётчик у правила 200 (команда zero) и повторили эксперимент.
                Теперь до 200-го правила добрались все ICMP пакеты: и
                «пинги» и «понги».
              
                Действие count позволяет
                разделить функции подсчёта трафика и функции фильтрации.
              
skipto numЛюбой пакет соответствующий правилу будет передан правилу, чей номер больше либо равен num.
add 1400 skipto 1800 all from any to any
                Это правило заставит брандмауэр игнорировать все правила с номерами от 1400 до 1800.
          В поле протокола можно указать любой протокол транспортного
          уравня.  Как правило это tcp, udp или icmp, но может быть и любой другой из
          указанных в файле /etc/protocols.
          Протокол можно указывать как по имени, так и по номеру.
        
Адрес источника и адрес назначения имеют одинаковый формат:
meme означает
                множество адресов присвоенных интерфейсам нашей машины.
              anyany означает
                любой адрес.
              table(number[,value])hostname
                Можно указать имя хоста из файла
                /etc/hosts или разрешающееся через
                DNS. Имейте в виду: если имя разрешается в несколько
                адресов по схеме round-robin, только одно имя будет
                реально добавлено в брандмауэр:
              
#host mx1.yandex.ru mx1.yandex.ru has address 213.180.223.89 mx1.yandex.ru has address 213.180.223.90 mx1.yandex.ru has address 213.180.200.1 mx1.yandex.ru has address 213.180.200.10 mx1.yandex.ru has address 213.180.200.11 mx1.yandex.ru has address 213.180.223.88#ipfw add 100 allow 1 from mx1.yandex.ru to any 00100 allow icmp from 213.180.223.88 to any
Можно конкретизировать какие именно хосты из указанной сети вас интересуют. Для этого применяются квадратные скобки. Если маска в этой форме не указана, подразумевается маска 24 бита.
# ipfw add 100 allow all from me to '172.19.0.34{123,5-55}'
00100 allow ip from me to 172.19.0.0/24{5-55,123}
                Обратите внимание: фигурные скобки обладают своим смыслом в оболочке bash(1). Если вы пользуетесь ею, то вам надо брать адрес в кавычки, как показанно в этом примере.
          Перед каждым адресом можно указать ключевое слово not с очевидным смыслом. Адреса можно
          указывать через запятую:
        
# ipfw add 100 allow all from mx1.yandex.ru, mx2.yandex.ru to me    
00100 allow ip from 213.180.200.10,213.180.223.121 to me
          
          После указания хоста или сети, можно указать номер порта или
          название протокола из файла
          /etc/services. Перед портами можно
          указывать, а можно не указывать ключевые слова dst-port или src-port.
        
#ipfw add 100 allow all from me to any 22,25,80,1024-65535 00100 allow ip from me to any dst-port 22,25,80,1024-65535#ipfw add 200 allow all from me to 172.19.0.34 telnet 00200 allow ip from me to 172.19.0.34 dst-port 23
          Если в названии протокола встретится знак минус, его
          необходимо защищать обратным слешем: ftp\-data. (А если вы вводите команды в
          оболочке, или пишите сценарий, то сам обратный слеш тоже надо
          экранировать: ftp\\-data.) Если его
          не защищать, то минус будет воспринят как диапазон:
        
# ipfw add 100 allow tcp from any to me ftp\\-data-ftp
00100 allow tcp from any to me dst-port 20-21
          Если операции с масками сети кажутся вам неясными, попробуйте обратиться к Раздел 6.8.2, «Маска подсети в формате CIDR».
Хотя рассмотренные правила покрывают множество простых ситуаций, вам могут понадобиться более сложные правила, в ситуации когда у вашей системы более одного сетевого интерфейса или вы хотите генерировать какие-то специальные ответы на пакеты или хотите лучше контролировать направление движения трафика.
Для начала приведём синтаксическую диаграмму правил IPFW:
<команда> [<номер правила>] <действие> [log [logamount <число>]] <протокол>
from <источник> to <назначение> [<интерфейс>] [<опции>]
        Всё, что находится в квадратных скобках, это необязательные аргументы, которые дают системе новый функционал. Эти-то правила и будут рассмотрены в данном разделе. Мы рассмотрим некоторые действия, которых не коснулись в предыдущем разделе.
          Дествие unreach
            «код> — отбрасывает пакет и
          генерирует ответное ICMP сообщение с указанным кодом
          недостижимости. (Например network unreachable или host
          unreachable, т.е. сеть недоступна или хост недоступен). Код
          можно указывать как по номеру, так и по имени. Если вы не
          знаете, что значат эти коды, то значит вам не надо их
          употрелять.
        
Важная возможность брандмауэра IPFW не рассмотренная в Раздел E.1.2, «Основы синтаксиса правил ipfw» — возможность контроля за тем, на каком интерфейсе появился пакет и в каком он движется направлении. До сих пор мы делали предположения о направлении пакетов просто на основании адресов источника и назначения, однако узнать откуда пакет пришёл в самом деле мы не могли.
          Если вы хотите, чтобы правило срабатывало только в отношении
          пакетов идущих внутрь или наружу, вы можете указывать ключевые
          слова in и out. Оба ключевых слова должны
          указываться там, где на приведённой выше диаграмме указано
          слово <интерфейс>, т.е. в
          конце правила, перед возможными опциями.
        
Например, если мы хотим обрабатывать все входящие пакеты вне зависимости от их направления, мы можем использовать правило
add 1000 allow all from any to any in
          Например:
#ipfw add 100 count icmp from any to any in 00100 count icmp from any to any in#ipfw add 200 count icmp from any to any out 00200 count icmp from any to any out#ipfw add 300 count icmp from any to any 00300 count icmp from any to any$ping -c3 172.19.0.34 PING 172.19.0.34 (172.19.0.34): 56 data bytes 64 bytes from 172.19.0.34: icmp_seq=0 ttl=64 time=1.358 ms 64 bytes from 172.19.0.34: icmp_seq=1 ttl=64 time=1.110 ms 64 bytes from 172.19.0.34: icmp_seq=2 ttl=64 time=1.174 ms --- 172.19.0.34 ping statistics --- 3 packets transmitted, 3 packets received, 0% packet loss round-trip min/avg/max/stddev = 1.110/1.214/1.358/0.105 ms#ipfw show 00100 3 252 count icmp from any to any in 00200 3 252 count icmp from any to any out 00300 6 504 count icmp from any to any 65535 0 0 deny ip from any to any
Как видно, правило 100 считало только исходящие «пинги», правило 200 считало входящие «понги», а правило 300 считало и те и другие пакеты. («пинг» — echo-request пакет, «понг» — echo-reply пакет.)
          Чтобы определять пакеты, идущие через конкретный интерфейс,
          используйте ключевое слово via и
          имя интерфейса. Например, если вы используете сетевую карту
          PCI 3Com 3c59x, Ваш сетевой интерфейс вероятно называется xl0.
          Чтобы пропустить все пакеты идущие через этот интерфейс вне
          зависимости от направления, используйте правило:
        
add 1100 allow all from any to any in via xl0
          Или если вы хотите детектировать трафик направленный от любого хоста любому хосту, но выходящий через любой интерфейс:
add 1200 allow all from any to any out via any
          
          В старых реализациях IPFW, если вы использовали сочетание
          ключевых слов in via xl0 в выводе
          команды ipfw list они заменялись на
          recv xl0, а out via xl0 на xmit xl0, сейчас это не так:
        
#ipfw add 100 allow all from any to any out via rl0 00100 allow ip from any to any out via rl0#ipfw list 00100 allow ip from any to any out via rl0 65535 deny ip from any to any
          Однако вы можете использовать ключевые слова recv и xmit
          в правилах. Причём даже одновременно. Например, следующее
          правило ищет исходящие пакеты, которые пришли через интерфейс
          ed0, а уйти собираются через интерфейс ed1:
        
ipfw add allow ip from any to any out recv ed0 xmit ed1
          Пакеты ICMP, TCP и UDP бывают различного типа в зависимости от выставленных в них флагах. Мы можем определять типы этих пакетов при помощи описанных ниже правил.
            Правило icmptype <type>
            ищет ICMP пакеты указанного типа. Ниже приведены возможные
            типы пакетов:
          
Таблица E.2. типы ICMP сообщений опознаваемые брандмауэром IPFW
| Тип | Расшифровка | Комментарий | 
|---|---|---|
| 0 | Echo Reply | «Понг» — ответ на «пинг» | 
| 3 | Destination Unreachable | Сообщение о недостижимости хоста, эти пакеты в свою очередь могут быть разного типа, см. Таблица E.1, «ICMP unreachable коды» | 
| 4 | Source Quench | |
| 5 | Redirect | Этот пакет может влиять на содержимое маршрутной таблицы и уж потому потенциально опасен. | 
| 8 | Echo Request | «Пинг» | 
| 9 | Router Advertisement | |
| 10 | Router Silicitation | |
| 11 | Time-to-Live Exceeded | Пакет высылается по истечении параметра TTL у пакета IP. Если его заблокировать, не будет работать программа traceroute(8). См. Раздел 6.4.2, «traceroute(1)». | 
| 12 | IP header bad | |
| 13 | Timestamp Request | |
| 14 | Timestamp Reply | |
| 15 | Information Request | |
| 16 | Information Reply | |
| 17 | Address Mask Request | |
| 18 | Address Mask Reply | 
К примеру, следующие три правила позводяют машине, защищаемой IPFW пинговать всех, но не дают никому пинговать нашу машину:
1000 allow icmp from any to any out icmptypes 8
1100 allow icmp from any to any in icmptypes 0
1200 deny icmp from any to any in icmptypes 8
            Здесь правило номер 1000 — разрешает исходящие «пинги», правило 1100 — разрешает ответные «понги», правило номер 1200 — блокирует внешине «пинги».
Надо заметить, что практика запрещения «пингов» весьма распространена, однако не они наиболее разрушительны для системы. Например, пакет ICMP-redirect может использоваться для подделки таблицы маршрутизации на вашем хосте, что намного серьёзнее. Такое внимание «пингам» обусловлено не в поледнюю очередь историческими причинами. (См. POD.)
            Опция tcpflags <flags>
            помогает обнаружить пакеты с одним из следующих флагов:
          
finsynrstpshackurgПодробнее о флагах TCP можно прочитать в Раздел B.1.4.3, «TCP».
Флаги можно указывать через запятую. Восклицательный знак означает отсутсвие флага. Например:
# ipfw 'add 100 allow all from any to me 80 tcpflags syn,!ack'
00100 allow ip from any to me dst-port 80 setup
            
            Восклицательный знак в некоторых оболочках обладает
            специальным значением, поэтому мы экранировали строку
            кавычками. Обратите внимание на отклик системы, вместо того,
            чтобы сказать syn,!ack, система
            ответила setup.
          
            Один из наибелее важных флагов для нас — флаг
            SYN, так как он выставляется у пакета открывающего TCP
            соединение. Из-за его важности у ipfw(8)
            есть специальное правило, которое отслеживает именно этот
            флаг — setup. Правило
            setup эквивалентно правилу tcpflags syn,!ack, таким образом, оно
            ловит первый, но не второй пакет тройного рукопожатия (см.
            Раздел B.1.4.3.2, «Открытие соединения TCP, тройное рукопожатие»).
          
            Таким образом, в приведённом выше примере мы разрешили
            открывать соединения к нам на 80-й
            порт. А как же быть с остальными пакетами, которые пойдут по
            установленному соединению? Характерной особенностью этих
            пакетов является то, что в них выставлен флаг
            RST — обрыв соединения, или флаг
            ACK — подтверждение о доставке предыдущих
            пакетов. Чтобы ловить пакеты в которых выстален либо флаг
            RST, либо ACK есть специальное правило established.
          
            С применением правил setup и
            established фильтр можно
            выстроить примерно так:
          
allow 1000 from any to me established
allow 1100 from any to me 22,25,80 setup
deny 65535 from any to any
            
            Первое правило пропускает все пакеты принадлежащие уже
            установленным соединениям. Этих пакетов будет большинство,
            поэтому мы вынесли данное правило в самое начало
            брандмауэра, это способствует оптимизации пропускной
            способности системы. Второе правило разрешает открывать
            соединения на порты номер 22, 25 и 80. Третье правило
            блокирует весь остальной трафик. Таким образом, мы запретили
            устанавливать соединения на неразешённые порты, а
            следовательно established пакетов
            на неразрешённые порты не появится. Подробнее см. Раздел E.1.5.1, «Основы учёта состояний соединений (stateful inspection)»
          
          Ключевое слово frag используется
          для того, чтобы детектировать (и блокировать)
          фрагментированный трафик. Обилие такого трафика может
          свидетельствовать о совершении на вас DOS атаки (см. DOS атака и POD). С
          появлениес stateful фильтрации значение этой опции пошло на
          убыль, так как брандмауэры, осуществляющие фильтрацию на
          основе таблицы состояний, собирают заново фрагментированный
          трафик. Тем не менее, если вы используете stateless
          брандмауэр, с правилами подобными описанным в предыдущем
          разделе (setup и established), не лишне будет добавить
          перед ними такое правило:
        
900 deny all from any to any in frag
          
          Одна из интереснейших возможностей IPFW —
          фильтрация на основе UID и GID сокета от которого получен
          пакет. Это значит, что исходящие соединения можно фильтровать
          по признаку «кто это соединение открыл». После
          ключевых слов uid и/или gid указывается номер или имя
          пользователя или группы.
        
Например, если мы хотим, чтобы только george мог ходить в интернет с нашей машины, мы можен написать следующее правило:
1000 allow all from me to any uid george
65535 deny all from any to any
          Данную возможность можно применять для ограничения возможностей мета-пользователей на случай их взлома. Речь идёт о пользователях от имени которых запускаются сервисы в системе.
Другое возможное назначение таких правил — ограничение полосы пропускания применительно к конкретным локальным пользователям в нашей системе. При этом надо понимать, что речь идёт лишь о локальных пользователях, если полосу пропускания надо ограничить пользователю вне нашего шлюза, находящемуся в локальной сети, на основе логина и пароля, то для этого удобнее использовать пакетный фильтр OpenBSD. (см. Раздел C.2.3.4, «Authpf: авторизация в пакетном фильтре»).
Преимущества журналирования многочислены. При помощи системных журналов вы можете по прошествии времени ответить на вопрос что когда как произошло в вашей системе. В тоже время неаккуратное ведение журнала в состоянии причинить существенный вред системе. Одна из разновдностей DOS атак может состоять в попытке переполнения вашего жёсткого диска путём заполнения журнальных файлов избыточной информацией.
Общие советы касающиеся журналирования могут выглядеть следующим образом:
Для включения журналирования в конфигурационном файле ядра можно указать пару опций, пересбрать ядро и перезагрузить систему:
options         IPFIREWALL_VERBOSE
options         IPFIREWALL_VERBOSE_LIMIT=#
            Последняя опция ограничивает количество обращений правил брандмауэра к системе syslogd(8). Если вы укажете в этой опцмм число 10, то каждое правило, которое должно отсылать сообщение демону syslogd(8) будет отсылать не более 10 сообщений. После достижения этого предела, сообщения перестанут направляться в систему журналирования до тех пор, пока не будут сброшены журнальные счётчики в брандмауэре. Журнальные счётчики, это не тоже самое, что обычные счётчики пакетов. Они сбрасываются при помощи следующей команды:
# ipfw resetlog
            Эти же опции можно включать не пересобирая ядро, при помощи переменных ядра:
#sysctl -w net.inet.ip.fw.verbose=1#sysctl -w net.inet.ip.fw.verbose_limit=#
            Куда будут записаны сообщения от брандмауэра, зависит от
            настроек сделанных в файле
            /etc/syslog.conf(5). Обычно эти
            сообщения попадают в файл
            /var/log/messages.
          
Чтобы застивить syslogd(8) журналировать сообщения от брандмауэра IPFW в отдельный журнальный файл, следует выполнить следующие три действия:
Во-первых.
Создайте пустой журнальный файл, а может даже специальный каталог для журналов и уже в нём журнальный файл:
#mkdir /var/log/ipfw#touch /var/log/ipfw/ipfw.log#chmod -R go-rwx /var/log/ipfw
Убедитесь, что никто не может читать из этих файлов.
Во-вторых.
              Сконфигурируйте syslogd(8) так, чтбы он
              писал журнал в этот файл. Для этого в самый конец (это
              важно, в конец файла)
              /etc/syslog.conf добавьте следующие
              две строки:
            
!ipfw
*.*                                     /var/log/ipfw/ipfw.log
              В некоторые другие файлы, в частности на консоль и терминал суперпользователя, тоже будут попадать некоторые сообщения. Не пытайтесь отменить журналирование на консоль и терминал суперпользователя. Такое поведение системы позволяет вам быстро отреагировать на то, что в системе происходит что-то не то.
В-третьих.
Не забудьте послать сигнал SIGHUP демону syslogd(8), для того, чтобы он перечитал сделанные вами изменения в его конфигурационном файле:
# killall -HUP syslogd
              Итак, мы настроили журналирование событий через демон syslogd(8). Теперь нам надо настроить вращение журнального файла, в противном случае, он будет всё время расти в объёме и переполнит партицию, меж тем нам не нужна информация о том, что происходило в сети год назад.
            Чтобы настроить вращение журнала достаточно добавить всего
            одну строку в файл
            /etc/newsyslog.conf(5):
          
/var/log/ipfw/ipfw.log          600     10      *       $W0D2   J
            
            Эта строка означает следующее: система
            newsyslog(8) будет вращать файл
            /var/log/ipfw/ipfw.log. Новый файл
            после вращения будет создаваться с пермиссиями 600, будет
            храниться не более 10 старых файлов, вращение будет
            происходить еженедельно в воскресенье в 2 часа ночи. После
            вращения журнал будет сжат при помощи команды
            bzip2(1).
          
Наша система полностью готова к принятию журнальной информации, теперь мы можем задавать правила в брандмауэре, которые будут журналировать сообщения через syslogd(8).
          Ключевое слово log заставляет
          брандмауэр генерировать сообщение для системного журнала
          каждый раз, когда срабатывае данное правило. данное ключевое
          слово должно идти вслед за действием:
        
65000 deny log all from any to any
          
          Параметр logamount
            <num> — указывает на ограничение
          количества пакетов журналируемых через данное правило. Этот
          параметр перебивает глобальные настройки сделанные при помощи
          опции ядра IPFIREWALL_VERBOSE_LIMIT.
        
65000 deny log logamount 100 all from any to any
          При журналировании в сохраняется следующая информация:
Например:
#sysctl net.inet.ip.fw.verbose=1 net.inet.ip.fw.verbose: 0 -> 1#ipfw add 100 allow log icmp from me to any 00100 allow log icmp from me to any$ping -c3 172.19.0.34 PING 172.19.0.34 (172.19.0.34): 56 data bytes 64 bytes from 172.19.0.34: icmp_seq=0 ttl=64 time=1.603 ms 64 bytes from 172.19.0.34: icmp_seq=1 ttl=64 time=3.701 ms 64 bytes from 172.19.0.34: icmp_seq=2 ttl=64 time=1.220 ms --- 172.19.0.34 ping statistics --- 3 packets transmitted, 3 packets received, 0% packet loss round-trip min/avg/max/stddev = 1.220/2.175/3.701/1.091 ms$ping -c3 194.87.0.50 PING www.ru (194.87.0.50): 56 data bytes 64 bytes from 194.87.0.50: icmp_seq=0 ttl=59 time=5.026 ms 64 bytes from 194.87.0.50: icmp_seq=1 ttl=59 time=5.322 ms 64 bytes from 194.87.0.50: icmp_seq=2 ttl=59 time=5.600 ms --- www.ru ping statistics --- 3 packets transmitted, 3 packets received, 0% packet loss round-trip min/avg/max/stddev = 5.026/5.316/5.600/0.234 ms#cat /var/log/ipfw.log Jun 7 12:55:58 house kernel: ipfw: 100 Accept ICMP:8.0 172.19.0.2 172.19.0.34 out via rl1 Jun 7 12:56:00 house last message repeated 2 times Jun 7 12:56:28 house kernel: ipfw: 100 Accept ICMP:8.0 172.19.0.2 194.87.0.50 out via rl1
          Обратите внимание как демон syslogd(8)
          обрабатывает ситуацию с повторяющимися событиями. Мы послали
          три пинга на адрес 172.19.0.34. syslogd(8)
          занёс в журнал первое событие, а остальные поместил в буфер,
          так как они по его мнению однотипные. После этого мы послали
          три пинга на другой адрес, это другое событие, поэтому
          syslog(8) освободил свой буфер выдав
          сообщение о двух непрожурналированных событиях: last message
          repeated 2 times. С одной строны, такое поведение экономит
          место в журнале, с другой стороны, оно затрудняет работу
          парсеров и главное, препятсвует сбору данных о времени
          совершения атаки. К сожалению, данную особенность
          syslogd(8) отключить невозможно. В этом
          смысле журналирование средствами пакетного фильтра
          OpenBSD выглядит более разумно (см. Раздел C.2.3.1, «Журналирование в пакетном фильтре»). Зато такая система может быть
          применена для конструирования системы активного реагирования
          на события, так как журналируемые события можно направлять из
          syslogd(8) на стандартный ввод любой
          программе, которая, например, может автоматически на лету
          переписывать правила брандмауэра. Впрочем, лучший вариант
          состоит в заворачивании пакетов в программу при помощи правила
          divert.
        
При фильтрации трафика без учёта состояний соединений, брандмауэр каждый пакет фильтрует индивидуально, без учёта других пакетов. Такой брандмауэр прост в реализации и может быть эффективно использован для:
Напротив, при фильтрации трафика с учётом состояния соединений, брандмауэр трактует трафик не как множество независящих друг от друга пакетов, а как совокупность потоков, каждый из которых, принадлежит некоторому соединению. Все соединения в большинстве протоколов используют некоторое число, указывающее в каком порядке должны собираться пакеты в сокете назначения. Брандмауэр, использующий stateful inspection, на основании этого числа может опознать пакеты как принадлежащие одному соединению. В особенности это относится к протоколам поддерживающим информацию о соединениях. Таким как TCP.
Такой брандмауэр более сложен в реализации, однако он может:
Брандмауэр с учётом состояния соединения создаёт динамические правила для каждого соединения и автоматически удаляет эти правила по истечении некоторого времени. Всё это позволяет такому брандмауэру принимать более интеллектуальные решения на основе сетевых критериев более высоких уровней. С другой стороны, такое поведение не даёт брандмауэру принимать решения индивидуально по каждому пакету, поскольку динамические правила относятся сразу ко всем пакетам принадлежащим установленному соединению и препятствуют какому-то анализу кроме как анализу по принципу правильности осуществления процедуры открытия/закрытия соединения. Разумный подход заключается в объединении обоих методов фильтрации, для того, чтобы использовать сильные стороны и того и другого подхода.
        Все приведённые выше примеры правил не учитывали состояние
        соединения. Единственным исключением были критерии tcpflags, setup и established, которые позволяли оценить
        состояние соединения TCP на основе TCP-флагов. Однако эти
        правила не позволяли создавать динамических правил фильтрации. И
        всё-таки, с помощью этих правил можно создать примитивный
        брандмауэр учитывающий состояние соединений. Долгое время это
        была единственная возможность создания stateful inspection в
        IPFW, однако начиная с FreeBSD 4.0 у нас
        появилась возможность создавать полноценные stateful-брандмауэры
        на основании IPFW.
      
          Для нашего первого примера мы используем старый функционал
          IPFW. Многие, кто использует в качестве примера для своего
          брандмауэра файл /etc/rc.firewall могут
          найти там подобные строки. В приведённом ниже примере мы,
          на основании TCP-флагов, разрешаем прохождение через наш
          брандмауэр. трафика SSH.
        
add 1000 allow tcp from any to any established
add 2000 allow tcp from any to any 22 in setup
          
          Итак, мы предполагаем, что политика брандмауэра закрытая,
          т.е. в ядре отсутствует опция IPFIREWALL_DEFAULT_TO_ACCEPT, и у нас
          нигде нет правила вроде allow all from any
            to any. Приведённые строки разрешают весь уже
          установленный TCP трафик и разрешают открывать TCP соединения
          на 22-й порт. Мы можем расчитывать на то, что никакой другой
          TCP трафик через брандмауэр не пройдёт, так как правило номер
          2000 позволяет открывать только соединения идущие на 22-й
          порт. В тоже время, данные правила будут пропускать
          «неправильные» пакеты, осколки не принадлежащие
          никаким соединениям на том основании, что в них есть флаг ACK.
          Настоящий брандмауэр с учётом состояния соединений должен был
          бы отфильтровать такие пакеты.
        
Аналогичного эффекта можно добиться при помощи правил, в которых вообще нет критериев изучающих флаги заголовка TCP, т.е. при помощи заведомо stateless брандмауэра:
add 1000 allow tcp from any to any out
add 2000 allow tcp from any to any 22 in
          В приведённом примере разрешён любой исходящий трафик в любом направлении, а входящий трафик разрешён только на 22-й порт.
В общем случае, тактика брандмауэра с учётом состояния соединений состоит в том, чтобы сперва пропускать все уже установленные соединения, а потом перечислить какие соединения можно открывать.
Вот более комплексный пример. Приведём правила, которые разрешают трафик FTP, SSH, SMTP и DNS в сеть 172.16.0.0/27:
add 1000 allow tcp from any to any established
add 2000 allow tcp from any to 172.16.0.0/27 21,22,25 setup
add 3000 allow udp from 172.16.0.0/27 to any 53
add 3100 allow udp from any 53 to 172.16.0.0/27
          
          Поскольку трафик DNS осуществляется по протоколу UDP, мы не
          используем в правилах 3000 и 3100 ключевые слова established и setup. Заметим так же, что в
          приведённом примере мы открыли только командный канал для FTP.
          Между тем как нам надо ещё пропустить данные FTP. Подробнее о
          функционировании этого протокола можно прочитать в Раздел C.2.3.3.1, «Режимы FTP».
        
          Как уже было сказано выше, проверка только флагов заголовка
          TCP ограничивает применимость stateful фильтрации. Начиная с
          FreeBSD 4.0 в IPFW появилась
          полноценная фильтрация с учётом состояния соединений. Это
          достигнуто путём создания так называемых динамических правил.
          Динамические правила образуются автоматически, если пакет
          соответствует правилу, в котором присутсвует ключевое слово keep-state или ключевое слово limit.
        
keep-statelimit {src-addr | src-port | dst-addr | dst-port} Nkeep-state, но
                динамическое правило заводится только в том случае, если
                не превышен указанный предел. Таким образом, можно легко
                ограничить количество одновременных подключений к
                некоторому хосту или порту.
              
          Динамические правила находятся в цепочке правил там же, где
          они заведены, т.е. если правило keep-state имеет номер 50000 и перед
          ним имеется пятьсот правил, проверяющих разнообразные
          параметры пакетов, то каждый из потенциально разрешённых
          пакетов, проходит проверку на этих пятистах правилах. Это не
          очень удачное решение с точки зрения производительности. Чтобы
          пропустить все потенциально разрешённые пакеты, мы можем в
          самом начале брандмауэра указать правило check-state:
        
add 1000 check-state
add 2000 allow tcp from any to any 22 in setup keep-state
          Вот переменные ядра влияющие на величины таймаутов:
$sysctl -a | grep dyn.*lifetime net.inet.ip.fw.dyn_ack_lifetime: 300 net.inet.ip.fw.dyn_syn_lifetime: 20 net.inet.ip.fw.dyn_fin_lifetime: 1 net.inet.ip.fw.dyn_rst_lifetime: 1 net.inet.ip.fw.dyn_udp_lifetime: 10 net.inet.ip.fw.dyn_short_lifetime: 5$sysctl -ad | grep dyn.*lifetime net.inet.ip.fw.dyn_ack_lifetime: Lifetime of dyn. rules for acks net.inet.ip.fw.dyn_syn_lifetime: Lifetime of dyn. rules for syn net.inet.ip.fw.dyn_fin_lifetime: Lifetime of dyn. rules for fin net.inet.ip.fw.dyn_rst_lifetime: Lifetime of dyn. rules for rst net.inet.ip.fw.dyn_udp_lifetime: Lifetime of dyn. rules for UDP net.inet.ip.fw.dyn_short_lifetime: Lifetime of dyn. rules for other situations
Мне кажется, что таймауты по умолчанию принятые в FreeBSD для корпоративного шлюза являются слишком жёсткими. Возможно в ряде случаев их стоит увеличить. Особенно если вы не слишком лимитированы объёмом оперативной памяти и можете увеличить размер таблицы с динамическими правилами (см. ниже).
Рассмотрим, как работают приведённые здесь два правила.
keep-stte не сработает и динамическое
            правило для него не будет заведено.
          
          Надо заметить, что в примере приведённом в Раздел E.1.5.1, «Основы учёта состояний соединений (stateful inspection)», поддельный пакет был бы
          пропущен правилом с ключевым словом established.
        
Существует так же такой тип сетевых атак как SYN-флуд. Он заключается в том, что злоумышленник организует большой поток TCP пакетов с выставленным в них флагом SYN. (См. так же Раздел C.2.1.4.9, «TCP SYN proxy».) Такой флуд переполняет таблицы сокетов на атакуемой машине, что не даёт возможности открыть соединения для легальных пользователей. Т.е. совершается DOS-атака.
          В брандмауэре такая атака приводит к росту количества
          динамических правил. Текущее количество динамических правил
          можно узнать из переменной net.inet.ip.fw.dyn_count, а размер
          таблицы с динамическими правилами ограничен переменной net.inet.ip.fw.dyn_max, которая по
          умолчанию равна 1000.
        
Если количество разрешённых соединений достигнет предела, то новые динамические правила перестанут образовываться и новые соединения не будут разрешены в брандмауэре.
Фильтрация с учётом состояния применима не только к трафику TCP. Например, ниже приведено правило, позволяющее нам пинговать из внутренней сети внешнюю, но не пропускающее обратные пинги:
add 1000 check-state
add 2000 allow icmp from any to any out icmptypes 8 keep-state
          
          Правило номер 2000 заводит динамическое правило в момент,
          когда мы посылаем пинг, нас можно будет пропинговать только с
          той машины, которую мы пингуем, и только в тот самый момент,
          пока не истёк таймаут от нашего пинга. (По умолчанию 5
          секунд — net.inet.ip.fw.dyn_short_lifetime).
        
Впрочем, надо заметить, что во-первых, чтобы мы могли пинговать хост снаружи, нам надо, чтобы он откликался быстрее чем за 5 секунд, а это не всегда так. Во-вторых, если злоумышленник нащупает время, когда мы пингуем его, он может продлевать действие динамического правила непрерывно бомбя нас пингами. Опять-таки, я говорю это не как о потенциальной опастности, а для понимания механизма действия динамических правил.
          Для просмотра текущих динамических правил, можно применять
          агрумент -d для команды
          ipfw:
          
# ipfw -d show
01000   0      0 check-state
02000 1194 704133 allow tcp from any to any keep-state
65535   0      0 deny ip from any to any
## Dynamic rules (18):
02000  44  38497 (296s) STATE tcp 194.1.161.14 2316 <-> 172.19.0.2 80
02000  26  18377 (296s) STATE tcp 194.1.161.14 2318 <-> 172.19.0.2 80
02000   4    320 (1s) STATE tcp 172.19.0.34 38100 <-> 172.19.0.2 22
            
            Обратите внимание, что в счётчике указано 18 динамических
            правил, а в листинге приведено только три. Это связано с
            тем, что правила, которые истекли по таймауту не удалены из
            таблицы динамических правил. Они не работают, но в таблице
            присутсвуют и будут замещены только когда это понадобится.
            Полностью таблицу динамических правил можно просмотреть при
            помощи опции -e (от слова expired):
          
# ipfw -de show
01000   0      0 check-state
02000 1194 704133 allow tcp from any to any keep-state
65535   0      0 deny ip from any to any
## Dynamic rules (18):
02000  44  38497 (296s) STATE tcp 194.1.161.14 2316 <-> 172.19.0.2 80
02000  26  18377 (296s) STATE tcp 194.1.161.14 2318 <-> 172.19.0.2 80
02000   4    320 (1s) STATE tcp 172.19.0.34 38100 <-> 172.19.0.2 22
02000    0       0 (0s) STATE tcp 195.222.87.11 62801 <-> 172.19.0.2 80
02000    8    1320 (0s) STATE tcp 195.222.87.11 56912 <-> 172.19.0.2 80
02000    9    1660 (0s) STATE tcp 193.108.240.20 45900 <-> 172.19.0.2 80
02000    8    1321 (0s) STATE tcp 195.222.87.11 54613 <-> 172.19.0.2 80
02000    0       0 (0s) STATE tcp 195.222.87.11 61268 <-> 172.19.0.2 80
02000    9    1906 (0s) STATE tcp 193.108.240.20 45910 <-> 172.19.0.2 80
02000    9    1958 (0s) STATE tcp 193.108.240.20 45911 <-> 172.19.0.2 80
02000    8    1603 (0s) STATE tcp 193.108.240.20 45909 <-> 172.19.0.2 80
02000    8    1598 (0s) STATE tcp 193.108.240.20 45907 <-> 172.19.0.2 80
02000    9    1662 (0s) STATE tcp 193.108.240.20 45904 <-> 172.19.0.2 80
02000    8    1585 (0s) STATE tcp 193.108.240.20 45905 <-> 172.19.0.2 80
02000  123  108527 (0s) STATE tcp 80.249.130.195 61576 <-> 172.19.0.2 80
02000   41   26403 (0s) STATE tcp 80.249.229.26 57170 <-> 172.19.0.2 80
02000   79   67509 (0s) STATE tcp 80.249.130.195 58511 <-> 172.19.0.2 80
02000  164  136800 (0s) STATE tcp 195.222.87.11 55679 <-> 172.19.0.2 80
            
        Управление трафиком подразумевает регулировку полосы пропускания
        (скорость связи), внедрение задержек, «случайная»
        потеря пакетов и др. Если регулировка скорости трафика может
        быть полезна для провайдеров доступа к сети, то прочие
        «фокусы» могут использоваться для исследовательских
        целей. Например для того, чтобы эмулировать соединение через
        модем при подключении через FastEthernet. Мы можем использовать
        dummynet(4) совместно с IPFW для
        контроля за полосой пропускания конкретных пользователей, для
        внедрения задержек в трафике с экспериментальными или другими
        целями.  Единственное, что можно сделать в IPFW на эту тему без
        привлечения dummynet(4) —
        вероятностное срабатывание правил. Эта возможность встроена в
        IPFW.
      
Обсуждаемые возможности не могут быть применены совместно с динамическими правилами.
          В составе IPFW имеется полезный инструмент для тестирования
          сети, с помощью которого можно случайно отбрасывать пакеты с
          некоторой вероятностью. Эта возможность активируетя при помщи
          опции prob и следующей за ним
          вероятностью — дробным числом от 0 до 1. Т.е.
          критерий prob 0.9 будет
          удовлетворён в 90% случаев и неудовлетворён в 10% случаев.
          Ниже приведена синтаксическая диаграмма:
        
<command> [<rule #>] [prob <match_probability>] <action> [log
[logamount <number>]] <proto> from <source> to <destination>
[<interface-spec>] [<options>]
          Например, чтобы отбрасывать 20% «пингов», мы можем использовать следующее правило:
add 1000 prob 0.8 allow icmp from any to any in icmptypes 8
          Или мы можем отбрасывать половину пакетов TCP SYN идущих к web-серверу, для того, чтобы эмулировать состояние перегрузки:
add 1000 prob 0.5 allow tcp from any to any in setup via ep0
          
          Любые дополнительные возможности по контролю за трафиком
          требуют наличия dummynet(4). Эта
          система должна быть встроена в ядро при помощи опции
        
options         DUMMYNET
          либо подгружена в виде модуля:
# kldload dummynet
          
          Когда dummynet(4) окажется
          доступен, мы сможем используя ключевое слово pipe направлять трафик в некоторые
          пронумерованные каналы. Например:
        
#kldload dummynet#ipfw pipe 10 config bw 100Kb/s#ipfw pipe list 00010: 100.000 Kbit/s 0 ms 50 sl. 0 queues (1 buckets) droptail
          Это простое правило позволяет ограничить полосу пропускания
          для трафика направляемого в 10-й канал величиной 100 килобит
          в секунду. Ширину полосы пропускания можно указывать в разных
          единицах: bit/s, Byte/s, Kbit/s, KByte/s Mbit/s, MByte/s.
          Ключевое слово bw указывает на то,
          что данное правило влияет на полосу пропускания (bandwidth).
        
          Другое действие, которое можно выполнить при помощи dummynet(4) — введение
          задержек, при помощи которых можно эмурировать реальные
          задержки происходящие при работе в распределённых сетях:
        
pipe 10 config delay 100
          
          После ключевого слова delay
          указывается величина задержки в миллисекундах. В приведённом
          примере трафик принадлежащий 1-му каналу будет задерживаться
          на 100 миллисекунд.
        
          Ключевое слово plr позволяет
          средствами dummynet(4)
          реализовывать то же, что мы делали в предыдущем разделе при
          помощи опции prob. Например, того
          же эффекта, что и при помощи опции prob
            0.8 можно добиться при помощи канала
        
pipe 10 config plr 0.2
          
          plr расшифровывается как packet
          loss rate и определяет вероятность, с которой пакеты теряются
          в распределённой сети.
        
При регулировании полосы пропускания при помощи каналов, следует уделить внимание регулировке размера буфера или очереди (queue). Размер очереди задаётся в слотах, размер которых равен размеру MTU — максимальный размер кадра на канальном уровне модели OSI (см. MTU). Размер MTU можно узнать при помощи команды ifconfig(8):
$ ifconfig rl0
rl0: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> mtu 1500
        options=8<VLAN_MTU>                             ~~~~~~~~
        inet 172.20.0.2 netmask 0xffffff00 broadcast 172.20.0.255
        ether 00:80:48:2d:f7:15
        media: Ethernet autoselect (none)
        status: no carrier
            Если на интерфейсе с достаточно большим размером MTU сильно заузить полосу пропускания, то большая очередь будет заполняться слишком долго. Например, если мы организуем канал, эмулирующий работу модема 56Kbit/s:
pipe 10 config bw 56Kbit/s
            то окажется, что очередь в таком канале заполняется в течение 1500*8(MTU)*50(slot)/56000=10.7 секунд. Здесь 1500*8 — величина MTU в битах, 50 слотов — размер очереди по умолчанию.
Чтобы снизить задержки можно либо уменьшить размер MTU при помощи команды ifconfig(8) (см. Раздел 6.2.2, «ifconfig(8) — настройки сетевых интерфейсов»), что явно неудачное решение, либо уменьшить количество слотов в очереди:
pipe 10 config bw 56Kbit/s queue 5Kbytes
            Размер очереди можно задавать как в слотах, так и в байтах (см. пример). В последнем сучае, размер очереди не будет зависеть от MTU.
Чем уже полоса пропускания канала, тем меньше должен быть размер очереди.
В одном канале может быть несколько очередей. Допустим у нас во внутренней сети класса C хосты должны иметь скорость не более 100Kbit/s. Чтобы обеспечить такое ограничение мы можем либо завести 254 каналов (по каналу на каждый хост), или, что лучше, организовать динамические каналы при помощи масок. Пусть у нас будет маска 0.0.0.255. При накладывании такой маски на адрес 192.168.0.34 мы получим число 0.0.0.34. Это число является идентификатором динамически созданного канала. В битовой маске единицы могут стоять в любой позиции, т.е. маска не обязана быть дополнительной к сетевой маске и вычисляться по правилу 2n-1.
Маски возможны следующих типов:
dst-ipsrc-ipdst-portsrc-portprotoalldst-ip).
              Маска указывает идентификатор канала. Например, если мы сделаем маску 0.0.0.255, то все адреса отличающиеся в третьем октете (т.е. из разных сетей класса C) будут принадлежать разным динамическим каналам, а при совпадении первых трёх октетов — одному каналу.
Для рассматриваемой ситуации мы должны были бы сделать следующие правила:
pipe 10 config mask src-ip 0x000000ff bw 100Kbit/s queue 10Kbytes
pipe 20 config mask dst-ip 0x000000ff bw 100Kbit/s queue 10Kbytes
add 1000 add pipe 10 all from 192.168.0.0/16 to any out via xl0
add 2000 add pipe 20 all from 192.168.0.0/16 to any in via xl0
            Здесь мы впервые столкнулись с правилом, которое направляет трафик в канал. Итак, мы организуем два канала, один (10-й) заводит динамические каналы по IP-адресам источника, другой по адресам назначения (20-й). Правило 1000 направляет весь исходящий трафик в 10-й канал, а правило 2000 направляет весь исходящий рафик в 20-й канал. Как видно из приведённого примера, маски можно указывать не только в точечно-десятичной, но и в шестнадцатеричной форме.
Обратите внимание, в этом примере в учебных целях присутствует одна странность: в канал направляется трафик из сети 192.168.0.0/16, а маска канала 0.0.0.255. Это приведёт к тому, что хосты 192.168.0.34, 192.168.5.34, 192.168.10.34, 192.168.16.34, 192.168.56.34, и т.д. будут находиться в одном канале с идентификатором 34 и будут делить общую полосу пропускания. В жизни это не самое удачное решение, оно приведено здесь с учебной целью.
            Пакеты прошедшие через канал могут вернуться в цепочку
            правил, для этого надо приравнять к нулю переменную ядра
            net.inet.ip.fw.one_pass, которая
            по умолчанию равна единице (т.е. по умолчанию пакеты в
            брандмауэр не возвращаются). Хотя разумнее было бы сперва
            отфильтровать ненужные пакеты и только потом заниматься
            ограничением полосы пропускания у оставшихся.
          
    /etc/login.conf — база данных для
    различных программ, в том числе для программы
    login(1). С его помощью можно задавать переменные
    окружения, настройки учётных записей вроде сроков действия учётных
    записей, метода шифрования и т.д.
  
    Файл /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:
    Каждое поле в записях может быть представлено в одном из следующих форматов:
boolfileprogramlistpathnumber0x — шестнадцатеричное, с
        префиксом 0 —
        восьмеричное.
      sizetime9600s,
        160m или 2h40m.
      Таблица F.1. Ограничение ресурсов средствами login.conf(5)
| Имя записи | Тип | Описание | OS | 
|---|---|---|---|
| coredumpsize | size | Максимальный размер файлов coredump | 
               
             | 
| cputime | time | Максимальное процессорное время, которое может потребить программа[a]. | 
               
             | 
| datasize | size | Максимальный размер данных. | 
               
             | 
| filesize | size | Максимальный размер файла. | 
               
             | 
| maxproc | number | Максимальное число процессов, которое может породить пользователь. | 
               
             | 
| memorylocked | size | Максимальный размер памяти в core memory, которую может залочить процесс. | 
               
             | 
| memoryuse | size | Максимальный размер памяти в core memory, которую может использовать процесс. | 
               
             | 
| openfiles | number | Максимальное количество файловых дескрипторов, которое может открыть приложение. | 
               
             | 
| sbsize | size | Максимально разрешёный размер буфера сокета | 
               
             | 
| vmemoryuse | size | Максимально разрешённый размер виртуальной памяти | 
               
             | 
| stacksize | size | Максимальный размер стека | 
               
             | 
              Есть ограничение current (мягкое) и maximum (жёсткое).
              Перечисленные опции задают сразу и то, и другое, если вы
              хотите отдельно задать мякое и жёсткое ограничение,
              используйте суффиксы -cur и -max. (Например cputime-max.) Разница между ними в
              том, что мягкие ограничения пользователь может
              переопределить в большую сторону.
             | |||
[a] Невозможно (и бессмысленно) ограничить программу так, чтобы она потребляла, скажем, не более 30% от CPU. Процессор может быть или занят или не занят, он не может быть занят на треть. То, что вы видите в выволе команды top(1), например, это лишь усреднение за некоторое время. Но можно ограничить CPU-time. Фактически это ограничение на количество тактов, которое выделит шедулер ядра на данный процесс. Если вы всё же хотите,
                  чтобы программа потребляла меньше ресурсов CPU «в
                  процентах», то вам надо подумать об опции
                    | |||
Таблица F.2. Формирование окружения средствами login.conf(5)
| Имя записи | Тип | Умолчание | Описание | OS | 
|---|---|---|---|---|
| charset | string | 
              Установка переменной окружения
              $MM_CHARSET.
             | 
               
             | |
| hushlogin | bool | false | 
              То же, как если бы пользователь имел файл
              ~/.hushlogin (не выводить
              /etc/motd при загрузке).
             | 
               
             | 
| ignorenologin | bool | false | 
              Логин не блокируется файлом
              /etc/nologin
             | 
               
             | 
| ftp-chroot | bool | false | При логине данного пользователя через ftpd(8) осуществлять chroot в его пользовательский каталог. (Речь идёт только о встроенном в BSD демоне, а не установленных из портов proftpd и т.д.) | 
               
             | 
| label | string | Политика MAC по умолчанию (см. maclabel(7)). | 
               
             | |
| lang | string | 
              Значение переменной окружения $LANG.
             | 
               
             | |
| manpath | path | Где по умолчанию искать man-страницы. | 
               
             | |
| nocheckmail | bool | false | Отображать состояние почтового ящика при входе в систему. | 
               
             | 
| nologin | file | Если указанный файл существует, при входен в систему отображается его содержимое и процедура входа прерывается. | 
               
             | |
| path | path | /bin /usr/bin | Каталоги, в которых по умолчанию искать исполнимые файлы. | 
               
             | 
| priority | number | Начальный приоритет (nice(1)) у задач пользователя. | 
               
             | |
| requirehome | bool | false | Требуется ли пригодный домашний каталог для входа пользователя в систему. | 
               
             | 
| setenv | list | 
              Разделённый запятыми список переменных и их значений,
              которые должны быть выставлены при входе пользователя в
              систему. Кавычки из файла login.conf
              переносятся в переменную как есть. Поэтому вхождение setenv=VAR1=value1,...,PAGER="/usr/bin/less -M",... —
              это ошибка. Правильно писать: setenv=VAR1=value1,...,PAGER=/usr/bin/less -M,...
             | 
               
             | |
| shell | program | 
              Оболочка пользователя. Имеет приоритет перед заданной в
              master.passwd(5), однако переменная
              $SHELL выставляется в значение
              указанное в master.passwd(5).
             | 
               
             | |
| term | string | Тип терминала, если он не может быть определён другим способом. | 
               
             | |
| timezone | string | 
              Значение переменной окружения $TZ.
             | 
               
             | |
| umask | number | 022 | Начальное значение umask (см. Раздел 3.7, «Просмотр и изменение пермиссий с использованием как символьных, так и восьмеричных мод»). Должно всегда начинаться с нуля, для того, чтобы формат воспринимался как всьмеричный. | 
               
             | 
| welcome | file | /etc/motd | Файл с приветствем. | 
               
             | 
Таблица F.3. Аутентификационные данные в login.conf(5)
| Имя записи | Тип | Умолчание | Описание | OS | 
|---|---|---|---|---|
| copyright | file | Файл, содержащий дополнительную информацию о copyright | 
               
             | |
| host.allow | list | Список шаблонов указывающих на хосты, с которых могут заходить пользователи приналежащие данному классу. | 
               
             | |
| host.deny | list | Список шаблонов указывающих на хосты, с которых не могут заходить пользователи приналежащие данному классу. | 
               
             | |
| login_prompt | string | 
              Строка выводимая утилитой login(1)
              при запросе логина (см. так же
              passwd_prompt).
             | 
               
             | |
| login-backoff | number | 3 | 
              Количество попыток логина разрешённых прежде чем начнут
              вставляться задержки между попытками логина. Величина
              задержки, равна значению login-backoff
              умноженной на 5 секунд. (Последняя, загадочная фраза
              есть только в man(1) в
              FreeBSD.)
             | 
               
             | 
| login-retries | number | 10 | 
              Количество разрешённых попыток логина, прежде чем логин
              будет признан неудачным.
              (OpenBSD —login-tries)
             | 
               
             | 
| passwd_format | string | md5 | 
              Формат в котором шифруется пароль в
              master.passwd. Допустимые варианты
              перечислены в Таблица 2.3, «Возможные значения опций crypt_default
          (FreeBSD) и localcipher,
          ypcipher (OpenBSD)».
             | 
               
             | 
| passwd_prompt | string | 
              Строка выводимая утилитой login(1)
              при запросе пароля (см. так же
              login_prompt).
             | 
               
             | |
| times.allow | list | Список временных промежутков, когда допустим логин в системе. | 
               
             | |
| times.deny | list | Список временных промежутков, когда логин в системе недопустим. | 
               
             | |
| ttys.allow | list | 
              Список терминалов и групп терминалов, с которых логин в
              системе разрешён. (Группы терминалов задаются в
              /etc/ttys(5).)
             | 
               
             | |
| ttys.deny | list | 
              Список терминалов и групп терминалов, с которых логин в
              системе запрещён. (Группы терминалов задаются в
              /etc/ttys(5).)
             | 
               
             | |
| warnexpire | time | Срок за который надо предупредить пользователя об истечении срока действия учётной записи. | 
               
             | |
| warnpassword | time | Срок за который надо предупредить пользователя об истечении срока действия пароля. | 
               
             | 
      Промежутки времени в списках times.allow и
      times.deny оформляются в 24-х часовом формате,
      через дефис. Например промежуток MoThSa0200-1300 означает: по
      понедельникам, четвергам и субботам с двух часов ночи до часу
      дня.
    
      Группы терминалов для опций ttys.allow и
      ttys.deny задаются в файле
      /etc/ttys(5) примерно так:
    
ttyh1   "/usr/libexec/getty std.9600"   vt100   on group=dialup
ttyp0   none    network         group=pty
ttyp1   none    network off     group=pty
      
      Следующие поля в файле login.conf(5)
      зарезервированы для сторонних разработчиков. В основной системе
      FreeBSD они не использются, однако могут
      использоваться программами установленными из портов, кроме того,
      некоторые из них используются OpenBSD.
    
Таблица F.4. Зарезервированные поля в login.conf(5) FreeBSD
| Имя записи | Тип | Умолчание | Описание | OS | 
|---|---|---|---|---|
| accounted | bool | false | Включить session time accounting для всех пользователей данного класса | 
               
             | 
| auth | list | passwd | Допустимые стили аутентификации. Первое вхождение — стиль по умолчанию[a]. | 
               
             | 
| auth-type | list | Допустимые стили аутентификации для предыдущей опции(?) | 
               
             | |
| autodelete | time | Время, которое должно пройти после истечения срока действия учётной записи, спустя которое учётная запись будет автоматически удалена. | 
               
             | |
| bootfull | bool | false | Включается страгетия «boot only if ttygroup is full> при обрыве сессий. | 
               
             | 
| daytime | time | Максимальное количество логинов в день | 
               
             | |
| expireperiod | time | Time for expiry allocation. | 
               
             | |
| graceexpire | time | Grace период в днях, на истечение срока действия учётной записи [возможно речь идёт о периоде после истечения срока действия учётной записи, когда она всё ещё будет доступна, возможно в каком-то усечённом виде]. | 
               
             | |
| gracetime | time | Additional grace login time allowed | 
               
             | |
| host.accounted | list | 
              Список шаблонов определяющих имена хостов при заходе с
              которых включается session time accounting (см. так же
              accounted).
             | 
               
             | |
| host.exempt | list | 
              Список шаблонов определяющих имена хостов при заходе с
              которых пользователь освобождён от session time
              accounting (см. так же accounted).
             | 
               
             | |
| idletime | time | Максимальное время бездействия, спустя которое пользователь будет разлогинен. | 
               
             | |
| minpasswordlen | number | 6 | Минимальная длина локального пароля. | 
               
             | 
| mixpasswordcase | bool | true | Будет ли passwd(1) предупреждать пользователя, если он ввёл пароль только в нижнем регистре. | 
               
             | 
| monthtime | time | Максимально время логина в месяц. | 
               
             | |
| passwordtime | time | Используется passwd(1) для установки следующего времени истечения срока действия пароля. | 
               
             | |
| refreshtime | time | New time allowed on account refresh | 
               
             | |
| refreshperiod | string(?) | Как часто account time is refreshed | 
               
             | |
| sessiontime | time | Максимальная длительность логина. | 
               
             | |
| sessionlimit | number | Максимальное число открытых сессий. | 
               
             | |
| ttys.accounted | list | 
              Список терминалов или групп терминалов при заходе с
              которых включается session time accounting (см. так же
              accounted).
             | 
               
             | |
| ttys.exempt | list | 
              Список терминалов или групп терминалов при заходе с
              которых пользователь освобождён от session time
              accounting (см. так же accounted).
             | 
               
             | |
| warntime | time | Срок за который предупреждают об истечении времени. | 
               
             | |
| weektime | time | Максимальное количество логинов в неделю. | 
               
             | |
Таблица F.5. Поля в login.conf(5) характерные для OpenBSD
| Имя записи | Тип | Умолчание | Описание | OS | 
|---|---|---|---|---|
| approve | program | Программа используемая для логина. | 
               
             | |
| approve-<сервис> | program | Программа используемая для логина <сервиса> | 
               
             | |
| auth | list | passwd | Допустимые методы аутентификации. Первое вхождение — метод по умолчанию. | 
               
             | 
| auth-type | list | Допустимые медоды аутентификации для предыдущей опции(?) | 
               
             | |
| classify | program | Classify type of login. | 
               
             | |
| copyright | file | Файл, содержащий дополнительную информацию о copyright | 
               
             | |
| coredumpsize | size | Максимальный размер файлов coredump | 
               
             | |
| cputime | time | Максимальное процессорное время, которое может потребить программа. | 
               
             | |
| datasize | size | Максимальный размер данных. | 
               
             | |
| expire-warn | time | 2w | Если срок действия учётной записи пользователя истечёт спустя указанное время, оповестить пользователя. | 
               
             | 
| filesize | size | Максимальный размер файла. | 
               
             | |
| hushlogin | bool | false | 
              То же, как если бы пользователь имел файл
              ~/.hushlogin (не выводить
              /etc/motd при загрузке).
             | 
               
             | 
| ignorenologin | bool | false | 
              Логин не блокируется файлом
              /etc/nologin
             | 
               
             | 
| localcipher | string | blowfish,6 | 
              Алгоритм шифрования локальных паролей. Возможные
              значения приведены в Таблица 2.3, «Возможные значения опций crypt_default
          (FreeBSD) и localcipher,
          ypcipher (OpenBSD)».
             | 
               
             | 
| ypcipher | string | old | 
              Алгоритм шифрования для сетевых (NIS)
              паролей. Возможные значения приведены в Таблица 2.3, «Возможные значения опций crypt_default
          (FreeBSD) и localcipher,
          ypcipher (OpenBSD)».
             | 
               
             | 
| login-backoff | number | 3 | 
              Количество попыток логина разрешённых прежде чем начнут
              вставляться задержки между попытками логина. Величина
              задержки, равна значению login-backoff
              умноженной на 5 секунд. (Последняя, загадочная фраза
              есть только в man(1) в
              FreeBSD.)
             | 
               
             | 
| login-timeout | time | 300 | Таймаут ожидания пароля программой login(1). Работает только для записи default (т.е. не может быть переопределена в классах). | 
               
             | 
| login-tries | number | 10 | 
              Количество разрешённых попыток логина, прежде чем
              программа login(1) закроет сессию.
              (FreeBSD —login-retries)
             | 
               
             | 
| stacksize | size | Максимальный размер стека | 
               
             | |
| maxproc | number | Максимальное число процессов, которое может породить пользователь. | 
               
             | |
| memorylocked | size | Максимальный размер памяти в core memory, которую может залочить процесс. | 
               
             | |
| memoryuse | size | Максимальный размер памяти в core memory, которую может использовать процесс. | 
               
             | |
| minpasswordlen | number | 6 | Минимальная длина пароля. Используется утилитой passwd(1). Отрицательное или нулевое значение означает отсцтствие ограничения. | 
               
             | 
| nologin | file | Если указанный файл существует, при входен в систему отображается его содержимое и процедура входа прерывается. | 
               
             | |
| openfiles | number | Максимальное количество файловых дескрипторов, которое может открыть приложение. | 
               
             | |
| password-dead | time | 0 | Время, после истечения пароля, в течение которого пароль, тем не менее, ещё не умер: Пользователю дают залогиниться в системе один раз для того, чтобы он смог сменить себе пароль. | 
               
             | 
| password-warn | time | 2w | Время перед истечением срока действия пароля, за которое надо предупредить пользователя. | 
               
             | 
| passwordcheck | program | Программа для проверки качества пароля. Пароль передаётся программе на стандартный ввод. Нулевой код возврата означает, что пароль достаточно качественный с точки зрения программы. | 
               
             | |
| passwordtime | time | 
              Срок жизни пароля в секундах. Сбрасывается при каждом
              обновлении пароля. По истечении данного периода,
              пользователю не дают зайти в систему, если только не
              указана опция password-dead.
             | 
               
             | |
| passwordtries | number | 3 | Сколько раз программа passwd(1) проверяет качество пароля. Если значение ноль, то принимаются только пароли прошедшие проверку на качество. | 
               
             | 
| path | path | значение _PATH_DEFPATH | Каталоги, в которых по умолчанию искать исполнимые файлы. | 
               
             | 
| priority | number | Начальный приоритет (nice(1)) у задач пользователя. | 
               
             | |
| requirehome | bool | false | Требуется ли пригодный домашний каталог для входа пользователя в систему. | 
               
             | 
| setenv | list | 
              Разделённый запятыми список переменных и их значений,
              которые должны быть выставлены при входе пользователя в
              систему. Кавычки из файла login.conf
              переносятся в переменную как есть. Поэтому вхождение setenv=VAR1=value1,...,PAGER="/usr/bin/less -M",... —
              это ошибка. Правильно писать: setenv=VAR1=value1,...,PAGER=/usr/bin/less -M,...
             | 
               
             | |
| shell | program | 
              Оболочка пользователя. Имеет приоритет перед заданной в
              master.passwd(5), однако переменная
              $SHELL выставляется в значение
              указанное в master.passwd(5).
             | 
               
             | |
| term | string | Тип терминала, если он не может быть определён другим способом. | 
               
             | |
| umask | number | 022 | Начальное значение umask (см. Раздел 3.7, «Просмотр и изменение пермиссий с использованием как символьных, так и восьмеричных мод»). Должно всегда начинаться с нуля, для того, чтобы формат воспринимался как всьмеричный. | 
               
             | 
| vmemoryuse | size | Максимально разрешённый размер виртуальной памяти | 
               
             | |
| welcome | file | /etc/motd | Файл с приветствем. | 
               
             | 
              Есть ограничение current (мягкое) и maximum (жёсткое).
              Перечисленные опции задают сразу и то, и другое, если вы
              хотите отдельно задать мякое и жёсткое ограничение,
              используйте суффиксы -cur и -max. (Например cputime-max.) Разница между ними в
              том, что мягкие ограничения пользователь может
              переопределить в большую сторону.
             | ||||
      OpenBSD 4.1 использует аутентификацию
      BSD, которая позволяет использовать различные
      стили аутентификации. За эти стили отвечают скрипты
      /usr/libexec/auth/login_стиль. Вы можете
      создавать пользовательские стили, однако во избежание конфликтов с
      будущими стилями, вам следует начинать их название с минуса:
      /usr/local/auth/login_-пользовательский_стиль.
    
      При аутентификации пользователь может запросить некоторый
      конкретный стиль аутентификации, для этого он при логине должен
      ввести: username:style.
    
Текущие стили аутентификации:
master.passwd(5).
        
      В man(1) по login.conf(5)
      в OpenBSD описано как надо писать
      польовательские стили аутентификации.
    
Мостом называют устройство канального уровня, которое соединяет два сегмента сети. Мост должен на основании MAC-адреса назначения принять решение о том надо ли пропустить ethernet-кадр из одного сегмента сети в другой. Коммутатор (switch) можно считать многопортовым мостом.
Мостом, так же, часто называют брандмауэр канального уровня: интерфейсам не присваиваются IP-адреса. При этом Ethernet кадры копируются с интерфейса на интерфейс, но проходят через фильтр. Таким образом, мост, как устройство канального уровня, не может быть детектирован злоумышленником. Он совершенно прозрачен для протоколов сетевого уровня OSI.
BSD Associate — совокупность операционных систем семейства BSD: DragonFly BSD, FreeBSD, NetBSD и OpenBSD.
Атака типа Deny Of Service — отказ в обслуживании. Возможна в том случае, если атакующий производит при атаке мЕньшую работу, чем атакуемый. Например, если непрерывно запрашивать WEB-ресурс, для генерирования которого на сервере выполняется сложный сценарий, можно добиться того, что сервер окажется перенапряжён и перестанет отвечать на запросы, либо будет отвечать с непозволительно большими задержками, т.е. произойдёт отказ в обслуживании.
Атака типа Distributed DOS — распределённая атака типа DOS. Атакующий выстраивает «бот-сеть» и производит DOS атаку одновременно с большого числа компьютеров. За счёт распределённости ресурсов при таком способе атаки снимается требование на то, чтобы атакующий выполнял работу меньше чем атакуемый. При DDOS атаке можно обрушить сеть простым ping(8)ом.
Demilitarized Zone — Демилитаризованная зона, так же называемая PSN (Private Service Network) это сеть содержащая в себе серверы, защищённая брандмауэром (возможно не одним) как от внешней сети Интернет, так и от внутренней локальной сети. Используется для защиты серверов от атак из внутренней, локальной сети, а так же для защиты локальной сети от взломщиков, которые могут захватить контроль над сервером используя различные уязвимости в его програмном обеспечении.
GNU is Not Unix — рекурсивный акроним. Сообщество программистов разрабатывающих свободное програмное обеспечение под лицензией GPL. Многие продукты GNU вошли в состав различных BSD систем (например компилятор gcc(1)). Однако многие утилиты входящие в поставку BSD (например find(1)) не являются продуктом GNU, ведут себя несколько иначе, имеют слегка иной синтаксис.
General Public License. Лицензия под которой распространяются продукты GNU. Основное отличие от лицензии BSD состоит в том, что код защищённый лицензией GPL не может быть включён в другой (в том числе коммерческий) проект, без того, чтобы на него тоже была распространена лицензия GPL.
Mail Delivery Agent — агент подачи почты. Предназначен для предварительной обработки почты перед передачей её MTA. Устанавливается на нагруженных системах. Обычно работает на 587 порту.
Mail Transfer Agent — агент доставки почты. Програмный комплекс предназначенный для пересылки почты между хостами. Пример: sendmail, postfix, qmail, Microsoft Exchange.
Maximum Transmission Unit — максимальный размер (в байтах) кадра (на канальном уровне модели OSI).
Mail User Agent — Пользовательская программа, предназначенная для чтения почты и взаимодействия с MTA локально или удалённо при помощи протокола SMTP. Пример: mail, pine, mutt; графические варианты evolution, kmail, tunderbird, M2; в Windows известны такие MUA как TheBAT!, Outlook Express.
Network Adress Translation — трансляция сетевых адресов. Один из способов скрыть целую сеть за одним адресом. Использование NAT необходимо в ситуации когда провайдер выделил адресов меньше чем компьютеров в сети. NAT описан в [RFC-1631].
NAT позволяет использовать блоки приватных адресов описанных в [RFC-1918]:
| 10.0.0.0/8 | (от 10.0.0.0 до 10.255.255.255) | 
| 172.16.0.0/12 | (от 172.16.0.0 до 172.31.255.255) | 
| 192.168.0.0/16 | (от 192.168.0.0 до 192.168.255.255) | 
В процессе трансляции у исходящего пакета исходящий адрес IP подменяется на адрес сетевого интерфейса шлюза, а так же при необходимости меняется номер порта источника (если у шлюза данный порт уже занят). С ответными пакетами проделывается обратное преобразование.
Ни внутренняя машина, ни внешняя не знают о существовании NAT. Всё происходит прозрачно. Для внутренней машины NAT это просто шлюз, а внешняя машина ничего не знает о внутренней и считает, что соединение открыто шлюзом. NAT можно попытаться засечь только по косвенным признакам.
Сетевая модель OSI (англ. Open Systems Interconnection Reference Model — модель взаимодействия открытых систем) — абстрактная модель для сетевых коммуникаций и разработки сетевых протоколов.
Модель разбивает сетевые протоколы на семь уровней:
Данную модель удобно использовать в учебных целях для классификации. В текущем пособии сетевая модель обсуждается в Раздел B.1, «Классификация сетевых протоколов». В сети Интернет о модели OSI можно почитать здесь: [url://wiki-OSI-ru].
Ping of Death — смертельный пинг. В норме, размер ICMP пакета echo request составляет 64 байта (84 байта с заголовком IP). Многие системы не могут обработать пакет ICMP echo request, длина которого превышает допустимый размер пакета IP (65535 байт). Отправка такого пакета может привести к падению системы на атакуемой машине. Такой пакет противоречит протоколу, однако отправить его довольно просто. Длинный ICMP пакет передаётся в фрагментированном виде и собираясь на атакуемой машине переполняет в ней буфер, что приводит к крушению операционной системы. Эта уязвимость была распространена повсеместно в UNIX, Linux, Windows, Mac, принтерах и маршрутизаторах. Однако она была исправлена практически во всех ситемах примерно в 1997-1998 годах.
В последние годы более актуальной стала другая атака основанная на пакетах ICMP echo request: ping flooding (см. DOS атака)
Portable Operating System — последние буквы добавлены для созвучия со словом UNIX. POSIX это стандарт, которому должна отвечать операционная система для того, чтобы в ней могли запускаться программы предназначенные для UNIX.
Private Service Network — см. DMZ.
          «Магическая строка» с которой должны начинаться
          скрипты в UNIX. Первые два символа строки:
          #!, затем идёт название
          интерпретатора, которому будет подан на вход текст скрипта.
        
Спуфинг — в заголовке IP пакета подделывается адрес источника. Спуфинг применяется для обхода аутентификации по IP адресу, а так же для выполнения сетевых атак. (Часто администраторы защищают систему от атак изнутри слабее, чем от атак снаружи, поэтому злоумышленник может попробовать прикинуться инсайдером.) Для борьбы со спуфингом применяют пакетные фильтры. Различают «ingress filtering» — запрет на прохождение внутрь системы пакетов с исходящими внутренними адресами; и «egress filtering» — запрет на выход из сети пакетов с исходящими адресами находящимися вне внутренней сети.
Протокол TCP имеет встроенный механизм для предотвращения спуфинга — так называемые номера последовательности и подтверждения (sequence number, acknowledgement number). Протокол UDP не имеет такого механизма, следовательно, построенные на его основе приложения более уязвимы для спуфинга. См. так же [url://buggzy-2002].
Термин «спуфинг» так же применяют применительно к подделке исходящих адресов в заголовках электронной почты и др.
Фильтрация трафика с учётом состояния соединений. (См. так же stateless inspection.)
В реализации более сложна, чем фильтрация без учёта состояний. stateful inspection трактует трафик не как множество независящих друг от друга пакетов, а как совокупность потоков, каждый из которых, принадлежит некоторому соединению. Все соединения в большинстве протоколов используют некоторое число, указывающее в каком порядке должны собираться пакеты в сокете назначения. Брандмауэр, использующий stateful inspection, на основании этого числа может опознать пакеты как принадлежащие одному соединению. В особенности это относится к протоколам поддерживающим информацию о соединениях. Таким как TCP.
Stateful брандмауэр может:
Фильтрация трафика без учёта состояния соединений. (См. так же stateful inspection.)
Каждый пакет брандмауэр фильтрует индивидуально, без учёта других пакетов. Такой брандмауэр прост в реализации и может быть эффективно использован для:
Unix File System. Файловая система принятая в BSD. Существует множество разновидностей UFS.
 [McKusick-2004] 
 [McKusick-2006-ru] 
 [Stevens-2003-ru] 
 [Albitz-2004-ru] 
 [Christenson-2004-ru] 
 [Friedl-2001-ru] Примечание: в связи с временной(?) гибелью домена www.protocols.ru (хотя домен проплачен...) документы перенесены на моё зеркало.
Примечание: в связи с временной(?) гибелью домена www.protocols.ru (хотя домен проплачен...) документы перенесены на моё зеркало.
Примечание: в связи с временной(?) гибелью домена www.protocols.ru (хотя домен проплачен...) документы перенесены на моё зеркало.