【问题标题】:Extract DNS record (MX) details from name server reply c++从名称服务器回复 C++ 中提取 DNS 记录(MX)详细信息
【发布时间】:2017-05-13 18:51:09
【问题描述】:

我正在尝试使用以下代码获取具有低优先级的 MX 记录的主机名,但我无法从给定的名称服务器回复中解析所需的详细信息(主机名、ttl、优先级)。

u_char nsbuf[4096], dispbuf[4096];
ns_msg msg;
ns_rr rr;
int i, j, l;
std::string domain("gmail.com");
l = res_query(domain.c_str(), ns_c_any, ns_t_mx, nsbuf, sizeof (nsbuf));

    ns_initparse(nsbuf, l, &msg);
    printf("%s :\n", domain.c_str());
    l = ns_msg_count(msg, ns_s_an);
    for (j = 0; j < l; j++)
    {
        int prr = ns_parserr(&msg, ns_s_an, j, &rr);


        ns_sprintrr(&msg, &rr, NULL, NULL, reinterpret_cast<char*> (dispbuf), sizeof (dispbuf));

        printf("%s\n", dispbuf);
    }

上面的代码给出的结果为

gmail.com。 15M 在 MX 30 alt3.gmail-smtp-in.l.google.com。

是否有任何可用的函数可以在如下的单独缓冲区中获取主机名、优先级、ttl 等?

主机 -> alt3.gmail-smtp-in.l.google.com

优先级 -> 30

ttl -> 15M

而且,我们是否应该手动检查更高优先级的记录, 或者是否有任何实用功能或代码可以满足要求?

编辑:

我尝试了以下代码来提取数据

#include <cstdlib>
#include <stdio.h>
#include <iostream>
#include <stdlib.h>
#include <unistd.h>
#include <netinet/in.h>
#include <resolv.h>
#include <cstring>
#include <string>
#include <string.h>

using namespace std;
int main(int argc, char** argv) {

    u_char nsbuf[4096];
    u_char dispbuf[4096];
    ns_msg msg;
    ns_rr rr;
    int i, j, l;
    std::string domain("gmail.com");
    l = res_query(domain.c_str(), ns_c_any, ns_t_mx, nsbuf, sizeof (nsbuf));
    if (l < 0) {
        perror(domain.c_str());
    } else {
#ifdef USE_PQUERY
        res_pquery(&_res, nsbuf, l, stdout);
#else
        ns_initparse(nsbuf, l, &msg);
        l = ns_msg_count(msg, ns_s_an);
        for (j = 0; j < l; j++) {
            int prr = ns_parserr(&msg, ns_s_an, j, &rr);

            //BLOCK 1
            char *cp;
            cp = (char *) ns_rr_name(rr);
            printf("CP->%s\n", (char *) cp);
            int i1 = ns_rr_type(rr);
            printf("Type->%d\n", i1);
            int i2 = ns_rr_class(rr);
            printf("Class->%d\n", i2);
            int i3 = ns_rr_ttl(rr);
            printf("TTL->%d\n", i3);
            int i4 = ns_rr_rdlen(rr);
            printf("DataLength->%d\n", i4);

            //BLOCK 2
            const u_char *rdata = ns_rr_rdata(rr) +1;
            printf("DataU_char-> %s\n", reinterpret_cast<const char*> (rdata));

            int len = strlen(reinterpret_cast<const char*> (rdata));
            printf("len->%d\n", len);

            char rdatatemp[1024];
            strncpy(rdatatemp, reinterpret_cast<const char*> (rdata), sizeof (rdatatemp));
            printf("DataChar->%s\n", rdatatemp);

            ns_sprintrr(&msg, &rr, NULL, NULL, reinterpret_cast<char*> (dispbuf), sizeof (dispbuf));
            printf("FullRecord->%s\n", dispbuf);
            printf("\n");
        }
#endif
    }
    return 0;
}

上面的代码对于txt记录运行良好,但是对于mx记录,解析不正确,结果如下

输出:

CP->gmail.com
类型->15
类->1
TTL->130
数据长度->32
DataU_char-> gmail-smtp-inlgoogle��
len->33
DataChar->gmail-smtp-inlgoogle��
完整记录->gmail.com。 2 分 10 秒 IN MX 30 alt3.gmail-smtp-in.l.google.com。

CP->gmail.com
类型->15
类->1
TTL->130
数据长度->9
DataU_char-> alt2�.�
len->10
DataChar->alt2...
完整记录->gmail.com。 2 分 10 秒 IN MX 20 alt2.gmail-smtp-in.l.google.com。

所以在 DataChar 和 DataU_char 中打印特殊符号。
打印“alt2�.�”而不是“alt2.gmail-smtp-in.l.google.com。”
此外,DataLength 值是错误的。
我也无法获得记录的优先级。
我在这里遗漏了什么,还是 c++ 库本身的错误?

【问题讨论】:

    标签: c++ dns mail-server nslookup


    【解决方案1】:

    libresolv 没有用于解压特定资源记录类型的公共函数,但其​​中有 函数可以帮助您自己完成。

    尤其是dn_expand,它可以读取(压缩的)域名,ns_get16 将从记录中读取一个大端的两个八位字节字段,所以在你的情况下:

    char exchange[NS_MAXDNAME];
    
    const u_char *rdata = ns_rr_rdata(rr);
    
    const uint16_t pri = ns_get16(rdata);
    int len = dn_expand(nsbuf, nsbuf + msg_len, rdata + 2, exchange, sizeof(exchange));
    
    printf("Pri->%d\n", pri);
    printf("Exchange->%s\n", exchange);
    

    其中msg_len 替换您覆盖的l 变量,其中包含接收数据包的长度。

    dn_expand() 的调用中的rdata + 2 跳过了16 位优先级字段。

    【讨论】:

    • 我只是尝试了答案中的内容并获得了优先权,但交换是空的。变量 len 是 -1,我不知道 msg_len 是什么。
    • @fury.slay 在您的原始代码中分配l = res_query(...),但随后您用ns_msg_count() 的结果覆盖该变量。您需要将 l 的原始值存储在 msg_len
    • 我们应该手动检查哪个优先级最低并使用该记录,还是有任何api?
    • libresolv 中没有 API 来选择应该使用哪个 MX 记录。另外,不要忘记在没有任何 MX 记录的情况下,AAAAA 记录应被视为优先级为 0 的 MX。
    猜你喜欢
    • 2010-11-08
    • 2018-05-13
    • 1970-01-01
    • 2021-11-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-07-16
    相关资源
    最近更新 更多