Сокет слушает только IPv6 или только IPv4 неожиданно
Сокет, слушающий порт без указания адреса, может принимать соединения по обоим протоколам или только по одному — это зависит от параметра двойного стека и настроек ядра. Неожиданная односторонность видна только при проверке со стороны клиента.
Вероятные причины
По порядку: сверху то, что встречается чаще.
-
Включён режим только одного протокола
При включённом режиме сокет принимает соединения только по IPv6, и клиенты по IPv4 получают отказ.
-
Настройка ядра меняет поведение по умолчанию
Значение по умолчанию наследует системную настройку. Она различается между дистрибутивами и может быть изменена локально.
-
Два слушателя конфликтуют за один порт
Отдельные слушатели на IPv4 и IPv6 при включённом двойном стеке конфликтуют: второй не может занять порт.
Диагностика
Команды идут в том порядке, в котором их стоит выполнять: каждая следующая проверяет то, что осталось после предыдущей.
На каких адресах и протоколах открыт порт.
sudo ss -tlnp | grep :8080Объявленные слушатели и режим двойного стека.
systemctl show myapp.socket -p BindIPv6Only -p ListenStreamПроверка со стороны клиента по IPv4.
timeout 3 bash -c "</dev/tcp/127.0.0.1/8080" && echo IPv4 открыт || echo IPv4 закрытРешение
Решение своё для каждой причины. Сначала определите, какая из них ваша, — иначе правки наложатся друг на друга.
- Почему происходит
- При включённом режиме сокет принимает соединения только по IPv6, и клиенты по IPv4 получают отказ.
- Как проверить
-
Посмотрите параметр и слушателей.
systemctl show myapp.socket -p BindIPv6Only sudo ss -tlnp | grep :8080
- Как исправить
-
Выберите поведение осознанно. Значение по умолчанию берёт настройку ядра, из-за чего одна и та же конфигурация ведёт себя по-разному на разных машинах.
[Socket] ListenStream=8080 BindIPv6Only=both
- Почему происходит
- Значение по умолчанию наследует системную настройку. Она различается между дистрибутивами и может быть изменена локально.
- Как проверить
-
Посмотрите настройку ядра.
sysctl net.ipv6.bindv6only
- Как исправить
- Задавайте параметр в описании сокета явно, не полагаясь на системное значение. Иначе перенос службы на другую машину меняет поведение.
- Почему происходит
- Отдельные слушатели на IPv4 и IPv6 при включённом двойном стеке конфликтуют: второй не может занять порт.
- Как проверить
-
Посмотрите объявленные слушатели.
systemctl cat myapp.socket | grep -E "^Listen" sudo ss -tlnp | grep :8080
- Как исправить
- Оставьте один слушатель с нужным режимом двойного стека вместо двух явных.
Пример вывода
Сокет слушает только IPv6, клиенты по IPv4 не подключаются. Пример показательный: он собран на тестовой машине специально для этой страницы, а не взят из чужого журнала.
$ sudo ss -tlnp | grep :8080
LISTEN 0 4096 [::]:8080 [::]:* users:(("systemd",pid=1,fd=42))
$ timeout 3 bash -c "</dev/tcp/127.0.0.1/8080" || echo отказ
отказ
$ systemctl show myapp.socket -p BindIPv6Only
BindIPv6Only=ipv6-only
Связанные ошибки
- status=232/ADDRESS_FAMILIES в systemd Код 232/ADDRESS_FAMILIES: не удалось применить ограничение семейств адресов из RestrictAddressFamilies=.
- Protocol not supported при создании сокета Ошибка 93: семейство или протокол не поддержаны. Разбор для IPv6, ограничений изоляции и контейнеров.
- Сокет без Listen: unit загружен, но ничего не слушает В .socket не задан ни один параметр Listen…= — сокет не принимает соединения. Как объявить адрес прослушивания.
- Соединения через сокет-активацию висят и не закрываются Клиенты уходят, соединения остаются: проверка живости соединений не включена.
- Сокет не принимает данные: не тот тип Служба не получает пакеты: объявлен потоковый сокет вместо датаграммного или наоборот.
- Address already in use при запуске службы Порт или адрес уже занят: bind() failed (98: Address already in use). Как найти владельца порта и что делать с остатками прежнего процесса.
- Automount: каталог монтируется не вовремя или отваливается Автомонтирование через .automount: как работает TimeoutIdleSec, почему ресурс отваливается и когда лучше обычный .mount.
- Bad file descriptor в журнале службы Ошибка 9 при операции с файлом: дескриптор закрыт или не тот. Разбор для служб и сокет-активации.
Источники
-
systemd.socket(5)
BindIPv6Only= и поведение двойного стека. -
Воспроизведено на тестовой машине, systemd 255 (Ubuntu 24.04)
Проверено на systemd 255: режим только IPv6 отвергает соединения по IPv4.