使用BIND系统和Mysql数据库构建智能DNS系统
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
使用BIND系统和Mysql数据库构建智能DNS系统
运维部吴红星第一,首言
目前市场上有F5、Citrix、Radware等智能网络设备厂商提供较为成熟的整体的高可用性的应用交付解决方案,会涉及智能DNS也即全局负载均衡、本地负载均衡,提供了完整的各种负载均衡算法,技术结构复杂,设备成本和管理、维护成本昂贵。
BIND(Berkeley Internet Name Domain)是由互联网软件协会(ISC)开发的开放源码的域名服务器软件,目前互联网上约有超过90%的域名服务器都在使用它提供域名解析服务,几乎所有UNIX族的操作系统都使用它作为其DNS服务的唯一实现。
本文将主要简述如何利用BIND开源系统结合Mysql数据库通过二次开发,实现简单的根据请求源IP地址和应用存活实时探测来智能分配服务器IP的域名解析系统,开发语言为ANSI C。
标准的DNS解析整个流程图示如下:
图示1 标准解析流程图
第二,智能DNS实现基本思路
在BIND服务软件获取源地址后,对比现有的互联网地址库分布,按请求客户端区分不同的运营商或者继续细分到省份、城市等,计算出自定义网络范围ID,然后通过存储在mysql中的资源记录,自定义条件返回解析结果。
在基本分析了bind源码后,确认了几个技术点:
1,bind在最终获取解析结果的数据库接口函数中没有传入的客户端源IP地址结构参数,需要解决如何传入客户端IP地址,该函数为dns_sdblookupfunc_t类型;
2,互联网拓扑结构分布的IP地址范围也存在数据库中,但是地址匹配的时候不能使用数据库计算返回结果,必须程序使用内存处理,提高效率。
如果地址调整,如何自动载入地址内存中的地址库链表;
3,如何监控解析主机IP地址的应用存活性。
第三,智能DNS各个实现细节阶段简述
1,传入clientaddr指针到dns_sdblookupfunc函数
原函数
typedef isc_result_t (*dns_sdblookupfunc_t)(const char *zone, const char *name, void *dbdata,dns_sdblookup_t *)
调整为:
typedef isc_result_t (*dns_sdblookupfunc_t)(const char *zone, const char *name, void *dbdata, dns_sdblookup_t *, isc_sockaddr_t *client_addr) 调整后加入client_addr地址参数,该函数被dns_dbmethods_t类型结构体中某些函数调用,需要在这些函数中传入含有client_addr相关信息的参数。
原isc_result_t (*findnode)(dns_db_t *db, dns_name_t *name,
isc_boolean_t create,
dns_dbnode_t **nodep);
调整为:
isc_result_t (*findnode)(dns_db_t *db, dns_name_t *name, isc_boolean_t create,
dns_dbnode_t **nodep, ns_client_t *client);
原isc_result_t (*find)(dns_db_t *db, dns_name_t *name, dns_dbversion_t *version,
dns_rdatatype_t type, unsigned int options, isc_stdtime_t now, dns_dbnode_t **nodep, dns_name_t *foundname, dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset);
调整为:
isc_result_t (*find)(dns_db_t *db, dns_name_t *name, dns_dbversion_t *version,
dns_rdatatype_t type, unsigned int options, isc_stdtime_t now, dns_dbnode_t **nodep, dns_name_t *foundname, dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset, ns_client_t *client);
最终ns_client_t类型的客户端地址信息由调用函数query_find(ns_client_t
*client, dns_fetchevent_t *event, dns_rdatatype_t qtype)传入。
2,实现内存存储地址结构链表,并实现遍历查询
定义地址信息结构体链表类型:
typedef struct subnet_id_link {
struct sockaddr_in subnet_num;
struct sockaddr_in subnet_mask;
int ispzoneid;
struct subnet_id_link *next;
} subnet_id_link_t;
用于存储现有的互联网地址链表,并约定ID号,如中国电信区域ID为1,中国网通为2,浙江电信为3等等,该链表头指针为全局变量,启动BIND时候读入mysql数据库
中的IP库信息初始化该数据段,并实现IP段更新后,使用BIND管理工具rndc在服务不停止的情况下重加载IP库信息。
定义一个域名解析客户端可能属于的网络ID号链表结构:
typedef struct ispzoneid_link {
int ispzoneid;
struct ispzoneid_link *next;
} ispzoneid_link_t;
该结构用于存储匹配客户从属于区域系列ID链,如一个浙江电信的client既属于中国电信也属于浙江电信甚至属于杭州电信(如果定位细分到市级别)。
其他定义:
extern subnet_id_link_t *subnet_id_link_table; --定义全局链表指针
void free_subnetidlink(subnet_id_link_t *subnetlink);--退出或者重启时候释放地址链表内存
static int insert_subnetidlink(subnet_id_link_t **subnetlink, char *subnet, int ispzoneid); --插入自定义地址链表,初始化地地址库结构和所属ID
static int insert_ispzoneidlink(ispzoneid_link_t **ispzoneidlink, int
ispzoneid); --匹配地址后插入id链表
static void free_ispzoneidlink(ispzoneid_link_t *ispzoneidlink);--生成查询语句后释放id链内存
static ispzoneid_link_t *lookup_ispzoneid(subnet_id_link_t *subnetlink, isc_sockaddr_t *client_addr);--匹配id,并生成id链数据,返回id链表指针static void make_str_query(char *querystr, ispzoneid_link_t
*ispzoneidlink);--生成sql查询语句,查询mysql数据库
static isc_result_t db_connect(struct dbinfo *dbi); --mysql数据库连接函数static isc_result_t mysqldb_lookup(const char *zone, const char *rname, void *dbdata, dns_sdblookup_t *lookup, isc_sockaddr_t *client_addr); --通过mysql获取解析最终结果函数
定义注册函数方法,并注册mysql查询模块:
static dns_sdbmethods_t mysqldb_methods = {
mysqldb_lookup,
NULL,
mysqldb_allnodes,
mysqldb_create,
mysqldb_destroy
};
isc_result_t mysqldb_init(void)
{
unsigned int flags;
flags = 0;
return (dns_sdb_register("mysqldb", &mysqldb_methods, NULL, flags, ns_g_mctx, &mysqldb));
}
3,mysql数据库设计
A.网络IP库表
CREATE TABLE `IspNetZone_Table` (
`subnet_num` varchar(20) default NULL, --网络地址段,如192.168.1.0/24
`ispzoneid` int(4) default '0' --运营商所属ID,如中国电信1,浙江电信2,中国联通3
)
B.DNS rddata存储表
CREATE TABLE [domain_table] (
name varchar(255) default NULL, --资源记录名,如
ttl int(11) default 1800, --记录解析生存周期
rdtype varchar(255) default NULL, --记录类型,A,CNAME,MX等
rdata varchar(255) default NULL, --记录数据,IP或者Aliases
ispzoneid int(4) default 0, --解析目标区域id如中国电信那么存值为1
weight int(4) default 100, --权值,解析优先值
iflive int(4) default 1, --监控主机是否存活,如果0值排除该条解析记录
disable int(4) default 0 --手工禁用,1为禁用,排除该条解析记录
);
c. 使用BIND配置文件的zone参数配置数据库链接信息:
zone "domain_name" {
type master;
notify no;
allow-update { none; };
database "mysqldb dns_db_name domain_table_name db_host_ip dbuser dbpassword";
};
D,服务器应用存活探测配置表
CREATE TABLE `monitor_table` (
`id` int(11) NOT NULL auto_increment,
`hostip` varchar(255) default NULL, --监控服务器主机IP
`port` int(11) default '80', --监控服务器数据TCP端口
`domainname` varchar(255) default NULL, --监控域名
`hostdes` varchar(255) default NULL, --用途描述
`dnstablename` varchar(255) default NULL, --所在解析表表名,同配置文件对应
`monitortype` int(11) default '0', --0 MOHTTP_REQ_GET, 1 MOHTTP_REQ_POST,2 MOHTTP_REQ_HEAD
`httpurl` varchar(255) NOT NULL, --监控URL
`return_v` varchar(255) default NULL, --匹配返回值,如为空,则判断返回HTTP状态码
`content` varchar(2048) default NULL, --POST方式监控时提交的的数据
`monitor_interval` int(11) default 30, --发送服务器轮训监控的时间间隔
`phone` varchar(2048) default NULL, --服务器存活监控失效后短信通知对象
PRIMARY KEY (`id`)
)
第四阶段,主机和应用监控实现
使用外部Daemon进程监控主机,服务启动后根据监控配置表加载监控配置,根据配
置中轮训时间和请求方式间隔发起监控请求,如果监控主机失败,直接条件性修改domain_table,置符合条件的记录iflive字段值为0,排除解析记录。
考虑大部分应用为http方式,使用http get、post、head方式监控,匹配返回内容,判断是否存活。
该监控服务使用了libevent库http功能模块,并使用syslog方式写入监控信息日志。
主要函数:
static void load_dbconfig(char *configfile); --加载本地监控数据库配置文件void initmonitorobj(struct dbinfo *mysqldb); --加载监控对象的数据库配置初始化
int hexchange( unsigned char *returnva, int m, char *value ); --post内容中包含16进制数据的转换递归函数;
int updatednstable(struct dbinfo *mysqldb, monitorconfig_t *config, int iflive); --根据监控结果调整解析表iflive字段函数
主要日志格式:
Jun 3 17:56:10 dns monitor: Run: 0 day 0 hours 42 min 26 sec !
Jun 3 17:56:40 skydns monitor: host:60.*.*.* , port:80 , url:/, table:×××_com_table
Jun 3 17:56:55 skydns monitor: 2010-06-03 17:56:55 Testing Request TO 60.*.*.* www.×××.com Connection: Status code zero FAILED
Jun 3 17:56:55 skydns monitor: 1 dns record updated, domainname is www.×××.com ip is 60.*.*.* status down!
Jun 3 17:56:55 skydns monitor: Run: 0 day 0 hours 43 min 11 sec !
Jun 3 17:57:25 skydns monitor: host:60.*.*.* , port:80 , url:/, table:×××_com_table
Jun 3 17:57:28 skydns monitor: 1 dns record updated, domainname is www.×××.com ip is 60.*.*.* status up!
第五,智能DNS使用场景之一,多IDC应用案例
用户根据智能DNS配置,选择合适的IDC访问业务服务,当某个IDC出现问题或者业务服务器出现问题,应用探测会及时更新解析记录中存活状态,在用户端域名的TTL时间到期后,重新发起请求时候,智能DNS服务器即会排除非存活的服务器返回用户存活的服务主机供用户访问,使得业务可以根据健康状态实现一定时间范围内的自动切换。
图示如下:
图示2 基于智能DNS多IDC应用部署案例。