SS-кунфу

Date April 3rd, 2014 Author Vitaly Agapov

– Вы откроете ворота?
– Откроем, когда вы уедете.

Дж. Р. Р. Мартин «Танец с драконами»

ss-kungfu

Нет, речь пойдёт не о 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: ,
Category: Linux | No comments »

Comments

Leave a comment

 Comment Form