Chinaunix首页 | 论坛 | 博客
  • 博客访问: 84509
  • 博文数量: 7
  • 博客积分: 1445
  • 博客等级: 上尉
  • 技术积分: 190
  • 用 户 组: 普通用户
  • 注册时间: 2006-06-12 15:18
文章分类

全部博文(7)

文章存档

2010年(1)

2008年(6)

我的朋友

分类:

2008-10-01 18:48:31

上文已提过,通常进行域名和IP地址的转换时,使用gethostbyname()gethostbyaddr()(在W.Richard Stevens的《Unix Network Programming》第11章有详细的说明)。当仔细分析了DNS的协议后,我们自己动手来写写看。
下例执行的环境在Debian4.0上,编译工具为gcc,DNS服务器地址为192.168.1.1(通常该服务的默认监听端口为53),文件名为DNSClient.c:

#include

#include

#include

#include

#include

#include

#include

#include

#include

 

static void printmessage(unsigned char *buf);

static unsigned char *printnamestring(unsigned char *p,unsigned char *buf);

 

#define GETWORD(__w,__p) do{__w=*(__p++)<<8;__w|=*(p++);}while(0)

#define GETLONG(__l,__p) do{__l=*(__p++)<<24;__l|=*(__p++)<<16;__l|=*(__p++)<<8;__l|=*(p++);}while(0)

 

int main(int argc,char* argv[])

{

    if(argc != 2)

    {

       printf("usage: dnsclient \n");

       return -1;

    }

 

    time_t ident;

    int fd;

    int rc;

    int serveraddrlent;

    char *q;

    unsigned char *p;

    unsigned char *countp;

    unsigned char reqBuf[512] = {0};

    unsigned char rplBuf[512] = {0};

    struct sockaddr_in serveraddr;

 

    //udp

    fd = socket(AF_INET, SOCK_DGRAM, 0);

    if(fd == -1)

    {

       perror("error create udp socket");

       return -1;

    }

   

    time(&ident);

    //copy

    p = reqBuf;

    //Transaction ID

    *(p++) = ident;

    *(p++) = ident>>8;

    //Header section

    //flag word = 0x1000

    *(p++) = 0x01;

    *(p++) = 0x00;

    //Questions = 0x0001

    //just one query

    *(p++) = 0x00;

    *(p++) = 0x01;

    //Answer RRs = 0x0000

    //no answers in this message

    *(p++) = 0x00;

    *(p++) = 0x00;

    //Authority RRs = 0x0000

    *(p++) = 0x00;

    *(p++) = 0x00;

    //Additional RRs = 0x0000

    *(p++) = 0x00;

    *(p++) = 0x00;

    //Query section

    countp = p;  

    *(p++) = 0;

    for(q=argv[1]; *q!=0; q++)

    {

       if(*q != '.')

       {

           (*countp)++;

           *(p++) = *q;

       }

       else if(*countp != 0)

       {

           countp = p;

           *(p++) = 0;

       }

    }

    if(*countp != 0)

       *(p++) = 0;

 

    //Type=1(A):host address

    *(p++)=0;

    *(p++)=1;

    //Class=1(IN):internet

    *(p++)=0;

    *(p++)=1;

 

    printf("\nRequest:\n");

    printmessage(reqBuf);

 

    //fill

    bzero(&serveraddr, sizeof(serveraddr));

    serveraddr.sin_family = AF_INET;

    serveraddr.sin_port = htons(53);

    serveraddr.sin_addr.s_addr = inet_addr("192.168.1.1");

 

    //send to DNS Serv

    if(sendto(fd,reqBuf,p-reqBuf,0,(void *)&serveraddr,sizeof(serveraddr)) < 0)

    {

       perror("error sending request");

       return -1;

    }

 

    //recev the reply

    bzero(&serveraddr,sizeof(serveraddr));

    serveraddrlent = sizeof(serveraddr);

    rc = recvfrom(fd,&rplBuf,sizeof(rplBuf),0,(void *)&serveraddr,&serveraddrlent);

    if(rc < 0)

    {

       perror("error receiving request\n");

       return -1;

    }  

 

    //print out results

    printf("\nReply:\n");

    printmessage(rplBuf);

 

    //exit

    printf("Program Exit\n");

    return 0; 

}

 

static void printmessage(unsigned char *buf)

{

    unsigned char *p;

    unsigned int ident,flags,qdcount,ancount,nscount,arcount;

    unsigned int i,j,type,class,ttl,rdlength;

 

    p = buf;

    GETWORD(ident,p);

    printf("ident=%#x\n",ident);

 

    GETWORD(flags,p);

    printf("flags=%#x\n",flags);

    //printf("qr=%u\n",(flags>>15)&1);

    printf("qr=%u\n",flags>>15);

 

    printf("opcode=%u\n",(flags>>11)&15);

    printf("aa=%u\n",(flags>>10)&1);

    printf("tc=%u\n",(flags>>9)&1);

    printf("rd=%u\n",(flags>>8)&1);

    printf("ra=%u\n",(flags>>7)&1);

    printf("z=%u\n",(flags>>4)&7);

    printf("rcode=%u\n",flags&15); 

 

    GETWORD(qdcount,p);

    printf("qdcount=%u\n",qdcount);

 

    GETWORD(ancount,p);

    printf("ancount=%u\n",ancount);

 

    GETWORD(nscount,p);

    printf("nscount=%u\n",nscount);

 

    GETWORD(arcount,p);

    printf("arcount=%u\n",arcount);

 

    for(i=0; i

    {

       printf("qd[%u]:\n",i);

       while(*p!=0)

       {

           p = printnamestring(p,buf);

           if(*p != 0)

              printf(".");

       }

       p++;

       printf("\n");

       GETWORD(type,p);

       printf("type=%u\n",type);

       GETWORD(class,p);

       printf("class=%u\n",class);

    }

 

    for(i=0; i

    {

       printf("an[%u]:\n",i);

       p = printnamestring(p,buf);

       printf("\n");

       GETWORD(type,p);

       printf("type=%u\n",type);

       GETWORD(class,p);

       printf("class=%u\n",class);

       GETLONG(ttl,p);

       printf("ttl=%u\n",ttl);

       GETWORD(rdlength,p);

       printf("rdlength=%u\n",rdlength);

       printf("rd=");

       for(j=0; j

       {

           printf("%2.2x(%u)",*p,*p);

           p++;

       }

       printf("\n");

    }

}

 

static unsigned char *printnamestring(unsigned char *p,unsigned char *buf)

{

    unsigned int nchars,offset;

 

    nchars = *(p++);

    if((nchars & 0xc0) == 0xc0)

    {

       offset = (nchars & 0x3f) << 8;

       offset |= *(p++);

       nchars = buf[offset++];

       printf("%*.*s",nchars,nchars,buf+offset);

    }

    else

    {

       printf("%*.*s",nchars,nchars,p);

       p += nchars;

    }

 

    return (p);

}

 

编译命令为
lsj@debian007:~$ gcc -g -Wall -o DNSClient DNSClient.c
然后执行:
lsj@debian007:~$ ./DNSClient bigdogchina.cublog.cn
就可以看见结果啦这里使用的是UDP的数据格式,我们知道UDP的头部有一个16bit的长度,那么能表示的最大长度为2的16次方65536,再减去包头20,所以UDP包最大长度为65536-20=65516,但是在实际应用中,最好不要超过1K
阅读(1690) | 评论(4) | 转发(0) |
给主人留下些什么吧!~~

chinaunix网友2009-01-09 11:58:55

你的程序在recvfrom这儿经常卡住,就在那儿不动了,

chinaunix网友2009-01-08 18:21:18

哇哈哈,你竟然开始写博客了,还以为你荒废了呢

chinaunix网友2009-01-06 13:04:03

if((nchars & 0xc0) == 0xc0) { offset = (nchars & 0x3f) << 8; offset |= *(p++); nchars = buf[offset++]; printf("%*.*s",nchars,nchars,buf+offset); } 为什么有这段代码?

chinaunix网友2009-01-06 00:27:01

p-reqBuf,是什么参数?