all-in-one 4.1 (bind9 - zone generator script)

ทำ dns server โดยใช้ bind9 - ต่อส่วนขยาย

ท่อนนี้ไม่มีอะไรมาก เพียงแต่ต้องการรวมศูนย์ข้อมูลไว้ในไฟล์เดียว เพื่อต้องการให้ดูง่ายตรวจสอบง่ายและลดโอกาสผิดพลาดในการแก้ไขไฟล์โซนและไฟล์รีเวิร์สโซน
จึงสร้างเป็นสคริปต์เล็ก ๆ ขึ้นมาเพื่อใช้อ่านค่าข้อมูลที่เราสร้างเอาไว้ แล้วผลิตไฟล์โซนต่าง ๆ ออกมาให้ครบตามที่เราตั้งไว้

สคริปต์ตั้งชื่อว่า d.bind-genzone เอาไว้ที่ /usr/local/sbin มีดังนี้
# vi /usr/local/sbin/d.bind-genzone

#!/bin/bash
# GENERATE ZONE FILE [AND REVERSE ZONE FILE IF ADD OPTION -b]
# READ DATA FROM DATAFILE IN FORMAT
#     zone:ZONENAME:HOSTNAME:SERIAL:IP_ABC
#     ns:NAMESERVER1 NAMESERVER2
#     mx:MAILSERVER1,RR1 MAILSERVER2,RR2
#     IP_D:NAME CNAME1 CNAME2 ...
#     ...
# EXAMPLE:
#     zone:example.com:server1:43:192.168.1
#     ns:ns1 ns2
#     mx:mail,10 mail2,20
#     1:server1 ns1 mail www ftp
#     2:ns2
#     101:work1
#     102:work2
#     ...

#GLOBAL VAR
TTL=86400
BINDUSER="bind"
BINDGROUP="bind"

#FUNTION
function usage {
    cat << EOF

Script to generate zone file and reverse zone file
USAGE: $0 [-b] DATAFILE
OPTIONS:
  -b = both, generate both forward and reverse zone file,
       only generate forward zone file, if omitted
ARGUMENT:
  DATAFILE : datafile in format:-
     zone:ZONENAME:HOSTNAME:SERIAL:IP_ABC
    [ns:NAMESERVER1 NAMESERVER2]
    [mx:MAILSERVER1,RR1 MAILSERVER2,RR2]
     IP_D:NAME CNAME1 CNAME2 ...
     ...
  EXAMPLE OF DATAFILE:
  example1:
     zone:example.com:server1:43:192.168.1
     ns:ns1 ns2
     mx:mail,10 mail2,20
     1:server1 ns1 mail www ftp
     2:ns2
     101:work1
     102:work2
     192.168.5.1:router
     ...
  example2:
     zone:example.org:ns2:44:192.168.1
     2:ns2
     ns:ns1 ns2

EOF
}

function gen_header {
    Z=$1
    H=$2
    S=$3
    cat << EOF
\$TTL   $TTL
@       IN      SOA $H.$Z. root.$H.$Z. (
                        $S      ; serial (d. adams)
                        3H      ; refresh
                        15M     ; retry
                        1W      ; expiry
                        1D )    ; minimum
EOF
}

function gen_ns {
    H=$1
    cat << EOF
@               NS      $H
EOF
}

function gen_mx {
    H=$1
    R=$2
    cat << EOF
@               MX      $R $H
EOF
}

function gen_name {
    N=$1
    I=$2
    cat << EOF
$N      IN      A       $I
EOF
}

function gen_ptr {
    I=$1
    N=$2
    cat << EOF
$I      IN      PTR     $N.$ZONENAME.
EOF
}

function gen_cname {
    C=$1
    N=$2
    cat << EOF
$C      IN      CNAME   $N
EOF
}

function get_ip {       
    I1="$1."      #input ip     
    I2="$2."      #$IP_ABC      
    A=$(echo "$I1" | cut -d. -f1) 
    B=$(echo "$I1" | cut -d. -f2)
    C=$(echo "$I1" | cut -d. -f3)
    D=$(echo "$I1" | cut -d. -f4)
    W=$(echo "$I2" | cut -d. -f1)
    X=$(echo "$I2" | cut -d. -f2)
    Y=$(echo "$I2" | cut -d. -f3)
    Z=$(echo "$I2" | cut -d. -f4)
    if [ ! "$B" ]; then
        echo "$W.$X.$Y.$A"; return
    elif [ ! "$C" ]; then
        echo "$W.$X.$A.$B"; return
    elif [ ! "$D" ]; then
        echo "$W.$A.$B.$C"; return
    else
        echo "$I1"      
    fi
}

#BEGIN MAIN
DATAFILE=""
WITHREVERSE=""
    
while getopts "b" ARGS; do
    case "$ARGS" in
        b) WITHREVERSE="true"; shift $(($OPTIND - 1)) ;;
    esac
done

DATAFILE=$1
shift

while getopts "b" ARGS; do
    case "$ARGS" in
        b) WITHREVERSE="true"; shift $(($OPTIND - 1)) ;;
    esac
done

if [ ! "$DATAFILE" ] || [ ! -f "$DATAFILE" ]; then
    usage
    exit 1
fi

ZONENAME=""
HOSTNAME=""
SERIAL=""
IP_ABC=""
ZONEFILE=""
REVERSEFILE=""

cat $DATAFILE | grep -v "#" | while read DATA; do
    #ZONE HEADER
    if [ "${DATA:0:5}" == "zone:" ]; then
        ZONENAME=$(echo $DATA | cut -d: -f2)
        HOSTNAME=$(echo $DATA | cut -d: -f3)
        SERIAL=$(echo $DATA | cut -d: -f4)
        IP_ABC=$(echo $DATA | cut -d: -f5)

        #FORWARD ZONE FILE
        ZONEFILE="$ZONENAME.zone"
        if [ -f "$ZONEFILE" ]; then
            mv "$ZONEFILE" "$ZONEFILE.bak"
        fi
        gen_header $ZONENAME $HOSTNAME $SERIAL > $ZONEFILE
        chown $BINDUSER:$BINDGROUP $ZONEFILE

        if [ "$WITHREVERSE" ]; then
            #REVERSE ZONE FILE
            REVERSEFILE="$ZONENAME.reverse"
            if [ -f "$REVERSEFILE" ]; then
                mv "$REVERSEFILE" "$REVERSEFILE.bak"
            fi
            gen_header $ZONENAME $HOSTNAME $SERIAL > $REVERSEFILE
            chown $BINDUSER:$BINDGROUP $REVERSEFILE
    
            echo "Generate $ZONEFILE and $REVERSEFILE ..."
        else
            echo "Generate $ZONEFILE ..."
        fi

    #NS 
    elif [ "${DATA:0:3}" == "ns:" ] && [ "$ZONENAME" ]; then
        for i in $(echo $DATA | cut -d: -f2); do
            gen_ns $i >> $ZONEFILE
            if [ "$WITHREVERSE" ]; then
                gen_ns $i >> $REVERSEFILE
            fi
        done
    
    #MX
    elif [ "${DATA:0:3}" == "mx:" ] && [ "$ZONENAME" ]; then
        for i in $(echo $DATA | cut -d: -f2); do
            $MAILNAME=$(echo $i | cut -d, -f1)
            $RRPRIORITY=$(echo $i | cut -d, -f2)
            gen_mx $MAILNAME $RRPRIORITY >> $ $ZONEFILE
        done
    
    #DATA
    elif [ "$DATA" ]; then
        RAW_IP=$(echo $DATA | cut -d: -f1)
        FULL_IP=`get_ip $RAW_IP $IP_ABC`
        NAMES=$(echo $DATA | cut -d: -f2)
        FIRSTNAME=$(echo $NAMES | cut -d\  -f1)
        gen_name $FIRSTNAME $FULL_IP >> $ZONEFILE
        if [ "$WITHREVERSE" ]; then
            gen_ptr $RAW_IP $FIRSTNAME >> $REVERSEFILE
        fi
        for i in $NAMES; do
            if [ "$i" != "$FIRSTNAME" ]; then
                gen_cname $i $FIRSTNAME >> $ZONEFILE
            fi
        done
    fi  

done

แก้ให้รันได้เฉพาะ root
# chmod 700 /usr/local/sbin/d.bind-genzone

หลังจากนั้นสร้างไฟล์ข้อมูลของ internal บรรจุข้อมูลของ example.com เอาไว้ใน /etc/bind/internal ตั้งชื่อว่า both-data เพราะจะทำค้นย้อนด้วย ดังนี้
# cd /etc/bind/internal
# vi both-data

# DATAFILE FORMAT
#     zone:ZONENAME:HOSTNAME:SERIAL:IP_ABC
#     ns:NAMESERVER1 NAMESERVER2
#     mx:MAILSERVER1,RR1 MAILSERVER2,RR2
#     IP_D:NAME CNAME1 CNAME2 ...
#     ...
# EXAMPLE:
#     zone:example.com:server1:43:192.168.1
#     ns:ns1 ns2
#     mx:mail,10 mail2,20
#     1:server1 ns1 mail www ftp
#     2:ns2
#     101:work1
#     102:work2
#     ...

#EXAMPLE.COM
zone:example.com:server1:41:192.168.1
ns:ns1
1:server1 www ftp mail ns1
101:work1
102:work2
103:work3

สั่งผลิตไฟล์
# d.bind-genzone -b both-data
จะได้ไฟล์โซนและไฟล์รีเวิร์สโซน ของ example.com ที่เป็นของเครือข่ายภายในออกมา
(ถ้ามีไฟล์เก่า จะสำเนาไว้ในชื่อเดิม ต่อท้ายนามสกุลด้วย .bak)

สร้างไฟล์ข้อมูลของ internal บรรจุข้อมูลของ example.org ตั้งชื่อว่า forward-data เพราะจะทำค้นชื่ออย่างเดียว ไม่ทำค้นย้อน ดังนี้
# vi forward-data

# DATAFILE FORMAT
#     zone:ZONENAME:HOSTNAME:SERIAL:IP_ABC
#     ns:NAMESERVER1 NAMESERVER2
#     mx:MAILSERVER1,RR1 MAILSERVER2,RR2
#     IP_D:NAME CNAME1 CNAME2 ...
#     ...
# EXAMPLE:
#     zone:example.com:server1:43:192.168.1
#     ns:ns1 ns2
#     mx:mail,10 mail2,20
#     1:server1 ns1 mail www ftp
#     2:ns2
#     101:work1
#     102:work2
#     ...

#EXAMPLE.ORG
zone:example.org:server1:42:192.168.1
ns:ns1
1:server1 www ns1 mail ftp

สั่งผลิตไฟล์ โดยไม่ต้องใส่ออปชั่น -b
# d.bind-genzone forward-data
จะได้ไฟล์โซน ของ example.org ที่เป็นของเครือข่ายภายใน

และสร้างไฟล์ข้อมูลของ external บรรจุข้อมูลของทุกโซน เอาไว้ใน /etc/bind/external ตั้งชื่อว่า forward-data (จะทำแค่ forward อย่างเดียว) ดังนี้
# cd /etc/bind/external
# vi forward-data

# DATAFILE FORMAT
#     zone:ZONENAME:HOSTNAME:SERIAL:IP_ABC
#     ns:NAMESERVER1 NAMESERVER2
#     mx:MAILSERVER1,RR1 MAILSERVER2,RR2
#     IP_D:NAME CNAME1 CNAME2 ...
#     ...
# EXAMPLE:
#     zone:example.com:server1:43:192.168.1
#     ns:ns1 ns2
#     mx:mail,10 mail2,20
#     1:server1 ns1 mail www ftp
#     2:ns2
#     101:work1
#     102:work2
#     ...

#EXAMPLE.COM
zone:example.com:server1:51:101.102.103
ns:ns1
104:server1 www ftp mail ns1

#EXAMPLE.ORG
zone:example.org:server1:52:101.102.103
ns:ns1
104:server1 www ns1 mail ftp

สั่งผลิตไฟล์ โดยไม่ต้องใส่ออปชั่น -b
# d.bind-genzone forward-data
จะได้เฉพาะไฟล์โซนของ example.com และ example.org ที่เป็นของเครือข่ายภายนอก

เสร็จแล้ว สั่งเริ่ม bind9 ใหม่ได้เลย
# /etc/init.d/bind9 restart

Topic: