文档章节

使用ACL库编写DNS查询应用

郑树新
 郑树新
发布于 2014/09/03 12:10
字数 1141
阅读 26
收藏 0

  在用C/C++写程序时,若要根据域名查找其对应的IP地址,大家一般会用到 gethostbyname 的标准函数,如若要查询 www.sina.com.cn 域名调用 gethostbyname 时,该函数首先会查找本机 hosts 文件里的条目,若该配置文件里没有对应域名,则该函数会向本机配置的DNS服务器发送查询请求,然后将DNS服务器的返回结果反给用户。该函数的使用较为简单,但却有一个限制,如果针对某个域名,在内外网有不同的IP地址时就不好办了,假设该域名由内网DNS(192.168.1.33)解析时的IP地址为 192.168.1.22, 由外网DNS(211.239.1.33)解析因为gethostbyname使用系统统一的 resolve.conf里的DNS服务器配置地址。要解决这个问题,最好的方式就是直接连接DNS服务器以遵循DNS协议格式发送查询指令,ACL库里便实现DNS协议的通信及协议解析功能(在 lib_acl/src/net/dns/ 目录下),下面介绍如何使用ACL的DNS库进行域名查询。

  首先列出本例子用到的函数接口说明:

/**
 * 创建一个DNS查询对象
 * @param dns_ip {const char*} DNS的IP地址
 * @param dns_port {unsigned short} DNS的Port
 * @return {ACL_RES*} 新创建的查询对象
 */
ACL_API ACL_RES *acl_res_new(const char *dns_ip, unsigned short dns_port);

/**
 * 释放一个DNS查询对象
 * @param res {ACL_RES*} DNS查询对象
 */
ACL_API void acl_res_free(ACL_RES *res);

/**
 * 查询某个域名的IP地址
 * @param res {ACL_RES*} DNS查询对象
 * @param domain {const char*} 要查询的域名
 * @return {ACL_DNS_DB*} 查询的结果集
 */
ACL_API ACL_DNS_DB *acl_res_lookup(ACL_RES *res, const char *domain);

/**
 * 根据错误号获得查询失败的原因
 * @param errnum {int} 错误号
 * @return {const char*} 错误信息
 */
ACL_API const char *acl_res_strerror(int errnum);

/**
 * 获得当前查询的错误信息
 * @param res {ACL_RES*} DNS查询对象
 * @return {const char*} 错误信息
 */
ACL_API const char *acl_res_errmsg(const ACL_RES *res);

 

  然后给出具体例子如下:

#include "lib_acl.h"
#include <stdio.h>

static int dns_lookup(const char *domain, const char *dns_ip,
	unsigned short dns_port)
{
	ACL_RES *res = NULL;  /* DNS 查询对象 */
	ACL_DNS_DB *dns_db = NULL;  /* 存储查询结果 */
	ACL_ITER iter;  /* 通用迭代对象 */

#define RETURN(_x_) do { \
	if (res) \
		acl_res_free(res); \
	if (dns_db) \
		acl_netdb_free(dns_db); \
	return (_x_); \
} while (0)

	/* 创建一个DNS查询对象 */
	res = acl_res_new(dns_ip, dns_port);

	/* 向DNS服务器发送查询指令并接收处理结果 */
	dns_db = acl_res_lookup(res, domain);
	if (dns_db == NULL) {
		printf("failed for domain %s, %s", domain, acl_res_errmsg(res));
		RETURN (-1);
	}

	/* 遍历查询结构并输出至标准输出 */
	printf("type\tttl\tip\t\tnet\t\tqid\t\n");
	acl_foreach(iter, dns_db) {
		ACL_HOST_INFO *info;
		struct in_addr in;
		char  buf[32];

		info = (ACL_HOST_INFO*) iter.data;
		in.s_addr = info->saddr.sin_addr.s_addr;

		/* 假设网络掩码为24位,获得网络地址 */
		acl_mask_addr((unsigned char*) &in.s_addr, sizeof(in.s_addr), 24);

		/* 将地址转换成字符串 */
		acl_inet_ntoa(in, buf, sizeof(buf));

		/* 输出查询结果 */
		printf("A\t%d\t%s\t%s\t%d\r\n",
			info->ttl, info->ip, buf, res->cur_qid);
	}

	RETURN (0);
}

int main(int argc acl_unused, char *argv[] acl_unused)
{
	const char *dns_in_ip = "192.168.1.33", *dns_out_ip = "211.239.1.33";
        unsigned short dns_in_port = 53, dns_out_port = 53;
	const char *domain = "www.test.com.cn";

	/* 查询内网DNS */
	(void) dns_lookup(domain, dns_in_ip, dns_in_port);

	/* 查询外网DNS */
	(void) dns_lookup(domain, dns_out_ip, dns_out_port);

	return (0);
}

 

  OK,这个例子很简单,完全满足刚才所说的需求。此外,该例子用到了几个结构类型,如下(也可以直接查询 lib_acl/include/net/ 目录下的头文件说明):

/* DNS查询对象结构定义 */
typedef struct ACL_RES {
	char dns_ip[64];                /**< DNS的IP地址 */
	unsigned short dns_port;        /**< DNS的Port */
	unsigned short cur_qid;         /**< 内部变量,数据包的标识 */
	time_t tm_spent;                /**< 查询时间耗费(秒) */
	int   errnum;
#define ACL_RES_ERR_SEND	-100    /**< 写出错 */
#define ACL_RES_ERR_READ	-101    /**< 读出错 */
#define ACL_RES_ERR_RTMO	-102    /**< 读超时 */
#define ACL_RES_ERR_NULL	-103    /**< 空结果 */
#define ACL_RES_ERR_CONN	-104    /**< TCP方式时连接失败 */

	int transfer;                   /**< TCP/UDP 传输模式 */
#define ACL_RES_USE_UDP		0       /**< UDP 传输模式 */
#define ACL_RES_USE_TCP		1       /**< TCP 传输模式 */

	int   conn_timeout;             /**< TCP 传输时的连接超时时间, 默认为10秒 */
	int   rw_timeout;               /**< TCP/UDP 传输的IO超时时间, 默认为10秒 */
} ACL_RES;

/**
 * 主机地址结构
 */
typedef struct ACL_HOSTNAME ACL_HOST_INFO;
typedef struct ACL_HOSTNAME {
	char  ip[64];                   /**< the ip addr of the HOST */
	struct sockaddr_in saddr;	/**< ip addr in sockaddr_in */
	unsigned int ttl;               /**< the HOST's ip timeout(second) */
	int   hport;
	unsigned int nrefer;            /**< refer number to this HOST */
} ACL_HOSTNAME;

/**
 * DNS查询结果集
 */
typedef struct ACL_DNS_DB {
	ACL_ARRAY *h_db;
	int   size;
	char  name[256];

	/* for acl_iterator */

	/* 取迭代器头函数 */
	const ACL_HOST_INFO *(*iter_head)(ACL_ITER*, struct ACL_DNS_DB*);
	/* 取迭代器下一个函数 */
	const ACL_HOST_INFO *(*iter_next)(ACL_ITER*, struct ACL_DNS_DB*);
	/* 取迭代器尾函数 */
	const ACL_HOST_INFO *(*iter_tail)(ACL_ITER*, struct ACL_DNS_DB*);
	/* 取迭代器上一个函数 */
	const ACL_HOST_INFO *(*iter_prev)(ACL_ITER*, struct ACL_DNS_DB*);
	/* 取迭代器关联的当前容器成员结构对象 */
	const ACL_HOST_INFO *(*iter_info)(ACL_ITER*, struct ACL_DNS_DB*);
} ACL_DNS_DB;

 

  至于文所提到的迭代器遍历过程,请参考文章:C语言中迭代器的设计与使用

      个人微博:http://weibo.com/zsxxsz

      QQ 群:242722074

© 著作权归作者所有

郑树新

郑树新

粉丝 104
博文 87
码字总数 161171
作品 2
昌平
程序员
私信 提问
DNS的简单实现

DNS的安装和主从区域的简单配置: 环境: 正反向主为10.1.19.1(hostname:centos7-1) ,从服务器为10.1.19.2(hostname:centos7-2),系统为centos7.2 软件安装: [root@centos7-1 ~]# yum -y i...

powerlife
2016/11/06
0
0
跨平台网络通信与服务器编程框架库(acl库)介绍

一、描述 acl 工程是一个跨平台(支持LINUX,WIN32,Solaris,MacOS,FreeBSD)的网络通信库及服务器编程框架,同时提供更多的实用功能 库。通过该库,用户可以非常容易地编写支持多种模式(...

郑树新
2014/08/23
0
0
[Dns] Linux 部署安装DNS(域名解析)系统与理论详解

本章Blog相关知识点: DNS(Domain Name System,域名系统),万维网上作为域名和IP地址相互映射的一个分布式数据库,方便用户使用名称的访问互联网。通过域名,最终得到该域名对应的IP地址的...

Wish_亮
2018/06/28
0
0
跨平台网络通信与服务器编程框架库(acl库)介绍

一、描述 acl 工程是一个跨平台(支持LINUX,WIN32,Solaris,MacOS,FreeBSD)的网络通信库及服务器编程框架,同时提供更多的实用功能 库。通过该库,用户可以非常容易地编写支持多种模式(...

郑树新
2014/08/18
7
0
DNS域名服务协议和其实现Bind应用

版权声明:本文为博主原创文章,转载请注明出处。 https://blog.csdn.net/gongxifacai_believe/article/details/84574174 1、DNS概述 DNS(Domain Name Service,域名服务)是一种应用层协议...

魏晓蕾
2018/11/27
0
0

没有更多内容

加载失败,请刷新页面

加载更多

Android双向绑定原理简述

Android双向绑定原理简述 双向绑定涉及两个部分,即将业务状态的变化传递给UI,以及将用户输入信息传递给业务模型。 首先我们来看业务状态是如何传递给UI的。开启dataBinding后,编译器为布局...

tommwq
今天
2
0
Spring系列教程八: Spring实现事务的两种方式

一、 Spring事务概念: 事务是一系列的动作,它们综合在一起才是一个完整的工作单元,这些动作必须全部完成,如果有一个失败的话,那么事务就会回滚到最开始的状态,仿佛什么都没发生过一样。...

我叫小糖主
今天
6
0
CentOS 的基本使用

1. 使用 sudo 命令, 可以以 root 身份执行命令, 必须要在 /etc/sudoers 中定义普通用户 2. 设置 阿里云 yum 镜像, 参考 https://opsx.alibaba.com/mirror # 备份mv /etc/yum.repos.d/CentO...

北漂的我
昨天
3
0
Proxmox VE技巧 移除PVE “没有有效订阅” 的弹窗提示

登陆的时候提示没有有效的订阅You do not have a valid subscription for this server. Please visit www.proxmox.com to get a list of available options. 用的是免费版的,所以每次都提示......

以谁为师
昨天
4
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部