Compare commits

...

104 Commits

Author SHA1 Message Date
Stephan de Wit
3c2ad5d6b3 ipsec: add DH Group 2 for basic Azure VPN gateway compatibility
While insecure, this is the best possible proposal combination out
of the list provided by Microsoft: https://learn.microsoft.com/en-us/azure/vpn-gateway/vpn-gateway-about-vpn-devices#ike-phase-1-main-mode-parameters
2025-04-25 09:43:59 +02:00
Franco Fichtner
a4124d7e99 pkg: adjust this a bit making it possible to shift the user UID and GID if needed #8521 2025-04-24 21:10:50 +02:00
Franco Fichtner
2a935b7afa
system: states kill checkbox clarification (#8578)
Co-authored-by: Stephan de Wit <stephan.de.wit@deciso.com>
2025-04-24 16:27:37 +02:00
Ad Schellevis
727967ed6d
Services: ISC DHCPv6 - show "tracking" interfaces when enabled and offer an explicit disable (#8576)
* Services: ISC DHCPv6 - show "tracking" interfaces when enabled an offer an explicit disable option for the service in question so someone could use dnsmasq or kea instead.

To avoid large changes, we opt for a  minimal set here.
In services_dhcpv6.php, we add a separate form and handler in case tracking (without dhcpd6track6allowoverride) is set, which either flushes the unused isc-dhcpv6 server configuration when enabled (default) or writes a small section only including ['enabled' => -1].
For visibility, we show the calculated range as would be set by dhcpd_dhcp6_configure() when tracking is used.

The backend code then double checks the services which er explicitly disabled (-1) and skip processing for these (not enabled).

In order to make people aware of the fact that an isc-dhcpv6 server could be running, make sure the menu system also reflects reality.

Since router advertisements are stored within the same container and will need a toggle as well, keep the value of ramode so we have a way to intervene in a similar way as for dhcpv6.
One small side affect of this commit is that it will show "Services: Router Advertisements" for the tracking interface, which we need to implement later.

One of the building blocks for: https://github.com/opnsense/core/issues/8528

* Update src/www/services_dhcpv6.php

Co-authored-by: Franco Fichtner <franco@opnsense.org>

* Services: Router Advertisements: show "tracking" interfaces when enabled an offer an explicit disable option for the service in question so someone could use dnsmasq instead.

More or less the same construction as added for dhcpv6, using the ramode field to switch between types (disabled or assisted).

While here, also bugfix fieldname in services_dhcpv6.php

also for https://github.com/opnsense/core/issues/8528

---------

Co-authored-by: Franco Fichtner <franco@opnsense.org>
2025-04-24 16:23:32 +02:00
Franco Fichtner
3280916191 Scripts: one more for JS 2025-04-24 10:57:26 +02:00
Franco Fichtner
35f46bbb11 firewall: remove unused function...
... imported into pfSense in 2007... unused ;)

https://github.com/pfsense/pfsense/commit/615b27bc267a98e72
2025-04-24 10:49:56 +02:00
Franco Fichtner
1c4a9830f9 Scripts: last adjustments? ;) 2025-04-24 10:29:37 +02:00
Franco Fichtner
39d5ff1a26 interfaces: allow the unused function script to find these 2025-04-24 10:05:41 +02:00
Franco Fichtner
e3003959bc Scripts: exclude plugin argument selector trick 2025-04-24 10:05:25 +02:00
Franco Fichtner
f5e0735d94 Scripts: a bit noisy, we just want the gory details now 2025-04-24 09:38:09 +02:00
Franco Fichtner
b2a6288437 ipsec: remove two unused functions 2025-04-24 09:37:05 +02:00
Franco Fichtner
bc9f73a562 Scripts: typo 2025-04-24 09:35:40 +02:00
Franco Fichtner
b1a84fc5b9 system: remove unused check_subnets_overlap() 2025-04-24 09:31:28 +02:00
Franco Fichtner
17134aef77 system: remove unused subnet_size() 2025-04-24 09:30:38 +02:00
Franco Fichtner
2d1c1fcebe Scripts: add unused-functions.sh helper
Processing is quite heavy but we don't need to run this all the time.
2025-04-24 09:27:41 +02:00
Franco Fichtner
30343809e9 system: remove unused format_bytes() 2025-04-24 08:59:26 +02:00
Franco Fichtner
54629f459d system: remove unused cert_get_subject_array() 2025-04-24 08:58:13 +02:00
Franco Fichtner
51dcbcc39e config: remove unused config_restore() 2025-04-24 08:39:52 +02:00
Franco Fichtner
5aa8d206e6 interfaces: remove unused is_interface_assigned() 2025-04-24 08:16:17 +02:00
Franco Fichtner
4ce4450537 openvpn: remove is_interface_assigned() so it can be removed 2025-04-24 08:15:41 +02:00
Franco Fichtner
f31d7a8aa6 interfaces: remove is_interface_assigned() use from wlan 2025-04-24 07:48:39 +02:00
Franco Fichtner
f30f0f05a0 interafaces: reduce diff between rc.newwanip scripts a little
The goal is still to merge these eventually.  ;)
2025-04-23 11:10:04 +02:00
Franco Fichtner
f5352f841e interfaces: do group sync for IPv6 just in case 2025-04-23 10:55:31 +02:00
Franco Fichtner
0deba9c9de tzdata: sync while here 2025-04-23 09:45:39 +02:00
Franco Fichtner
f9ea24113a system: move get_country_codes() to only caller
Also cleans up the last raw use of $contribDir which neatly lands
in the file that was already modified.
2025-04-23 09:41:26 +02:00
Freddie Sackur
a819b91049
Add contribDir to app config (#8567) 2025-04-23 09:34:41 +02:00
Franco Fichtner
08a86fdae9 pkg: add a user for www-only access #8521
Added a group as well, but we can always drop it if it doesn't
make sense.
2025-04-23 09:09:35 +02:00
Franco Fichtner
bdb3f73315 reporting: header style 2025-04-23 08:45:01 +02:00
Ad Schellevis
b83cc529eb Firewall: multiselect for icmptype for both legacy and icmp. closes https://github.com/opnsense/core/issues/8513 2025-04-22 21:17:52 +02:00
Ad Schellevis
bf14a0a2e3 Firewall: prevent source/destination inversion when multiple nets are selected. closes https://github.com/opnsense/core/issues/8559 2025-04-22 20:37:56 +02:00
Ad Schellevis
9c50cbfcb8
Services: Kea DHCP: Kea DHCPv6 - add new option based on v4 (#8571)
This contains roughly the same configuration items as our current isc-dhcp6 alternative, with the exception of not trying to implement dynamic ranges based on data received from dhclient6.
In terms of target audience, dynamic environments (receiving their "wan" type addressess via dhcp), should logically use dnsmasq for client configuration. Large (enterprise) setups usually are static by nature and may require prefix deligation to routers behind the primary one. In these cases Kea will be the tool of choice.

Both v4 and v6 share the same rc scripts underneath, which means reconfiguration happens per package (eventhough two services are registered).
Existing hooks for v4 have been extended with v6 data (firewall rules and staticmaps).

Advanced configurations can still opt out of config file generation and supply their own json config, same as implemented for v4.

The lease view still needs to be implemented, but that's likely a minor addition.
2025-04-22 17:43:27 +02:00
Stephan de Wit
25e5341dd4 captive portal: exclude portal table in destination (https://github.com/opnsense/core/issues/8564) 2025-04-22 15:07:13 +02:00
Ad Schellevis
7beec43db9 Services: Dnsmasq DNS & DHCP - fix validation for static ipv4, closes https://github.com/opnsense/core/issues/8568 2025-04-20 10:55:21 +02:00
Monviech
5636079c16
auth: Implement base_bootgrid_table in user, group and priv templates (#8529) 2025-04-17 11:48:13 +02:00
Franco Fichtner
302ed6b037 ipsec: fix trimming NULL values
Not sure how I managed to misconfigure this but since the
function relies on returning null make the trimming conditional.
2025-04-17 10:00:24 +02:00
Ad Schellevis
e09112ab45 System/Trust - fix scoping issue in CertificatesField causing issues for consumers of ArrayFields in migrations, closes https://github.com/opnsense/core/pull/8546 2025-04-17 09:44:45 +02:00
eopo
c53dc21190
Add field boottime to api/system/systemTime (#8557) 2025-04-16 20:03:12 +02:00
Ad Schellevis
5d0007a023 Interfaces: Diagnostics: Packet Capture - fix wrapping as suggested in https://github.com/opnsense/core/pull/8554 2025-04-16 19:58:22 +02:00
Franco Fichtner
4d20b54aa5 interfaces: make this return explict 2025-04-16 15:13:37 +02:00
Ad Schellevis
1e37f6a7fc Interfaces: Diagnostics: Packet Capture - more strict jQuery selector for "(de)select all" button. for https://github.com/opnsense/core/pull/8554 2025-04-16 15:10:24 +02:00
Stephan de Wit
27fdbd950f diagnostics: ARP: wire up refresh button 2025-04-16 14:25:57 +02:00
Monviech
e72077c376
dnsmasq: Improve interface/tag selectpicker (#8560)
* dnsmasq: Add button to quickly clear the tag/interface filter

* dnsmasq: Autofill filter selectpicker choices in add dialog
2025-04-16 13:12:09 +02:00
Franco Fichtner
045dec233a system: add logging to state kills and polish comments #8548 2025-04-16 10:34:14 +02:00
Franco Fichtner
927bda891f firewall: improve labels in pf debug setting
The level key words are easy to find in the source code, but knowing
which verbose description they belong to is difficult without pulling
up our source code as well.  Make it explicit.
2025-04-16 10:33:12 +02:00
Ad Schellevis
4f3db31351
System: Gateways - kill opposite states when a gateway "up" is triggered (#8548) 2025-04-16 09:40:36 +02:00
Ad Schellevis
6d579db491 VPN: IPsec: Mobile & Advanced Settings - copy "Split DNS name" to undocumented "25", closes https://github.com/opnsense/core/issues/8552
* https://docs.strongswan.org/docs/latest/plugins/attr.html
* https://lists.strongswan.org/pipermail/dev/2019-May/001994.html
2025-04-15 14:10:34 +02:00
Ad Schellevis
b87eba3085 Services: Intrusion Detection: Administration - template style cleanups 2025-04-15 13:31:04 +02:00
Franco Fichtner
f30c28ca79 mvc: allow referencing disabled interfaces in LinkAddressField
This prevents validation errors when interfaces are temporarily
disabled.  Other device components received similar fixes in the
past due to this "glitch" of not offering valid devices and selectpickers
would lose their correct value on save too (the field is a bit different
here but the same principle applies).
2025-04-15 12:36:04 +02:00
Franco Fichtner
25585eb6b9 interfaces: consider tracked interface's linked devices on reload #7713
When attaching a GIF tunnel to an IPv6 device it's more likely a LAN
device but that is being missed when WAN is reloaded here.  Much of the
other code still accounts for this so this merely goes with the flow
and since we only operate in IPv6 scope that is ok.
2025-04-15 11:00:54 +02:00
Ad Schellevis
6a89c8968b Services: Intrusion Detection: Administration - our fix in the reverse log reader (7446f8cbbf) caused a regression in the alert view. closes https://github.com/opnsense/core/issues/8550
It looks like this worked by accident, since we started with the wrong offset, we accidentally hit the right record.
2025-04-15 10:49:32 +02:00
Ad Schellevis
d0f745a70e Services: Captive Portal - fix display issue for pass rule when client not in zone
inverse rules unfortunately contain some mappings, which means we need to map them differently for legacy and mvc code.
2025-04-14 17:09:39 +02:00
Franco Fichtner
5ad41a236c system: typo 2025-04-14 12:39:07 +02:00
Ad Schellevis
0d6aa56527 Services: ISC DHCPv4: hide menu items when dnsmasq is enabled to improve "out of the box" experience. closes https://github.com/opnsense/core/issues/8329 2025-04-14 10:34:22 +02:00
Ad Schellevis
413f49c3ef Services: Captive Portal - configd actions should use long opts (fix regression in 7e838c6d92)
argparse needs long params too..
2025-04-14 09:47:50 +02:00
Alex Goodkind
02e511091d
DHCP6: use lease_type to key lease map in addition to iaid_duid (#8492)
* dhcp6: key lease map by type in addition to duid

* Update src/opnsense/scripts/dhcp/get_leases6.py

Co-authored-by: Ad Schellevis <AdSchellevis@users.noreply.github.com>

---------

Co-authored-by: Ad Schellevis <AdSchellevis@users.noreply.github.com>
2025-04-11 18:54:15 +02:00
Stephan de Wit
4567021437 captive portal: remove interfaces_inbound option (https://github.com/opnsense/core/issues/8326)
In the old situation, one would need explicit pf rules on top of
this feature to make this work. With the removal of IPFW,
those rules are now enough to make the same happen.
2025-04-11 09:25:06 +02:00
Franco Fichtner
d81b2eec9d dnsmasq: move default setting to where dhcp disappeared before 2025-04-11 09:15:07 +02:00
Franco Fichtner
5a2e399586 ipsec: settings page also unaccounted for
PR: https://forum.opnsense.org/index.php?topic=46595.0
2025-04-11 09:02:45 +02:00
Franco Fichtner
54fed30cf1 ipsec: fix more ACLs related to individual IPsec page use
PR: https://forum.opnsense.org/index.php?topic=46595.0
2025-04-11 08:43:31 +02:00
Franco Fichtner
d4ddc8def6 ipsec: add missing copyright header 2025-04-11 08:41:32 +02:00
Franco Fichtner
fb87f688f6 ipsec: fix auth server parsing regression
PR: https://forum.opnsense.org/index.php?topic=46774.0
2025-04-10 20:52:25 +02:00
Ad Schellevis
25b2716325 Services: Captive Portal - regression in https://github.com/opnsense/core/issues/8326 when reflection is enabled.
Captive portal installs redirects, but these should be excluded when calculating reflection rules.

ref: https://forum.opnsense.org/index.php?topic=46775.0
2025-04-10 20:34:32 +02:00
Ad Schellevis
7e838c6d92 Services: Captive Portal - configd actions should use long opts 2025-04-10 14:16:11 +02:00
Ad Schellevis
6d507b1dd9 Services: Captive Portal - fix regresssion in 8ba454ab04, argparse doesn't seem to like an argument starting with a minus (-) sign even when quoted.
making assignments explicit with an equal [=] sign seems to fix this.
2025-04-10 14:07:37 +02:00
Franco Fichtner
86ffbd88ad firmware: this broke too 2025-04-10 12:42:00 +02:00
Franco Fichtner
0e5a5c3ba2 system: fix gateway watcher backoff 2025-04-10 11:27:12 +02:00
Franco Fichtner
da6fab5bff backend: adjust for #8525 2025-04-10 09:44:03 +02:00
Ad Schellevis
7446f8cbbf logging: reverse_log_reader() - fix off by one error due to line ending at the end of the file
Usually log lines start with a line ending, which means the first hit is always an empty line with reading things backwards.
This empty line has no relevance, but only indicates we're at the end of the file.

This commits stores the file starting position in all cases and ignores the output when we trying to yield the end of the file.
2025-04-10 09:08:23 +02:00
Ad Schellevis
d0b1c8d369 Services: Intrusion Detection: Administration - example usage of configd errors:no property (https://github.com/opnsense/core/issues/8525) 2025-04-09 17:38:11 +02:00
Ad Schellevis
9f7a1fa062 configd: support "errors:no" clause on actions, closes https://github.com/opnsense/core/issues/8525 2025-04-09 17:36:13 +02:00
Stephan de Wit
8d3d392ae6 dashboard: traffic: use client time (https://github.com/opnsense/core/issues/8225) 2025-04-09 14:39:26 +02:00
Franco Fichtner
817e7fb11d LICENSE: sync 2025-04-09 13:17:18 +02:00
Franco Fichtner
7b2ad791ee src: syle sweep 2025-04-09 13:16:51 +02:00
Ad Schellevis
983a0663b0
Interfaces: Devices: Bridge - refactor to MVC closes https://github.com/opnsense/core/issues/8353 (#8534)
* Interfaces: Devices: Bridge - refactor to MVC for https://github.com/opnsense/core/issues/8353

* move existing properties to model which overlays existing config path
* add a simple wrapper script for [re]configuration which diffs and applies using the new _interfaces_bridge_configure() implementation

* Update src/opnsense/mvc/app/models/OPNsense/Interfaces/Bridge.xml

Co-authored-by: Franco Fichtner <franco@opnsense.org>

---------

Co-authored-by: Franco Fichtner <franco@opnsense.org>
2025-04-09 13:09:09 +02:00
Ad Schellevis
09bd2d96cc Interfaces: Devices: Bridge - refactor bridge (re)configuration, as with most new components, we should check what we have first before applying to prevent a lot of unuseful calls and possible service disruptions. pre work for https://github.com/opnsense/core/issues/8353
In order to plan->do->act we need the current settings of the existing bridge, which is where legacy_interfaces_details() comes into play, which needs some additional parsing.
Next we can diff per type of setting and apply when changed.
2025-04-09 11:16:42 +02:00
Ad Schellevis
5629911558 System: Trust: Authorities - prevent recusrion loop when ca's are cross referencing eachother.
Although this is highly uncommon, it's very annoying when the certificate path leads to an "Fatat error: Allowed memory size exhausted...".
If we do end in a loop (e.g. same ca already in the path), exit the calculation and return what we found sofar.
2025-04-08 11:45:21 +02:00
Franco Fichtner
d240c8b0fa firmware: fix page after f569ead1a5371 changed the defaults
Make it backwards-compatible but always store the new value now.

    # pluginctl -g firmware.reboot

will still return an empty string instead of "0".
2025-04-08 11:29:59 +02:00
Franco Fichtner
c1b1af2ac2 src: style sweep 2025-04-07 19:51:40 +02:00
Franco Fichtner
0a33697a90 interfaces: allow literal comma by escape sequence '\,'; closes #8503 2025-04-07 12:09:23 +02:00
Monviech
ce2abde150
dashboard: Certificates.js adjustments for f90e544 (#8526)
* dashboard: Use search link for certificates not in the trust model

* dashboard: Use toLocaleDateString to only display the expiry date but not the exact time.

* dashboard: Show the commonname of a certificate if it exists. Since certificates from external sources all have the same description, they would not be easily distinguished otherwise.

* Fix style

* dashboard: The value of hidden items must be changed to uuid to ensure uniqueness when hiding certificates

* dashboard: Simplify hiddenItemOptions value
2025-04-04 14:12:27 +02:00
Franco Fichtner
d3c5aa22a0 system: refactor vip access 2025-04-04 11:52:39 +02:00
Franco Fichtner
e6a4bde0bf system: cleanup unused since 945bd66a3dc8 2025-04-04 11:49:55 +02:00
Franco Fichtner
868a74e058 interfaces: cleanup spurious functions regarding VIP access
We do this for different reasons, but mainly for code maintenance
and simplicity.  It also fixes a few aquire/display bugs with
overlapping linl-local VIPs across interfaces, but not all.
2025-04-04 11:29:51 +02:00
Monviech
7210f016eb
dnsmasq: Implement a light validation for option6 values (#8520)
* dnsmasq: Implement a light validation for option6 values as they require to be wrapped inside square brackets if they contain an IPv6 address

* dnsmasq: Improve the IPv6 bracket check, also handle multiple ipv6 addresses that are comma separated, use isIpv6Address()

* dnsmasq: Put IPv6 value check inline since dhcp-match and dhcp-option have been unified in master.

* Update src/opnsense/mvc/app/models/OPNsense/Dnsmasq/Dnsmasq.php

Co-authored-by: Ad Schellevis <AdSchellevis@users.noreply.github.com>

* Update src/opnsense/mvc/app/models/OPNsense/Dnsmasq/Dnsmasq.php

Co-authored-by: Ad Schellevis <AdSchellevis@users.noreply.github.com>

* dnsmasq: trim value directly

---------

Co-authored-by: Ad Schellevis <AdSchellevis@users.noreply.github.com>
2025-04-04 08:42:13 +02:00
Ad Schellevis
905b990dea filter: replace update_params for argparse 2025-04-03 21:05:18 +02:00
Monviech
207bddcad5
TrafficShaper: Implement base_bootgrid_table and base_apply_button (#8524) 2025-04-03 16:08:04 +02:00
Ad Schellevis
368598eafc plist 2025-04-03 15:12:35 +02:00
Ad Schellevis
f90e5445db System: Trust: Certificates - offer config directory (/usr/local/etc/ssl/ext_sources/) to store locations for certificates not managed by us, but practical to know about their existence. closes https://github.com/opnsense/core/issues/8279
This is useful for services like OPNWAF and Caddy. This commit only adds the facility and changes the admin page, the widget is left unaltered.
2025-04-03 15:11:54 +02:00
Franco Fichtner
63b9f2e1aa system: allow multiple manual DNS search domains; closes #8522
The length and input isn't bound but when writing resolv.conf
we will adhere to the requirement mentioned in the man page:

    The search list is currently limited to six domains
    with a total of 256 characters.

We simply don't always know how many the system was being provided
with from the ISP so it is what it is.
2025-04-03 11:18:25 +02:00
Stephan de Wit
dbf37413b9 Revert "bootgrid: resizable columns (#8496)"
This reverts commit de5dd5f5278edbae14bfa1bc76751ae360b834e0.

table-layout: auto; seems to do more harm than good, while originally
intended to improve out-of-bounds table row situations, it proves
to cause the same issue for long cell content as it now
ignores overflow:ellipsis.
2025-04-03 08:37:26 +02:00
Monviech
732a393fb7
dnsmasq: Unify dhcp-option and dhcp-match in the same grid (#8516)
* dnsmasq: Unify dhcp-option and dhcp-match in the same grid

Both dhcp-option and dhcp-match use almost the same fields in the form and concern the same options.
Unifying them could make sense to remove some duplicate code and potentially improving the UX.

* make plist and remove console log debug statement
2025-04-03 08:10:48 +02:00
Ad Schellevis
7ec7e1d174 Firewall: Aliases - fix regression in alias table in json format (https://github.com/opnsense/core/issues/8277)
In order to support both formats, we should break with the first succesful compile().

A workaround in the current version is to omit the {.} in the path expression.
2025-04-02 18:05:01 +02:00
Franco Fichtner
97da2221d7 radvd: refactor use of get_configured_carp_interface_list() 2025-04-02 16:24:44 +02:00
Monviech
ef1c4e07c8
kea: Fix missing ACL privileges (#8519) 2025-04-02 14:13:58 +02:00
Franco Fichtner
adf95bc108 radvd: fix description lookup for #8512 2025-04-02 13:19:58 +02:00
Robin Müller
25d629fcd3
radvd: fix list of source addresses on overlapping link-locals (#8517) 2025-04-02 13:08:32 +02:00
Franco Fichtner
557b793a4e mvc: style 2025-04-02 12:13:45 +02:00
Ad Schellevis
04b5749010 System: Access: Users - fix two typo's, missing comments in grid and disfunctional default landing page 2025-04-02 09:45:40 +02:00
Ad Schellevis
b55023315c Services: Kea DHCP: Kea DHCPv4 - allow manual configuration for advanced scenarios, closes https://github.com/opnsense/core/issues/7822
This commit adds a toggle which skips config file generation for kea-dhcp4.conf and lets the user handle it manuallt, service startup and control stays in place while manually configured.
When manual mode is selected, all other options will be hidden in the form, which should help people understand (and read) what the purpose of this toggle is (advanced mode).
2025-04-01 21:22:02 +02:00
Ad Schellevis
4de4bd2774 Firewall: Rules - fix presentation when alias name overlaps group name. closes https://github.com/opnsense/core/issues/8423
Unfortunately we can't prevent all overlaps, but at least we cab make it consistent with the rules being generated. loadAliasMap() overlays aliases on top of networks (and interface groups), swapping the order makes sure we thread them equally.
2025-04-01 20:48:29 +02:00
Alexander Lauster
8c609298f3 Sunset mirror dns-root.de 2025-03-31 20:57:40 +02:00
Ad Schellevis
d8adc429f7 VPN: OpenVPN: Client Export - add "Enable static challenge (OTP)" option, closes https://github.com/opnsense/core/issues/8488 2025-03-31 18:52:26 +02:00
Franco Fichtner
f698e25cbb firmware: "fix" the issue of user clicking check after clicking check from dashboard
We could move the check to backend() at the risk of breaking firmware upgrades on
errors.  Breaking the auto-check seems like the lesser evil.

In reality you can always go back to the status tab and re-create the issue by
clicking check for updates again after already having it clicked.  That is why the
page actually switches to the updates tab on click.  The update click is also delayed
to give the status call to fill the status tab first which immitates a normal page
render.

The issue actually appears because:

1. Backend options are detached and are dispatched, but since they run in the backround
   we don't return any feedback because we don't have it.  This then...
2. ... creates a parallel chain of trackStatus() calls which eventually reports the same
   modal.

The issue only appears when no updates are found or triggering a separate error modal.
When updates are found this is handled gracefully.

Making the modals and errors static seems like overkill as well.

Keeping friction and magic out of this page is important too.
2025-03-31 17:06:18 +02:00
Monviech
3f1ed2dff5
auth/user: Fix url hash in link so redirection shows the correct menu path (#8509) 2025-03-31 13:06:47 +02:00
163 changed files with 3581 additions and 2328 deletions

View File

@ -1,3 +1,25 @@
PW=/usr/sbin/pw
USER=wwwonly
UID=789
GROUP=${USER}
GID=${UID}
PW_ARG=add
if ${PW} groupshow ${GROUP} >/dev/null 2>&1; then
PW_ARG=mod
fi
echo "Creating group '${GROUP}' with gid '${GID}'"
${PW} group${PW_ARG} ${GROUP} -g ${GID}
PW_ARG=add
if ${PW} usershow ${USER} >/dev/null 2>&1; then
PW_ARG=mod
fi
echo "Creating user '${USER}' with uid '${UID}'"
${PW} user${PW_ARG} ${USER} -u ${UID} -g ${GID} -c "World Wide Web Only" -d /nonexistent -s /usr/sbin/nologin
echo "Updating /etc/shells" echo "Updating /etc/shells"
cp /etc/shells /etc/shells.bak cp /etc/shells /etc/shells.bak
(grep -v /usr/local/sbin/opnsense-shell /etc/shells.bak; \ (grep -v /usr/local/sbin/opnsense-shell /etc/shells.bak; \

View File

@ -3,7 +3,7 @@ Copyright (c) 2017 Alexander Shursha <kekek2@ya.ru>
Copyright (c) 2004 Bachman Kharazmi Copyright (c) 2004 Bachman Kharazmi
Copyright (c) 2005-2008 Bill Marquette <bill.marquette@gmail.com> Copyright (c) 2005-2008 Bill Marquette <bill.marquette@gmail.com>
Copyright (c) 2012 Carlos Cesario <carloscesario@gmail.com> Copyright (c) 2012 Carlos Cesario <carloscesario@gmail.com>
Copyright (c) 2024 Cedrik Pischem Copyright (c) 2024-2025 Cedrik Pischem
Copyright (c) 2005-2006 Colin Smith <ethethlay@gmail.com> Copyright (c) 2005-2006 Colin Smith <ethethlay@gmail.com>
Copyright (c) 2013 Dagorlad Copyright (c) 2013 Dagorlad
Copyright (c) 2006 Daniel S. Haischt Copyright (c) 2006 Daniel S. Haischt

86
Scripts/unused-functions.sh Executable file
View File

@ -0,0 +1,86 @@
#!/bin/sh
# Copyright (c) 2025 Franco Fichtner <franco@opnsense.org>
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
#
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.
PLUGINS="configure cron devices firewall interfaces run services syslog xmlrpc_sync"
if [ -n "${1}" ]; then
cd "${1}"
fi
TESTDIR=src
DIRS=${TESTDIR}
NOTE="(did not check plugins)"
if [ -d ../plugins ]; then
DIRS="${DIRS} ../plugins"
NOTE="(cross-checked plugins)"
fi
grep -Eor '^function &?[^( ]+' ${TESTDIR} | tr ':' ' ' | tr -d '&' | while read FILE X FUNC; do
BASEDIR=$(dirname ${FILE})
BASEDIR=$(basename ${BASEDIR})
MODULE=$(basename ${FILE})
MODULE=${MODULE%.inc}
# exclude indirect plugin calls not otherwise referenced
if [ "${BASEDIR}" = "plugins.inc.d" ]; then
for PLUGIN in ${PLUGINS}; do
if [ "${FUNC}" = "${MODULE}_${PLUGIN}" ]; then
continue 2
fi
done
fi
# exclude xmlrpc magic
if [ "${BASEDIR}" = "xmlrpc" ]; then
if [ "${FUNC}" = "xmlrpc_publishable_${MODULE}" ]; then
continue 2
fi
fi
# exclude obvious and non-obvious ways to call a function
USED=$(grep -Fr "${FUNC}" ${DIRS} | grep -F \
-e "${FUNC}(" \
-e "'${FUNC}'" \
-e "'${FUNC}:" \
-e "${FUNC}.bind" \
-e "${FUNC}.call" \
-e ".keyup(${FUNC})" \
-e "= ${FUNC};" \
| wc -l | awk '{ print $1 }')
if [ ${USED} -le 1 ]; then
echo "${FUNC}() appears unused" ${NOTE}
elif [ ${USED} -eq 2 ]; then
# XXX if a match happens in the same file it's probably already considered ;)
#echo "${FUNC}() only used once, consider refactor"
:
else
USED=$((USED - 1))
#echo "${FUNC}() used ${USED} times"
fi
done

View File

@ -3,17 +3,22 @@
# This file is in the public domain, so clarified as of # This file is in the public domain, so clarified as of
# 2009-05-17 by Arthur David Olson. # 2009-05-17 by Arthur David Olson.
# #
# From Paul Eggert (2015-05-02): # From Paul Eggert (2023-09-06):
# This file contains a table of two-letter country codes. Columns are # This file contains a table of two-letter country codes. Columns are
# separated by a single tab. Lines beginning with '#' are comments. # separated by a single tab. Lines beginning with '#' are comments.
# All text uses UTF-8 encoding. The columns of the table are as follows: # All text uses UTF-8 encoding. The columns of the table are as follows:
# #
# 1. ISO 3166-1 alpha-2 country code, current as of # 1. ISO 3166-1 alpha-2 country code, current as of
# ISO 3166-1 N905 (2016-11-15). See: Updates on ISO 3166-1 # ISO/TC 46 N1108 (2023-04-05). See: ISO/TC 46 Documents
# http://isotc.iso.org/livelink/livelink/Open/16944257 # https://www.iso.org/committee/48750.html?view=documents
# 2. The usual English name for the coded region, # 2. The usual English name for the coded region. This sometimes
# chosen so that alphabetic sorting of subsets produces helpful lists. # departs from ISO-listed names, sometimes so that sorted subsets
# This is not the same as the English name in the ISO 3166 tables. # of names are useful (e.g., "Samoa (American)" and "Samoa
# (western)" rather than "American Samoa" and "Samoa"),
# sometimes to avoid confusion among non-experts (e.g.,
# "Czech Republic" and "Turkey" rather than "Czechia" and "Türkiye"),
# and sometimes to omit needless detail or churn (e.g., "Netherlands"
# rather than "Netherlands (the)" or "Netherlands (Kingdom of the)").
# #
# The table is sorted by country code. # The table is sorted by country code.
# #
@ -166,7 +171,7 @@ ME Montenegro
MF St Martin (French) MF St Martin (French)
MG Madagascar MG Madagascar
MH Marshall Islands MH Marshall Islands
MK Macedonia MK North Macedonia
ML Mali ML Mali
MM Myanmar (Burma) MM Myanmar (Burma)
MN Mongolia MN Mongolia
@ -235,10 +240,10 @@ ST Sao Tome & Principe
SV El Salvador SV El Salvador
SX St Maarten (Dutch) SX St Maarten (Dutch)
SY Syria SY Syria
SZ Swaziland SZ Eswatini (Swaziland)
TC Turks & Caicos Is TC Turks & Caicos Is
TD Chad TD Chad
TF French Southern & Antarctic Lands TF French S. Terr.
TG Togo TG Togo
TH Thailand TH Thailand
TJ Tajikistan TJ Tajikistan

View File

@ -3,7 +3,7 @@
# This file is in the public domain, so clarified as of # This file is in the public domain, so clarified as of
# 2009-05-17 by Arthur David Olson. # 2009-05-17 by Arthur David Olson.
# #
# From Paul Eggert (2018-06-27): # From Paul Eggert (2021-09-20):
# This file is intended as a backward-compatibility aid for older programs. # This file is intended as a backward-compatibility aid for older programs.
# New programs should use zone1970.tab. This file is like zone1970.tab (see # New programs should use zone1970.tab. This file is like zone1970.tab (see
# zone1970.tab's comments), but with the following additional restrictions: # zone1970.tab's comments), but with the following additional restrictions:
@ -16,6 +16,9 @@
# clocks have agreed since 1970; this is a narrower definition than # clocks have agreed since 1970; this is a narrower definition than
# that of zone1970.tab. # that of zone1970.tab.
# #
# Unlike zone1970.tab, a row's third column can be a Link from
# 'backward' instead of a Zone.
#
# This table is intended as an aid for users, to help them select timezones # This table is intended as an aid for users, to help them select timezones
# appropriate for their practical needs. It is not intended to take or # appropriate for their practical needs. It is not intended to take or
# endorse any position on legal or territorial claims. # endorse any position on legal or territorial claims.
@ -45,7 +48,7 @@ AR -3124-06411 America/Argentina/Cordoba Argentina (most areas: CB, CC, CN, ER,
AR -2447-06525 America/Argentina/Salta Salta (SA, LP, NQ, RN) AR -2447-06525 America/Argentina/Salta Salta (SA, LP, NQ, RN)
AR -2411-06518 America/Argentina/Jujuy Jujuy (JY) AR -2411-06518 America/Argentina/Jujuy Jujuy (JY)
AR -2649-06513 America/Argentina/Tucuman Tucuman (TM) AR -2649-06513 America/Argentina/Tucuman Tucuman (TM)
AR -2828-06547 America/Argentina/Catamarca Catamarca (CT); Chubut (CH) AR -2828-06547 America/Argentina/Catamarca Catamarca (CT), Chubut (CH)
AR -2926-06651 America/Argentina/La_Rioja La Rioja (LR) AR -2926-06651 America/Argentina/La_Rioja La Rioja (LR)
AR -3132-06831 America/Argentina/San_Juan San Juan (SJ) AR -3132-06831 America/Argentina/San_Juan San Juan (SJ)
AR -3253-06849 America/Argentina/Mendoza Mendoza (MZ) AR -3253-06849 America/Argentina/Mendoza Mendoza (MZ)
@ -56,8 +59,7 @@ AS -1416-17042 Pacific/Pago_Pago
AT +4813+01620 Europe/Vienna AT +4813+01620 Europe/Vienna
AU -3133+15905 Australia/Lord_Howe Lord Howe Island AU -3133+15905 Australia/Lord_Howe Lord Howe Island
AU -5430+15857 Antarctica/Macquarie Macquarie Island AU -5430+15857 Antarctica/Macquarie Macquarie Island
AU -4253+14719 Australia/Hobart Tasmania (most areas) AU -4253+14719 Australia/Hobart Tasmania
AU -3956+14352 Australia/Currie Tasmania (King Island)
AU -3749+14458 Australia/Melbourne Victoria AU -3749+14458 Australia/Melbourne Victoria
AU -3352+15113 Australia/Sydney New South Wales (most areas) AU -3352+15113 Australia/Sydney New South Wales (most areas)
AU -3157+14127 Australia/Broken_Hill New South Wales (Yancowinna) AU -3157+14127 Australia/Broken_Hill New South Wales (Yancowinna)
@ -85,7 +87,7 @@ BN +0456+11455 Asia/Brunei
BO -1630-06809 America/La_Paz BO -1630-06809 America/La_Paz
BQ +120903-0681636 America/Kralendijk BQ +120903-0681636 America/Kralendijk
BR -0351-03225 America/Noronha Atlantic islands BR -0351-03225 America/Noronha Atlantic islands
BR -0127-04829 America/Belem Para (east); Amapa BR -0127-04829 America/Belem Para (east), Amapa
BR -0343-03830 America/Fortaleza Brazil (northeast: MA, PI, CE, RN, PB) BR -0343-03830 America/Fortaleza Brazil (northeast: MA, PI, CE, RN, PB)
BR -0803-03454 America/Recife Pernambuco BR -0803-03454 America/Recife Pernambuco
BR -0712-04812 America/Araguaina Tocantins BR -0712-04812 America/Araguaina Tocantins
@ -105,34 +107,29 @@ BT +2728+08939 Asia/Thimphu
BW -2439+02555 Africa/Gaborone BW -2439+02555 Africa/Gaborone
BY +5354+02734 Europe/Minsk BY +5354+02734 Europe/Minsk
BZ +1730-08812 America/Belize BZ +1730-08812 America/Belize
CA +4734-05243 America/St_Johns Newfoundland; Labrador (southeast) CA +4734-05243 America/St_Johns Newfoundland, Labrador (SE)
CA +4439-06336 America/Halifax Atlantic - NS (most areas); PE CA +4439-06336 America/Halifax Atlantic - NS (most areas), PE
CA +4612-05957 America/Glace_Bay Atlantic - NS (Cape Breton) CA +4612-05957 America/Glace_Bay Atlantic - NS (Cape Breton)
CA +4606-06447 America/Moncton Atlantic - New Brunswick CA +4606-06447 America/Moncton Atlantic - New Brunswick
CA +5320-06025 America/Goose_Bay Atlantic - Labrador (most areas) CA +5320-06025 America/Goose_Bay Atlantic - Labrador (most areas)
CA +5125-05707 America/Blanc-Sablon AST - QC (Lower North Shore) CA +5125-05707 America/Blanc-Sablon AST - QC (Lower North Shore)
CA +4339-07923 America/Toronto Eastern - ON, QC (most areas) CA +4339-07923 America/Toronto Eastern - ON & QC (most areas)
CA +4901-08816 America/Nipigon Eastern - ON, QC (no DST 1967-73) CA +6344-06828 America/Iqaluit Eastern - NU (most areas)
CA +4823-08915 America/Thunder_Bay Eastern - ON (Thunder Bay) CA +484531-0913718 America/Atikokan EST - ON (Atikokan), NU (Coral H)
CA +6344-06828 America/Iqaluit Eastern - NU (most east areas) CA +4953-09709 America/Winnipeg Central - ON (west), Manitoba
CA +6608-06544 America/Pangnirtung Eastern - NU (Pangnirtung)
CA +484531-0913718 America/Atikokan EST - ON (Atikokan); NU (Coral H)
CA +4953-09709 America/Winnipeg Central - ON (west); Manitoba
CA +4843-09434 America/Rainy_River Central - ON (Rainy R, Ft Frances)
CA +744144-0944945 America/Resolute Central - NU (Resolute) CA +744144-0944945 America/Resolute Central - NU (Resolute)
CA +624900-0920459 America/Rankin_Inlet Central - NU (central) CA +624900-0920459 America/Rankin_Inlet Central - NU (central)
CA +5024-10439 America/Regina CST - SK (most areas) CA +5024-10439 America/Regina CST - SK (most areas)
CA +5017-10750 America/Swift_Current CST - SK (midwest) CA +5017-10750 America/Swift_Current CST - SK (midwest)
CA +5333-11328 America/Edmonton Mountain - AB; BC (E); SK (W) CA +5333-11328 America/Edmonton Mountain - AB, BC(E), NT(E), SK(W)
CA +690650-1050310 America/Cambridge_Bay Mountain - NU (west) CA +690650-1050310 America/Cambridge_Bay Mountain - NU (west)
CA +6227-11421 America/Yellowknife Mountain - NT (central)
CA +682059-1334300 America/Inuvik Mountain - NT (west) CA +682059-1334300 America/Inuvik Mountain - NT (west)
CA +4906-11631 America/Creston MST - BC (Creston) CA +4906-11631 America/Creston MST - BC (Creston)
CA +5946-12014 America/Dawson_Creek MST - BC (Dawson Cr, Ft St John) CA +5546-12014 America/Dawson_Creek MST - BC (Dawson Cr, Ft St John)
CA +5848-12242 America/Fort_Nelson MST - BC (Ft Nelson) CA +5848-12242 America/Fort_Nelson MST - BC (Ft Nelson)
CA +6043-13503 America/Whitehorse MST - Yukon (east)
CA +6404-13925 America/Dawson MST - Yukon (west)
CA +4916-12307 America/Vancouver Pacific - BC (most areas) CA +4916-12307 America/Vancouver Pacific - BC (most areas)
CA +6043-13503 America/Whitehorse Pacific - Yukon (south)
CA +6404-13925 America/Dawson Pacific - Yukon (north)
CC -1210+09655 Indian/Cocos CC -1210+09655 Indian/Cocos
CD -0418+01518 Africa/Kinshasa Dem. Rep. of Congo (west) CD -0418+01518 Africa/Kinshasa Dem. Rep. of Congo (west)
CD -1140+02728 Africa/Lubumbashi Dem. Rep. of Congo (east) CD -1140+02728 Africa/Lubumbashi Dem. Rep. of Congo (east)
@ -141,7 +138,7 @@ CG -0416+01517 Africa/Brazzaville
CH +4723+00832 Europe/Zurich CH +4723+00832 Europe/Zurich
CI +0519-00402 Africa/Abidjan CI +0519-00402 Africa/Abidjan
CK -2114-15946 Pacific/Rarotonga CK -2114-15946 Pacific/Rarotonga
CL -3327-07040 America/Santiago Chile (most areas) CL -3327-07040 America/Santiago most of Chile
CL -5309-07055 America/Punta_Arenas Region of Magallanes CL -5309-07055 America/Punta_Arenas Region of Magallanes
CL -2709-10926 Pacific/Easter Easter Island CL -2709-10926 Pacific/Easter Easter Island
CM +0403+00942 Africa/Douala CM +0403+00942 Africa/Douala
@ -153,10 +150,10 @@ CU +2308-08222 America/Havana
CV +1455-02331 Atlantic/Cape_Verde CV +1455-02331 Atlantic/Cape_Verde
CW +1211-06900 America/Curacao CW +1211-06900 America/Curacao
CX -1025+10543 Indian/Christmas CX -1025+10543 Indian/Christmas
CY +3510+03322 Asia/Nicosia Cyprus (most areas) CY +3510+03322 Asia/Nicosia most of Cyprus
CY +3507+03357 Asia/Famagusta Northern Cyprus CY +3507+03357 Asia/Famagusta Northern Cyprus
CZ +5005+01426 Europe/Prague CZ +5005+01426 Europe/Prague
DE +5230+01322 Europe/Berlin Germany (most areas) DE +5230+01322 Europe/Berlin most of Germany
DE +4742+00841 Europe/Busingen Busingen DE +4742+00841 Europe/Busingen Busingen
DJ +1136+04309 Africa/Djibouti DJ +1136+04309 Africa/Djibouti
DK +5540+01235 Europe/Copenhagen DK +5540+01235 Europe/Copenhagen
@ -189,7 +186,7 @@ GF +0456-05220 America/Cayenne
GG +492717-0023210 Europe/Guernsey GG +492717-0023210 Europe/Guernsey
GH +0533-00013 Africa/Accra GH +0533-00013 Africa/Accra
GI +3608-00521 Europe/Gibraltar GI +3608-00521 Europe/Gibraltar
GL +6411-05144 America/Godthab Greenland (most areas) GL +6411-05144 America/Nuuk most of Greenland
GL +7646-01840 America/Danmarkshavn National Park (east coast) GL +7646-01840 America/Danmarkshavn National Park (east coast)
GL +7029-02158 America/Scoresbysund Scoresbysund/Ittoqqortoormiit GL +7029-02158 America/Scoresbysund Scoresbysund/Ittoqqortoormiit
GL +7634-06847 America/Thule Thule/Pituffik GL +7634-06847 America/Thule Thule/Pituffik
@ -210,8 +207,8 @@ HT +1832-07220 America/Port-au-Prince
HU +4730+01905 Europe/Budapest HU +4730+01905 Europe/Budapest
ID -0610+10648 Asia/Jakarta Java, Sumatra ID -0610+10648 Asia/Jakarta Java, Sumatra
ID -0002+10920 Asia/Pontianak Borneo (west, central) ID -0002+10920 Asia/Pontianak Borneo (west, central)
ID -0507+11924 Asia/Makassar Borneo (east, south); Sulawesi/Celebes, Bali, Nusa Tengarra; Timor (west) ID -0507+11924 Asia/Makassar Borneo (east, south), Sulawesi/Celebes, Bali, Nusa Tengarra, Timor (west)
ID -0232+14042 Asia/Jayapura New Guinea (West Papua / Irian Jaya); Malukus/Moluccas ID -0232+14042 Asia/Jayapura New Guinea (West Papua / Irian Jaya), Malukus/Moluccas
IE +5320-00615 Europe/Dublin IE +5320-00615 Europe/Dublin
IL +314650+0351326 Asia/Jerusalem IL +314650+0351326 Asia/Jerusalem
IM +5409-00428 Europe/Isle_of_Man IM +5409-00428 Europe/Isle_of_Man
@ -229,7 +226,7 @@ KE -0117+03649 Africa/Nairobi
KG +4254+07436 Asia/Bishkek KG +4254+07436 Asia/Bishkek
KH +1133+10455 Asia/Phnom_Penh KH +1133+10455 Asia/Phnom_Penh
KI +0125+17300 Pacific/Tarawa Gilbert Islands KI +0125+17300 Pacific/Tarawa Gilbert Islands
KI -0308-17105 Pacific/Enderbury Phoenix Islands KI -0247-17143 Pacific/Kanton Phoenix Islands
KI +0152-15720 Pacific/Kiritimati Line Islands KI +0152-15720 Pacific/Kiritimati Line Islands
KM -1141+04316 Indian/Comoro KM -1141+04316 Indian/Comoro
KN +1718-06243 America/St_Kitts KN +1718-06243 America/St_Kitts
@ -237,7 +234,7 @@ KP +3901+12545 Asia/Pyongyang
KR +3733+12658 Asia/Seoul KR +3733+12658 Asia/Seoul
KW +2920+04759 Asia/Kuwait KW +2920+04759 Asia/Kuwait
KY +1918-08123 America/Cayman KY +1918-08123 America/Cayman
KZ +4315+07657 Asia/Almaty Kazakhstan (most areas) KZ +4315+07657 Asia/Almaty most of Kazakhstan
KZ +4448+06528 Asia/Qyzylorda Qyzylorda/Kyzylorda/Kzyl-Orda KZ +4448+06528 Asia/Qyzylorda Qyzylorda/Kyzylorda/Kzyl-Orda
KZ +5312+06337 Asia/Qostanay Qostanay/Kostanay/Kustanay KZ +5312+06337 Asia/Qostanay Qostanay/Kostanay/Kustanay
KZ +5017+05710 Asia/Aqtobe Aqtobe/Aktobe KZ +5017+05710 Asia/Aqtobe Aqtobe/Aktobe
@ -261,14 +258,13 @@ MD +4700+02850 Europe/Chisinau
ME +4226+01916 Europe/Podgorica ME +4226+01916 Europe/Podgorica
MF +1804-06305 America/Marigot MF +1804-06305 America/Marigot
MG -1855+04731 Indian/Antananarivo MG -1855+04731 Indian/Antananarivo
MH +0709+17112 Pacific/Majuro Marshall Islands (most areas) MH +0709+17112 Pacific/Majuro most of Marshall Islands
MH +0905+16720 Pacific/Kwajalein Kwajalein MH +0905+16720 Pacific/Kwajalein Kwajalein
MK +4159+02126 Europe/Skopje MK +4159+02126 Europe/Skopje
ML +1239-00800 Africa/Bamako ML +1239-00800 Africa/Bamako
MM +1647+09610 Asia/Yangon MM +1647+09610 Asia/Yangon
MN +4755+10653 Asia/Ulaanbaatar Mongolia (most areas) MN +4755+10653 Asia/Ulaanbaatar most of Mongolia
MN +4801+09139 Asia/Hovd Bayan-Olgiy, Govi-Altai, Hovd, Uvs, Zavkhan MN +4801+09139 Asia/Hovd Bayan-Olgii, Hovd, Uvs
MN +4804+11430 Asia/Choibalsan Dornod, Sukhbaatar
MO +221150+1133230 Asia/Macau MO +221150+1133230 Asia/Macau
MP +1512+14545 Pacific/Saipan MP +1512+14545 Pacific/Saipan
MQ +1436-06105 America/Martinique MQ +1436-06105 America/Martinique
@ -278,17 +274,18 @@ MT +3554+01431 Europe/Malta
MU -2010+05730 Indian/Mauritius MU -2010+05730 Indian/Mauritius
MV +0410+07330 Indian/Maldives MV +0410+07330 Indian/Maldives
MW -1547+03500 Africa/Blantyre MW -1547+03500 Africa/Blantyre
MX +1924-09909 America/Mexico_City Central Time MX +1924-09909 America/Mexico_City Central Mexico
MX +2105-08646 America/Cancun Eastern Standard Time - Quintana Roo MX +2105-08646 America/Cancun Quintana Roo
MX +2058-08937 America/Merida Central Time - Campeche, Yucatan MX +2058-08937 America/Merida Campeche, Yucatan
MX +2540-10019 America/Monterrey Central Time - Durango; Coahuila, Nuevo Leon, Tamaulipas (most areas) MX +2540-10019 America/Monterrey Durango; Coahuila, Nuevo Leon, Tamaulipas (most areas)
MX +2550-09730 America/Matamoros Central Time US - Coahuila, Nuevo Leon, Tamaulipas (US border) MX +2550-09730 America/Matamoros Coahuila, Nuevo Leon, Tamaulipas (US border)
MX +2313-10625 America/Mazatlan Mountain Time - Baja California Sur, Nayarit, Sinaloa MX +2838-10605 America/Chihuahua Chihuahua (most areas)
MX +2838-10605 America/Chihuahua Mountain Time - Chihuahua (most areas) MX +3144-10629 America/Ciudad_Juarez Chihuahua (US border - west)
MX +2934-10425 America/Ojinaga Mountain Time US - Chihuahua (US border) MX +2934-10425 America/Ojinaga Chihuahua (US border - east)
MX +2904-11058 America/Hermosillo Mountain Standard Time - Sonora MX +2313-10625 America/Mazatlan Baja California Sur, Nayarit (most areas), Sinaloa
MX +3232-11701 America/Tijuana Pacific Time US - Baja California MX +2048-10515 America/Bahia_Banderas Bahia de Banderas
MX +2048-10515 America/Bahia_Banderas Central Time - Bahia de Banderas MX +2904-11058 America/Hermosillo Sonora
MX +3232-11701 America/Tijuana Baja California
MY +0310+10142 Asia/Kuala_Lumpur Malaysia (peninsula) MY +0310+10142 Asia/Kuala_Lumpur Malaysia (peninsula)
MY +0133+11020 Asia/Kuching Sabah, Sarawak MY +0133+11020 Asia/Kuching Sabah, Sarawak
MZ -2558+03235 Africa/Maputo MZ -2558+03235 Africa/Maputo
@ -303,7 +300,7 @@ NO +5955+01045 Europe/Oslo
NP +2743+08519 Asia/Kathmandu NP +2743+08519 Asia/Kathmandu
NR -0031+16655 Pacific/Nauru NR -0031+16655 Pacific/Nauru
NU -1901-16955 Pacific/Niue NU -1901-16955 Pacific/Niue
NZ -3652+17446 Pacific/Auckland New Zealand (most areas) NZ -3652+17446 Pacific/Auckland most of New Zealand
NZ -4357-17633 Pacific/Chatham Chatham Islands NZ -4357-17633 Pacific/Chatham Chatham Islands
OM +2336+05835 Asia/Muscat OM +2336+05835 Asia/Muscat
PA +0858-07932 America/Panama PA +0858-07932 America/Panama
@ -311,9 +308,9 @@ PE -1203-07703 America/Lima
PF -1732-14934 Pacific/Tahiti Society Islands PF -1732-14934 Pacific/Tahiti Society Islands
PF -0900-13930 Pacific/Marquesas Marquesas Islands PF -0900-13930 Pacific/Marquesas Marquesas Islands
PF -2308-13457 Pacific/Gambier Gambier Islands PF -2308-13457 Pacific/Gambier Gambier Islands
PG -0930+14710 Pacific/Port_Moresby Papua New Guinea (most areas) PG -0930+14710 Pacific/Port_Moresby most of Papua New Guinea
PG -0613+15534 Pacific/Bougainville Bougainville PG -0613+15534 Pacific/Bougainville Bougainville
PH +1435+12100 Asia/Manila PH +143512+1205804 Asia/Manila
PK +2452+06703 Asia/Karachi PK +2452+06703 Asia/Karachi
PL +5215+02100 Europe/Warsaw PL +5215+02100 Europe/Warsaw
PM +4703-05620 America/Miquelon PM +4703-05620 America/Miquelon
@ -332,10 +329,13 @@ RO +4426+02606 Europe/Bucharest
RS +4450+02030 Europe/Belgrade RS +4450+02030 Europe/Belgrade
RU +5443+02030 Europe/Kaliningrad MSK-01 - Kaliningrad RU +5443+02030 Europe/Kaliningrad MSK-01 - Kaliningrad
RU +554521+0373704 Europe/Moscow MSK+00 - Moscow area RU +554521+0373704 Europe/Moscow MSK+00 - Moscow area
RU +4457+03406 Europe/Simferopol MSK+00 - Crimea # The obsolescent zone.tab format cannot represent Europe/Simferopol well.
# Put it in RU section and list as UA. See "territorial claims" above.
# Programs should use zone1970.tab instead; see above.
UA +4457+03406 Europe/Simferopol Crimea
RU +5836+04939 Europe/Kirov MSK+00 - Kirov RU +5836+04939 Europe/Kirov MSK+00 - Kirov
RU +4844+04425 Europe/Volgograd MSK+00 - Volgograd
RU +4621+04803 Europe/Astrakhan MSK+01 - Astrakhan RU +4621+04803 Europe/Astrakhan MSK+01 - Astrakhan
RU +4844+04425 Europe/Volgograd MSK+01 - Volgograd
RU +5134+04602 Europe/Saratov MSK+01 - Saratov RU +5134+04602 Europe/Saratov MSK+01 - Saratov
RU +5420+04824 Europe/Ulyanovsk MSK+01 - Ulyanovsk RU +5420+04824 Europe/Ulyanovsk MSK+01 - Ulyanovsk
RU +5312+05009 Europe/Samara MSK+01 - Samara, Udmurtia RU +5312+05009 Europe/Samara MSK+01 - Samara, Udmurtia
@ -354,7 +354,7 @@ RU +4310+13156 Asia/Vladivostok MSK+07 - Amur River
RU +643337+1431336 Asia/Ust-Nera MSK+07 - Oymyakonsky RU +643337+1431336 Asia/Ust-Nera MSK+07 - Oymyakonsky
RU +5934+15048 Asia/Magadan MSK+08 - Magadan RU +5934+15048 Asia/Magadan MSK+08 - Magadan
RU +4658+14242 Asia/Sakhalin MSK+08 - Sakhalin Island RU +4658+14242 Asia/Sakhalin MSK+08 - Sakhalin Island
RU +6728+15343 Asia/Srednekolymsk MSK+08 - Sakha (E); North Kuril Is RU +6728+15343 Asia/Srednekolymsk MSK+08 - Sakha (E), N Kuril Is
RU +5301+15839 Asia/Kamchatka MSK+09 - Kamchatka RU +5301+15839 Asia/Kamchatka MSK+09 - Kamchatka
RU +6445+17729 Asia/Anadyr MSK+09 - Bering Sea RU +6445+17729 Asia/Anadyr MSK+09 - Bering Sea
RW -0157+03004 Africa/Kigali RW -0157+03004 Africa/Kigali
@ -389,15 +389,13 @@ TK -0922-17114 Pacific/Fakaofo
TL -0833+12535 Asia/Dili TL -0833+12535 Asia/Dili
TM +3757+05823 Asia/Ashgabat TM +3757+05823 Asia/Ashgabat
TN +3648+01011 Africa/Tunis TN +3648+01011 Africa/Tunis
TO -2110-17510 Pacific/Tongatapu TO -210800-1751200 Pacific/Tongatapu
TR +4101+02858 Europe/Istanbul TR +4101+02858 Europe/Istanbul
TT +1039-06131 America/Port_of_Spain TT +1039-06131 America/Port_of_Spain
TV -0831+17913 Pacific/Funafuti TV -0831+17913 Pacific/Funafuti
TW +2503+12130 Asia/Taipei TW +2503+12130 Asia/Taipei
TZ -0648+03917 Africa/Dar_es_Salaam TZ -0648+03917 Africa/Dar_es_Salaam
UA +5026+03031 Europe/Kiev Ukraine (most areas) UA +5026+03031 Europe/Kyiv most of Ukraine
UA +4837+02218 Europe/Uzhgorod Ruthenia
UA +4750+03510 Europe/Zaporozhye Zaporozh'ye/Zaporizhia; Lugansk/Luhansk (east)
UG +0019+03225 Africa/Kampala UG +0019+03225 Africa/Kampala
UM +2813-17722 Pacific/Midway Midway Islands UM +2813-17722 Pacific/Midway Midway Islands
UM +1917+16637 Pacific/Wake Wake Island UM +1917+16637 Pacific/Wake Wake Island
@ -419,8 +417,8 @@ US +470659-1011757 America/North_Dakota/Center Central - ND (Oliver)
US +465042-1012439 America/North_Dakota/New_Salem Central - ND (Morton rural) US +465042-1012439 America/North_Dakota/New_Salem Central - ND (Morton rural)
US +471551-1014640 America/North_Dakota/Beulah Central - ND (Mercer) US +471551-1014640 America/North_Dakota/Beulah Central - ND (Mercer)
US +394421-1045903 America/Denver Mountain (most areas) US +394421-1045903 America/Denver Mountain (most areas)
US +433649-1161209 America/Boise Mountain - ID (south); OR (east) US +433649-1161209 America/Boise Mountain - ID (south), OR (east)
US +332654-1120424 America/Phoenix MST - Arizona (except Navajo) US +332654-1120424 America/Phoenix MST - AZ (except Navajo)
US +340308-1181434 America/Los_Angeles Pacific US +340308-1181434 America/Los_Angeles Pacific
US +611305-1495401 America/Anchorage Alaska (most areas) US +611305-1495401 America/Anchorage Alaska (most areas)
US +581807-1342511 America/Juneau Alaska - Juneau area US +581807-1342511 America/Juneau Alaska - Juneau area
@ -428,7 +426,7 @@ US +571035-1351807 America/Sitka Alaska - Sitka area
US +550737-1313435 America/Metlakatla Alaska - Annette Island US +550737-1313435 America/Metlakatla Alaska - Annette Island
US +593249-1394338 America/Yakutat Alaska - Yakutat US +593249-1394338 America/Yakutat Alaska - Yakutat
US +643004-1652423 America/Nome Alaska (west) US +643004-1652423 America/Nome Alaska (west)
US +515248-1763929 America/Adak Aleutian Islands US +515248-1763929 America/Adak Alaska - western Aleutians
US +211825-1575130 Pacific/Honolulu Hawaii US +211825-1575130 Pacific/Honolulu Hawaii
UY -345433-0561245 America/Montevideo UY -345433-0561245 America/Montevideo
UZ +3940+06648 Asia/Samarkand Uzbekistan (west) UZ +3940+06648 Asia/Samarkand Uzbekistan (west)

22
plist
View File

@ -155,6 +155,7 @@
/usr/local/etc/rc.syshook.d/upgrade/20-unbound-duckdb.py /usr/local/etc/rc.syshook.d/upgrade/20-unbound-duckdb.py
/usr/local/etc/rc.syshook.d/upgrade/90-cleanup.sh /usr/local/etc/rc.syshook.d/upgrade/90-cleanup.sh
/usr/local/etc/ssh/sshd_config.d/README /usr/local/etc/ssh/sshd_config.d/README
/usr/local/etc/ssl/ext_sources/README
/usr/local/etc/ssl/opnsense.cnf /usr/local/etc/ssl/opnsense.cnf
/usr/local/etc/strongswan.opnsense.d/README /usr/local/etc/strongswan.opnsense.d/README
/usr/local/etc/unbound.opnsense.d/README /usr/local/etc/unbound.opnsense.d/README
@ -285,7 +286,6 @@
/usr/local/opnsense/mvc/app/controllers/OPNsense/Dnsmasq/LeasesController.php /usr/local/opnsense/mvc/app/controllers/OPNsense/Dnsmasq/LeasesController.php
/usr/local/opnsense/mvc/app/controllers/OPNsense/Dnsmasq/SettingsController.php /usr/local/opnsense/mvc/app/controllers/OPNsense/Dnsmasq/SettingsController.php
/usr/local/opnsense/mvc/app/controllers/OPNsense/Dnsmasq/forms/dialogDHCPboot.xml /usr/local/opnsense/mvc/app/controllers/OPNsense/Dnsmasq/forms/dialogDHCPboot.xml
/usr/local/opnsense/mvc/app/controllers/OPNsense/Dnsmasq/forms/dialogDHCPmatch.xml
/usr/local/opnsense/mvc/app/controllers/OPNsense/Dnsmasq/forms/dialogDHCPoption.xml /usr/local/opnsense/mvc/app/controllers/OPNsense/Dnsmasq/forms/dialogDHCPoption.xml
/usr/local/opnsense/mvc/app/controllers/OPNsense/Dnsmasq/forms/dialogDHCPrange.xml /usr/local/opnsense/mvc/app/controllers/OPNsense/Dnsmasq/forms/dialogDHCPrange.xml
/usr/local/opnsense/mvc/app/controllers/OPNsense/Dnsmasq/forms/dialogDHCPtag.xml /usr/local/opnsense/mvc/app/controllers/OPNsense/Dnsmasq/forms/dialogDHCPtag.xml
@ -360,6 +360,7 @@
/usr/local/opnsense/mvc/app/controllers/OPNsense/IPsec/forms/dialogSPD.xml /usr/local/opnsense/mvc/app/controllers/OPNsense/IPsec/forms/dialogSPD.xml
/usr/local/opnsense/mvc/app/controllers/OPNsense/IPsec/forms/dialogVTI.xml /usr/local/opnsense/mvc/app/controllers/OPNsense/IPsec/forms/dialogVTI.xml
/usr/local/opnsense/mvc/app/controllers/OPNsense/IPsec/forms/settings.xml /usr/local/opnsense/mvc/app/controllers/OPNsense/IPsec/forms/settings.xml
/usr/local/opnsense/mvc/app/controllers/OPNsense/Interfaces/Api/BridgeSettingsController.php
/usr/local/opnsense/mvc/app/controllers/OPNsense/Interfaces/Api/GifSettingsController.php /usr/local/opnsense/mvc/app/controllers/OPNsense/Interfaces/Api/GifSettingsController.php
/usr/local/opnsense/mvc/app/controllers/OPNsense/Interfaces/Api/GreSettingsController.php /usr/local/opnsense/mvc/app/controllers/OPNsense/Interfaces/Api/GreSettingsController.php
/usr/local/opnsense/mvc/app/controllers/OPNsense/Interfaces/Api/LaggSettingsController.php /usr/local/opnsense/mvc/app/controllers/OPNsense/Interfaces/Api/LaggSettingsController.php
@ -369,6 +370,7 @@
/usr/local/opnsense/mvc/app/controllers/OPNsense/Interfaces/Api/VipSettingsController.php /usr/local/opnsense/mvc/app/controllers/OPNsense/Interfaces/Api/VipSettingsController.php
/usr/local/opnsense/mvc/app/controllers/OPNsense/Interfaces/Api/VlanSettingsController.php /usr/local/opnsense/mvc/app/controllers/OPNsense/Interfaces/Api/VlanSettingsController.php
/usr/local/opnsense/mvc/app/controllers/OPNsense/Interfaces/Api/VxlanSettingsController.php /usr/local/opnsense/mvc/app/controllers/OPNsense/Interfaces/Api/VxlanSettingsController.php
/usr/local/opnsense/mvc/app/controllers/OPNsense/Interfaces/BridgeController.php
/usr/local/opnsense/mvc/app/controllers/OPNsense/Interfaces/GifController.php /usr/local/opnsense/mvc/app/controllers/OPNsense/Interfaces/GifController.php
/usr/local/opnsense/mvc/app/controllers/OPNsense/Interfaces/GreController.php /usr/local/opnsense/mvc/app/controllers/OPNsense/Interfaces/GreController.php
/usr/local/opnsense/mvc/app/controllers/OPNsense/Interfaces/LaggController.php /usr/local/opnsense/mvc/app/controllers/OPNsense/Interfaces/LaggController.php
@ -378,6 +380,7 @@
/usr/local/opnsense/mvc/app/controllers/OPNsense/Interfaces/VipController.php /usr/local/opnsense/mvc/app/controllers/OPNsense/Interfaces/VipController.php
/usr/local/opnsense/mvc/app/controllers/OPNsense/Interfaces/VlanController.php /usr/local/opnsense/mvc/app/controllers/OPNsense/Interfaces/VlanController.php
/usr/local/opnsense/mvc/app/controllers/OPNsense/Interfaces/VxlanController.php /usr/local/opnsense/mvc/app/controllers/OPNsense/Interfaces/VxlanController.php
/usr/local/opnsense/mvc/app/controllers/OPNsense/Interfaces/forms/dialogBridge.xml
/usr/local/opnsense/mvc/app/controllers/OPNsense/Interfaces/forms/dialogGif.xml /usr/local/opnsense/mvc/app/controllers/OPNsense/Interfaces/forms/dialogGif.xml
/usr/local/opnsense/mvc/app/controllers/OPNsense/Interfaces/forms/dialogGre.xml /usr/local/opnsense/mvc/app/controllers/OPNsense/Interfaces/forms/dialogGre.xml
/usr/local/opnsense/mvc/app/controllers/OPNsense/Interfaces/forms/dialogLagg.xml /usr/local/opnsense/mvc/app/controllers/OPNsense/Interfaces/forms/dialogLagg.xml
@ -388,14 +391,20 @@
/usr/local/opnsense/mvc/app/controllers/OPNsense/Interfaces/forms/dialogVxlan.xml /usr/local/opnsense/mvc/app/controllers/OPNsense/Interfaces/forms/dialogVxlan.xml
/usr/local/opnsense/mvc/app/controllers/OPNsense/Kea/Api/CtrlAgentController.php /usr/local/opnsense/mvc/app/controllers/OPNsense/Kea/Api/CtrlAgentController.php
/usr/local/opnsense/mvc/app/controllers/OPNsense/Kea/Api/Dhcpv4Controller.php /usr/local/opnsense/mvc/app/controllers/OPNsense/Kea/Api/Dhcpv4Controller.php
/usr/local/opnsense/mvc/app/controllers/OPNsense/Kea/Api/Dhcpv6Controller.php
/usr/local/opnsense/mvc/app/controllers/OPNsense/Kea/Api/Leases4Controller.php /usr/local/opnsense/mvc/app/controllers/OPNsense/Kea/Api/Leases4Controller.php
/usr/local/opnsense/mvc/app/controllers/OPNsense/Kea/Api/ServiceController.php /usr/local/opnsense/mvc/app/controllers/OPNsense/Kea/Api/ServiceController.php
/usr/local/opnsense/mvc/app/controllers/OPNsense/Kea/DhcpController.php /usr/local/opnsense/mvc/app/controllers/OPNsense/Kea/DhcpController.php
/usr/local/opnsense/mvc/app/controllers/OPNsense/Kea/forms/agentSettings.xml /usr/local/opnsense/mvc/app/controllers/OPNsense/Kea/forms/agentSettings.xml
/usr/local/opnsense/mvc/app/controllers/OPNsense/Kea/forms/dialogPDPool6.xml
/usr/local/opnsense/mvc/app/controllers/OPNsense/Kea/forms/dialogPeer4.xml /usr/local/opnsense/mvc/app/controllers/OPNsense/Kea/forms/dialogPeer4.xml
/usr/local/opnsense/mvc/app/controllers/OPNsense/Kea/forms/dialogPeer6.xml
/usr/local/opnsense/mvc/app/controllers/OPNsense/Kea/forms/dialogReservation4.xml /usr/local/opnsense/mvc/app/controllers/OPNsense/Kea/forms/dialogReservation4.xml
/usr/local/opnsense/mvc/app/controllers/OPNsense/Kea/forms/dialogReservation6.xml
/usr/local/opnsense/mvc/app/controllers/OPNsense/Kea/forms/dialogSubnet4.xml /usr/local/opnsense/mvc/app/controllers/OPNsense/Kea/forms/dialogSubnet4.xml
/usr/local/opnsense/mvc/app/controllers/OPNsense/Kea/forms/dialogSubnet6.xml
/usr/local/opnsense/mvc/app/controllers/OPNsense/Kea/forms/generalSettings4.xml /usr/local/opnsense/mvc/app/controllers/OPNsense/Kea/forms/generalSettings4.xml
/usr/local/opnsense/mvc/app/controllers/OPNsense/Kea/forms/generalSettings6.xml
/usr/local/opnsense/mvc/app/controllers/OPNsense/Monit/Api/ServiceController.php /usr/local/opnsense/mvc/app/controllers/OPNsense/Monit/Api/ServiceController.php
/usr/local/opnsense/mvc/app/controllers/OPNsense/Monit/Api/SettingsController.php /usr/local/opnsense/mvc/app/controllers/OPNsense/Monit/Api/SettingsController.php
/usr/local/opnsense/mvc/app/controllers/OPNsense/Monit/Api/StatusController.php /usr/local/opnsense/mvc/app/controllers/OPNsense/Monit/Api/StatusController.php
@ -752,6 +761,9 @@
/usr/local/opnsense/mvc/app/models/OPNsense/IPsec/Swanctl.php /usr/local/opnsense/mvc/app/models/OPNsense/IPsec/Swanctl.php
/usr/local/opnsense/mvc/app/models/OPNsense/IPsec/Swanctl.xml /usr/local/opnsense/mvc/app/models/OPNsense/IPsec/Swanctl.xml
/usr/local/opnsense/mvc/app/models/OPNsense/Interfaces/ACL/ACL.xml /usr/local/opnsense/mvc/app/models/OPNsense/Interfaces/ACL/ACL.xml
/usr/local/opnsense/mvc/app/models/OPNsense/Interfaces/Bridge.php
/usr/local/opnsense/mvc/app/models/OPNsense/Interfaces/Bridge.xml
/usr/local/opnsense/mvc/app/models/OPNsense/Interfaces/FieldTypes/BridgeMemberField.php
/usr/local/opnsense/mvc/app/models/OPNsense/Interfaces/FieldTypes/LaggInterfaceField.php /usr/local/opnsense/mvc/app/models/OPNsense/Interfaces/FieldTypes/LaggInterfaceField.php
/usr/local/opnsense/mvc/app/models/OPNsense/Interfaces/FieldTypes/LinkAddressField.php /usr/local/opnsense/mvc/app/models/OPNsense/Interfaces/FieldTypes/LinkAddressField.php
/usr/local/opnsense/mvc/app/models/OPNsense/Interfaces/FieldTypes/NeighborField.php /usr/local/opnsense/mvc/app/models/OPNsense/Interfaces/FieldTypes/NeighborField.php
@ -783,6 +795,8 @@
/usr/local/opnsense/mvc/app/models/OPNsense/Kea/KeaCtrlAgent.xml /usr/local/opnsense/mvc/app/models/OPNsense/Kea/KeaCtrlAgent.xml
/usr/local/opnsense/mvc/app/models/OPNsense/Kea/KeaDhcpv4.php /usr/local/opnsense/mvc/app/models/OPNsense/Kea/KeaDhcpv4.php
/usr/local/opnsense/mvc/app/models/OPNsense/Kea/KeaDhcpv4.xml /usr/local/opnsense/mvc/app/models/OPNsense/Kea/KeaDhcpv4.xml
/usr/local/opnsense/mvc/app/models/OPNsense/Kea/KeaDhcpv6.php
/usr/local/opnsense/mvc/app/models/OPNsense/Kea/KeaDhcpv6.xml
/usr/local/opnsense/mvc/app/models/OPNsense/Kea/Menu/Menu.xml /usr/local/opnsense/mvc/app/models/OPNsense/Kea/Menu/Menu.xml
/usr/local/opnsense/mvc/app/models/OPNsense/Monit/ACL/ACL.xml /usr/local/opnsense/mvc/app/models/OPNsense/Monit/ACL/ACL.xml
/usr/local/opnsense/mvc/app/models/OPNsense/Monit/Menu/Menu.xml /usr/local/opnsense/mvc/app/models/OPNsense/Monit/Menu/Menu.xml
@ -915,6 +929,7 @@
/usr/local/opnsense/mvc/app/views/OPNsense/IPsec/spd.volt /usr/local/opnsense/mvc/app/views/OPNsense/IPsec/spd.volt
/usr/local/opnsense/mvc/app/views/OPNsense/IPsec/tunnels.volt /usr/local/opnsense/mvc/app/views/OPNsense/IPsec/tunnels.volt
/usr/local/opnsense/mvc/app/views/OPNsense/IPsec/vti.volt /usr/local/opnsense/mvc/app/views/OPNsense/IPsec/vti.volt
/usr/local/opnsense/mvc/app/views/OPNsense/Interface/bridge.volt
/usr/local/opnsense/mvc/app/views/OPNsense/Interface/gif.volt /usr/local/opnsense/mvc/app/views/OPNsense/Interface/gif.volt
/usr/local/opnsense/mvc/app/views/OPNsense/Interface/gre.volt /usr/local/opnsense/mvc/app/views/OPNsense/Interface/gre.volt
/usr/local/opnsense/mvc/app/views/OPNsense/Interface/lagg.volt /usr/local/opnsense/mvc/app/views/OPNsense/Interface/lagg.volt
@ -926,6 +941,7 @@
/usr/local/opnsense/mvc/app/views/OPNsense/Interface/vxlan.volt /usr/local/opnsense/mvc/app/views/OPNsense/Interface/vxlan.volt
/usr/local/opnsense/mvc/app/views/OPNsense/Kea/ctrl_agent.volt /usr/local/opnsense/mvc/app/views/OPNsense/Kea/ctrl_agent.volt
/usr/local/opnsense/mvc/app/views/OPNsense/Kea/dhcpv4.volt /usr/local/opnsense/mvc/app/views/OPNsense/Kea/dhcpv4.volt
/usr/local/opnsense/mvc/app/views/OPNsense/Kea/dhcpv6.volt
/usr/local/opnsense/mvc/app/views/OPNsense/Kea/leases4.volt /usr/local/opnsense/mvc/app/views/OPNsense/Kea/leases4.volt
/usr/local/opnsense/mvc/app/views/OPNsense/Monit/index.volt /usr/local/opnsense/mvc/app/views/OPNsense/Monit/index.volt
/usr/local/opnsense/mvc/app/views/OPNsense/Monit/status.volt /usr/local/opnsense/mvc/app/views/OPNsense/Monit/status.volt
@ -1175,6 +1191,7 @@
/usr/local/opnsense/scripts/interfaces/ppp-linkup.sh /usr/local/opnsense/scripts/interfaces/ppp-linkup.sh
/usr/local/opnsense/scripts/interfaces/ppp-rename.sh /usr/local/opnsense/scripts/interfaces/ppp-rename.sh
/usr/local/opnsense/scripts/interfaces/ppp-uptime.sh /usr/local/opnsense/scripts/interfaces/ppp-uptime.sh
/usr/local/opnsense/scripts/interfaces/reconfigure_bridges.php
/usr/local/opnsense/scripts/interfaces/reconfigure_gifs.php /usr/local/opnsense/scripts/interfaces/reconfigure_gifs.php
/usr/local/opnsense/scripts/interfaces/reconfigure_gres.php /usr/local/opnsense/scripts/interfaces/reconfigure_gres.php
/usr/local/opnsense/scripts/interfaces/reconfigure_laggs.php /usr/local/opnsense/scripts/interfaces/reconfigure_laggs.php
@ -1270,6 +1287,7 @@
/usr/local/opnsense/scripts/syslog/streamLog.py /usr/local/opnsense/scripts/syslog/streamLog.py
/usr/local/opnsense/scripts/system/activity.py /usr/local/opnsense/scripts/system/activity.py
/usr/local/opnsense/scripts/system/bectl.py /usr/local/opnsense/scripts/system/bectl.py
/usr/local/opnsense/scripts/system/cert_fetch_local.py
/usr/local/opnsense/scripts/system/certctl.py /usr/local/opnsense/scripts/system/certctl.py
/usr/local/opnsense/scripts/system/cpu.py /usr/local/opnsense/scripts/system/cpu.py
/usr/local/opnsense/scripts/system/crl_fetch.py /usr/local/opnsense/scripts/system/crl_fetch.py
@ -2403,8 +2421,6 @@
/usr/local/www/index.php /usr/local/www/index.php
/usr/local/www/interfaces.php /usr/local/www/interfaces.php
/usr/local/www/interfaces_assign.php /usr/local/www/interfaces_assign.php
/usr/local/www/interfaces_bridge.php
/usr/local/www/interfaces_bridge_edit.php
/usr/local/www/interfaces_ppps.php /usr/local/www/interfaces_ppps.php
/usr/local/www/interfaces_ppps_edit.php /usr/local/www/interfaces_ppps_edit.php
/usr/local/www/interfaces_wireless.php /usr/local/www/interfaces_wireless.php

View File

@ -81,9 +81,6 @@
<track6-prefix-id>0</track6-prefix-id> <track6-prefix-id>0</track6-prefix-id>
</lan> </lan>
</interfaces> </interfaces>
<unbound>
<enable>1</enable>
</unbound>
<dnsmasq> <dnsmasq>
<enable>1</enable> <enable>1</enable>
<port>0</port> <port>0</port>
@ -94,6 +91,9 @@
<end_addr>192.168.1.199</end_addr> <end_addr>192.168.1.199</end_addr>
</dhcp_ranges> </dhcp_ranges>
</dnsmasq> </dnsmasq>
<unbound>
<enable>1</enable>
</unbound>
<snmpd> <snmpd>
<syslocation/> <syslocation/>
<syscontact/> <syscontact/>

View File

@ -49,13 +49,9 @@ $userindex = index_users();
*/ */
function isAuthLocalIP($http_host) function isAuthLocalIP($http_host)
{ {
global $config; foreach (config_read_array('virtualip', 'vip') as $vip) {
if ($vip['subnet'] == $http_host) {
if (isset($config['virtualip']['vip'])) { return true;
foreach ($config['virtualip']['vip'] as $vip) {
if ($vip['subnet'] == $http_host) {
return true;
}
} }
} }

View File

@ -107,6 +107,9 @@ function ca_chain_array(&$cert)
$crt = false; $crt = false;
} }
if ($crt) { if ($crt) {
if (in_array($crt, $chain)) {
break; /* exit endless loop */
}
$chain[] = $crt; $chain[] = $crt;
} }
} }
@ -192,25 +195,6 @@ function cert_get_subject($str_crt, $decode = true)
return certs_build_name($components); return certs_build_name($components);
} }
function cert_get_subject_array($crt)
{
$str_crt = base64_decode($crt);
$inf_crt = openssl_x509_parse($str_crt);
$components = $inf_crt['subject'];
if (!is_array($components)) {
return;
}
$subject_array = array();
foreach ($components as $a => $v) {
$subject_array[] = array('a' => $a, 'v' => $v);
}
return $subject_array;
}
function cert_get_issuer($str_crt, $decode = true) function cert_get_issuer($str_crt, $decode = true)
{ {
if ($decode) { if ($decode) {

View File

@ -256,25 +256,6 @@ function write_config($desc = '', $backup = true)
return $config; return $config;
} }
function config_restore($conffile)
{
global $config;
if (!file_exists($conffile)) {
return 1;
}
$cnf = OPNsense\Core\Config::getInstance();
$cnf->backup();
$cnf->restoreBackup($conffile);
$config = parse_config();
write_config(sprintf('Reverted to %s', array_pop(explode('/', $conffile))), false);
return 0;
}
function &config_read_array() function &config_read_array()
{ {
global $config; global $config;

View File

@ -205,122 +205,106 @@ function interfaces_bridge_configure($device)
return null; return null;
} }
function _interfaces_bridge_configure($bridge) function _interfaces_bridge_configure($bridge, $ifconfig_details = null)
{ {
$ret = $bridge['bridgeif']; $bridgeif = $bridge['bridgeif'];
/* XXX avoid destroy/create */ if (empty($ifconfig_details)) {
legacy_interface_destroy($bridge['bridgeif']); $ifconfig_details = legacy_interfaces_details();
legacy_interface_create($bridge['bridgeif']); }
$this_if = !empty($ifconfig_details[$bridgeif]) ? $ifconfig_details[$bridgeif] : [];
$checklist = get_configured_interface_with_descr(); if (empty($ifconfig_details[$bridgeif]) && empty(legacy_interface_create($bridgeif))) {
$members = []; /* not found, unable to create. errors are logged inside legacy_interface_create() */
return null;
}
/* find all required members */ /* find all required members */
$members = [];
foreach (explode(',', $bridge['members'] ?? '') as $member) { foreach (explode(',', $bridge['members'] ?? '') as $member) {
if (empty($checklist[$member])) {
/* ignores disabled ones */
continue;
}
$device = get_real_interface($member); $device = get_real_interface($member);
if (!does_interface_exist($device)) { if (empty($ifconfig_details[$device])) {
log_msg("Device {$bridge['bridgeif']} cannot attach non-existent member {$device}, skipping now."); log_msg("Device {$bridgeif} cannot attach non-existent member {$device}, skipping now.");
/* continue but mark this as failed for caller so they could retry */
$ret = null;
continue; continue;
} }
$members[$member] = $device; $members[$member] = $device;
} }
/* calculate smaller mtu and enforce it */ if (
$mtu = null; empty($this_if) || empty($this_if['nd6']) ||
foreach ($members as $member => $device) { in_array('AUTO_LINKLOCAL', $this_if['nd6']['flags']) != !empty($bridge['linklocal'])
$opts = legacy_interface_stats($device); ) {
if (!empty($opts['mtu']) && ($mtu == null || $opts['mtu'] < $mtu)) { mwexecf('/sbin/ifconfig %s inet6 %sauto_linklocal', [$bridgeif, !empty($bridge['linklocal']) ? '' : '-']);
$mtu = $opts['mtu'];
}
} }
mwexecf('/sbin/ifconfig %s inet6 %sauto_linklocal', [$bridge['bridgeif'], isset($bridge['linklocal']) ? '' : '-']);
/* add member interfaces to bridge */ /* add member interfaces to bridge */
$current_members = !empty($this_if['members']) ? $this_if['members'] : [];
foreach ($members as $member => $device) { foreach ($members as $member => $device) {
configure_interface_hardware($device); if (empty($current_members[$device])) {
legacy_interface_mtu($device, $mtu); configure_interface_hardware($device, $ifconfig_details);
legacy_interface_flags($device, 'up'); legacy_interface_flags($device, 'up');
legacy_bridge_member($bridge['bridgeif'], $device); legacy_bridge_member($bridgeif, $device);
}
} }
if (isset($bridge['enablestp'])) { /* remove unassigned members */
mwexecf('/sbin/ifconfig %s proto %s', [$bridge['bridgeif'], $bridge['proto']]); foreach (array_keys($current_members) as $device) {
if (!empty($bridge['stp'])) { if (!in_array($device, $members)) {
foreach (explode(',', $bridge['stp']) as $stpif) { mwexecf('/sbin/ifconfig %s deletem %s', [$bridgeif, $device]);
mwexecf('/sbin/ifconfig %s stp %s', [$bridge['bridgeif'], get_real_interface($stpif)]); }
}
/* compare and apply requested flags */
foreach (['stp', 'edge', 'autoedge', 'ptp', 'autoptp', 'static', 'private', 'span'] as $section) {
$section_members = explode(',', $bridge[$section] ?? '');
foreach ($members as $member => $device) {
$flag = $section == 'static' ? 'sticky' : $section;
if (
str_starts_with($section, 'auto') && (
!isset($current_members[$device]) ||
in_array($flag, $current_members[$device]['flags']) == in_array($member, $section_members)
)
) {
/* in list equals off for tags starting with "auto" */
mwexecf(sprintf(
"/sbin/ifconfig %s %s %s",
$bridgeif,
(in_array($member, $section_members) ? '-' : '') . $flag,
$device
));
} elseif (
!str_starts_with($section, 'auto') && (
!isset($current_members[$device]) ||
in_array($flag, $current_members[$device]['flags']) != in_array($member, $section_members)
)
) {
mwexecf(sprintf(
"/sbin/ifconfig %s %s %s",
$bridgeif,
(!in_array($member, $section_members) ? '-' : '') . $flag,
$device
));
} }
} }
if (!empty($bridge['maxage'])) { }
mwexec("/sbin/ifconfig {$bridge['bridgeif']} maxage " . escapeshellarg($bridge['maxage']));
} /* update changed bridge properties */
if (!empty($bridge['fwdelay'])) { foreach (['maxage', 'fwddelay', 'holdcnt', 'maxaddr', 'timeout', 'proto'] as $prop) {
mwexec("/sbin/ifconfig {$bridge['bridgeif']} fwddelay " . escapeshellarg($bridge['fwdelay'])); if (!empty($bridge[$prop]) && (empty($this_if[$prop]) || $this_if[$prop] != $bridge[$prop])) {
} mwexecf(sprintf(
if (!empty($bridge['holdcnt'])) { "/sbin/ifconfig %s %s %s",
mwexec("/sbin/ifconfig {$bridge['bridgeif']} holdcnt " . escapeshellarg($bridge['holdcnt'])); $bridgeif,
$prop,
$bridge[$prop]
));
} }
} }
if (!empty($bridge['maxaddr'])) { if (empty($this_if['flags']) || !in_array('up', $this_if['flags'])) {
mwexec("/sbin/ifconfig {$bridge['bridgeif']} maxaddr " . escapeshellarg($bridge['maxaddr'])); legacy_interface_flags($bridgeif, 'up');
}
if (!empty($bridge['timeout'])) {
mwexec("/sbin/ifconfig {$bridge['bridgeif']} timeout " . escapeshellarg($bridge['timeout']));
}
if (!empty($bridge['span'])) {
$realif = get_real_interface($bridge['span']);
mwexec("/sbin/ifconfig {$bridge['bridgeif']} span {$realif}");
}
if (!empty($bridge['edge'])) {
foreach (explode(',', $bridge['edge']) as $edgeif) {
$realif = get_real_interface($edgeif);
mwexec("/sbin/ifconfig {$bridge['bridgeif']} edge {$realif}");
}
}
if (!empty($bridge['autoedge'])) {
foreach (explode(',', $bridge['autoedge']) as $edgeif) {
$realif = get_real_interface($edgeif);
mwexec("/sbin/ifconfig {$bridge['bridgeif']} -autoedge {$realif}");
}
}
if (!empty($bridge['ptp'])) {
foreach (explode(',', $bridge['ptp']) as $ptpif) {
$realif = get_real_interface($ptpif);
mwexec("/sbin/ifconfig {$bridge['bridgeif']} ptp {$realif}");
}
}
if (!empty($bridge['autoptp'])) {
foreach (explode(',', $bridge['autoptp']) as $ptpif) {
$realif = get_real_interface($ptpif);
mwexec("/sbin/ifconfig {$bridge['bridgeif']} -autoptp {$realif}");
}
}
if (!empty($bridge['static'])) {
foreach (explode(',', $bridge['static']) as $stickyif) {
$realif = get_real_interface($stickyif);
mwexec("/sbin/ifconfig {$bridge['bridgeif']} sticky {$realif}");
}
}
if (!empty($bridge['private'])) {
foreach (explode(',', $bridge['private']) as $privateif) {
$realif = get_real_interface($privateif);
mwexec("/sbin/ifconfig {$bridge['bridgeif']} private {$realif}");
}
} }
legacy_interface_flags($bridge['bridgeif'], 'up'); return $bridgeif;
return $ret;
} }
function interfaces_lagg_configure($verbose = false) function interfaces_lagg_configure($verbose = false)
@ -3325,9 +3309,9 @@ function DHCP_Config_File_Advanced($interface, $wancfg, $wanif)
$option_modifiers = ""; $option_modifiers = "";
if ($wancfg['adv_dhcp_option_modifiers'] != '') { if ($wancfg['adv_dhcp_option_modifiers'] != '') {
$modifiers = preg_split('/\s*,\s*(?=(?:[^"]*"[^"]*")*[^"]*$)/', $wancfg['adv_dhcp_option_modifiers']); $modifiers = preg_split('/\s*(?<!\\\),\s*(?=(?:[^"]*"[^"]*")*[^"]*$)/', $wancfg['adv_dhcp_option_modifiers']);
foreach ($modifiers as $modifier) { foreach ($modifiers as $modifier) {
$option_modifiers .= "\t" . $modifier . ";\n"; $option_modifiers .= "\t" . str_replace('\,', ',', $modifier) . ";\n";
} }
} }
@ -3679,39 +3663,34 @@ function link_interface_to_bridge($interface, $attach_device = null, $ifconfig_d
function link_interface_to_gre($interface, $update = false, $family = null) function link_interface_to_gre($interface, $update = false, $family = null)
{ {
global $config;
$aliaslist = get_configured_ip_aliases_list();
$result = []; $result = [];
if (isset($config['gres']['gre'])) { foreach (config_read_array('gres', 'gre') as $gre) {
foreach ($config['gres']['gre'] as $gre) { $parent = explode('_vip', $gre['if'])[0];
$parent = explode('_vip', $gre['if'])[0]; if (is_ipaddr($parent)) {
if (is_ipaddr($parent)) { foreach (config_read_array('virtualip', 'vip') as $vip) {
foreach ($aliaslist as $ip => $int) { if ($vip['mode'] == 'ipalias' && $vip['subnet'] == $parent) {
if ($ip == $parent) { $parent = $vip['interface'];
$parent = $int; break;
break;
}
} }
} }
if ($parent != $interface) {
continue;
} elseif ($family == 4 && !is_ipaddrv4($gre['remote-addr'])) {
continue;
} elseif ($family == 6 && !is_ipaddrv6($gre['remote-addr'])) {
continue;
}
if ($update && empty(_interfaces_gre_configure($gre))) {
/* only return the ones that did configure correctly */
continue;
}
/* callers are only concerned with the resulting device names */
$result[] = $gre['greif'];
} }
if ($parent != $interface) {
continue;
} elseif ($family == 4 && !is_ipaddrv4($gre['remote-addr'])) {
continue;
} elseif ($family == 6 && !is_ipaddrv6($gre['remote-addr'])) {
continue;
}
if ($update && empty(_interfaces_gre_configure($gre))) {
/* only return the ones that did configure correctly */
continue;
}
/* callers are only concerned with the resulting device names */
$result[] = $gre['greif'];
} }
return $result; return $result;
@ -3719,28 +3698,24 @@ function link_interface_to_gre($interface, $update = false, $family = null)
function link_interface_to_gif($interface, $update = false, $family = null) function link_interface_to_gif($interface, $update = false, $family = null)
{ {
global $config;
$result = []; $result = [];
if (isset($config['gifs']['gif'])) { foreach (config_read_array('gifs', 'gif') as $gif) {
foreach ($config['gifs']['gif'] as $gif) { if (explode('_vip', $gif['if'])[0] != $interface) {
if (explode('_vip', $gif['if'])[0] != $interface) { continue;
continue; } elseif ($family == 4 && !is_ipaddrv4($gif['remote-addr'])) {
} elseif ($family == 4 && !is_ipaddrv4($gif['remote-addr'])) { continue;
continue; } elseif ($family == 6 && !is_ipaddrv6($gif['remote-addr'])) {
} elseif ($family == 6 && !is_ipaddrv6($gif['remote-addr'])) { continue;
continue;
}
if ($update && empty(_interfaces_gif_configure($gif))) {
/* only return the ones that did configure correctly */
continue;
}
/* callers are only concerned with the resulting device names */
$result[] = $gif['gifif'];
} }
if ($update && empty(_interfaces_gif_configure($gif))) {
/* only return the ones that did configure correctly */
continue;
}
/* callers are only concerned with the resulting device names */
$result[] = $gif['gifif'];
} }
return $result; return $result;
@ -3838,19 +3813,6 @@ function get_interface_mac($interface, $ifconfig_details = null)
return $intf_details['macaddr']; return $intf_details['macaddr'];
} }
function get_vip_descr($ipaddress)
{
global $config;
foreach ($config['virtualip']['vip'] as $vip) {
if ($vip['subnet'] == $ipaddress) {
return ($vip['descr'] ?? '');
}
}
return '';
}
function interfaces_staticarp_configure($if, $ifconfig_details = null) function interfaces_staticarp_configure($if, $ifconfig_details = null)
{ {
global $config; global $config;

View File

@ -501,6 +501,27 @@ function legacy_interfaces_details($intf = null)
$result[$current_interface]['vxlan']['group'] = null; $result[$current_interface]['vxlan']['group'] = null;
$result[$current_interface]["vxlan"]["remote"] = $line_parts[6]; $result[$current_interface]["vxlan"]["remote"] = $line_parts[6];
} }
} elseif (preg_match("/member: (.*)\Wflags=\w+<(.*)>.*/", $line, $matches)) {
if (empty($result[$current_interface]["members"])) {
$result[$current_interface]["members"] = [];
}
$result[$current_interface]["members"][$matches[1]] = [
"flags" => explode(",", strtolower($matches[2]))
];
} elseif (preg_match("/\tnd6 options=\w+<(.*)>/", $line, $matches)) {
$result[$current_interface]["nd6"] = [
"flags" => explode(",", strtolower($matches[1]))
];
} elseif (preg_match("/\tid ([\w\:]+) priority (\d+) hellotime (\d+) fwddelay (\d+).*/", $line, $matches)) {
$result[$current_interface]["priority"] = $matches[2];
$result[$current_interface]["hellotime"] = $matches[3];
$result[$current_interface]["fwddelay"] = $matches[4];
} elseif (preg_match("/\tmaxage (\d+) holdcnt (\d+) proto (\w+) maxaddr (\d+) timeout (\d+).*/", $line, $matches)) {
$result[$current_interface]["maxage"] = $matches[1];
$result[$current_interface]["holdcnt"] = $matches[2];
$result[$current_interface]["proto"] = $matches[3];
$result[$current_interface]["maxaddr"] = $matches[4];
$result[$current_interface]["timeout"] = $matches[5];
} }
} }

View File

@ -120,10 +120,12 @@ function captiveportal_firewall($fw)
'protocol' => 'tcp', 'protocol' => 'tcp',
'from' => "<__captiveportal_zone_{$zoneid}>", 'from' => "<__captiveportal_zone_{$zoneid}>",
'from_not' => true, 'from_not' => true,
'to' => 'any', 'to' => "<__captiveportal_zone_{$zoneid}>",
'to_not' => true,
'to_port' => $to_port, 'to_port' => $to_port,
'target' => '127.0.0.1', 'target' => '127.0.0.1',
'localport' => $rdr_port, 'localport' => $rdr_port,
'natreflection' => 'disable',
'descr' => "Redirect to Captive Portal (zone {$zoneid})", 'descr' => "Redirect to Captive Portal (zone {$zoneid})",
'#ref' => "ui/captiveportal#edit={$uuid}" '#ref' => "ui/captiveportal#edit={$uuid}"
] ]
@ -157,7 +159,8 @@ function captiveportal_firewall($fw)
'direction' => 'in', 'direction' => 'in',
'from' => "<__captiveportal_zone_{$zoneid}>", 'from' => "<__captiveportal_zone_{$zoneid}>",
'from_not' => true, 'from_not' => true,
'to' => 'any', 'to' => "<__captiveportal_zone_{$zoneid}>",
'to_not' => true,
'descr' => "Default Captive Portal block rule (zone {$zoneid})", 'descr' => "Default Captive Portal block rule (zone {$zoneid})",
'log' => !isset($config['syslog']['nologdefaultblock']), 'log' => !isset($config['syslog']['nologdefaultblock']),
'#ref' => "ui/captiveportal#edit={$uuid}", '#ref' => "ui/captiveportal#edit={$uuid}",

View File

@ -47,16 +47,23 @@ function dhcpd_run()
function dhcpd_dhcpv6_enabled() function dhcpd_dhcpv6_enabled()
{ {
global $config; global $config;
$explicit_off = [];
/* handle manually configured DHCP6 server settings first */ /* handle manually configured DHCP6 server settings first */
foreach (config_read_array('dhcpdv6') as $dhcpv6if => $dhcpv6ifconf) { foreach (config_read_array('dhcpdv6') as $dhcpv6if => $dhcpv6ifconf) {
if (isset($config['interfaces'][$dhcpv6if]['enable']) && isset($dhcpv6ifconf['enable'])) { if (isset($config['interfaces'][$dhcpv6if]['enable']) && isset($dhcpv6ifconf['enable'])) {
return true; if ($dhcpv6ifconf['enable'] == '-1') {
$explicit_off[] = $dhcpv6if;
} else {
return true;
}
} }
} }
/* handle DHCP-PD prefixes and 6RD dynamic interfaces */ /* handle DHCP-PD prefixes and 6RD dynamic interfaces */
foreach (legacy_config_get_interfaces(array('virtual' => false)) as $ifcfg) { foreach (legacy_config_get_interfaces(array('virtual' => false)) as $ifnm => $ifcfg) {
if (in_array($ifnm, $explicit_off)) {
continue;
}
if (isset($ifcfg['enable']) && !empty($ifcfg['track6-interface']) && !isset($ifcfg['dhcpd6track6allowoverride'])) { if (isset($ifcfg['enable']) && !empty($ifcfg['track6-interface']) && !isset($ifcfg['dhcpd6track6allowoverride'])) {
return true; return true;
} }
@ -864,8 +871,12 @@ function dhcpd_dhcp6_configure($verbose = false, $blacklist = [])
if (!isset($config['interfaces'][$ifname]['dhcpd6track6allowoverride'])) { if (!isset($config['interfaces'][$ifname]['dhcpd6track6allowoverride'])) {
/* mock a real server */ /* mock a real server */
$dhcpdv6cfg[$ifname] = array(); if (!empty($dhcpdv6cfg[$ifname]) && $dhcpdv6cfg[$ifname]['enable'] == '-1') {
$dhcpdv6cfg[$ifname]['enable'] = true; /* tracking, but dhcpv6 disabled */
$dhcpdv6cfg[$ifname] = [];
} else {
$dhcpdv6cfg[$ifname] = ['enable' => true];
}
/* fixed range */ /* fixed range */
$ifcfgipv6arr[7] = '1000'; $ifcfgipv6arr[7] = '1000';

View File

@ -311,6 +311,9 @@ function dpinger_status()
'monitor' => !empty($gwitem['monitor']) ? $gwitem['monitor'] : '~', 'monitor' => !empty($gwitem['monitor']) ? $gwitem['monitor'] : '~',
'gateway' => $gwitem['gateway'] ?? '', 'gateway' => $gwitem['gateway'] ?? '',
'monitor_killstates' => $gwitem['monitor_killstates'] ?? '0', 'monitor_killstates' => $gwitem['monitor_killstates'] ?? '0',
'monitor_killstates_priority' => $gwitem['monitor_killstates_priority'] ?? '0',
'priority' => $gwitem['priority'] ?? '255',
'ipprotocol' => $gwitem['ipprotocol'],
'name' => $gwname, 'name' => $gwname,
'stddev' => '~', 'stddev' => '~',
'delay' => '~', 'delay' => '~',

View File

@ -583,52 +583,6 @@ function ipsec_idinfo_to_cidr(&$idinfo, $addrbits = false, $mode = '')
} }
} }
/*
* Return phase1 association for phase2
*/
function ipsec_lookup_phase1(&$ph2ent, &$ph1ent)
{
global $config;
if (!isset($config['ipsec']) || !is_array($config['ipsec'])) {
return false;
}
if (!is_array($config['ipsec']['phase1'])) {
return false;
}
if (empty($config['ipsec']['phase1'])) {
return false;
}
foreach ($config['ipsec']['phase1'] as $ph1tmp) {
if ($ph1tmp['ikeid'] == $ph2ent['ikeid']) {
$ph1ent = $ph1tmp;
return $ph1ent;
}
}
return false;
}
/*
* Check phase1 communications status
*/
function ipsec_phase1_status($ipsec_status, $ikeid)
{
foreach ($ipsec_status as $ike) {
if ($ike['id'] != $ikeid) {
continue;
}
if ($ike['status'] == 'established') {
return true;
}
break;
}
return false;
}
function ipsec_resolve($hostname, $ipproto = 'inet') function ipsec_resolve($hostname, $ipproto = 'inet')
{ {
if (!is_ipaddr($hostname)) { if (!is_ipaddr($hostname)) {
@ -686,7 +640,7 @@ function ipsec_find_id(&$ph1ent, $side = 'local')
$thisid_data = $id_data; $thisid_data = $id_data;
} }
return trim($thisid_data); return is_string($thisid_data) ? trim($thisid_data) : $thisid_data;
} }
/* include all configuration functions */ /* include all configuration functions */

View File

@ -42,6 +42,23 @@ function kea_services()
'name' => 'kea-dhcpv4', 'name' => 'kea-dhcpv4',
]; ];
} }
if (!empty((string)(new \OPNsense\Kea\KeaDhcpv6())->general->enabled)) {
/**
* Although kea's backend operation is a single package, various services do offer their own pid files.
* Ideally we should have a list of pids to check for the services and only return a single item,
* but showing both with the same action below is the second best we can achieve.
*/
$services[] = [
'description' => gettext('KEA DHCPv6 server'),
'pidfile' => '/var/run/kea/kea-dhcp6.kea-dhcp6.pid',
'configd' => [
'restart' => ['kea restart'],
'start' => ['kea start'],
'stop' => ['kea stop'],
],
'name' => 'kea-dhcpv6',
];
}
return $services; return $services;
} }
@ -55,14 +72,18 @@ function kea_run()
function kea_staticmap($proto = null, $valid_addresses = true, $ifconfig_details = null) function kea_staticmap($proto = null, $valid_addresses = true, $ifconfig_details = null)
{ {
$staticmap = []; $staticmap = [];
$keav4 = new \OPNsense\Kea\KeaDhcpv4(); if ($proto == 6) {
$keamdl = new \OPNsense\Kea\KeaDhcpv6();
} else {
$keamdl = new \OPNsense\Kea\KeaDhcpv4();
}
if ($proto == 6 || empty((string)$keav4->general->enabled)) { if (empty((string)$keamdl->general->enabled)) {
/* unsupported protocol or not enabled */ /* not enabled */
return $staticmap; return $staticmap;
} }
foreach ($keav4->reservations->reservation->iterateItems() as $reservation) { foreach ($keamdl->reservations->reservation->iterateItems() as $reservation) {
$hostname = !empty((string)$reservation->hostname) ? (string)$reservation->hostname : null; $hostname = !empty((string)$reservation->hostname) ? (string)$reservation->hostname : null;
$ip_address = (string)$reservation->ip_address; $ip_address = (string)$reservation->ip_address;
if ($valid_addresses) { if ($valid_addresses) {
@ -81,11 +102,13 @@ function kea_staticmap($proto = null, $valid_addresses = true, $ifconfig_details
$description = !empty((string)$reservation->description) ? (string)$reservation->description : null; $description = !empty((string)$reservation->description) ? (string)$reservation->description : null;
$subnet_node = $keav4->getNodeByReference("subnets.subnet4.{$reservation->subnet}");
$domain = null; $domain = null;
if ($subnet_node) { if ($proto == 4) {
if (!empty((string)$subnet_node->option_data->domain_name)) { $subnet_node = $keamdl->getNodeByReference("subnets.subnet4.{$reservation->subnet}");
$domain = (string)$subnet_node->option_data->domain_name; if ($subnet_node) {
if (!empty((string)$subnet_node->option_data->domain_name)) {
$domain = (string)$subnet_node->option_data->domain_name;
}
} }
} }
@ -113,9 +136,17 @@ function kea_configure()
function kea_configure_do($verbose = false) function kea_configure_do($verbose = false)
{ {
$keaDhcpv4 = new \OPNsense\Kea\KeaDhcpv4(); $keaDhcpv4 = new \OPNsense\Kea\KeaDhcpv4();
if ($keaDhcpv4->isEnabled()) { $keaDhcpv6 = new \OPNsense\Kea\KeaDhcpv6();
if ($keaDhcpv4->isEnabled() || $keaDhcpv6->isEnabled()) {
service_log('Sync KEA DHCP config...', $verbose); service_log('Sync KEA DHCP config...', $verbose);
$keaDhcpv4->generateConfig(); if ($keaDhcpv4->isEnabled() && $keaDhcpv4->general->manual_config->isEmpty()) {
/* skip kea-dhcp4.conf when configured manually */
$keaDhcpv4->generateConfig();
}
if ($keaDhcpv6->isEnabled() && $keaDhcpv6->general->manual_config->isEmpty()) {
/* skip kea-dhcp6.conf when configured manually */
$keaDhcpv6->generateConfig();
}
(new \OPNsense\Kea\KeaCtrlAgent())->generateConfig(); (new \OPNsense\Kea\KeaCtrlAgent())->generateConfig();
service_log("done.\n", $verbose); service_log("done.\n", $verbose);
} }
@ -133,6 +164,7 @@ function kea_firewall($fw)
{ {
global $config; global $config;
$keav4 = new \OPNsense\Kea\KeaDhcpv4(); $keav4 = new \OPNsense\Kea\KeaDhcpv4();
$keav6 = new \OPNsense\Kea\KeaDhcpv6();
if ($keav4->fwrulesEnabled()) { if ($keav4->fwrulesEnabled()) {
// automatic (IPv4) rules enabled // automatic (IPv4) rules enabled
foreach (explode(',', $keav4->general->interfaces) as $intf) { foreach (explode(',', $keav4->general->interfaces) as $intf) {
@ -166,6 +198,65 @@ function kea_firewall($fw)
); );
} }
} }
if ($keav6->fwrulesEnabled()) {
foreach (explode(',', $keav6->general->interfaces) as $intf) {
$default_opts = [
'protocol' => 'udp',
'ipprotocol' => 'inet6',
'interface' => $intf,
'#ref' => 'ui/kea/dhcp/v6',
'descr' => 'allow access to DHCPv6 server',
'log' => !isset($config['syslog']['nologdefaultpass'])
];
$fw->registerFilterRule(
1,
[
'from' => 'fe80::/10',
'to' => 'fe80::/10,ff02::/16',
'to_port' => 546
],
$default_opts
);
$fw->registerFilterRule(
1,
[
'from' => 'fe80::/10',
'to' => 'ff02::/16',
'to_port' => 547
],
$default_opts
);
$fw->registerFilterRule(
1,
[
'from' => 'ff02::/16',
'to' => 'fe80::/10',
'to_port' => 547
],
$default_opts
);
$fw->registerFilterRule(
1,
[
'from' => 'fe80::/10',
'to' => '(self)',
'to_port' => 546
],
$default_opts
);
$fw->registerFilterRule(
1,
[
'from' => '(self)',
'to' => 'fe80::/10',
'from_port' => 547,
'direction' => 'out'
],
$default_opts
);
}
}
} }
function kea_xmlrpc_sync() function kea_xmlrpc_sync()
@ -176,7 +267,7 @@ function kea_xmlrpc_sync()
'description' => gettext('Kea DHCP'), 'description' => gettext('Kea DHCP'),
'section' => 'OPNsense.Kea', 'section' => 'OPNsense.Kea',
'id' => 'kea', 'id' => 'kea',
'services' => ["kea-dhcpv4"], 'services' => ["kea-dhcpv4", "kea-dhcpv6"],
]; ];
return $result; return $result;

View File

@ -40,16 +40,21 @@ function radvd_configure()
function radvd_enabled() function radvd_enabled()
{ {
global $config; global $config;
$explicit_off = [];
/* handle manually configured DHCP6 server settings first */ /* handle manually configured DHCP6 server settings first */
foreach (config_read_array('dhcpdv6') as $dhcpv6if => $dhcpv6ifconf) { foreach (config_read_array('dhcpdv6') as $dhcpv6if => $dhcpv6ifconf) {
if (isset($config['interfaces'][$dhcpv6if]['enable']) && isset($dhcpv6ifconf['ramode']) && $dhcpv6ifconf['ramode'] != 'disabled') { if (isset($config['interfaces'][$dhcpv6if]['enable']) && isset($dhcpv6ifconf['ramode']) && $dhcpv6ifconf['ramode'] != 'disabled') {
return true; return true;
} elseif (isset($dhcpv6ifconf['ramode']) && $dhcpv6ifconf['ramode'] == 'disabled') {
$explicit_off[] = $dhcpv6if;
} }
} }
/* handle DHCP-PD prefixes and 6RD dynamic interfaces */ /* handle DHCP-PD prefixes and 6RD dynamic interfaces */
foreach (legacy_config_get_interfaces(array('virtual' => false)) as $ifcfg) { foreach (legacy_config_get_interfaces(array('virtual' => false)) as $ifnm => $ifcfg) {
if (in_array($ifnm, $explicit_off)) {
continue;
}
if (isset($ifcfg['enable']) && !empty($ifcfg['track6-interface']) && !isset($ifcfg['dhcpd6track6allowoverride'])) { if (isset($ifcfg['enable']) && !empty($ifcfg['track6-interface']) && !isset($ifcfg['dhcpd6track6allowoverride'])) {
return true; return true;
} }
@ -349,6 +354,9 @@ function radvd_configure_do($verbose = false, $blacklist = [])
} elseif (isset($blacklist[$if])) { } elseif (isset($blacklist[$if])) {
$radvdconf .= "# Skipping blacklisted interface {$if}\n"; $radvdconf .= "# Skipping blacklisted interface {$if}\n";
continue; continue;
} elseif (!empty($config['dhcpdv6'][$if]) && !empty($config['dhcpdv6'][$if]['ramode']) && $config['dhcpdv6'][$if]['ramode'] == 'disabled') {
$radvdconf .= "# Skipping explicit disabled interface {$if}\n";
continue;
} }
$trackif = $config['interfaces'][$if]['track6-interface']; $trackif = $config['interfaces'][$if]['track6-interface'];

View File

@ -285,22 +285,6 @@ function get_locale_list()
return $locales; return $locales;
} }
function get_country_codes()
{
$dn_cc = array();
$iso3166_tab = '/usr/local/opnsense/contrib/tzdata/iso3166.tab';
if (file_exists($iso3166_tab)) {
$dn_cc_file = file($iso3166_tab);
foreach ($dn_cc_file as $line) {
if (preg_match('/^([A-Z][A-Z])\t(.*)$/', $line, $matches)) {
$dn_cc[$matches[1]] = trim($matches[2]);
}
}
}
return $dn_cc;
}
function get_zoneinfo() function get_zoneinfo()
{ {
$zones = timezone_identifiers_list(DateTimeZone::ALL ^ DateTimeZone::UTC); $zones = timezone_identifiers_list(DateTimeZone::ALL ^ DateTimeZone::UTC);
@ -326,13 +310,17 @@ function get_searchdomains()
} }
if (!empty($syscfg['dnssearchdomain'])) { if (!empty($syscfg['dnssearchdomain'])) {
if ($syscfg['dnssearchdomain'] == '.') { $dnssds = array_unique(explode(',', $syscfg['dnssearchdomain']));
/* pass root only */
return [$syscfg['dnssearchdomain']];
}
/* add custom search entries after default domain before potential provider entries */ foreach ($dnssds as $dnssd) {
$master_list[] = $syscfg['dnssearchdomain']; if ($dnssd == '.') {
/* pass root only but including other manually set domains as is */
return $dnssds;
}
/* add custom search entries after default domain before potential provider entries */
$master_list[] = $dnssd;
}
} }
if (!empty($syscfg['dnsallowoverride'])) { if (!empty($syscfg['dnsallowoverride'])) {

View File

@ -32,7 +32,6 @@
require_once 'IPv6.inc'; require_once 'IPv6.inc';
/* XXX only two callers left, better remove this unreliable function */
function killbyname($procname, $sig = 'TERM', $waitforit = true) function killbyname($procname, $sig = 'TERM', $waitforit = true)
{ {
/* pgrep -n only kills the newest matching process */ /* pgrep -n only kills the newest matching process */
@ -636,41 +635,6 @@ function is_uniquelocal($ipaddr)
return !!preg_match('/^fd[0-9a-f][0-9a-f]:/i', $ipaddr ?? ''); return !!preg_match('/^fd[0-9a-f][0-9a-f]:/i', $ipaddr ?? '');
} }
/* returns true if $ipaddr is a valid literal IPv6 address */
function is_literalipaddrv6($ipaddr)
{
if (preg_match('/\[([0-9a-f:]+)\]/i', $ipaddr, $match)) {
$ipaddr = $match[1];
} else {
return false;
}
return is_ipaddrv6($ipaddr);
}
function is_ipaddrwithport($ipport)
{
$parts = explode(":", $ipport);
$port = array_pop($parts);
if (count($parts) == 1) {
return is_ipaddrv4($parts[0]) && is_port($port);
} elseif (count($parts) > 1) {
return is_literalipaddrv6(implode(":", $parts)) && is_port($port);
} else {
return false;
}
}
function is_hostnamewithport($hostport)
{
$parts = explode(":", $hostport);
$port = array_pop($parts);
if (count($parts) == 1) {
return is_hostname($parts[0]) && is_port($port);
} else {
return false;
}
}
/* returns true if $ipaddr is a valid dotted IPv4 address or an alias thereof */ /* returns true if $ipaddr is a valid dotted IPv4 address or an alias thereof */
function is_ipaddroralias($ipaddr) function is_ipaddroralias($ipaddr)
{ {
@ -802,32 +766,6 @@ function is_inrange($test, $start, $end)
return is_ipaddrv6($test) ? is_inrange_v6($test, $start, $end) : is_inrange_v4($test, $start, $end); return is_ipaddrv6($test) ? is_inrange_v6($test, $start, $end) : is_inrange_v4($test, $start, $end);
} }
function get_configured_carp_interface_list()
{
$carp_list = [];
foreach (config_read_array('virtualip', 'vip') as $vip) {
if ($vip['mode'] == 'carp') {
$carp_list["{$vip['interface']}_vip{$vip['vhid']}"] = $vip['subnet'];
}
}
return $carp_list;
}
function get_configured_ip_aliases_list()
{
$alias_list = [];
foreach (config_read_array('virtualip', 'vip') as $vip) {
if ($vip['mode'] == 'ipalias') {
$alias_list[$vip['subnet']] = $vip['interface'];
}
}
return $alias_list;
}
function get_configured_interface_with_descr() function get_configured_interface_with_descr()
{ {
$iflist = []; $iflist = [];
@ -1011,41 +949,6 @@ function is_alias($name)
return \OPNsense\Firewall\Util::isAlias($name); return \OPNsense\Firewall\Util::isAlias($name);
} }
function subnet_size($subnet)
{
if (is_subnetv4($subnet)) {
list ($ip, $bits) = explode("/", $subnet);
return round(exp(log(2) * (32 - $bits)));
} elseif (is_subnetv6($subnet)) {
list ($ip, $bits) = explode("/", $subnet);
return round(exp(log(2) * (128 - $bits)));
} else {
return 0;
}
}
/* find out whether two subnets overlap */
function check_subnets_overlap($subnet1, $bits1, $subnet2, $bits2)
{
if (!is_numeric($bits1)) {
$bits1 = 32;
}
if (!is_numeric($bits2)) {
$bits2 = 32;
}
if ($bits1 < $bits2) {
$relbits = $bits1;
} else {
$relbits = $bits2;
}
$sn1 = gen_subnet_mask_long($relbits) & ip2long($subnet1);
$sn2 = gen_subnet_mask_long($relbits) & ip2long($subnet2);
return ($sn1 == $sn2);
}
/* compare two IP addresses */ /* compare two IP addresses */
function ipcmp($a, $b) function ipcmp($a, $b)
{ {
@ -1087,23 +990,6 @@ function is_private_ip($iptocheck)
return false; return false;
} }
function format_bytes($bytes)
{
if ($bytes >= 1024 ** 5) {
return sprintf("%.2f PB", $bytes / (1024 ** 5));
} elseif ($bytes >= 1024 ** 4) {
return sprintf("%.2f TB", $bytes / (1024 ** 4));
} elseif ($bytes >= 1024 ** 3) {
return sprintf("%.2f GB", $bytes / (1024 ** 3));
} elseif ($bytes >= 1024 ** 2) {
return sprintf("%.2f MB", $bytes / (1024 ** 2));
} elseif ($bytes >= 1024) {
return sprintf("%.0f KB", $bytes / 1024);
} else {
return sprintf("%d bytes", $bytes);
}
}
/* /*
* get_sysctl($names) * get_sysctl($names)
* Get values of sysctl OID's listed in $names (accepts an array or a single * Get values of sysctl OID's listed in $names (accepts an array or a single
@ -1329,27 +1215,3 @@ function dhcp6c_duid_clear()
/* clear the backup so that it will not be restored: */ /* clear the backup so that it will not be restored: */
@unlink('/conf/dhcp6c_duid'); @unlink('/conf/dhcp6c_duid');
} }
/**
* check if interface is assigned
* @param $interface technical interface name
* @return string interface name (lan, wan, optX)
*/
function is_interface_assigned($interface)
{
global $config;
foreach (legacy_config_get_interfaces() as $if => $intf) {
if (isset($intf['if']) && $intf['if'] == $interface) {
return true;
}
}
if (isset($config['vlans']['vlan'])) {
foreach ($config['vlans']['vlan'] as $vlan) {
if ($vlan['if'] == $interface) {
return true;
}
}
}
return false;
}

View File

@ -2,7 +2,7 @@
<?php <?php
/* /*
* Copyright (C) 2017-2024 Franco Fichtner <franco@opnsense.org> * Copyright (C) 2017-2025 Franco Fichtner <franco@opnsense.org>
* Copyright (C) 2006 Scott Ullrich <sullrich@gmail.com> * Copyright (C) 2006 Scott Ullrich <sullrich@gmail.com>
* Copyright (C) 2003-2005 Manuel Kasper <mk@neon1.net> * Copyright (C) 2003-2005 Manuel Kasper <mk@neon1.net>
* All rights reserved. * All rights reserved.
@ -38,6 +38,8 @@ require_once("interfaces.inc");
$argument = isset($argv[1]) ? trim($argv[1]) : ''; $argument = isset($argv[1]) ? trim($argv[1]) : '';
$force = !empty($argv[2]) ? 'yes' : 'no'; $force = !empty($argv[2]) ? 'yes' : 'no';
$family = 'inet';
$family_int = 4;
exit_on_bootup(function ($argument) { exit_on_bootup(function ($argument) {
log_msg("IP renewal deferred during boot on '{$argument}'"); log_msg("IP renewal deferred during boot on '{$argument}'");
@ -66,7 +68,7 @@ if (!is_ipaddr($ip)) {
return; return;
} }
$gw = OPNsense\Interface\Autoconf::getRouter($device, 'inet'); $gw = OPNsense\Interface\Autoconf::getRouter($device, $family);
$cacheip_file = "/tmp/{$device}_oldip"; $cacheip_file = "/tmp/{$device}_oldip";
$cacheip = trim(@file_get_contents($cacheip_file)); $cacheip = trim(@file_get_contents($cacheip_file));
@ -81,10 +83,17 @@ if ($force == 'no' && $ip == $cacheip) {
log_msg("IP renewal starting (new: {$ip}, old: {$cacheip}, interface: {$interface}, device: {$device}, force: {$force})"); log_msg("IP renewal starting (new: {$ip}, old: {$cacheip}, interface: {$interface}, device: {$device}, force: {$force})");
interfaces_vips_configure($interface, 4); interfaces_vips_configure($interface, $family_int);
$greifs = link_interface_to_gre($interface, true, 4); $auxdevs = [];
$gififs = link_interface_to_gif($interface, true, 4);
/* find and reconfigure all linked devices */
foreach (link_interface_to_gre($interface, true, $family_int) as $linked) {
$auxdevs[] = $linked;
}
foreach (link_interface_to_gif($interface, true, $family_int) as $linked) {
$auxdevs[] = $linked;
}
switch (isset($config['system']['ipv6allow']) ? ($config['interfaces'][$interface]['ipaddrv6'] ?? 'none') : 'none') { switch (isset($config['system']['ipv6allow']) ? ($config['interfaces'][$interface]['ipaddrv6'] ?? 'none') : 'none') {
case '6to4': case '6to4':
@ -99,7 +108,8 @@ switch (isset($config['system']['ipv6allow']) ? ($config['interfaces'][$interfac
break; break;
} }
interfaces_restart_by_device(false, array_merge($greifs, $gififs)); /* linked devices that are assigned need to be reconfigured now */
interfaces_restart_by_device(false, $auxdevs);
/* /*
* Interface reconfigure finished here so sync * Interface reconfigure finished here so sync
@ -107,7 +117,10 @@ interfaces_restart_by_device(false, array_merge($greifs, $gififs));
*/ */
ifgroup_setup(); ifgroup_setup();
system_routing_configure(false, $interface, true, 'inet'); $interfaces = [/* empty for v6 compat */];
array_unshift($interfaces, $interface);
system_routing_configure(false, $interfaces, true, $family);
filter_configure_sync(); filter_configure_sync();
@ -126,5 +139,5 @@ if (is_ipaddr($cachegw) && is_ipaddr($gw) && $gw != $cachegw) {
@file_put_contents($cachegw_file, $gw . PHP_EOL); @file_put_contents($cachegw_file, $gw . PHP_EOL);
plugins_configure('vpn', false, [[$interface], 'inet']); plugins_configure('vpn', false, [$interfaces, $family]);
plugins_configure('newwanip', false, [[$interface], 'inet']); plugins_configure('newwanip', false, [$interfaces, $family]);

View File

@ -2,7 +2,7 @@
<?php <?php
/* /*
* Copyright (C) 2017-2024 Franco Fichtner <franco@opnsense.org> * Copyright (C) 2017-2025 Franco Fichtner <franco@opnsense.org>
* Copyright (C) 2006 Scott Ullrich <sullrich@gmail.com> * Copyright (C) 2006 Scott Ullrich <sullrich@gmail.com>
* Copyright (C) 2003-2005 Manuel Kasper <mk@neon1.net> * Copyright (C) 2003-2005 Manuel Kasper <mk@neon1.net>
* All rights reserved. * All rights reserved.
@ -38,6 +38,8 @@ require_once("interfaces.inc");
$argument = isset($argv[1]) ? trim($argv[1]) : ''; $argument = isset($argv[1]) ? trim($argv[1]) : '';
$force = !empty($argv[2]) ? 'yes' : 'no'; $force = !empty($argv[2]) ? 'yes' : 'no';
$family = 'inet6';
$family_int = 6;
exit_on_bootup(function ($argument) { exit_on_bootup(function ($argument) {
log_msg("IP renewal deferred during boot on '{$argument}'"); log_msg("IP renewal deferred during boot on '{$argument}'");
@ -46,7 +48,7 @@ exit_on_bootup(function ($argument) {
if (empty($argument)) { if (empty($argument)) {
$interface = 'wan'; $interface = 'wan';
$device = get_real_interface($interface, 'inet6'); $device = get_real_interface($interface, $family);
} else { } else {
$interface = convert_real_interface_to_friendly_interface_name($argument); $interface = convert_real_interface_to_friendly_interface_name($argument);
$device = $argument; $device = $argument;
@ -89,15 +91,24 @@ if (!is_ipaddr($ip)) {
log_msg("IP renewal starting (address: {$ip}, interface: {$interface}, device: {$device})"); log_msg("IP renewal starting (address: {$ip}, interface: {$interface}, device: {$device})");
interfaces_vips_configure($interface, 6); interfaces_vips_configure($interface, $family_int);
$greifs = link_interface_to_gre($interface, true, 6); $auxdevs = [];
$gififs = link_interface_to_gif($interface, true, 6);
/* find and reconfigure all linked devices which includes looking up tracked interfaces */
foreach (array_merge([$interface], array_keys(link_interface_to_track6($interface))) as $allif) {
foreach (link_interface_to_gre($allif, true, $family_int) as $linked) {
$auxdevs[] = $linked;
}
foreach (link_interface_to_gif($allif, true, $family_int) as $linked) {
$auxdevs[] = $linked;
}
}
switch (isset($config['system']['ipv6allow']) ? ($config['interfaces'][$interface]['ipaddrv6'] ?? 'none') : 'none') { switch (isset($config['system']['ipv6allow']) ? ($config['interfaces'][$interface]['ipaddrv6'] ?? 'none') : 'none') {
case 'slaac': case 'slaac':
/* require immediate reconfiguration before reconfiguring clients */ /* require immediate reconfiguration before reconfiguring clients */
plugins_configure('dhcp', false, ['inet6']); plugins_configure('dhcp', false, [$family]);
break; break;
default: default:
/* /*
@ -111,14 +122,21 @@ switch (isset($config['system']['ipv6allow']) ? ($config['interfaces'][$interfac
break; break;
} }
interfaces_restart_by_device(false, array_merge($greifs, $gififs)); /* linked devices that are assigned need to be reconfigured now */
interfaces_restart_by_device(false, $auxdevs);
/*
* Interface reconfigure finished here so sync
* firewall groups in case of destroy/create use.
*/
ifgroup_setup();
$interfaces = array_keys(link_interface_to_track6($interface, true)); $interfaces = array_keys(link_interface_to_track6($interface, true));
array_unshift($interfaces, $interface); array_unshift($interfaces, $interface);
system_routing_configure(false, $interfaces, true, 'inet6'); system_routing_configure(false, $interfaces, true, $family);
filter_configure_sync(); filter_configure_sync();
plugins_configure('vpn', false, [$interfaces, 'inet6']); plugins_configure('vpn', false, [$interfaces, $family]);
plugins_configure('newwanip', false, [$interfaces, 'inet6']); plugins_configure('newwanip', false, [$interfaces, $family]);

View File

@ -35,12 +35,34 @@ require_once 'interfaces.inc';
$gwnames = []; $gwnames = [];
$affected_gateways = !empty($argv[1]) ? explode(',', $argv[1]) : []; $affected_gateways = !empty($argv[1]) ? explode(',', $argv[1]) : [];
$metered_found_prios = ['inet' => 256, 'inet6' => 256];
$metered_gws = ['inet' => [], 'inet6' => []];
foreach (return_gateways_status() as $status) { foreach (return_gateways_status() as $status) {
if ($status['status'] == 'down') { if ($status['status'] == 'down') {
/* try to recover monitors stuck in down state ignoring "force_down" */ /* recover monitors stuck in down state ignoring "force_down" */
$gwnames[] = $status['name']; $gwnames[] = $status['name'];
if (!empty($status['monitor_killstates']) && in_array($status['name'], $affected_gateways)) { if (!empty($status['monitor_killstates']) && in_array($status['name'], $affected_gateways)) {
configdp_run('filter kill gateway_states', [$status['gateway']], true); $uuid = trim(configdp_run('filter kill gateway_states', [$status['gateway']], true));
log_msg("ROUTING: killing states for unreachable gateway {$status['name']} [$uuid]", LOG_NOTICE);
}
} elseif ($status['status'] != 'force_down') {
/* collect "metered" gateways for all non-down status reports */
if (!empty($status['monitor_killstates_priority'])) {
$metered_gws[$status['ipprotocol']][] = $status;
/* only consider currently affected gateways as priority candidates */
} elseif (in_array($status['name'], $affected_gateways)) {
$metered_found_prios[$status['ipprotocol']] = min($status['priority'], $metered_found_prios[$status['ipprotocol']]);
}
}
}
foreach ($metered_found_prios as $ipproto => $metered_found_prio) {
/* kill states for "metered" gateways */
foreach ($metered_gws[$ipproto] as $status) {
if ($status['priority'] > $metered_found_prio) {
$uuid = trim(configdp_run('filter kill gateway_states', [$status['gateway']], true));
log_msg("ROUTING: killing states for deferred gateway {$status['name']} [$uuid]", LOG_NOTICE);
} }
} }
} }

View File

@ -0,0 +1,14 @@
OPNsense certificates used by external applications and registered in the gui for viewing purposes only.
In this directory you can create files with a .conf extension (e.g. myapp.conf) with the following (sample) config:
[location]
base=/usr/local/md/domains
pattern=pubcert.pem
description=OPNWAF
"base" is the directory to recursively iterate, "pattern" is a regex matcher and each item returned will have a description
attached to it for the frontend.
Files found can be identified by their id, which is an md5 hash of the contents.

View File

@ -36,6 +36,7 @@ return new OPNsense\Core\AppConfig([
'pluginsDir' => __DIR__ . '/../../app/plugins/', 'pluginsDir' => __DIR__ . '/../../app/plugins/',
'libraryDir' => __DIR__ . '/../../app/library/', 'libraryDir' => __DIR__ . '/../../app/library/',
'cacheDir' => __DIR__ . '/../../app/cache/', 'cacheDir' => __DIR__ . '/../../app/cache/',
'contribDir' => __DIR__ . '/../../../contrib/',
'baseUri' => '/opnsense_gui/', 'baseUri' => '/opnsense_gui/',
], ],
'globals' => [ 'globals' => [

View File

@ -33,6 +33,7 @@ class GroupController extends \OPNsense\Base\IndexController
public function indexAction() public function indexAction()
{ {
$this->view->formDialogEditGroup = $this->getForm("dialogGroup"); $this->view->formDialogEditGroup = $this->getForm("dialogGroup");
$this->view->formGridGroup = $this->getFormGrid("dialogGroup");
$this->view->pick('OPNsense/Auth/group'); $this->view->pick('OPNsense/Auth/group');
} }
} }

View File

@ -33,6 +33,7 @@ class PrivController extends \OPNsense\Base\IndexController
public function indexAction() public function indexAction()
{ {
$this->view->formDialogEditPriv = $this->getForm("dialogPriv"); $this->view->formDialogEditPriv = $this->getForm("dialogPriv");
$this->view->formGridPriv = $this->getFormGrid("dialogPriv");
$this->view->pick('OPNsense/Auth/priv'); $this->view->pick('OPNsense/Auth/priv');
} }
} }

View File

@ -51,6 +51,7 @@ class UserController extends \OPNsense\Base\IndexController
public function indexAction() public function indexAction()
{ {
$this->view->formDialogEditUser = $this->getForm("dialogUser"); $this->view->formDialogEditUser = $this->getForm("dialogUser");
$this->view->formGridUser = $this->getFormGrid("dialogUser");
$this->view->pick('OPNsense/Auth/user'); $this->view->pick('OPNsense/Auth/user');
} }
} }

View File

@ -3,32 +3,50 @@
<id>group.scope</id> <id>group.scope</id>
<label>Defined By</label> <label>Defined By</label>
<type>info</type> <type>info</type>
<grid_view>
<visible>false</visible>
</grid_view>
</field> </field>
<field> <field>
<id>group.gid</id> <id>group.gid</id>
<label>gid</label> <label>gid</label>
<type>info</type> <type>info</type>
<grid_view>
<visible>false</visible>
</grid_view>
</field> </field>
<field> <field>
<id>group.name</id> <id>group.name</id>
<label>Group name</label> <label>Group name</label>
<type>text</type> <type>text</type>
<grid_view>
<sequence>10</sequence>
</grid_view>
</field> </field>
<field> <field>
<id>group.description</id> <id>group.description</id>
<label>Description</label> <label>Description</label>
<type>text</type> <type>text</type>
<help>You may enter a description here for your reference (not parsed).</help> <help>You may enter a description here for your reference (not parsed).</help>
<grid_view>
<sequence>40</sequence>
</grid_view>
</field> </field>
<field> <field>
<id>group.priv</id> <id>group.priv</id>
<label>Privileges</label> <label>Privileges</label>
<type>select_multiple</type> <type>select_multiple</type>
<grid_view>
<sequence>20</sequence>
</grid_view>
</field> </field>
<field> <field>
<id>group.member</id> <id>group.member</id>
<label>Members</label> <label>Members</label>
<type>select_multiple</type> <type>select_multiple</type>
<help>List of users that are a member of this group</help> <help>List of users that are a member of this group</help>
<grid_view>
<sequence>30</sequence>
</grid_view>
</field> </field>
</form> </form>

View File

@ -4,14 +4,33 @@
<label>Id</label> <label>Id</label>
<type>info</type> <type>info</type>
</field> </field>
<field>
<id>priv.name</id>
<label>Name</label>
<type>ignore</type>
<grid_view>
<formatter>lines</formatter>
</grid_view>
</field>
<field>
<id>priv.match</id>
<label>Match</label>
<type>ignore</type>
</field>
<field> <field>
<id>priv.users</id> <id>priv.users</id>
<label>Users</label> <label>Users</label>
<type>select_multiple</type> <type>select_multiple</type>
<grid_view>
<formatter>count</formatter>
</grid_view>
</field> </field>
<field> <field>
<id>priv.groups</id> <id>priv.groups</id>
<label>Groups</label> <label>Groups</label>
<type>select_multiple</type> <type>select_multiple</type>
<grid_view>
<formatter>count</formatter>
</grid_view>
</field> </field>
</form> </form>

View File

@ -3,93 +3,149 @@
<id>user.scope</id> <id>user.scope</id>
<label>Defined By</label> <label>Defined By</label>
<type>info</type> <type>info</type>
<grid_view>
<visible>false</visible>
</grid_view>
</field> </field>
<field> <field>
<id>user.uid</id> <id>user.uid</id>
<label>uid</label> <label>uid</label>
<type>info</type> <type>info</type>
<grid_view>
<visible>false</visible>
</grid_view>
</field> </field>
<field> <field>
<id>user.disabled</id> <id>user.disabled</id>
<label>Disabled</label> <label>Disabled</label>
<type>checkbox</type> <type>checkbox</type>
<help>Deny authentication, only applicable for local users</help> <help>Deny authentication, only applicable for local users</help>
<grid_view>
<visible>false</visible>
<type>boolean</type>
<formatter>boolean</formatter>
</grid_view>
</field> </field>
<field> <field>
<id>user.name</id> <id>user.name</id>
<label>Username</label> <label>Username</label>
<type>text</type> <type>text</type>
<grid_view>
<formatter>username</formatter>
<sequence>10</sequence>
</grid_view>
</field> </field>
<field> <field>
<id>user.password</id> <id>user.password</id>
<label>Password</label> <label>Password</label>
<type>password</type> <type>password</type>
<grid_view>
<ignore>true</ignore>
</grid_view>
</field> </field>
<field> <field>
<id>user.scrambled_password</id> <id>user.scrambled_password</id>
<label>Scrambled Password</label> <label>Scrambled Password</label>
<type>checkbox</type> <type>checkbox</type>
<help>Generate a scrambled password to prevent local database logins for this user.</help> <help>Generate a scrambled password to prevent local database logins for this user.</help>
<grid_view>
<visible>false</visible>
<type>boolean</type>
<formatter>boolean</formatter>
</grid_view>
</field> </field>
<field> <field>
<id>user.descr</id> <id>user.descr</id>
<label>Full name</label> <label>Full name</label>
<type>text</type> <type>text</type>
<help>User's full name, for your own information only</help> <help>User's full name, for your own information only</help>
<grid_view>
<sequence>30</sequence>
</grid_view>
</field> </field>
<field> <field>
<id>user.email</id> <id>user.email</id>
<label>E-mail</label> <label>E-mail</label>
<type>text</type> <type>text</type>
<help>User's e-mail address, for your own information only</help> <help>User's e-mail address, for your own information only</help>
<grid_view>
<visible>false</visible>
</grid_view>
</field> </field>
<field> <field>
<id>user.comment</id> <id>user.comment</id>
<label>Comment</label> <label>Comment</label>
<type>textbox</type> <type>textbox</type>
<help>User comment, for your own information only</help> <help>User comment, for your own information only</help>
<grid_view>
<visible>false</visible>
</grid_view>
</field> </field>
<field> <field>
<id>user.landing_page</id> <id>user.landing_page</id>
<label>Preferred landing page</label> <label>Preferred landing page</label>
<type>text</type> <type>text</type>
<help>Preferred landing page after login or authentication failure</help> <help>Preferred landing page after login or authentication failure</help>
<grid_view>
<visible>false</visible>
</grid_view>
</field> </field>
<field> <field>
<id>user.language</id> <id>user.language</id>
<label>Language</label> <label>Language</label>
<type>dropdown</type> <type>dropdown</type>
<grid_view>
<visible>false</visible>
</grid_view>
</field> </field>
<field> <field>
<id>user.shell</id> <id>user.shell</id>
<label>Login shell</label> <label>Login shell</label>
<type>dropdown</type> <type>dropdown</type>
<grid_view>
<visible>false</visible>
</grid_view>
</field> </field>
<field> <field>
<id>user.expires</id> <id>user.expires</id>
<label>Expiration date</label> <label>Expiration date</label>
<type>text</type> <type>text</type>
<style>datepicker</style> <style>datepicker</style>
<grid_view>
<visible>false</visible>
</grid_view>
</field> </field>
<field> <field>
<id>user.group_memberships</id> <id>user.group_memberships</id>
<label>Group membership</label> <label>Group membership</label>
<type>select_multiple</type> <type>select_multiple</type>
<grid_view>
<sequence>20</sequence>
</grid_view>
</field> </field>
<field> <field>
<id>user.priv</id> <id>user.priv</id>
<label>Privileges</label> <label>Privileges</label>
<type>select_multiple</type> <type>select_multiple</type>
<grid_view>
<visible>false</visible>
</grid_view>
</field> </field>
<field> <field>
<id>user.otp_seed</id> <id>user.otp_seed</id>
<label>OTP seed</label> <label>OTP seed</label>
<type>text</type> <type>text</type>
<style>otp_seed otp_default_hidden</style> <style>otp_seed otp_default_hidden</style>
<grid_view>
<ignore>true</ignore>
</grid_view>
</field> </field>
<field> <field>
<id>user.authorizedkeys</id> <id>user.authorizedkeys</id>
<label>Authorized Keys</label> <label>Authorized Keys</label>
<type>textbox</type> <type>textbox</type>
<grid_view>
<ignore>true</ignore>
</grid_view>
</field> </field>
</form> </form>

View File

@ -17,15 +17,6 @@
<type>select_multiple</type> <type>select_multiple</type>
<help><![CDATA[Select interface(s) to enable for captive portal.]]></help> <help><![CDATA[Select interface(s) to enable for captive portal.]]></help>
</field> </field>
<field>
<id>zone.interfaces_inbound</id>
<label>Allow inbound</label>
<type>select_multiple</type>
<help><![CDATA[
Select interfaces from which to allow inbound (stateful) traffic. This can be convenient if the zone in question
contains machines/servers which should be accessible from other networks attached to this firewall.
]]></help>
</field>
<field> <field>
<id>zone.authservers</id> <id>zone.authservers</id>
<label>Authenticate using</label> <label>Authenticate using</label>

View File

@ -145,6 +145,7 @@ class SystemController extends ApiControllerBase
$response = [ $response = [
'uptime' => $this->formatUptime(time() - $matches[1]), 'uptime' => $this->formatUptime(time() - $matches[1]),
'datetime' => date("D M j G:i:s T Y"), 'datetime' => date("D M j G:i:s T Y"),
'boottime' => date("D M j G:i:s T Y", $matches[1]),
'config' => $last_change, 'config' => $last_change,
'loadavg' => $loadavg, 'loadavg' => $loadavg,
]; ];

View File

@ -256,32 +256,6 @@ class SettingsController extends ApiMutableModelControllerBase
return $this->delBase('dhcp_options', $uuid); return $this->delBase('dhcp_options', $uuid);
} }
/* dhcp match options */
public function searchMatchAction()
{
return $this->searchBase('dhcp_options_match', null, null, $this->buildFilterFunction());
}
public function getMatchAction($uuid = null)
{
return $this->getBase('match', 'dhcp_options_match', $uuid);
}
public function setMatchAction($uuid)
{
return $this->setBase('match', 'dhcp_options_match', $uuid);
}
public function addMatchAction()
{
return $this->addBase('match', 'dhcp_options_match');
}
public function delMatchAction($uuid)
{
return $this->delBase('dhcp_options_match', $uuid);
}
/* dhcp boot options */ /* dhcp boot options */
public function searchBootAction() public function searchBootAction()
{ {

View File

@ -43,8 +43,6 @@ class SettingsController extends \OPNsense\Base\IndexController
$this->view->formGridDHCPrange = $this->getFormGrid("dialogDHCPrange", "range"); $this->view->formGridDHCPrange = $this->getFormGrid("dialogDHCPrange", "range");
$this->view->formDialogEditDHCPoption = $this->getForm("dialogDHCPoption"); $this->view->formDialogEditDHCPoption = $this->getForm("dialogDHCPoption");
$this->view->formGridDHCPoption = $this->getFormGrid("dialogDHCPoption", "option"); $this->view->formGridDHCPoption = $this->getFormGrid("dialogDHCPoption", "option");
$this->view->formDialogEditDHCPmatch = $this->getForm("dialogDHCPmatch");
$this->view->formGridDHCPmatch = $this->getFormGrid("dialogDHCPmatch", "match");
$this->view->formDialogEditDHCPboot = $this->getForm("dialogDHCPboot"); $this->view->formDialogEditDHCPboot = $this->getForm("dialogDHCPboot");
$this->view->formGridDHCPboot = $this->getFormGrid("dialogDHCPboot", "boot"); $this->view->formGridDHCPboot = $this->getFormGrid("dialogDHCPboot", "boot");

View File

@ -1,32 +0,0 @@
<form>
<field>
<id>match.option</id>
<label>Option</label>
<type>dropdown</type>
<help>DHCPv4 option to offer to the client.</help>
</field>
<field>
<id>match.option6</id>
<label>Option6</label>
<type>dropdown</type>
<help>DHCPv6 option to offer to the client.</help>
</field>
<field>
<id>match.set_tag</id>
<label>Tag [set]</label>
<type>dropdown</type>
<help>Tag to set for requests matching this range which can be used to selectively match dhcp options</help>
</field>
<field>
<id>match.value</id>
<label>Value</label>
<type>text</type>
<help>Value to match, leave empty to match on the option only</help>
</field>
<field>
<id>match.description</id>
<label>Description</label>
<type>text</type>
<help>You may enter a description here for your reference (not parsed).</help>
</field>
</form>

View File

@ -1,4 +1,10 @@
<form> <form>
<field>
<id>option.type</id>
<label>Type</label>
<type>dropdown</type>
<help>"Set" option to send it to a client in a DHCP offer or "Match" option to dynamically tag clients that send it in the initial DHCP request.</help>
</field>
<field> <field>
<id>option.option</id> <id>option.option</id>
<label>Option</label> <label>Option</label>
@ -15,6 +21,7 @@
<id>option.interface</id> <id>option.interface</id>
<label>Interface</label> <label>Interface</label>
<type>dropdown</type> <type>dropdown</type>
<style>selectpicker style_set</style>
<help>This adds a single interface as tag so this DHCP option can match the interface of a DHCP range.</help> <help>This adds a single interface as tag so this DHCP option can match the interface of a DHCP range.</help>
</field> </field>
<field> <field>
@ -22,18 +29,27 @@
<label>Tag</label> <label>Tag</label>
<type>select_multiple</type> <type>select_multiple</type>
<help>If the optional tags are given then this option is only sent when all the tags are matched. Can be optionally combined with an interface tag.</help> <help>If the optional tags are given then this option is only sent when all the tags are matched. Can be optionally combined with an interface tag.</help>
<style>selectpicker style_set</style>
</field>
<field>
<id>option.set_tag</id>
<label>Tag [set]</label>
<type>dropdown</type>
<help>Tag to set for requests matching this range which can be used to selectively match dhcp options</help>
<style>selectpicker style_match</style>
</field> </field>
<field> <field>
<id>option.value</id> <id>option.value</id>
<label>Value</label> <label>Value</label>
<type>text</type> <type>text</type>
<help>Value (or values) to send to the client. The special address 0.0.0.0 is taken to mean "the address of the machine running dnsmasq"</help> <help>Value (or values) to send to the client. The special address 0.0.0.0 or [::] is taken to mean "the address of the machine running dnsmasq". When using "Match", leave empty to match on the option only.</help>
</field> </field>
<field> <field>
<id>option.force</id> <id>option.force</id>
<label>Force</label> <label>Force</label>
<type>checkbox</type> <type>checkbox</type>
<help>Always send the option, also when the client does not ask for it in the parameter request list.</help> <help>Always send the option, also when the client does not ask for it in the parameter request list.</help>
<style>style_set</style>
<grid_view> <grid_view>
<type>boolean</type> <type>boolean</type>
<formatter>boolean</formatter> <formatter>boolean</formatter>

View File

@ -32,6 +32,7 @@ namespace OPNsense\Firewall\Api;
use OPNsense\Base\ApiMutableModelControllerBase; use OPNsense\Base\ApiMutableModelControllerBase;
use OPNsense\Base\UserException; use OPNsense\Base\UserException;
use OPNsense\Core\AppConfig;
use OPNsense\Core\Backend; use OPNsense\Core\Backend;
use OPNsense\Core\Config; use OPNsense\Core\Config;
use OPNsense\Firewall\Category; use OPNsense\Firewall\Category;
@ -256,7 +257,8 @@ class AliasController extends ApiMutableModelControllerBase
] ]
]; ];
foreach (explode("\n", file_get_contents('/usr/local/opnsense/contrib/tzdata/iso3166.tab')) as $line) { $contribDir = (new AppConfig())->application->contribDir;
foreach (explode("\n", file_get_contents($contribDir . '/tzdata/iso3166.tab')) as $line) {
$line = trim($line); $line = trim($line);
if (strlen($line) > 3 && substr($line, 0, 1) != '#') { if (strlen($line) > 3 && substr($line, 0, 1) != '#') {
$result[substr($line, 0, 2)] = array( $result[substr($line, 0, 2)] = array(
@ -265,7 +267,7 @@ class AliasController extends ApiMutableModelControllerBase
); );
} }
} }
foreach (explode("\n", file_get_contents('/usr/local/opnsense/contrib/tzdata/zone.tab')) as $line) { foreach (explode("\n", file_get_contents($contribDir . '/tzdata/zone.tab')) as $line) {
if (strlen($line) > 0 && substr($line, 0, 1) == '#') { if (strlen($line) > 0 && substr($line, 0, 1) == '#') {
continue; continue;
} }

View File

@ -168,6 +168,16 @@
<sortable>false</sortable> <sortable>false</sortable>
</grid_view> </grid_view>
</field> </field>
<field>
<id>rule.icmptype</id>
<label>ICMP type</label>
<type>select_multiple</type>
<hint>Any</hint>
<advanced>true</advanced>
<grid_view>
<ignore>true</ignore>
</grid_view>
</field>
<field> <field>
<id>rule.source_not</id> <id>rule.source_not</id>
<label>Invert Source</label> <label>Invert Source</label>

View File

@ -0,0 +1,138 @@
<?php
/*
* Copyright (C) 2025 Deciso B.V.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
namespace OPNsense\Interfaces\Api;
use OPNsense\Base\ApiMutableModelControllerBase;
use OPNsense\Base\UserException;
use OPNsense\Core\Backend;
use OPNsense\Core\Config;
/**
* @package OPNsense\Interfaces
*/
class BridgeSettingsController extends ApiMutableModelControllerBase
{
protected static $internalModelName = 'bridge';
protected static $internalModelClass = 'OPNsense\Interfaces\Bridge';
/**
* search bridges
* @return array search results
*/
public function searchItemAction()
{
return $this->searchBase("bridged", null, "descr");
}
/**
* Update bridge with given properties
* @param string $uuid internal id
* @return array save result + validation output
*/
public function setItemAction($uuid)
{
Config::getInstance()->lock();
$node = $this->getModel()->getNodeByReference('bridged.' . $uuid);
$overlay = null;
if (!empty($node)) {
// not allowed to change bridge interface name
$overlay['bridgeif'] = (string)$node->bridgeif;
}
return $this->setBase("bridge", "bridged", $uuid, $overlay);
}
/**
* Add new bridge and set with attributes from post
* @return array save result + validation output
*/
public function addItemAction()
{
Config::getInstance()->lock();
$overlay = [];
$ifnames = [];
foreach ($this->getModel()->bridged->iterateItems() as $node) {
$ifnames[] = (string)$node->bridgeif;
}
for ($i = 0; true; ++$i) {
$gifif = sprintf('bridge%d', $i);
if (!in_array($gifif, $ifnames)) {
$overlay['bridgeif'] = $gifif;
break;
}
}
return $this->addBase("bridge", "bridged", $overlay);
}
/**
* Retrieve bridge settings or return defaults for new one
* @param $uuid item unique id
* @return array bridge content
*/
public function getItemAction($uuid = null)
{
return $this->getBase("bridge", "bridged", $uuid);
}
/**
* Delete bridge by uuid
* @param string $uuid internal id
* @return array save status
*/
public function delItemAction($uuid)
{
Config::getInstance()->lock();
$node = $this->getModel()->getNodeByReference('bridged.' . $uuid);
if ($node != null) {
$cfg = Config::getInstance()->object();
foreach ($cfg->interfaces->children() as $key => $value) {
if ((string)$value->if == (string)$node->bridgeif) {
throw new \OPNsense\Base\UserException(
sprintf(gettext("Cannot delete bridge. Currently in use by [%s] %s"), $key, $value),
gettext("bridge in use")
);
}
}
}
return $this->delBase("bridged", $uuid);
}
/**
* reconfigure bridges
*/
public function reconfigureAction()
{
if ($this->request->isPost()) {
(new Backend())->configdRun("interface bridge configure");
return ["status" => "ok"];
} else {
return ["status" => "failed"];
}
}
}

View File

@ -0,0 +1,40 @@
<?php
/*
* Copyright (C) 2025 Deciso B.V.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
namespace OPNsense\Interfaces;
class BridgeController extends \OPNsense\Base\IndexController
{
public function indexAction()
{
$this->view->pick('OPNsense/Interface/bridge');
$this->view->formDialogBridge = $this->getForm("dialogBridge");
$this->view->formGridBridge = $this->getFormGrid("dialogBridge");
}
}

View File

@ -0,0 +1,194 @@
<form>
<field>
<id>bridge.bridgeif</id>
<label>Device</label>
<type>info</type>
<grid_view>
<width>12em</width>
</grid_view>
</field>
<field>
<id>bridge.members</id>
<label>Member interfaces</label>
<type>select_multiple</type>
<help>Interfaces participating in the bridge.</help>
</field>
<field>
<id>bridge.descr</id>
<label>Description</label>
<type>text</type>
<help>You may enter a description here for your reference (not parsed).</help>
</field>
<field>
<id>bridge.linklocal</id>
<label>Enable link-local address</label>
<type>checkbox</type>
<help>By default, link-local addresses for bridges are disabled. You can enable them manually using this option. However, when a bridge interface has IPv6 addresses, IPv6 addresses on a member interface will be automatically removed before the interface is added.</help>
<grid_view>
<type>boolean</type>
<formatter>boolean</formatter>
</grid_view>
</field>
<field>
<type>header</type>
<label>Spanning Tree Protocol (RSTP/STP)</label>
<advanced>true</advanced>
</field>
<field>
<id>bridge.enablestp</id>
<label>Enable</label>
<type>checkbox</type>
<help>Enable spanning tree options for this bridge.</help>
<advanced>true</advanced>
<grid_view>
<type>boolean</type>
<formatter>boolean</formatter>
<visible>false</visible>
</grid_view>
</field>
<field>
<id>bridge.proto</id>
<label>Protocol</label>
<type>dropdown</type>
<help>Protocol used for spanning tree.</help>
<advanced>true</advanced>
<grid_view>
<visible>false</visible>
</grid_view>
</field>
<field>
<id>bridge.stp</id>
<label>STP interfaces</label>
<type>select_multiple</type>
<help>Enable Spanning Tree Protocol on interface. The if_bridge(4) driver has support for the IEEE 802.1D Spanning Tree Protocol (STP). STP is used to detect and remove loops in a network topology.</help>
<advanced>true</advanced>
<grid_view>
<visible>false</visible>
</grid_view>
</field>
<field>
<id>bridge.maxage</id>
<label>Valid time</label>
<type>text</type>
<help>Set the time that a Spanning Tree Protocol configuration is valid. The default is 20 seconds. The minimum is 6 seconds and the maximum is 40 seconds.</help>
<advanced>true</advanced>
<grid_view>
<visible>false</visible>
</grid_view>
</field>
<field>
<id>bridge.fwdelay</id>
<label>Forward time</label>
<type>text</type>
<help>Set the time that must pass before an interface begins forwarding packets when Spanning Tree is enabled. The default is 15 seconds. The minimum is 4 seconds and the maximum is 30 seconds.</help>
<advanced>true</advanced>
<grid_view>
<visible>false</visible>
</grid_view>
</field>
<field>
<id>bridge.holdcnt</id>
<label>Hold count</label>
<type>text</type>
<help>Set the transmit hold count for Spanning Tree. This is the number of packets transmitted before being rate limited. The default is 6. The minimum is 1 and the maximum is 10.</help>
<advanced>true</advanced>
<grid_view>
<visible>false</visible>
</grid_view>
</field>
<field>
<type>header</type>
<label>Advanced</label>
<advanced>true</advanced>
</field>
<field>
<id>bridge.maxaddr</id>
<label>Cache size</label>
<type>text</type>
<help>Set the size of the bridge address cache to size. The default is 2000 entries.</help>
<advanced>true</advanced>
<grid_view>
<visible>false</visible>
</grid_view>
</field>
<field>
<id>bridge.timeout</id>
<label>Cache entry expire time (s)</label>
<type>text</type>
<help>Set the timeout of address cache entries to this number of seconds. If seconds is zero, then address cache entries will not be expired. The default is 1200 seconds.</help>
<advanced>true</advanced>
<grid_view>
<visible>false</visible>
</grid_view>
</field>
<field>
<id>bridge.span</id>
<label>Span port</label>
<type>dropdown</type>
<help>Add the interface named by interface as a span port on the bridge. Span ports transmit a copy of every frame received by the bridge. This is most useful for snooping a bridged network passively on another host connected to one of the span ports of the bridge.</help>
<advanced>true</advanced>
<grid_view>
<visible>false</visible>
</grid_view>
</field>
<field>
<id>bridge.edge</id>
<label>Edge ports</label>
<type>select_multiple</type>
<help>Set interface as an edge port. An edge port connects directly to end stations and cannot create bridging loops in the network; this allows it to transition straight to forwarding.</help>
<advanced>true</advanced>
<grid_view>
<visible>false</visible>
</grid_view>
</field>
<field>
<id>bridge.autoedge</id>
<label>Auto Edge ports</label>
<type>select_multiple</type>
<help>Allow interface to automatically detect edge status. This is the default for all interfaces added to a bridge. (This will disable the autoedge status of interfaces.)</help>
<advanced>true</advanced>
<grid_view>
<visible>false</visible>
</grid_view>
</field>
<field>
<id>bridge.ptp</id>
<label>PTP ports</label>
<type>select_multiple</type>
<help>Set the interface as a point-to-point link. This is required for straight transitions to forwarding and should be enabled on a direct link to another RSTP-capable switch.</help>
<advanced>true</advanced>
<grid_view>
<visible>false</visible>
</grid_view>
</field>
<field>
<id>bridge.autoptp</id>
<label>Auto PTP ports</label>
<type>select_multiple</type>
<help>Automatically detect the point-to-point status on interface by checking the full duplex link status. This is the default for interfaces added to the bridge. (The interfaces selected here will be removed from default autoedge status.)</help>
<advanced>true</advanced>
<grid_view>
<visible>false</visible>
</grid_view>
</field>
<field>
<id>bridge.static</id>
<label>Sticky ports</label>
<type>select_multiple</type>
<help>Mark an interface as a "sticky" interface. Dynamically learned address entries are treated as static once entered into the cache. Sticky entries are never aged out of the cache or replaced, even if the address is seen on a different interface.</help>
<advanced>true</advanced>
<grid_view>
<visible>false</visible>
</grid_view>
</field>
<field>
<id>bridge.private</id>
<label>Private ports</label>
<type>select_multiple</type>
<help>Mark an interface as a "private" interface. A private interface does not forward any traffic to any other port that is also a private interface.</help>
<advanced>true</advanced>
<grid_view>
<visible>false</visible>
</grid_view>
</field>
</form>

View File

@ -0,0 +1,188 @@
<?php
/*
* Copyright (C) 2025 Deciso B.V.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
namespace OPNsense\Kea\Api;
use OPNsense\Base\ApiMutableModelControllerBase;
use OPNsense\Core\Config;
use OPNsense\Firewall\Util;
class Dhcpv6Controller extends ApiMutableModelControllerBase
{
protected static $internalModelName = 'dhcpv6';
protected static $internalModelClass = 'OPNsense\Kea\KeaDhcpv6';
/**
* @inheritdoc
*/
public function getAction()
{
$data = parent::getAction();
return [
self::$internalModelName => [
'general' => $data[self::$internalModelName]['general'],
'ha' => $data[self::$internalModelName]['ha'],
'this_hostname' => (string)Config::getInstance()->object()->system->hostname
]
];
}
public function searchSubnetAction()
{
return $this->searchBase("subnets.subnet6", null, "subnet");
}
public function setSubnetAction($uuid)
{
return $this->setBase("subnet6", "subnets.subnet6", $uuid);
}
public function addSubnetAction()
{
return $this->addBase("subnet6", "subnets.subnet6");
}
public function getSubnetAction($uuid = null)
{
return $this->getBase("subnet6", "subnets.subnet6", $uuid);
}
public function delSubnetAction($uuid)
{
return $this->delBase("subnets.subnet6", $uuid);
}
public function searchReservationAction()
{
return $this->searchBase("reservations.reservation", null, "duid");
}
public function setReservationAction($uuid)
{
return $this->setBase("reservation", "reservations.reservation", $uuid);
}
public function addReservationAction()
{
return $this->addBase("reservation", "reservations.reservation");
}
public function getReservationAction($uuid = null)
{
return $this->getBase("reservation", "reservations.reservation", $uuid);
}
public function delReservationAction($uuid)
{
return $this->delBase("reservations.reservation", $uuid);
}
public function downloadReservationsAction()
{
if ($this->request->isGet()) {
$this->exportCsv($this->getModel()->reservations->reservation->asRecordSet(false, ['subnet']));
}
}
public function uploadReservationsAction()
{
if ($this->request->isPost() && $this->request->hasPost('payload')) {
$subnets = [];
foreach ($this->getModel()->subnets->subnet6->iterateItems() as $key => $node) {
$subnets[(string)$node->subnet] = $key;
}
return $this->importCsv(
'reservations.reservation',
$this->request->getPost('payload'),
['duid', 'subnet'],
function (&$record) use ($subnets) {
/* seek matching subnet */
if (!empty($record['ip_address'])) {
foreach ($subnets as $subnet => $uuid) {
if (Util::isIPInCIDR($record['ip_address'], $subnet)) {
$record['subnet'] = $uuid;
}
}
}
}
);
} else {
return ['status' => 'failed'];
}
}
public function searchPdPoolAction()
{
return $this->searchBase("pd_pools.pd_pool");
}
public function setPdPoolAction($uuid)
{
return $this->setBase("pd_pool", "pd_pools.pd_pool", $uuid);
}
public function addPdPoolAction()
{
return $this->addBase("pd_pool", "pd_pools.pd_pool");
}
public function getPdPoolAction($uuid = null)
{
return $this->getBase("pd_pool", "pd_pools.pd_pool", $uuid);
}
public function delPdPoolAction($uuid)
{
return $this->delBase("pd_pools.pd_pool", $uuid);
}
public function searchPeerAction()
{
return $this->searchBase("ha_peers.peer", null, "name");
}
public function setPeerAction($uuid)
{
return $this->setBase("peer", "ha_peers.peer", $uuid);
}
public function addPeerAction()
{
return $this->addBase("peer", "ha_peers.peer");
}
public function getPeerAction($uuid = null)
{
return $this->getBase("peer", "ha_peers.peer", $uuid);
}
public function delPeerAction($uuid)
{
return $this->delBase("ha_peers.peer", $uuid);
}
}

View File

@ -30,6 +30,8 @@ namespace OPNsense\Kea\Api;
use OPNsense\Base\ApiMutableServiceControllerBase; use OPNsense\Base\ApiMutableServiceControllerBase;
use OPNsense\Core\Backend; use OPNsense\Core\Backend;
use OPNsense\Kea\KeaDhcpv4;
use OPNsense\Kea\KeaDhcpv6;
class ServiceController extends ApiMutableServiceControllerBase class ServiceController extends ApiMutableServiceControllerBase
{ {
@ -38,8 +40,8 @@ class ServiceController extends ApiMutableServiceControllerBase
protected static $internalServiceEnabled = 'general.enabled'; protected static $internalServiceEnabled = 'general.enabled';
protected static $internalServiceName = 'kea'; protected static $internalServiceName = 'kea';
/** protected function serviceEnabled()
* TODO: overwrite when implementing KeaDhcpv6 as well. Both services share the same rc script {
* protected function serviceEnabled() {} return (new KeaDhcpv4())->general->enabled == '1' || (new KeaDhcpv6())->general->enabled == '1';
*/ }
} }

View File

@ -61,6 +61,24 @@ class DhcpController extends \OPNsense\Base\IndexController
$this->view->formGridPeer = $this->getFormGrid("dialogPeer4"); $this->view->formGridPeer = $this->getFormGrid("dialogPeer4");
} }
public function v6Action()
{
$this->view->pick('OPNsense/Kea/dhcpv6');
$this->view->formGeneralSettings = $this->getForm("generalSettings6");
$this->view->formDialogSubnet = $this->getForm("dialogSubnet6");
$this->view->formGridSubnet = $this->getFormGrid("dialogSubnet6");
$this->view->formDialogReservation = $this->getForm("dialogReservation6");
$this->view->formGridReservation = $this->getFormGrid("dialogReservation6");
$this->view->formDialogPDPool = $this->getForm("dialogPDPool6");
$this->view->formGridPDPool = $this->getFormGrid("dialogPDPool6");
$this->view->formDialogPeer = $this->getForm("dialogPeer6");
$this->view->formGridPeer = $this->getFormGrid("dialogPeer6");
}
public function leases4Action() public function leases4Action()
{ {
$this->view->pick('OPNsense/Kea/leases4'); $this->view->pick('OPNsense/Kea/leases4');

View File

@ -0,0 +1,32 @@
<form>
<field>
<id>pd_pool.subnet</id>
<label>Subnet</label>
<type>dropdown</type>
<help>Subnet this reservation belongs to</help>
</field>
<field>
<id>pd_pool.prefix</id>
<label>Prefix</label>
<type>text</type>
<help></help>
</field>
<field>
<id>pd_pool.prefix_len</id>
<label>Prefix length</label>
<type>text</type>
<help></help>
</field>
<field>
<id>pd_pool.delegated_len</id>
<label>Delegated Length</label>
<type>text</type>
<help></help>
</field>
<field>
<id>pd_pool.description</id>
<label>Description</label>
<type>text</type>
<help>You may enter a description here for your reference (not parsed).</help>
</field>
</form>

View File

@ -0,0 +1,21 @@
<form>
<field>
<id>peer.name</id>
<label>Name</label>
<type>text</type>
<help>Peer name, there should be one entry matching this machines "This server name"</help>
</field>
<field>
<id>peer.role</id>
<label>Role</label>
<type>dropdown</type>
<help>This peers role</help>
</field>
<field>
<id>peer.url</id>
<label>Url</label>
<type>text</type>
<help>This specifies the URL of our server instance, which should use a different port than the control agent.
For example http://my.host:8001/</help>
</field>
</form>

View File

@ -0,0 +1,44 @@
<form>
<field>
<id>reservation.subnet</id>
<label>Subnet</label>
<type>dropdown</type>
<help>Subnet this reservation belongs to</help>
</field>
<field>
<id>reservation.ip_address</id>
<label>IP address</label>
<type>text</type>
<help>IP address to offer to the client</help>
</field>
<field>
<id>reservation.duid</id>
<label>DUID</label>
<type>text</type>
<help>duid of the client in question</help>
</field>
<field>
<id>reservation.hostname</id>
<label>Hostname</label>
<type>text</type>
<help>Offer a hostname to the client</help>
</field>
<field>
<id>reservation.domain_search</id>
<label>Domain search</label>
<type>select_multiple</type>
<style>tokenize</style>
<allownew>true</allownew>
<separator>,</separator>
<help>Specifies a ´search list´ of Domain Names to be used by the client to locate not-fully-qualified domain names.</help>
<grid_view>
<visible>false</visible>
</grid_view>
</field>
<field>
<id>reservation.description</id>
<label>Description</label>
<type>text</type>
<help>You may enter a description here for your reference (not parsed).</help>
</field>
</form>

View File

@ -0,0 +1,47 @@
<form>
<field>
<id>subnet6.subnet</id>
<label>Subnet</label>
<type>text</type>
<help>Subnet to use, should be large enough to hold the specified pools and reservations</help>
</field>
<field>
<id>subnet6.description</id>
<label>Description</label>
<type>text</type>
<help>You may enter a description here for your reference (not parsed).</help>
</field>
<field>
<id>subnet6.pools</id>
<label>Pools</label>
<type>textbox</type>
<help>List of pools, one per line in range or subnet format (e.g. 2001:db8:1::-2001:db8:1::100, 2001:db8:1::/80</help>
</field>
<field>
<type>header</type>
<label>DHCP option data</label>
</field>
<field>
<id>subnet6.option_data.dns_servers</id>
<label>DNS servers</label>
<type>select_multiple</type>
<style>tokenize</style>
<allownew>true</allownew>
<help>DNS servers to offer to the clients</help>
<grid_view>
<visible>false</visible>
</grid_view>
</field>
<field>
<id>subnet6.option_data.domain_search</id>
<label>Domain search</label>
<type>select_multiple</type>
<style>tokenize</style>
<allownew>true</allownew>
<separator>,</separator>
<help>Specifies a ´search list´ of Domain Names to be used by the client to locate not-fully-qualified domain names.</help>
<grid_view>
<visible>false</visible>
</grid_view>
</field>
</form>

View File

@ -1,7 +1,7 @@
<form> <form>
<field> <field>
<type>header</type> <type>header</type>
<label>General settings</label> <label>Service</label>
</field> </field>
<field> <field>
<id>dhcpv4.general.enabled</id> <id>dhcpv4.general.enabled</id>
@ -9,6 +9,17 @@
<type>checkbox</type> <type>checkbox</type>
<help>Enable DHCPv4 server.</help> <help>Enable DHCPv4 server.</help>
</field> </field>
<field>
<id>dhcpv4.general.manual_config</id>
<label>Manual config</label>
<type>checkbox</type>
<advanced>true</advanced>
<help>Disable configuration file generation and manage the file (/usr/local/etc/kea/kea-dhcp4.conf) manually.</help>
</field>
<field>
<type>header</type>
<label>General settings</label>
</field>
<field> <field>
<id>dhcpv4.general.interfaces</id> <id>dhcpv4.general.interfaces</id>
<label>Interfaces</label> <label>Interfaces</label>

View File

@ -0,0 +1,69 @@
<form>
<field>
<type>header</type>
<label>Service</label>
</field>
<field>
<id>dhcpv6.general.enabled</id>
<label>Enabled</label>
<type>checkbox</type>
<help>Enable DHCPv6 server.</help>
</field>
<field>
<id>dhcpv6.general.manual_config</id>
<label>Manual config</label>
<type>checkbox</type>
<advanced>true</advanced>
<help>Disable configuration file generation and manage the file (/usr/local/etc/kea/kea-dhcp4.conf) manually.</help>
</field>
<field>
<type>header</type>
<label>General settings</label>
</field>
<field>
<id>dhcpv6.general.interfaces</id>
<label>Interfaces</label>
<type>select_multiple</type>
<help>Select interfaces to listen on.</help>
</field>
<field>
<id>dhcpv6.general.valid_lifetime</id>
<label>Valid lifetime</label>
<type>text</type>
<help>Defines how long the addresses (leases) given out by the server are valid (in seconds)</help>
</field>
<field>
<id>dhcpv6.general.fwrules</id>
<label>Firewall rules</label>
<type>checkbox</type>
<help>Automatically add a basic set of firewall rules to allow dhcp traffic, more fine grained controls can be offered manually when disabling this option.</help>
</field>
<field>
<type>header</type>
<label>High Availability</label>
</field>
<field>
<id>dhcpv6.ha.enabled</id>
<label>Enabled</label>
<type>checkbox</type>
<help>Enable High availability hook, requires the Control Agent to be enabled as well.</help>
</field>
<field>
<id>dhcpv6.ha.this_server_name</id>
<label>This server name</label>
<type>text</type>
<help>The name of this server, should match with one of the entries in the HA peers.
Leave empty to use this machines hostname
</help>
</field>
<field>
<id>dhcpv6.ha.max_unacked_clients</id>
<label>Max Unacked clients</label>
<type>text</type>
<help>
This specifies the number of clients which send messages to the partner but appear to not receive any response.
A higher value needs a busier environment in order to consider a member down, when set to 0,
any network disruption will cause a failover to happen.
</help>
</field>
</form>

View File

@ -57,6 +57,13 @@
<style>export_option</style> <style>export_option</style>
<help>Sets auth-nocache in the exported configuration when password authentication is used. This prevents OpenVPN from caching passwords in memory.</help> <help>Sets auth-nocache in the exported configuration when password authentication is used. This prevents OpenVPN from caching passwords in memory.</help>
</field> </field>
<field>
<id>openvpn_export.static_challenge</id>
<label>Enable static challenge (OTP)</label>
<type>checkbox</type>
<style>export_option</style>
<help>Ask the user for its one time password token separately (instead of as part the password).</help>
</field>
<field> <field>
<id>openvpn_export.plain_config</id> <id>openvpn_export.plain_config</id>
<label>Custom config</label> <label>Custom config</label>

View File

@ -58,10 +58,17 @@
</field> </field>
<field> <field>
<id>gateway_item.monitor_killstates</id> <id>gateway_item.monitor_killstates</id>
<label>Kill states when down</label> <label>Failover States</label>
<type>checkbox</type> <type>checkbox</type>
<style>monitor_opt</style> <style>monitor_opt</style>
<help>When a monitor down event is triggered, kill all states to this gateway.</help> <help>If this gateway goes down, force clients to reconnect over a different online gateway by killing states associated with this gateway. This option requires "default gateway switching" to be enabled, or this gateway assigned as part of a gateway group to trigger.</help>
</field>
<field>
<id>gateway_item.monitor_killstates_priority</id>
<label>Failback States</label>
<type>checkbox</type>
<style>monitor_opt</style>
<help>If another gateway comes up with a higher priority than this gateway, force clients to reconnect by killing states associated with this gateway. This option requires "default gateway switching" to be enabled, or this gateway assigned as part of a gateway group to trigger. The common use case for this option are metered connections over LTE that should only be used when no other gateway is online.</help>
</field> </field>
<field> <field>
<id>gateway_item.monitor</id> <id>gateway_item.monitor</id>

View File

@ -114,11 +114,7 @@ class SettingsController extends ApiMutableModelControllerBase
*/ */
public function searchPipesAction() public function searchPipesAction()
{ {
return $this->searchBase( return $this->searchBase("pipes.pipe", null, "number");
"pipes.pipe",
array("enabled","number", "bandwidth","bandwidthMetric","description","mask","origin"),
"number"
);
} }
@ -129,11 +125,7 @@ class SettingsController extends ApiMutableModelControllerBase
*/ */
public function searchQueuesAction() public function searchQueuesAction()
{ {
return $this->searchBase( return $this->searchBase("queues.queue", null, "number");
"queues.queue",
array("enabled","number", "pipe","weight","description","mask","origin"),
"number"
);
} }
/** /**
@ -204,12 +196,7 @@ class SettingsController extends ApiMutableModelControllerBase
*/ */
public function searchRulesAction() public function searchRulesAction()
{ {
return $this->searchBase( return $this->searchBase("rules.rule", null, "sequence");
"rules.rule",
array("enabled", "interface", "proto", "source_not","source", "destination_not",
"destination", "description", "origin", "sequence", "target"),
"sequence"
);
} }
/** /**

View File

@ -44,8 +44,14 @@ class IndexController extends \OPNsense\Base\IndexController
{ {
// include dialog form definitions // include dialog form definitions
$this->view->formDialogPipe = $this->getForm("dialogPipe"); $this->view->formDialogPipe = $this->getForm("dialogPipe");
$this->view->formGridPipe = $this->getFormGrid("dialogPipe");
$this->view->formDialogQueue = $this->getForm("dialogQueue"); $this->view->formDialogQueue = $this->getForm("dialogQueue");
$this->view->formGridQueue = $this->getFormGrid("dialogQueue");
$this->view->formDialogRule = $this->getForm("dialogRule"); $this->view->formDialogRule = $this->getForm("dialogRule");
$this->view->formGridRule = $this->getFormGrid("dialogRule");
// choose template // choose template
$this->view->pick('OPNsense/TrafficShaper/index'); $this->view->pick('OPNsense/TrafficShaper/index');
} }

View File

@ -4,6 +4,11 @@
<label>Enabled</label> <label>Enabled</label>
<type>checkbox</type> <type>checkbox</type>
<help>Enable this pipe and its related queues and rules</help> <help>Enable this pipe and its related queues and rules</help>
<grid_view>
<width>6em</width>
<type>boolean</type>
<formatter>rowtoggle</formatter>
</grid_view>
</field> </field>
<field> <field>
<id>pipe.bandwidth</id> <id>pipe.bandwidth</id>
@ -22,6 +27,9 @@
<type>text</type> <type>text</type>
<help>number of dynamic queues, leave empty for default</help> <help>number of dynamic queues, leave empty for default</help>
<advanced>true</advanced> <advanced>true</advanced>
<grid_view>
<visible>false</visible>
</grid_view>
</field> </field>
<field> <field>
<id>pipe.mask</id> <id>pipe.mask</id>
@ -39,6 +47,9 @@
<type>text</type> <type>text</type>
<help>Specifies the size of the hash table used for storing the various dynamic pipes configured with the mask setting</help> <help>Specifies the size of the hash table used for storing the various dynamic pipes configured with the mask setting</help>
<advanced>true</advanced> <advanced>true</advanced>
<grid_view>
<visible>false</visible>
</grid_view>
</field> </field>
<field> <field>
<id>pipe.scheduler</id> <id>pipe.scheduler</id>
@ -46,12 +57,20 @@
<type>dropdown</type> <type>dropdown</type>
<advanced>true</advanced> <advanced>true</advanced>
<help>Specify the scheduling algorithm to use</help> <help>Specify the scheduling algorithm to use</help>
<grid_view>
<visible>false</visible>
</grid_view>
</field> </field>
<field> <field>
<id>pipe.codel_enable</id> <id>pipe.codel_enable</id>
<label>Enable CoDel</label> <label>Enable CoDel</label>
<type>checkbox</type> <type>checkbox</type>
<help>Enable CoDel active queue management</help> <help>Enable CoDel active queue management</help>
<grid_view>
<visible>false</visible>
<type>boolean</type>
<formatter>boolean</formatter>
</grid_view>
</field> </field>
<field> <field>
<id>pipe.codel_target</id> <id>pipe.codel_target</id>
@ -59,6 +78,9 @@
<type>text</type> <type>text</type>
<advanced>true</advanced> <advanced>true</advanced>
<help>Minimum acceptable persistent queue delay (in ms), leave empty for default</help> <help>Minimum acceptable persistent queue delay (in ms), leave empty for default</help>
<grid_view>
<visible>false</visible>
</grid_view>
</field> </field>
<field> <field>
<id>pipe.codel_interval</id> <id>pipe.codel_interval</id>
@ -66,6 +88,9 @@
<type>text</type> <type>text</type>
<advanced>true</advanced> <advanced>true</advanced>
<help>Interval before dropping packets (in ms), leave empty for default</help> <help>Interval before dropping packets (in ms), leave empty for default</help>
<grid_view>
<visible>false</visible>
</grid_view>
</field> </field>
<field> <field>
<id>pipe.codel_ecn_enable</id> <id>pipe.codel_ecn_enable</id>
@ -73,6 +98,11 @@
<type>checkbox</type> <type>checkbox</type>
<advanced>true</advanced> <advanced>true</advanced>
<help>Explicit Congestion Notification</help> <help>Explicit Congestion Notification</help>
<grid_view>
<visible>false</visible>
<type>boolean</type>
<formatter>boolean</formatter>
</grid_view>
</field> </field>
<field> <field>
<id>pipe.fqcodel_quantum</id> <id>pipe.fqcodel_quantum</id>
@ -80,6 +110,9 @@
<type>text</type> <type>text</type>
<advanced>true</advanced> <advanced>true</advanced>
<help>The number of bytes a queue can serve before being moved to the tail of old queues list (bytes), leave empty for defaults</help> <help>The number of bytes a queue can serve before being moved to the tail of old queues list (bytes), leave empty for defaults</help>
<grid_view>
<visible>false</visible>
</grid_view>
</field> </field>
<field> <field>
<id>pipe.fqcodel_limit</id> <id>pipe.fqcodel_limit</id>
@ -87,6 +120,9 @@
<type>text</type> <type>text</type>
<advanced>true</advanced> <advanced>true</advanced>
<help>The hard size limit of all queues managed by this instance, leave empty for defaults</help> <help>The hard size limit of all queues managed by this instance, leave empty for defaults</help>
<grid_view>
<visible>false</visible>
</grid_view>
</field> </field>
<field> <field>
<id>pipe.fqcodel_flows</id> <id>pipe.fqcodel_flows</id>
@ -94,12 +130,20 @@
<type>text</type> <type>text</type>
<advanced>true</advanced> <advanced>true</advanced>
<help>The number of flow queues that are created and managed, leave empty for defaults</help> <help>The number of flow queues that are created and managed, leave empty for defaults</help>
<grid_view>
<visible>false</visible>
</grid_view>
</field> </field>
<field> <field>
<id>pipe.pie_enable</id> <id>pipe.pie_enable</id>
<label>Enable PIE</label> <label>Enable PIE</label>
<type>checkbox</type> <type>checkbox</type>
<help>Enable PIE active queue management</help> <help>Enable PIE active queue management</help>
<grid_view>
<visible>false</visible>
<type>boolean</type>
<formatter>boolean</formatter>
</grid_view>
</field> </field>
<field> <field>
<id>pipe.delay</id> <id>pipe.delay</id>
@ -107,6 +151,9 @@
<type>text</type> <type>text</type>
<advanced>true</advanced> <advanced>true</advanced>
<help>Add delay in ms to this pipe.</help> <help>Add delay in ms to this pipe.</help>
<grid_view>
<visible>false</visible>
</grid_view>
</field> </field>
<field> <field>
<id>pipe.description</id> <id>pipe.description</id>

View File

@ -4,6 +4,11 @@
<label>Enabled</label> <label>Enabled</label>
<type>checkbox</type> <type>checkbox</type>
<help>Enable this queue and its related rules</help> <help>Enable this queue and its related rules</help>
<grid_view>
<width>6em</width>
<type>boolean</type>
<formatter>rowtoggle</formatter>
</grid_view>
</field> </field>
<field> <field>
<id>queue.pipe</id> <id>queue.pipe</id>
@ -26,6 +31,9 @@
<li>Choose source to evenly share every IP in the source field of rules the specified bandwidth. Normally this is used for upload queues.</li> <li>Choose source to evenly share every IP in the source field of rules the specified bandwidth. Normally this is used for upload queues.</li>
<li>Leave this value empty if you want to specify multiple queues with different weights.</li> <li>Leave this value empty if you want to specify multiple queues with different weights.</li>
]]></help> ]]></help>
<grid_view>
<visible>false</visible>
</grid_view>
</field> </field>
<field> <field>
<id>queue.buckets</id> <id>queue.buckets</id>
@ -33,12 +41,20 @@
<type>text</type> <type>text</type>
<help>Specifies the size of the hash table used for storing the various dynamic queues configured with the mask setting</help> <help>Specifies the size of the hash table used for storing the various dynamic queues configured with the mask setting</help>
<advanced>true</advanced> <advanced>true</advanced>
<grid_view>
<visible>false</visible>
</grid_view>
</field> </field>
<field> <field>
<id>queue.codel_enable</id> <id>queue.codel_enable</id>
<label>Enable CoDel</label> <label>Enable CoDel</label>
<type>checkbox</type> <type>checkbox</type>
<help>Enable CoDel active queue management</help> <help>Enable CoDel active queue management</help>
<grid_view>
<visible>false</visible>
<type>boolean</type>
<formatter>boolean</formatter>
</grid_view>
</field> </field>
<field> <field>
<id>queue.codel_target</id> <id>queue.codel_target</id>
@ -46,6 +62,9 @@
<type>text</type> <type>text</type>
<advanced>true</advanced> <advanced>true</advanced>
<help>Minimum acceptable persistent queue delay (in ms), leave empty for default</help> <help>Minimum acceptable persistent queue delay (in ms), leave empty for default</help>
<grid_view>
<visible>false</visible>
</grid_view>
</field> </field>
<field> <field>
<id>queue.codel_interval</id> <id>queue.codel_interval</id>
@ -53,6 +72,9 @@
<type>text</type> <type>text</type>
<advanced>true</advanced> <advanced>true</advanced>
<help>Interval before dropping packets (in ms), leave empty for default</help> <help>Interval before dropping packets (in ms), leave empty for default</help>
<grid_view>
<visible>false</visible>
</grid_view>
</field> </field>
<field> <field>
<id>queue.codel_ecn_enable</id> <id>queue.codel_ecn_enable</id>
@ -60,12 +82,22 @@
<type>checkbox</type> <type>checkbox</type>
<advanced>true</advanced> <advanced>true</advanced>
<help>Explicit Congestion Notification</help> <help>Explicit Congestion Notification</help>
<grid_view>
<visible>false</visible>
<type>boolean</type>
<formatter>boolean</formatter>
</grid_view>
</field> </field>
<field> <field>
<id>queue.pie_enable</id> <id>queue.pie_enable</id>
<label>Enable PIE</label> <label>Enable PIE</label>
<type>checkbox</type> <type>checkbox</type>
<help>Enable PIE active queue management</help> <help>Enable PIE active queue management</help>
<grid_view>
<visible>false</visible>
<type>boolean</type>
<formatter>boolean</formatter>
</grid_view>
</field> </field>
<field> <field>
<id>queue.description</id> <id>queue.description</id>

View File

@ -4,6 +4,11 @@
<label>Enabled</label> <label>Enabled</label>
<type>checkbox</type> <type>checkbox</type>
<help>enable this rule</help> <help>enable this rule</help>
<grid_view>
<width>6em</width>
<type>boolean</type>
<formatter>rowtoggle</formatter>
</grid_view>
</field> </field>
<field> <field>
<id>rule.sequence</id> <id>rule.sequence</id>
@ -22,6 +27,9 @@
<type>dropdown</type> <type>dropdown</type>
<advanced>true</advanced> <advanced>true</advanced>
<help>secondary interface, matches packets traveling to/from interface (1) to/from interface (2). can be combined with direction.</help> <help>secondary interface, matches packets traveling to/from interface (1) to/from interface (2). can be combined with direction.</help>
<grid_view>
<visible>false</visible>
</grid_view>
</field> </field>
<field> <field>
<id>rule.proto</id> <id>rule.proto</id>
@ -35,6 +43,9 @@
<advanced>true</advanced> <advanced>true</advanced>
<type>text</type> <type>text</type>
<help>Specifies the maximum size of packets to match in bytes</help> <help>Specifies the maximum size of packets to match in bytes</help>
<grid_view>
<visible>false</visible>
</grid_view>
</field> </field>
<field> <field>
<id>rule.source</id> <id>rule.source</id>
@ -49,12 +60,18 @@
<label>Invert source</label> <label>Invert source</label>
<type>checkbox</type> <type>checkbox</type>
<help>invert source (not)</help> <help>invert source (not)</help>
<grid_view>
<ignore>true</ignore>
</grid_view>
</field> </field>
<field> <field>
<id>rule.src_port</id> <id>rule.src_port</id>
<label>Src-port</label> <label>Src-port</label>
<type>text</type> <type>text</type>
<help>Source port number or well known name (imap, imaps, http, https, ...), for ranges use a dash</help> <help>Source port number or well known name (imap, imaps, http, https, ...), for ranges use a dash</help>
<grid_view>
<visible>false</visible>
</grid_view>
</field> </field>
<field> <field>
<id>rule.destination</id> <id>rule.destination</id>
@ -69,12 +86,18 @@
<label>Invert destination</label> <label>Invert destination</label>
<type>checkbox</type> <type>checkbox</type>
<help>invert destination (not)</help> <help>invert destination (not)</help>
<grid_view>
<ignore>true</ignore>
</grid_view>
</field> </field>
<field> <field>
<id>rule.dst_port</id> <id>rule.dst_port</id>
<label>Dst-port</label> <label>Dst-port</label>
<type>text</type> <type>text</type>
<help>Destination port number or well known name (imap, imaps, http, https, ...), for ranges use a dash</help> <help>Destination port number or well known name (imap, imaps, http, https, ...), for ranges use a dash</help>
<grid_view>
<visible>false</visible>
</grid_view>
</field> </field>
<field> <field>
<id>rule.dscp</id> <id>rule.dscp</id>
@ -82,6 +105,9 @@
<type>select_multiple</type> <type>select_multiple</type>
<advanced>true</advanced> <advanced>true</advanced>
<help>Match against one or multiple DSCP values.</help> <help>Match against one or multiple DSCP values.</help>
<grid_view>
<visible>false</visible>
</grid_view>
</field> </field>
<field> <field>
<id>rule.direction</id> <id>rule.direction</id>
@ -89,6 +115,9 @@
<type>dropdown</type> <type>dropdown</type>
<advanced>true</advanced> <advanced>true</advanced>
<help>matches incoming or outgoing packets or both (default)</help> <help>matches incoming or outgoing packets or both (default)</help>
<grid_view>
<visible>false</visible>
</grid_view>
</field> </field>
<field> <field>
<id>rule.target</id> <id>rule.target</id>

View File

@ -352,7 +352,7 @@ class FilterRule extends Rule
} }
public function isUIFromNot() public function isUIFromNot()
{ {
return isset($this->rule['source']) && isset($this->rule['source']['not']); return (isset($this->rule['source']) && isset($this->rule['source']['not'])) || !empty($this->rule['from_not']);
} }
public function getUIFromPort() public function getUIFromPort()
{ {
@ -378,7 +378,7 @@ class FilterRule extends Rule
} }
public function isUIToNot() public function isUIToNot()
{ {
return isset($this->rule['destination']) && isset($this->rule['destination']['not']); return isset($this->rule['destination']) && isset($this->rule['destination']['not']) || !empty($this->rule['to_not']);
} }
public function getUIToPort() public function getUIToPort()
{ {

View File

@ -48,7 +48,7 @@ class ArchiveOpenVPN extends PlainOpenVPN
*/ */
public function supportedOptions() public function supportedOptions()
{ {
return array("plain_config", "p12_password", "random_local_port", "auth_nocache", "cryptoapi"); return ["plain_config", "p12_password", "random_local_port", "auth_nocache", "cryptoapi", "static_challenge"];
} }
/** /**

View File

@ -48,7 +48,7 @@ class PlainOpenVPN extends BaseExporter implements IExportProvider
*/ */
public function supportedOptions() public function supportedOptions()
{ {
return array("plain_config", "random_local_port", "auth_nocache", "cryptoapi"); return ["plain_config", "random_local_port", "auth_nocache", "cryptoapi", "static_challenge"];
} }
/** /**
@ -143,6 +143,10 @@ class PlainOpenVPN extends BaseExporter implements IExportProvider
} }
} }
if (!empty($this->config['static_challenge'])) {
$conf[] = sprintf('static-challenge "%s" 1', addslashes(gettext('Enter OTP token:')));
}
if (!empty($this->config['compression'])) { if (!empty($this->config['compression'])) {
switch ($this->config['compression']) { switch ($this->config['compression']) {
case 'no': case 'no':

View File

@ -48,7 +48,7 @@ class ViscosityVisz extends PlainOpenVPN
*/ */
public function supportedOptions() public function supportedOptions()
{ {
return array("plain_config", "p12_password", "random_local_port", "auth_nocache", "cryptoapi"); return ["plain_config", "p12_password", "random_local_port", "auth_nocache", "cryptoapi", "static_challenge"];
} }
/** /**

View File

@ -596,7 +596,11 @@ class Store
{ {
$chain = []; $chain = [];
while (($item = self::getCA(!isset($item) ? $caref : $item->caref)) != null) { while (($item = self::getCA(!isset($item) ? $caref : $item->caref)) != null) {
$chain[] = base64_decode((string)$item->crt); $data = base64_decode((string)$item->crt);
if (in_array($data, $chain)) {
break; /* exit endless loop */
}
$chain[] = $data;
} }
return implode("\n", $chain); return implode("\n", $chain);
} }

View File

@ -28,6 +28,8 @@
namespace OPNsense\Base\FieldTypes; namespace OPNsense\Base\FieldTypes;
use OPNsense\Core\AppConfig;
/** /**
* Class CountryField field type to select iso3166 countries * Class CountryField field type to select iso3166 countries
* @package OPNsense\Base\FieldTypes * @package OPNsense\Base\FieldTypes
@ -62,7 +64,8 @@ class CountryField extends BaseListField
self::$internalCacheOptionList[$setid] = []; self::$internalCacheOptionList[$setid] = [];
} }
if (empty(self::$internalCacheOptionList[$setid])) { if (empty(self::$internalCacheOptionList[$setid])) {
$filename = '/usr/local/opnsense/contrib/tzdata/iso3166.tab'; $contribDir = (new AppConfig())->application->contribDir;
$filename = $contribDir . '/tzdata/iso3166.tab';
$data = file_get_contents($filename); $data = file_get_contents($filename);
foreach (explode("\n", $data) as $line) { foreach (explode("\n", $data) as $line) {
$line = trim($line); $line = trim($line);

View File

@ -169,6 +169,27 @@ class MenuSystem
return true; return true;
} }
/**
* temporary legacy glue to remove isc dhcp4 settings when not enabled and Dnsmasq is configured as dhcp
* @return boolean
*/
private function isc_v4_enabled($if)
{
$config = Config::getInstance()->object();
if (isset($config->dhcpd) && isset($config->dhcpd->$if) && !empty((string)$config->dhcpd->$if->enable)) {
/* still configured on interface */
return true;
} elseif (isset($config->dnsmasq) && empty((string)$config->dnsmasq->enable)) {
/* dnsmasq not configured at all */
return true;
} elseif (isset($config->dnsmasq) && !empty((string)$config->dnsmasq->interface)) {
/* dnsmasq configured, but only on selected interfaces */
return !in_array($if, explode(',', $config->dnsmasq->interface));
}
return false;
}
/** /**
* construct a new menu * construct a new menu
* @throws MenuInitException * @throws MenuInitException
@ -238,10 +259,13 @@ class MenuSystem
} }
// "Services: DHCPv[46]" menu tab: // "Services: DHCPv[46]" menu tab:
if (empty($node->virtual) && isset($node->enable)) { if (empty($node->virtual) && isset($node->enable)) {
if (!empty(filter_var($node->ipaddr, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4))) { if (
$this->isc_v4_enabled($key) &&
!empty(filter_var($node->ipaddr, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4))
) {
$iftargets['dhcp4'][$key] = !empty($node->descr) ? (string)$node->descr : strtoupper($key); $iftargets['dhcp4'][$key] = !empty($node->descr) ? (string)$node->descr : strtoupper($key);
} }
if (!empty(filter_var($node->ipaddrv6, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) || !empty($node->dhcpd6track6allowoverride)) { if (!empty(filter_var($node->ipaddrv6, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) || !empty($node->{'track6-interface'})) {
$iftargets['dhcp6'][$key] = !empty($node->descr) ? (string)$node->descr : strtoupper($key); $iftargets['dhcp6'][$key] = !empty($node->descr) ? (string)$node->descr : strtoupper($key);
} }
} }

View File

@ -31,7 +31,6 @@
namespace OPNsense\CaptivePortal; namespace OPNsense\CaptivePortal;
use OPNsense\Base\BaseModel; use OPNsense\Base\BaseModel;
use OPNsense\Base\Messages\Message;
/** /**
* Class CaptivePortal * Class CaptivePortal
@ -85,35 +84,4 @@ class CaptivePortal extends BaseModel
$newItem->fileid = uniqid(); $newItem->fileid = uniqid();
return $newItem; return $newItem;
} }
/**
* {@inheritdoc}
*/
public function performValidation($validateFullModel = false)
{
$messages = parent::performValidation($validateFullModel);
// validate changed instances
foreach ($this->zones->zone->iterateItems() as $zone) {
if (!$validateFullModel && !$zone->isFieldChanged()) {
continue;
}
$key = $zone->__reference;
if (!empty((string)$zone->interfaces_inbound) && !empty((string)$zone->interfaces)) {
$ifs_inbound = array_filter(explode(',', $zone->interfaces_inbound));
$ifs = array_filter(explode(',', $zone->interfaces));
$overlap = array_intersect($ifs_inbound, $ifs);
if (!empty($overlap)) {
$messages->appendMessage(
new Message(
sprintf(
gettext("Inbound interfaces may not overlap with zone interfaces (%s)"),
implode(',', $overlap)
),
$key . ".interfaces_inbound"
)
);
}
}
}
return $messages;
}
} }

View File

@ -1,6 +1,6 @@
<model> <model>
<mount>//OPNsense/captiveportal</mount> <mount>//OPNsense/captiveportal</mount>
<version>1.0.2</version> <version>1.0.3</version>
<description>Captive portal application model</description> <description>Captive portal application model</description>
<items> <items>
<zones> <zones>
@ -25,12 +25,6 @@
</filters> </filters>
<ValidationMessage>At least one interface must be selected</ValidationMessage> <ValidationMessage>At least one interface must be selected</ValidationMessage>
</interfaces> </interfaces>
<interfaces_inbound type="InterfaceField">
<Multiple>Y</Multiple>
<filters>
<enable>/^(?!0).*$/</enable>
</filters>
</interfaces_inbound>
<authservers type="AuthenticationServerField"> <authservers type="AuthenticationServerField">
<Multiple>Y</Multiple> <Multiple>Y</Multiple>
</authservers> </authservers>

View File

@ -366,7 +366,7 @@ class ACL
return "ui/user_portal"; return "ui/user_portal";
} elseif (!empty($this->userDatabase[$username]['landing_page'])) { } elseif (!empty($this->userDatabase[$username]['landing_page'])) {
// remove leading slash, which would result in redirection to //page (without host) after login or auth failure. // remove leading slash, which would result in redirection to //page (without host) after login or auth failure.
$page = ltrim($this->userDatabase[$username]['landing_page'], '/'); return ltrim($this->userDatabase[$username]['landing_page'], '/');
} elseif (!empty($this->userDatabase[$username])) { } elseif (!empty($this->userDatabase[$username])) {
// default behaviour, find first accessible location from configured privileges, but prefer / // default behaviour, find first accessible location from configured privileges, but prefer /
if ($this->isPageAccessible($username, '/')) { if ($this->isPageAccessible($username, '/')) {

View File

@ -299,17 +299,12 @@
</patterns> </patterns>
</page-interfaces-assignnetworkports> </page-interfaces-assignnetworkports>
<page-interfaces-bridge-edit> <page-interfaces-bridge-edit>
<name>Interfaces: Bridge edit</name>
<patterns>
<pattern>interfaces_bridge_edit.php*</pattern>
</patterns>
</page-interfaces-bridge-edit>
<page-interfaces-bridge>
<name>Interfaces: Bridge</name> <name>Interfaces: Bridge</name>
<patterns> <patterns>
<pattern>interfaces_bridge.php*</pattern> <pattern>ui/interfaces/bridge</pattern>
<pattern>api/interfaces/bridge_settings/*</pattern>
</patterns> </patterns>
</page-interfaces-bridge> </page-interfaces-bridge-edit>
<page-interfaces-gif-edit> <page-interfaces-gif-edit>
<name>Interfaces: GIF</name> <name>Interfaces: GIF</name>
<patterns> <patterns>

View File

@ -16,10 +16,6 @@
<url>https://opnsense-update.deciso.com</url> <url>https://opnsense-update.deciso.com</url>
<description>Deciso (HTTPS, NL, Commercial)</description> <description>Deciso (HTTPS, NL, Commercial)</description>
</mirror> </mirror>
<mirror>
<url>https://mirror.dns-root.de/opnsense</url>
<description>dns-root.de (HTTPS, Cloudflare CDN)</description>
</mirror>
<mirror> <mirror>
<url>https://opnsense.c0urier.net</url> <url>https://opnsense.c0urier.net</url>
<description>c0urier.net (HTTPS, Horsens, DK)</description> <description>c0urier.net (HTTPS, Horsens, DK)</description>

View File

@ -31,6 +31,7 @@ namespace OPNsense\Dnsmasq;
use OPNsense\Base\BaseModel; use OPNsense\Base\BaseModel;
use OPNsense\Base\Messages\Message; use OPNsense\Base\Messages\Message;
use OPNsense\Core\Backend; use OPNsense\Core\Backend;
use OPNsense\Firewall\Util;
/** /**
* Class Dnsmasq * Class Dnsmasq
@ -174,7 +175,16 @@ class Dnsmasq extends BaseModel
); );
} }
if (in_array('static', explode(',', $range->mode)) && $start_inet == 'inet6') { $is_static = in_array('static', explode(',', $range->mode));
if (!$range->end_addr->isEmpty() && $is_static) {
$messages->appendMessage(
new Message(
gettext("Static only accepts a starting address."),
$key . ".end_addr"
)
);
}
if ($is_static && $start_inet == 'inet6') {
$messages->appendMessage( $messages->appendMessage(
new Message( new Message(
gettext("Static is only available IPv4."), gettext("Static is only available IPv4."),
@ -250,30 +260,34 @@ class Dnsmasq extends BaseModel
) )
); );
} }
}
foreach ($this->dhcp_options_match->iterateItems() as $match) { if ($option->type == 'match' && $option->set_tag->isEmpty()) {
if (!$validateFullModel && !$match->isFieldChanged()) {
continue;
}
$key = $match->__reference;
if (!$match->option->isEmpty() && !$match->option6->isEmpty()) {
$messages->appendMessage( $messages->appendMessage(
new Message( new Message(
gettext("'Option' and 'Option6' cannot be selected at the same time."), gettext("When type is 'Match', a tag must be set."),
$key . ".option" $key . ".set_tag"
) )
); );
} }
if ($match->option->isEmpty() && $match->option6->isEmpty()) { if (
$messages->appendMessage( !$option->value->isEmpty() &&
new Message( !$option->option6->isEmpty()
gettext("Either 'Option' or 'Option6' is required."), ) {
$key . ".option" $values = array_map('trim', explode(',', (string)$option->value));
) foreach ($values as $value) {
); if (
Util::isIpv6Address(trim($value, '[]')) &&
!(str_starts_with($value, '[') && str_ends_with($value, ']'))
) {
$messages->appendMessage(
new Message(
gettext("Each IPv6 address must be wrapped inside square brackets '[fe80::]'."),
$key . ".value"
)
);
}
}
} }
} }

View File

@ -1,6 +1,6 @@
<model> <model>
<mount>/dnsmasq</mount> <mount>/dnsmasq</mount>
<version>1.0.4</version> <version>1.0.5</version>
<items> <items>
<enable type="BooleanField"/> <enable type="BooleanField"/>
<regdhcp type="BooleanField"/> <regdhcp type="BooleanField"/>
@ -219,6 +219,14 @@
<description type="DescriptionField"/> <description type="DescriptionField"/>
</dhcp_ranges> </dhcp_ranges>
<dhcp_options type="ArrayField"> <dhcp_options type="ArrayField">
<type type="OptionField">
<OptionValues>
<set>Set</set>
<match>Match</match>
</OptionValues>
<Default>set</Default>
<Required>Y</Required>
</type>
<option type="JsonKeyValueStoreField"> <option type="JsonKeyValueStoreField">
<ConfigdPopulateAct>dnsmasq list dhcp_options</ConfigdPopulateAct> <ConfigdPopulateAct>dnsmasq list dhcp_options</ConfigdPopulateAct>
</option> </option>
@ -243,17 +251,6 @@
</Model> </Model>
<Multiple>Y</Multiple> <Multiple>Y</Multiple>
</tag> </tag>
<value type="TextField"/>
<force type="BooleanField"/>
<description type="DescriptionField"/>
</dhcp_options>
<dhcp_options_match type="ArrayField">
<option type="JsonKeyValueStoreField">
<ConfigdPopulateAct>dnsmasq list dhcp_options</ConfigdPopulateAct>
</option>
<option6 type="JsonKeyValueStoreField">
<ConfigdPopulateAct>dnsmasq list dhcp_options6</ConfigdPopulateAct>
</option6>
<set_tag type="ModelRelationField"> <set_tag type="ModelRelationField">
<Model> <Model>
<tag> <tag>
@ -262,11 +259,11 @@
<display>tag</display> <display>tag</display>
</tag> </tag>
</Model> </Model>
<Required>Y</Required>
</set_tag> </set_tag>
<value type="TextField"/> <value type="TextField"/>
<force type="BooleanField"/>
<description type="DescriptionField"/> <description type="DescriptionField"/>
</dhcp_options_match> </dhcp_options>
<dhcp_boot type="ArrayField"> <dhcp_boot type="ArrayField">
<tag type="ModelRelationField"> <tag type="ModelRelationField">
<Model> <Model>

View File

@ -7,7 +7,6 @@
<Dhcpranges VisibleName="DHCP ranges" order="50" url="/ui/dnsmasq/settings#dhcpranges"/> <Dhcpranges VisibleName="DHCP ranges" order="50" url="/ui/dnsmasq/settings#dhcpranges"/>
<Dhcpoptions VisibleName="DHCP options" order="60" url="/ui/dnsmasq/settings#dhcpoptions"/> <Dhcpoptions VisibleName="DHCP options" order="60" url="/ui/dnsmasq/settings#dhcpoptions"/>
<Dhcptags VisibleName="DHCP tags" order="65" url="/ui/dnsmasq/settings#dhcptags"/> <Dhcptags VisibleName="DHCP tags" order="65" url="/ui/dnsmasq/settings#dhcptags"/>
<Dhcpmatches VisibleName="DHCP matches" order="70" url="/ui/dnsmasq/settings#dhcpmatches"/>
<Leases order="80" url="/ui/dnsmasq/leases"/> <Leases order="80" url="/ui/dnsmasq/leases"/>
<LogFile VisibleName="Log File" order="90" url="/ui/diagnostics/log/core/dnsmasq"/> <LogFile VisibleName="Log File" order="90" url="/ui/diagnostics/log/core/dnsmasq"/>
</Dnsmasq> </Dnsmasq>

View File

@ -31,6 +31,7 @@ namespace OPNsense\Firewall\FieldTypes;
use OPNsense\Base\FieldTypes\BaseField; use OPNsense\Base\FieldTypes\BaseField;
use OPNsense\Base\Messages\Message; use OPNsense\Base\Messages\Message;
use OPNsense\Base\Validators\CallbackValidator; use OPNsense\Base\Validators\CallbackValidator;
use OPNsense\Core\AppConfig;
use OPNsense\Core\Config; use OPNsense\Core\Config;
use OPNsense\Firewall\Util; use OPNsense\Firewall\Util;
@ -105,7 +106,8 @@ class AliasContentField extends BaseField
if (empty(self::$internalCountryCodes)) { if (empty(self::$internalCountryCodes)) {
// Maxmind's country code 6255148 (EU Unclassified) // Maxmind's country code 6255148 (EU Unclassified)
self::$internalCountryCodes[] = 'EU'; self::$internalCountryCodes[] = 'EU';
foreach (explode("\n", file_get_contents('/usr/local/opnsense/contrib/tzdata/iso3166.tab')) as $line) { $contribDir = (new AppConfig())->application->contribDir;
foreach (explode("\n", file_get_contents($contribDir . '/tzdata/iso3166.tab')) as $line) {
$line = trim($line); $line = trim($line);
if (strlen($line) > 3 && substr($line, 0, 1) != '#') { if (strlen($line) > 3 && substr($line, 0, 1) != '#') {
self::$internalCountryCodes[] = substr($line, 0, 2); self::$internalCountryCodes[] = substr($line, 0, 2);

View File

@ -1,31 +1,29 @@
<?php <?php
/** /*
* Copyright (C) 2023 Deciso B.V. * Copyright (C) 2023 Deciso B.V.
* All rights reserved.
* *
* All rights reserved. * Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* *
* Redistribution and use in source and binary forms, with or without * 1. Redistributions of source code must retain the above copyright notice,
* modification, are permitted provided that the following conditions are met: * this list of conditions and the following disclaimer.
* *
* 1. Redistributions of source code must retain the above copyright notice, * 2. Redistributions in binary form must reproduce the above copyright
* this list of conditions and the following disclaimer. * notice, this list of conditions and the following disclaimer in the
* * documentation and/or other materials provided with the distribution.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
* *
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/ */
namespace OPNsense\Firewall\FieldTypes; namespace OPNsense\Firewall\FieldTypes;
@ -46,17 +44,17 @@ class GroupField extends ArrayField
'openvpn' => [ 'openvpn' => [
'sequence' => 10, 'sequence' => 10,
'ifname' => 'openvpn', 'ifname' => 'openvpn',
'descr' => gettext('All OpenVPN interfaces') 'descr' => gettext('All OpenVPN interfaces'),
], ],
'enc0' => [ 'enc0' => [
'sequence' => 10, 'sequence' => 10,
'ifname' => 'enc0', 'ifname' => 'enc0',
'descr' => gettext('IPsec') 'descr' => gettext('IPsec'),
], ],
'wireguard' => [ 'wireguard' => [
'sequence' => 10, 'sequence' => 10,
'ifname' => 'wireguard', 'ifname' => 'wireguard',
'descr' => gettext('WireGuard') 'descr' => gettext('WireGuard'),
] ]
]; ];
} }

View File

@ -92,6 +92,26 @@ class Filter extends BaseModel
} }
} }
if (!$rule->icmptype->isEmpty() && !in_array($rule->protocol, ['ICMP'])) {
$messages->appendMessage(new Message(
gettext("Option only applies to ICMP packets"),
$rule->icmptype->__reference
));
}
if (strpos($rule->source_net, ',') !== false && $rule->source_not == '1') {
$messages->appendMessage(new Message(
gettext("Inverting sources is only allowed for single targets to avoid mis-interpretations"),
$rule->source_not->__reference
));
}
if (strpos($rule->destination_net, ',') !== false && $rule->destination_not == '1') {
$messages->appendMessage(new Message(
gettext("Inverting destinations is only allowed for single targets to avoid mis-interpretations"),
$rule->destination_net->__reference
));
}
// Additional source nat validations // Additional source nat validations
if ($rule->target !== null) { if ($rule->target !== null) {
$target_is_addr = Util::isSubnet($rule->target) || Util::isIpAddress($rule->target); $target_is_addr = Util::isSubnet($rule->target) || Util::isIpAddress($rule->target);

View File

@ -85,6 +85,27 @@
<opt1 value='TCP/UDP'>TCP/UDP</opt1> <opt1 value='TCP/UDP'>TCP/UDP</opt1>
</AddOptions> </AddOptions>
</protocol> </protocol>
<icmptype type="OptionField">
<Multiple>Y</Multiple>
<OptionValues>
<echoreq>Echo Request</echoreq>
<echorep>Echo Reply</echorep>
<unreach>Destination Unreachable</unreach>
<squench>Source Quench (Deprecated)</squench>
<redir>Redirect</redir>
<althost>Alternate Host Address (Deprecated)</althost>
<routeradv>Router Advertisement</routeradv>
<routersol>Router Solicitation</routersol>
<timex>Time Exceeded</timex>
<paramprob>Parameter Problem</paramprob>
<timereq>Timestamp</timereq>
<timerep>Timestamp Reply</timerep>
<inforeq>Information Request (Deprecated)</inforeq>
<inforep>Information Reply (Deprecated)</inforep>
<maskreq>Address Mask Request (Deprecated)</maskreq>
<maskrep>Address Mask Reply (Deprecated)</maskrep>
</OptionValues>
</icmptype>
<!-- XXX: should map internally to 'source' => array('network' => $source_net, "not" => true|false) --> <!-- XXX: should map internally to 'source' => array('network' => $source_net, "not" => true|false) -->
<source_net type="NetworkAliasField"> <source_net type="NetworkAliasField">
<Default>any</Default> <Default>any</Default>

View File

@ -6,11 +6,11 @@
<patterns> <patterns>
<pattern>ui/ipsec/key_pairs/*</pattern> <pattern>ui/ipsec/key_pairs/*</pattern>
<pattern>api/ipsec/key_pairs/*</pattern> <pattern>api/ipsec/key_pairs/*</pattern>
<pattern>api/ipsec/legacy_subsystem/*</pattern> <pattern>api/ipsec/service/*</pattern>
</patterns> </patterns>
</page-vpn-ipsec-keypairs> </page-vpn-ipsec-keypairs>
<page-vpn-ipsec> <page-vpn-ipsec>
<name>VPN: IPsec: Tunnels Settings [legacy]</name> <name>VPN: IPsec: Tunnels [legacy]</name>
<patterns> <patterns>
<pattern>ui/ipsec/tunnels</pattern> <pattern>ui/ipsec/tunnels</pattern>
<pattern>api/ipsec/tunnel/*</pattern> <pattern>api/ipsec/tunnel/*</pattern>
@ -21,11 +21,12 @@
<name>VPN: IPsec: Connections</name> <name>VPN: IPsec: Connections</name>
<patterns> <patterns>
<pattern>ui/ipsec/connections</pattern> <pattern>ui/ipsec/connections</pattern>
<pattern>ui/ipsec/connections/settings</pattern>
<pattern>ui/ipsec/vti</pattern> <pattern>ui/ipsec/vti</pattern>
<pattern>api/ipsec/connections/*</pattern> <pattern>api/ipsec/connections/*</pattern>
<pattern>api/ipsec/pools/*</pattern> <pattern>api/ipsec/pools/*</pattern>
<pattern>api/ipsec/service/*</pattern>
<pattern>api/ipsec/vti/*</pattern> <pattern>api/ipsec/vti/*</pattern>
<pattern>api/ipsec/legacy_subsystem/*</pattern>
</patterns> </patterns>
</page-vpn-ipsec-connections> </page-vpn-ipsec-connections>
@ -47,10 +48,11 @@
<patterns> <patterns>
<pattern>ui/ipsec/pre_shared_keys</pattern> <pattern>ui/ipsec/pre_shared_keys</pattern>
<pattern>api/ipsec/pre_shared_keys/*</pattern> <pattern>api/ipsec/pre_shared_keys/*</pattern>
<pattern>api/ipsec/service/*</pattern>
</patterns> </patterns>
</page-vpn-ipsec-editkeys> </page-vpn-ipsec-editkeys>
<page-vpn-ipsec-mobile> <page-vpn-ipsec-mobile>
<name>VPN: IPsec: Mobile</name> <name>VPN: IPsec: Mobile [legacy]</name>
<patterns> <patterns>
<pattern>vpn_ipsec_mobile.php*</pattern> <pattern>vpn_ipsec_mobile.php*</pattern>
</patterns> </patterns>
@ -82,6 +84,7 @@
<pattern>ui/ipsec/spd</pattern> <pattern>ui/ipsec/spd</pattern>
<pattern>api/ipsec/spd/*</pattern> <pattern>api/ipsec/spd/*</pattern>
<pattern>api/ipsec/manual_spd/*</pattern> <pattern>api/ipsec/manual_spd/*</pattern>
<pattern>api/ipsec/service/*</pattern>
</patterns> </patterns>
</page-status-ipsec-spd> </page-status-ipsec-spd>
<page-status-systemlogs-ipsecvpn> <page-status-systemlogs-ipsecvpn>

View File

@ -122,6 +122,7 @@ class IPsecProposalField extends BaseListField
'aes128-sha1-modp2048' => 'aes128-sha1-modp2048 [DH14]', 'aes128-sha1-modp2048' => 'aes128-sha1-modp2048 [DH14]',
'aes256-sha1-modp4096' => 'aes256-sha1-modp4096 [DH16]', 'aes256-sha1-modp4096' => 'aes256-sha1-modp4096 [DH16]',
'aes256-sha1-ecp521' => 'aes256-sha1-ecp521 [DH21, NIST EC]', 'aes256-sha1-ecp521' => 'aes256-sha1-ecp521 [DH21, NIST EC]',
'aes256-sha256-modp1024' => 'aes256-sha256-modp1024 [DH2]',
'aes256-sha512-modp1024' => 'aes256-sha512-modp1024 [DH2]', 'aes256-sha512-modp1024' => 'aes256-sha512-modp1024 [DH2]',
'aes256-sha256' => 'aes256-sha256', 'aes256-sha256' => 'aes256-sha256',
'null' => gettext('null (testing only, no encryption and no integrity checking!)') 'null' => gettext('null (testing only, no encryption and no integrity checking!)')

View File

@ -203,8 +203,8 @@ class IPsec extends BaseModel
foreach (explode(',', (string)$item) as $item) { foreach (explode(',', (string)$item) as $item) {
$idx = 'server' . (string)(count($servers) + 1); $idx = 'server' . (string)(count($servers) + 1);
$mapping = []; $mapping = [];
if (isset($cnf->authserver)) { if (isset($cnf->system->authserver)) {
foreach ($cnf->authserver as $authserver) { foreach ($cnf->system->authserver as $authserver) {
if ($authserver->name == $item) { if ($authserver->name == $item) {
$servers[$idx] = [ $servers[$idx] = [
'address' => (string)$authserver->host, 'address' => (string)$authserver->host,
@ -223,6 +223,10 @@ class IPsec extends BaseModel
if ($target_key == '28672') { if ($target_key == '28672') {
/* Unity login banner, needs to be wrapped? */ /* Unity login banner, needs to be wrapped? */
$result[$target_key] = '"' . str_replace(['\\', '"'], '', (string)$item) . '"'; $result[$target_key] = '"' . str_replace(['\\', '"'], '', (string)$item) . '"';
} elseif ($target_key == '28675') {
/* 28675 (splitdns name) is equal/similar to 25 (INTERNAL_DNS_DOMAIN) */
$result['25'] = (string)$item;
$result[$target_key] = (string)$item;
} else { } else {
$result[$target_key] = (string)$item; $result[$target_key] = (string)$item;
} }

View File

@ -113,7 +113,6 @@
<!-- UNITY_DEF_DOMAIN --> <!-- UNITY_DEF_DOMAIN -->
<x_28674 type="TextField"/> <x_28674 type="TextField"/>
<x_28675 type="TextField"/> <x_28675 type="TextField"/>
<x_25 type="TextField"/>
<x_28672 type="TextField"/> <x_28672 type="TextField"/>
<x_28673 type="BooleanField"/> <x_28673 type="BooleanField"/>
<x_28679 type="OptionField"> <x_28679 type="OptionField">

View File

@ -6,7 +6,7 @@
<Phase1 url="/vpn_ipsec_phase1.php*" visibility="hidden"/> <Phase1 url="/vpn_ipsec_phase1.php*" visibility="hidden"/>
<Phase2 url="/vpn_ipsec_phase2.php*" visibility="hidden"/> <Phase2 url="/vpn_ipsec_phase2.php*" visibility="hidden"/>
</Tunnels> </Tunnels>
<Mobile order="20" VisibleName="Mobile Clients (legacy)" url="/vpn_ipsec_mobile.php"> <Mobile order="20" VisibleName="Mobile Clients [legacy]" url="/vpn_ipsec_mobile.php">
<Act url="/vpn_ipsec_mobile.php*" visibility="hidden"/> <Act url="/vpn_ipsec_mobile.php*" visibility="hidden"/>
</Mobile> </Mobile>
<Keys order="30" VisibleName="Pre-Shared Keys" url="/ui/ipsec/pre_shared_keys"/> <Keys order="30" VisibleName="Pre-Shared Keys" url="/ui/ipsec/pre_shared_keys"/>

View File

@ -0,0 +1,76 @@
<?php
/*
* Copyright (C) 2025 Deciso B.V.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
namespace OPNsense\Interfaces;
use OPNsense\Base\Messages\Message;
use OPNsense\Base\BaseModel;
use OPNsense\Firewall\Util;
class Bridge extends BaseModel
{
/**
* {@inheritdoc}
*/
public function performValidation($validateFullModel = false)
{
$messages = parent::performValidation($validateFullModel);
foreach ($this->bridged->iterateItems() as $bridge) {
if (!$validateFullModel && !$bridge->isFieldChanged()) {
continue;
}
$key = $bridge->__reference;
$members = explode(',', $bridge->members->getCurrentValue());
if (!$bridge->span->isEmpty() && in_array($bridge->span->getCurrentValue(), $members)) {
$messages->appendMessage(
new Message(
gettext("Span interface cannot be part of the bridge."),
$key . ".span"
)
);
}
foreach (['stp', 'edge', 'autoedge', 'ptp', 'autoptp', 'static', 'private'] as $section) {
if ($bridge->$section->isEmpty()) {
continue;
}
foreach (explode(',', $bridge->$section->getCurrentValue()) as $if) {
if (!in_array($if, $members)) {
$messages->appendMessage(
new Message(
gettext("Contains non bridge members."),
$key . "." . $section
)
);
break;
}
}
}
}
return $messages;
}
}

View File

@ -0,0 +1,74 @@
<model>
<mount>/bridges</mount>
<version>1.0.0</version>
<description>Bridge interfaces</description>
<items>
<bridged type="ArrayField">
<bridgeif type="TextField">
<Required>Y</Required>
<Constraints>
<check001>
<ValidationMessage>Bridge already exists!</ValidationMessage>
<type>UniqueConstraint</type>
</check001>
</Constraints>
<Mask>/^bridge[\d]+$/</Mask>
</bridgeif>
<members type=".\BridgeMemberField">
<Required>Y</Required>
<Multiple>Y</Multiple>
</members>
<linklocal type="BooleanField"/>
<enablestp type="BooleanField"/>
<proto type="OptionField">
<Required>Y</Required>
<Default>rstp</Default>
<OptionValues>
<rstp>RSTP</rstp>
<stp>STP</stp>
</OptionValues>
</proto>
<stp type=".\BridgeMemberField">
<Multiple>Y</Multiple>
</stp>
<maxage type="IntegerField">
<MinimumValue>6</MinimumValue>
<MaximumValue>40</MaximumValue>
</maxage>
<fwdelay type="IntegerField">
<MinimumValue>4</MinimumValue>
<MaximumValue>30</MaximumValue>
</fwdelay>
<holdcnt type="IntegerField">
<MinimumValue>1</MinimumValue>
<MaximumValue>10</MaximumValue>
</holdcnt>
<maxaddr type="IntegerField">
<MinimumValue>1</MinimumValue>
</maxaddr>
<timeout type="IntegerField">
<MinimumValue>0</MinimumValue>
</timeout>
<span type=".\BridgeMemberField"/>
<edge type=".\BridgeMemberField">
<Multiple>Y</Multiple>
</edge>
<autoedge type=".\BridgeMemberField">
<Multiple>Y</Multiple>
</autoedge>
<ptp type=".\BridgeMemberField">
<Multiple>Y</Multiple>
</ptp>
<autoptp type=".\BridgeMemberField">
<Multiple>Y</Multiple>
</autoptp>
<static type=".\BridgeMemberField">
<Multiple>Y</Multiple>
</static>
<private type=".\BridgeMemberField">
<Multiple>Y</Multiple>
</private>
<descr type="DescriptionField"/>
</bridged>
</items>
</model>

View File

@ -0,0 +1,58 @@
<?php
/*
* Copyright (C) 2025 Deciso B.V.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
namespace OPNsense\Interfaces\FieldTypes;
use OPNsense\Base\FieldTypes\BaseListField;
use OPNsense\Core\Config;
class BridgeMemberField extends BaseListField
{
private static $interfaces = [];
protected function actionPostLoadingEvent()
{
if (empty(self::$interfaces)) {
$configHandle = Config::getInstance()->object();
if (!empty($configHandle->interfaces)) {
foreach ($configHandle->interfaces->children() as $ifname => $node) {
if (!empty((string)$node->virtual)) {
continue;
} elseif (!empty((string)$node->if) && str_starts_with('gre', $node->if)) {
continue;
} elseif (!empty((string)$node->if) && str_starts_with('lo', $node->if)) {
continue;
}
$descr = !empty((string)$node->descr) ? (string)$node->descr : strtoupper($ifname);
self::$interfaces[$ifname] = $descr;
}
}
}
$this->internalOptionList = self::$interfaces;
return parent::actionPostLoadingEvent();
}
}

View File

@ -53,7 +53,7 @@ class LinkAddressField extends BaseField
self::$option_groups['ipalias'] = ['items' => [], 'title' => gettext('IP Alias')]; self::$option_groups['ipalias'] = ['items' => [], 'title' => gettext('IP Alias')];
foreach ($cfg->interfaces->children() as $ifname => $node) { foreach ($cfg->interfaces->children() as $ifname => $node) {
$descr = !empty((string)$node->descr) ? (string)$node->descr : strtoupper($ifname); $descr = !empty((string)$node->descr) ? (string)$node->descr : strtoupper($ifname);
if (!empty((string)$node->virtual) || empty((string)$node->enable)) { if (!empty((string)$node->virtual)) {
continue; continue;
} }
self::$known_addresses[$ifname] = $descr; self::$known_addresses[$ifname] = $descr;

View File

@ -2,9 +2,7 @@
<Interfaces> <Interfaces>
<Assignments order="200" url="/interfaces_assign.php" cssClass="fa fa-pencil fa-fw"/> <Assignments order="200" url="/interfaces_assign.php" cssClass="fa fa-pencil fa-fw"/>
<Devices order="210" cssClass="fa fa-archive fa-fw"> <Devices order="210" cssClass="fa fa-archive fa-fw">
<Bridge url="/interfaces_bridge.php"> <Bridge url="/ui/interfaces/bridge"/>
<Edit url="/interfaces_bridge_edit.php*" visibility="hidden"/>
</Bridge>
<GIF url="/ui/interfaces/gif"/> <GIF url="/ui/interfaces/gif"/>
<GRE url="/ui/interfaces/gre"/> <GRE url="/ui/interfaces/gre"/>
<LAGG url="/ui/interfaces/lagg"/> <LAGG url="/ui/interfaces/lagg"/>

View File

@ -4,9 +4,38 @@
<description>Allow access to the KEA dhcp4 server</description> <description>Allow access to the KEA dhcp4 server</description>
<patterns> <patterns>
<pattern>ui/kea/dhcp/v4</pattern> <pattern>ui/kea/dhcp/v4</pattern>
<pattern>ui/kea/dhcp/leases4</pattern>
<pattern>api/kea/dhcpv4/*</pattern> <pattern>api/kea/dhcpv4/*</pattern>
<pattern>api/kea/leases4/*</pattern> <pattern>api/kea/leases4/*</pattern>
<pattern>api/kea/service/*</pattern> <pattern>api/kea/service/*</pattern>
</patterns> </patterns>
</page-dhcp-kea-v4> </page-dhcp-kea-v4>
<page-dhcp-kea-v6>
<name>Services: DHCP: Kea(v6)</name>
<description>Allow access to the KEA dhcp6 server</description>
<patterns>
<pattern>ui/kea/dhcp/v6</pattern>
<pattern>ui/kea/dhcp/leases6</pattern>
<pattern>api/kea/dhcpv6/*</pattern>
<pattern>api/kea/leases6/*</pattern>
<pattern>api/kea/service/*</pattern>
</patterns>
</page-dhcp-kea-v6>
<page-dhcp-kea-ctrl-agent>
<name>Services: DHCP: Kea Ctrl Agent</name>
<description>Allow access to the KEA Ctrl Agent</description>
<patterns>
<pattern>ui/kea/dhcp/ctrl_agent</pattern>
<pattern>api/kea/ctrl_agent/*</pattern>
<pattern>api/kea/service/*</pattern>
</patterns>
</page-dhcp-kea-ctrl-agent>
<page-diagnostics-logs-kea>
<name>Services: DHCP: Kea Log File</name>
<description>Allow access to the KEA Log File</description>
<patterns>
<pattern>ui/diagnostics/log/core/kea/*</pattern>
<pattern>api/diagnostics/log/core/kea/*</pattern>
</patterns>
</page-diagnostics-logs-kea>
</acl> </acl>

View File

@ -8,6 +8,7 @@
<Default>0</Default> <Default>0</Default>
<Required>Y</Required> <Required>Y</Required>
</enabled> </enabled>
<manual_config type="BooleanField"/>
<interfaces type="InterfaceField"> <interfaces type="InterfaceField">
<Multiple>Y</Multiple> <Multiple>Y</Multiple>
</interfaces> </interfaces>

View File

@ -0,0 +1,239 @@
<?php
/*
* Copyright (C) 2025 Deciso B.V.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
namespace OPNsense\Kea;
use OPNsense\Base\Messages\Message;
use OPNsense\Base\BaseModel;
use OPNsense\Core\Config;
use OPNsense\Core\Backend;
use OPNsense\Core\File;
use OPNsense\Firewall\Util;
class KeaDhcpv6 extends BaseModel
{
/**
* {@inheritdoc}
*/
public function performValidation($validateFullModel = false)
{
$messages = parent::performValidation($validateFullModel);
// validate changed reservations
foreach ($this->reservations->reservation->iterateItems() as $reservation) {
if (!$validateFullModel && !$reservation->isFieldChanged()) {
continue;
}
$key = $reservation->__reference;
$subnet = "";
$subnet_node = $this->getNodeByReference("subnets.subnet6.{$reservation->subnet}");
if ($subnet_node) {
$subnet = (string)$subnet_node->subnet;
}
if (!Util::isIPInCIDR((string)$reservation->ip_address, $subnet)) {
$messages->appendMessage(new Message(gettext("Address not in specified subnet"), $key . ".ip_address"));
}
}
return $messages;
}
public function isEnabled()
{
return (string)$this->general->enabled == '1' && !empty((string)(string)$this->general->interfaces);
}
/**
* should filter rules be enabled
* @return bool
*/
public function fwrulesEnabled()
{
return (string)$this->general->enabled == '1' &&
(string)$this->general->fwrules == '1' &&
!empty((string)$this->general->interfaces);
}
/**
*
*/
private function getConfigPhysicalInterfaces()
{
$result = [];
$cfg = Config::getInstance()->object();
foreach (explode(',', $this->general->interfaces) as $if) {
if (isset($cfg->interfaces->$if) && !empty($cfg->interfaces->$if->if)) {
$result[] = (string)$cfg->interfaces->$if->if;
}
}
return $result;
}
private function getConfigThisServerHostname()
{
$hostname = (string)$this->ha->this_server_name;
if (empty($hostname)) {
$hostname = (string)Config::getInstance()->object()->system->hostname;
}
return $hostname;
}
private function getConfigSubnets()
{
$result = [];
$subnet_id = 1;
foreach ($this->subnets->subnet6->iterateItems() as $subnet_uuid => $subnet) {
$record = [
'id' => $subnet_id++,
'subnet' => (string)$subnet->subnet,
'option-data' => [],
'pools' => [],
'pd-pools' => [],
'reservations' => []
];
/* standard option-data elements */
foreach ($subnet->option_data->iterateItems() as $key => $value) {
$target_fieldname = str_replace('_', '-', $key);
if ((string)$value != '') {
$record['option-data'][] = [
'name' => $target_fieldname,
'data' => (string)$value
];
} elseif ($key == 'domain_name') {
$record['option-data'][] = [
'name' => $target_fieldname,
'data' => (string)Config::getInstance()->object()->system->domain
];
}
}
/* add pools */
foreach (array_filter(explode("\n", $subnet->pools)) as $pool) {
$record['pools'][] = ['pool' => $pool];
}
/* add pd-pools */
foreach ($this->pd_pools->pd_pool->iterateItems() as $key => $pdpool) {
if ($pdpool->subnet != $subnet_uuid) {
continue;
}
$record['pd-pools'][] = [
'prefix' => (string)$pdpool->prefix,
'prefix-len' => (int)$pdpool->prefix_len->getCurrentValue(),
'delegated-len' => (int)$pdpool->delegated_len->getCurrentValue()
];
}
/* static reservations */
foreach ($this->reservations->reservation->iterateItems() as $key => $reservation) {
if ($reservation->subnet != $subnet_uuid) {
continue;
}
$res = ['option-data' => []];
foreach (['duid', 'hostname'] as $key) {
if (!empty((string)$reservation->$key)) {
$res[str_replace('_', '-', $key)] = (string)$reservation->$key;
}
}
$res['ip-addresses'] = explode(',', (string)$reservation->ip_address);
if (!$reservation->domain_search->isEmpty()) {
$res['option-data'][] = [
'name' => 'domain-search',
'data' => (string)$reservation->domain_search
];
}
$record['reservations'][] = $res;
}
$result[] = $record;
}
return $result;
}
public function generateConfig($target = '/usr/local/etc/kea/kea-dhcp6.conf')
{
$cnf = [
'Dhcp6' => [
'valid-lifetime' => (int)$this->general->valid_lifetime->__toString(),
'interfaces-config' => [
'interfaces' => $this->getConfigPhysicalInterfaces()
],
'lease-database' => [
'type' => 'memfile',
'persist' => true,
],
'control-socket' => [
'socket-type' => 'unix',
'socket-name' => '/var/run/kea6-ctrl-socket'
],
'loggers' => [
[
'name' => 'kea-dhcp6',
'output_options' => [
[
'output' => 'syslog'
]
],
'severity' => 'INFO',
]
],
'subnet6' => $this->getConfigSubnets(),
]
];
if (!empty((string)(new KeaCtrlAgent())->general->enabled)) {
$cnf['Dhcp6']['hooks-libraries'] = [];
$cnf['Dhcp6']['hooks-libraries'][] = [
'library' => '/usr/local/lib/kea/hooks/libdhcp_lease_cmds.so'
];
if (!empty((string)$this->ha->enabled)) {
$record = [
'library' => '/usr/local/lib/kea/hooks/libdhcp_ha.so',
'parameters' => [
'high-availability' => [
[
'this-server-name' => $this->getConfigThisServerHostname(),
'mode' => 'hot-standby',
'heartbeat-delay' => 10000,
'max-response-delay' => 60000,
'max-ack-delay' => 5000,
'max-unacked-clients' => (int)((string)$this->ha->max_unacked_clients),
'sync-timeout' => 60000,
]
]
]
];
foreach ($this->ha_peers->peer->iterateItems() as $peer) {
if (!isset($record['parameters']['high-availability'][0]['peers'])) {
$record['parameters']['high-availability'][0]['peers'] = [];
}
$record['parameters']['high-availability'][0]['peers'][] = array_map(
fn($x) => (string)$x,
iterator_to_array($peer->iterateItems())
);
}
$cnf['Dhcp6']['hooks-libraries'][] = $record;
}
}
File::file_put_contents($target, json_encode($cnf, JSON_PRETTY_PRINT), 0600);
}
}

View File

@ -0,0 +1,181 @@
<model>
<mount>//OPNsense/Kea/dhcp6</mount>
<version>1.0.0</version>
<description>Kea DHCPv6 configuration</description>
<items>
<general>
<enabled type="BooleanField">
<Default>0</Default>
<Required>Y</Required>
</enabled>
<manual_config type="BooleanField"/>
<interfaces type="InterfaceField">
<Multiple>Y</Multiple>
</interfaces>
<valid_lifetime type="IntegerField">
<Default>4000</Default>
<Required>Y</Required>
</valid_lifetime>
<fwrules type="BooleanField">
<Required>Y</Required>
<Default>1</Default>
</fwrules>
</general>
<ha>
<enabled type="BooleanField">
<Default>0</Default>
<Required>Y</Required>
</enabled>
<this_server_name type="TextField">
<Mask>/^([0-9a-zA-Z.\:\-,_]){0,1024}$/u</Mask>
</this_server_name>
<max_unacked_clients type="IntegerField">
<MinimumValue>0</MinimumValue>
<MaximumValue>65535</MaximumValue>
<Default>2</Default>
<Required>Y</Required>
</max_unacked_clients>
</ha>
<subnets>
<subnet6 type="ArrayField">
<subnet type="NetworkField">
<NetMaskRequired>Y</NetMaskRequired>
<AddressFamily>ipv6</AddressFamily>
<Required>Y</Required>
</subnet>
<option_data>
<dns_servers type="NetworkField">
<NetMaskAllowed>N</NetMaskAllowed>
<AddressFamily>ipv6</AddressFamily>
<AsList>Y</AsList>
<FieldSeparator>,</FieldSeparator>
</dns_servers>
<domain_search type="HostnameField">
<IpAllowed>N</IpAllowed>
<FieldSeparator>,</FieldSeparator>
<AsList>Y</AsList>
<ValidationMessage>Please specify a valid list of domains</ValidationMessage>
</domain_search>
</option_data>
<pools type=".\KeaPoolsField">
</pools>
<description type="DescriptionField"/>
</subnet6>
</subnets>
<reservations>
<reservation type="ArrayField">
<subnet type="ModelRelationField">
<Model>
<subnets>
<source>OPNsense.Kea.KeaDhcpv6</source>
<items>subnets.subnet6</items>
<display>subnet</display>
</subnets>
</Model>
<ValidationMessage>Related subnet not found</ValidationMessage>
<Constraints>
<check001>
<reference>duid.check001</reference>
</check001>
</Constraints>
<Required>Y</Required>
</subnet>
<ip_address type="NetworkField">
<NetMaskAllowed>N</NetMaskAllowed>
<AddressFamily>ipv6</AddressFamily>
<Constraints>
<check001>
<ValidationMessage>Duplicate entry exists</ValidationMessage>
<type>UniqueConstraint</type>
</check001>
</Constraints>
</ip_address>
<duid type="TextField">
<Required>Y</Required>
<Mask>/^(?:[0-9A-Fa-f]{2}(?::[0-9A-Fa-f]{2})+)$/</Mask>
<ValidationMessage>Value must be a colon-separated hexadecimal sequence (e.g., 01:02:f3).</ValidationMessage>
<Constraints>
<check001>
<ValidationMessage>Duplicate entry exists</ValidationMessage>
<type>UniqueConstraint</type>
<addFields>
<field1>subnet</field1>
</addFields>
</check001>
</Constraints>
</duid>
<hostname type="HostnameField">
<IsDNSName>Y</IsDNSName>
</hostname>
<domain_search type="HostnameField">
<IpAllowed>N</IpAllowed>
<FieldSeparator>,</FieldSeparator>
<AsList>Y</AsList>
<ValidationMessage>Please specify a valid list of domains</ValidationMessage>
</domain_search>
<description type="DescriptionField"/>
</reservation>
</reservations>
<pd_pools>
<pd_pool type="ArrayField">
<subnet type="ModelRelationField">
<Model>
<subnets>
<source>OPNsense.Kea.KeaDhcpv6</source>
<items>subnets.subnet6</items>
<display>subnet</display>
</subnets>
</Model>
<ValidationMessage>Related subnet not found</ValidationMessage>
<Required>Y</Required>
</subnet>
<prefix type="NetworkField">
<AddressFamily>ipv6</AddressFamily>
</prefix>
<prefix_len type="IntegerField">
<MinimumValue>1</MinimumValue>
<MaximumValue>128</MaximumValue>
<Default>56</Default>
<Required>Y</Required>
</prefix_len>
<delegated_len type="IntegerField">
<MinimumValue>1</MinimumValue>
<MaximumValue>128</MaximumValue>
<Required>Y</Required>
<Default>64</Default>
</delegated_len>
<description type="DescriptionField"/>
</pd_pool>
</pd_pools>
<ha_peers>
<peer type="ArrayField">
<name type="TextField">
<Required>Y</Required>
<Constraints>
<check001>
<ValidationMessage>Duplicate entry exists</ValidationMessage>
<type>UniqueConstraint</type>
</check001>
</Constraints>
</name>
<role type="OptionField">
<Default>primary</Default>
<Required>Y</Required>
<OptionValues>
<primary>primary</primary>
<standby>standby</standby>
</OptionValues>
</role>
<url type="UrlField">
<Required>Y</Required>
<Constraints>
<check001>
<ValidationMessage>Duplicate entry exists</ValidationMessage>
<type>UniqueConstraint</type>
</check001>
</Constraints>
</url>
</peer>
</ha_peers>
</items>
</model>

View File

@ -3,6 +3,7 @@
<KeaDHCP VisibleName="Kea DHCP" cssClass="fa fa-bullseye fa-fw"> <KeaDHCP VisibleName="Kea DHCP" cssClass="fa fa-bullseye fa-fw">
<ControlAgent order="5" VisibleName="Control Agent" url="/ui/kea/dhcp/ctrl_agent"/> <ControlAgent order="5" VisibleName="Control Agent" url="/ui/kea/dhcp/ctrl_agent"/>
<Keav4 order="10" VisibleName="Kea DHCPv4" url="/ui/kea/dhcp/v4"/> <Keav4 order="10" VisibleName="Kea DHCPv4" url="/ui/kea/dhcp/v4"/>
<Keav6 order="20" VisibleName="Kea DHCPv6" url="/ui/kea/dhcp/v6"/>
<Leases4 order="50" VisibleName="Leases DHCPv4" url="/ui/kea/dhcp/leases4"/> <Leases4 order="50" VisibleName="Leases DHCPv4" url="/ui/kea/dhcp/leases4"/>
<LogFile order="100" VisibleName="Log File" url="/ui/diagnostics/log/core/kea"/> <LogFile order="100" VisibleName="Log File" url="/ui/diagnostics/log/core/kea"/>
</KeaDHCP> </KeaDHCP>

View File

@ -29,6 +29,7 @@
</validate_server_cn> </validate_server_cn>
<cryptoapi type="BooleanField"/> <cryptoapi type="BooleanField"/>
<auth_nocache type="BooleanField"/> <auth_nocache type="BooleanField"/>
<static_challenge type="BooleanField"/>
<plain_config type="TextField"/> <plain_config type="TextField"/>
</server> </server>
</servers> </servers>

View File

@ -56,6 +56,7 @@
</monitor_disable> </monitor_disable>
<monitor_noroute type="BooleanField"/> <monitor_noroute type="BooleanField"/>
<monitor_killstates type="BooleanField"/> <monitor_killstates type="BooleanField"/>
<monitor_killstates_priority type="BooleanField"/>
<monitor type="TextField"> <monitor type="TextField">
<Constraints> <Constraints>
<check001> <check001>

View File

@ -28,6 +28,7 @@
namespace OPNsense\Trust\FieldTypes; namespace OPNsense\Trust\FieldTypes;
use OPNsense\Core\Backend;
use OPNsense\Core\Config; use OPNsense\Core\Config;
use OPNsense\Base\FieldTypes\ArrayField; use OPNsense\Base\FieldTypes\ArrayField;
use OPNsense\Base\FieldTypes\ContainerField; use OPNsense\Base\FieldTypes\ContainerField;
@ -94,6 +95,11 @@ class CertificateContainerField extends ContainerField
*/ */
class CertificatesField extends ArrayField class CertificatesField extends ArrayField
{ {
/**
* {@inheritdoc}
*/
protected static $internalStaticChildren = [];
/** /**
* @inheritDoc * @inheritDoc
*/ */
@ -105,6 +111,26 @@ class CertificatesField extends ArrayField
return $container_node; return $container_node;
} }
/**
* @return array of externally managed certificates
*/
protected static function getStaticChildren()
{
$result = [];
$ext_data = json_decode((new Backend())->configdRun('system trust ext_sources') ?? '', true);
if (is_array($ext_data)) {
foreach ($ext_data as $data) {
$payload = \OPNsense\Trust\Store::parseX509($data['cert'] ?? '');
if ($payload !== false && !empty($data['id'])) {
$payload['crt_payload'] = $data['cert'];
$payload['descr'] = $data['descr'] ?? '';
$result[$data['id']] = $payload;
}
}
}
return $result;
}
protected function actionPostLoadingEvent() protected function actionPostLoadingEvent()
{ {
$usernames = []; $usernames = [];

View File

@ -28,7 +28,7 @@
'use strict'; 'use strict';
$( document ).ready(function () { $( document ).ready(function () {
let grid_group = $("#grid-group").UIBootgrid({ let grid_group = $("#{{formGridGroup['table_id']}}").UIBootgrid({
search:'/api/auth/group/search/', search:'/api/auth/group/search/',
get:'/api/auth/group/get/', get:'/api/auth/group/get/',
add:'/api/auth/group/add/', add:'/api/auth/group/add/',
@ -56,32 +56,8 @@
</script> </script>
<div class="tab-content content-box"> <div class="tab-content content-box">
<div id="group" class="tab-pane fade in active"> {{ partial('layout_partials/base_bootgrid_table', formGridGroup + {'command_width': '10em'})}}
<table id="grid-group" class="table table-condensed table-hover table-striped table-responsive" data-editDialog="DialogGroup">
<thead>
<tr>
<th data-column-id="uuid" data-type="string" data-identifier="true" data-visible="false">{{ lang._('ID') }}</th>
<th data-column-id="name" data-type="string">{{ lang._('Name') }}</th>
<th data-column-id="member" data-type="string" data-formatter="member_count">{{ lang._('Member Count') }}</th>
<th data-column-id="description" data-type="string">{{ lang._('Description') }}</th>
<th data-column-id="commands" data-width="10em" data-formatter="commands" data-sortable="false">{{ lang._('Commands') }}</th>
</tr>
</thead>
<tbody>
</tbody>
<tfoot>
<tr>
<td></td>
<td>
<button data-action="add" type="button" class="btn btn-xs btn-primary"><span class="fa fa-fw fa-plus"></span></button>
<button data-action="deleteSelected" type="button" class="btn btn-xs btn-default"><span class="fa fa-fw fa-trash-o"></span></button>
</td>
</tr>
</tfoot>
</table>
</div>
</div> </div>
{{ partial("layout_partials/base_dialog",['fields':formDialogEditGroup,'id':'DialogGroup','label':lang._('Edit Group')])}} {{ partial("layout_partials/base_dialog",['fields':formDialogEditGroup,'id':formGridGroup['edit_dialog_id'],'label':lang._('Edit Group')])}}

View File

@ -28,7 +28,7 @@
'use strict'; 'use strict';
$( document ).ready(function () { $( document ).ready(function () {
let grid_group = $("#grid-group").UIBootgrid({ let grid_priv = $("#{{formGridPriv['table_id']}}").UIBootgrid({
search:'/api/auth/priv/search/', search:'/api/auth/priv/search/',
get:'/api/auth/priv/get_item/', get:'/api/auth/priv/get_item/',
set:'/api/auth/priv/set_item/', set:'/api/auth/priv/set_item/',
@ -58,27 +58,15 @@
} }
}); });
$('button[data-action="add"]').hide();
$('button[data-action="deleteSelected"]').hide();
}); });
</script> </script>
<div class="tab-content content-box"> <div class="tab-content content-box">
<div id="group" class="tab-pane fade in active"> {{ partial('layout_partials/base_bootgrid_table', formGridPriv)}}
<table id="grid-group" class="table table-condensed table-hover table-striped table-responsive" data-editDialog="DialogPriv">
<thead>
<tr>
<th data-column-id="id" data-type="string" data-identifier="true">{{ lang._('ID') }}</th>
<th data-column-id="name" data-type="string">{{ lang._('Name') }}</th>
<th data-column-id="match" data-type="string" data-formatter="lines">{{ lang._('Match') }}</th>
<th data-column-id="users" data-type="string" data-formatter="count" data-sortable="false">{{ lang._('Users') }}</th>
<th data-column-id="groups" data-type="string" data-formatter="count" data-sortable="false">{{ lang._('Groups') }}</th>
<th data-column-id="commands" data-width="10em" data-formatter="commands" data-sortable="false">{{ lang._('Commands') }}</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
</div>
</div> </div>
{{ partial("layout_partials/base_dialog",['fields':formDialogEditPriv,'id':'DialogPriv','label':lang._('Edit Privilege')])}} {{ partial("layout_partials/base_dialog",['fields':formDialogEditPriv,'id':formGridPriv['edit_dialog_id'],'label':lang._('Edit Privilege')])}}

View File

@ -28,7 +28,7 @@
'use strict'; 'use strict';
$( document ).ready(function () { $( document ).ready(function () {
let grid_user = $("#grid-user").UIBootgrid({ let grid_user = $("#{{formGridUser['table_id']}}").UIBootgrid({
search:'/api/auth/user/search/', search:'/api/auth/user/search/',
get:'/api/auth/user/get/', get:'/api/auth/user/get/',
add:'/api/auth/user/add/', add:'/api/auth/user/add/',
@ -43,7 +43,7 @@
let refid = $(this).data("row-id") !== undefined ? $(this).data("row-id") : ''; let refid = $(this).data("row-id") !== undefined ? $(this).data("row-id") : '';
ajaxGet('/api/auth/user/get/' + refid, {}, function(data){ ajaxGet('/api/auth/user/get/' + refid, {}, function(data){
if (data.user) { if (data.user) {
window.location ='/ui/trust/cert/#user=' + data.user.name ; window.location ='/ui/trust/cert#user=' + data.user.name ;
} }
}); });
}, },
@ -171,6 +171,8 @@
$('.datepicker').datepicker({format: 'mm/dd/yyyy'}); $('.datepicker').datepicker({format: 'mm/dd/yyyy'});
/* format authorizedkeys */ /* format authorizedkeys */
$("#user\\.authorizedkeys").css('max-width', 'inherit').prop('wrap', 'off'); $("#user\\.authorizedkeys").css('max-width', 'inherit').prop('wrap', 'off');
$("#grid-user-buttons").children().insertAfter($("#{{ formGridUser['table_id'] }} tfoot [data-action='deleteSelected']"));
}); });
</script> </script>
@ -182,49 +184,32 @@
.tooltip-inner { .tooltip-inner {
max-width: 1000px !important; max-width: 1000px !important;
} }
.btn-user-action {
margin-left: 3px;
}
</style> </style>
<ul class="nav nav-tabs" data-tabs="tabs" id="maintabs"> <ul class="nav nav-tabs" data-tabs="tabs" id="maintabs">
<li class="active"><a data-toggle="tab" href="#user">{{ lang._('Users') }}</a></li> <li class="active"><a data-toggle="tab" href="#user">{{ lang._('Users') }}</a></li>
<li><a data-toggle="tab" href="#apikeys" id="tab_apikeys"> {{ lang._('ApiKeys') }} </a></li> <li><a data-toggle="tab" href="#apikeys" id="tab_apikeys"> {{ lang._('ApiKeys') }} </a></li>
</ul> </ul>
<div id="grid-user-buttons" style="display: none;">
<button
id="upload_users"
type="button"
data-title="{{ lang._('Import Users') }}"
data-endpoint='/api/auth/user/upload'
title="{{ lang._('Import csv') }}"
data-toggle="tooltip"
class="btn btn-xs btn-user-action"
><span class="fa fa-fw fa-upload"></span></button>&nbsp;
<button id="download_users" type="button" title="{{ lang._('Export as csv') }}" data-toggle="tooltip" class="btn btn-xs btn-user-action"><span class="fa fa-fw fa-table"></span></button>
</div>
<div class="tab-content content-box"> <div class="tab-content content-box">
<div id="user" class="tab-pane fade in active"> <div id="user" class="tab-pane fade in active">
<table id="grid-user" class="table table-condensed table-hover table-striped table-responsive" data-editDialog="DialogUser"> {{ partial('layout_partials/base_bootgrid_table', formGridUser + {'command_width': '9em'})}}
<thead>
<tr>
<th data-column-id="uuid" data-type="string" data-identifier="true" data-visible="false">{{ lang._('ID') }}</th>
<th data-column-id="name" data-type="string" data-formatter="username">{{ lang._('Name') }}</th>
<th data-column-id="email" data-type="string" data-visible="false">{{ lang._('Email') }}</th>
<th data-column-id="comments" data-type="string" data-visible="false">{{ lang._('Comments') }}</th>
<th data-column-id="language" data-type="string" data-visible="false">{{ lang._('Language') }}</th>
<th data-column-id="group_memberships" data-type="string">{{ lang._('Groups') }}</th>
<th data-column-id="descr" data-type="string">{{ lang._('Description') }}</th>
<th data-column-id="commands" data-width="10em" data-formatter="commands" data-sortable="false">{{ lang._('Commands') }}</th>
</tr>
</thead>
<tbody>
</tbody>
<tfoot>
<tr>
<td></td>
<td>
<button data-action="add" type="button" class="btn btn-xs btn-primary"><span class="fa fa-fw fa-plus"></span></button>
<button data-action="deleteSelected" type="button" class="btn btn-xs btn-default"><span class="fa fa-fw fa-trash-o"></span></button>
<button
id="upload_users"
type="button"
data-title="{{ lang._('Import Users') }}"
data-endpoint='/api/auth/user/upload'
title="{{ lang._('Import csv') }}"
data-toggle="tooltip"
class="btn btn-xs"
><span class="fa fa-fw fa-upload"></span></button>
<button id="download_users" type="button" title="{{ lang._('Export as csv') }}" data-toggle="tooltip" class="btn btn-xs"><span class="fa fa-fw fa-table"></span></button>
</td>
</tr>
</tfoot>
</table>
</div> </div>
<div id="apikeys" class="tab-pane fade in"> <div id="apikeys" class="tab-pane fade in">
<table id="grid-apikey" class="table table-condensed table-hover table-striped table-responsive" data-editDialog="DialogUser"> <table id="grid-apikey" class="table table-condensed table-hover table-striped table-responsive" data-editDialog="DialogUser">
@ -250,4 +235,4 @@
</div> </div>
</div> </div>
{{ partial("layout_partials/base_dialog",['fields':formDialogEditUser,'id':'DialogUser','label':lang._('Edit User')])}} {{ partial("layout_partials/base_dialog",['fields':formDialogEditUser,'id':formGridUser['edit_dialog_id'],'label':lang._('Edit User')])}}

View File

@ -130,7 +130,7 @@
* perform backend action and install poller to update status * perform backend action and install poller to update status
*/ */
function backend(type) { function backend(type) {
$.upgrade_check = type == 'check' $.upgrade_check = type == 'check';
$('#update_status').html(''); $('#update_status').html('');
$('#updatelist').hide(); $('#updatelist').hide();
@ -647,7 +647,13 @@
backend('audit'); backend('audit');
} else if (window.location.hash == '#checkupdate') { } else if (window.location.hash == '#checkupdate') {
// dashboard link: run check automatically after delay // dashboard link: run check automatically after delay
setTimeout(function () { backend('check'); }, 2000); setTimeout(function () {
ajaxGet('/api/core/firmware/running', {}, function(data, status) {
if (data['status'] != 'busy') {
backend('check');
}
});
}, 2000);
} }
}); });
@ -661,7 +667,7 @@
$("#firmware_mirror").find('option').remove(); $("#firmware_mirror").find('option').remove();
$("#firmware_type").find('option').remove(); $("#firmware_type").find('option').remove();
$("#firmware_flavour").find('option').remove(); $("#firmware_flavour").find('option').remove();
$("#firmware_reboot").prop('checked', firmwareconfig['reboot'] !== ''); $("#firmware_reboot").prop('checked', firmwareconfig['reboot'] == '1');
$.each(firmwareoptions.mirrors, function(key, value) { $.each(firmwareoptions.mirrors, function(key, value) {
var selected = false; var selected = false;
@ -758,7 +764,7 @@
confopt.mirror = $("#firmware_mirror_value").val(); confopt.mirror = $("#firmware_mirror_value").val();
confopt.flavour = $("#firmware_flavour_value").val(); confopt.flavour = $("#firmware_flavour_value").val();
confopt.type = $("#firmware_type").val(); confopt.type = $("#firmware_type").val();
confopt.reboot = $("#firmware_reboot").is(":checked"); confopt.reboot = $("#firmware_reboot").is(":checked") ? '1' : '0';
confopt.subscription = $("#firmware_subscription").val(); confopt.subscription = $("#firmware_subscription").val();
ajaxCall('/api/core/firmware/set', { 'firmware': confopt }, function (data, status) { ajaxCall('/api/core/firmware/set', { 'firmware': confopt }, function (data, status) {
$("#settingstab_progress").removeClass("fa fa-spinner fa-pulse"); $("#settingstab_progress").removeClass("fa fa-spinner fa-pulse");

View File

@ -41,6 +41,10 @@ POSSIBILITY OF SUCH DAMAGE.
$('#grid-arp').bootgrid('reload'); $('#grid-arp').bootgrid('reload');
}); });
$("#refresh").click(function() {
$("#grid-arp").bootgrid("reload");
});
$("#flushModal").click(function(event){ $("#flushModal").click(function(event){
BootstrapDialog.show({ BootstrapDialog.show({
type:BootstrapDialog.TYPE_DANGER, type:BootstrapDialog.TYPE_DANGER,

Some files were not shown because too many files have changed in this diff Show More