IP

Интернет-протокол

Прототип:

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

Описание:

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

Существует множество опций IP-уровня setsockopt() и getsockopt(). Можно использовать IP_OPTIONS для предоставления параметров IP, которые должны передаваться в IP-заголовке каждого исходящего пакета, или для проверки параметров заголовка для входящих пакетов. Параметры IP могут использоваться с любым типом сокета в семействе Internet. Формат передаваемых параметров IP соответствует формату, указанному в спецификации протокола IP (RFC 791), с одним исключением: список адресов для параметров исходного маршрута должен включать шлюз первого перехода в начале списка шлюзов. Адрес шлюза первого перехода извлекается из списка опций, и его размер соответствующим образом корректируется перед использованием. Чтобы отключить ранее указанные параметры, следует использовать буфер нулевой длины:

setsockopt( s, IPPROTO_IP, IP_OPTIONS, NULL, 0 );

Можно использовать IP_TOS и IP_TTL для установки полей типа обслуживания и "времени жизни" в IP-заголовке для сокетов SOCK_STREAM и SOCK_DGRAM. Например:

int tos = IPTOS_LOWDELAY; /* см. <netinet/ip.h> */
setsockopt( s, IPPROTO_IP, IP_TOS, &tos, sizeof( tos ) );
int ttl = 60; /* max = 255 */
setsockopt( s, IPPROTO_IP, IP_TTL, &ttl, sizeof( ttl ) );

Если опция IP_RECVDSTADDR включена на сокете SOCK_DGRAM или SOCK_RAW, вызов recvmsg() вернет адрес назначения для датаграммы UDP. Поле msg_control структуры msghdr указывает на буфер, содержащий структуру cmsghdr, за которой следует IP адрес. Поля cmsghdr имеют следующие значения:

cmsg_len = sizeof( struct cmsghdr ) + sizeof( struct in_addr )
cmsg_level = IPPROTO_IP
cmsg_type = IP_RECVDSTADDR

Если опция IP_RECVIF включена на сокете SOCK_DGRAM или SOCK_RAW, вызов recvmsg() возвращает структуру sockaddr_dl соответствующий интерфейсу, на котором был получен пакет. Поле msg_control в структуре msghdr указывает на буфер, который содержит структуру cmsghdr, за которой следует структура sockaddr_dl. Поля cmsghdr имеют следующие значения:

cmsg_len = sizeof( struct cmsghdr ) + sizeof( struct sockaddr_dl )
cmsg_level = IPPROTO_IP
cmsg_type = IP_RECVIF

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

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

К исходящим пакетам автоматически добавляется IP-заголовок (на основе адреса назначения и номера протокола, с которым создается сокет), если не была установлена опция IP_HDRINCL. Входящие пакеты принимаются без изменений IP-заголовка и параметров.

IP_HDRINCL указывает, что полный заголовок IP включен в данные и может использоваться только с типом SOCK_RAW.

#include <netinet/ip.h>
int hincl = 1; /* 1 = on, 0 = off */
setsockopt( s, IPPROTO_IP, IP_HDRINCL, &hincl, sizeof( hincl ) );

Программа должна установить все поля заголовка IP, включая следующие:

ip->ip_v = IPVERSION;
ip->ip_hl = hlen >> 2;
ip->ip_id = 0; /* 0 означает, что ядро установило соответствующее значение */
ip->ip_off = offset;

Если адрес источника заголовка установлен на INADDR_ANY, ядро выбирает соответствующий адрес.

Многоадресная рассылка

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

Опции многоадресной рассылки

IP_MULTICAST_TTL
Изменить "время жизни" (TTL) для исходящих датаграмм многоадресной рассылки, чтобы контролировать объем многоадресных рассылок:

u_char ttl; /* range: 0 to 255, default = 1 */
setsockopt( s, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof( ttl ) );

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

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

struct in_addr addr;
setsockopt( s, IPPROTO_IP, IP_MULTICAST_IF, &addr, sizeof( addr ) );

где addr - это локальный IP-адрес желаемого интерфейса или INADDR_ANY чтобы указать интерфейс по умолчанию. Можно получить локальный IP-адрес интерфейса и возможность многоадресной рассылки, отправив запросы SIOCGIFCONF и SIOCGIFFLAGS в ioctl(). Обычные приложения не должны использовать эту опцию.

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

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

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

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

struct ip_mreq mreq;
setsockopt( s, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof( mreq ) );

где mreq является следующей структурой:

struct ip_mreq {
struct in_addr imr_multiaddr; /* multicast group to join */
struct in_addr imr_interface; /* interface to join on */
}

Установите imr_interface в значение INADDR_ANY для выбора интерфейса многоадресной рассылки по умолчанию или на IP-адрес конкретного интерфейса с поддержкой многоадресной рассылки, если хост является многосетевым. Членство связано с единым интерфейсом; программам, работающим на многосетевых хостах, может потребоваться присоединение к одной группе на более чем одном интерфейсе. Для одного сокета можно добавить до IP_MAX_MEMBERSHIPS членов (в настоящее время 20).

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

struct ip_mreq mreq;
setsockopt( s, IPPROTO_IP, IP_DROP_MEMBERSHIP, &mreq, sizeof( mreq ) );

где mreq содержит те же значения, которые использовались для добавления членства. Членство сбрасывается при закрытии сокета или выходе из процесса.

Возвращаемое значение:

Дескриптор сокета. Если возникла ошибка функция возвращает -1, код ошибки записывается в errno.

Коды ошибок:

EADDRNOTAVAIL
Произведена попытка создать сокет с сетевым адресом, для которого не существует сетевого интерфейса.
EISCONN
Произведена попытка установить соединение с сокетом, в котором он уже есть, или отправить датаграмму с указанным адресом назначения, но сокет уже подключен.
ENOBUFS
Системе не хватило памяти для внутренней структуры данных.
ENOTCONN
Произведена попытка отправить датаграмму, однако адрес назначения не был указан и сокет не был подключен.


Note: Следующая ошибка, специфичная для IP, может возникнуть при установке или получении параметров IP:

EINVAL
Было указано неизвестное имя параметра сокета. Поле опции IP было неправильно сформировано - поле опции было короче минимального значения или длиннее, чем предоставленный буфер опций.

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

ICMP протокол

connect(), getsockopt(), ioctl(), read(), recv(), recvfrom(), recvmsg(), send(), sendto(), setsockopt(), socket(), write()

Основано на RFC 791




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