多级中文域名解析系统-1(c语言)

Introduce

  • 支持中文域名解析,支持缓存与多请求

  • 遵循RFC1180标准,可被wireshark抓包检测到

  • 本系统包含一个客户端,四个中间多级DNS,一个根DNS,一个本地DNS

  • 难点在于①不用python而使用C语言必须写非常多的底层操作,主要集中在defAndTools库中②DNS请求的逻辑

Project Structure

CODES EXPLAINATION
defAndTools.h 此包为主要工具包,涉及网络中的核心底层的操作,是主要难点之一
LOCAL_DNS.c 本地DNS服务器核心逻辑,是本网络中的核心部件,是主要难点之一
Client.c 客户端主逻辑
ROOT_DNS.c 根域名解析服务器的逻辑代码
DNS1.c 第一级域名解析服务器主逻辑
DNS2.c 第二级域名解析服务器主逻辑
DNS3.c 第三级域名解析服务器主逻辑
DNS4.c 第四级域名解析服务器主逻辑
localServer.h 本地DNS服务器的参数设置
FILES EXPLAINATION
localCache.txt 本地DNS服务器的缓存
RRL1.txt 第一级域名解析服务器的缓存
RRL2.txt 第二级域名解析服务器的缓存
RRL3.txt 第三级域名解析服务器的缓存
RRL4.txt 第四级域名解析服务器的缓存
RRroot.txt 根域名解析服务器的缓存

defAndTools

此包为主要工具包,涉及网络中的底层的操作

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
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
#include <stdio.h>
#include <string.h>
#include <arpa/inet.h>
#include <stdlib.h>

#define MAX_SIZE_OF_DOMAIN 100
#define SERVER_PORT 53
#define ROOT_SERVER_IP "127.0.0.3"

//用于储存域名方便处理的全局变量
char domain_temp[MAX_SIZE_OF_DOMAIN];
typedef struct DNS_Header
{
unsigned short id; //16位的消息ID标示一次正常的交互,该ID由消息请求者设置,消息响应者回复请求时带上该ID。
unsigned short tag; //tag要拆,并单独写一个生成tag函数
unsigned short queryNum; //标示请求部分的条目数
unsigned short answerNum;//标示响应部分的资源记录数。如果响应消息中没有记录,则设置为0
unsigned short authorNum;//标示权威部分的域名服务器资源记录数。如果响应消息中没有权威记录,则设置为0
unsigned short addNum; //标示额外部分的资源记录数。
}DNS_HEAD;

typedef struct DNS_Query
{
char *name; //请求的域名。
unsigned short qtype; //记录的类型 [A:0x0001] [NS:0x0002] [CNAME:0x0005] [MX:0x000F]
unsigned short qclass; //请求的资源记录的类型 一般为[IN:0x0001]
}DNS_QUERY;

typedef struct DNS_RR
{
char *name;
unsigned short type; //请求的域名
unsigned short _class; //响应的资源记录的类型 一般为[IN:0x0001]
unsigned int ttl; //该资源记录被缓存的秒数。
unsigned short data_len; //RDATA部分的长度
unsigned short pre; //MX特有的优先级 Preference
char *rdata; //[A:32位的IP地址(4字节)] [CNAME/NS/MX:域名]
}DNS_ResouceRecord;

typedef struct tag
{
unsigned short qr; //[1]标示该消息是请求消息(该位为0)还是应答消息(该位为1)
unsigned short opcode; //[4]0 QUERY。标准查询
unsigned short aa; //[1]只在响应消息中有效。该位标示响应该消息的域名服务器是该域中的权威域名服务器。因为Answer Section中可能会有很多域名
unsigned short tc; //[1]标示这条消息是否因为长度超过UDP数据包的标准长度512字节,如果超过512字节,该位被设置为1
unsigned short rd; //[1]是否递归查询。1为递归查询
unsigned short ra; //[1]在响应消息中清除并设置。标示该DNS域名服务器是否支持递归查询。
unsigned short z; //[3] 冗余res 0
unsigned short rcode; //[4] 0 成功的响应
}TAG;

/***********************缓冲区操作和工具***************************/
/*此函数用于向buffer中写入8bit数据
* *buffer:指向缓冲区
* *bufferPointer:目前已写入的缓冲区最新一位的下一位
* 以下put16bits put32bits同理
*/
void put1Byte(char *buffer,int *bufferPointer, char value)
{
//调整value为网络字节序
value = htons(value);
//void *memcpy(void *dest, void *src, unsigned int count);
//用于 把资源内存(src所指向的内存区域) 拷贝到目标内存(dest所指向的内存区域),count为拷贝区域大小.
//buffer为缓冲区首地址,bufferPointer为缓冲区已写入下标,此函数参数为指向这两个量的指针,通过传递地址来实现主函数与子函数的实参传递。
//value为欲写入缓冲区的数据(value为8bit)
memcpy(buffer + *bufferPointer,&value,1);
//缓冲区已写入下标向后移动,使其指向下一次写入时应该写入的位置,*bufferPointer为指针bufferPointer所指地址的内容
*bufferPointer += 1;
}
void put2Bytes(char *buffer,int *bufferPointer, unsigned short value)
{
value = htons(value);
memcpy(buffer + *bufferPointer,&value,2);
*bufferPointer += 2;
}
void put4Bytes(char *buffer,int *bufferPointer, unsigned int value)
{
value = htons(value);
memcpy(buffer + *bufferPointer,&value,4);
*bufferPointer += 4;
}
//将变长字符串str写入buffer
void putDomainName(char *buffer,int *bufferPointer, char *str)
{
memcpy(buffer + *bufferPointer,str,strlen(str)+1); //末尾0需要一起打印
*bufferPointer += strlen(str)+1;
}
//从缓冲区取16个位
unsigned short get2Bytes(char *buffer,int *bufferPointer)
{
unsigned short value;
memcpy(&value,buffer + *bufferPointer,2);
*bufferPointer += 2;

return ntohs(value);
}
unsigned int get4bits(char *buffer,int *bufferPointer)
{
unsigned int value;
memcpy(&value,buffer + *bufferPointer,4);
*bufferPointer += 4;

return ntohs(value);
}
//读取变长字符串str 读取到0即停止 0即为'\0'
//域名不考虑字节序问题 ,也不用考虑编码问题,都是一个字节一个字节读
void getDomainName(char *buffer,int *bufferPointer,int *lengthOfDomain)
{

int valueWriting=0;
while(buffer[*bufferPointer]!=0)
{
domain_temp[valueWriting] = buffer[*bufferPointer];
valueWriting++;
(*bufferPointer)++;
}
domain_temp[valueWriting] = 0; //末尾为0,写入字符串结束符,方便对字符数组进行字符串操作
(*bufferPointer)++; //缓冲区读写下一位指针指示跳过末尾0
*lengthOfDomain = valueWriting+1; //包含了末尾结束符

}
//eg 3www6google3com0
//生成域名编码
//一个UTF8 数字占1个字节。一个UTF8汉字占3个字节
void encode_domain(char* domain)
{
memset(domain_temp,0,MAX_SIZE_OF_DOMAIN);
int valueWriting=0;
char *p,*q;
q = domain;
p = q;
char count = 0;
while(1)
{
if((*p=='.')||(*p==0))
{
//第一位为count,写入字符串
*(domain_temp+valueWriting)=count; //此处最后一位0的情况写入了
valueWriting += 1;
//写入q开始,长度为count的字符串(长度为count)
memcpy(domain_temp+valueWriting,q,count);
valueWriting += count;

//计数清0
count = 0;
//如果未读到字符串末尾,将q移动到p+1的位置,重新开始下一轮
if (*p=='.')
{
q=p+1;
p = q;
}else break;
}else
{
p++;
count++;
}
}
}
//解析编码的域名
void decode_domain(char* domain)
{
memset(domain_temp,0,MAX_SIZE_OF_DOMAIN);
int valueWriting = 0;
char *p = domain;
int count = *p;
while(count!=0)
{
for(int i=0;i<count;i++)
{
p += 1;
domain_temp[valueWriting] = *p;
valueWriting++;
}
if (*(p+1)!=0)
{
domain_temp[valueWriting] = '.';
valueWriting++;
}
p += 1;
count = *p;
}
domain_temp[valueWriting]=0;
}

//OPCODE、Z、RCODE不用管,无论输入什么都为0。其他都是单位的
unsigned short create_tag(unsigned short qr,unsigned short opcode,unsigned short aa,unsigned short tc,unsigned short rd,unsigned short ra,unsigned short z,unsigned short rcode)
{
unsigned short tag = 0;
if (qr==1) tag = tag | 0x8000;
if (aa==1) tag = tag | 0x0400;
if (tc==1) tag = tag | 0x0200;
if (rd==1) tag = tag | 0x0100;
if (ra==1) tag = tag | 0x0080;
return tag;
}

//类型的名字与编码的转换
unsigned short strTypeToCode(char* type)
{
if (strcmp(type,"A")==0) return 0x0001;
if (strcmp(type,"NS")==0) return 0x0002;
if (strcmp(type,"CNAME")==0) return 0x0005;
if (strcmp(type,"MX")==0) return 0x000F;
return 0;
}
char* codeTypeToStr(unsigned short num)
{
if (num==0x0001) return "A";
if (num==0x0002) return "NS";
if (num==0x0005) return "CNAME";
if (num==0x000F) return "MX";
return "ERROR";
}

/***********************DNS头部操作***************************/
/*
*此函数用于填充客户端发送请求的dns包的头部
*/
void create_query_header(struct DNS_Header *query_header,unsigned short id,unsigned short tag,unsigned short queryNum,unsigned short answerNum,unsigned short authorNum,unsigned short addNum)
{
query_header->id = id;
query_header->tag = tag;
query_header->queryNum = queryNum;
query_header->answerNum = answerNum;
query_header->authorNum = authorNum;
query_header->addNum = addNum;
}
/*此函数用于将已经填充好的dns头部结构体的成员依次写入buffer
* *header: 指向已填充好的dns头部结构体的指针
* *buffer: 指向缓冲区
* *bufferPointer: 目前已写入的缓冲区最新一位的下一位
*/
void encode_header(struct DNS_Header *header,char *buffer,int *bufferPointer)
{
put2Bytes(buffer,bufferPointer,header->id);
put2Bytes(buffer,bufferPointer,header->tag);
put2Bytes(buffer,bufferPointer,header->queryNum);
put2Bytes(buffer,bufferPointer,header->answerNum);
put2Bytes(buffer,bufferPointer,header->authorNum);
put2Bytes(buffer,bufferPointer,header->addNum);
}
void decode_header(struct DNS_Header *header,char *buffer,int *bufferPointer)
{
header->id=get2Bytes(buffer,bufferPointer);
header->tag=get2Bytes(buffer,bufferPointer);
header->queryNum=get2Bytes(buffer,bufferPointer);
header->answerNum=get2Bytes(buffer,bufferPointer);
header->authorNum=get2Bytes(buffer,bufferPointer);
header->addNum=get2Bytes(buffer,bufferPointer);
}
void print_header(struct DNS_Header *query_header)
{
printf("[DNS HEADER]\n");
printf("ID : %d\n",query_header->id);
printf("TAG : 0x%x\n",query_header->tag);
printf("QueryNum : %d\n",query_header->queryNum);
printf("AnswerNum : %d\n",query_header->answerNum);
printf("AuthorNum : %d\n",query_header->authorNum);
printf("AddNum : %d\n",query_header->addNum);
}

/***********************DNS请求部分操作***************************/
/*
*生成DNS包的请求部分
*/
void create_query_section(struct DNS_Query *query_section,char* domain_name, unsigned short qtype, unsigned short qclass)
{
int domain_length = strlen(domain_name);
query_section->name = malloc(domain_length+1);
memcpy(query_section->name,domain_name,domain_length+1);

query_section->qtype = qtype;
query_section->qclass = qclass;
}
/*
*将已经填充好的dns的一个请求结构体的成员依次写入buffer(调用一次该函数只写入一个请求
*/
void encode_query_section(struct DNS_Query *query_section,char *buffer,int *bufferPointer)
{
//先计算用decodeDomain得到字符串
//再用strlen计算字符串长度为点语法name长度+2(头尾多了一个数字)
//再发送
char *domain_name;
int lengthOfEncodedDomain = strlen(query_section->name)+2;
domain_name = malloc(lengthOfEncodedDomain);
encode_domain(query_section->name);
memcpy(domain_name,domain_temp,lengthOfEncodedDomain);
putDomainName(buffer,bufferPointer,domain_name);

put2Bytes(buffer,bufferPointer,query_section->qtype);
put2Bytes(buffer,bufferPointer,query_section->qclass);
}
/*
*解析请求部分。解析即为将缓冲区的字节流提取,转码,生成对应的结构体
*/
void decode_query_section(struct DNS_Query *query_section,char *buffer,int *bufferPointer)
{
//从缓冲区读出编码过的域名
char* domain_name = malloc(MAX_SIZE_OF_DOMAIN);
memset(domain_name,0,MAX_SIZE_OF_DOMAIN);
int lengthOfDomain=0;
getDomainName(buffer,bufferPointer,&lengthOfDomain);
memcpy(domain_name,domain_temp,lengthOfDomain);

//解码域名
decode_domain(domain_name);
memcpy(domain_name,domain_temp,strlen(domain_name));

query_section->name = domain_name;
query_section->qtype = get2Bytes(buffer,bufferPointer);
query_section->qclass = get2Bytes(buffer,bufferPointer);
}

void print_query_section(struct DNS_Query *query_section)
{
printf("[DNS QUERY]\n");
printf("Name : %s\n",query_section->name);
printf("Type : %s\n",codeTypeToStr(query_section->qtype));
printf("Class : IN\n");
}

/***********************DNS RR操作和RR文件解析操作***************************/
//生成resource record记录
void create_resource_record(struct DNS_RR *resource_record,char* name, unsigned short type, unsigned short _class, unsigned int ttl, unsigned short pre,char *rdata) //data_len不用输入
{
//unsigned short pre为一个MX类型特有的优先级,定长,只有MX类型发送。
int domain_length = strlen(name);
//易错点:strlen只读到0但不包含0,所以为了把结束符也复制进去,长度要+1
resource_record->name = malloc(domain_length+1);
memcpy(resource_record->name,name,domain_length+1);

resource_record->type = type;
resource_record->_class = _class;
resource_record->ttl = ttl; //data_len
if (type==0x0001) resource_record->data_len=4; //对于IP,长度为4 data_len是编码后的长度,length是非编码长度,注意
else resource_record->data_len = strlen(rdata) + 2; //对于域名,生成data_len包含末尾结束符(域名末尾结束符)

//pre
if (type==0x000F) {
resource_record->pre = pre;
resource_record->data_len += 2; //对于邮件类型,由于有pre的存在,多占两个字节
}

//char* rdata
int rdata_length = strlen(rdata); //要加上末尾结束符
resource_record->rdata = malloc(rdata_length+1);
memcpy(resource_record->rdata,rdata,rdata_length+1);
}

//编码resource record记录,编码即为将结构体的内容编码,处理为字节流,写入缓冲区
void encode_resource_record(struct DNS_RR *resource_record,char *buffer,int *bufferPointer)
{
char *domain_name;
int lengthOfEncodedDomain = strlen(resource_record->name)+2;
domain_name = malloc(lengthOfEncodedDomain);

encode_domain(resource_record->name);
memcpy(domain_name,domain_temp,lengthOfEncodedDomain);

putDomainName(buffer,bufferPointer,domain_name);

put2Bytes(buffer,bufferPointer,resource_record->type);
put2Bytes(buffer,bufferPointer,resource_record->_class);
put4Bytes(buffer,bufferPointer,resource_record->ttl);
put2Bytes(buffer,bufferPointer,resource_record->data_len);
if (resource_record->type==0x000F)
put2Bytes(buffer,bufferPointer,resource_record->pre);

//如果类型为A,发送的是IP,将IP写入缓冲区
if(resource_record->type == 0x0001)
{
//不能调用get put函数,因为inet_addr自带字节序变换功能
unsigned int rdata = inet_addr(resource_record->rdata);
memcpy(buffer + *bufferPointer,&rdata,4);
*bufferPointer += 4;

}else{
//如果类型为MX、CNAME、NS
//则发送的是域名,则调用域名编码
char *rdata;
int lengthOfEncodedDomain2 = strlen(resource_record->rdata)+2;
rdata = malloc(lengthOfEncodedDomain2);
encode_domain(resource_record->rdata);
memcpy(rdata,domain_temp,lengthOfEncodedDomain2);
putDomainName(buffer,bufferPointer,rdata);
}
}

//解析resource record记录
void decode_resource_record(struct DNS_RR *resource_record,char *buffer,int *bufferPointer)
{
//从缓冲区读出编码过的域名
char* domain_name = malloc(MAX_SIZE_OF_DOMAIN);
memset(domain_name,0,MAX_SIZE_OF_DOMAIN);
int lengthOfDomain=0;
getDomainName(buffer,bufferPointer,&lengthOfDomain);
memcpy(domain_name,domain_temp,lengthOfDomain);
//解码域名

decode_domain(domain_name);
memcpy(domain_name,domain_temp,strlen(domain_name));
resource_record->name = domain_name;

resource_record->type = get2Bytes(buffer,bufferPointer);
resource_record->_class = get2Bytes(buffer,bufferPointer);
resource_record->ttl = get4bits(buffer,bufferPointer);
resource_record->data_len = get2Bytes(buffer,bufferPointer);
if (resource_record->type==0x000F)
resource_record->pre = get2Bytes(buffer,bufferPointer);

//如果发送的是IP(类型为A),则读出IP 。 不能采用get put方法,因为inet_ntoa方法已经更换字节序
if(resource_record->type == 0x0001)
{
unsigned int rdata;
memcpy(&rdata,buffer + *bufferPointer,4);
*bufferPointer += 4;

struct in_addr in;
memcpy(&in, &rdata, 4);

resource_record->rdata = malloc(MAX_SIZE_OF_DOMAIN);
char *temp = inet_ntoa(in);
memcpy(resource_record->rdata,temp,strlen(temp)+1); //+1是为了包含末尾0
}else{
//如果发送的是域名,则调用域名解码(类型为CNAME NS MX)
//从缓冲区读出编码过的域名
char* rdata = malloc(MAX_SIZE_OF_DOMAIN);
int lengthOfDomain2=0;
getDomainName(buffer,bufferPointer,&lengthOfDomain2);
memcpy(rdata,domain_temp,lengthOfDomain2);
//解码域名
decode_domain(rdata);
memcpy(rdata,domain_temp,strlen(rdata));
resource_record->rdata = rdata;
}
}

void print_resource_record(struct DNS_RR *resource_record)
{
printf("[RESOURCE RECORD]\n");
printf("Name : %s\n",resource_record->name);
printf("Type : %s\n",codeTypeToStr(resource_record->type));
printf("Class : IN\n");
printf("TTL : %d\n",resource_record->ttl);
printf("Data_Len : %d\n",resource_record->data_len);
if (resource_record->type==0x000F)
printf("Preference : %d\n",resource_record->pre);
printf("IP|DOMAIN : %s\n",resource_record->rdata);
printf("===================================\n");
}

//砍掉一个域名第一个.之前的部分,如果已经是最后一节,指向域名的指针指向NULL
void cut(char** domainPointer) //这里传入的是 指向指向域名的指针的指针
{
while(1)
{
(*domainPointer)++;
if (**domainPointer=='.')
{
(*domainPointer)++;
break;
}
if (**domainPointer==0)
{
*domainPointer = NULL;
break;
}
}
}

/***********************文件读写***************************/
//将RR写进cache文件里
void addRRToCache(struct DNS_RR *resource_record, char* cacheFile)
{
FILE *RR = fopen(cacheFile, "a+");
fprintf(RR,"%s ",resource_record->name);
fprintf(RR,"%d ",resource_record->ttl);
fprintf(RR,"IN ");
fprintf(RR,"%s ",codeTypeToStr(resource_record->type));
fprintf(RR,"%s\n",resource_record->rdata);
fclose(RR);
}

//第一次在RR文件里扫描 (初次搜索函数)
//如果找到了,返回1,且encode进buffer
int firstFindRR(struct DNS_Query *query_section,char *RRDOCUMENT,char *buffer,int *bufferPointer)
{
int over = 0;
FILE *RR = fopen( RRDOCUMENT, "r" );
//定义一个RR结构体用来储存从文件中读入的一条RR
struct DNS_RR *fileRR;
fileRR = malloc(sizeof(DNS_ResouceRecord));
memset(fileRR,0,sizeof(DNS_ResouceRecord));
fileRR->name=malloc(MAX_SIZE_OF_DOMAIN);
fileRR->rdata=malloc(MAX_SIZE_OF_DOMAIN);
//第一次搜索
while(fscanf(RR,"%s ",fileRR->name)!=EOF)
{
fscanf(RR,"%d",&fileRR->ttl);
char type[10],_class[10];
fscanf(RR,"%s ",_class);
fscanf(RR,"%s ",type);
fileRR->type = strTypeToCode(type);
fscanf(RR,"%s\n",fileRR->rdata);

if((strcmp(query_section->name,fileRR->name)==0) && (query_section->qtype==fileRR->type))
{
printf("\n发送回复:\n");
//生成answer RR
create_resource_record(fileRR,fileRR->name, fileRR->type, 0x0001, fileRR->ttl, 0x0000,fileRR->rdata);
//生成头
struct DNS_Header *header;
header = malloc(sizeof(DNS_HEAD));
unsigned short tag = create_tag(1,0,1,0,0,0,0,0);
if (strcmp(type,"MX")==0) create_query_header(header,0x1235,tag,0,1,0,1);
else create_query_header(header,999,tag,0,1,0,0);
//将头和answer encode进buffer
encode_header(header,buffer,bufferPointer);
print_header(header);
encode_resource_record(fileRR,buffer,bufferPointer);
print_resource_record(fileRR);
over=1;
break;
}
}

//读指针回到开头
fseek(RR,0,0);
//对于MX类型,特殊,需要再搜索一遍,搜索到的邮件服务器域名的IP,并写入addition RR中发送
if ((fileRR->type==0x000F)&&(over==1))
{
struct DNS_RR *addFileRR;
addFileRR = malloc(sizeof(DNS_ResouceRecord));
addFileRR->name=malloc(MAX_SIZE_OF_DOMAIN);
addFileRR->rdata=malloc(MAX_SIZE_OF_DOMAIN);
while(fscanf(RR,"%s ",addFileRR->name)!=EOF)
{
fscanf(RR,"%d ",&addFileRR->ttl);
char type[10],_class[10];
fscanf(RR,"%s ",_class);
fscanf(RR,"%s ",type);
addFileRR->type = strTypeToCode(type);
fscanf(RR,"%s\n",addFileRR->rdata);
if(strcmp(fileRR->rdata,addFileRR->name)==0)
{
printf("邮件服务器:\n");
//生成addition RR
create_resource_record(addFileRR,fileRR->rdata, 1, 1, fileRR->ttl, 0, addFileRR->rdata);
encode_resource_record(addFileRR,buffer,bufferPointer);
print_resource_record(addFileRR);
break;
}
}
}
fclose(RR);
return over;
}

void loopFindNS(struct DNS_Query *query_section,char *RRDOCUMENT,char *buffer,int *bufferPointer)
{
FILE *RR = fopen( RRDOCUMENT, "r" );
cut(&query_section->name);
//剪掉首段地址,进行第二次搜索
while(query_section->name!=NULL)
{
fseek(RR,0,0);

struct DNS_RR *nextRR;
nextRR = malloc(sizeof(DNS_ResouceRecord));
nextRR->name=malloc(MAX_SIZE_OF_DOMAIN);
nextRR->rdata=malloc(MAX_SIZE_OF_DOMAIN);
while(fscanf(RR,"%s ",nextRR->name)!=EOF)
{
fscanf(RR,"%d ",&nextRR->ttl);
char type[10],_class[10];
fscanf(RR,"%s ",_class);
fscanf(RR,"%s ",type);
nextRR->type = strTypeToCode(type);
fscanf(RR,"%s\n",nextRR->rdata);
if(strcmp(query_section->name,nextRR->name)==0)
{
printf("\n下一级服务器信息:\n");
//生成头
struct DNS_Header *header;
header = malloc(sizeof(DNS_HEAD));
unsigned short tag = create_tag(1,0,1,0,0,0,0,0);
create_query_header(header,999,tag,0,0,1,1);
encode_header(header,buffer,bufferPointer);
print_header(header);

//生成authority RR NS记录type=2 此时query_section->name经过cut后已经变成了下一个要去的DNS服务器域名
struct DNS_RR *authRR;
authRR = malloc(sizeof(DNS_ResouceRecord));
create_resource_record(authRR, query_section->name, 2, 1, nextRR->ttl, 0, query_section->name);
encode_resource_record(authRR,buffer,bufferPointer);
print_resource_record(authRR);

//生成additon RR A记录type=1
struct DNS_RR *addRR;
addRR = malloc(sizeof(DNS_ResouceRecord));
create_resource_record(addRR, query_section->name, 1, 1, nextRR->ttl, 0, nextRR->rdata);
encode_resource_record(addRR,buffer,bufferPointer);
print_resource_record(addRR);

goto out;
}
}
cut(&query_section->name);
}
out:
fclose(RR);
}