Установка greylistd в NetBSD
Содержание
Введение
greylistd - это демон, написанный на языке программирования Python. С его помощью можно добавить в почтовый сервер Exim функции фильтрации писем по серым спискам. Мне понадобилось установить его в NetBSD, но в pkgsrc нет greylistd, поэтому пришлось добавить его в pkgsrc самостоятельно. На всякий случай решил описать процесс, т.к. до этого я только дорабатывал только чужие pkgsrc, а этот pkgsrc был моим первым, созданным самостоятельно.
Написание pkgsrc
Т.к. до этого я пользовался greylistd в Debian, то решил собрать такую же версию, которая есть в официальных репозиториях Debian. На момент написания этой заметки это была версия 0.9.0.2.
Получение исходных текстов
Оказалось, что сейчас разработка greylistd ведётся одним из разработчиков Debian и git-репозиторий проекта находится на GitLab-сервере Debian. Нашёл ссылку на скачивание архива исходных текстов версии 0.9.0.2 и с помощью утилиты url2pkg
сгенерировал заготовку:
$ url2pkg https://salsa.debian.org/debian/greylistd/-/archive/master/greylistd-master.tar.bz2
Сразу же поправил в Makefile
информацию о сопровождающем пакета, лицензии и прописал ссылку на домашний сайт проекта:
MAINTAINER= vladimir@stupin.su
HOMEPAGE= https://salsa.debian.org/debian/greylistd/
COMMENT= Greylisting daemon for use with Exim 4
LICENSE= gnu-gpl-v2
В этот же файл предпоследней строчкой добавил зависимость от языка программирования Python:
.include "../../lang/python/egg.mk"
Заменил автоматически сгенерированное содержимое файла DESCR
на простую строчку с описанием назначения программы:
Greylisting daemon for use with Exim 4
На этом этапе можно было выполнить распаковку проекта с помощью команды make extract
, но сборка не выполнялась, т.к. для сборки проектов на Python требуется файл setup.py
, которого не оказалось в исходных текстах, т.к. разработчики Debian собирают сразу пакет для Debian.
Сборка
Вооружившись статьёй, в которой описано, как писать файлы setup.py
, написал такой файл:
#!/usr/bin/env python
from distutils.core import setup
setup(name='Greylistd',
version='0.9.0.2',
maintainer='Vladimir Stupin',
maintainer_email='vladimir@stupin.su',
url='https://salsa.debian.org/debian/greylistd/',
description='Greylisting daemon for use with Exim 4',
keywords=['mail'],
license='GPLv2+',
classifiers=['License :: OSI Approved :: GNU General Public License v2 or later (GPLv2+)',
'Programming Language :: Python',
'Topic :: Communications :: Email :: Filters'],
packages=['greylistd'],
package_dir={'greylistd': 'program'},
data_files=[('bin', ['program/greylist']),
('sbin', ['program/greylistd-setup-exim4',
'program/greylistd']),
('share/examples/greylistd', ['doc/examples/exim4-acl-example.txt',
'doc/examples/whitelist-hosts']),
('etc/greylistd', ['config/config',
'config/whitelist-hosts']),
('man/man1', ['doc/man1/greylist.1']),
('man/man8', ['doc/man8/greylistd.8',
'doc/man8/greylistd-setup-exim4.8']),
]
)
Этот файл сохранил под именем files/setup.py
.
Для того, чтобы файл попадал в каталог с исходными текстами перед сборкой, прописал в Makefile
дополнительное правило:
post-extract:
${CP} ${FILESDIR}/setup.py ${WRKSRC}/setup.py
Теперь сборка командой make
выполнилась успешно.
Сборка пакета
Осталось наполнить файл PLIST
правильным списком файлов, входящих в состав пакета. Для этого я выполнил две команды:
$ make package
$ make print-PLIST > PLIST
Запуск скриптов на Python
В получившемся пакете исполняемые файлы не имеют бита исполнимости. Чтобы исправить это, добавим в правило post-extract
в Makefile
дополнительные команды:
${RUN}${CHMOD} +x ${WRKSRC}/program/greylist
${RUN}${CHMOD} +x ${WRKSRC}/program/greylistd
${RUN}${CHMOD} +x ${WRKSRC}/program/greylistd-setup-exim4
Но этого не достаточно. Поскольку исполняемые файлы являются скриптами, для их запуска используется интерпретатор. Путь к интерпретатору содержится в первой строке исполняемого файла и начинается с символов #!
. Изменить путь к интерпретатору языка Python можно с помощью опции REPLACE_PYTHON
, в качестве значения которой нужно указать все скрипты на языке Python, в которых нужно исправить путь к интерпретатору:
REPLACE_PYTHON= program/greylist program/greylistd program/greylistd-setup-exim4
Если заглянуть в файл program/greylistd
, то можно заметить, что для его запуска требуется Python версии 3.6 или выше:
# Ensure that we can run this program
if sys.version_info.major < 3 or sys.version_info.minor < 6:
sys.stderr.write("This program requires Python 3.6 or newer\n")
sys.exit(1)
Проверим, какие версии Python доступны из pkgsrc:
# cd /usr/pkgsrc/lang
# ls -d python*
python python27 python310 python311 python37 python38 python39
Версии 3.7, 3.8, 3.9, 3.10, 3.11 совместимы с greylistd, а версия 2.7 - нет. Добавим в Makefile список несовместимых версий Python:
PYTHON_VERSIONS_INCOMPATIBLE= 27
Для поддержки этой опции в конец Makefile
перед прочими директивами .include
нужно добавить ещё одну:
.include "../../lang/python/application.mk"
Исправление путей
В исполняемых файлах и файлах конфигурации указаны пути к файлам конфигурации, к Unix-сокету, к файлам базы данных демона. Нужно откорректировать пути ко всем этим файлам так, чтобы они соответствовали настройкам, заданным при сборке пакета из pkgsrc. Для этого воспользуемся функционалом SUBST
из pkgsrc и пропишем в Makefile
следующие настройки:
SUBST_CLASSES+= paths
SUBST_STAGE.paths= pre-configure
SUBST_MESSAGE.paths= Fixing absolute paths.
SUBST_FILES.paths= config/config program/greylist program/greylistd program/greylistd-setup-exim4 doc/man8/greylistd.8
SUBST_SED.paths= -e 's,/etc/,${PREFIX}/etc/,g'
SUBST_SED.paths+= -e 's,/var/lib/greylistd/,${VARBASE}/db/greylistd/,g'
SUBST_SED.paths+= -e 's,/var/run/greylistd/socket,${VARBASE}/run/greylistd.sock,g'
SUBST_VARS.paths= PREFIX VARBASE
В указанных выше настройках есть только одна группа замен, которая называется paths
. Выполняются замены на этапе pre-configure
. Пути к изменяемым файлам перечислены в переменной SUBST_FILES
. Далее следуют три правила замены, в которых используются значения переменных PREFIX
и VARBASE
. Имена переменных, участвующих в замене, перечислены в переменной SUBST_VARS
.
Пользователь и группа
Для запуска greylistd нужны пользователь и группа greylist, т.к. они используются в качестве владельца Unix-сокета. Добавим в Makefile
настройки:
GREYLIST_USER?= greylist
GREYLIST_GROUP?= greylist
Добавим в Makefile
опции, преписывающие создать необходимых для работы пакета группу и пользователя:
PKG_GROUPS+= ${GREYLIST_GROUP}
PKG_USERS+= ${GREYLIST_USER}:${GREYLIST_GROUP}
И добавим в Makefile
замену пользователя и группы владельца Unix-сокета в исходном тексте greylistd:
SUBST_CLASSES+= user_group
SUBST_STAGE.user_group= pre-configure
SUBST_MESSAGE.user_group= Replacing user and group.
SUBST_FILES.user_group= program/greylistd
SUBST_SED.user_group= -e 's,SOCKOWNER: "greylist:greylist",SOCKOWNER: "${GREYLIST_USER}:${GREYLIST_GROUP}",g'
SUBST_VARS.user_group= GREYLIST_USER GREYLIST_GROUP
Права доступа
Для работы greylistd нужен доступ в каталог /var/db/greylistd
, в котором он хранит статистику, белые, чёрные и серые списки. Для создания этого каталога с соответсвующими правами доступа добавим в файл Makefile
такую строку:
OWN_DIRS_PERMS+= ${VARBASE}/db/greylistd/ ${GREYLIST_USER} ${GREYLIST_GROUP} 0766
Кроме этого, как оказалось, при запуске greylistd от имени пользователя greylist, ему не удаётся создать Unix-сокет в каталоге /var/run/
из-за нехватки прав. Поэтому изменим путь к Unix-сокету, переместив его в каталог с файлами данных greylistd. Для этого найдём ранее добавленную в Makefile
строчку:
SUBST_SED.paths+= -e 's,/var/run/greylistd/socket,${VARBASE}/run/greylistd.sock,g'
И заменим её на такую строчку:
SUBST_SED.paths+= -e 's,/var/run/greylistd/socket,${VARBASE}/db/greylistd/socket,g'
Файлы конфигурации
В системе pkgsrc для корректной работы с файлами конфигурации предусмотрена опция CONF_FILES
. Она позволяет устанавливать файлы конфигурации при установке пакета в соответствующий каталог etc
, если этих файлов ещё нет, и автоматически удалять не изменившиеся файлы при удалении пакета. К сожалению, нельзя просто указать, какие из устанавливаемых файлов являются файлами конфигурации - возможно только указать путь к примерам файлов конфигурации и к месту их установки. В нашем случае это может выглядеть, например, следующим образом:
CONF_FILES+= ${PREFIX}/share/examples/greylistd/config ${PKG_SYSCONFDIR}/greylistd/config
CONF_FILES+= ${PREFIX}/share/examples/greylistd/whitelist-hosts ${PKG_SYSCONFDIR}/greylistd/whitelist-hosts
Остаётся только положить в каталог ${PREFIX}/share/examples/greylistd/
нужные файлы. Но в нашем случае в этом каталоге уже лежит файл whitelist-hosts
и он отличается от нужного, т.к. происходит из файла ${WRKSRC}/doc/examples/whitelist-hosts
. Этот файл предназначен для использования с Exim, поэтому переименуем его в exim4-whitelist-hosts
, добавив в правило post-extract
действие по переименованию этого файла:
${MV} ${WRKSRC}/doc/examples/whitelist-hosts ${WRKSRC}/doc/examples/exim4-whitelist-hosts
Вернёмся к файлу files/setup.py
, с которого мы начинали сборку пакета, и поменяем место установки файлов конфигруации так, чтобы они устанавливались в каталог с примерами файлов конфигурации:
data_files=[('bin', ['program/greylist']),
('sbin', ['program/greylistd-setup-exim4',
'program/greylistd']),
('share/examples/greylistd', ['doc/examples/exim4-acl-example.txt',
'doc/examples/exim4-whitelist-hosts',
'config/config',
'config/whitelist-hosts']),
('man/man1', ['doc/man1/greylist.1']),
('man/man8', ['doc/man8/greylistd.8',
'doc/man8/greylistd-setup-exim4.8']),
]
И добавим ещё одно правило для создания каталога для файлов конфигурации:
OWN_DIRS_PERMS+= ${PKG_SYSCONFDIR}/greylistd/ ${GREYLIST_USER} ${GREYLIST_GROUP} 0766
Так как после изменений, внесённых в файлы Makefile
и files/setup.py
, изменилось место установки файлов конфигруации, нужно обновить и файл PLIST
. Для этого снова выполним две команды:
$ make package
$ make print-PLIST > PLIST
Использование PKGBASE
Внесём ещё одно небольшое изменение. Пакет использует для хранения собственых файлов каталог ${VARBASE}/db/greylistd/
, для размещения файлов конфигруации каталог ${PKG_SYSCONFDIR}/greylistd/
, а для размещения примеров файлов конфигурации - каталог ${PREFIX}/share/examples/greylistd/
. Как видно, самый последний подкаталог имеет имя greylistd
. Гипотетически может произойти так, что появится две несовместимые между собой версии greylistd
, которые может потребоваться использовать одновременно, как, например, это происходило с различными версиями apache, php-fpm и т.п. Согласен, звучит натянуто, однако чисто теоретически это возможно. В таких случаях принято вместо жёстко прописанного имени использовать переменную ${PKGBASE}
. Заменим в файле Makefile
все эти каталоги с учётом возможности использования ${PKGBASE}
. Изменить придётся не так много строк:
SUBST_SED.paths+= -e 's,/var/lib/greylistd/,${VARBASE}/db/${PKGBASE}/,g'
SUBST_SED.paths+= -e 's,/var/run/greylistd/socket,${VARBASE}/db/${PKGBASE}/socket,g'
CONF_FILES+= ${PREFIX}/share/examples/${PKGBASE}/config ${PKG_SYSCONFDIR}/${PKGBASE}/config
CONF_FILES+= ${PREFIX}/share/examples/${PKGBASE}/whitelist-hosts ${PKG_SYSCONFDIR}/${PKGBASE}/whitelist-hosts
OWN_DIRS_PERMS+= ${VARBASE}/db/${PKGBASE}/ ${GREYLIST_USER} ${GREYLIST_GROUP} 0766
OWN_DIRS_PERMS+= ${PKG_SYSCONFDIR}/${PKGBASE}/ ${GREYLIST_USER} ${GREYLIST_GROUP} 0766
Вывод журналов на stderr
greylistd умеет выводить сообщения об ошибках на стандартный поток диагностических сообщений - stderr или отправлять их демону syslog. Но выбрать, куда нужно отправлять сообщения, нельзя: если greylistd запущен из терминала, то сообщения направляются на stderr, а в противном случае сообщения отправляются в syslog. Я собираюсь запускать greylistd под управлением daemontools и мне было бы удобнее, чтобы сообщения отправлялись на stderr. Для того, чтобы оставить поведение по умолчанию, но добавить возможность выбора, я подготовил небольшую заплатку, которая добавляет в greylistd опцию logmode
в секции [daemon]
.
Заплатку для исправления исходных текстов самого демона я поместил в файл patches/patch-program_greylistd
, выглядит она следующим образом:
$NetBSD$
--- program/greylistd.orig 2020-11-10 09:16:46.000000000 +0000
+++ program/greylistd
@@ -39,6 +39,9 @@ if sys.version_info.major < 3 or sys.ver
# Configuration file sections, items
+(DAEMON, LOGMODE) = (
+ "daemon", "logmode")
+
(DATA, STATEFILE, TRIPLETFILE, SAVETRIPLETS, UPDATEINTERVAL,
SINGLECHECK, SINGLEUPDATE) = (
"data", "statefile", "tripletfile", "savetriplets", "update",
@@ -54,7 +57,9 @@ if sys.version_info.major < 3 or sys.ver
# Defaults for various configuration items
conffile = "/etc/greylistd/config"
-config = {DATA: {STATEFILE: "/var/lib/greylistd/states",
+config = {DAEMON: {LOGMODE: "auto"},
+
+ DATA: {STATEFILE: "/var/lib/greylistd/states",
TRIPLETFILE: "/var/lib/greylistd/triplets",
SAVETRIPLETS: True,
SINGLECHECK: False,
@@ -124,7 +129,11 @@ def listStatus(searchkey):
def log(message, priority=LOG_NOTICE):
- if os.isatty(sys.stderr.fileno()):
+ if config[DAEMON][LOGMODE] == "stderr":
+ sys.stderr.write("%s\n" % (message,))
+ elif config[DAEMON][LOGMODE] == "syslog":
+ syslog.syslog(priority, message)
+ elif os.isatty(sys.stderr.fileno()):
sys.stderr.write("%s\n" % (message,))
else:
syslog.syslog(priority, message)
Вторую заплатку для исправления файла конфигурации я поместил в файл patches/patch-config_config
, выглядит она так:
$NetBSD$
--- config/config.orig 2023-02-12 06:19:52.291251220 +0000
+++ config/config
@@ -2,6 +2,10 @@
### FILE: /etc/greylistd/config
### PURPOSE: Configuration settings for the "greylistd(8)" daemon
########################################################################
+[daemon]
+# Logging mode, one of the following: syslog, stderr, auto
+# Default mode is auto: use stderr if it is a tty, otherwise use syslog
+logmode = auto
[timeouts]
# Initial delay before previously unknown triplets are allowed to pass
Заплатку для исправления справочного руководства я поместил в файл patches/patch-doc_man8_greylistd.8
, в ней содержатся следующие исправления:
$NetBSD$
--- doc/man8/greylistd.8.orig 2023-02-12 14:10:15.847567733 +0000
+++ doc/man8/greylistd.8
@@ -111,6 +111,9 @@ other MTAs, check the links on Evan Harr
.SS "/etc/greylistd/config"
Configuration settings. Currently, this file consists of three
sections:
+.IP "[daemon]" 4
+General options for the daemon. Currently contains only one option
+to switch the logging mode.
.IP "[timeout]" 4
Lists various timeouts used to determine how long to keep a new
\fItriplet\fP greylisted, and when to expire previosly known
Как видно из заплаток, для выбора режима можно поменять значение опции logmode
в секции [daemon]
со значения auto
на значение stderr
или syslog
.
Поместим список заплаток вместе с их контрольными файлами в файл distinfo
:
# make makepatchsum
Итоги
До полноценного пакета для NetBSD не хватает скрипта инициализации, но этот вопрос меня не интересует, т.к. я собираюсь запускать greylistd под управлением daemontools. Возможно в pkgsrc понадобится добавить ещё некоторые доработки, чтобы поменять пути к файлам конфигурации, путь к месту размещения базы данных демона и т.п.
Я добавил получившийся порт для сборки на свой сборочный сервер, чтобы в дальнейшем готовый пакет можно было установить с помощью pkgin из репозитория.
Использованные материалы
- salsa.debian.org/debian/greylistd/ - актуальный git-репозиторий
greylistd
, поддерживаемый разработчиками Debian, - github.com/eurovibes/greylistd - устаревшее ответвление git-репозитория
greylistd
, - The pkgsrc developer's guide - руководство разработчика pgsrc,
- Writing the Setup Script - написание скрипта
setup.py
.