On 31.3.2016 13:45, Martin Basti wrote:
> 
> 
> On 21.03.2016 16:51, Petr Spacek wrote:
>> 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.
>>
>>
>>
>  * Remove function ipapython.ipautil.host_exists() *
> ACK
> 
> 
> * Extend installers with --forward-policy option *
> 1)
> There is no --forward-policy option in ipa-dns-install
> 
> 
> * Move automatic empty zone list into ipapython.dnsutil and make it reusable *
> ACK
> 
> 
> * Add assert_absolute_dnsname() helper to ipapython.dnsutil *
> ACK
> 
> 
> * Move function is_auto_empty_zone() into ipapython.dnsutil *
> ACK
> 
> 
> * Use shared sanity check and tests ipapython.dnsutil.is_auto_empty_zone() *
> ACK
> 
> * Add function ipapython.dnsutil.inside_auto_empty_zone() *
> ACK
> 
> * Auto-detect default value for --forward-policy option in installers *
> LGTM, but ipa-dns-install is missing option --forward-policy
> 
> # ipa-dns-install
> ...
> Unexpected error - see /var/log/ipaserver-install.log for details:
> AttributeError: Values instance has no attribute 'forward_policy'
> 
> 
> Summary: 6 ACKs, 1 LGTM, 1 NACK => NACK

Thank you very much for review.

Here is my second attempt :-)

-- 
Petr^2 Spacek
From 57f64495c645d3c7b82b1d91b2b66b8b651bd114 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 6d1fc93c4c8499dcb4cd0924ff837a0216395821..3d2a467afd1c8552a64dd0f1c72efb92d9789bf1 100755
--- a/install/tools/ipa-replica-manage
+++ b/install/tools/ipa-replica-manage
@@ -38,7 +38,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
@@ -743,10 +743,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 d705c51f8d1937ffe57e52cce4b590951653c37b..c2e68e177f7f2c0af7af13605dee728b63fe8cb4 100644
--- a/ipapython/ipautil.py
+++ b/ipapython/ipautil.py
@@ -1014,20 +1014,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.5

From b0145d16f3f3bab451533edfb17774dc44ca08ce 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/ipa-dns-install           | 3 +++
 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 +++--
 9 files changed, 28 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/ipa-dns-install b/install/tools/ipa-dns-install
index 2eb1d0258bd6e323f9659da84692facef85a788d..53afd714d0d3ca2712eb622b7723da4db5973bda 100755
--- a/install/tools/ipa-dns-install
+++ b/install/tools/ipa-dns-install
@@ -57,6 +57,9 @@ def parse_options():
     parser.add_option("--auto-forwarders", dest="auto_forwarders",
                       action="store_true", default=False,
                       help="Use DNS forwarders configured in /etc/resolv.conf")
+    parser.add_option("--forward-policy", dest="forward_policy",
+                      choices=("first", "only"), default="first",
+                      help="DNS forwarding policy for global forwarders")
     parser.add_option("--reverse-zone", dest="reverse_zones",
                       default=[], action="append", metavar="REVERSE_ZONE",
                       help="The reverse DNS zone to use. This option can be used multiple times")
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 0b451e5f5041339a6d2ee6b01d0bd90f3e29868d..0cc8d2589be7ae835c807218b5c63ab3cb02a3a7 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 dbeacaee804dacd102d47aa28e9600adedead884..cae8787a4e849b4700b08bf93d326215becc7be5 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 f01022c4c3a056513db47f70727aa48157a8c6f2..f672684e64087fab4992fbdc67a77bda4d634f40 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.5

From b18a6193abfcf8574b7ab782ba9d12bbebffe1d6 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 c2e68e177f7f2c0af7af13605dee728b63fe8cb4..7f965f36f502582351c367e247809f5f8cd32096 100644
--- a/ipapython/ipautil.py
+++ b/ipapython/ipautil.py
@@ -51,7 +51,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
@@ -1065,59 +1065,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.5

From 916ba7077b61308abbba02100255459cfaa99960 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.5

From a2855a9bb2f4c2df712b83a0d90561b235d5edeb 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 7f965f36f502582351c367e247809f5f8cd32096..943f468fbe358dfa1d19c983e9ad902155e3f979 100644
--- a/ipapython/ipautil.py
+++ b/ipapython/ipautil.py
@@ -51,7 +51,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
@@ -1064,12 +1064,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.5

From 3c0e4e1d1b50a7b42092b573d0aa77195c3b613c 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.5

From a691c9494b5d1e1142592df4b7e94d5193749b3e 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.5

From e645ce0f6b3e8a8a964f4a5ef8f12c73f8b4caf7 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/ipa-dns-install           |  2 +-
 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                | 11 +++++++++++
 ipaserver/install/server/common.py      |  2 +-
 6 files changed, 25 insertions(+), 5 deletions(-)

diff --git a/install/tools/ipa-dns-install b/install/tools/ipa-dns-install
index 53afd714d0d3ca2712eb622b7723da4db5973bda..d8b2eb0fe2842208c64a3a8bb4e4fc295681fb9b 100755
--- a/install/tools/ipa-dns-install
+++ b/install/tools/ipa-dns-install
@@ -58,7 +58,7 @@ def parse_options():
                       action="store_true", default=False,
                       help="Use DNS forwarders configured in /etc/resolv.conf")
     parser.add_option("--forward-policy", dest="forward_policy",
-                      choices=("first", "only"), default="first",
+                      choices=("first", "only"), default=None,
                       help="DNS forwarding policy for global forwarders")
     parser.add_option("--reverse-zone", dest="reverse_zones",
                       default=[], action="append", metavar="REVERSE_ZONE",
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 cae8787a4e849b4700b08bf93d326215becc7be5..ccb7760e3c835d195963e9338e4a5fab8cb608b0 100644
--- a/ipaserver/install/dns.py
+++ b/ipaserver/install/dns.py
@@ -259,6 +259,17 @@ 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'
+                root_logger.debug('IP address %s belongs to a private range, '
+                                  'using forward policy only', ip)
+                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.5

-- 
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