В данной главе описывается создание символьных сокетов, а также операции ввода и вывода с этими сокетами. Далее приводятся версии программ ping
и traceroute
, работающие как с версией IPv4, так и с версией IPv6.
28.2. Создание символьных сокетов
При создании символьных сокетов выполняются следующие шаги:
1. Символьный сокет создается функцией socket
со вторым аргументом SOCK_RAW
. Третий аргумент (протокол) обычно ненулевой. Например, для создания символьного сокета IPv4 следует написать:
int sockfd;
sockfd = socket(AF_INET, SOCK_RAW, protocol );
где protocol
— одна из констант IPPROTO_xxx
, определенных в подключенном заголовочном файле , например IPPROTO_ICMP
.
Только привилегированный пользователь может создать символьный сокет. Такой подход предотвращает отправку IP-дейтаграмм в сеть обычными пользователями.
2. Параметр сокета IP_HDRINCL
может быть установлен следующим образом:
const int on = 1;
if (setsockopt(sockfd, IPPROTO_IP, IP_HDRINCL, &on, sizeof(on))
обработка ошибки
В следующем разделе описывается действие этого параметра.
3. На символьном сокете можно вызвать функцию bind
, но это делается редко. Эта функция устанавливает только локальный адрес: на символьном сокете нет понятия порта. Что касается вывода, вызов функции bind
устанавливает IP-адрес отправителя, который будет использоваться для дейтаграмм, отправляемых на символьном сокете (только если не установлен параметр сокета IP_HDRINCL
). Если функция bind
не вызывается, ядро использует в качестве IP-адреса отправителя основной IP-адрес исходящего интерфейса.
4. На символьном сокете можно вызвать функцию connect
, но это делается редко. Эта функция устанавливает только внешний адрес, так как на символьном сокете нет понятия порта. О выводе можно сказать, что вызов функции connect позволяет нам вызвать функцию write
или send
вместо sendto
, поскольку IP-адрес получателя уже определен.
28.3. Вывод на символьном сокете
Вывод на символьном сокете регулируется следующими правилами:
1. Стандартный вывод выполняется путем вызова функции sendto
или sendmsg
и определения IP-адреса получателя. Функции write
, writev
и send
также можно использовать, если сокет был присоединен.
2. Если не установлен параметр сокета IP_HDRINCL
, то начальный адрес данных, предназначенных для записи ядром, указывает на первый байт, следующий за IP-заголовком, поскольку ядро будет строить IP-заголовок и добавлять его к началу данных из процесса. Ядро устанавливает поле протокола создаваемого заголовка IPv4 равным значению третьего аргумента функции socket
.
3. Если параметр сокета IP_HDRINCL
установлен, то начальный адрес данных, предназначенных для записи ядром, указывает на первый байт IP-заголовка. Размер данных для записи должен включать размер IP-заголовка вызывающего процесса. Процесс полностью формирует IP-заголовок, за исключением того, что, во-первых, значение поля идентификации IPv4 может быть нулевым (что указывает ядру на необходимость самостоятельно установить это значение), во-вторых, ядро всегда вычисляет и сохраняет контрольную сумму заголовка IPv4, в-третьих, включает или не включает параметры IP (см. раздел 27.2).
4. Ядро фрагментирует символьные пакеты, превышающие значение MTU исходящего интерфейса.
ПРИМЕЧАНИЕ
Согласно документации, символьные сокеты должны предоставлять протоколу такой же интерфейс, как если бы он был реализован в ядре [74]. К сожалению, это означает, что некоторые части интерфейса зависят от ядра операционной системы. В частности, это относится к порядку байтов полей заголовка IP. В Беркли-ядрах все поля имеют порядок байтов сети, за исключением полей ip_len и ip_off, имеющих порядок байтов узла [128, с. 233, с. 1057]. В системах Linux и OpenBSD все поля имеют порядок байтов сети.
Параметр сокета IP_HDRINCL впервые был представлен в системе 4.3BSD Reno. До этого приложение имело единственную возможность определить свой собственный IP- заголовок в пакетах, отсылаемых на символьный сокет, — использовать заплату ядра (kernel patch), которая была представлена в 1988 году Ван Якобсоном (Van Jacobson) для поддержки программы traceroute. Эта заплата позволяла приложению создавать символьный IP-сокет, определяя протокол как IPPROTO_RAW, что соответствовало значению 255 (это значение является зарезервированным и никогда не должно появляться в поле протокола IP-заголовка).
Читать дальше
Конец ознакомительного отрывка
Купить книгу