LOCAL_DNS
local DNS作为本地网络中的逻辑核心非常重要
#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为本机主逻辑
#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);
}