Internet Info, s.r.o. Lupa Root Měšec Podnikatel DigiZone Slunečnice Vitalianew Bomba Navrcholu Weblogy Jagg Woko Dobrý web Computer.cz SK: MojeLinky

Hlavní navigace

Sokety a C/C++: přijímání ICMP paketů

V minulém dílu jsme se seznámili se strukturou a formátem ICMP paketu. Dnes si uděláme první jednoduchý příklad používající ICMP protokol. Bude se jednat o program monitorující všechny ICMP pakety přicházející na počítač.

Každý program, který na počítači běží, může přijímat všechny ICMP pakety. Programu stačí, aby vytvořil soket typu SOCK_RAW používající protokol IPPROTO_ICMP (samozřejmě musí mít k tomu přístupová – administrátorská – práva).

Použití protokolu ICMP v programu

Už jsem vše nastínil v minulém dílu. Chceme-li odeslat data (což v dnešním dílu ještě dělat nebudeme), musí odesílací buffer obsahovat řádně vyplněnou hlavičku ICMP protokolu. Za ní následují data, jestliže nějaká jsou. Při odesílání paketu nevkládáme hlavičku IP do odesílaného bufferu. Když ICMP paket přijímáme, v přijímajícím bufferu je IP hlavička i ICMP hlavička. Za ní teprve následují data, jsou-li nějaká.

Malá poznámka k WinSock

Celý seriál používám (píšu pro něj příklady) prostředí DEV-CPP založené na překladači MinGW. S překladačem MinGW jsou dodávány hlavičkové soubory, ve kterých bohužel není vše, co by v nich být mělo. Již v článku Sokety a C/C++ – Raw soket jsem narazil na problém, že nebyla k dispozici struktura reprezentující IP a UDP hlavičky. S protokolem ICMP tomu není jinak. Stejně jako tenkrát jsem i nyní pro WinSock vytvořil hlavičkový soubor, který je ke stažení jako součást příkladu pro MS WindowsŽ na konci článku. Pokud používáte jiný překladač, budete nejspíše mít potřebné struktury a makra definované v jeho hlavičkových souborech. Poté můžete použít buďto mé struktury, anebo raději „originální“ dodávané s překladačem. V takovém případě ale musíte počítat s tím, že se názvy struktur nebo atributů budou asi trochu lišit. Já pojmenoval struktury i atributy struktur stejně, jako jsou pojmenovány v Linuxu.

Příklad – přijímač ICMP paketů

Příklad je vlastně velice jednoduchý. Vytvoříme soket typu SOCK_RAW používající protokol IPPROTO_ICMP. Poté v cyklu voláme funkcirecvfrom, která čte příchozí ICMP pakety. Z každého ICMP paketu získám nějaké ty informace a vypíšu je. Přijmu tolik ICMP paketů, kolik si uživatel přál.

Formality

Nejprve provedeme náležité formality. Vložíme potřebné hlavičkové soubory, začneme funkci main, deklarujeme potřebné proměnné a ošetříme parametry příkazové řádky.

#include <stdio.h>
#include <stdlib.h>

#include <string.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netdb.h>
#include <arpa/inet.h>

#include <netinet/ip.h>
#include <netinet/ip_icmp.h>
#include <unistd.h>

#define BUFSIZE 1024

using namespace std;

int main(int argc, char *argv[])
{
  hostent *host;
  iphdr *ip;
  icmphdr *icmp;
  int sock;
  unsigned int count;
  sockaddr_in sender;
  char buffer[BUFSIZE];
  int bufferLenght;
  socklen_t lenght;
  char *stringIP, *unknown = "?";

  if (argc != 2)
  {
    printf
      ("Správná syntaxe:\n\t%s\tpočet sledovaných paketů\n",
      argv[0]);
    return -1;
  }
  count = atoi(argv[1]);

Vytvoření soketu

Vytvoříme soket typu raw (hodnota makra SOCK_RAW) s použitím protokolu ICMP (hodnota makra IPPROTO_ICMP).

  if ((sock = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP)) == -1)
  {
    perror("Inicializace soketů");
    return -1;
  }

Příjem ICMP paketů

Postupně v cyklu budeme přijímat ICMP pakety. V bufferu, který přijmeme, je obsažena hlavička IP protokolu, hlavička ICMP protokolu a data, která ICMP paket přenáší.

for(unsigned int p = 0; p < count; p++)
{
 lenght = sizeof(sockaddr_in);
 if ((bufferLenght =
    recvfrom(sock, buffer, BUFSIZE, 0, (sockaddr *)&sender, &lenght))
    == -1)
 {
   printf("Příjem dat: %u\n", 0);
   close(sock);
   return -1;
 }

Získáme potřebné informace z jednotlivých hlaviček

První v bufferu je hlavička IP protokolu. Ukazatel na strukturu s atributy IP hlavičky bude ukazovat na začátek bufferu. Hned za IP hlavičkou je ICMP hlavička. Velikost IP hlavičky zjistíme pomocí atributu ihl. Tím zjistíme také polohu ICMP hlavičky v bufferu. Poté připravíme textovou reprezentaci adresy odesílatele a doménové jméno odesílatele. Všechny informace vypíšeme na standardní výstup.

ip = (iphdr*)buffer;
icmp = (icmphdr *) (buffer + ip->ihl * 4);
stringIP = strdup(inet_ntoa(sender.sin_addr));
host = gethostbyaddr((char *)&sender.sin_addr, 4, AF_INET);
printf(
  "\nPřišel ICMP paket velikosti %d bytů\nOdesílatel: %s (%s)\n"
  "TTL: %d\nTyp ICMP: %d\nKód ICMP: %d\n",
  bufferLenght, stringIP, (host == NULL? unknown : host->h_name),
  (int)ip->ttl, icmp->type, icmp->code);
free(stringIP);

Rozdělení podle typu paketu

Jestliže byl doručen nějaký typ paketu, kterého si chceme podrobněji všímat, vypíšeme o něm více informaci. Informace jsou obsaženy v proměnné části hlavičky ICMP paketu. Pomocí soketového API je celá věc implementována prostřednictvím unie jazyka C. Unie ve struktuře icmphdr se jmenuje un. Některé ICMP pakety obsahují za ICMP hlavičkou nějaká data. O těch si ale povíme až příště.

switch (icmp->type)
{
  /* Tady podle jednotlivých typů vypisuji
    podrobné informace. Viz příklad ke stažení.*/
}

Konec programu

Zavřeme soket a ukončíme program.

  }
  close(sock);
  return 0;
}

Příklady ke stažení

Tabulka č. 457
Soubor OS
lin20.tgz Linux
win20.zip MS WindowsŽ

Příklady ke stažení lze podle potřeby samozřejmě upravit. Nerozeznají mnoho typů ICMP paketů a také by mohly vypisovat více informací.

Několikrát jsem se zmínil, že protokol ICMP může přenášet také nějaká data (nejen svou hlavičku s informacemi). Nejedná se ale o nějaká data protokolu vyšší vrstvy. Jedná se o data, která nějakým způsobem doplňují informace v hlavičce ICMP paketu. Na tuto situaci se podíváme příště.

Školení: Úvod do XML schémat

Akademie Root
  • Jiří Kosek vás seznámí se základy schémového jazyka W3C XML Schema!
  • Bez základní znalosti XML schémat se dnes neobejde žádný vývojář moderních aplikací!
  • Porozumíte hotovým schématům, pochopíte jakou strukturu XML připouštějí a a naučíte se provádět ve schématech dílčí úpravy.

Detailní informace o kurzu...

Ohodnoťte jako ve škole: 12345
Průměrná známka 2,79

Přehled názorů

ICMP a uzivatelska data
PaJaSoft 21. 7. 2003 17:45
├ 
Re: ICMP a uzivatelska data
Strec 22. 7. 2003 11:00
└ 
Re: ICMP a uzivatelska data
Radim Dostál 23. 7. 2003 00:17
bez titulku
roman 22. 7. 2003 17:37
winsock ve zdrojacich
roman 22. 7. 2003 20:13
└ 
Re: winsock ve zdrojacich
Radim Dostál 23. 7. 2003 00:11
socket()
bln 23. 7. 2003 17:15
└ 
Re: socket()
Radim Dostál 28. 7. 2003 09:02
       

Tento text je již více než dva měsíce starý. Chcete-li na něj reagovat v diskusi, pravděpodobně vám již nikdo neodpoví. Pro řešení aktuálních problémů doporučujeme využít naše diskusní fórum.

Zasílat nově přidané příspěvky e-mailem