今天的故事开始于一个看似简单的问题
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=./test
LIBS=-lresolv
all:
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.125
IP address for www.ce-service.com.cn:
IPv4: 47.104.176.12
原创文章,作者:速盾高防cdn,如若转载,请注明出处:https://www.sudun.com/ask/93408.html