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' %}