raw -
неструктурированные
сокеты IPv4 в Linux
#include <sys/socket.h>
#include <netinet/in.h>
raw_socket = socket(AF_INET, SOCK_RAW, int protocol);
Неструктурированные
(raw) сокеты
позволяют
реализовать
новые
протоколы IPv4
в
пространстве
пользователя.
Через
неструктурированный
сокет
получают
или
посылают
необработанные
датаграммы,
не
включающие
в себя
заголовки
уровня
соединения
(link level).
Уровень IPv4
генерирует
заголовок IP
при
посылке
пакета,
если
только для
сокета не
включён
параметр
IP_HDRINCL. Если он
включён, то
пакет
должен
содержать
заголовок IP.
Принимаемые
пакеты
всегда
содержат
заголовок IP.
Для
создания
неструктурированного
сокета
процесс
должен
иметь
мандат
CAP_NET_RAW в
пользовательском
пространстве
имён,
определяемом
по его
сетевому
пространству
имён.
Все пакеты
или ошибки,
совпадающие
с номером
протокола
protocol,
указанным
неструктурированному
сокету,
передаются
этому
сокету.
Список
допустимых
протоколов
назначается
списком IANA
http://www.iana.org/assignments/protocol-numbers/
и
содержится
в
getprotobyname(3).
Протокол
IPPROTO_RAW
подразумевает
включённый
параметр
IP_HDRINCL и
позволяет
отправлять
любой
протокол IP,
который
указан в
передаваемом
заголовке.
Приём
любых
протоколов
IP
посредством
IPPROTO_RAW через
неструктурированные
сокеты
невозможен.
Поля
заголовка
IP,
изменяемые
IP_HDRINCL при
передаче |
|
контрольная
сумма IP |
всегда
заполняется |
адрес
источника |
заполняется,
если
значение
равно
нулю |
ID пакета |
заполняется,
если
значение
равно
нулю |
общая
длина |
всегда
заполняется |
Если
указан
IP_HDRINCL и
заголовок IP
имеет
ненулевой
адрес
назначения,
то для
маршрутизации
пакета
используется
адрес
назначения
сокета.
Если
указан
MSG_DONTROUTE,
то адрес
назначения
должен
ссылаться
на
локальный
интерфейс,
иначе в
любом
случае
будет
производиться
поиск в
таблице
маршрутизации,
но
маршруты
со шлюзами
будут
игнорироваться.
Если
IP_HDRINCL не
указан, то
параметры
заголовка IP
в
неструктурированных
сокетах
могут быть
установлены
с помощью
setsockopt(2); более
подробная
информация
приведена
в
ip(7).
Начиная с Linux 2.2
все поля
заголовка IP
и
параметры
могут быть
заданы с
помощью
параметров
сокета IP. Это
означает,
что
неструктурированные
сокеты, как
правило,
необходимы
лишь для
новых
протоколов
или
протоколов
без
интерфейса
пользователя
(например, ICMP).
Принятый
пакет
передаётся
всем
подключенным
(bound) к этому
протоколу
неструктурированным
сокетам до
того, как он
будет
передан
другим
обработчикам
протоколов
(например,
протокольным
модулям
ядра).
При
отправке и
приёме
дейтаграмм
(
sendto(2),
recvfrom(2) и similar)
через
неструктурированные
сокеты
используется
стандартная
адресная
структура
sockaddr_in,
определённая
в
ip(7). Поле
sin_port
можно
использовать
для
указания
номера
протокола IP,
но в Linux 2.2 и
новее оно
игнорируется
при
отправке, и
должно
всегда
равняться 0
(смотрите
ДЕФЕКТЫ). У
входящих
пакетов
sin_port
равен нулю.
Параметры
неструктурированных
сокетов
могут быть
установлены
с помощью
setsockopt(2) и
прочитаны
с помощью
getsockopt(2) с
указанием
флага
семейства
IPPROTO_RAW.
- ICMP_FILTER
- Запускает
специальный
фильтр для
неструктурированных
сокетов,
подключенных
к
протоколу
IPPROTO_ICMP.
Значение
представляет
собой
набор бит —
по
установленному
биту для
каждого
типа
сообщений
ICMP, который
должен
быть
отфильтрован.
По
умолчанию
сообщения
ICMP не
фильтруются.
Кроме
этого,
поддерживаются
все
датаграммные
параметры
сокетов
ip(7)
для
IPPROTO_IP.
Ошибки,
возникающие
в сети,
передаются
пользователю
только,
если сокет
подключён
или
установлен
флаг
IP_RECVERR. В
целях
совместимости
в
подключенные
сокеты
передаются
только
EMSGSIZE и
EPROTO. При
указании
IP_RECVERR в
очереди
ошибок
сохраняются
все
сетевые
ошибки.
- EACCES
- Пользователь
попытался
передать
пакет по
широковещательному
адресу без
указания
на сокете
флага
широковещательной
передачи.
- EFAULT
- Указан
неправильный
адрес
памяти.
- EINVAL
- Неверный
аргумент.
- EMSGSIZE
- Размер
пакета
слишком
велик, либо
включён Path MTU
Discovery (флаг
сокета IP_PMTU_DISCOVER),
либо
размер
пакета
превышает
максимально
разрешенный
для IPv4
размер,
равный
64 КБ.
- EOPNOTSUPP
- Сокетному
вызову был
передан
неверный
флаг
(например,
MSG_OOB).
- EPERM
- Пользователь
не имеет
прав на
открытие
неструктурированных
сокетов.
Это могут
делать
только
процессы с
идентификатором
эффективного
пользователя
равным 0,
или
имеющие
мандат CAP_NET_RAW.
- EPROTO
- Получена
ошибка ICMP,
сообщающая
о проблеме
с
параметром.
Значения
IP_RECVERR и
ICMP_FILTER
появились
в Linux 2.2. Они
являются
расширениями
Linux и не
должны
использоваться
в
переносимых
программах.
Код
неструктурированных
сокетов в
версии Linux 2.0
при
установленном
параметре
SO_BSDCOMPAT был
специально
сделан
совместимым
с BSD «вплоть
до ошибок».
Из Linux 2.2 это
было
удалено.
По
умолчанию,
для
неструктурированных
сокетов
выполняется
обнаружение
MTU (Maximum Transmission Unit) пути.
Это
означает,
что ядро
будет
следить за MTU
до IP-адреса
назначения
и
возвращать
EMSGSIZE, если
запись
неструктурированного
пакета
превысит
это
значение.
Когда это
происходит,
приложение
должно
уменьшить
размер
пакета.
Также
обнаружение
MTU пути можно
выключить
с помощью
параметра
сокета
IP_MTU_DISCOVER
или в файле
/proc/sys/net/ipv4/ip_no_pmtu_disc;
подробней
смотрите в
ip(7). При
отключении
обнаружения
неструктурированные
сокеты
фрагментируют
исходящие
пакеты,
размер
которых
превышает MTU
интерфейса.
Однако по
соображениям
производительности
и
надёжности
отключение
не
рекомендуется.
Неструктурированный
сокет
может быть
подключён
к
определённому
локальному
адресу с
помощью
вызова
bind(2).
Если он не
подключён,
то
принимаются
все пакеты
указанного
протокола IP.
Кроме того,
неструктурированный
сокет
может быть
подключён
к
определённому
сетевому
устройству
с помощью
SO_BINDTODEVICE;
смотрите
socket(7).
Сокет
IPPROTO_RAW
предназначен
только для
отправки.
Если вы
хотите
получать
все пакеты IP,
используйте
сокет
packet(7) с
протоколом
ETH_P_IP. Заметим,
что
пакетные
сокеты, в
отличие от
неструктурированных
сокетов, не
собирают
пакеты из
фрагментов
IP.
Если вы
хотите
получать
все пакеты ICMP
для
датаграммного
сокета, то
лучше
использовать
IP_RECVERR на
определённом
сокете;
смотрите
ip(7).
Неструктурированные
сокеты
могут
перехватывать
в Linux все
протоколы IP,
даже
имеющие
протокольный
модуль в
ядре (такие,
как ICMP или TCP). В
этом
случае
пакеты
передаются
как модулю
ядра, так и
неструктурированным
сокетам. На
это нельзя
закладываться
в
переносимых
программах,
так как
многие
другие
реализации
сокетов BSD
так не
делают.
Linux никогда не
изменяет
заголовки,
полученные
от
пользователя
(за
исключением
обнуления
некоторых
полей, как
описано в
случае с
IP_HDRINCL).
Такое
поведение
отличается
от
поведения
многих
других
реализаций
неструктурированных
сокетов.
Неструктурированные
сокеты, в
общем
случае, не
являются
переносимыми,
поэтому
следует
избегать
их
использования
в
переносимых
программах.
Передача
через
неструктурированный
сокет
должна
осуществляться
с помощью
протокола IP
из
sin_port; эта
возможность
исчезла в Linux 2.2.
Метод
обхода —
использовать
IP_HDRINCL.
Не описаны
расширения
прозрачного
прокси.
Если
установлен
параметр
IP_HDRINCL,
датаграммы
не будут
фрагментированы
и их размер
будет
ограничен MTU
интерфейса.
В Linux 2.2
отсутствует
настройка
протокола IP
для
отправки
sin_port — всегда
используется
тот
протокол, к
которому
был
подключён
сокет или
который
был указан
при первом
вызове
socket(2).
recvmsg(2),
sendmsg(2),
capabilities(7),
ip(7),
socket(7)
В
RFC 1191 описан
процесс
обнаружения
маршрута MTU. В
RFC 791 и
заголовочном
файле
<linux/ip.h>
описан
протокол IP.
Русский
перевод
этой
страницы
руководства
был сделан
aereiae <
[email protected]>, Azamat Hackimov
<
[email protected]>, Dmitriy S. Seregin <
[email protected]>,
Katrin Kutepova <
[email protected]>, Lockal
<
[email protected]>, Yuri Kozlov <
[email protected]>,
Баринов
Владимир и
Иван
Павлов <
[email protected]>
Этот
перевод
является
бесплатной
документацией;
прочитайте
Стандартную
общественную
лицензию GNU
версии 3
или более
позднюю,
чтобы
узнать об
условиях
авторского
права. Мы не
несем
НИКАКОЙ
ОТВЕТСТВЕННОСТИ.
Если вы
обнаружите
ошибки в
переводе
этой
страницы
руководства,
пожалуйста,
отправьте
электронное
письмо на
[email protected]