如何在Synology NAS上从DHCP更新非Windows DNS服务器A记录

时间:2018-11-05 22:32:46

标签: dns dhcp synology

背景 我想从我的DHCP服务器动态更新我的DNS A记录,它们都运行在同一个Synology NAS上。遗憾的是,Synology尚未(为此)提供有效的解决方案。

我一直在使用shell script来完成此操作,但是它似乎不完美,因为一段时间(几天,几周)后,我的DNS服务器不再解析我的本地地址,这很可能是因为shell脚本将dns记录置于不兼容的顺序。

所以..

3 个答案:

答案 0 :(得分:2)

没关系,我发现了一种不同于c#和mono的方式来动态更新本地dns。

我最初尝试的脚本是我发现的脚本here,但是几天后,由于某些未知原因,我的本地DNS查询不再起作用。

事实证明,租约更改后,Synology NAS上的dhcp服务器(DS214Play)在位置/usr/share/dhcpd/dhcpd-script.sh上调用了bash脚本

我发现您实际上可以使用nsupdate命令轻松更改(本地)dns记录后,将现有脚本更新为以下脚本。我添加的行标有我的缩写HH。

关于dns更新的安全性:我没有使用密钥,因为我的DNS服务器仍然只接受来自内部网络和本地主机的更新。

如果您发现我的答案很有用,请在问题仍为否定的情况下,对问题进行投票。 (我自己回答了)

#!/bin/sh
# Copyright (c) 2000-2013 Synology Inc. All rights reserved.
# HH20181109 Updated for dynamic DNS updates

DHCPD_DIR="/etc/dhcpd/"
LEASE_FILE="${DHCPD_DIR}/dhcpd.conf.leases"
LOG_FILE="${DHCPD_DIR}/dhcpd-leases.log"
TMP_FILE="${DHCPD_DIR}/tmp-dhcpd-leases.log"

# define the zone (local domain name) here, but without a trailing point
ZONE_NAME="hhbhasenack.local"

# Prepare a file for updating the DNS through the nsupdate command
TMP_NSUPDATE="${DHCPD_DIR}/tmp-nsupdate.log"
NSUPDATE_LOG_FILE="${DHCPD_DIR}/nsupdate.log"
echo "server 127.0.0.1" > ${TMP_NSUPDATE}
echo "zone ${ZONE_NAME}." >> ${TMP_NSUPDATE}


del_leases() { # $2: mac
    local mac=$2
    grep -v "${mac}" ${LOG_FILE} > ${TMP_FILE}
    cp ${TMP_FILE} ${LOG_FILE}
# HH:prep dns update command
    local ip="$3"
    local hostname="$4"
    echo "update delete ${hostname}.${ZONE_NAME}" >> ${TMP_NSUPDATE}
}

renew_record() { # $1: expired $2 mac $3 ip $4 hostname $5 iface
    local record=$@
    local mac=$2
    local iface=$5

    grep -v "${mac}" ${LOG_FILE} > ${TMP_FILE}
    echo "${record}" >> ${TMP_FILE}
    cp ${TMP_FILE} ${LOG_FILE}

# HH:prep dns update command
    local ip="$3"
    local hostname="$4"
    echo "update delete ${hostname}.${ZONE_NAME} A"  >> ${TMP_NSUPDATE}
    echo "update add ${hostname}.${ZONE_NAME} 3600 A ${ip}" >> ${TMP_NSUPDATE}

}

add_new_record() {
    local record="$@"
    local mac=$2

    # when disable dhcp-server and any lease is expired, then next time the dhcp client
    # renew the lease the action will be add, so remove the old record has same MAC address
    grep -v "${mac}" ${LOG_FILE} > ${TMP_FILE}
    cp ${TMP_FILE} ${LOG_FILE}

    if [ -s ${LOG_FILE} ]; then
        sed -i "1 i${record}" ${LOG_FILE}
    else
        echo ${record} >> ${LOG_FILE}
    fi

# HH:prep dns update command
    local ip="$3"
    local hostname="$4"
    echo "update add ${hostname}.${ZONE_NAME} 3600 A ${ip}" >> ${TMP_NSUPDATE}
}

get_hostname_from_logfile() {
    local mac="$1"
    local filename="";
    local line="`grep \"${mac}\" ${LOG_FILE}`"
    local tokens=( $line )

    if [ 5 -eq ${#tokens[@]} ]; then
        filename=${tokens[3]}
    fi

    echo $filename
}

get_new_record() {
    local mac="$2"
    local ip="$3"
    local hostname="$4"
    local fileHostname=$(get_hostname_from_logfile $mac)

    if [ "x" = "x${hostname}" ] && [ "xold" = "x${ACTION}" ];then
        if [ "x" != "x${DNSMASQ_SUPPLIED_HOSTNAME}" ]; then
            hostname=${DNSMASQ_SUPPLIED_HOSTNAME}
        elif [ "x" != "x${fileHostname}" ]; then
            hostname=${fileHostname}
        fi
    fi

    NEW_RECORD="${DNSMASQ_LEASE_EXPIRES} ${mac} ${ip} ${hostname} ${DNSMASQ_INTERFACE}"
}

# record format: action mac ip hostname
NEW_RECORD=$@
ACTION=`echo ${NEW_RECORD} | awk '{print $1}'`

if [ "${DNSMASQ_INTERFACE}" = "" ]; then
    exit 0
fi
get_new_record ${NEW_RECORD}

case "${ACTION}" in
    old)
        renew_record ${NEW_RECORD}
        ;;
    add)
        add_new_record ${NEW_RECORD}
        ;;
    del)
        del_leases ${NEW_RECORD}
        ;;
    *)
        ;;
esac

# HH:complete command file for nsupdate with a send command
echo "send" >> ${TMP_NSUPDATE}
# HH: actually execute the nsupdate command
nsupdate ${TMP_NSUPDATE} >>${NSUPDATE_LOG_FILE}



exit 0

答案 1 :(得分:0)

这对我不起作用。我的区域是在Synology Directory Server安装过程中创建的。由于该区域是通过samba进行管理的,因此使用nsupdate进行任何数量的操作和使用密钥都不会起作用。

Smb-tool已经安装好,可以很好地处理我的用例。除了脚本以外,唯一的其他任务是创建一个非特权服务帐户并将其添加到“ DNSAdmins”组。

这是我的版本:

#!/bin/sh
# Copyright (c) 2000-2013 Synology Inc. All rights reserved.
#GB: define our variables
ZONE="example.com"
REVERSE="1.168.192.in-addr.arpa"
SERVER="127.0.0.1"
USERNAME="dhcp-to-dns"
PASSWORD="insertreallyinsecurepasswordhere"

DHCPD_DIR="/etc/dhcpd/"
LEASE_FILE="${DHCPD_DIR}/dhcpd.conf.leases"
LOG_FILE="${DHCPD_DIR}/dhcpd-leases.log"
TMP_FILE="${DHCPD_DIR}/tmp-dhcpd-leases.log"

del_leases() { # $2: mac
    local mac=$2
    local IP=$3
#GB: Define Reverse IP address and Hostname. Could have defined this global but stuck with the conventions of the original script
    local REVIP=$(echo $IP | cut -d '.' -f 4)
    local HOSTNAME=$4
    grep -v "${mac}" ${LOG_FILE} > ${TMP_FILE}
    cp ${TMP_FILE} ${LOG_FILE}
#GB: use samba-tool to delete forward/reverse DNS entries of expired leases.
    samba-tool dns delete $SERVER $ZONE $HOSTNAME A $IP --username=$USERNAME --password=$PASSWORD 2> /dev/null
    samba-tool dns delete $SERVER $REVERSE $REVIP PTR ${HOSTNAME}.${ZONE} --username=$USERNAME --password=$PASSWORD 2> /dev/null
}

renew_record() { # $1: expired $2 mac $3 ip $4 hostname $5 iface
    local record=$@
    local mac=$2
    local iface=$5

    grep -v "${mac}" ${LOG_FILE} > ${TMP_FILE}
    echo "${record}" >> ${TMP_FILE}
    cp ${TMP_FILE} ${LOG_FILE}
}

add_new_record() {
    local record="$@"
    local mac=$2
#GB: Variables again
    local IP=$3
    local REVIP=$(echo $IP | cut -d '.' -f 4)
    local HOSTNAME=$4

    # when disable dhcp-server and any lease is expired, then next time the dhcp client
    # renew the lease the action will be add, so remove the old record has same MAC address
    grep -v "${mac}" ${LOG_FILE} > ${TMP_FILE}
    cp ${TMP_FILE} ${LOG_FILE}

    if [ -s ${LOG_FILE} ]; then
        sed -i "1 i${record}" ${LOG_FILE}
    else
        echo ${record} >> ${LOG_FILE}
    fi
#GB: Use samba-tool to add forward/reverse DNS Entries.
    samba-tool dns add $SERVER $ZONE $HOSTNAME A $IP --username=$USERNAME --password=$PASSWORD 2> /dev/null
    samba-tool dns add $SERVER $REVERSE $REVIP PTR ${HOSTNAME}.${ZONE} --username=$USERNAME --password=$PASSWORD 2> /dev/null
}

get_hostname_from_logfile() {
    local mac="$1"
    local filename="";
    local line="`grep \"${mac}\" ${LOG_FILE}`"
    local tokens=( $line )

    if [ 5 -eq ${#tokens[@]} ]; then
        filename=${tokens[3]}
    fi

    echo $filename
}

get_new_record() {
    local mac="$2"
    local ip="$3"
    local hostname="$4"
    local fileHostname=$(get_hostname_from_logfile $mac)

    if [ "x" = "x${hostname}" ] && [ "xold" = "x${ACTION}" ];then
        if [ "x" != "x${DNSMASQ_SUPPLIED_HOSTNAME}" ]; then
            hostname=${DNSMASQ_SUPPLIED_HOSTNAME}
        elif [ "x" != "x${fileHostname}" ]; then
            hostname=${fileHostname}
        fi
    fi

    NEW_RECORD="${DNSMASQ_LEASE_EXPIRES} ${mac} ${ip} ${hostname} ${DNSMASQ_INTERFACE}"
}

# record format: action mac ip hostname
NEW_RECORD=$@
ACTION=`echo ${NEW_RECORD} | awk '{print $1}'`

if [ "${DNSMASQ_INTERFACE}" = "" ]; then
    exit 0
fi
get_new_record ${NEW_RECORD}

case "${ACTION}" in
    old)
        renew_record ${NEW_RECORD}
        ;;
    add)
        add_new_record ${NEW_RECORD}
        ;;
    del)
        del_leases ${NEW_RECORD}
        ;;
    *)
        ;;
esac

exit 0

答案 2 :(得分:0)

另一个使用类似NAS diagram1

的图表的示例

从上面完成诊断所使用的角色是:域服务器,DNS服务器,DHCPD服务器。 管理DNS更改的用户是dhcptodns(Synology Directory Server中DNSAdmin组的一部分)。 在这种情况下,脚本/usr/share/dhcpd/dhcpd-script.sh是:

// Rule 1 check parent metadata category whether be empty

// Rule 2 and 3
function find_in_children(children, parent_category) {
    children_has_same_category = []
    for(var i in children) {
        let child = children[i];
        if(child.children != undefined && child.children.length > 0 && child.data.metadata.category == parent_category) {
            children_has_same_category.push(child);
        }
    }
    if(children_has_same_category.length > 0) {
        return children_has_same_category
    } else {
        for(var i in children) {
            let child = children[i];
            return find_in_children(child.children, parent_category);
        }
    }
}

function check_object(object) {
    let parent_category = object.data.metadata.category[0];
    if(object.children != undefined && object.children.length > 0) {
        return {'data': object.data, 'children': find_in_children(object.children, parent_category)}
    } else {
        return {'data': object.data}
    }
}

function apply_rules(object) {
    // Rule 1 check parent metadata category whether be empty
    if(object.data.metadata.category.length > 0) {
        return {'data': object.data}
    } else {
        return check_object(object)
    }
}

 target = {
    value: 'Isv'
}
filtered_datas = []
for(var i in datas) {
    let data = datas[i];
    if(data.data.metadata.category.length > 0) {
        result = apply_rules(data)
        if(result.data.metadata.category[0] == target.value) {
            filtered_datas.push(result);
        }
    }
}

我已将日志记录功能添加到synology系统日志中:

#!/bin/sh
# Copyright (c) 2000-2013 Synology Inc. All rights reserved.
ZONE="yourdomain.local"
REVERSE="1.168.192.in-addr.arpa"
SERVER="127.0.0.1"
USERNAME="dhcptodns"
PASSWORD="change_me_with_a_real_password"

DHCPD_DIR="/etc/dhcpd/"
LEASE_FILE="${DHCPD_DIR}/dhcpd.conf.leases"
LOG_FILE="${DHCPD_DIR}/dhcpd-leases.log"
TMP_FILE="${DHCPD_DIR}/tmp-dhcpd-leases.log"

internal_logger() {
     local _tmp_msg1="$1"
         /usr/syno/bin/synologset1 sys info 0x11100000 "DHCP:$$:${_tmp_msg1} "
     return 0
}

del_leases() {
# $1: expired
# $2: mac
# $3: ip
# $4: hostname
# $5: iface
   local del_MAC=$2
   local del_IP=$3
   local del_REVIP=$(echo ${del_IP} | cut -d '.' -f 4)
   local del_HOSTNAME=$4
   internal_logger  "del $2 $3 $4"
   grep -vi "$del_MAC" ${LOG_FILE} > ${TMP_FILE}
   cp ${TMP_FILE} ${LOG_FILE}
   cat  ${LOG_FILE}
   if [ `samba-tool dns query $SERVER $ZONE ${del_HOSTNAME} --username=${USERNAME} A --password=${PASSWORD} 2>/dev/null|grep 'A:'|sed 's/(.*//;s/.*A: //'|wc -l|cut -d ' ' -f 1` -gt 0 ] ; then
   {
     for del_i in `samba-tool dns query $SERVER $ZONE ${del_HOSTNAME} A --username=${USERNAME} --password=${PASSWORD} 2>/dev/null|grep 'A:'|sed 's/(.*//;s/.*A: //'` ; do
        internal_logger  "Record to be cleaned.... ${del_i}"
        samba-tool dns delete $SERVER $ZONE ${del_HOSTNAME} A ${del_i} --username=$USERNAME --password=${PASSWORD} 2>/dev/null
        internal_logger  "samba-tool dns delete $SERVER $ZONE ${del_HOSTNAME} A ${del_i} --username=${USERNAME} --password=<masked>"
     done
   }
   fi
   # Reverse is already cleaned up
   samba-tool dns delete $SERVER $REVERSE ${del_REVIP} PTR ${del_HOSTNAME}.${ZONE} --username=${USERNAME} --password=${PASSWORD} 2>/dev/null
   internal_logger  "samba-tool dns delete $SERVER $REVERSE ${del_REVIP} PTR ${del_HOSTNAME}.${ZONE} --username=${USERNAME} --password=<masked>"
   return 0
}

renew_record() {
# $1: expired
# $2: mac
# $3: ip
# $4: hostname
# $5: iface
   local record=$@
   local mac=$2
   local iface=$5

   grep -vi "${mac}" ${LOG_FILE} > ${TMP_FILE}
   echo "${NEW_RECORD}" >> ${TMP_FILE}
   cp ${TMP_FILE} ${LOG_FILE}
   return 0
}

add_new_record() {
# $1: expired
# $2: mac
# $3: ip
# $4: hostname
# $5: iface
   local record="$@"
   local mac=$2
   local IP=$3
   local REVIP=$(echo $IP | cut -d '.' -f 4)
   local HOSTNAME=$4

   # when disable dhcp-server and any lease is expired, then next time the dhcp client
   # renew the lease the action will be add, so remove the old record has same MAC address
   grep -v "${mac}" ${LOG_FILE} > ${TMP_FILE}
   cp ${TMP_FILE} ${LOG_FILE}
   if [ -s ${LOG_FILE} ]; then
       sed -i "1 i${record}" ${LOG_FILE}
   else
       echo ${record} >> ${LOG_FILE}
   fi
   # DEBUG
   #internal_logger `samba-tool dns query $SERVER $ZONE $HOSTNAME --username=$USERNAME A --password=$PASSWORD 2>/dev/null|grep 'A:'|sed 's/(.*//;s/.*A: //'|wc -l|cut -d ' ' -f 1`
   if [ `samba-tool dns query $SERVER $ZONE $HOSTNAME --username=$USERNAME A --password=$PASSWORD 2>/dev/null|grep 'A:'|sed 's/(.*//;s/.*A: //'|wc -l|cut -d ' ' -f 1` -gt 0 ] ; then
   {
      del_leases  ${NEW_RECORD}
   }
   fi
   samba-tool dns add $SERVER $ZONE $HOSTNAME A $IP --username=$USERNAME --password=$PASSWORD 2> /dev/null
   internal_logger  "samba-tool dns add $SERVER $ZONE $HOSTNAME A $IP --username=$USERNAME --password=<masked>"
   samba-tool dns add $SERVER $REVERSE $REVIP PTR ${HOSTNAME}.${ZONE} --username=$USERNAME --password=$PASSWORD 2> /dev/null
   internal_logger  "samba-tool dns add $SERVER $REVERSE $REVIP PTR ${HOSTNAME}.${ZONE} --username=$USERNAME --password=<masked>"
   return 0
}

get_hostname_from_logfile() {
   local mac="$1"
   local filename="";
   local line="`grep \"${mac}\" ${LOG_FILE}`"
   local tokens=( $line )

   if [ 5 -eq ${#tokens[@]} ]; then
       filename=${tokens[3]}
   fi
   echo $filename
}

get_new_record() {
# $1: expired
# $2: mac
# $3: ip
# $4: hostname
# $5: iface
   local VALIDHOSTMAC="$2"
   local VALIDHOSTIP="$3"
   local VALIDHOST="$4"
   local VALIDHOSTIF="$5"
   local FILEVALIDHOST=$(get_hostname_from_logfile $mac)
   if [[ "X${VALIDHOST}" == "X" ]] && [[ "Xold" == "X${ACTION}" ]]; then
   {
    [[ "X${DNSMASQ_SUPPLIED_HOSTNAME}" == "X" ]] || VALIDHOST=${DNSMASQ_SUPPLIED_HOSTNAME}
    [[ "X${VALIDHOST}" == "X" ]] &&  export VALIDHOST=${FILEVALIDHOST}
    [[ "X${VALIDHOST}" == "X" ]] && VALIDHOST="unknown_`echo $VALIDHOSTMAC|tr -d ':'`"
        # DEBUG
        #internal_logger  "Exception found: $1 $2 $3 $4"
   }
   fi
   [[ "X$VALIDHOST" == "X" ]] && VALIDHOST="unknown_`echo $VALIDHOSTMAC|tr -d ':'`"
   NEW_RECORD="${DNSMASQ_LEASE_EXPIRES} ${VALIDHOSTMAC} ${VALIDHOSTIP} ${VALIDHOST} ${DNSMASQ_INTERFACE}"
   return 0
}

# record format: action mac ip hostname
NEW_RECORD=$@
ACTION=`echo ${NEW_RECORD} | awk '{print $1}'`

[[ "X${DNSMASQ_INTERFACE}" == "X" ]] && exit 0

get_new_record ${NEW_RECORD}

case "${ACTION}" in
    old)
        renew_record ${NEW_RECORD}
        ;;
    add)
        add_new_record ${NEW_RECORD}
        ;;
    del)
        del_leases ${NEW_RECORD}
        ;;
    *)
        ;;
esac

exit 0

并修复了添加不提供DNSMASQ_SUPPLIED_HOSTNAME字段的主机。添加主机名的块,例如unknown_mac:

internal_logger() {
     local _tmp_msg1="$1"
     #[ -t ] || echo -e "${_tmp_msg1}" && echo -e "${_tmp_msg1}" |tee -a /etc/dhcpd/debug.log
     /usr/syno/bin/synologset1 sys info 0x11100000 "DHCP:$$:${_tmp_msg1} "
     return 0
}