getaddrinfo не возвращает детали ipv6 - PullRequest
0 голосов
/ 07 декабря 2018

У меня возникают проблемы при получении ipv6 using getaddrinfo():

#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <arpa/inet.h>

int main()
{
        int soc = 00;
        struct addrinfo hints,*results,*res;
        hints.ai_family = AF_UNSPEC;
        hints.ai_socktype = SOCK_STREAM;
        hints.ai_protocol = IPPROTO_TCP;
        hints.ai_flags = AI_PASSIVE;

        int m = getaddrinfo("myhost","2018",&hints,&results);
        if (m<0)
        {
                printf("getaddrinfo error :  %s\n", gai_strerror(m));
                return 1;
        }
        res=results;
        do
        {
                if(res->ai_family == AF_INET6)
                {
                        struct sockaddr_in6* a= (struct sockaddr_in6*)res->ai_addr;
                        char straddr[INET6_ADDRSTRLEN];
                        inet_ntop(AF_INET6, &a->sin6_addr, straddr, sizeof(straddr));
                        printf("IP v6 - %s\n",straddr);
                }
                if(res->ai_family == AF_INET)
                {
                        struct sockaddr_in* b= (struct sockaddr_in*)res->ai_addr;
                        const char* dotted_decimal1 = inet_ntoa(b->sin_addr);
                        printf("IP v4 - %s\n",dotted_decimal1);
                }
        }
        while((res=res->ai_next) !=NULL);

        return 0;
}

Вывод:

IP v4 - xx.xx.xx.xx

Поскольку я установил hints.ai_family = AF_UNSPEC, он должен вернуть мне обадетали (ipv4 и ipv6). Но он возвращает подробности только ipv4.

Примечание: по команде ifconfig Я вижу как ipv4, так и ipv6 адрес.

> $ ifconfig
> eth3      Link encap:Ethernet  HWaddr xx:xx:xx:xx:xx:xx
> inet addr:x.x.x.x  Bcast:x.x.x.x  Mask:255.255.255.128
> inet6 addr: xx::xx:xx:xx:xx/64 Scope:Link
  1. Может ли кто-нибудь объяснить мне, почему он не выбирает ipv6?

  2. Нужно ли вносить какие-либо изменения на моем хосте (Linux)?

Я удалил фактические данные ip и заменил на xxxx.

Ответы [ 2 ]

0 голосов
/ 18 декабря 2018

Поскольку я установил hints.ai_family = AF_UNSPEC, он должен вернуть мне обе детали (ipv4 и ipv6)

Нет, не должен.getaddrinfo API не гарантирует возврат адресов IPv4 и IPv6.Он возвращает тип IP-адреса, связанный с данным именем хоста.

Чтобы убедиться, что ваш код работает нормально, вы можете просто проверить google.com хост через 80 или 443 порты, т.е.

 int m = getaddrinfo("google.com","80",&hints,&results);

Эта проверка возвращает адреса IPv4 и IPv6 на моем ПК с Linux (к вашему сведению, у меня также нет глобального адреса IPv6).

Если вам нужно получить локальный адрес IPv6, яРекомендую использовать getifaddrs или читать /proc/net/if_inet6 файл в Linux и GetAdaptersAddresses в Windows.
Также обратите внимание, что ваш IPv6-адрес является локальной связью, которая автоматически генерируется ОС.

0 голосов
/ 08 декабря 2018

Чтобы получить локальные адреса (поскольку вы используете AI_PASSIVE), вы можете (и должны) установить для параметра node значение NULL вместо указания фактического имени, согласно документации :

Если в hints.ai_flags указан флаг AI_PASSIVE, а узел NULL, то возвращаемые адреса сокетов будут подходить для bind(2) сокета, который будет accept(2) подключаться.

Кроме того, inet_ntop() поддерживает AF_INET, поэтому вы можете избавиться от своих операторов if и безоговорочно использовать inet_ntop() для обоих семейств адресов.

Попробуйте это:

#include <iostream>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <netdb.h>
#include <unistd.h>
#include <errno.h>
#include <arpa/inet.h>

void* getSinAddr(int af, sockaddr *addr)
{
    switch (af)
    {
        case AF_INET:
            return &(reinterpret_cast<sockaddr_in*>(addr)->sin_addr);

        case AF_INET6:
            return &(reinterpret_cast<sockaddr_in6*>(addr)->sin6_addr);
    }
    return NULL;
}

int main()
{
    addrinfo hints = {}, *results, *res;

    hints.ai_family = AF_UNSPEC;
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_protocol = IPPROTO_TCP;
    hints.ai_flags = AI_PASSIVE;

    int m = getaddrinfo(NULL, "2018", &hints, &results);
    if (m < 0)
    {
        std::cout << "getaddrinfo error : " << gai_strerror(m) << std::endl;
        return 1;
    }

    for(res = results; res != NULL; res = res->ai_next)
    {
        char straddr[INET6_ADDRSTRLEN] = {};
        if (inet_ntop(res->ai_family, getSinAddr(res->ai_family, res->ai_addr), straddr, sizeof(straddr)))
            std::cout << "IP - " << straddr << "\n";
        else
            std::cout << "inet_ntop error : " << strerror(errno) << std::endl;
    }

    freeaddrinfo(results);

    return 0;
}
...