[原创]Linux下的地址解析函数应用实例

    Linux下的地址解析函数应用实例

作者: 默难 ( monnand@gmail.com )

0    引言
域名系统(DNS)是一种用于TCP/IP应用程序的分布式数据库, 它提供主机名字和IP地址之间的转换及有关电子邮件的选路信息.[1] 目前, 它已经在全球范围内被广泛应用. 从应用的角度上看, 对DNS的访问是通过一个地址解析器(resolver)来完成的. 本文通过讲解一些常用的地址解析函数, 并利用精简后的部分qmail代码, 让不熟悉DNS相关函数的程序员了解并掌握常用的地址解析函数.

1    概述
DNS查询中, 最常用的两类分别是A类查询(A query)和指针查询(PTR query). 前者是已知主机名, 询问IP; 后者是已知IP, 询问主机名. 对于这些查询, 在Unix主机中可以直接调用基本DNS函数: gethostbyname(3)和gethostbyaddr(3)来实现. 但是对于其他类型的查询(例如MX查询), 则没有专门的函数来负责处理. 此时, 程序员不得不依赖地址解析函数来亲自处理这些问题. 这需要对DNS报文格式有基本的了解, 这些将在下面几节进行说明. 关于gethostbyname(3)和gethostbyaddr(3)两个函数, 读者可以查阅自己系统上的man手册.

2    DNS报文格式
在对地址解析函数讲解之前, 有必要先了解一下DNS报文格式. 之后的几节会频繁地涉及到本节所讲的内容. 如果想对DNS相关协议有更深的了解, 可以阅读参考文献[1] [2] [3].

DNS定义了一个用于查询和响应的报文格式, 图1 显示了这个报文的总体格式.

[图1]

每个DNS查询(或响应)报文都包含有一个12字节长的首部和四个变长的字段组成.

对于本文来说, 首部中主要关心的是问题数和资源记录数两个字段. 这两个字段分别用于说明各自对应的变长字段中的条目数. 问题数说明查询问题字段中的条目数; 资源记录数则说明回答字段中的条目数. 对于一个DNS查询报文, 问题数通常是1. 对于应答报文, 回答数至少是1.

首部以下是四个变长字段, 本文所关心的是查询问题字段和回答字段.

查询问题字段可以包含多个查询问题, 每个问题的格式如图2 所示.
图二
[图2]

其中, 查询名一项存储着要查找的名字. 它长度可变并以一种特殊的格式存储. 程序可以通过其中存储的内容确定其长度. 具体获得其中存储内容的方法, 将在下一节中进行详细讲解. 每一个问题有一个查询类型, 每个响应(下文中将会提到)也同样有一个类型. 常用的类型有: A类型---表示期望获得查询名的IP地址; PTR查询---表示期望获得一个IP地址对应的域名; MX查询---邮件交换查询(关于MX查询的具体内容, 下文会提到). 查询类指定了所使用的协议簇, 通常是1, 表示Internet地址.

回答字段可以包含多个条目. 每个回答字段是以一种叫做资源记录(Resource Record, RR)的格式存储的. ( 授权字段和额外信息字段也同样以资源记录的格式存储信息). 资源记录的格式如图3 所示.
图三
[图3]

域名是记录中资源数据对应的名字. 它的格式和前面介绍的查询名字段格式相同. 类型和类字段和前面介绍的查询类型, 查询类字段的功能一样. 类字段的取值通常是1, 表示Internet地址. 生存时间字段是客户程序保留该资源记录的秒数. 资源数据长度说明资源数据包含的字节数. 资源数据则根据类型字段的值有不同的格式. 对于A类型, 资源数据是IP地址. 对于MX查询, 资源数据是优先值和域名, 域名的格式与查询名字段格式相同(MX记录的具体内容下文会有介绍).

至此, DNS中用到的报文格式已经基本介绍完. 下一节中将会介绍一些常用的地址解析函数. 阅读下文时, 最好随时翻阅本节所讲的内容以便于理解.

3    地址解析函数

除了经常用到的gethostbyname(3)和gethostbyaddr(3)函数以外, Linux(以及其它UNIX/UNIX-like系统)还提供了一套用于在底层处理DNS相关问题的函数(这里所说的底层仅是相对gethostbyname和gethostbyaddr两个函数而言). 这套函数被称为地址解析函数(resolver functions). 用户可以通过键入man resolver来了解其中的具体信息. 这里将对其中常用到的函数做一个解释. 常用的地址解析函数原型如下:
       #include <netinet/in.h>
       #include <arpa/nameser.h>
       #include <resolv.h>
       extern struct state _res;

       int res_init(void);

       int res_query(const char *dname, int class, int type,
              unsigned char *answer, int anslen);

       int res_search(const char *dname, int class, int type,
              unsigned char *answer, int anslen);

       int dn_expand(unsigned char *msg, unsigned char *eomorig,
              unsigned char *comp_dn, unsigned char *exp_dn,
              int length);

_res:
  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值