linux 接受dns报文,Linux下构造UDP原始数据报-DNS报文示例C语言实现

这几天构造一个DNS报文,查了好些资料,好象许多朋友对UDP报文的校验和老是出问题,自己试了一些例子代码,也有问题。所以花了一些时间,做了一个成功的例子,在Linux下GCC通过并验证成功。

#include #include #include #include #include #include #include #include #include

unsigned short checksum(unsigned short *buffer, int size)

{

unsigned long cksum=0;

while (size > 1)

{

cksum += *buffer++;

size  -= sizeof(unsigned short);

}

if (size)

{

cksum += *(unsigned char *)buffer;

}

cksum = (cksum >> 16) + (cksum & 0xffff);

cksum += (cksum >>16);

return (unsigned short)(~cksum);

}

void CalculateCheckSum(

void    *iphdr,

struct udphdr *udphdr,

char    *payload,

int      payloadlen)

{

struct iphdr  *v4hdr=NULL;

unsigned long zero=0;

char          buf[1000],

*ptr=NULL;

int           chksumlen=0,

i;

ptr = buf;

v4hdr = (struct iphdr *)iphdr;

// Include the source and destination IP addresses

memcpy(ptr, &v4hdr->saddr,  sizeof(v4hdr->saddr));

ptr += sizeof(v4hdr->saddr);

chksumlen += sizeof(v4hdr->saddr);

memcpy(ptr, &v4hdr->daddr, sizeof(v4hdr->daddr));

ptr += sizeof(v4hdr->daddr);

chksumlen += sizeof(v4hdr->daddr);

// Include the 8 bit zero field

memcpy(ptr, &zero, 1);

ptr++;

chksumlen += 1;

// Protocol

memcpy(ptr, &v4hdr->protocol, sizeof(v4hdr->protocol));

ptr += sizeof(v4hdr->protocol);

chksumlen += sizeof(v4hdr->protocol);

// UDP length

memcpy(ptr, &udphdr->len, sizeof(udphdr->len));

ptr += sizeof(udphdr->len);

chksumlen += sizeof(udphdr->len);

// UDP source port

memcpy(ptr, &udphdr->source, sizeof(udphdr->source));

ptr += sizeof(udphdr->source);

chksumlen += sizeof(udphdr->source);

// UDP destination port

memcpy(ptr, &udphdr->dest, sizeof(udphdr->dest));

ptr += sizeof(udphdr->dest);

chksumlen += sizeof(udphdr->dest);

// UDP length again

memcpy(ptr, &udphdr->len, sizeof(udphdr->len));

ptr += sizeof(udphdr->len);

chksumlen += sizeof(udphdr->len);

// 16-bit UDP checksum, zero

memcpy(ptr, &zero, sizeof(unsigned short));

ptr += sizeof(unsigned short);

chksumlen += sizeof(unsigned short);

// payload

memcpy(ptr, payload, payloadlen);

ptr += payloadlen;

chksumlen += payloadlen;

// pad to next 16-bit boundary

for(i=0 ; i < payloadlen%2 ; i++, ptr++)

{

printf("pad one byte\n");

*ptr = 0;

ptr++;

chksumlen++;

}

// Compute the checksum and put it in the UDP header

udphdr->check = checksum((unsigned short *)buf, chksumlen);

return;

}

void main()

{

int sock;

unsigned int buffer_size = sizeof(struct iphdr) + sizeof(struct udphdr);

char DNS_Data[] = "\x71\x79\x81\x80\x00\x01"

"\x00\x02\x00\x04\x00\x04\x03\x77\x77\x77\x03\x61\x62\x63\x03\x63"

"\x6f\x6d\x00\x00\x01\x00\x01\xc0\x0c\x00\x05\x00\x01\x00\x00\x02"

"\xe8\x00\x02\xc0\x10\xc0\x10\x00\x01\x00\x01\x00\x00\x02\xe9\x00"

"\x04\x0a\xb5\x84\xfa\xc0\x10\x00\x02\x00\x01\x00\x00\xda\xeb\x00"

"\x0d\x06\x73\x65\x6e\x73\x30\x31\x03\x64\x69\x67\xc0\x14\xc0\x10"

"\x00\x02\x00\x01\x00\x00\xda\xeb\x00\x09\x06\x73\x65\x6e\x73\x30"

"\x32\xc0\x4e\xc0\x10\x00\x02\x00\x01\x00\x00\xda\xeb\x00\x09\x06"

"\x6f\x72\x6e\x73\x30\x31\xc0\x4e\xc0\x10\x00\x02\x00\x01\x00\x00"

"\xda\xeb\x00\x09\x06\x6f\x72\x6e\x73\x30\x32\xc0\x4e\xc0\x75\x00"

"\x01\x00\x01\x00\x00\x7a\x36\x00\x04\x0a\xbb\xbd\x2c\xc0\x8a\x00"

"\x01\x00\x01\x00\x00\x1b\x96\x00\x04\x0a\xbb\xbe\x2c\xc0\x47\x00"

"\x01\x00\x01\x00\x00\x92\xb1\x00\x04\x0a\xb5\x86\x10\xc0\x60\x00"

"\x01\x00\x01\x00\x00\x92\xb1\x00\x04\x0a\xb5\x87\xc7";

buffer_size += sizeof(DNS_Data);

unsigned char buffer[buffer_size];

memset (buffer, 0, buffer_size);

struct iphdr *ip = (struct iphdr *)buffer;

struct udphdr *udp = (struct udphdr *)(buffer + sizeof(struct iphdr));

if ((sock = socket(AF_INET,SOCK_RAW,IPPROTO_UDP)) == -1) {

perror("socket()");

exit(EXIT_FAILURE);

}

int o = 1;

if (setsockopt(sock,IPPROTO_IP,IP_HDRINCL,&o,sizeof(o)) == -1) {

perror("setsockopt()");

exit(EXIT_FAILURE);

}

ip->version = 4;

ip->ihl = 5;

ip->id = htonl(random());

ip->saddr = inet_addr("1.0.0.1");

ip->daddr = inet_addr("10.0.0.63");

ip->ttl = 255;

ip->protocol = IPPROTO_UDP;

ip->tot_len = buffer_size;

ip->check = 0;

udp->source = htons(53);

udp->dest = htons(1234);

udp->len = htons(buffer_size - sizeof(struct iphdr));

udp->check = 0;

struct sockaddr_in addr;

addr.sin_family = AF_INET;

addr.sin_port = udp->source;

addr.sin_addr.s_addr = ip->saddr;

memcpy(buffer+sizeof(struct iphdr) + sizeof(struct udphdr),DNS_Data,sizeof(DNS_Data));

CalculateCheckSum(ip,udp,DNS_Data,sizeof(DNS_Data));

if ((sendto(sock, buffer, buffer_size, 0, (struct sockaddr*)&addr,

sizeof(struct sockaddr_in))) == -1) {

perror("send()");

exit(1);

}

else

printf("OK\n");

}

上面代码构造了一个DNS应答报文。用抓包程序抓下来验证正确。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
下面是一个简单的 DNS 查询代码,使用 C 语言在 Linux 上编写: ``` #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #define DNS_QUERY_PORT 53 #define DNS_SERVER_IP "8.8.8.8" #define DNS_QUERY_NAME "www.google.com" struct DNS_HEADER { unsigned short id; unsigned char rd :1; unsigned char tc :1; unsigned char aa :1; unsigned char opcode :4; unsigned char qr :1; unsigned char rcode :4; unsigned char cd :1; unsigned char ad :1; unsigned char z :1; unsigned char ra :1; unsigned short q_count; unsigned short ans_count; unsigned short auth_count; unsigned short add_count; }; struct QUESTION { unsigned short qtype; unsigned short qclass; }; int main(int argc, char *argv[]) { int sockfd; struct sockaddr_in serv_addr; char send_buf[1024]; char recv_buf[1024]; int send_len; int recv_len; // 创建套接字 if ((sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) { perror("socket error"); exit(EXIT_FAILURE); } memset(&serv_addr, 0, sizeof(serv_addr)); serv_addr.sin_family = AF_INET; serv_addr.sin_port = htons(DNS_QUERY_PORT); serv_addr.sin_addr.s_addr = inet_addr(DNS_SERVER_IP); struct DNS_HEADER *dns = (struct DNS_HEADER *)send_buf; struct QUESTION *qinfo = (struct QUESTION *)(send_buf + sizeof(struct DNS_HEADER)); dns->id = (unsigned short)htons(getpid()); dns->qr = 0; dns->opcode = 0; dns->aa = 0; dns->tc = 0; dns->rd = 1; dns->ra = 0; dns->z = 0; dns->ad = 0; dns->cd = 0; dns->rcode = 0; dns->q_count = htons(1); dns->ans_count = 0; dns->auth_count = 0; dns->add_count = 0; qinfo->qtype = htons(1);

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值