Internet Control Message Protocol Aplikacja ping

Transkrypt

Internet Control Message Protocol Aplikacja ping
Internet Control Message Protocol
Aplikacja ping
Zagadnienia:
• Protokół ICMP.
•Specyfikacja projektu ping.
• Specyfikacja struktur i funkcji programu.
• Struktura programu.
dr Zbigniew Lipiński
Instytut Matematyki i Informatyki
ul. Oleska 48
50-204 Opole
[email protected]
Internet Control Message Protocol
ICMP, ang. Internet Control Message Protocol.
Protokół ICMP jest protokołem warstwy sieci modelu OSI.
Protokół IP jest protokołem bezpołączeniowym, bez mechanizmów kontroli błędów.
Protokół ICMP został opracowany do obsługi błędów w transmisji datagramów IP.
Protokół ICMP wykorzystywany jest do:
• przesyłania informacji do nadawcy o błędach w transmisji,
• generowania pakietów do testowania sieci.
2
Z. Lipiński, Instytut Matematyki i Informatyki, Uniwersytet Opolski, Podstawy programowania sieciowego
Internet Control Message Protocol
Wiadomości ICMP są generowane gdy:
• datagram IP nie może być przesłany do odbiorcy ze względu na wartość pola TTL = 0 w nagłówku datagramu IP,
• przesyłane datgramy IP są zbyt duże dla danej sieci a datagram ma ustawioną opcję ‘nie fragmentować’,
• szybkość transmisji jest zbyt duża i odbiorca nie może odebrać nadchodzących pakietów, pole 'Window' w nagłówku
segmentu TCP,
• odbiorca chce aby datagramy były przesyłane inna trasą, pole 'Opcje' w datagramie IP,
• błędna wartość w polu 'Header Checksum’, np. z powodu uszkodzenia datagramu.
3
Z. Lipiński, Instytut Matematyki i Informatyki, Uniwersytet Opolski, Podstawy programowania sieciowego
Wartości pola 'Typ wiadomości' w komunikacie ICMP
Pole 'Type'
Opis pola
0
Odpowiedz Echo
3
Cel nieosiagalny (Destination Unreachable).
4
Wygasniecie zrodla (Source Quench).
5
Przekierowanie (Redirect).
8
Zadanie Echo (Echo Request).
11
Parametr TTL =0 (Time To Live Exceeded)
12
Niewlasciwy parametr (Parameter Problem).
13
Zadanie znacznika czasu (Timestamp).
14
Odpowiedz ze znacznikiem czasu
(Timestamp Reply).
15
Zadanie informacji (Information Request).
16
Odpowiedz z informacja (Information Reply).
Wartosci pola 'Typ wiadomosci'
4
Z. Lipiński, Instytut Matematyki i Informatyki, Uniwersytet Opolski, Podstawy programowania sieciowego
Struktura wiadomości ICMP typu 0, 8
Typ=8, 0
Wiadomość: Echo request, Echo Reply.
Kod=0
Identyfikator
Suma kontr.
Kolejny numer
Dane
Pole: Typ = 8 (typ wiadomości: echo).
0 (typ wiadomości: echo reply).
Wiadomosci ICMP: Echo, Echo Reply
Pole: Kod = 0.
Pole: Suma kontrolna.
Pole: Identyfikator. Dla pola ‘Kod = 0’ pole służy do skojarzenia odpowiedzi z zapytaniem.
Pole: Kolejny numer. Dla pola ‘Kod = 0’ pole służy do skojarzenia odpowiedzi z zapytaniem.
Pole: Dane.
Dane zawarte w wiadomości 'Echo' muszą być zwrócone w wiadomości 'Echo Replay'.
Wiadomości: echo, echo reply (typ 8, 0) są używane do sprawdzania jakości łączy i stanu urządzeń w sieci.
5
Z. Lipiński, Instytut Matematyki i Informatyki, Uniwersytet Opolski, Podstawy programowania sieciowego
Specyfikacja struktury ECHOREQUEST
Nazwa struktury: ECHOREQUEST
Opis
: Struktura zawiera komunikat ICMP Echo Request
typedef struct
{
ICMPHDR
DWORD
char
} ECHOREQUEST,
tagECHOREQUEST
icmpHdr;
dwTime;
cData[REQ_DATASIZE];
*PECHOREQUEST;
6
Z. Lipiński, Instytut Matematyki i Informatyki, Uniwersytet Opolski, Podstawy programowania sieciowego
Specyfikacja struktury ECHOREPLY
Nazwa struktury : ECHOREPLY
Opis
: Struktura zawiera komunikat ICMP Echo Reply
typedef struct tagECHOREPLY
{
IPHDR
ipHdr;
ECHOREQUEST echoRequest;
char
cFiller[256];
} ECHOREPLY, *PECHOREPLY;
7
Z. Lipiński, Instytut Matematyki i Informatyki, Uniwersytet Opolski, Podstawy programowania sieciowego
Specyfikacja struktury IPHDR
Nazwa struktury : IPHDR
Opis
: Struktura zawiera nagłówek datagramu IP, pole Protocol = 1.
typedef struct tagIPHDR
{
u_char
VIHL;
u_char
TOS;
short
TotLen;
short
ID;
short
FlagOff;
u_char
TTL;
u_char
Protocol;
u_short
Checksum;
struct in_addr
iaSrc;
struct in_addr
iaDst;
} IPHDR, *PIPHDR;
//
//
//
//
//
//
//
//
//
//
Pola:
Pole:
Pole:
Pole:
Pola:
Pole:
Pole:
Pole:
Pole:
Pole:
wersja protokolu IP, długość nagłówka (4 bity, 4 bity)
Type of service (8 bitów)
Total length (8 bitów)
Identification (16 bitów)
Flags, Fragment offset (3 bity, 13 bitow)
Time-to-live (8 bitów)
Protocol, dla ICMP pole Protocol = 1, (8 bitów)
Checksum, (16 bitów)
Internet address, source (32 bity)
Internet address, destination (32 bity)
8
Z. Lipiński, Instytut Matematyki i Informatyki, Uniwersytet Opolski, Podstawy programowania sieciowego
Specyfikacja struktury ICMPHDR
Nazwa struktury : ICMPHDR
Opis
: Struktura zawiera nagłówek wiadomości ICMP echo request/reply.
typedef struct tagICMPHDR
{
// Pole: Type, (8 bitów)
u_char Type;
u_char Code;
// Pole: Code, (pole kod błędu powinno mieć wielkość 32 bitów)
u_short Checksum; // Pole: Checksum, (16 bitów)
u_short ID;
// Pole: Identification, (8 bitów)
u_short Seq;
// Pole: Sequence, (8 bitów)
// pola ID i Seq służą do kojarzenia pytań z odpowiedziami
} ICMPHDR, *PICMPHDR;
9
Z. Lipiński, Instytut Matematyki i Informatyki, Uniwersytet Opolski, Podstawy programowania sieciowego
Specyfikacja struktury sockaddr_in
Nazwa struktury: sockaddr_in
Opis
: Zawiera adres IP i numer portu odbiorcy danych.
Struktura zadeklarowana w pliku Winsock2.h (dla IPv4), ws2tcpip.h (dla IPv6).
Atrybuty : short sin_family; unsigned short sin_port; struct in_addr sin_addr; char sin_zero[8];
sin_family
Kod rodziny adresów TCP//IP (wartość musi być AF_INET).
sin_port
Numer portu (IP port).
sin_addr
Adres IP odbiorcy.
sin_zero
Pole służy do uzupełniania tak, aby wielkość struktury była taka sama jak SOCKADDR.
Implementacja struktury sockaddr_in:
struct sockaddr_in
{
short
u_short
struct in_addr
char
};
sin_family;
sin_port;
sin_addr;
sin_zero[8];
struct sockaddr_in6
{
short
u_short
u_long
struct in6_addr
u_long
};
sin6_family;
sin6_port;
sin6_flowinfo;
sin6_addr;
sin6_scope_id;
10
Z. Lipiński, Instytut Matematyki i Informatyki, Uniwersytet Opolski, Podstawy programowania sieciowego
Specyfikacja struktury in_addr
Nazwa struktury : in_addr
Opis
: Struktura zdefiniowana w pliku WINSOCK.H
struct
in_addr
{
union {
struct
{
unsigned char
s_b1, s_b2, s_b3, s_b4;
} S_un_b;
struct
{
unsigned short s_w1, s_w2;
} S_un_w;
unsigned long S_addr;
} S_un;
};
11
Z. Lipiński, Instytut Matematyki i Informatyki, Uniwersytet Opolski, Podstawy programowania sieciowego
Specyfikacja struktury fd_set
Nazwa struktury: fd_set
Opis
Atrybuty
: Struktura służy do tworzenia zbiorów gniazd.
Struktura używana przez funkcje winsock np. funkcję select().
Struktura zadeklarowana w pliku Winsock2.h.
: u_int fd_count; SOCKET fd_array[FD_SETSIZE];
fd_count - Liczba gniazd w zbiorze.
fd_array - Tablica gniazd.
Implementacja struktury fd_set:
typedef struct fd_set {
u_int fd_count;
SOCKET fd_array[FD_SETSIZE];
} fd_set;
12
Z. Lipiński, Instytut Matematyki i Informatyki, Uniwersytet Opolski, Podstawy programowania sieciowego
Specyfikacja struktury timeval
Nazwa struktury: timeval
Opis
Atrybuty
: Struktura stosowana do określania wartości czasu.
Struktura zadeklarowana w pliku time.h.
: long tv_sec;
long tv_usec;
tv_sec - wartość czasu w sekundach.
tv_usec - wartość czasu w mikrosekundach (mikro µ = 1 / 1.000.000).
Implementacja struktury timeval:
typedef struct timeval {
long
tv_sec;
long
tv_usec;
} timeval;
13
Z. Lipiński, Instytut Matematyki i Informatyki, Uniwersytet Opolski, Podstawy programowania sieciowego
Specyfikacja funkcji GetTickCount()
Nazwa funkcji : GetTickCount()
Zwracana wartość: DWORD
Zwarcaną wartością jest liczba milisekund od czasu uruchmienia systemu.
Argumenty
: brak
Opis
:
Funkcja zwraca liczbę milisekund jak upłynęła od czasu uruchomienia systemu, maks. czas 49,7 dnia.
Zwracane wartości ograniczone są ‘rozdzielczością czasową’ systemu. Do uzyskania infomacji o
rozdzielczości czasowej systemu należy użyć funkcji GetSystemTimeAdjustment().
Zwracana wartość jest przechowywana w zmienej DWORD (32-bit unsigned integer), dlatego po około 49,7
dniach ciągłej pracy systemu wartość jest liczona ponownie (zerowna).
Funkcja zadeklarowana w plilku Winbase.h.
Implementacja w pliku Kernel32.lib.
Przykład: użycie funkcji GetTickCount().
#define
TIMELIMIT = 774545841
DWORD dwStart = GetTickCount();
// zatrzymaj gdy działanie programu przekroczy czas TIMELIMIT
if( GetTickCount() - dwStart >= TIMELIMIT )
Cancel();
14
Z. Lipiński, Instytut Matematyki i Informatyki, Uniwersytet Opolski, Podstawy programowania sieciowego
Specyfikacja funkcji select()
Nazwa funkcji
: select()
Zwracana wartość: int
Funkcja zwraca
- liczbę uchwytów do gniazd (socket handles) które są w strukturze fd_set,
- zero, gdy wygasł limit czasu lub
- SOCKET_ERROR, gdy wystąpił błąd.
Kody błędów: WSANOTINITIALISED, WSAEFAULT, WSAENETDOWN, WSAEINVAL,
WSAEINTR, WSAEINPROGRESS, WSAENOTSOCK
Argumenty
: int nfds, fd_set* readfds, fd_set* writefds, fd_set* exceptfds, const struct timeval* timeout
nfds Readfds writefds exceptfds timeout -
Opis
[in] Ignorowany. Parameter dodany dla zgodności z gniazdami Berkeley.
[in-ot] Opcjonalny, wskaźnik do zbioru gniazd, do weryfikacji czy mają atrybut do czytania (readability).
[in-out] Opcjonalny, wskaźnik do zbioru gniazd, do weryfikacji czy mają atrybut for zapisu (writability).
[in-out] Opcjonalny, wskaźnik do zbioru gniazd, do weryfikacji czy są bez błędów.
[in] Maksymalny czas oczekiwania pod warunkiem, że jest w formacie struktury TIMEVAL.
Wartość parametru równa zero blokuje operacje.
: Funkcja select() określa status gniazd oczekujących na wykonanie synchronicznej operacji
wejścia/wyjścia.
15
Z. Lipiński, Instytut Matematyki i Informatyki, Uniwersytet Opolski, Podstawy programowania sieciowego
Specyfikacja funkcji Ping()
int Ping(SOCKET raw, SOCKADDR_IN target_addr)
{
DWORD
start;
struct timeval
timeout;
fd_set
readfds;
int
sel;
int
rcv; //liczba wysłanych bajtów, sendto()
if(SendEchoRequest(raw, &target_addr) == SOCKET_ERROR)
{
cerr << "sendto() error no: " << WSAGetLastError() << endl;
WSACleanup();
return 1;
}
start = GetTickCount();
do {
readfds.fd_count = 1; // struktura fd_set
readfds.fd_array[0] = raw; // struktura fd_set
timeout.tv_sec =
5; // struktura timeval
timeout.tv_usec = 0; // struktura timeval
if((sel = select(1, &readfds, NULL, NULL, &timeout)) == SOCKET_ERROR)
{
cerr << "select() error no: " << WSAGetLastError() << endl;
WSACleanup();
return 1;
}
if(sel == 0)
cout << "uplynal czas oczekiwania na odpowiedz ... " << endl;
else if((rcv = RecvEchoReply(raw, start)) == SOCKET_ERROR)
{
cerr << "recvfrom() error no: " << WSAGetLastError() << endl;
WSACleanup();
return 1;
}
} while( rcv == 0 );
return 0; }
16
Specyfikacja funkcji in_cksum()
Nazwa funkcji
: in_cksum()
Zwracana wartość: u_short
Argumenty
: u_short *addr, int len
Opis
: Funkcja wylicza sumę kontrolną tak, jak dla nagłówka datagramu IP, czyli zwracaną wartością
jest liczba 16-bitowych słów w nagłówku datagramu IP (jeżeli wyliczona suma nie zajmuje
16 bitów wartość jest uzupełniana jedynkami). Przy obliczaniu sumy kontrolnej przyjmuje
się, że pole ‘Header Checksum’ zawiera same zera.
u_short in_cksum(u_short *addr, int len)
{
register int
nleft = len;
register u_short
*w = addr;
register u_short
answer;
register int
sum = 0;
while( nleft > 1 )
{
sum += *w++;
nleft -= 2;
}
if( nleft == 1 )
{
u_short
u = 0;
*(u_char *)(&u) = *(u_char *)w;
sum += u;
}
// sum & 65535 (sum & 1111111111111111)
sum = (sum >> 16) + (sum & 0xffff);
sum += (sum >> 16);
answer = ~sum;
return (answer);
}
17
Specyfikacja funkcji SendEchoRequest()
Nazwa funkcji : SendEchoRequest();
Zwracana wartość: int
Argumenty
: SOCKET, SOCKADDR_IN *
Wartości arg
:
Funkcjonalność : Funkcja wysyła żądanie echa.
int SendEchoRequest(SOCKET sock, SOCKADDR_IN * target_addr)
{
static ECHOREQUEST echo_req;
static int
seq = 1;
int
rc; // liczba wysłanych bajtów
echo_req.icmpHdr.Type
= ICMP_ECHOREQ; // typ wiadomosci icmp, typy wiadomosci ICMP (RFC 792)
echo_req.icmpHdr.Code
= 0;
// kod wiadomosci 0
echo_req.icmpHdr.Checksum
= 0;
// przed obliczniem sumy kontrolnej pole Checksum=0
echo_req.icmpHdr.ID
= _getpid();
// proces id
echo_req.icmpHdr.Seq
= seq++;
// kolejny numer
memset(echo_req.cData, '*', REQ_DATASIZE);
echo_req.dwTime = GetTickCount();
echo_req.icmpHdr.Checksum = in_cksum((u_short *)&echo_req, sizeof(ECHOREQUEST));
rc = sendto(sock, (const char *)&echo_req, sizeof(ECHOREQUEST), 0, (SOCKADDR *) target_addr,
sizeof(SOCKADDR_IN));
return (rc);
}
18
Z. Lipiński, Instytut Matematyki i Informatyki, Uniwersytet Opolski, Podstawy programowania sieciowego
Specyfikacja funkcji RecvEchoReply()
Nazwa funkcji
: RecvEchoReply()
Zwracana wartośc: int
Argumenty
: SOCKET, DWORD
Opis
: Funkcja odbiera komunikat Echo Reply.
int RecvEchoReply(SOCKET sock, DWORD start)
{
ECHOREPLY
echo_reply;
SOCKADDR_IN
from_addr;
int
addrlen;
int
rc; // liczba wysłanych bajtów
DWORD
elapsed;
addrlen = sizeof(struct sockaddr_in);
rc = recvfrom(sock, (char *) &echo_reply, sizeof(ECHOREPLY), 0, (SOCKADDR *) &from_addr, &addrlen);
if (rc == SOCKET_ERROR)
return(rc);
if (echo_reply.echoRequest.icmpHdr.ID != _getpid())
{
cout << "Brak odpowiedzi na zapytanie o ID: " <<
return 1;
}
elapsed = GetTickCount() - start;
echo_reply.echoRequest.icmpHdr.ID << endl;
if (echo_reply.echoRequest.icmpHdr.Type != ICMP_ECHOREPLY)
cout << "Niewlasciwy typ odpowiedzi: "<< echo_reply.echoRequest.icmpHdr.Type << endl;
else
cout << "Czas odpowiedzi: " << elapsed << " ms, (id= " << echo_reply.echoRequest.icmpHdr.ID << ", seq= "
<< echo_reply.echoRequest.icmpHdr.Seq << ") "<< endl;
return 1;
}
19
Z. Lipiński, Instytut Matematyki i Informatyki, Uniwersytet Opolski, Podstawy programowania sieciowego
Specyfikacja funkcji sendto()
Nazwa funkcji : sendto()
Zwracana wartość: Funkcja sento() zwraca całkowitą liczbę wysłanych bajtów.
W pozostałych przypadkach zwracana jest wartość SOCKET_ERROR.
Argumenty
Opis
: SOCKET s, const char* buf, int len, int flags, const struct sockaddr* to, int tolen.
s
[in] Obiekt identyfikujący gniazdo.
buf
[in] Bufor na dane do wysłania.
len
[in] Długośc danych w buf, (liczona w bajtach).
flags
[in] Wskaźnik określający sposób wywołania funkcji.
to
[in] Argument opcjonalny, wskaźnik do struktury sockaddr zawierającej adres gniazda odbiorcy.
tolen
[in] Wielkość adresu w zmiennej to, (liczona w bajtach).
: Funkcja sendto() wysyła dane do konkretnego odbiorcy.
Funkcja zadeklarowana w pliku: Winsock2.h.
Implementacja w bibliotece: Ws2_32.lib.
20
Z. Lipiński, Instytut Matematyki i Informatyki, Uniwersytet Opolski, Podstawy programowania sieciowego
Specyfikacja funkcji recvfrom()
Nazwa funkcji
: recvfrom()
Zwracana wartość: typ int, liczba odebranych bajtów
Argumenty
: SOCKET s, char* buf, int len, int flags, struct sockaddr* from, int* fromlen
s-
[in] Obiekt identyfikujący połączone gniazdo (bound socket).
buf -
[out] Bufor na przychodzące dane.
len -
[in] Długość zmiennej buf (w bajtach).
flags -
[in] Wskaźnik określający sposób wywołania funkcji. Określa procesy OOB (‘Out-of-Band Data’).
MSG_PEEK Peeks at the incoming data. The data is copied into the buffer but is not removed from the input queue. The
function subsequently returns the amount of data that can be read in a single call to the recvfrom (or recv) function,
which may not be the same as the total amount of data queued on the socket. The amount of data that can actually be
read in a single call to the recvfrom (or recv) function is limited to the data size written in the send or sendto function call.
MSG_OOB.
from -
[out] Argument opcjonalny, wskaźnik do atrybutu ‘struct in_addr sin_addr’ w strukturze
SOCKADDR.
fromlen Opis
[in, out] Argument opcjonalny, wskaźnik do zmiennej przechowującej wielkość zmiennej from.
: Funkcja recvfrom() odbiera datagramy i przechowuje adres nadawcy.
21
Z. Lipiński, Instytut Matematyki i Informatyki, Uniwersytet Opolski, Podstawy programowania sieciowego
Specyfikacja funkcji socket()
Nazwa funkcji
: socket()
Zwracana wartość: SOCKET
Jeżeli nie ma błędów, funkcja socket() zwraca referencje do nowego gniazda.
W przeciwnym przypadku zwraca kod INVALID_SOCKET.
Kod błędu można uzyskać przez wywołanie funkcji WSAGetLastError().
Argumenty
: int af, int type, int protocol
af -
[in] Typ adresu stosu (address family specification).
type -
[in] Typ adresu dla nowych gniazd (SOCK_STREAM, SOCK_DGRAM).
protocol-
[in] Numer protokołu użytego przez gniazdo.
Wartości parametruprotocol: IPPROTO_IP, IPPROTO_TCP, 0.
Opis
: Funkcja socket() tworzy gniazdo o określonym typie (specific service provider).
Funkcja zadeklarowana w pliku winsock2.h, implementacja w pliku ws2_32.lib.
22
Z. Lipiński, Instytut Matematyki i Informatyki, Uniwersytet Opolski, Podstawy programowania sieciowego
Specyfikacja funkcji _getpid()
Nazwa funkcji
: _getpid()
Zwracana wartość: int
Funkcja _getpid() zwraca identyfikator procesu (process ID).
Argumenty
: brak
Opis
: Funkcja zadeklarowana w pliku process.h
23
Z. Lipiński, Instytut Matematyki i Informatyki, Uniwersytet Opolski, Podstawy programowania sieciowego
Surowe gniazda (typ gniazda SOCK_RAW)
Obsługa gniazd typu SOCK_RAW nie jest wymagana.
Odmiany gniazd typu SOCK_RAW:
• odmiana w której zakłada się, że znany jest typ protokołu zapisany w nagłówku datagramu IP.
Przykładem takiego gniazda jest gniazdo ICMP.
• druga odmiana pozwala użyć dowolnego typ protokołu. Odmiana gniazda stosowana np. dla protokołów
eksperymentalnych, gdy nie jest znana wartość pola ‘typ protokołu’ w nagłówku datagramu IP.
24
Z. Lipiński, Instytut Matematyki i Informatyki, Uniwersytet Opolski, Podstawy programowania sieciowego
Zasady użycia gniazd SOCK_RAW
Wysyłany datagram może nie zawierać nagłówka IP jeżeli jest ustawiona opcja gniazda IP_HDRINCL.
Do gniazda odbiorcy zawsze dociera datagram z nagłówkiem bez względu na to, czy jest ustawiona opcja gniazda IP_HDRINCL.
Odebrane datagramy są kopiowane do wszystkich gniazd SOCK_RAW jeżeli spełniają następujące warunki:
• Numer protokołu określony dla gniazda jest zgodny z numerem w nagłówku przychodzącego datagramu IP.
• Jeżeli adres IP lokalnego hosta jest przypisany do gniazda to powinien być zgodny z adresem IP odbiorcy w nagłówku
datagramu IP. Aplikacja może określić adres IP lokalnego hosta poprzez wywołanie funkcji bind().
Jeżeli żaden adres IP lokalnego hosta jest nie jest przypisany do gniazda to datagramy są zawsze kopiowane do gniazda
(bez względu jaki adres jest w nagłówku datagramu IP).
• Jeżeli adres IP nadawcy jest przypisany do gniazda to powinien być zgodny z adresem IP nadawcy w nagłówku datagramu IP.
• Aplikacja może określić adres IP nadawcy poprzez wywołanie funkcji connect().
Jeżeli adres IP nadawcy jest nie jest przypisany do gniazda to datagramy są zawsze kopiowane do gniazda.
Uwaga:
Gniazda typu SOCK_RAW mogą odbierać przypadkowe, nieoczekiwane datagramy, np. aplikacja ping wysyła żądanie echa
(datagram ‘ICMP echo requests’), spodziewa się odebrać datagram ‘ICMP echo response’ ale może odebrać inne datagramy np.
‘ICMP HOST_UNREACHABLE’.
Jeżeli kilka gniazd typu SOCK_RAW jest otwartych na danym hoście to do wszystkich gniazd docierają takie same datagramy.
Apliakcja powinna mieć mechanizm rozróżniania datagramów.
25
Z. Lipiński, Instytut Matematyki i Informatyki, Uniwersytet Opolski, Podstawy programowania sieciowego
Specyfikacja projektu
Nazwa projektu: ping2
Typ projektu : Win32 console application
Lista plików : ping2.cpp, icmp.h
Kompilacja
: Microsoft Visual C++ 2008
Utworzyć projekt typu 'Win32 console application‘ w menu
(-)File-> New -> Project-> Other languages-> Visual C++ -> win32 ->
Win32 console application -> wpisać nazwę: ping2 -> przycisk (OK) ->
Okno Win32 application wizard – ping2-> wybrać: Application settings ->
wybrać: Empty project-> Przycisk (Finish).
Konfiguracja projektu:
(-)Project-> nazwa_projektu Properies... -> Configuration Properies-> Linker-> Input -> Additional
Dependecies, wpisać: ws2_32.lib.
Wkopiować pliki: icmp.h do katalogu projektu.
Funkcjonalność:
uruchomienie \> ping2 adres_IP_hosta
26
Z. Lipiński, Instytut Matematyki i Informatyki, Uniwersytet Opolski, Podstawy programowania sieciowego
Specyfikacja projektu
Pliki nagłówkowe:
process.h, winsock2.h, iostream, "icmp.h"
Funkcje programu:
WSAStartup(),
socket(),
gethostbyname(),
select(),
sendto(),
recvfrom(),
_getpid()
Ping(),
SendEchoRequest(),
RecvEchoReply(),
GetTickCount(),
in_cksum()
27
Z. Lipiński, Instytut Matematyki i Informatyki, Uniwersytet Opolski, Podstawy programowania sieciowego
Specyfikacja projektu
Zmienne programu:
#define NUM_PINGS 10
// Liczba wyslanych zapytan ‘Echo Request’
WSADATA
WORD
int
SOCKET
HOSTENT *
SOCKADDR_IN
int
wsaData;
wVersionRequested = MAKEWORD(2,2);
rc;
raw;
host_ent;
target_addr;
count;
struct timeval
fd_set
timeout;
readfds;
static ECHOREQUEST echo_req;
ECHOREPLY
echo_reply;
28
Z. Lipiński, Instytut Matematyki i Informatyki, Uniwersytet Opolski, Podstawy programowania sieciowego
Struktura programu (struktura funkcji main())
1. Sprawdzenie poprawności argumentów programu.
2. Uruchomienie Winsock’a
rc = WSAStartup(wVersionRequested, &wsaData);
3. Sprawdzenie wersji Winsock
Czy wsaData.wVersion != wVersionRequested ?
4. Utworzenie gniazda
raw = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
5. Inicjowanie zmiennej adresem IP odbiorcy lub nazwą hosta
target_addr.sin_addr.s_addr = inet_addr(argv[1])
6. Gdy podano adres hosta
host_ent = gethostbyname(argv[1]);
7. Przekazanie nazwy do obiektu target_addr:
memcpy(&target_addr.sin_addr, host_ent->h_addr, host_ent->h_length);
29
Z. Lipiński, Instytut Matematyki i Informatyki, Uniwersytet Opolski, Podstawy programowania sieciowego
Struktura programu (struktura funkcji main())
8. Przekazanie wartości atrybutów obiektu target_addr
target_addr.sin_family = AF_INET;
target_addr.sin_port = 0;
9. Przekierowanie na ekran wiadomości:
cout << "Pingowanie hosta: " << argv[1] << " (" << inet_ntoa(target_addr.sin_addr) << ") " << endl;
10. Wywołanie funkcji Ping()
Ping(raw, target_addr);
11. Zamknięcie gniazda
closesocket(raw);
WSACleanup();
30
Z. Lipiński, Instytut Matematyki i Informatyki, Uniwersytet Opolski, Podstawy programowania sieciowego
#include <process.h>
#include <winsock2.h>
#include <iostream>
#include "icmp.h"
using namespace std;
#define
int
u_short
int
int
NUM_PINGS 10
// liczba wysłanych wiad. ICMP Echo Request
Ping(SOCKET, SOCKADDR_IN);
in_cksum(u_short *addr, int len);
SendEchoRequest(SOCKET, SOCKADDR_IN *);
RecvEchoReply(SOCKET, DWORD);
31
int main(int argc, char **argv)
{
WSADATA
wsaData;
WORD
wVersionRequested = MAKEWORD(2,2);
int
rc;
SOCKET
raw;
HOSTENT *
host_ent;
SOCKADDR_IN
target_addr;
int
count;
if (argc != 2)
{
cerr << "Wpisz: " << argv[0] << " hazwaHosta" << endl;
return 1;
}
if (rc = WSAStartup(wVersionRequested, &wsaData))
cerr << "WSAStartup() error no: " << rc << endl;
if (wsaData.wVersion != wVersionRequested)
{
cerr << "WinSock version: " << LOBYTE(wVersionRequested) <<"." <<
HIBYTE(wVersionRequested) << " not supported" << endl;
WSACleanup();
return 1;
}
32
if ((raw = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP)) == SOCKET_ERROR)
{
cerr << "socket() error no: " << WSAGetLastError() << endl;
WSACleanup();
return 1;
}
if ((target_addr.sin_addr.s_addr = inet_addr(argv[1])) == INADDR_NONE)
{
if (host_ent = gethostbyname(argv[1]))
memcpy(&target_addr.sin_addr, host_ent->h_addr, host_ent->h_length);
else
{
cerr << "Nie znaleziono hosta " << argv[1] << " error no: " <<
WSAGetLastError() << endl;
WSACleanup();
return 1;
}
}
target_addr.sin_family = AF_INET;
target_addr.sin_port = 0;
cout << "Pingowanie hosta: " << argv[1] << " ("<< inet_ntoa(target_addr.sin_addr) << ") "<< endl;
for (count = 0; count < NUM_PINGS; ++count)
Ping(raw, target_addr);
closesocket(raw);
WSACleanup();
return 0;
}
33
Specyfikacja funkcji setsockopt() (aplikacja tracert)
Nazwa funkcji : setsockopt()
Zwracana wartość: int
setsockopt() zwraca zero gdy wywołanie funkcji zakończyło się sukcesem.
W innym przypadku zwraca SOCKET_ERROR, i określony kod błędu może być uzyskany poprzez
wywołanie funkcji WSAGetLastError():
Argumenty
: SOCKET s, int level, int optname, const char* optval, int optlen
s–
[in] identyfikator gniazda.
level – [in] nazwa poziomu opcji (SOL_SOCKET, IPPROTO_TCP).
SOL_SOCKET: SO_ACCEPTCONN, SO_BROADCAST, SO_CONDITIONAL_ACCEPT,SO_CONNDATA,
SO_CONNDATALEN, SO_CONNECT_TIME, SO_CONNOPT, SO_CONNOPTLEN, SO_DISCDATA, SO_DISCDATALEN, SO_DISCOPT,
SO_DISCOPTLEN, SO_DEBUG, SO_DONTLINGER, SO_DONTROUTE, SO_ERROR, SO_EXCLUSIVEADDRUSE, SO_GROUP_ID,
SO_GROUP_PRIORITY, SO_KEEPALIVE, SO_LINGER, SO_MAX_MSG_SIZE, SO_MAXDG, SO_MAXPATHDG, SO_OOBINLINE,
SO_OPENTYPE, SO_PROTECT, SO_PROTOCOL_INFO, SO_PROTOCOL_INFOA, SO_PROTOCOL_INFOW,SO_RCVBUF, SO_RCVLOWAT,
SO_RCVTIMEO, SO_REUSEADDR, SO_SNDBUF, SO_SNDLOWAT, SO_SNDTIMEO, SO_SYNCHRONOUS_ALERT,
SO_SYNCHRONOUS_NONALERT, SO_TYPE, SO_UPDATE_ACCEPT_CONTEXT, SO_UPDATE_CONNECT_CONTEXT,
SO_USELOOPBACK.
IPPROTO_TCP: TCP_EXPEDITED_1122, TCP_NODELAY.
IPPROTO_IP: IP_ADD_MEMBERSHIP, IP_ADD_SOURCE_MEMBERSHIP, IP_BLOCK_SOURCE, IP_DONTFRAGMENT,
IP_DROP_MEMBERSHIP, IP_DROP_SOURCE_MEMBERSHIP, IP_HDRINCL,IP_MULTICAST_IF, IP_MULTICAST_LOOP,
IP_MULTICAST_TTL,
IP_OPTIONS, IP_PKTINFO,IP_RECEIVE_BROADCAST,IP_TOS, IP_TTL, IP_UNBLOCK_SOURCE.
optname – [in] nazwa opcji, wartość poziomu opcji.
optval – [in] wskaźnik do zmiennej która przechowuje dane o opcji.
optlen – [in] wielkość zmiennej która przechowuje dane o opcji.
Opis
: Funkcja służy do ustawiania opcji gniazd.
Funkcja zadeklarowana w pliku Winbase.h. Implementacja w pliku ws2_32.lib.
Note If the setsockopt function is called before the bind function, TCP/IP options will not be checked with TCP/IP until the bind occurs.
In this case, the setsockopt function call will always succeed, but the bind function call may fail because of an early setsockopt failing.
Note If a socket is opened, a setsockopt call is made, and then a sendto call is made, Windows Sockets performs an implicit bind function call.
34
Z. Lipiński, Instytut Matematyki i Informatyki, Uniwersytet Opolski, Podstawy programowania sieciowego

Podobne dokumenty