代码之家  ›  专栏  ›  技术社区  ›  x-yuri

getaddrinfo()返回几个相同的结果

  •  5
  • x-yuri  · 技术社区  · 8 年前

    在里面 /etc/hosts 我有:

    127.0.0.1   localhost.localdomain   localhost
    ::1     localhost.localdomain   localhost
    

    测试程序:

    #include <string.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <sys/types.h>
    #include <sys/socket.h>
    #include <netdb.h>
    #include <netinet/in.h>
    
    const char* family_to_string(int family)
    {
        return family == AF_INET ? "AF_INET"
            : family == AF_INET6 ? "AF_INET6"
            : "<unknown>";
    }
    
    const char* socktype_to_string(int socktype)
    {
        return socktype == SOCK_STREAM ? "SOCK_STREAM"
            : socktype == SOCK_DGRAM ? "SOCK_DGRAM"
            : "<unknown>";
    }
    
    const char* protocol_to_string(int protocol)
    {
        return protocol == IPPROTO_TCP ? "IPPROTO_TCP"
            : protocol == IPPROTO_UDP ? "IPPROTO_UDP"
            : "<unknown>";
    }
    
    void print_addrinfo(struct addrinfo *ai)
    {
        int r;
        char hbuf[NI_MAXHOST], sbuf[NI_MAXSERV];
        r = getnameinfo(ai->ai_addr, ai->ai_addrlen, hbuf, sizeof(hbuf), sbuf,
                        sizeof(sbuf), NI_NUMERICHOST | NI_NUMERICSERV);
        if (r)
        {
            fputs("getnameinfo\n", stderr);
            exit(EXIT_FAILURE);
        }
        const char *family = family_to_string(ai->ai_family);
        const char *socktype = socktype_to_string(ai->ai_socktype);
        const char *protocol = protocol_to_string(ai->ai_protocol);
        const char *family2 = family_to_string(ai->ai_addr->sa_family);
        printf("flags=%i, family=%s, socktype=%s, protocol=%s, family=%s, host=%s, serv=%s\n",
               ai->ai_flags, family, socktype, protocol, family2, hbuf, sbuf);
    }
    
    int main(int argc, char *argv[])
    {
        (void)argc;
        (void)argv;
        int r;
        struct addrinfo hints;
        struct addrinfo *result, *ai;
    
        memset(&hints, 0, sizeof(struct addrinfo));
        // hints.ai_family = AF_INET;
        hints.ai_socktype = SOCK_STREAM;
        r = getaddrinfo("localhost", "8000", &hints, &result);
        if (r)
        {
            fputs("getaddrinfo\n", stderr);
            exit(EXIT_FAILURE);
        }
    
        ai = result;
        while (ai)
        {
            print_addrinfo(ai);
            ai = ai->ai_next;
        }
    
        exit(EXIT_SUCCESS);
    }
    

    当我没有设置 hints.ai_family ,正如所料:

    $ gcc -Wall -Wextra -Werror -pedantic -pedantic-errors -g -gdwarf-2 -g3 % && ./a.out
    flags=0, family=AF_INET6, socktype=SOCK_STREAM, protocol=IPPROTO_TCP, family=AF_INET6, host=::1, serv=8000
    flags=0, family=AF_INET, socktype=SOCK_STREAM, protocol=IPPROTO_TCP, family=AF_INET, host=127.0.0.1, serv=8000
    

    具有 提示。ai\U系列 它返回两个相同的 addrinfo 结构:

    flags=0, family=AF_INET, socktype=SOCK_STREAM, protocol=IPPROTO_TCP, family=AF_INET, host=127.0.0.1, serv=8000
    flags=0, family=AF_INET, socktype=SOCK_STREAM, protocol=IPPROTO_TCP, family=AF_INET, host=127.0.0.1, serv=8000
    

    你能解释一下发生了什么事吗?我想 hints 用作过滤器。也就是说,在这种情况下只返回一个结果。

    UPD公司 /etc/nsswitch.conf

    # Begin /etc/nsswitch.conf
    
    passwd: compat mymachines systemd
    group: compat mymachines systemd
    shadow: compat
    
    publickey: files
    
    hosts: files mymachines resolve [!UNAVAIL=return] dns myhostname
    networks: files
    
    protocols: files
    services: files
    ethers: files
    rpc: files
    
    netgroup: files
    
    # End /etc/nsswitch.conf
    

    /etc/resolv.conf :

    # Generated by resolvconf
    search Dlink
    nameserver 192.168.0.1
    

    192.168.0.1 是我的路由器。我的IP地址是 192.168.0.39 .

    1 回复  |  直到 8 年前
        1
  •  1
  •   x-yuri    8 年前

    据我所见:

    sysdeps/posix/getaddrinfo.c:2206

    int
    getaddrinfo (const char *name, const char *service,
                 const struct addrinfo *hints, struct addrinfo **pai)
    

    sysdeps/posix/getaddrinfo.c:2304

    last_i = gaih_inet (name, pservice, hints, end, &naddrs, &tmpbuf);
    

    sysdeps/posix/getaddrinfo.c:342

    static int
    gaih_inet (const char *name, const struct gaih_service *service,
               const struct addrinfo *req, struct addrinfo **pai,
               unsigned int *naddrs, struct scratch_buffer *tmpbuf)
    

    sysdeps/posix/getaddrinfo.c:595

    rc = __gethostbyname2_r (name, AF_INET, &th,
                             tmpbuf->data, tmpbuf->length,
                             &h, &h_errno);
    

    nss/getXXbyYY_r.c:189

    int
    INTERNAL (REENTRANT_NAME) (ADD_PARAMS, LOOKUP_TYPE *resbuf, char *buffer,
                               size_t buflen, LOOKUP_TYPE **result H_ERRNO_PARM
                               EXTRA_PARAMS)
    

    nss/getXXbyYY_r.c:316

    status = DL_CALL_FCT (fct.l, (ADD_VARIABLES, resbuf, buffer, buflen,
                                  &errno H_ERRNO_VAR EXTRA_VARIABLES));
    

    nss/nss_files/files-hosts.c:385

    enum nss_status
    _nss_files_gethostbyname2_r (const char *name, int af, struct hostent *result,
                                 char *buffer, size_t buflen, int *errnop,
                                 int *herrnop)
    

    nss/nss_files/files-hosts.c:389

    return _nss_files_gethostbyname3_r (name, af, result, buffer, buflen,
                                        errnop, herrnop, NULL, NULL);
    

    nss/nss_files/files-hosts.c:334

    enum nss_status
    _nss_files_gethostbyname3_r (const char *name, int af, struct hostent *result,
                                 char *buffer, size_t buflen, int *errnop,
                                 int *herrnop, int32_t *ttlp, char **canonp)
    

    这里是第一场比赛,如果 multi on 在里面 /etc/host.conf 其他人:

    nss/nss_files/files-hosts.c:352

    while ((status = internal_getent (stream, result, buffer, buflen, errnop,
                                      herrnop, af, flags))
           == NSS_STATUS_SUCCESS)
      {
        LOOKUP_NAME_CASE (h_name, h_aliases)
      }
    
    if (status == NSS_STATUS_SUCCESS
        && _res_hconf.flags & HCONF_FLAG_MULTI)
      status = gethostbyname3_multi
        (stream, name, af, result, buffer, buflen, errnop, herrnop, flags);
    

    nss/nss_files/files-hosts.c:127

    static enum nss_status
    gethostbyname3_multi (FILE * stream, const char *name, int af,
                          struct hostent *result, char *buffer, size_t buflen,
                          int *errnop, int *herrnop, int flags)
    

    nss/nss_files/files-hosts.c:162

    status = internal_getent (stream, &tmp_result_buf, tmp_buffer.data,
                              tmp_buffer.length, errnop, herrnop, af,
                              flags);
    

    nss/nss_files/files-XXX.c:178

    static enum nss_status
    internal_getent (FILE *stream, struct STRUCTURE *result,
                     char *buffer, size_t buflen, int *errnop H_ERRNO_PROTO
                     EXTRA_ARGS_DECL)
    

    nss/nss_files/files-XXX.c:222

    || ! (parse_result = parse_line (p, result, data, buflen, errnop
                                     EXTRA_ARGS)));
    

    这里我们分析“::1 localhost.localdomain localhost”行。我们尝试 要运行 inet_pton 结束 ::1 . 失败了,因为 af == AF_INET . 然后我们 请注意 ::1 是IPv6环回地址,因此返回IPv4环回 地址:

    nss/nss_files/files-hosts.c:51

    LINE_PARSER
    

    nss/nss_files/files-hosts.c:59

    if (inet_pton (af == AF_UNSPEC ? AF_INET : af, addr, entdata->host_addr)
        > 0)
      af = af == AF_UNSPEC ? AF_INET : af;
    else
      {
        if (...)
          ...
        else if (af == AF_INET
                 && inet_pton (AF_INET6, addr, entdata->host_addr) > 0)
          {
            if (...)
              ...
            else if (IN6_IS_ADDR_LOOPBACK (entdata->host_addr))
              {
                in_addr_t localhost = htonl (INADDR_LOOPBACK);
                memcpy (entdata->host_addr, &localhost, sizeof (localhost));
              }
    

    也许有人在 mailing list 将会回复,我们将了解更多。