diff --git a/src/opnsense/mvc/app/controllers/OPNsense/Dnsmasq/forms/dialogDHCPmatch.xml b/src/opnsense/mvc/app/controllers/OPNsense/Dnsmasq/forms/dialogDHCPmatch.xml
index aae97dcd5..7feb25868 100644
--- a/src/opnsense/mvc/app/controllers/OPNsense/Dnsmasq/forms/dialogDHCPmatch.xml
+++ b/src/opnsense/mvc/app/controllers/OPNsense/Dnsmasq/forms/dialogDHCPmatch.xml
@@ -3,7 +3,13 @@
match.option
dropdown
- Option to offer to the client.
+ DHCPv4 option to offer to the client.
+
+
+ match.option6
+
+ dropdown
+ DHCPv6 option to offer to the client.
match.set_tag
diff --git a/src/opnsense/mvc/app/controllers/OPNsense/Dnsmasq/forms/dialogDHCPoption.xml b/src/opnsense/mvc/app/controllers/OPNsense/Dnsmasq/forms/dialogDHCPoption.xml
index 712ac7f0d..461af1bc6 100644
--- a/src/opnsense/mvc/app/controllers/OPNsense/Dnsmasq/forms/dialogDHCPoption.xml
+++ b/src/opnsense/mvc/app/controllers/OPNsense/Dnsmasq/forms/dialogDHCPoption.xml
@@ -3,13 +3,13 @@
option.option
dropdown
- Option to offer to the client.
+ DHCPv4 option to offer to the client.
- option.protocol
-
+ option.option6
+
dropdown
- The protocol to use for this option. Options used for DHCPv6 require IPv6 to match.
+ DHCPv6 option to offer to the client.
option.interface
diff --git a/src/opnsense/mvc/app/models/OPNsense/Dnsmasq/Dnsmasq.php b/src/opnsense/mvc/app/models/OPNsense/Dnsmasq/Dnsmasq.php
index 535d0cf24..9ce90b359 100644
--- a/src/opnsense/mvc/app/models/OPNsense/Dnsmasq/Dnsmasq.php
+++ b/src/opnsense/mvc/app/models/OPNsense/Dnsmasq/Dnsmasq.php
@@ -162,6 +162,56 @@ class Dnsmasq extends BaseModel
}
}
+ foreach ($this->dhcp_options->iterateItems() as $option) {
+ if (!$validateFullModel && !$option->isFieldChanged()) {
+ continue;
+ }
+ $key = $option->__reference;
+
+ if (!$option->option->isEmpty() && !$option->option6->isEmpty()) {
+ $messages->appendMessage(
+ new Message(
+ gettext("'Option' and 'Option6' cannot be selected at the same time."),
+ $key . ".option"
+ )
+ );
+ }
+
+ if ($option->option->isEmpty() && $option->option6->isEmpty()) {
+ $messages->appendMessage(
+ new Message(
+ gettext("Either 'Option' or 'Option6' is required."),
+ $key . ".option"
+ )
+ );
+ }
+ }
+
+ foreach ($this->dhcp_options_match->iterateItems() as $match) {
+ if (!$validateFullModel && !$match->isFieldChanged()) {
+ continue;
+ }
+ $key = $match->__reference;
+
+ if (!$match->option->isEmpty() && !$match->option6->isEmpty()) {
+ $messages->appendMessage(
+ new Message(
+ gettext("'Option' and 'Option6' cannot be selected at the same time."),
+ $key . ".option"
+ )
+ );
+ }
+
+ if ($match->option->isEmpty() && $match->option6->isEmpty()) {
+ $messages->appendMessage(
+ new Message(
+ gettext("Either 'Option' or 'Option6' is required."),
+ $key . ".option"
+ )
+ );
+ }
+ }
+
if (
($validateFullModel || $this->enable->isFieldChanged() || $this->port->isFieldChanged()) &&
!empty((string)$this->enable)
diff --git a/src/opnsense/mvc/app/models/OPNsense/Dnsmasq/Dnsmasq.xml b/src/opnsense/mvc/app/models/OPNsense/Dnsmasq/Dnsmasq.xml
index 9cb66284f..db13e9938 100644
--- a/src/opnsense/mvc/app/models/OPNsense/Dnsmasq/Dnsmasq.xml
+++ b/src/opnsense/mvc/app/models/OPNsense/Dnsmasq/Dnsmasq.xml
@@ -185,14 +185,10 @@
-
- IPv4
-
- IPv6
-
-
+
+ dnsmasq list dhcp_options6
+
Any
@@ -217,8 +213,10 @@
+
+ dnsmasq list dhcp_options6
+
diff --git a/src/opnsense/scripts/dns/dnsmasq_dhcp_options.py b/src/opnsense/scripts/dns/dnsmasq_dhcp_options.py
index 83af23282..f10f44955 100755
--- a/src/opnsense/scripts/dns/dnsmasq_dhcp_options.py
+++ b/src/opnsense/scripts/dns/dnsmasq_dhcp_options.py
@@ -28,13 +28,20 @@
"""
import json
import subprocess
+import argparse
+
+parser = argparse.ArgumentParser()
+parser.add_argument("mode", nargs="?", default="dhcp", choices=["dhcp", "dhcp6"])
+args = parser.parse_args()
+
+result = {}
# not yet registered by name, but pratical to have
# https://www.iana.org/assignments/bootp-dhcp-parameters/bootp-dhcp-parameters.xhtml
-result = {
- '114' : 'dhcp captive-portal [114]'
-}
-sp = subprocess.run(['/usr/local/sbin/dnsmasq', '--help','dhcp'], capture_output=True, text=True)
+if args.mode == "dhcp":
+ result['114'] = 'dhcp captive-portal [114]'
+
+sp = subprocess.run(['/usr/local/sbin/dnsmasq', '--help', args.mode], capture_output=True, text=True)
for line in sp.stdout.split("\n"):
parts = line.split(maxsplit=1)
if len(parts) == 2 and parts[0].isdigit():
diff --git a/src/opnsense/service/conf/actions.d/actions_dnsmasq.conf b/src/opnsense/service/conf/actions.d/actions_dnsmasq.conf
index 380ca9eba..1e1d0d84c 100644
--- a/src/opnsense/service/conf/actions.d/actions_dnsmasq.conf
+++ b/src/opnsense/service/conf/actions.d/actions_dnsmasq.conf
@@ -20,11 +20,17 @@ type:script_output
message:Request Dnsmasq status
[list.dhcp_options]
-command:/usr/local/opnsense/scripts/dns/dnsmasq_dhcp_options.py
+command:/usr/local/opnsense/scripts/dns/dnsmasq_dhcp_options.py dhcp
type:script_output
message:request dhcp options
cache_ttl:86400
+[list.dhcp_options6]
+command:/usr/local/opnsense/scripts/dns/dnsmasq_dhcp_options.py dhcp6
+type:script_output
+message:request dhcp options6
+cache_ttl:86400
+
[list.leases]
command:/usr/local/opnsense/scripts/dhcp/get_dnsmasq_leases.py
parameters:
diff --git a/src/opnsense/service/templates/OPNsense/Dnsmasq/dnsmasq.conf b/src/opnsense/service/templates/OPNsense/Dnsmasq/dnsmasq.conf
index 930bbc247..79b2860a7 100644
--- a/src/opnsense/service/templates/OPNsense/Dnsmasq/dnsmasq.conf
+++ b/src/opnsense/service/templates/OPNsense/Dnsmasq/dnsmasq.conf
@@ -186,7 +186,13 @@ dhcp-host={{host.hwaddr}}{% if host.set_tag%},set:{{host.set_tag|replace('-','')
{% if option.interface %}
{% do all_tags.append('tag:' + helpers.physical_interface(option.interface)) %}
{% endif %}
-dhcp-option{% if option.force == '1' %}-force{% endif %}={% if all_tags %}{{ all_tags|join(',') }},{% endif %}{% if option.protocol %}{{ option.protocol }}:{% endif %}{{ option.option }},{{ option.value }}
+dhcp-option{% if option.force == '1' %}-force{% endif -%}=
+{%- if all_tags %}{{ all_tags|join(',') }},{% endif -%}
+{%- if option.option6 -%}
+option6:{{ option.option6 }},{{ option.value }}
+{%- else -%}
+{{ option.option }},{{ option.value }}
+{%- endif +%}
{% if not option.tag and not option.interface and option.option == '6' %}
{% do has_default.append(1) %}
{% endif %}
@@ -198,7 +204,12 @@ dhcp-option=6,0.0.0.0
{% endif %}
{% for match in helpers.toList('dnsmasq.dhcp_options_match') %}
-dhcp-match=set:{{match.set_tag.replace('-','')}},{{match.option}}{%if match.value %},{{match.value}}{% endif +%}
+dhcp-match=set:{{ match.set_tag.replace('-','') }},
+{%- if match.option6 -%}
+option6:{{ match.option6 }}{% if match.value %},{{ match.value }}{% endif %}
+{%- else -%}
+{{ match.option }}{% if match.value %},{{ match.value }}{% endif %}
+{%- endif +%}
{% endfor %}
{% if dnsmasq.no_ident == '1' %}