diff --git a/README.md b/README.md index 7c36a665..6f84d350 100644 --- a/README.md +++ b/README.md @@ -15,11 +15,17 @@ Functionality changes and additions * Add fail2ban jails for both above mentioned geoipblocking filters * Add fail2ban filters for web scanners and badbots * Add xapian full text searching to dovecot (from https://github.com/grosjo/fts-xapian) -* Add rkhunter and chkrootkit -* Configure domain names for which only www will be hosted. Edit /etc/miabwwwdomains.conf to configure. +* Add rkhunter and chkrootkit + chkrootkit support is a bit dodgy, creating false positives every now and then, notably on kernel update. +* Configure domain names for which only www will be hosted. + Edit /etc/miabwwwdomains.conf to configure. The box will handle incoming traffic asking for these domain names. The DNS entries are entered in an external DNS provider! If you want this box to handle the DNS entries, simply add a mail alias. (existing functionality of the vanilla Mail-in-a-Box) * Add some munin plugins * Update nextcloud to 20.0.8 * Update roundcube carddav plugin to 4.1.1 +* Use shorter TTL values in the DNS server. + To be used before for example when changing IP addresses. Shortening TTL values will propagate changes faster. For reference, default TTL is 1 day, short TTL is 5 minutes. To use, edit file /etc/forceshortdnsttl and add a line for each domain for which shorter TTLs should be used. To use short TTLs for all known domains, add "forceshortdnsttl" +* Use the box as a Hidden Master in the DNS system + Thus only the secondary DNS servers are used as public DNS servers. When using a hidden master, no glue records are necessary at your domain hoster. To use, first setup secondary DNS servers via the Custom DNS administration page. At least two secondary servers should be set. When that functions, edit file /etc/usehiddenmasterdns and add a line for each domain for which Hidden Master should be used. To use Hidden Master for all known domains, add "usehiddenmasterdns". Bug fixes * Munin routes are ignored for Multi Factor Authentication [see github issue](https://github.com/mail-in-a-box/mailinabox/issues/1865) diff --git a/management/dns_update.py b/management/dns_update.py index 569de9b1..3ad13b51 100755 --- a/management/dns_update.py +++ b/management/dns_update.py @@ -145,17 +145,29 @@ def build_zone(domain, all_domains, additional_records, www_redirect_domains, en # 'False' in the tuple indicates these records would not be used if the zone # is managed outside of the box. if is_zone: - # Obligatory definition of ns1.PRIMARY_HOSTNAME. - records.append((None, "NS", "ns1.%s." % env["PRIMARY_HOSTNAME"], False)) - # Define ns2.PRIMARY_HOSTNAME or whatever the user overrides. # User may provide one or more additional nameservers - secondary_ns_list = get_secondary_dns(additional_records, mode="NS") \ - or ["ns2." + env["PRIMARY_HOSTNAME"]] + secondary_ns_list = get_secondary_dns(additional_records, mode="NS") + + # Need at least two nameservers in the secondary dns list + useHiddenMaster = False + if os.path.exists("/etc/usehiddenmasterdns") and len(secondary_ns_list) > 1: + with open("/etc/usehiddenmasterdns") as f: + for line in f: + if line.strip() == domain or line.strip() == "usehiddenmasterdns": + useHiddenMaster = True + break + + if not useHiddenMaster: + # Obligatory definition of ns1.PRIMARY_HOSTNAME. + records.append((None, "NS", "ns1.%s." % env["PRIMARY_HOSTNAME"], False)) + + if len(secondary_ns_list) == 0: + secondary_ns_list = ["ns2." + env["PRIMARY_HOSTNAME"]] + for secondary_ns in secondary_ns_list: records.append((None, "NS", secondary_ns+'.', False)) - # In PRIMARY_HOSTNAME... if domain == env["PRIMARY_HOSTNAME"]: # Define ns1 and ns2. @@ -466,23 +478,72 @@ def write_nsd_zone(domain, zonefile, records, env, force): # For the refresh through TTL fields, a good reference is: # http://www.peerwisdom.org/2013/05/15/dns-understanding-the-soa-record/ + + # Time To Refresh – How long in seconds a nameserver should wait prior to checking for a Serial Number + # increase within the primary zone file. An increased Serial Number means a transfer is needed to sync + # your records. Only applies to zones using secondary DNS. + # Time To Retry – How long in seconds a nameserver should wait prior to retrying to update a zone after + # a failed attempt. Only applies to zones using secondary DNS. + # Time To Expire – How long in seconds a nameserver should wait prior to considering data from a secondary + # zone invalid and stop answering queries for that zone. Only applies to zones using secondary DNS. + # Minimum TTL – How long in seconds that a nameserver or resolver should cache a negative response. + + # To make use of hidden master initialize the DNS to be used as secondary DNS. Then change the following + # in the zone file: + # - Name the secondary DNS server as primary DNS in the SOA record + # - Do not add NS records for the Mail-in-a-Box server zone = """ $ORIGIN {domain}. -$TTL 86400 ; default time to live +$TTL {defttl} ; default time to live -@ IN SOA ns1.{primary_domain}. hostmaster.{primary_domain}. ( - __SERIAL__ ; serial number - 7200 ; Refresh (secondary nameserver update interval) - 86400 ; Retry (when refresh fails, how often to try again) - 1209600 ; Expire (when refresh fails, how long secondary nameserver will keep records around anyway) - 86400 ; Negative TTL (how long negative responses are cached) - ) +@ IN SOA {primary_dns}. hostmaster.{primary_domain}. ( + __SERIAL__ ; serial number + {refresh} ; Refresh (secondary nameserver update interval) + {retry} ; Retry (when refresh fails, how often to try again) + {expire} ; Expire (when refresh fails, how long secondary nameserver will keep records around anyway) + {negttl} ; Negative TTL (how long negative responses are cached) + ) """ + # Default ttl values, following recomendations from zonemaster.iis.se + p_defttl = "1d" + p_refresh = "4h" + p_retry = "1h" + p_expire = "14d" + p_negttl = "12h" + + # Shorten dns ttl if file exists. Use before moving domains, changing secondary dns servers etc + if os.path.exists("/etc/forceshortdnsttl"): + with open("/etc/forceshortdnsttl") as f: + for line in f: + if line.strip() == domain or line.strip() == "forceshortdnsttl": + # Override the ttl values + p_defttl = "5m" + p_refresh = "30m" + p_retry = "5m" + p_expire = "1d" + p_negttl = "5m" + break + + primary_dns = "ns1." + env["PRIMARY_HOSTNAME"] + + # Obtain the secondary nameserver list + additional_records = list(get_custom_dns_config(env)) + secondary_ns_list = get_secondary_dns(additional_records, mode="NS") + + # Using hidden master for a domain if it is configured + if os.path.exists("/etc/usehiddenmasterdns") and len(secondary_ns_list) > 1: + with open("/etc/usehiddenmasterdns") as f: + for line in f: + if line.strip() == domain or line.strip() == "usehiddenmasterdns": + primary_dns = secondary_ns_list[0] + break + # Replace replacement strings. - zone = zone.format(domain=domain, primary_domain=env["PRIMARY_HOSTNAME"]) + zone = zone.format(domain=domain, primary_dns=primary_dns, primary_domain=env["PRIMARY_HOSTNAME"], defttl=p_defttl, + refresh=p_refresh, retry=p_retry, expire=p_expire, negttl=p_negttl) # Add records. for subdomain, querytype, value, explanation in records: @@ -620,7 +681,7 @@ def dnssec_choose_algo(domain, env): # A variety of algorithms are supported for .fund. This # is preferred. # Gandi tells me that .be does not support RSASHA1-NSEC3-SHA1 - # Nic.lv does not support RSASHA1-NSEC3-SHA1 for .lv tld's + # Nic.lv does not support RSASHA1-NSEC3-SHA1 for .lv tld's return "RSASHA256" # For any domain we were able to sign before, don't change the algorithm @@ -1011,7 +1072,7 @@ def get_custom_dns_records(custom_dns, qname, rtype): def build_recommended_dns(env): ret = [] for (domain, zonefile, records) in build_zones(env): - # remove records that we don't dislay + # remove records that we don't display records = [r for r in records if r[3] is not False] # put Required at the top, then Recommended, then everythiing else diff --git a/management/status_checks.py b/management/status_checks.py index 38bea752..187b640e 100755 --- a/management/status_checks.py +++ b/management/status_checks.py @@ -505,7 +505,17 @@ def check_dns_zone(domain, env, output, dns_zonefiles): secondary_ns = custom_secondary_ns or ["ns2." + env['PRIMARY_HOSTNAME']] existing_ns = query_dns(domain, "NS") + correct_ns = "; ".join(sorted(["ns1." + env['PRIMARY_HOSTNAME']] + secondary_ns)) + + # Take hidden master dns into account, the mail-in-a-box is not known as nameserver in that case + if os.path.exists("/etc/usehiddenmasterdns") and len(secondary_ns) > 1: + with open("/etc/usehiddenmasterdns") as f: + for line in f: + if line.strip() == domain or line.strip() == "usehiddenmasterdns": + correct_ns = "; ".join(sorted(secondary_ns)) + break + ip = query_dns(domain, "A") probably_external_dns = False