1.DNS的报文头部格式
2.wireshark的显示
捕获以太网数据包后,过滤DNS并停止捕获数据包。将显示以下内容:
图1从上到下依次为物理层、链路层、网络层、传输层和应用层。
域名系统对应图1,请求包和对应的响应包具有相同的事务ID。
国际意义上的代码是1。
3.c代码实现
查询名称格式:
搜索域名时,使用霍夫曼树状方法。以0 为根,求w,w,w。等等。
定义标头和查询数据结构。
typedef 结构DNS_header {
未签名的短ID。
未签名的短标志。
简短的未签名问题。
简短的未签名答案。
简短的、未签名的授权书。
添加无符号短。
};
typedef 结构查询{
整数长度;
无符号短类型。
未签名的短期课程。
字符*名称;
};
由于这里name的长度不确定,所以使用length和char*name。
创建一个标题。
int Create_DNS_Header(DNS_header* 标头) {
if (!header)返回-1;
memset(标头, 0, sizeof(DNS_header));
srandom(时间(NULL));
标头ID=random();
标题问题=1;
标头标志=htons(0X0100);
返回0。
}
消息:
srandom(时间(NULL));
标头ID=random();
如果另一个线程在srandom(time(NULL)); 之后使用random() ,它将使用随机种子重新随机化。
标头标志=htons(0X0100);
将大端和小端存储方案集成到网络传输格式中。
创建查询:
int Create_DNS_Query(查询* q, char* 名称) {
if (!q || !name)返回-1;
memset(q, 0, sizeof(查询));
q-类型=htons(1);
qclass=htons(1);
q-length=strlen(名称) + 2;
字符分割=\’.\’;
q-名称=NULL;
字符*标记;
char*namedup=strdup(名称);
令牌=strtok(名称, 分割);
char* 令牌名称=q-名称;
而(令牌){
size_t 大小=strlen(令牌);
*代币名称=大小;
代币名称++;
strncpy(代币名称、代币、大小+1);
代币名称+=大小;
令牌=strtok(NULL, 分割);
}
自由(命名);
返回0。
}
strncpy后面的size+1和q-length=strlen(name)+2是因为需要在name后面加0。 \\0在你的电脑上是0X00,可以代替0
消息:
strtok 保存结果,但它不是线程安全函数。
所有代码(cpp):
#include 字符串.h
#include stdio.h
#包括ctime
#include sys/socket.h
#include netinet/in.h
#包括stdlib.h
#include cstring
#include unistd.h
#include arpa/inet.h
#include errno.h
#定义DNS_HOST0x01
#定义DNS_CNAME0x05
#定义DNSPORT 53
#定义DNSIP \’114.114.114.114\’
typedef 结构DNS_Header {
未签名的短ID。
未签名的短标志。
简短的未签名问题。
简短的未签名答案。
简短的、未签名的授权书。
添加无符号短。
};
结构dns_item {
字符*域;
查*叶;
};
typedef 结构DNS_Query {
整数长度;
无符号短类型。
未签名的短期课程。
字符*名称;
};
int Create_DNS_Header(DNS_Header* 标头) {
if (!header)返回-1;
memset(标头, 0, sizeof(DNS_Header));
srandom(时间(NULL));
标头ID=random();
标题问题=htons(1);
标头标志=htons(0X0100);
返回0。
}
int Create_DNS_Query(DNS_Query* q, char* 名称) {
if (!q || !name)返回-1;
memset(q, 0, sizeof(DNS_Query));
q-类型=htons(1);
qclass=htons(1);
q-length=strlen(名称) + 2;
字符分割[2]=\’.\’;
q-name=(char*)malloc(strlen(name) + 2);
字符*标记;
char*namedup=strdup(名称);
令牌=strtok(名称, 分割);
char* 令牌名称=q-名称;
而(令牌){
size_t 大小=strlen(令牌);
*代币名称=大小;
代币名称++;
strncpy(代币名称、代币、大小+1);
代币名称+=大小;
令牌=strtok(NULL, 分割);
}
自由(命名);
返回0。
}
int Bind_Header_Query(DNS_Query* 查询, DNS_Header* 标头, char* 请求) {
size_t 标头大小=sizeof(DNS_Header);
memcpy(请求, header, header_size);
size_t 偏移量=标头大小;
memcpy(请求+偏移量,查询名称,查询长度);
偏移量+=查询长度;
memcpy(请求+偏移量, 查询类型, sizeof(查询类型));
offset +=size(查询类型);
memcpy(请求+偏移量, 查询类, sizeof(查询类));
offset +=size(查询类);
返回偏移量。
}
静态int is_pointer(int in) {
返回((0xC0)==0xC0);
}
static void dns_parse_name(unsigned char* chunk, unsigned char* ptr, char* out, int* len) {
int 标志=0,n=0,alen=0;
char* pos=out + (*len);
另一方面(1) {
标志=(int)ptr[0];
如果(标志==0)中断;
如果(is_pointer(标志)){
n=(int)ptr[1];
ptr=块+ n;
dns_parse_name(块,ptr,out,len);
休息;
}
除此之外{
ptr++;
memcpy(pos, ptr, 标志);
pos +=标志;
ptr +=标志;
*len +=标志;
if ((int)ptr[0] !=0) {
memcpy(pos, \’.\’, 1);
位置+=1;
(*len) +=1;
}
}
}
}
静态int dns_parse_response(char* 缓冲区, struct dns_item** 域) {
整数i=0;
无符号字符* ptr=(无符号字符*)缓冲区;
指针+=4;
int 查询=ntohs(*(无符号短*)ptr);
指针+=2;
int 答案=ntohs(*(无符号短*)ptr);
指针+=6;
for (i=0; i 查询; i++) {
另一方面(1) {
int 标志=(int)ptr[0];
ptr +=(标志+ 1);
如果(标志==0)中断;
}
指针+=4;
}
char cname[128]、aname[128]、ip[20]、netip[4];
int len、类型、ttl、datalen;
整数cnt=0;
struct dns_item* list=(struct dns_item*)calloc(answers, sizeof(struct dns_item));
如果(列表==NULL){
返回-1。
}
for (i=0; i 的答案; i++) {
bzero(aname, sizeof(aname));
任=0;
dns_parse_name((unsigned char*)buffer, ptr, aname, len);
指针+=2;
类型=htons(*(无符号短*)ptr);
指针+=4;
ttl=htons(*(无符号短*)ptr);
指针+=4;
datalen=ntohs(*(无符号短*)ptr);
指针+=2;
如果(类型==DNS_CNAME){
bzero(cname, sizeof(cname));
任=0;
dns_parse_name((unsigned char*)buffer, ptr, cname, len);
ptr +=数据长度;
}
否则如果(类型==DNS_HOST){
bzero(ip, sizeof(ip));
if (datalen==4) {
memcpy(netip, ptr, datalen);
inet_ntop(AF_INET, netip, ip, sizeof(struct sockaddr));
printf(\’%s 地址是%s\\n\’, aname, ip);
printf(\’\\t生存时间: %d 分钟,%d 秒\\n\’, ttl/60, ttl % 60);
list[cnt].domain=(char*)calloc(strlen(aname) + 1, 1);
memcpy(list[cnt].domain, aname, strlen(aname));
list[cnt].ip=(char*)calloc(strlen(ip) + 1, 1);
memcpy(列表[cnt].ip, ip, strlen(ip));
cnt++;
}
ptr +=数据长度;
}
}
*域=列表;
指针+=2;
返回cnt。
}
int Send_Client_Commit(char* 域) {
int out=套接字(AF_INET, SOCK_DGRAM, 0);
如果(输出0){
printf(\’套接字错误: %s\\n\’, strerror(errno));
返回-1。
}
sockaddr_in skaddr={ 0 };
skaddr.sin_family=AF_INET;
skaddr.sin_port=htons(DNSPORT);
skaddr.sin_addr.s_addr=inet_addr(DNSIP);
DNS_Query 查询={ 0 };
DNS_Header 标头={ 0 };
int ret=Create_DNS_Query(查询, 域);
如果(返回){
返回-2。
}
ret=Create_DNS_Header(标头);
如果(返回){
返回-3。
}
连接(out, (struct sockaddr*)skaddr, sizeof(sockaddr_in));
字符请求[1024]={ 0 };
int length=Bind_Header_Query(查询、标头、请求);
如果(长度0){
返回-4。
}
int 大小=sizeof(sockaddr);
ret=sendto(out, request, length, 0, (struct sockaddr*)skaddr, sizeof(struct sockaddr));
如果(ret==-1){
返回-5。
}
字符响应[1024]={ 0 };
sockaddr_in 添加;
size_t addr_len=sizeof(struct sockaddr_in);
ret=recvfrom(out, 响应, sizeof(响应), 0, (struct sockaddr*)add, (socklen_t*)addr_len);
结构dns_item* dns_domain=NULL;
dns_parse_response(响应,dns_domain);
免费(dns_domain);
返回0。
}
int main(int argc, char* argv[]) {
如果(参数2){
printf(\’输入错误\’);
返回-1。
Send_Client_Commit(argv[1]);
返回0。
}
以上关于实现#DNS和UDP编程的相关内容摘自互联网,仅供参考。相关信息请参见官方公告。
原创文章,作者:CSDN,如若转载,请注明出处:https://www.sudun.com/ask/93136.html