我是靠谱客的博主 谨慎黑米,这篇文章主要介绍网络协议-DNS组包实例,现在分享给大家,希望可以做个参考。

DNS应用

根据DNS报文格式,可以通过自组DNS请求报文,判断当前设备是否已连接外网。DNS报文格式链接: DNS报文格式.

1. 结构体构造

DNS请求报文为header + 正文,其中正文为name+type+class。所以我们需要构造的DNS请求报文格式为header+name+type+class,header可用一个结构体表示,长度为16 * 6位,type+class可用一个结构体表示,长度为16 * 2位。
具体如下:

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
typedef struct { u16 id; u16 flags; u16 ques; u16 answer; u16 auth; u16 addi; }dns_header; // DNS请求头 typedef struct { u16 type; u16 class; }dns_query; // DNS请求正文

2. name处理

在DNS报文中,需要注意域名的编码。请求的域名中没有“.”,域名中的“.”被编码为元信息,指示接下来的多少字节是有效信息。
看个例子,我要请求www.google.com.hk。
报文中的name为 03 77 77 77 06 67 6f 6f 67 6c 65 03 63 6f 6d 02 68 6b 00,即为03 w w w 06 g o o g l e 03 c o m 02 h k 00
其中加粗的就是元信息,最后一个字符为0。

3. 完整代码

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <errno.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #define TRUE 0 #define FALSE 1 #define MAX_SIZE 1024 /* * DNS header : * * | ID | flag | * | Questions | Answer | * | Authority RRs | Additional RRs | * | Name | * | Type | Class | * * size : 2 + 2 + 2 + 2 + 2 + 1 + NameLen + 1 + 2 + 2 */ typedef unsigned char uchar; typedef unsigned short u16; typedef struct { u16 id; u16 flags; u16 ques; u16 answer; u16 auth; u16 addi; }dns_header; typedef struct { u16 type; u16 class; }dns_query; static int socket_init(void) { return socket(AF_INET, SOCK_DGRAM, 0); } int get_host_by_name(const char *name) { if (!name || 0 == strlen(name)) return FALSE; int fd = socket_init(); if (fd < 0) { printf("socket_init error, socket creat fail n"); return FALSE; } int i = 0; char *tmpPtr = NULL; char sendBuff[MAX_SIZE]; dns_header *dnsheader_p = (dns_header *)sendBuff; dns_query * dnsquery_p = NULL; // DNS header 构造 memset(sendBuff, 0, MAX_SIZE); dnsheader_p->id = (u16)1; dnsheader_p->flags = htons(0x0100); dnsheader_p->ques = htons(1); dnsheader_p->answer = htons(0); dnsheader_p->auth = htons(0); dnsheader_p->addi = htons(0); // DNS name 填充 strcpy(sendBuff + sizeof(dns_header) + 1, name); tmpPtr = sendBuff + sizeof(dns_header) + 1; // www.baidu.com -> 3www5baidu3com0 while (tmpPtr < (sendBuff + sizeof(dns_header) + 1 + strlen(name))) { if (*tmpPtr != '.') { i++; } else { *(tmpPtr - i - 1) = i; i = 0; } tmpPtr++; } *(tmpPtr - i - 1) = i; // DNS query 构造 dnsquery_p = (dns_query *)(sendBuff + sizeof(dns_header) + 2 + strlen(name)); dnsquery_p->type = htons(1); dnsquery_p->class = htons(1); // 1 name -> ipv4 28 name -> ipv6 struct timeval tv; struct sockaddr_in servaddr; tv.tv_sec = 5; tv.tv_usec = 5; // 发送DNS请求包 memset(&servaddr, 0, sizeof(struct sockaddr_in)); servaddr.sin_family = AF_INET; servaddr.sin_port = htons(53); if (inet_pton(AF_INET, "114.114.114.114", &servaddr.sin_addr) < 0) { printf("inet_pton error, get sin_addr fail n"); close(fd); return FALSE; } setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(struct timeval)); if (sendto(fd, sendBuff, sizeof(dns_header) + 1 + strlen(name) + 1 + sizeof(dns_query), 0, (const struct sockaddr *)&servaddr, sizeof(struct sockaddr_in)) < 0) { printf("send to error, send buff fail n"); close(fd); return FALSE; } // 接收DNS响应包 int len, size; size = sizeof(struct sockaddr_in); if ((len = recvfrom(fd, sendBuff, MAX_SIZE, 0, (struct sockaddr *)&servaddr, (socklen_t *)&size)) < 0) { if (errno == EWOULDBLOCK) { printf("recvfrom error, timeout n"); } else { printf("recvfrom error, unknow failn"); } close(fd); return FALSE; } if (0 == dnsheader_p->answer) { printf("ack error, no answer n"); close(fd); return FALSE; } tmpPtr = sendBuff + len - 4; printf("parsing %s success ! it’s addr is %u.%u.%u.%u n", name, (uchar)*tmpPtr, (uchar)*(tmpPtr+1), (uchar)*(tmpPtr+2), (uchar)*(tmpPtr+3)); close(fd); return TRUE; } void usage(void) { printf("usage :nnt./test namennteg. ./test www.zhihu.comnn"); exit(-1); } int main(int argc, char *argv[]) { if (argc != 2) usage(); get_host_by_name(argv[1]); return 0; }

程序执行结果如下:
在这里插入图片描述

最后

以上就是谨慎黑米最近收集整理的关于网络协议-DNS组包实例的全部内容,更多相关网络协议-DNS组包实例内容请搜索靠谱客的其他文章。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(56)

评论列表共有 0 条评论

立即
投稿
返回
顶部