web-dev-qa-db-ja.com

getaddrinfoおよびIPv6

Getaddrinfo関数が何を返すかを理解しようとしています:

#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netdb.h>

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


struct addrinfo *res = 0 ;

  getaddrinfo("localhost", NULL ,NULL,&res);
  printf("ai_flags -> %i\n", res->ai_flags) ;
  printf("ai_family -> %i\n", res->ai_family) ;
  printf("ai_socktype -> %i\n", res->ai_socktype) ;
  printf("ai_protocol -> %i\n", res->ai_protocol) ;
  printf("ai_addrlen -> %i\n", res->ai_addrlen) ;
  struct sockaddr_in* saddr = (struct sockaddr_in*)res->ai_addr;
  printf("ai_addr hostname ->  %s\n", inet_ntoa(saddr->sin_addr));

  freeaddrinfo(res);

  return 0 ;
}

結果 :

ai_flags -> 40
ai_family -> 2
ai_socktype -> 1
ai_protocol -> 6
ai_addrlen -> 16
ai_addr hostname ->  127.0.0.1

/ etc/hostsには、次のものがあります。

127.0.0.1 localhost    
::1     localhost

Getaddrinfoは127.0.0.1のみを返し、:: 1は返しませんか?理由がわかりませんか?

2番目の質問は、これらのint(40、2、1、6など)の意味をどこで見つけることができるかです。私はその男を読みましたが、それについては何もありません。

また、IPv6アドレス(たとえば:: 1)を指定でき、関数が名前を返すかどうかも知りたいと思いました:localhost?

どうもありがとう !!

17
lilawood

@jwodderと@onteria_はIPv6の部分をうまくカバーしているので、numbersの部分に取り組むだけです。

ai_flags -> 40

おそらく、これは/usr/include/netdb.hの次の2つの合計になります。

# define AI_V4MAPPED    0x0008  /* IPv4 mapped addresses are acceptable.  */
# define AI_ADDRCONFIG  0x0020  /* Use configuration of this Host to choose

これはプロトコルファミリ、inet、inet6、apx、unixなどです。

ai_family -> 2

bits/socket.h:78:#define    PF_INET     2   /* IP protocol family.  */
bits/socket.h:119:#define   AF_INET     PF_INET

これはソケットタイプ、ストリーム、dgram、パケット、rdm、seqpacketです:

ai_socktype -> 1

bits/socket.h:42:  SOCK_STREAM = 1,     /* Sequenced, reliable, connection-based

上位レベルプロトコル、TCP、UDP、TCP6、UDP6、UDPlite、ospf、icmpなど:

ai_protocol -> 6

おかしなことに、/etc/protocols

tcp 6   TCP     # transmission control protocol

struct sockaddrのサイズ。 (アドレスファミリによって異なります!うーん。)

ai_addrlen -> 16

これは、struct sockaddr_inが返されるためです。linux/in.hを参照してください。

#define __SOCK_SIZE__   16      /* sizeof(struct sockaddr)  */
struct sockaddr_in {
  sa_family_t       sin_family; /* Address family       */
  __be16        sin_port;   /* Port number          */
  struct in_addr    sin_addr;   /* Internet address     */

  /* Pad to size of `struct sockaddr'. */
  unsigned char     __pad[__SOCK_SIZE__ - sizeof(short int) -
            sizeof(unsigned short int) - sizeof(struct in_addr)];
};

そして最後のもの、/etc/hostsから:)

ai_addr hostname ->  127.0.0.1
10
sarnold

resには、フィールド_struct addrinfo *ai_next;_も含まれています。これは、getaddrinfoによって検出された追加のエントリへのポインタであり、他のエントリがなかった場合はNULLです。 _res->ai_next_を調べると、IPv6エントリが見つかるはずです。

_struct addrinfo_の整数フィールドについては、実装定義の値を持つ事前定義された定数に対応しており、整数値自体は一般的に重要ではありません。特定のフィールドの意味を知りたい場合は、そのフィールドに割り当てることができる定数(_SOCK_STREAM_、_SOCK_DGRAM_などの_ai_socktype_; _IPPROTO_TCP_)と比較してください。 、_IPPROTO_UDP_など(_ai_protocol_;など)または_ai_flags_の場合は、事前定義された定数(if (res->ai_flags & AI_NUMERICHOST) {printf("ai_flags has AI_NUMERICHOST\n"); }など)に対応する各ビットをテストします。

9
jwodder
extern struct sockaddr_in6 create_socket6(int port, const char * address) {

    struct addrinfo hints, *res, *resalloc;
    struct sockaddr_in6 input_socket6;
    int errcode;

    /* 0 out our structs to be on the safe side */
    memset (&hints, 0, sizeof (hints));
    memset (&input_socket6, 0, sizeof(struct sockaddr_in6));

    /* We only care about IPV6 results */
    hints.ai_family = AF_INET6;
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_flags = AI_DEFAULT;

    errcode = getaddrinfo (address, NULL, &hints, &res);
    if (errcode != 0)
    {
     perror ("[ERROR] getaddrinfo ");
     return input_socket6;
    }

    resalloc = res;

    while (res)
    {
        /* Check to make sure we have a valid AF_INET6 address */
        if(res->ai_family == AF_INET6) {
                /* Use memcpy since we're going to free the res variable later */
                        memcpy (&input_socket6, res->ai_addr, res->ai_addrlen);

                       /* Here we convert the port to network byte order */
                        input_socket6.sin6_port = htons (port);
                        input_socket6.sin6_family = AF_INET6;
               break;
        }

        res = res->ai_next;
    }

    freeaddrinfo(resalloc);

    return input_socket6;
}

これはそれを説明するいくつかのコードです。基本的に、getaddrinfoにIPV6でのみ機能するように指示するヒントを与えない限り、IPV4の結果も得られます。そのため、示されているように結果をループする必要があります。

6
onteria_

他の答えはほとんどの部分に与えられました、しかしこの最後の部分に答えるために:

また、IPv6アドレス(たとえば:: 1)を指定でき、関数が名前を返すかどうかも知りたいと思いました:localhost?

必要な関数はgetnameinfo()です。ソケットアドレスを指定すると、文字列名が返されます。

4
LeoNerd