|
Packit Service |
0a38ef |
# -*- coding: utf-8 -*-
|
|
Packit Service |
0a38ef |
|
|
Packit Service |
0a38ef |
# Authors:
|
|
Packit Service |
0a38ef |
# Sergio Oliveira Campos <seocam@redhat.com>
|
|
Packit Service |
0a38ef |
#
|
|
Packit Service |
0a38ef |
# Copyright (C) 2020 Red Hat
|
|
Packit Service |
0a38ef |
# see file 'COPYING' for use and warranty information
|
|
Packit Service |
0a38ef |
#
|
|
Packit Service |
0a38ef |
# This program is free software; you can redistribute it and/or modify
|
|
Packit Service |
0a38ef |
# it under the terms of the GNU General Public License as published by
|
|
Packit Service |
0a38ef |
# the Free Software Foundation, either version 3 of the License, or
|
|
Packit Service |
0a38ef |
# (at your option) any later version.
|
|
Packit Service |
0a38ef |
#
|
|
Packit Service |
0a38ef |
# This program is distributed in the hope that it will be useful,
|
|
Packit Service |
0a38ef |
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit Service |
0a38ef |
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
Packit Service |
0a38ef |
# GNU General Public License for more details.
|
|
Packit Service |
0a38ef |
#
|
|
Packit Service |
0a38ef |
# You should have received a copy of the GNU General Public License
|
|
Packit Service |
0a38ef |
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
Packit Service |
0a38ef |
|
|
Packit Service |
0a38ef |
ANSIBLE_METADATA = {
|
|
Packit Service |
0a38ef |
"metadata_version": "1.0",
|
|
Packit Service |
0a38ef |
"supported_by": "community",
|
|
Packit Service |
0a38ef |
"status": ["preview"],
|
|
Packit Service |
0a38ef |
}
|
|
Packit Service |
0a38ef |
|
|
Packit Service |
0a38ef |
DOCUMENTATION = """
|
|
Packit Service |
a166ed |
---
|
|
Packit Service |
0a38ef |
module: ipadnszone
|
|
Packit Service |
0a38ef |
short description: Manage FreeIPA dnszone
|
|
Packit Service |
0a38ef |
description: Manage FreeIPA dnszone
|
|
Packit Service |
0a38ef |
options:
|
|
Packit Service |
0a38ef |
ipaadmin_principal:
|
|
Packit Service |
0a38ef |
description: The admin principal
|
|
Packit Service |
0a38ef |
default: admin
|
|
Packit Service |
0a38ef |
ipaadmin_password:
|
|
Packit Service |
0a38ef |
description: The admin password
|
|
Packit Service |
0a38ef |
required: false
|
|
Packit Service |
0a38ef |
name:
|
|
Packit Service |
0a38ef |
description: The zone name string.
|
|
Packit Service |
0a38ef |
required: true
|
|
Packit Service |
a166ed |
type: list
|
|
Packit Service |
5b5096 |
alises: ["zone_name"]
|
|
Packit Service |
a166ed |
name_from_ip:
|
|
Packit Service |
a166ed |
description: |
|
|
Packit Service |
a166ed |
Derive zone name from reverse of IP (PTR).
|
|
Packit Service |
a166ed |
Can only be used with `state: present`.
|
|
Packit Service |
a166ed |
required: false
|
|
Packit Service |
a166ed |
type: str
|
|
Packit Service |
0a38ef |
forwarders:
|
|
Packit Service |
0a38ef |
description: The list of global DNS forwarders.
|
|
Packit Service |
0a38ef |
required: false
|
|
Packit Service |
0a38ef |
options:
|
|
Packit Service |
0a38ef |
ip_address:
|
|
Packit Service |
0a38ef |
description: The forwarder nameserver IP address list (IPv4 and IPv6).
|
|
Packit Service |
0a38ef |
required: true
|
|
Packit Service |
0a38ef |
port:
|
|
Packit Service |
0a38ef |
description: The port to forward requests to.
|
|
Packit Service |
0a38ef |
required: false
|
|
Packit Service |
0a38ef |
forward_policy:
|
|
Packit Service |
0a38ef |
description:
|
|
Packit Service |
0a38ef |
Global forwarding policy. Set to "none" to disable any configured
|
|
Packit Service |
0a38ef |
global forwarders.
|
|
Packit Service |
0a38ef |
required: false
|
|
Packit Service |
0a38ef |
choices: ['only', 'first', 'none']
|
|
Packit Service |
0a38ef |
allow_sync_ptr:
|
|
Packit Service |
0a38ef |
description:
|
|
Packit Service |
0a38ef |
Allow synchronization of forward (A, AAAA) and reverse (PTR) records.
|
|
Packit Service |
0a38ef |
required: false
|
|
Packit Service |
0a38ef |
type: bool
|
|
Packit Service |
0a38ef |
state:
|
|
Packit Service |
0a38ef |
description: State to ensure
|
|
Packit Service |
0a38ef |
default: present
|
|
Packit Service |
0a38ef |
choices: ["present", "absent", "enabled", "disabled"]
|
|
Packit Service |
0a38ef |
name_server:
|
|
Packit Service |
0a38ef |
description: Authoritative nameserver domain name
|
|
Packit Service |
0a38ef |
required: false
|
|
Packit Service |
0a38ef |
type: str
|
|
Packit Service |
0a38ef |
admin_email:
|
|
Packit Service |
0a38ef |
description: Administrator e-mail address
|
|
Packit Service |
0a38ef |
required: false
|
|
Packit Service |
0a38ef |
type: str
|
|
Packit Service |
0a38ef |
update_policy:
|
|
Packit Service |
0a38ef |
description: BIND update policy
|
|
Packit Service |
0a38ef |
required: false
|
|
Packit Service |
0a38ef |
type: str
|
|
Packit Service |
0a38ef |
dynamic_update:
|
|
Packit Service |
0a38ef |
description: Allow dynamic updates
|
|
Packit Service |
0a38ef |
required: false
|
|
Packit Service |
0a38ef |
type: bool
|
|
Packit Service |
0a38ef |
alises: ["dynamicupdate"]
|
|
Packit Service |
0a38ef |
dnssec:
|
|
Packit Service |
0a38ef |
description: Allow inline DNSSEC signing of records in the zone
|
|
Packit Service |
0a38ef |
required: false
|
|
Packit Service |
0a38ef |
type: bool
|
|
Packit Service |
0a38ef |
allow_transfer:
|
|
Packit Service |
0a38ef |
description: List of IP addresses or networks which are allowed to transfer the zone
|
|
Packit Service |
0a38ef |
required: false
|
|
Packit Service |
0a38ef |
type: bool
|
|
Packit Service |
0a38ef |
allow_query:
|
|
Packit Service |
0a38ef |
description: List of IP addresses or networks which are allowed to issue queries
|
|
Packit Service |
0a38ef |
required: false
|
|
Packit Service |
0a38ef |
type: bool
|
|
Packit Service |
0a38ef |
serial:
|
|
Packit Service |
0a38ef |
description: SOA record serial number
|
|
Packit Service |
0a38ef |
required: false
|
|
Packit Service |
0a38ef |
type: int
|
|
Packit Service |
0a38ef |
refresh:
|
|
Packit Service |
0a38ef |
description: SOA record refresh time
|
|
Packit Service |
0a38ef |
required: false
|
|
Packit Service |
0a38ef |
type: int
|
|
Packit Service |
0a38ef |
retry:
|
|
Packit Service |
0a38ef |
description: SOA record retry time
|
|
Packit Service |
0a38ef |
required: false
|
|
Packit Service |
0a38ef |
type: int
|
|
Packit Service |
0a38ef |
expire:
|
|
Packit Service |
0a38ef |
description: SOA record expire time
|
|
Packit Service |
0a38ef |
required: false
|
|
Packit Service |
0a38ef |
type: int
|
|
Packit Service |
0a38ef |
minimum:
|
|
Packit Service |
0a38ef |
description: How long should negative responses be cached
|
|
Packit Service |
0a38ef |
required: false
|
|
Packit Service |
0a38ef |
type: int
|
|
Packit Service |
0a38ef |
ttl:
|
|
Packit Service |
0a38ef |
description: Time to live for records at zone apex
|
|
Packit Service |
0a38ef |
required: false
|
|
Packit Service |
0a38ef |
type: int
|
|
Packit Service |
0a38ef |
default_ttl:
|
|
Packit Service |
0a38ef |
description: Time to live for records without explicit TTL definition
|
|
Packit Service |
0a38ef |
required: false
|
|
Packit Service |
0a38ef |
type: int
|
|
Packit Service |
0a38ef |
nsec3param_rec:
|
|
Packit Service |
a166ed |
description: |
|
|
Packit Service |
a166ed |
NSEC3PARAM record for zone in format: hash_algorithm flags iterations
|
|
Packit Service |
a166ed |
salt.
|
|
Packit Service |
0a38ef |
required: false
|
|
Packit Service |
0a38ef |
type: str
|
|
Packit Service |
0a38ef |
skip_overlap_check:
|
|
Packit Service |
a166ed |
description: |
|
|
Packit Service |
a166ed |
Force DNS zone creation even if it will overlap with an existing zone
|
|
Packit Service |
0a38ef |
required: false
|
|
Packit Service |
0a38ef |
type: bool
|
|
Packit Service |
0a38ef |
skip_nameserver_check:
|
|
Packit Service |
0a38ef |
description: Force DNS zone creation even if nameserver is not resolvable
|
|
Packit Service |
0a38ef |
required: false
|
|
Packit Service |
0a38ef |
type: bool
|
|
Packit Service |
0a38ef |
""" # noqa: E501
|
|
Packit Service |
0a38ef |
|
|
Packit Service |
0a38ef |
EXAMPLES = """
|
|
Packit Service |
0a38ef |
---
|
|
Packit Service |
0a38ef |
# Ensure the zone is present (very minimal)
|
|
Packit Service |
0a38ef |
- ipadnszone:
|
|
Packit Service |
0a38ef |
name: test.example.com
|
|
Packit Service |
0a38ef |
|
|
Packit Service |
0a38ef |
# Ensure the zone is present (all available arguments)
|
|
Packit Service |
0a38ef |
- ipadnszone:
|
|
Packit Service |
0a38ef |
name: test.example.com
|
|
Packit Service |
0a38ef |
ipaadmin_password: SomeADMINpassword
|
|
Packit Service |
0a38ef |
allow_sync_ptr: true
|
|
Packit Service |
0a38ef |
dynamic_update: true
|
|
Packit Service |
0a38ef |
dnssec: true
|
|
Packit Service |
0a38ef |
allow_transfer:
|
|
Packit Service |
0a38ef |
- 1.1.1.1
|
|
Packit Service |
0a38ef |
- 2.2.2.2
|
|
Packit Service |
0a38ef |
allow_query:
|
|
Packit Service |
0a38ef |
- 1.1.1.1
|
|
Packit Service |
0a38ef |
- 2.2.2.2
|
|
Packit Service |
0a38ef |
forwarders:
|
|
Packit Service |
0a38ef |
- ip_address: 8.8.8.8
|
|
Packit Service |
0a38ef |
- ip_address: 8.8.4.4
|
|
Packit Service |
0a38ef |
port: 52
|
|
Packit Service |
0a38ef |
serial: 1234
|
|
Packit Service |
0a38ef |
refresh: 3600
|
|
Packit Service |
0a38ef |
retry: 900
|
|
Packit Service |
0a38ef |
expire: 1209600
|
|
Packit Service |
0a38ef |
minimum: 3600
|
|
Packit Service |
0a38ef |
ttl: 60
|
|
Packit Service |
0a38ef |
default_ttl: 90
|
|
Packit Service |
0a38ef |
name_server: ipaserver.test.local.
|
|
Packit Service |
0a38ef |
admin_email: admin.admin@example.com
|
|
Packit Service |
0a38ef |
nsec3param_rec: "1 7 100 0123456789abcdef"
|
|
Packit Service |
0a38ef |
skip_overlap_check: true
|
|
Packit Service |
0a38ef |
skip_nameserver_check: true
|
|
Packit Service |
0a38ef |
state: present
|
|
Packit Service |
0a38ef |
|
|
Packit Service |
0a38ef |
# Ensure zone is present and disabled
|
|
Packit Service |
0a38ef |
- ipadnszone:
|
|
Packit Service |
0a38ef |
name: test.example.com
|
|
Packit Service |
0a38ef |
state: disabled
|
|
Packit Service |
0a38ef |
|
|
Packit Service |
0a38ef |
# Ensure zone is present and enabled
|
|
Packit Service |
0a38ef |
- ipadnszone:
|
|
Packit Service |
0a38ef |
name: test.example.com
|
|
Packit Service |
0a38ef |
state: enabled
|
|
Packit Service |
0a38ef |
"""
|
|
Packit Service |
0a38ef |
|
|
Packit Service |
0a38ef |
RETURN = """
|
|
Packit Service |
a166ed |
dnszone:
|
|
Packit Service |
a166ed |
description: DNS Zone dict with zone name infered from `name_from_ip`.
|
|
Packit Service |
a166ed |
returned:
|
|
Packit Service |
a166ed |
If `state` is `present`, `name_from_ip` is used, and a zone was created.
|
|
Packit Service |
a166ed |
options:
|
|
Packit Service |
a166ed |
name:
|
|
Packit Service |
a166ed |
description: The name of the zone created, inferred from `name_from_ip`.
|
|
Packit Service |
a166ed |
returned: always
|
|
Packit Service |
0a38ef |
"""
|
|
Packit Service |
0a38ef |
|
|
Packit Service |
0a38ef |
from ipapython.dnsutil import DNSName # noqa: E402
|
|
Packit Service |
0a38ef |
from ansible.module_utils.ansible_freeipa_module import (
|
|
Packit Service |
0a38ef |
FreeIPABaseModule,
|
|
Packit Service |
0a38ef |
is_ipv4_addr,
|
|
Packit Service |
0a38ef |
is_ipv6_addr,
|
|
Packit Service |
0a38ef |
is_valid_port,
|
|
Packit Service |
0a38ef |
) # noqa: E402
|
|
Packit Service |
a166ed |
import ipalib.errors
|
|
Packit Service |
a166ed |
import netaddr
|
|
Packit Service |
a166ed |
import six
|
|
Packit Service |
a166ed |
|
|
Packit Service |
a166ed |
|
|
Packit Service |
a166ed |
if six.PY3:
|
|
Packit Service |
a166ed |
unicode = str
|
|
Packit Service |
0a38ef |
|
|
Packit Service |
0a38ef |
|
|
Packit Service |
0a38ef |
class DNSZoneModule(FreeIPABaseModule):
|
|
Packit Service |
0a38ef |
|
|
Packit Service |
0a38ef |
ipa_param_mapping = {
|
|
Packit Service |
0a38ef |
# Direct Mapping
|
|
Packit Service |
0a38ef |
"idnsforwardpolicy": "forward_policy",
|
|
Packit Service |
0a38ef |
"idnssoaserial": "serial",
|
|
Packit Service |
0a38ef |
"idnssoarefresh": "refresh",
|
|
Packit Service |
0a38ef |
"idnssoaretry": "retry",
|
|
Packit Service |
0a38ef |
"idnssoaexpire": "expire",
|
|
Packit Service |
0a38ef |
"idnssoaminimum": "minimum",
|
|
Packit Service |
0a38ef |
"dnsttl": "ttl",
|
|
Packit Service |
0a38ef |
"dnsdefaultttl": "default_ttl",
|
|
Packit Service |
0a38ef |
"idnsallowsyncptr": "allow_sync_ptr",
|
|
Packit Service |
0a38ef |
"idnsallowdynupdate": "dynamic_update",
|
|
Packit Service |
0a38ef |
"idnssecinlinesigning": "dnssec",
|
|
Packit Service |
0a38ef |
"idnsupdatepolicy": "update_policy",
|
|
Packit Service |
0a38ef |
# Mapping by method
|
|
Packit Service |
0a38ef |
"idnsforwarders": "get_ipa_idnsforwarders",
|
|
Packit Service |
0a38ef |
"idnsallowtransfer": "get_ipa_idnsallowtransfer",
|
|
Packit Service |
0a38ef |
"idnsallowquery": "get_ipa_idnsallowquery",
|
|
Packit Service |
0a38ef |
"idnssoamname": "get_ipa_idnssoamname",
|
|
Packit Service |
0a38ef |
"idnssoarname": "get_ipa_idnssoarname",
|
|
Packit Service |
0a38ef |
"skip_nameserver_check": "get_ipa_skip_nameserver_check",
|
|
Packit Service |
0a38ef |
"skip_overlap_check": "get_ipa_skip_overlap_check",
|
|
Packit Service |
0a38ef |
"nsec3paramrecord": "get_ipa_nsec3paramrecord",
|
|
Packit Service |
0a38ef |
}
|
|
Packit Service |
0a38ef |
|
|
Packit Service |
0a38ef |
def validate_ips(self, ips, error_msg):
|
|
Packit Service |
0a38ef |
invalid_ips = [
|
|
Packit Service |
0a38ef |
ip for ip in ips if not is_ipv4_addr(ip) or is_ipv6_addr(ip)
|
|
Packit Service |
0a38ef |
]
|
|
Packit Service |
0a38ef |
if any(invalid_ips):
|
|
Packit Service |
0a38ef |
self.fail_json(msg=error_msg % invalid_ips)
|
|
Packit Service |
0a38ef |
|
|
Packit Service |
0a38ef |
def is_valid_nsec3param_rec(self, nsec3param_rec):
|
|
Packit Service |
0a38ef |
try:
|
|
Packit Service |
0a38ef |
part1, part2, part3, part4 = nsec3param_rec.split(" ")
|
|
Packit Service |
0a38ef |
except ValueError:
|
|
Packit Service |
0a38ef |
return False
|
|
Packit Service |
0a38ef |
|
|
Packit Service |
0a38ef |
if not all([part1.isdigit(), part2.isdigit(), part3.isdigit()]):
|
|
Packit Service |
0a38ef |
return False
|
|
Packit Service |
0a38ef |
|
|
Packit Service |
0a38ef |
if not 0 <= int(part1) <= 255:
|
|
Packit Service |
0a38ef |
return False
|
|
Packit Service |
0a38ef |
|
|
Packit Service |
0a38ef |
if not 0 <= int(part2) <= 255:
|
|
Packit Service |
0a38ef |
return False
|
|
Packit Service |
0a38ef |
|
|
Packit Service |
0a38ef |
if not 0 <= int(part3) <= 65535:
|
|
Packit Service |
0a38ef |
return False
|
|
Packit Service |
0a38ef |
|
|
Packit Service |
0a38ef |
try:
|
|
Packit Service |
0a38ef |
int(part4, 16)
|
|
Packit Service |
0a38ef |
except ValueError:
|
|
Packit Service |
0a38ef |
is_hex = False
|
|
Packit Service |
0a38ef |
else:
|
|
Packit Service |
0a38ef |
is_hex = True
|
|
Packit Service |
0a38ef |
|
|
Packit Service |
0a38ef |
even_digits = len(part4) % 2 == 0
|
|
Packit Service |
0a38ef |
is_dash = part4 == "-"
|
|
Packit Service |
0a38ef |
|
|
Packit Service |
0a38ef |
# If not hex with even digits or dash then
|
|
Packit Service |
0a38ef |
# part4 is invalid
|
|
Packit Service |
0a38ef |
if not ((is_hex and even_digits) or is_dash):
|
|
Packit Service |
0a38ef |
return False
|
|
Packit Service |
0a38ef |
|
|
Packit Service |
0a38ef |
return True
|
|
Packit Service |
0a38ef |
|
|
Packit Service |
a166ed |
def get_ipa_nsec3paramrecord(self, **kwargs):
|
|
Packit Service |
0a38ef |
nsec3param_rec = self.ipa_params.nsec3param_rec
|
|
Packit Service |
0a38ef |
if nsec3param_rec is not None:
|
|
Packit Service |
0a38ef |
error_msg = (
|
|
Packit Service |
0a38ef |
"Invalid nsec3param_rec: %s. "
|
|
Packit Service |
0a38ef |
"Expected format: <0-255> <0-255> <0-65535> "
|
|
Packit Service |
0a38ef |
"even-length_hexadecimal_digits_or_hyphen"
|
|
Packit Service |
0a38ef |
) % nsec3param_rec
|
|
Packit Service |
0a38ef |
if not self.is_valid_nsec3param_rec(nsec3param_rec):
|
|
Packit Service |
0a38ef |
self.fail_json(msg=error_msg)
|
|
Packit Service |
0a38ef |
return nsec3param_rec
|
|
Packit Service |
0a38ef |
|
|
Packit Service |
a166ed |
def get_ipa_idnsforwarders(self, **kwargs):
|
|
Packit Service |
0a38ef |
if self.ipa_params.forwarders is not None:
|
|
Packit Service |
0a38ef |
forwarders = []
|
|
Packit Service |
0a38ef |
for forwarder in self.ipa_params.forwarders:
|
|
Packit Service |
0a38ef |
ip_address = forwarder.get("ip_address")
|
|
Packit Service |
0a38ef |
if not (is_ipv4_addr(ip_address) or is_ipv6_addr(ip_address)):
|
|
Packit Service |
0a38ef |
self.fail_json(
|
|
Packit Service |
0a38ef |
msg="Invalid IP for DNS forwarder: %s" % ip_address
|
|
Packit Service |
0a38ef |
)
|
|
Packit Service |
0a38ef |
|
|
Packit Service |
0a38ef |
port = forwarder.get("port", None)
|
|
Packit Service |
0a38ef |
if port and not is_valid_port(port):
|
|
Packit Service |
0a38ef |
self.fail_json(
|
|
Packit Service |
0a38ef |
msg="Invalid port number for DNS forwarder: %s %s"
|
|
Packit Service |
0a38ef |
% (ip_address, port)
|
|
Packit Service |
0a38ef |
)
|
|
Packit Service |
0a38ef |
formatted_forwarder = ip_address
|
|
Packit Service |
0a38ef |
port = forwarder.get("port")
|
|
Packit Service |
0a38ef |
if port:
|
|
Packit Service |
0a38ef |
formatted_forwarder += " port %d" % port
|
|
Packit Service |
0a38ef |
forwarders.append(formatted_forwarder)
|
|
Packit Service |
0a38ef |
|
|
Packit Service |
0a38ef |
return forwarders
|
|
Packit Service |
0a38ef |
|
|
Packit Service |
a166ed |
def get_ipa_idnsallowtransfer(self, **kwargs):
|
|
Packit Service |
0a38ef |
if self.ipa_params.allow_transfer is not None:
|
|
Packit Service |
0a38ef |
error_msg = "Invalid ip_address for DNS allow_transfer: %s"
|
|
Packit Service |
0a38ef |
self.validate_ips(self.ipa_params.allow_transfer, error_msg)
|
|
Packit Service |
0a38ef |
|
|
Packit Service |
0a38ef |
return (";".join(self.ipa_params.allow_transfer) or "none") + ";"
|
|
Packit Service |
0a38ef |
|
|
Packit Service |
a166ed |
def get_ipa_idnsallowquery(self, **kwargs):
|
|
Packit Service |
0a38ef |
if self.ipa_params.allow_query is not None:
|
|
Packit Service |
0a38ef |
error_msg = "Invalid ip_address for DNS allow_query: %s"
|
|
Packit Service |
0a38ef |
self.validate_ips(self.ipa_params.allow_query, error_msg)
|
|
Packit Service |
0a38ef |
|
|
Packit Service |
0a38ef |
return (";".join(self.ipa_params.allow_query) or "any") + ";"
|
|
Packit Service |
0a38ef |
|
|
Packit Service |
0a38ef |
@staticmethod
|
|
Packit Service |
0a38ef |
def _replace_at_symbol_in_rname(rname):
|
|
Packit Service |
0a38ef |
"""
|
|
Packit Service |
0a38ef |
See RFC 1035 for more information.
|
|
Packit Service |
0a38ef |
|
|
Packit Service |
0a38ef |
Section 8. MAIL SUPPORT
|
|
Packit Service |
0a38ef |
https://tools.ietf.org/html/rfc1035#section-8
|
|
Packit Service |
0a38ef |
"""
|
|
Packit Service |
0a38ef |
if "@" not in rname:
|
|
Packit Service |
0a38ef |
return rname
|
|
Packit Service |
0a38ef |
|
|
Packit Service |
0a38ef |
name, domain = rname.split("@")
|
|
Packit Service |
0a38ef |
name = name.replace(".", r"\.")
|
|
Packit Service |
0a38ef |
|
|
Packit Service |
0a38ef |
return ".".join((name, domain))
|
|
Packit Service |
0a38ef |
|
|
Packit Service |
a166ed |
def get_ipa_idnssoarname(self, **kwargs):
|
|
Packit Service |
0a38ef |
if self.ipa_params.admin_email is not None:
|
|
Packit Service |
0a38ef |
return DNSName(
|
|
Packit Service |
0a38ef |
self._replace_at_symbol_in_rname(self.ipa_params.admin_email)
|
|
Packit Service |
0a38ef |
)
|
|
Packit Service |
0a38ef |
|
|
Packit Service |
a166ed |
def get_ipa_idnssoamname(self, **kwargs):
|
|
Packit Service |
0a38ef |
if self.ipa_params.name_server is not None:
|
|
Packit Service |
0a38ef |
return DNSName(self.ipa_params.name_server)
|
|
Packit Service |
0a38ef |
|
|
Packit Service |
a166ed |
def get_ipa_skip_overlap_check(self, **kwargs):
|
|
Packit Service |
a166ed |
zone = kwargs.get('zone')
|
|
Packit Service |
a166ed |
if not zone and self.ipa_params.skip_overlap_check is not None:
|
|
Packit Service |
0a38ef |
return self.ipa_params.skip_overlap_check
|
|
Packit Service |
0a38ef |
|
|
Packit Service |
a166ed |
def get_ipa_skip_nameserver_check(self, **kwargs):
|
|
Packit Service |
a166ed |
zone = kwargs.get('zone')
|
|
Packit Service |
a166ed |
if not zone and self.ipa_params.skip_nameserver_check is not None:
|
|
Packit Service |
0a38ef |
return self.ipa_params.skip_nameserver_check
|
|
Packit Service |
0a38ef |
|
|
Packit Service |
a166ed |
def __reverse_zone_name(self, ipaddress):
|
|
Packit Service |
a166ed |
"""
|
|
Packit Service |
a166ed |
Infer reverse zone name from an ip address.
|
|
Packit Service |
a166ed |
|
|
Packit Service |
a166ed |
This function uses the same heuristics as FreeIPA to infer the zone
|
|
Packit Service |
a166ed |
name from ip.
|
|
Packit Service |
a166ed |
"""
|
|
Packit Service |
a166ed |
try:
|
|
Packit Service |
a166ed |
ip = netaddr.IPAddress(str(ipaddress))
|
|
Packit Service |
a166ed |
except (netaddr.AddrFormatError, ValueError):
|
|
Packit Service |
a166ed |
net = netaddr.IPNetwork(ipaddress)
|
|
Packit Service |
a166ed |
items = net.ip.reverse_dns.split('.')
|
|
Packit Service |
a166ed |
prefixlen = net.prefixlen
|
|
Packit Service |
a166ed |
ip_version = net.version
|
|
Packit Service |
a166ed |
else:
|
|
Packit Service |
a166ed |
items = ip.reverse_dns.split('.')
|
|
Packit Service |
a166ed |
prefixlen = 24 if ip.version == 4 else 64
|
|
Packit Service |
a166ed |
ip_version = ip.version
|
|
Packit Service |
a166ed |
if ip_version == 4:
|
|
Packit Service |
a166ed |
return u'.'.join(items[4 - prefixlen // 8:])
|
|
Packit Service |
a166ed |
elif ip_version == 6:
|
|
Packit Service |
a166ed |
return u'.'.join(items[32 - prefixlen // 4:])
|
|
Packit Service |
a166ed |
else:
|
|
Packit Service |
a166ed |
self.fail_json(msg="Invalid IP version for reverse zone.")
|
|
Packit Service |
a166ed |
|
|
Packit Service |
0a38ef |
def get_zone(self, zone_name):
|
|
Packit Service |
0a38ef |
get_zone_args = {"idnsname": zone_name, "all": True}
|
|
Packit Service |
0a38ef |
|
|
Packit Service |
a166ed |
try:
|
|
Packit Service |
a166ed |
response = self.api_command("dnszone_show", args=get_zone_args)
|
|
Packit Service |
a166ed |
except ipalib.errors.NotFound:
|
|
Packit Service |
a166ed |
zone = None
|
|
Packit Service |
a166ed |
is_zone_active = False
|
|
Packit Service |
a166ed |
else:
|
|
Packit Service |
a166ed |
zone = response["result"]
|
|
Packit Service |
a166ed |
is_zone_active = zone.get("idnszoneactive") == ["TRUE"]
|
|
Packit Service |
0a38ef |
|
|
Packit Service |
a166ed |
return zone, is_zone_active
|
|
Packit Service |
0a38ef |
|
|
Packit Service |
a166ed |
def get_zone_names(self):
|
|
Packit Service |
a166ed |
zone_names = self.__get_zone_names_from_params()
|
|
Packit Service |
a166ed |
if len(zone_names) > 1 and self.ipa_params.state != "absent":
|
|
Packit Service |
a166ed |
self.fail_json(
|
|
Packit Service |
a166ed |
msg=("Please provide a single name. Multiple values for 'name'"
|
|
Packit Service |
a166ed |
"can only be supplied for state 'absent'.")
|
|
Packit Service |
a166ed |
)
|
|
Packit Service |
a166ed |
|
|
Packit Service |
a166ed |
return zone_names
|
|
Packit Service |
a166ed |
|
|
Packit Service |
a166ed |
def __get_zone_names_from_params(self):
|
|
Packit Service |
a166ed |
if not self.ipa_params.name:
|
|
Packit Service |
a166ed |
return [self.__reverse_zone_name(self.ipa_params.name_from_ip)]
|
|
Packit Service |
0a38ef |
return self.ipa_params.name
|
|
Packit Service |
0a38ef |
|
|
Packit Service |
a166ed |
def check_ipa_params(self):
|
|
Packit Service |
a166ed |
if not self.ipa_params.name and not self.ipa_params.name_from_ip:
|
|
Packit Service |
a166ed |
self.fail_json(
|
|
Packit Service |
a166ed |
msg="Either `name` or `name_from_ip` must be provided."
|
|
Packit Service |
a166ed |
)
|
|
Packit Service |
a166ed |
if self.ipa_params.state != "present" and self.ipa_params.name_from_ip:
|
|
Packit Service |
a166ed |
self.fail_json(
|
|
Packit Service |
a166ed |
msg=(
|
|
Packit Service |
a166ed |
"Cannot use argument `name_from_ip` with state `%s`."
|
|
Packit Service |
a166ed |
% self.ipa_params.state
|
|
Packit Service |
a166ed |
)
|
|
Packit Service |
a166ed |
)
|
|
Packit Service |
a166ed |
|
|
Packit Service |
0a38ef |
def define_ipa_commands(self):
|
|
Packit Service |
a166ed |
for zone_name in self.get_zone_names():
|
|
Packit Service |
a166ed |
# Look for existing zone in IPA
|
|
Packit Service |
a166ed |
zone, is_zone_active = self.get_zone(zone_name)
|
|
Packit Service |
a166ed |
args = self.get_ipa_command_args(zone=zone)
|
|
Packit Service |
a166ed |
set_serial = self.ipa_params.serial is not None
|
|
Packit Service |
a166ed |
|
|
Packit Service |
a166ed |
if set_serial:
|
|
Packit Service |
a166ed |
del args["idnssoaserial"]
|
|
Packit Service |
a166ed |
|
|
Packit Service |
a166ed |
if self.ipa_params.state in ["present", "enabled", "disabled"]:
|
|
Packit Service |
a166ed |
if not zone:
|
|
Packit Service |
a166ed |
# Since the zone doesn't exist we just create it
|
|
Packit Service |
a166ed |
# with given args
|
|
Packit Service |
a166ed |
self.add_ipa_command("dnszone_add", zone_name, args)
|
|
Packit Service |
a166ed |
is_zone_active = True
|
|
Packit Service |
a166ed |
# just_added = True
|
|
Packit Service |
a166ed |
|
|
Packit Service |
a166ed |
else:
|
|
Packit Service |
a166ed |
# Zone already exist so we need to verify if given args
|
|
Packit Service |
a166ed |
# matches the current config. If not we updated it.
|
|
Packit Service |
a166ed |
if self.require_ipa_attrs_change(args, zone):
|
|
Packit Service |
a166ed |
self.add_ipa_command("dnszone_mod", zone_name, args)
|
|
Packit Service |
a166ed |
|
|
Packit Service |
a166ed |
if self.ipa_params.state == "enabled" and not is_zone_active:
|
|
Packit Service |
a166ed |
self.add_ipa_command("dnszone_enable", zone_name)
|
|
Packit Service |
a166ed |
|
|
Packit Service |
a166ed |
if self.ipa_params.state == "disabled" and is_zone_active:
|
|
Packit Service |
a166ed |
self.add_ipa_command("dnszone_disable", zone_name)
|
|
Packit Service |
a166ed |
|
|
Packit Service |
a166ed |
if self.ipa_params.state == "absent" and zone is not None:
|
|
Packit Service |
a166ed |
self.add_ipa_command("dnszone_del", zone_name)
|
|
Packit Service |
a166ed |
|
|
Packit Service |
a166ed |
# Due to a bug in FreeIPA dnszone-add won't set
|
|
Packit Service |
a166ed |
# SOA Serial in the creation of a zone, or if
|
|
Packit Service |
a166ed |
# another field is modified along with it.
|
|
Packit Service |
a166ed |
# As a workaround, we set only the SOA serial,
|
|
Packit Service |
a166ed |
# with dnszone-mod, after other changes.
|
|
Packit Service |
a166ed |
# See:
|
|
Packit Service |
a166ed |
# - https://pagure.io/freeipa/issue/8227
|
|
Packit Service |
a166ed |
# - https://pagure.io/freeipa/issue/8489
|
|
Packit Service |
a166ed |
if set_serial:
|
|
Packit Service |
a166ed |
args = {
|
|
Packit Service |
a166ed |
"idnssoaserial": self.ipa_params.serial,
|
|
Packit Service |
a166ed |
}
|
|
Packit Service |
a166ed |
self.add_ipa_command("dnszone_mod", zone_name, args)
|
|
Packit Service |
a166ed |
|
|
Packit Service |
a166ed |
def process_command_result(self, name, command, args, result):
|
|
Packit Service |
a166ed |
super(DNSZoneModule, self).process_command_result(
|
|
Packit Service |
a166ed |
name, command, args, result
|
|
Packit Service |
a166ed |
)
|
|
Packit Service |
a166ed |
if command == "dnszone_add" and self.ipa_params.name_from_ip:
|
|
Packit Service |
a166ed |
dnszone_exit_args = self.exit_args.setdefault('dnszone', {})
|
|
Packit Service |
a166ed |
dnszone_exit_args['name'] = name
|
|
Packit Service |
2939af |
|
|
Packit Service |
0a38ef |
|
|
Packit Service |
0a38ef |
def get_argument_spec():
|
|
Packit Service |
0a38ef |
forwarder_spec = dict(
|
|
Packit Service |
0a38ef |
ip_address=dict(type=str, required=True),
|
|
Packit Service |
0a38ef |
port=dict(type=int, required=False, default=None),
|
|
Packit Service |
0a38ef |
)
|
|
Packit Service |
0a38ef |
|
|
Packit Service |
0a38ef |
return dict(
|
|
Packit Service |
0a38ef |
state=dict(
|
|
Packit Service |
0a38ef |
type="str",
|
|
Packit Service |
0a38ef |
default="present",
|
|
Packit Service |
0a38ef |
choices=["present", "absent", "enabled", "disabled"],
|
|
Packit Service |
0a38ef |
),
|
|
Packit Service |
0a38ef |
ipaadmin_principal=dict(type="str", default="admin"),
|
|
Packit Service |
0a38ef |
ipaadmin_password=dict(type="str", required=False, no_log=True),
|
|
Packit Service |
0a38ef |
name=dict(
|
|
Packit Service |
a166ed |
type="list", default=None, required=False, aliases=["zone_name"]
|
|
Packit Service |
0a38ef |
),
|
|
Packit Service |
a166ed |
name_from_ip=dict(type="str", default=None, required=False),
|
|
Packit Service |
0a38ef |
forwarders=dict(
|
|
Packit Service |
0a38ef |
type="list",
|
|
Packit Service |
0a38ef |
default=None,
|
|
Packit Service |
0a38ef |
required=False,
|
|
Packit Service |
0a38ef |
options=dict(**forwarder_spec),
|
|
Packit Service |
0a38ef |
),
|
|
Packit Service |
0a38ef |
forward_policy=dict(
|
|
Packit Service |
0a38ef |
type="str",
|
|
Packit Service |
0a38ef |
required=False,
|
|
Packit Service |
0a38ef |
default=None,
|
|
Packit Service |
0a38ef |
choices=["only", "first", "none"],
|
|
Packit Service |
0a38ef |
),
|
|
Packit Service |
0a38ef |
name_server=dict(type="str", required=False, default=None),
|
|
Packit Service |
0a38ef |
admin_email=dict(type="str", required=False, default=None),
|
|
Packit Service |
0a38ef |
allow_sync_ptr=dict(type="bool", required=False, default=None),
|
|
Packit Service |
0a38ef |
update_policy=dict(type="str", required=False, default=None),
|
|
Packit Service |
0a38ef |
dynamic_update=dict(
|
|
Packit Service |
0a38ef |
type="bool",
|
|
Packit Service |
0a38ef |
required=False,
|
|
Packit Service |
0a38ef |
default=None,
|
|
Packit Service |
0a38ef |
aliases=["dynamicupdate"],
|
|
Packit Service |
0a38ef |
),
|
|
Packit Service |
0a38ef |
dnssec=dict(type="bool", required=False, default=None),
|
|
Packit Service |
0a38ef |
allow_transfer=dict(type="list", required=False, default=None),
|
|
Packit Service |
0a38ef |
allow_query=dict(type="list", required=False, default=None),
|
|
Packit Service |
0a38ef |
serial=dict(type="int", required=False, default=None),
|
|
Packit Service |
0a38ef |
refresh=dict(type="int", required=False, default=None),
|
|
Packit Service |
0a38ef |
retry=dict(type="int", required=False, default=None),
|
|
Packit Service |
0a38ef |
expire=dict(type="int", required=False, default=None),
|
|
Packit Service |
0a38ef |
minimum=dict(type="int", required=False, default=None),
|
|
Packit Service |
0a38ef |
ttl=dict(type="int", required=False, default=None),
|
|
Packit Service |
0a38ef |
default_ttl=dict(type="int", required=False, default=None),
|
|
Packit Service |
0a38ef |
nsec3param_rec=dict(type="str", required=False, default=None),
|
|
Packit Service |
0a38ef |
skip_nameserver_check=dict(type="bool", required=False, default=None),
|
|
Packit Service |
0a38ef |
skip_overlap_check=dict(type="bool", required=False, default=None),
|
|
Packit Service |
0a38ef |
)
|
|
Packit Service |
0a38ef |
|
|
Packit Service |
0a38ef |
|
|
Packit Service |
0a38ef |
def main():
|
|
Packit Service |
a166ed |
DNSZoneModule(
|
|
Packit Service |
a166ed |
argument_spec=get_argument_spec(),
|
|
Packit Service |
a166ed |
mutually_exclusive=[["name", "name_from_ip"]],
|
|
Packit Service |
a166ed |
required_one_of=[["name", "name_from_ip"]],
|
|
Packit Service |
a166ed |
).ipa_run()
|
|
Packit Service |
0a38ef |
|
|
Packit Service |
0a38ef |
|
|
Packit Service |
0a38ef |
if __name__ == "__main__":
|
|
Packit Service |
0a38ef |
main()
|