头文件的内容dns.h
/**
* file dns.h
* Define the DNS request packet header format.
* Author : Wen Shifang
* 2015.8.20
*/
#ifndef __DNS_H__
#define __DNS_H__
#define PLATFORM_WINDOWS
/* 域名查询请求报文头定义,1字节对齐*/
#if defined(PLATFORM_WINDOWS)
#pragma pack(push)
#pragma pack(1)
#endif
struct DnsHeader{
unsigned short id;
unsigned char rd:1; /*期望递归解析*/
unsigned char tc:1; /*报文未截断 */
unsigned char aa:1; /*授权解析服务器 */
unsigned char opcode:4;/*标准查询 */
unsigned char qr:1; /*0:查询,1:响应 */
unsigned char rcode:4;/*响应吗:0没有出错 */
unsigned char z:3; /*保留将来使用 */
unsigned char ra:1; /*DNS服务器是否支持递归解析 */
unsigned short qdCount; /* 问题数*/
unsigned short anCount; /* 应答数*/
unsigned short nsCount; /* 授权机构数 */
unsigned short arCount; /* 附加信息数 */
}
#if defined (PLATFORM_LINUX)
__attribute__(("packed"))
#endif
;
#if defined(PLATFORM_WINDOWS)
#pragma pack(pop)
#endif
#define COMMENT_MAX 64
#define SYMBOL_MAX 8
struct QueryType
{
unsigned short q_class;
unsigned char mnemonic_symbol[SYMBOL_MAX];
unsigned char comment[COMMENT_MAX];
};
#endif
主文件内容main.c
#include <stdio.h>
#include <winsock2.h>
#include "dns.h"
#pragma comment(lib,"ws2_32.lib")
#define DNS_ADDR "202.96.134.33"
#define SERVER_PORT 53
#define MAX_TRY_CNT 3
static unsigned short packet_id = 0x55AA;
/* 交换字节序 */
void exchangeByteOrder(unsigned char *byte)
{
unsigned char temp;
temp = byte[0];
byte[0] = byte[1];
byte[1] = temp;
}
/* 交换一个字的字节顺序 */
void exchangeWordOrder(unsigned int *word)
{
unsigned char temp;
unsigned char *ptr[4];
ptr[0] = (unsigned char *)(word);
ptr[1] = ((unsigned char *)(word))+1;
ptr[2] = ((unsigned char *)(word))+2;
ptr[3] = ((unsigned char *)(word))+3;
temp = *ptr[0];
*ptr[0] = *ptr[3];
*ptr[3] = temp;
temp = *ptr[1];
*ptr[1] = *ptr[2];
*ptr[2] = temp;
}
/* 构造 DNS 请求报文包头(12 bytes) */
int dns_packet_hdr_construct(struct DnsHeader *header)
{
/* 定义DNS查询报文请求头,没有使用的字段必须设置为0 */
header->id = packet_id; /* ID ,由进程任意指定,以作标识 */
header->rd = 1; /*期望递归解析*/
header->tc = 0;
header->aa = 0;
header->opcode = 0; /*标准查询 */
header->qr = 0;
header->rcode = 0;
header->z = 0;
header->ra = 0;
header->qdCount = 1; /*问题数量 */
header->anCount = 0;
header->nsCount = 0;
header->arCount = 0;
/* 16 bits 的本地格式转换为网络格式 */
exchangeByteOrder((unsigned char *)&header->anCount);
exchangeByteOrder((unsigned char *)&header->qdCount);
exchangeByteOrder((unsigned char *)&header->nsCount);
exchangeByteOrder((unsigned char *)&header->arCount);
return sizeof(struct DnsHeader);
}
/* 构造 NDS 请求报文内容 */
int dns_packet_body_construct(char *packet_body, const char *buf)
{
const char *domain_ptr = buf ;
int i = 0, j = 0;
while(*domain_ptr != '\0'){
if(*domain_ptr != '.'){
packet_body[i+1] = *domain_ptr;
j++;
}else{
packet_body[i-j] = j;
j = 0;
}
i++; domain_ptr++;
}
packet_body[i-j] = j;
packet_body[++i] = 0; /* null */
packet_body[++i] = 0x00;
packet_body[++i] = 0x01; /* 查询类型 为 1 : IPv4地址 */
packet_body[++i] = 0x00; /* 查询类 为 1 : Inetnet数据 */
packet_body[++i] = 0x01;
return i;
}
/**
* 解析 问题
* packet:数据包头部指针
* body: 指向问题域开始部分
*/
const char *dns_packet_question_resovle(const struct DnsHeader *packet, const char *body)
{
const char *ptr;
unsigned char cnt = 0;
unsigned char len = 0;
printf("the queston:");
ptr = body;
while(*ptr != '\0'){
cnt = *ptr++;
while(cnt--){
printf("%c", *ptr);
ptr++;
}
if(*ptr != '\0'){
printf(".");
}
}
printf("\n");
ptr++; /* skip null */
printf("Type : ");
if(*ptr == 0x0 && *(ptr+1) == 0x1){
printf("Host Address\n");
}else{
printf("%02x%02x\n",*ptr, *(ptr+1));
}
ptr += 2; /* skip Type area */
printf("Class : ");
if(*ptr == 0x0 && *(ptr+1) == 0x01){
printf("IN\n");
}else{
printf("%02x%02x\n");
}
ptr += 2; /* skip Class area */
return ptr;
}
/* 解析名字 */
const char *dns_packet_name_resovle(const struct DnsHeader *packet, const char *name)
{
const char *p;
unsigned char cnt,len;
p = name;
len = 0;
while(*p != '\0'){
if(((*p & 0xC0) >> 6) == 0x3){
p = (const char *)packet + (((*p & 0x3F)<<8) | *(p+1));
p = dns_packet_name_resovle(packet, p);
}else{
cnt = *p++;
while(cnt--){
printf("%c",*p++);
}
if(*p != '\0'){
printf(".");
}
}
}
return p;
}
/* 解析资源数据 */
const char *dns_packet_rr_resovle(const struct DnsHeader *packet, const char *rr, unsigned short rlen)
{
const char *p;
unsigned char cnt = 0;
if(rlen == 0x4){ /* IP addr */
printf("%d.%d.%d.%d\n", (unsigned char)rr[0],(unsigned char)rr[1],
(unsigned char)rr[2],(unsigned char)rr[3]);
return (rr += 4);
}
while(rlen > 0){
if(((*rr & 0xC0) >> 6) == 0x3){
p = (const char *)packet + ((*rr & 0x3F)<<8 | (*(rr+1)));
rlen -= 2;
cnt = *p++;
rr += 2;
}else{
p = rr;
cnt = *p++;
rlen -= ( cnt + 1 );
rr += ( cnt + 1 );
}
while(cnt--){
printf("%c", *p);
p++;
}
if(rlen != 0){
printf(".");
}
}
printf("\n");
return rr;
}
/**
* 解析 应答
* packet:数据包头部指针
* body: 指向应答域开始部分
*/
const char *dns_packet_response_resovle(const struct DnsHeader *packet, const char *body)
{
const char *ptr;
unsigned char cnt = 0;
unsigned char len = 0;
unsigned int ttl = 0;
unsigned short rs_len = 0;
printf("\nthe answer:\nName : ");
ptr = dns_packet_name_resovle(packet, body);
printf("%\n");
ptr = body + 2; /* skip null ,Get Type (2 bytes) */
printf("Type : ");
if((*ptr == 0x0) && (*(ptr+1) == 0x1)){
printf("Host Address\n");
}else if((*ptr == 0x0) && (*(ptr+1) == 0x5)){
printf("CNAME (Canonical name for an alias)\n");
}else{
printf("%02x%02x\n",*ptr, *(ptr+1));
}
ptr += 2; /* skip Type area , Get Class (2 bytes) */
printf("Class : ");
if(*ptr == 0x0 && *(ptr+1) == 0x01){
printf("IN\n");
}else{
printf("%02x%02x\n");
}
ptr += 2; /* skip Class area ,Get TTL(4 bytes) */
ttl = *(unsigned int *)(ptr);
exchangeWordOrder(&ttl);
printf("TTL(Time To live) :");
printf("%d\n",ttl);
ptr += 4; /* skip TTL area , Get Resource length (2 bytes) */
rs_len = *(unsigned short*)(ptr);
exchangeByteOrder((unsigned char *)&rs_len);
printf("Data length :");
printf("%d\n",rs_len );
ptr += 2; /* skip Resource length area ,Get Resource Records */
printf("Data : ");
ptr = dns_packet_rr_resovle(packet, ptr, rs_len);
return ptr;
}
/**
* 解析 授权机构
* packet:数据包头部指针
* body: 指向授权机构开始部分
*/
const char * dns_packet_authority_resovle(const struct DnsHeader *packet, const char *body)
{
return 0;
}
/**
* 解析 附加信息
* packet:数据包头部指针
* body: 指向附加信息域开始部分
*/
const char * dns_packet_addtional_resovle(const struct DnsHeader *packet, const char *body)
{
return 0;
}
/* 解析 DNS 响应内容 */
int dns_packet_body_resolve(const char *packet)
{
const struct DnsHeader *header;
const char *ptr;
unsigned short cnt;
header = (struct DnsHeader *)packet;
ptr = (const char *)header+sizeof(struct DnsHeader);
printf("Queston count is %d\n", header->qdCount);
printf("Answer count is %d\n", header->anCount);
printf("Authoritative count is %d\n", header->nsCount);
printf("Addtional count is %d\n", header->arCount);
/* 如果问题数量不为0,则解析问题域 */
if(header->qdCount > 0){
cnt = header->qdCount;
while(cnt--){
ptr = dns_packet_question_resovle(header, ptr);
}
}
/* 如果回答数量不为零,则解析回答域 */
if(header->anCount > 0){
cnt = header->anCount;
while(cnt--){
ptr = dns_packet_response_resovle(header, ptr);
}
}
/* 如果授权机构数不为零,则解析授权机构 */
if(header->nsCount > 0){
cnt = header->nsCount;
while(cnt--){
ptr = dns_packet_authority_resovle(header, ptr);
}
}
/* 如果附加信息数不为0,则解析附加信息 */
if(header->arCount > 0){
cnt = header->arCount;
while(1){
ptr = dns_packet_addtional_resovle(header, ptr);
}
}
return 0;
}
/* 解析 DNS 响应报文头 */
int dns_packet_hdr_resolve(char *rbuf, int rlen)
{
struct DnsHeader *header;
header = (struct DnsHeader *)(rbuf);
if(header->id != packet_id){
printf("Packet don't match us\n");
return -1;
}
if(header->qr != 1){
printf("Not a response packet\n");
return -1;
}
/* 16 bits 的网络格式转换为 本地格式*/
exchangeByteOrder((unsigned char *)&header->anCount);
exchangeByteOrder((unsigned char *)&header->qdCount);
exchangeByteOrder((unsigned char *)&header->nsCount);
exchangeByteOrder((unsigned char *)&header->arCount);
if(header->anCount == 0){
printf("Answer count is zero\n");
return -1;
}
printf("Now ,we get a valid DNS response\n");
printf("Resovle Now.......\n");
dns_packet_body_resolve((char *)header);
return 0;
}
int main(int argc, char *argv[])
{
SOCKET soc;
SOCKADDR_IN addr,raddr;
char rbuf[BUFSIZ],sbuf[BUFSIZ];
struct DnsHeader header;
WSADATA wsa;
int i = 0,j = 0;
int rlen = 0, addr_len,try_cnt = 0;
if(argc != 2){
printf("usage : dns_request domain_name\n");
printf("example : dns_requst www.baidu.com");
return -1;
}
/* Initial Ws2_32.dll by a process */
if(WSAStartup(MAKEWORD(2,2), &wsa) != 0){
printf("WSAStartup : Error code %d\n",WSAGetLastError());
return -1;
}
if((soc = socket(AF_INET,SOCK_DGRAM,0)) <= 0)
{
printf("Create socket fail!\n");
return -1;
}
addr_len = sizeof(raddr);
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = inet_addr(DNS_ADDR);
addr.sin_port = htons(SERVER_PORT);
/* fill domain name field */
dns_packet_hdr_construct(&header);
memcpy(sbuf, (char *)&header, sizeof(header));
i = dns_packet_body_construct(sbuf + sizeof(header), argv[1]);
while(1) {
printf("try to request DNS(%s) to resolve the %s\n", DNS_ADDR, argv[1]);
if(sendto(soc, sbuf, i + sizeof(header) + 1, 0, (struct sockaddr *)&addr, sizeof(addr))< 0){
printf("sendto Error\n", WSAGetLastError());
break;
}
printf("waiting to response...");
if((rlen = recvfrom(soc, rbuf, BUFSIZ, 0, (struct sockaddr *)&raddr, &addr_len)) < 0){
printf("recvfrom Error Err %d\n", WSAGetLastError());
break;
}else{
if(dns_packet_hdr_resolve(rbuf, rlen) == 0){
printf("ok DNS request successfully\n");
break;
}
}
if(++try_cnt >= MAX_TRY_CNT){
printf("try %d times total, but still can't resolve the %s\n", MAX_TRY_CNT,argv[1]);
break;
}
}
WSACleanup(); //clean up Ws2_32.dll
return 0;
}