On 10.3.2016 22:17, Lukas Slebodnik wrote:
> On (10/03/16 22:14), Petr Spacek wrote:
>> Hello,
>>
>> I forgot to send a patches before I leave, so here it is:
>>
>> Auto-detect default value for --forward-policy option in installers
>>
>> See
>> https://fedorahosted.org/freeipa/ticket/5710
>> commit messages, and design page
>> https://fedorahosted.org/bind-dyndb-ldap/wiki/BIND9/Design/AutomaticEmptyZones
>>
>>
>> I did not have time to test it thoroughly but it LGTM :-D
>>
>> Please note that this is first part, it does not solve upgrade (yet) and
>> warnings in forwardzone-* interface.
>>
>> This can be solved in another patch set, this can be pushed if it passes 
>> review.
>>
> ENOPATH

LOL, here it is.

-- 
Petr^2 Spacek
From 14fc37af42fedc230a6e2f8a942d9ca16abd36ff Mon Sep 17 00:00:00 2001
From: Petr Spacek <pspa...@redhat.com>
Date: Mon, 7 Mar 2016 10:52:35 +0100
Subject: [PATCH] Remove function ipapython.ipautil.host_exists()

The function duplicated ipalib.util.verify_host_resolvable() in slightly
incompatible way because it used NSS while rest of IPA is using only DNS.
---
 install/tools/ipa-replica-manage | 12 ++++++++----
 ipapython/ipautil.py             | 14 --------------
 2 files changed, 8 insertions(+), 18 deletions(-)

diff --git a/install/tools/ipa-replica-manage b/install/tools/ipa-replica-manage
index 0497a0f0549b392216c654ab67d98cedbf122a4b..cf558977cb9dbf3bb1a0ae8dbd6ad9be1955be26 100755
--- a/install/tools/ipa-replica-manage
+++ b/install/tools/ipa-replica-manage
@@ -37,7 +37,7 @@ from ipaserver.install import opendnssecinstance, dnskeysyncinstance
 from ipapython import version, ipaldap
 from ipalib import api, errors
 from ipalib.constants import CACERT
-from ipalib.util import has_managed_topology
+from ipalib.util import has_managed_topology, verify_host_resolvable
 from ipapython.ipa_log_manager import root_logger, standard_logging_setup
 from ipapython.dn import DN
 from ipapython.config import IPAOptionParser
@@ -742,10 +742,14 @@ def check_last_link(delrepl, realm, dirman_passwd, force):
 
 
 def enforce_host_existence(host, message=None):
-    if host is not None and not ipautil.host_exists(host):
+    if host is None:
+        return
+
+    try:
+        verify_host_resolvable(host, root_logger)
+    except errors.DNSNotARecordError as ex:
         if message is None:
-            message = "Unknown host %s" % host
-
+            message = "Unknown host %s: %s" % (host, ex)
         sys.exit(message)
 
 def ensure_last_services(conn, hostname, masters, options):
diff --git a/ipapython/ipautil.py b/ipapython/ipautil.py
index 95357fa54ecf7f836e07de4a4322a9040c57c87e..7c2e3bc189c22f803e8685e9cd29c5edcc1e8e40 100644
--- a/ipapython/ipautil.py
+++ b/ipapython/ipautil.py
@@ -1013,20 +1013,6 @@ def bind_port_responder(port, socket_type=socket.SOCK_STREAM, socket_timeout=Non
         raise last_socket_error # pylint: disable=E0702
 
 
-def host_exists(host):
-    """
-    Resolve the host to see if it exists.
-
-    Returns True/False
-    """
-    try:
-        socket.getaddrinfo(host, 80)
-    except socket.gaierror:
-        return False
-    else:
-        return True
-
-
 def reverse_record_exists(ip_address):
     """
     Checks if IP address have some reverse record somewhere.
-- 
2.5.0

From 5e1a8528293f21cd2efe40fdf612295b10a6a508 Mon Sep 17 00:00:00 2001
From: Petr Spacek <pspa...@redhat.com>
Date: Tue, 1 Mar 2016 11:13:18 +0100
Subject: [PATCH] Extend installers with --forward-policy option

This option specified forward policy for global forwarders.
The value is put inside /etc/named.conf.

https://fedorahosted.org/freeipa/ticket/5710
---
 install/share/bind.named.conf.template  | 2 +-
 install/tools/man/ipa-dns-install.1     | 3 +++
 install/tools/man/ipa-replica-install.1 | 3 +++
 install/tools/man/ipa-server-install.1  | 3 +++
 ipaserver/install/bindinstance.py       | 7 +++++--
 ipaserver/install/dns.py                | 4 ++--
 ipaserver/install/server/common.py      | 5 +++++
 ipaserver/install/server/install.py     | 5 +++--
 8 files changed, 25 insertions(+), 7 deletions(-)

diff --git a/install/share/bind.named.conf.template b/install/share/bind.named.conf.template
index 3c19383c0dde4353b30b16240ec2b81d7ea65776..eb6d4ae278f8646a25e18ed95989b8b0c4d89d28 100644
--- a/install/share/bind.named.conf.template
+++ b/install/share/bind.named.conf.template
@@ -8,7 +8,7 @@ options {
 	statistics-file		"data/named_stats.txt";
 	memstatistics-file	"data/named_mem_stats.txt";
 
-	forward first;
+	forward $FORWARD_POLICY;
 	forwarders {$FORWARDERS};
 
 	// Any host is permitted to issue recursive queries
diff --git a/install/tools/man/ipa-dns-install.1 b/install/tools/man/ipa-dns-install.1
index a997eb84153fd0b28a8fcbf6a475a3a0361429fe..e3739e2bbeeccfb24721faa0a5da5600ee145f7c 100644
--- a/install/tools/man/ipa-dns-install.1
+++ b/install/tools/man/ipa-dns-install.1
@@ -41,6 +41,9 @@ Do not add any DNS forwarders, send non\-resolvable addresses to the DNS root se
 \fB\-\-auto\-forwarders\fR
 Add DNS forwarders configured in /etc/resolv.conf to the list of forwarders used by IPA DNS.
 .TP
+\fB\-\-forward\-policy\fR=\fIfirst|only\fR
+DNS forwarding policy for global forwarders specified using other options. Defaults to first.
+.TP
 \fB\-\-reverse\-zone\fR=\fIREVERSE_ZONE\fR
 The reverse DNS zone to use. This option can be used multiple times to specify multiple reverse zones.
 .TP
diff --git a/install/tools/man/ipa-replica-install.1 b/install/tools/man/ipa-replica-install.1
index 68976e7f9d40e79df409d8ad61e38ea61fb292dd..6875f4e416adea502b7c3136060f231212e60ef1 100644
--- a/install/tools/man/ipa-replica-install.1
+++ b/install/tools/man/ipa-replica-install.1
@@ -149,6 +149,9 @@ Do not add any DNS forwarders. Root DNS servers will be used instead.
 \fB\-\-auto\-forwarders\fR
 Add DNS forwarders configured in /etc/resolv.conf to the list of forwarders used by IPA DNS.
 .TP
+\fB\-\-forward\-policy\fR=\fIfirst|only\fR
+DNS forwarding policy for global forwarders specified using other options. Defaults to first.
+.TP
 \fB\-\-reverse\-zone\fR=\fIREVERSE_ZONE\fR
 The reverse DNS zone to use. This option can be used multiple times to specify multiple reverse zones.
 .TP
diff --git a/install/tools/man/ipa-server-install.1 b/install/tools/man/ipa-server-install.1
index 242b41b774081b7b2ab2848bf3a2b872c8efce94..e5f6f760bf854f3e36a5372504e7c1b8c8acb9b1 100644
--- a/install/tools/man/ipa-server-install.1
+++ b/install/tools/man/ipa-server-install.1
@@ -158,6 +158,9 @@ Do not add any DNS forwarders. Root DNS servers will be used instead.
 \fB\-\-auto\-forwarders\fR
 Add DNS forwarders configured in /etc/resolv.conf to the list of forwarders used by IPA DNS.
 .TP
+\fB\-\-forward\-policy\fR=\fIfirst|only\fR
+DNS forwarding policy for global forwarders specified using other options. Defaults to first.
+.TP
 \fB\-\-reverse\-zone\fR=\fIREVERSE_ZONE\fR
 The reverse DNS zone to use. This option can be used multiple times to specify multiple reverse zones.
 .TP
diff --git a/ipaserver/install/bindinstance.py b/ipaserver/install/bindinstance.py
index 3d4900e78c361d47af08af6e6fb0a41d7931507d..4edd52214ef3de65b98d1d6076ee9d6a5e734ffb 100644
--- a/ipaserver/install/bindinstance.py
+++ b/ipaserver/install/bindinstance.py
@@ -609,15 +609,17 @@ class BindInstance(service.Service):
 
     suffix = ipautil.dn_attribute_property('_suffix')
 
-    def setup(self, fqdn, ip_addresses, realm_name, domain_name, forwarders, ntp,
-              reverse_zones, named_user=constants.NAMED_USER, zonemgr=None,
+    def setup(self, fqdn, ip_addresses, realm_name, domain_name, forwarders,
+              forward_policy, ntp, reverse_zones,
+              named_user=constants.NAMED_USER, zonemgr=None,
               ca_configured=None, no_dnssec_validation=False):
         self.named_user = named_user
         self.fqdn = fqdn
         self.ip_addresses = ip_addresses
         self.realm = realm_name
         self.domain = domain_name
         self.forwarders = forwarders
+        self.forward_policy = forward_policy
         self.host = fqdn.split(".")[0]
         self.suffix = ipautil.realm_to_suffix(self.realm)
         self.ntp = ntp
@@ -775,6 +777,7 @@ class BindInstance(service.Service):
             REALM=self.realm,
             SERVER_ID=installutils.realm_to_serverid(self.realm),
             FORWARDERS=fwds,
+            FORWARD_POLICY=self.forward_policy,
             SUFFIX=self.suffix,
             OPTIONAL_NTP=optional_ntp,
             ZONEMGR=self.zonemgr,
diff --git a/ipaserver/install/dns.py b/ipaserver/install/dns.py
index 9a2fde29f613a3ce07b4f85f5ae2a856b806bdc8..70962252c7f8ae28e4de00e1a2ab2cace76ad8a0 100644
--- a/ipaserver/install/dns.py
+++ b/ipaserver/install/dns.py
@@ -318,8 +318,8 @@ def install(standalone, replica, options, api=api):
     bind = bindinstance.BindInstance(fstore, ldapi=True, api=api,
                                      autobind=AUTOBIND_ENABLED)
     bind.setup(api.env.host, ip_addresses, api.env.realm, api.env.domain,
-               options.forwarders, conf_ntp, reverse_zones,
-               zonemgr=options.zonemgr,
+               options.forwarders, options.forward_policy, conf_ntp,
+               reverse_zones, zonemgr=options.zonemgr,
                no_dnssec_validation=options.no_dnssec_validation,
                ca_configured=options.setup_ca)
 
diff --git a/ipaserver/install/server/common.py b/ipaserver/install/server/common.py
index bd103517277fe6fda540deeef7e0df8266fec2dc..53a238f356ed2c3a184fb24aa587c2e184adbad1 100644
--- a/ipaserver/install/server/common.py
+++ b/ipaserver/install/server/common.py
@@ -169,6 +169,11 @@ class BaseServerDNS(common.Installable, core.Group, core.Composite):
         cli_name='forwarder',
     )
 
+    forward_policy = Knob(
+        {'only', 'first'}, 'first',
+        description=("DNS forwarding policy for global forwarders"),
+    )
+
     auto_forwarders = Knob(
         bool, False,
         description="Use DNS forwarders configured in /etc/resolv.conf",
diff --git a/ipaserver/install/server/install.py b/ipaserver/install/server/install.py
index b7a38a57c0f4fa7a38605585e663e767de8b0fee..7323f190a28ff7209c99cf55b17d230f2927974a 100644
--- a/ipaserver/install/server/install.py
+++ b/ipaserver/install/server/install.py
@@ -746,10 +746,11 @@ def install_check(installer):
 
     if options.setup_dns:
         print("BIND DNS server will be configured to serve IPA domain with:")
-        print("Forwarders:    %s" % (
+        print("Forwarders:       %s" % (
             "No forwarders" if not options.forwarders
             else ", ".join([str(ip) for ip in options.forwarders])
         ))
+        print('Forward policy:   %s' % options.forward_policy)
         print("Reverse zone(s):  %s" % (
             "No reverse zone" if options.no_reverse or not dns.reverse_zones
             else ", ".join(str(rz) for rz in dns.reverse_zones)
@@ -979,7 +980,7 @@ def install(installer):
         # Create a BIND instance
         bind = bindinstance.BindInstance(fstore, dm_password)
         bind.setup(host_name, ip_addresses, realm_name,
-                   domain_name, (), not options.no_ntp, (),
+                   domain_name, (), 'first', not options.no_ntp, (),
                    zonemgr=options.zonemgr, ca_configured=setup_ca,
                    no_dnssec_validation=options.no_dnssec_validation)
         bind.create_sample_bind_zone()
-- 
2.5.0

From 54b80cf87e3d117e24163bbcc9d4a7fd484587de Mon Sep 17 00:00:00 2001
From: Petr Spacek <pspa...@redhat.com>
Date: Mon, 7 Mar 2016 12:00:21 +0100
Subject: [PATCH] Move automatic empty zone list into ipapython.dnsutil and
 make it reusable

https://fedorahosted.org/freeipa/ticket/5710
---
 ipapython/dnsutil.py | 57 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 ipapython/ipautil.py | 56 +++------------------------------------------------
 2 files changed, 60 insertions(+), 53 deletions(-)

diff --git a/ipapython/dnsutil.py b/ipapython/dnsutil.py
index 18141fa091b37c5e59a2efc1028812981bfd4884..0cab0f49709a94ae877db5b6aad7ae3bb5bdc947 100644
--- a/ipapython/dnsutil.py
+++ b/ipapython/dnsutil.py
@@ -109,3 +109,60 @@ DNSName.root = DNSName(dns.name.root)  # '.'
 DNSName.empty = DNSName(dns.name.empty)  # '@'
 DNSName.ip4_rev_zone = DNSName(('in-addr', 'arpa', ''))
 DNSName.ip6_rev_zone = DNSName(('ip6', 'arpa', ''))
+
+# Empty zones are defined in various RFCs. BIND is by default serving them.
+# This constat should contain everything listed in
+# IANA registry "Locally-Served DNS Zones"
+# URL: http://www.iana.org/assignments/locally-served-dns-zones
+# + AS112 zone defined in RFC 7534. It is not in the registry for some
+# reason but BIND 9.10 is serving it as automatic empty zones.
+EMPTY_ZONES = [DNSName(aez).make_absolute() for aez in [
+        # RFC 1918
+        "10.IN-ADDR.ARPA", "16.172.IN-ADDR.ARPA", "17.172.IN-ADDR.ARPA",
+        "18.172.IN-ADDR.ARPA", "19.172.IN-ADDR.ARPA", "20.172.IN-ADDR.ARPA",
+        "21.172.IN-ADDR.ARPA", "22.172.IN-ADDR.ARPA", "23.172.IN-ADDR.ARPA",
+        "24.172.IN-ADDR.ARPA", "25.172.IN-ADDR.ARPA", "26.172.IN-ADDR.ARPA",
+        "27.172.IN-ADDR.ARPA", "28.172.IN-ADDR.ARPA", "29.172.IN-ADDR.ARPA",
+        "30.172.IN-ADDR.ARPA", "31.172.IN-ADDR.ARPA", "168.192.IN-ADDR.ARPA",
+        # RFC 6598
+        "64.100.IN-ADDR.ARPA", "65.100.IN-ADDR.ARPA", "66.100.IN-ADDR.ARPA",
+        "67.100.IN-ADDR.ARPA", "68.100.IN-ADDR.ARPA", "69.100.IN-ADDR.ARPA",
+        "70.100.IN-ADDR.ARPA", "71.100.IN-ADDR.ARPA", "72.100.IN-ADDR.ARPA",
+        "73.100.IN-ADDR.ARPA", "74.100.IN-ADDR.ARPA", "75.100.IN-ADDR.ARPA",
+        "76.100.IN-ADDR.ARPA", "77.100.IN-ADDR.ARPA", "78.100.IN-ADDR.ARPA",
+        "79.100.IN-ADDR.ARPA", "80.100.IN-ADDR.ARPA", "81.100.IN-ADDR.ARPA",
+        "82.100.IN-ADDR.ARPA", "83.100.IN-ADDR.ARPA", "84.100.IN-ADDR.ARPA",
+        "85.100.IN-ADDR.ARPA", "86.100.IN-ADDR.ARPA", "87.100.IN-ADDR.ARPA",
+        "88.100.IN-ADDR.ARPA", "89.100.IN-ADDR.ARPA", "90.100.IN-ADDR.ARPA",
+        "91.100.IN-ADDR.ARPA", "92.100.IN-ADDR.ARPA", "93.100.IN-ADDR.ARPA",
+        "94.100.IN-ADDR.ARPA", "95.100.IN-ADDR.ARPA", "96.100.IN-ADDR.ARPA",
+        "97.100.IN-ADDR.ARPA", "98.100.IN-ADDR.ARPA", "99.100.IN-ADDR.ARPA",
+        "100.100.IN-ADDR.ARPA", "101.100.IN-ADDR.ARPA",
+        "102.100.IN-ADDR.ARPA", "103.100.IN-ADDR.ARPA",
+        "104.100.IN-ADDR.ARPA", "105.100.IN-ADDR.ARPA",
+        "106.100.IN-ADDR.ARPA", "107.100.IN-ADDR.ARPA",
+        "108.100.IN-ADDR.ARPA", "109.100.IN-ADDR.ARPA",
+        "110.100.IN-ADDR.ARPA", "111.100.IN-ADDR.ARPA",
+        "112.100.IN-ADDR.ARPA", "113.100.IN-ADDR.ARPA",
+        "114.100.IN-ADDR.ARPA", "115.100.IN-ADDR.ARPA",
+        "116.100.IN-ADDR.ARPA", "117.100.IN-ADDR.ARPA",
+        "118.100.IN-ADDR.ARPA", "119.100.IN-ADDR.ARPA",
+        "120.100.IN-ADDR.ARPA", "121.100.IN-ADDR.ARPA",
+        "122.100.IN-ADDR.ARPA", "123.100.IN-ADDR.ARPA",
+        "124.100.IN-ADDR.ARPA", "125.100.IN-ADDR.ARPA",
+        "126.100.IN-ADDR.ARPA", "127.100.IN-ADDR.ARPA",
+        # RFC 5735 and RFC 5737
+        "0.IN-ADDR.ARPA", "127.IN-ADDR.ARPA", "254.169.IN-ADDR.ARPA",
+        "2.0.192.IN-ADDR.ARPA", "100.51.198.IN-ADDR.ARPA",
+        "113.0.203.IN-ADDR.ARPA", "255.255.255.255.IN-ADDR.ARPA",
+        # Local IPv6 Unicast Addresses
+        "0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.IP6.ARPA",
+        "1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.IP6.ARPA",
+        # LOCALLY ASSIGNED LOCAL ADDRESS SCOPE
+        "D.F.IP6.ARPA", "8.E.F.IP6.ARPA", "9.E.F.IP6.ARPA", "A.E.F.IP6.ARPA",
+        "B.E.F.IP6.ARPA",
+        # Example Prefix, RFC 3849.
+        "8.B.D.0.1.0.0.2.IP6.ARPA",
+        # RFC 7534
+        "EMPTY.AS112.ARPA",
+    ]]
diff --git a/ipapython/ipautil.py b/ipapython/ipautil.py
index 7c2e3bc189c22f803e8685e9cd29c5edcc1e8e40..35506dab427c26be36469aabd3c633bbfc4b7020 100644
--- a/ipapython/ipautil.py
+++ b/ipapython/ipautil.py
@@ -50,7 +50,7 @@ from ipapython.ipa_log_manager import root_logger
 from ipapython import config
 from ipaplatform.paths import paths
 from ipapython.dn import DN
-from ipapython.dnsutil import DNSName
+from ipapython.dnsutil import DNSName, EMPTY_ZONES
 
 SHARE_DIR = paths.USR_SHARE_IPA_DIR
 PLUGINS_SHARE_DIR = paths.IPA_PLUGINS
@@ -1064,59 +1064,9 @@ def check_zone_overlap(zone, raise_on_error=True):
 
 
 def is_auto_empty_zone(zone):
+    """True if specified zone name exactly matches an automatic empty zone."""
     assert isinstance(zone, DNSName)
-
-    automatic_empty_zones = [DNSName(aez).make_absolute() for aez in [
-        # RFC 1918
-        "10.IN-ADDR.ARPA", "16.172.IN-ADDR.ARPA", "17.172.IN-ADDR.ARPA",
-        "18.172.IN-ADDR.ARPA", "19.172.IN-ADDR.ARPA", "20.172.IN-ADDR.ARPA",
-        "21.172.IN-ADDR.ARPA", "22.172.IN-ADDR.ARPA", "23.172.IN-ADDR.ARPA",
-        "24.172.IN-ADDR.ARPA", "25.172.IN-ADDR.ARPA", "26.172.IN-ADDR.ARPA",
-        "27.172.IN-ADDR.ARPA", "28.172.IN-ADDR.ARPA", "29.172.IN-ADDR.ARPA",
-        "30.172.IN-ADDR.ARPA", "31.172.IN-ADDR.ARPA", "168.192.IN-ADDR.ARPA",
-        # RFC 6598
-        "64.100.IN-ADDR.ARPA", "65.100.IN-ADDR.ARPA", "66.100.IN-ADDR.ARPA",
-        "67.100.IN-ADDR.ARPA", "68.100.IN-ADDR.ARPA", "69.100.IN-ADDR.ARPA",
-        "70.100.IN-ADDR.ARPA", "71.100.IN-ADDR.ARPA", "72.100.IN-ADDR.ARPA",
-        "73.100.IN-ADDR.ARPA", "74.100.IN-ADDR.ARPA", "75.100.IN-ADDR.ARPA",
-        "76.100.IN-ADDR.ARPA", "77.100.IN-ADDR.ARPA", "78.100.IN-ADDR.ARPA",
-        "79.100.IN-ADDR.ARPA", "80.100.IN-ADDR.ARPA", "81.100.IN-ADDR.ARPA",
-        "82.100.IN-ADDR.ARPA", "83.100.IN-ADDR.ARPA", "84.100.IN-ADDR.ARPA",
-        "85.100.IN-ADDR.ARPA", "86.100.IN-ADDR.ARPA", "87.100.IN-ADDR.ARPA",
-        "88.100.IN-ADDR.ARPA", "89.100.IN-ADDR.ARPA", "90.100.IN-ADDR.ARPA",
-        "91.100.IN-ADDR.ARPA", "92.100.IN-ADDR.ARPA", "93.100.IN-ADDR.ARPA",
-        "94.100.IN-ADDR.ARPA", "95.100.IN-ADDR.ARPA", "96.100.IN-ADDR.ARPA",
-        "97.100.IN-ADDR.ARPA", "98.100.IN-ADDR.ARPA", "99.100.IN-ADDR.ARPA",
-        "100.100.IN-ADDR.ARPA", "101.100.IN-ADDR.ARPA",
-        "102.100.IN-ADDR.ARPA", "103.100.IN-ADDR.ARPA",
-        "104.100.IN-ADDR.ARPA", "105.100.IN-ADDR.ARPA",
-        "106.100.IN-ADDR.ARPA", "107.100.IN-ADDR.ARPA",
-        "108.100.IN-ADDR.ARPA", "109.100.IN-ADDR.ARPA",
-        "110.100.IN-ADDR.ARPA", "111.100.IN-ADDR.ARPA",
-        "112.100.IN-ADDR.ARPA", "113.100.IN-ADDR.ARPA",
-        "114.100.IN-ADDR.ARPA", "115.100.IN-ADDR.ARPA",
-        "116.100.IN-ADDR.ARPA", "117.100.IN-ADDR.ARPA",
-        "118.100.IN-ADDR.ARPA", "119.100.IN-ADDR.ARPA",
-        "120.100.IN-ADDR.ARPA", "121.100.IN-ADDR.ARPA",
-        "122.100.IN-ADDR.ARPA", "123.100.IN-ADDR.ARPA",
-        "124.100.IN-ADDR.ARPA", "125.100.IN-ADDR.ARPA",
-        "126.100.IN-ADDR.ARPA", "127.100.IN-ADDR.ARPA",
-        # RFC 5735 and RFC 5737
-        "0.IN-ADDR.ARPA", "127.IN-ADDR.ARPA", "254.169.IN-ADDR.ARPA",
-        "2.0.192.IN-ADDR.ARPA", "100.51.198.IN-ADDR.ARPA",
-        "113.0.203.IN-ADDR.ARPA", "255.255.255.255.IN-ADDR.ARPA",
-        # Local IPv6 Unicast Addresses
-        "0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.IP6.ARPA",
-        "1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.IP6.ARPA",
-        # LOCALLY ASSIGNED LOCAL ADDRESS SCOPE
-        "D.F.IP6.ARPA", "8.E.F.IP6.ARPA", "9.E.F.IP6.ARPA", "A.E.F.IP6.ARPA",
-        "B.E.F.IP6.ARPA",
-        # Example Prefix, RFC 3849.
-        "8.B.D.0.1.0.0.2.IP6.ARPA",
-        # RFC 7534
-        "EMPTY.AS112.ARPA",
-    ]]
-    return zone in automatic_empty_zones
+    return zone in EMPTY_ZONES
 
 
 def config_replace_variables(filepath, replacevars=dict(), appendvars=dict()):
-- 
2.5.0

From f9d3a3bb630ba4b73bdec711f6751410cde32bdf Mon Sep 17 00:00:00 2001
From: Petr Spacek <pspa...@redhat.com>
Date: Mon, 7 Mar 2016 13:24:31 +0100
Subject: [PATCH] Add assert_absolute_dnsname() helper to ipapython.dnsutil

Sanity check for zone names and such should be the same everywhere.
This new function will be a replacement for ad-hoc checks.

https://fedorahosted.org/freeipa/ticket/5710
---
 ipapython/dnsutil.py | 19 +++++++++++++++++++
 1 file changed, 19 insertions(+)

diff --git a/ipapython/dnsutil.py b/ipapython/dnsutil.py
index 0cab0f49709a94ae877db5b6aad7ae3bb5bdc947..7f0a094f28d5226b58c5e751b5c1dae7bcf97d61 100644
--- a/ipapython/dnsutil.py
+++ b/ipapython/dnsutil.py
@@ -166,3 +166,22 @@ EMPTY_ZONES = [DNSName(aez).make_absolute() for aez in [
         # RFC 7534
         "EMPTY.AS112.ARPA",
     ]]
+
+
+def assert_absolute_dnsname(name):
+    """Raise AssertionError if name is not DNSName or is not absolute.
+
+    >>> assert_absolute_dnsname(DNSName('absolute.name.example.'))
+    >>> assert_absolute_dnsname(DNSName('relative.name.example'))
+    Traceback (most recent call last):
+      ...
+    AssertionError: name must be absolute, ...
+    >>> assert_absolute_dnsname('absolute.string.example.')
+    Traceback (most recent call last):
+      ...
+    AssertionError: name must be DNSName instance, ...
+    """
+
+    assert isinstance(name, DNSName), ("name must be DNSName instance, "
+                                       "got '%s'" % type(name))
+    assert name.is_absolute(), "name must be absolute, got '%s'" % name
-- 
2.5.0

From b75dea9c245327dbdb363eadb90f2603c0cc249b Mon Sep 17 00:00:00 2001
From: Petr Spacek <pspa...@redhat.com>
Date: Mon, 7 Mar 2016 13:30:35 +0100
Subject: [PATCH] Move function is_auto_empty_zone() into ipapython.dnsutil

I'm going to extend this so it is better to have it in module.
At the same time it is now using shared assert_absolute_dnsname()
helper.

https://fedorahosted.org/freeipa/ticket/5710
---
 ipapython/dnsutil.py | 6 ++++++
 ipapython/ipautil.py | 8 +-------
 2 files changed, 7 insertions(+), 7 deletions(-)

diff --git a/ipapython/dnsutil.py b/ipapython/dnsutil.py
index 7f0a094f28d5226b58c5e751b5c1dae7bcf97d61..6ff500b220e81ce5a013392d9268a9740615eccf 100644
--- a/ipapython/dnsutil.py
+++ b/ipapython/dnsutil.py
@@ -185,3 +185,9 @@ def assert_absolute_dnsname(name):
     assert isinstance(name, DNSName), ("name must be DNSName instance, "
                                        "got '%s'" % type(name))
     assert name.is_absolute(), "name must be absolute, got '%s'" % name
+
+
+def is_auto_empty_zone(zone):
+    """True if specified zone name exactly matches an automatic empty zone."""
+    assert isinstance(zone, DNSName)
+    return zone in EMPTY_ZONES
diff --git a/ipapython/ipautil.py b/ipapython/ipautil.py
index 35506dab427c26be36469aabd3c633bbfc4b7020..217dced97605b24f2b07a5889aa6e8d372747d4b 100644
--- a/ipapython/ipautil.py
+++ b/ipapython/ipautil.py
@@ -50,7 +50,7 @@ from ipapython.ipa_log_manager import root_logger
 from ipapython import config
 from ipaplatform.paths import paths
 from ipapython.dn import DN
-from ipapython.dnsutil import DNSName, EMPTY_ZONES
+from ipapython.dnsutil import DNSName, is_auto_empty_zone
 
 SHARE_DIR = paths.USR_SHARE_IPA_DIR
 PLUGINS_SHARE_DIR = paths.IPA_PLUGINS
@@ -1063,12 +1063,6 @@ def check_zone_overlap(zone, raise_on_error=True):
         raise ValueError(msg)
 
 
-def is_auto_empty_zone(zone):
-    """True if specified zone name exactly matches an automatic empty zone."""
-    assert isinstance(zone, DNSName)
-    return zone in EMPTY_ZONES
-
-
 def config_replace_variables(filepath, replacevars=dict(), appendvars=dict()):
     """
     Take a key=value based configuration file, and write new version
-- 
2.5.0

From 941ec80ff76334048996a942113a5a61dfb0f862 Mon Sep 17 00:00:00 2001
From: Petr Spacek <pspa...@redhat.com>
Date: Mon, 7 Mar 2016 14:10:34 +0100
Subject: [PATCH] Use shared sanity check and tests
 ipapython.dnsutil.is_auto_empty_zone()

https://fedorahosted.org/freeipa/ticket/5710
---
 ipapython/dnsutil.py | 16 ++++++++++++++--
 1 file changed, 14 insertions(+), 2 deletions(-)

diff --git a/ipapython/dnsutil.py b/ipapython/dnsutil.py
index 6ff500b220e81ce5a013392d9268a9740615eccf..e8d2f6ff6bd4b6338db498fad70c1b3bf84e248f 100644
--- a/ipapython/dnsutil.py
+++ b/ipapython/dnsutil.py
@@ -188,6 +188,18 @@ def assert_absolute_dnsname(name):
 
 
 def is_auto_empty_zone(zone):
-    """True if specified zone name exactly matches an automatic empty zone."""
-    assert isinstance(zone, DNSName)
+    """True if specified zone name exactly matches an automatic empty zone.
+
+    >>> is_auto_empty_zone(DNSName('in-addr.arpa.'))
+    False
+    >>> is_auto_empty_zone(DNSName('10.in-addr.arpa.'))
+    True
+    >>> is_auto_empty_zone(DNSName('1.10.in-addr.arpa.'))
+    False
+    >>> is_auto_empty_zone(DNSName('10.in-addr.arpa'))
+    Traceback (most recent call last):
+      ...
+    AssertionError: ...
+    """
+    assert_absolute_dnsname(zone)
     return zone in EMPTY_ZONES
-- 
2.5.0

From 019474e455b772d63f8b55ca853c7d7df8e13cd4 Mon Sep 17 00:00:00 2001
From: Petr Spacek <pspa...@redhat.com>
Date: Mon, 7 Mar 2016 14:10:54 +0100
Subject: [PATCH] Add function ipapython.dnsutil.inside_auto_empty_zone()

It allows to test if given DNS name belongs to an automatic empty zone.

https://fedorahosted.org/freeipa/ticket/5710
---
 ipapython/dnsutil.py | 25 +++++++++++++++++++++++++
 1 file changed, 25 insertions(+)

diff --git a/ipapython/dnsutil.py b/ipapython/dnsutil.py
index e8d2f6ff6bd4b6338db498fad70c1b3bf84e248f..240b7c9cd2168db17b9fa673dc4eefcfa78fef45 100644
--- a/ipapython/dnsutil.py
+++ b/ipapython/dnsutil.py
@@ -203,3 +203,28 @@ def is_auto_empty_zone(zone):
     """
     assert_absolute_dnsname(zone)
     return zone in EMPTY_ZONES
+
+
+def inside_auto_empty_zone(name):
+    """True if specified absolute name is a subdomain of an automatic empty
+    zone.
+
+    DNS domain is a subdomain of itself so this function
+    returns True for zone apexes, too.
+
+    >>> inside_auto_empty_zone(DNSName('in-addr.arpa.'))
+    False
+    >>> inside_auto_empty_zone(DNSName('10.in-addr.arpa.'))
+    True
+    >>> inside_auto_empty_zone(DNSName('1.10.in-addr.arpa.'))
+    True
+    >>> inside_auto_empty_zone(DNSName('1.10.in-addr.arpa'))
+    Traceback (most recent call last):
+      ...
+    AssertionError: ...
+    """
+    assert_absolute_dnsname(name)
+    for aez in EMPTY_ZONES:
+        if name.is_subdomain(aez):
+            return True
+    return False
-- 
2.5.0

From 06ca4d52a78be42c7d9a256da6c7fecde4ad5539 Mon Sep 17 00:00:00 2001
From: Petr Spacek <pspa...@redhat.com>
Date: Mon, 7 Mar 2016 14:37:31 +0100
Subject: [PATCH] Auto-detect default value for --forward-policy option in
 installers

Forward policy defaults to 'first' if no IP address belonging to a private
or reserved ranges is detected on local interfaces (RFC 6303).
Defaults to only if a private IP address is detected.

This prevents problems with BIND automatic empty zones because
conflicting zones cannot be disabled unless forwarding policy == only.

https://fedorahosted.org/freeipa/ticket/5710
---
 install/tools/man/ipa-dns-install.1     | 5 ++++-
 install/tools/man/ipa-replica-install.1 | 5 ++++-
 install/tools/man/ipa-server-install.1  | 5 ++++-
 ipaserver/install/dns.py                | 9 +++++++++
 ipaserver/install/server/common.py      | 2 +-
 5 files changed, 22 insertions(+), 4 deletions(-)

diff --git a/install/tools/man/ipa-dns-install.1 b/install/tools/man/ipa-dns-install.1
index e3739e2bbeeccfb24721faa0a5da5600ee145f7c..ad937cc59bc0b1cff2dd73faa494a8121b6eb45d 100644
--- a/install/tools/man/ipa-dns-install.1
+++ b/install/tools/man/ipa-dns-install.1
@@ -42,7 +42,10 @@ Do not add any DNS forwarders, send non\-resolvable addresses to the DNS root se
 Add DNS forwarders configured in /etc/resolv.conf to the list of forwarders used by IPA DNS.
 .TP
 \fB\-\-forward\-policy\fR=\fIfirst|only\fR
-DNS forwarding policy for global forwarders specified using other options. Defaults to first.
+DNS forwarding policy for global forwarders specified using other options.
+Defaults to first if no IP address belonging to a private or reserved ranges is
+detected on local interfaces (RFC 6303). Defaults to only if a private
+IP address is detected.
 .TP
 \fB\-\-reverse\-zone\fR=\fIREVERSE_ZONE\fR
 The reverse DNS zone to use. This option can be used multiple times to specify multiple reverse zones.
diff --git a/install/tools/man/ipa-replica-install.1 b/install/tools/man/ipa-replica-install.1
index 6875f4e416adea502b7c3136060f231212e60ef1..0e9f51a645afeac63b0c87418cd1468db951c4ef 100644
--- a/install/tools/man/ipa-replica-install.1
+++ b/install/tools/man/ipa-replica-install.1
@@ -150,7 +150,10 @@ Do not add any DNS forwarders. Root DNS servers will be used instead.
 Add DNS forwarders configured in /etc/resolv.conf to the list of forwarders used by IPA DNS.
 .TP
 \fB\-\-forward\-policy\fR=\fIfirst|only\fR
-DNS forwarding policy for global forwarders specified using other options. Defaults to first.
+DNS forwarding policy for global forwarders specified using other options.
+Defaults to first if no IP address belonging to a private or reserved ranges is
+detected on local interfaces (RFC 6303). Defaults to only if a private
+IP address is detected.
 .TP
 \fB\-\-reverse\-zone\fR=\fIREVERSE_ZONE\fR
 The reverse DNS zone to use. This option can be used multiple times to specify multiple reverse zones.
diff --git a/install/tools/man/ipa-server-install.1 b/install/tools/man/ipa-server-install.1
index e5f6f760bf854f3e36a5372504e7c1b8c8acb9b1..55b49449e3c44aebfeefe5cb71d73e9abf07c5b2 100644
--- a/install/tools/man/ipa-server-install.1
+++ b/install/tools/man/ipa-server-install.1
@@ -159,7 +159,10 @@ Do not add any DNS forwarders. Root DNS servers will be used instead.
 Add DNS forwarders configured in /etc/resolv.conf to the list of forwarders used by IPA DNS.
 .TP
 \fB\-\-forward\-policy\fR=\fIfirst|only\fR
-DNS forwarding policy for global forwarders specified using other options. Defaults to first.
+DNS forwarding policy for global forwarders specified using other options.
+Defaults to first if no IP address belonging to a private or reserved ranges is
+detected on local interfaces (RFC 6303). Defaults to only if a private
+IP address is detected.
 .TP
 \fB\-\-reverse\-zone\fR=\fIREVERSE_ZONE\fR
 The reverse DNS zone to use. This option can be used multiple times to specify multiple reverse zones.
diff --git a/ipaserver/install/dns.py b/ipaserver/install/dns.py
index 70962252c7f8ae28e4de00e1a2ab2cace76ad8a0..8821ca3edd3de67d5af0c936d7d0f46ef9abb0b7 100644
--- a/ipaserver/install/dns.py
+++ b/ipaserver/install/dns.py
@@ -259,6 +259,15 @@ def install_check(standalone, api, replica, options, hostname):
     ip_addresses = get_server_ip_address(hostname, options.unattended,
                                          True, options.ip_addresses)
 
+    if not options.forward_policy:
+        # user did not specify policy, derive it: default is 'first' but
+        # if any of local IP addresses belongs to private ranges use 'only'
+        options.forward_policy = 'first'
+        for ip in ip_addresses:
+            if dnsutil.inside_auto_empty_zone(dnsutil.DNSName(ip.reverse_dns)):
+                options.forward_policy = 'only'
+                break
+
     if options.no_forwarders:
         options.forwarders = []
     elif options.forwarders or options.auto_forwarders:
diff --git a/ipaserver/install/server/common.py b/ipaserver/install/server/common.py
index 53a238f356ed2c3a184fb24aa587c2e184adbad1..63bf0d1e8bee696e57ec31d0ddf70a883cc28a31 100644
--- a/ipaserver/install/server/common.py
+++ b/ipaserver/install/server/common.py
@@ -170,7 +170,7 @@ class BaseServerDNS(common.Installable, core.Group, core.Composite):
     )
 
     forward_policy = Knob(
-        {'only', 'first'}, 'first',
+        {'only', 'first'}, None,
         description=("DNS forwarding policy for global forwarders"),
     )
 
-- 
2.5.0

-- 
Manage your subscription for the Freeipa-devel mailing list:
https://www.redhat.com/mailman/listinfo/freeipa-devel
Contribute to FreeIPA: http://www.freeipa.org/page/Contribute/Code

Reply via email to