dhcp
Ansible role dhcp
Ansible role for setting up ISC DHCPD. The responsibilities of this role are to install packages and manage the configuration (dhcpd.conf(5)). Managing the firewall configuration is NOT a concern of this role. You can do this in your local playbook, or use another role (e.g. bertvv.rh-base.
Refer to the change log for notable changes in each release.
Do you use/like this role? Please consider giving it a star. If you rate this role on Ansible Galaxy and find it lacking in some respect, please consider opening an Issue with actionable feedback or a PR so we can improve it. Thank you!
Requirements
No specific requirements
Role Variables
This role is able to set global options, and to specify subnet declarations.
See the test playbook for a working example of a DHCP server in a test environment based on Vagrant and VirtualBox. This section is a reference of all supported options.
Global options
The following variables, when set, will be added to the global section of the DHCP configuration file. If there is no default value specified, the corresponding setting will be left out of dhcpd.conf(5)
.
See the dhcp-options(5) man page for more information about these options.
Variable | Comments |
---|---|
dhcp_global_authoritative |
Global authoritative statement (authoritative , not authoritative ) |
dhcp_global_booting |
Global booting (allow , deny , ignore ) |
dhcp_global_bootp |
Global bootp (allow , deny , ignore ) |
dhcp_global_broadcast_address |
Global broadcast address |
dhcp_global_classes |
Class definitions with a match statement(1) |
dhcp_global_default_lease_time |
Default lease time in seconds |
dhcp_global_domain_name_servers |
A list of IP addresses of DNS servers(2) |
dhcp_global_domain_name |
The domain name the client should use when resolving host names |
dhcp_global_domain_search |
A list of domain names to be used by the client to locate non-FQDNs(1) |
dhcp_global_failover |
Failover peer settings (3) |
dhcp_global_failover_peer |
Name for the failover peer (e.g. foo ) |
dhcp_global_filename |
Filename to request for boot |
dhcp_global_includes_missing |
Boolean. Continue if includes file(s) missing from role's files/ |
dhcp_global_includes |
List of config files to be included (from dhcp_config_dir ) |
dhcp_global_log_facility |
Global log facility (e.g. daemon , syslog , user , ...) |
dhcp_global_max_lease_time |
Maximum lease time in seconds |
dhcp_global_next_server |
IP for PXEboot server |
dhcp_global_ntp_servers |
List of IP addresses of NTP servers |
dhcp_global_omapi_port |
OMAPI port |
dhcp_global_omapi_secret |
OMAPI secret |
dhcp_global_other_options |
Array of arbitrary additional global options |
dhcp_global_routers |
IP address of the router |
dhcp_global_server_name |
Server name sent to the client |
dhcp_global_server_state |
Service state (started, stopped) |
dhcp_global_subnet_mask |
Global subnet mask |
dhcp_custom_includes |
List of jinja config files to be included (from dhcp_config_dir ) |
dhcp_custom_includes_modes |
List of modes for the destination custom config file |
Remarks
(1) This role supports the definition of classes with a match statement, e.g.:
# Class for VirtualBox VMs
dhcp_global_classes:
- name: vbox
match: 'match if binary-to-ascii(16,8,":",substring(hardware, 1, 3)) = "8:0:27"'
Class names can be used in the definition of address pools (see below).
(2) The role variable dhcp_global_domain_name_servers
may be written either as a list (when you have more than one item), or as a string (when you have only one). The following snippet shows an example of both:
# A single DNS server
dhcp_global_domain_name_servers: 8.8.8.8
# A list of DNS servers
dhcp_global_domain_name_servers:
- 8.8.8.8
- 8.8.4.4
(3) This role also supports the definition of a failover peer, e.g.:
# Failover peer definition
dhcp_global_failover_peer: failover-group
dhcp_global_failover:
role: primary # | secondary
address: 192.168.222.2
port: 647
peer_address: 192.168.222.3
peer_port: 647
max_response_delay: 15
max_unacked_updates: 10
load_balance_max_seconds: 5
split: 255
mclt: 3600
The variable dhcp_global_failover_peer
contains a name for the configured peer, to be used on a per pool basis. The failover declaration options are specified with the variable dhcp_global_failover
, a dictionary that may contain the following options:
Option | Required | Comment |
---|---|---|
address |
no | This server's IP address |
hba |
no | colon-separated-hex-list |
load_balance_max_seconds |
no | Cutoff after which load balance is disabled (3 to 5 recommended) |
max-balance |
no | Failover pool balance statement |
max-lease-misbalance |
no | Failover pool balance statement |
max-lease-ownership |
no | Failover pool balance statement |
max_response_delay |
no | Maximum seconds without contact before engaging failover |
max_unacked_updates |
no | Maximum BNDUPD it can send before receiving a BNDACK (10 recommended) |
mclt |
no | Maximum Client Lead Time |
min-balance |
no | Failover pool balance statement |
peer_address |
no | Failover peer's IP addres |
peer_port |
no | This server's port (generally 519/520 or 647/847) |
port |
no | This server's port (generally 519/520 or 647/847) |
role |
no | primary, secondary |
split |
no | Load balance split (0-255) |
The failover peer directive has to be in the definition of address pools (see below).
Subnet declarations
The role variable dhcp_subnets
contains a list of dicts, specifying the subnet declarations to be added to the DHCP configuration file. Every subnet declaration should have an ip
and netmask
, other options are not mandatory. We start this section with an example, a complete overview of supported options follows.
dhcp_subnets:
- ip: 192.168.222.0
netmask: 255.255.255.128
domain_name_servers:
- 10.0.2.3
- 10.0.2.4
range_begin: 192.168.222.50
range_end: 192.168.222.127
- ip: 192.168.222.128
default_lease_time: 3600
max_lease_time: 7200
netmask: 255.255.255.128
domain_name_servers: 10.0.2.3
routers: 192.168.222.129
An alphabetical list of supported options in a subnet declaration:
Option | Required | Comment |
---|---|---|
booting |
no | allow,deny,ignore |
bootp |
no | allow,deny,ignore |
default_lease_time |
no | Default lease time for this subnet (in seconds) |
domain_name_servers |
no | List of domain name servers for this subnet(1) |
domain_search |
no | List of domain names for resolution of non-FQDNs(1) |
filename |
no | filename to retrieve from boot server |
hosts |
no | List of fixed IP address hosts for each subnet, similar to dhcp_hosts |
interface |
no | Overrides the interface of the subnet declaration |
ip |
yes | Required. IP address of the subnet |
max_lease_time |
no | Maximum lease time for this subnet (in seconds) |
netmask |
yes | Required. Network mask of the subnet (in dotted decimal notation) |
next_server |
no | IP address of the boot server |
ntp_servers |
no | List of NTP servers for this subnet |
range_begin |
no | Lowest address in the range of dynamic IP addresses to be assigned |
range_end |
no | Highest address in the range of dynamic IP addresses to be assigned |
ranges |
no | If multiple ranges are needed, they can be specified as a list (2) |
routers |
no | IP address of the gateway for this subnet |
server_name |
no | Server name sent to the client |
subnet_mask |
no | Overrides the netmask of the subnet declaration |
options |
no | A dict of options to add to this subnet |
You can specify address pools within a subnet by setting the pools
options. This allows you to specify a pool of addresses that will be treated differently than another pool of addresses, even on the same network segment or subnet. It is a list of dicts with the following keys, all of which are optional:
Option | Comment |
---|---|
allow |
Specifies which hosts are allowed in this pool(1) |
default_lease_time |
The default lease time for this pool |
deny |
Specifies which hosts are not allowed in this pool |
domain_name_servers |
The domain name servers to be used for this pool(1) |
failover_peer |
Specifies a failover server |
max_lease_time |
The maximum lease time for this pool |
min_lease_time |
The minimum lease time for this pool |
range_begin |
The lowest address in this pool |
range_end |
The highest address in this pool |
ranges |
If multiple ranges are needed, they can be specified as a list (2) |
(1) For the allow
and deny
fields, the options are enumerated in dhcpd.conf(5), but include:
booting
bootp
client-updates
known-clients
members of "CLASS"
unknown-clients
(2) For multiple subnet ranges, they can be specified, thus:
ranges:
- { begin: 192.168.222.50, end: 192.168.222.99 }
- { begin: 192.168.222.110, end: 192.168.222.127 }
Host declarations
You can specify hosts that should get a fixed IP address based on their MAC by setting the dhcp_hosts
option. This is a list of dicts with the following three keys, of which name
and mac
are mandatory:
Option | Comment |
---|---|
name |
The name of the host |
mac |
The MAC address of the host |
ip |
The IP address to be assigned to the host |
hostname |
Hostname to be assigned through DHCP (optional) |
dhcp_hosts:
- name: cl1
mac: '00:11:22:33:44:55'
ip: 192.168.222.150
- name: cl2
mac: '00:de:ad:be:ef:00'
ip: 192.168.222.151
Specify PXEBoot server
Setting the variable dhcp_pxeboot_server
, will redirect PXE clients to the specified PXEBoot server in order to boot over the network. The specified server should have boot images on the expected locations. Use e.g. bertvv.pxeserver to configure it.
Custom Includes
Setting the variable dhcp_custom_inludes
to a jinja template will allow custom configurations to be used which will subsequently be included into the dhcpd.conf
file. If the template file name has the .j2
extension it will be removed from the destination file name, else it will preserve the template file name in the destination.
dhcp_custom_includes:
- custom-dhcp-config.conf[.j2]
The default mode for the destination custom config file is 0644. To modify this set the variable dhcp_custom_includes_modes
. The zip_longest filter will be used in conjunction with dhcp_custom_includes
variable.
dhcp_custom_includes_modes:
- '0600'
You can create your own variables to use within the template allowing for total flexibility. To avoid variable conflicts make sure that you use variables that are not referenced within this role as this will duplicate configuration in multiple .conf
files.
dhcp_custom_hosts:
- name: Juniper1
mac: 'de:ad:c0:de:ca:fe'
ip: 192.168.35.160
options:
- name: tftp-server-name
value: 192.168.35.152
- name: host-name
value: Juniper1
- name: NEW_OP.transfer-mode
value: "http"
- name: NEW_OP.config-file-name
value: "/configurations/j1-switch.config"
Finally the jinja template must contain valid ISC DHCPD configuration (dhcpd.conf(5)). This is an example of using bertvv.dhcp for juniper Zero-Touch-Provisioning.
option space NEW_OP;
option NEW_OP.image-file-name code 0 = text;
option NEW_OP.config-file-name code 1 = text;
option NEW_OP.image-file-type code 2 = text;
option NEW_OP.transfer-mode code 3 = text;
option NEW_OP.alt-image-file-name code 4= text;
option NEW_OP.http-port code 5= text;
option NEW_OP-encapsulation code 43 = encapsulate NEW_OP;
{% if dhcp_custom_hosts is defined %}
#
# Host declarations
#
{% for host in dhcp_custom_hosts %}
host {{ host.name | replace (" ","_") | replace ("'","_") | replace (":","_") }} {
hardware ethernet {{ host.mac }};
{% if host.ip is defined %}
fixed-address {{ host.ip }};
{% endif %}
{% if host.options is defined %}
{% for option in host.options %}
{{ option.name }} "{{ option.value }}"
{% endfor %}
{% endif %}
}
{% endfor %}
{% endif %}
Dependencies
No dependencies.
Example Playbook
See the test playbook
Testing
To run the tests for this playbook, you need to have Molecule, VirtualBox and Vagrant installed. Running the command molecule converge
will create a VirtualBox VM with a host-only interface with IP address 192.168.222.2. To test, you can e.g. use the nmap dhcp-discover script:
$ sudo nmap --script broadcast-dhcp-discover -e vboxnet7
Starting Nmap 7.91 ( https://nmap.org ) at 2021-11-30 11:32 CET
Pre-scan script results:
| broadcast-dhcp-discover:
| Response 1 of 2:
| Interface: vboxnet7
| IP Offered: 192.168.222.50
| DHCP Message Type: DHCPOFFER
| Server Identifier: 192.168.222.2
| IP Address Lease Time: 5m00s
| Subnet Mask: 255.255.255.0
| Domain Name Server: 10.0.2.3, 10.0.2.4
| Domain Name: example.com
| Broadcast Address: 192.168.222.255
| Response 2 of 2:
| Interface: vboxnet7
| IP Offered: 192.168.222.50
| DHCP Message Type: DHCPOFFER
| Server Identifier: 192.168.222.2
| IP Address Lease Time: 5m00s
| Subnet Mask: 255.255.255.0
| Domain Name Server: 10.0.2.3, 10.0.2.4
| Domain Name: example.com
|_ Broadcast Address: 192.168.222.255
WARNING: No targets were specified, so 0 hosts scanned.
Nmap done: 0 IP addresses (0 hosts up) scanned in 10.19 seconds
License
BSD
Contributing
Issues, feature requests, ideas are appreciated and can be posted in the Issues section. Pull requests are also very welcome. Preferably, create a topic branch and when submitting, squash your commits into one (with a descriptive message).
Contributors
ansible-galaxy install bertvv/ansible-role-dhcp