Hlavní navigace

Sokety a C/C++: ICMP protokol

14. 7. 2003
Doba čtení: 6 minut

Sdílet

Další čistě teoretický článek v seriálu. Nenaleznete v něm zdrojový text. Seznámíme se se služebním protokolem ICMP, se kterým se budeme setkávat i v několika dalších dílech. V článku je nutný teoretický základ pro pochopení budoucích příkladů.

ICMP (Internet Control Message Protocol) je protokol internetové vrstvy komunikačního modelu TCP/IP. Jedná se o služební protokol protokolu IP. Slouží k signalizaci všemožných chybových stavů a k přenosu řídících informací. Pomocí protokolu ICMP lze například signalizovat zahození IP paketu, nedosažitelnost síťového uzlu a podobně.

Protokol ICMP nemůže samostatně bez protokolu IP existovat (mohlo by se zdát, že ICMP je součástí IP). Datagramy ICMP jsou přenášeny pomocí IP paketů – ICMP datagram je vkládán do IP paketu. Protokol IP pohlíží na ICMP datagram jako na data, která přenáší. Stejným způsobem IP protokol pohlíží třeba na UDP datagram nebo na TCP segment. Tím by mohl vzniknout MYLNÝ dojem, že ICMP je stejně jako TCP nebo UDP o vrstvu výše než IP. To ale není pravda. ICMP protokol NENÍ protokol transportní vrstvy, i když stejně jako protokoly transportní vrstvy využívá pro přenos IP protokol (ICMP paket je přenášen v IP paketu). Pokusím se vysvětlit, proč.

Už v prvním dílu seriálu jsem se snažil zjednodušeně říci, že zatímco internetová vrstva má za úkol zajistit komunikaci dvou počítačů (které nemusí být bezprostředně propojeny), transportní vrstva již zajišťuje komunikaci mezi aplikacemi, které na daných dvou počítačích běží. Zatímco IP adresa nám přesně identifikuje počítač v internetu (IP adresa je součástí IP hlavičky, tedy záležitostí internetové vrstvy), číslo portu (ať už UDP, nebo TCP) nám přesně identifikuje aplikaci, která na daném počítači běží. Na TCP nebo UDP port lze pohlížet jako na adresu aplikace na daném počítači. Odesílané TCP segmenty nebo UDP datagramy ve své hlavičce nesou číslo portu (adresu aplikace). U ICMP protokolu tomu tak není. Neexistuje nic jako ICMP port nebo nějaká obdoba ICMP portu. ICMP paket je určen počítači, nikoliv aplikaci. Proto považujeme ICMP protokol za protokol internetové vrstvy. Všechny aplikace běžící na daném počítači mohou příchozí ICMP paket získat (mají-li zájem).

ICMP a IP protokol jsou na sobě závislé protokoly. Jeden bez druhého nemůže existovat. Asi proto se lze někdy dokonce setkat s (asi ne příliš správným) názorem, že ICMP protokol je vlastně součástí IP protokolu.

Formát hlavičky ICMP paketu

Hlavička ICMP paketu má 8 byte délku. První čtyři byty jsou pro všechny typy zpráv stejné. Další čtyři se mění v závislosti na typu ICMP paketu. Za osmibytovou hlavičkou mohou (ale nemusí) následovat data ICMP paketu. Podívejme se podrobně na položky hlavičky.

Tabulka č. 450
Velikost (bity) Název atributu Název položky Popis
8 type Typ ICMP paketu Udává jednoznačně typ ICMP paketu. Možnosti popíšu v následujícím textu a další tabulce.
8 code Kód (pod typ) Blíže určuje typ ICMP paketu. Jedná se o jemnější dělení paketů na podtypy.
16 checksum Kontrolní součet Kontrolní součet ICMP paketu. Zajišťuje ochranu paketu před poškozením.
32  — Proměnné atributy V těchto čtyřech bytech jsou umístěny další atributy. Jejich názvy a hlavně velikosti jsou závislé na typu paketu. V podstatě na prvních dvou bytech.

Pro práci s ICMP hlavičkou budeme používat strukturu icmphdr deklarovanou v hlavičkovém souboru netinet/ip_ic­mp.h.

Typy ICMP paketu

Tabulka č. 451
Hodnota Název Popis
0 Ozvěna (odpověď ECHO) Odpovědí ECHO počítač reaguje na žádost o ECHO (viz typ 8). Každý počítač, který obdrží žádost o ECHO, by měl odpovědět odesílateli žádosti ECHO odpovědí.
3 Signalizace nedoručení IP paketu. ICMP paket signalizující nedoručitelný IP paket. Je vyslán v případě, že se na síti objevil (byl vyslán) IP paket, který nemůže být doručen na adresu, kterou nese ve své hlavičce. Takový IP paket je zahozen a směrem k odesílateli je vyslán ICMP paket typu 3. Kód (podtyp) je číslo, které určuje přesně důvod, proč nemůže být IP paket doručen.
4 Žádost o snížení rychlosti odesílání Signalizuje, že síť je přetížena
5 Žádost o změnu směrování. ICMP paket signalizující změnu směrování.
8 Žádost o ozvěnu (ECHO) Vysláním ECHO žádosti k nějakému počítači zjišťujeme, zda počítač v síti existuje. Každý počítač, který obdrží žádost o ECHO, by měl odpovědět ECHO odpovědí. Typ 8 má pouze jeden podtyp, je to 0. Vysíláme-li ECHO žádost, je typ nastaven na 8 a podtyp na 0.
11 Čas vypršel Je-li podtyp 0, paket informuje o zahození IP paketu, jehož TTL dosáhlo hodnoty 0. Jestliže je na směrovači položka TTL nějakého IP paketu snížena na 0, je paket zahozen a odesílateli IP paketu je vyslán ICMP paket typu 11 a podtypu 0.
12 Signalizuje chybný parametr v IP hlavičce Objeví-li se na síti IP paket se špatně vyplněnou hlavičkou, je zahozen a odesílatel informován tímto typem ICMP paketu. Podtyp přesněji určuje, co bylo špatně.
13 Požadavek na časovou synchronizaci Tento ICMP paket je vyslán v případě, že chceme získat čas nastavený na nějakém počítači
14 Odpověď na požadavek o časovou synchronizaci ICMP paket obsahuje čas vyslání.

Existuje více typů ICMP paketů. Zdaleka ne se všemi se však při programování setkáme. Spíše při konfigurování sítí. Ostatní typy ICMP paketů a jejich číselné reprezentace, případně čísla kódů a popis typů, lze nalézt na mnoha místech na Internetu (například na http://www.faq­s.org/rfcs/rfc79­2.html) nebo v mnoha knihách. Například v knize Velký průvodce protokoly TCP/IP a systémem DNS autorů L. Dostálka a A. Kabelové, ze které jsem čerpal i já.

Některé typy ICMP paketů

Nyní bych se rád podrobněji zmínil o některých vybraných typech ICMP paketů, se kterými budeme v následujících článcích experimentovat.

Žádost o ECHO

Tabulka č. 452
Typ: 8
Kód: 0

Žádáme vzdálený počítač o zaslání ICMP paketu (ECHO odpověď). Slouží k testování dostupnosti počítače. V tomto typu ICMP paketu mají čtyři byty proměnných atributů hlavičky tvar:

Tabulka č. 453
Velikost (bity) Název atributu Název položky Popis
16 id Identifikátor ICMP paketu Vyplníme jednoznačným číslem, jaké určitě nevyplní žádná jiná aplikace (proces) na stejném počítači, která by chtěla přibližně ve stejný okamžik odesílat ICMP žádost o ECHO. Jak si ale můžeme být jisti, že vkládané číslo je jednoznačné? Existuje nepsané pravidlo použít identifikátor procesu. Proto tento atribut budeme zaplňovat identifikátorem běžícího procesu, který by měl být v rámci OS (tedy i v rámci počítače) jednoznačný. V Linuxu budeme používat návratovou hodnotu funkce getpid, v MS Windows Ž budeme používat návratovou hodnotu funkce GetCurrentPro­cessId (po přetypování). V ECHO odpovědi bude mít identifikátor ICMP paketu stejnou hodnotu jako v žádosti. Tím zjistíme, že odpověď patří k našemu požadavku.
16 sequence Pořadové číslo ECHO žádosti Můžeme vyslat více ECHO žádostí, které odlišíme pořadovým číslem. Příchozí ECHO odpovědi budou obsahovat stejné pořadové číslo.

Odpověď ECHO

Tabulka č. 454
Typ: 0
Kód: 0

Odpověď na ECHO žádost. Počítač, který ECHO žádost obdrží, by měl odpovědět ECHO odpovědí. Tento typ ICMP paketu v našich experimentech nebudeme vytvářet, ale budeme jej příjímat.

Čas vypršel – položka TTL klesla na 0

Tabulka č. 455
Typ: 11
Kód: 0

Tento typ ICMP paketu budeme v našich experimentech rovněž přijímat, nikoliv vysílat. Cyklickým odesíláním ECHO žádostí, zvyšováním TTL v IP hlavičce a odchytávání ICMP paketu typu 11 a podtypu 0 můžeme zjistit všechny počítače, přes které IP paket putuje k cíli. V budoucnu věnuji naprogramování tohoto příkladu jeden celý článek.

Nedosažitelný port protokolu UDP

Tabulka č. 456
Typ: 3
Kód: 3

Jestliže je na počítač doručen IP paket nesoucí UDP datagram s číslem cílového portu, který není přiřazen žádné aplikaci, je směrem k odesílateli vyslán tento ICMP paket. Ukážeme si, že při používání příkladu z minulého dílu dochází k odesílání tohoto ICMP paketu.

Práce s ICMP protokolem

S ICMP protokolem budeme pracovat pomocí soketu typu SOCK_RAW. Protokol (3. parametr funkce socket) je dán hodnotou makra IPPROTO_ICMP.

bitcoin_skoleni

Vytvoříme-li soket následujícím způsobem:

socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);

budeme pomocí funkce sendto odesílat buffer obsahující vyplněnou ICMP hlavičku. Nikoliv ale IP hlavičku. Parametry IP hlavičky můžeme měnit pomocí voleb soketů. Budeme-li ale pomocí funkce recvfrom přijímat data z takto vytvořeného soketu, bude přijímací buffer zaplněn jak IP hlavičkou, tak i ICMP hlavičkou. Nesmíme na to zapomenout a musíme vždy posunout začátek bufferu o offset(posunutí), jehož velikost je dána atributem ihl z IP hlavičky. O tom si ale povíme více příště, kdy si vytvoříme (a podrobně popíšeme) jednoduchý program, který bude přijímat všechny ICMP pakety doručené počítači, na kterém poběží, a vypíše, o jaký typ se jedná.