Ответ
Для работы ping без прав суперпользователя необходимо настроить Linux capabilities или параметры ядра, так как ping использует raw sockets для отправки ICMP-пакетов, что по умолчанию требует привилегий.
1. Настройка через Linux Capabilities (предпочтительный метод):
# Устанавливаю CAP_NET_RAW capability на бинарник ping
sudo setcap cap_net_raw+ep /bin/ping
# Проверяю
getcap /bin/ping
# Ожидаемый вывод: /bin/ping = cap_net_raw+ep
Что это дает: Флаг +ep (Effective, Permitted) позволяет процессу ping использовать raw sockets. После этой настройки любой пользователь сможет выполнять ping.
2. Настройка через параметр ядра ping_group_range (Linux 5.7+):
# Разрешаю неограниченному диапазону групп использовать ICMP sockets
echo "net.ipv4.ping_group_range = 0 2147483647" | sudo tee -a /etc/sysctl.conf
# Или для IPv6
echo "net.ipv6.ping_group_range = 0 2147483647" | sudo tee -a /etc/sysctl.conf
# Применяю изменения
sudo sysctl -p
Этот метод позволяет процессам, чей GID находится в указанном диапазоне, создавать ICMP sockets напрямую через системный вызов socket(AF_INET, SOCK_DGRAM, IPPROTO_ICMP), без необходимости в raw sockets.
3. Практическое применение в DevOps: В контейнеризированных средах (Docker/Kubernetes) часто приходится настраивать это для sidecar-контейнеров мониторинга. Например, в Dockerfile:
FROM alpine:latest
RUN apk add --no-cache iputils &&
setcap cap_net_raw+ep /bin/ping
# Теперь контейнер может использовать ping без привилегий
Или в securityContext Pod в Kubernetes:
securityContext:
capabilities:
add: ["NET_RAW"] # Добавляем capability контейнеру
Архитектурный контекст: Когда обычный пользователь запускает ping с CAP_NET_RAW, процесс выполняет системный вызов socket() с типом SOCK_RAW и протоколом IPPROTO_ICMP. Ядро проверяет capabilities процесса (через capable(CAP_NET_RAW)) и, если проверка проходит, создает raw socket, через который процесс может отправлять и принимать ICMP-пакеты напрямую.
Ответ 18+ 🔞
А, ну это же классика, ёпта! Ситуация, когда обычный юзер пытается пингануть, а ему в ответ — «Permission denied». Прямо волнение ебать, как будто он не в консоль зашёл, а в запретный храм какой. А всё потому, что ping по умолчанию лезет в raw sockets, чтобы ICMP-пакеты формировать, а это, блядь, привилегированная операция, как будто ты в ядро стучишься.
Но есть же способы, чтобы не быть полупидором и не бегать с sudo перед каждой командой. Смотри сюда.
1. Способ через Linux Capabilities (самый адекватный, имхо) Вместо того чтобы давать процессу права суперпользователя целиком, можно навесить на сам бинарник нужную «способность». Это как выдать не все ключи от квартиры, а только один — от входной двери.
# Вешаем на ping магическую способность CAP_NET_RAW
sudo setcap cap_net_raw+ep /bin/ping
# Проверяем, прилипла ли способность
getcap /bin/ping
# Должно вывести: /bin/ping = cap_net_raw+ep
Вот этот флаг +ep (Effective, Permitted) — он и говорит ядру: «Э, сабака сука, пусть этот процесс использует raw sockets, доверяем ему». После этого любой чувак в системе сможет пинговать. Красота, да и только.
2. Способ через настройку ядра (ping_group_range)
Это для более новых ядер (5.7+), там появилась фича поинтереснее. Можно разрешить целым группам пользователей работать с ICMP-сокетами напрямую, без всей этой возни с raw sockets.
# Разрешаем всем группам от нуля до какого-то овердохуища
echo "net.ipv4.ping_group_range = 0 2147483647" | sudo tee -a /etc/sysctl.conf
# Для IPv6, если вдруг живёшь в будущем
echo "net.ipv6.ping_group_range = 0 2147483647" | sudo tee -a /etc/sysctl.conf
# Применяем настройки, чтобы ядро прочухало
sudo sysctl -p
Суть в том, что если GID процесса попадает в этот диапазон, то он может создавать ICMP-сокеты через обычный socket() вызов. Это уже не raw socket, а типа «датаграмный» ICMP-сокет. Более цивилизованно, что ли.
3. А где это пригождается на практике? Ну, DevOps же! Особенно в этих ваших контейнерах. Представь: у тебя sidecar-контейнер для мониторинга, а он нихуя не может пинговать хост, потому что запущен без привилегий. Пиздец, а не мониторинг.
В Dockerfile это решается так:
FROM alpine:latest
RUN apk add --no-cache iputils &&
setcap cap_net_raw+ep /bin/ping
# Всё, теперь внутри контейнера ping работает у любого пользователя
А в манифестах для Kubernetes (Pod spec) это выглядит как добавление capability:
securityContext:
capabilities:
add: ["NET_RAW"] # Просто добавляем способность контейнеру
Никаких privileged: true, никаких дыр в безопасность на весь корабль. Точечно, аккуратно.
Ну и под капотом-то что происходит?
Когда юзерский ping с подвешенной CAP_NET_RAW делает системный вызов socket() с типом SOCK_RAW и протоколом IPPROTO_ICMP, ядро вместо проверки uid == 0 идёт и смотрит: «А есть ли у процесса в effective-наборе эта самая CAP_NET_RAW?». Если есть — ок, проходи, создавай raw socket и шли свои эхо-запросы куда хочешь. Если нет — иди на хуй, смерд пердящий, без прав.
Вот так вот, блядь, изящно решается проблема, вместо того чтобы раздавать всем подряд sudo. Удивление пиздец, как всё продумано, когда знаешь, куда смотреть.