简体   繁体   English

查询服务器并将结果作为addrinfo结构

[英]Query a server and get the results as addrinfo struct

I want to query a specific server, and get the result at the same way as we get it via getaddrinfo . 我想查询一个特定的服务器,并以与通过getaddrinfo获取它相同的方式获取结果。 I want to get a addrinfo struct, so I can have the ip, port and a pointer to the next result. 我想获得一个addrinfo结构,因此我可以使用ip,端口和一个指向下一个结果的指针。

I'm using the code below, which query the server I want, and gets the results. 我正在使用下面的代码,该代码查询我想要的服务器并获取结果。 But each result is at another struct and they don't point one another (not in a list). 但是每个结果都在另一个结构上,它们彼此不指向(不在列表中)。

This is the code: 这是代码:

static int my_getaddrinfo(const char *dns_server_s, const char *node, const char *service, const struct addrinfo *hints, struct addrinfo **res) {
    int retValue = 1;
    struct __res_state result;
    char ip[16];
    memset(ip, '\0', sizeof(ip));

    res_ninit(&result);
    struct in_addr addr;
    inet_aton(dns_server_s, &addr);

    result.nsaddr_list[0].sin_addr = addr;
    result.nsaddr_list[0].sin_family = AF_INET;
    result.nsaddr_list[0].sin_port = htons(NS_DEFAULTPORT);
    result.nscount = 1;

    u_char answer[NS_PACKETSZ];
    int len = res_nquery(&result, node, ns_c_in, ns_t_a, answer, sizeof(answer));
    ns_msg handle;
    ns_initparse(answer, len, &handle);

    if(ns_msg_count(handle, ns_s_an) > 0) {
        ns_rr rr;
        if(ns_parserr(&handle, ns_s_an, 0, &rr) == 0) {
            strcpy(ip, inet_ntoa(*(struct in_addr *)ns_rr_rdata(rr)));
            getaddrinfo(ip, service, hints, res);
            retValue = 0;
        }
    }

    return retValue;
}

Is it possible to get the results the way I want? 是否有可能以我想要的方式获得结果? something similar to addrinfo struct? 类似于addrinfo结构?

Edit: I can see that I get three answers ns_msg_count(handle, ns_s_an) = 3 and to access each answer I should call ns_parserr(&handle, ns_s_an, answer_index, &rr) But as I said, I want to get those answers as a list just like I get them by calling getaddrinfo . 编辑:我看到我得到三个答案ns_msg_count(handle, ns_s_an) = 3并访问每个答案,我应该调用ns_parserr(&handle, ns_s_an, answer_index, &rr)但是正如我所说,我想将这些答案作为一个列表来获取就像我通过调用getaddrinfo获取它们。

getaddrinfo returns more than just ip addresses, it will also resolve service names to port number, and it could support different protocols, majorly tcp and udp. getaddrinfo不仅返回IP地址,还将服务名称解析为端口号,并且可以支持不同的协议,主要是tcp和udp。 So you will need to resolve service name by calling getservbyname_r and manually construct the result addrinfo for each combination of ip, port and protocols. 因此,您将需要通过调用getservbyname_r来解析服务名称,并为IP,端口和协议的每种组合手动构造结果addrinfo Here is a simple version which parse ip and port, but it only returns addrinfo for TCP. 这是一个解析ip和port的简单版本,但它仅返回TCP的addrinfo。 You could extended it to including UDP easily. 您可以轻松地将其扩展为包括UDP。

Another feature is that getaddrinfo also supports IPV6, in which case you will need to call res_nquery with T_AAAA instead of T_A to resolve IPV6 addresses. 另一个功能是getaddrinfo也支持IPV6,在这种情况下,您将需要使用T_AAAA而不是T_A调用res_nquery来解析IPV6地址。

Here is an example, note it returns a linked list of struct addrinfo just like getaddrinfo does, so the result should be free with freeaddrinfo when you are done. 这是一个示例,请注意,它像getaddrinfo一样返回struct addrinfo的链接列表,因此完成后,结果应该与freeaddrinfo一起freeaddrinfo

static int my_getaddrinfo(const char *dns_server,
        const char *node, const char *service,
        const struct addrinfo *hints, struct addrinfo **res) {

    int ret;

    // get dns server sockaddr
    struct addrinfo hint = {0};
    struct addrinfo *ai = NULL;

    hint.ai_family = AF_INET;
    hint.ai_socktype = SOCK_DGRAM;
    hint.ai_protocol = IPPROTO_UDP;
    ret = getaddrinfo(dns_server, "domain", &hint, &ai);
    if (ret != 0) {
        puts("getaddrinfo dns error");
        return 1;
    }

    if (!ai) {
        printf("getaddrinfo returned no result\n");
        return 1;
    }

    freeaddrinfo(ai);

    int port = 0;
    // get service port
    if (service) {
        struct servent srv, *sres;
        char buf[1024];
        ret = getservbyname_r(service, NULL, &srv, buf, sizeof buf, &sres);
        if (ret != 0) {
            printf("getservbyname error\n");
            return 1;
        }
        port = sres->s_port;
    }

    struct __res_state p = {0};
    res_state state = &p;
    unsigned char ans[NS_MAXMSG];
    ns_msg msg;
    ns_rr rr;
    char line[1024];
    int len ;

    ret = res_ninit(state);
    if (ret != 0) {
        printf("res_ninit error\n");
        return 1;
    }

    state->nscount = 1;
    memset(state->nsaddr_list, 0, sizeof state->nsaddr_list);
    memcpy(state->nsaddr_list, ai->ai_addr, sizeof state->nsaddr_list[0]);

    ret = res_nquery(state, node, C_IN, T_A, ans, sizeof ans);
    if (ret < 0) {
        printf("res_nquery error\n");
        return 1;
    }

    len = ret;
    ret = ns_initparse(ans, len, &msg);
    if (ret != 0) {
        printf("ns_initparse error\n");
        return 1;
    }

    len = ns_msg_count(msg, ns_s_an);

    if (len == 0) {
        printf("no address found\n");
        return 0;
    }

    struct addrinfo *head = NULL;
    struct addrinfo *cur = NULL;
    struct addrinfo *prev = NULL;
    struct sockaddr_in *sin;

    for (int i = 0; i < len; i++) {
        ret = ns_parserr(&msg, ns_s_an, i, &rr);
        if (ret != 0) {
            printf("ns_parserr error\n");
        }

        if (ns_rr_rdlen(rr) != NS_INADDRSZ) {
            continue;
        }

        cur = malloc(sizeof *cur + sizeof(struct sockaddr_in));
        memset(cur, 0, sizeof *cur);
        cur->ai_family = AF_INET;
        cur->ai_socktype = SOCK_STREAM;
        cur->ai_protocol = IPPROTO_TCP;
        cur->ai_addrlen = sizeof(struct sockaddr_in);
        cur->ai_addr = (void*)(cur + 1);
        cur->ai_canonname = NULL;
        cur->ai_next = NULL;
        sin = (struct sockaddr_in*)(cur->ai_addr);
        sin->sin_family = cur->ai_family;
        sin->sin_port = port;
        memcpy(&sin->sin_addr, ns_rr_rdata(rr), sizeof sin->sin_addr);
        if (prev)
            prev->ai_next = cur;
        if (head == NULL)
            head = cur;
        prev = cur;
    }
    *res = head;

    return 0;
}

int main(int argc, char *argv[])
{
    const char *node = "bing.com";
    struct addrinfo *res = NULL;
    if (argc == 2)
        node = argv[1];
    int ret = my_getaddrinfo("8.8.8.8", node, "http", NULL, &res);
    if (ret != 0) {
        puts("getaddrinfo error");
        return 1;
    }

    // do stuff with res
    struct addrinfo *rp;
    struct sockaddr_in *sin;
    char p[1024];
    for (rp = res; rp != NULL; rp = rp->ai_next) {
        sin = (struct sockaddr_in*)rp->ai_addr;
        const char *s = inet_ntop(rp->ai_family,
                &sin->sin_addr, p, sizeof p);
        printf("Got %s: %d\n", s, ntohs(sin->sin_port));
    }
    freeaddrinfo(res);
    return 0;
}

example: 例:

$ ./a.out bing.com
Got 204.79.197.200: 80
Got 13.107.21.200: 80
$ ./a.out google.com
Got 172.217.24.14: 80

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM