今天的故事开始于一个看似简单的问题
20:44:44.190970 socket(AF_INET, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, IPPROTO_IP) = 9 <0.000021>20:44:44.191027 connect(9, {sa_family=AF_INET, sin_port=htons(53), sin_addr=inet_addr("<主DNS服务器IP>")}, 16) = 0 <0.000023><<===创建一个UDP socket,连接到主DNS服务器,端口是53(dns默认端口)20:44:44.191102 poll([{fd=9, events=POLLOUT}], 1, 0) = 1 ([{fd=9, revents=POLLOUT}]) <0.000019>20:44:44.191163 sendto(9, "p2331��1������vnovulorcu6410icbc-ax"..., 38, MSG_NOSIGNAL, NULL, 0) = 38 <0.000037>20:44:44.191236 poll([{fd=9, events=POLLIN}], 1, 1000) = 0 (Timeout) <1.001080><<===利用epoll向服务器发送dns报文,并等待返回,1秒钟后超时20:44:45.192402 socket(AF_INET, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, IPPROTO_IP) = 10 <0.000048>20:44:45.192548 connect(10, {sa_family=AF_INET, sin_port=htons(53), sin_addr=inet_addr("<备用DNS服务器IP>")}, 16) = 0 <0.000047>20:44:45.192686 poll([{fd=10, events=POLLOUT}], 1, 0) = 1 ([{fd=10, revents=POLLOUT}]) <0.000044>20:44:45.192831 sendto(10, "p2331��1������vnovulorcu6410icbc-ax"..., 38, MSG_NOSIGNAL, NULL, 0) = 38 <0.000058>20:44:45.192971 poll([{fd=10, events=POLLIN}], 1, 1000) = 0 (Timeout) <1.000812><<===创建第二个UDP socket,连接到第备用DNS服务器,发送DNS报文,并等待返回20:44:46.193875 poll([{fd=9, events=POLLOUT}], 1, 0) = 1 ([{fd=9, revents=POLLOUT}]) <0.000032>20:44:46.193977 sendto(9, "p2331��1������vnovulorcu6410icbc-ax"..., 38, MSG_NOSIGNAL, NULL, 0) = 38 <0.000061>20:44:46.194092 poll([{fd=9, events=POLLIN}], 1, 1000) = 0 (Timeout) <1.001073><<===重新向主DNS服务器发送报文,1秒钟后又超时20:44:47.195234 poll([{fd=10, events=POLLOUT}], 1, 0) = 1 ([{fd=10, revents=POLLOUT}]) <0.000032>20:44:47.195336 sendto(10, "p2331��1������vnovulorcu6410icbc-ax"..., 38, MSG_NOSIGNAL, NULL, 0) = 38 <0.000062>20:44:47.195452 poll([{fd=10, events=POLLIN}], 1, 1000) = 0 (Timeout) <1.001104><<===重新向备用DNS服务器发送报文,1秒钟后又超时20:44:48.196677 close(9) = 0 <0.000077>20:44:48.196868 close(10) = 0 <0.000051><<===重试结束关闭上面两个socket
20:45:00.248651 open("/etc/hosts", O_RDONLY|O_CLOEXEC) = 9 <0.000041>20:45:00.248803 fstat(9, {st_mode=S_IFREG|0644, st_size=184, ...}) = 0 <0.000030>20:45:00.248918 mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fffc17f5000 <0.000030>20:45:00.249025 read(9, "127.0.0.1 localhost localhost."..., 4096) = 184 <0.000049>20:45:00.249182 read(9, "", 4096) = 0 <0.000030>20:45:00.249324 close(9) = 0 <0.000031>20:45:00.249425 munmap(0x7fffc17f5000, 4096) = 0 <0.000042>20:45:00.249631 write(10, "��4P6�����3s3������������!���376377377"..., 1104) = 1104 <0.000047>20:45:00.249769 read(11, "��62146�����1034�23���23AUTH_VERSION_S"..., 8208) = 1676 <0.015974>20:45:00.266029 open("/u01/oracle/product/db12cr2/rdbms/mesg/oraus.msb", O_RDONLY) = 9 <0.000048><<===从DNS拿不到结果,只好从/etc/host里找了,最后勉强登录完成.
PART 1
找出问题原因

PART 2
我也要写个DNS客户端
跟客户沟通,等客户验证完成,已经是当天夜里23:30了,躺在床上毫无睡意的专家,脑子里萦绕着,“我也要写个DNS客户端,我也要写个DNS客户端…”。于是——

1
头文件
定义两个函数原型:
* dns_client_commit: 手写DNS报文,查询IP
* simple_convert_domain_ip: 利用getaddrinfo获取IP
DNS服务器,就用联通的114.114.114.114,端口默认的53
源码清单: 3.1 dnsClient.h
/*通过自己组DNS报文,向dns服务器发送UDP消息,获取IP地址。*/int dns_client_commit(const char *domain);/*通过getaddrinfo函数从DNS获取IP地址*/void simple_convert_domain_ip(const char *domain);
2
函数实现
要点:DNS报文中的域名,要变成标准格式的。比如,www.163.com这个域名,标准格式是:
03 77 77 77 03 31 36 33 03 63 6f 6d就是: 3 www 3 163 3 com
这个函数原型定义在resolv.h中,编译时需要引用resolv库。代码清单: 3.2 dnsClient./*利用res_mkquery函数,生成一个DNS报文*/int create_dns_request(const char *domain, unsigned char *request, int rlen){int len = strlen(domain);int request_size = res_mkquery(ns_o_query, domain, ns_c_in, ns_t_a, NULL, 0, NULL, request, rlen);if (request_size < 0){perror("res_mkquery");return -1;}return request_size;}/*打印dns报文,用于调试 */void print_dns_request(unsigned char *request, int request_size){printf("DNS Request:n");int i;for (i = 0; i < request_size; i++){printf("%02x ", request[i]);if ((i + 1) % 16 == 0){printf("n");}}printf("n");}/* 利用ns_initparse函数解析dns回复的报文消息*/void parse_dns_response(const unsigned char *response, int response_size){printf("DBS Response:n");ns_msg handle;if (ns_initparse(response, response_size, &handle) < 0){fprintf(stderr, "ns_initparse errorn");return;}int answer_count = ns_msg_count(handle, ns_s_an);int i;for (i = 0; i < answer_count; i++){ns_rr rr;if (ns_parserr(&handle, ns_s_an, i, &rr) < 0){fprintf(stderr, "ns_parserr errorn");return;}// ns_rr_type(rr) == ns_t_a && ns_rr_class(rr) == ns_c_in &&if (ns_rr_rdlen(rr) == 4){struct in_addr ip_address;memcpy(&ip_address, ns_rr_rdata(rr), sizeof(struct in_addr));printf("%sn", inet_ntoa(ip_address));}}}/*向dns服务器发送报文 */int dns_client_commit(const char *domain){struct sockaddr_in servaddr;unsigned char request[1024] = {0};int length = create_dns_request(domain, (unsigned char *)request, 1024);// print_dns_request(request, length);servaddr.sin_family = AF_INET;servaddr.sin_port = htons(DNS_SERVER_PORT);servaddr.sin_addr.s_addr = inet_addr(DNS_SERVER_IP);int sockfd = socket(AF_INET, SOCK_DGRAM, 0);if (sockfd < 0){perror("socket");return -1;}int ret = connect(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr));if (ret != 0){perror("connect");return -1;}int slen = sendto(sockfd, request, length, 0, NULL, 0);if (slen < 0){printf("error:%dn", errno);perror("sendto");return -2;}char response[1024] = {0};struct sockaddr_in addr;size_t addr_len = sizeof(struct sockaddr_in);int n = recvfrom(sockfd, response, sizeof(response), 0, (struct sockaddr *)&addr, (socklen_t *)&addr_len);parse_dns_response((unsigned char *)response, n);return n;}/*利用getaddrinfo函数获取IP */void simple_convert_domain_ip(const char *domain){struct addrinfo hints, *res, *p;int status;char ip[INET6_ADDRSTRLEN];memset(&hints, 0, sizeof(hints));hints.ai_family = AF_UNSPEC;hints.ai_socktype = SOCK_STREAM;if ((status = getaddrinfo(domain, NULL, &hints, &res)) != 0){perror("getaddrinfo");return;}printf("nIP address for %s:n", domain);for (p = res; p != NULL; p = p->ai_next){void *addr;char *ip_version;if (p->ai_family == AF_INET){struct sockaddr_in *ipv4 = (struct sockaddr_in *)p->ai_addr;addr = &(ipv4->sin_addr);ip_version = "IPv4";}else{struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *)p->ai_addr;addr = &(ipv6->sin6_addr);ip_version = "IPv6";}inet_ntop(p->ai_family, addr, ip, sizeof(ip));printf("%s: %sn", ip_version, ip);}freeaddrinfo(res);return;}
3
测试函数

代码清单:3.3 test.c
int main(int argc, char *argv[]){if (argc < 2)return -1;dns_client_commit(argv[1]);simple_convert_domain_ip(argv[1]);exit(EXIT_SUCCESS);}
4
Makefile

代码清单:3.4 Makefile
TARGET=./testLIBS=-lresolvall:gcc -o $(TARGET) dnsClient.c test.c $(LIBS)clean:rm -f $(TARGET)
5
编译测试
make./test www.ce-service.com.cn
DBS Response:47.104.176.125IP address for www.ce-service.com.cn:IPv4: 47.104.176.12
原创文章,作者:速盾高防cdn,如若转载,请注明出处:https://www.sudun.com/ask/93408.html