Destination NAT: Configuration fails with "Danger: Unexpected Error..."

Started by miketubby, February 02, 2026, 04:31:45 PM

Previous topic - Next topic
Over the weekend I have upgraded my OPNsense system from 25.7_11 to 26.1_4 and everything is working except inbound port forwarding (aka "Destination NAT").

I am trying to configure Asterisk IAX2 (UDP/4569) from my Work firwall to my home firewall.

I have host aliases for the work firewall (single IPv4) and the home PBX.  I have a port alias "iax2_port" = 4569.

I go to Firewall > NAT > Destination NAT and use "+" to add a new rule:

  Interface:
       Interface: WAN
       Version: IPv4
       Protocol: UDP

  Source (advanced):
       Invert Source:  (unchecked)
       Source Address: thorcom_gate  <- alias with correct IPv4 source
       Source Port: iax_port

   Destination:
       Invert Destination:  (unchecked)
       Destination Address: WAN address  (from drop down)
       Destination Port: iax_port

   Translation:
       Redirect Target IP: tubby_pbs  <- alias with correct host IP for my internal PBX
       Redirect Taget Port: iax_port


When I save the rule I get the error "Danger: Unexpected error, check log for details", but there's nothing visible in the logs accessible from the UI?

It appears that all of my inbound DNATs (formerly "port forwards") have disappeared/failed to be migrated as I have also lost the rules for my NVD/DVR and for my SDR - all of which were working fine under 25.7_11

How do I get inbound DNAT/port forwarding to work again?


Mike


System: Firmware: Reporter should have logs. Better paste the PHP errors here than submitting them (it's a bit difficult to find them out of context).


Cheers,
Franco
"AI has absolutely reduced the cost of creating technical debt." -- ChatGPT

Hi Franco,

User-Agent Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36
FreeBSD 14.3-RELEASE-p7 stable/26.1-n271965-1bab7230df71 SMP amd64
OPNsense 26.1_4 889098cfa
Time Mon, 02 Feb 2026 17:00:14 +0000
OpenSSL 3.0.18
Python 3.11.14
PHP 8.3.28


Each time I attempt to add a Destination NAT I get a PHP stack trace:

[02-Feb-2026 14:25:40 Europe/London] TypeError: dom_import_simplexml(): Argument #1 ($node) must be of type object, null given in /usr/local/opnsense/mvc/app/models/OPNsense/Base/BaseModel.php:755
Stack trace:
#0 /usr/local/opnsense/mvc/app/models/OPNsense/Base/BaseModel.php(755): dom_import_simplexml(NULL)
#1 /usr/local/opnsense/mvc/app/models/OPNsense/Base/BaseModel.php(822): OPNsense\Base\BaseModel->internalSerializeToConfig()
#2 /usr/local/opnsense/mvc/app/controllers/OPNsense/Base/ApiMutableModelControllerBase.php(327): OPNsense\Base\BaseModel->serializeToConfig(false, true)
#3 /usr/local/opnsense/mvc/app/controllers/OPNsense/Base/ApiMutableModelControllerBase.php(498): OPNsense\Base\ApiMutableModelControllerBase->save(false, true)
#4 /usr/local/opnsense/mvc/app/controllers/OPNsense/Firewall/Api/DNatController.php(122): OPNsense\Base\ApiMutableModelControllerBase->addBase('rule', 'rule')
#5 /usr/local/opnsense/mvc/app/library/OPNsense/Mvc/Dispatcher.php(166): OPNsense\Firewall\Api\DNatController->addRuleAction()
#6 /usr/local/opnsense/mvc/app/library/OPNsense/Mvc/Router.php(156): OPNsense\Mvc\Dispatcher->dispatch(Object(OPNsense\Mvc\Request), Object(OPNsense\Mvc\Response), Object(OPNsense\Mvc\Session))
#7 /usr/local/opnsense/mvc/app/library/OPNsense/Mvc/Router.php(139): OPNsense\Mvc\Router->performRequest(Object(OPNsense\Mvc\Dispatcher))
#8 /usr/local/opnsense/www/api.php(36): OPNsense\Mvc\Router->routeRequest('/api/firewall/d...', Array)
#9 {main}
[02-Feb-2026 15:15:06 Europe/London] TypeError: dom_import_simplexml(): Argument #1 ($node) must be of type object, null given in /usr/local/opnsense/mvc/app/models/OPNsense/Base/BaseModel.php:755
Stack trace:
#0 /usr/local/opnsense/mvc/app/models/OPNsense/Base/BaseModel.php(755): dom_import_simplexml(NULL)
#1 /usr/local/opnsense/mvc/app/models/OPNsense/Base/BaseModel.php(822): OPNsense\Base\BaseModel->internalSerializeToConfig()
#2 /usr/local/opnsense/mvc/app/controllers/OPNsense/Base/ApiMutableModelControllerBase.php(327): OPNsense\Base\BaseModel->serializeToConfig(false, true)
#3 /usr/local/opnsense/mvc/app/controllers/OPNsense/Base/ApiMutableModelControllerBase.php(498): OPNsense\Base\ApiMutableModelControllerBase->save(false, true)
#4 /usr/local/opnsense/mvc/app/controllers/OPNsense/Firewall/Api/DNatController.php(122): OPNsense\Base\ApiMutableModelControllerBase->addBase('rule', 'rule')
#5 /usr/local/opnsense/mvc/app/library/OPNsense/Mvc/Dispatcher.php(166): OPNsense\Firewall\Api\DNatController->addRuleAction()
#6 /usr/local/opnsense/mvc/app/library/OPNsense/Mvc/Router.php(156): OPNsense\Mvc\Dispatcher->dispatch(Object(OPNsense\Mvc\Request), Object(OPNsense\Mvc\Response), Object(OPNsense\Mvc\Session))
#7 /usr/local/opnsense/mvc/app/library/OPNsense/Mvc/Router.php(139): OPNsense\Mvc\Router->performRequest(Object(OPNsense\Mvc\Dispatcher))
#8 /usr/local/opnsense/www/api.php(36): OPNsense\Mvc\Router->routeRequest('/api/firewall/d...', Array)
#9 {main}
[02-Feb-2026 15:21:43 Europe/London] TypeError: dom_import_simplexml(): Argument #1 ($node) must be of type object, null given in /usr/local/opnsense/mvc/app/models/OPNsense/Base/BaseModel.php:755
Stack trace:
#0 /usr/local/opnsense/mvc/app/models/OPNsense/Base/BaseModel.php(755): dom_import_simplexml(NULL)
#1 /usr/local/opnsense/mvc/app/models/OPNsense/Base/BaseModel.php(822): OPNsense\Base\BaseModel->internalSerializeToConfig()
#2 /usr/local/opnsense/mvc/app/controllers/OPNsense/Base/ApiMutableModelControllerBase.php(327): OPNsense\Base\BaseModel->serializeToConfig(false, true)
#3 /usr/local/opnsense/mvc/app/controllers/OPNsense/Base/ApiMutableModelControllerBase.php(498): OPNsense\Base\ApiMutableModelControllerBase->save(false, true)
#4 /usr/local/opnsense/mvc/app/controllers/OPNsense/Firewall/Api/DNatController.php(122): OPNsense\Base\ApiMutableModelControllerBase->addBase('rule', 'rule')
#5 /usr/local/opnsense/mvc/app/library/OPNsense/Mvc/Dispatcher.php(166): OPNsense\Firewall\Api\DNatController->addRuleAction()
#6 /usr/local/opnsense/mvc/app/library/OPNsense/Mvc/Router.php(156): OPNsense\Mvc\Dispatcher->dispatch(Object(OPNsense\Mvc\Request), Object(OPNsense\Mvc\Response), Object(OPNsense\Mvc\Session))
#7 /usr/local/opnsense/mvc/app/library/OPNsense/Mvc/Router.php(139): OPNsense\Mvc\Router->performRequest(Object(OPNsense\Mvc\Dispatcher))
#8 /usr/local/opnsense/www/api.php(36): OPNsense\Mvc\Router->routeRequest('/api/firewall/d...', Array)
#9 {main}


Regards


Mike

Can you do a health check and/or reinstall the "opnsense" package from the firmware packages tab?

It looks like a damaged file on disk.


Cheers,
Franco
"AI has absolutely reduced the cost of creating technical debt." -- ChatGPT

Here's the result of:

    System > Firmware > Status > Run Audit > Health

***GOT REQUEST TO AUDIT HEALTH***
Currently running OPNsense 26.1_4 (amd64) at Mon Feb  2 17:34:21 GMT 2026
>>> Root file system: /dev/gpt/rootfs
>>> Check installed kernel version
Version 26.1 is correct.
>>> Check for missing or altered kernel files
No problems detected.
>>> Check installed base version
Version 26.1 is correct.
>>> Check for missing or altered base files
No problems detected.
>>> Check installed repositories
OPNsense (Priority: 11)
>>> Check installed plugins
No plugins found.
>>> Check locked packages
No locks found.
>>> Check for missing package dependencies
Checking all packages: .......... done
>>> Check for missing or altered package files
Checking all packages: .......... done
>>> Check for core packages consistency
Core package "opnsense" at 26.1_4 has 67 dependencies to check.
Checking packages: .................................................................... done
***DONE***


Regards

Mike

Re-installation pf "opnsense 26.1_4" package performed:

***GOT REQUEST TO REINSTALL***
Currently running OPNsense 26.1_4 (amd64) at Mon Feb  2 18:23:36 GMT 2026
Updating OPNsense repository catalogue...
OPNsense repository is up to date.
All repositories are up to date.
The following packages will be fetched:

New packages to be FETCHED:
   opnsense: 26.1_4 (6 MiB: 100.00% of the 6 MiB to download)

Number of packages to be fetched: 1

The process will require 6 MiB more space.
6 MiB to be downloaded.
Fetching opnsense-26.1_4.pkg: .......... done
opnsense-26.1_4: already unlocked
Updating OPNsense repository catalogue...
OPNsense repository is up to date.
All repositories are up to date.
Checking integrity... done (0 conflicting)
The following 1 package(s) will be affected (of 0 checked):

Installed packages to be REINSTALLED:
   opnsense-26.1_4

Number of packages to be reinstalled: 1
[1/1] Reinstalling opnsense-26.1_4...
[1/1] Extracting opnsense-26.1_4: .......... done
Stopping configd...done
Resetting root shell
Updating /etc/shells
Unhooking from /etc/rc
Unhooking from /etc/rc.shutdown
Updating /etc/shells
Registering root shell
Hooking into /etc/rc
Hooking into /etc/rc.shutdown
Starting configd.
>>> Invoking update script 'refresh.sh'
Flushing all caches...done.
Writing firmware settings: FreeBSD OPNsense
Writing trust files...done.
Scanning /usr/share/certs/untrusted for certificates...
Scanning /usr/share/certs/trusted for certificates...
Scanning /usr/local/share/certs for certificates...
certctl: No changes to trust store were made.
Writing trust bundles...done.
Configuring login behaviour...done.
Configuring cron...done.
Configuring system logging...done.
=====
Message from opnsense-26.1_4:

--
One step ahead, one step behind it, now you gotta run to get even
Checking integrity... done (0 conflicting)
Nothing to do.
***DONE***


I will now re-boot and try the DNAT configuration again.

Regards

Mike

Quote from: franco on February 02, 2026, 05:35:13 PMSystem: Firmware: Reporter should have logs. Better paste the PHP errors here than submitting them (it's a bit difficult to find them out of context).


Cheers,
Franco

Hi Franco,

I have run the health check (no problems) and re-installed the opnsense 26.1 package and upgraded to 26.1_4 and rebooted.

I still see the same problem when I try to add the Destination NAT with this PHP stack-trace:

[03-Feb-2026 12:29:19 Europe/London] TypeError: dom_import_simplexml(): Argument #1 ($node) must be of type object, null given in /usr/local/opnsense/mvc/app/models/OPNsense/Base/BaseModel.php:755
Stack trace:
#0 /usr/local/opnsense/mvc/app/models/OPNsense/Base/BaseModel.php(755): dom_import_simplexml(NULL)
#1 /usr/local/opnsense/mvc/app/models/OPNsense/Base/BaseModel.php(822): OPNsense\Base\BaseModel->internalSerializeToConfig()
#2 /usr/local/opnsense/mvc/app/controllers/OPNsense/Base/ApiMutableModelControllerBase.php(327): OPNsense\Base\BaseModel->serializeToConfig(false, true)
#3 /usr/local/opnsense/mvc/app/controllers/OPNsense/Base/ApiMutableModelControllerBase.php(498): OPNsense\Base\ApiMutableModelControllerBase->save(false, true)
#4 /usr/local/opnsense/mvc/app/controllers/OPNsense/Firewall/Api/DNatController.php(122): OPNsense\Base\ApiMutableModelControllerBase->addBase('rule', 'rule')
#5 /usr/local/opnsense/mvc/app/library/OPNsense/Mvc/Dispatcher.php(166): OPNsense\Firewall\Api\DNatController->addRuleAction()
#6 /usr/local/opnsense/mvc/app/library/OPNsense/Mvc/Router.php(156): OPNsense\Mvc\Dispatcher->dispatch(Object(OPNsense\Mvc\Request), Object(OPNsense\Mvc\Response), Object(OPNsense\Mvc\Session))
#7 /usr/local/opnsense/mvc/app/library/OPNsense/Mvc/Router.php(139): OPNsense\Mvc\Router->performRequest(Object(OPNsense\Mvc\Dispatcher))
#8 /usr/local/opnsense/www/api.php(36): OPNsense\Mvc\Router->routeRequest('/api/firewall/d...', Array)
#9 {main}

What to try next?

Regards

Mike

This is strange. Maybe there's something wrong in the initial data?

# pluginctl -v

Ignore some of the noise.  We want to find DNat-specific complaints.

The rules aren't gone since they were not migrated, which could also point to the fact that the model doesn't like something in the initial data.

A full dump can be done with

# pluginctl -g nat

but don't paste it here. Just see if your hidden rules are still there and maybe we can find out why they are different.


Cheers,
Franco
"AI has absolutely reduced the cost of creating technical debt." -- ChatGPT

Hi Franco,

Pluginctl -v results in a message per interface in the form:

root@gate:~ # pluginctl -v
OPNsense\Firewall\Alias.aliases.alias.__wan_network.name => The name must start with a letter or single underscore, be less than 32 characters and only consist of alphanumeric characters or underscores.

and pluginctl -g nat results in an empy set:

root@gate:~ # pluginctl -g nat
root@gate:~ #

... does that help?

Regards

Mike



Thanks, I think we can reproduce this now.

The question is why your nat section has gone. You should find it being dropped under System: Configuration: History and perhaps restore it manually (  I wouldn't advise reverting to that configuration).


Cheers,
Franco
"AI has absolutely reduced the cost of creating technical debt." -- ChatGPT

The following should fix the write on your end without any prior data, but again not why it was lost.

# opnsense-patch https://github.com/opnsense/core/commit/40cb82128d


Cheers,
Franco
"AI has absolutely reduced the cost of creating technical debt." -- ChatGPT

Hi Franco,

Thanks, patch applied and I am now able to add DNAT rules ;-)

I don't know where my previous NAT rules went... this is what I did:

1. Existing Server, working system (25.7_11) ... Backed up config

2. New (temp) server, installed 26.1, imported backup, upgraded to 26.1_4. Didn't explicitly test DNAT but everything seemed to be working.

3. Flattened exiting server, installed 26.1. Backed up temp server, imported to existing server. Upgraded to 26.1_4

Found that DNAT wasn't working. I guess somewhere along the way it broke...

All is good now. Thanks for the help.  Have sent €50,00 donation.

Regards

Mike

Hi Mike,

Thank you.  That's very kind.  :)

We'll ship the change in 26.1.1 and likely issue new images (for assorted reasons) so that other users won't run into this.


Cheers,
Franco
"AI has absolutely reduced the cost of creating technical debt." -- ChatGPT