Разработка пакетов для pfSense
Пакеты расширяют функциональность pfSense без модификации базовой системы. Каждый пакет представляет собой FreeBSD-порт со специфичной для pfSense структурой: XML-манифест определяет метаданные, XML-файлы конфигурации описывают интерфейс, а PHP-файлы реализуют логику. Package Manager устанавливает пакеты из официального репозитория, но разработчики могут собирать и устанавливать собственные пакеты вручную.
Структура порта пакета
Пакеты pfSense именуются по схеме pfSense-pkg-<Name> и размещаются в категорийных каталогах FreeBSD-портов (например, sysutils/, net/, security/). Разработка ведется в ветке devel репозитория pfSense FreeBSD-ports
.
Типичная структура порта:
sysutils/pfSense-pkg-MyPackage/
├── Makefile # Версия, зависимости, сборка
├── pkg-descr # Текстовое описание пакета
├── pkg-plist # Список устанавливаемых файлов
└── files/
├── pkg-install.in # Скрипт установки
├── pkg-deinstall.in # Скрипт удаления
└── usr/local/
├── bin/ # Исполняемые скрипты
├── pkg/
│ ├── mypackage.xml # Конфигурация GUI
│ └── mypackage.inc # PHP-модуль с логикой
├── share/pfSense-pkg-MyPackage/
│ └── info.xml # Манифест пакета
└── www/packages/mypackage/
└── mypackage.php # Веб-страницы пакетаMakefile
Makefile определяет версию пакета, зависимости и процедуру сборки. Версия задается через переменную PORTVERSION, а зависимости от бинарных пакетов FreeBSD указываются в RUN_DEPENDS:
PORTNAME= pfSense-pkg-MyPackage
PORTVERSION= 0.1.0
CATEGORIES= sysutils
MASTER_SITES= # пусто для локальных пакетов
MAINTAINER= developer@example.com
COMMENT= My custom pfSense package
RUN_DEPENDS+= bash:shells/bash
NO_BUILD= yes
NO_MTREE= yes
.include <bsd.port.mk>При каждом обновлении пакета необходимо увеличивать PORTVERSION. Без изменения версии система не обнаружит обновление.
pkg-plist
Файл pkg-plist перечисляет все файлы, устанавливаемые пакетом, относительно /usr/local/:
share/pfSense-pkg-MyPackage/info.xml
pkg/mypackage.xml
pkg/mypackage.inc
www/packages/mypackage/mypackage.phpПри добавлении новых файлов в пакет обязательно обновляйте pkg-plist, иначе файлы не будут включены в сборку.
Скрипты установки и удаления
Файлы pkg-install.in и pkg-deinstall.in одинаковы для всех пакетов pfSense и обеспечивают интеграцию с Package Manager. Копируйте их из любого существующего пакета без изменений.
XML-манифест (info.xml)
Манифест info.xml размещается в files/usr/local/share/pfSense-pkg-<Name>/info.xml и содержит метаданные пакета:
<?xml version="1.0" encoding="utf-8" ?>
<pfsensepkgs>
<package>
<name>mypackage</name>
<descr>Description of my package</descr>
<pkginfolink>https://example.com/docs</pkginfolink>
<version>%%PKGVERSION%%</version>
<configurationfile>
https://packages.pfsense.org/packages/config/mypackage/mypackage.xml
</configurationfile>
</package>
</pfsensepkgs>Переменная %%PKGVERSION%% автоматически подставляется из PORTVERSION в Makefile при сборке.
Конфигурация GUI (XML-файл пакета)
XML-файл конфигурации (например, mypackage.xml) определяет интеграцию пакета с веб-интерфейсом pfSense: пункты меню, страницы настроек, поля форм и хуки жизненного цикла.
Интеграция в меню
Элемент <menu> регистрирует пакет в навигации pfSense:
<packagegui>
<menu>
<name>MyPackage</name>
<section>Services</section>
<url>/packages/mypackage/mypackage.php</url>
</menu>
</packagegui>Пакет появится в разделе Services главного меню после установки.
Определение полей настроек
Раздел <fields> описывает элементы формы на странице настроек пакета:
<fields>
<field>
<fielddescr>Enable Service</fielddescr>
<fieldname>enable</fieldname>
<type>checkbox</type>
<description>Enable or disable the service</description>
</field>
<field>
<fielddescr>Listen Port</fielddescr>
<fieldname>port</fieldname>
<type>input</type>
<size>5</size>
<description>Port number for the service (default: 8080)</description>
</field>
<field>
<fielddescr>Network Interface</fielddescr>
<fieldname>interface</fieldname>
<type>interfaces_selection</type>
<description>Select the interface to bind</description>
</field>
</fields>Поддерживаемые типы полей: input, password, textarea, checkbox, select, interfaces_selection, info, button.
Для группировки полей в одну строку используйте <combinefields>. Для табличного ввода нескольких записей - <rowhelper>. Для списков с добавлением, удалением и редактированием - <adddeleteeditpagefields>.
Хуки жизненного цикла
PHP-функции, выполняемые на различных этапах работы пакета:
| Хук | Назначение |
|---|---|
custom_php_install_command | Действия после установки пакета |
custom_php_deinstall_command | Очистка при удалении пакета |
custom_php_resync_config_command | Синхронизация конфигурации (вызывается при сохранении) |
custom_php_validation_command | Валидация введенных данных перед сохранением |
Хуки указываются в XML как имена PHP-функций, определенных в .inc-файле пакета.
PHP-файлы пакета
Include-файл (.inc)
Файл mypackage.inc в каталоге files/usr/local/pkg/ содержит основную логику пакета: функции валидации, применения конфигурации, генерации конфигурационных файлов сервисов.
<?php
require_once("config.inc");
require_once("util.inc");
require_once("service-utils.inc");
function mypackage_validate_input($post, &$input_errors) {
if (!is_port($post['port'])) {
$input_errors[] = "Invalid port number.";
}
}
function mypackage_resync_config() {
global $config;
$settings = $config['installedpackages']['mypackage']['config'][0];
if ($settings['enable'] != "on") {
mypackage_stop_service();
return;
}
// Generate configuration file
$conf = "listen_port={$settings['port']}\n";
file_put_contents("/usr/local/etc/mypackage.conf", $conf);
mypackage_restart_service();
}
function mypackage_restart_service() {
mwexec("/usr/local/bin/mypackage restart");
}
function mypackage_stop_service() {
mwexec("/usr/local/bin/mypackage stop");
}Веб-страницы (.php)
PHP-файлы в files/usr/local/www/packages/mypackage/ отвечают за отображение страниц пакета в веб-интерфейсе. Для большинства пакетов достаточно стандартного шаблона, который автоматически генерирует страницу настроек на основе XML-конфигурации.
Зависимости пакета
Зависимости от бинарных пакетов FreeBSD указываются в Makefile через RUN_DEPENDS. XML-конфигурация пакета не управляет зависимостями - это задача системы портов.
RUN_DEPENDS+= python3:lang/python3 \
curl:ftp/curl
pfSense использует собственный репозиторий пакетов, основанный на FreeBSD pkg. Не все пакеты из стандартного репозитория FreeBSD доступны - проверяйте наличие нужных зависимостей в репозитории pfSense перед их использованием.
Компиляция ПО для pfSense
pfSense намеренно не включает средства компиляции (make, заголовочные файлы) из соображений безопасности. Для компиляции стороннего ПО:
- Разверните виртуальную машину с версией FreeBSD, соответствующей вашей версии pfSense
- Скомпилируйте программу в этой среде
- Перенесите готовые бинарные файлы или пакеты на межсетевой экран
Альтернативный вариант - использовать предкомпилированные пакеты FreeBSD через pkg install при условии совместимости версий.
Сборка и тестирование пакета
Сборка пакета
Для сборки пакета из порта используется стандартный механизм FreeBSD:
cd /usr/ports/sysutils/pfSense-pkg-MyPackage
make packageРезультатом будет файл .pkg (или .txz), готовый к установке.
Установка на тестовый экземпляр
Установите собранный пакет на тестовый pfSense:
pkg add pfSense-pkg-MyPackage-0.1.0.pkgПосле установки:
- Проверьте появление пункта в меню
- Протестируйте сохранение и загрузку настроек
- Убедитесь, что хуки жизненного цикла работают корректно
- Проверьте корректную работу при удалении и повторной установке пакета
Отладка
При ошибках в пакете просматривайте журнал системы:
tail -f /var/log/system.logPHP-ошибки пакетов отображаются на странице Status > System Logs в разделе System > General.
Публикация пакета
Для включения пакета в официальный репозиторий pfSense:
- Убедитесь, что пакет соответствует руководству по стилю
- Создайте запись в Redmine pfSense с описанием пакета
- Отправьте pull request в репозиторий pfSense FreeBSD-ports
в ветку
devel - Дождитесь ревью от разработчиков Netgate
Pull request должен содержать ссылку на запись в Redmine, описание функциональности и результаты тестирования.
Типичные ошибки
| Проблема | Причина | Решение |
|---|---|---|
| Пакет не обновляется | Не увеличен PORTVERSION в Makefile | Инкрементируйте версию при каждом изменении |
| Файлы не устанавливаются | Не обновлен pkg-plist | Добавьте все новые файлы в pkg-plist |
| Ошибки PHP после обновления pfSense | Несовместимость с PHP 8.x | Замените устаревшие функции, используйте elseif вместо else if |
| Пакет работает на 2.7, но не на 2.8 | Изменения в базовой версии FreeBSD | Проверяйте совместимость с целевой версией FreeBSD |
| Пробелы вместо табуляции | Нарушение стиля кодирования | Используйте табуляцию с шириной 8 для отступов |
| XSS-уязвимости | Вывод пользовательского ввода без экранирования | Используйте htmlspecialchars() для всех выводимых данных |
Связанные разделы
- Пользовательские скрипты pfSense - скрипты автоматизации, Shellcmd, Cron и PHP Shell
- API и автоматизация - программное управление pfSense через REST API
- Пакеты pfSense - установка и управление пакетами через Package Manager