Menu

Show posts

This section allows you to view all posts made by this member. Note that you can only see posts made in areas you currently have access to.

Show posts Menu

Topics - jonny5

#1
26.1, 26,4 Series / PF/Alias list update oddity
June 25, 2026, 04:58:01 PM
Already feeling bad about making this post, but, if someone else has this happen - hope you find this and we can figure it out together.

My OPNSense upgraded to 26.1.10 w/no issue, and I have CrowdSec installed and the Firewall Blocker feature enabled (this means there are two PF/Alias lists that CrowdSec manages updates for).

Instead of configuring my Firewall to use the "CrowdSec managed lists" aliases, I have made a new alias/list where I included the CrowdSec lists (IPv4 and IPv6), SpamHaus list, and a personally kept list as my combined blocklist. This is my blocklist for Inbound and Outbound traffic - works great!

Some time ago, I realized I could have "Uptime Kuma" check an alias/list via API to see how recently it has been updated and let me know if it starts aging too much. After a while I found that the 25 minute marker was good for watching this combined blocklist that I had created - more or less, it near always updates within 25 minutes.

For those wondering, it is a JSON check:
URL: https://opnsense.domain.tld/api/firewall/alias/getItem/<UUIDOfList>
Check: (($millis() - $toMillis(alias.last_updated)) / 60000)

Here is the issue:
Yesterday there was an alert that my combined blocklist hadn't updated, and it was getting into its 4th hour. After restarting the PF service, restarting the CrowdSec Firewall Blocker, and trying to modify my combined blocklist (basically open to edit and hit save) in the Alias list, my combined blocklist would never update. The CrowdSec managed lists were updating (even though you cannot see an edit date, you can tell their count had gone down as it didn't add up to the total sum of my combined blocklist), but my combined blocklist held its aging modify/update time and high count.

Once I restarted the OPNSense, things returned to normal and now the next day, continues to do so. No idea what happened there, but, I would recommend you watch your lists and make sure you track the last update date in case they get locked too. If it happens again (this has only happened once so far), I hope to be able to do more to figure out what the hang up is - would love ideas to check!
#2
Wanted to start with a thank you, the /usr/local/etc/suricata/conf.d/custom.yaml appears persistent and this allows us to further customize Suricata, thank you OPNSense!! We have had difficulty customizing and having it persist until now.

The issue found appears to be that BPF Filtering via netmap in the Suricata config does not appear to work, hosts/networks filtered still show up in the Suricata alerts. The netmap area of suricata.yaml from OPNSense 25.x to OPNSense 26.x appears to have gone through a lot of changes.

The new divert feature being one of the new elements I have not had a chance to explore, I'm using PCAP IPD mode for Suricata.

The documentation for BPF-Filtering within Suricata shows this as an example:
not (host IP1 or IP2 or IP3 or net NET/24)
A most desired filter is between a subnet and one or more other subnets, and I've tried this in several methods, here's the most basic I have tried:
not ((net NET1/24 and NET2/24) or (net NET2/24 and NET3/24) or (net NET3/24 and NET1/24))
So far none of the BPF filters work with Suricata - does anyone use this and/or have experience?

Edit:
For a while I was only looking at the suricata.yaml file and didn't realize the level of control that went into the command line execution of arguments sent to suricata on service start. For a while I was trying to put netmap in IDS mode thinking that's how the traffic was going and wondering why the BPF filter for netmap wasn't working.
#3
Did the upgrade to 26.1.3, everything so far was working, except a home grown automation to sync stuff gathered from the OPNSense API, Portainer, and kept in a Redis Cache to my BIND setup. This is done by a Python script.

In a most strangest interaction, use case testing Python using requests, http, or httpx and was not able to reach and more correctly connect to OPNSense's API, but Postman/CURL both could - and got valid responses back. Tested the HTTP/1.1 or HTTP/2 nature, always worked for Postman and CURL, never worked for Python.

So I went back to the OPNSense, maybe I could re-reset some stuff, started simple - restarted the System Configuration Daemon and then Web GUI services from the Web GUI, suddenly Python is working again.

Also did a another restart of the OPNSense (it restart initially after the upgrade), and the issue did not present itself again. So this is just a heads up to any that might hit whatever edge case I did, restart services and/or host, should work again.
#4
Just wanted to extend OPNSense, the community, FreeBSD, associated projects, and the Open Source community a thank you!!

I wrote a Linux ran multi-threaded Python detail to update several Aliases (two of which have 10k+ IPs) with IP lists via OPNSense API, and on average it is completing now in about 30% less time (that means I block an attacker (CrowdSec enabled Reverse Proxy + Suricata) at Layer 3 faster).

No change to my code, I've already tweaked it for speed in about every way (nice in Linux, pre-compiling Python...) and this speed up is purely because OPNSense continues to become a more lean/mean beast.
#5
Environment detail:
OPNSense Unbound for DNS Upstream + Overrides (so when external to OPNSense local domain BIND is down critical infra still works), Hosts use PiHoles, and both OPNSense Unbound and PiHoles use local BIND infra for the Local Domain. The Local BIND has the forward and reverse lookup all setup, and populated, and Unbound and the PiHoles are set to forward for the local domain and all /24 IPv4 and /64 IPv6 subnets for reverse DNS lookup. This worked previously - I am considering going back to verify.

Upgrade journey:
Migrated from ISC to KEA, Upgraded, did the firewall migration, removed ISC plugin, most everything works well - most hosts seem to correctly populate their Alias content counts for IPs to Hostnames.

Testing the process:
There is a Python script I wrote that updates forward and reverse records in the local Bind infra for the hostnames via OPNSense(ARP/NDP/Reservations)/Portainer(Docker Hosts) and I can
drill fqdn @pihole or
drill -x ip @pihole for A and AAAA/IPv4 and IPv6, and together I get 2+ IPs back as expected. In this case the hostname happens to be "plex.localdomain.home" (not really but close enough), and yeah, most/all other hostnames appear to correctly populate their counts (especially those that are overridden via IPv4 and IPv6 entries in Unbound's Override space).

Problem:
The issue is that the OPNSense Firewall Alias for the FQDN in question only has one value for its "content", or just one IP resolved. This FQDN is not overridden in Unbound. OPNSense's Host discovery / Host detect sees all the IPs for the FQDN's associated MAC address, and all of them resolve to the FQDN against PiHoles/BIND, but Alias does not? Seems odd. I'm curious where the configuration/direction for OPNSense's firewall to resolve hosts comes from - which DNS source of truth is it using?

!!! Interesting:
Doing a drill against the OPNSense for that FQDN and AAAA returns nothing, but from either PiHole or BIND, results. Interestingly though, if I do a reverse lookup on the FQDN's IPv6 against the OPNSense it would seem Unbound responds with the IPv6's FQDN, so A (IPv4 forward DNS) and IPv4 and IPv6 PTR (both IPv4 and IPv6 reverse DNS) works, but AAAA (IPv6 forward DNS) does not for Unbound query forward/response?
!!! Further:
After disabling all Unbound Overrides for the local domain, it still has the same issue - AAAA query for local domains fails - and yes, I have the local domain added to the "Private Domains" in Unbound's Advanced settings. Extra, in this, it would seem to only know about the IPv6 addresses for FQDNs that were overridden, and is unable to do a conditionally forwarded AAAA/forward-ipv6 lookup (unless the FQDN in question is IPv6 overridden manually, and then it isn't forwarding/asking, it is merely answering if you will).

(Extra - I'm considering setting up the BIND plugin on the OPNSense just so I can have my existing Primary BIND send updates to what would be OPNSense's Secondary BIND. Want to possibly understand why it doesn't already work, and maybe explore what is necessary to configure the BIND plugin to be a secondary BIND server as a part of my existing infra while keeping the state in OPNSense conf/backup - fix 1 problem w/possibly 2 or more problems lol, but if anyone has pointers on the original issue, pls lmk)

Ok - so it was the "Register DHCP Static Mappings" which more or less cancelled the forwarding for the local domain, with that disabled, it follows forwarding rules...
#6
Currently still on 25.7.11_9 and have transitioned from ISC to KEA, and so far things are working okay.

With ISC, I could find all of my leases for DHCPv4 and DHCPv6, but with KEA, that does not seem accessible. I tried looking into "host discovery" / "host watch", but maybe it isn't built out in 25.7.x yet. Curious what we can expect to use "host discovery" for and if the data will be available via the API?

Are there plans with KEA to allow us to see our DHCPv6 leases via API, both reserved and un-reserved?
#7
As the CrowdSec default firewall is only stopping incoming for items on the list, I wanted to upgrade how that feature worked, and honestly allow a few hosts I have to not be blocked by the firewall - an unfiltered host if you will.

So, I made my own "Hosts" based Firewall Alias, and have a Python script that will get the latest list and put it in there.

This took a little bit usually, and so I tried to see if I could thread the operation to increase speed, I might try to multi-process it next as the dual sends is about the fastest send (two sub lists, each about 30,000 items) and if there is a change I just update the whole sublist that changed and do a reconfigure.

Still, this takes too long as 10 seconds. The other kinds of aliases are interesting to me, such as Internal and External.

It would seem (and I did this too... but didn't understand how to 'reconfigure' or set the updates as active) that you can do it faster via pfctl via python, but, how do you reconfigure after updating a "Hosts" based Alias? Do the Internal or External Alias types not need a 'reconfigure' to have their populations be active in the rules that use them?

I'm fairly new to pf/FreeBSD so please do not take for granted anything I might 'should' or 'could' know, teach me!
#8
Issue:
Last two updates, on restart, WAN has IPv6 address but no IPv4 address

Further:
The solve is easy, I just go to WAN interface and hit 'Save' at the bottom, it applies, and then I have an IPv4 address on WAN followed by a little later the IPv6 address shows up again on WAN. LAN interfaces have their IPv6 (and IPv4) details, but the missing IPv4 on WAN is initially keeping a few things from working after the update.

I will be able to do more testing later as far as the reboot w/out an update, but I do not have that change management window right now.
#9
External hosts includes internal IPs, Internal hosts includes external IPs

I'm only in detection for 3 LAN Interfaces, I do have RSS enabled (it suggests I disable it... but it has been around for years now and certainly appears to work for everything else including Suricata)

The "Traffic Graph (Throughput)" Dashboard that shows activity, only shows activity for Upload, not Download (even if I speed test Up/Down, just shows Upload)

Any ideas, I'm completely new to Zenarmor and have a free account but have it integrated to their Cloud too?

That said, I have had a few detections for hosts going to odd FQDNs, not bad!
#10
I have several WOL hosts on my network, and I can trigger them to turn on, that works.

What does not work is the 'active status' on the WOL Plug-in Dashboard on the OPNSense. Further, it seems you have to 'wake all' now from the Wake On LAN plug-in menu... it seems you cannot select a specific device to wake up when in the plug-ins menu?
#11
Just released, open for testing, if you BIND with your OPNSense and Docker (w/Portainer), this might be of interest!

As I have ran my own internal BIND DNS setup for a while, and did not explore the built-in that OPNSense has (wanted to learn-it-all), and then wanted to resolve IPv6 for my network this became an eventual desire and then creation. It uses the OPNSense API as well as the Portainer API, then directly and securely interacts with BIND via TSIG.

Please feel free to check it out, comment, or even suggest how else one would do the same in a different way:

Homelab DNS Updater (Github)
#12
After having implemented IPv6, there is a need to be able to update the DNS Servers in this list dynamically, and I do not want to be limited to the two DNS servers for each ISC DHCP entry (and I am not using 'Kea DHCP' yet)

It is great that we have eight fields to add DNS Servers to in the System -> Settings -> General area, but it seems you cannot update these elements via the API, can anyone point out how to do it, or would this be a feature request?

Further, just want to say thank you to whoever got the ARP and NDP lists to be available via API - that is amazing and has let me dynamically update my BIND from MAC <-> Hostname for IPv6 rather easily. Also, just want to say to the network-gurus inventing things, thank-goodness MACs for IPv6 == MACs for IPv4. <3
#13
There's a comment I made on the plugins pull but I thought I would share here too:
https://github.com/opnsense/plugins/pull/2945

It would possibly be even better to allow us to select which auto rules get created instead of having to accept all or none, but if in the CrowdSec plugin we could get this option that would be acceptable.

That said, my intent here is to keep all of the rest of the functionality - so, I want the two aliases to be kept up to date by the plugin - I want to create my own rule to use those aliases but do not want the 'auto rule' getting in the way as it isn't deployed where or how I would want it.

The default rule only blocks in as a source, and does not block as a destination. Might be paranoid, but, I prefer to not even reach out to the badness as well. Further, I have a few hosts that I do not want to filter the traffic this way for, and want to let them interact with the IPs if they are on the CrowdSec blocklist or not.

Certainly interested to hear feedback on the idea/methods to help build it/how to get started.

Thank you all for all you do, I'd like to help but am a little inexperienced to take such a large bite.

Edit - Thank you OPNSense!!
#14
Huge thanks as always!!

Using:
VLANs and Multi-Interface LAN FW Group
DHCP ISC
Unbound
APCUPSD
Crowdsec
Suricata IDS
Wireguard VPN for Clients
NAT Inbound Port Forwarding
Outbound NAT Forwarding
UPnP
mDNS Repeater
IGMP Proxy

Extra:
DHCP -> Side BIND environment

Moded:
Suricata-update w/125k+ rules modified enabled in ~5 minutes
Crowdsec (only running Agent now, and parsing default and suricata eve logs too)
#15
So you are doing port forwarding, and you also have a blocking rule present on at least the WAN (ideally also the LAN(s)). It might be the Crowdsec IPv4 & IPv6 rules the plugin installs, or you maybe made the Spamhaus block rules and the Alias to sync the list from their sources.

What you might not realize is happening is, the Port Forward happens BEFORE any firewall rule on the WAN, so, it will forward in and then block on the LAN (if you have your rules blocking there) and this means extra work.

You can block at WAN and not forward!!

Just enable the 'Source' on the Port Forward rule, and set the 'Inverse' option, select your Blocklist (you can make a new list and have it hold multiple other lists that are syncing so you just give yourself one complete list to add to things) and hit save.

Do this on your Outbound NAT as well, just more or less in reverse - do the 'Destination' + 'Inverse' + your Blocklist, enjoy!

See image in attachments to this post! Hope this has helped someone, and happy Routing! Note - I did modify the image to remove my Proxy's Internal IP - so the blank field with no IP in it is only that way because of that.
#16
TLDR;
The issue is it appears at least the CrowdSec rule matches inconsistently, and I must admit, I wonder if other rules do too, or if this is due to alias <-> rule update sync/propagation, or some other elements of the pf/OPNSense management feature set?

The Long;
After 25.1, I noticed some oddity with the CrowdSec firewall rule entries and if they got matches or not

So I created two aliases, threatIPv4=CrowdSecIPv4+SpamhausIPv4 and threatIPv6=CrowdSecIPv6+SpamhausIPv6

Then I created two rules in Floating applied to both WAN and LAN that would match IPv4+IPv6 and In, one "Source Threatlist Block Inbound" for Source=threatIPv4+threatIPv6, the second "Destination Threatlist Block Outbound" for Destination=threatIPv4+threatIPv6

See the Floating Rules Screenshot_2025-02-13_20-42-38.png

What as happened since 25.1.1 is I am seeing blocks on the default "CrowdSec IPv4" list again, but, I am seeing my added "Source Threatlist Block Inbound" as well but not as many. Not sure if I have seen a default IPv6 show up in the Dashboard dial

See the Dashboard Firewall Screenshot_2025-02-13_20-41-03.png

In full transparency, I am logging this stuff to a data-lake, but the parsing of the hex rule eludes me and getting the matching rule text and applying it further eludes me. That said, our refreshed Dashboard is my source of detail and IMHO, appears correct and is currently my primary indicator of which rule is hitting
#17
Hello all,

The default/auto PF (Firewall) rules for the OPNSense are good, but once you really start customizing your router you might want to modify one or more of those rules. I'm not sure I would want to disable all of them, and more, I want to clone them into these 'auto rules' according to use (WAN/LAN) and modify them.

Specifically the sshlockout/HTTPS-redirect port forwarding appears to never go away after I've unchecked and saved into the WebGUI. To make sure I don't get locked out, I've written my own NAT Port Forward rules for 80 (into DMZ) 443 (to router ip for LAN) and 443 (to DMZ from WAN ips) configured with a "not from source blocklist" into them.

Still the "rdr rule" will fire for port 443 (and 80). It would appear that this built-in rule is handling Port Forwards for IPs that would be on my blocklist which would make sense, I cannot edit or see the 'rdr rule' redirect rule outside maybe the 'sshlockout' rule which stays around in-spite of being disabled.

It would seem to disable these you should check-mark the options on the System -> Settings -> Administration -> "HTTP Redirect", and the Firewall -> Settings -> Advanced -> "Disable anti-lockout", but this does not disable the built-in 'rdr rule' Port Forward and 'sshlockout' Pass rules.

Can anyone else verify this affect? Unexpected 'rdr rule' logs in your "Firewall: Log Files: Live View"?

NOTE: If you do not make the correct Pass rules and Forwarding rules, you could lock yourself out of your device!!
Example:
The first screen shot is a Rule in Floating, and LAN is a Group with all internal Interfaces, this should allow me to access the router.
The second screen shot is evidence that the 'rdr rule' is firing as I believe it should not be.

Thank you for your time reading this, please feel free to correct/ask me detail about my setup/intent!!
#18
It would seem you can only set the listener for the DNSCrypt-Proxy as an IPv4 address (0.0.0.0:5353 or if you don't want to get in the way of mDNS 0.0.0.0:5355 and if you wanted to set it to localhost 127.0.0.1:5355) but you cannot set for example :::5355 (any IPv6 address assigned to an OPNSense Interface) or even ::1:5355 (IPv6 localhost).

If you try to add an IPv6 address to the listener list, it will fail the service. Only once you remove the IPv6 address will the DNSCrypt-Proxy server start and run.

Is there a reason for this? Further, does Unbound handle the traffic the DNSCrypt-Proxy would? If so, should I just forward Outbound 853 for DNSCrypt and 443 for Known DoH to Unbound's port 53?
#19
Goal:
To modify specific SIDs using suricata-update's "--modify" option

To do this we need suricata-update, and it is already installed w/Suricata! ^_^ Nice!!

Now, it has a lot of flags/options, and OPNSense's Suricata installation is a bit unique, so, after a bit of discovery I think I've resolve this to be the most accurate form of the command:
suricata-update --suricata-conf /usr/local/etc/suricata/suricata.yaml --suricata /usr/local/bin/suricata --data-dir /usr/local/etc/suricata --no-merge --modify-conf=/root/suricata/modify.conf --output /usr/local/etc/suricata/rules --no-test --no-reload --offline

This appears to update/replace files in the /usr/local/suricata/rules folder, but, it does not make a sid map file in the same format (v1 and v2 both look different than the one OPNSense sets up) and OPNSense already does things for IDS Rules in a two different main fashions...

The two fashions are defined in this file:
/usr/local/opnsense/service/conf/actions.d/actions_ids.conf
In it are the update and reload details and a few other actions. The update (update) and reload (install) scrips are as such:

Rule Updater by OPNSense
/usr/local/opnsense/scripts/suricata/rule-updater.py
( gets updated rules from the internet, puts them in /usr/local/etc/suricata/rules )

Rule Installer by OPNSense
/usr/local/opnsense/scripts/suricata/installRules.py
( gets rules from /usr/local/etc/suricata/rules, and appears to copy/mod them to /usr/local/etc/suricata/opnsense.rules and then makes /usr/local/etc/suricata/installed_rules.yaml - it seems to also make an SQLite file for the SIDs )

What I'm not sure about is, what might break if I get in the mix here, and...

  • Disable OPNSense's Update & Reload (Install) Cron routines
  • Setup new Cron Scripts in /usr/local/opnsense/service/conf/actions.d with 'Descriptions' so I can Cron them
  • Have these scripts run the suricata-update with the correct flags, and create the expected merged file?
#20
In my Syslog output, it seems filterlog/firewall applied a simple numeric to the 'rule' and 'subrule' elements

In the API output, each rule has a UUID and I get them at /diagnostics/firewall/listRuleIds then query the rule's elements at /firewall/filter/getRule?{UUID} and for the output below I've summarized the output as it doesn't seem like the rule data matches what is in the GUI for OPNSense? These are some of the default rules, but, their data all says Pass and that does not make sense to me as the first four are block rules.

3c2cd03c70091e3732710e44c3b97506 named Block bogon IPv4 networks from WAN is...
['action pass Pass',
'direction in In',
'ipprotocol inet IPv4',
'protocol any any',
'gateway  None']
57401c13616c94401fc89cafa777581e named Block bogon IPv6 networks from WAN is...
['action pass Pass',
'direction in In',
'ipprotocol inet IPv4',
'protocol any any',
'gateway  None']
1072878c6245b52440bc89c6107a9d0a named Block private networks from WAN is...
['action pass Pass',
'direction in In',
'ipprotocol inet IPv4',
'protocol any any',
'gateway  None']
dcde0621a9f0daa594b014e15f65c076 named Block private networks from WAN is...
['action pass Pass',
'direction in In',
'ipprotocol inet IPv4',
'protocol any any',
'gateway  None']
5ddcbf1f0688962629f1a2166ba2ab0c named CARP defaults is...
['action pass Pass',
'direction in In',
'ipprotocol inet IPv4',
'protocol any any',
'gateway  None']
846c09139ef5484c01967052b15e454a named CARP defaults is...
['action pass Pass',
'direction in In',
'ipprotocol inet IPv4',
'protocol any any',
'gateway  None']


In the end, I am after a method to match the rule+subrule to a UUID, so that I can label my rules in my Syslog output/Kibana so that it shows the firewall histogram w/Rule naming context?