IP6

Интернет-протокол версии 6

Прототип:

#include <sys/socket.h>
#include <netinet/in.h>
int socket( AF_INET6,
SOCK_RAW,
proto );

Описание:

Протокол IP6 - это протокол сетевого уровня, используемый семейством интернет-протокола версии 6 (AF_INET6). Параметры могут быть установлены на уровне IP6 при использовании протоколов более высокого уровня на основе IP6 (таких как TCP и UDP). К нему также можно получить доступ через «сырой сокет» при разработке новых протоколов или специальных приложений.

Существует несколько параметров setsockopt()/ getsockopt() уровня IP6. Они разделены на базовое API сокетов IP6 (определенное в RFC 2553) и расширенное API (определенное в RFC 2292). Базовое API очень похоже на API, представленное в IP. Расширенное API использует вспомогательные данные и может обрабатывать более сложные случаи.


Note: Для указания некоторых параметров сокета требуются привилегии суперпользователя.

Базовое API сокетов IP6

Можно использовать параметр IPV6_UNICAST_HOPS для установки поля hoplimit в заголовке IP6 для одноадресных пакетов. При указании -1, менеджер сокетов будет использовать значение по умолчанию. При указании значения от 0 до 255, пакет будет использовать указанное значение в качестве hoplimit. Другие значения считаются недопустимыми и приводят к коду ошибки EINVAL. Например:

int hlim = 60; /* max = 255 */
setsockopt( s, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &hlim, sizeof( hlim ) );

Многоадресная рассылка IP6 поддерживается только на сокетах AF_INET6 типа SOCK_DGRAM и SOCK_RAW и только в сетях, где драйвер интерфейса поддерживает многоадресную рассылку.

Параметр IPV6_MULTICAST_HOPS изменяет предел переходов для исходящих датаграмм многоадресной рассылки, чтобы контролировать объем многоадресных рассылок:

unsigned int hlim; /* range: 0 to 255, default = 1 */
setsockopt( s, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &hlim, sizeof( hlim ) );

Датаграммы с hoplimit равным 1 не пересылаются за пределы локальной сети. Многоадресные датаграммы с hoplimit равным 0 не будут передаваться ни в какую сеть, но могут быть доставлены локально, если отправляющий хост принадлежит к группе назначения и если кольцевой контроль многоадресной рассылки не отключен на отправляющем сокете (см. ниже). Многоадресные датаграммы с hoplimit больше 1 могут быть перенаправлены в другие сети, если к локальной сети подключен многоадресный маршрутизатор.

Для хостов с несколькими интерфейсами каждая многоадресная передача отправляется с основного сетевого интерфейса. Параметр IPV6_MULTICAST_IF отменяет значение по умолчанию для последующих передач из данного сокета:

unsigned int outif;
outif = if_nametoindex( "ne0" );
setsockopt( s, IPPROTO_IPV6, IPV6_MULTICAST_IF, &outif, sizeof( outif ) );

(Аргумент outif - это индекс желаемого интерфейса или 0, если требуется указать интерфейс по умолчанию.)

Если многоадресная датаграмма отправляется группе, к которой принадлежит сам отправляющий хост (на исходящем интерфейсе), копия датаграммы по умолчанию возвращается обратно на уровень IP6 для локальной доставки. Параметр IPV6_MULTICAST_LOOP дает отправителю явный контроль над тем, возвращаются ли последующие датаграммы обратно:

u_char loop; /* 0 = disable, 1 = enable (default) */
setsockopt( s, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &loop, sizeof( loop ) );

Этот параметр повышает производительность приложений, которые могут иметь не более одного экземпляра на одном хосте (например, демон маршрутизатора), за счет устранения накладных расходов на получение собственных передач. Не следует использовать параметр IPV6_MULTICAST_LOOP, если на одном хосте может быть более одного экземпляра приложения (например, программа конференц-связи) или если отправитель не принадлежит к группе назначения (например, программа запросов времени).

Многоадресная датаграмма, отправленная с начальным hoplimit, превышающим 1, может быть доставлена на хост-отправитель по интерфейсу, отличному от того, на котором она была отправлена, если хост принадлежит к группе назначения на этом самом другом интерфейсе. Опция управления закольцовыванием не влияет на такую доставку.

Хост должен стать членом группы многоадресной рассылки, прежде чем он сможет получать датаграммы, отправленные в группу. Чтобы присоединиться к группе многоадресной рассылки, используется параметр IPV6_JOIN_GROUP:

struct ipv6_mreq mreq6;
setsockopt( s, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq6, sizeof( mreq6 ) );

Обратите внимание, что аргумент mreq6 имеет следующую структуру:

struct ipv6_mreq {
struct in6_addr ipv6mr_multiaddr;
unsigned int ipv6mr_interface;
};

Установите для поля ipv6mr_interface значение 0, чтобы выбрать интерфейс многоадресной рассылки по умолчанию, или установите для него индекс интерфейса конкретного интерфейса с поддержкой многоадресной рассылки, если хост является многосетевым. Членство связано с единым интерфейсом; программам, работающим на многосетевых хостах, может потребоваться присоединение к одной группе на более чем одном интерфейсе.

Чтобы отказаться от членства, используйте:

struct ipv6_mreq mreq6;
setsockopt( s, IPPROTO_IPV6, IPV6_LEAVE_GROUP, &mreq6, sizeof( mreq6 ) );

Аргумент mreq6 содержит те же значения, которые используются для добавления членства. Членство прекращается при закрытии сокета или выходе из процесса.

Параметр IPV6_PORTRANGE управляет распределением временных портов для сокетов SOCK_STREAM и SOCK_DGRAM. Например:

int range = IPV6_PORTRANGE_LOW; /* see <netinet/in.h> */
setsockopt( s, IPPROTO_IPV6, IPV6_PORTRANGE, &range, sizeof( range ) );

Параметр IPV6_BINDV6ONLY управляет поведением сокета AF_INET6, ожидающего специальный символ. В следующем примере для параметра устанавливается значение 1:

int on = 1;
setsockopt( s, IPPROTO_IPV6, IPV6_BINDV6ONLY, &on, sizeof( on ) );

При установке параметру IPV6_BINDV6ONLY значения 1, сокет, ожидающий специальный символ AF_INET6 принимает только трафик IP6. Если значение равно 0, сокет также принимает трафик IPv4, как если бы он был со смапированного адреса IPv4, например ::ffff:10.1.1.1. Обратите внимание, что при установке для параметра значения 0, управление доступом IPv4 станет намного сложнее. Например, даже если нет прослушивающего сокета AF_INET на порту X, в конечном итоге придется принимать трафик IPv4 от прослушивающего сокета AF_INET6 на том же порту. Значение по умолчанию для этого флага копируется во время создания экземпляра сокета из переменной net.inet6.ip6.bindv6only из утилиты sysctl. Параметр значим только для сокетов TCP и UDP.

Расширенное API сокетов IP6

Расширенное API сокетов IP6 позволяет приложениям указывать или получать подробную информацию о заголовках IP6 и расширениях в пакетах. Расширенное API использует вспомогательные данные для передачи данных в менеджер сокетов или из него.

Также присутствуют парамтеры setsockopt()/ getsockopt() для получения дополнительной информации о входящих пакетах:

int on = 1;
setsockopt( fd, IPPROTO_IPV6, IPV6_PKTINFO, &on, sizeof( on ) );
setsockopt( fd, IPPROTO_IPV6, IPV6_HOPLIMIT, &on, sizeof( on ) );
setsockopt( fd, IPPROTO_IPV6, IPV6_HOPOPTS, &on, sizeof( on ) );
setsockopt( fd, IPPROTO_IPV6, IPV6_DSTOPTS, &on, sizeof( on ) );
setsockopt( fd, IPPROTO_IPV6, IPV6_RTHDR, &on, sizeof( on ) );

Когда любой из этих параметров включен, соответствующие данные возвращаются в качестве управляющей информации функцией recvmsg() в виде одного или нескольких объектов вспомогательных данных.

Если установлен IPV6_PKTINFO, IP6-адрес назначения и индекс прибывающего интерфейса доступны через структуру in6_pktinfo во вспомогательном потоке данных. Можно выбрать структуру, проверив элемент вспомогательных данных, установив для аргумента cmsg_level значение IPPROTO_IPV6, а для аргумента cmsg_type - значение IPV6_PKTINFO.

Если установлен IPV6_HOPLIMIT, значение hoplimit пакета становится доступным для приложения. Поток вспомогательных данных содержит целочисленный элемент данных с cmsg_level равным IPPROTO_IPV6 и cmsg_type равным IPV6_HOPLIMIT.

Семейство функций inet6_option_space() помогает анализировать элементы вспомогательных данных для IPV6_HOPOPTS и IPV6_DSTOPTS. Точно так же семейство функций inet6_rthdr_space() помогает проанализировать элементы вспомогательных данных для IPV6_RTHDR.


Note: Значения IPV6_HOPOPTS и IPV6_DSTOPTS могут появляться несколько раз в потоке вспомогательных данных (обратите внимание, что поведение несколько отличается от спецификации). Другие элементы вспомогательных данных появляются не более одного раза.

Можно передавать элементы вспомогательных данных с обычными данными полезной нагрузки, используя функцию sendmsg(). Элементы вспомогательных данных анализируются менеджером сокетов и используются для создания заголовка IP6 и заголовков расширения. Для значений cmsg_level, перечисленных выше, формат вспомогательных данных такой же, как и для входящего случая.

Кроме того, можно указать объект данных IPV6_NEXTHOP. Объект вспомогательных данных IPV6_NEXTHOP определяет следующий переход для датаграммы как структуру адреса сокета. В структуре cmsghdr, содержащей эти вспомогательные данные, аргумент cmsg_level - это IPPROTO_IPV6, аргумент cmsg_type - это IPV6_NEXTHOP, а первый байт cmsg_data является первым байтом структуры адреса сокета.

Если структура адреса сокета содержит IP6-адрес (например, аргумент sin6_family равен AF_INET6), то узел, идентифицированный этим адресом, должен быть соседом хоста-отправителя. Если этот адрес равен IP6-адресу назначения датаграммы, то это эквивалентно существующей опции сокета SO_DONTROUTE.

Для приложений, которые не используют или не могут использовать функцию sendmsg() или recvmsg(), определена опция сокета IPV6_PKTOPTIONS. Установка параметра сокета определяет любое из дополнительных полей вывода:

setsockopt( fd, IPPROTO_IPV6, IPV6_PKTOPTIONS, &buf, len );

Аргумент buf указывает на буфер, содержащий один или несколько объектов вспомогательных данных; аргумент len - это общая длина всех этих объектов. Приложение заполняет этот буфер точно так же, как если бы он передавался функции sendmsg() в качестве управляющей информации.

Параметры, устанавливаемые путем вызова setsockopt() для IPV6_PKTOPTIONS, называются «закрепленными» параметрами, потому что после установки они применяются ко всем пакетам, отправляемым через этот сокет. Приложение может снова вызвать setsockopt(), чтобы изменить все закрепленные параметры, или оно может вызвать setsockopt() с длиной 0, чтобы удалить все закрепленные параметры для сокета.

Соответствующий вариант получения:

getsockopt( fd, IPPROTO_IPV6, IPV6_PKTOPTIONS, &buf, &len );

возвращает буфер с одним или несколькими объектами вспомогательных данных для всей дополнительной информации приема, которую приложение ранее указало, как желаемую. Аргумент buf указывает на буфер, который заполняется при вызове. Аргумент len является указателем на целочисленную пару "значение-результат"; при вызове функции целое число определяет размер буфера, на который указывает buf, а при возврате это целое число содержит фактическое количество байт, которые были сохранены в буфере. Приложение обрабатывает этот буфер точно так же, как если бы он был возвращен recvmsg() в качестве управляющей информации.

Расширенное API и сокеты TCP

При использовании getsockopt() с параметром IPV6_PKTOPTIONS и сокетом TCP, только параметры из последнего полученного сегмента сохраняются и возвращаются вызывающей стороне, и только после того, как параметр сокета был установлен. Приложению не разрешено указывать вспомогательные данные при вызове sendmsg() на сокете TCP, и никакие из дополнительных данных, описанных выше, никогда не возвращаются в качестве управляющей информации функцией recvmsg() на сокете TCP.

Разрешение конфликтов

В некоторых случаях существует несколько API, определенных для управления полем заголовка IP6. Хорошим примером является исходящий интерфейс для многоадресных датаграмм: им можно управлять с помощью IPV6_MULTICAST_IF в базовом API, с помощью IPV6_PKTINFO в расширенном API и с помощью поля sin6_scope_id структуры адреса сокета, передаваемого в функцию sendto().

В ЗОСРВ «Нейтрино», когда менеджеру сокетов передаются конфликтующие параметры, диспетчер сокетов получает значения в следующем порядке:

  1. параметры, указанные с использованием дополнительных данных
  2. параметры, указанные "sticky" опцией расширенного API
  3. параметры, указанные с помощью базового API
  4. параметры, указанные адресом сокета.


Note: Разрешение конфликтов не определено в спецификации API и зависит от реализации.

Сырые IP6 сокеты

Сырые IP6 сокеты не требуют подключения и обычно используются с sendto() и recvfrom(), хотя также можно использовать и connect() чтобы исправить место назначения для будущих пакетов (в этом случае можно использовать read() или recv(), и write() или send()).

Если proto равно 0, для исходящих пакетов используется протокол по умолчанию IPPROTO_RAW, и принимаются только входящие пакеты, предназначенные для этого протокола. Если proto отличен от нуля, этот номер протокола используется для исходящих пакетов и для фильтрации входящих пакетов.

К исходящим пакетам автоматически добавляется заголовок IP6 (на основе адреса назначения и номера протокола, с которым создается сокет). Входящие пакеты принимаются без заголовка IP6 или расширенных заголовков.

Все данные, отправляемые через сырые сокеты, должны быть в сетевом порядке байт; все данные, полученные через сырые сокеты, находятся в сетевом байтовом порядке. Это отличается от исходных сокетов IPv4, которые не указывали порядок байт и обычно использовали порядок байт хоста.

Еще одно отличие от сырых сокетов IPv4 заключается в том, что полные пакеты (то есть пакеты IP6 с расширенными заголовками) не могут быть прочитаны или записаны с использованием API сырых сокетов IP6. Вместо этого для передачи заголовков расширений используются объекты вспомогательных данных, как описано выше.

Все поля в заголовке IP6, которые приложение может захотеть изменить (то есть все, кроме номера версии), могут быть изменены приложением для вывода с помощью вспомогательных данных и/или параметров сокета. Все поля в полученном заголовке IP6 (кроме полей номера версии и следующего заголовка) и все заголовки расширений также становятся доступными для приложения в качестве вспомогательных данных при вводе. Следовательно, нет необходимости в опции сокета, аналогичной опции сокета IPv4 IP_HDRINCL.

При записи в сырой сокет менеджер сокетов автоматически фрагментирует пакет, если размер превышает MTU пути, вставляя необходимые заголовки фрагментации. При вводе менеджер сокетов повторно собирает полученные фрагменты, поэтому читатель сырого сокета никогда не видит заголовков фрагментов.

Большинство реализаций IPv4 уделяют особое внимание сырому сокету, созданному с помощью третьего аргумента socket() для IPPROTO_RAW, значение которого обычно равно 255. Отметим, что это значение не имеет особого значения для исходного сокета IP6. (и IANA в настоящее время резервирует значение 255 при использовании в качестве поля следующего заголовка).

Для сырых сокетов ICMP6 менеджер сокетов вычисляет и вставляет обязательную контрольную сумму ICMP6.

Для других сырых сокетов IP6 (т.е. для сырых сокетов IP6, созданных с третьим аргументом, отличным от IPPROTO_ICMPV6) приложение должно:

  1. Установить новую опцию сокета IPV6_CHECKSUM, чтобы менеджер сокетов вычислял и сохранял контрольную сумму псевдозаголовка для вывода.
  2. Проверить полученную контрольную сумму псевдозаголовка на входе, отбросив пакет, если контрольная сумма ошибочна.

Этот параметр предотвращает необходимость выбора приложениями адреса источника для отправляемых ими пакетов. Контрольная сумма включает в себя псевдозаголовок IP6, определенный в разделе 8.1 RFC 2460. Эта новая опция сокета также определяет целочисленное смещение в пользовательских данных того места, где находится контрольная сумма.

int offset = 2;
setsockopt( fd, IPPROTO_IPV6, IPV6_CHECKSUM, &offset, sizeof( offset ) );

По умолчанию эта опция сокета отключена. Установка смещения на -1 также отключает эту опцию. Отключено означает:

  1. Менеджер сокетов не будет вычислять и сохранять контрольную сумму для исходящих пакетов.
  2. Ядро менеджера сокетов не проверяет контрольную сумму полученных пакетов.


Note:
  • Поскольку контрольная сумма всегда вычисляется менеджером сокетов для сокета ICMP6, приложения не могут генерировать пакеты ICMPv6 с неверными контрольными суммами (предположительно для целей тестирования) с помощью этого API.
  • Объект/параметр IPV6_NEXTHOP реализован не полностью.

Тематические ссылки:

getsockopt(), ICMP6 протокол, INET6 протокол, recv(), send(), setsockopt()

Основано на RFC 2553, RFC 2292, RFC 2460




Предыдущий раздел: Описание API сетевой библиотеки