Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow setting UniFi Controller IP in Kea DHCP. #7361

Open
wants to merge 16 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -166,4 +166,29 @@ public function delPeerAction($uuid)
{
return $this->delBase("ha_peers.peer", $uuid);
}

public function searchOptionAction()
{
return $this->searchBase("options.option", ['name', 'code', 'space', 'type', 'data'], "name");
}

public function setOptionAction($uuid)
{
return $this->setBase("option", "options.option", $uuid);
}

public function addOptionAction()
{
return $this->addBase("option", "options.option");
}

public function getOptionAction($uuid = null)
{
return $this->getBase("option", "options.option", $uuid);
}

public function delOptionAction($uuid)
{
return $this->delBase("options.option", $uuid);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ public function v4Action()
$this->view->formDialogSubnet = $this->getForm("dialogSubnet4");
$this->view->formDialogReservation = $this->getForm("dialogReservation4");
$this->view->formDialogPeer = $this->getForm("dialogPeer4");
$this->view->formDialogOption = $this->getForm("dialogOption4");
}

public function leases4Action()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
<form>
<field>
<id>option.name</id>
<label>Name</label>
<type>text</type>
</field>
<field>
<id>option.test</id>
<label>Client Class Test</label>
<type>text</type>
<advanced>true</advanced>
<help><![CDATA[Only send this option if the client matches the given <a rel="help" href="https://kea.readthedocs.io/en/kea-2.2.0/arm/classify.html?highlight=test%20expressions#using-expressions-in-classification">test expression</a>.]]></help>
</field>
<field>
<id>option.code</id>
<label>Code</label>
<type>text</type>
</field>
<field>
<id>option.space</id>
<label>Space</label>
<type>dropdown</type>
</field>
<field>
<id>option.type</id>
<label>Type</label>
<type>dropdown</type>
<help><![CDATA[A <a rel="help" href="https://kea.readthedocs.io/en/latest/arm/dhcp4-srv.html#dhcp-types">DHCP option type</a>.]]></help>
</field>
<field>
<id>option.array</id>
<label>Array</label>
<type>checkbox</type>
<help><![CDATA[If enabled and <b>Type</b> is <code>record</code>, the last field in <b>Record Types</b> can contain one or multiple values.]]></help>
</field>
<field>
<id>option.record_types</id>
<label>Record Types</label>
<type>text</type>
<help><![CDATA[Comma-separated list of <a rel="help" href="https://kea.readthedocs.io/en/latest/arm/dhcp4-srv.html#dhcp-types">DHCP option types</a>. Only applies if <b>Type</b> is <code>record</code>.]]></help>
<style>record_types</style>
</field>
<field>
<id>option.data</id>
<label>Data</label>
<type>text</type>
</field>
</form>
Original file line number Diff line number Diff line change
Expand Up @@ -86,4 +86,10 @@
<type>text</type>
<help>Boot filename to request</help>
</field>
<field>
<id>subnet4.additional_options</id>
<label>Additional options</label>
<type>select_multiple</type>
<style>tokenize</style>
</field>
</form>
80 changes: 80 additions & 0 deletions src/opnsense/mvc/app/models/OPNsense/Kea/KeaDhcpv4.xml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,74 @@
<Mask>/^([0-9a-zA-Z.\:\-,_]){0,1024}$/u</Mask>
</this_server_name>
</ha>
<options>
<option type="ArrayField">
<name type="TextField">
<Required>Y</Required>
<Constraints>
<check001>
<ValidationMessage>Duplicate entry exists</ValidationMessage>
<type>UniqueConstraint</type>
</check001>
</Constraints>
</name>
<test type="TextField">
<Default></Default>
</test>
<code type="IntegerField">
<Required>Y</Required>
</code>
<space type="OptionField">
<Required>Y</Required>
<Default>dhcp4</Default>
<OptionValues>
<dhcp4>dhcp4</dhcp4>
<vendor_encapsulated_options_space>vendor-encapsulated-options-space</vendor_encapsulated_options_space>
</OptionValues>
</space>
<type type="OptionField">
<Required>Y</Required>
<OptionValues>
<binary>binary</binary>
<boolean>boolean</boolean>
<fqdn>fqdn</fqdn>
<ipv4_address>ipv4-address</ipv4_address>
<ipv6_address>ipv6-address</ipv6_address>
<ipv6_prefix>ipv6-prefix</ipv6_prefix>
<psid>psid</psid>
<record>record</record>
<string>string</string>
<tuple>tuple</tuple>
<uint8>uint8</uint8>
<uint16>uint16</uint16>
<uint32>uint32</uint32>
<int8>int8</int8>
<int16>int16</int16>
<int32>int32</int32>
</OptionValues>
</type>
<array type="BooleanField">
<Required>Y</Required>
<Default>0</Default>
</array>
<record_types type="TextField">
<Default></Default>
<Constraints>
<check001>
<ValidationMessage>Record requires at least one field type.</ValidationMessage>
<type>SetIfConstraint</type>
<field>type</field>
<check>record</check>
</check001>
</Constraints>
<AsList>Y</AsList>
<FieldSeparator>,</FieldSeparator>
</record_types>
<data type="TextField">
<Required>Y</Required>
</data>
</option>
</options>
<subnets>
<subnet4 type="ArrayField">
<subnet type="NetworkField">
Expand Down Expand Up @@ -84,6 +152,18 @@
<Mask>/^([^\n"])*$/u</Mask>
</boot_file_name>
</option_data>
<additional_options type="ModelRelationField">
<Multiple>Y</Multiple>
<Model>
<subnets>
<source>OPNsense.Kea.KeaDhcpv4</source>
<items>options.option</items>
<display>name</display>
</subnets>
</Model>
<ValidationMessage>Related option not found</ValidationMessage>
<AsList>1</AsList>
</additional_options>
<pools type=".\KeaPoolsField">
</pools>
</subnet4>
Expand Down
38 changes: 38 additions & 0 deletions src/opnsense/mvc/app/views/OPNsense/Kea/dhcpv4.volt
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,15 @@
}
);

$("#grid-options").UIBootgrid(
{ search:'/api/kea/dhcpv4/search_option',
get:'/api/kea/dhcpv4/get_option/',
set:'/api/kea/dhcpv4/set_option/',
add:'/api/kea/dhcpv4/add_option/',
del:'/api/kea/dhcpv4/del_option/'
}
);

$("#reconfigureAct").SimpleActionButton({
onPreAction: function() {
const dfObj = new $.Deferred();
Expand Down Expand Up @@ -112,6 +121,7 @@
<li><a data-toggle="tab" href="#subnets" id="tab_pools"> {{ lang._('Subnets') }} </a></li>
<li><a data-toggle="tab" href="#reservations" id="tab_reservations"> {{ lang._('Reservations') }} </a></li>
<li><a data-toggle="tab" href="#ha-peers" id="tab_ha-peers"> {{ lang._('HA Peers') }} </a></li>
<li><a data-toggle="tab" href="#options" id="tab_options"> {{ lang._('Options') }} </a></li>
</ul>
<div class="tab-content content-box">
<!-- general settings -->
Expand Down Expand Up @@ -200,6 +210,33 @@
</table>
</div>

<!-- Options -->
<div id="options" class="tab-pane fade in">
<table id="grid-options" class="table table-condensed table-hover table-striped" data-editDialog="DialogOption">
<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="code" data-type="number">{{ lang._('Code') }}</th>
<th data-column-id="space" data-type="string">{{ lang._('Space') }}</th>
<th data-column-id="type" data-type="string">{{ lang._('Type') }}</th>
<th data-column-id="data" data-type="string">{{ lang._('Data') }}</th>
<th data-column-id="commands" data-width="7em" 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>
</td>
</tr>
</tfoot>
</table>
</div>

</div>

<section class="page-content-main">
Expand All @@ -220,3 +257,4 @@
{{ partial("layout_partials/base_dialog",['fields':formDialogSubnet,'id':'DialogSubnet','label':lang._('Edit Subnet')])}}
{{ partial("layout_partials/base_dialog",['fields':formDialogReservation,'id':'DialogReservation','label':lang._('Edit Reservation')])}}
{{ partial("layout_partials/base_dialog",['fields':formDialogPeer,'id':'DialogPeer','label':lang._('Edit Peer')])}}
{{ partial("layout_partials/base_dialog",['fields':formDialogOption,'id':'DialogOption','label':lang._('Edit Option')])}}
81 changes: 76 additions & 5 deletions src/opnsense/service/templates/OPNsense/Kea/kea-dhcp4.conf
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
'domain_name': system.domain
}) -%}
{%- set general = OPNsense.Kea.dhcp4.general -%}
{%- set options = helpers.toList('OPNsense.Kea.dhcp4.options.option') -%}
{
"Dhcp4": {
"valid-lifetime": {{general.valid_lifetime}},
Expand All @@ -33,18 +34,87 @@
"severity": "INFO"
}
],
"option-def": [
{% for option in options if option.space == 'vendor_encapsulated_options_space' %}
{
"name": {{option.name.replace('_','-')|tojson}},
"code": {{option.code|int|tojson}},
"space": {{option.name.replace('_','-')|tojson}},
"type": {{option.type.replace('_','-')|tojson}},
"array": {{((option.array|int) == 1)|tojson}}
{%- if option.type == 'record' -%}
,
"record-types": {{option.record_types|default('')|tojson}}
{% endif +%}
}{% if not loop.last %},{% endif +%}
{% endfor %}
],
{% for option in options %}
{% if loop.first %}
"client-classes": [
{%- endif +%}
{
"name": {{option.name|tojson}},
{%- if option.test +%}
"test": {{option.test|tojson}},
{%- else +%}
"test": "0 == 0",
{%- endif +%}
"only-if-required": true,
{% if option.space == 'vendor_encapsulated_options_space' %}
"option-def": [
{
"name": "vendor-encapsulated-options",
"code": 43,
"type": "empty",
"encapsulate": {{option.name.replace('_','-')|tojson}}
}
],
{% endif %}
"option-data": [
{% if option.space == 'vendor_encapsulated_options_space' %}
{
"name": {{option.name.replace('_','-')|tojson}},
"space": {{option.name.replace('_','-')|tojson}},
"code": {{option.code|int|tojson}},
"data": {{option.data|tojson}}
},
{
"name": "vendor-encapsulated-options",
"always-send": true
}
{%- else -%}
{
"name": {{option.name.replace('_','-')|tojson}},
"space": {{option.space.replace('_','-')|tojson}},
"code": {{option.code|int|tojson}},
"data": {{option.data|tojson}}
}
{%- endif +%}
]
}{% if not loop.last %},{% endif +%}
{% if loop.last %}
],
{% endif %}
{% endfor %}
"subnet4": [
{% for subnet in helpers.toList('OPNsense.Kea.dhcp4.subnets.subnet4') %}
{%- for subnet in helpers.toList('OPNsense.Kea.dhcp4.subnets.subnet4') %}
{% set additional_options = (subnet.additional_options|default('')).split(',') +%}
{
"id": {{loop.index}},
"subnet": "{{subnet.subnet}}",
"require-client-classes": [
{%- for option in options if option['@uuid'] in additional_options +%}
{{option.name|tojson}}{% if not loop.last %},{% endif %}
{%- endfor +%}
],
"option-data": [
{% for od_attr in (subnet.option_data|list + option_data_defaults|list)|unique if subnet.option_data[od_attr]|length > 1 or od_attr in option_data_defaults %}
{
"name": "{{od_attr.replace('_','-')}}",
"name": {{od_attr.replace('_','-')|tojson}},
"data": {{subnet.option_data[od_attr]|default(option_data_defaults[od_attr])|tojson}}
}{% if not loop.last %},{% endif +%}
{% endfor %}
{%- endfor +%}
],
"pools": [
{% for pool in (subnet.pools|default('')).split("\n") if pool|length > 1%}
Expand All @@ -63,8 +133,9 @@
}{% if not loop.last %},{% endif +%}
{% endfor %}
]
{% if not helpers.empty('OPNsense.Kea.ctrl_agent.general.enabled') %}
,"hooks-libraries": [
{%- if not helpers.empty('OPNsense.Kea.ctrl_agent.general.enabled') -%}
,
"hooks-libraries": [
{
"library": "/usr/local/lib/kea/hooks/libdhcp_lease_cmds.so",
"parameters": { }
Expand Down