Урок по треку Linux 8 мин

Сеть в Linux за 8 минут

ip, ss, dig, curl, порты и сокеты, DNS-резолвинг, iptables и nftables, разбор «сервис недоступен».

Самый частый вопрос на собесе DevOps и бэкендера: «сервис недоступен, что будешь проверять?». Ответ это прогулка по стеку снизу вверх: интерфейс, маршрут, DNS, порт, фаервол, приложение. Ниже инструменты для каждого шага.

Интерфейсы и адреса: ip

ifconfig и netstat из пакета net-tools устарели, на свежих системах их может не быть. Современный набор это ip и ss (iproute2).

ip -br addr            # кратко: интерфейс, состояние, адреса
ip addr show eth0
ip link set eth0 up
ip route               # таблица маршрутов
ip route get 8.8.8.8   # через какой интерфейс и шлюз пойдёт пакет
ip neigh               # ARP-таблица

default via 10.0.0.1 dev eth0 в ip route это шлюз по умолчанию. Нет его, значит в интернет пакеты не уйдут.

Порты и сокеты: ss

ss -tlnp          # TCP, слушающие, без резолва имён, с процессом
ss -ulnp          # то же для UDP
ss -tn state established '( dport = :5432 )'
ss -s             # сводка по состояниям

Важно смотреть, на каком адресе слушает сервис. 127.0.0.1:8080 доступен только с этой машины, 0.0.0.0:8080 или *:8080 со всех интерфейсов. Классика: приложение в контейнере слушает 127.0.0.1, и снаружи до него не достучаться.

Состояния TCP, о которых спрашивают:

  • LISTEN: ждёт соединений.
  • ESTABLISHED: открыто.
  • TIME_WAIT: сторона, закрывшая первой, ждёт 2×MSL (в Linux 60 секунд), чтобы опоздавшие пакеты не попали в новое соединение. Тысячи TIME_WAIT у клиента часто значат, что соединения не переиспользуются.
  • CLOSE_WAIT: удалённая сторона закрыла, а наше приложение ещё нет. Рост CLOSE_WAIT это почти всегда баг в коде: соединения не закрываются.

DNS: dig и resolv.conf

dig example.com              # A-запись через системный резолвер
dig +short example.com AAAA
dig @1.1.1.1 example.com     # спросить конкретный сервер
dig example.com MX
dig +trace example.com       # пройти от корня
getent hosts example.com     # как резолвит система (с /etc/hosts)

Порядок резолвинга задаёт /etc/nsswitch.conf (обычно сначала files, то есть /etc/hosts, потом dns). Серверы DNS лежат в /etc/resolv.conf; в Ubuntu там часто 127.0.0.53, это локальный systemd-resolved, настоящие серверы смотрят resolvectl status. dig идёт в DNS напрямую и /etc/hosts не читает, а getent и обычные программы читают.

HTTP: curl

curl -I https://api.example.com/health           # только заголовки
curl -v https://api.example.com                  # TLS, заголовки, всё подряд
curl -sS -o /dev/null -w '%{http_code} %{time_total}\n' URL
curl --resolve api.example.com:443:10.0.0.5 https://api.example.com/   # мимо DNS
curl -k https://...                               # не проверять сертификат (только для отладки)

-w с переменными time_namelookup, time_connect, time_starttransfer показывает, где теряется время: на DNS, на TCP или на ответе приложения.

Проверка доступности порта

ping проверяет ICMP, а его часто режут. Для TCP: nc -zv host 5432, curl -v telnet://host:5432 или чистый bash timeout 2 bash -c '</dev/tcp/host/5432'.

Что означает ответ:

  • Connection refused: хост доступен, но на порту никто не слушает (или фаервол отвечает RST).
  • Timeout: пакеты теряются: фаервол с DROP, нет маршрута, хост выключен.
  • No route to host: нет маршрута или ICMP host unreachable (иногда так отвечает фаервол с REJECT).

Фаервол: iptables и nftables

Под капотом netfilter в ядре. iptables это классический интерфейс, nftables (nft) современный, и на свежих дистрибутивах команда iptables часто работает через слой совместимости iptables-nft. Надстройки: ufw в Ubuntu, firewalld в RHEL.

Цепочки таблицы filter: INPUT (пакеты к этой машине), OUTPUT (от неё), FORWARD (транзитные, например в контейнеры). Правила проверяются по порядку, первое совпавшее с действием ACCEPT, DROP или REJECT решает судьбу пакета. Если ничего не совпало, работает политика цепочки.

iptables -L -n -v --line-numbers
iptables -A INPUT -p tcp --dport 22 -j ACCEPT
iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
iptables -P INPUT DROP
nft list ruleset

DROP молча выбрасывает (клиент видит таймаут), REJECT отвечает ошибкой (клиент видит refused). Таблица nat делает DNAT и SNAT/MASQUERADE: так Docker публикует порты контейнеров.

Правила iptables не переживают перезагрузку сами: их сохраняют (iptables-save, пакет iptables-persistent) или описывают в конфиге nftables.

Алгоритм «сервис недоступен»

  1. Слушает ли процесс и на каком адресе: ss -tlnp | grep 8080.
  2. Отвечает ли локально: curl -v localhost:8080/health.
  3. DNS: dig +short api.example.com, правильный ли IP.
  4. Сеть до хоста: ip route get, ping, traceroute/mtr.
  5. Порт снаружи: nc -zv host 8080, refused или timeout.
  6. Фаервол на хосте и в облаке (security groups).
  7. Лог приложения и прокси.

Частые ошибки

  • Проверять доступность ping-ом и делать вывод про порт.
  • Забыть, что сервис слушает только 127.0.0.1.
  • Править /etc/resolv.conf, которым управляет systemd-resolved, и терять правки.
  • Добавлять iptables -A ... ACCEPT после правила, которое уже всё отбросило.
  • Применить -P INPUT DROP по SSH без правила для своего соединения.

Что спросят на собесе

  • Сервис недоступен: по шагам, что проверишь.
  • Чем Connection refused отличается от таймаута.
  • Что значат TIME_WAIT и CLOSE_WAIT, что делать, если их тысячи.
  • Как работает резолвинг имени в Linux.
  • Как устроены цепочки iptables и чем DROP отличается от REJECT.

Закрепите за 5 минут

После урока в тренажёре 3-5 проверочных вопросов, дальше модуль уходит в повторения.