Просмотр исходного кода

Add support for DNSSEC (#2938)

* Solve issues with DNSKEY in v-add-dns-record


Bug in v-add-dns-record


Fix


A new NS DNSKEY Mix up


Don't add " 


Fix error 


Fix few typos

* Add support for DS record

* Apply changes to user account

Bind need write access to the folder where .db file is stored

* Add support for DS  type and allow . in common name

* Add support for DNSSEC

* Remove hardcoded domain

* Fix permission issues

* Make sure DS record is last and fix small issues

* Add option to enable existing DNS domain and clean up everything

* Get public key

Need to improved to support json

* Don't add DS records

* Rebuild on changes

* Update rebuild.sh

* Add rebuild.sh

* Remove non needed lines

* Fix error

* Add support for zonetransfer but Hestia create the slave record

* Fix error

* Fix error

* Add new options to v-insert-dns-domain

* Solve issue with remote creation

* Update error

* Adjust spacing

* Remove double space

* Add inline signing

* Update some other scripts that might use v-insert-domain

* Check if DNS-CLUSTER is set to yes and not if exists

* Fix issues with IDN domains

* Fix error

* Execute pipe before continue

* Fix issue in sync-dns-cluster breaking everything

* DNS_CLUSTER_SYSTEM caused issues with DNS_CLUSTER

* Fixed an issue with rebuild and key is 4 digits long instead of 5

* Update v-list-dns-domain to include DNSSEC

* Add more information

* Add UI interface

* Fix bug in v-delete-dns-domain

When deleting DNS domain it doesn't delete the keys

* Backup DNSSEC keys

* Fix restore

* Include DS record also

* Update from element

* Add missing  <div class="form-check">

Co-authored-by: Raphael <rs@scit.ch>
Jaap Marcus 3 лет назад
Родитель
Сommit
bc4a07eb9a

+ 13 - 24
bin/v-add-dns-domain

@@ -27,6 +27,7 @@ ns6=$9
 ns7=${10}
 ns7=${10}
 ns8=${11}
 ns8=${11}
 restart=${12}
 restart=${12}
+dnssec=${13}
 
 
 # Includes
 # Includes
 # shellcheck source=/etc/hestiacp/hestia.conf
 # shellcheck source=/etc/hestiacp/hestia.conf
@@ -35,6 +36,8 @@ source /etc/hestiacp/hestia.conf
 source $HESTIA/func/main.sh
 source $HESTIA/func/main.sh
 # shellcheck source=/usr/local/hestia/func/domain.sh
 # shellcheck source=/usr/local/hestia/func/domain.sh
 source $HESTIA/func/domain.sh
 source $HESTIA/func/domain.sh
+# shellcheck source=/usr/local/hestia/func/rebuild.sh
+source $HESTIA/func/rebuild.sh
 # load config file
 # load config file
 source_conf "$HESTIA/conf/hestia.conf"
 source_conf "$HESTIA/conf/hestia.conf"
 
 
@@ -70,6 +73,10 @@ if [ -n "$restart" ]; then
     is_format_valid 'restart'
     is_format_valid 'restart'
 fi
 fi
 
 
+if [ -n "$dnssec" ]; then
+    is_boolean_format_valid "$dnssec" 'dnssec'
+fi
+
 is_package_full 'DNS_DOMAINS'
 is_package_full 'DNS_DOMAINS'
 template=$(get_user_value '$DNS_TEMPLATE')
 template=$(get_user_value '$DNS_TEMPLATE')
 is_dns_template_valid "$template"
 is_dns_template_valid "$template"
@@ -152,6 +159,9 @@ fi
 if [ -z "$ns8" ]; then
 if [ -z "$ns8" ]; then
     template_data=$(echo "$template_data" |grep -v %ns8%)
     template_data=$(echo "$template_data" |grep -v %ns8%)
 fi
 fi
+if [ -z "$dnssec" ]; then
+    dnssec="no"
+fi
 
 
 # Generating timestamp
 # Generating timestamp
 time_n_date=$(date +'%T %F')
 time_n_date=$(date +'%T %F')
@@ -180,36 +190,15 @@ records="$(wc -l $USER_DATA/dns/$domain.conf |cut -f 1 -d ' ')"
 # Adding dns.conf record
 # Adding dns.conf record
 dns_rec="DOMAIN='$domain' IP='$ip' TPL='$template' TTL='$ttl' EXP='$exp'"
 dns_rec="DOMAIN='$domain' IP='$ip' TPL='$template' TTL='$ttl' EXP='$exp'"
 dns_rec="$dns_rec SOA='$soa' SERIAL='$serial' SRC='' RECORDS='$records'"
 dns_rec="$dns_rec SOA='$soa' SERIAL='$serial' SRC='' RECORDS='$records'"
-dns_rec="$dns_rec SUSPENDED='no' TIME='$time' DATE='$date'"
+dns_rec="$dns_rec DNSSEC='$dnssec' KEY='' SLAVE='no' MASTER='' SUSPENDED='no' TIME='$time' DATE='$date'"
 
 
 echo "$dns_rec" >> $USER_DATA/dns.conf
 echo "$dns_rec" >> $USER_DATA/dns.conf
 chmod 660 $USER_DATA/dns.conf
 chmod 660 $USER_DATA/dns.conf
 
 
-# Creating system configs
-if [[ "$DNS_SYSTEM" =~ named|bind ]]; then
-    if [ -e '/etc/named.conf' ]; then
-        dns_conf='/etc/named.conf'
-        dns_group='named'
-    else
-        dns_conf='/etc/bind/named.conf'
-        dns_group='bind'
-    fi
-
-    # Adding zone in named.conf
-    named="zone \"$domain_idn\" {type master; file"
-    named="$named \"$HOMEDIR/$user/conf/dns/$domain.db\";};"
-    echo "$named" >> $dns_conf
-
-    # Updating domain dns zone
-    update_domain_zone
-
-    # Changing permissions
-    chmod 640 $HOMEDIR/$user/conf/dns/$domain.db
-    chown root:$dns_group $HOMEDIR/$user/conf/dns/$domain.db
-fi
+rebuild_dns_domain_conf
 
 
 # Updating dns-cluster queue
 # Updating dns-cluster queue
-if [ -n "$DNS_CLUSTER" ]; then
+if [ "$DNS_CLUSTER"  = "yes" ]; then
     cmd="$BIN/v-add-remote-dns-domain $user $domain yes"
     cmd="$BIN/v-add-remote-dns-domain $user $domain yes"
     echo "$cmd" >> $HESTIA/data/queue/dns-cluster.pipe
     echo "$cmd" >> $HESTIA/data/queue/dns-cluster.pipe
 fi
 fi

+ 15 - 10
bin/v-add-dns-record

@@ -38,6 +38,8 @@ source /etc/hestiacp/hestia.conf
 source $HESTIA/func/main.sh
 source $HESTIA/func/main.sh
 # shellcheck source=/usr/local/hestia/func/domain.sh
 # shellcheck source=/usr/local/hestia/func/domain.sh
 source $HESTIA/func/domain.sh
 source $HESTIA/func/domain.sh
+# shellcheck source=/usr/local/hestia/func/rebuild.sh
+source $HESTIA/func/rebuild.sh
 # load config file
 # load config file
 source_conf "$HESTIA/conf/hestia.conf"
 source_conf "$HESTIA/conf/hestia.conf"
 
 
@@ -47,29 +49,32 @@ if [ "$rtype" != 'MX' ] && [ "$rtype" != 'SRV' ]; then
 fi
 fi
 
 
 # Add trailing dot at the end of NS/CNAME/MX/PTR/SRV record
 # Add trailing dot at the end of NS/CNAME/MX/PTR/SRV record
-if [[ $rtype =~ NS|CNAME|MX|PTR|SRV ]]; then
+if [[ $rtype =~ ^NS|CNAME|MX|PTR|SRV ]]; then
     trailing_dot=$(echo $dvalue | grep "\.$")
     trailing_dot=$(echo $dvalue | grep "\.$")
     if [ -z "$trailing_dot" ]; then
     if [ -z "$trailing_dot" ]; then
         dvalue="$dvalue."
         dvalue="$dvalue."
     fi
     fi
 fi
 fi
 
 
-if [[ $rtype =~ NS|CNAME|MX|PTR|SRV ]]; then
+if [[ $rtype =~ ^NS|CNAME|MX|PTR|SRV ]]; then
     dvalue=$(idn2 --quiet  "$dvalue" )
     dvalue=$(idn2 --quiet  "$dvalue" )
     record=$(idn2 --quiet  "$record" )
     record=$(idn2 --quiet  "$record" )
 fi
 fi
 
 
 # Cleanup quotes on dvalue
 # Cleanup quotes on dvalue
 # - [CAA] records will be left unchanged
 # - [CAA] records will be left unchanged
-# - [SRV] will be  stripped of double quotes even when  containg spaces
+# - [SRV] will be  stripped of double quotes even when  containing spaces
+# - [DNSKEY] will be  stripped of double quotes even when  containing spaces
 # - Rest of record types will be striped of quotes and the final string
 # - Rest of record types will be striped of quotes and the final string
-#   will be enclosed in double quotes if  containg spaces or semicolons 
+#   will be enclosed in double quotes if containing spaces or semicolons 
 
 
 if [ "$rtype" != "CAA" ]; then
 if [ "$rtype" != "CAA" ]; then
     dvalue=${dvalue//\"/}
     dvalue=${dvalue//\"/}
-
-    if [ "$rtype" != 'SRV' ] && [[ "$dvalue" =~ [\;[:space:]] ]]; then
-        dvalue='"'"$dvalue"'"'
+    # Add support for DS key
+    if [ "$rtype" != "DNSKEY" ] && [ "$rtype" != "DS" ] ; then 
+        if [ "$rtype" != 'SRV' ] && [[ "$dvalue" =~ [\;[:space:]] ]]; then
+            dvalue='"'"$dvalue"'"'
+        fi
     fi
     fi
 fi
 fi
 
 
@@ -129,12 +134,12 @@ sort_dns_records
 
 
 # Updating zone
 # Updating zone
 if [[ "$DNS_SYSTEM" =~ named|bind ]]; then
 if [[ "$DNS_SYSTEM" =~ named|bind ]]; then
-    update_domain_serial
-    update_domain_zone
+    # Do full rebuild due DNS SEC
+    rebuild_dns_domain_conf
 fi
 fi
 
 
 # Updating dns-cluster queue
 # Updating dns-cluster queue
-if [ -n "$DNS_CLUSTER" ]; then
+if [ "$DNS_CLUSTER"  = "yes" ]; then
     # Check for first sync
     # Check for first sync
     dlock=$(grep "domain $user $domain" $HESTIA/data/queue/dns-cluster.pipe)
     dlock=$(grep "domain $user $domain" $HESTIA/data/queue/dns-cluster.pipe)
     if [ -z "$dlock" ]; then
     if [ -z "$dlock" ]; then

+ 31 - 16
bin/v-add-remote-dns-domain

@@ -69,22 +69,37 @@ for cluster in $(grep "SUSPENDED='no'" $HESTIA/conf/dns-cluster.conf); do
     # Parsing domain parameters
     # Parsing domain parameters
     parse_object_kv_list "$str"
     parse_object_kv_list "$str"
 
 
-    # Syncing domain data
-    cluster_cmd v-insert-dns-domain $DNS_USER "$str" $HOSTNAME $flush 'no'
-    check_result $? "$HOST connection failed" "$E_CONNECT"
-
-    # Syncing domain records
-    tmp_file="/tmp/vst-sync.$DOMAIN"
-    cluster_file $USER_DATA/dns/$DOMAIN.conf $tmp_file
-    check_result $? "$HOST connection failed" "$E_CONNECT"
-
-    # Inserting synced records
-    cluster_cmd v-insert-dns-records $DNS_USER $DOMAIN $tmp_file 'no'
-    check_result $? "$HOST connection failed" "$E_CONNECT"
-
-    # Rebuilding dns zone
-    cluster_cmd v-rebuild-dns-domain $DNS_USER $domain 'yes' 'no'
-    check_result $? "$HOST connection failed" "$E_CONNECT"
+    if [ "$DNS_CLUSTER_SYSTEM" = "zone" ]; then
+        str=$(echo "$str" | sed "s/SLAVE='no'/SLAVE='yes'/g");
+        ip=$($BIN/v-list-sys-ips plain | cut -f1);
+        str=$(echo "$str" | sed "s/MASTER='*'/MASTER='$ip'/g");
+            
+        # Syncing domain data
+        cluster_cmd v-insert-dns-domain $DNS_USER "$str" $HOSTNAME $flush 'no'
+        check_result $? "$HOST connection failed" "$E_CONNECT"
+        
+        cluster_cmd v-rebuild-dns-domain $DNS_USER $domain 'yes' 'no'
+        check_result $? "$HOST connection failed" "$E_CONNECT"
+        
+        rndc notify $domain  > /dev/null 2>&1
+    else
+        # Syncing domain data
+        cluster_cmd v-insert-dns-domain $DNS_USER "$str" $HOSTNAME $flush 'no'
+        check_result $? "$HOST connection failed" "$E_CONNECT"
+    
+        # Syncing domain records
+        tmp_file="/tmp/vst-sync.$DOMAIN"
+        cluster_file $USER_DATA/dns/$DOMAIN.conf $tmp_file
+        check_result $? "$HOST connection failed" "$E_CONNECT"
+    
+        # Inserting synced records
+        cluster_cmd v-insert-dns-records $DNS_USER $DOMAIN $tmp_file 'no'
+        check_result $? "$HOST connection failed" "$E_CONNECT"
+    
+        # Rebuilding dns zone
+        cluster_cmd v-rebuild-dns-domain $DNS_USER $domain 'yes' 'no'
+        check_result $? "$HOST connection failed" "$E_CONNECT"
+    fi
 done
 done
 
 
 #----------------------------------------------------------#
 #----------------------------------------------------------#

+ 1 - 1
bin/v-add-remote-dns-host

@@ -92,7 +92,7 @@ echo "$str" >> $HESTIA/conf/dns-cluster.conf
 chmod 660 $HESTIA/conf/dns-cluster.conf
 chmod 660 $HESTIA/conf/dns-cluster.conf
 
 
 # Enabling DNS_CLUSTER
 # Enabling DNS_CLUSTER
-if [ -z "$(grep DNS_CLUSTER $HESTIA/conf/hestia.conf)" ]; then
+if [ -z "$(grep DNS_CLUSTER= $HESTIA/conf/hestia.conf)" ]; then
     sed -i "s/^STATS_/DNS_CLUSTER='yes'\nSTATS_/g" $HESTIA/conf/hestia.conf
     sed -i "s/^STATS_/DNS_CLUSTER='yes'\nSTATS_/g" $HESTIA/conf/hestia.conf
 else
 else
     sed -i "s/DNS_CLUSTER=.*/DNS_CLUSTER='yes'/g" $HESTIA/conf/hestia.conf
     sed -i "s/DNS_CLUSTER=.*/DNS_CLUSTER='yes'/g" $HESTIA/conf/hestia.conf

+ 9 - 2
bin/v-add-remote-dns-record

@@ -63,9 +63,13 @@ for cluster in $(grep "SUSPENDED='no'" $HESTIA/conf/dns-cluster.conf); do
     
     
     # Parsing remote host parameters
     # Parsing remote host parameters
     parse_object_kv_list "$cluster"
     parse_object_kv_list "$cluster"
-
+    
     # Syncing serial
     # Syncing serial
     str=$(grep "DOMAIN='$domain'" $USER_DATA/dns.conf)
     str=$(grep "DOMAIN='$domain'" $USER_DATA/dns.conf)
+    # Parsing domain parameters
+    parse_object_kv_list "$str"
+    
+    if [ "$DNS_CLUSTER_SYSTEM" != "zone" ]; then
     cluster_cmd v-insert-dns-domain $DNS_USER "$str" $HOSTNAME 'domain' 'no'
     cluster_cmd v-insert-dns-domain $DNS_USER "$str" $HOSTNAME 'domain' 'no'
     check_result $? "$HOST connection failed (soa sync)" "$E_CONNECT"
     check_result $? "$HOST connection failed (soa sync)" "$E_CONNECT"
 
 
@@ -77,9 +81,12 @@ for cluster in $(grep "SUSPENDED='no'" $HESTIA/conf/dns-cluster.conf); do
     # Rebuilding dns zone
     # Rebuilding dns zone
     cluster_cmd v-rebuild-dns-domain $DNS_USER $domain 'yes' 'no'
     cluster_cmd v-rebuild-dns-domain $DNS_USER $domain 'yes' 'no'
     check_result $? "$HOST connection failed (rebuild)" "$E_CONNECT"
     check_result $? "$HOST connection failed (rebuild)" "$E_CONNECT"
-
+    fi
 done
 done
 
 
+if [ "$DNS_CLUSTER_SYSTEM" != "zone" ]; then
+    rndc notify $domain  > /dev/null 2>&1
+fi
 #----------------------------------------------------------#
 #----------------------------------------------------------#
 #                       Hestia                             #
 #                       Hestia                             #
 #----------------------------------------------------------#
 #----------------------------------------------------------#

+ 7 - 1
bin/v-add-user

@@ -117,8 +117,14 @@ if [ -n "$MAIL_SYSTEM" ]; then
 fi
 fi
 
 
 if [ -n "$DNS_SYSTEM" ]; then
 if [ -n "$DNS_SYSTEM" ]; then
+    if [ "$DNS_SYSTEM" = 'named' ]; then
+        dns_group='named'
+    else
+        dns_group='bind'
+    fi
     mkdir $HOMEDIR/$user/conf/dns
     mkdir $HOMEDIR/$user/conf/dns
-    chmod 751 $HOMEDIR/$user/conf/dns
+    chmod 771 $HOMEDIR/$user/conf/dns
+    chown root:$dns_group $HOMEDIR/$user/conf/dns
 fi 
 fi 
 
 
 # Create default writeable folders
 # Create default writeable folders

+ 7 - 0
bin/v-backup-user

@@ -419,6 +419,7 @@ if [ -n "$DNS_SYSTEM" ] && [ "$DNS" != '*' ]; then
 
 
         # Building directory tree
         # Building directory tree
         mkdir -p $tmpdir/dns/$domain/conf
         mkdir -p $tmpdir/dns/$domain/conf
+        mkdir -p $tmpdir/dns/$domain/conf/keys
         mkdir -p $tmpdir/dns/$domain/hestia
         mkdir -p $tmpdir/dns/$domain/hestia
 
 
         # Backup dns.conf
         # Backup dns.conf
@@ -431,6 +432,12 @@ if [ -n "$DNS_SYSTEM" ] && [ "$DNS" != '*' ]; then
         if [ "$DNS_SYSTEM" != 'remote' ]; then
         if [ "$DNS_SYSTEM" != 'remote' ]; then
             cp $HOMEDIR/$user/conf/dns/$domain.db conf/$domain.db
             cp $HOMEDIR/$user/conf/dns/$domain.db conf/$domain.db
         fi
         fi
+        # Backup DNSSEC public and private key if enabled
+        dnssec=$(grep "DOMAIN='$domain'" $USER_DATA/dns.conf |grep "DNSSEC='yes'")
+        if [ -n "$dnssec" ]; then
+            format_domain_idn
+            cp $USER_DATA/keys/K$domain_idn*.* $tmpdir/dns/$domain/conf/keys
+        fi
     done
     done
 
 
     # Print total
     # Print total

+ 93 - 0
bin/v-change-dns-domain-dnssec

@@ -0,0 +1,93 @@
+#!/bin/bash
+# info: change dns domain dnssec status
+# options: USER DOMAIN STATUS
+#
+# example: v-change-dns-domain-status admin domain.pp.ua yes
+
+#----------------------------------------------------------#
+#                Variables & Functions                     #
+#----------------------------------------------------------#
+
+# Argument definition
+user=$1
+domain=$2
+domain_idn=$2
+status=$3
+
+# Includes
+# shellcheck source=/etc/hestiacp/hestia.conf
+source /etc/hestiacp/hestia.conf
+# shellcheck source=/usr/local/hestia/func/main.sh
+source $HESTIA/func/main.sh
+# shellcheck source=/usr/local/hestia/func/rebuild.sh
+source $HESTIA/func/rebuild.sh
+# shellcheck source=/usr/local/hestia/func/domain.sh
+source $HESTIA/func/domain.sh
+# load config file
+source_conf "$HESTIA/conf/hestia.conf"
+
+# Additional argument formatting
+format_domain
+format_domain_idn
+
+#----------------------------------------------------------#
+#                    Verifications                         #
+#----------------------------------------------------------#
+
+check_args '3' "$#" 'USER DOMAIN STATUS'
+is_format_valid 'user' 'domain' ''
+is_system_enabled "$DNS_SYSTEM" 'DNS_SYSTEM'
+is_object_valid 'user' 'USER' "$user"
+is_object_unsuspended 'user' 'USER' "$user"
+is_object_valid 'dns' 'DOMAIN' "$domain"
+is_object_unsuspended 'dns' 'DOMAIN' "$domain"
+
+if [ -n "$status" ]; then
+    is_boolean_format_valid "$status" 'status'
+fi
+
+# Perform verification if read-only mode is enabled
+check_hestia_demo_mode
+
+#----------------------------------------------------------#
+#                       Action                             #
+#----------------------------------------------------------#
+
+if [ -f "$HESTIA/data/queue/dns-cluster.pipe" ]; then 
+    bash $HESTIA/data/queue/dns-cluster.pipe
+fi
+
+# Changing exp
+update_object_value 'dns' 'DOMAIN' "$domain" '$DNSSEC' "$status"
+
+# Rebuild DNS config
+
+rebuild_dns_domain_conf
+
+if [ $status = "no" ]; then
+    update_object_value 'dns' 'DOMAIN' "$domain" '$KEY' ""
+    # Delete existing keys
+    rm -fr  $HOMEDIR/$user/conf/dns/$domain.db.*
+    rm -fr /var/cache/bind/K$domain_idn.*
+    rm -fr $USER_DATA/keys/K$domain_idn.*
+fi
+
+# Updating dns-cluster queue
+if [ "$DNS_CLUSTER"  = "yes" ]; then
+    # Check for first sync
+    dlock=$(grep "domain $user $domain" $HESTIA/data/queue/dns-cluster.pipe)
+    if [ -z "$dlock" ]; then
+        cmd="$BIN/v-add-remote-dns-domain $user $domain yes"
+        echo "$cmd" >> $HESTIA/data/queue/dns-cluster.pipe
+    fi
+fi
+
+#----------------------------------------------------------#
+#                       Hestia                             #
+#----------------------------------------------------------#
+
+# Logging
+$BIN/v-log-action "$user" "Info" "DNS" "Updated DNS SOA expiration date (Domain: $domain, Value: $exp)."
+log_event "$OK" "$ARGUMENTS"
+
+exit

+ 1 - 1
bin/v-change-dns-domain-exp

@@ -53,7 +53,7 @@ check_hestia_demo_mode
 update_object_value 'dns' 'DOMAIN' "$domain" '$EXP' "$exp"
 update_object_value 'dns' 'DOMAIN' "$domain" '$EXP' "$exp"
 
 
 # Updating dns-cluster queue
 # Updating dns-cluster queue
-if [ -n "$DNS_CLUSTER" ]; then
+if [ "$DNS_CLUSTER"  = "yes" ]; then
     # Check for first sync
     # Check for first sync
     dlock=$(grep "domain $user $domain" $HESTIA/data/queue/dns-cluster.pipe)
     dlock=$(grep "domain $user $domain" $HESTIA/data/queue/dns-cluster.pipe)
     if [ -z "$dlock" ]; then
     if [ -z "$dlock" ]; then

+ 4 - 3
bin/v-change-dns-domain-ip

@@ -24,6 +24,8 @@ source /etc/hestiacp/hestia.conf
 source $HESTIA/func/main.sh
 source $HESTIA/func/main.sh
 # shellcheck source=/usr/local/hestia/func/domain.sh
 # shellcheck source=/usr/local/hestia/func/domain.sh
 source $HESTIA/func/domain.sh
 source $HESTIA/func/domain.sh
+# shellcheck source=/usr/local/hestia/func/rebuild.sh
+source $HESTIA/func/rebuild.sh
 # load config file
 # load config file
 source_conf "$HESTIA/conf/hestia.conf"
 source_conf "$HESTIA/conf/hestia.conf"
 
 
@@ -63,12 +65,11 @@ sed -i "s/$old/$ip/g" $USER_DATA/dns/$domain.conf
 
 
 # Updating zone
 # Updating zone
 if [[ "$DNS_SYSTEM" =~ named|bind ]]; then
 if [[ "$DNS_SYSTEM" =~ named|bind ]]; then
-    update_domain_serial
-    update_domain_zone
+    rebuild_dns_domain_conf
 fi
 fi
 
 
 # Updating dns-cluster queue
 # Updating dns-cluster queue
-if [ -n "$DNS_CLUSTER" ]; then
+if [ "$DNS_CLUSTER"  = "yes" ]; then
     # Check for first sync
     # Check for first sync
     dlock=$(grep "domain $user $domain" $HESTIA/data/queue/dns-cluster.pipe)
     dlock=$(grep "domain $user $domain" $HESTIA/data/queue/dns-cluster.pipe)
     if [ -z "$dlock" ]; then
     if [ -z "$dlock" ]; then

+ 4 - 3
bin/v-change-dns-domain-soa

@@ -25,6 +25,8 @@ source /etc/hestiacp/hestia.conf
 source $HESTIA/func/main.sh
 source $HESTIA/func/main.sh
 # shellcheck source=/usr/local/hestia/func/domain.sh
 # shellcheck source=/usr/local/hestia/func/domain.sh
 source $HESTIA/func/domain.sh
 source $HESTIA/func/domain.sh
+# shellcheck source=/usr/local/hestia/func/rebuild.sh
+source $HESTIA/func/rebuild.sh
 # load config file
 # load config file
 source_conf "$HESTIA/conf/hestia.conf"
 source_conf "$HESTIA/conf/hestia.conf"
 
 
@@ -57,12 +59,11 @@ update_object_value 'dns' 'DOMAIN' "$domain" '$SOA' "$soa"
 
 
 # Updating zone
 # Updating zone
 if [[ "$DNS_SYSTEM" =~ named|bind ]]; then
 if [[ "$DNS_SYSTEM" =~ named|bind ]]; then
-    update_domain_serial
-    update_domain_zone
+    rebuild_dns_domain_conf
 fi
 fi
 
 
 # Updating dns-cluster queue
 # Updating dns-cluster queue
-if [ -n "$DNS_CLUSTER" ]; then
+if [ "$DNS_CLUSTER"  = "yes" ]; then
     # Check for first sync
     # Check for first sync
     dlock=$(grep "domain $user $domain" $HESTIA/data/queue/dns-cluster.pipe)
     dlock=$(grep "domain $user $domain" $HESTIA/data/queue/dns-cluster.pipe)
     if [ -z "$dlock" ]; then
     if [ -z "$dlock" ]; then

+ 4 - 3
bin/v-change-dns-domain-tpl

@@ -26,6 +26,8 @@ source /etc/hestiacp/hestia.conf
 source $HESTIA/func/main.sh
 source $HESTIA/func/main.sh
 # shellcheck source=/usr/local/hestia/func/domain.sh
 # shellcheck source=/usr/local/hestia/func/domain.sh
 source $HESTIA/func/domain.sh
 source $HESTIA/func/domain.sh
+# shellcheck source=/usr/local/hestia/func/rebuild.sh
+source $HESTIA/func/rebuild.sh
 # load config file
 # load config file
 source_conf "$HESTIA/conf/hestia.conf"
 source_conf "$HESTIA/conf/hestia.conf"
 
 
@@ -131,12 +133,11 @@ fi
 
 
 # Updating zone
 # Updating zone
 if [[ "$DNS_SYSTEM" =~ named|bind ]]; then
 if [[ "$DNS_SYSTEM" =~ named|bind ]]; then
-    update_domain_serial
-    update_domain_zone
+    rebuild_dns_domain_conf
 fi
 fi
 
 
 # Updating dns-cluster queue
 # Updating dns-cluster queue
-if [ ! -z "$DNS_CLUSTER" ]; then
+if [ "$DNS_CLUSTER"  = "yes" ]; then
     # Check for first sync
     # Check for first sync
     dlock=$(grep "domain $user $domain" $HESTIA/data/queue/dns-cluster.pipe)
     dlock=$(grep "domain $user $domain" $HESTIA/data/queue/dns-cluster.pipe)
     if [ -z "$dlock" ]; then
     if [ -z "$dlock" ]; then

+ 4 - 3
bin/v-change-dns-domain-ttl

@@ -24,6 +24,8 @@ source /etc/hestiacp/hestia.conf
 source $HESTIA/func/main.sh
 source $HESTIA/func/main.sh
 # shellcheck source=/usr/local/hestia/func/domain.sh
 # shellcheck source=/usr/local/hestia/func/domain.sh
 source $HESTIA/func/domain.sh
 source $HESTIA/func/domain.sh
+# shellcheck source=/usr/local/hestia/func/rebuild.sh
+source $HESTIA/func/rebuild.sh
 # load config file
 # load config file
 source_conf "$HESTIA/conf/hestia.conf"
 source_conf "$HESTIA/conf/hestia.conf"
 
 
@@ -56,12 +58,11 @@ update_object_value 'dns' 'DOMAIN' "$domain" '$TTL' "$ttl"
 
 
 # Updating zone
 # Updating zone
 if [[ "$DNS_SYSTEM" =~ named|bind ]]; then
 if [[ "$DNS_SYSTEM" =~ named|bind ]]; then
-    update_domain_serial
-    update_domain_zone
+    rebuild_dns_domain_conf
 fi
 fi
 
 
 # Updating dns-cluster queue
 # Updating dns-cluster queue
-if [ -n "$DNS_CLUSTER" ]; then
+if [ "$DNS_CLUSTER"  = "yes" ]; then
     # Check for first sync
     # Check for first sync
     dlock=$(grep "domain $user $domain" $HESTIA/data/queue/dns-cluster.pipe)
     dlock=$(grep "domain $user $domain" $HESTIA/data/queue/dns-cluster.pipe)
     if [ -z "$dlock" ]; then
     if [ -z "$dlock" ]; then

+ 4 - 3
bin/v-change-dns-record

@@ -29,6 +29,8 @@ source /etc/hestiacp/hestia.conf
 source $HESTIA/func/main.sh
 source $HESTIA/func/main.sh
 # shellcheck source=/usr/local/hestia/func/domain.sh
 # shellcheck source=/usr/local/hestia/func/domain.sh
 source $HESTIA/func/domain.sh
 source $HESTIA/func/domain.sh
+# shellcheck source=/usr/local/hestia/func/rebuild.sh
+source $HESTIA/func/rebuild.sh
 # load config file
 # load config file
 source_conf "$HESTIA/conf/hestia.conf"
 source_conf "$HESTIA/conf/hestia.conf"
 
 
@@ -137,12 +139,11 @@ sort_dns_records
 
 
 # Updating zone
 # Updating zone
 if [[ "$DNS_SYSTEM" =~ named|bind ]]; then
 if [[ "$DNS_SYSTEM" =~ named|bind ]]; then
-    update_domain_serial
-    update_domain_zone
+    rebuild_dns_domain_conf
 fi
 fi
 
 
 # Updating dns-cluster queue
 # Updating dns-cluster queue
-if [ -n "$DNS_CLUSTER" ]; then
+if [ "$DNS_CLUSTER"  = "yes" ]; then
     # Check for first sync
     # Check for first sync
     dlock=$(grep "domain $user $domain" $HESTIA/data/queue/dns-cluster.pipe)
     dlock=$(grep "domain $user $domain" $HESTIA/data/queue/dns-cluster.pipe)
     if [ -z "$dlock" ]; then
     if [ -z "$dlock" ]; then

+ 4 - 3
bin/v-change-dns-record-id

@@ -25,6 +25,8 @@ source /etc/hestiacp/hestia.conf
 source $HESTIA/func/main.sh
 source $HESTIA/func/main.sh
 # shellcheck source=/usr/local/hestia/func/domain.sh
 # shellcheck source=/usr/local/hestia/func/domain.sh
 source $HESTIA/func/domain.sh
 source $HESTIA/func/domain.sh
+# shellcheck source=/usr/local/hestia/func/rebuild.sh
+source $HESTIA/func/rebuild.sh
 # load config file
 # load config file
 source_conf "$HESTIA/conf/hestia.conf"
 source_conf "$HESTIA/conf/hestia.conf"
 
 
@@ -62,12 +64,11 @@ sort_dns_records
 
 
 # Updating zone
 # Updating zone
 if [[ "$DNS_SYSTEM" =~ named|bind ]]; then
 if [[ "$DNS_SYSTEM" =~ named|bind ]]; then
-    update_domain_serial
-    update_domain_zone
+    rebuild_dns_domain_conf
 fi
 fi
 
 
 # Updating dns-cluster queue
 # Updating dns-cluster queue
-if [ -n "$DNS_CLUSTER" ]; then
+if [ "$DNS_CLUSTER"  = "yes" ]; then
     # Check for first sync
     # Check for first sync
     dlock=$(grep "domain $user $domain" $HESTIA/data/queue/dns-cluster.pipe)
     dlock=$(grep "domain $user $domain" $HESTIA/data/queue/dns-cluster.pipe)
     if [ -z "$dlock" ]; then
     if [ -z "$dlock" ]; then

+ 1 - 1
bin/v-change-domain-owner

@@ -162,7 +162,7 @@ if [ -n "$dns_data" ]; then
     rm -f $HOMEDIR/$owner/conf/dns/$domain.db
     rm -f $HOMEDIR/$owner/conf/dns/$domain.db
 
 
     # Resync dns cluster
     # Resync dns cluster
-    if [ -n "$DNS_CLUSTER" ]; then
+    if [ "$DNS_CLUSTER"  = "yes" ]; then
         $BIN/v-sync-dns-cluster
         $BIN/v-sync-dns-cluster
     fi
     fi
 fi
 fi

+ 14 - 2
bin/v-change-remote-dns-domain-exp

@@ -52,8 +52,20 @@ for cluster in $(grep "SUSPENDED='no'" $HESTIA/conf/dns-cluster.conf); do
 
 
     # Syncing domain
     # Syncing domain
     str=$(grep "DOMAIN='$domain'" $USER_DATA/dns.conf)
     str=$(grep "DOMAIN='$domain'" $USER_DATA/dns.conf)
-    cluster_cmd v-insert-dns-domain "$DNS_USER" "$str" "$HOSTNAME" 'no'
-    check_result $? "$HOST connection failed (exp insert)" "$E_CONNECT"
+    if [ "$DNS_CLUSTER_SYSTEM" = "zone" ]; then
+        str=$(echo "$str" | sed "s/SLAVE='no'/SLAVE='yes'/g");
+        ip=$($BIN/v-list-sys-ips plain | cut -f1);
+        str=$(echo "$str" | sed "s/MASTER='*'/MASTER='$ip'/g");
+            
+        # Syncing domain data
+        cluster_cmd v-insert-dns-domain $DNS_USER "$str" $HOSTNAME $flush 'no'
+        check_result $? "$HOST connection failed" "$E_CONNECT"
+        
+        rndc notify $domain  > /dev/null 2>&1
+    else
+        cluster_cmd v-insert-dns-domain "$DNS_USER" "$str" "$HOSTNAME" 'no'
+        check_result $? "$HOST connection failed (exp insert)" "$E_CONNECT"
+    fi
 
 
 done
 done
 
 

+ 24 - 10
bin/v-change-remote-dns-domain-soa

@@ -51,16 +51,30 @@ for cluster in $(grep "SUSPENDED='no'" $HESTIA/conf/dns-cluster.conf); do
     
     
     # Parsing remote host parameters
     # Parsing remote host parameters
     parse_object_kv_list "$cluster"
     parse_object_kv_list "$cluster"
-
-    # Syncing SOA
-    str=$(grep "DOMAIN='$domain'" $USER_DATA/dns.conf)
-    cluster_cmd v-insert-dns-domain "$DNS_USER" "$str" "$HOSTNAME" 'domain' 'no'
-    check_result $? "$HOST connection failed (sync)" "$E_CONNECT"
-
-    # Rebuilding dns zone
-    cluster_cmd v-rebuild-dns-domain "$DNS_USER" "$domain" 'yes' 'no'
-    check_result $? "$HOST connection failed (rebuild)" "$E_CONNECT"
-
+    
+    if [ "$DNS_CLUSTER_SYSTEM" = "zone" ]; then
+        str=$(echo "$str" | sed "s/SLAVE='no'/SLAVE='yes'/g");
+        ip=$($BIN/v-list-sys-ips plain | cut -f1);
+        str=$(echo "$str" | sed "s/MASTER='*'/MASTER='$ip'/g");
+            
+        # Syncing domain data
+        cluster_cmd v-insert-dns-domain $DNS_USER "$str" $HOSTNAME $flush 'no'
+        check_result $? "$HOST connection failed" "$E_CONNECT"
+        
+        cluster_cmd v-rebuild-dns-domain $DNS_USER $domain 'yes' 'no'
+        check_result $? "$HOST connection failed" "$E_CONNECT"
+        
+        rndc notify $domain  > /dev/null 2>&1
+    else
+        # Syncing SOA
+        str=$(grep "DOMAIN='$domain'" $USER_DATA/dns.conf)
+        cluster_cmd v-insert-dns-domain "$DNS_USER" "$str" "$HOSTNAME" 'domain' 'no'
+        check_result $? "$HOST connection failed (sync)" "$E_CONNECT"
+    
+        # Rebuilding dns zone
+        cluster_cmd v-rebuild-dns-domain "$DNS_USER" "$domain" 'yes' 'no'
+        check_result $? "$HOST connection failed (rebuild)" "$E_CONNECT"
+    fi
 done
 done
 
 
 #----------------------------------------------------------#
 #----------------------------------------------------------#

+ 21 - 7
bin/v-change-remote-dns-domain-ttl

@@ -54,13 +54,27 @@ for cluster in $(grep "SUSPENDED='no'" $HESTIA/conf/dns-cluster.conf); do
 
 
     # Syncing TTL
     # Syncing TTL
     str=$(grep "DOMAIN='$domain'" $USER_DATA/dns.conf)
     str=$(grep "DOMAIN='$domain'" $USER_DATA/dns.conf)
-    cluster_cmd v-insert-dns-domain "$DNS_USER" "$str" "$HOSTNAME" 'domain' 'no'
-    check_result $? "$HOST connection failed (sync)" "$E_CONNECT"
-
-    # Rebuilding dns zone
-    cluster_cmd v-rebuild-dns-domain "$DNS_USER" "$domain" 'yes' 'no'
-    check_result $? "$HOST connection failed (rebuild)" "$E_CONNECT"
-
+    if [ "$DNS_CLUSTER_SYSTEM" = "zone" ]; then
+        str=$(echo "$str" | sed "s/SLAVE='no'/SLAVE='yes'/g");
+        ip=$($BIN/v-list-sys-ips plain | cut -f1);
+        str=$(echo "$str" | sed "s/MASTER='*'/MASTER='$ip'/g");
+            
+        # Syncing domain data
+        cluster_cmd v-insert-dns-domain $DNS_USER "$str" $HOSTNAME $flush 'no'
+        check_result $? "$HOST connection failed" "$E_CONNECT"
+        
+        cluster_cmd v-rebuild-dns-domain $DNS_USER $domain 'yes' 'no'
+        check_result $? "$HOST connection failed" "$E_CONNECT"
+        
+        rndc notify $domain  > /dev/null 2>&1
+    else
+        cluster_cmd v-insert-dns-domain "$DNS_USER" "$str" "$HOSTNAME" 'domain' 'no'
+        check_result $? "$HOST connection failed (sync)" "$E_CONNECT"
+    
+        # Rebuilding dns zone
+        cluster_cmd v-rebuild-dns-domain "$DNS_USER" "$domain" 'yes' 'no'
+        check_result $? "$HOST connection failed (rebuild)" "$E_CONNECT"
+    fi
 done
 done
 
 
 #----------------------------------------------------------#
 #----------------------------------------------------------#

+ 13 - 1
bin/v-delete-dns-domain

@@ -30,6 +30,9 @@ source_conf "$HESTIA/conf/hestia.conf"
 #                    Verifications                         #
 #                    Verifications                         #
 #----------------------------------------------------------#
 #----------------------------------------------------------#
 
 
+format_domain
+format_domain_idn
+
 check_args '2' "$#" 'USER DOMAIN'
 check_args '2' "$#" 'USER DOMAIN'
 is_format_valid 'user' 'domain'
 is_format_valid 'user' 'domain'
 is_system_enabled "$DNS_SYSTEM" 'DNS_SYSTEM'
 is_system_enabled "$DNS_SYSTEM" 'DNS_SYSTEM'
@@ -45,6 +48,8 @@ check_hestia_demo_mode
 
 
 suspended=$(grep "DOMAIN='$domain'" $USER_DATA/dns.conf |grep "SUSPENDED='yes'")
 suspended=$(grep "DOMAIN='$domain'" $USER_DATA/dns.conf |grep "SUSPENDED='yes'")
 
 
+dnssec=$(grep "DOMAIN='$domain'" $USER_DATA/dns.conf |grep "DNSSEC='yes'")
+
 records=$(wc -l $USER_DATA/dns/$domain.conf | cut -f 1 -d ' ')
 records=$(wc -l $USER_DATA/dns/$domain.conf | cut -f 1 -d ' ')
 
 
 # Deleting system configs
 # Deleting system configs
@@ -59,8 +64,15 @@ if [[ "$DNS_SYSTEM" =~ named|bind ]]; then
     rm -f $HOMEDIR/$user/conf/dns/$domain.db
     rm -f $HOMEDIR/$user/conf/dns/$domain.db
 fi
 fi
 
 
+if [ -n "$dnssec" ]; then 
+    # Delete existing keys
+    rm -fr  $HOMEDIR/$user/conf/dns/$domain.db.*
+    rm -fr /var/cache/bind/K$domain_idn.*
+    rm -fr $USER_DATA/keys/K$domain_idn.*
+fi
+
 # Updating dns-cluster queue
 # Updating dns-cluster queue
-if [ -n "$DNS_CLUSTER" ]; then
+if [ "$DNS_CLUSTER"  = "yes" ]; then
     cmd="$BIN/v-delete-remote-dns-domain $user $domain"
     cmd="$BIN/v-delete-remote-dns-domain $user $domain"
     echo "$cmd" >> $HESTIA/data/queue/dns-cluster.pipe
     echo "$cmd" >> $HESTIA/data/queue/dns-cluster.pipe
 fi
 fi

+ 4 - 3
bin/v-delete-dns-record

@@ -25,6 +25,8 @@ source /etc/hestiacp/hestia.conf
 source $HESTIA/func/main.sh
 source $HESTIA/func/main.sh
 # shellcheck source=/usr/local/hestia/func/domain.sh
 # shellcheck source=/usr/local/hestia/func/domain.sh
 source $HESTIA/func/domain.sh
 source $HESTIA/func/domain.sh
+# shellcheck source=/usr/local/hestia/func/rebuild.sh
+source $HESTIA/func/rebuild.sh
 # load config file
 # load config file
 source_conf "$HESTIA/conf/hestia.conf"
 source_conf "$HESTIA/conf/hestia.conf"
 
 
@@ -56,12 +58,11 @@ sed -i "/^ID='$id'/d" $USER_DATA/dns/$domain.conf
 
 
 # Updating zone
 # Updating zone
 if [[ "$DNS_SYSTEM" =~ named|bind ]]; then
 if [[ "$DNS_SYSTEM" =~ named|bind ]]; then
-    update_domain_serial
-    update_domain_zone
+    rebuild_dns_domain_conf
 fi
 fi
 
 
 # Updating dns-cluster queue
 # Updating dns-cluster queue
-if [ -n "$DNS_CLUSTER" ]; then
+if [ "$DNS_CLUSTER"  = "yes" ]; then
     # Check for first sync
     # Check for first sync
     dlock=$(grep "domain $user $domain" $HESTIA/data/queue/dns-cluster.pipe)
     dlock=$(grep "domain $user $domain" $HESTIA/data/queue/dns-cluster.pipe)
     if [ -z "$dlock" ]; then
     if [ -z "$dlock" ]; then

+ 5 - 1
bin/v-insert-dns-domain

@@ -71,10 +71,14 @@ date=$(echo "$time_n_date" |cut -f 2 -d \ )
 
 
 # Prepare values for the insert
 # Prepare values for the insert
 dns_rec="DOMAIN='$DOMAIN' IP='$IP' TPL='$TPL' TTL='$TTL' EXP='$EXP'"
 dns_rec="DOMAIN='$DOMAIN' IP='$IP' TPL='$TPL' TTL='$TTL' EXP='$EXP'"
-dns_rec="$dns_rec SOA='$SOA' SERIAL="$SERIAL" SRC='$src' RECORDS='$RECORDS'"
+dns_rec="$dns_rec SOA='$SOA' SERIAL='$SERIAL' SRC='$src' RECORDS='$RECORDS'"
+dns_rec="$dns_rec DNSSEC='$DNSSEC' KEY='$KEY' SLAVE='$SLAVE' MASTER='$MASTER'"
 dns_rec="$dns_rec SUSPENDED='$SUSPENDED' TIME='$time' DATE='$date'"
 dns_rec="$dns_rec SUSPENDED='$SUSPENDED' TIME='$time' DATE='$date'"
 echo "$dns_rec" >> $USER_DATA/dns.conf
 echo "$dns_rec" >> $USER_DATA/dns.conf
 
 
+if [ "$SLAVE" = "yes" ]; then 
+    touch $USER_DATA/dns/$domain.conf
+fi
 # Set permission
 # Set permission
 chmod 660 $USER_DATA/dns.conf
 chmod 660 $USER_DATA/dns.conf
 
 

+ 5 - 3
bin/v-list-dns-domain

@@ -33,6 +33,7 @@ json_list() {
         "EXP": "'$EXP'",
         "EXP": "'$EXP'",
         "SOA": "'$SOA'",
         "SOA": "'$SOA'",
         "SERIAL": "'$SERIAL'",
         "SERIAL": "'$SERIAL'",
+        "DNSSEC": "'$DNSSEC'",
         "SRC": "'$SRC'",
         "SRC": "'$SRC'",
         "RECORDS": "'$RECORDS'",
         "RECORDS": "'$RECORDS'",
         "SUSPENDED": "'$SUSPENDED'",
         "SUSPENDED": "'$SUSPENDED'",
@@ -51,6 +52,7 @@ shell_list() {
     echo "EXP:            $EXP"
     echo "EXP:            $EXP"
     echo "SOA:            $SOA"
     echo "SOA:            $SOA"
     echo "SERIAL:         $SERIAL"
     echo "SERIAL:         $SERIAL"
+    echo "DNSSEC:         $DNSSEC"
     echo "RECORDS:        $RECORDS"
     echo "RECORDS:        $RECORDS"
     echo "SUSPENDED:      $SUSPENDED"
     echo "SUSPENDED:      $SUSPENDED"
     echo "TIME:           $TIME"
     echo "TIME:           $TIME"
@@ -60,14 +62,14 @@ shell_list() {
 
 
 # PLAIN list function
 # PLAIN list function
 plain_list() {
 plain_list() {
-    echo -ne "$DOMAIN\t$IP\t$TPL\t$TTL\t$EXP\t$SOA\t$SERIAL\t$RECORDS\t"
+    echo -ne "$DOMAIN\t$IP\t$TPL\t$TTL\t$EXP\t$SOA\t$SERIAL\t$DNSSEC\t$RECORDS\t"
     echo -e "$SUSPENDED\t$TIME\t$DATE"
     echo -e "$SUSPENDED\t$TIME\t$DATE"
 }
 }
 
 
 # CSV list function
 # CSV list function
 csv_list() {
 csv_list() {
-    echo "DOMAIN,IP,TPL,TTL,EXP,SOA,SERIAL,RECORDS,SUSPENDED,TIME,DATE"
-    echo -n "$DOMAIN,$IP,$TPL,$TTL,$EXP,$SOA,$SERIAL,$RECORDS,$SUSPENDED,"
+    echo "DOMAIN,IP,TPL,TTL,EXP,SOA,SERIAL,DNSSEC,RECORDS,SUSPENDED,TIME,DATE"
+    echo -n "$DOMAIN,$IP,$TPL,$TTL,$EXP,$SOA,$SERIAL,$DNSSEC,$RECORDS,$SUSPENDED,"
     echo "$TIME,$DATE"
     echo "$TIME,$DATE"
 }
 }
 
 

+ 7 - 6
bin/v-list-dns-domains

@@ -37,6 +37,7 @@ json_list() {
         "EXP": "'$EXP'",
         "EXP": "'$EXP'",
         "SOA": "'$SOA'",
         "SOA": "'$SOA'",
         "SERIAL": "'$SERIAL'",
         "SERIAL": "'$SERIAL'",
+        "DNSSEC": "'$DNSSEC'",
         "SRC": "'$SRC'",
         "SRC": "'$SRC'",
         "RECORDS": "'$RECORDS'",
         "RECORDS": "'$RECORDS'",
         "SUSPENDED": "'$SUSPENDED'",
         "SUSPENDED": "'$SUSPENDED'",
@@ -56,11 +57,11 @@ json_list() {
 # SHELL list function
 # SHELL list function
 shell_list() {
 shell_list() {
     IFS=$'\n'
     IFS=$'\n'
-    echo "DOMAIN   IP   TPL   TTL   REC   SPND   DATE"
-    echo "------   --   ---   ---   ---   ----   ----"
+    echo "DOMAIN   IP   TPL   TTL   DNSSEC   REC   SPND   DATE"
+    echo "------   --   ---   ---   ------   ---   ----   ----"
     while read str; do
     while read str; do
         parse_object_kv_list "$str"
         parse_object_kv_list "$str"
-        echo "$DOMAIN $IP $TPL $TTL $RECORDS $SUSPENDED $DATE"
+        echo "$DOMAIN $IP $TPL $TTL $DNSSEC $RECORDS $SUSPENDED $DATE"
     done < <(cat $USER_DATA/dns.conf)
     done < <(cat $USER_DATA/dns.conf)
 }
 }
 
 
@@ -70,7 +71,7 @@ plain_list() {
     IFS=$'\n'
     IFS=$'\n'
     while read str; do
     while read str; do
         parse_object_kv_list "$str"
         parse_object_kv_list "$str"
-        echo -ne "$DOMAIN\t$IP\t$TPL\t$TTL\t$EXP\t$SOA\t$SERIAL\t"
+        echo -ne "$DOMAIN\t$IP\t$TPL\t$TTL\t$EXP\t$SOA\t$DNSSEC\t$SERIAL\t"
         echo -e "$SRC\t$RECORDS\t$SUSPENDED\t$TIME\t$DATE"
         echo -e "$SRC\t$RECORDS\t$SUSPENDED\t$TIME\t$DATE"
     done < <(cat $USER_DATA/dns.conf)
     done < <(cat $USER_DATA/dns.conf)
 }
 }
@@ -79,11 +80,11 @@ plain_list() {
 # CSV list function
 # CSV list function
 csv_list() {
 csv_list() {
     IFS=$'\n'
     IFS=$'\n'
-    echo "DOMAIN,IP,TPL,TTL,EXP,SOA,SERIAL,SRC,RECORDS,SUSPENDED,TIME,DATE"
+    echo "DOMAIN,IP,TPL,TTL,EXP,SOA,SERIAL,SRC,DNSSEC,RECORDS,SUSPENDED,TIME,DATE"
     while read str; do
     while read str; do
         parse_object_kv_list "$str"
         parse_object_kv_list "$str"
         echo -n "$DOMAIN,$IP,$TPL,$TTL,$EXP,$SOA,$SERIAL,"
         echo -n "$DOMAIN,$IP,$TPL,$TTL,$EXP,$SOA,$SERIAL,"
-        echo "$SRC,$RECORDS,$SUSPENDED,$TIME,$DATE"
+        echo "$SRC,$DNSSEC,$RECORDS,$SUSPENDED,$TIME,$DATE"
     done < <(cat $USER_DATA/dns.conf)
     done < <(cat $USER_DATA/dns.conf)
 }
 }
 
 

+ 98 - 0
bin/v-list-dnssec-public-key

@@ -0,0 +1,98 @@
+#!/bin/bash
+# info: list public dnssec key 
+# options: USER DOMAIN [FROMAT]
+#
+# example: v-list-dns-public-key admin acme.com
+#
+# This function list the public key to be used with DNSSEC and needs to be added to the domain register.
+
+#----------------------------------------------------------#
+#                Variables & Functions                     #
+#----------------------------------------------------------#
+
+# Argument definition
+user=$1
+domain=$2
+format=$3
+dnstype=$4
+
+# Includes
+# shellcheck source=/etc/hestiacp/hestia.conf
+source /etc/hestiacp/hestia.conf
+# shellcheck source=/usr/local/hestia/func/main.sh
+source $HESTIA/func/main.sh
+# shellcheck source=/usr/local/hestia/func/domain.sh
+source $HESTIA/func/domain.sh
+# load config file
+source_conf "$HESTIA/conf/hestia.conf"
+
+#----------------------------------------------------------#
+#                    Verifications                         #
+#----------------------------------------------------------#
+
+
+format_domain
+format_domain_idn
+
+check_args '2' "$#" 'USER DOMAIN [FORMAT]'
+is_format_valid 'user' 'domain'
+is_object_valid 'user' 'USER' "$user"
+is_object_valid 'dns' 'DOMAIN' "$domain"
+
+# JSON list function
+json_list() {
+    echo '{'
+    echo '    "'$DOMAIN'": {
+       "RECORD": "'$record'",
+       "FLAG": "'$flag'",
+       "ALGORITHM": "'$algorithm'",
+       "KEY": "'$key'",
+       "DS":"'$ds'"
+    }'
+    echo '}'
+}
+
+# SHELL list function
+shell_list() {
+   echo "RECORD:    $record"
+   echo "DS:        $DS" 
+   echo "FLAG:      $flag" 
+   echo "ALGORITHM: $algorithm" 
+   echo "KEY:       $key"  
+}
+
+# PLAIN list function
+plain_list() {
+   if [ "$dnstype" != "DS" ];then
+      echo -e "$record"
+   else
+      echo -e "$ds"
+   fi
+}
+
+#----------------------------------------------------------#
+#                       Action                             #
+#----------------------------------------------------------#
+
+parse_object_kv_list $(grep "DOMAIN='$domain'" $USER_DATA/dns.conf)
+
+
+if [ -n "$KEY" ]; then
+   record=$(cat "/var/cache/bind/K$domain_idn.+013+$KEY.key" | grep DNSKEY );
+   flag=$(echo "$record" | cut -d' ' -f5)
+   algorithm=$(echo "$record" | cut -d' ' -f7)
+   key="$(echo "$record" | cut -d' ' -f8) $(echo "$record" | cut -d' ' -f9)"
+   ds=$(dnssec-dsfromkey "/var/cache/bind/K$domain_idn.+013+$KEY.key");
+fi
+
+case $format in
+    json)   json_list ;;
+    plain)  plain_list ;;
+    shell)  shell_list ;;
+esac
+
+#----------------------------------------------------------#
+#                       Hestia                             #
+#----------------------------------------------------------#
+
+exit

+ 12 - 3
bin/v-restore-user

@@ -438,7 +438,7 @@ if [ "$dns" != 'no' ] && [ -n "$DNS_SYSTEM" ]; then
         echo -e "$(date "+%F %T") $domain" |tee -a $tmpdir/restore.log
         echo -e "$(date "+%F %T") $domain" |tee -a $tmpdir/restore.log
 
 
         # Cleanup previous config keys
         # Cleanup previous config keys
-        unset -v DOMAIN IP TPL TTL EXP SOA RECORDS
+        unset -v DOMAIN IP TPL TTL EXP SOA RECORDS DNSSEC KEY SLAVE MASTER
 
 
         # Checking domain existance
         # Checking domain existance
         check_config=$(grep "DOMAIN='$domain'" $USER_DATA/dns.conf)
         check_config=$(grep "DOMAIN='$domain'" $USER_DATA/dns.conf)
@@ -484,11 +484,20 @@ if [ "$dns" != 'no' ] && [ -n "$DNS_SYSTEM" ]; then
 
 
             # Merging dns.conf keys
             # Merging dns.conf keys
             str="DOMAIN='$domain' IP='$IP' TPL='$TPL' TTL='$TTL' EXP='$EXP'"
             str="DOMAIN='$domain' IP='$IP' TPL='$TPL' TTL='$TTL' EXP='$EXP'"
-            str="$str SOA='$SOA' RECORDS='$RECORDS' SUSPENDED='no'"
+            str="$str SOA='$SOA' RECORDS='$RECORDS'  DNSSEC='$DNSSEC'"
+            str="$str KEY='$KEY' SLAVE='$SLAVE' MASTER='$MASTER' SUSPENDED='no'"
             str="$str TIME='$(date +%T)' DATE='$(date +%F)'"
             str="$str TIME='$(date +%T)' DATE='$(date +%F)'"
             echo $str >> $USER_DATA/dns.conf
             echo $str >> $USER_DATA/dns.conf
         fi
         fi
-
+        
+        if [ "$DNSSEC" = "yes" ]; then
+            format_domain_idn
+            # Probably need to change the cache dir for RHEL
+            cp $tmpdir/dns/$domain/conf/keys/* /var/cache/bind/
+            chown bind:bind /var/cache/bind/K$domain_idn*
+            chmod 644 /var/cache/bind/K$domain_idn*
+        fi
+        
         # Restoring DNS records
         # Restoring DNS records
         cp -f $tmpdir/dns/$domain/$backup_system/$domain.conf $USER_DATA/dns/
         cp -f $tmpdir/dns/$domain/$backup_system/$domain.conf $USER_DATA/dns/
 
 

+ 31 - 18
bin/v-sync-dns-cluster

@@ -62,26 +62,39 @@ for cluster in $hosts; do
     user_list=$(ls -d $HESTIA/data/users/*/ | sed "s#$HESTIA/data/users/##" | sed s"/.$//" | grep -v "dns-cluster")
     user_list=$(ls -d $HESTIA/data/users/*/ | sed "s#$HESTIA/data/users/##" | sed s"/.$//" | grep -v "dns-cluster")
     for user in $user_list; do
     for user in $user_list; do
         for str in $(cat $HESTIA/data/users/$user/dns.conf); do
         for str in $(cat $HESTIA/data/users/$user/dns.conf); do
-
-            # Syncing domain index
-            parse_object_kv_list "$str"
-            cluster_cmd v-insert-dns-domain "$DNS_USER" "$str" "$HOSTNAME" ' ' "no"
-            check_result $? "$HOST connection failed" "$E_CONNECT"
-
-            # Syncing domain records
-            tmp_file="/tmp/vst-sync.$DOMAIN"
-            cluster_file "$USER_DATA/$user/dns/$DOMAIN.conf" "$tmp_file"
-            check_result $? "$HOST connection failed" "$E_CONNECT"
-
-            cluster_cmd v-insert-dns-records "$DNS_USER" "$DOMAIN" "$tmp_file" 'no'
-            check_result $? "$HOST connection failed" "$E_CONNECT"
+            if [ "$DNS_CLUSTER_SYSTEM" != "zone" ]; then            
+                # Syncing domain index
+                parse_object_kv_list "$str"
+                cluster_cmd v-insert-dns-domain "$DNS_USER" "$str" "$HOSTNAME" ' ' "no"
+                check_result $? "$HOST connection failed" "$E_CONNECT"
+
+                # Syncing domain records
+                tmp_file="/tmp/vst-sync.$DOMAIN"
+                cluster_file "$USER_DATA/$user/dns/$DOMAIN.conf" "$tmp_file"
+                check_result $? "$HOST connection failed" "$E_CONNECT"
+    
+                cluster_cmd v-insert-dns-records "$DNS_USER" "$DOMAIN" "$tmp_file" 'no'
+                check_result $? "$HOST connection failed" "$E_CONNECT"
+            fi
+            if [ "$DNS_CLUSTER_SYSTEM" = "zone" ]; then
+                str=$(echo "$str" | sed "s/SLAVE='no'/SLAVE='yes'/g");
+                ip=$($BIN/v-list-sys-ips plain | cut -f1);
+                str=$(echo "$str" | sed "s/MASTER='*'/MASTER='$ip'/g");
+
+                # Syncing domain data
+                cluster_cmd v-insert-dns-domain $DNS_USER "$str" $HOSTNAME $flush 'no'
+                check_result $? "$HOST connection failed" "$E_CONNECT"
+                
+                cluster_cmd v-rebuild-dns-domain "$DNS_USER" "$DOMAIN"
+                rndc notify $DOMAIN  > /dev/null 2>&1
+            fi
         done
         done
     done
     done
-
-    # Rebuilding dns zones
-    cluster_cmd v-rebuild-dns-domains "$DNS_USER"
-    check_result $? "$TYPE connection to $HOST failed" "$E_CONNECT"
-
+    if [ "$DNS_CLUSTER_SYSTEM" != "zone" ]; then
+        # Rebuilding dns zones
+        cluster_cmd v-rebuild-dns-domains "$DNS_USER"
+        check_result $? "$TYPE connection to $HOST failed" "$E_CONNECT"
+    fi
 done
 done
 
 
 #----------------------------------------------------------#
 #----------------------------------------------------------#

+ 3 - 7
func/domain.sh

@@ -532,11 +532,8 @@ update_domain_zone() {
                 fi
                 fi
             fi
             fi
         fi
         fi
-
-        if [ "$SUSPENDED" != 'yes' ]; then
-            eval echo -e "\"$fields\""|sed "s/%quote%/'/g" >> $zn_conf
-        fi
-    done < $USER_DATA/dns/$domain.conf
+        eval echo -e "\"$fields\""|sed "s/%quote%/'/g" >> $zn_conf
+    done < $USER_DATA/dns/$domain.conf    
 }
 }
 
 
 # Update zone serial
 # Update zone serial
@@ -598,12 +595,11 @@ is_dns_record_critical() {
 is_dns_fqnd() {
 is_dns_fqnd() {
     t=$1
     t=$1
     r=$2
     r=$2
-    fqdn_type=$(echo $t | grep "NS\|CNAME\|MX\|PTR\|SRV")
+    fqdn_type=$(echo $t | grep "^NS\|CNAME\|MX\|PTR\|SRV")
     tree_length=3
     tree_length=3
     if [[ $t = 'CNAME' || $t = 'MX' || $t = 'PTR' ]]; then
     if [[ $t = 'CNAME' || $t = 'MX' || $t = 'PTR' ]]; then
         tree_length=2
         tree_length=2
     fi
     fi
-
     if [ -n "$fqdn_type" ]; then
     if [ -n "$fqdn_type" ]; then
         dots=$(echo $dvalue | grep -o "\." | wc -l)
         dots=$(echo $dvalue | grep -o "\." | wc -l)
         if [ "$dots" -lt "$tree_length" ]; then
         if [ "$dots" -lt "$tree_length" ]; then

+ 2 - 2
func/main.sh

@@ -878,7 +878,7 @@ is_common_format_valid() {
                         check_result "$E_INVALID" "invalid $2 format :: $1"
                         check_result "$E_INVALID" "invalid $2 format :: $1"
         fi
         fi
     fi
     fi
-    if [[ $(echo -n "$1" | tail -c 1) =~ [^a-zA-Z0-9_*@] ]]; then
+    if [[ $(echo -n "$1" | tail -c 1) =~ [^a-zA-Z0-9_*@.] ]]; then
            check_result "$E_INVALID" "invalid $2 format :: $1"
            check_result "$E_INVALID" "invalid $2 format :: $1"
     fi
     fi
     if [[ $(echo -n "$1" | grep -c '\.\.') -gt 0 ]];then
     if [[ $(echo -n "$1" | grep -c '\.\.') -gt 0 ]];then
@@ -941,7 +941,7 @@ is_dbuser_format_valid() {
 
 
 # DNS record type validator
 # DNS record type validator
 is_dns_type_format_valid() {
 is_dns_type_format_valid() {
-    known_dnstype='A,AAAA,NS,CNAME,MX,TXT,SRV,DNSKEY,KEY,IPSECKEY,PTR,SPF,TLSA,CAA'
+    known_dnstype='A,AAAA,NS,CNAME,MX,TXT,SRV,DNSKEY,KEY,IPSECKEY,PTR,SPF,TLSA,CAA,DS'
     if [ -z "$(echo $known_dnstype |grep -w $1)" ]; then
     if [ -z "$(echo $known_dnstype |grep -w $1)" ]; then
         check_result "$E_INVALID" "invalid dns record type format :: $1"
         check_result "$E_INVALID" "invalid dns record type format :: $1"
     fi
     fi

+ 70 - 33
func/rebuild.sh

@@ -164,7 +164,13 @@ rebuild_user_conf() {
         chmod 660 $USER_DATA/dns.conf
         chmod 660 $USER_DATA/dns.conf
 
 
         mkdir -p $HOMEDIR/$user/conf/dns
         mkdir -p $HOMEDIR/$user/conf/dns
-        chmod 751 $HOMEDIR/$user/conf/dns
+        chmod 771 $HOMEDIR/$user/conf/dns
+        if [ "$DNS_SYSTEM" = 'named' ]; then
+            dns_group='named'
+        else
+            dns_group='bind'
+        fi
+        chown root:$dns_group $HOMEDIR/$user/conf/dns
         if [ "$create_user" = "yes" ]; then
         if [ "$create_user" = "yes" ]; then
             $BIN/v-rebuild-dns-domains $user $restart
             $BIN/v-rebuild-dns-domains $user $restart
         fi
         fi
@@ -469,37 +475,39 @@ rebuild_dns_domain_conf() {
     get_domain_values 'dns'
     get_domain_values 'dns'
     domain_idn=$(idn2 --quiet "$domain")
     domain_idn=$(idn2 --quiet "$domain")
 
 
-    # Checking zone file
-    if [ ! -e "$USER_DATA/dns/$domain.conf" ]; then
-        cat $DNSTPL/$TPL.tpl |\
-            sed -e "s/%ip%/$IP/g" \
-                -e "s/%domain_idn%/$domain_idn/g" \
-                -e "s/%domain%/$domain/g" \
-                -e "s/%ns1%/$ns1/g" \
-                -e "s/%ns2%/$ns2/g" \
-                -e "s/%ns3%/$ns3/g" \
-                -e "s/%ns4%/$ns4/g" \
-                -e "s/%time%/$TIME/g" \
-                -e "s/%date%/$DATE/g" > $USER_DATA/dns/$domain.conf
-    fi
-
-    # Sorting records
-    sort_dns_records
-
-    # Updating zone
-    update_domain_zone
-
-    # Set permissions
-    if [ "$DNS_SYSTEM" = 'named' ]; then
-        dns_group='named'
-    else
-        dns_group='bind'
+    if [ "$SLAVE" != "yes" ]; then
+        # Checking zone file
+        if [ ! -e "$USER_DATA/dns/$domain.conf" ]; then
+            cat $DNSTPL/$TPL.tpl |\
+                sed -e "s/%ip%/$IP/g" \
+                    -e "s/%domain_idn%/$domain_idn/g" \
+                    -e "s/%domain%/$domain/g" \
+                    -e "s/%ns1%/$ns1/g" \
+                    -e "s/%ns2%/$ns2/g" \
+                    -e "s/%ns3%/$ns3/g" \
+                    -e "s/%ns4%/$ns4/g" \
+                    -e "s/%time%/$TIME/g" \
+                    -e "s/%date%/$DATE/g" > $USER_DATA/dns/$domain.conf
+        fi
+    
+        # Sorting records
+        sort_dns_records
+        #Remove old sign files
+        rm -fr  $HOMEDIR/$user/conf/dns/$domain.db.*
+        # Updating zone
+        update_domain_zone
+    
+        # Set permissions
+        if [ "$DNS_SYSTEM" = 'named' ]; then
+            dns_group='named'
+        else
+            dns_group='bind'
+        fi
+        # Set file permissions
+        chmod 640 $HOMEDIR/$user/conf/dns/$domain.db
+        chown root:$dns_group $HOMEDIR/$user/conf/dns/$domain.db   
     fi
     fi
-
-    # Set file permissions
-    chmod 640 $HOMEDIR/$user/conf/dns/$domain.db
-    chown root:$dns_group $HOMEDIR/$user/conf/dns/$domain.db
-
+    
     # Get dns config path
     # Get dns config path
     if [ -e '/etc/named.conf' ]; then
     if [ -e '/etc/named.conf' ]; then
         dns_conf='/etc/named.conf'
         dns_conf='/etc/named.conf'
@@ -517,16 +525,45 @@ rebuild_dns_domain_conf() {
         fi
         fi
         suspended_dns=$((suspended_dns + 1))
         suspended_dns=$((suspended_dns + 1))
     else
     else
-        if [ -z "$(grep /$domain.db $dns_conf)" ]; then
-            named="zone \"$domain_idn\" {type master; file"
+        sed -i "/dns\/$domain.db/d" $dns_conf
+        if [ "$SLAVE" = "yes" ]; then
+            named="zone \"$domain_idn\" in {type slave; masters { $MASTER; }; file"
             named="$named \"$HOMEDIR/$user/conf/dns/$domain.db\";};"
             named="$named \"$HOMEDIR/$user/conf/dns/$domain.db\";};"
             echo "$named" >> $dns_conf
             echo "$named" >> $dns_conf
+        else
+            if [ "$DNSSEC" = "yes" ]; then
+                named="zone \"$domain_idn\" in {type master; dnssec-policy default; inline-signing yes; file"
+                named="$named \"$HOMEDIR/$user/conf/dns/$domain.db\";};"
+                echo "$named" >> $dns_conf
+                else
+                named="zone \"$domain_idn\" {type master; file"
+                named="$named \"$HOMEDIR/$user/conf/dns/$domain.db\";};"
+                echo "$named" >> $dns_conf
+            fi
         fi
         fi
     fi
     fi
     user_domains=$((user_domains + 1))
     user_domains=$((user_domains + 1))
     records=$(wc -l $USER_DATA/dns/$domain.conf | cut -f 1 -d ' ')
     records=$(wc -l $USER_DATA/dns/$domain.conf | cut -f 1 -d ' ')
     user_records=$((user_records + records))
     user_records=$((user_records + records))
     update_object_value 'dns' 'DOMAIN' "$domain" '$RECORDS' "$records"
     update_object_value 'dns' 'DOMAIN' "$domain" '$RECORDS' "$records"
+    
+    # Load new config
+    /usr/sbin/rndc reconfig > /dev/null 2>&1
+    
+    # Reload config
+    /usr/sbin/rndc reload > /dev/null 2>&1
+    
+    if [ "$DNSSEC" = "yes" ]; then
+        # Key consists always out of 5 digits when less is used they are "lost" 
+        key=$(/usr/sbin/rndc dnssec -status $domain_idn | grep ^key: | cut -f2 -d' ' | numfmt --format='%05.0f' --invalid=ignore);
+        
+        if [ ! -d "$USER_DATA/keys/" ]; then
+            mkdir -p $USER_DATA/keys/
+        fi
+        cp /var/cache/bind/K$domain_idn.+013+$key.* $USER_DATA/keys/
+        update_object_value 'dns' 'DOMAIN' "$domain" '$KEY' "$key"
+    fi
+    rndc notify $domain_idn  > /dev/null 2>&1
 }
 }
 
 
 # MAIL domain rebuild
 # MAIL domain rebuild

+ 5 - 1
func/syshealth.sh

@@ -64,7 +64,7 @@ function syshealth_update_dns_config_format() {
     # DNS DOMAINS
     # DNS DOMAINS
     # Create array of known keys in configuration file
     # Create array of known keys in configuration file
     system="dns"
     system="dns"
-    known_keys="DOMAIN IP TPL TTL EXP SOA SERIAL SRC RECORDS SUSPENDED TIME DATE"
+    known_keys="DOMAIN IP TPL TTL EXP SOA SERIAL SRC RECORDS DNSSEC KEY SLAVE SUSPENDED TIME DATE"
     write_kv_config_file
     write_kv_config_file
     unset system
     unset system
     unset known_keys
     unset known_keys
@@ -463,6 +463,10 @@ function syshealth_repair_system_config() {
         echo "[ ! ] Adding missing variable to hestia.conf: POLICY_CSRF_STRICTNESS ('')"
         echo "[ ! ] Adding missing variable to hestia.conf: POLICY_CSRF_STRICTNESS ('')"
         $BIN/v-change-sys-config-value "POLICY_CSRF_STRICTNESS" "1"
         $BIN/v-change-sys-config-value "POLICY_CSRF_STRICTNESS" "1"
     fi
     fi
+    if [[ -z $(check_key_exists 'DNS_CLUSTER_SYSTEM') ]]; then
+        echo "[ ! ] Adding missing variable to hestia.conf: DNS_CLUSTER_SYSTEM ('')"
+        $BIN/v-change-sys-config-value "DNS_CLUSTER_SYSTEM" "hestia"
+    fi
     
     
     touch $HESTIA/conf/hestia.conf.new
     touch $HESTIA/conf/hestia.conf.new
     while IFS='= ' read -r lhs rhs
     while IFS='= ' read -r lhs rhs

+ 10 - 1
web/add/dns/index.php

@@ -66,6 +66,9 @@ if (!empty($_POST['ok'])) {
     if (empty($_POST['v_ns8'])) {
     if (empty($_POST['v_ns8'])) {
         $_POST['v_ns8'] = '';
         $_POST['v_ns8'] = '';
     }
     }
+    if (empty($_POST['v_dnssec'])) {
+        $_POST['v_dnssec'] = 'no';
+    }
     $v_ns1 = quoteshellarg($_POST['v_ns1']);
     $v_ns1 = quoteshellarg($_POST['v_ns1']);
     $v_ns2 = quoteshellarg($_POST['v_ns2']);
     $v_ns2 = quoteshellarg($_POST['v_ns2']);
     $v_ns3 = quoteshellarg($_POST['v_ns3']);
     $v_ns3 = quoteshellarg($_POST['v_ns3']);
@@ -74,10 +77,11 @@ if (!empty($_POST['ok'])) {
     $v_ns6 = quoteshellarg($_POST['v_ns6']);
     $v_ns6 = quoteshellarg($_POST['v_ns6']);
     $v_ns7 = quoteshellarg($_POST['v_ns7']);
     $v_ns7 = quoteshellarg($_POST['v_ns7']);
     $v_ns8 = quoteshellarg($_POST['v_ns8']);
     $v_ns8 = quoteshellarg($_POST['v_ns8']);
+    $v_dnssec = quoteshellarg($_POST['v_dnssec']);
 
 
     // Add dns domain
     // Add dns domain
     if (empty($_SESSION['error_msg'])) {
     if (empty($_SESSION['error_msg'])) {
-        exec(HESTIA_CMD."v-add-dns-domain ".$user." ".$v_domain." ".quoteshellarg($v_ip)." ".$v_ns1." ".$v_ns2." ".$v_ns3." ".$v_ns4." ".$v_ns5."  ".$v_ns6."  ".$v_ns7." ".$v_ns8." no", $output, $return_var);
+        exec(HESTIA_CMD."v-add-dns-domain ".$user." ".$v_domain." ".quoteshellarg($v_ip)." ".$v_ns1." ".$v_ns2." ".$v_ns3." ".$v_ns4." ".$v_ns5."  ".$v_ns6."  ".$v_ns7." ".$v_ns8." no ".$v_dnssec, $output, $return_var);
         check_return_code($return_var, $output);
         check_return_code($return_var, $output);
         unset($output);
         unset($output);
     }
     }
@@ -168,6 +172,7 @@ if (!empty($_POST['ok_rec'])) {
     $v_val = quoteshellarg($_POST['v_val']);
     $v_val = quoteshellarg($_POST['v_val']);
     $v_priority = quoteshellarg($_POST['v_priority']);
     $v_priority = quoteshellarg($_POST['v_priority']);
     $v_ttl = quoteshellarg($_POST['v_ttl']);
     $v_ttl = quoteshellarg($_POST['v_ttl']);
+
     // Add dns record
     // Add dns record
     if (empty($_SESSION['error_msg'])) {
     if (empty($_SESSION['error_msg'])) {
         exec(HESTIA_CMD."v-add-dns-record ".$user." ".$v_domain." ".$v_rec." ".$v_type." ".$v_val." ".$v_priority." '' yes ".$v_ttl, $output, $return_var);
         exec(HESTIA_CMD."v-add-dns-record ".$user." ".$v_domain." ".$v_rec." ".$v_type." ".$v_val." ".$v_priority." '' yes ".$v_ttl, $output, $return_var);
@@ -183,6 +188,7 @@ if (!empty($_POST['ok_rec'])) {
         unset($v_rec);
         unset($v_rec);
         unset($v_val);
         unset($v_val);
         unset($v_priority);
         unset($v_priority);
+        unset($v_dnssec);
     }
     }
 }
 }
 
 
@@ -282,6 +288,9 @@ if (empty($_GET['domain'])) {
     if (empty($v_ttl)) {
     if (empty($v_ttl)) {
         $v_ttl = '';
         $v_ttl = '';
     }
     }
+    if (empty($v_dnssec)) {
+        $v_dnssec = '';
+    }
     render_page($user, $TAB, 'add_dns_rec');
     render_page($user, $TAB, 'add_dns_rec');
 }
 }
 
 

+ 18 - 0
web/edit/dns/index.php

@@ -38,6 +38,7 @@ if ((!empty($_GET['domain'])) && (empty($_GET['record_id']))) {
     $v_ip = $data[$v_domain]['IP'];
     $v_ip = $data[$v_domain]['IP'];
     $v_template = $data[$v_domain]['TPL'];
     $v_template = $data[$v_domain]['TPL'];
     $v_ttl = $data[$v_domain]['TTL'];
     $v_ttl = $data[$v_domain]['TTL'];
+    $v_dnssec = $data[$v_domain]['DNSSEC'];
     $v_exp = $data[$v_domain]['EXP'];
     $v_exp = $data[$v_domain]['EXP'];
     $v_soa = $data[$v_domain]['SOA'];
     $v_soa = $data[$v_domain]['SOA'];
     $v_date = $data[$v_domain]['DATE'];
     $v_date = $data[$v_domain]['DATE'];
@@ -132,6 +133,23 @@ if ((!empty($_POST['save'])) && (!empty($_GET['domain'])) && (empty($_GET['recor
         unset($output);
         unset($output);
         $restart_dns = 'yes';
         $restart_dns = 'yes';
     }
     }
+    // Change domain dnssec
+    if (($_POST['v_dnssec'] == '' && $v_dnssec == 'yes') && (empty($_SESSION['error_msg']))) {
+        exec(HESTIA_CMD."v-change-dns-domain-dnssec ".$user." ".$v_domain." 'no'", $output, $return_var);
+        check_return_code($return_var, $output);
+        unset($output);
+        $v_dnssec = 'no';
+        $restart_dns = 'yes';
+    }
+    
+    // Change domain dnssec
+    if (($_POST['v_dnssec'] == 'yes' && $v_dnssec == 'no') && (empty($_SESSION['error_msg']))) {
+        exec(HESTIA_CMD."v-change-dns-domain-dnssec ".$user." ".$v_domain." 'yes'", $output, $return_var);
+        check_return_code($return_var, $output);
+        unset($output);
+        $v_dnssec = 'yes';
+        $restart_dns = 'yes';
+    }
 
 
     // Restart dns server
     // Restart dns server
     if (!empty($restart_dns) && (empty($_SESSION['error_msg']))) {
     if (!empty($restart_dns) && (empty($_SESSION['error_msg']))) {

+ 58 - 1
web/list/dns/index.php

@@ -6,6 +6,7 @@ $TAB = 'DNS';
 include($_SERVER['DOCUMENT_ROOT']."/inc/main.php");
 include($_SERVER['DOCUMENT_ROOT']."/inc/main.php");
 
 
 // Data & Render page
 // Data & Render page
+
 if (empty($_GET['domain'])){
 if (empty($_GET['domain'])){
     exec (HESTIA_CMD."v-list-dns-domains ".$user." 'json'", $output, $return_var);
     exec (HESTIA_CMD."v-list-dns-domains ".$user." 'json'", $output, $return_var);
     $data = json_decode(implode('', $output), true);
     $data = json_decode(implode('', $output), true);
@@ -17,7 +18,63 @@ if (empty($_GET['domain'])){
     unset($output);
     unset($output);
 
 
     render_page($user, $TAB, 'list_dns');
     render_page($user, $TAB, 'list_dns');
-} else {
+} else if (!empty($_GET['action'])){
+    
+    exec (HESTIA_CMD."v-list-dnssec-public-key ".$user." ".quoteshellarg($_GET['domain'])." 'json'", $output, $return_var);
+    $data = json_decode(implode('', $output), true);
+    $domain=$_GET['domain'];
+    
+    switch ($data[$domain]['FLAG']) {
+        case 257:
+            $flag="KSK (257)";
+            break;
+        case 256:
+            $flag="ZSK (256)";
+            break;
+    }
+    
+    switch ($data[$domain]['ALGORITHM']) {
+        case 3:
+            $algorithm="3 - DSA";
+            break;
+        case 5:
+            $algorithm="5 - RSA/SHA1";
+            break;
+        case 6:
+            $algorithm="6 - DSA-NSEC3-SHA1";
+            break;
+        case 7:
+            $algorithm="7 - RSA/SHA1-NSEC3-SHA1";
+            break;
+        case 8:
+            $algorithm="8 - RSA/SHA256";
+            break;
+        case 10:
+            $algorithm="10 - RSA/SHA512";
+            break;
+        case 12:
+            $algorithm="12 - ECC-GOST";
+            break;
+        case 13:
+            $algorithm="13 - ECDSAP256/SHA256";
+            break;
+        case 14:
+            $algorithm="14 - ECDSAP384/SHA384";
+            break;
+        case 15:
+            $algorithm="15 - ED25519/SHA512";
+            break;
+        case 16:
+            $algorithm="16 - ED448/SHA912";
+            break;
+        default:
+            $algorithm="Unknown";
+    }
+    
+    unset($output);
+    
+    render_page($user, $TAB, 'list_dns_public');    
+}else {
     exec (HESTIA_CMD."v-list-dns-records ".$user." ".quoteshellarg($_GET['domain'])." 'json'", $output, $return_var);
     exec (HESTIA_CMD."v-list-dns-records ".$user." ".quoteshellarg($_GET['domain'])." 'json'", $output, $return_var);
     $data = json_decode(implode('', $output), true);
     $data = json_decode(implode('', $output), true);
     if($_SESSION['userSortOrder'] == 'name'){
     if($_SESSION['userSortOrder'] == 'name'){

+ 8 - 0
web/templates/pages/add_dns.html

@@ -111,6 +111,14 @@
 							<tr>
 							<tr>
 								<td class="u-pt18">
 								<td class="u-pt18">
 									<table style="display:<?php if (empty($v_adv)) echo 'none';?> ;" id="advtable">
 									<table style="display:<?php if (empty($v_adv)) echo 'none';?> ;" id="advtable">
+										<tr>
+											<td class="u-pt6">
+												<div class="form-check">
+													<input type="checkbox" class="form-check-input" name="v_dnssec" id="v_dnssec" value="yes" <?php if($v_dnssec != 'no'){ echo ' checked'; } ?>>
+													<label for="v_dnssec" class="form-label"> <?=_('Enable DNSEC');?></label>
+												</div>
+											</td>
+										</tr>
 										<tr>
 										<tr>
 											<td class="u-pt6">
 											<td class="u-pt6">
 												<label for="v_exp" class="form-label">
 												<label for="v_exp" class="form-label">

+ 8 - 0
web/templates/pages/edit_dns.html

@@ -86,6 +86,14 @@
 								</td>
 								</td>
 							</tr>
 							</tr>
 						<?php } ?>
 						<?php } ?>
+						<tr>
+							<td class="u-pt6">
+								<div class="form-check">
+									<input type="checkbox" class="form-check-input" name="v_dnssec" id="v_dnssec" value="yes" <?php if($v_dnssec != 'no'){ echo ' checked'; } ?>>
+									<label for="v_dnssec" class="form-label"><?=_('Enable DNSEC');?></label>
+								</div>
+							</td>
+						</tr>
 						<tr>
 						<tr>
 							<td class="u-pt6">
 							<td class="u-pt6">
 								<label for="v_exp" class="form-label">
 								<label for="v_exp" class="form-label">

+ 13 - 2
web/templates/pages/list_dns.html

@@ -71,7 +71,8 @@
 			<div class="clearfix l-unit__stat-col--left text-center compact"><b><?=_('Records_DNS');?></b></div>
 			<div class="clearfix l-unit__stat-col--left text-center compact"><b><?=_('Records_DNS');?></b></div>
 			<div class="clearfix l-unit__stat-col--left text-center"><b><?=_('Template');?></b></div>
 			<div class="clearfix l-unit__stat-col--left text-center"><b><?=_('Template');?></b></div>
 			<div class="clearfix l-unit__stat-col--left text-center compact"><b><?=_('TTL');?></b></div>
 			<div class="clearfix l-unit__stat-col--left text-center compact"><b><?=_('TTL');?></b></div>
-			<div class="clearfix l-unit__stat-col--left text-center wide"><b><?=_('SOA');?></b></div>
+			<div class="clearfix l-unit__stat-col--left text-center"><b><?=_('SOA');?></b></div>
+			<div class="clearfix l-unit__stat-col--left text-center compact-3"><b><?=_('DNSSEC');?></b></div>
 			<div class="clearfix l-unit__stat-col--left text-center"><b><?=_('Expiration Date');?></b></div>
 			<div class="clearfix l-unit__stat-col--left text-center"><b><?=_('Expiration Date');?></b></div>
 		</div>
 		</div>
 	</div>
 	</div>
@@ -91,6 +92,11 @@
 				$spnd_icon = 'fa-pause';
 				$spnd_icon = 'fa-pause';
 				$spnd_confirmation = _('SUSPEND_DOMAIN_CONFIRMATION');
 				$spnd_confirmation = _('SUSPEND_DOMAIN_CONFIRMATION');
 			}
 			}
+			if ($data[$key]['DNSSEC'] == 'no') {
+				$dnssec_icon = 'fa-times-circle';
+			} else {
+				$dnssec_icon = 'fa-check-circle';
+			}
 		?>
 		?>
 		<div class="l-unit <?php if ($status == 'suspended') echo ' l-unit--suspended'; ?> animated fadeIn" v_unit_id="<?=htmlentities($key);?>"
 		<div class="l-unit <?php if ($status == 'suspended') echo ' l-unit--suspended'; ?> animated fadeIn" v_unit_id="<?=htmlentities($key);?>"
 			v_section="dns" sort-ip="<?=str_replace('.', '', $data[$key]['IP'])?>" sort-date="<?=strtotime($data[$key]['DATE'].' '.$data[$key]['TIME'])?>" sort-name="<?=htmlentities($key);?>"
 			v_section="dns" sort-ip="<?=str_replace('.', '', $data[$key]['IP'])?>" sort-date="<?=strtotime($data[$key]['DATE'].' '.$data[$key]['TIME'])?>" sort-name="<?=htmlentities($key);?>"
@@ -114,6 +120,8 @@
 								<?php if ($data[$key]['SUSPENDED'] == 'no') {?>
 								<?php if ($data[$key]['SUSPENDED'] == 'no') {?>
 									<div class="actions-panel__col actions-panel__logs shortcut-n" key-action="href"><a href="/add/dns/?domain=<?=htmlentities($key);?>&token=<?=$_SESSION['token']?>" title="<?=_('Add DNS Record');?>"><i class="fas fa-plus-circle status-icon green status-icon dim"></i></a></div>
 									<div class="actions-panel__col actions-panel__logs shortcut-n" key-action="href"><a href="/add/dns/?domain=<?=htmlentities($key);?>&token=<?=$_SESSION['token']?>" title="<?=_('Add DNS Record');?>"><i class="fas fa-plus-circle status-icon green status-icon dim"></i></a></div>
 									<div class="actions-panel__col actions-panel__logs shortcut-enter" key-action="href"><a href="/edit/dns/?domain=<?=htmlentities($key);?>&token=<?=$_SESSION['token']?>" title="<?=_('Editing DNS Domain');?>"><i class="fas fa-pencil-alt status-icon orange status-icon dim"></i></a></div>
 									<div class="actions-panel__col actions-panel__logs shortcut-enter" key-action="href"><a href="/edit/dns/?domain=<?=htmlentities($key);?>&token=<?=$_SESSION['token']?>" title="<?=_('Editing DNS Domain');?>"><i class="fas fa-pencil-alt status-icon orange status-icon dim"></i></a></div>
+									<?php if($data[$key]['DNSSEC'] == "yes"){?><div class="actions-panel__col actions-panel__logs shortcut-enter" key-action="href"><a href="/list/dns/?domain=<?=htmlentities($key);?>&action=dnssec&token=<?=$_SESSION['token']?>" title="<?=_('View Public DNSSEC key');?>"><i class="fas fa-key status-icon orange status-icon dim"></i></a></div>
+									<?php } ?>
 								<?php } ?>
 								<?php } ?>
 								<div class="actions-panel__col actions-panel__edit shortcut-l" key-action="href"><a href="/list/dns/?domain=<?=htmlentities($key);?>&token=<?=$_SESSION['token']?>" title="<?=_('DNS records');?>"><i class="fas fa-list status-icon lightblue status-icon dim"></i></a></div>
 								<div class="actions-panel__col actions-panel__edit shortcut-l" key-action="href"><a href="/list/dns/?domain=<?=htmlentities($key);?>&token=<?=$_SESSION['token']?>" title="<?=_('DNS records');?>"><i class="fas fa-list status-icon lightblue status-icon dim"></i></a></div>
 								<div class="actions-panel__col actions-panel__suspend shortcut-s" key-action="js">
 								<div class="actions-panel__col actions-panel__suspend shortcut-s" key-action="js">
@@ -144,7 +152,10 @@
 				</div>
 				</div>
 				<div class="clearfix l-unit__stat-col--left text-center"><b><?=$data[$key]['TPL']?></b></div>
 				<div class="clearfix l-unit__stat-col--left text-center"><b><?=$data[$key]['TPL']?></b></div>
 				<div class="clearfix l-unit__stat-col--left text-center compact"><?=$data[$key]['TTL']?></div>
 				<div class="clearfix l-unit__stat-col--left text-center compact"><?=$data[$key]['TTL']?></div>
-				<div class="clearfix l-unit__stat-col--left text-center wide"><?=$data[$key]['SOA']?></div>
+				<div class="clearfix l-unit__stat-col--left text-center"><?=$data[$key]['SOA']?></div>
+				<div class="clearfix l-unit__stat-col--left text-center compact-3">
+					<i class="fas <?=$dnssec_icon;?>"></i>
+				</div>
 				<div class="clearfix l-unit__stat-col--left text-center"><b><?=$data[$key]['EXP']?></b></div>
 				<div class="clearfix l-unit__stat-col--left text-center"><b><?=$data[$key]['EXP']?></b></div>
 			</div>
 			</div>
 		</div>
 		</div>

+ 94 - 0
web/templates/pages/list_dns_public.html

@@ -0,0 +1,94 @@
+<!-- Begin toolbar -->
+<div class="l-center">
+	<div class="l-sort clearfix noselect">
+		<div class="l-unit-toolbar__buttonstrip">
+			<?php if ($read_only !== 'true') {?>
+				<a href="/add/dns/" id="btn-create" class="ui-button cancel" dir="ltr"><i class="fas fa-plus-circle status-icon green"></i><?=_('Add DNS Domain');?></a>
+			<?php } ?>
+		</div>
+		<ul class="context-menu sort-order animated fadeIn" style="display: none;">
+			<li entity="sort-date" sort_as_int="1"><span class="name <?php if ($_SESSION['userSortOrder'] === 'date') { echo 'active'; } ?>"><?=_('Date');?> <i class="fas fa-sort-alpha-down"></i></span><span class="up"><i class="fas fa-sort-alpha-up"></i></span></li>
+			<li entity="sort-expire" sort_as_int="1"><span class="name"><?=_('Expire');?> <i class="fas fa-sort-alpha-down"></i></span><span class="up"><i class="fas fa-sort-alpha-up"></i></span></li>
+			<li entity="sort-ip"><span class="name"><?=_('IP address');?> <i class="fas fa-sort-alpha-down"></i></span><span class="up"><i class="fas fa-sort-alpha-up"></i></span></li>
+			<li entity="sort-name"><span class="name <?php if ($_SESSION['userSortOrder'] === 'name') { echo 'active'; } ?>"><?=_('Name');?> <i class="fas fa-sort-alpha-down"></i></span><span class="up"><i class="fas fa-sort-alpha-up"></i></span></li>
+			<li entity="sort-records"><span class="name"><?=_('Records');?> <i class="fas fa-sort-alpha-down"></i></span><span class="up"><i class="fas fa-sort-alpha-up"></i></span></li>
+		</ul>
+		<span class="name <?php if ($_SESSION['userSortOrder'] === 'date') { echo 'active'; } ?>">
+			<div class="l-sort-toolbar clearfix">
+				<table>
+					<tr>
+						<td class="sort-by" title="<?=_('Sort items');?>">
+							<?=_('sort by');?>: <span>
+								<b>
+									<?php if ($_SESSION['userSortOrder'] === 'name') { $label = _('Name'); } else { $label = _('Date'); } ?>
+									<?=$label;?> <i class="fas fa-sort-alpha-down"></i>
+								</b>
+							</span>
+						</td>
+						<td class="l-sort-toolbar__search-box">
+							<form action="/search/" method="get">
+								<input type="hidden" name="token" value="<?=$_SESSION['token']?>" />
+								<input type="text" class="search-input" name="q" value="<? echo isset($_POST['q']) ? htmlspecialchars($_POST['q']) : '' ?>" title="<?=_('Search');?>">
+								<button type="submit" class="l-sort-toolbar__filter-apply" onclick="return doSearch('/search/')" value="" title="<?=_('Search');?>"><i class="fas fa-search"></i></button>
+							</form>
+						</td>
+						<?php if ($read_only !== 'true') {?>
+							<td>
+								<form action="/bulk/dns/" method="post" id="objects">
+									<input type="hidden" name="token" value="<?=$_SESSION['token']?>" />
+									<div class="l-select">
+										<select name="action" id="">
+											<option value=""><?=_('apply to selected');?></option>
+											<?php if ($_SESSION['userContext'] === 'admin') {?>
+												<option value="rebuild"><?=_('rebuild');?></option>
+											<?php } ?>
+											<option value="suspend"><?=_('suspend');?></option>
+											<option value="unsuspend"><?=_('unsuspend');?></option>
+											<option value="delete"><?=_('delete');?></option>
+										</select>
+									</div>
+									<button type="submit" class="l-sort-toolbar__filter-apply" value="" title="<?=_('apply to selected');?>"><i class="fas fa-arrow-right"></i></button>
+								</form>
+							</td>
+						<?php } ?>
+					</tr>
+				</table>
+			</div>
+	</div>
+</div>
+<!-- End toolbar -->
+
+<div class="l-separator"></div>
+
+<div class="l-center units">
+		
+<div class="l-unit animated fadeIn">
+	<div class="l-unit__col l-unit__col--right">
+		<div class="clearfix l-unit__stat-col--left text-center u-pt18"><b><?=_('DNSKEY record');?></b></div>
+		<div class="clearfix l-unit__stat-col--left wide-3"><b><input type="text" class="vst-input" value="<?php echo $data[$domain]['RECORD'];?>"></b></div>
+	</div>
+</div>
+<div class="l-unit animated fadeIn">
+	<div class="l-unit__col l-unit__col--right">
+		<div class="clearfix l-unit__stat-col--left text-center u-pt18"><b><?=_('DS record');?></b></div>
+		<div class="clearfix l-unit__stat-col--left wide-3"><b><input type="text" class="vst-input" value="<?php echo $data[$domain]['DS'];?>"></b></div>
+	</div>
+</div>
+<div class="l-unit animated fadeIn">
+	<div class="l-unit__col l-unit__col--right">
+		<div class="clearfix l-unit__stat-col--left text-center u-pt18"><b><?=_('Public key');?></b></div>
+		<div class="clearfix l-unit__stat-col--left wide-3"><b><input type="text" class="vst-input" value="<?php echo $data[$domain]['KEY'];?>"></b></div>
+	</div>
+</div>
+<div class="l-unit animated fadeIn">
+	<div class="l-unit__col l-unit__col--right">
+		<div class="clearfix l-unit__stat-col--left text-center u-pt18"><b><?=_('Key Tag / Flag');?></b></div>
+		<div class="clearfix l-unit__stat-col--left wide-3"><b><input type="text" class="vst-input" value="<?php echo $flag;?>"></b></div>
+	</div>
+</div>
+<div class="l-unit animated fadeIn">
+	<div class="l-unit__col l-unit__col--right">
+		<div class="clearfix l-unit__stat-col--left text-center u-pt18"><b><?=_('Algorithm');?></b></div>
+		<div class="clearfix l-unit__stat-col--left wide-3"><b><input type="text" class="vst-input" value="<?php echo $algorithm;?>"></b></div>
+	</div>
+</div>