getaddrinfo - возвращаемые данные о порте по доменному имени

Вопрос собственно касается функции getaddrinfo: Вот код вызова getaddrinfo:

char my_char_HOST[] = "ru.stackoverflow.com";
char my_char_NAME_SERVICE[] = "https";
 
    ADDRINFOA my_ADDRINFOA;
 
    memset(&my_ADDRINFOA, 0, sizeof(my_ADDRINFOA)); 
    my_ADDRINFOA.ai_family = AF_INET;     
    my_ADDRINFOA.ai_socktype = SOCK_STREAM; 
    my_ADDRINFOA.ai_protocol = IPPROTO_TCP;
 

    struct addrinfo *servinfo;  // Сюда getaddrinfo - заносит возвращенную информацию
 
    INT my_getaddrinfo = getaddrinfo(my_char_HOST, my_char_NAME_SERVICE, &my_ADDRINFOA, &servinfo);
  1. Судя из описания rfc3493 - ai_family выполняет некую функцию "фильтрации", то есть оно работает так, когда я запрашиваю у DNS информацию об IP-адресе по имени хоста, то DNS возвращает эти адреса, предположим у какого то сайта google.com – есть адрес и в Ipv4 и в Ipv6, то если указать к примеру только AF_INET, то DNS вернет только адреса Ipv4, если AF_INET6, то только адреса Ipv6.

  2. А вот с ai_socktype и ai_protocol - не понятно, потому что они точно не аналогичную ai_family функцию выполняют, потому что, если я к примеру указываю при вызове getaddrinfo:

    my_ADDRINFOA.ai_socktype = SOCK_STREAM; 
    my_ADDRINFOA.ai_protocol = IPPROTO_TCP;
    

    То в возвращенной заполненной структуре addrinfo - фигурируют те же значения полей, и если я изменяю их на:

    my_ADDRINFOA.ai_socktype = SOCK_DGRAM; 
    my_ADDRINFOA.ai_protocol = IPPROTO_UDP;
    

    То возвращаются уже эти значения.

    Из rfc я так и не понял назначения, но судя по результату могу предположить, что параметры ai_socktype и ai_protocol - служат указанием для getaddrinfo - по какому протоколу обращается к DNS-серверу. Вот может кто знает так это или нет ?

  3. И тоже самое касается второго параметра функции getaddrinfo - это номер службы или номер порта. Если я передаю NULL, то, когда я смотрю поле структуры sockaddr_in.sin_port, там указано 0. Если я меняю с NULL, к примеру на "80", то в sockaddr_in.sin_port указано 80.

    То ест опять не понятно, просто повторяются те значения, которые я сам же и внес. Но, а, как тогда вообще узнать, как номер порта соответствует запрашиваемому доменному имени ? То есть, по какому порту мне делать запрос на сервер ?


Ответы (1 шт):

Автор решения: Fat-Zer

Третий параметр getaddrinfo() называется hints (pHints), т.е. это некие «подсказки» службе имён, какие адреса искать и возвращать. Важно также иметь в виду, что getaddrinfo() представляет собой абстрактный интерфейс, который может поддерживать разные службы имён, не только DNS и не только в ip-сетях, например, обычно, он возвращает также имена из /etc/hosts (windows\system32\drivers\etc\hosts), а может также использовать и другие службы для поиска хостов: mdns, wins и др.

Также удобство getaddrinfo() в том, что его ответа (struct addrinfo) вполне достаточно для создания сокета и установки соединения (socket()/connect()), т.е. ai_family, ai_socktype и ai_protocol можно передавать напрямую в socket(), а ai_addr и ai_addrlen в connect().

  1. Да, всё примерно так и есть. ai_family должно использоваться и используется на практике, чтобы ограничить возвращаемые адреса конкретным семейством протоколов.

  2. Гипотетически, ai_socktype и ai_protocol также могут использоваться для фильтрации, как и ai_family, но я не смогу назвать службу, которая это поддерживала бы (хотя это в принципе и возможно). Так что на практике они применяются исключительно, чтобы инициализировать соответствующие значения в возвращаемом векторе servinfo.

  3. Второй параметр — это не обязательно номер порта, это может быть и имя службы. Например, https, как в примере выше, — в таком случае getaddrinfo() просто ищет порт соответствующий данной службе аналогично getservbyname() (только без вероятности гонки).

    Но, а, как тогда вообще узнать, как номер порта соответствует запрашиваемому доменному имени? То есть, по какому порту мне делать запрос на сервер ?

    Доменному имени соответствует только адрес, а порты ему «соответствуют» все: от 1 до 65535.

    Запрос нужно делать на конкретный, заданный пользователем/оговорённый сервером порт. Есть стандартные порты для конкретных служб, обычно если порт не указывается пользователем, то запрос делается на один из таких, для этого собственно можно и указать имя службы, например https. Проверить, предоставляет ли данный хост конкретную службу на конкретном порту можно только установив соединение (вообще говоря, есть некоторые другие «хакерские» способы, но все они всё равно подразумевают отправку каких-либо данных на удалённый сервер).

→ Ссылка