Netstat, де мої дейтаграми?

Певно, що важко знайти іншу, настільки ж корисну і погано документовану програму, як
Netstat
, мається на увазі, опція показу статистики мережного потоку даних. Коли ми проводимо інспекцію стану мережі на окремо взятому Linux сайті, завжди можна бути впевненим, що це утиліта є в наявності. І ось ми хочемо зрозуміти — справляється мережевий стек з навантаженням, або проблема на верхніх поверхах OSI, власне там, де зосереджено коліщатка крутяться бізнес-логіки нашої програми.

(5:562)$ netstat -s |wc -l
124
Ура, у нас купа корисної інформації, зараз ми швиденько зметикуємо, що до чого. От тільки б зрозуміти, що ж це за звір такий
timeout in transit
, явно щось недобре.
Icmp:
11475275 ICMP messages received
327527 input ICMP message failed.
ICMP input histogram:
detination unreachable: 2233840
timeout in transit: 5612259

Зараз гляну в мануал.
# man netstat |grep timeout
#

Пусте безліч підказує, що пора дізнаватися у Яндекса, Гугла і навіть у DuckDuckGo. Результат пошуку був приблизно такий же, але тільки Гугл видав 111 тис. варіантів порожнього безлічі, а Яндекс лаконічно обмежився 326 варіантами.
Але ми адже не даремно вибрали відкрите ПЗ, завжди можна звіритися з першоджерелом. У нашому випадку вихідний код знаходиться у файлі
nertstat.c
пакету
Net-tools
.
Ось та частина функції
int main
, в якій визначається дія для показу статистики.
case '?':
usage(E_OPTERR);
case 'h':
usage(E_USAGE);
case 's':
flag_sta++;
...
if (flag_sta) {
if (!afname[0])
safe_strncpy(afname, DFLT_AF, sizeof(afname));

if (!strcmp(afname, "inet")) {
#if HAVE_AFINET
parsesnmp(flag_raw, flag_tcp, flag_udp, flag_sctp);

Функція
parsesnmp
визначена у файлі
statistics.c
і парсити файли:
/proc/net/netstat
/proc/net/snmp
/proc/net/sctp/snmp

Ясно зрозуміло, отже, можна просто заглянути в /proc/net/snmp і побачити, що стоїть за
timeout in transit
.
# cat /proc/net/snmp |grep -iw icmp
Icmp: InMsgs InErrors InCsumErrors InDestUnreachs InTimeExcds InParmProbs InSrcQuenchs InRedirects InEchos InEchoReps InTimestamps InTimestampReps InAddrMasks InAddrMaskReps OutMsgs OutErrors OutDestUnreachs OutTimeExcds OutParmProbs OutSrcQuenchs OutRedirects OutEchos OutEchoReps OutTimestamps OutTimestampReps OutAddrMasks OutAddrMaskReps
Icmp: 127 2 0 90 0 0 0 0 25 0 8 0 4 0 1763 0 1730 0 0 0 0 0 25 0 8 0 0

Порівнюючи ці значення з висновком команди
netstat
, можемо укласти, що
timeout in transit
відповідає змінної
InTimeExcds
, а ланцюжок далі веде до файлу
/usr/include/linux/snmp.h
, де визначені всі ці поля.
/* icmp mib definitions */
/*
* RFC 1213: MIB-II ICMP Group
* RFC 2011 (updates 1213): SNMPv2 MIB for IP: ICMP group
*/
enum
{
ICMP_MIB_NUM = 0,
ICMP_MIB_INMSGS, /* InMsgs */
ICMP_MIB_INERRORS, /* InErrors */
ICMP_MIB_INDESTUNREACHS, /* InDestUnreachs */
ICMP_MIB_INTIMEEXCDS, /* InTimeExcds */
ICMP_MIB_INPARMPROBS, /* InParmProbs */
ICMP_MIB_INSRCQUENCHS, /* InSrcQuenchs */
ICMP_MIB_INREDIRECTS, /* InRedirects */
ICMP_MIB_INECHOS, /* InEchos */
ICMP_MIB_INECHOREPS, /* InEchoReps */
ICMP_MIB_INTIMESTAMPS, /* InTimestamps */
ICMP_MIB_INTIMESTAMPREPS, /* InTimestampReps */
ICMP_MIB_INADDRMASKS, /* InAddrMasks */
ICMP_MIB_INADDRMASKREPS, /* InAddrMaskReps */
ICMP_MIB_OUTMSGS, /* OutMsgs */
ICMP_MIB_OUTERRORS, /* OutErrors */
ICMP_MIB_OUTDESTUNREACHS, /* OutDestUnreachs */
ICMP_MIB_OUTTIMEEXCDS, /* OutTimeExcds */
ICMP_MIB_OUTPARMPROBS, /* OutParmProbs */
ICMP_MIB_OUTSRCQUENCHS, /* OutSrcQuenchs */
ICMP_MIB_OUTREDIRECTS, /* OutRedirects */
ICMP_MIB_OUTECHOS, /* OutEchos */
ICMP_MIB_OUTECHOREPS, /* OutEchoReps */
ICMP_MIB_OUTTIMESTAMPS, /* OutTimestamps */
ICMP_MIB_OUTTIMESTAMPREPS, /* OutTimestampReps */
ICMP_MIB_OUTADDRMASKS, /* OutAddrMasks */
ICMP_MIB_OUTADDRMASKREPS, /* OutAddrMaskReps */
ICMP_MIB_CSUMERRORS, /* InCsumErrors */
__ICMP_MIB_MAX
};

Кому як, а для мене RFC 1213 як для хіміка таблиця Менделєєва — необхідно знати на зубок, так як, це один з наріжних каменів моніторингу мережевих пристроїв. Ось визначення елемента з RFC 1213 пишу по пам'яті.
icmpInTimeExcds OBJECT-TYPE
SYNTAX Counter
ACCESS read-only
STATUS mandatory
DESCRIPTION
"The number of ICMP Time Exceeded messages received."
::= { icmp 4 }

Поки що складається враження, що всі ці визначення як масло масляне, не розкривають суті, але на щастя
ICMP Time Exceeded
— частина визначення протоколу ICMP.
Якщо обробний дейтаграмму шлюз бачить, що поле TTL містить нульове значення, дейтаграма повинна бути відкинута. Шлюз може повідомити відправника дейтаграми з допомогою повідомлення time exceeded.
Отже, ми знайшли те, що шукали. Висновок команди
netstat
, в якому було це загадкове поле, означає кількість відкинутих пакетів ICMP з нульовим TTL. IRL[1] це означає, що в мережі є кільце, де пакети профукали весь TTL[2] .
timeout in transit: 5612259

Linux MIB
У процесі цього занурення в нетрі Linux ядра, я з подивом виявив SNMP підсистему. Ні, не SNMP агента, боронь нас Alan Cox, а саме невеликий SNMP стек. Про це написано у коментаря до файлу
/usr/src/linux/include/net/snmp.h
.
/*
* SNMP MIB entries for the IP subsystem.
* Alan Cox <gw4pts@gw4pts.ampr.org>
*
* We don't chose to implement SNMP in the kernel (this would
* be silly as SNMP is a pain in the backside in places). We do
* however need to collect the MIB statistics and export them
* out of /proc (eventually)
*/

SNMP означає Simple Network Management Protocol, але як свідчить бородатий жарт, ніколи ще в абревіатурі буква S так не брехала. Я планую написати про цю мозгодробилке окремо, так як саме на ньому крутиться весь софт моніторингу обчислювальних мереж і мережевих вузлів. Поки ж — необхідний мінімум, щоб було зрозуміло, звідки беруться змінні статистики
netstat
.


У найпростішому випадку ми маємо архітектуру клієнт — сервер, де в ролі клієнта може виступати MRTG або Munin, а серверна частина — це SNMP агент на мережевому вузлі. Майже всі сучасні мережеві пристрої мають на борту SNMP агента, навіть домашні WiFi-роутери. Windows має свій
SNMP Service
, а Linux і відкриті Unix системи використовують
Net-SNMP
.
SNMP клієнт і сервер обмінюються повідомленнями: клієнт посилає запит, а сервер повертає відповідь. Зазвичай, цей обмін виглядає наступним чином.
К. — Чебурашка, прилади!
С. — Сорок
К. — сорок?
С. — А що прилади?
Клієнт просить видати значення деякої змінної з Великого Словника. Сервер дивиться у ВС, знаходить змінну, дивиться в свій реєстру і повертає значення. Великий Словник — це
MIB Database
з малюнка.
Ось як виглядає опитування системних змінних,
uptime
на man сторінці.
snmpwalk -Os -c public -v 1 zeus system 

sysDescr.0 = STRING: "SunOS zeus.net.cmu.edu 4.1.3_U1 1 sun4m"
sysObjectID.0 = OID: enterprises.hp.nm.hpsystem.10.1.1
sysUpTime.0 = Timeticks: (155274552) 17 days, 23:19:05
sysContact.0 = STRING: ""
sysName.0 = STRING: "zeus.net.cmu.edu"
sysLocation.0 = STRING: ""
sysServices.0 = INTEGER: 72

Треба розуміти, що за евфемізмами Великого Словника, реєстру і самого протоколу SNMP ховаються десятки RFC і безодня їх можливих реалізацій. Повертаючись до нашого файлу
snmp.h
, видно лише надводна частина айсберга:
# grep RFC /usr/include/linux/snmp.h

* RFC 1213: MIB-II
* RFC 2011 (updates 1213): SNMPv2-MIB-IP
* RFC 2863: Interfaces Group MIB
* RFC 2465: IPv6 MIB: General Group
* RFC 1213: MIB-II ICMP Group
* RFC 2011 (updates 1213): SNMPv2 MIB for IP: ICMP group
* RFC 2466: ICMPv6-MIB
* RFC 1213: MIB-II TCP group
* RFC 2012 (updates 1213): SNMPv2-MIB-TCP
* RFC 1213: MIB-II UDP group
* RFC 2013 (updates 1213): SNMPv2-MIB-UDP
LINUX_MIB_TCPMINTTLDROP, /* RFC 5082 */

І якщо б це було все, розшифровка статистки
netstat
могла бути такий:
змінна з netstat --> відповідна їй рядок з /proc:
* /proc/net/snmp
* /proc/net/netstat
* /proc/net/sctp/snmp
--> відповідне RFC --> визначення.

Проте, навіть такий багатоступінчастої розшифровки недостатньо, так як значну частину
snmp.h
займає загадковий
Linux MIB
, змінні якого ні в якому RFC не визначені, і у Великому Словнику — MIB Database, їх теж немає.
/* linux mib definitions */
enum
{
LINUX_MIB_NUM = 0,
LINUX_MIB_SYNCOOKIESSENT, /* SyncookiesSent */
LINUX_MIB_SYNCOOKIESRECV, /* SyncookiesRecv */
LINUX_MIB_SYNCOOKIESFAILED, /* SyncookiesFailed */
LINUX_MIB_EMBRYONICRSTS, /* EmbryonicRsts */
LINUX_MIB_PRUNECALLED, /* PruneCalled */
LINUX_MIB_RCVPRUNED, /* RcvPruned */
LINUX_MIB_OFOPRUNED, /* OfoPruned */
...
LINUX_MIB_TCPMTUPSUCCESS, /* TCPMTUPSuccess */
__LINUX_MIB_MAX
};

Ми готові до наступного етапу занурення у статті спробуємо з'ясувати, що ховається за помилками пам'яті буфера, і як в tcp колапсують порушників черги .


  1. В реальному житті, від англійського in real life.
  2. Час життя пакету, від англійського time to live
Джерело: Хабрахабр

0 коментарів

Тільки зареєстровані та авторизовані користувачі можуть залишати коментарі.