LibEvent中文帮助文档--第16章【DNS服务器接口】
来源:互联网 发布:mac 不显示隐藏文件 编辑:程序博客网 时间:2024/05/29 16:38
LiEvent中文帮助文档--第16章【DNS服务器接口】
返回主目录
Libevent
快速可移植非阻塞式网络编程
修订历史
版本
日期
作者
备注
V1.0
2016-11-15
周勇
Libevent编程中文帮助文档
文档是2009-2012年由Nick-Mathewson基于Attribution-Noncommercial-Share Alike许可协议3.0创建,未来版本将会使用约束性更低的许可来创建.
此外,本文档的源代码示例也是基于BSD的"3条款"或"修改"条款.详情请参考BSD文件全部条款.本文档最新下载地址:
英文:http://libevent.org/
中文:http://blog.csdn.net/zhouyongku/article/details/53431750
请下载并运行"gitclonegit://github.com/nmathewson/libevent- book.git"获取本文档描述的最新版本源码.
<<上一章>>
libevent为实现不重要的DNS服务器,响应通过UDP传输的DNS请求提供了简单机制。本节要求读者对DNS协议有一定的了解。
16.1创建和关闭DNS服务器
接口
struct evdns_server_port* evdns_add_server_port_with_base(struct event_base* base,evutil_socket_t socket,int flags,evdns_request_callback_fn_type callback,void* user_data);typedef void ( * evdns_request_callback_fn_type)(struct evdns_server_request* request,void* user_data);void evdns_close_server_port(struct evdns_server_port* port);
要开始监听 DNS请求,调用evdns_add_server_port_with_base()。函数要求用于事件处理的event_base、用于监听的UDP套接字、可用的标志(现在总是0) 、一个收到DNS查询 时 要 调 用 的 回 调 函 数 , 以 及 要 传 递 给 回 调 函 数 的 用 户 数 据 指 针 。 函 数 返 回evdns_server_port对象。
使用 DNS服务器完成工作后,需要调用evdns_close_server_port()。
evdns_add_server_port_with_base()是2.0.1-alpha版 本 引 入 的 , 而evdns_close_server_port()则由1.3版本引入。
16.2检测DNS请求
不幸的是,当前 libevent没有提供较好的获取DNS请求的编程接口,用户需要包含event2/dns_struct.h文件,查看evdns_server_request结构体。
未来版本的 libevent应该会提供更好的方法。
接口
struct evdns_server_request {int flags;int nquestions;struct evdns_server_question** questions;};#define EVDNS_QTYPE_AXFR 252#define EVDNS_QTYPE_ALL 255struct evdns_server_question {int type;int dns_question_class;char name[1];};
flags字段包含请求中设置的DNS标志;nquestions字段是请求中的问题数;questions是evdns_server_question结构体指针数组。每个evdns_server_question包含请求的资源类型(请看下面的EVDNS_*_TYPE宏列表) 、请求类别(通常为EVDNS_CLASS_INET) ,以及请求的主机名。
这些结构体在1.3版本中引入,但是1.4版之前的名字是dns_question_class。名字中的“class”会让C++用户迷惑。仍然使用原来的“class”名字的C程序将不能在未来发布版本中正确工作。
接口
int evdns_server_request_get_requesting_addr(struct evdns_server_request* req,struct sockaddr* sa, int addr_len);
有时候 需 要 知道某 特 定 DNS 请 求 来 自 何 方 , 这 时 调 用evdns_server_request_get_requesting_add()就可以了。 应该传入有足够存储空间以容量地址的sockaddr:建议使用sockaddr_storage结构体。
这个函数在1.3版本中引入.
16.3响应DNS请求
DNS服务器收到每个请求后,会将请求传递给用户提供的回调函数,还带有用户数据指针 。回调函数必须响应请求或者忽略请求,或者确保请求最终会被回答或者忽略。回应请求前可以向回应中添加一个或者多个答案:
接口
int evdns_server_request_add_a_reply(struct evdns_server_request* req,const char* name, int n, const void * addrs, int ttl);int evdns_server_request_add_aaaa_reply(struct evdns_server_request* req,const char* name, int n, const void * addrs, int ttl);int evdns_server_request_add_cname_reply(struct evdns_server_request* req,const char* name, const char * cname, int ttl);
上述函数为请求 req的DNS 回应的结果节添加一个RR(类型分别为A、AAAA和CNAME) 。各个函数中,name是要为之添加结果的主机名,ttl是以秒为单位的存活时间。对于A和AAAA记录,n是要添加的地址个数,addrs是到原始地址的指针:对于A记录,是以n*4字节序列格式给出的IPv4地址; 对于AAAA记录, 是以n*16字节序列格式给出的IPv6地址。
成功时函数返回0,失败时返回-1。
接口
int evdns_server_request_add_ptr_reply(struct evdns_server_request* req,struct in_addr* in, const char * inaddr_name, const char * hostname,int ttl);
这个函数为请求的结果节添加一个 PTR记录。参数req 和ttl 跟上面的函数相同。必须提供in(一个IPv4地址)和inaddr_name(一个arpa域的地址)中的一个,而且只能提供一个 ,以指示为回应提供哪种地址。hostname是PTR查询的答案。
接口
#define EVDNS_ANSWER_SECTION 0#define EVDNS_AUTHORITY_SECTION 1#define EVDNS_ADDITIONAL_SECTION 2#define EVDNS_TYPE_A 1#define EVDNS_TYPE_NS 2#define EVDNS_TYPE_CNAME 5#define EVDNS_TYPE_SOA 6#define EVDNS_TYPE_PTR 12#define EVDNS_TYPE_MX 15#define EVDNS_TYPE_TXT 16#define EVDNS_TYPE_AAAA 28#define EVDNS_CLASS_INET 1int evdns_server_request_add_reply(struct evdns_server_request* req,int section, const char* name, int type, int dns_class, int ttl,int datalen, int is_name, const char* data);
这个函数为请求 req的DNS 回应添加任意RR。section字段指示添加到哪一节,其值应该是某个EVDNS_*_SECTION。name参数是RR的名字字段。type参数是RR的类型字段 ,其值应该是某个EVDNS_TYPE_*。dns_class参数是RR的类别字段。RR的rdata和rdlength字段将从data处的datalen字节中产生。如果is_name为true,data将被编码成DNS名字(例如,使用DNS名字压缩) 。否则,data将被直接包含到RR中。
接口
int evdns_server_request_respond(struct evdns_server_request* req, int err);int evdns_server_request_drop(struct evdns_server_request* req);
evdns_server_request_respond()函数为请求发送DNS回应,带有用户添加的所有RR, 以及错误码err。 如果不想回应某个请求, 可以调用evdns_server_request_drop()来忽略请求 ,释放请求关联的内存和结构体。
接口
#define EVDNS_FLAGS_AA 0x400#define EVDNS_FLAGS_RD 0x080void evdns_server_request_set_flags(struct evdns_server_request* req,int flags);
如果要为回应消息设置任何标志,可以在发送回应前的任何时候调用这个函数。除了 evdns_server_request_set_flags()首次在2.0.1-alpha版本中出现外,本节描述的所有函数都在1.3版本中引入。
16.4DNS服务器示例
接口
#include <event2/dns.h>#include <event2/dns_struct.h>#include <event2/util.h>#include <event2/event.h>#include <sys/socket.h>#include <stdio.h>#include <string.h>#include <assert.h>/* Let’s try binding to 5353. Port 53 is more traditional, but on mostoperating systems it requires root privileges.*/#define LISTEN_PORT 5353#define LOCALHOST_IPV4_ARPA "1.0.0.127.in-addr.arpa"#define LOCALHOST_IPV6_ARPA ("1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0." \"0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa")const ev_uint8_t LOCALHOST_IPV4[] = { 127, 0, 0, 1 };const ev_uint8_t LOCALHOST_IPV6[] = { 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,1 };#define TTL 4242/* This toy DNS server callback answers requests for localhost (mapping it to127.0.0.1 or ::1) and for 127.0.0.1 or ::1 (mapping them to localhost).*/void server_callback(struct evdns_server_request* request, void * data){int i;int error=DNS_ERR_NONE;/* We should try to answer all the questions. Some DNS servers don’t dothis reliably, though, so you should think hard before putting twoquestions in one request yourself.*/for (i=0; i < request->nquestions; ++i) {const struct evdns_server_question* q = request->questions[i];int ok=-1;/* We don’t use regular strcasecmp here, since we want a locale-independent comparison.*/if (0 == evutil_ascii_strcasecmp(q->name, "localhost")) {if (q->type == EVDNS_TYPE_A)ok = evdns_server_request_add_a_reply(request,q->name, 1, LOCALHOST_IPV4, TTL);else if (q->type == EVDNS_TYPE_AAAA)ok = evdns_server_request_add_aaaa_reply(request,q->name, 1, LOCALHOST_IPV6, TTL);} else if (0 == evutil_ascii_strcasecmp(q->name, LOCALHOST_IPV4_ARPA)) {if (q->type == EVDNS_TYPE_PTR)ok = evdns_server_request_add_ptr_reply(request, NULL, q->name, "LOCALHOST", TTL);} else if (0 == evutil_ascii_strcasecmp(q->name, LOCALHOST_IPV6_ARPA)) {if (q->type == EVDNS_TYPE_PTR)ok = evdns_server_request_add_ptr_reply(request, NULL, q->name, "LOCALHOST", TTL);} else {error = DNS_ERR_NOTEXIST;}if (ok<0 && error==DNS_ERR_NONE)error = DNS_ERR_SERVERFAILED;}/* Now send the reply.*/evdns_server_request_respond(request, error);}int main(int argc, char** argv){struct event_base* base;struct evdns_server_port* server;evutil_socket_t server_fd;struct sockaddr_in listenaddr;base = event_base_new();if (!base)return 1;server_fd = socket(AF_INET, SOCK_DGRAM, 0);if (server_fd < 0)return 2;memset(&listenaddr, 0, sizeof(listenaddr));listenaddr.sin_family = AF_INET;listenaddr.sin_port = htons(LISTEN_PORT);listenaddr.sin_addr.s_addr = INADDR_ANY;if (bind(server_fd, (struct sockaddr * )&listenaddr, sizeof(listenaddr))<0)return 3;server = evdns_add_server_port_with_base(base, server_fd, 0,server_callback, NULL);event_base_dispatch(base);evdns_close_server_port(server);event_base_free(base);return 0;}
<<下一章>>
- LibEvent中文帮助文档--第16章【DNS服务器接口】
- LibEvent中文帮助文档--第15章【底层DNS接口】
- LibEvent中文帮助文档--第17章【废弃的DNS接口】
- LibEvent中文帮助文档--第14章【使用LibEvent的DNS:高和低层功能】
- LibEvent中文帮助文档--第5章【设置LibEvent库】
- LibEvent中文帮助文档--第18章【LibEvent编程示例】
- LibEvent中文帮助文档--第1、2、3、4章
- LibEvent中文帮助文档-第6章【创建Event_base】
- LibEvent中文帮助文档-第8章【处理事件】
- LibEvent中文帮助文档-第7章【事件循环】
- LibEvent中文帮助文档--第11章【高级话题】
- LibEvent中文帮助文档--第12章【Evbuffer IO实用功能】
- LibEvent中文帮助文档
- LibEvent中文帮助文档
- LibEvent中文帮助文档
- LibEvent中文帮助文档--第9章【辅助类型和函数】
- LibEvent中文帮助文档--第10章【Bufferevent 概念和入门】
- LibEvent中文帮助文档--第13章【连接监听器:接受一个TCP连接】
- Conscription
- Device Tree Usage
- 39. Combination Sum
- poj 1201 Intervals
- 解决music模块中白条问题
- LibEvent中文帮助文档--第16章【DNS服务器接口】
- python这个老顽固
- UML基础——面向对象技术
- 如何判断CPU是大端存放还是小端存放
- c语言==测量各种数据类型的长度以及typedf关键字对数据类型的作用(21)
- 时间序列分析这件小事(二)--自回归
- matcaffe
- 自定义树莓派的显示分辨率
- 解读 DecompressManifest