在用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语言中迭代器的设计与使用
QQ 群:242722074
相关推荐
1. **创建ACL**:使用`acl`命令创建一个新的ACL,例如: ``` acl number 2000 // 创建一个编号为2000的标准ACL acl number 3000 // 创建一个编号为3000的扩展ACL ``` 2. **定义规则**:在创建的ACL中添加允许或...
- 使用解析库可以简化客户端应用程序对DNS查询的支持。 通过上述知识点的学习,读者不仅可以深入了解DNS的工作原理和技术细节,还能掌握实际配置与管理BIND DNS服务器的方法,同时增强DNS系统的安全性,以应对日益...
- **创建Resolver规则和端点**:此库允许用户通过编程方式创建Route 53 Resolver规则,这些规则定义了如何处理VPC内或从VPC发出的DNS查询。同时,它可以设置Inbound和Outbound端点,以便将流量路由到正确的目的地。 ...
《Windows 2000活动目录开发人员参考库 第3卷 ADSI程序员指南》是一本专为开发人员设计的深入指南,旨在帮助他们理解和利用ADSI(Active Directory Service Interfaces)来构建与Windows 2000活动目录集成的应用程序...
- 使用`yum install bind`安装BIND DNS服务器。 - **配置DNS服务器**: - 编辑`/etc/named.conf`来配置DNS区域文件。 - 创建区域文件`/var/named/yourdomain.zone`并定义DNS记录。 **2.6 配置虚拟主机** - **...
1. **Visual Basic**: 这是一种编程语言,参赛者可能需要掌握基本的编程知识,编写简单的应用程序或脚本。 2. **VLAN与ACL**: 这涉及到网络管理,学生可能需要理解虚拟局域网的设置和访问控制列表的应用,以实现...
《SCO UNIX系统应用500问》是一本深入探讨SCO UNIX操作系统管理的书籍,NLC格式的数据表明这可能是一个早期的电子文档格式,适合详细学习和查阅。SCO UNIX,全称为Santa Cruz Operation Unix,是曾经广泛应用的一种...
4. 线程编程:使用pthread库创建和管理线程。 5. 编译与调试:使用gcc/g++编译器,学会gdb调试技巧。 此外,课程可能还涉及其他高级主题,如Linux内核模块开发、系统性能分析、存储系统、网络编程等。通过这门课程...
- `libappindicator3-1`: 应用程序指示器库。 - `libasound2-plugins`: 音频系统插件。 - `libatk-bridge2.0-0`: 辅助技术桥接库。 - `libatk1.0-0` 和 `libatk1.0-data`: 辅助技术框架。 - `libatspi2.0-0`: ...
1. **Amazon Route 53**:AWS的全球DNS服务,用于路由用户请求到应用程序的最优化位置。 2. **Amazon CloudFront**:AWS的CDN服务,用于缓存和分发静态内容,提高用户访问速度。 3. **CNAME记录与A记录**:CNAME记录...
- ACL访问控制列表:学习如何使用ACL来限制网络流量,实现基本的安全防护。 - VLSM可变长子网掩码:应用VLSM进行更高效的地址规划和安全策略实施。 - SSH安全远程访问:配置SSH以替代不安全的telnet,确保网络...
1. **Linux系统结构**:Linux采用微内核设计,由内核、系统库、shell、应用程序等组成。内核负责管理硬件资源,提供进程调度、内存管理、文件系统等基本服务。系统库如Glibc为应用程序提供API接口,shell则作为用户...
- 安全策略设置,如防火墙规则(ipf)、访问控制列表(ACL)以及SELinux。 8. **性能调优** - 通过性能监视工具分析系统瓶颈,如`perfmon`和`vmstat`。 - 调整系统参数,如内核参数、内存分配策略等,以优化系统...