DNS和UDP编程的实现 dns tcp udp

DNS和UDP编程的实现1.DNS的报文头部格式 2.wireshark的显示 在抓以太网包之后,通过筛选DNS并停止抓包,双击一个包,有: 图1中从上到下,依次是物理层

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

(0)
CSDN's avatarCSDN
上一篇 2024年7月5日 下午1:04
下一篇 2024年7月5日 下午1:40

相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注