Где команда ping в Linux получает свой счетчик идентификаторов?

Вопрос или проблема

Я заметил, что ping (iputils) увеличивает счетчик ICMP id каждый раз, когда он выполняется. Я попытался взглянуть на исходный код ping и быстро его просмотрел, но не нашел счетчика. Насколько я знаю, ping не запускает никаких демонов или другого глобального состояния системы, так что сам ядро Linux ведет учет этого счетчика?

% ping -c 3 127.0.0.1
PING 127.0.0.1 (127.0.0.1) 56(84) байт данных.
64 байта от 127.0.0.1: icmp_seq=1 ttl=64 время=0.039 мс
64 байта от 127.0.0.1: icmp_seq=2 ttl=64 время=0.039 мс
64 байта от 127.0.0.1: icmp_seq=3 ttl=64 время=0.033 мс

Tshark (id=0x0043):

14267 196372.989831489    127.0.0.1 → 127.0.0.1    ICMP 98 Запрос эха (ping)  id=0x0043, seq=1/256, ttl=64
14268 196372.989843064    127.0.0.1 → 127.0.0.1    ICMP 98 Ответ эха (ping)    id=0x0043, seq=1/256, ttl=64 (запрос в 14267)
14269 196374.001333266    127.0.0.1 → 127.0.0.1    ICMP 98 Запрос эха (ping)  id=0x0043, seq=2/512, ttl=64
14270 196374.001345051    127.0.0.1 → 127.0.0.1    ICMP 98 Ответ эха (ping)    id=0x0043, seq=2/512, ttl=64 (запрос в 14269)
14271 196375.014707417    127.0.0.1 → 127.0.0.1    ICMP 98 Запрос эха (ping)  id=0x0043, seq=3/768, ttl=64
14272 196375.014717838    127.0.0.1 → 127.0.0.1    ICMP 98 Ответ эха (ping)    id=0x0043, seq=3/768, ttl=64 (запрос в 14271)

Ping снова:

% ping -c 3 127.0.0.1
PING 127.0.0.1 (127.0.0.1) 56(84) байт данных.
64 байта от 127.0.0.1: icmp_seq=1 ttl=64 время=0.047 мс
64 байта от 127.0.0.1: icmp_seq=2 ttl=64 время=0.062 мс
64 байта от 127.0.0.1: icmp_seq=3 ttl=64 время=0.037 мс

Tshark (id=0x0044):

14273 196381.959906106    127.0.0.1 → 127.0.0.1    ICMP 98 Запрос эха (ping)  id=0x0044, seq=1/256, ttl=64
14274 196381.959921324    127.0.0.1 → 127.0.0.1    ICMP 98 Ответ эха (ping)    id=0x0044, seq=1/256, ttl=64 (запрос в 14273)
14275 196382.961393309    127.0.0.1 → 127.0.0.1    ICMP 98 Запрос эха (ping)  id=0x0044, seq=2/512, ttl=64
14276 196382.961404803    127.0.0.1 → 127.0.0.1    ICMP 98 Ответ эха (ping)    id=0x0044, seq=2/512, ttl=64 (запрос в 14275)
14277 196383.974709944    127.0.0.1 → 127.0.0.1    ICMP 98 Запрос эха (ping)  id=0x0044, seq=3/768, ttl=64
14278 196383.974722217    127.0.0.1 → 127.0.0.1    ICMP 98 Ответ эха (ping)    id=0x0044, seq=3/768, ttl=64 (запрос в 14277)

Идентификатор в icmp аналогичен исходному порту сеанса. Для сокета SOCK_DGRAM его идентификатор выбирается ядром (обычно это число с автоинкрементом), смотрите тут: https://github.com/torvalds/linux/blob/850925a8133c73c4a2453c360b2c3beb3bab67c9/net/ipv4/ping.c#L103C4-L103C37

Для SOCK_RAW (для ping -e) это младший байт идентификатора процесса, смотрите тут: https://github.com/iputils/iputils/blob/aeb124025c9d802ea2a00842dca4c7db66b780bb/ping/ping_common.c#L550

Ответ или решение

Откуда ping в Linux получает свой идентификатор?

Команда ping в операционной системе Linux используется для отправки ICMP (Internet Control Message Protocol) Echo-запросов, что позволяет проверять связь с удалёнными узлами. Однако, не всегда очевидно, как формируется идентификатор (ID) ICMP-пакетов при выполнении команды ping. В данном ответе мы подробно рассмотрим, как и откуда ping получает этот идентификатор.

Анализ кода ping

Как было замечено, каждый раз при выполнении команды ping, идентификатор пакета ICMP увеличивается. Это связано с тем, что Linux использует специфический механизм для назначения этого идентификатора. Код, отвечающий за присвоение идентификатора, можно найти в репозитории iputils, который содержит исходники команды ping.

  1. Сокеты и идентификаторы

    Команда ping может использовать разные типы сокетов, включая SOCK_DGRAM и SOCK_RAW. Для SOCK_DGRAM сокетов идентификатор, как правило, автоматически инкрементируется и назначается ядром. Это значит, что в процессе выполнения команды, ядро отслеживает последний использованный идентификатор и выдает следующий доступный.

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

  2. Идентификатор и PID

    При использовании SOCK_RAW, который предоставляет больше контроля над содержимым пакетов, идентификатор формируется на основе PID (идентификатора процесса) программы. Конкретно, используется низкий байт PID процесса, который отправляет запросы ping. Это поведение можно увидеть в исходном коде ping.

Важно знать

Каждый раз, когда вы запускаете команду ping, создаётся новый процесс, что приводит к генерации нового PID. В результате идентификатор ICMP может варьироваться от одного запуска к другому, если процесс ping используется с SOCK_RAW. Однако, если вы используете SOCK_DGRAM, идентификатор будет инкрементироваться от предыдущего значения.

Заключение

Таким образом, ping в Linux увеличивает ICMP идентификатор, основываясь на механизме управления идентификаторами в ядре Linux, где для сокетов SOCK_DGRAM идентификатор назначается автоматически и увеличивается, а для SOCK_RAW используется PID процесса. Этот подход обеспечивает уникальность идентификаторов для различных сеансов связи и помогает различать разные запросы и ответы, что крайне важно для корректной работы сетевых утилит.

Если у вас остались вопросы или хотите узнать больше о функциональности команды ping, не стесняйтесь обращаться!

Оцените материал
Добавить комментарий

Капча загружается...