- 論壇徽章:
- 1
|
3. DDNS 的前端及後臺(tái)控制範(fàn)例
說是範(fàn)例主要是讓大家參考原理,並沒有必要一定都用我的方式,只要前面講的東西您可以了解,程式控制的部份
僅是末節(jié),以下僅列出我所用的方式供大家參考
3.1 MYSQL table
主要由三個(gè)表構(gòu)成,分別為 RR (Resource Record), RR_LOG (舊資料,建議您依狀況適當(dāng)保存),USER (user 認(rèn)證)
- CREATE TABLE RR (
- SN int(20) NOT NULL auto_increment,
- USERNAME varchar(64) NOT NULL default '',
- FQDN varchar(64) NOT NULL default '',
- TTL int(5) NOT NULL default '60',
- TYPE varchar(10) NOT NULL default '',
- RDATA varchar(64) NOT NULL default '',
- CREATE_TIME timestamp(14) NOT NULL,
- PRIMARY KEY (SN),
- KEY USERNAME (USERNAME),
- KEY FQDN (FQDN),
- KEY TTL (TTL),
- KEY TYPE (TYPE),
- KEY CREATE_TIME (CREATE_TIME)
- ) TYPE=MyISAM;
- --
- -- Table structure for table 'RR_LOG'
- --
- CREATE TABLE RR_LOG (
- SN int(20) NOT NULL default '0',
- USERNAME varchar(64) NOT NULL default '',
- FQDN varchar(64) NOT NULL default '',
- TTL int(5) NOT NULL default '60',
- TYPE varchar(10) NOT NULL default '',
- RDATA varchar(64) NOT NULL default '',
- CREATE_TIME varchar(14) default NULL,
- PRIMARY KEY (SN),
- KEY USERNAME (USERNAME),
- KEY FQDN (FQDN),
- KEY CREATE_TIME (CREATE_TIME)
- ) TYPE=MyISAM;
- --
- -- Table structure for table 'USER'
- --
- CREATE TABLE USER (
- SN int(20) NOT NULL auto_increment,
- USERNAME varchar(64) NOT NULL default '',
- PASSWD varchar(64) NOT NULL default '',
- EMAIL varchar(64) NOT NULL default '',
- MEMO varchar(255) NOT NULL default '',
- PRIMARY KEY (SN),
- UNIQUE KEY USERNAME (USERNAME)
- ) TYPE=MyISAM;
復(fù)制代碼
3.2 dyndns.cfg 設(shè)定檔
這個(gè)設(shè)定檔主要為了給 CGI 程式及產(chǎn)生 nsupdate 的程式 (dyndns-cron.sh) 所使用,透過 eval 方式來執(zhí)行,
以取得共同的變數(shù)
- # mysql host/db/user/password
- DBHOST=localhost
- DBNAME=dyndns
- DBUSER=UserName
- DBPASS=Your_Passwd
- MYSQL="mysql $DBNAME -h $DBHOST -u $DBUSER -p$DBPASS"
- # dyndns domain
- DOMAIN=dyndns.twnic.tw
- # Master IP
- DYNDNS_MASTER=127.0.0.1
- # nsupdate command file
- CMD_FILE=/tmp/nsupdate.cmd
- # update freqency
- UPD_FREQ=15
- # RR valid time (seconds),default 20 mins
- RR_ALIVE=1200
復(fù)制代碼
3.3 dyndns.cgi CGI 程式
這個(gè) CGI 主要用於接收 USER 端來的資訊,驗(yàn)證通過後即為把 USERNAME.DOMAIN 資料,A/MX 及對(duì)應(yīng) IP 存入
Table RR 中,此外這個(gè) CGI 以 shell script 做成,可以於多數(shù)人的環(huán)境執(zhí)行 (chmod 755 及目錄的 CGI 執(zhí)
行權(quán)限 ExecCGI 莫忘)
- #!/bin/sh
- echo -ne "Content-Type: text/html\n\n"
- if [ -n "$QUERY_STRING" ];then
- # 取得 QUERY_STRING,以下這個(gè)作法是危險(xiǎn)的,因?yàn)闆]有檢查資料的正確性就 eval
- # 我的用意只在於說明作法
- eval `echo "$QUERY_STRING" | sed "s/&/;/g"`
- # 讀取設(shè)定檔,這個(gè)路徑您需要自行調(diào)整
- eval `cat /home/abelyang/dyndns/dyndns.cfg `
- sql0="select 1 from USER where USERNAME='$LOGIN' and PASSWD='$PASSWD'"
- res=`echo $sql0 | $MYSQL `
- # 如果 USER 密碼正確, ${#res} 應(yīng)為2,不對(duì)則為 0
- if [ ${#res} -lt 1 ];then
- echo "Login Failure"
- else
- # 取得 IP, 需判斷有 Proxy 存在,但是不考慮 Proxy 後是 NAT 情形
- IP=${HTTP_X_FORWARDED_FOR:-$REMOTE_ADDR}
- FQDN="$LOGIN.$DOMAIN"
- # 刪除上一次的登入
- sql1="delete from RR where USERNAME='$LOGIN'"
- # 預(yù)設(shè)的動(dòng)態(tài)更新項(xiàng)目為 A/MX
- sql2="insert into RR(USERNAME,FQDN,TYPE,RDATA) values('$LOGIN','$FQDN','A','$IP')"
- sql3="insert into RR(USERNAME,FQDN,TYPE,RDATA) values('$LOGIN','$FQDN','MX','10 $FQDN')"
- echo $sql1 | $MYSQL
- echo $sql2 | $MYSQL
- echo $sql3 | $MYSQL
- echo $LOGIN login success @$IP
- fi
- else
- # 以下只是網(wǎng)頁的部份,我沒有做 DDNS 申請(qǐng),這個(gè)部份我想只要懂網(wǎng)頁的朋友應(yīng)該都會(huì)才是
- cat <<EOF
- <html>
- <head>
- <meta http-equiv="Content-Type" content="text/html; charset=big5" />
- <link rel="stylesheet" href="./style1.css">
- </head>
- <body>
- <BR><BR><center>
- <form>
- <h3>Abel Dyndns Demo </h3>
- Login:<input type=text name=LOGIN ><BR>
- Passwd:<input type=password name=PASSWD><BR>
- <input type=submit values="Start DynDNS">
- </form>
- <BR></center>
- </body>
- </html>
- EOF
- fi
復(fù)制代碼
3.4 dyndns-cron.sh 定時(shí)產(chǎn)生 nsupdate
這隻程式主要進(jìn)行讀取 Table RR , 並產(chǎn)生 nsupdate 所需要的指令格式後執(zhí)行 nsupdate, 程式預(yù)設(shè)
每15秒執(zhí)行一次(參數(shù)如上 dyndns.cfg 中的 UPD_FREQ 更新頻率),您可以拿掉 while [ 1 ] 的迴圈,
改用 crontab 方式來跑,不過這樣就較不容易控制一分鐘以內(nèi)的更新頻率了,最後,這個(gè)程式會(huì)把 SOA
的序號(hào)改成更新時(shí)間,這個(gè)時(shí)間是 UTC 的秒數(shù)(意即 1970/1/1 至今秒數(shù), date +%s 可得),由 SOA 的
序號(hào)就可以知道最後的 update 時(shí)間,這個(gè)原理和 .com 的verisign 或是 dyndns 中的 dyndns.org/
noip.com 是相同的.
另外,根據(jù) RR_VALID 參數(shù),若 USER 的登錄時(shí)間 小於 現(xiàn)在時(shí)間-RR_VALID (秒數(shù)),則該 Record 視同
離線,所以我們需要進(jìn)行 delete 動(dòng)作
- #!/bin/sh
- while [ 1 ]
- do
- # 您必需調(diào)整路徑,放在 while loop 裏是要讓修改了設(shè)定檔即可生效,若不要可放在 while 之外
- eval `cat /home/abelyang/dyndns/dyndns.cfg`
- cat <<EOF > $CMD_FILE
- server $DYNDNS_MASTER
- zone $DOMAIN
- EOF
- # 取得最後一次的更新時(shí)間, 多減一秒是為了預(yù)防程式的 delay
- last=`date -d "-$UPD_FREQ seconds -3 seconds" "+%Y%m%d%H%M%S"`
- now=`date "+%Y%m%d%H%M%S"`
- # 取得這段時(shí)間內(nèi)有上來更新的 USER,這個(gè)部份不檢查 IP 不變動(dòng)情形
- # 主要因?yàn)?nsupdate 巳執(zhí)行很快,而且 named 它自己會(huì)檢查重覆更新的東西
- echo "select FQDN,TTL,TYPE,RDATA from RR where CREATE_TIME between $last and $now" | $MYSQL| grep -v 'RDATA' | while read FQDN TTL TYPE RDATA RDATA2
- do
- # 組出更新指令,主要為一個(gè)刪除,一個(gè)增加
- echo "update delete $FQDN $TYPE $RDATA $RDATA2" >>$CMD_FILE
- echo "update add $FQDN $TTL $TYPE $RDATA $RDATA2" >>$CMD_FILE
- done
- # 超過 RR_ALIVE (20分鐘) 未有 login 資料則清除 DNS 記錄
- last=`date -d "-$RR_ALIVE seconds" "+%Y%m%d%H%M%S"`
- # 備份舊的資料,並清除過時(shí)資料 (看你自己要不要備份了)
- # echo "insert into RR_LOG select * from RR where CREATE_TIME<$last"|$MYSQL
- # echo "delete from RR where CREATE_TIME < $last" |$MYSQL
- # 取得過期 (RR_ALIVE) 而未登錄的列表進(jìn)行刪除動(dòng)作,因?yàn)槲覀冇昧?wildcard (*),所以若別人連時(shí)
- # 將會(huì)被指到 wildcard 所指的 IP 上,而您可這個(gè) Web Server 上做一些文章,例如 Offline 說明等
- echo "select USERNAME,FQDN,TYPE,RDATA from RR where CREATE_TIME - $last < 0 order by USERNAME" | $MYSQL | grep -v 'USERNAME' | while read USERNAME FQDN TYPE RDATA RDATA2
- do
- echo "; delete $FQDN $TYPE $RDATA $RDATA2" >>$CMD_FILE
- echo "update delete $FQDN $TYPE $RDATA $RDATA2" >>$CMD_FILE
- done
- # 自定更新 SOA, 主要是為了讓序號(hào)欄位為現(xiàn)在時(shí)間 (UTC)
- echo "update delete $DOMAIN SOA" >>$CMD_FILE
- echo "update add $DOMAIN 600 SOA ns1.dyndns.twnic.tw abelyang.eai1.twnic.tw $(date +%s) 900 60 604800 60" >>$CMD_FILE
- echo "send" >>$CMD_FILE
- # 執(zhí)行 nsupdate 指令
- nsupdate $CMD_FILE
- # echo "process ok"
- sleep $UPD_FREQ
- done
復(fù)制代碼
3.5 登入及更新方法
所有的東西都準(zhǔn)備好了後,我們就可以測試:
- wget "http://eai1.twnic.tw/dyndns.cgi?LOGIN=abelyang&PASSWD=abelyang-dyndns" -O /tmp/dyndns-login-status 2>/dev/null
復(fù)制代碼
在最多等待15秒(我的預(yù)設(shè)值)的情況下,就可以更新到 DNS 中了
3.6 其他資料
其他資料如 named.conf , dyndns.twnic.tw zone file 您都可以在前面的說明裏找到,我於下面 link
放了一份所有的資料供大家參考,較不用費(fèi)事 copy & paste ,但不保證下面 link 永遠(yuǎn)有效 (其中的
.tgz 即有所有檔案的 tarball)
http://eai1.twnic.tw/example/
4. DDNS 再探討
如前言所言, DDNS 可以使用資料庫來用 (意即我的範(fàn)例中可以少掉 dyndns-cron.sh 那隻),不過資料庫
因其先天的狀況,更據(jù)我的測試(PowerDNS),在 5 萬資 Record 的情況下,只能到達(dá)每秒 1000 次的查詢,
而且此時(shí)尚不考量同時(shí)有 update/delete/insert 等情形,主要因?yàn)槭芟揿断忍?DB 的 select 速度所致
,當(dāng)然您可以透過微調(diào)或細(xì)部處理讓這個(gè)數(shù)字變成1500 或 2000, 但都永不如 BIND 隨便都可以透過每秒
6000 次查詢,當(dāng)然用 DB 直接來做一定是可以且更簡單的,不過安全性及抗壓性 PowerDNS 是隨時(shí)都會(huì)有
當(dāng)?shù)舻娘L(fēng)險(xiǎn),至於用 BIND 倒是沒有看過,主要是因?yàn)檫@種 Server 肯定是不遞迴(recursion no). 所以
著名的 DDNS 廠商都是用 BIND 而不用 DB 方式,因其抗壓性不足而致風(fēng)險(xiǎn)過高.
此外,若我們看 dyndns.org/noip.com 的做法,可以知道他們也是用 BIND 來做,你可以查詢其 SOA 的序
號(hào)即可以知道他每60秒更新一次,若是使用 DB 來做是沒有必要顧慮序號(hào)問題的 (DB 有 DB 同步方法,用
SOA 序號(hào)無關(guān)),此外您更可以查看 .com 的 Verisign,他們的做法也是像 BIND 一樣,而其以每15秒更新
頻率在進(jìn)行,所以若您使用 .com 的域名,變更DNS 大概只要15秒就可以同步到所有的 .com NameServer,
而不是過去的2天 (因?yàn)檫^去是 AXFR,現(xiàn)在是 IXFR),雖然Verigisn 仍不降低 NS 記錄的 TTL 值 (二天),
但至少不會(huì)發(fā)生像過去最多會(huì)4天 .com 的 DNS 資料 Cache 才會(huì)過期的情況 (二天的更新頻率+二天的
快取時(shí)間)
- # 檢查 .com 的 NameServer (d.gtld-servers.net) SOA 資訊來驗(yàn)證
- [root@eai1 example]# for i in `seq 1 1000`;do dig +short @d.gtld-servers.net com soa;sleep 1;done
- a.gtld-servers.net. nstld.verisign-grs.com. 1153990708 1800 900 604800 900
- a.gtld-servers.net. nstld.verisign-grs.com. 1153990708 1800 900 604800 900
- a.gtld-servers.net. nstld.verisign-grs.com. 1153990708 1800 900 604800 900
- a.gtld-servers.net. nstld.verisign-grs.com. 1153990723 1800 900 604800 900 # 這裏變更了, serial 即時(shí)間
- a.gtld-servers.net. nstld.verisign-grs.com. 1153990723 1800 900 604800 900
- a.gtld-servers.net. nstld.verisign-grs.com. 1153990723 1800 900 604800 900
- a.gtld-servers.net. nstld.verisign-grs.com. 1153990723 1800 900 604800 900
- a.gtld-servers.net. nstld.verisign-grs.com. 1153990723 1800 900 604800 900
- a.gtld-servers.net. nstld.verisign-grs.com. 1153990723 1800 900 604800 900
- a.gtld-servers.net. nstld.verisign-grs.com. 1153990723 1800 900 604800 900
- a.gtld-servers.net. nstld.verisign-grs.com. 1153990723 1800 900 604800 900
- a.gtld-servers.net. nstld.verisign-grs.com. 1153990723 1800 900 604800 900
- a.gtld-servers.net. nstld.verisign-grs.com. 1153990723 1800 900 604800 900
- a.gtld-servers.net. nstld.verisign-grs.com. 1153990723 1800 900 604800 900
- a.gtld-servers.net. nstld.verisign-grs.com. 1153990723 1800 900 604800 900
- a.gtld-servers.net. nstld.verisign-grs.com. 1153990738 1800 900 604800 900 # 變更序號(hào)
- a.gtld-servers.net. nstld.verisign-grs.com. 1153990738 1800 900 604800 900
- a.gtld-servers.net. nstld.verisign-grs.com. 1153990738 1800 900 604800 900
復(fù)制代碼
5. 結(jié)語
我所寫的 script 都是以簡單的角度來出發(fā),以供大家參考,至於用戶及域名管理這個(gè)有待想要用的人自行
開發(fā),用 shell script 有利於多數(shù)人閱讀及了解原理,細(xì)節(jié)的東西唯有您自己做了後才更能體會(huì).
對(duì)多數(shù)的公司來說使用 DDNS 是沒有意義的,除了 Registy (.com/cn/tw/jp/hk...),或是以 DDNS 做為營
運(yùn)的公司,而 DDNS其實(shí)是不難的,但是網(wǎng)路上較缺乏這方面的介紹文章,所以在此為大家介紹一下這些東西
的細(xì)節(jié), 以利想要研究的朋友能初窺門徑. 有任何意見都非常歡迎大家多多交流
註:
此外,有些做 DDNS 的公司可能對(duì) IXFR 不了解,而是把所有的 zone type 都設(shè)成了 MASTER,然後對(duì)這些
NameServer進(jìn)行 nsupdate , 這種做法也是可以的,不過中間若漏了一步或那一臺(tái)少做了一件事,那兩邊
的資料就會(huì)不一致,導(dǎo)致可能同一個(gè)名稱會(huì)有不同的解析結(jié)果 (例如 gnway.net 做法,我猜測),而像 dyndns.org
/noip.com 和花生殼(vicp.net,oray.net) 等的做法是一樣的(也就是和本文所提的做法一樣). 而有些
公司則使用 PowerDNS/Mydnl..等套接 DB 的 DNS ,雖然可用,而且方式更簡單,但是這些 DDNS 服務(wù)肯定
無法負(fù)荷大量的查詢,因?yàn)槊看蔚?dns 查詢會(huì)在其內(nèi)產(chǎn)生 N 次的 Select 指令,資料庫處理 select 的
速度肯定是比不上 dns flooding 的速度
==== 每帖不得超過 20000 字,每次發(fā)帖不能小於30秒,這不是叫人不寫文章嗎 ======
[ 本帖最后由 abel 于 2006-7-28 14:56 編輯 ] |
|