BIND+Mysql實現DNS輪詢泛解析和IP視圖

文檔內容:
1.關於本文檔
2.Bind+Mysql+Mysql-bind環境搭建
3.Bind配置
4.Mysql數據庫設置
5.常見問題解決
文檔正文:

1. 關於本文檔
本文檔用於DNS和BIND結合配置域名解析和其他更深化的服務,如DNS輪詢和squid反向加速結合做簡單的流量動態均衡,泛解析和apachemod_rewrite結合做虛擬多級域名,應用IP視圖做流量處理。偶爾涉及到源碼修正是爲更好提供服務和進行調試所用。如果有興趣可以發郵件至文檔頭處的郵箱進行討論。另外,在後面的文檔中還有一個自動安裝和簡單配置bind+mysql+mysql-bind的腳本auto_bind_sdb.sh,可以方便使用者使用。
文檔分五個部分:
1.關於本文檔,介紹文檔內容和結構。
2.Bind+Mysql+Mysql-bind環境搭建,略爲介紹Bind+Mysql+Mysql-bind的獲取和安裝。
3.Bind配置,初略介紹Bind用於DNS輪詢,泛解析和IP視圖的配置。
4.Mysql數據庫設置,正確設置Mysql數據庫取代Bind的文檔格式的分佈式IP庫。
5.常見問題解決,在配置過程的一些常見問題解決和分析,這是文章的重點。
如果你是帶着問題前來,前往第五和第六部分即可。如果需要了解Bind,還需要參看第二和第三部分。

2. Bind+Mysql+Mysql-bind環境搭建
1.安裝Mysql
安裝mysql的文檔很多,在這裏不再贅述,無非是這麼幾個步驟:
引用
wget mysql*.tar.gz
tar vxzf mysql*.tar.gz && cd mysql*
./configure --prefix=/usr/local/mysql--with-charset=gbk >configure.log 2>&1
make >make.log 2>&1 && makeinstall >install.log 2>&1

然後運行mysql_install_db,注意/var/lib/mysql下的權限,然後便可以啓動mysql了。需要注意的是,一定要確保mysql–uroot能直接訪問進mysql (這是最簡便的方法)。

2.安裝bind,使用bind的mysql sdb
我使用的bind版本是9.3.4,在bind的官網ftp上可以下載到最新穩定的bind版本.Bind的mysql sdb在sf.net上可以下載到0.1版本,似乎mysql-bind(mysqlsdb)已經停止更新了.下載到bind-9.3.4.tar.gz和mysql-bind-0.1.tgz後便可以安裝了.

引用 tar vxzf bind-9.3.4.tar.gz && tarvxzf mysql-bind-0.1.tgz
cp mysql-bind/mysqldb.c bind-9.3.4/bin/named-f
cp mysql-bind/mysqldb.hbind-9.3.4/bin/named/include -f
同時,修改bind-9.3.4.tar.gz/bin/named/Makefile.in文件:

DBDRIVER_OBJS =
DBDRIVER_SRCS =
DBDRIVER_INCLUDES =
DBDRIVER_LIBS =
更改爲
DBDRIVER_OBJS=mysqldb.@O@
DBDRIVER_SRCS = mysqldb.c
DBDRIVER_INCLUDES =-I'/usr/local/mysql/include/mysql'
DBDRIVER_LIBS = -L'/usr/local/mysql/lib/mysql'-lmysqlclient -lz -lcrypt -lnsl -lm -lc -lnss_files -lnss_dns-lresolv -lc -lnss_files -lnss_dns -lresolv
同時在bind-9.3.4/bin/named/main.c中,找到
/* xxdb_init(); */
在後面添加
mysqldb_init();
再找到
/* xxdb_clear(); */
在後面添加
mysqldb_clear();

./configure –prefix=/usr/local/named–enable-threads >configure.log 2>&1
make >make.log 2>&1 && makeinstall >install.log 2>&1
如此,如果沒有出錯,正常的bind mysqlsdb就已經添加了.初步配置好bind和建立mysql的dns數據庫後便可以做測試了.

3.啓動並測試
關於bind的配置和mysql的dns數據庫建立在第三和第四部分介紹.你可以先查看後面兩部分再回來看bind啓動和測試.
啓動bind有幾種模式,在調試的時候,建議採用 bind -unamed -g的方式運行,可以在終端看見詳細的調試信息.也可以在mysqldb.c中加入query語句的輸出和query.c中加入bind解析流程的輸入,來查看bind的運行狀態.
而以daemon方式運行則可以採用 bind -u named -c/etc/named.conf .建議採用named用戶setuid方式運行.
如果named能夠正常運作,這裏的正常的運作是說named啓動後沒有任何fail或任何error,例如加載所有zone/db時都成功,而沒有fail.那麼便可以在隨意一臺能互相訪問的機器上做測試了.設計client上的/etc/resolv.conf,在第一行添加nameservernamed_server_ip.然後便可以用安裝bind時已經額外安裝的工具dig/nslookup進行測試了.關於dig和nslookup命令,可以用man1 dig和man 1 nslookup查看. 最常用的dig進行正向解析:
引用dig www.mydomain.com
dig -x **.**.**.**(IP)
如果沒有得到結果,卻有授權信息的話,那麼基本配置是正確的,問題可能在A記錄或者視圖是否正確上.如果連授權信息都不顯示的話,那麼基本配置出現了問題,如zone未能加載,db鏈接問題等等.可以查看調試信息分析原因.

3. Bind配置
bind是一款開放源碼的DNS服務器軟件,Bind由美國加州大學Berkeley分校開發和維護的,全名爲BerkeleyInternet NameDomain。它是目前世界上使用最爲廣泛的DNS服務器軟件,也是大多數系統管理員最喜歡的DNS軟件,支持各種unix平臺和windows平臺。
bind的配置比較繁瑣,在其官方網站上有爲系統管理員編寫的80多頁的手冊,對於9.0以上的版本早有漢化版本,xplore提供下載地址在此。或者,可以直接參考鳥哥的linux私房菜中關於dns配置一章,基本上能滿足所需的要求(http://linux.vbird.org/lin...
這裏簡單介紹bind配置IP視圖,DNS輪詢和泛解析.(主要是兩個方面:named.conf和zone文件)
bind的IP視圖是在bind9中才引用的強大功能,能實現根據ip來源定義不同域名系統的功能,解決多入口則多出口的問題.在named.conf中,IP視圖的關鍵字是view,其定義規則和zone基本一致,只是zone沒有view的一個功能,那就是對於單獨的view,可以擁有zone實現域名體系.
例如:
引用view "outside" {
match-clients { outside; };
recursion yes;

zone "." IN {
type hint;
file "var/root.zone";
};

zone "test.mydomain.com.cn" IN {
type master;
database "mysqldb dnstest_mydomain_com_cn_outside localhost root rootroot";
# file "var/test.mydomain.com.cn.outside";
};

zone "10.in-addr.arpa" IN {
type master;
database "mysqldb dns10_outside localhost root rootroot";
# file "var/10.outside";
};

zone "localhost" IN {
type master;
file"var/localhost.zone";
allow-update { none; };
};

zone "0.0.127.in-addr.arpa" IN {
type master;
file "var/127.0.0.zone";
allow-update { none; };
};
};
當然,上面的view_name:“outside”是在前面acl中定義的.但是需要注意的是,多個視圖的並集最好是一個ip全集,不要丟掉某些ip.而且,在view視圖配置中,如果定義master/slaver模式做分佈式的話,slaver接受的notify和數據只會匹配slaver自己ip所在視圖的數據,也就是說,如果單個ip的slaver需要和master同步數據的話,永遠只能同步一個view,而其他的則不能.解決辦法可以考慮在slaver的機器上進行ipalias,設置多個別名分別位於master的不同view中,在master的allow-transfer和allow-notify中添加這些ip別名,便可以完成所有view的數據同步了.更詳細的信息參看這篇文檔(http://www.chinaunix.net/j...).
對於DNS輪詢,主要是在zone裏進行設置.zone的SOA,NS記錄基本不變.例如需要將www.mydomain.com關聯到192.168.0.[1-4],則可以這麼寫:
引用
www.mydomain.com. IN A 192.168.0.1
www.mydomain.com. IN A 192.168.0.2
www.mydomain.com. IN A 192.168.0.3
www.mydomain.com. IN A 192.168.0.4

在逆向zone裏可以這麼寫:
引用
1.0.168.192.in-addr.arpa. IN PTR www.mydomain.com
2.0.168.192.in-addr.arpa. IN PTR www.mydomain.com
3.0.168.192.in-addr.arpa. IN PTR www.mydomain.com
4.0.168.192.in-addr.arpa. IN PTR www.mydomain.com
利用bind做DNS輪詢(roundrabin)可以將多個session分散到不同的ip上去減緩單臺機器的鏈接壓力.但是,它並不能真正做到負載均衡,因爲一旦某個ip失效,那麼在輪詢到該ip的session將全部丟失,bind本身並不能多做些什麼.但是,如果使用了bind的mysqlsdb的話,這個問題能夠得到一定緩解.因爲,基於某個協程(一段時間間隔內監聽bind做round-rabin的ip)可以動態剔除失效ip,並動態加入復效ip.然而,並不能保證,bind不會將某個session分配給負載最重的ip.
泛解析在多級虛擬域名上有很好的利用.它可以將符合某個規則的域名解析到一個ip上,利用該ip上的其他應用結合(如apache的mod_rewrite),可以實現額外的功能(如多級虛擬域名).在zone配置中,對於一條這樣的記錄:
引用 * IN A 192.168.0.111

對於任意匹配到該zone的域名,首先都會查詢和該域名完全匹配的記錄,如果存在完全匹配的,則將這個域名關聯到與之對應的ip上.如果沒有完全匹配的,則將之關聯到192.168.0.111上. 而不論* IN A192.168.0.111寫在zone A記錄的何處,都遵循該流程(bind9).這點在named.conf中的view和zone的訪問原則是不同的,view和zone只會在第一個匹配的裏面進行解析.
對於一般的bind配置,建議參看文章前面提到的鳥哥的linux私房菜關於dns部分.包括如何設置根zone和localhostzone等等,還有rndc控制bind等等.
然而,在mysql的sdb中最初並不能支持泛解析.需要進行源碼修改才能支持.這個問題在第五部分給出.

4. Mysql數據庫配置

需要注意的是,如果需要利用mysql的sdb,那麼需要在named.conf中的zone資源中用database關鍵字,而不是file關鍵字或者其他.規則如下:
引用 database "mysqldb dns 10_outside localhostroot rootroot";
mysqldb是sdb驅動註冊的名稱,dns是mysql中bind使用的數據庫名,10_outside是表明,對應於一個zone(裏面的內容也就是zone file中的內容),localhost是mysql的host, root是登陸mysql的用戶,rootroot是登陸mysql用戶的密碼(需要明文顯示,可以自己修改即可).
看到上面的說明,那麼,很顯然,需要在mysql中做相應的配置.如創建一個dns的數據庫;將root密碼改成rootroot(就本例子而言,其實你可以不用root,同時grant權限便可以);創建一個表名10_outside;往表10_outside中按bind的要求引入數據記錄,SOA/NS/A/PTR/CNAME/MX/TXT/HINFO等等.但是,需要注意的是,在sdb中,沒有設計$ORIGIN和$TTL這兩個全局變量,因此,$TTL一般都在記錄裏寫明,$ORIGIN則全部默認爲.(根),也就是說所有記錄的第一項都必須以根作爲$ORIGIN.而IN字段是sdb默認的方式,一般省略,目前,非基於inet的DNS已經很少了.
進行如下操作:
引用 mysqladmin -uroot password rootroot
mysqladmin -uroot -prootroot create dns

cat tmpfile -- MySQL dump 9.11
--
-- Host: localhost Database:dns
-- ------------------------------------------------------
-- Server version 4.0.27

--
-- Table structure for table `10_outside`
--

DROP TABLE IF EXISTS 10_outside;
CREATE TABLE 10_outside (
name varchar(255) default NULL,
ttl int(11) default NULL,
rdtype varchar(255) default NULL,
rdata varchar(255) default NULL
) TYPE=MyISAM;

--
-- Dumping data for table `10_outside`
--

LOCK TABLES 10_outside WRITE;
INSERT INTO 10_outside VALUES('25.71.210.10.in-addr.arpa',3600,'PTR','cas1.test.mydomain.com.cn.');
INSERT INTO 10_outside VALUES('10.in-addr.arpa',3600,'SOA','test.mydomain.com.cn.zhengyu.staff.mydomain.com.cn. 20070319 1800 600 604800600');
INSERT INTO 10_outside VALUES('10.in-addr.arpa',3600,'NS','cas1.test.mydomain.com.cn.');
INSERT INTO 10_outside VALUES('10.in-addr.arpa',3600,'NS','cas2.test.mydomain.com.cn.');
INSERT INTO 10_outside VALUES('10.in-addr.arpa',3600,'NS','cas3.test.mydomain.com.cn.');
INSERT INTO 10_outside VALUES('27.71.210.10.in-addr.arpa',3600,'PTR','cas2.test.mydomain.com.cn.');
UNLOCK TABLES;

--
-- Table structure for table `test_mydomain_com_cn_outside`
--

DROP TABLE IF EXISTS test_mydomain_com_cn_outside;
CREATE TABLE test_mydomain_com_cn_outside (
name varchar(255) default NULL,
ttl int(11) default NULL,
rdtype varchar(255) default NULL,
rdata varchar(255) default NULL
) TYPE=MyISAM;

--
-- Dumping data for table `test_mydomain_com_cn_outside`
--

LOCK TABLES test_mydomain_com_cn_outside WRITE;
INSERT INTO test_mydomain_com_cn_outside VALUES('test.mydomain.com.cn',3600,'SOA','test.mydomain.com.cn.zhengyu.staff.mydomain.com.cn. 20070319 1800 600 604800600');
INSERT INTO test_mydomain_com_cn_outside VALUES('test.mydomain.com.cn',3600,'NS','cas1.test.mydomain.com.cn.');
INSERT INTO test_mydomain_com_cn_outside VALUES('test.mydomain.com.cn',3600,'NS','cas2.test.mydomain.com.cn.');
INSERT INTO test_mydomain_com_cn_outside VALUES('test.mydomain.com.cn',3600,'NS','cas3.test.mydomain.com.cn.');
INSERT INTO test_mydomain_com_cn_outside VALUES('cas1.test.mydomain.com.cn',3600,'A','10.210.71.25');
INSERT INTO test_mydomain_com_cn_outside VALUES('cas2.test.mydomain.com.cn',3600,'A','10.210.71.27');
INSERT INTO test_mydomain_com_cn_outside VALUES('cas3.test.mydomain.com.cn',3600,'A','10.210.132.80');
INSERT INTO test_mydomain_com_cn_outside VALUES('yhzh.test.mydomain.com.cn',3600,'A','10.218.26.191');
INSERT INTO test_mydomain_com_cn_outside VALUES('yhzh.test.mydomain.com.cn',3600,'A','10.218.26.192');
INSERT INTO test_mydomain_com_cn_outside VALUES('yhzh.test.mydomain.com.cn',3600,'A','10.218.26.193');
INSERT INTO test_mydomain_com_cn_outside VALUES('yhzh.test.mydomain.com.cn',3600,'A','10.218.26.194');
INSERT INTO test_mydomain_com_cn_outside VALUES('*',3600,'A','10.210.71.1');
INSERT INTO test_mydomain_com_cn_outside VALUES('conf.test.mydomain.com.cn',3600,'CNAME','cas2.test.mydomain.com.cn.');
UNLOCK TABLES;
EOF

mysql -uroot -prootroot dns rm-rf tmpfile

其中寫進tmpfile中的各個ip和域名對可以自己定義便可.利用mysqlsdb有個很顯著的好處,那便是做了mysql數據庫裏的修改,不需要對bind服務進行重新啓動.當然,排除新建表的操作,如果需要新建一張表的話,也就意味着要加入一個zone,是需要在named.conf裏面進行添加的.(可以考慮採用cron.d/ld.conf.d/udev.rules.d的方式include進去,呵呵.)
如果配置成功了mysql數據庫後,嘗試用dig/nslookup/host測試,是否能夠獲得解析.

5. 常見問題解決
1.讓mysql sdb支持泛解析,DNS輪詢和IP視圖.
對於IP視圖,由於sdb是用數據庫表取代zonefile,那麼意味着sdb無論如何是支持IP視圖的,只需要在named.conf中配置好view便可.對於DNS輪詢,同樣在數據庫中建立一個域名對應於多個ip的記錄便可.而對應於泛解析,由於數據庫本身並不能智能識別*的含義,因此需要在sdb程序段進行修改才能實現泛解析.因此在分析bind的sdb原理和處理流程後,很容易在mysqldb.c中加入泛解析的實現.可以下載mysql-bind-0.1-modify.tar.gz取代最開始的mysql-bind-0.1.tgz,解壓後的mysqldb.c便已經實現泛解析功能.或者使用patch打上補丁,補丁:mysql-bind-modify.patch.然後在需要進行泛解析的數據庫表(對應於相應的zone)中加入一條A記錄:

引用 INSERT INTO your_table_name VALUES('*',3600,'A','your_ip');
這樣便可以進行泛解析了.測試一下.
www.xplore.cn提供了bind-9.3.4下載,mysql-bind-0.1下載和增加了泛解析的mysql-bind-0.1-modify.tar.gz下載.

2.打開bind處理流程的調試信息.
打開bind處理流程的調試信息對於以 named -u named-g方式進行調試時有很大的作用.在bind-9.3.4/bin/named/query.c中,找到
引用#if 0(惟一一處)
將下面的內容
#if 0
#define CTRACE(m) isc_log_write(ns_g_lctx, \
NS_LOGCATEGORY_CLIENT, \
NS_LOGMODULE_QUERY, \
ISC_LOG_DEBUG(3), \
"client %p: %s", client, (m))
#define QTRACE(m) isc_log_write(ns_g_lctx, \
NS_LOGCATEGORY_GENERAL, \
NS_LOGMODULE_QUERY, \
ISC_LOG_DEBUG(3), \
"query %p: %s", query, (m))
#else
#define CTRACE(m) ((void)m)
#define QTRACE(m) ((void)m)
#endif
替換成:
#if 1
/*
#define CTRACE(m) isc_log_write(ns_g_lctx, \
NS_LOGCATEGORY_CLIENT, \
NS_LOGMODULE_QUERY, \
ISC_LOG_DEBUG(3), \
"client %p: %s", client, (m))
#define QTRACE(m) isc_log_write(ns_g_lctx, \
NS_LOGCATEGORY_GENERAL, \
NS_LOGMODULE_QUERY, \
ISC_LOG_DEBUG(3), \
"query %p: %s", query, (m))
*/
#define CTRACE(m) fprintf(stderr,"client %p:%s\n",client,(m))
#define QTRACE(m) fprintf(stderr,"query %p:%s\n",query,(m));
#else
#define CTRACE(m) ((void)m)
#define QTRACE(m) ((void)m)
#endif
所有源碼操作過之後都需要重新編譯,重新運行才能生效.這樣在-g運行named時會將一些解析信息顯示出來.
3.loading zone: creating database: failure錯誤處理.
如果出現這個問題,那說明bindsdb驅動和mysql鏈接出現了問題,諸如密碼錯誤,dns沒有建立,引用/tmp/mysql.sock錯誤等等.這個問題出現之後,你需要在mysqldb.c中加入一些調試信息:
在mysqldb.c的db_connect函數中修改:

引用if (mysql_real_connect ( &dbi->conn, dbi->host,dbi->user, dbi->passwd, dbi->database, 0, NULL, 0 ))
{
fprintf(stderr,"\nconnect successfully.............. \n");
return (ISC_R_SUCCESS);
}
else
{
fprintf(stderr,"\nconnect fail:%s , host %s,user%s,passwd %s,db %s,port %d...................\n",mysql_error(&dbi->conn),dbi->host,dbi->user,dbi->passwd,dbi->database);
return (ISC_R_FAILURE);
}

這樣方便得到出錯信息.然後根據出錯信息調試mysql,使bindsdb能成功鏈接mysql.
4.Dig結果分析處理.
如果在執行dig xx.mydomain.com出現以下幾種情況:
引用;; QUESTION SECTION:
;xx.mydomain.com. IN A
;; AUTHORITY SECTION:
*****************************************************************
;; Query time: 8 msec
這說明在bind的基本配置都正確,但是數據庫表項中沒有添加該A記錄或者添加的記錄有問題,特別是那些對file方式配置bind用熟的管理員,他們已經能很好的使用$ORIGIN進行處理,但是需要明白那就是mysql是不識別$ORIGIN的,一定需要寫全稱.同時第一項的最後一個點是不必要的.如果上面的分析還不能解決問題,請在mysqldb.c中凡事出現mysql_query()API之前將query的str打印出來.便可以知道問題是否出在mysql查詢中.
而其他錯誤,如沒有出現
引用;; AUTHORITY SECTION:
這一選項,說明bind的基本配置出現問題,諸如在mysql的表中是否丟失SOA/NS記錄,或者SOA/NS記錄出現錯誤.特別是SOA/NS的第一項後面多了一個小黑點.
具體原理分析請參看第四部分的第三段.自動腳本請參見下一篇文章:http://wf.xplore.cn/read.p...

本文參考瞭如下網絡資源,謹向這些文章的作者致敬:
1. http://linux.vbird.org/lin...
2. http://www.study-area.org/...
3. 官方文檔
發佈了52 篇原創文章 · 獲贊 4 · 訪問量 2429
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章