socket编程实现简单DNS协议实现获取域名ip(TCP)

上次在文章《socket编程实现简单DNS协议实现获取域名ip(UDP)》中提到使用udp协议发送dns数据包查询站点ip,这次带来TCP版本的查询代码。

其实不管是tcp协议还是udp协议,都是构造dns报文,填写查询方式,发送数据包即可。

然而,在dns协议中有个特殊的地方需要重点强调!使用tcp协议和udp协议发送的dns报文有个很容易被忽略的问题:在tcp协议时,除了udp协议时的dns报文数据,还要在原有的报文数据之前添加两个字节,这两个字节指名其后的dns报文数据有多少字节!

除了上述的区别,其他的都一样。

另外,再提个问题,其实在dns服务器返回的数据包中可能包含了同一个域名的多个ip地址,我们在UDP的那篇文章中只解析了最后一个提供的ip地址~,这次的tcp模式同时解析了所有返回的ip地址~

这次的代码使用了文章《socket编程之TCP通信模块》中的头文件。main函数文件代码如下:

#include 
#include 
#include "tcp_client.h"
typedef unsigned short U16;
const char srv_ip[] = "8.8.8.8";
#define R_OK    0
#define R_ERROR -1
/*typedef struct _DNS_HDR
{  
    U16 id;
    U16 tag;
    U16 numq;
    U16 numa;
    U16 numa1;
    U16 numa2;
}DNS_HDR;*/
typedef struct
{
    unsigned short id;       // identification number
    unsigned char rd :1;     // recursion desired
    unsigned char tc :1;     // truncated message
    unsigned char aa :1;     // authoritive answer
    unsigned char opcode :4; // purpose of message
    unsigned char qr :1;     // query/response flag
    unsigned char rcode :4;  // response code
    unsigned char cd :1;     // checking disabled
    unsigned char ad :1;     // authenticated data
    unsigned char z :1;      // its z! reserved
    unsigned char ra :1;     // recursion available
    unsigned short q_count;  // number of question entries
    unsigned short ans_count; // number of answer entries
    unsigned short auth_count; // number of authority entries
    unsigned short add_count; // number of resource entries
}DNS_HDR;
/*typedef struct _DNS_QER
{
    U16 type;
    U16 classes;
}DNS_QER;*/
typedef struct
{
    unsigned short type;
    unsigned short classes;
}DNS_QES;
int main(int argc, char **argv)
{
    unsigned char buff[1024];
    unsigned char *buf = buff + 2;
    unsigned char *p;
    int len, i;
    DNS_HDR  *dnshdr = (DNS_HDR *)buf;
    DNS_QES  *dnsqes = NULL;
   
    if (R_ERROR == tcp_client_init(argv[2], 53))
    {
        printf("Conn Error!\n");
        return -1;
    }
    else
    {
        printf("Conn OK!\n");
    }
   
    memset(buff, 0, 1024);
    dnshdr->id = htons(0x2000);//(U16)1;
    dnshdr->qr = 0;
    dnshdr->opcode = 0;
    dnshdr->aa = 0;
    dnshdr->tc = 0;
    dnshdr->rd = 1;
    dnshdr->ra = 1;
    dnshdr->z  = 0;
    dnshdr->ad = 0;
    dnshdr->cd = 0;
    dnshdr->rcode = 0;
    dnshdr->q_count = htons(1);
    dnshdr->ans_count = 0;
    dnshdr->auth_count = 0;
    dnshdr->add_count = 0;
    strcpy(buf + sizeof(DNS_HDR) + 1, argv[1]);
    p = buf + sizeof(DNS_HDR) + 1; i = 0;
    while (p < (buf + sizeof(DNS_HDR) + 1 + strlen(argv[1])))
    {
        if ( *p == '.')
        {
            *(p - i - 1) = i;
            i = 0;
        }
        else
        {
            i++;
        }
        p++;
    }
    *(p - i - 1) = i;
                                   
    dnsqes = (DNS_QES *)(buf + sizeof(DNS_HDR) + 2 + strlen(argv[1]));
    dnsqes->classes = htons(1);
    dnsqes->type = htons(1);
    buff[0] = 0; buff[1] = sizeof(DNS_HDR) + sizeof(DNS_QES) + strlen(argv[1]) + 2;
    if (R_ERROR == tcp_client_send(buff, sizeof(DNS_HDR) + sizeof(DNS_QES) + strlen(argv[1]) + 4))
    {
        printf("Send Error!\n");
        return -1;
    }
    else
    {
        printf("Send OK!\n");
    }
   
    len = tcp_client_recv(buff, 1024);
    if (len < 0)
    {
        printf("Recv Error!\n");
        return -1;
    }
    else
    {
        printf("Recv OK!\n");
    }
   
    if (dnshdr->rcode !=0 || dnshdr->ans_count == 0)
    {
        printf("Ack Error\n");
        return -1;
    }
    p = buff + 2 + sizeof(DNS_HDR) + sizeof(DNS_QES) + strlen(argv[1]) + 2;
    printf("Ans Count = %d\n", ntohs(dnshdr->ans_count));
    for (i = 0; i < ntohs(dnshdr->ans_count); i++)
    {
        p = p + 12;
        printf("%s ==> %u.%u.%u.%u\n", argv[1], (unsigned char)*p, (unsigned char)*(p + 1), (unsigned char)*(p + 2), (unsigned char)*(p + 3));
        p = p + 4;
    }
    tcp_client_close();
    return 0;
}

执行结果如下:

[root@isayme socket]# ./dns_tcp isayme.org 8.8.8.8
Conn OK!
Send OK!
Recv OK!
Ans Count = 1
isayme.org ==> 173.231.29.114
[root@isayme socket]# ./dns_tcp google.com 8.8.8.8
Conn OK!
Send OK!
Recv OK!
Ans Count = 6
google.com ==> 74.125.71.106
google.com ==> 74.125.71.103
google.com ==> 74.125.71.147
google.com ==> 74.125.71.105
google.com ==> 74.125.71.104
google.com ==> 74.125.71.99


需要的头文件在文章《socket编程之TCP通信模块》中下载!

转自:https://blog.csdn.net/bytxl/article/details/10395089

你可能感兴趣的:(socket编程实现简单DNS协议实现获取域名ip(TCP))