多级中文域名解析系统-2

LOCAL_DNS

local DNS作为本地网络中的逻辑核心非常重要

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
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <netdb.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#include "defAndTools.h"
#include "localServer.h"

#define CACHEFILE "localCache.txt"
int isEnd(struct DNS_Header *header)
{
if (header->authorNum!=0)
return 0;
return 1;
}

int main(int argc, char *argv[])
{
//①设置监听
int serverSocket = socket(AF_INET, SOCK_STREAM, 0);
//发送缓冲区和接收缓冲区
char sendbuf[512];
char recvbuf[512];
int sendBufferPointer=0;
int recvBufferPointer=0;
//初始化缓冲区
memset(sendbuf,0,512);
memset(recvbuf,0,512);

//声明两个套接字sockaddr_in结构体,分别用于客户端和服务器
struct sockaddr_in server_addr;
struct sockaddr_in clientAddr;
int addr_len = sizeof(clientAddr);

int client;
//初始化服务器端的套接字
bzero(&server_addr, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(SERVER_PORT);
server_addr.sin_addr.s_addr = inet_addr(LOCAL_SERVER_IP);

//绑定套接字
bind(serverSocket, (struct sockaddr *)&server_addr, sizeof(server_addr));
//设置监听状态
listen(serverSocket, 5);

//②循环监听
while(1)
{
printf("监听端口 : %d\n",SERVER_PORT);
//调用accept,进入阻塞状态,返回一个client套接字描述符
client = accept(serverSocket, (struct sockaddr*)&clientAddr, (socklen_t*)&addr_len);
printf("连接成功\n");

struct sockaddr_in c;
socklen_t cLen = sizeof(c);
getpeername(client, (struct sockaddr*) &c, &cLen);
printf("请求端信息: %s : %d\n",inet_ntoa(c.sin_addr),ntohs(c.sin_port));

//对于TCP,先接收一个两字节的包长度
unsigned short recv_length;
recv(client,&recv_length,2,0);
recv_length = ntohs(recv_length);

//接收客户端发来的数据,recv返回值为接收字节数
int dataNum = recv(client,recvbuf,recv_length,0);

//③提取recvbuf,构建DNS包
//构造DNS包头部,从缓冲区读取一个DNS头部
struct DNS_Header *client_query_header;
client_query_header = malloc(sizeof(DNS_HEAD));
decode_header(client_query_header,recvbuf,&recvBufferPointer);
printf("\n请求端信息:\n");
print_header(client_query_header);

//构造准备发送的DNS头部
struct DNS_Header *query_header;
query_header = malloc(sizeof(DNS_HEAD));
memcpy(query_header,client_query_header,sizeof(DNS_HEAD));
query_header->queryNum = 1;

//④解析并处理请求
//有多少个请求,就进行几次循环,每个循环完成一次系统运作
for(int i=0;i<client_query_header->queryNum;i++)
{
//读取解析一个请求部分
struct DNS_Query *client_query_section;
client_query_section = malloc(sizeof(DNS_QUERY));
decode_query_section(client_query_section,recvbuf,&recvBufferPointer);
printf("\n正在处理第 %d 个请求\n",i+1);
print_query_section(client_query_section);

//判断本地缓存中是否存在
int findInCache = firstFindRR(client_query_section,CACHEFILE,sendbuf,&sendBufferPointer);

if (findInCache==1)
{
printf("在本地缓存中找到记录,直接回复请求\n");
goto findit;
}

//本地缓存不存在
char UDPsendbuf[512];
char UDPrecvbuf[512];
int UDPsendBufferPointer=0;
int UDPrecvBufferPointer=0;
memset(UDPsendbuf,0,512);
memset(UDPrecvbuf,0,512);

//直接将从客户端接受收的包写入缓冲区
printf("\n发送给根服务器的请求:\n");
encode_header(query_header,UDPsendbuf,&UDPsendBufferPointer);
print_header(query_header);
encode_query_section(client_query_section,UDPsendbuf,&UDPsendBufferPointer);
print_query_section(client_query_section);

//定义用于接收的结构。由于根服务器必然不可能返回最终结果,所以不需要构造answer
struct DNS_Header *recv_header;
struct DNS_RR *recv_answer,*recv_authority,*recv_additional;
recv_header = malloc(sizeof(DNS_HEAD));
recv_authority = malloc(sizeof(DNS_ResouceRecord));
recv_additional = malloc(sizeof(DNS_ResouceRecord));

//与根服务器建立UDP连接
int sockfd=socket(AF_INET,SOCK_DGRAM,0);
struct sockaddr_in addr;
addr.sin_family =AF_INET;
addr.sin_port =htons(SERVER_PORT);
addr.sin_addr.s_addr=inet_addr(ROOT_SERVER_IP);

bind(sockfd,(struct sockaddr*)&addr,sizeof(addr));

//发送
sendto(sockfd,UDPsendbuf,UDPsendBufferPointer,0,(struct sockaddr*)&addr,sizeof(addr));

//接收回复
socklen_t len=sizeof(addr);
recvfrom(sockfd,UDPrecvbuf,sizeof(UDPrecvbuf),0,(struct sockaddr*)&addr,&len);

//断开
close(sockfd);

printf("\n收到根服务器的回复:\n");
//从接收缓冲区解析并构造包结构然后打印
decode_header(recv_header,UDPrecvbuf,&UDPrecvBufferPointer);
print_header(recv_header);

decode_resource_record(recv_authority,UDPrecvbuf,&UDPrecvBufferPointer);
print_resource_record(recv_authority);
decode_resource_record(recv_additional,UDPrecvbuf,&UDPrecvBufferPointer);
print_resource_record(recv_additional);

//重置缓冲区
UDPsendBufferPointer=0;
UDPrecvBufferPointer=0;
memset(UDPsendbuf,0,512);
memset(UDPrecvbuf,0,512);

//用于计数本次循环是第几级服务器发来的
int count=0;
while(isEnd(recv_header)==0)
{
count++;
//向下一个服务器建立UDP连接
int sockfm=socket(AF_INET,SOCK_DGRAM,0);
struct sockaddr_in addr;
addr.sin_family =AF_INET;
addr.sin_port =htons(SERVER_PORT);
addr.sin_addr.s_addr=inet_addr(recv_additional->rdata);
//recv_additional->rdata即保存着下一个服务器的IP

bind(sockfm,(struct sockaddr*)&addr,sizeof(addr));

//重置缓冲区和结构
UDPsendBufferPointer=0;
UDPrecvBufferPointer=0;
memset(UDPsendbuf,0,512);
memset(UDPrecvbuf,0,512);
free(recv_header); recv_header = NULL;
free(recv_authority); recv_authority = NULL;
free(recv_additional); recv_additional = NULL;

//直接将从客户端接受收的请求写入发送缓冲区
printf("\n发送给 %d级 服务器的请求:\n",count);
encode_header(query_header,UDPsendbuf,&UDPsendBufferPointer);
print_header(query_header);
encode_query_section(client_query_section,UDPsendbuf,&UDPsendBufferPointer);
print_query_section(client_query_section);

//发送
sendto(sockfm,UDPsendbuf,UDPsendBufferPointer,0,(struct sockaddr*)&addr,sizeof(addr));

//接收回复
len=sizeof(addr);
recvfrom(sockfm,UDPrecvbuf,sizeof(UDPrecvbuf),0,(struct sockaddr*)&addr,&len);

//断开连接
close(sockfm);

//开始处理
printf("\n收到 %d级 服务器发来的回复:\n",count);

recv_header = malloc(sizeof(DNS_HEAD));
recv_answer = malloc(sizeof(DNS_ResouceRecord));
recv_authority = malloc(sizeof(DNS_ResouceRecord));
recv_additional = malloc(sizeof(DNS_ResouceRecord));

decode_header(recv_header,UDPrecvbuf,&UDPrecvBufferPointer);
print_header(recv_header);

for(int j=0;j<recv_header->answerNum;j++){
decode_resource_record(recv_answer,UDPrecvbuf,&UDPrecvBufferPointer);
print_resource_record(recv_answer);
}

for(int j=0;j<recv_header->authorNum;j++){
decode_resource_record(recv_authority,UDPrecvbuf,&UDPrecvBufferPointer);
print_resource_record(recv_authority);
}

for(int j=0;j<recv_header->addNum;j++){
decode_resource_record(recv_additional,UDPrecvbuf,&UDPrecvBufferPointer);
print_resource_record(recv_additional);
}
}

//UDP请求的循环结束,此时构造得到的结构体已经得到该次请求目标结果,且已经在循环中打印
//将从最终结果服务器返回来的结构写入发送缓冲区,本次循环结束
encode_header(recv_header,sendbuf,&sendBufferPointer);
for(int j=0;j<recv_header->answerNum;j++){
encode_resource_record(recv_answer,sendbuf,&sendBufferPointer);
//将结果写入cache
addRRToCache(recv_answer,"localCache.txt");
}
for(int j=0;j<recv_header->authorNum;j++){
encode_resource_record(recv_authority,sendbuf,&sendBufferPointer);
addRRToCache(recv_authority,"localCache.txt");
}
for(int j=0;j<recv_header->addNum;j++){
encode_resource_record(recv_additional,sendbuf,&sendBufferPointer);
addRRToCache(recv_additional,"localCache.txt");
}

findit:;
//⑤发送缓冲
//发送已准备好的在缓冲区的数据,包总长度即为当下发送缓冲区指针下标
unsigned short send_length = htons(sendBufferPointer);
send(client,&send_length,2,0);
send(client, sendbuf, sendBufferPointer, 0);
//一个请求的解析与回答发送结束,清空发送缓冲区与指针,准备进行下一次发送
sendBufferPointer=0;
memset(sendbuf,0,512);
}

//对一个客户端的所有请求解析结束
close(client);
recvBufferPointer=0;
memset(recvbuf,0,512);
printf("连接关闭\n");
printf("===================================\n\n");
}
}

Client

Client为本机主逻辑

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
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <netdb.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdint.h>
//底层操作
#include "defAndTools.h"
//本地服务器
#include "localServer.h"

int main(int argc, char *argv[])
{
//容错
for (int i=1;i<=(argc-1)/2;i++)
if (strTypeToCode(argv[2*i])==0)
{
printf("类型错误!\n");
exit(0);
}

//①连接本地服务器 初始化TCP连接
int clientSocket = socket(AF_INET, SOCK_STREAM, 0);
//发送缓冲和接收缓冲
char sendbuf[512];
char recvbuf[512];
//定义缓冲区指示下标
int sendBufferPointer=0;
int recvBufferPointer=0;
//清空缓冲区
memset(sendbuf,0,512);
memset(recvbuf,0,512);

struct sockaddr_in serverAddr;
serverAddr.sin_family = AF_INET;
serverAddr.sin_port = htons(SERVER_PORT);
serverAddr.sin_addr.s_addr = inet_addr(LOCAL_SERVER_IP);
//连接服务器
if(connect(clientSocket, (struct sockaddr *)&serverAddr, sizeof(serverAddr))==-1)
printf("连接失败\n");
printf("发送信息:\n");

//②根据输入内容,准备DNS包,并写入发送缓冲区
//定义DNS头部
struct DNS_Header *query_header;
query_header = malloc(sizeof(DNS_HEAD));
//调用函数,填写欲发送的DNS包的头部结构体
unsigned short tag = create_tag(0,0,0,0,0,0,0,0);
//argc-1除2即为域名请求的个数,因为每个域名参数后带一个类型
create_query_header(query_header,999,tag,argc/2,0x0000,0x0000,0x0000);
//将头部写入缓冲区
encode_header(query_header,sendbuf,&sendBufferPointer);
//打印生成的头部
print_header(query_header);

//根据运行参数生成一个或多个请求部分并写入缓冲区
for(int i=1;i<=(argc-1)/2;i++)
{
//填写DNS请求结构,argv[2*i]字符串对应的类型
unsigned short qtype = strTypeToCode(argv[2*i]);
unsigned short qclass = 0x0001;

struct DNS_Query *query_section;
query_section = malloc(sizeof(DNS_QUERY));
create_query_section(query_section,argv[2*i-1],qtype,qclass);
encode_query_section(query_section,sendbuf,&sendBufferPointer);
print_query_section(query_section);
}

//③向本地服务器发包
//发送已准备好的在缓冲区的数据,包总长度即为当下发送缓冲区指针下标
unsigned short length = htons(sendBufferPointer);
//对于TCP连接,必须先发送一个DNS包总长度,否则wireshark不会识别!
send(clientSocket,&length,2,0);
send(clientSocket, sendbuf, sendBufferPointer, 0);

//④根据请求数量收包,有多少个请求就会收到多少个DNS包
for(int k=0;k<query_header->queryNum;k++)
{
unsigned short recv_length;
recv(clientSocket,&recv_length,2,0);
recv_length = ntohs(recv_length);
int dataNum = recv(clientSocket, recvbuf, recv_length, 0);

//⑤处理接收到缓冲区的DNS包,从中抽取出需要返还给用户的数据
//构造DNS包头部,从缓冲区读取并填充DNS头部
struct DNS_Header *recv_header;
recv_header = malloc(sizeof(DNS_HEAD));
decode_header(recv_header,recvbuf,&recvBufferPointer);
printf("[回复: %d]\n",k+1);
print_header(recv_header);
struct DNS_RR *recv_answer,*recv_add;
//标准回复只可能在answer和addition有值,所以只需要考虑读这两个部分
for(int i=0;i<recv_header->answerNum;i++)
{
//读取解析打印一个回应部分
recv_answer = NULL;
recv_answer = malloc(sizeof(DNS_ResouceRecord));
decode_resource_record(recv_answer,recvbuf,&recvBufferPointer);
print_resource_record(recv_answer);
}
for(int i=0;i<recv_header->addNum;i++)
{
//读取解析打印一个addition部分
recv_add = NULL;
recv_add = malloc(sizeof(DNS_QUERY));
decode_resource_record(recv_add,recvbuf,&recvBufferPointer);
print_resource_record(recv_add);
}
recvBufferPointer=0;
memset(recvbuf,0,512);
}
close(clientSocket);
}