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

T6773: RFC-2136 support for Kea DHCP4 server #4153

Open
wants to merge 10 commits into
base: current
Choose a base branch
from
Open
30 changes: 30 additions & 0 deletions data/templates/dhcp-server/kea-dhcp-ddns.conf.j2
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
{
"DhcpDdns": {
"ip-address": "127.0.0.1",
"port": 53001,
"control-socket": {
"socket-type": "unix",
"socket-name": "/run/kea/kea-ddns-ctrl-socket"
},
"tsig-keys": {{ dynamic_dns_update | kea_dynamic_dns_update_tsig_key_json }},
"forward-ddns" : {
"ddns-domains": {{ dynamic_dns_update | kea_dynamic_dns_update_domains('forward_domain') }}
},
"reverse-ddns" : {
"ddns-domains": {{ dynamic_dns_update | kea_dynamic_dns_update_domains('reverse_domain') }}
},
"loggers": [
{
"name": "kea-dhcp-ddns",
"output_options": [
{
"output": "stdout",
"pattern": "%-5p %m\n"
}
],
"severity": "INFO",
"debuglevel": 0
}
]
}
}
13 changes: 13 additions & 0 deletions data/templates/dhcp-server/kea-dhcp4.conf.j2
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,19 @@
"space": "ubnt"
}
],
{% if dynamic_dns_update is vyos_defined %}
"dhcp-ddns": {
"enable-updates": true,
"server-ip": "127.0.0.1",
"server-port": 53001,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if these ports should be configurable, in case someone is already running something on 53001.

"sender-ip": "",
"sender-port": 0,
"max-queue-size": 1024,
"ncr-protocol": "UDP",
"ncr-format": "JSON"
},
{{ dynamic_dns_update | kea_dynamic_dns_update_main_json }}
{% endif %}
"hooks-libraries": [
{% if high_availability is vyos_defined %}
{
Expand Down
19 changes: 19 additions & 0 deletions interface-definitions/include/dhcp/ddns-dns-server.xml.i
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<!-- include start from dhcp/ddns-dns-server.xml.i -->
<tagNode name="dns-server">
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In Kea's config, the ip-address is the required option and the "primary key" of server entries. It also has hostname key which is currently ignored, but that we could add to make servers easier to identify visually.

My feeling is that the server number here is just extra information — as far as I can see from the docs, the order of servers in the list has no special meaning to Kea.

Unless I'm missing anything here, I would make it set dns-server ns1.example.com ip-address 192.0.2.10 (which would generate {'ip-address': '192.0.2.10', 'hostname': 'ns1.example.com'}).

<properties>
<help>DNS server specification</help>
<valueHelp>
<format>u32:1-999999</format>
<description>Number for this DNS server</description>
</valueHelp>
<constraint>
<validator name="numeric" argument="--range 1-999999"/>
</constraint>
<constraintErrorMessage>DNS server number must be between 1 and 999999</constraintErrorMessage>
</properties>
<children>
#include <include/address-ipv4-ipv6-single.xml.i>
#include <include/port-number.xml.i>
</children>
</tagNode>
<!-- include end -->
103 changes: 103 additions & 0 deletions interface-definitions/include/dhcp/ddns-settings.xml.i
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
<!-- include start from dhcp/ddns-settings.xml.i -->
<leafNode name="force-updates">
<properties>
<help>Send updates for this scope</help>
<valueless />
</properties>
</leafNode>
<leafNode name="force-client-update">
<properties>
<help>Always update both forward and reverse DNS data, regardless of the client's request</help>
<valueless />
</properties>
</leafNode>
<leafNode name="force-no-update">
<properties>
<help>Perform a DDNS update, even if the client instructs the server not to</help>
<valueless />
</properties>
</leafNode>
<leafNode name="replace-client-name">
<properties>
<help>Replace client name mode</help>
<completionHelp>
<list>never always when-present when-not-present</list>
</completionHelp>
<valueHelp>
<format>never</format>
<description>Use the name the client sent. If the client sent no name, do not generate
one</description>
</valueHelp>
<valueHelp>
<format>always</format>
<description>Replace the name the client sent. If the client sent no name, generate one
for the client</description>
</valueHelp>
<valueHelp>
<format>when-present</format>
<description>Replace the name the client sent. If the client sent no name, do not
generate one</description>
</valueHelp>
<valueHelp>
<format>when-not-present</format>
<description>Use the name the client sent. If the client sent no name, generate one for
the client</description>
</valueHelp>
<defaultValue>never</defaultValue>
<constraint>
<regex>(never|always|when-present|when-not-present)</regex>
</constraint>
<constraintErrorMessage>Invalid replace client name mode</constraintErrorMessage>
</properties>
</leafNode>
<leafNode name="generated-prefix">
<properties>
<help>The prefix used in the generation of an FQDN</help>
<constraint>
<validator name="fqdn" />
</constraint>
<constraintErrorMessage>Invalid generated prefix</constraintErrorMessage>
</properties>
</leafNode>
<leafNode name="qualifying-suffix">
<properties>
<help>The suffix used when generating an FQDN, or when qualifying a partial name</help>
<constraint>
<validator name="fqdn" />
</constraint>
<constraintErrorMessage>Invalid qualifying suffix</constraintErrorMessage>
</properties>
</leafNode>
<leafNode name="update-on-renew">
<properties>
<help>Update DNS record on lease renew</help>
<valueless />
</properties>
</leafNode>
<leafNode name="use-conflict-resolution">
<properties>
<help>Defines DNS conflict resolution behavior</help>
<valueless />
</properties>
</leafNode>
<leafNode name="ttl-percent">
<properties>
<help>Calculate TTL of the DNS record as a percentage of the lease lifetime</help>
<constraint>
<validator name="numeric" argument="--range 1-100" />
</constraint>
<constraintErrorMessage>Invalid qualifying suffix</constraintErrorMessage>
</properties>
</leafNode>
<leafNode name="hostname-char-set">
<properties>
<help>A regular expression describing the invalid character set in the host name</help>
</properties>
</leafNode>
<leafNode name="hostname-char-replacement">
<properties>
<help>A string of zero or more characters with which to replace each invalid character in
the host name</help>
</properties>
</leafNode>
<!-- include end -->
121 changes: 118 additions & 3 deletions interface-definitions/service_dhcp-server.xml.in
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,111 @@
</properties>
<children>
#include <include/generic-disable-node.xml.i>
<leafNode name="dynamic-dns-update">
<node name="dynamic-dns-update">
<properties>
<help>Dynamically update Domain Name System (RFC4702)</help>
<valueless/>
</properties>
</leafNode>
<children>
#include <include/dhcp/ddns-settings.xml.i>
<tagNode name="tsig-key">
<properties>
<help>TSIG key definition for DNS updates</help>
<constraint>
#include <include/constraint/alpha-numeric-hyphen-underscore.xml.i>
</constraint>
<constraintErrorMessage>Invalid TSIG key name. May only contain letters, numbers, hyphen and underscore</constraintErrorMessage>
</properties>
<children>
<leafNode name="algorithm">
<properties>
<help>TSIG key algorithm</help>
<completionHelp>
<list>hmac-md5 hmac-sha1 hmac-sha224 hmac-sha256 hmac-sha384 hmac-sha512</list>
</completionHelp>
<valueHelp>
<format>hmac-md5</format>
<description>MD5 HMAC algorithm</description>
</valueHelp>
<valueHelp>
<format>hmac-sha1</format>
<description>SHA1 HMAC algorithm</description>
</valueHelp>
<valueHelp>
<format>hmac-sha224</format>
<description>SHA224 HMAC algorithm</description>
</valueHelp>
<valueHelp>
<format>hmac-sha256</format>
<description>SHA256 HMAC algorithm</description>
</valueHelp>
<valueHelp>
<format>hmac-sha384</format>
<description>SHA384 HMAC algorithm</description>
</valueHelp>
<valueHelp>
<format>hmac-sha512</format>
<description>SHA512 HMAC algorithm</description>
</valueHelp>
<constraint>
<regex>(hmac-md5|hmac-sha1|hmac-sha224|hmac-sha256|hmac-sha384|hmac-sha512)</regex>
</constraint>
<constraintErrorMessage>Invalid TSIG key algorithm</constraintErrorMessage>
</properties>
</leafNode>
<leafNode name="secret">
<properties>
<help>TSIG key secret (base64-encoded)</help>
<constraint>
<validator name="base64"/>
</constraint>
</properties>
</leafNode>
</children>
</tagNode>
<tagNode name="forward-domain">
<properties>
<help>Forward DNS domain name</help>
<constraint>
<validator name="fqdn"/>
</constraint>
<constraintErrorMessage>Invalid forward DNS domain name</constraintErrorMessage>
abukharov marked this conversation as resolved.
Show resolved Hide resolved
</properties>
<children>
<leafNode name="key-name">
<properties>
<help>TSIG key name for forward DNS updates</help>
<constraint>
#include <include/constraint/alpha-numeric-hyphen-underscore.xml.i>
</constraint>
<constraintErrorMessage>Invalid TSIG key name. May only contain letters, numbers, numbers, hyphen and underscore</constraintErrorMessage>
</properties>
</leafNode>
#include <include/dhcp/ddns-dns-server.xml.i>
</children>
</tagNode>
<tagNode name="reverse-domain">
<properties>
<help>Reverse DNS domain name</help>
<constraint>
<validator name="fqdn"/>
</constraint>
<constraintErrorMessage>Invalid reverse DNS domain name</constraintErrorMessage>
</properties>
<children>
<leafNode name="key-name">
<properties>
<help>TSIG key name for reverse DNS updates</help>
<constraint>
#include <include/constraint/alpha-numeric-hyphen-underscore.xml.i>
</constraint>
<constraintErrorMessage>Invalid TSIG key name. May only contain letters, numbers, numbers, hyphen and underscore</constraintErrorMessage>
</properties>
</leafNode>
#include <include/dhcp/ddns-dns-server.xml.i>
</children>
</tagNode>
</children>
</node>
<node name="high-availability">
<properties>
<help>DHCP high availability configuration</help>
Expand Down Expand Up @@ -105,6 +204,14 @@
<constraintErrorMessage>Invalid shared network name. May only contain letters, numbers and .-_</constraintErrorMessage>
</properties>
<children>
<node name="dynamic-dns-update">
<properties>
<help>Dynamically update Domain Name System (RFC4702)</help>
</properties>
<children>
#include <include/dhcp/ddns-settings.xml.i>
</children>
</node>
<leafNode name="authoritative">
<properties>
<help>Option to make DHCP server authoritative for this physical network</help>
Expand All @@ -130,6 +237,14 @@
#include <include/dhcp/option-v4.xml.i>
#include <include/generic-description.xml.i>
#include <include/generic-disable-node.xml.i>
<node name="dynamic-dns-update">
<properties>
<help>Dynamically update Domain Name System (RFC4702)</help>
</properties>
<children>
#include <include/dhcp/ddns-settings.xml.i>
</children>
</node>
<leafNode name="exclude">
<properties>
<help>IP address to exclude from DHCP lease range</help>
Expand Down
38 changes: 38 additions & 0 deletions python/vyos/kea.py
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,9 @@ def kea_parse_subnet(subnet, config):
reservations.append(reservation)
out['reservations'] = reservations

if 'dynamic_dns_update' in config:
out.update(kea_parse_ddns_settings(config['dynamic_dns_update']))

return out

def kea6_parse_options(config):
Expand Down Expand Up @@ -295,6 +298,41 @@ def kea6_parse_subnet(subnet, config):

return out

def kea_parse_tsig_algo(algo_spec):
translate = {
'hmac-md5': 'HMAC-MD5',
'hmac-sha1': 'HMAC-SHA1',
'hmac-sha224': 'HMAC-SHA224',
'hmac-sha256': 'HMAC-SHA256',
'hmac-sha384': 'HMAC-SHA384',
'hmac-sha512': 'HMAC-SHA512'
}
return translate[algo_spec]

def kea_parse_ddns_settings(config):
data = {
"ddns-send-updates": 'force_updates' in config,
"ddns-override-no-update": 'force_no_update' in config,
"ddns-override-client-update": 'force_client_update' in config,
"ddns-update-on-renew": 'update_on_renew' in config,
"ddns-use-conflict-resolution": 'use_conflict_resolution' in config,
}

if 'replace_client_name' in config:
data['ddns-replace-client-name'] = config['replace_client_name']
if 'generated_prefix' in config:
data['ddns-generated-prefix'] = config['generated_prefix']
if 'qualifying_suffix' in config:
data['ddns-qualifying-suffix'] = config['qualifying_suffix']
if 'ttl_percent' in config:
data['ddns-ttl-percent'] = int(config['ttl_percent']) / 100
if 'hostname_char_set' in config:
data['hostname-char-set'] = config['hostname_char_set']
if 'hostname_char_replacement' in config:
data['hostname-char-replacement'] = config['hostname_char_replacement']

return data

def _ctrl_socket_command(inet, command, args=None):
path = kea_ctrl_socket.format(inet=inet)

Expand Down
Loading
Loading