Skip to content

Latest commit

 

History

History
87 lines (61 loc) · 4.91 KB

File metadata and controls

87 lines (61 loc) · 4.91 KB

IP-адреса и сети

Конвертация адреса

Из строки в бинарный

Предположим, у нас есть struct sockaddr_in ina и IP-адрес "10.12.110.57" или 2001:db8:63b3:1::3490, который вы хотите сохранить в этой структуре.

Для этого нужна функция inet_pton(), она конвертирует строку адреса в структуру struct in_addr или struct in_6addr, в зависимости от указания семейства адресов AF_INET (для IPv4) ли AF_INET6 (для IPv6).

pton - означает "Presentation to network", можно просто сказать - строка к сетевой структуре.

Пример конвертации для IPv4 и для IPv6:

struct sockaddr_in sa;    //IPv4
struct sockaddr_in6 sa6;  //IPv6

// inet_pton() возвращает -1 в случае ошибке, нужно это обрабатывать!
inet_pton(AF_INET, "10.12.110.57", &(sa.sin_addr));
inet_pton(AF_INET6, "2001:db8:63b3:1::3490", &(sa6.sin6_addr));

Старый способ включен в себя вызов функции inet_addr() или inet_aton(), сейчас это устаревший способ, который не работает с IPv6.

Из бинарного в строку

Функция inet_ntop() используется для преобразования бинарного адреса (уже полученного откуда-то) в строку.

ntop означает Network to represetntation

Пример вывода адреса для IPv4 и IPv6:

  // IPv4:
  char ip4[INET_ADDRSTRLEN]; // буфер для хранения IPv4 строки
  struct sockaddr_in sa; // предположим, что уже загружен откуда-то
  inet_ntop(AF_INET, &(sa.sin_addr), ip4,  INET_ADDRSTRLEN);
  
  printf("IPv4 Address: %s\n", ip4);

  // IPv6:
  char ip6[INET6_ADDRSTRLEN];
  struct sockaddr_in6 sa6;
  inet_ntop(AF_INET6, &(sa6.sin6_addr), ip6, INET6_ADDRSTRLEN);

  printf("IPv6 Address: %s\n", ip6);

Эти функции работают только с прямым, числовым адресом (xxx.xxx.xxx.xxx или IPv6), они не делают поиска в DNS-сервере по имени хоста (например, example.com). Для этих целей есть другая функция - getaddrinfo(), с которой ознакомимся позже.

Переоход от IPv4 к IPv6

Чтобы ваш код поддерживал обе версии - IPv4 и IPv6, можно следовать следующим наставлениям:

  1. Используйте системную функцию getaddrinfo(), чтобы получать все структуры struct sockaddr. Это сделает ваш код независимым от версии IP.

  2. Любое место, где происходит жесткое кодирование конкретной версии IP, оберните в функцию-помощник, которая сама подставляет нужные значения (IPv4 или IPv6).

  3. Если вам нужен IPv6, то:

    • заменяйте константу AF_INET на AF_INET6.

    • заменяйте константу PF_INET на PF_INET6.

    • изменяйте назначение IN_ADDRANY к in6addr_any:

      struct sockaddr_in sa;
      struct sockaddr_in6 sa6;
      
      sa.sin_addr.s_addr = INADDR_ANY; // использовать IPv4
      sa6.sin6_addr = in6addr_any;    // использовать IPv6
    • используйте значение IN6ADDR_ANY_INIT для инициализации struct in6_addr:

      struct in6_addr ia6 = IN6ADDR_ANY_INIT.
    • вместо struct sockaddr_in, используйте struct sockaddr_in6 , удостоверьтесь, что вы работаете с полями, где есть указание "6", что они конкретно для IPv6.

    • вместо struct in_addr, используйте struct in6_addr , удостоверьтесь, что вы работаете с полями, где есть указание "6", что они конкретно для IPv6.

  4. вместо inet_aton() или inet_addr(), используйте inet_pton().

  5. вместо inet_ntoa(), используйте inet_ntop().

  6. вместо gethostbyname(), используйте getaddrinfo().

  7. вместо gethostbyaddr(), используйте getnameinfo().