SS-кунфу
Date April 3rd, 2014 Author Vitaly Agapov
– Откроем, когда вы уедете.
Нет, речь пойдёт не о Schutzstaffel, как можно было подумать, посмотрев на картинку и название поста, а о консольной утилите GNU ss для получения статистики по сетевым (TCP, UDP, DCCP) и unix-сокетам. В общем то, ss и расшифровывается как "socket statistics". Входит она в пакет iproute, то есть присутствует в принципе во всех Linux-дистрибутивах, но несмотря на это не пользуется большой популярностью – подавляющее большинство использует более известную утилиту netstat.
Надо добиться небольшой кармической справедливости и заняться популяризацией ss (как бы двусмысленно это всё-таки ни звучало).
Итак, что мы можем получить.
Статистика по TCP-сокетам
Берётся из ядра с помощью сокета netlink и представляется в удобном виде:
# ss -s Total: 7566 (kernel 9540) TCP: 82453 (estab 7195, closed 74867, orphaned 309, synrecv 0, timewait 74841/0), ports 0 Transport Total IP IPv6 * 9540 - - RAW 0 0 0 UDP 17 11 6 TCP 7586 7581 5 INET 7603 7592 11 FRAG 0 0 0
Тут, кстати, отчётливо видно, что львиная доля сессий висят в TIME-WAIT. Есть повод посмотреть в сторону net.ipv4.tcp_tw_reuse / net.ipv4.tcp_tw_recycle или, скажем, включить keepalive.
Ключи в ss обычно имеют те же значения, что и в netstat. Что касается конкретно ключа -s, то netstat -s тоже показывает много разной интересной статистики.
Открытые порты
Для получения списка портов с PID'ами соответствующих процессов, можно воспользоваться командой
ss -lnp
Ключ -p покажет процессы, а -n отменит резолвинг.
С помощью grep можно выяснить, какой процесс слушает тот или иной порт.
Утилита netstat ту же самую функцию выполняет с тем же набором ключей:
# time netstat -lnp | grep 443 tcp 0 0 0.0.0.0:443 0.0.0.0:* LISTEN 5658/nginx: worker real 0m0.746s user 0m0.376s sys 0m0.364s
Но, как видно, заметно медленнее, чем ss:
# time ss -lnp | grep 443 LISTEN 0 128 *:443 *:* users:(("nginx",26299,19),("nginx",5673,19),("nginx",5672,19),("nginx",5671,19),("nginx",5670,19),("nginx",5669,19),("nginx",5668,19),("nginx",5667,19),("nginx",5666,19),("nginx",5665,19),("nginx",5664,19),("nginx",5663,19),("nginx",5662,19),("nginx",5661,19),("nginx",5660,19),("nginx",5659,19),("nginx",5658,19)) real 0m0.091s user 0m0.020s sys 0m0.036s
Это объясняется тем, что в данном случае ss не использует /proc/net/tcp в отличие от netstat, а получает информацию напрямую из ядра Linux.
Исходящие порты
Может возникнуть задача посчитать число использованных эфемерных портов, и для этого потребуется небольшая обработка общего выхлопа команды ss -an. Для ускорения обработки можно уточнить конкретный источник, так как число портов всё равно придётся считать по разным интерфейсам, включая loopback, отдельно.
ss -an src 127.0.0.1 | awk '{print $5}' | sort | uniq | grep -c 127.0.0.1 ss -an src `hostname -I | awk '{print $1}'` | awk '{print $5}' | sort | uniq | grep -c `hostname -I | awk '{print $1}'`
Аналогичные цифры можно получить и с помощью netstat, но опять же, с чуть большим временем исполнения:
netstat -n | awk '{print $5}' | grep 127.0.0.1 | sort | uniq | wc -l
Если полученные цифры слишком большие и велика опасность исчерпания диапазона портов, то нужно смотреть в сторону net.ipv4.ip_local_port_range и (если, как было написано выше, большая часть сессий висит в TIME-WAIT) net.ipv4.tcp_tw_reuse / net.ipv4.tcp_tw_recycle.
Фильтрация результатов
Вот и добрались до самых интересных фич ss. Он может не просто выводить данные по сокетам, но и фильтровать эти данные. Можно задавать порты (sport, dport), адреса (dst, src), статусы (state).
Вот пример вывода всех http-сессий в статусе time-wait с клиентами в определённой сети:
# ss -o state time-wait '( sport = :80 or sport = :443 )' dst 82.0.0.0/8 | head Recv-Q Send-Q Local Address:Port Peer Address:Port 0 0 x.x.x.x:http 82.146.x.x:36608 timer:(timewait,20sec,0) 0 0 x.x.x.x:https 82.146.x.x:14149 timer:(timewait,,0)
При этом ключ -o ещё и выведет таймер по каждой конкретной сессии. Впрочем, всё опять же по аналогии с netstat.
Вот возможные значения ключа state:
- established
- syn-sent
- syn-recv
- fin-wait-1
- fin-wait-2
- time-wait
- closed
- close-wait
- last-ack
- listen
- closing
- all
- connected (всё кроме listen и closed)
- synchronized (ещё и кроме syn-sent)
- bucket (минисокеты: time-wait и syn-recv)
- big (всё кроме минисокетов)
Для задания условий можно применять разные операнды, включая = (или eq), != (или ne), > (или gt), < (или lt), <= (или le), >= (или ge).
Вот, кстати, ещё один способ узнать процесс по его порту:
# ss -pl sport = :21 State Recv-Q Send-Q Local Address:Port Peer Address:Port LISTEN 0 32 *:ftp *:* users:(("vsftpd",1532,3))
А вот способ подсчитать число уникальных IP-адресов, подключённых к определённому порту:
ss -o state established sport = :80 or sport = :443 | awk -F"[\t :]+" 'NR!=1{ ip[$5]+=1 } END{ for (i in ip){n++};print n }'
Если смотреть не только established, то нужно изменить номаре колонки в awk:
ss -o state all sport = :80 or sport = :443 | awk -F"[\t :]+" 'NR!=1{ ip[$6]+=1 } END{ for (i in ip){n++};print n }'
Дополнительные данные
С помощью дополнительных ключей можно увеличивать количество информации, которую ss будет сообщать о каждом сокете:
-i выведет внутренню информацию TCP
-e выведет дополнительную информацию, включая таймер
-m выведет информацию о памяти
-o выведет таймер
Так, например, можно выжать максимум информации о сокетах:
# ss -ieom sport = :21 State Recv-Q Send-Q Local Address:Port Peer Address:Port ESTAB 0 0 x.x.x.x:ftp x.x.x.x:45978 timer:(keepalive,19min,0) ino:1752682702 sk:ffff8805264ba1c0 mem:(r0,w0,f0,t0) ts sack cubic wscale:7,7 rto:216 rtt:7.5/3 ato:40 cwnd:6 ssthresh:17 send 9.3Mbps rcv_rtt:54369.1 rcv_space:29172
И это ещё не всё
Tags: KungFu, Linux
Category:
Linux |
No comments »