diff --git a/src/opnsense/mvc/app/controllers/OPNsense/Dnsmasq/forms/dialogDHCPrange.xml b/src/opnsense/mvc/app/controllers/OPNsense/Dnsmasq/forms/dialogDHCPrange.xml index 01c5fffea..4f0e5c3f4 100644 --- a/src/opnsense/mvc/app/controllers/OPNsense/Dnsmasq/forms/dialogDHCPrange.xml +++ b/src/opnsense/mvc/app/controllers/OPNsense/Dnsmasq/forms/dialogDHCPrange.xml @@ -15,7 +15,7 @@ range.start_addr text - Start of the range, e.g. 192.168.1.100, 2000::1 or when constructor is used a partial like ::1. + Start of the range, e.g. 192.168.1.100 for DHCPv4, 2000::1 for DHCPv6 or when a constructor is using a suffix like ::1. To reveal IPv6 related options, enter a IPv6 address. When using router advertisements, it is possible to use a constructor with :: as the start address and no end address. range.end_addr @@ -27,19 +27,81 @@ range.constructor dropdown - Interface to use to calculate the proper range, when selected, a range maybe specified as partial (e.g. ::1, ::400) + + Interface to use to calculate the proper range, when selected, a range may be specified as a suffix (e.g. ::1, ::400) + + false + range.prefix_len text 64 - Prefix length offered to the client. + + Prefix length offered to the client. Custom values in this field will be ignored if Router Advertisements are enabled, as SLAAC will only work with a prefix length of 64. + + false + + + + range.ra_mode + + select_multiple + Default + + Control how IPv6 clients receive their addresses. Enabling Router Advertisements in general settings will enable it for all configured DHCPv6 ranges with the managed address bits set, and the use SLAAC bit reset. To change this default, select a combination of the possible options here. "slaac", "ra-stateless" and "ra-names" can be freely combined, all other options shall remain single selections. + + false + + + + range.ra_priority + + dropdown + Priority of the RA announcements. + + + false + + + + range.ra_mtu + + text + + Optional MTU to send to clients via Router Advertisements. If unsure leave empty. + + false + + + + range.ra_interval + + text + 60 + + Time (seconds) between Router Advertisements. + + false + + + + range.ra_router_lifetime + + text + 1200 + + The lifetime of the route may be changed or set to zero, which allows a router to advertise prefixes but not a route via itself. When using HA, setting a short timespan here is adviced for faster IPv6 failover. A good combination could be 10 seconds RA interval and 30 seconds RA router lifetime. Going lower than that can pose issues in busy networks. + + false + range.mode select_multiple + Mode flags to set for this range, 'static' means no addresses will be automatically assigned. diff --git a/src/opnsense/mvc/app/controllers/OPNsense/Dnsmasq/forms/general.xml b/src/opnsense/mvc/app/controllers/OPNsense/Dnsmasq/forms/general.xml index b2869e6bd..e5d361618 100644 --- a/src/opnsense/mvc/app/controllers/OPNsense/Dnsmasq/forms/general.xml +++ b/src/opnsense/mvc/app/controllers/OPNsense/Dnsmasq/forms/general.xml @@ -178,6 +178,12 @@ checkbox Automatically register firewall rules to allow dhcp traffic for all explicitly selected interfaces, can be disabled for more fine grained control if needed. Changes are only effective after a firewall service restart (see system diagnostics). + + dnsmasq.dhcp.enable_ra + + checkbox + Setting this will enable Router Advertisements for all configured DHCPv6 ranges with the managed address bits set, and the use SLAAC bit reset. To change this default, select a combination of the possible options in the individual DHCPv6 ranges. Keep in mind that this is a global option; if there are configured DHCPv6 ranges, RAs will be sent unconditionally and cannot be deactivated selectively. Setting Router Advertisement modes in DHCPv6 ranges will have no effect without this global option enabled. + dnsmasq.dhcp.nosync diff --git a/src/opnsense/mvc/app/models/OPNsense/Dnsmasq/Dnsmasq.php b/src/opnsense/mvc/app/models/OPNsense/Dnsmasq/Dnsmasq.php index 9ce90b359..ac94790d0 100644 --- a/src/opnsense/mvc/app/models/OPNsense/Dnsmasq/Dnsmasq.php +++ b/src/opnsense/mvc/app/models/OPNsense/Dnsmasq/Dnsmasq.php @@ -160,6 +160,39 @@ class Dnsmasq extends BaseModel ) ); } + + // Validate RA mode combinations + $valid_ra_mode_combinations = [ + ['ra-names', 'slaac'], + ['ra-names', 'ra-stateless'], + ['slaac', 'ra-stateless'], + ['ra-names', 'slaac', 'ra-stateless'] + ]; + + $selected_ra_modes = explode(',', $range->ra_mode); + + // If only one mode is selected, it is always valid + if (count($selected_ra_modes) > 1) { + $is_ra_mode_valid = false; + foreach ($valid_ra_mode_combinations as $ra_mode_combination) { + // Ensure order independant comparing + if (empty(array_diff($selected_ra_modes, $ra_mode_combination)) && + empty(array_diff($ra_mode_combination, $selected_ra_modes))) { + $is_ra_mode_valid = true; + break; + } + } + + if (!$is_ra_mode_valid) { + $messages->appendMessage( + new Message( + gettext("Invalid RA mode combination."), + $key . ".ra_mode" + ) + ); + } + } + } foreach ($this->dhcp_options->iterateItems() as $option) { diff --git a/src/opnsense/mvc/app/models/OPNsense/Dnsmasq/Dnsmasq.xml b/src/opnsense/mvc/app/models/OPNsense/Dnsmasq/Dnsmasq.xml index db13e9938..759abec62 100644 --- a/src/opnsense/mvc/app/models/OPNsense/Dnsmasq/Dnsmasq.xml +++ b/src/opnsense/mvc/app/models/OPNsense/Dnsmasq/Dnsmasq.xml @@ -1,6 +1,6 @@ /dnsmasq - 1.0.3 + 1.0.4 @@ -63,6 +63,7 @@ 0 60 + @@ -180,6 +181,27 @@ N + + + ra-only + slaac + ra-names + ra-stateless + ra-advrouter + off-link + + Y + + + Normal + + High + Low + + + + + diff --git a/src/opnsense/mvc/app/views/OPNsense/Dnsmasq/settings.volt b/src/opnsense/mvc/app/views/OPNsense/Dnsmasq/settings.volt index d2d096502..7d11c6a0c 100644 --- a/src/opnsense/mvc/app/views/OPNsense/Dnsmasq/settings.volt +++ b/src/opnsense/mvc/app/views/OPNsense/Dnsmasq/settings.volt @@ -124,6 +124,18 @@ }); let selected_tab = window.location.hash != "" ? window.location.hash : "#general"; $('a[href="' +selected_tab + '"]').click(); + + $("#range\\.start_addr").on("keyup change", function() { + let value = $(this).val() || ""; + if (value.includes(":")) { + $(".style_dhcpv6").closest('tr').show(); + $(".style_dhcpv4").closest('tr').hide(); + } else { + $(".style_dhcpv6").closest('tr').hide(); + $(".style_dhcpv4").closest('tr').show(); + } + }); + }); diff --git a/src/opnsense/service/templates/OPNsense/Dnsmasq/dnsmasq.conf b/src/opnsense/service/templates/OPNsense/Dnsmasq/dnsmasq.conf index 79b2860a7..8ca8c8300 100644 --- a/src/opnsense/service/templates/OPNsense/Dnsmasq/dnsmasq.conf +++ b/src/opnsense/service/templates/OPNsense/Dnsmasq/dnsmasq.conf @@ -42,6 +42,10 @@ dhcp-authoritative dhcp-reply-delay={{dnsmasq.dhcp.reply_delay}} {% endif %} +{# Globally enable RA #} +{% if dnsmasq.dhcp.enable_ra|default('0') == '1' %} +enable-ra +{% endif %} {% if dnsmasq.strictbind == '1' %} # On systems which support it, dnsmasq binds the wildcard address, @@ -123,7 +127,6 @@ local-ttl={{dnsmasq.local_ttl|default('1')}} conf-dir=/usr/local/etc/dnsmasq.conf.d,\*.conf - {% for dhcp_range in helpers.toList('dnsmasq.dhcp_ranges') %} {% if dhcp_range.start_addr and ':' not in dhcp_range.start_addr %} {# IPv4 range #} @@ -142,7 +145,7 @@ set:{{dhcp_range.set_tag|replace('-','')}}, {%- endif -%} {{dhcp_range.lease_time|default('86400')}} {% else %} -{# IPv6 range #} +{# IPv6 range and RA #} dhcp-range={%if dhcp_range.interface -%} tag:{{helpers.physical_interface(dhcp_range.interface)}}, {%- endif -%} @@ -159,13 +162,25 @@ constructor:{{helpers.physical_interface(dhcp_range.constructor)}}, {%- if dhcp_range.mode -%} {{dhcp_range.mode}}, {%- endif -%} -{%- if dhcp_range.prefix_len -%} -{{ dhcp_range.prefix_len }}, -{%- endif -%} -{{dhcp_range.lease_time|default('86400')}} +{#- Using a prefix other than 64 is illegal when slaac is used. -#} +{%- if not dhcp_range.ra_mode and dnsmasq.dhcp.enable_ra|default('0') == '0' -%} +{{ dhcp_range.prefix_len|default('64') }}, +{%- endif %} +{%- if dhcp_range.ra_mode %}{{ dhcp_range.ra_mode }},{% endif %} +{{ dhcp_range.lease_time|default('86400') }} {% endif %} + {% if dhcp_range.domain %} domain={{ dhcp_range.domain }},{{dhcp_range.start_addr}},{{dhcp_range.end_addr}} +{% endif %} + +{% if dhcp_range.ra_mode %} +ra-param={{ helpers.physical_interface(dhcp_range.constructor) }} +{%- if dhcp_range.ra_mtu %},mtu:{{ dhcp_range.ra_mtu }}{% endif -%} +{%- if dhcp_range.ra_priority %},{{ dhcp_range.ra_priority }}{% endif -%}, +{%- if dhcp_range.ra_interval %}{{ dhcp_range.ra_interval }}{% else %}60{% endif -%}, +{%- if dhcp_range.ra_router_lifetime %}{{ dhcp_range.ra_router_lifetime }}{% else %}1200{% endif +%} + {% endif %} {% endfor %}