Skip to content

sysutils/nut: fix upsstatus diagnostics and netclient model definition#5469

Open
Drinker09 wants to merge 2 commits into
opnsense:masterfrom
Drinker09:master
Open

sysutils/nut: fix upsstatus diagnostics and netclient model definition#5469
Drinker09 wants to merge 2 commits into
opnsense:masterfrom
Drinker09:master

Conversation

@Drinker09
Copy link
Copy Markdown

@Drinker09 Drinker09 commented May 29, 2026

Important notices

Before you submit a pull request, we ask you kindly to acknowledge the following:

If AI was used, please disclose:

  • Model used: Claude Sonet 4.6
  • Extent of AI involvement: Claude did pretty much all the work. I just followed along. Seriously.

This PR covers issue #5470

Description

This PR fixes two issues with the NUT plugin that prevent the diagnostics page, dashboard widget, and API endpoint from returning UPS status data when running in netclient mode.

Problem 1: upsc binary segfaults on FreeBSD 14.x with NUT 2.8.5

The DiagnosticsController::upsstatusAction() method called /usr/local/bin/upsc via configd to retrieve UPS status. This approach fails for two reasons:

1.) configd sanitizes the @ symbol in parameters, making it impossible to pass upsname@host as an argument via configdpRun().

2.) On FreeBSD 14.x with NUT 2.8.5, upsc segfaults (SIGSEGV, exit code 11) when querying a remote upsd server, producing no output before crashing.

This bug has been reported to the NUT project: networkupstools/nut#3454

Fix: Replace the upsc call with a direct TCP socket connection to the remote upsd server using the NUT protocol. This is more reliable, faster, and bypasses both issues entirely.

Problem 2: Bare HostnameField definition in netclient model

The netclient->address field in Nut.xml was defined as a bare address type="HostnameField" with no configuration, which is inconsistent with how other fields in the model are defined.

Fix: Add explicit Required and IpWithPrefix attributes to properly define the field.

Files changed

sysutils/nut/src/opnsense/mvc/app/controllers/OPNsense/Nut/Api/DiagnosticsController.php — replaced upsc call with direct NUT protocol socket connection
sysutils/nut/src/opnsense/mvc/app/models/OPNsense/Nut/Nut.xml — properly defined netclient address HostnameField

Testing

Tested on OPNsense 26.1 (FreeBSD 14.3-RELEASE-p12) with NUT 2.8.5 in netclient mode, monitoring a CyberPower CP1500PFCLCDa connected to a Raspberry Pi NUT server. After this fix:

Services > NUT > Diagnostics > UPS Status displays full UPS data
Dashboard NUT widget displays UPS status, battery level, and runtime
/api/nut/diagnostics/upsstatus API endpoint returns correct data

$response = $backend->configdpRun('nut upsstatus', array("{$upsname}@{$host}"));

$response = '';
$socket = @fsockopen($host, $port, $errno, $errstr, 5);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

given that the GUI will eventually be privilege separated and the backend call is removed this is not a dependable way forward.

I'm also trying to understand the issue that nut has with something that worked at least up to 2.8.3 and if there isn't a better way to deal with this (if upstream is even aware this is a regression).

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for the feedback @fichtner!

Regarding the privilege separation concern — that's a completely valid point and we appreciate the heads up about the direction OPNsense is heading. We agree that fsockopen() is not an ideal long-term solution for that reason.

However, the root cause of this issue is a regression in NUT 2.8.5 itself rather than in the plugin. We filed a bug report with the NUT project which has been confirmed by core NUT developer @jimklimov:

NUT issue #3454: networkupstools/nut#3454

The short version is that upsc segfaults (SIGSEGV, exit code 11) on FreeBSD 14.x with NUT 2.8.5 when querying a remote upsd server. The crash occurs during SSL cleanup on exit — SSL is half-initialized after a failed STARTTLS attempt, and upscli_cleanup() crashes dereferencing a null pointer when trying to free the SSL context. jimklimov has confirmed this is a regression introduced late in the 2.8.5 release cycle as part of SSL modernization work, and noted that 2.8.6 is being worked on.

The original configdpRun approach also has a separate issue — configd sanitizes the @ symbol in parameters, making it impossible to pass upsname@host correctly regardless of the upsc segfault.
We're happy to revisit this PR once NUT 2.8.6 is released and the upstream bug is fixed. At that point the original configdpRun approach may work correctly again, or a cleaner solution may be possible that fits the future privilege separation model.

In the meantime, our fsockopen() workaround does restore full functionality for OPNsense 26.1 users running NUT 2.8.5 in netclient mode. We leave it to your judgment whether to merge it as a temporary fix or wait for the upstream resolution.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

2 participants