จะทำให้สามารถใช้งานได้ทั้งภายใน และภายนอก (ภายนอกไม่ค่อยจำเป็น แต่ติดตั้งไว้เผื่อในอนาคตอาจเพิ่มการ lookup จากเซิร์ฟเวอร์ของเราที่อยู่ภายนอก)
โดยจะแยกไอพีภายในและภายนอกเป็น 2 กลุ่ม
และสร้างกรงขังด้วย (chroot jail)
สมมุติว่า
ติดตั้งแพกเกจ แล้วสั่งหยุดการทำงาน
# aptitude install bind9 dnsutils
# /etc/init.d/bind9 stop
เรื่องกรงขัง (chroot jail) จะเก็บไว้ที่ /sys1/sysb/chroot/bind
สร้างไดเรกทอรี่ก่อน แล้วโยงลิงก์ chroot ไปที่ / ให้พิมพ์ง่าย
# mkdir -p /sys1/sysb/chroot/bind
# ln -sf /sys1/sysb/chroot /
# chown root:bind /chroot/bind
แก้ให้อยู่ในกรง
# vi /etc/default/bind9
... # OPTIONS="-u bind" OPTIONS="-u bind -t /chroot/bind" ...
แก้ไขผู้ใช้ชื่อ bind ให้ย้ายบ้านไปที่ /chroot/bind แทน
# usermod --home /chroot/bind bind
เตรียมไดเรคทอรี่ย่อยในกรง
# mkdir -p /chroot/bind/{etc,dev,var/{cache,log,run}}
# mkdir -p /chroot/bind/var/cache/bind
# mv /etc/bind /chroot/bind/etc
# ln -sf /chroot/bind/etc/bind /etc
# mknod /chroot/bind/dev/null c 1 3
# mknod /chroot/bind/dev/random c 1 8
# chmod 666 /chroot/bind/dev/{null,random}
# chown -R bind:bind /chroot/bind/var/*
ทำให้ระบบเก็บปูมของ bind (system logging - syslogd)
# vi /etc/default/syslogd
... # SYSLOGD="" SYSLOGD="-a /chroot/bind/dev/log" ...
ปรับตั้งระบบปูมของ bind
# vi /etc/bind/named.conf.local
... logging { channel "querylog" { file "/var/log/bind9-query.log"; print-time yes; }; category queries { querylog; }; }; ...
ปรับตั้งประวัติปูมของ bind
# vi /etc/logrotate.d/bind9-query
/chroot/bind/var/log/bind9-query.log { weekly missingok rotate 10 postrotate /etc/init.d/bind9 reload > /dev/null endscript compress notifempty }
# ln -sf /chroot/bind/var/log/bind9-query.log /var/log/bind9-query.log
แก้ไข options ให้มาเก็บ pid ในกรงขัง
# vi /etc/bind/named.conf.options
... options { directory "/var/cache/bind"; pid-file "/var/run/named.pid"; ...
เสร็จขั้นต้น ทดสอบระบบครั้งแรก
# /etc/init.d/sysklogd restart
# /etc/init.d/bind9 restart
ต้องไม่มีรายงานข้อผิดพลาด
ถ้าเรียบร้อยก็สั่งหยุดบริการ เพื่อปรับตั้งต่อ
# /etc/init.d/bind9 stop
ต่อไปเป็นเรื่องการทำให้รองรับเครือข่ายภายในและภายนอก
สร้างไดเรกทอรี่ขึ้นมารองรับ
# mkdir -p /etc/bind/{internal,external}
# cd /etc/bind
สร้างกฎ acl สำหรับเครือข่ายภายใน ตั้งชื่อว่า acl_internal (นอกจากนั้นจะถือว่าเป็น external ทั้งหมด)
และให้มาอ่านไฟล์คอนฟิกที่เราจะสร้างขึ้นภายหลัง ของโซน example.com และ example.org
# vi named.conf.local
... acl acl_internal { # 127.0.0.0/8; 192.168.0.0/16; }; include "/etc/bind/allzone.conf"; ...
หมายเหตุ - ปกติวง 127.0.0.0/8 ควรจะถึอเป็นวงในด้วย แต่ในที่นี้เราจะตัดออกจาก acl_internal เนื่องจากเราไม่สามารถสั่งอัปเดตไอพีจากวงในได้ เพราะตั้งเป็นแบบเปลี่ยนค่าไม่ได้ ดังนั้นเราจะใช้ localhost ในการอัปเดตไอพีที่ถูกเรียกจากวงนอก จึงต้องเว้นไว้ แต่ใส่คอมเมนต์ไว้เพื่อจะได้ไม่หลงลืมข้อนี้
สร้างไฟล์คอนฟิกของ example.com และ example.org รวมกัน ตั้งชื่อว่า allzone.conf โดยตัดเอาเนื้อไฟล์ใน named.conf ในส่วนของการกำหนดโซนมาใส่ไว้
(ถ้ามีการใช้ view เราต้องใส่การกำหนดโซนไว้ภายใต้ view เท่านั้น ไม่สามารถกำหนดแบบซ้อนได้)
ตัดเนื้อไฟล์จาก named.conf ออก
# vi named.conf
... //-----8<------------------------------------------- // prime the server with knowledge of the root servers zone "." { type hint; file "/etc/bind/db.root"; }; // be authoritative for the localhost forward and reverse zones, and for // broadcast zones as per RFC 1912 zone "localhost" { type master; file "/etc/bind/db.local"; }; zone "127.in-addr.arpa" { type master; file "/etc/bind/db.127"; }; zone "0.in-addr.arpa" { type master; file "/etc/bind/db.0"; }; zone "255.in-addr.arpa" { type master; file "/etc/bind/db.255"; }; //------------------------------------------->8----- ...
สร้างไฟล์ allzone.conf ในการกำหนดค่าไฟล์ในการคุมทุกโซน โดยเอาเนื้อจาก named.conf ข้างบนมาใส่ในส่วนของ view internal
# vi allzone.conf
include "/etc/bind/key.conf"; view "internal" { match-clients { acl_internal; }; // ----- PASTE FROM named.conf ---------------------------------------- // prime the server with knowledge of the root servers zone "." { type hint; file "/etc/bind/db.root"; }; // be authoritative for the localhost forward and reverse zones, and for // broadcast zones as per RFC 1912 zone "localhost" { type master; file "/etc/bind/db.local"; }; zone "127.in-addr.arpa" { type master; file "/etc/bind/db.127"; }; zone "0.in-addr.arpa" { type master; file "/etc/bind/db.0"; }; zone "255.in-addr.arpa" { type master; file "/etc/bind/db.255"; }; // ----- END PASTE FROM named.conf ------------------------------------ zone "example.com" IN { type master; file "/etc/bind/internal/example.com.zone"; allow-update { none; }; }; zone "1.168.192.in-addr.arpa" IN { type master; file "/etc/bind/internal/example.com.reverse"; allow-update { none; }; }; zone "example.org" IN { type master; file "/etc/bind/internal/example.org.zone"; allow-update { none; }; }; }; view "external" { match-clients { any; }; zone "example.com" IN { type master; file "/etc/bind/external/example.com.zone"; allow-update { key allhost.; }; }; zone "example.org" IN { type master; file "/etc/bind/external/example.org.zone"; allow-update { key allhost.; }; }; };
สร้างกุญแจสำหรับเปลี่ยนค่าโซน ใช้กุญแจเดียวกันทุกโซน
# dnssec-keygen -r /dev/urandom -a HMAC-MD5 -b 512 -n HOST allhost
Kallhost.+157+38278
และได้ไฟล์ Kallhost.+157+38278.key และ Kallhost.+157+38278.private
ตัวอย่างเนื้อไฟล์ของ Kallhost.+157+38278.key มีดังนี้
allhost. IN KEY 512 3 157 hvql4JlIIajNJzxFLuQQQg4HUNSQExpTuO2kzLudphxHPo3+N976ztqI dPXn2rdvVM6mHSG+0wwhlky+MRwQ+Q==
นำเนื้อไฟล์ของ Kallhost.+157+38278.key ท่อนที่เป็นรหัสมาสร้างไฟล์กุญแจ ตั้งชื่อว่า key.conf
# vi key.conf
key allhost. { algorithm HMAC-MD5; secret "hvql4JlIIajNJzxFLuQQQg4HUNSQExpTuO2kzLudphxHPo3+N976ztqI dPXn2rdvVM6mHSG+0wwhlky+MRwQ+Q=="; };
ส่วนต่อไปนี้ เขียนไว้เพื่อให้เห็นโครงสร้าง แต่ตอนหน้าจะเขียนเป็นสคริปต์สำหรับผลิตไฟล์โซน และไฟล์รีเวิร์ส หากคร้านที่จะเขียนโซนไฟล์เอง อาจข้ามไปอ่านส่วนขยายตอนหน้าเลยก็ได้ครับ
ต่อไปเป็นการสร้างไฟล์โซนและไฟล์รีเวิร์สโซน
ไฟล์โซน internal ของ example.com
# vi internal/example.com.zone
$TTL 86400 @ IN SOA server1.example.com. root.server1.example.com. ( 41 ; serial (d. adams) 3H ; refresh 15M ; retry 1W ; expiry 1D ) ; minimum @ NS ns1 server1 IN A 192.168.1.1 www IN CNAME server1 ftp IN CNAME server1 mail IN CNAME server1 ns1 IN CNAME server1 work1 IN A 192.168.1.101 work2 IN A 192.168.1.102 work3 IN A 192.168.1.103
ไฟล์รีเวิร์ส internal ของ example.com
# vi internal/example.com.reverse
$TTL 86400 @ IN SOA server1.example.com. root.server1.example.com. ( 41 ; serial (d. adams) 3H ; refresh 15M ; retry 1W ; expiry 1D ) ; minimum @ NS ns1 1 IN PTR server1.example.com. 101 IN PTR work1.example.com. 102 IN PTR work2.example.com. 103 IN PTR work3.example.com.
ไฟล์โซน internal ของ example.org
# vi internal/example.org.zone
$TTL 86400 @ IN SOA server1.example.org. root.server1.example.org. ( 42 ; serial (d. adams) 3H ; refresh 15M ; retry 1W ; expiry 1D ) ; minimum @ NS ns1 server1 IN A 192.168.1.1 www IN CNAME server1 ns1 IN CNAME server1 mail IN CNAME server1 ftp IN CNAME server1
สร้างโซนไฟล์ external ของ example.com
# vi external/example.com.zone
$TTL 86400 @ IN SOA server1.example.com. root.server1.example.com. ( 51 ; serial (d. adams) 3H ; refresh 15M ; retry 1W ; expiry 1D ) ; minimum @ NS ns1 server1 IN A 101.102.103.104 www IN CNAME server1 ftp IN CNAME server1 mail IN CNAME server1 ns1 IN CNAME server1
สร้างโซนไฟล์ external ของ example.org
# vi external/example.org.zone
$TTL 86400 @ IN SOA server1.example.org. root.server1.example.org. ( 52 ; serial (d. adams) 3H ; refresh 15M ; retry 1W ; expiry 1D ) ; minimum @ NS ns1 server1 IN A 101.102.103.104 www IN CNAME server1 ns1 IN CNAME server1 mail IN CNAME server1 ftp IN CNAME server1
เปลี่ยนเจ้าของและกลุ่ม
# chown -R bind:bind *
ทดสอบขั้นต้น
# /etc/init.d/bind9 restart
ต้องไม่มีรายงานข้อผิดพลาด
เสร็จหมดแล้ว
เนื่องจากเราแบ่งเป็นวงในและวงนอก โดยที่สามารถอัปเดตได้เฉพาะวงนอกเท่านั้น ดังนั้นในการสั่งอัปเดต ต้องระบุเซิร์ฟเวอร์เป็น localhost เท่านั้น (ถ้าระบุเซิร์ฟเวอร์เป็น 192.168.1.1 เขาจะไม่ยอมอัปเดตให้)
ทดลองอัปเดต
# nsupdate -d -v -k /etc/bind/Kallhost.+157+38278.private
Creating key... > server localhost > update add testing.example.com. 86400 IN A 101.102.103.155 > send Reply from SOA query: ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 22523 ;; flags: qr aa rd ra ; QUESTION: 1, ANSWER: 0, AUTHORITY: 1, ADDITIONAL: 1 ;; QUESTION SECTION: ;testing.example.com. IN SOA ;; AUTHORITY SECTION: example.com. 86400 IN SOA server1.example.com. root.server1.example.com. 57 10800 900 604800 86400 ;; TSIG PSEUDOSECTION: allhost. 0 ANY TSIG hmac-md5.sig-alg.reg.int. 1203992365 300 16 sMkuPmAy7VF1RCoGpHjrXA== 22523 NOERROR 0 Found zone name: example.com The master is: server1.example.com Sending update to 127.0.0.1#53 Outgoing update query: ;; ->>HEADER<<- opcode: UPDATE, status: NOERROR, id: 50100 ;; flags: ; ZONE: 1, PREREQ: 0, UPDATE: 1, ADDITIONAL: 1 ;; ZONE SECTION: ;example.com. IN SOA ;; UPDATE SECTION: testing.example.com. 86400 IN A 101.102.103.155 ;; TSIG PSEUDOSECTION: allhost. 0 ANY TSIG hmac-md5.sig-alg.reg.int. 1203992365 300 16 pmaYIKqjlgGU+FJvT3uZxA== 50100 NOERROR 0 Reply from update query: ;; ->>HEADER<<- opcode: UPDATE, status: NOERROR, id: 50100 ;; flags: qr ra ; ZONE: 0, PREREQ: 0, UPDATE: 0, ADDITIONAL: 1 ;; TSIG PSEUDOSECTION: allhost. 0 ANY TSIG hmac-md5.sig-alg.reg.int. 1203992365 300 16 9ca6E1RY9RfHacqi7uSuaQ== 50100 NOERROR 0 > quit
ทั้งหมดต้องไม่มีข้อผิดพลาด
ลองค้นค่าดู
# nslookup testing.example.com localhost
nslookup testing.example.com Server: localhost Address: 127.0.0.1#53 Name: testing.example.com Address: 101.102.103.155
เริ่ม bind ใหม่
# /etc/init.d/bind9 restart
จบส่วนของ name server ปกติ
(ส่วนนี้เป็นตอนต่อจากตอนที่แล้ว คือการทำเรื่อง dynamic dns client)
กลับไปแก้ไขไฟล์ d.router-reconnect โดยเพิ่มส่วนของการอัปเดตไอพี
# vi /usr/local/sbin/d.router-reconnect
... #-------ADDITIONAL BIND9 SCRIPT:------------------ #UPDATE LOCAL BIND9 IP=`/usr/local/sbin/d.router-getip` KEY="/etc/bind/Kallhost.+157+38278.private" HOSTNAME=`hostname` #GET DOMAIN FROM FIRST PROVIDER ONLY DIR="/etc/ddns/ddns-enabled" PROVIDER=`ls $DIR | cut -d\ -f1` . $DIR/$PROVIDER for i in $UPDATE_DOMAIN; do DOMAIN=`echo $i | cut -d: -f1` nsupdate -k $KEY << EOF server localhost update delete $HOSTNAME.$DOMAIN update add $HOSTNAME.$DOMAIN. 86400 IN A $IP send quit EOF done
จบจริง ๆ แล้ว
อ้างอิง
ท่อนนี้ไม่มีอะไรมาก เพียงแต่ต้องการรวมศูนย์ข้อมูลไว้ในไฟล์เดียว เพื่อต้องการให้ดูง่ายตรวจสอบง่ายและลดโอกาสผิดพลาดในการแก้ไขไฟล์โซนและไฟล์รีเวิร์สโซน
จึงสร้างเป็นสคริปต์เล็ก ๆ ขึ้นมาเพื่อใช้อ่านค่าข้อมูลที่เราสร้างเอาไว้ แล้วผลิตไฟล์โซนต่าง ๆ ออกมาให้ครบตามที่เราตั้งไว้
สคริปต์ตั้งชื่อว่า 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
ปรับสคริปต์นิดหน่อย
# 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:IP_D:CNAME1 CNAME2 ...:SERIAL:IP_ABC # ns:NAMESERVER1 NAMESERVER2 # mx:MAILSERVER1,RR1 MAILSERVER2,RR2 # IP_D:NAME CNAME1 CNAME2 ... # ... # EXAMPLE: # zone:example.com:1:server1 ns1 mail www ftp:43:192.168.1 # ns:ns1 ns2 # mx:mail,10 mail2,20 # 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:IP_D:CNAME1 CNAME2 ...:SERIAL:IP_ABC [ns:NAMESERVER1 NAMESERVER2] [mx:MAILSERVER1,RR1 MAILSERVER2,RR2] IP_D:NAME CNAME1 CNAME2 ... ... EXAMPLE OF DATAFILE: example1: zone:example.com:1:server1 ns1 mail www ftp:43:192.168.1 ns:ns1 ns2 mx:mail,10 mail2,20 2:ns2 101:work1 102:work2 192.168.5.1:router ... example2: zone:ns2.example.org:2::44:192.168.1 ns:ns1 ns2 EOF } function gen_header { Z=$1 S=$2 cat << EOF \$TTL $TTL @ IN SOA $Z. root.$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="" 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) IP_D=$(echo $DATA | cut -d: -f3) CNAMES=$(echo $DATA | cut -d: -f4) SERIAL=$(echo $DATA | cut -d: -f5) IP_ABC=$(echo $DATA | cut -d: -f6) #FORWARD ZONE FILE ZONEFILE="$ZONENAME.zone" if [ -f "$ZONEFILE" ]; then mv "$ZONEFILE" "$ZONEFILE.bak" fi FULL_IP=`get_ip $IP_D $IP_ABC` gen_header $ZONENAME $SERIAL > $ZONEFILE chown $BINDUSER:$BINDGROUP $ZONEFILE gen_name "@" $FULL_IP >> $ZONEFILE for i in $CNAMES; do gen_cname $i $ZONENAME >> $ZONEFILE done if [ "$WITHREVERSE" ]; then #REVERSE ZONE FILE REVERSEFILE="$ZONENAME.reverse" if [ -f "$REVERSEFILE" ]; then mv "$REVERSEFILE" "$REVERSEFILE.bak" fi gen_header $ZONENAME $SERIAL > $REVERSEFILE chown $BINDUSER:$BINDGROUP $REVERSEFILE gen_ptr $IP_D "" >> $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) echo "gen_name $FIRSTNAME $FULL_IP $ZONEFILE" 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