Welcome to Энциклопедия сетевых протоколов
Поиск

Модули
· Титульная страница
· Мир протоколов
· Основные темы
· Архив публикаций
· Поиск
· Каталог ссылок
· Участники
· Документы и программы

Выбор языка
Язык интерфейса:


Статистика
20490562
запросов с 22 сентября 2005

Внешняя статистика
Rambler's Top100

  
Обзоры: Реализация протокола IP в Linux
Опубликовано 03 окт. 2005 (Пн.) в 17:47:34
Тема: Реализации протоколов

Реализация протокола IP в Linux

В ядре Linux реализована поддержка протокола IP версии 4 в соответствии с требованиями RFC791 и RFC1122. Реализация IP в ядре Linux включает поддержку групповой маршрутизации уровня 2 в соответствии с RFC1112. Кроме того, ядро Linux обеспечивает маршрутизацию трафика IP с возможностью фильтрации пакетов.



Интерфейс API совместим с интерфейсом сокетов BSD. IP-сокеты создается путем вызова функции

socket(PF_INET, socket_type, protocol).

Параметр socket_type задает тип создаваемого сокета - SOCK_STREAM открывает сокет tcp (приложение на стр. ), SOCK_DGRAM - сокет udp (приложение на стр. ), а SOCK_RAW – сокет raw (приложение на стр. ). Параметр protocol задает тип протокола IP, указываемый в заголовке пакета IP. Этот параметр может принимать значение 0 или IPPROTO_TCP для сокетов TCP, 0 или IPPROTO_UDP для сокетов UDP. Для SOCK_RAW можно указывать любой зарегистрированный протокол IP.

Если процесс планирует принимать входящие пакеты или соединения, он должен связать созданный сокет с адресом локального интерфейса, используя функцию bind. С каждой локальной парой адрес-порт может быть связан только один сокет IP. Если при вызове функции bind указать параметр INADDR_ANY, сокет будет связан со всеми локальными интерфейсами. При вызове функций listen или connect для несвязанного сокета, такой сокет будет автоматически привязан к случайно выбранному свободному порту, а в качестве локального адреса будет использован INADDR_ANY.

Адрес локального сокета TCP, который был связан, в течение некоторого времени после закрытия сокета остается недоступным, если не был установлен флаг SO_REUSEADDR. Следует проявлять

Адресация сокетов IP

Адресация сокетов IP обеспечивается парами “адрес IP - номер порта”. Протокол IP, как таковой, не связан с номерами портов, но эти номера используются протоколами вышележащих уровней типа UDP и TCP. Для сокетов типа raw поле sin_port указывает на протокол IP.

struct sockaddr_in {

sa_family_t sin_family; /* семейство адресов: AF_INET */

u_int16_t sin_port; /* номер порта */

struct in_addr sin_addr; /* адрес IP */

};


/* адрес IP */

struct in_addr {

u_int32_t s_addr; /* адрес */

};

Значение поля sin_family всегда должно быть равно AF_INET. Большинство сетевых функций ядра Linux 2.2 будет возвращать код ошибки EINVAL, если это поле опущено. Переменная sin_port содержит номер порта, используемого сокетом. Номера портов менее 1024 зарезервированы и такие порты часто называют привилегированными. Связывать сокеты с привилегированными портами могут только процессы, выполняющиеся от имени пользователя с UID=0, или процессы с флагом возможности CAP_NET_BIND_SERVICE.

Поле sin_addr содержит IP-адрес хоста как структуру с единственным полем s_addr, содержащим адрес хоста, заданный в формате network byte order. Для работы со структурами in_addr следует использовать библиотечные функции inet_aton, inet_addr, inet_makeaddr или функцию прямой трансляции имен gethostbyname. Адреса IPv4 делятся на индивидуальные (unicast), групповые (multicast) и широковещательные (broadcast). Unicast-адрес задает один интерфейс хоста, групповой адрес – множество интерфейсов (группу), а широковещательный адрес указывают на все хосты сети (подсети). Дейтаграммы с широковещательным адресом получателя можно принимать или передавать только при наличии у сокета флага SO_BROADCAST. В текущей реализации протокола для сокетов, работающих на основе явных соединений, можно использовать только индивидуальную адресацию.

Подчеркнем еще раз что все параметры, содержащие адреса и номера портов используют так называемый сетевой формат (big-endian или network byte order). Все функции стандартной библиотеки, работающие с сетевыми адресами и номерами портов, принимают параметры в сетевом формате. Для преобразования числа в сетевой формат служит системная функция htons.

Некоторые адреса IP зарезервированы для определенных целей: INADDR_LOOPBACK (127.0.0.1) всегда используется для петлевого (loopback) интерфейса локального хоста; INADDR_ANY (0.0.0.0) обозначает все адреса для привязки сокета; INADDR_BROADCAST (255.255.255.255) обозначает любой хост и в силу сложившейся традиции, также используется для связывания сокета со всеми адресами хоста.

Опции сокета IP

Для сокетов IP поддерживается специфических набор опций, которые можно устанавливать с помощью функции setsockopt и считывать с помощью getsockopt. Параметр "уровень опции сокета" этих функций равен SOL_IP. Для логических переменных 0 соответствует значению FALSE, все остальные числа – значению TRUE.

Таблица 1 Опции сокетов IP (SOL_IP)

Опция

Описание

IP_OPTIONS

Устанавливает или возвращает опции IP для пакетов, передаваемых через данный сокет. Аргументами служат указатель на буфер опций в памяти и размер поля опций. Опции для сокета устанавливаются с помощью функции setsockopt. Для IPv4 максимальный размер опций составляет 40 байтов. Описание опций IP вы сможете найти в RFC 791. Если пакет запроса на соединение типа SOCK_STREAM содержит опции IP, такие же опции (с обращенными заголовками маршрутизации) будут использоваться для созданного по запросу сокета. Не допускается изменение опций входящих пакетов после организации соединения. По умолчанию обработка опций source routing из входящих пакетов отключена и включить ее можно с помощью параметра accept_source_route (sysctl). Остальные опции таких пакетов обрабатываются как обычно. Для сокетов дейтаграмм опции IP может устанавливать только локальный пользователь. Вызов функции getsockopt с аргументом IP_OPTIONS помещает заданные опцией аргументы в заголовок IP передаваемого пакета.

IP_PKTINFO

Передает служебное сообщение IP_PKTINFO, содержащее структуру pktinfo с информацией о входящем пакете. Эта опция применима только к сокетам дейтаграмм. Аргументом служит флаг, который говорит сокету нужно ли передавать сообщение IP_PKTINFO. Само сообщение может быть передано или принято только в качестве управляющего (вместе с пакетом) с помощью функции recvmsg или sendmsg.

struct in_pktinfo {

unsigned int ipi_ifindex; /* индекс интерфейса */

struct in_addr ipi_spec_dst; /* локальный адрес */

struct in_addr ipi_addr; /* адрес получателя из заголовка */

};

ipi_ifindex – уникальный интдекс интерфейса, через который принят пакет; ipi_spec_dst – локальный адрес пакета; ipi_addr – адрес получателя в заголовке пакет. Если IP_PKTINFO передается функции sendmsg, исходящий пакет будет передан через интерфейс, заданный параметром ipi_ifindex по адресу, указанному в ipi_spec_dst.

IP_RECVTOS

Управляет передачей служебных сообщений IP_TOS со входящими пакетами. Управляющие сообщения содержат поле Type of Service/Precedence, определяющие соответствующие поля заголовка пакетов.

IP_RECVTTL

При установке этого флага передается управляющее сообщение IP_RECVTTL с полем времени жизни из принятого пакета. Эта опция не поддерживается для сокетом SOCK_STREAM.

IP_RECVOPTS

Передает пользователю все опции IP из входящего пакета как управляющее сообщение IP_OPTIONS. Заголовок маршрутизации и другие опции уже установлены для локального хоста. Эта опция не поддерживается для сокетов SOCK_STREAM.

IP_RETOPTS

Идентична IP_RECVOPTS, но возвращает необработанные опции с пустой временной меткой и маршрутной записью для данного хопа.

IP_TOS

Устанавливает или определяет значение поля TOS (Type-Of-Service) для каждого пакета IP, передаваемого данным сокетом. Поле типа обслуживания может использоваться для приоритизации пакетов. Поле TOS занимает 1 байт. Определены следующие флаги TOS:

IPTOS_LOWDELAY – для минимизации задержки интерактивного трафика;

IPTOS_THROUGHPUT – для оптимизации пропускной способности;

IPTOS_RELIABILITY – для оптимизации надежности доставки;

IPTOS_MINCOST – малозначимые данные, которые могут передаваться в последнюю очередь.

В поле TOS может быть указано не более одного из перечисленных значений. Все остальные биты поля не используются и должны быть сброшены. Linux по умолчанию передает дейтаграммы IPTOS_LOWDELAY первыми, но порядок обработки может быть изменен дисциплинами очередей. Некоторые уровни с высоким приоритетом могут потребовать запуска процессов от имени пользователя с UID=0 или наличия флага возможностей CAP_NET_ADMIN. Уровень приоритета можно установить независимо от протокола с помощью опции сокета SO_PRIORITY.

IP_TTL

Устанавливает или определяет значение поля TTL для каждого пакета, передаваемого с использованием данного сокета.

IP_HDRINCL

Установленный флаг означает, что пользователь уже добавил заголовок IP перед своими данными. Опцию допустимо использовать только с сокетами SOCK_RAW. При установке этого флага значения опций IP_OPTIONS, IP_TTL и IP_TOS игнорируются.

IP_RECVERR

Включает расширенные средства передачи сообщений об ошибках с повышением гарантии их доставки. При использовании с сокетами дейтаграмм все сгенерированные сообщения об ошибках будут помещаться в специальную очередь данного сокета. Когда возникает ошибка при пользовательской операции с сокетом, сообщение об этой ошибке можно получить с помощью функции recvmsg с установленным флагом MSG_ERRQUEUE. Описывающая ошибку структура sock_extended_err будет возвращена в служебном сообщении с типом IP_RECVERR и уровнем SOL_IP. Такая возможность весьма полезна для надежной обработки ошибок в неподключенных сокетах. Данные служебного сообщения, получаемого из очереди, содержат ошибочный пакет.

Структура sock_extended_err определена как:

#define SO_EE_ORIGIN_NONE 0

#define SO_EE_ORIGIN_LOCAL 1

#define SO_EE_ORIGIN_ICMP 2

#define SO_EE_ORIGIN_ICMP6 3


struct sock_extended_err {

u_int32_t ee_errno; /* код ошибки */

u_int8_t ee_origin; /* код источника ошибки */

u_int8_t ee_type; /* тип ICMP */

u_int8_t ee_code; /* лщв ICMP */

u_int8_t ee_pad;

u_int32_t ee_info; /* дополнительная информация */

u_int32_t ee_data; /* прочие данные */

/* Структура может включать дополнительные поля данных */

};


struct sockaddr *SO_EE_OFFENDER(struct sock_extended_err *);

Макрос SO_EE_OFFENDER возвращает указатель на адрес сетевого объекта, с которым связана ошибка, на основании принятого указателя на служебное сообщение. Если адрес неизвестен, поле sa_family структуры sockaddr содержит значение AF_UNSPEC, а остальные поля sockaddr не определены.

IP использует структуру sock_extended_err следующим образом: в поле ee_origin устанавливается значение SO_EE_ORIGIN_ICMP для сообщений об ошибках, полученных в пакетах ICMP, и SO_EE_ORIGIN_LOCAL для локально сгенерированных сообщений. Неизвестные значения следует игнорировать. Поля ee_type и ee_code устанавливаются из соответствующих полей заголовка ICMP. Для сообщений EMSGSIZE поле ee_info содержит определенное значение MTU.

Сообщение включает также значение sockaddr_in вызвавшего ошибку узла, к которому можно обратиться с помощью макроса SO_EE_OFFENDER. Поле sin_family, возвращенное макросом SO_EE_OFFENDER. Содержит значение AF_UNSPEC, если источник ошибки неизвестен. Если ошибка произошла в сети, все опции IP (IP_OPTIONS, IP_TTL и т. д.), поддерживаемые сокетом и содержащиеся в связанном с ошибкой пакете, передаются как управляющее сообщение. Данные из вызвавшего ошибку пакета возвращаются как обычные данные. Отметим, что протокол TCP не использует очереди ошибок и флаг MSG_ERRQUEUE недопустим для сокетов SOCK_STREAM. Таким образом, функции сокета всегда возвращают результат или код ошибки SO_ERROR.

Для сокетов raw опция IP_RECVERR разрешает передачу всех полученных ICMP-сообщений об ошибках приложению. При выключенной опции сообщения об ошибках выдаются только для подключенных сокетов.

По умолчанию опция IP_RECVERR отключена.

IP_PMTU_DISCOVER

Устанавливает или определяет значение Path MTU Discovery для сокета. При включенной опции Linux будет выполнять для сокета операции Path MTU Discovery в соответствии с RFC 1191. Для всех исходящих пакетов будет устанавливаться флаг запрета фрагментирования. По умолчанию режим определения MTU для сокетов SOCK_STREAM задается параметром ip_no_pmtu_disc (sysctl), а для всех остальных протоколов отключена. Для сокетов, не относящихся к типу SOCK_STREAM, пользователь отвечает за размер передаваемых пакетов и их повторную передачу при необходимости. Если данный флаг установлен, ядро будет отбрасывать пакеты, размер которых превышает известное для пути передачи значение MTU, возвращая код ошибки EMSGSIZE. Определены следующие значения флагов Path MTU Discovery

IP_PMTUDISC_WANT Использовать помаршрутные установки

IP_PMTUDISC_DONT Никогда не выполнять Path MTU Discovery.

IP_PMTUDISC_DO Всегда выполнять операции Path MTU Discovery.

При включенном определении MTU ядро автоматически отслеживает значение MTU для получателей пакетов. При подключении к заданному хосту с помощью функции connect известное в данный момент значение MTU можно определить с помощью опции сокета IP_MTU (например, после получения сообщения об ошибке EMSGSIZE). Значение MTU может изменяться в процессе работы. Для сокетов, не организующих явных соединений и работающих с множеством адресатов, новое значение MTU для конкретного адресата можно получить с использованием очереди ошибок (см. описание опции IP_RECVERR на стр. 5). Сообщение об ошибке будет помещаться в очередь при каждом входящем обновлении MTU.

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

Чтобы инициировать процесс определения MTU для неподключенных сокетов, можно начать с передачи дейтаграмм большого размера (с заголовком до 64K) и впоследствии изменить значение в соответствии с обновлениями path MTU.

Для начальной оценки MTU соедините сокет дейтаграмм с адресатом, используя функцию connect и определите значение MTU путем вызова функции getsockopt с опцией IP_MTU.

IP_MTU

Определяет текущее значение path MTU для данного сокета. Опция корректна только для соединенных сокетов и может использоваться только с функцией getsockopt.

IP_ROUTER_ALERT

Передает данному сокету все пакеты, которые должны пересылаться с установленным флагом IP Router Alert. Опция может использоваться только для raw-сокетов. Этот флаг может быть полезен, например, для демонов RSVP, работающих в пользовательском пространстве. Перехваченные пакеты не будут пересылаться ядром и пользовательское приложение должно принять на себя ответственность за их дальнейшую пересылку. Привязка сокета не принимается во внимание и пакеты фильтруются только протоколом.

IP_MULTICAST_TTL

Устанавливает или определяет значение поля TTL для исходящих от данного сокета пакетов с групповыми адресами. Для групповых пакетов важно установить минимально возможное значение времени жизни. По умолчанию TTL=1 и пакеты с групповыми адресами не будут покидать локальную сеть, пока пользовательская программа явно не запросит иного.

IP_MULTICAST_LOOP

Устанавливает или определяет логическое значение флага возврата multicast-пакетов локальным сокетам.

IP_ADD_MEMBERSHIP

Присоединяет сокет к multicast-группе. Аргументом опции служит структура structip_mreqn

struct ip_mreqn {

struct in_addr imr_multiaddr; /* IP-адрес multicast-группы */

struct in_addr imr_address; /* IP-адрес локального интерфейса */

int imr_ifindex; /* индекс интерфеса */

};

Поле imr_multiaddr задает корректный multicast-адрес группы, к которой присоединяется сокет, а in_addr – адрес локального интерфейса, через который осуществляется подключение к группе. Поле imr_ifindex содержит индекс интерфейса, который должен быть добавлен/удален в группу, или 0 для индикации любого интерфейса.

Для обеспечения обратной совместимости поддерживаются также старые структуры ip_mreq, отличающиеся только отсутствием поля imr_ifindex.

Опция применима только с функцией setsockopt.

IP_DROP_MEMBERSHIP

Удаляет сокет из multicast-группы. В качестве аргумента может использоваться структура ip_mreqn или ip_mreq, описанная в предыдущей опции.

IP_MULTICAST_IF

Задает локальное устройство для группового (multicast) сокета. В качестве аргумента передается структура ip_mreqn или ip_mreq, описанная выше (опция IP_ADD_MEMBERSHIP).

При передаче сокету некорректной опции возвращается значение ENOPROTOOPT.

Параметры SysCtl

Протокол IP использует интерфейс SysCtl для контроля и настройки ряда глобальных опций. Описание параметров SysCtl для протокола IP приведено в Приложении .

Операции IOCTL

Все операции IOCTL для протокола socket применимы и для протокола IP. Операции IOCTL для настройки межсетевых экранов описаны в руководствах соответствующих программ (ipfw, ipchains, iptables).

Коды ошибок

Таблица 2 Коды ошибок протокола IP

Код

Описание

ENOTCONN

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

EINVAL

Передан недопустимый аргумент. Для передачи пакетов такая ошибка может быть связана с адресацией пакета в “черную дыру” (blackhole route).

EMSGSIZE

Размер дейтаграммы, которую запрещено фрагментировать, превышает значение MTU.

EACCES

Попытка выполнения пользователем недозволенной операции. К таким операциям относятся: передача пакетов по широковещательному адресу при отсутствии флага SO_BROADCAST, передача пакетов через запрещенный маршрут, попытка изменения настроек межсетевого экрана без флага возможностей CAP_NET_ADMIN или эффективного идентификатора UID=0, связывание сокета с зарезервированным портом при отсутствии флага возможностей CAP_NET_BIND_SERVICE и эффективном значении UID<>0.

EADDRINUSE

Попытка связать сокет с используемым адресом.

ENOPROTOOPT

Передана некорректная опция.

EOPNOTSUPP

Передана некорректная опция.

EPERM

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

EADDRNOTAVAIL

Запрошен несуществующий интерфейс или указан нелокальный адрес отправителя.

EAGAIN

Операция над неблокируемым сокетом, требующая блокировки.

ESOCKTNOSUPPORT

Запрошен неизвестный тип сокета или конфигурация сокета не настроена.

EISCONN

Для сокета, уже установившего соединение, вызвана функция connect.

EALREADY

Операция соединения для неблокируемого сокета уже выполняется.

ECONNABORTED

Соединение было закрыто в период работы функции accept.

EPIPE

Соединение неожиданно закрылось или было разорвано удаленной стороной.

ENOENT

Вызов SIOCGSTAMP для сокета, который еще не получил ни одного пакета.

EHOSTUNREACH

В таблице маршрутизации нет корректной записи для адресата. Причиной может послужить сообщение ICMP от удаленного маршрутизатора или состояние локальной таблицы маршрутов.

ENODEV

Сетевое устройство недоступно или не может передавать пакеты IP.

ENOPKG

Не настроена поддержка IP в ядре Linux.

ENOBUFS

Недостаточно свободной памяти. Это сообщение вызвано ограниченным размером буфера сокетов или нехваткой оперативной памяти в системе.

ENOMEM

Недостаточно свободной памяти. Это сообщение вызвано ограниченным размером буфера сокетов или нехваткой оперативной памяти в системе.

Протоколы вышележащих уровней TCP, raw, UDP и socket могут добавлять свои сообщения об ошибках.

Известные проблемы

  1. Слишком много противоречивых кодов ошибок.

  2. Не описаны операции IOCTL для настройки IP-опций интерфейсов и таблиц ARP.

  3. Некоторые версии glibc не включают описание структуры in_pktinfo. Вы можете просто скопировать это описание в glibc.

Копии этих спецификаций вы сможете найти в каталоге Documents/ приложенного к книге компакт-диска или загрузить с сайта http://rfc-editor.org/rfc/. На сайте protocols.ru имеются переводы спецификаций на русский язык.

Список зарегистрированных протоколов можно посмотреть в RFC 1700, копия которого имеется на диске. Однако этот документ изрядно устарел и более не будет обновляться, поэтому лучше обращаться к списку зарегистрированных протоколов на сайте http://www.iana.org/assignments/protocol-numbers

Этот флаг следует использовать с осторожностью, поскольку он снижает уровень надежности TCP.

Номера портов и адреса представляются в формате big-endian или network byte order, когда первым указывается (передается) наиболее значимый (старший) байт

См. примечание 4.

Документ можно загрузить с сайта http://rfc-editor.org/rfc/rfc791.txt, его копия имеется в каталоге Documents/ приложенного к книге компакт-диска. На сайте https://protocols.ru имеется перевод спецификации на русский язык.

Некоторые реализации сокетов BSD в других ОС используют опции сокета IP_RCVDSTADDR и IP_RECVIF для определения адреса получателя и физического интерфейса. Linux использует для решения таких задач опцию IP_PKTINFO.

Опция объявлена в заголовочном файле linux/errqueue.h

Копию RFC 1191 вы можете найти в каталоге Documents/ приложенного к книге компакт-диска или загрузить с сайта rfc-editor.org/rfc/rfc1191.txt. Перевод документа на русский язык имеется на сайте protocols.ru.

Если это поле содержит значение INADDR_ANY, система выбирает интерфейс, подходящий для соединения с группой.


 
Вход
Регистрационное имя

Пароль

[Восстановить пароль]

Если у Вас еще нет учетной записи, Вы можете зарегистрироваться.


Связанные ссылки
· Поиск в разделе Реализации протоколов
· Статьи пользователя Николай Малых


Самая популярная статья раздела Реализации протоколов:
RAW-сокеты в Linux


Оценка статьи
Средняя оценка: 5
голос.: 3


Оцените эту публикацию:

Отлично
Очень хорошо
Хорошо
Приемлемо
Плохо


Параметры

 Вариант для печати Вариант для печати


Связанные темы

Настройка сетевых параметров хостовВопросы безопасностиВопросы маршрутизации

"Вход" | Вход/регистрация | 0 коммент.
Комментарии выражают мнение их авторов. Администрация сайта не несет никакой ответственности за достоверность представленных в комментариях посетителей сведений, а также за содержание таких комментариев.

Для публикации своих комментариев Вам нужно зарегистрироваться..
Copyright © Nikolai Malykh
Все права на опубликованные на сайте материалы принадлежат Nikolai Malykh, если в опубликованном на сайте документе явно не указано иное.
Не разрешается воспроизведение опубликованных на сайте документов без согласия правообладателя.

Hosted By Web Hosting by iPage

Copyright © 2005 by Nikolai Malykh
Based on PHP-Nuke by Francisco Burzi. This is free software, and you may redistribute it under the GPL. Author comes with absolutely no warranty.
Время генерации страницы: 0.15 сек.