The culprit is pfblockerng_do_xmlrpc_sync() — it issues its own XMLRPC call (merge_installedpackages_section) which collides with the system XMLRPC sync (likely a lock/recursion/race), so restore_config_section() on the peer never completes
/usr/local/pkg/pfblockerng/pfblockerng.inc
/* Do the actual XMLRPC sync */
function pfblockerng_do_xmlrpc_sync($sync_to_ip, $port, $protocol, $username, $password, $synctimeout) {
global $g;
$success = TRUE;
// Take care of IPv6 literal address
if (is_ipaddrv6($sync_to_ip)) {
$sync_to_ip = "[{$sync_to_ip}]";
}
$sections = [];
// If User Disabled, remove 'General/IP/DNSBL Tab Customizations' from Sync
if (config_get_path('installedpackages/pfblockerngsync/config/0/syncinterfaces') != 'on') {
$sections = array_merge($sections, [
'pfblockerng',
'pfblockerngipsettings',
'pfblockerngdnsblsettings'
]);
}
$sections = array_merge($sections, [
'pfblockernglistsv4',
'pfblockernglistsv6',
'pfblockerngreputation',
'pfblockerngtopspammers',
'pfblockerngafrica',
'pfblockerngantarctica',
'pfblockerngasia',
'pfblockerngeurope',
'pfblockerngnorthamerica',
'pfblockerngoceania',
'pfblockerngsouthamerica',
'pfblockerngproxyandsatellite',
'pfblockerngdnsbl',
'pfblockerngblacklist',
'pfblockerngglobal',
'pfblockerngsafesearch'
]);
/* xml will hold the sections to sync */
$xml = array();
foreach ($sections as $section) {
$section_config = config_get_path("installedpackages/{$section}");
if (!isset($section_config)) {
continue;
}
$xml[$section] = $section_config;
}
// Increase CARP Advskew value, see https://redmine.pfsense.org/issues/11964
$advskew = array_get_path($xml, 'pfblockerngdnsblsettings/config/0/pfb_dnsvip_skew');
if (isset($advskew)) {
array_set_path($xml, 'pfblockerngdnsblsettings/config/0/pfb_dnsvip_skew', min((intval($advskew) + 100), 254));
}
require_once('xmlrpc_client.inc');
// xmlrpc cannot encode NULL objects/arrays
foreach ($xml as $xmlkey => $xmlvalue) {
if (gettype($xmlvalue) == 'NULL') {
$xml[$xmlkey] = array();
}
}
$synctimeout = intval($synctimeout);
$rpc_client = new pfsense_xmlrpc_client();
$rpc_client->setConnectionData($sync_to_ip, $port, $username, $password, $protocol);
$resp = $rpc_client->xmlrpc_method('merge_installedpackages_section', $xml, $synctimeout);
if (!isset($resp)) {
return FALSE;
} else {
return TRUE;
}
}
So we need some patch for this function, something like that:
--- a/usr/local/pkg/pfblockerng/pfblockerng.inc
+++ b/usr/local/pkg/pfblockerng/pfblockerng.inc
@@
/* Do the actual XMLRPC sync */
function pfblockerng_do_xmlrpc_sync($sync_to_ip, $port, $protocol, $username, $password, $synctimeout) {
- global $g;
- $success = TRUE;
+ global $g;
+
+ // Re-entrancy guard: if running inside inbound XMLRPC handler, skip to avoid recursive sync/deadlock.
+ if (isset($_SERVER['SCRIPT_NAME']) && strpos($_SERVER['SCRIPT_NAME'], 'xmlrpc.php') !== false) {
+ return TRUE;
+ }
// Take care of IPv6 literal address
if (is_ipaddrv6($sync_to_ip)) {
$sync_to_ip = "[{$sync_to_ip}]";
}
So the final version is
/* Do the actual XMLRPC sync */
function pfblockerng_do_xmlrpc_sync($sync_to_ip, $port, $protocol, $username, $password, $synctimeout) {
global $g;
// Re-entrancy guard: if running inside inbound XMLRPC handler, skip to avoid recursive sync/deadlock.
if (isset($_SERVER['SCRIPT_NAME']) && strpos($_SERVER['SCRIPT_NAME'], 'xmlrpc.php') !== false) {
return TRUE;
}
// Take care of IPv6 literal address
if (is_ipaddrv6($sync_to_ip)) {
$sync_to_ip = "[{$sync_to_ip}]";
}
$sections = [];
// If User Disabled, remove 'General/IP/DNSBL Tab Customizations' from Sync
if (config_get_path('installedpackages/pfblockerngsync/config/0/syncinterfaces') != 'on') {
$sections = array_merge($sections, [
'pfblockerng',
'pfblockerngipsettings',
'pfblockerngdnsblsettings'
]);
}
$sections = array_merge($sections, [
'pfblockernglistsv4',
'pfblockernglistsv6',
'pfblockerngreputation',
'pfblockerngtopspammers',
'pfblockerngafrica',
'pfblockerngantarctica',
'pfblockerngasia',
'pfblockerngeurope',
'pfblockerngnorthamerica',
'pfblockerngoceania',
'pfblockerngsouthamerica',
'pfblockerngproxyandsatellite',
'pfblockerngdnsbl',
'pfblockerngblacklist',
'pfblockerngglobal',
'pfblockerngsafesearch'
]);
/* xml will hold the sections to sync */
$xml = array();
foreach ($sections as $section) {
$section_config = config_get_path("installedpackages/{$section}");
if (!isset($section_config)) {
continue;
}
$xml[$section] = $section_config;
}
// Increase CARP Advskew value, see https://redmine.pfsense.org/issues/11964
$advskew = array_get_path($xml, 'pfblockerngdnsblsettings/config/0/pfb_dnsvip_skew');
if (isset($advskew)) {
array_set_path($xml, 'pfblockerngdnsblsettings/config/0/pfb_dnsvip_skew', min((intval($advskew) + 100), 254));
}
require_once('xmlrpc_client.inc');
// xmlrpc cannot encode NULL objects/arrays
foreach ($xml as $xmlkey => $xmlvalue) {
if (gettype($xmlvalue) == 'NULL') {
$xml[$xmlkey] = array();
}
}
$synctimeout = intval($synctimeout);
$rpc_client = new pfsense_xmlrpc_client();
$rpc_client->setConnectionData($sync_to_ip, $port, $username, $password, $protocol);
$resp = $rpc_client->xmlrpc_method('merge_installedpackages_section', $xml, $synctimeout);
if (!isset($resp)) {
return FALSE;
} else {
return TRUE;
}
}
Looks like this fix works—at least for me. Not sure if it’s a bug in the function or in how it’s being called. Let’s see what the developers say.