Разработка пакетов для 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, заголовочные файлы) из соображений безопасности. Для компиляции стороннего ПО:

  1. Разверните виртуальную машину с версией FreeBSD, соответствующей вашей версии pfSense
  2. Скомпилируйте программу в этой среде
  3. Перенесите готовые бинарные файлы или пакеты на межсетевой экран

Альтернативный вариант - использовать предкомпилированные пакеты 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.log

PHP-ошибки пакетов отображаются на странице Status > System Logs в разделе System > General.

Публикация пакета

Для включения пакета в официальный репозиторий pfSense:

  1. Убедитесь, что пакет соответствует руководству по стилю
  2. Создайте запись в Redmine pfSense с описанием пакета
  3. Отправьте pull request в репозиторий pfSense FreeBSD-ports в ветку devel
  4. Дождитесь ревью от разработчиков 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() для всех выводимых данных

Связанные разделы

Last updated on