Refactor (#1)

- Migrated the authentication page from XML to a fully custom PHP implementation for better control and flexibility
- Service is now started on installation and persisted via an RC file for automatic restart after system reboot
- Added support for start/stop/restart actions via the pfSense service shortcuts
This commit is contained in:
Bethuel Mmbaga
2025-07-01 21:40:48 +03:00
committed by GitHub
parent e6ac5892cd
commit e01db24a48
15 changed files with 443 additions and 201 deletions
+74
View File
@@ -0,0 +1,74 @@
name: Release
on:
push:
tags:
- "v*"
branches:
- main
pull_request:
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}-${{ github.head_ref || github.actor_id }}
cancel-in-progress: true
jobs:
release:
runs-on: ubuntu-22.04
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Build
id: build
uses: vmactions/freebsd-vm@v1
with:
usesh: true
copyback: true
release: "15.0"
prepare: |
pkg install -y git go124 ca_root_nss poudriere
git clone -b devel --depth 1 --single-branch https://github.com/pfsense/FreeBSD-ports.git /usr/ports
run: |
set -ex
cd pfSense-pkg-NetBird
make
make package
cd ../netbird
make makesum
make package
- name: Upload pfSense package artifact
uses: actions/upload-artifact@v4
with:
name: pfSense-package
path: pfSense-pkg-NetBird/work/pkg/pfSense-pkg-NetBird-*.pkg
retention-days: 3
- name: Upload FreeBSD package artifact
uses: actions/upload-artifact@v4
with:
name: FreeBSD-package
path: netbird/work/pkg/netbird-*.pkg
retention-days: 3
- name: Create Release
if: startsWith(github.ref, 'refs/tags/')
uses: actions/create-release@v1
with:
tag_name: ${{ github.ref_name }}
release_name: Release ${{ github.ref_name }}
draft: false
prerelease: false
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Upload packages to release page
if: startsWith(github.ref, 'refs/tags/')
uses: softprops/action-gh-release@v1
with:
files: |
pfSense-pkg-NetBird/work/pkg/pfSense-pkg-NetBird-*.pkg
netbird/work/pkg/netbird-*.pkg
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 194 KiB

After

Width:  |  Height:  |  Size: 68 KiB

+30
View File
@@ -0,0 +1,30 @@
PORTNAME= netbird
DISTVERSIONPREFIX= v
DISTVERSION= 0.49.0
CATEGORIES= security net net-vpn
MAINTAINER= hakan.external@netbird.io
COMMENT= Peer-to-peer VPN that seamlessly connects your devices
WWW= https://netbird.io/
LICENSE= BSD3CLAUSE
LICENSE_FILE= ${WRKSRC}/LICENSE
NOT_FOR_ARCHS= i386
NOT_FOR_ARCHS_REASON= "no 32-bit builds supported"
RUN_DEPENDS= ca_root_nss>0:security/ca_root_nss
USES= go:modules
USE_RC_SUBR= netbird
GO_MODULE= github.com/netbirdio/netbird
GO_TARGET= ./client:netbird
GO_BUILDFLAGS= -tags freebsd -o ${PORTNAME} -ldflags \
"-s -w -X github.com/netbirdio/netbird/version.version=${DISTVERSION}"
WRKSRC= ${WRKDIR}/netbird-${DISTVERSION}
PLIST_FILES= bin/netbird
.include <bsd.port.mk>
+18
View File
@@ -0,0 +1,18 @@
#!/bin/sh
#
# PROVIDE: netbird
# REQUIRE: SERVERS
# KEYWORD: shutdown
#
. /etc/rc.subr
name="netbird"
netbird_env="IS_DAEMON=1"
pidfile="/var/run/${name}.pid"
command="/usr/sbin/daemon"
daemon_args="-P ${pidfile} -r -t \"${name}: daemon\""
command_args="${daemon_args} /usr/local/bin/netbird service run --config /var/db/netbird/config.json --log-level info --daemon-addr unix:///var/run/netbird.sock --log-file /var/log/netbird/client.log"
run_rc_command "$1"
+18
View File
@@ -0,0 +1,18 @@
NetBird is an open-source WireGuard-based overlay network combined with
Zero Trust Network Access, providing secure and reliable connectivity
to internal resources.
Key features:
- Zero-config VPN: Easily create secure connections between devices without
manual network setup.
- Built on WireGuard: Leverages WireGuard's high-performance encryption for
fast and secure communication.
- Self-hosted or Cloud-managed: Users can deploy their own NetBird management
server or use NetBird Cloud for centralized control.
- Access Control & Routing: Fine-grained access control policies and automatic
network routing simplify connectivity.
- This FreeBSD port provides the NetBird client daemon and CLI tools, allowing
FreeBSD systems to join a NetBird mesh network and securely communicate with
other peers.
For more details, visit: https://netbird.io
+11
View File
@@ -0,0 +1,11 @@
[
{ type: install
message: <<EOM
At this time this code is new, unvetted, possibly buggy, and should be
considered "experimental". It might contain security issues. We gladly
welcome your testing and bug reports, but do keep in mind that this code
is new, so some caution should be exercised at the moment for using it
in mission critical environments.
EOM
}
]
@@ -34,7 +34,7 @@
<name>NetBird</name>
<section>VPN</section>
<configfile>netbird.xml</configfile>
<url>/pkg_edit.php?xml=netbird/netbird_auth.xml</url>
<url>/netbird_auth.php</url>
</menu>
<menu>
<name>NetBird</name>
@@ -42,10 +42,16 @@
<configfile>netbird.xml</configfile>
<url>/netbird_status.php</url>
</menu>
<service>
<name>netbird</name>
<rcfile>netbird.sh</rcfile>
<executable>netbird</executable>
<description>NetBird secure overlay network</description>
</service>
<tabs>
<tab>
<text>Authentication</text>
<url>pkg_edit.php?xml=netbird/netbird_auth.xml</url>
<url>netbird_auth.php</url>
</tab>
<tab>
<text>Settings</text>
@@ -250,6 +256,12 @@
]]>
</note>
<custom_php_install_command>
<![CDATA[netbird_install();]]>
</custom_php_install_command>
<custom_php_pre_deinstall_command>
<![CDATA[netbird_deinstall();]]>
</custom_php_pre_deinstall_command>
<custom_php_after_head_command>
<![CDATA[netbird_display_connection_info();]]>
</custom_php_after_head_command>
@@ -20,47 +20,56 @@
*/
require_once('service-utils.inc');
require_once("config.inc");
require_once("util.inc");
define('NETBIRD_BIN', '/usr/local/bin/netbird');
define('NETBIRD_CONFIG', '/var/db/netbird/config.json');
define('PKG_BIN', '/usr/sbin/pkg');
function netbird_resync_config()
{
$json = file_get_contents(NETBIRD_CONFIG);
$config = json_decode($json, true);
if (!is_array($config)) {
log_error("Invalid netbird configuration");
return;
}
if (!empty($_POST['wireguardport'])) {
$config['WgPort'] = (int)$_POST['wireguardport'];
}
$config_map = [
'enablessh' => ['ServerSSHAllowed', true],
'blockinboundconn' => ['BlockInbound', true],
'allowfirewallconfig' => ['DisableFirewall', false],
'enabledns' => ['DisableDNS', false],
'accesslan' => ['BlockLANAccess', false],
'allowclientroutes' => ['DisableClientRoutes', false],
'allowserverroutes' => ['DisableServerRoutes', false],
'enablerosenpass' => ['RosenpassEnabled', true],
'rosenpasspermissive' => ['RosenpassPermissive', true],
];
foreach ($config_map as $post_key => [$json_key, $enabled_val]) {
$checked = ($_POST[$post_key] ?? '') === 'on';
$config[$json_key] = ($checked === $enabled_val);
}
file_put_contents(NETBIRD_CONFIG, json_encode($config, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES));
if (netbird_is_connected()) {
if (!netbird_disconnect()) {
return;
}
$cmd = implode(' ', [NETBIRD_BIN, 'up']);
exec($cmd);
}
$cmd = [NETBIRD_BIN, 'up'];
if (!empty($_POST['wireguardport'])) {
$cmd[] = '--wireguard-port=' . escapeshellarg((int)$_POST['wireguardport']);
}
if (!empty($_POST['loglevel'])) {
$cmd[] = '--log-level=' . escapeshellarg($_POST['loglevel']);
}
$options = [
'enablessh' => ['--allow-server-ssh', true],
'blockinboundconn' => ['--block-inbound', true],
'allowfirewallconfig' => ['--disable-firewall', false],
'enabledns' => ['--disable-dns', false],
'accesslan' => ['--block-lan-access', false],
'allowclientroutes' => ['--disable-client-routes', false],
'allowserverroutes' => ['--disable-server-routes', false],
'enablerosenpass' => ['--enable-rosenpass', true],
'rosenpasspermissive' => ['--rosenpass-permissive', true],
];
foreach ($options as $key => [$flag, $enabled_value]) {
$is_checked = ($_POST[$key] ?? '') === 'on';
$cmd[] = $flag . '=' . ($is_checked === $enabled_value ? 'true' : 'false');
}
exec(implode(' ', $cmd));
}
@@ -114,7 +123,7 @@ function netbird_display_connection_info(): void
$type = 'danger';
$closable = false;
} elseif (!netbird_is_connected()) {
$message = gettext('NetBird is not connected. Refresh or check the NetBird status page.');
$message = gettext('NetBird is not connected.');
$type = 'warning';
$closable = false;
} else {
@@ -125,4 +134,38 @@ function netbird_display_connection_info(): void
print_info_box($message, $type, $closable ? 'close' : false);
}
function netbird_write_rcfile() {
$rc['file'] = 'netbird.sh';
$rc['start'] .= "/usr/local/bin/netbird service start\n\t";
$rc['stop'] .= "/usr/local/bin/netbird service stop\n\t";
$rc['restart'] .= "/usr/local/bin/netbird service restart\n\t";
write_rcfile($rc);
}
function netbird_install()
{
netbird_write_rcfile();
if (!netbird_is_running()){
$cmd = implode(' ', [NETBIRD_BIN, 'service', 'start']);
exec($cmd);
}
}
function netbird_deinstall()
{
global $config;
if (netbird_is_running()) {
stop_service("netbird");
}
unlink_if_exists(NETBIRD_CONFIG);
if (isset($config['installedpackages']['netbird'])) {
unset($config['installedpackages']['netbird']);
write_config("Removed netbird configuration");
}
}
?>
@@ -1,65 +0,0 @@
<?php
/*
* netbird_auth.inc
*
* part of pfSense (https://www.pfsense.org)
* Copyright (c) 2022-2025 Rubicon Communications, LLC (Netgate)
* All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
require_once('netbird/netbird.inc');
function netbird_auth_apply_config()
{
if (!empty($_POST['disconnect'])) {
netbird_disconnect();
return;
}
if (netbird_is_connected() && !netbird_disconnect()) {
return;
}
$cmd = sprintf(
'%s up -m %s -k %s',
escapeshellcmd(NETBIRD_BIN),
escapeshellarg($_POST['managementurl']),
escapeshellarg($_POST['setupkey'])
);
exec($cmd);
}
function netbird_auth_validate_input($post, &$input_errors)
{
if (!empty($post['disconnect'])) {
return;
}
$managementurl = $post['managementurl'];
$setupkey = $post['setupkey'];
if (!empty($managementurl) && !is_URL($managementurl)) {
$input_errors[] = sprintf(gettext('Management URL (%s) is not a valid URL.'), $managementurl);
}
if (empty($setupkey)) {
$input_errors[] = gettext('Setup Key is required.');
}
}
?>
@@ -1,95 +0,0 @@
<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE packagegui SYSTEM "../schema/packages.dtd">
<?xml-stylesheet type="text/xsl" href="../xsl/package.xsl"?>
<packagegui>
<copyright>
<![CDATA[
/*
* netbird_auth.xml
*
* part of pfSense (https://www.pfsense.org)
* Copyright (c) 2022-2025 Rubicon Communications, LLC (Netgate)
* All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
]]>
</copyright>
<name>netbird_auth</name>
<version>%%PKGVERSION%%</version>
<title>VPN/NetBird</title>
<include_file>/usr/local/pkg/netbird/netbird_auth.inc</include_file>
<aftersaveredirect>/pkg_edit.php?xml=netbird/netbird_auth.xml</aftersaveredirect>
<tabs>
<tab>
<text>Authentication</text>
<url>pkg_edit.php?xml=netbird/netbird_auth.xml</url>
<active/>
</tab>
<tab>
<text>Settings</text>
<url>pkg_edit.php?xml=netbird.xml</url>
</tab>
<tab>
<text>Status</text>
<url>netbird_status.php</url>
</tab>
</tabs>
<fields>
<field>
<name>Authentication</name>
<type>listtopic</type>
</field>
<field>
<fielddescr>Management URL</fielddescr>
<fieldname>managementurl</fieldname>
<description>
<![CDATA[Base URL of management service]]>
</description>
<type>input</type>
<default_value>https://api.netbird.io:443</default_value>
<required/>
</field>
<field>
<fielddescr>Setup Key</fielddescr>
<fieldname>setupkey</fieldname>
<description>
<![CDATA[Set the authentication setup key]]>
</description>
<type>input</type>
<required/>
</field>
<field>
<fielddescr>Disconnect</fielddescr>
<fieldname>disconnect</fieldname>
<type>button</type>
<buttonicon>fa-solid fa-right-from-bracket</buttonicon>
<buttonclass>btn-danger</buttonclass>
<description>
<![CDATA[
Disconnect the peer from management service (if connected)
]]>
</description>
</field>
</fields>
<custom_php_after_head_command>
<![CDATA[netbird_display_connection_info();]]>
</custom_php_after_head_command>
<custom_php_validation_command>
<![CDATA[netbird_auth_validate_input($_POST, $input_errors);]]>
</custom_php_validation_command>
<custom_php_resync_config_command>
<![CDATA[netbird_auth_apply_config();]]>
</custom_php_resync_config_command>
</packagegui>
@@ -0,0 +1,165 @@
<?php
/*
* netbird_auth.php
*
* part of pfSense (https://www.pfsense.org)
* Copyright (c) 2022-2025 Rubicon Communications, LLC (Netgate)
* All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
require_once('guiconfig.inc');
require_once('util.inc');
require_once("classes/autoload.inc.php");
require_once('netbird/netbird.inc');
$shortcut_section = 'netbird';
$auth_config = &$config['installedpackages']['netbird']['auth'];
if (!is_array($auth_config)) {
$auth_config = [];
}
if ($_POST) {
if (isset($_POST['connect'])) {
unset($input_errors);
$management_url = $_POST['managementurl'];
$setup_key = $_POST['setupkey'];
if (!empty($management_url) && !is_URL($management_url)) {
$input_errors[] = sprintf(gettext('Management URL (%s) is not a valid URL.'), $management_url);
}
if (empty($setup_key)) {
$input_errors[] = gettext('Setup Key is required.');
}
if (empty($input_errors)) {
if ($setup_key !== $auth_config['setupkey']) {
$auth_config['setupkey'] = $setup_key;
}
$auth_config['managementurl'] = $management_url;
if (netbird_is_connected() && !netbird_disconnect()) {
return;
}
$cmd = sprintf(
'%s up -m %s -k %s',
NETBIRD_BIN,
escapeshellarg($management_url),
escapeshellarg($setup_key)
);
exec($cmd, $out, $return_code);
$joined_output = implode("\n", $out);
if ($return_code !== 0 || stripos($joined_output, 'connected') === false) {
$input_errors[] = "Failed to connect to the management service.";
if (!empty($joined_output)) {
$input_errors[] = "Output: " . htmlspecialchars($joined_output);
}
}
write_config("NetBird connected");
header("Location: netbird_auth.php");
exit;
}
} elseif (isset($_POST['disconnect'])) {
netbird_disconnect();
header("Location: netbird_auth.php");
exit;
}
}
$tabs = [
[gettext('Authentication'), true, '/netbird_auth.php'],
[gettext('Settings'), false, 'pkg_edit.php?xml=netbird.xml'],
[gettext('Status'), false, '/netbird_status.php'],
];
$pgtitle = [gettext('VPN'), gettext('NetBird'), gettext('Authentication')];
$pglinks = ['', '@self'];
include('head.inc');
if ($input_errors) {
print_input_errors($input_errors);
}
netbird_display_connection_info();
display_top_tabs($tabs);
$management_url = $auth_config['managementurl'] ?? 'https://api.netbird.io:443';
$setup_key = $auth_config['setupkey'] ?? '';
$masked_key = '';
if (!empty($setup_key)) {
$visible_part = substr($setup_key, 0, 4);
$masked_key = $visible_part . str_repeat('*', max(4, strlen($setup_key) - 4));
}
$form = new Form(false);
$section = new Form_Section('Authentication');
$section->addInput(new Form_Input(
'managementurl',
'Management URL',
'text',
$management_url
))->setHelp('Base URL of the management service');
$section->addInput(new Form_Input(
'setupkey',
'Setup Key',
'text',
$masked_key
))->setHelp('Set the authentication setup key');
if (netbird_is_connected()) {
$button = new Form_Button(
'disconnect',
'Disconnect',
null,
'fa-solid fa-right-from-bracket'
);
$button->setAttribute('type', 'submit')->addClass('btn-danger');
$section->addInput(new Form_StaticText(
null,
$button
))->setHelp('Disconnect from the management service');
} else {
$button = new Form_Button(
'connect',
'Connect',
null,
'fa-solid fa-right-to-bracket'
);
$button->setAttribute('type', 'submit')->addClass('btn-primary');
$section->addInput(new Form_StaticText(
null,
$button
))->setHelp('Connect to the management service');
}
$form->add($section);
print $form;
include('foot.inc');
@@ -23,8 +23,10 @@ require_once('guiconfig.inc');
require_once('util.inc');
require_once('netbird/netbird_status.inc');
$shortcut_section = 'netbird';
$tabs = [
[gettext('Authentication'), false, 'pkg_edit.php?xml=netbird/netbird_auth.xml'],
[gettext('Authentication'), false, '/netbird_auth.php'],
[gettext('Settings'), false, 'pkg_edit.php?xml=netbird.xml'],
[gettext('Status'), true, '/netbird_status.php'],
];
@@ -0,0 +1,30 @@
<?php
/*
* pkg_netbird.xml
*
* part of pfSense (https://www.pfsense.org)
* Copyright (c) 2022-2025 Rubicon Communications, LLC (Netgate)
* All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
global $shortcuts;
$shortcuts['netbird'] = [];
$shortcuts['netbird']['main'] = '/pkg_edit.php?xml=netbird.xml';
$shortcuts['netbird']['auth'] = '/netbird_auth.php';
$shortcuts['netbird']['status'] = '/netbird_status.php';
$shortcuts['netbird']['service'] = 'netbird';
+5 -6
View File
@@ -25,7 +25,7 @@ do-extract:
do-install:
${MKDIR} ${STAGEDIR}${DATADIR}
${MKDIR} ${STAGEDIR}${PREFIX}/pkg/netbird
${MKDIR} ${STAGEDIR}${PREFIX}/www
${MKDIR} ${STAGEDIR}${PREFIX}/www/shortcuts
${INSTALL_DATA} ${FILESDIR}${DATADIR}/info.xml \
${STAGEDIR}${DATADIR}
@@ -36,15 +36,14 @@ do-install:
${INSTALL_DATA} ${FILESDIR}${PREFIX}/pkg/netbird/*.inc \
${STAGEDIR}${PREFIX}/pkg/netbird
${INSTALL_DATA} ${FILESDIR}${PREFIX}/pkg/netbird/*.xml \
${STAGEDIR}${PREFIX}/pkg/netbird
${INSTALL_DATA} ${FILESDIR}${PREFIX}/www/*.php \
${STAGEDIR}${PREFIX}/www
${INSTALL_DATA} ${FILESDIR}${PREFIX}/www/shortcuts/*.inc \
${STAGEDIR}${PREFIX}/www/shortcuts
@${REINPLACE_CMD} -i '' -e "s|%%PKGVERSION%%|${PKGVERSION}|" \
${STAGEDIR}${DATADIR}/info.xml \
${STAGEDIR}${PREFIX}/pkg/netbird.xml \
${STAGEDIR}${PREFIX}/pkg/netbird/netbird_auth.xml
${STAGEDIR}${PREFIX}/pkg/netbird.xml
.include <bsd.port.mk>
+2 -2
View File
@@ -1,7 +1,7 @@
pkg/netbird.xml
pkg/netbird/netbird.inc
pkg/netbird/netbird_status.inc
pkg/netbird/netbird_auth.inc
pkg/netbird/netbird_auth.xml
%%DATADIR%%/info.xml
www/netbird_status.php
www/netbird_auth.php
www/shortcuts/pkg_netbird.inc