- 论坛徽章:
- 1
|
3. DDNS 的前端及後台控制範例
說是範例主要是讓大家參考原理,並沒有必要一定都用我的方式,只要前面講的東西您可以了解,程式控制的部份
僅是末節,以下僅列出我所用的方式供大家參考
3.1 MYSQL table
主要由三個表構成,分別為 RR (Resource Record), RR_LOG (舊資料,建議您依狀況適當保存),USER (user 認證)
- 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;
复制代码
3.2 dyndns.cfg 設定檔
這個設定檔主要為了給 CGI 程式及產生 nsupdate 的程式 (dyndns-cron.sh) 所使用,透過 eval 方式來執行,
以取得共同的變數
- # 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
复制代码
3.3 dyndns.cgi CGI 程式
這個 CGI 主要用於接收 USER 端來的資訊,驗證通過後即為把 USERNAME.DOMAIN 資料,A/MX 及對應 IP 存入
Table RR 中,此外這個 CGI 以 shell script 做成,可以於多數人的環境執行 (chmod 755 及目錄的 CGI 執
行權限 ExecCGI 莫忘)
- #!/bin/sh
- echo -ne "Content-Type: text/html\n\n"
- if [ -n "$QUERY_STRING" ];then
- # 取得 QUERY_STRING,以下這個作法是危險的,因為沒有檢查資料的正確性就 eval
- # 我的用意只在於說明作法
- eval `echo "$QUERY_STRING" | sed "s/&/;/g"`
- # 讀取設定檔,這個路徑您需要自行調整
- eval `cat /home/abelyang/dyndns/dyndns.cfg `
- sql0="select 1 from USER where USERNAME='$LOGIN' and PASSWD='$PASSWD'"
- res=`echo $sql0 | $MYSQL `
- # 如果 USER 密碼正確, ${#res} 應為2,不對則為 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'"
- # 預設的動態更新項目為 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
- # 以下只是網頁的部份,我沒有做 DDNS 申請,這個部份我想只要懂網頁的朋友應該都會才是
- 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
复制代码
3.4 dyndns-cron.sh 定時產生 nsupdate
這隻程式主要進行讀取 Table RR , 並產生 nsupdate 所需要的指令格式後執行 nsupdate, 程式預設
每15秒執行一次(參數如上 dyndns.cfg 中的 UPD_FREQ 更新頻率),您可以拿掉 while [ 1 ] 的迴圈,
改用 crontab 方式來跑,不過這樣就較不容易控制一分鐘以內的更新頻率了,最後,這個程式會把 SOA
的序號改成更新時間,這個時間是 UTC 的秒數(意即 1970/1/1 至今秒數, date +%s 可得),由 SOA 的
序號就可以知道最後的 update 時間,這個原理和 .com 的verisign 或是 dyndns 中的 dyndns.org/
noip.com 是相同的.
另外,根據 RR_VALID 參數,若 USER 的登錄時間 小於 現在時間-RR_VALID (秒數),則該 Record 視同
離線,所以我們需要進行 delete 動作
- #!/bin/sh
- while [ 1 ]
- do
- # 您必需調整路徑,放在 while loop 裏是要讓修改了設定檔即可生效,若不要可放在 while 之外
- eval `cat /home/abelyang/dyndns/dyndns.cfg`
- cat <<EOF > $CMD_FILE
- server $DYNDNS_MASTER
- zone $DOMAIN
- EOF
- # 取得最後一次的更新時間, 多減一秒是為了預防程式的 delay
- last=`date -d "-$UPD_FREQ seconds -3 seconds" "+%Y%m%d%H%M%S"`
- now=`date "+%Y%m%d%H%M%S"`
- # 取得這段時間內有上來更新的 USER,這個部份不檢查 IP 不變動情形
- # 主要因為 nsupdate 巳執行很快,而且 named 它自己會檢查重覆更新的東西
- 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
- # 組出更新指令,主要為一個刪除,一個增加
- 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"`
- # 備份舊的資料,並清除過時資料 (看你自己要不要備份了)
- # echo "insert into RR_LOG select * from RR where CREATE_TIME<$last"|$MYSQL
- # echo "delete from RR where CREATE_TIME < $last" |$MYSQL
- # 取得過期 (RR_ALIVE) 而未登錄的列表進行刪除動作,因為我們用了 wildcard (*),所以若別人連時
- # 將會被指到 wildcard 所指的 IP 上,而您可這個 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, 主要是為了讓序號欄位為現在時間 (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
- # 執行 nsupdate 指令
- nsupdate $CMD_FILE
- # echo "process ok"
- sleep $UPD_FREQ
- done
复制代码
3.5 登入及更新方法
所有的東西都準備好了後,我們就可以測試:
- wget "http://eai1.twnic.tw/dyndns.cgi?LOGIN=abelyang&PASSWD=abelyang-dyndns" -O /tmp/dyndns-login-status 2>/dev/null
复制代码
在最多等待15秒(我的預設值)的情況下,就可以更新到 DNS 中了
3.6 其他資料
其他資料如 named.conf , dyndns.twnic.tw zone file 您都可以在前面的說明裏找到,我於下面 link
放了一份所有的資料供大家參考,較不用費事 copy & paste ,但不保證下面 link 永遠有效 (其中的
.tgz 即有所有檔案的 tarball)
http://eai1.twnic.tw/example/
4. DDNS 再探討
如前言所言, DDNS 可以使用資料庫來用 (意即我的範例中可以少掉 dyndns-cron.sh 那隻),不過資料庫
因其先天的狀況,更據我的測試(PowerDNS),在 5 萬資 Record 的情況下,只能到達每秒 1000 次的查詢,
而且此時尚不考量同時有 update/delete/insert 等情形,主要因為受限於先天 DB 的 select 速度所致
,當然您可以透過微調或細部處理讓這個數字變成1500 或 2000, 但都永不如 BIND 隨便都可以透過每秒
6000 次查詢,當然用 DB 直接來做一定是可以且更簡單的,不過安全性及抗壓性 PowerDNS 是隨時都會有
當掉的風險,至於用 BIND 倒是沒有看過,主要是因為這種 Server 肯定是不遞迴(recursion no). 所以
著名的 DDNS 廠商都是用 BIND 而不用 DB 方式,因其抗壓性不足而致風險過高.
此外,若我們看 dyndns.org/noip.com 的做法,可以知道他們也是用 BIND 來做,你可以查詢其 SOA 的序
號即可以知道他每60秒更新一次,若是使用 DB 來做是沒有必要顧慮序號問題的 (DB 有 DB 同步方法,用
SOA 序號無關),此外您更可以查看 .com 的 Verisign,他們的做法也是像 BIND 一樣,而其以每15秒更新
頻率在進行,所以若您使用 .com 的域名,變更DNS 大概只要15秒就可以同步到所有的 .com NameServer,
而不是過去的2天 (因為過去是 AXFR,現在是 IXFR),雖然Verigisn 仍不降低 NS 記錄的 TTL 值 (二天),
但至少不會發生像過去最多會4天 .com 的 DNS 資料 Cache 才會過期的情況 (二天的更新頻率+二天的
快取時間)
- # 檢查 .com 的 NameServer (d.gtld-servers.net) SOA 資訊來驗證
- [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 即時間
- 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 # 變更序號
- 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
复制代码
5. 結語
我所寫的 script 都是以簡單的角度來出發,以供大家參考,至於用戶及域名管理這個有待想要用的人自行
開發,用 shell script 有利於多數人閱讀及了解原理,細節的東西唯有您自己做了後才更能體會.
對多數的公司來說使用 DDNS 是沒有意義的,除了 Registy (.com/cn/tw/jp/hk...),或是以 DDNS 做為營
運的公司,而 DDNS其實是不難的,但是網路上較缺乏這方面的介紹文章,所以在此為大家介紹一下這些東西
的細節, 以利想要研究的朋友能初窺門徑. 有任何意見都非常歡迎大家多多交流
註:
此外,有些做 DDNS 的公司可能對 IXFR 不了解,而是把所有的 zone type 都設成了 MASTER,然後對這些
NameServer進行 nsupdate , 這種做法也是可以的,不過中間若漏了一步或那一台少做了一件事,那兩邊
的資料就會不一致,導致可能同一個名稱會有不同的解析結果 (例如 gnway.net 做法,我猜測),而像 dyndns.org
/noip.com 和花生殼(vicp.net,oray.net) 等的做法是一樣的(也就是和本文所提的做法一樣). 而有些
公司則使用 PowerDNS/Mydnl..等套接 DB 的 DNS ,雖然可用,而且方式更簡單,但是這些 DDNS 服務肯定
無法負荷大量的查詢,因為每次的 dns 查詢會在其內產生 N 次的 Select 指令,資料庫處理 select 的
速度肯定是比不上 dns flooding 的速度
==== 每帖不得超過 20000 字,每次發帖不能小於30秒,這不是叫人不寫文章嗎 ======
[ 本帖最后由 abel 于 2006-7-28 14:56 编辑 ] |
|